strikethroo 4.0.0 → 4.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.
- package/README.md +16 -2
- package/dist/__tests__/fixtures/blueprint-trailing-summary.d.ts +14 -0
- package/dist/__tests__/fixtures/blueprint-trailing-summary.d.ts.map +1 -0
- package/dist/__tests__/fixtures/blueprint-trailing-summary.js +54 -0
- package/dist/__tests__/fixtures/blueprint-trailing-summary.js.map +1 -0
- package/dist/cli.js +23 -1
- package/dist/cli.js.map +1 -1
- package/dist/conflict-detector.d.ts +28 -12
- package/dist/conflict-detector.d.ts.map +1 -1
- package/dist/conflict-detector.js +45 -53
- package/dist/conflict-detector.js.map +1 -1
- package/dist/export-profile.d.ts +6 -0
- package/dist/export-profile.d.ts.map +1 -1
- package/dist/export-profile.js +46 -4
- package/dist/export-profile.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -86
- package/dist/index.js.map +1 -1
- package/dist/metadata.d.ts +12 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +76 -11
- package/dist/metadata.js.map +1 -1
- package/dist/profiles.d.ts.map +1 -1
- package/dist/profiles.js +52 -7
- package/dist/profiles.js.map +1 -1
- package/dist/prompts.d.ts +6 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +47 -3
- package/dist/prompts.js.map +1 -1
- package/dist/serve/config-write.d.ts +6 -3
- package/dist/serve/config-write.d.ts.map +1 -1
- package/dist/serve/config-write.js +20 -21
- package/dist/serve/config-write.js.map +1 -1
- package/dist/serve/derivation.d.ts +17 -19
- package/dist/serve/derivation.d.ts.map +1 -1
- package/dist/serve/derivation.js +43 -82
- package/dist/serve/derivation.js.map +1 -1
- package/dist/serve/events.d.ts +37 -8
- package/dist/serve/events.d.ts.map +1 -1
- package/dist/serve/events.js +114 -28
- package/dist/serve/events.js.map +1 -1
- package/dist/serve/self-review.d.ts +37 -7
- package/dist/serve/self-review.d.ts.map +1 -1
- package/dist/serve/self-review.js +93 -33
- package/dist/serve/self-review.js.map +1 -1
- package/dist/serve/server.d.ts +107 -0
- package/dist/serve/server.d.ts.map +1 -1
- package/dist/serve/server.js +502 -135
- package/dist/serve/server.js.map +1 -1
- package/dist/serve/workspace-model.d.ts +11 -17
- package/dist/serve/workspace-model.d.ts.map +1 -1
- package/dist/serve/workspace-model.js +84 -83
- package/dist/serve/workspace-model.js.map +1 -1
- package/dist/skill-scripts/shared/blueprint-parse.d.ts +16 -0
- package/dist/skill-scripts/shared/blueprint-parse.d.ts.map +1 -0
- package/dist/skill-scripts/shared/blueprint-parse.js +66 -0
- package/dist/skill-scripts/shared/blueprint-parse.js.map +1 -0
- package/dist/skill-scripts/shared/root.d.ts +6 -0
- package/dist/skill-scripts/shared/root.d.ts.map +1 -1
- package/dist/skill-scripts/shared/root.js +10 -4
- package/dist/skill-scripts/shared/root.js.map +1 -1
- package/dist/skill-scripts/shared/safe-fs.d.ts +89 -0
- package/dist/skill-scripts/shared/safe-fs.d.ts.map +1 -0
- package/dist/skill-scripts/shared/safe-fs.js +324 -0
- package/dist/skill-scripts/shared/safe-fs.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +13 -1
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +15 -1
- package/dist/update.js.map +1 -1
- package/dist/validation/graph-checks.d.ts +6 -14
- package/dist/validation/graph-checks.d.ts.map +1 -1
- package/dist/validation/graph-checks.js +8 -15
- package/dist/validation/graph-checks.js.map +1 -1
- package/dist/validation/metadata-gate.d.ts +2 -6
- package/dist/validation/metadata-gate.d.ts.map +1 -1
- package/dist/validation/metadata-gate.js +17 -6
- package/dist/validation/metadata-gate.js.map +1 -1
- package/dist/validation/strict-pass.d.ts.map +1 -1
- package/dist/validation/strict-pass.js +50 -6
- package/dist/validation/strict-pass.js.map +1 -1
- package/dist-web/assets/abnfDiagram-VCTEODGH-CY8QEBrj.js +1 -0
- package/dist-web/assets/apl-gfMMiTNf.js +1 -0
- package/dist-web/assets/arc-Pry-7G1_.js +1 -0
- package/dist-web/assets/architecture-7GRP2DOG-drIky86B.js +1 -0
- package/dist-web/assets/architectureDiagram-5GKGNRK7-YZUSf-Fx.js +36 -0
- package/dist-web/assets/array-BifhSqXX.js +1 -0
- package/dist-web/assets/asciiarmor-C_eisQCp.js +1 -0
- package/dist-web/assets/asn1-DCl_8MCW.js +1 -0
- package/dist-web/assets/asterisk-BEn0Cwpx.js +1 -0
- package/dist-web/assets/blockDiagram-I7D4REHJ-ByyeaYP7.js +129 -0
- package/dist-web/assets/brainfuck-D5EjA2JK.js +1 -0
- package/dist-web/assets/c4Diagram-7LVT6UL2-YSA0IA7A.js +38 -0
- package/dist-web/assets/channel-DEeX8XvW.js +1 -0
- package/dist-web/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist-web/assets/chunk-4HAMMTFA-8VzDhfwy.js +62 -0
- package/dist-web/assets/{chunk-FMBD7UC4-zW3dYoIJ.js → chunk-5VM5RSS4-ZNzvKenW.js} +2 -2
- package/dist-web/assets/chunk-75Z2AOVW-D3fZto5-.js +2 -0
- package/dist-web/assets/chunk-DU6HZSFF-vtUmBAxv.js +125 -0
- package/dist-web/assets/chunk-F27PBJKO-BMcZVmbf.js +1 -0
- package/dist-web/assets/chunk-FOHPRMQF-DzxwRta7.js +161 -0
- package/dist-web/assets/chunk-GMAD6QVW-C5gwfNkR.js +72 -0
- package/dist-web/assets/chunk-GVQU2GXP-CqFZMp6I.js +1 -0
- package/dist-web/assets/chunk-IMKFNOWR-CJDfPbiX.js +231 -0
- package/dist-web/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist-web/assets/chunk-L3NEJ4N5-CHeJ2XSW.js +1 -0
- package/dist-web/assets/chunk-OSK3NFVY-CXOClbf5.js +10 -0
- package/dist-web/assets/chunk-P2QGCYS3-C9Wc2Z2I.js +1 -0
- package/dist-web/assets/chunk-POPQ4Y6H-CfiiGKfO.js +1 -0
- package/dist-web/assets/chunk-PWAF6VOD-CtZ4gx65.js +1 -0
- package/dist-web/assets/chunk-SHT3W25Y-C50-QCrR.js +168 -0
- package/dist-web/assets/chunk-SVP7TREG-EIHQbPfX.js +88 -0
- package/dist-web/assets/chunk-TICWLB2K-DOB5NZ4R.js +206 -0
- package/dist-web/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
- package/dist-web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist-web/assets/classDiagram-ZZMXUADV-H5H_txsg.js +1 -0
- package/dist-web/assets/classDiagram-v2-VYDZK3BY-H5H_txsg.js +1 -0
- package/dist-web/assets/clike-D_6L3tnO.js +1 -0
- package/dist-web/assets/clojure-BflJGmDX.js +1 -0
- package/dist-web/assets/cmake-84nbDH0I.js +1 -0
- package/dist-web/assets/cobol-DHLQUbN7.js +1 -0
- package/dist-web/assets/coffeescript-De_zI4J0.js +1 -0
- package/dist-web/assets/commonlisp-DgAKBe0r.js +1 -0
- package/dist-web/assets/cose-bilkent-JH36ORCC-BEpcWcmK.js +1 -0
- package/dist-web/assets/crystal-Bsdphhtm.js +1 -0
- package/dist-web/assets/css-CnaYoQib.js +1 -0
- package/dist-web/assets/cynefin-OW5HDTMX-mR6pfDSH.js +1 -0
- package/dist-web/assets/cynefinDiagram-5FMLGOSQ-6-2oQdEg.js +62 -0
- package/dist-web/assets/cypher-p9eYesGn.js +1 -0
- package/dist-web/assets/cytoscape.esm-Yq6u8L66.js +321 -0
- package/dist-web/assets/d-DWkQyNnU.js +1 -0
- package/dist-web/assets/dagre-C-rnJpZF.js +1 -0
- package/dist-web/assets/dagre-GXQ25YYZ-Cm1zvIWj.js +4 -0
- package/dist-web/assets/defaultLocale-BFoDCU3G.js +1 -0
- package/dist-web/assets/diagram-S7CK7UJ4-D6mECnyP.js +30 -0
- package/dist-web/assets/diagram-UQ7AKVKN-CzmXABVS.js +41 -0
- package/dist-web/assets/diagram-VSXAHHWV-CpEauecU.js +3 -0
- package/dist-web/assets/diagram-VX7I27RA-CXPYrCgX.js +24 -0
- package/dist-web/assets/diagram-Z3DM3KII-RcMIMVWZ.js +24 -0
- package/dist-web/assets/diff-ChtP43wD.js +1 -0
- package/dist-web/assets/dist--eYrBgi0.js +2 -0
- package/dist-web/assets/dist-B-O4eZD_.js +1 -0
- package/dist-web/assets/dist-B27L6oW0.js +1 -0
- package/dist-web/assets/dist-BKXbBuAc.js +1 -0
- package/dist-web/assets/dist-BPcC0hnc.js +9 -0
- package/dist-web/assets/dist-BgwxV8e_.js +1 -0
- package/dist-web/assets/dist-BlG40nRw.js +1 -0
- package/dist-web/assets/dist-Bqc6e86z.js +1 -0
- package/dist-web/assets/dist-BsvASXHG.js +1 -0
- package/dist-web/assets/dist-C15GN054.js +1 -0
- package/dist-web/assets/dist-C4QRmcTO.js +1 -0
- package/dist-web/assets/dist-C4lZy0XG.js +6 -0
- package/dist-web/assets/dist-CFLbFzpB.js +23 -0
- package/dist-web/assets/dist-CP6AUVtv.js +1 -0
- package/dist-web/assets/dist-CpYnHHz6.js +1 -0
- package/dist-web/assets/dist-DHnGmK79.js +1 -0
- package/dist-web/assets/dist-DYmIHv0n.js +13 -0
- package/dist-web/assets/dist-DauRO0RO.js +1 -0
- package/dist-web/assets/dist-Day7i26p.js +1 -0
- package/dist-web/assets/dist-Do_t70vA.js +1 -0
- package/dist-web/assets/dist-G8nWWSie.js +11 -0
- package/dist-web/assets/dist-QfYLz_N1.js +1 -0
- package/dist-web/assets/dist-TZhb2tj2.js +1 -0
- package/dist-web/assets/dist-Wr2Wo_KE.js +1 -0
- package/dist-web/assets/dist-kYRo7Db1.js +1 -0
- package/dist-web/assets/dist-kfqV1Lu-.js +2 -0
- package/dist-web/assets/dist-v5Q1xZ2K.js +1 -0
- package/dist-web/assets/dockerfile-DJkHQgkl.js +1 -0
- package/dist-web/assets/dtd-DTF72YNO.js +1 -0
- package/dist-web/assets/dylan-BCDoL_-p.js +1 -0
- package/dist-web/assets/ebnf-D4c0_ac3.js +1 -0
- package/dist-web/assets/ebnfDiagram-PWID7BFC-MZpZ_VnU.js +1 -0
- package/dist-web/assets/ecl-BVIeWmwY.js +1 -0
- package/dist-web/assets/eiffel-BEjRio4Q.js +1 -0
- package/dist-web/assets/elm-Cshzl8qu.js +1 -0
- package/dist-web/assets/erDiagram-RLTQ6QDP-BcZ7Ctxy.js +99 -0
- package/dist-web/assets/erlang-BV0c4Hdn.js +1 -0
- package/dist-web/assets/esm-CQW0DO89.js +2 -0
- package/dist-web/assets/eventmodeling-NTZA5JFV-BwLlQZcI.js +1 -0
- package/dist-web/assets/factor-LKH5gN8L.js +1 -0
- package/dist-web/assets/fcl-ClOhbFR7.js +1 -0
- package/dist-web/assets/flowDiagram-HODETNUW-DGqUYaRC.js +1 -0
- package/dist-web/assets/forth-D6RzAl64.js +1 -0
- package/dist-web/assets/fortran-Bt6PBEDR.js +1 -0
- package/dist-web/assets/ganttDiagram-EL5Y4UJY-CcJ72sCU.js +292 -0
- package/dist-web/assets/gas-BHEdbvp9.js +1 -0
- package/dist-web/assets/gherkin-oBAE_ms0.js +1 -0
- package/dist-web/assets/gitGraph-4MIJSDKK-BheSjO6S.js +1 -0
- package/dist-web/assets/gitGraphDiagram-WWUBYQGX-Qv13SyYh.js +106 -0
- package/dist-web/assets/graphlib-DS17s2tU.js +1 -0
- package/dist-web/assets/groovy-CUpZ7dEl.js +1 -0
- package/dist-web/assets/haskell-BRsoo5mP.js +1 -0
- package/dist-web/assets/haxe-DjVOVvNP.js +1 -0
- package/dist-web/assets/http-CLVgA2GD.js +1 -0
- package/dist-web/assets/idl-BUZw3wgd.js +1 -0
- package/dist-web/assets/index-D0npIBvI.css +2 -0
- package/dist-web/assets/index-DsQxKERJ.js +103 -0
- package/dist-web/assets/info-A6RAGUB7-BemnwZ_B.js +1 -0
- package/dist-web/assets/infoDiagram-27XIBGKW-otpjj8PV.js +2 -0
- package/dist-web/assets/init-C-OQMol4.js +1 -0
- package/dist-web/assets/ishikawaDiagram-5VMMS53U-BuZBZkYN.js +70 -0
- package/dist-web/assets/javascript-Bu8mWwtz.js +1 -0
- package/dist-web/assets/journeyDiagram-3NMN7TZE-D-uflaQS.js +139 -0
- package/dist-web/assets/julia-CQfgDRfP.js +1 -0
- package/dist-web/assets/kanban-definition-UXKFOSKX-BI643rxH.js +89 -0
- package/dist-web/assets/katex-ZlcWpGUi.js +257 -0
- package/dist-web/assets/line-fay7lQM4.js +1 -0
- package/dist-web/assets/linear-SzVmGSw4.js +1 -0
- package/dist-web/assets/livescript-BXxG0Yva.js +1 -0
- package/dist-web/assets/lua-DPCEkfD_.js +1 -0
- package/dist-web/assets/mathematica-u8YMmbU0.js +1 -0
- package/dist-web/assets/mbox-BEMVcqjs.js +1 -0
- package/dist-web/assets/mermaid-parser.core-CI9Bt8lf.js +7 -0
- package/dist-web/assets/mermaid.core-CpvTzp9Q.js +44 -0
- package/dist-web/assets/mindmap-definition-YA3MSWOX-Dw-DFKfU.js +96 -0
- package/dist-web/assets/{mirc-CjQqDB4T.js → mirc-C9zpzAZU.js} +1 -1
- package/dist-web/assets/mllike-B45xgp2S.js +1 -0
- package/dist-web/assets/modelica-CqHI_q-D.js +1 -0
- package/dist-web/assets/mscgen-qgSLujhx.js +1 -0
- package/dist-web/assets/mumps-BSzj6Xyz.js +1 -0
- package/dist-web/assets/{nginx-DdIZxoE0.js → nginx-8H7HVH4w.js} +1 -1
- package/dist-web/assets/nsis-CfSuhXs5.js +1 -0
- package/dist-web/assets/ntriples-B9h1VB_g.js +1 -0
- package/dist-web/assets/octave-D2Q8cUp1.js +1 -0
- package/dist-web/assets/ordinal-BDEzSJ7C.js +1 -0
- package/dist-web/assets/oz-BwTct_5T.js +1 -0
- package/dist-web/assets/packet-AYTQ26CC-CsBrScsn.js +1 -0
- package/dist-web/assets/pascal-Dp_KdFgX.js +1 -0
- package/dist-web/assets/path-fybaL0A-.js +1 -0
- package/dist-web/assets/pegDiagram-XKGWAZYB-BVal7Apj.js +1 -0
- package/dist-web/assets/perl-BkSkiI9m.js +1 -0
- package/dist-web/assets/pie-WAS4IAKB-DZFMDceO.js +1 -0
- package/dist-web/assets/pieDiagram-E7YTZNPT-B3QEKixf.js +39 -0
- package/dist-web/assets/pig-AF4Hwhju.js +1 -0
- package/dist-web/assets/powershell-BcIto6Sf.js +1 -0
- package/dist-web/assets/properties-C357ku5U.js +1 -0
- package/dist-web/assets/protobuf-D1ij_kNL.js +1 -0
- package/dist-web/assets/pug-3K-JMW4g.js +1 -0
- package/dist-web/assets/puppet-BZyAS7I4.js +1 -0
- package/dist-web/assets/python-B_1Jd8HM.js +1 -0
- package/dist-web/assets/q-B9NhS7L_.js +1 -0
- package/dist-web/assets/quadrantDiagram-AXDQQJYC-CRgAf_p-.js +7 -0
- package/dist-web/assets/r-CxDmU1I4.js +1 -0
- package/dist-web/assets/radar-RG4KPBEZ-BkOoPAbJ.js +1 -0
- package/dist-web/assets/railroad-74A4TZTK-BgIna4sT.js +1 -0
- package/dist-web/assets/railroad-abnf-HS5TGJTU-CVlFeN1b.js +1 -0
- package/dist-web/assets/railroad-ebnf-LZEXJU2U-DCEa0WVT.js +1 -0
- package/dist-web/assets/railroad-peg-WCYAUIDC-BHX1T-4x.js +1 -0
- package/dist-web/assets/railroadDiagram-O6MQD6OU-BZwRaQM3.js +1 -0
- package/dist-web/assets/requirementDiagram-BXWQKSXE-BN3nmFpY.js +84 -0
- package/dist-web/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/dist-web/assets/rough.esm-Dy-Kn_BL.js +1 -0
- package/dist-web/assets/rpm-gpDK5sbt.js +1 -0
- package/dist-web/assets/ruby-BjXV7-Qa.js +1 -0
- package/dist-web/assets/sankeyDiagram-P5KCCOFB-DBhFOKcq.js +40 -0
- package/dist-web/assets/{sas-B4kiWyti.js → sas-C2OyD2Y6.js} +1 -1
- package/dist-web/assets/scheme-D9qYN0V5.js +1 -0
- package/dist-web/assets/sequenceDiagram-WJ2MYXX4-CBc9y9xq.js +162 -0
- package/dist-web/assets/shell-DwuoZtxw.js +1 -0
- package/dist-web/assets/sieve-tLWDfEkZ.js +1 -0
- package/dist-web/assets/simple-mode-DXiLM1-G.js +1 -0
- package/dist-web/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
- package/dist-web/assets/smalltalk-BLp5-jwC.js +1 -0
- package/dist-web/assets/solr-B78wSQJQ.js +1 -0
- package/dist-web/assets/sparql-Dz-mlCAC.js +1 -0
- package/dist-web/assets/spreadsheet-CTIncYxj.js +1 -0
- package/dist-web/assets/sql-DuQMFDvy.js +1 -0
- package/dist-web/assets/src-B6xuSHsQ.js +1 -0
- package/dist-web/assets/stateDiagram-D77RDMKH-BDdsXTTr.js +1 -0
- package/dist-web/assets/stateDiagram-v2-MP3YSRHH-C04o4SeT.js +1 -0
- package/dist-web/assets/stex-DNzd62Q_.js +1 -0
- package/dist-web/assets/stylus-BOVgKnng.js +1 -0
- package/dist-web/assets/swift-DKB6_1j6.js +1 -0
- package/dist-web/assets/swimlanes-42K2YHIH-1QXV5L5H.js +1 -0
- package/dist-web/assets/swimlanesDiagram-VR7AAH4N-CQ46EU90.js +8 -0
- package/dist-web/assets/tcl-BGfruO1u.js +1 -0
- package/dist-web/assets/textile-C4jVoHG1.js +1 -0
- package/dist-web/assets/tiddlywiki-VlUiK86J.js +1 -0
- package/dist-web/assets/tiki-AK6FwT8q.js +1 -0
- package/dist-web/assets/timeline-definition-24CTP7MA-D9CdAGEV.js +120 -0
- package/dist-web/assets/toml-BPTmHmyx.js +1 -0
- package/dist-web/assets/treeView-Q6P3EWNA-CxKfpZsz.js +1 -0
- package/dist-web/assets/treemap-WGGIJYW6-Bg5-PJ6G.js +1 -0
- package/dist-web/assets/troff-C2dAgh7P.js +1 -0
- package/dist-web/assets/ttcn-PPSTk1ow.js +1 -0
- package/dist-web/assets/ttcn-cfg-2b4Gb5sE.js +1 -0
- package/dist-web/assets/turtle-Cx3rYX2g.js +1 -0
- package/dist-web/assets/vb-BthdM_4N.js +1 -0
- package/dist-web/assets/vbscript-D9f6rSsU.js +1 -0
- package/dist-web/assets/velocity-CqftRsjg.js +1 -0
- package/dist-web/assets/vennDiagram-4TSXK5OY-DIlZEQm_.js +34 -0
- package/dist-web/assets/verilog-CjI9Y6RI.js +1 -0
- package/dist-web/assets/vhdl-kS471soi.js +1 -0
- package/dist-web/assets/wardley-WFR3VGLG-DCKFxH5V.js +1 -0
- package/dist-web/assets/wardleyDiagram-VM6X3IG4-D8O8WtAP.js +78 -0
- package/dist-web/assets/webidl-D5jiJvOU.js +1 -0
- package/dist-web/assets/xquery-BKJx4mf9.js +1 -0
- package/dist-web/assets/xychartDiagram-S5SC5T6Z-Dz9bYgtE.js +7 -0
- package/dist-web/assets/yacas-CXXgtw0p.js +1 -0
- package/dist-web/assets/z80-Co3PbHdE.js +1 -0
- package/dist-web/index.html +6 -18
- package/dist-web/theme-guard.js +21 -0
- package/package.json +34 -26
- package/templates/strikethroo/config/config.yaml +2 -2
- package/templates/strikethroo/config/templates/TASK_TEMPLATE.md +1 -1
- package/dist-web/assets/apl-B4CMkyY2.js +0 -1
- package/dist-web/assets/arc-DA6tr0lU.js +0 -1
- package/dist-web/assets/architectureDiagram-3BPJPVTR-BEH2YihV.js +0 -36
- package/dist-web/assets/asciiarmor-Df11BRmG.js +0 -1
- package/dist-web/assets/asn1-EdZsLKOL.js +0 -1
- package/dist-web/assets/asterisk-B-8jnY81.js +0 -1
- package/dist-web/assets/blockDiagram-GPEHLZMM-jgUyFGxx.js +0 -132
- package/dist-web/assets/brainfuck-C4LP7Hcl.js +0 -1
- package/dist-web/assets/c4Diagram-AAUBKEIU-Do-n7I5O.js +0 -10
- package/dist-web/assets/channel-DJ33z8Wx.js +0 -1
- package/dist-web/assets/chunk-2J33WTMH-CgMvCn22.js +0 -1
- package/dist-web/assets/chunk-4BX2VUAB-FO8RQkkL.js +0 -1
- package/dist-web/assets/chunk-55IACEB6-DL_6pZjw.js +0 -1
- package/dist-web/assets/chunk-727SXJPM-DW7J3hiD.js +0 -206
- package/dist-web/assets/chunk-AQP2D5EJ-TPWnvFSC.js +0 -231
- package/dist-web/assets/chunk-ND2GUHAM-D0Nmkz3P.js +0 -1
- package/dist-web/assets/chunk-QZHKN3VN-BxgxRNWB.js +0 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK--tqQjy0s.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2--tqQjy0s.js +0 -1
- package/dist-web/assets/clike-B9uivgTg.js +0 -1
- package/dist-web/assets/clojure-BMjYHr_A.js +0 -1
- package/dist-web/assets/cmake-BQqOBYOt.js +0 -1
- package/dist-web/assets/cobol-CWcv1MsR.js +0 -1
- package/dist-web/assets/coffeescript-S37ZYGWr.js +0 -1
- package/dist-web/assets/commonlisp-DBKNyK5s.js +0 -1
- package/dist-web/assets/cose-bilkent-S5V4N54A-ysHXC5GT.js +0 -1
- package/dist-web/assets/crystal-SjHAIU92.js +0 -1
- package/dist-web/assets/css-BnMrqG3P.js +0 -1
- package/dist-web/assets/cypher-C_CwsFkJ.js +0 -1
- package/dist-web/assets/cytoscape.esm-BHYC38rz.js +0 -331
- package/dist-web/assets/d-pRatUO7H.js +0 -1
- package/dist-web/assets/dagre-BM42HDAG-G_XIk8Dj.js +0 -4
- package/dist-web/assets/defaultLocale-CrowFXzY.js +0 -1
- package/dist-web/assets/diagram-2AECGRRQ-7HG2PLhr.js +0 -43
- package/dist-web/assets/diagram-5GNKFQAL-BdS1bF_R.js +0 -10
- package/dist-web/assets/diagram-KO2AKTUF-AFaiXGZQ.js +0 -3
- package/dist-web/assets/diagram-LMA3HP47-CTWrauj7.js +0 -24
- package/dist-web/assets/diagram-OG6HWLK6-BmBckGLa.js +0 -24
- package/dist-web/assets/diff-DbItnlRl.js +0 -1
- package/dist-web/assets/dockerfile-BKs6k2Af.js +0 -1
- package/dist-web/assets/dtd-DF_7sFjM.js +0 -1
- package/dist-web/assets/dylan-DwRh75JA.js +0 -1
- package/dist-web/assets/ebnf-CDyGwa7X.js +0 -1
- package/dist-web/assets/ecl-Cabwm37j.js +0 -1
- package/dist-web/assets/eiffel-CnydiIhH.js +0 -1
- package/dist-web/assets/elm-vLlmbW-K.js +0 -1
- package/dist-web/assets/erDiagram-TEJ5UH35-C0B2cXE-.js +0 -85
- package/dist-web/assets/erlang-BNw1qcRV.js +0 -1
- package/dist-web/assets/factor-kuTfRLto.js +0 -1
- package/dist-web/assets/fcl-Kvtd6kyn.js +0 -1
- package/dist-web/assets/flowDiagram-I6XJVG4X-CZ70tn_Q.js +0 -162
- package/dist-web/assets/forth-Ffai-XNe.js +0 -1
- package/dist-web/assets/fortran-DYz_wnZ1.js +0 -1
- package/dist-web/assets/ganttDiagram-6RSMTGT7-h7O-Xh-D.js +0 -292
- package/dist-web/assets/gas-Bneqetm1.js +0 -1
- package/dist-web/assets/gherkin-heZmZLOM.js +0 -1
- package/dist-web/assets/gitGraphDiagram-PVQCEYII-BDZixURw.js +0 -106
- package/dist-web/assets/graph-Dqkl27Ch.js +0 -1
- package/dist-web/assets/groovy-D9Dt4D0W.js +0 -1
- package/dist-web/assets/haskell-BWDZoCOh.js +0 -1
- package/dist-web/assets/haxe-H-WmDvRZ.js +0 -1
- package/dist-web/assets/http-DBlCnlav.js +0 -1
- package/dist-web/assets/idl-BEugSyMb.js +0 -1
- package/dist-web/assets/index-B-KlYMEI.js +0 -1
- package/dist-web/assets/index-B0a4C4Lb.js +0 -1
- package/dist-web/assets/index-B90tvIxG.js +0 -3
- package/dist-web/assets/index-BLXIwDvb.js +0 -1
- package/dist-web/assets/index-BjZYUODU.js +0 -1
- package/dist-web/assets/index-BmsczLPZ.js +0 -1
- package/dist-web/assets/index-BpU7RpGz.js +0 -1
- package/dist-web/assets/index-BwFIiA6J.js +0 -2
- package/dist-web/assets/index-C53NKwQ5.js +0 -1
- package/dist-web/assets/index-C73riuQN.js +0 -1
- package/dist-web/assets/index-C9RcHSPW.js +0 -1
- package/dist-web/assets/index-CEBV-m_B.js +0 -1
- package/dist-web/assets/index-CG1O2Vjg.js +0 -1
- package/dist-web/assets/index-CRL66wiY.js +0 -169
- package/dist-web/assets/index-CddJufqj.js +0 -1
- package/dist-web/assets/index-CrzBaw1K.css +0 -1
- package/dist-web/assets/index-CuBsNWzH.js +0 -13
- package/dist-web/assets/index-CuCAyRTw.js +0 -7
- package/dist-web/assets/index-CuUh3dvS.js +0 -1
- package/dist-web/assets/index-CwPWc9jQ.js +0 -1
- package/dist-web/assets/index-DHBbud_j.js +0 -1
- package/dist-web/assets/index-LLaxWDbg.js +0 -1
- package/dist-web/assets/index-XOpAvr0E.js +0 -13
- package/dist-web/assets/index-aX67gnlS.js +0 -2
- package/dist-web/assets/index-lkaAPBmM.js +0 -6
- package/dist-web/assets/index-pUkuW0EP.js +0 -1
- package/dist-web/assets/index-sbfqG9cy.js +0 -1
- package/dist-web/assets/index-udFbjSlZ.js +0 -2
- package/dist-web/assets/index-yjEPVwyN.js +0 -1
- package/dist-web/assets/infoDiagram-5YYISTIA-CKXHxMh_.js +0 -2
- package/dist-web/assets/init-Gi6I4Gst.js +0 -1
- package/dist-web/assets/ishikawaDiagram-YF4QCWOH-DGancylI.js +0 -70
- package/dist-web/assets/javascript-qCveANmP.js +0 -1
- package/dist-web/assets/journeyDiagram-JHISSGLW-DifvKy-w.js +0 -139
- package/dist-web/assets/julia-DuME0IfC.js +0 -1
- package/dist-web/assets/kanban-definition-UN3LZRKU-ByC-4YyY.js +0 -89
- package/dist-web/assets/katex-C5jXJg4s.js +0 -257
- package/dist-web/assets/layout-DO9UvE1P.js +0 -1
- package/dist-web/assets/linear-Cm0Y2OWD.js +0 -1
- package/dist-web/assets/livescript-BwQOo05w.js +0 -1
- package/dist-web/assets/lua-VAEuO923.js +0 -1
- package/dist-web/assets/mathematica-DTrFuWx2.js +0 -1
- package/dist-web/assets/mbox-CNhZ1qSd.js +0 -1
- package/dist-web/assets/mermaid.core-DBlLt9sa.js +0 -307
- package/dist-web/assets/mindmap-definition-RKZ34NQL-tkThiQWd.js +0 -96
- package/dist-web/assets/mllike-CXdrOF99.js +0 -1
- package/dist-web/assets/modelica-Dc1JOy9r.js +0 -1
- package/dist-web/assets/mscgen-BA5vi2Kp.js +0 -1
- package/dist-web/assets/mumps-BT43cFF4.js +0 -1
- package/dist-web/assets/nsis-LdVXkNf5.js +0 -1
- package/dist-web/assets/ntriples-BfvgReVJ.js +0 -1
- package/dist-web/assets/octave-Ck1zUtKM.js +0 -1
- package/dist-web/assets/ordinal-Cboi1Yqb.js +0 -1
- package/dist-web/assets/oz-BzwKVEFT.js +0 -1
- package/dist-web/assets/pascal--L3eBynH.js +0 -1
- package/dist-web/assets/perl-CdXCOZ3F.js +0 -1
- package/dist-web/assets/pieDiagram-4H26LBE5-BXGBVjcj.js +0 -30
- package/dist-web/assets/pig-CevX1Tat.js +0 -1
- package/dist-web/assets/powershell-CFHJl5sT.js +0 -1
- package/dist-web/assets/properties-C78fOPTZ.js +0 -1
- package/dist-web/assets/protobuf-ChK-085T.js +0 -1
- package/dist-web/assets/pug-DukmZTjD.js +0 -1
- package/dist-web/assets/puppet-DMA9R1ak.js +0 -1
- package/dist-web/assets/python-BuPzkPfP.js +0 -1
- package/dist-web/assets/q-pXgVlZs6.js +0 -1
- package/dist-web/assets/quadrantDiagram-W4KKPZXB-DnF0iEBo.js +0 -7
- package/dist-web/assets/r-DUYO_cvP.js +0 -1
- package/dist-web/assets/requirementDiagram-4Y6WPE33-BooGjmPb.js +0 -84
- package/dist-web/assets/rpm-CTu-6PCP.js +0 -1
- package/dist-web/assets/ruby-B2Rjki9n.js +0 -1
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-7le5uaC7.js +0 -40
- package/dist-web/assets/scheme-C41bIUwD.js +0 -1
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-B9GCKMDd.js +0 -162
- package/dist-web/assets/shell-CjFT_Tl9.js +0 -1
- package/dist-web/assets/sieve-C3Gn_uJK.js +0 -1
- package/dist-web/assets/simple-mode-GW_nhZxv.js +0 -1
- package/dist-web/assets/smalltalk-CnHTOXQT.js +0 -1
- package/dist-web/assets/solr-DehyRSwq.js +0 -1
- package/dist-web/assets/sparql-DkYu6x3z.js +0 -1
- package/dist-web/assets/spreadsheet-BCZA_wO0.js +0 -1
- package/dist-web/assets/sql-D0XecflT.js +0 -1
- package/dist-web/assets/stateDiagram-AJRCARHV-CO2qL8R6.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-DUkgqBTd.js +0 -1
- package/dist-web/assets/stex-C3f8Ysf7.js +0 -1
- package/dist-web/assets/stylus-B533Al4x.js +0 -1
- package/dist-web/assets/swift-BzpIVaGY.js +0 -1
- package/dist-web/assets/tcl-DVfN8rqt.js +0 -1
- package/dist-web/assets/textile-CnDTJFAw.js +0 -1
- package/dist-web/assets/tiddlywiki-DO-Gjzrf.js +0 -1
- package/dist-web/assets/tiki-DGYXhP31.js +0 -1
- package/dist-web/assets/timeline-definition-PNZ67QCA-FLzWM85F.js +0 -120
- package/dist-web/assets/toml-Bm5Em-hy.js +0 -1
- package/dist-web/assets/troff-wAsdV37c.js +0 -1
- package/dist-web/assets/ttcn-CfJYG6tj.js +0 -1
- package/dist-web/assets/ttcn-cfg-B9xdYoR4.js +0 -1
- package/dist-web/assets/turtle-B1tBg_DP.js +0 -1
- package/dist-web/assets/vb-CmGdzxic.js +0 -1
- package/dist-web/assets/vbscript-BuJXcnF6.js +0 -1
- package/dist-web/assets/velocity-D8B20fx6.js +0 -1
- package/dist-web/assets/vennDiagram-CIIHVFJN-Dt6p6Ib1.js +0 -34
- package/dist-web/assets/verilog-C6RDOZhf.js +0 -1
- package/dist-web/assets/vhdl-lSbBsy5d.js +0 -1
- package/dist-web/assets/wardley-L42UT6IY-D6k_B5It.js +0 -173
- package/dist-web/assets/wardleyDiagram-YWT4CUSO-jT3ItNLi.js +0 -78
- package/dist-web/assets/webidl-ZXfAyPTL.js +0 -1
- package/dist-web/assets/xquery-CQfU5ijd.js +0 -1
- package/dist-web/assets/xychartDiagram-2RQKCTM6-CpM6UhUO.js +0 -7
- package/dist-web/assets/yacas-BJ4BC0dw.js +0 -1
- package/dist-web/assets/z80-Hz9HOZM7.js +0 -1
package/dist/serve/events.d.ts
CHANGED
|
@@ -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
|
|
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.
|
|
12
|
-
*
|
|
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
|
-
|
|
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
|
-
/**
|
|
33
|
-
|
|
34
|
-
/**
|
|
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
|
|
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"}
|
package/dist/serve/events.js
CHANGED
|
@@ -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
|
|
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.
|
|
13
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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;
|
package/dist/serve/events.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/serve/events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAGH,uCAAqE;AAErE,0EAA0E;AAC7D,QAAA,aAAa,GAAG,KAAK,CAAC;AAEnC,iEAAiE;AACpD,QAAA,eAAe,GAAG,EAAE,CAAC;AAElC,oFAAoF;AACvE,QAAA,kBAAkB,GAAG,KAAK,CAAC;AAExC,4EAA4E;AAC5E,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,MAAM,aAAa,GAAG,8BAA8B,CAAC;AACrD,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAsB9C;;;;GAIG;AACH,MAAa,SAAS;IAKpB,YACmB,YAAoB,EACpB,UAAmB,EACpC,SAAmC,EAAE;QAFpB,iBAAY,GAAZ,YAAY,CAAQ;QACpB,eAAU,GAAV,UAAU,CAAS;QANrB,YAAO,GAAG,IAAI,GAAG,EAAoC,CAAC;QAC/D,YAAO,GAA4B,IAAI,CAAC;QA2IhD,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;QA9IA,IAAI,CAAC,MAAM,GAAG;YACZ,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,uBAAe;YAChD,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,0BAAkB;YAC/D,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,qBAAa;SACjD,CAAC;IACJ,CAAC;IAED,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,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7C,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,6DAA6D;YAC7D,IAAI,KAAK,CAAC,OAAO;gBAAE,GAAG,CAAC,OAAO,EAAE,CAAC;;gBAC5B,GAAG,CAAC,GAAG,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,uEAAuE;IACvE,IAAI,kBAAkB;QACpB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE;YAAE,IAAI,KAAK,CAAC,OAAO;gBAAE,KAAK,IAAI,CAAC,CAAC;QACzE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,SAAS;QACP,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,OAAO;gBAAE,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;;gBACnC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAED;;;;OAIG;IACK,IAAI,CAAC,GAAwB,EAAE,KAAkB,EAAE,KAAa;QACtE,IAAI,KAAK,CAAC,OAAO;YAAE,OAAO;QAC1B,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO;QAC7B,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;QACrB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAChC,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,GAAG,CAAC,OAAO,EAAE,CAAC;QAChB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;QACjC,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;IAC5B,CAAC;IAED,2EAA2E;IAC3E,gBAAgB,CAAC,GAAyB,EAAE,GAAwB;QAClE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YAChD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;YACzE,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;gBACjB,cAAc,EAAE,iCAAiC;gBACjD,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;gBACzC,aAAa,EAAE,MAAM,CAAC,mBAAmB,CAAC;aAC3C,CAAC,CAAC;YACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;QACT,CAAC;QAED,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QAEH,MAAM,KAAK,GAAgB;YACzB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,WAAW,CACpB,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,kBAAkB,CAAC,EAC/C,IAAI,CAAC,MAAM,CAAC,WAAW,CACxB;YACD,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;oBAAE,OAAO;gBACnC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;gBACtB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;oBACpB,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;oBAC9B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;gBACzB,CAAC;gBACD,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;oBAClB,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;oBACtB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;gBACvC,CAAC;YACH,CAAC;YACD,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC;oBAAE,OAAO;gBACtC,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,SAAS;oBAAE,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACnD,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC3C,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;gBAC3C,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7C,CAAC;SACF,CAAC;QACF,qEAAqE;QACrE,KAAK,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAE/B,sEAAsE;QACtE,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAC3C,CAAC;CAcF;AAzJD,8BAyJC"}
|
|
@@ -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
|
|
66
|
+
/** Seams for testing: availability probe, the spawn, and the registry. */
|
|
45
67
|
export interface LaunchDeps {
|
|
46
68
|
available?: () => boolean;
|
|
47
|
-
|
|
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,
|
|
67
|
-
* `self-review <absolutePath>` detached.
|
|
68
|
-
*
|
|
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
|
|
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"}
|
|
@@ -15,6 +15,12 @@
|
|
|
15
15
|
* Untrusted input (the path string) is never passed to the shell: `spawn` is
|
|
16
16
|
* invoked with an argv array, and the path is rejected before spawning unless it
|
|
17
17
|
* resolves to an existing file under `plans/` or `archive/`. Node built-ins only.
|
|
18
|
+
*
|
|
19
|
+
* Launches are bounded: a {@link LaunchRegistry} tracks the plans whose child is
|
|
20
|
+
* still running, refusing a duplicate for the same plan and anything past
|
|
21
|
+
* {@link MAX_CONCURRENT_SELF_REVIEWS}. The registry is in-memory and per server
|
|
22
|
+
* instance: a restart resets the accounting, and the detached children — which
|
|
23
|
+
* the viewer never waits on — can outlive it. It is not a job manager.
|
|
18
24
|
*/
|
|
19
25
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
26
|
if (k2 === undefined) k2 = k;
|
|
@@ -50,12 +56,17 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
50
56
|
};
|
|
51
57
|
})();
|
|
52
58
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
-
exports.launchSelfReview = exports.resolveReviewPath = exports.isSelfReviewAvailable = exports.SELF_REVIEW_URL = exports.SELF_REVIEW_BINARY = void 0;
|
|
59
|
+
exports.launchSelfReview = exports.resolveReviewPath = exports.createLaunchRegistry = exports.isSelfReviewAvailable = exports.SELF_REVIEW_URL = exports.MAX_CONCURRENT_SELF_REVIEWS = exports.SELF_REVIEW_BINARY = void 0;
|
|
54
60
|
const fs = __importStar(require("fs"));
|
|
55
61
|
const path = __importStar(require("path"));
|
|
56
62
|
const child_process_1 = require("child_process");
|
|
63
|
+
const safe_fs_1 = require("../skill-scripts/shared/safe-fs");
|
|
57
64
|
/** The binary name looked up on PATH and spawned. */
|
|
58
65
|
exports.SELF_REVIEW_BINARY = 'self-review';
|
|
66
|
+
/** Upper bound on self-review children running at once per server instance. */
|
|
67
|
+
exports.MAX_CONCURRENT_SELF_REVIEWS = 2;
|
|
68
|
+
/** Seconds a client should wait before retrying a `429` launch. */
|
|
69
|
+
const BUSY_RETRY_AFTER_SECONDS = 30;
|
|
59
70
|
/** Where to obtain self-review; surfaced by the SPA when it is not installed. */
|
|
60
71
|
exports.SELF_REVIEW_URL = 'https://github.com/e0ipso/self-review';
|
|
61
72
|
/** Cache key derived from the environment inputs that affect the PATH scan. */
|
|
@@ -104,13 +115,21 @@ const isSelfReviewAvailable = (env = process.env) => {
|
|
|
104
115
|
return result;
|
|
105
116
|
};
|
|
106
117
|
exports.isSelfReviewAvailable = isSelfReviewAvailable;
|
|
107
|
-
/**
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
118
|
+
/** Creates an empty {@link LaunchRegistry}. */
|
|
119
|
+
const createLaunchRegistry = () => new Set();
|
|
120
|
+
exports.createLaunchRegistry = createLaunchRegistry;
|
|
121
|
+
/** Fallback registry for callers that do not own one (tests pass their own). */
|
|
122
|
+
const defaultRegistry = (0, exports.createLaunchRegistry)();
|
|
123
|
+
/** Spawns the binary detached with no stdio so it can outlive the request. */
|
|
124
|
+
const spawnDetached = (command, args) => (0, child_process_1.spawn)(command, args, { stdio: 'ignore', detached: true });
|
|
125
|
+
/** Resolves once the child reports `spawn`; rejects on a launch `error`. */
|
|
126
|
+
const awaitSpawn = (child) => new Promise((resolve, reject) => {
|
|
127
|
+
child.once('spawn', () => resolve());
|
|
128
|
+
child.once('error', (err) => reject(err));
|
|
129
|
+
});
|
|
130
|
+
const LAUNCH_FAILED = {
|
|
131
|
+
status: 500,
|
|
132
|
+
body: { ok: false, error: 'Failed to launch self-review.' },
|
|
114
133
|
};
|
|
115
134
|
/**
|
|
116
135
|
* Resolves a client-supplied plan path to an absolute path, requiring it to be
|
|
@@ -120,40 +139,56 @@ const spawnDetached = (command, args) => {
|
|
|
120
139
|
* `root` is the absolute `.ai/strikethroo` directory; client paths are the
|
|
121
140
|
* workspace-relative form the SPA shows (e.g. `.ai/strikethroo/plans/NN--s/…`),
|
|
122
141
|
* so they are resolved against the project root (`root/../..`). Absolute client
|
|
123
|
-
* paths are accepted too — the containment check is what enforces safety
|
|
142
|
+
* paths are accepted too — the containment check is what enforces safety: the
|
|
143
|
+
* lexical check below picks the subtree, and the shared helper walks the real
|
|
144
|
+
* components so a symlinked plan file or directory is refused rather than
|
|
145
|
+
* followed out of the workspace.
|
|
124
146
|
*/
|
|
125
147
|
const resolveReviewPath = (root, clientPath) => {
|
|
126
148
|
if (typeof clientPath !== 'string' || clientPath.trim() === '') {
|
|
127
149
|
return { error: 'A plan path is required.', status: 400 };
|
|
128
150
|
}
|
|
129
|
-
const
|
|
151
|
+
const absRoot = path.resolve(root);
|
|
152
|
+
const projectRoot = path.resolve(absRoot, '..', '..');
|
|
130
153
|
const resolved = path.resolve(projectRoot, clientPath);
|
|
131
|
-
const
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
154
|
+
const rel = path.relative(absRoot, resolved);
|
|
155
|
+
const first = rel.split(path.sep)[0];
|
|
156
|
+
const outside = {
|
|
157
|
+
error: 'Plan path must be inside the workspace plans/ or archive/ directory.',
|
|
158
|
+
status: 400,
|
|
159
|
+
};
|
|
160
|
+
if (path.isAbsolute(rel) || first === '..' || (first !== 'plans' && first !== 'archive')) {
|
|
161
|
+
return outside;
|
|
139
162
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
163
|
+
const contained = (0, safe_fs_1.resolveContained)(absRoot, rel);
|
|
164
|
+
if ('error' in contained) {
|
|
165
|
+
switch (contained.error) {
|
|
166
|
+
case 'not-found':
|
|
167
|
+
return { error: 'Plan file not found.', status: 404 };
|
|
168
|
+
case 'not-a-file':
|
|
169
|
+
case 'not-a-directory':
|
|
170
|
+
return { error: 'Plan path does not point to a file.', status: 404 };
|
|
171
|
+
case 'fs-error':
|
|
172
|
+
return { error: 'Plan path could not be inspected.', status: 500 };
|
|
173
|
+
default:
|
|
174
|
+
// invalid-path, outside-root, symlink: the path does not denote a plain
|
|
175
|
+
// file inside the workspace.
|
|
176
|
+
return outside;
|
|
143
177
|
}
|
|
144
178
|
}
|
|
145
|
-
catch {
|
|
146
|
-
return { error: 'Plan file not found.', status: 404 };
|
|
147
|
-
}
|
|
148
179
|
return { absPath: resolved };
|
|
149
180
|
};
|
|
150
181
|
exports.resolveReviewPath = resolveReviewPath;
|
|
151
182
|
/**
|
|
152
|
-
* Validates `clientPath` and, if the binary is available,
|
|
153
|
-
* `self-review <absolutePath>` detached.
|
|
154
|
-
*
|
|
183
|
+
* Validates `clientPath` and, if the binary is available and a slot is free,
|
|
184
|
+
* launches `self-review <absolutePath>` detached. Resolves `200` only after the
|
|
185
|
+
* child's `spawn` event; a launch `error` (e.g. `ENOENT`) is a fixed `500`. The
|
|
186
|
+
* plan's slot is taken synchronously before the spawn, so two simultaneous
|
|
187
|
+
* requests for one plan cannot both launch, and is released — idempotently —
|
|
188
|
+
* when the child exits, errors, or fails to launch. Pure of HTTP concerns:
|
|
189
|
+
* returns the status/body the endpoint should send so it stays unit-testable.
|
|
155
190
|
*/
|
|
156
|
-
const launchSelfReview = (root, clientPath, deps = {}) => {
|
|
191
|
+
const launchSelfReview = async (root, clientPath, deps = {}) => {
|
|
157
192
|
const available = deps.available ?? exports.isSelfReviewAvailable;
|
|
158
193
|
if (!available()) {
|
|
159
194
|
return {
|
|
@@ -165,15 +200,40 @@ const launchSelfReview = (root, clientPath, deps = {}) => {
|
|
|
165
200
|
if ('error' in resolved) {
|
|
166
201
|
return { status: resolved.status, body: { ok: false, error: resolved.error } };
|
|
167
202
|
}
|
|
168
|
-
|
|
169
|
-
|
|
203
|
+
const registry = deps.registry ?? defaultRegistry;
|
|
204
|
+
const key = resolved.absPath;
|
|
205
|
+
if (registry.has(key)) {
|
|
206
|
+
return {
|
|
207
|
+
status: 409,
|
|
208
|
+
body: { ok: false, error: 'A self-review is already running for this plan.' },
|
|
209
|
+
};
|
|
170
210
|
}
|
|
171
|
-
|
|
211
|
+
if (registry.size >= exports.MAX_CONCURRENT_SELF_REVIEWS) {
|
|
172
212
|
return {
|
|
173
|
-
status:
|
|
174
|
-
body: {
|
|
213
|
+
status: 429,
|
|
214
|
+
body: {
|
|
215
|
+
ok: false,
|
|
216
|
+
error: `Too many self-reviews are running (limit ${exports.MAX_CONCURRENT_SELF_REVIEWS}). Try again when one finishes.`,
|
|
217
|
+
},
|
|
218
|
+
headers: { 'Retry-After': String(BUSY_RETRY_AFTER_SECONDS) },
|
|
175
219
|
};
|
|
176
220
|
}
|
|
221
|
+
registry.add(key);
|
|
222
|
+
const release = () => {
|
|
223
|
+
registry.delete(key);
|
|
224
|
+
};
|
|
225
|
+
let child;
|
|
226
|
+
try {
|
|
227
|
+
child = (deps.spawn ?? spawnDetached)(exports.SELF_REVIEW_BINARY, [key]);
|
|
228
|
+
await awaitSpawn(child);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
release();
|
|
232
|
+
return LAUNCH_FAILED;
|
|
233
|
+
}
|
|
234
|
+
child.once('exit', release);
|
|
235
|
+
child.once('error', release);
|
|
236
|
+
child.unref();
|
|
177
237
|
return { status: 200, body: { ok: true } };
|
|
178
238
|
};
|
|
179
239
|
exports.launchSelfReview = launchSelfReview;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-review.js","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"self-review.js","sourceRoot":"","sources":["../../src/serve/self-review.ts"],"names":[],"mappings":"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"}
|