hitloop 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -2
- package/dist/agent.js +318 -0
- package/dist/cli.js +897 -0
- package/dist/client/assets/app.css +1 -0
- package/dist/client/assets/chunks/abap-EINPUMCJ.js +1 -0
- package/dist/client/assets/chunks/abnfDiagram-S7VZAUFO-W2CM2W6D.js +1 -0
- package/dist/client/assets/chunks/actionscript-3-O776AQUO.js +1 -0
- package/dist/client/assets/chunks/ada-WLOTXRTV.js +1 -0
- package/dist/client/assets/chunks/ahk-EF37A2DY.js +1 -0
- package/dist/client/assets/chunks/ahk2-FH4K3CKT.js +1 -0
- package/dist/client/assets/chunks/angular-html-ZALQFV2H.js +1 -0
- package/dist/client/assets/chunks/angular-ts-4IWMF7QO.js +1 -0
- package/dist/client/assets/chunks/apache-44AYOEWM.js +1 -0
- package/dist/client/assets/chunks/apex-XRYPID42.js +1 -0
- package/dist/client/assets/chunks/apl-5HBALFOI.js +1 -0
- package/dist/client/assets/chunks/applescript-2DZEHZEC.js +1 -0
- package/dist/client/assets/chunks/ara-ZGZQBLXL.js +1 -0
- package/dist/client/assets/chunks/architecture-WOLXFQ4H-EJGENNRL.js +1 -0
- package/dist/client/assets/chunks/architectureDiagram-YGSQEFNW-2VHWSKO6.js +36 -0
- package/dist/client/assets/chunks/asciidoc-GSQAKCPO.js +1 -0
- package/dist/client/assets/chunks/asm-BFURM5BK.js +1 -0
- package/dist/client/assets/chunks/astro-VJORWDZJ.js +1 -0
- package/dist/client/assets/chunks/awk-BSHTWXXX.js +1 -0
- package/dist/client/assets/chunks/ballerina-HAOQJ4B2.js +1 -0
- package/dist/client/assets/chunks/bat-OSH45EOF.js +1 -0
- package/dist/client/assets/chunks/beancount-RBATIHOV.js +1 -0
- package/dist/client/assets/chunks/berry-CZUIOUM4.js +1 -0
- package/dist/client/assets/chunks/bibtex-KCL2UWHE.js +1 -0
- package/dist/client/assets/chunks/bicep-SZJZB3SG.js +1 -0
- package/dist/client/assets/chunks/bird2-XBF5YQQV.js +1 -0
- package/dist/client/assets/chunks/blade-Q24LEVFC.js +1 -0
- package/dist/client/assets/chunks/blockDiagram-APKKGZFW-53LXSOOT.js +140 -0
- package/dist/client/assets/chunks/bpmnIcons-APHXDYXF-FMBRQNTY.js +1 -0
- package/dist/client/assets/chunks/bsl-TI44NWFB.js +1 -0
- package/dist/client/assets/chunks/c-NLHY4Y4N.js +1 -0
- package/dist/client/assets/chunks/c3-BUTEM6PO.js +1 -0
- package/dist/client/assets/chunks/c4Diagram-KJ2TOQU5-O53G4GQH.js +38 -0
- package/dist/client/assets/chunks/cadence-JIRTEU64.js +1 -0
- package/dist/client/assets/chunks/cairo-3W6NVDNW.js +1 -0
- package/dist/client/assets/chunks/chapel-BPBJ2E7K.js +1 -0
- package/dist/client/assets/chunks/chunk-25KVF5ZE.js +1 -0
- package/dist/client/assets/chunks/chunk-2CJKSQOI.js +1 -0
- package/dist/client/assets/chunks/chunk-2QIJRTWR.js +1 -0
- package/dist/client/assets/chunks/chunk-2ZCRJZGF.js +2 -0
- package/dist/client/assets/chunks/chunk-3ILNDZNY.js +213 -0
- package/dist/client/assets/chunks/chunk-3M2OOQ7S.js +1 -0
- package/dist/client/assets/chunks/chunk-3M57NTNK.js +1 -0
- package/dist/client/assets/chunks/chunk-3MR6DCZJ.js +1 -0
- package/dist/client/assets/chunks/chunk-3WGHS7F7.js +1 -0
- package/dist/client/assets/chunks/chunk-4JK75V33.js +1 -0
- package/dist/client/assets/chunks/chunk-4NXNVEWK.js +1 -0
- package/dist/client/assets/chunks/chunk-4RNNBDFQ.js +1 -0
- package/dist/client/assets/chunks/chunk-4T4NVH7V.js +1 -0
- package/dist/client/assets/chunks/chunk-4TFFBC35.js +1 -0
- package/dist/client/assets/chunks/chunk-4WYBE67P.js +1 -0
- package/dist/client/assets/chunks/chunk-56ITEUFA.js +1 -0
- package/dist/client/assets/chunks/chunk-5DXRE7IH.js +1 -0
- package/dist/client/assets/chunks/chunk-5IMADCNU.js +1 -0
- package/dist/client/assets/chunks/chunk-5XZPGKN4.js +1 -0
- package/dist/client/assets/chunks/chunk-6O32UKSP.js +1 -0
- package/dist/client/assets/chunks/chunk-7BAEB64Q.js +1 -0
- package/dist/client/assets/chunks/chunk-7FMWBHZO.js +1 -0
- package/dist/client/assets/chunks/chunk-7GFDITUT.js +1 -0
- package/dist/client/assets/chunks/chunk-7H4MLBHI.js +1 -0
- package/dist/client/assets/chunks/chunk-7OJ4MEEB.js +1 -0
- package/dist/client/assets/chunks/chunk-7RSEISFE.js +1 -0
- package/dist/client/assets/chunks/chunk-7YNZZQVT.js +1 -0
- package/dist/client/assets/chunks/chunk-AB7TIL2G.js +1 -0
- package/dist/client/assets/chunks/chunk-ADDF76FL.js +1 -0
- package/dist/client/assets/chunks/chunk-AF6UTCD4.js +321 -0
- package/dist/client/assets/chunks/chunk-AJ2K6ASU.js +1 -0
- package/dist/client/assets/chunks/chunk-AUBAENQZ.js +1 -0
- package/dist/client/assets/chunks/chunk-BJEYVZ65.js +1 -0
- package/dist/client/assets/chunks/chunk-BLRM6LXA.js +1 -0
- package/dist/client/assets/chunks/chunk-BOCTYCDZ.js +1 -0
- package/dist/client/assets/chunks/chunk-BU4VRYN7.js +1 -0
- package/dist/client/assets/chunks/chunk-CALYHV7D.js +1 -0
- package/dist/client/assets/chunks/chunk-CF4W3RZ4.js +1 -0
- package/dist/client/assets/chunks/chunk-DCZ2OBSL.js +1 -0
- package/dist/client/assets/chunks/chunk-DUFPBTHD.js +1 -0
- package/dist/client/assets/chunks/chunk-DUICIQBC.js +88 -0
- package/dist/client/assets/chunks/chunk-EH2N475V.js +1 -0
- package/dist/client/assets/chunks/chunk-EHLLNPZT.js +1 -0
- package/dist/client/assets/chunks/chunk-EIBFAW37.js +1 -0
- package/dist/client/assets/chunks/chunk-EO3ER3GN.js +1 -0
- package/dist/client/assets/chunks/chunk-FH24BIIA.js +1 -0
- package/dist/client/assets/chunks/chunk-FNOXGAL5.js +2 -0
- package/dist/client/assets/chunks/chunk-FTY6WLQF.js +3 -0
- package/dist/client/assets/chunks/chunk-FZFME6UK.js +1 -0
- package/dist/client/assets/chunks/chunk-FZJZZYYO.js +1 -0
- package/dist/client/assets/chunks/chunk-G4Z6L7OO.js +1 -0
- package/dist/client/assets/chunks/chunk-GNCEAN2B.js +1 -0
- package/dist/client/assets/chunks/chunk-GQJIKV3T.js +1 -0
- package/dist/client/assets/chunks/chunk-GUMNOKT2.js +1 -0
- package/dist/client/assets/chunks/chunk-GXRORAF3.js +1 -0
- package/dist/client/assets/chunks/chunk-H36ABDKY.js +1 -0
- package/dist/client/assets/chunks/chunk-HAR5NYVW.js +1 -0
- package/dist/client/assets/chunks/chunk-HIGPS4L2.js +1 -0
- package/dist/client/assets/chunks/chunk-HMOBGTME.js +1 -0
- package/dist/client/assets/chunks/chunk-HNO6SQ7M.js +1 -0
- package/dist/client/assets/chunks/chunk-HYVZ3GYN.js +1 -0
- package/dist/client/assets/chunks/chunk-I6TGFOQS.js +1 -0
- package/dist/client/assets/chunks/chunk-IHIOJK7I.js +1 -0
- package/dist/client/assets/chunks/chunk-IHJNUMSC.js +1 -0
- package/dist/client/assets/chunks/chunk-IP7PB2OC.js +1 -0
- package/dist/client/assets/chunks/chunk-ISDTMH2Y.js +1 -0
- package/dist/client/assets/chunks/chunk-J65M2LNT.js +1 -0
- package/dist/client/assets/chunks/chunk-JCWYZ7X2.js +62 -0
- package/dist/client/assets/chunks/chunk-JENWYTLI.js +1 -0
- package/dist/client/assets/chunks/chunk-JJ6YWJQS.js +1 -0
- package/dist/client/assets/chunks/chunk-JMUVGGX7.js +32 -0
- package/dist/client/assets/chunks/chunk-JNQUFMM4.js +1 -0
- package/dist/client/assets/chunks/chunk-JPTECOAL.js +1 -0
- package/dist/client/assets/chunks/chunk-JZNK4LKS.js +1 -0
- package/dist/client/assets/chunks/chunk-KPNXJBIW.js +1 -0
- package/dist/client/assets/chunks/chunk-KZO2GZL7.js +1 -0
- package/dist/client/assets/chunks/chunk-L2REESOQ.js +1 -0
- package/dist/client/assets/chunks/chunk-LJPJXR7R.js +1 -0
- package/dist/client/assets/chunks/chunk-LOEZMLCI.js +1 -0
- package/dist/client/assets/chunks/chunk-MLYC6FSE.js +1 -0
- package/dist/client/assets/chunks/chunk-MMDGEZYU.js +1 -0
- package/dist/client/assets/chunks/chunk-MYXE7CGE.js +1 -0
- package/dist/client/assets/chunks/chunk-NBH7YOBD.js +15 -0
- package/dist/client/assets/chunks/chunk-NCOVM3YF.js +1 -0
- package/dist/client/assets/chunks/chunk-NCWOBVU7.js +1 -0
- package/dist/client/assets/chunks/chunk-NLRIHHEH.js +1 -0
- package/dist/client/assets/chunks/chunk-NUPEOYK6.js +1 -0
- package/dist/client/assets/chunks/chunk-O4MVOA7X.js +1 -0
- package/dist/client/assets/chunks/chunk-OBHQQZ4H.js +1 -0
- package/dist/client/assets/chunks/chunk-OKPNJIIR.js +1 -0
- package/dist/client/assets/chunks/chunk-OLMPB57R.js +1 -0
- package/dist/client/assets/chunks/chunk-P2FYOAEV.js +1 -0
- package/dist/client/assets/chunks/chunk-PI3SNP4C.js +1 -0
- package/dist/client/assets/chunks/chunk-PRDTEROB.js +1 -0
- package/dist/client/assets/chunks/chunk-PZELHD2H.js +136 -0
- package/dist/client/assets/chunks/chunk-QR2Q34LM.js +1 -0
- package/dist/client/assets/chunks/chunk-R4GIXL6S.js +1 -0
- package/dist/client/assets/chunks/chunk-RORF4F5V.js +1 -0
- package/dist/client/assets/chunks/chunk-S73BYTLL.js +1 -0
- package/dist/client/assets/chunks/chunk-SFC5MRYR.js +1 -0
- package/dist/client/assets/chunks/chunk-SVM2H22K.js +2 -0
- package/dist/client/assets/chunks/chunk-SZ6UCGVD.js +1 -0
- package/dist/client/assets/chunks/chunk-SZYM6GIJ.js +127 -0
- package/dist/client/assets/chunks/chunk-TT5KJZKM.js +1 -0
- package/dist/client/assets/chunks/chunk-UFBKUYNH.js +1 -0
- package/dist/client/assets/chunks/chunk-UL57AD4T.js +1 -0
- package/dist/client/assets/chunks/chunk-UNEI7LMM.js +1 -0
- package/dist/client/assets/chunks/chunk-VNQBBFIY.js +1 -0
- package/dist/client/assets/chunks/chunk-WGVITPII.js +1 -0
- package/dist/client/assets/chunks/chunk-WRA6KJHX.js +10 -0
- package/dist/client/assets/chunks/chunk-WS5EHW43.js +1 -0
- package/dist/client/assets/chunks/chunk-XE6SLBBE.js +3 -0
- package/dist/client/assets/chunks/chunk-XF5T2P7U.js +72 -0
- package/dist/client/assets/chunks/chunk-XFRY5WKO.js +1 -0
- package/dist/client/assets/chunks/chunk-XWYV4OPA.js +1 -0
- package/dist/client/assets/chunks/chunk-YCE5ECKY.js +1 -0
- package/dist/client/assets/chunks/chunk-YIN5CSIF.js +1 -0
- package/dist/client/assets/chunks/chunk-YLFUX6XH.js +1 -0
- package/dist/client/assets/chunks/chunk-YNXJICZM.js +1 -0
- package/dist/client/assets/chunks/chunk-YOHF7NGD.js +1 -0
- package/dist/client/assets/chunks/chunk-YORIST7Z.js +1 -0
- package/dist/client/assets/chunks/chunk-YUL7CG4R.js +1 -0
- package/dist/client/assets/chunks/chunk-YUN7JSFJ.js +2 -0
- package/dist/client/assets/chunks/chunk-YZ7D2IT7.js +1 -0
- package/dist/client/assets/chunks/chunk-Z7LAPMFJ.js +1 -0
- package/dist/client/assets/chunks/chunk-ZE325LPC.js +1 -0
- package/dist/client/assets/chunks/chunk-ZN7TN6PO.js +1 -0
- package/dist/client/assets/chunks/chunk-ZST3EVPO.js +1 -0
- package/dist/client/assets/chunks/chunk-ZZHMDDZN.js +1 -0
- package/dist/client/assets/chunks/clarity-RKRYQ7WF.js +1 -0
- package/dist/client/assets/chunks/classDiagram-v2-L25IHNXF-Y67HVDZV.js +217 -0
- package/dist/client/assets/chunks/clojure-2X2DQECJ.js +1 -0
- package/dist/client/assets/chunks/cmake-LH5524XE.js +1 -0
- package/dist/client/assets/chunks/cobol-7DALQF3W.js +1 -0
- package/dist/client/assets/chunks/codeowners-52SZU5P5.js +1 -0
- package/dist/client/assets/chunks/codeql-EISH3KUP.js +1 -0
- package/dist/client/assets/chunks/coffee-VAWSGA7Y.js +1 -0
- package/dist/client/assets/chunks/common-lisp-4MVK2AN6.js +1 -0
- package/dist/client/assets/chunks/coq-4VRYZRZV.js +1 -0
- package/dist/client/assets/chunks/core-BRBMZSD2.js +12 -0
- package/dist/client/assets/chunks/cose-bilkent-JH36ORCC-BIOOHSAA.js +1 -0
- package/dist/client/assets/chunks/cpp-RFECMSKD.js +1 -0
- package/dist/client/assets/chunks/crystal-ZBGGFAOI.js +1 -0
- package/dist/client/assets/chunks/csharp-BZDPMKKW.js +1 -0
- package/dist/client/assets/chunks/css-3WWGM6UD.js +1 -0
- package/dist/client/assets/chunks/csv-AB4GNWSB.js +1 -0
- package/dist/client/assets/chunks/cue-2E46MZP2.js +1 -0
- package/dist/client/assets/chunks/cynefin-EF2NZ3EQ-TLFQLWUN.js +1 -0
- package/dist/client/assets/chunks/cynefinDiagram-L36ESFBY-FLPXCSSG.js +62 -0
- package/dist/client/assets/chunks/cypher-HR3ILFOL.js +1 -0
- package/dist/client/assets/chunks/d-TARSZPOL.js +1 -0
- package/dist/client/assets/chunks/dagre-SPEB5RXH-7EGEINJ2.js +4 -0
- package/dist/client/assets/chunks/dart-SALLJHVI.js +1 -0
- package/dist/client/assets/chunks/dax-WYMRGMXC.js +1 -0
- package/dist/client/assets/chunks/desktop-ND5CGLLJ.js +1 -0
- package/dist/client/assets/chunks/diagram-3B7GL73J-6USY4HZX.js +200 -0
- package/dist/client/assets/chunks/diagram-DNEMPZML-BNSOC4VW.js +24 -0
- package/dist/client/assets/chunks/diagram-L3MUGCDN-5V5FZYIG.js +41 -0
- package/dist/client/assets/chunks/diagram-LA4NIPWU-25VLY2CO.js +24 -0
- package/dist/client/assets/chunks/diagram-MHCOC4E2-G2LFP3JU.js +3 -0
- package/dist/client/assets/chunks/diagram-XPFHEONP-E6HBBIBV.js +30 -0
- package/dist/client/assets/chunks/diff-PWYGPM7B.js +1 -0
- package/dist/client/assets/chunks/docker-A4D7DT7W.js +1 -0
- package/dist/client/assets/chunks/dotenv-VWQWV2DY.js +1 -0
- package/dist/client/assets/chunks/dream-maker-M5YDQS35.js +1 -0
- package/dist/client/assets/chunks/ebnfDiagram-UZSYDL2S-BMXXZZPI.js +1 -0
- package/dist/client/assets/chunks/edge-3QXIDJHI.js +1 -0
- package/dist/client/assets/chunks/elixir-3OX2UHIZ.js +1 -0
- package/dist/client/assets/chunks/elk-XV6XMXQE-IPR65FON.js +27 -0
- package/dist/client/assets/chunks/elm-CTS65NCT.js +1 -0
- package/dist/client/assets/chunks/emacs-lisp-HHS2IDO7.js +1 -0
- package/dist/client/assets/chunks/engine-javascript-DNHSF67B.js +141 -0
- package/dist/client/assets/chunks/erDiagram-EYBAPDEH-3GEHFWHG.js +99 -0
- package/dist/client/assets/chunks/erb-ICYWK6HS.js +1 -0
- package/dist/client/assets/chunks/erlang-BDQPNCKX.js +1 -0
- package/dist/client/assets/chunks/eventmodeling-K75KTNOO-B27BJTZL.js +1 -0
- package/dist/client/assets/chunks/fennel-4ONBA2PH.js +1 -0
- package/dist/client/assets/chunks/fish-ATLPBZSD.js +1 -0
- package/dist/client/assets/chunks/flowDiagram-MALGAFMO-5PCLR4AE.js +1 -0
- package/dist/client/assets/chunks/fluent-GGMONBVW.js +1 -0
- package/dist/client/assets/chunks/fortran-fixed-form-5MSBDRWQ.js +1 -0
- package/dist/client/assets/chunks/fortran-free-form-TT3RBL75.js +1 -0
- package/dist/client/assets/chunks/fsharp-PAGHNW4O.js +1 -0
- package/dist/client/assets/chunks/ganttDiagram-23REXITY-VE5MVBTO.js +292 -0
- package/dist/client/assets/chunks/gdresource-5OTP326D.js +1 -0
- package/dist/client/assets/chunks/gdscript-VPWHSCLF.js +1 -0
- package/dist/client/assets/chunks/gdshader-FYLPXFE5.js +1 -0
- package/dist/client/assets/chunks/genie-UYMEEMA2.js +1 -0
- package/dist/client/assets/chunks/gherkin-SU7D5DMY.js +1 -0
- package/dist/client/assets/chunks/git-commit-5CF5QAG7.js +1 -0
- package/dist/client/assets/chunks/git-rebase-X72BAUZI.js +1 -0
- package/dist/client/assets/chunks/gitGraph-VSP46ZUC-J6CJ5YZF.js +1 -0
- package/dist/client/assets/chunks/gitGraphDiagram-STJD7YCW-7YJGT6ZP.js +106 -0
- package/dist/client/assets/chunks/gleam-LR42YRKO.js +1 -0
- package/dist/client/assets/chunks/glimmer-js-JPF67FJU.js +1 -0
- package/dist/client/assets/chunks/glimmer-ts-BYPAVIZT.js +1 -0
- package/dist/client/assets/chunks/glsl-GTGUULBN.js +1 -0
- package/dist/client/assets/chunks/gn-NMDQA4K3.js +1 -0
- package/dist/client/assets/chunks/gnuplot-UUAMYBCZ.js +1 -0
- package/dist/client/assets/chunks/go-4RERSTNP.js +1 -0
- package/dist/client/assets/chunks/graphql-5A6RK6YF.js +1 -0
- package/dist/client/assets/chunks/groovy-O7BJONCU.js +1 -0
- package/dist/client/assets/chunks/hack-7QGTNPDP.js +1 -0
- package/dist/client/assets/chunks/haml-ON5GAWN4.js +1 -0
- package/dist/client/assets/chunks/handlebars-6UOQSUBP.js +1 -0
- package/dist/client/assets/chunks/haskell-OIZXZ26Y.js +1 -0
- package/dist/client/assets/chunks/haxe-7FFVS4FO.js +1 -0
- package/dist/client/assets/chunks/hcl-XFUFQJHV.js +1 -0
- package/dist/client/assets/chunks/hjson-QDBHMTD5.js +1 -0
- package/dist/client/assets/chunks/hlsl-4LP25FFN.js +1 -0
- package/dist/client/assets/chunks/html-7RNQXAAV.js +1 -0
- package/dist/client/assets/chunks/html-derivative-ESOY72Q2.js +1 -0
- package/dist/client/assets/chunks/http-SAD4PMBD.js +1 -0
- package/dist/client/assets/chunks/hurl-ZSJJXPQH.js +1 -0
- package/dist/client/assets/chunks/hxml-HJCC37RK.js +1 -0
- package/dist/client/assets/chunks/hy-CLDE3P4K.js +1 -0
- package/dist/client/assets/chunks/imba-REB34U5V.js +1 -0
- package/dist/client/assets/chunks/info-OHQRW6UA-EQQKXR77.js +1 -0
- package/dist/client/assets/chunks/infoDiagram-KBXO4MBG-F6KGZCGS.js +2 -0
- package/dist/client/assets/chunks/ini-PDFEMGRA.js +1 -0
- package/dist/client/assets/chunks/ishikawaDiagram-M35NCXHK-5D6ZOZ34.js +70 -0
- package/dist/client/assets/chunks/java-KB6XENAD.js +1 -0
- package/dist/client/assets/chunks/javascript-3JX5T423.js +1 -0
- package/dist/client/assets/chunks/jinja-V4UNU6K4.js +1 -0
- package/dist/client/assets/chunks/jison-KH5XNLJP.js +1 -0
- package/dist/client/assets/chunks/journeyDiagram-OPLOXDXO-ANDOJZKW.js +139 -0
- package/dist/client/assets/chunks/json-HPXFRRPY.js +1 -0
- package/dist/client/assets/chunks/json5-LJM6TXWM.js +1 -0
- package/dist/client/assets/chunks/jsonc-UZWRU3JV.js +1 -0
- package/dist/client/assets/chunks/jsonl-RFZD5UN4.js +1 -0
- package/dist/client/assets/chunks/jsonnet-GFZABBL6.js +1 -0
- package/dist/client/assets/chunks/jssm-2YIGBISJ.js +1 -0
- package/dist/client/assets/chunks/jsx-KLV2ZWUT.js +1 -0
- package/dist/client/assets/chunks/julia-3TZDIPPO.js +1 -0
- package/dist/client/assets/chunks/just-UHCONBQS.js +1 -0
- package/dist/client/assets/chunks/kanban-definition-BZKZHSQY-GF5I5NVD.js +89 -0
- package/dist/client/assets/chunks/katex-PIN72PQZ.js +257 -0
- package/dist/client/assets/chunks/kdl-DARTFOCL.js +1 -0
- package/dist/client/assets/chunks/kotlin-7KT5DW6Y.js +1 -0
- package/dist/client/assets/chunks/kusto-EKYXZTC5.js +1 -0
- package/dist/client/assets/chunks/langs-GO3UQR4H.js +1 -0
- package/dist/client/assets/chunks/latex-T57MIHR5.js +1 -0
- package/dist/client/assets/chunks/lean-5QVPRMV6.js +1 -0
- package/dist/client/assets/chunks/less-K6QEH5TN.js +1 -0
- package/dist/client/assets/chunks/liquid-3LCNNEIV.js +1 -0
- package/dist/client/assets/chunks/llvm-O32ZIVRF.js +1 -0
- package/dist/client/assets/chunks/log-C4YPJ5BB.js +1 -0
- package/dist/client/assets/chunks/logo-JPMO43A6.js +1 -0
- package/dist/client/assets/chunks/lua-YKVSOG7K.js +1 -0
- package/dist/client/assets/chunks/luau-K4EECYSO.js +1 -0
- package/dist/client/assets/chunks/make-VHSYMHHW.js +1 -0
- package/dist/client/assets/chunks/markdown-GC5J46H4.js +1 -0
- package/dist/client/assets/chunks/marko-U45YFADC.js +1 -0
- package/dist/client/assets/chunks/matlab-AMOKC4LU.js +1 -0
- package/dist/client/assets/chunks/mdc-DIGA2UXP.js +1 -0
- package/dist/client/assets/chunks/mdx-BZUGCKQA.js +1 -0
- package/dist/client/assets/chunks/mermaid-WHDP6ZPA.js +1 -0
- package/dist/client/assets/chunks/mermaid.core-SQMPMUDN.js +10 -0
- package/dist/client/assets/chunks/mindmap-definition-I2QAS2VK-4NH5S56C.js +98 -0
- package/dist/client/assets/chunks/mipsasm-2S4CUGQV.js +1 -0
- package/dist/client/assets/chunks/mojo-ZOL2PNKT.js +1 -0
- package/dist/client/assets/chunks/moonbit-U3BDAIFE.js +1 -0
- package/dist/client/assets/chunks/move-YSXALBWA.js +1 -0
- package/dist/client/assets/chunks/narrat-DHFIAUJH.js +1 -0
- package/dist/client/assets/chunks/nextflow-ESAKNTI3.js +1 -0
- package/dist/client/assets/chunks/nextflow-groovy-FKDSPJUI.js +1 -0
- package/dist/client/assets/chunks/nginx-XYAYERLO.js +1 -0
- package/dist/client/assets/chunks/nim-XOWBVFDH.js +1 -0
- package/dist/client/assets/chunks/nix-RVSTQSHC.js +1 -0
- package/dist/client/assets/chunks/nsis-KMDUKQRL.js +1 -0
- package/dist/client/assets/chunks/nushell-SKJHHZ7U.js +1 -0
- package/dist/client/assets/chunks/objective-c-3B3KXQ7Q.js +1 -0
- package/dist/client/assets/chunks/objective-cpp-6JDULPJS.js +1 -0
- package/dist/client/assets/chunks/ocaml-TMRFXBVO.js +1 -0
- package/dist/client/assets/chunks/odin-IN3PLCK7.js +1 -0
- package/dist/client/assets/chunks/openscad-P52IKPNH.js +1 -0
- package/dist/client/assets/chunks/org-N3SJ2PIA.js +1 -0
- package/dist/client/assets/chunks/packet-JDAUHWVQ-4SWIKSKP.js +1 -0
- package/dist/client/assets/chunks/pascal-T7CUWCQ4.js +1 -0
- package/dist/client/assets/chunks/pegDiagram-FD4XPPHP-WDKZSEGN.js +1 -0
- package/dist/client/assets/chunks/perl-LCZ4KODH.js +1 -0
- package/dist/client/assets/chunks/php-4XHMBVR5.js +1 -0
- package/dist/client/assets/chunks/pie-XZMESJXO-PSSWOWGV.js +1 -0
- package/dist/client/assets/chunks/pieDiagram-J4AKIIQI-BDW5I5ON.js +39 -0
- package/dist/client/assets/chunks/pkl-OACG5B67.js +1 -0
- package/dist/client/assets/chunks/plsql-7E5C7CJX.js +1 -0
- package/dist/client/assets/chunks/po-ZSREFRRP.js +1 -0
- package/dist/client/assets/chunks/polar-4GBINVA7.js +1 -0
- package/dist/client/assets/chunks/postcss-B7RPVGFW.js +1 -0
- package/dist/client/assets/chunks/powerquery-6UFMTY4G.js +1 -0
- package/dist/client/assets/chunks/powershell-3STRPCNT.js +1 -0
- package/dist/client/assets/chunks/prisma-4TPSPIZ5.js +1 -0
- package/dist/client/assets/chunks/prolog-HEAYPKQW.js +1 -0
- package/dist/client/assets/chunks/proto-Y3Y3VKXM.js +1 -0
- package/dist/client/assets/chunks/pug-7PBPMG3M.js +1 -0
- package/dist/client/assets/chunks/puppet-FR35R4OI.js +1 -0
- package/dist/client/assets/chunks/purescript-OUHXQAOW.js +1 -0
- package/dist/client/assets/chunks/python-SNDG7FNU.js +1 -0
- package/dist/client/assets/chunks/qml-UVIOSWP4.js +1 -0
- package/dist/client/assets/chunks/qmldir-6JGUNYL5.js +1 -0
- package/dist/client/assets/chunks/qss-ZCC466IZ.js +1 -0
- package/dist/client/assets/chunks/quadrantDiagram-XTYBLID2-5VKXWVJ6.js +7 -0
- package/dist/client/assets/chunks/r-4XW4O3ZF.js +1 -0
- package/dist/client/assets/chunks/racket-YJAYXOOG.js +1 -0
- package/dist/client/assets/chunks/radar-ABXABTNO-3AXZCEY2.js +1 -0
- package/dist/client/assets/chunks/railroad-I3PHUGI6-2PLXYPOT.js +1 -0
- package/dist/client/assets/chunks/railroad-abnf-LNEFI6M7-M4DGICQX.js +1 -0
- package/dist/client/assets/chunks/railroad-ebnf-DWYD2UWJ-UEIHQMSZ.js +1 -0
- package/dist/client/assets/chunks/railroad-peg-JR7BVNR7-I7VLIBXM.js +1 -0
- package/dist/client/assets/chunks/railroadDiagram-MRQ6NCDL-Y6IYWEFL.js +1 -0
- package/dist/client/assets/chunks/raku-63NEL5JK.js +1 -0
- package/dist/client/assets/chunks/razor-J3CJP523.js +1 -0
- package/dist/client/assets/chunks/rbs-6GQLT7NW.js +1 -0
- package/dist/client/assets/chunks/reg-6Q3OEC2C.js +1 -0
- package/dist/client/assets/chunks/regexp-LPIMILT3.js +1 -0
- package/dist/client/assets/chunks/rel-TOQGUTHB.js +1 -0
- package/dist/client/assets/chunks/requirementDiagram-Y7LWUY3S-CIWXVVWJ.js +84 -0
- package/dist/client/assets/chunks/riscv-UELGBOXE.js +1 -0
- package/dist/client/assets/chunks/ron-FW7LCJJH.js +1 -0
- package/dist/client/assets/chunks/rosmsg-O63VHE3L.js +1 -0
- package/dist/client/assets/chunks/rst-3WJXGLA7.js +1 -0
- package/dist/client/assets/chunks/ruby-7S7L6JTH.js +1 -0
- package/dist/client/assets/chunks/rust-LIK4HRRI.js +1 -0
- package/dist/client/assets/chunks/sankeyDiagram-WGJFYUXA-OGNQPX5V.js +40 -0
- package/dist/client/assets/chunks/sas-FHDPZ2JH.js +1 -0
- package/dist/client/assets/chunks/sass-UI4HW2FN.js +1 -0
- package/dist/client/assets/chunks/scala-KN7RQSUJ.js +1 -0
- package/dist/client/assets/chunks/scheme-5R527YZ5.js +1 -0
- package/dist/client/assets/chunks/scss-KZ6DRE4A.js +1 -0
- package/dist/client/assets/chunks/sdbl-FHOCL5SL.js +1 -0
- package/dist/client/assets/chunks/sequenceDiagram-5NDRBG5M-QX2V24ZU.js +169 -0
- package/dist/client/assets/chunks/shaderlab-2TLHUS2H.js +1 -0
- package/dist/client/assets/chunks/shellscript-PIB6ZBDM.js +1 -0
- package/dist/client/assets/chunks/shellsession-5KL7NFNN.js +1 -0
- package/dist/client/assets/chunks/sizeCapture-INFHLROL-LCS2PIHM.js +1 -0
- package/dist/client/assets/chunks/smalltalk-JFLFU247.js +1 -0
- package/dist/client/assets/chunks/smithy-HONEXZAM.js +1 -0
- package/dist/client/assets/chunks/solidity-SJ3INJFZ.js +1 -0
- package/dist/client/assets/chunks/soy-ND4SWTM2.js +1 -0
- package/dist/client/assets/chunks/sparql-YB2JQBZD.js +1 -0
- package/dist/client/assets/chunks/splunk-UXIDDAWL.js +1 -0
- package/dist/client/assets/chunks/sql-K6OMG7SQ.js +1 -0
- package/dist/client/assets/chunks/ssh-config-I7KJY3KQ.js +1 -0
- package/dist/client/assets/chunks/stata-DNZ3DTFJ.js +1 -0
- package/dist/client/assets/chunks/stateDiagram-v2-FJ4FJNEA-LVAUWF3A.js +291 -0
- package/dist/client/assets/chunks/stylus-GWPR6IQY.js +1 -0
- package/dist/client/assets/chunks/surrealql-KQNHBWLC.js +1 -0
- package/dist/client/assets/chunks/svelte-YQKF25S4.js +1 -0
- package/dist/client/assets/chunks/swift-ZCIZUJXA.js +1 -0
- package/dist/client/assets/chunks/swimlanes-UMQ2AFYF-B3RQOARQ.js +1 -0
- package/dist/client/assets/chunks/swimlanesDiagram-OMPLPG4O-JOE33EOV.js +8 -0
- package/dist/client/assets/chunks/system-verilog-Y7E6FIO3.js +1 -0
- package/dist/client/assets/chunks/systemd-WHC7NBZP.js +1 -0
- package/dist/client/assets/chunks/talonscript-WC7SODAH.js +1 -0
- package/dist/client/assets/chunks/tasl-QHY2GTCB.js +1 -0
- package/dist/client/assets/chunks/tcl-VAMIL5PJ.js +1 -0
- package/dist/client/assets/chunks/temml-ISNSX3VV.js +96 -0
- package/dist/client/assets/chunks/templ-B3BHKWV4.js +1 -0
- package/dist/client/assets/chunks/terraform-Q4UEK6FK.js +1 -0
- package/dist/client/assets/chunks/tex-63OWCYAB.js +1 -0
- package/dist/client/assets/chunks/timeline-definition-SEUHKTQE-FDFTVAJG.js +120 -0
- package/dist/client/assets/chunks/toml-7Z4IPGES.js +1 -0
- package/dist/client/assets/chunks/treeView-D4JQ5SDB-ABSGRAGI.js +1 -0
- package/dist/client/assets/chunks/treemap-SAJKECNS-MYX2CBJN.js +1 -0
- package/dist/client/assets/chunks/ts-tags-DT62HE52.js +1 -0
- package/dist/client/assets/chunks/tsv-RTXHWADP.js +1 -0
- package/dist/client/assets/chunks/tsx-UANUBOC7.js +1 -0
- package/dist/client/assets/chunks/turtle-QVOUNUUL.js +1 -0
- package/dist/client/assets/chunks/twig-ZPC4BPDA.js +1 -0
- package/dist/client/assets/chunks/typescript-WGWKIMMW.js +1 -0
- package/dist/client/assets/chunks/typespec-TYCVR32J.js +1 -0
- package/dist/client/assets/chunks/typst-PIBFYUO6.js +1 -0
- package/dist/client/assets/chunks/usecaseDiagram-AFA6YXN4-KW7ADINR.js +370 -0
- package/dist/client/assets/chunks/v-3ERNWBSP.js +1 -0
- package/dist/client/assets/chunks/vala-UCBCT2GS.js +1 -0
- package/dist/client/assets/chunks/vb-DGI3VTPA.js +1 -0
- package/dist/client/assets/chunks/vennDiagram-NNMJR3RB-RDGLGOGM.js +34 -0
- package/dist/client/assets/chunks/verilog-G72NZROS.js +1 -0
- package/dist/client/assets/chunks/vhdl-PYGA77XE.js +1 -0
- package/dist/client/assets/chunks/viml-OOC5B5UU.js +1 -0
- package/dist/client/assets/chunks/vue-GTNHIOPG.js +1 -0
- package/dist/client/assets/chunks/vue-html-DKAMJV55.js +1 -0
- package/dist/client/assets/chunks/vue-vine-WTM5HREV.js +1 -0
- package/dist/client/assets/chunks/vyper-RHYEHOJM.js +1 -0
- package/dist/client/assets/chunks/wardley-7MLQ67FV-QJL2HSBT.js +1 -0
- package/dist/client/assets/chunks/wardleyDiagram-S7YFUSEH-A4XX3UJR.js +78 -0
- package/dist/client/assets/chunks/wasm-ZMM2Z5XV.js +1 -0
- package/dist/client/assets/chunks/wenyan-HF5UTKSJ.js +1 -0
- package/dist/client/assets/chunks/wgsl-O7D7OPO7.js +1 -0
- package/dist/client/assets/chunks/wikitext-T7BSWSKQ.js +1 -0
- package/dist/client/assets/chunks/wit-TKCHPPT6.js +1 -0
- package/dist/client/assets/chunks/wolfram-7MN66A7N.js +1 -0
- package/dist/client/assets/chunks/xml-NLTLAWOD.js +1 -0
- package/dist/client/assets/chunks/xsl-NZ4ECK3P.js +1 -0
- package/dist/client/assets/chunks/xychartDiagram-GGNKY7IX-OXJILWHR.js +7 -0
- package/dist/client/assets/chunks/yaml-HRJLEV3V.js +1 -0
- package/dist/client/assets/chunks/zenscript-4LLRSLPI.js +1 -0
- package/dist/client/assets/chunks/zig-Y7MUQFUO.js +1 -0
- package/dist/client/assets/icon.svg +1 -0
- package/dist/client/assets/main.js +254 -0
- package/dist/client/index.html +59 -0
- package/dist/diff.js +119 -0
- package/dist/fs/files.js +233 -0
- package/dist/fs/git.js +369 -0
- package/dist/fs/glob.js +89 -0
- package/dist/fs/notes.js +368 -0
- package/dist/fs/search.js +136 -0
- package/dist/fs/watch.js +69 -0
- package/dist/fs/zip.js +100 -0
- package/dist/hooks.js +65 -0
- package/dist/http.js +81 -0
- package/dist/hub/atomic.js +77 -0
- package/dist/hub/notify.js +239 -0
- package/dist/hub/registry.js +219 -0
- package/dist/mcp.js +500 -0
- package/dist/q/agent.js +215 -0
- package/dist/q/model.js +633 -0
- package/dist/q/schema.js +133 -0
- package/dist/q/store.js +413 -0
- package/dist/r/model.js +323 -0
- package/dist/r/schema.js +53 -0
- package/dist/r/store.js +489 -0
- package/dist/server.js +246 -0
- package/dist/settings.js +30 -0
- package/dist/workspace.js +639 -0
- package/package.json +73 -4
- package/schema/questions.schema.json +1670 -0
- package/schema/reviews.schema.json +151 -0
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// The Claude Code hooks hitl can add to a project (opt-in): one tells Claude what the human said whenever they send it a
|
|
2
|
+
// message; the other stops Claude finishing while an approval or a blocking question is waiting. They live in the
|
|
3
|
+
// project's .claude/settings.json; `hitl hooks`, `hitl init --hook/--stop-hook` and the page's settings change them.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
/** How Claude Code should start hitl: through npx once it's published, else this copy. */
|
|
8
|
+
export function launcher() {
|
|
9
|
+
const cli = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'cli.js');
|
|
10
|
+
if (/[\\/]_npx[\\/]|[\\/]node_modules[\\/]hitloop[\\/]/.test(cli)) {
|
|
11
|
+
return process.platform === 'win32'
|
|
12
|
+
? { command: 'cmd', args: ['/c', 'npx', '-y', 'hitloop@latest'], line: 'cmd /c npx -y hitloop@latest' }
|
|
13
|
+
: { command: 'npx', args: ['-y', 'hitloop@latest'], line: 'npx -y hitloop@latest' };
|
|
14
|
+
}
|
|
15
|
+
return { command: process.execPath, args: [cli], line: `"${process.execPath}" "${cli}"` };
|
|
16
|
+
}
|
|
17
|
+
export function setHooks(root, want) {
|
|
18
|
+
const file = path.join(root, '.claude', 'settings.json');
|
|
19
|
+
let settings = {};
|
|
20
|
+
try {
|
|
21
|
+
settings = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
settings = {};
|
|
25
|
+
}
|
|
26
|
+
const l = launcher();
|
|
27
|
+
const out = [];
|
|
28
|
+
const isOurs = (cmd, which) => /hitl/.test(cmd) && new RegExp(` hook${which === 'stop' ? ' stop' : '( prompt)?'}$`).test(cmd);
|
|
29
|
+
const apply = (event, which, on, label) => {
|
|
30
|
+
if (on === undefined)
|
|
31
|
+
return;
|
|
32
|
+
settings.hooks ??= {};
|
|
33
|
+
const list = (settings.hooks[event] ??= []);
|
|
34
|
+
const has = list.some((h) => h.hooks?.some((x) => isOurs(x.command, which)));
|
|
35
|
+
if (on && !has) {
|
|
36
|
+
list.push({ hooks: [{ type: 'command', command: `${l.line} hook ${which}` }] });
|
|
37
|
+
out.push(`✓ ${label}: on`);
|
|
38
|
+
}
|
|
39
|
+
else if (!on && has) {
|
|
40
|
+
settings.hooks[event] = list.map((h) => ({ ...h, hooks: h.hooks.filter((x) => !isOurs(x.command, which)) })).filter((h) => h.hooks.length);
|
|
41
|
+
if (!settings.hooks[event]?.length)
|
|
42
|
+
delete settings.hooks[event];
|
|
43
|
+
out.push(`✓ ${label}: off`);
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
out.push(`✓ ${label}: already ${on ? 'on' : 'off'}`);
|
|
47
|
+
};
|
|
48
|
+
apply('UserPromptSubmit', 'prompt', want.prompt, 'News hook (tells Claude what you said when you send a message)');
|
|
49
|
+
apply('Stop', 'stop', want.stop, "Stop hook (Claude can't finish while an approval or blocking question waits)");
|
|
50
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
51
|
+
fs.writeFileSync(file, JSON.stringify(settings, null, 2) + '\n');
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
/** which of hitl's hooks are on in a project */
|
|
55
|
+
export function hookStatus(root) {
|
|
56
|
+
let s = {};
|
|
57
|
+
try {
|
|
58
|
+
s = JSON.parse(fs.readFileSync(path.join(root, '.claude', 'settings.json'), 'utf8'));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
s = {};
|
|
62
|
+
}
|
|
63
|
+
const has = (ev, re) => !!s.hooks?.[ev]?.some((x) => x.hooks?.some((c) => /hitl/.test(c.command) && re.test(c.command)));
|
|
64
|
+
return { prompt: has('UserPromptSubmit', / hook( prompt)?$/), stop: has('Stop', / hook stop$/) };
|
|
65
|
+
}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { StoreError } from './hub/atomic.js';
|
|
3
|
+
export function json(res, code, data) {
|
|
4
|
+
res.writeHead(code, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }).end(JSON.stringify(data));
|
|
5
|
+
}
|
|
6
|
+
export function text(res, body, type = 'text/plain; charset=utf-8') {
|
|
7
|
+
res.writeHead(200, { 'content-type': type, 'cache-control': 'no-store' }).end(body);
|
|
8
|
+
}
|
|
9
|
+
export async function body(req, max = 1_000_000) {
|
|
10
|
+
if (!String(req.headers['content-type'] ?? '').includes('application/json'))
|
|
11
|
+
throw new StoreError('Send JSON');
|
|
12
|
+
const chunks = [];
|
|
13
|
+
let size = 0;
|
|
14
|
+
for await (const c of req) {
|
|
15
|
+
const b = Buffer.isBuffer(c) ? c : Buffer.from(String(c));
|
|
16
|
+
size += b.length;
|
|
17
|
+
if (size > max)
|
|
18
|
+
throw new StoreError('Too large');
|
|
19
|
+
chunks.push(b);
|
|
20
|
+
}
|
|
21
|
+
const data = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}');
|
|
22
|
+
if (!data || typeof data !== 'object' || Array.isArray(data))
|
|
23
|
+
throw new StoreError('Send a JSON object');
|
|
24
|
+
return Object.fromEntries(Object.entries(data));
|
|
25
|
+
}
|
|
26
|
+
export const disposition = (name) => `attachment; filename="${name.replace(/[^\x20-\x7e]|["\\]/g, '_')}"; filename*=UTF-8''${encodeURIComponent(name)}`;
|
|
27
|
+
export const bearer = (req) => /^Bearer (.+)$/i.exec(String(req.headers.authorization ?? ''))?.[1];
|
|
28
|
+
export const cookie = (req, name) => {
|
|
29
|
+
for (const part of String(req.headers.cookie ?? '').split(';')) {
|
|
30
|
+
const [k, ...v] = part.trim().split('=');
|
|
31
|
+
if (k === name)
|
|
32
|
+
return decodeURIComponent(v.join('='));
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
};
|
|
36
|
+
export function same(a, b) {
|
|
37
|
+
const x = crypto.createHash('sha256').update(a).digest();
|
|
38
|
+
const y = crypto.createHash('sha256').update(b).digest();
|
|
39
|
+
return crypto.timingSafeEqual(x, y);
|
|
40
|
+
}
|
|
41
|
+
export const str = (v) => (typeof v === 'string' ? v : '');
|
|
42
|
+
export const posInt = (v) => (typeof v === 'number' && Number.isInteger(v) && v > 0 ? v : undefined);
|
|
43
|
+
export const strList = (v) => (Array.isArray(v) ? v.map(String) : typeof v === 'string' && v ? [v] : []);
|
|
44
|
+
/** a picture comment's marks from a request: the area, the strokes, and the marked-up picture (a PNG data URL) */
|
|
45
|
+
export function imageMarks(b) {
|
|
46
|
+
const out = {};
|
|
47
|
+
const a = b['area'];
|
|
48
|
+
if (a && typeof a === 'object' && !Array.isArray(a)) {
|
|
49
|
+
const r = Object.fromEntries(Object.entries(a));
|
|
50
|
+
const n = (k) => (typeof r[k] === 'number' && Number.isFinite(r[k]) && Number(r[k]) >= 0 ? Math.round(Number(r[k])) : undefined);
|
|
51
|
+
const [x, y, w, h] = [n('x'), n('y'), n('w'), n('h')];
|
|
52
|
+
if (x !== undefined && y !== undefined && w && h)
|
|
53
|
+
out.area = { x, y, w, h };
|
|
54
|
+
}
|
|
55
|
+
const s = b['strokes'];
|
|
56
|
+
if (Array.isArray(s)) {
|
|
57
|
+
let budget = 20_000;
|
|
58
|
+
const strokes = s
|
|
59
|
+
.filter((st) => Array.isArray(st))
|
|
60
|
+
.map((st) => st.filter((v) => typeof v === 'number' && v >= 0 && v <= 1).map((v) => Math.round(v * 10000) / 10000))
|
|
61
|
+
.filter((st) => st.length >= 2 && st.length % 2 === 0 && (budget -= st.length) >= 0);
|
|
62
|
+
if (strokes.length)
|
|
63
|
+
out.strokes = strokes;
|
|
64
|
+
}
|
|
65
|
+
const snap = typeof b['snapshot'] === 'string' ? /^data:image\/png;base64,([A-Za-z0-9+/=]+)$/.exec(b['snapshot']) : null;
|
|
66
|
+
if (snap && out.strokes) {
|
|
67
|
+
const buf = Buffer.from(snap[1] ?? '', 'base64');
|
|
68
|
+
if (buf.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) {
|
|
69
|
+
out.snapshot = buf;
|
|
70
|
+
out.snapshotUrl = String(b['snapshot']);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
/** photos attached to a comment: image data URLs only */
|
|
76
|
+
export function photos(b) {
|
|
77
|
+
const p = b['photos'];
|
|
78
|
+
if (!Array.isArray(p))
|
|
79
|
+
return [];
|
|
80
|
+
return p.filter((x) => typeof x === 'string' && /^data:image\/(png|jpeg|webp|gif|heic|avif);base64,[A-Za-z0-9+/=]+$/.test(x)).slice(0, 8);
|
|
81
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Safe writes from many processes at once: an atomic rename, under a lock file.
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
export class StoreError extends Error {
|
|
5
|
+
}
|
|
6
|
+
export const stripBom = (s) => (s.charCodeAt(0) === 0xfeff ? s.slice(1) : s);
|
|
7
|
+
export function writeAtomic(file, text) {
|
|
8
|
+
const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
9
|
+
fs.writeFileSync(tmp, text);
|
|
10
|
+
for (let i = 0;; i++) {
|
|
11
|
+
try {
|
|
12
|
+
fs.renameSync(tmp, file);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
// Windows: a reader holding the file open makes rename fail for a moment
|
|
17
|
+
if (i >= 20) {
|
|
18
|
+
fs.rmSync(tmp, { force: true });
|
|
19
|
+
throw e;
|
|
20
|
+
}
|
|
21
|
+
sleep(25);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function sleep(ms) {
|
|
26
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
27
|
+
}
|
|
28
|
+
/** Run fn holding <file>.lock (made with O_EXCL; a lock older than 10 s is taken as abandoned). */
|
|
29
|
+
export function withLock(file, fn) {
|
|
30
|
+
const lock = file + '.lock';
|
|
31
|
+
const until = Date.now() + 8000;
|
|
32
|
+
for (;;) {
|
|
33
|
+
try {
|
|
34
|
+
fs.writeFileSync(lock, String(process.pid), { flag: 'wx' });
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
if (e.code !== 'EEXIST')
|
|
39
|
+
throw e;
|
|
40
|
+
try {
|
|
41
|
+
if (Date.now() - fs.statSync(lock).mtimeMs > 10_000)
|
|
42
|
+
fs.rmSync(lock, { force: true });
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// gone already
|
|
46
|
+
}
|
|
47
|
+
if (Date.now() > until)
|
|
48
|
+
throw new StoreError(`${path.basename(file)} is locked by another process`);
|
|
49
|
+
sleep(15);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
return fn();
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
fs.rmSync(lock, { force: true });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** .hitl/README.md: what the folder holds (written once). */
|
|
60
|
+
export function ensureReadme(dir) {
|
|
61
|
+
const file = path.join(dir, 'README.md');
|
|
62
|
+
if (fs.existsSync(file))
|
|
63
|
+
return;
|
|
64
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
65
|
+
fs.writeFileSync(file, HITL_README);
|
|
66
|
+
}
|
|
67
|
+
const HITL_README = `# hitl: Human In The Loop
|
|
68
|
+
|
|
69
|
+
What an agent asked, showed or sent for review in this project, and what the human said back.
|
|
70
|
+
Open it with \`npx hitloop\` (the links it prints work on a phone too). What's new for the agent: \`npx hitloop news\`.
|
|
71
|
+
|
|
72
|
+
- \`questions/<id>.json\`: question sets (an agent writes these; the format: \`npx hitloop schema questions\`).
|
|
73
|
+
- \`reviews/<id>.json\`: things shown for review or approval (an agent writes these; \`npx hitloop schema reviews\`).
|
|
74
|
+
- \`answers/<id>.json\` and \`.md\`: the human's answers, verdicts and comments, one file per question set or review.
|
|
75
|
+
- \`notes/\`: notes from the human on files, lines and picture areas (notes.json, NOTES.md, images/).
|
|
76
|
+
- \`media/\`: pictures an agent passed as data, and photos the human attached.
|
|
77
|
+
`;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
// Push notifications to your phone when an agent asks for something: through ntfy (a push app for Android and iOS;
|
|
2
|
+
// the hub posts to your private topic) or any webhook (Pushover, Discord, Home Assistant, …). Changes are batched: an
|
|
3
|
+
// agent adding 50 questions over a minute makes one notification, sent once it has been quiet for a while. An approval
|
|
4
|
+
// is someone waiting at a gate, so it goes out within a couple of seconds.
|
|
5
|
+
//
|
|
6
|
+
// Web Push isn't used: a phone only allows it on HTTPS pages, and hitl is opened over plain http on the LAN.
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import { userConfig, lanAddresses } from './registry.js';
|
|
9
|
+
import { allQuestions, visibility, isDone } from '../q/model.js';
|
|
10
|
+
export const notifyConfig = (cfg = userConfig()) => (cfg.notify && typeof cfg.notify === 'object' ? cfg.notify : {});
|
|
11
|
+
export const notifyEnabled = (n) => !!(n.ntfy || n.webhook);
|
|
12
|
+
export class Notifier {
|
|
13
|
+
project;
|
|
14
|
+
port;
|
|
15
|
+
token;
|
|
16
|
+
base;
|
|
17
|
+
log;
|
|
18
|
+
seen = new Map();
|
|
19
|
+
pending = new Map();
|
|
20
|
+
started = Date.now();
|
|
21
|
+
constructor(project, port, token, base, log = () => undefined) {
|
|
22
|
+
this.project = project;
|
|
23
|
+
this.port = port;
|
|
24
|
+
this.token = token;
|
|
25
|
+
this.base = base;
|
|
26
|
+
this.log = log;
|
|
27
|
+
}
|
|
28
|
+
state(p, kind, id) {
|
|
29
|
+
if (kind === 'questions') {
|
|
30
|
+
const l = p.questions.load(id);
|
|
31
|
+
if (!l)
|
|
32
|
+
return undefined;
|
|
33
|
+
const af = p.questions.answers(id);
|
|
34
|
+
let agentMessages = 0;
|
|
35
|
+
for (const list of Object.values(af.threads))
|
|
36
|
+
for (const m of list)
|
|
37
|
+
if (m.from === 'agent')
|
|
38
|
+
agentMessages++;
|
|
39
|
+
return { things: new Set(allQuestions(l.set).map((q) => q.id)), agentMessages };
|
|
40
|
+
}
|
|
41
|
+
if (kind === 'review') {
|
|
42
|
+
const l = p.reviews.load(id);
|
|
43
|
+
if (!l)
|
|
44
|
+
return undefined;
|
|
45
|
+
const fb = p.reviews.feedback(id);
|
|
46
|
+
let agentMessages = 0;
|
|
47
|
+
for (const c of fb.comments)
|
|
48
|
+
agentMessages += (c.from === 'agent' ? 1 : 0) + c.replies.filter((r) => r.from === 'agent').length;
|
|
49
|
+
// "@open": the review is (again) open, so an approval asked again counts as new
|
|
50
|
+
return { things: new Set([...l.review.items.map((i) => i.id), `@${l.review.status}`]), agentMessages };
|
|
51
|
+
}
|
|
52
|
+
let agentMessages = 0;
|
|
53
|
+
for (const c of p.notes.all())
|
|
54
|
+
agentMessages += (c.replies ?? []).filter((r) => r.from === 'agent' || r.author === 'agent').length;
|
|
55
|
+
return { things: new Set(), agentMessages };
|
|
56
|
+
}
|
|
57
|
+
created(p, kind, id) {
|
|
58
|
+
const c = kind === 'questions' ? p.questions.load(id)?.set.created : kind === 'review' ? p.reviews.load(id)?.review.created : '';
|
|
59
|
+
return Date.parse(c ?? '') || 0;
|
|
60
|
+
}
|
|
61
|
+
/** What's there now counts as seen (on start). */
|
|
62
|
+
baseline(key) {
|
|
63
|
+
const p = this.project(key);
|
|
64
|
+
if (!p)
|
|
65
|
+
return;
|
|
66
|
+
for (const id of p.questions.ids())
|
|
67
|
+
this.keep(key, p, 'questions', id);
|
|
68
|
+
for (const id of p.reviews.ids())
|
|
69
|
+
this.keep(key, p, 'review', id);
|
|
70
|
+
this.keep(key, p, 'notes', 'notes');
|
|
71
|
+
}
|
|
72
|
+
keep(key, p, kind, id) {
|
|
73
|
+
const s = this.state(p, kind, id);
|
|
74
|
+
if (s)
|
|
75
|
+
this.seen.set(`${key}/${kind}/${id}`, s);
|
|
76
|
+
}
|
|
77
|
+
/** Something changed in a request: queue what's new. */
|
|
78
|
+
observe(key, kind, id) {
|
|
79
|
+
const k = `${key}/${kind}/${id}`;
|
|
80
|
+
const p = this.project(key);
|
|
81
|
+
if (!p)
|
|
82
|
+
return;
|
|
83
|
+
const now = this.state(p, kind, id);
|
|
84
|
+
if (!now)
|
|
85
|
+
return;
|
|
86
|
+
let was = this.seen.get(k);
|
|
87
|
+
if (!was)
|
|
88
|
+
was = this.created(p, kind, id) >= this.started - 5000 ? { things: new Set(), agentMessages: 0 } : now;
|
|
89
|
+
const fresh = [...now.things].filter((t) => !was.things.has(t) && t !== '@closed');
|
|
90
|
+
const replies = Math.max(0, now.agentMessages - was.agentMessages);
|
|
91
|
+
this.seen.set(k, now);
|
|
92
|
+
if (!fresh.length && !replies)
|
|
93
|
+
return;
|
|
94
|
+
const cfg = notifyConfig();
|
|
95
|
+
if (!notifyEnabled(cfg))
|
|
96
|
+
return;
|
|
97
|
+
const pend = this.pending.get(k) ?? { fresh: new Set(), replies: 0, first: Date.now() };
|
|
98
|
+
for (const t of fresh)
|
|
99
|
+
pend.fresh.add(t);
|
|
100
|
+
pend.replies += cfg.replies === false ? 0 : replies;
|
|
101
|
+
if (!pend.fresh.size && !pend.replies)
|
|
102
|
+
return;
|
|
103
|
+
this.pending.set(k, pend);
|
|
104
|
+
clearTimeout(pend.timer);
|
|
105
|
+
const quiet = Math.max(1, cfg.quietSeconds ?? 20) * 1000;
|
|
106
|
+
const isGate = kind === 'review' && p.reviews.load(id)?.review.mode === 'approve';
|
|
107
|
+
const wait = isGate ? 1500 : Math.min(quiet, Math.max(0, pend.first + 120_000 - Date.now()));
|
|
108
|
+
pend.timer = setTimeout(() => void this.flush(key, kind, id), wait);
|
|
109
|
+
pend.timer.unref?.();
|
|
110
|
+
}
|
|
111
|
+
async flush(key, kind, id) {
|
|
112
|
+
const k = `${key}/${kind}/${id}`;
|
|
113
|
+
const pend = this.pending.get(k);
|
|
114
|
+
this.pending.delete(k);
|
|
115
|
+
const p = this.project(key);
|
|
116
|
+
if (!pend || !p)
|
|
117
|
+
return;
|
|
118
|
+
const notice = this.compose(p, key, kind, id, pend);
|
|
119
|
+
if (!notice)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
await send(notifyConfig(), notice);
|
|
123
|
+
this.log(`notified: ${notice.title}`);
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
this.log(`couldn't notify: ${e instanceof Error ? e.message : String(e)}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
compose(p, key, kind, id, pend) {
|
|
130
|
+
const base = { url: this.link(key, kind, id), project: key, request: id, newQuestions: 0, newItems: 0, approval: false, blocking: 0, replies: pend.replies };
|
|
131
|
+
const replyText = pend.replies ? `${pend.replies} repl${pend.replies === 1 ? 'y' : 'ies'} from the agent` : '';
|
|
132
|
+
if (kind === 'questions') {
|
|
133
|
+
const l = p.questions.load(id);
|
|
134
|
+
if (!l)
|
|
135
|
+
return undefined;
|
|
136
|
+
const af = p.questions.answers(id);
|
|
137
|
+
const vis = visibility(l.set, af.answers);
|
|
138
|
+
const fresh = allQuestions(l.set).filter((q) => pend.fresh.has(q.id) && vis.question(q.id));
|
|
139
|
+
const blocking = fresh.filter((q) => q.priority === 'blocking' && !isDone(af.answers[q.id])).length;
|
|
140
|
+
if (!fresh.length && !pend.replies)
|
|
141
|
+
return undefined;
|
|
142
|
+
const first = fresh[0];
|
|
143
|
+
return {
|
|
144
|
+
...base,
|
|
145
|
+
kind: 'questions',
|
|
146
|
+
title: `${l.set.title}: ${[fresh.length ? `${fresh.length} new question${fresh.length === 1 ? '' : 's'}` : '', replyText].filter(Boolean).join(', ')}`,
|
|
147
|
+
message: [
|
|
148
|
+
blocking ? `${blocking} blocking: the agent is waiting on ${blocking === 1 ? 'it' : 'them'}.` : '',
|
|
149
|
+
first ? `“${first.question.replace(/\s+/g, ' ').slice(0, 120)}”${fresh.length > 1 ? ` and ${fresh.length - 1} more` : ''}` : 'Tap to read.',
|
|
150
|
+
`${key} · ${id}`,
|
|
151
|
+
]
|
|
152
|
+
.filter(Boolean)
|
|
153
|
+
.join('\n'),
|
|
154
|
+
newQuestions: fresh.length,
|
|
155
|
+
blocking,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (kind === 'review') {
|
|
159
|
+
const l = p.reviews.load(id);
|
|
160
|
+
if (!l)
|
|
161
|
+
return undefined;
|
|
162
|
+
const r = l.review;
|
|
163
|
+
const items = r.items.filter((i) => pend.fresh.has(i.id));
|
|
164
|
+
const gate = r.mode === 'approve';
|
|
165
|
+
const asked = gate && pend.fresh.has('@open');
|
|
166
|
+
if (!items.length && !pend.replies && !asked)
|
|
167
|
+
return undefined;
|
|
168
|
+
const what = gate ? 'asks for your OK' : `${items.length} thing${items.length === 1 ? '' : 's'} to ${r.mode === 'show' ? 'look at' : 'review'}`;
|
|
169
|
+
return {
|
|
170
|
+
...base,
|
|
171
|
+
kind: gate ? 'approve' : 'review',
|
|
172
|
+
title: `${r.title}: ${[items.length || asked ? what : '', replyText].filter(Boolean).join(', ')}`,
|
|
173
|
+
message: [
|
|
174
|
+
r.from ? `From ${r.from}.` : '',
|
|
175
|
+
gate ? 'Approve or refuse: the agent is waiting.' : items[0] ? `“${items[0].title.slice(0, 120)}”${items.length > 1 ? ` and ${items.length - 1} more` : ''}` : 'Tap to read.',
|
|
176
|
+
`${key} · ${id}`,
|
|
177
|
+
]
|
|
178
|
+
.filter(Boolean)
|
|
179
|
+
.join('\n'),
|
|
180
|
+
newItems: items.length,
|
|
181
|
+
approval: gate,
|
|
182
|
+
blocking: gate ? 1 : 0,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
if (!pend.replies)
|
|
186
|
+
return undefined;
|
|
187
|
+
return { ...base, kind: 'notes', title: `${key}: ${replyText} on your notes`, message: 'Tap to read.' };
|
|
188
|
+
}
|
|
189
|
+
link(key, kind, id) {
|
|
190
|
+
const hash = kind === 'notes' ? `#/p/${encodeURIComponent(key)}/notes` : `#/p/${encodeURIComponent(key)}/${kind === 'review' ? 'r' : 'q'}/${encodeURIComponent(id)}`;
|
|
191
|
+
return linkBase(notifyConfig(), this.port(), this.token, this.base) + hash;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/** Where links in notifications point: the configured base, else Tailscale (works anywhere), else the LAN. */
|
|
195
|
+
export function linkBase(cfg, port, token, hubBase = '/') {
|
|
196
|
+
let base = cfg.link?.replace(/\/+$/, '');
|
|
197
|
+
if (!base) {
|
|
198
|
+
const ips = lanAddresses();
|
|
199
|
+
const ts = ips.find((ip) => /^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\./.test(ip));
|
|
200
|
+
base = `http://${ts ?? ips[0] ?? os.hostname()}:${port}${hubBase.replace(/\/$/, '')}`;
|
|
201
|
+
}
|
|
202
|
+
return `${base}/${cfg.includeToken && token ? `?token=${encodeURIComponent(token)}` : ''}`;
|
|
203
|
+
}
|
|
204
|
+
/** Send one notice to every configured channel. */
|
|
205
|
+
export async function send(cfg, n) {
|
|
206
|
+
const errors = [];
|
|
207
|
+
if (cfg.ntfy) {
|
|
208
|
+
try {
|
|
209
|
+
const u = new URL(cfg.ntfy);
|
|
210
|
+
const topic = u.pathname.replace(/^\/+|\/+$/g, '');
|
|
211
|
+
if (!topic)
|
|
212
|
+
throw new Error(`no topic in ${cfg.ntfy}`);
|
|
213
|
+
const tags = [n.approval ? 'raising_hand' : n.blocking ? 'warning' : n.kind === 'review' ? 'eyes' : n.kind === 'notes' ? 'speech_balloon' : 'question'];
|
|
214
|
+
const res = await fetch(u.origin, {
|
|
215
|
+
method: 'POST',
|
|
216
|
+
headers: { 'content-type': 'application/json', ...(cfg.ntfyToken ? { authorization: `Bearer ${cfg.ntfyToken}` } : {}) },
|
|
217
|
+
body: JSON.stringify({ topic, title: n.title, message: n.message, click: n.url, tags, priority: n.approval ? 5 : n.blocking ? 4 : 3 }),
|
|
218
|
+
signal: AbortSignal.timeout(10_000),
|
|
219
|
+
});
|
|
220
|
+
if (!res.ok)
|
|
221
|
+
throw new Error(`ntfy: ${res.status} ${await res.text().catch(() => '')}`.trim());
|
|
222
|
+
}
|
|
223
|
+
catch (e) {
|
|
224
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (cfg.webhook) {
|
|
228
|
+
try {
|
|
229
|
+
const res = await fetch(cfg.webhook, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(n), signal: AbortSignal.timeout(10_000) });
|
|
230
|
+
if (!res.ok)
|
|
231
|
+
throw new Error(`webhook: ${res.status}`);
|
|
232
|
+
}
|
|
233
|
+
catch (e) {
|
|
234
|
+
errors.push(e instanceof Error ? e.message : String(e));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (errors.length)
|
|
238
|
+
throw new Error(errors.join('; '));
|
|
239
|
+
}
|