hammoc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +272 -0
- package/bin/hammoc.js +59 -0
- package/package.json +86 -0
- package/packages/client/dist/assets/abap-DsBKuouk.js +1 -0
- package/packages/client/dist/assets/actionscript-3-D_z4Izcz.js +1 -0
- package/packages/client/dist/assets/ada-727ZlQH0.js +1 -0
- package/packages/client/dist/assets/andromeeda-C3khCPGq.js +1 -0
- package/packages/client/dist/assets/angular-html-LfdN0zeE.js +1 -0
- package/packages/client/dist/assets/angular-ts-CKsD7JZE.js +1 -0
- package/packages/client/dist/assets/apache-Dn00JSTd.js +1 -0
- package/packages/client/dist/assets/apex-COJ4H7py.js +1 -0
- package/packages/client/dist/assets/apl-BBq3IX1j.js +1 -0
- package/packages/client/dist/assets/applescript-Bu5BbsvL.js +1 -0
- package/packages/client/dist/assets/ara-7O62HKoU.js +1 -0
- package/packages/client/dist/assets/asciidoc-BPT9niGB.js +1 -0
- package/packages/client/dist/assets/asm-Dhn9LcZ4.js +1 -0
- package/packages/client/dist/assets/astro-CqkE3fuf.js +1 -0
- package/packages/client/dist/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/packages/client/dist/assets/awk-eg146-Ew.js +1 -0
- package/packages/client/dist/assets/ayu-dark-Cv9koXgw.js +1 -0
- package/packages/client/dist/assets/ballerina-Du268qiB.js +1 -0
- package/packages/client/dist/assets/bat-fje9CFhw.js +1 -0
- package/packages/client/dist/assets/beancount-BwXTMy5W.js +1 -0
- package/packages/client/dist/assets/berry-3xVqZejG.js +1 -0
- package/packages/client/dist/assets/bibtex-xW4inM5L.js +1 -0
- package/packages/client/dist/assets/bicep-DHo0CJ0O.js +1 -0
- package/packages/client/dist/assets/blade-a8OxSdnT.js +1 -0
- package/packages/client/dist/assets/bsl-Dgyn0ogV.js +1 -0
- package/packages/client/dist/assets/c-C3t2pwGQ.js +1 -0
- package/packages/client/dist/assets/cadence-DNquZEk8.js +1 -0
- package/packages/client/dist/assets/cairo--RitsXJZ.js +1 -0
- package/packages/client/dist/assets/catppuccin-frappe-CD_QflpE.js +1 -0
- package/packages/client/dist/assets/catppuccin-latte-DRW-0cLl.js +1 -0
- package/packages/client/dist/assets/catppuccin-macchiato-C-_shW-Y.js +1 -0
- package/packages/client/dist/assets/catppuccin-mocha-LGGdnPYs.js +1 -0
- package/packages/client/dist/assets/clarity-BHOwM8T6.js +1 -0
- package/packages/client/dist/assets/clojure-DxSadP1t.js +1 -0
- package/packages/client/dist/assets/cmake-DbXoA79R.js +1 -0
- package/packages/client/dist/assets/cobol-PTqiYgYu.js +1 -0
- package/packages/client/dist/assets/codeowners-Bp6g37R7.js +1 -0
- package/packages/client/dist/assets/codeql-sacFqUAJ.js +1 -0
- package/packages/client/dist/assets/coffee-dyiR41kL.js +1 -0
- package/packages/client/dist/assets/common-lisp-C7gG9l05.js +1 -0
- package/packages/client/dist/assets/coq-Dsg_Bt_b.js +1 -0
- package/packages/client/dist/assets/cpp-BksuvNSY.js +1 -0
- package/packages/client/dist/assets/crystal-DtDmRg-F.js +1 -0
- package/packages/client/dist/assets/csharp-D9R-vmeu.js +1 -0
- package/packages/client/dist/assets/css-BPhBrDlE.js +1 -0
- package/packages/client/dist/assets/csv-B0qRVHPH.js +1 -0
- package/packages/client/dist/assets/cue-DtFQj3wx.js +1 -0
- package/packages/client/dist/assets/cypher-m2LEI-9-.js +1 -0
- package/packages/client/dist/assets/d-BoXegm-a.js +1 -0
- package/packages/client/dist/assets/dark-plus-C3mMm8J8.js +1 -0
- package/packages/client/dist/assets/dart-B9wLZaAG.js +1 -0
- package/packages/client/dist/assets/dax-ClGRhx96.js +1 -0
- package/packages/client/dist/assets/desktop-DEIpsLCJ.js +1 -0
- package/packages/client/dist/assets/diff-BgYniUM_.js +1 -0
- package/packages/client/dist/assets/docker-COcR7UxN.js +1 -0
- package/packages/client/dist/assets/dotenv-BjQB5zDj.js +1 -0
- package/packages/client/dist/assets/dracula-BzJJZx-M.js +1 -0
- package/packages/client/dist/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/packages/client/dist/assets/dream-maker-C-nORZOA.js +1 -0
- package/packages/client/dist/assets/edge-D5gP-w-T.js +1 -0
- package/packages/client/dist/assets/elixir-CLiX3zqd.js +1 -0
- package/packages/client/dist/assets/elm-CmHSxxaM.js +1 -0
- package/packages/client/dist/assets/emacs-lisp-BX77sIaO.js +1 -0
- package/packages/client/dist/assets/erb-BYTLMnw6.js +1 -0
- package/packages/client/dist/assets/erlang-B-DoSBHF.js +1 -0
- package/packages/client/dist/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/packages/client/dist/assets/everforest-light-C8M2exoo.js +1 -0
- package/packages/client/dist/assets/fennel-bCA53EVm.js +1 -0
- package/packages/client/dist/assets/fish-w-ucz2PV.js +1 -0
- package/packages/client/dist/assets/fluent-Dayu4EKP.js +1 -0
- package/packages/client/dist/assets/fortran-fixed-form-TqA4NnZg.js +1 -0
- package/packages/client/dist/assets/fortran-free-form-DKXYxT9g.js +1 -0
- package/packages/client/dist/assets/fsharp-XplgxFYe.js +1 -0
- package/packages/client/dist/assets/gdresource-BHYsBjWJ.js +1 -0
- package/packages/client/dist/assets/gdscript-DfxzS6Rs.js +1 -0
- package/packages/client/dist/assets/gdshader-SKMF96pI.js +1 -0
- package/packages/client/dist/assets/genie-ajMbGru0.js +1 -0
- package/packages/client/dist/assets/gherkin--30QC5Em.js +1 -0
- package/packages/client/dist/assets/git-commit-i4q6IMui.js +1 -0
- package/packages/client/dist/assets/git-rebase-B-v9cOL2.js +1 -0
- package/packages/client/dist/assets/github-dark-DHJKELXO.js +1 -0
- package/packages/client/dist/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/packages/client/dist/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/packages/client/dist/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/packages/client/dist/assets/github-light-DAi9KRSo.js +1 -0
- package/packages/client/dist/assets/github-light-default-D7oLnXFd.js +1 -0
- package/packages/client/dist/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/packages/client/dist/assets/gleam-B430Bg39.js +1 -0
- package/packages/client/dist/assets/glimmer-js-D-cwc0-E.js +1 -0
- package/packages/client/dist/assets/glimmer-ts-pgjy16dm.js +1 -0
- package/packages/client/dist/assets/glsl-DBO2IWDn.js +1 -0
- package/packages/client/dist/assets/gnuplot-CM8KxXT1.js +1 -0
- package/packages/client/dist/assets/go-B1SYOhNW.js +1 -0
- package/packages/client/dist/assets/graphql-cDcHW_If.js +1 -0
- package/packages/client/dist/assets/groovy-DkBy-JyN.js +1 -0
- package/packages/client/dist/assets/hack-D1yCygmZ.js +1 -0
- package/packages/client/dist/assets/haml-B2EZWmdv.js +1 -0
- package/packages/client/dist/assets/handlebars-BQGss363.js +1 -0
- package/packages/client/dist/assets/haskell-BILxekzW.js +1 -0
- package/packages/client/dist/assets/haxe-C5wWYbrZ.js +1 -0
- package/packages/client/dist/assets/hcl-HzYwdGDm.js +1 -0
- package/packages/client/dist/assets/hjson-T-Tgc4AT.js +1 -0
- package/packages/client/dist/assets/hlsl-ifBTmRxC.js +1 -0
- package/packages/client/dist/assets/houston-DnULxvSX.js +1 -0
- package/packages/client/dist/assets/html-C2L_23MC.js +1 -0
- package/packages/client/dist/assets/html-derivative-CSfWNPLT.js +1 -0
- package/packages/client/dist/assets/http-FRrOvY1W.js +1 -0
- package/packages/client/dist/assets/hxml-TIA70rKU.js +1 -0
- package/packages/client/dist/assets/hy-BMj5Y0dO.js +1 -0
- package/packages/client/dist/assets/imba-bv_oIlVt.js +1 -0
- package/packages/client/dist/assets/index-Bzql1gnR.js +2 -0
- package/packages/client/dist/assets/index-DjQDxRju.css +32 -0
- package/packages/client/dist/assets/index-q3VZc6RP.js +1297 -0
- package/packages/client/dist/assets/ini-BjABl1g7.js +1 -0
- package/packages/client/dist/assets/java-xI-RfyKK.js +1 -0
- package/packages/client/dist/assets/javascript-ySlJ1b_l.js +1 -0
- package/packages/client/dist/assets/jinja-DGy0s7-h.js +1 -0
- package/packages/client/dist/assets/jison-BqZprYcd.js +1 -0
- package/packages/client/dist/assets/json-BQoSv7ci.js +1 -0
- package/packages/client/dist/assets/json5-w8dY5SsB.js +1 -0
- package/packages/client/dist/assets/jsonc-TU54ms6u.js +1 -0
- package/packages/client/dist/assets/jsonl-DREVFZK8.js +1 -0
- package/packages/client/dist/assets/jsonnet-BfivnA6A.js +1 -0
- package/packages/client/dist/assets/jssm-P4WzXJd0.js +1 -0
- package/packages/client/dist/assets/jsx-BAng5TT0.js +1 -0
- package/packages/client/dist/assets/julia-BBuGR-5E.js +1 -0
- package/packages/client/dist/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/packages/client/dist/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/packages/client/dist/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/packages/client/dist/assets/kotlin-B5lbUyaz.js +1 -0
- package/packages/client/dist/assets/kusto-mebxcVVE.js +1 -0
- package/packages/client/dist/assets/laserwave-DUszq2jm.js +1 -0
- package/packages/client/dist/assets/latex-C-cWTeAZ.js +1 -0
- package/packages/client/dist/assets/lean-XBlWyCtg.js +1 -0
- package/packages/client/dist/assets/less-BfCpw3nA.js +1 -0
- package/packages/client/dist/assets/light-plus-B7mTdjB0.js +1 -0
- package/packages/client/dist/assets/liquid-D3W5UaiH.js +1 -0
- package/packages/client/dist/assets/log-Cc5clBb7.js +1 -0
- package/packages/client/dist/assets/logo-IuBKFhSY.js +1 -0
- package/packages/client/dist/assets/lua-CvWAzNxB.js +1 -0
- package/packages/client/dist/assets/luau-Du5NY7AG.js +1 -0
- package/packages/client/dist/assets/make-Bvotw-X0.js +1 -0
- package/packages/client/dist/assets/markdown-UIAJJxZW.js +1 -0
- package/packages/client/dist/assets/marko-z0MBrx5-.js +1 -0
- package/packages/client/dist/assets/material-theme-D5KoaKCx.js +1 -0
- package/packages/client/dist/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/packages/client/dist/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/packages/client/dist/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/packages/client/dist/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/packages/client/dist/assets/matlab-D9-PGadD.js +1 -0
- package/packages/client/dist/assets/mdc-DB_EDNY_.js +1 -0
- package/packages/client/dist/assets/mdx-sdHcTMYB.js +1 -0
- package/packages/client/dist/assets/mermaid-Ci6OQyBP.js +1 -0
- package/packages/client/dist/assets/min-dark-CafNBF8u.js +1 -0
- package/packages/client/dist/assets/min-light-CTRr51gU.js +1 -0
- package/packages/client/dist/assets/mipsasm-BC5c_5Pe.js +1 -0
- package/packages/client/dist/assets/mojo-Tz6hzZYG.js +1 -0
- package/packages/client/dist/assets/monokai-D4h5O-jR.js +1 -0
- package/packages/client/dist/assets/move-DB_GagMm.js +1 -0
- package/packages/client/dist/assets/narrat-DLbgOhZU.js +1 -0
- package/packages/client/dist/assets/nextflow-B0XVJmRM.js +1 -0
- package/packages/client/dist/assets/nginx-D_VnBJ67.js +1 -0
- package/packages/client/dist/assets/night-owl-C39BiMTA.js +1 -0
- package/packages/client/dist/assets/nim-ZlGxZxc3.js +1 -0
- package/packages/client/dist/assets/nix-shcSOmrb.js +1 -0
- package/packages/client/dist/assets/nord-Ddv68eIx.js +1 -0
- package/packages/client/dist/assets/nushell-D4Tzg5kh.js +1 -0
- package/packages/client/dist/assets/objective-c-Deuh7S70.js +1 -0
- package/packages/client/dist/assets/objective-cpp-BUEGK8hf.js +1 -0
- package/packages/client/dist/assets/ocaml-BNioltXt.js +1 -0
- package/packages/client/dist/assets/one-dark-pro-GBQ2dnAY.js +1 -0
- package/packages/client/dist/assets/one-light-PoHY5YXO.js +1 -0
- package/packages/client/dist/assets/pascal-JqZropPD.js +1 -0
- package/packages/client/dist/assets/perl-CHQXSrWU.js +1 -0
- package/packages/client/dist/assets/php-B5ebYQev.js +1 -0
- package/packages/client/dist/assets/plastic-3e1v2bzS.js +1 -0
- package/packages/client/dist/assets/plsql-LKU2TuZ1.js +1 -0
- package/packages/client/dist/assets/po-BFLt1xDp.js +1 -0
- package/packages/client/dist/assets/poimandres-CS3Unz2-.js +1 -0
- package/packages/client/dist/assets/polar-DKykz6zU.js +1 -0
- package/packages/client/dist/assets/postcss-B3ZDOciz.js +1 -0
- package/packages/client/dist/assets/powerquery-CSHBycmS.js +1 -0
- package/packages/client/dist/assets/powershell-BIEUsx6d.js +1 -0
- package/packages/client/dist/assets/prisma-B48N-Iqd.js +1 -0
- package/packages/client/dist/assets/prolog-BY-TUvya.js +1 -0
- package/packages/client/dist/assets/proto-zocC4JxJ.js +1 -0
- package/packages/client/dist/assets/pug-CM9l7STV.js +1 -0
- package/packages/client/dist/assets/puppet-Cza_XSSt.js +1 -0
- package/packages/client/dist/assets/purescript-Bg-kzb6g.js +1 -0
- package/packages/client/dist/assets/python-DhUJRlN_.js +1 -0
- package/packages/client/dist/assets/qml-D8XfuvdV.js +1 -0
- package/packages/client/dist/assets/qmldir-C8lEn-DE.js +1 -0
- package/packages/client/dist/assets/qss-DhMKtDLN.js +1 -0
- package/packages/client/dist/assets/r-CwjWoCRV.js +1 -0
- package/packages/client/dist/assets/racket-CzouJOBO.js +1 -0
- package/packages/client/dist/assets/raku-B1bQXN8T.js +1 -0
- package/packages/client/dist/assets/razor-CNLDkMZG.js +1 -0
- package/packages/client/dist/assets/red-bN70gL4F.js +1 -0
- package/packages/client/dist/assets/reg-5LuOXUq_.js +1 -0
- package/packages/client/dist/assets/regexp-DWJ3fJO_.js +1 -0
- package/packages/client/dist/assets/rel-DJlmqQ1C.js +1 -0
- package/packages/client/dist/assets/riscv-QhoSD0DR.js +1 -0
- package/packages/client/dist/assets/rose-pine-CmCqftbK.js +1 -0
- package/packages/client/dist/assets/rose-pine-dawn-Ds-gbosJ.js +1 -0
- package/packages/client/dist/assets/rose-pine-moon-CjDtw9vr.js +1 -0
- package/packages/client/dist/assets/rst-4NLicBqY.js +1 -0
- package/packages/client/dist/assets/ruby-DeZ3UC14.js +1 -0
- package/packages/client/dist/assets/rust-Be6lgOlo.js +1 -0
- package/packages/client/dist/assets/sas-BmTFh92c.js +1 -0
- package/packages/client/dist/assets/sass-BJ4Li9vH.js +1 -0
- package/packages/client/dist/assets/scala-DQVVAn-B.js +1 -0
- package/packages/client/dist/assets/scheme-BJGe-b2p.js +1 -0
- package/packages/client/dist/assets/scss-C31hgJw-.js +1 -0
- package/packages/client/dist/assets/sdbl-BLhTXw86.js +1 -0
- package/packages/client/dist/assets/shaderlab-B7qAK45m.js +1 -0
- package/packages/client/dist/assets/shellscript-atvbtKCR.js +1 -0
- package/packages/client/dist/assets/shellsession-C_rIy8kc.js +1 -0
- package/packages/client/dist/assets/slack-dark-BthQWCQV.js +1 -0
- package/packages/client/dist/assets/slack-ochin-DqwNpetd.js +1 -0
- package/packages/client/dist/assets/smalltalk-DkLiglaE.js +1 -0
- package/packages/client/dist/assets/snazzy-light-Bw305WKR.js +1 -0
- package/packages/client/dist/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/packages/client/dist/assets/solarized-light-L9t79GZl.js +1 -0
- package/packages/client/dist/assets/solidity-C1w2a3ep.js +1 -0
- package/packages/client/dist/assets/soy-C-lX7w71.js +1 -0
- package/packages/client/dist/assets/sparql-bYkjHRlG.js +1 -0
- package/packages/client/dist/assets/splunk-Cf8iN4DR.js +1 -0
- package/packages/client/dist/assets/sql-COK4E0Yg.js +1 -0
- package/packages/client/dist/assets/ssh-config-BknIz3MU.js +1 -0
- package/packages/client/dist/assets/stata-DorPZHa4.js +1 -0
- package/packages/client/dist/assets/stylus-BeQkCIfX.js +1 -0
- package/packages/client/dist/assets/svelte-MSaWC3Je.js +1 -0
- package/packages/client/dist/assets/swift-BSxZ-RaX.js +1 -0
- package/packages/client/dist/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/packages/client/dist/assets/system-verilog-C7L56vO4.js +1 -0
- package/packages/client/dist/assets/systemd-CUnW07Te.js +1 -0
- package/packages/client/dist/assets/talonscript-C1XDQQGZ.js +1 -0
- package/packages/client/dist/assets/tasl-CQjiPCtT.js +1 -0
- package/packages/client/dist/assets/tcl-DQ1-QYvQ.js +1 -0
- package/packages/client/dist/assets/templ-dwX3ZSMB.js +1 -0
- package/packages/client/dist/assets/terraform-BbSNqyBO.js +1 -0
- package/packages/client/dist/assets/tex-rYs2v40G.js +1 -0
- package/packages/client/dist/assets/tokyo-night-DBQeEorK.js +1 -0
- package/packages/client/dist/assets/toml-CB2ApiWb.js +1 -0
- package/packages/client/dist/assets/ts-tags-CipyTH0X.js +1 -0
- package/packages/client/dist/assets/tsv-B_m7g4N7.js +1 -0
- package/packages/client/dist/assets/tsx-B6W0miNI.js +1 -0
- package/packages/client/dist/assets/turtle-BMR_PYu6.js +1 -0
- package/packages/client/dist/assets/twig-NC5TFiHP.js +1 -0
- package/packages/client/dist/assets/typescript-Dj6nwHGl.js +1 -0
- package/packages/client/dist/assets/typespec-BpWG_bgh.js +1 -0
- package/packages/client/dist/assets/typst-BVUVsWT6.js +1 -0
- package/packages/client/dist/assets/v-CAQ2eGtk.js +1 -0
- package/packages/client/dist/assets/vala-BFOHcciG.js +1 -0
- package/packages/client/dist/assets/vb-CdO5JTpU.js +1 -0
- package/packages/client/dist/assets/verilog-CJaU5se_.js +1 -0
- package/packages/client/dist/assets/vesper-BEBZ7ncR.js +1 -0
- package/packages/client/dist/assets/vhdl-DYoNaHQp.js +1 -0
- package/packages/client/dist/assets/viml-m4uW47V2.js +1 -0
- package/packages/client/dist/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/packages/client/dist/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/packages/client/dist/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/packages/client/dist/assets/vue-BuYVFjOK.js +1 -0
- package/packages/client/dist/assets/vue-html-xdeiXROB.js +1 -0
- package/packages/client/dist/assets/vyper-nyqBNV6O.js +1 -0
- package/packages/client/dist/assets/wasm-C6j12Q_x.js +1 -0
- package/packages/client/dist/assets/wasm-CG6Dc4jp.js +1 -0
- package/packages/client/dist/assets/wenyan-7A4Fjokl.js +1 -0
- package/packages/client/dist/assets/wgsl-CB0Krxn9.js +1 -0
- package/packages/client/dist/assets/wikitext-DCE3LsBG.js +1 -0
- package/packages/client/dist/assets/wolfram-C3FkfJm5.js +1 -0
- package/packages/client/dist/assets/xml-e3z08dGr.js +1 -0
- package/packages/client/dist/assets/xsl-Dd0NUgwM.js +1 -0
- package/packages/client/dist/assets/yaml-CVw76BM1.js +1 -0
- package/packages/client/dist/assets/zenscript-HnGAYVZD.js +1 -0
- package/packages/client/dist/assets/zig-BVz_zdnA.js +1 -0
- package/packages/client/dist/index.html +13 -0
- package/packages/server/dist/__tests__/i18n.test.d.ts +5 -0
- package/packages/server/dist/__tests__/i18n.test.d.ts.map +1 -0
- package/packages/server/dist/__tests__/i18n.test.js +31 -0
- package/packages/server/dist/__tests__/i18n.test.js.map +1 -0
- package/packages/server/dist/app.d.ts +15 -0
- package/packages/server/dist/app.d.ts.map +1 -0
- package/packages/server/dist/app.js +120 -0
- package/packages/server/dist/app.js.map +1 -0
- package/packages/server/dist/cli/passwordSetup.d.ts +5 -0
- package/packages/server/dist/cli/passwordSetup.d.ts.map +1 -0
- package/packages/server/dist/cli/passwordSetup.js +74 -0
- package/packages/server/dist/cli/passwordSetup.js.map +1 -0
- package/packages/server/dist/config/index.d.ts +81 -0
- package/packages/server/dist/config/index.d.ts.map +1 -0
- package/packages/server/dist/config/index.js +107 -0
- package/packages/server/dist/config/index.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/authController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/authController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/authController.test.js +198 -0
- package/packages/server/dist/controllers/__tests__/authController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/bmadStatusController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/bmadStatusController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/bmadStatusController.test.js +121 -0
- package/packages/server/dist/controllers/__tests__/bmadStatusController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/commandController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/commandController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/commandController.test.js +73 -0
- package/packages/server/dist/controllers/__tests__/commandController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/dashboardController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/dashboardController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/dashboardController.test.js +63 -0
- package/packages/server/dist/controllers/__tests__/dashboardController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/gitController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/gitController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/gitController.test.js +585 -0
- package/packages/server/dist/controllers/__tests__/gitController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/projectController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/projectController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/projectController.test.js +175 -0
- package/packages/server/dist/controllers/__tests__/projectController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/queueController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/queueController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/queueController.test.js +115 -0
- package/packages/server/dist/controllers/__tests__/queueController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/queueTemplateController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/queueTemplateController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/queueTemplateController.test.js +167 -0
- package/packages/server/dist/controllers/__tests__/queueTemplateController.test.js.map +1 -0
- package/packages/server/dist/controllers/__tests__/sessionController.test.d.ts +6 -0
- package/packages/server/dist/controllers/__tests__/sessionController.test.d.ts.map +1 -0
- package/packages/server/dist/controllers/__tests__/sessionController.test.js +113 -0
- package/packages/server/dist/controllers/__tests__/sessionController.test.js.map +1 -0
- package/packages/server/dist/controllers/authController.d.ts +30 -0
- package/packages/server/dist/controllers/authController.d.ts.map +1 -0
- package/packages/server/dist/controllers/authController.js +209 -0
- package/packages/server/dist/controllers/authController.js.map +1 -0
- package/packages/server/dist/controllers/bmadStatusController.d.ts +5 -0
- package/packages/server/dist/controllers/bmadStatusController.d.ts.map +1 -0
- package/packages/server/dist/controllers/bmadStatusController.js +53 -0
- package/packages/server/dist/controllers/bmadStatusController.js.map +1 -0
- package/packages/server/dist/controllers/boardController.d.ts +16 -0
- package/packages/server/dist/controllers/boardController.d.ts.map +1 -0
- package/packages/server/dist/controllers/boardController.js +295 -0
- package/packages/server/dist/controllers/boardController.js.map +1 -0
- package/packages/server/dist/controllers/cliController.d.ts +7 -0
- package/packages/server/dist/controllers/cliController.d.ts.map +1 -0
- package/packages/server/dist/controllers/cliController.js +27 -0
- package/packages/server/dist/controllers/cliController.js.map +1 -0
- package/packages/server/dist/controllers/commandController.d.ts +14 -0
- package/packages/server/dist/controllers/commandController.d.ts.map +1 -0
- package/packages/server/dist/controllers/commandController.js +31 -0
- package/packages/server/dist/controllers/commandController.js.map +1 -0
- package/packages/server/dist/controllers/dashboardController.d.ts +10 -0
- package/packages/server/dist/controllers/dashboardController.d.ts.map +1 -0
- package/packages/server/dist/controllers/dashboardController.js +23 -0
- package/packages/server/dist/controllers/dashboardController.js.map +1 -0
- package/packages/server/dist/controllers/fileSystemController.d.ts +54 -0
- package/packages/server/dist/controllers/fileSystemController.d.ts.map +1 -0
- package/packages/server/dist/controllers/fileSystemController.js +435 -0
- package/packages/server/dist/controllers/fileSystemController.js.map +1 -0
- package/packages/server/dist/controllers/gitController.d.ts +57 -0
- package/packages/server/dist/controllers/gitController.d.ts.map +1 -0
- package/packages/server/dist/controllers/gitController.js +494 -0
- package/packages/server/dist/controllers/gitController.js.map +1 -0
- package/packages/server/dist/controllers/projectController.d.ts +57 -0
- package/packages/server/dist/controllers/projectController.d.ts.map +1 -0
- package/packages/server/dist/controllers/projectController.js +358 -0
- package/packages/server/dist/controllers/projectController.js.map +1 -0
- package/packages/server/dist/controllers/queueController.d.ts +15 -0
- package/packages/server/dist/controllers/queueController.d.ts.map +1 -0
- package/packages/server/dist/controllers/queueController.js +131 -0
- package/packages/server/dist/controllers/queueController.js.map +1 -0
- package/packages/server/dist/controllers/queueTemplateController.d.ts +15 -0
- package/packages/server/dist/controllers/queueTemplateController.d.ts.map +1 -0
- package/packages/server/dist/controllers/queueTemplateController.js +187 -0
- package/packages/server/dist/controllers/queueTemplateController.js.map +1 -0
- package/packages/server/dist/controllers/serverController.d.ts +14 -0
- package/packages/server/dist/controllers/serverController.d.ts.map +1 -0
- package/packages/server/dist/controllers/serverController.js +164 -0
- package/packages/server/dist/controllers/serverController.js.map +1 -0
- package/packages/server/dist/controllers/sessionController.d.ts +39 -0
- package/packages/server/dist/controllers/sessionController.d.ts.map +1 -0
- package/packages/server/dist/controllers/sessionController.js +230 -0
- package/packages/server/dist/controllers/sessionController.js.map +1 -0
- package/packages/server/dist/dev.d.ts +2 -0
- package/packages/server/dist/dev.d.ts.map +1 -0
- package/packages/server/dist/dev.js +8 -0
- package/packages/server/dist/dev.js.map +1 -0
- package/packages/server/dist/handlers/__tests__/websocket.auth.test.d.ts +7 -0
- package/packages/server/dist/handlers/__tests__/websocket.auth.test.d.ts.map +1 -0
- package/packages/server/dist/handlers/__tests__/websocket.auth.test.js +125 -0
- package/packages/server/dist/handlers/__tests__/websocket.auth.test.js.map +1 -0
- package/packages/server/dist/handlers/__tests__/websocket.test.d.ts +2 -0
- package/packages/server/dist/handlers/__tests__/websocket.test.d.ts.map +1 -0
- package/packages/server/dist/handlers/__tests__/websocket.test.js +1316 -0
- package/packages/server/dist/handlers/__tests__/websocket.test.js.map +1 -0
- package/packages/server/dist/handlers/streamCallbacks.d.ts +52 -0
- package/packages/server/dist/handlers/streamCallbacks.d.ts.map +1 -0
- package/packages/server/dist/handlers/streamCallbacks.js +107 -0
- package/packages/server/dist/handlers/streamCallbacks.js.map +1 -0
- package/packages/server/dist/handlers/websocket.d.ts +82 -0
- package/packages/server/dist/handlers/websocket.d.ts.map +1 -0
- package/packages/server/dist/handlers/websocket.js +1041 -0
- package/packages/server/dist/handlers/websocket.js.map +1 -0
- package/packages/server/dist/i18n.d.ts +7 -0
- package/packages/server/dist/i18n.d.ts.map +1 -0
- package/packages/server/dist/i18n.js +32 -0
- package/packages/server/dist/i18n.js.map +1 -0
- package/packages/server/dist/index.d.ts +2 -0
- package/packages/server/dist/index.d.ts.map +1 -0
- package/packages/server/dist/index.js +114 -0
- package/packages/server/dist/index.js.map +1 -0
- package/packages/server/dist/locales/en/server.json +303 -0
- package/packages/server/dist/locales/es/server.json +303 -0
- package/packages/server/dist/locales/ja/server.json +303 -0
- package/packages/server/dist/locales/ko/server.json +303 -0
- package/packages/server/dist/locales/pt/server.json +303 -0
- package/packages/server/dist/locales/zh-CN/server.json +303 -0
- package/packages/server/dist/middleware/__tests__/auth.test.d.ts +6 -0
- package/packages/server/dist/middleware/__tests__/auth.test.d.ts.map +1 -0
- package/packages/server/dist/middleware/__tests__/auth.test.js +146 -0
- package/packages/server/dist/middleware/__tests__/auth.test.js.map +1 -0
- package/packages/server/dist/middleware/__tests__/i18n.test.d.ts +5 -0
- package/packages/server/dist/middleware/__tests__/i18n.test.d.ts.map +1 -0
- package/packages/server/dist/middleware/__tests__/i18n.test.js +96 -0
- package/packages/server/dist/middleware/__tests__/i18n.test.js.map +1 -0
- package/packages/server/dist/middleware/__tests__/pathGuard.test.d.ts +6 -0
- package/packages/server/dist/middleware/__tests__/pathGuard.test.d.ts.map +1 -0
- package/packages/server/dist/middleware/__tests__/pathGuard.test.js +73 -0
- package/packages/server/dist/middleware/__tests__/pathGuard.test.js.map +1 -0
- package/packages/server/dist/middleware/__tests__/session.test.d.ts +6 -0
- package/packages/server/dist/middleware/__tests__/session.test.d.ts.map +1 -0
- package/packages/server/dist/middleware/__tests__/session.test.js +33 -0
- package/packages/server/dist/middleware/__tests__/session.test.js.map +1 -0
- package/packages/server/dist/middleware/auth.d.ts +18 -0
- package/packages/server/dist/middleware/auth.d.ts.map +1 -0
- package/packages/server/dist/middleware/auth.js +52 -0
- package/packages/server/dist/middleware/auth.js.map +1 -0
- package/packages/server/dist/middleware/i18n.d.ts +17 -0
- package/packages/server/dist/middleware/i18n.d.ts.map +1 -0
- package/packages/server/dist/middleware/i18n.js +42 -0
- package/packages/server/dist/middleware/i18n.js.map +1 -0
- package/packages/server/dist/middleware/pathGuard.d.ts +15 -0
- package/packages/server/dist/middleware/pathGuard.d.ts.map +1 -0
- package/packages/server/dist/middleware/pathGuard.js +41 -0
- package/packages/server/dist/middleware/pathGuard.js.map +1 -0
- package/packages/server/dist/middleware/session.d.ts +18 -0
- package/packages/server/dist/middleware/session.d.ts.map +1 -0
- package/packages/server/dist/middleware/session.js +35 -0
- package/packages/server/dist/middleware/session.js.map +1 -0
- package/packages/server/dist/routes/__tests__/auth.integration.test.d.ts +6 -0
- package/packages/server/dist/routes/__tests__/auth.integration.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/auth.integration.test.js +111 -0
- package/packages/server/dist/routes/__tests__/auth.integration.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/auth.test.d.ts +6 -0
- package/packages/server/dist/routes/__tests__/auth.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/auth.test.js +155 -0
- package/packages/server/dist/routes/__tests__/auth.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/board.test.d.ts +2 -0
- package/packages/server/dist/routes/__tests__/board.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/board.test.js +201 -0
- package/packages/server/dist/routes/__tests__/board.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/cli.test.d.ts +2 -0
- package/packages/server/dist/routes/__tests__/cli.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/cli.test.js +121 -0
- package/packages/server/dist/routes/__tests__/cli.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/commands.test.d.ts +6 -0
- package/packages/server/dist/routes/__tests__/commands.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/commands.test.js +74 -0
- package/packages/server/dist/routes/__tests__/commands.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/projects.integration.test.d.ts +9 -0
- package/packages/server/dist/routes/__tests__/projects.integration.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/projects.integration.test.js +517 -0
- package/packages/server/dist/routes/__tests__/projects.integration.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/projects.test.d.ts +7 -0
- package/packages/server/dist/routes/__tests__/projects.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/projects.test.js +361 -0
- package/packages/server/dist/routes/__tests__/projects.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/sessions.integration.test.d.ts +8 -0
- package/packages/server/dist/routes/__tests__/sessions.integration.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/sessions.integration.test.js +287 -0
- package/packages/server/dist/routes/__tests__/sessions.integration.test.js.map +1 -0
- package/packages/server/dist/routes/__tests__/sessions.test.d.ts +6 -0
- package/packages/server/dist/routes/__tests__/sessions.test.d.ts.map +1 -0
- package/packages/server/dist/routes/__tests__/sessions.test.js +261 -0
- package/packages/server/dist/routes/__tests__/sessions.test.js.map +1 -0
- package/packages/server/dist/routes/auth.d.ts +8 -0
- package/packages/server/dist/routes/auth.d.ts.map +1 -0
- package/packages/server/dist/routes/auth.js +18 -0
- package/packages/server/dist/routes/auth.js.map +1 -0
- package/packages/server/dist/routes/bmadStatus.d.ts +3 -0
- package/packages/server/dist/routes/bmadStatus.d.ts.map +1 -0
- package/packages/server/dist/routes/bmadStatus.js +7 -0
- package/packages/server/dist/routes/bmadStatus.js.map +1 -0
- package/packages/server/dist/routes/board.d.ts +3 -0
- package/packages/server/dist/routes/board.d.ts.map +1 -0
- package/packages/server/dist/routes/board.js +16 -0
- package/packages/server/dist/routes/board.js.map +1 -0
- package/packages/server/dist/routes/cli.d.ts +3 -0
- package/packages/server/dist/routes/cli.d.ts.map +1 -0
- package/packages/server/dist/routes/cli.js +10 -0
- package/packages/server/dist/routes/cli.js.map +1 -0
- package/packages/server/dist/routes/commands.d.ts +8 -0
- package/packages/server/dist/routes/commands.d.ts.map +1 -0
- package/packages/server/dist/routes/commands.js +12 -0
- package/packages/server/dist/routes/commands.js.map +1 -0
- package/packages/server/dist/routes/dashboard.d.ts +3 -0
- package/packages/server/dist/routes/dashboard.d.ts.map +1 -0
- package/packages/server/dist/routes/dashboard.js +7 -0
- package/packages/server/dist/routes/dashboard.js.map +1 -0
- package/packages/server/dist/routes/debug.d.ts +6 -0
- package/packages/server/dist/routes/debug.d.ts.map +1 -0
- package/packages/server/dist/routes/debug.js +59 -0
- package/packages/server/dist/routes/debug.js.map +1 -0
- package/packages/server/dist/routes/fileSystem.d.ts +8 -0
- package/packages/server/dist/routes/fileSystem.d.ts.map +1 -0
- package/packages/server/dist/routes/fileSystem.js +24 -0
- package/packages/server/dist/routes/fileSystem.js.map +1 -0
- package/packages/server/dist/routes/git.d.ts +8 -0
- package/packages/server/dist/routes/git.d.ts.map +1 -0
- package/packages/server/dist/routes/git.js +24 -0
- package/packages/server/dist/routes/git.js.map +1 -0
- package/packages/server/dist/routes/preferences.d.ts +7 -0
- package/packages/server/dist/routes/preferences.d.ts.map +1 -0
- package/packages/server/dist/routes/preferences.js +112 -0
- package/packages/server/dist/routes/preferences.js.map +1 -0
- package/packages/server/dist/routes/projects.d.ts +9 -0
- package/packages/server/dist/routes/projects.d.ts.map +1 -0
- package/packages/server/dist/routes/projects.js +84 -0
- package/packages/server/dist/routes/projects.js.map +1 -0
- package/packages/server/dist/routes/queue.d.ts +7 -0
- package/packages/server/dist/routes/queue.d.ts.map +1 -0
- package/packages/server/dist/routes/queue.js +22 -0
- package/packages/server/dist/routes/queue.js.map +1 -0
- package/packages/server/dist/routes/server.d.ts +3 -0
- package/packages/server/dist/routes/server.d.ts.map +1 -0
- package/packages/server/dist/routes/server.js +10 -0
- package/packages/server/dist/routes/server.js.map +1 -0
- package/packages/server/dist/routes/sessions.d.ts +8 -0
- package/packages/server/dist/routes/sessions.d.ts.map +1 -0
- package/packages/server/dist/routes/sessions.js +47 -0
- package/packages/server/dist/routes/sessions.js.map +1 -0
- package/packages/server/dist/services/__tests__/authConfigService.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/authConfigService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/authConfigService.test.js +274 -0
- package/packages/server/dist/services/__tests__/authConfigService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/bmadStatusService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/bmadStatusService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/bmadStatusService.test.js +456 -0
- package/packages/server/dist/services/__tests__/bmadStatusService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/chatService.integration.test.d.ts +32 -0
- package/packages/server/dist/services/__tests__/chatService.integration.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/chatService.integration.test.js +97 -0
- package/packages/server/dist/services/__tests__/chatService.integration.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/chatService.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/chatService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/chatService.test.js +517 -0
- package/packages/server/dist/services/__tests__/chatService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/cliService.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/cliService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/cliService.test.js +172 -0
- package/packages/server/dist/services/__tests__/cliService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/commandService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/commandService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/commandService.test.js +525 -0
- package/packages/server/dist/services/__tests__/commandService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/dashboardService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/dashboardService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/dashboardService.test.js +248 -0
- package/packages/server/dist/services/__tests__/dashboardService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/fileSystemService.test.d.ts +7 -0
- package/packages/server/dist/services/__tests__/fileSystemService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/fileSystemService.test.js +348 -0
- package/packages/server/dist/services/__tests__/fileSystemService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/gitService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/gitService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/gitService.test.js +340 -0
- package/packages/server/dist/services/__tests__/gitService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/historyParser.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/historyParser.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/historyParser.test.js +471 -0
- package/packages/server/dist/services/__tests__/historyParser.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/issueService.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/issueService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/issueService.test.js +382 -0
- package/packages/server/dist/services/__tests__/issueService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/notificationService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/notificationService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/notificationService.test.js +131 -0
- package/packages/server/dist/services/__tests__/notificationService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/preferencesService.telegram.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/preferencesService.telegram.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/preferencesService.telegram.test.js +101 -0
- package/packages/server/dist/services/__tests__/preferencesService.telegram.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/preferencesService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/preferencesService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/preferencesService.test.js +68 -0
- package/packages/server/dist/services/__tests__/preferencesService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/projectService.settings.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/projectService.settings.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/projectService.settings.test.js +101 -0
- package/packages/server/dist/services/__tests__/projectService.settings.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/projectService.test.d.ts +7 -0
- package/packages/server/dist/services/__tests__/projectService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/projectService.test.js +618 -0
- package/packages/server/dist/services/__tests__/projectService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/ptyService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/ptyService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/ptyService.test.js +289 -0
- package/packages/server/dist/services/__tests__/ptyService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/queueService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/queueService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/queueService.test.js +477 -0
- package/packages/server/dist/services/__tests__/queueService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/queueTemplateService.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/queueTemplateService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/queueTemplateService.test.js +129 -0
- package/packages/server/dist/services/__tests__/queueTemplateService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/rateLimiter.test.d.ts +6 -0
- package/packages/server/dist/services/__tests__/rateLimiter.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/rateLimiter.test.js +123 -0
- package/packages/server/dist/services/__tests__/rateLimiter.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/sessionService.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/sessionService.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/sessionService.test.js +349 -0
- package/packages/server/dist/services/__tests__/sessionService.test.js.map +1 -0
- package/packages/server/dist/services/__tests__/streamHandler.test.d.ts +2 -0
- package/packages/server/dist/services/__tests__/streamHandler.test.d.ts.map +1 -0
- package/packages/server/dist/services/__tests__/streamHandler.test.js +654 -0
- package/packages/server/dist/services/__tests__/streamHandler.test.js.map +1 -0
- package/packages/server/dist/services/authConfigService.d.ts +56 -0
- package/packages/server/dist/services/authConfigService.d.ts.map +1 -0
- package/packages/server/dist/services/authConfigService.js +186 -0
- package/packages/server/dist/services/authConfigService.js.map +1 -0
- package/packages/server/dist/services/bmadStatusService.d.ts +56 -0
- package/packages/server/dist/services/bmadStatusService.d.ts.map +1 -0
- package/packages/server/dist/services/bmadStatusService.js +438 -0
- package/packages/server/dist/services/bmadStatusService.js.map +1 -0
- package/packages/server/dist/services/chatService.d.ts +78 -0
- package/packages/server/dist/services/chatService.d.ts.map +1 -0
- package/packages/server/dist/services/chatService.js +335 -0
- package/packages/server/dist/services/chatService.js.map +1 -0
- package/packages/server/dist/services/cliService.d.ts +29 -0
- package/packages/server/dist/services/cliService.d.ts.map +1 -0
- package/packages/server/dist/services/cliService.js +101 -0
- package/packages/server/dist/services/cliService.js.map +1 -0
- package/packages/server/dist/services/commandService.d.ts +84 -0
- package/packages/server/dist/services/commandService.d.ts.map +1 -0
- package/packages/server/dist/services/commandService.js +322 -0
- package/packages/server/dist/services/commandService.js.map +1 -0
- package/packages/server/dist/services/dashboardService.d.ts +23 -0
- package/packages/server/dist/services/dashboardService.d.ts.map +1 -0
- package/packages/server/dist/services/dashboardService.js +81 -0
- package/packages/server/dist/services/dashboardService.js.map +1 -0
- package/packages/server/dist/services/fileSystemService.d.ts +105 -0
- package/packages/server/dist/services/fileSystemService.d.ts.map +1 -0
- package/packages/server/dist/services/fileSystemService.js +498 -0
- package/packages/server/dist/services/fileSystemService.js.map +1 -0
- package/packages/server/dist/services/gitService.d.ts +25 -0
- package/packages/server/dist/services/gitService.d.ts.map +1 -0
- package/packages/server/dist/services/gitService.js +230 -0
- package/packages/server/dist/services/gitService.js.map +1 -0
- package/packages/server/dist/services/historyParser.d.ts +45 -0
- package/packages/server/dist/services/historyParser.d.ts.map +1 -0
- package/packages/server/dist/services/historyParser.js +315 -0
- package/packages/server/dist/services/historyParser.js.map +1 -0
- package/packages/server/dist/services/issueService.d.ts +79 -0
- package/packages/server/dist/services/issueService.d.ts.map +1 -0
- package/packages/server/dist/services/issueService.js +708 -0
- package/packages/server/dist/services/issueService.js.map +1 -0
- package/packages/server/dist/services/notificationService.d.ts +78 -0
- package/packages/server/dist/services/notificationService.d.ts.map +1 -0
- package/packages/server/dist/services/notificationService.js +246 -0
- package/packages/server/dist/services/notificationService.js.map +1 -0
- package/packages/server/dist/services/preferencesService.d.ts +35 -0
- package/packages/server/dist/services/preferencesService.d.ts.map +1 -0
- package/packages/server/dist/services/preferencesService.js +121 -0
- package/packages/server/dist/services/preferencesService.js.map +1 -0
- package/packages/server/dist/services/projectService.d.ts +210 -0
- package/packages/server/dist/services/projectService.d.ts.map +1 -0
- package/packages/server/dist/services/projectService.js +892 -0
- package/packages/server/dist/services/projectService.js.map +1 -0
- package/packages/server/dist/services/ptyService.d.ts +83 -0
- package/packages/server/dist/services/ptyService.d.ts.map +1 -0
- package/packages/server/dist/services/ptyService.js +214 -0
- package/packages/server/dist/services/ptyService.js.map +1 -0
- package/packages/server/dist/services/queueService.d.ts +93 -0
- package/packages/server/dist/services/queueService.d.ts.map +1 -0
- package/packages/server/dist/services/queueService.js +598 -0
- package/packages/server/dist/services/queueService.js.map +1 -0
- package/packages/server/dist/services/queueTemplateService.d.ts +12 -0
- package/packages/server/dist/services/queueTemplateService.d.ts.map +1 -0
- package/packages/server/dist/services/queueTemplateService.js +73 -0
- package/packages/server/dist/services/queueTemplateService.js.map +1 -0
- package/packages/server/dist/services/rateLimitProbeService.d.ts +56 -0
- package/packages/server/dist/services/rateLimitProbeService.d.ts.map +1 -0
- package/packages/server/dist/services/rateLimitProbeService.js +227 -0
- package/packages/server/dist/services/rateLimitProbeService.js.map +1 -0
- package/packages/server/dist/services/rateLimiter.d.ts +32 -0
- package/packages/server/dist/services/rateLimiter.d.ts.map +1 -0
- package/packages/server/dist/services/rateLimiter.js +60 -0
- package/packages/server/dist/services/rateLimiter.js.map +1 -0
- package/packages/server/dist/services/sessionService.d.ts +152 -0
- package/packages/server/dist/services/sessionService.d.ts.map +1 -0
- package/packages/server/dist/services/sessionService.js +672 -0
- package/packages/server/dist/services/sessionService.js.map +1 -0
- package/packages/server/dist/services/streamHandler.d.ts +145 -0
- package/packages/server/dist/services/streamHandler.d.ts.map +1 -0
- package/packages/server/dist/services/streamHandler.js +753 -0
- package/packages/server/dist/services/streamHandler.js.map +1 -0
- package/packages/server/dist/utils/__tests__/networkUtils.test.d.ts +6 -0
- package/packages/server/dist/utils/__tests__/networkUtils.test.d.ts.map +1 -0
- package/packages/server/dist/utils/__tests__/networkUtils.test.js +106 -0
- package/packages/server/dist/utils/__tests__/networkUtils.test.js.map +1 -0
- package/packages/server/dist/utils/__tests__/pathUtils.test.d.ts +6 -0
- package/packages/server/dist/utils/__tests__/pathUtils.test.d.ts.map +1 -0
- package/packages/server/dist/utils/__tests__/pathUtils.test.js +111 -0
- package/packages/server/dist/utils/__tests__/pathUtils.test.js.map +1 -0
- package/packages/server/dist/utils/errors.d.ts +79 -0
- package/packages/server/dist/utils/errors.d.ts.map +1 -0
- package/packages/server/dist/utils/errors.js +167 -0
- package/packages/server/dist/utils/errors.js.map +1 -0
- package/packages/server/dist/utils/logger.d.ts +28 -0
- package/packages/server/dist/utils/logger.d.ts.map +1 -0
- package/packages/server/dist/utils/logger.js +87 -0
- package/packages/server/dist/utils/logger.js.map +1 -0
- package/packages/server/dist/utils/networkUtils.d.ts +26 -0
- package/packages/server/dist/utils/networkUtils.d.ts.map +1 -0
- package/packages/server/dist/utils/networkUtils.js +70 -0
- package/packages/server/dist/utils/networkUtils.js.map +1 -0
- package/packages/server/dist/utils/pathUtils.d.ts +30 -0
- package/packages/server/dist/utils/pathUtils.d.ts.map +1 -0
- package/packages/server/dist/utils/pathUtils.js +81 -0
- package/packages/server/dist/utils/pathUtils.js.map +1 -0
- package/packages/server/package.json +48 -0
- package/packages/shared/dist/constants/errorCodes.d.ts +31 -0
- package/packages/shared/dist/constants/errorCodes.d.ts.map +1 -0
- package/packages/shared/dist/constants/errorCodes.js +33 -0
- package/packages/shared/dist/constants/errorCodes.js.map +1 -0
- package/packages/shared/dist/index.d.ts +26 -0
- package/packages/shared/dist/index.d.ts.map +1 -0
- package/packages/shared/dist/index.js +48 -0
- package/packages/shared/dist/index.js.map +1 -0
- package/packages/shared/dist/types/auth.d.ts +159 -0
- package/packages/shared/dist/types/auth.d.ts.map +1 -0
- package/packages/shared/dist/types/auth.js +74 -0
- package/packages/shared/dist/types/auth.js.map +1 -0
- package/packages/shared/dist/types/bmadStatus.d.ts +97 -0
- package/packages/shared/dist/types/bmadStatus.d.ts.map +1 -0
- package/packages/shared/dist/types/bmadStatus.js +18 -0
- package/packages/shared/dist/types/bmadStatus.js.map +1 -0
- package/packages/shared/dist/types/board.d.ts +68 -0
- package/packages/shared/dist/types/board.d.ts.map +1 -0
- package/packages/shared/dist/types/board.js +108 -0
- package/packages/shared/dist/types/board.js.map +1 -0
- package/packages/shared/dist/types/cli.d.ts +34 -0
- package/packages/shared/dist/types/cli.d.ts.map +1 -0
- package/packages/shared/dist/types/cli.js +10 -0
- package/packages/shared/dist/types/cli.js.map +1 -0
- package/packages/shared/dist/types/command.d.ts +39 -0
- package/packages/shared/dist/types/command.d.ts.map +1 -0
- package/packages/shared/dist/types/command.js +6 -0
- package/packages/shared/dist/types/command.js.map +1 -0
- package/packages/shared/dist/types/dashboard.d.ts +15 -0
- package/packages/shared/dist/types/dashboard.d.ts.map +1 -0
- package/packages/shared/dist/types/dashboard.js +3 -0
- package/packages/shared/dist/types/dashboard.js.map +1 -0
- package/packages/shared/dist/types/fileSystem.d.ts +175 -0
- package/packages/shared/dist/types/fileSystem.d.ts.map +1 -0
- package/packages/shared/dist/types/fileSystem.js +62 -0
- package/packages/shared/dist/types/fileSystem.js.map +1 -0
- package/packages/shared/dist/types/git.d.ts +81 -0
- package/packages/shared/dist/types/git.d.ts.map +1 -0
- package/packages/shared/dist/types/git.js +34 -0
- package/packages/shared/dist/types/git.js.map +1 -0
- package/packages/shared/dist/types/history.d.ts +103 -0
- package/packages/shared/dist/types/history.d.ts.map +1 -0
- package/packages/shared/dist/types/history.js +6 -0
- package/packages/shared/dist/types/history.js.map +1 -0
- package/packages/shared/dist/types/logger.d.ts +18 -0
- package/packages/shared/dist/types/logger.d.ts.map +1 -0
- package/packages/shared/dist/types/logger.js +29 -0
- package/packages/shared/dist/types/logger.js.map +1 -0
- package/packages/shared/dist/types/message.d.ts +34 -0
- package/packages/shared/dist/types/message.d.ts.map +1 -0
- package/packages/shared/dist/types/message.js +14 -0
- package/packages/shared/dist/types/message.js.map +1 -0
- package/packages/shared/dist/types/preferences.d.ts +95 -0
- package/packages/shared/dist/types/preferences.d.ts.map +1 -0
- package/packages/shared/dist/types/preferences.js +15 -0
- package/packages/shared/dist/types/preferences.js.map +1 -0
- package/packages/shared/dist/types/project.d.ts +205 -0
- package/packages/shared/dist/types/project.d.ts.map +1 -0
- package/packages/shared/dist/types/project.js +64 -0
- package/packages/shared/dist/types/project.js.map +1 -0
- package/packages/shared/dist/types/queue.d.ts +94 -0
- package/packages/shared/dist/types/queue.d.ts.map +1 -0
- package/packages/shared/dist/types/queue.js +2 -0
- package/packages/shared/dist/types/queue.js.map +1 -0
- package/packages/shared/dist/types/sdk.d.ts +156 -0
- package/packages/shared/dist/types/sdk.d.ts.map +1 -0
- package/packages/shared/dist/types/sdk.js +13 -0
- package/packages/shared/dist/types/sdk.js.map +1 -0
- package/packages/shared/dist/types/session.d.ts +149 -0
- package/packages/shared/dist/types/session.d.ts.map +1 -0
- package/packages/shared/dist/types/session.js +51 -0
- package/packages/shared/dist/types/session.js.map +1 -0
- package/packages/shared/dist/types/streaming.d.ts +269 -0
- package/packages/shared/dist/types/streaming.d.ts.map +1 -0
- package/packages/shared/dist/types/streaming.js +43 -0
- package/packages/shared/dist/types/streaming.js.map +1 -0
- package/packages/shared/dist/types/terminal.d.ts +93 -0
- package/packages/shared/dist/types/terminal.d.ts.map +1 -0
- package/packages/shared/dist/types/terminal.js +38 -0
- package/packages/shared/dist/types/terminal.js.map +1 -0
- package/packages/shared/dist/types/websocket.d.ts +196 -0
- package/packages/shared/dist/types/websocket.d.ts.map +1 -0
- package/packages/shared/dist/types/websocket.js +7 -0
- package/packages/shared/dist/types/websocket.js.map +1 -0
- package/packages/shared/dist/utils/__tests__/queueParser.test.d.ts +2 -0
- package/packages/shared/dist/utils/__tests__/queueParser.test.d.ts.map +1 -0
- package/packages/shared/dist/utils/__tests__/queueParser.test.js +246 -0
- package/packages/shared/dist/utils/__tests__/queueParser.test.js.map +1 -0
- package/packages/shared/dist/utils/__tests__/queueTemplateUtils.test.d.ts +6 -0
- package/packages/shared/dist/utils/__tests__/queueTemplateUtils.test.d.ts.map +1 -0
- package/packages/shared/dist/utils/__tests__/queueTemplateUtils.test.js +138 -0
- package/packages/shared/dist/utils/__tests__/queueTemplateUtils.test.js.map +1 -0
- package/packages/shared/dist/utils/queueParser.d.ts +3 -0
- package/packages/shared/dist/utils/queueParser.d.ts.map +1 -0
- package/packages/shared/dist/utils/queueParser.js +165 -0
- package/packages/shared/dist/utils/queueParser.js.map +1 -0
- package/packages/shared/dist/utils/queueTemplateUtils.d.ts +17 -0
- package/packages/shared/dist/utils/queueTemplateUtils.d.ts.map +1 -0
- package/packages/shared/dist/utils/queueTemplateUtils.js +65 -0
- package/packages/shared/dist/utils/queueTemplateUtils.js.map +1 -0
- package/packages/shared/package.json +23 -0
- package/scripts/postinstall.cjs +23 -0
|
@@ -0,0 +1,1041 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Handler for Socket.io
|
|
3
|
+
* Story 1.4: WebSocket Server Setup
|
|
4
|
+
* Story 1.5: Chat event handler with streaming
|
|
5
|
+
* Story 4.6: Timeout handling and error management
|
|
6
|
+
*/
|
|
7
|
+
import { Server as SocketIOServer } from 'socket.io';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import { ERROR_CODES, IMAGE_CONSTRAINTS, parseQueueScript, TERMINAL_ERRORS } from '@hammoc/shared';
|
|
10
|
+
import i18next from '../i18n.js';
|
|
11
|
+
import { SUPPORTED_LANGUAGES } from '@hammoc/shared';
|
|
12
|
+
import { isLocalIP, extractClientIP } from '../utils/networkUtils.js';
|
|
13
|
+
import { ChatService } from '../services/chatService.js';
|
|
14
|
+
import { SessionService } from '../services/sessionService.js';
|
|
15
|
+
import { parseSDKError, AbortedError } from '../utils/errors.js';
|
|
16
|
+
import { createSessionMiddleware } from '../middleware/session.js';
|
|
17
|
+
import { config } from '../config/index.js';
|
|
18
|
+
import { notificationService, formatAskQuestionPrompt } from '../services/notificationService.js';
|
|
19
|
+
import { preferencesService } from '../services/preferencesService.js';
|
|
20
|
+
import { getOrCreateQueueService, getQueueInstances } from '../controllers/queueController.js';
|
|
21
|
+
import { createLogger } from '../utils/logger.js';
|
|
22
|
+
import { buildStreamCallbacks } from './streamCallbacks.js';
|
|
23
|
+
import { rateLimitProbeService } from '../services/rateLimitProbeService.js';
|
|
24
|
+
import { ptyService } from '../services/ptyService.js';
|
|
25
|
+
import { projectService } from '../services/projectService.js';
|
|
26
|
+
import { dashboardService } from '../services/dashboardService.js';
|
|
27
|
+
const log = createLogger('websocket');
|
|
28
|
+
// Alias for concise usage in guards
|
|
29
|
+
const queueInstances = getQueueInstances;
|
|
30
|
+
// Socket-to-terminal mapping: socket.id → Set of terminalIds (Story 17.1)
|
|
31
|
+
const socketTerminals = new Map();
|
|
32
|
+
// Story 20.1: Session-to-project mapping for dashboard triggers
|
|
33
|
+
const sessionProjectMap = new Map();
|
|
34
|
+
// Story 20.1: Per-project debounced dashboard status change broadcaster
|
|
35
|
+
const dashboardDebounceTimers = new Map();
|
|
36
|
+
function triggerDashboardStatusChange(projectSlug) {
|
|
37
|
+
const existing = dashboardDebounceTimers.get(projectSlug);
|
|
38
|
+
if (existing)
|
|
39
|
+
clearTimeout(existing);
|
|
40
|
+
dashboardDebounceTimers.set(projectSlug, setTimeout(async () => {
|
|
41
|
+
dashboardDebounceTimers.delete(projectSlug);
|
|
42
|
+
try {
|
|
43
|
+
const status = await dashboardService.getProjectStatus(projectSlug);
|
|
44
|
+
io.to('dashboard').emit('dashboard:status-change', { projectSlug, status });
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
log.error(`Failed to broadcast dashboard status for ${projectSlug}:`, err);
|
|
48
|
+
}
|
|
49
|
+
}, 300));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Check terminal access for a socket connection.
|
|
53
|
+
* Fail-closed: denies access on any error (e.g., preferences file read failure).
|
|
54
|
+
* Story 17.5: Terminal Security
|
|
55
|
+
*/
|
|
56
|
+
async function checkTerminalAccess(socket, lang) {
|
|
57
|
+
const t = i18next.getFixedT(lang);
|
|
58
|
+
try {
|
|
59
|
+
const terminalEnabled = await preferencesService.getTerminalEnabled();
|
|
60
|
+
if (!terminalEnabled) {
|
|
61
|
+
return {
|
|
62
|
+
allowed: false,
|
|
63
|
+
error: {
|
|
64
|
+
code: TERMINAL_ERRORS.TERMINAL_DISABLED.code,
|
|
65
|
+
message: t('ws.error.terminalDisabled'),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
// Fail-closed: deny access if preferences read fails
|
|
72
|
+
log.error('Failed to check terminal enabled state, denying access:', err);
|
|
73
|
+
return {
|
|
74
|
+
allowed: false,
|
|
75
|
+
error: {
|
|
76
|
+
code: TERMINAL_ERRORS.TERMINAL_DISABLED.code,
|
|
77
|
+
message: t('ws.error.terminalDisabled'),
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const clientIP = extractClientIP(socket);
|
|
82
|
+
if (!isLocalIP(clientIP)) {
|
|
83
|
+
return {
|
|
84
|
+
allowed: false,
|
|
85
|
+
error: {
|
|
86
|
+
code: TERMINAL_ERRORS.TERMINAL_ACCESS_DENIED.code,
|
|
87
|
+
message: t('ws.error.terminalAccessDenied'),
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return { allowed: true };
|
|
92
|
+
}
|
|
93
|
+
let io;
|
|
94
|
+
let connectedClients = 0;
|
|
95
|
+
// Primary maps: sessionId → ActiveStream, socketId → sessionId
|
|
96
|
+
const activeStreams = new Map();
|
|
97
|
+
const socketToSession = new Map();
|
|
98
|
+
let permissionRequestCounter = 0;
|
|
99
|
+
/** Create a buffered emit function that buffers and broadcasts to all connected sockets */
|
|
100
|
+
function createStreamEmit(stream) {
|
|
101
|
+
return (event, data) => {
|
|
102
|
+
stream.buffer.push({ event, data });
|
|
103
|
+
for (const sock of stream.sockets) {
|
|
104
|
+
if (sock.connected) {
|
|
105
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
106
|
+
sock.emit(event, data);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Get session IDs of all currently running active streams */
|
|
112
|
+
export function getActiveStreamSessionIds() {
|
|
113
|
+
return [...activeStreams.entries()]
|
|
114
|
+
.filter(([, stream]) => stream.status === 'running')
|
|
115
|
+
.map(([key]) => key);
|
|
116
|
+
}
|
|
117
|
+
/** Get active (running) session counts grouped by project slug (in-memory, no I/O) */
|
|
118
|
+
export function getActiveSessionCountsByProject() {
|
|
119
|
+
const counts = new Map();
|
|
120
|
+
for (const [sessionId, stream] of activeStreams.entries()) {
|
|
121
|
+
if (stream.status !== 'running')
|
|
122
|
+
continue;
|
|
123
|
+
const slug = sessionProjectMap.get(sessionId);
|
|
124
|
+
if (slug) {
|
|
125
|
+
counts.set(slug, (counts.get(slug) ?? 0) + 1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return counts;
|
|
129
|
+
}
|
|
130
|
+
/** Check if a specific session has a running active stream */
|
|
131
|
+
export function isSessionStreaming(sessionId) {
|
|
132
|
+
const stream = activeStreams.get(sessionId);
|
|
133
|
+
return !!stream && stream.status === 'running';
|
|
134
|
+
}
|
|
135
|
+
/** Clean up a stream from all maps */
|
|
136
|
+
function cleanupStream(streamKey) {
|
|
137
|
+
activeStreams.delete(streamKey);
|
|
138
|
+
for (const [sockId, sessId] of socketToSession.entries()) {
|
|
139
|
+
if (sessId === streamKey)
|
|
140
|
+
socketToSession.delete(sockId);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create a headless ActiveStream (no attached socket) for queue execution.
|
|
145
|
+
* Returns a buffered emit function and a broadcast function for project room delivery.
|
|
146
|
+
* The stream is registered in activeStreams so session:join/reconnect works.
|
|
147
|
+
*/
|
|
148
|
+
export function createHeadlessStream(sessionId, abortController, projectSlug) {
|
|
149
|
+
// Collect sockets from session room (same as chat:send handler)
|
|
150
|
+
const sockets = new Set();
|
|
151
|
+
if (io) {
|
|
152
|
+
const roomSockets = io.sockets.adapter.rooms.get(`session:${sessionId}`);
|
|
153
|
+
if (roomSockets) {
|
|
154
|
+
for (const socketId of roomSockets) {
|
|
155
|
+
const sock = io.sockets.sockets.get(socketId);
|
|
156
|
+
if (sock)
|
|
157
|
+
sockets.add(sock);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const stream = {
|
|
162
|
+
sessionId,
|
|
163
|
+
sockets,
|
|
164
|
+
abortController,
|
|
165
|
+
buffer: [],
|
|
166
|
+
pendingPermissions: new Map(),
|
|
167
|
+
status: 'running',
|
|
168
|
+
startedAt: Date.now(),
|
|
169
|
+
};
|
|
170
|
+
activeStreams.set(sessionId, stream);
|
|
171
|
+
if (projectSlug) {
|
|
172
|
+
sessionProjectMap.set(sessionId, projectSlug);
|
|
173
|
+
}
|
|
174
|
+
for (const sock of sockets) {
|
|
175
|
+
socketToSession.set(sock.id, sessionId);
|
|
176
|
+
}
|
|
177
|
+
const emit = createStreamEmit(stream);
|
|
178
|
+
return { stream, emit };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Re-key a stream when SDK assigns a different sessionId than the initial key.
|
|
182
|
+
* Updates activeStreams map and socketToSession references.
|
|
183
|
+
*/
|
|
184
|
+
export function rekeyStream(stream, newSessionId) {
|
|
185
|
+
if (stream.sessionId === newSessionId)
|
|
186
|
+
return;
|
|
187
|
+
const oldSessionId = stream.sessionId;
|
|
188
|
+
const projectSlug = sessionProjectMap.get(oldSessionId);
|
|
189
|
+
activeStreams.delete(oldSessionId);
|
|
190
|
+
stream.sessionId = newSessionId;
|
|
191
|
+
activeStreams.set(newSessionId, stream);
|
|
192
|
+
if (projectSlug) {
|
|
193
|
+
sessionProjectMap.delete(oldSessionId);
|
|
194
|
+
sessionProjectMap.set(newSessionId, projectSlug);
|
|
195
|
+
}
|
|
196
|
+
for (const sock of stream.sockets) {
|
|
197
|
+
socketToSession.set(sock.id, newSessionId);
|
|
198
|
+
sock.leave(`session:${oldSessionId}`);
|
|
199
|
+
sock.join(`session:${newSessionId}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Mark a stream as completed and broadcast stream-change.
|
|
204
|
+
* Cleans up from activeStreams map.
|
|
205
|
+
*/
|
|
206
|
+
export function finalizeStream(sessionId) {
|
|
207
|
+
const stream = activeStreams.get(sessionId);
|
|
208
|
+
if (stream) {
|
|
209
|
+
stream.status = 'completed';
|
|
210
|
+
cleanupStream(sessionId);
|
|
211
|
+
}
|
|
212
|
+
io.emit('session:stream-change', { sessionId, active: false });
|
|
213
|
+
const slug = sessionProjectMap.get(sessionId);
|
|
214
|
+
if (slug) {
|
|
215
|
+
sessionProjectMap.delete(sessionId);
|
|
216
|
+
triggerDashboardStatusChange(slug);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Broadcast session:stream-change to all connected clients.
|
|
221
|
+
* Used by queue service to signal stream start/end.
|
|
222
|
+
* Story 20.1: Also triggers dashboard status change when projectSlug is known.
|
|
223
|
+
*/
|
|
224
|
+
export function broadcastStreamChange(sessionId, active) {
|
|
225
|
+
io.emit('session:stream-change', { sessionId, active });
|
|
226
|
+
const slug = sessionProjectMap.get(sessionId);
|
|
227
|
+
if (slug) {
|
|
228
|
+
triggerDashboardStatusChange(slug);
|
|
229
|
+
if (!active)
|
|
230
|
+
sessionProjectMap.delete(sessionId);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Match Accept-Language header against SUPPORTED_LANGUAGES.
|
|
235
|
+
* Returns the first matching language code or null.
|
|
236
|
+
*/
|
|
237
|
+
function matchAcceptLanguage(header) {
|
|
238
|
+
if (!header)
|
|
239
|
+
return null;
|
|
240
|
+
const parts = header.split(',').map(part => {
|
|
241
|
+
const [lang, qStr] = part.trim().split(';q=');
|
|
242
|
+
return { lang: lang.trim().split('-')[0].toLowerCase(), q: qStr ? parseFloat(qStr) : 1.0 };
|
|
243
|
+
}).sort((a, b) => b.q - a.q);
|
|
244
|
+
for (const { lang } of parts) {
|
|
245
|
+
if (SUPPORTED_LANGUAGES.includes(lang)) {
|
|
246
|
+
return lang;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Initialize Socket.io server with the HTTP server
|
|
253
|
+
* @param httpServer - HTTP server instance from Express
|
|
254
|
+
* @returns Socket.io server instance
|
|
255
|
+
* [Source: Story 2.5 - Task 4]
|
|
256
|
+
*/
|
|
257
|
+
export async function initializeWebSocket(httpServer) {
|
|
258
|
+
io = new SocketIOServer(httpServer, {
|
|
259
|
+
cors: config.websocket.cors,
|
|
260
|
+
maxHttpBufferSize: 100 * 1024 * 1024, // 100MB for base64 image payloads
|
|
261
|
+
});
|
|
262
|
+
// Session middleware for WebSocket (Story 2.5 - Task 4)
|
|
263
|
+
const sessionMiddleware = await createSessionMiddleware();
|
|
264
|
+
// Parse session from cookie for Socket.io connections
|
|
265
|
+
io.use((socket, next) => {
|
|
266
|
+
// Express middleware adapter for Socket.io
|
|
267
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
268
|
+
sessionMiddleware(socket.request, {}, next);
|
|
269
|
+
});
|
|
270
|
+
// Authentication middleware (Story 2.5 - Task 4)
|
|
271
|
+
io.use((socket, next) => {
|
|
272
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
273
|
+
const session = socket.request.session;
|
|
274
|
+
if (session?.authenticated) {
|
|
275
|
+
return next();
|
|
276
|
+
}
|
|
277
|
+
return next(new Error('Unauthorized'));
|
|
278
|
+
});
|
|
279
|
+
io.on('connection', (socket) => {
|
|
280
|
+
connectedClients++;
|
|
281
|
+
log.info(`Client connected. Total: ${connectedClients}`);
|
|
282
|
+
// Set default language synchronously; resolved asynchronously below.
|
|
283
|
+
// Handlers read socket.data.language at invocation time (not capture time).
|
|
284
|
+
socket.data.language = 'en';
|
|
285
|
+
// Resolve language preference and send terminal:access asynchronously.
|
|
286
|
+
// Event listeners are registered synchronously below to prevent race conditions
|
|
287
|
+
// where early client emits could be dropped during async preference loading.
|
|
288
|
+
(async () => {
|
|
289
|
+
try {
|
|
290
|
+
const prefs = await preferencesService.readPreferences();
|
|
291
|
+
const prefLang = prefs.language && SUPPORTED_LANGUAGES.includes(prefs.language)
|
|
292
|
+
? prefs.language : null;
|
|
293
|
+
const headerLang = matchAcceptLanguage(socket.request?.headers?.['accept-language']);
|
|
294
|
+
socket.data.language = prefLang || headerLang || 'en';
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
// Keep default 'en'
|
|
298
|
+
}
|
|
299
|
+
// Story 17.5: Send terminal access info on connection (after language resolved)
|
|
300
|
+
const lang = socket.data.language || 'en';
|
|
301
|
+
const t = i18next.getFixedT(lang);
|
|
302
|
+
try {
|
|
303
|
+
const clientIP = extractClientIP(socket);
|
|
304
|
+
const isLocal = isLocalIP(clientIP);
|
|
305
|
+
const terminalEnabled = await preferencesService.getTerminalEnabled();
|
|
306
|
+
socket.emit('terminal:access', {
|
|
307
|
+
allowed: terminalEnabled && isLocal,
|
|
308
|
+
enabled: terminalEnabled,
|
|
309
|
+
reason: !terminalEnabled
|
|
310
|
+
? t('ws.error.terminalDisabled')
|
|
311
|
+
: !isLocal
|
|
312
|
+
? t('ws.error.terminalAccessDenied')
|
|
313
|
+
: undefined,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
log.error('Failed to send terminal:access event:', err);
|
|
318
|
+
// Fail-closed: report as disabled
|
|
319
|
+
socket.emit('terminal:access', {
|
|
320
|
+
allowed: false,
|
|
321
|
+
enabled: false,
|
|
322
|
+
reason: t('ws.error.terminalDisabled'),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
})();
|
|
326
|
+
// Start rate limit polling on first client connection
|
|
327
|
+
if (connectedClients === 1) {
|
|
328
|
+
rateLimitProbeService.startPolling((data) => { io.emit('rateLimit:update', data); }, (data) => { io.emit('apiHealth:update', data); });
|
|
329
|
+
}
|
|
330
|
+
// Send cached rate limit data immediately to newly connected client
|
|
331
|
+
const cachedRateLimit = rateLimitProbeService.getCachedResult();
|
|
332
|
+
if (cachedRateLimit) {
|
|
333
|
+
socket.emit('rateLimit:update', cachedRateLimit);
|
|
334
|
+
}
|
|
335
|
+
// Send cached API health status to newly connected client
|
|
336
|
+
const cachedHealth = rateLimitProbeService.getApiHealth();
|
|
337
|
+
if (cachedHealth) {
|
|
338
|
+
socket.emit('apiHealth:update', cachedHealth);
|
|
339
|
+
}
|
|
340
|
+
// Handle chat:send event — background streaming with reconnect support
|
|
341
|
+
socket.on('chat:send', async (data) => {
|
|
342
|
+
const lang = socket.data.language || 'en';
|
|
343
|
+
const t = i18next.getFixedT(lang);
|
|
344
|
+
// Reject if queue has locked this session (server-side enforcement)
|
|
345
|
+
if (data.sessionId) {
|
|
346
|
+
for (const [, qs] of queueInstances()) {
|
|
347
|
+
if (qs.lockedSessionId === data.sessionId) {
|
|
348
|
+
socket.emit('error', {
|
|
349
|
+
code: ERROR_CODES.CHAT_ERROR,
|
|
350
|
+
message: t('ws.error.queueSessionLocked'),
|
|
351
|
+
});
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
const abortController = new AbortController();
|
|
357
|
+
const streamKey = data.sessionId || `pending-${socket.id}`;
|
|
358
|
+
// Abort existing active stream for same session — notify all watchers
|
|
359
|
+
const existingStream = activeStreams.get(streamKey);
|
|
360
|
+
if (existingStream && existingStream.status === 'running') {
|
|
361
|
+
for (const sock of existingStream.sockets) {
|
|
362
|
+
if (sock.id !== socket.id) {
|
|
363
|
+
sock.emit('stream:detached', { sessionId: streamKey, reason: 'another-client' });
|
|
364
|
+
socketToSession.delete(sock.id);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
existingStream.abortController.abort('another-client');
|
|
368
|
+
}
|
|
369
|
+
// Collect all sockets viewing this session (from persistent session room)
|
|
370
|
+
const initialSockets = new Set([socket]);
|
|
371
|
+
const roomSockets = io.sockets.adapter.rooms.get(`session:${streamKey}`);
|
|
372
|
+
if (roomSockets) {
|
|
373
|
+
for (const socketId of roomSockets) {
|
|
374
|
+
const roomSocket = io.sockets.sockets.get(socketId);
|
|
375
|
+
if (roomSocket && roomSocket.id !== socket.id) {
|
|
376
|
+
initialSockets.add(roomSocket);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
const stream = {
|
|
381
|
+
sessionId: streamKey,
|
|
382
|
+
sockets: initialSockets,
|
|
383
|
+
abortController,
|
|
384
|
+
buffer: [],
|
|
385
|
+
pendingPermissions: new Map(),
|
|
386
|
+
status: 'running',
|
|
387
|
+
startedAt: Date.now(),
|
|
388
|
+
};
|
|
389
|
+
activeStreams.set(streamKey, stream);
|
|
390
|
+
for (const sock of initialSockets) {
|
|
391
|
+
socketToSession.set(sock.id, streamKey);
|
|
392
|
+
}
|
|
393
|
+
// Story 20.1: Populate session→project mapping for dashboard triggers
|
|
394
|
+
// Use stream.sessionId (mutable) instead of captured streamKey to handle
|
|
395
|
+
// race condition where rekeyStream() may have already changed the session ID
|
|
396
|
+
projectService.findProjectByPath(data.workingDirectory).then((project) => {
|
|
397
|
+
if (project && stream.status === 'running') {
|
|
398
|
+
sessionProjectMap.set(stream.sessionId, project.projectSlug);
|
|
399
|
+
triggerDashboardStatusChange(project.projectSlug);
|
|
400
|
+
}
|
|
401
|
+
}).catch(() => { });
|
|
402
|
+
try {
|
|
403
|
+
await handleChatSend(stream, data, abortController, lang);
|
|
404
|
+
}
|
|
405
|
+
finally {
|
|
406
|
+
stream.status = 'completed';
|
|
407
|
+
const endedSessionId = stream.sessionId;
|
|
408
|
+
// Only cleanup if this stream is still the active one for this session.
|
|
409
|
+
// A replacement stream (from another chat:send) may have already taken over
|
|
410
|
+
// the same key — deleting it would be a race condition.
|
|
411
|
+
if (activeStreams.get(endedSessionId) === stream) {
|
|
412
|
+
cleanupStream(endedSessionId);
|
|
413
|
+
io.emit('session:stream-change', { sessionId: endedSessionId, active: false });
|
|
414
|
+
// Story 20.1: Trigger dashboard status change on stream end
|
|
415
|
+
const endProjectSlug = sessionProjectMap.get(endedSessionId);
|
|
416
|
+
if (endProjectSlug) {
|
|
417
|
+
triggerDashboardStatusChange(endProjectSlug);
|
|
418
|
+
sessionProjectMap.delete(endedSessionId);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
// Handle permission:respond event — route to ActiveStream (covers both normal chat and queue)
|
|
424
|
+
socket.on('permission:respond', (data) => {
|
|
425
|
+
const sessionId = socketToSession.get(socket.id);
|
|
426
|
+
if (!sessionId)
|
|
427
|
+
return;
|
|
428
|
+
const stream = activeStreams.get(sessionId);
|
|
429
|
+
if (stream?.pendingPermissions.has(data.requestId)) {
|
|
430
|
+
stream.pendingPermissions.get(data.requestId).resolve({ approved: data.approved, response: data.response });
|
|
431
|
+
stream.pendingPermissions.delete(data.requestId);
|
|
432
|
+
// Broadcast the actual resolution to all OTHER viewers so their
|
|
433
|
+
// tool/interactive cards can show the correct approve/deny state
|
|
434
|
+
for (const sock of stream.sockets) {
|
|
435
|
+
if (sock.id !== socket.id) {
|
|
436
|
+
sock.emit('permission:resolved', {
|
|
437
|
+
requestId: data.requestId,
|
|
438
|
+
approved: data.approved,
|
|
439
|
+
interactionType: data.interactionType,
|
|
440
|
+
response: data.response,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
// Permission already resolved by another viewer — notify sender
|
|
447
|
+
socket.emit('permission:already-resolved', { requestId: data.requestId });
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
// Handle chat:abort event — find stream and abort, notify all viewers
|
|
451
|
+
socket.on('chat:abort', () => {
|
|
452
|
+
const sessionId = socketToSession.get(socket.id);
|
|
453
|
+
if (!sessionId)
|
|
454
|
+
return;
|
|
455
|
+
const stream = activeStreams.get(sessionId);
|
|
456
|
+
if (stream && stream.status === 'running') {
|
|
457
|
+
// Emit abort notification to all connected viewers BEFORE triggering abort.
|
|
458
|
+
// This ensures passive viewers (who didn't initiate the abort) also
|
|
459
|
+
// receive a completion signal, preventing them from being stuck in isStreaming=true.
|
|
460
|
+
for (const sock of stream.sockets) {
|
|
461
|
+
sock.emit('stream:detached', { sessionId, reason: 'user-abort' });
|
|
462
|
+
}
|
|
463
|
+
stream.abortController.abort('user-abort');
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
// Handle permission:mode-change — update SDK permission mode during active stream
|
|
467
|
+
socket.on('permission:mode-change', async (data) => {
|
|
468
|
+
const sessionId = socketToSession.get(socket.id);
|
|
469
|
+
if (!sessionId)
|
|
470
|
+
return;
|
|
471
|
+
const stream = activeStreams.get(sessionId);
|
|
472
|
+
if (!stream?.chatService || stream.status !== 'running')
|
|
473
|
+
return;
|
|
474
|
+
try {
|
|
475
|
+
await stream.chatService.setPermissionMode(data.mode);
|
|
476
|
+
log.debug(`Permission mode changed to "${data.mode}" for session ${sessionId}`);
|
|
477
|
+
// Broadcast to other viewers so their UI stays in sync
|
|
478
|
+
for (const sock of stream.sockets) {
|
|
479
|
+
if (sock.id !== socket.id) {
|
|
480
|
+
sock.emit('permission:mode-change', { mode: data.mode });
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
log.error('Failed to change permission mode:', err);
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
// Handle session:join event — attach socket to active running stream (broadcast)
|
|
489
|
+
// Also joins a persistent Socket.io room so future streams auto-include this socket.
|
|
490
|
+
socket.on('session:join', (sessionId) => {
|
|
491
|
+
// Detach this socket from any previously-attached stream to prevent
|
|
492
|
+
// events from the old stream leaking to a different session's listeners
|
|
493
|
+
const prevSessionId = socketToSession.get(socket.id);
|
|
494
|
+
if (prevSessionId && prevSessionId !== sessionId) {
|
|
495
|
+
const prevStream = activeStreams.get(prevSessionId);
|
|
496
|
+
if (prevStream) {
|
|
497
|
+
prevStream.sockets.delete(socket);
|
|
498
|
+
}
|
|
499
|
+
socketToSession.delete(socket.id);
|
|
500
|
+
socket.leave(`session:${prevSessionId}`);
|
|
501
|
+
}
|
|
502
|
+
// Join persistent session room (survives beyond ActiveStream lifecycle)
|
|
503
|
+
socket.join(`session:${sessionId}`);
|
|
504
|
+
const stream = activeStreams.get(sessionId);
|
|
505
|
+
if (!stream || stream.status !== 'running') {
|
|
506
|
+
socket.emit('stream:status', { active: false, sessionId });
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
// Add socket to broadcast set (multiple browsers can watch simultaneously)
|
|
510
|
+
stream.sockets.add(socket);
|
|
511
|
+
socketToSession.set(socket.id, sessionId);
|
|
512
|
+
// Notify this client that stream is active, then replay entire buffer
|
|
513
|
+
socket.emit('stream:status', { active: true, sessionId });
|
|
514
|
+
for (const entry of stream.buffer) {
|
|
515
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
516
|
+
socket.emit(entry.event, entry.data);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
// Handle session:leave event — detach socket from current stream and session room
|
|
520
|
+
// (client navigating away from a session while streaming continues in background)
|
|
521
|
+
socket.on('session:leave', (sessionId) => {
|
|
522
|
+
const prevSessionId = socketToSession.get(socket.id);
|
|
523
|
+
if (prevSessionId) {
|
|
524
|
+
const prevStream = activeStreams.get(prevSessionId);
|
|
525
|
+
if (prevStream) {
|
|
526
|
+
prevStream.sockets.delete(socket);
|
|
527
|
+
}
|
|
528
|
+
socketToSession.delete(socket.id);
|
|
529
|
+
}
|
|
530
|
+
// Use prevSessionId as fallback — client may send empty string when
|
|
531
|
+
// the sessionId is not available at unmount time (e.g., ChatPage cleanup)
|
|
532
|
+
const roomSessionId = sessionId || prevSessionId;
|
|
533
|
+
if (roomSessionId) {
|
|
534
|
+
socket.leave(`session:${roomSessionId}`);
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
// Story 20.1: Dashboard subscribe/unsubscribe
|
|
538
|
+
socket.on('dashboard:subscribe', () => {
|
|
539
|
+
socket.join('dashboard');
|
|
540
|
+
});
|
|
541
|
+
socket.on('dashboard:unsubscribe', () => {
|
|
542
|
+
socket.leave('dashboard');
|
|
543
|
+
});
|
|
544
|
+
// Handle project:join/leave — room for queue event delivery (Story 15.2)
|
|
545
|
+
socket.on('project:join', (projectSlug) => {
|
|
546
|
+
socket.join(`project:${projectSlug}`);
|
|
547
|
+
});
|
|
548
|
+
socket.on('project:leave', (projectSlug) => {
|
|
549
|
+
socket.leave(`project:${projectSlug}`);
|
|
550
|
+
});
|
|
551
|
+
// Handle queue events via WebSocket (Story 15.2)
|
|
552
|
+
socket.on('queue:start', async (data) => {
|
|
553
|
+
const { items, sessionId, projectSlug, permissionMode } = data;
|
|
554
|
+
socket.join(`project:${projectSlug}`);
|
|
555
|
+
const queueService = getOrCreateQueueService(projectSlug);
|
|
556
|
+
if (queueService.isRunning) {
|
|
557
|
+
const t = i18next.getFixedT(socket.data.language || 'en');
|
|
558
|
+
socket.emit('error', { code: 'QUEUE_ALREADY_RUNNING', message: t('ws.error.queueAlreadyRunning') });
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
queueService.start(items, projectSlug, sessionId, permissionMode).catch((err) => {
|
|
562
|
+
log.error('Queue execution error:', err);
|
|
563
|
+
});
|
|
564
|
+
triggerDashboardStatusChange(projectSlug);
|
|
565
|
+
});
|
|
566
|
+
socket.on('queue:pause', (data) => {
|
|
567
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
568
|
+
if (qs.isRunning)
|
|
569
|
+
qs.pause();
|
|
570
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
571
|
+
});
|
|
572
|
+
socket.on('queue:resume', (data) => {
|
|
573
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
574
|
+
if (qs.isRunning)
|
|
575
|
+
qs.resume().catch(() => { });
|
|
576
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
577
|
+
});
|
|
578
|
+
socket.on('queue:abort', (data) => {
|
|
579
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
580
|
+
if (qs.isRunning)
|
|
581
|
+
qs.abort();
|
|
582
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
583
|
+
});
|
|
584
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
585
|
+
socket.on('queue:dismiss', (data) => {
|
|
586
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
587
|
+
qs.dismiss();
|
|
588
|
+
});
|
|
589
|
+
socket.on('queue:removeItem', (data) => {
|
|
590
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
591
|
+
qs.removeItem(data.itemIndex);
|
|
592
|
+
});
|
|
593
|
+
socket.on('queue:addItem', (data) => {
|
|
594
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
595
|
+
const result = parseQueueScript(data.rawLine);
|
|
596
|
+
if (result.items.length > 0) {
|
|
597
|
+
qs.addItem(result.items[0]);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
socket.on('queue:reorderItems', (data) => {
|
|
601
|
+
const qs = getOrCreateQueueService(data.projectSlug);
|
|
602
|
+
qs.reorderItems(data.newOrder);
|
|
603
|
+
});
|
|
604
|
+
// --- Story 17.1: Terminal PTY events ---
|
|
605
|
+
socketTerminals.set(socket.id, new Set());
|
|
606
|
+
socket.on('terminal:create', async (data) => {
|
|
607
|
+
const lang = socket.data.language || 'en';
|
|
608
|
+
const t = i18next.getFixedT(lang);
|
|
609
|
+
// Story 17.5: Security guard
|
|
610
|
+
const access = await checkTerminalAccess(socket, lang);
|
|
611
|
+
if (!access.allowed) {
|
|
612
|
+
log.warn(`Terminal access denied for ${extractClientIP(socket)} on terminal:create`);
|
|
613
|
+
socket.emit('terminal:error', access.error);
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
// Reattach to existing session
|
|
618
|
+
if (data.terminalId) {
|
|
619
|
+
const tid = data.terminalId;
|
|
620
|
+
const existing = ptyService.getSession(tid);
|
|
621
|
+
if (!existing) {
|
|
622
|
+
socket.emit('terminal:error', {
|
|
623
|
+
terminalId: tid,
|
|
624
|
+
code: TERMINAL_ERRORS.TERMINAL_NOT_FOUND.code,
|
|
625
|
+
message: t('ws.error.terminalNotFound'),
|
|
626
|
+
});
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
ptyService.cancelCleanup(tid);
|
|
630
|
+
ptyService.onData(tid, (output) => {
|
|
631
|
+
socket.emit('terminal:data', { terminalId: tid, data: output });
|
|
632
|
+
});
|
|
633
|
+
ptyService.onExit(tid, (exitCode) => {
|
|
634
|
+
socket.emit('terminal:exit', { terminalId: tid, exitCode });
|
|
635
|
+
socketTerminals.get(socket.id)?.delete(tid);
|
|
636
|
+
});
|
|
637
|
+
socketTerminals.get(socket.id)?.add(tid);
|
|
638
|
+
socket.emit('terminal:created', { terminalId: tid, shell: existing.shell });
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
// Create new session
|
|
642
|
+
const projectPath = await projectService.resolveProjectPath(data.projectSlug);
|
|
643
|
+
if (!projectPath) {
|
|
644
|
+
socket.emit('terminal:error', {
|
|
645
|
+
code: TERMINAL_ERRORS.PTY_SPAWN_ERROR.code,
|
|
646
|
+
message: t('ws.error.terminalProjectNotFound'),
|
|
647
|
+
});
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
const { terminalId, shell } = ptyService.createSession(projectPath, data.projectSlug);
|
|
651
|
+
ptyService.onData(terminalId, (output) => {
|
|
652
|
+
socket.emit('terminal:data', { terminalId, data: output });
|
|
653
|
+
});
|
|
654
|
+
ptyService.onExit(terminalId, (exitCode) => {
|
|
655
|
+
socket.emit('terminal:exit', { terminalId, exitCode });
|
|
656
|
+
socketTerminals.get(socket.id)?.delete(terminalId);
|
|
657
|
+
// Story 20.1: Trigger dashboard on natural PTY exit
|
|
658
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
659
|
+
});
|
|
660
|
+
socketTerminals.get(socket.id)?.add(terminalId);
|
|
661
|
+
socket.emit('terminal:created', { terminalId, shell });
|
|
662
|
+
// Story 20.1: Trigger dashboard on terminal create
|
|
663
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
const code = err.code || TERMINAL_ERRORS.PTY_SPAWN_ERROR.code;
|
|
667
|
+
const message = err.message || t('ws.error.ptySpawnError');
|
|
668
|
+
socket.emit('terminal:error', { terminalId: data.terminalId, code, message });
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
socket.on('terminal:input', async (data) => {
|
|
672
|
+
// Story 17.5: Security guard
|
|
673
|
+
const inputAccess = await checkTerminalAccess(socket, socket.data.language || 'en');
|
|
674
|
+
if (!inputAccess.allowed) {
|
|
675
|
+
log.warn(`Terminal access denied for ${extractClientIP(socket)} on terminal:input`);
|
|
676
|
+
socket.emit('terminal:error', { ...inputAccess.error, terminalId: data.terminalId });
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
try {
|
|
680
|
+
ptyService.writeInput(data.terminalId, data.data);
|
|
681
|
+
}
|
|
682
|
+
catch (err) {
|
|
683
|
+
const code = err.code || TERMINAL_ERRORS.TERMINAL_NOT_FOUND.code;
|
|
684
|
+
socket.emit('terminal:error', { terminalId: data.terminalId, code, message: err.message });
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
socket.on('terminal:resize', async (data) => {
|
|
688
|
+
// Story 17.5: Security guard
|
|
689
|
+
const resizeAccess = await checkTerminalAccess(socket, socket.data.language || 'en');
|
|
690
|
+
if (!resizeAccess.allowed) {
|
|
691
|
+
log.warn(`Terminal access denied for ${extractClientIP(socket)} on terminal:resize`);
|
|
692
|
+
socket.emit('terminal:error', { ...resizeAccess.error, terminalId: data.terminalId });
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
try {
|
|
696
|
+
ptyService.resize(data.terminalId, data.cols, data.rows);
|
|
697
|
+
}
|
|
698
|
+
catch (err) {
|
|
699
|
+
const code = err.code || TERMINAL_ERRORS.INVALID_DIMENSIONS.code;
|
|
700
|
+
socket.emit('terminal:error', { terminalId: data.terminalId, code, message: err.message });
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
socket.on('terminal:list', async (data) => {
|
|
704
|
+
const lang = socket.data.language || 'en';
|
|
705
|
+
const access = await checkTerminalAccess(socket, lang);
|
|
706
|
+
if (!access.allowed) {
|
|
707
|
+
socket.emit('terminal:list', { projectSlug: data.projectSlug, terminals: [] });
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
try {
|
|
711
|
+
const sessions = ptyService.getSessionsByProject(data.projectSlug);
|
|
712
|
+
const socketTerminalSet = socketTerminals.get(socket.id);
|
|
713
|
+
const terminals = sessions.map((s) => {
|
|
714
|
+
ptyService.cancelCleanup(s.terminalId);
|
|
715
|
+
// Only re-register callbacks if not already attached to this socket
|
|
716
|
+
if (!socketTerminalSet?.has(s.terminalId)) {
|
|
717
|
+
ptyService.onData(s.terminalId, (output) => {
|
|
718
|
+
socket.emit('terminal:data', { terminalId: s.terminalId, data: output });
|
|
719
|
+
});
|
|
720
|
+
ptyService.onExit(s.terminalId, (exitCode) => {
|
|
721
|
+
socket.emit('terminal:exit', { terminalId: s.terminalId, exitCode });
|
|
722
|
+
socketTerminals.get(socket.id)?.delete(s.terminalId);
|
|
723
|
+
triggerDashboardStatusChange(data.projectSlug);
|
|
724
|
+
});
|
|
725
|
+
socketTerminalSet?.add(s.terminalId);
|
|
726
|
+
}
|
|
727
|
+
return { terminalId: s.terminalId, shell: s.shell };
|
|
728
|
+
});
|
|
729
|
+
socket.emit('terminal:list', { projectSlug: data.projectSlug, terminals });
|
|
730
|
+
}
|
|
731
|
+
catch (err) {
|
|
732
|
+
log.error('terminal:list error:', err);
|
|
733
|
+
socket.emit('terminal:list', { projectSlug: data.projectSlug, terminals: [] });
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
socket.on('terminal:close', async (data) => {
|
|
737
|
+
// Story 17.5: Security guard
|
|
738
|
+
const closeAccess = await checkTerminalAccess(socket, socket.data.language || 'en');
|
|
739
|
+
if (!closeAccess.allowed) {
|
|
740
|
+
log.warn(`Terminal access denied for ${extractClientIP(socket)} on terminal:close`);
|
|
741
|
+
socket.emit('terminal:error', { ...closeAccess.error, terminalId: data.terminalId });
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
// Story 20.1: Extract projectSlug BEFORE closeSession removes the session
|
|
746
|
+
const closingSession = ptyService.getSession(data.terminalId);
|
|
747
|
+
const closeProjectSlug = closingSession?.projectSlug;
|
|
748
|
+
ptyService.closeSession(data.terminalId);
|
|
749
|
+
socketTerminals.get(socket.id)?.delete(data.terminalId);
|
|
750
|
+
if (closeProjectSlug) {
|
|
751
|
+
triggerDashboardStatusChange(closeProjectSlug);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
catch {
|
|
755
|
+
// Ignore close errors — session may already be gone
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
// Disconnect: detach socket from stream, DON'T abort or deny permissions
|
|
759
|
+
socket.on('disconnect', () => {
|
|
760
|
+
const sessionId = socketToSession.get(socket.id);
|
|
761
|
+
if (sessionId) {
|
|
762
|
+
const stream = activeStreams.get(sessionId);
|
|
763
|
+
if (stream) {
|
|
764
|
+
stream.sockets.delete(socket);
|
|
765
|
+
}
|
|
766
|
+
socketToSession.delete(socket.id);
|
|
767
|
+
}
|
|
768
|
+
// PTY sessions are NOT cleaned up on socket disconnect.
|
|
769
|
+
// They persist until explicitly closed by the user, the PTY process exits,
|
|
770
|
+
// or the server shuts down. This prevents losing long-running terminal
|
|
771
|
+
// work during browser refreshes or temporary network interruptions.
|
|
772
|
+
const terminalIds = socketTerminals.get(socket.id);
|
|
773
|
+
if (terminalIds) {
|
|
774
|
+
socketTerminals.delete(socket.id);
|
|
775
|
+
}
|
|
776
|
+
connectedClients--;
|
|
777
|
+
log.info(`Client disconnected. Total: ${connectedClients}`);
|
|
778
|
+
// Stop polling when no clients connected
|
|
779
|
+
if (connectedClients === 0) {
|
|
780
|
+
rateLimitProbeService.stopPolling();
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
return io;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Get the Socket.io server instance
|
|
788
|
+
* @throws Error if Socket.io is not initialized
|
|
789
|
+
* @returns Socket.io server instance
|
|
790
|
+
*/
|
|
791
|
+
export function getIO() {
|
|
792
|
+
if (!io) {
|
|
793
|
+
throw new Error('Socket.io not initialized');
|
|
794
|
+
}
|
|
795
|
+
return io;
|
|
796
|
+
}
|
|
797
|
+
/**
|
|
798
|
+
* Get the current number of connected clients
|
|
799
|
+
* @returns Number of connected clients
|
|
800
|
+
*/
|
|
801
|
+
export function getConnectedClientsCount() {
|
|
802
|
+
return connectedClients;
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* Validate image attachments
|
|
806
|
+
* Story 5.5: Image Attachment
|
|
807
|
+
*/
|
|
808
|
+
function validateImages(images, lang) {
|
|
809
|
+
const t = i18next.getFixedT(lang);
|
|
810
|
+
if (images.length > IMAGE_CONSTRAINTS.MAX_COUNT) {
|
|
811
|
+
return { valid: false, error: t('ws.error.maxImages', { value: IMAGE_CONSTRAINTS.MAX_COUNT }) };
|
|
812
|
+
}
|
|
813
|
+
for (const img of images) {
|
|
814
|
+
if (!IMAGE_CONSTRAINTS.ACCEPTED_TYPES.includes(img.mimeType)) {
|
|
815
|
+
return { valid: false, error: t('ws.error.unsupportedImageFormat', { value: img.mimeType }) };
|
|
816
|
+
}
|
|
817
|
+
// base64 size approximation: base64 length * 0.75 ≈ original bytes
|
|
818
|
+
const sizeBytes = Math.ceil(img.data.length * 0.75);
|
|
819
|
+
if (sizeBytes > IMAGE_CONSTRAINTS.MAX_SIZE_BYTES) {
|
|
820
|
+
return { valid: false, error: t('ws.error.imageSizeExceeded', { value: img.name }) };
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return { valid: true };
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Check if error message indicates a session not found error
|
|
827
|
+
*/
|
|
828
|
+
function isSessionNotFoundError(error) {
|
|
829
|
+
const message = error.message.toLowerCase();
|
|
830
|
+
return (message.includes('session not found') ||
|
|
831
|
+
message.includes('session does not exist') ||
|
|
832
|
+
message.includes('invalid session') ||
|
|
833
|
+
message.includes('no such session'));
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Handle chat:send event from client
|
|
837
|
+
* Processes user message through ChatService and streams response back
|
|
838
|
+
* All emit calls are buffered via createStreamEmit for reconnect support.
|
|
839
|
+
*/
|
|
840
|
+
async function handleChatSend(stream, data, abortController, lang) {
|
|
841
|
+
const emit = createStreamEmit(stream);
|
|
842
|
+
const t = i18next.getFixedT(lang);
|
|
843
|
+
const { content, workingDirectory, sessionId, resume, permissionMode, model, images } = data;
|
|
844
|
+
// Validate images if present (Story 5.5)
|
|
845
|
+
if (images && images.length > 0) {
|
|
846
|
+
const validation = validateImages(images, lang);
|
|
847
|
+
if (!validation.valid) {
|
|
848
|
+
emit('error', {
|
|
849
|
+
code: ERROR_CODES.VALIDATION_ERROR,
|
|
850
|
+
message: validation.error,
|
|
851
|
+
});
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
// Validate workingDirectory exists
|
|
856
|
+
if (!workingDirectory || !existsSync(workingDirectory)) {
|
|
857
|
+
emit('error', {
|
|
858
|
+
code: ERROR_CODES.INVALID_WORKING_DIR,
|
|
859
|
+
message: t('ws.error.projectPathNotFound'),
|
|
860
|
+
});
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
// Buffer the user's message so reconnecting clients can display it
|
|
864
|
+
// (SDK may not have written the JSONL file yet at reconnect time)
|
|
865
|
+
emit('user:message', { content, sessionId: sessionId || '' });
|
|
866
|
+
const isResuming = resume && sessionId;
|
|
867
|
+
const sessionService = new SessionService();
|
|
868
|
+
let timeoutId = null;
|
|
869
|
+
try {
|
|
870
|
+
const chatService = new ChatService({ workingDirectory, permissionMode });
|
|
871
|
+
stream.chatService = chatService;
|
|
872
|
+
// Load preferences early for advanced settings + timeout
|
|
873
|
+
const effectivePrefs = await preferencesService.getEffectivePreferences();
|
|
874
|
+
const chatOptions = {
|
|
875
|
+
...(isResuming ? { resume: sessionId } : { sessionId }),
|
|
876
|
+
abortController,
|
|
877
|
+
model,
|
|
878
|
+
images,
|
|
879
|
+
// Advanced settings from preferences
|
|
880
|
+
customSystemPrompt: effectivePrefs.customSystemPrompt,
|
|
881
|
+
maxThinkingTokens: effectivePrefs.maxThinkingTokens,
|
|
882
|
+
maxTurns: effectivePrefs.maxTurns,
|
|
883
|
+
maxBudgetUsd: effectivePrefs.maxBudgetUsd,
|
|
884
|
+
};
|
|
885
|
+
// Create canUseTool callback for permission & AskUserQuestion handling
|
|
886
|
+
// Promise stays pending if socket disconnected — SDK naturally waits
|
|
887
|
+
const canUseTool = async (toolName, input, options) => {
|
|
888
|
+
// Auto-approve ExitPlanMode when the user originally chose Bypass mode.
|
|
889
|
+
// The SDK internally switches to 'plan' after EnterPlanMode, which causes
|
|
890
|
+
// ExitPlanMode to request approval even though the user intended full bypass.
|
|
891
|
+
if (toolName === 'ExitPlanMode' && permissionMode === 'bypassPermissions') {
|
|
892
|
+
log.debug('Auto-approving ExitPlanMode: original permissionMode is bypassPermissions');
|
|
893
|
+
return { behavior: 'allow', updatedInput: input };
|
|
894
|
+
}
|
|
895
|
+
const isAskUserQuestion = toolName === 'AskUserQuestion';
|
|
896
|
+
const requestId = options.toolUseID || `perm-${++permissionRequestCounter}`;
|
|
897
|
+
log.debug(`canUseTool called: tool=${toolName}, toolUseID=${options.toolUseID}, requestId=${requestId}`);
|
|
898
|
+
// Emit permission:request (buffered + forwarded to connected socket)
|
|
899
|
+
emit('permission:request', {
|
|
900
|
+
id: requestId,
|
|
901
|
+
sessionId: sessionIdRef.current || '',
|
|
902
|
+
toolCall: { id: requestId, name: toolName, input },
|
|
903
|
+
requiresApproval: true,
|
|
904
|
+
});
|
|
905
|
+
// Notify via Telegram if no socket connected (or alwaysNotify enabled)
|
|
906
|
+
if (notificationService.shouldNotify(stream.sockets.size)) {
|
|
907
|
+
const prompt = isAskUserQuestion
|
|
908
|
+
? formatAskQuestionPrompt(input)
|
|
909
|
+
: `${toolName}`;
|
|
910
|
+
notificationService.notifyInputRequired(stream.sessionId, toolName, prompt);
|
|
911
|
+
}
|
|
912
|
+
// Wait for user response — Promise stays pending if no socket connected
|
|
913
|
+
const userResponse = await new Promise((resolve) => {
|
|
914
|
+
stream.pendingPermissions.set(requestId, {
|
|
915
|
+
resolve,
|
|
916
|
+
interactionType: isAskUserQuestion ? 'question' : 'permission',
|
|
917
|
+
});
|
|
918
|
+
});
|
|
919
|
+
if (isAskUserQuestion) {
|
|
920
|
+
const questions = input.questions;
|
|
921
|
+
let answers;
|
|
922
|
+
if (typeof userResponse.response === 'object' && !Array.isArray(userResponse.response) && userResponse.response !== null) {
|
|
923
|
+
answers = userResponse.response;
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
const answer = typeof userResponse.response === 'string'
|
|
927
|
+
? userResponse.response
|
|
928
|
+
: Array.isArray(userResponse.response) ? userResponse.response.join(', ') : '';
|
|
929
|
+
answers = { [questions[0].question]: answer };
|
|
930
|
+
}
|
|
931
|
+
return {
|
|
932
|
+
behavior: 'allow',
|
|
933
|
+
updatedInput: {
|
|
934
|
+
questions,
|
|
935
|
+
answers,
|
|
936
|
+
},
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
if (userResponse.approved) {
|
|
940
|
+
return { behavior: 'allow', updatedInput: input };
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
return { behavior: 'deny', message: 'User denied permission', interrupt: true };
|
|
944
|
+
}
|
|
945
|
+
};
|
|
946
|
+
// Activity-based timeout: resets on every SDK callback event
|
|
947
|
+
// Prevents cancellation while SDK is actively working (e.g., large Write input streaming)
|
|
948
|
+
// Timeout value from preferences (with env var override), clamped to 30s–30min range
|
|
949
|
+
const rawTimeoutMs = effectivePrefs.chatTimeoutMs ?? config.chat.timeoutMs;
|
|
950
|
+
const timeoutMs = (rawTimeoutMs >= 30000 && rawTimeoutMs <= 1800000) ? rawTimeoutMs : 300000;
|
|
951
|
+
let lastResetSource = 'initial';
|
|
952
|
+
const resetTimeout = (source) => {
|
|
953
|
+
if (source)
|
|
954
|
+
lastResetSource = source;
|
|
955
|
+
if (timeoutId)
|
|
956
|
+
clearTimeout(timeoutId);
|
|
957
|
+
timeoutId = setTimeout(() => {
|
|
958
|
+
log.warn(`TIMEOUT FIRED after ${timeoutMs}ms inactivity (last reset by: ${lastResetSource})`);
|
|
959
|
+
abortController.abort('timeout');
|
|
960
|
+
}, timeoutMs);
|
|
961
|
+
};
|
|
962
|
+
resetTimeout('initial');
|
|
963
|
+
// Build shared callbacks (common logic for browser & queue paths)
|
|
964
|
+
const { callbacks, sessionIdRef } = buildStreamCallbacks({
|
|
965
|
+
emit,
|
|
966
|
+
stream,
|
|
967
|
+
isResuming: !!isResuming,
|
|
968
|
+
initialSessionId: sessionId,
|
|
969
|
+
rekeyStream: (sid) => rekeyStream(stream, sid),
|
|
970
|
+
broadcastStreamChange,
|
|
971
|
+
notificationService,
|
|
972
|
+
}, {
|
|
973
|
+
onCallbackActivity: (source) => resetTimeout(source),
|
|
974
|
+
onSessionIdResolved: (sid) => {
|
|
975
|
+
sessionService.saveSessionId(workingDirectory, sid).catch(() => { });
|
|
976
|
+
},
|
|
977
|
+
});
|
|
978
|
+
// Browser-only callbacks
|
|
979
|
+
callbacks.onActivity = (messageType) => {
|
|
980
|
+
resetTimeout(`onActivity:${messageType}`);
|
|
981
|
+
};
|
|
982
|
+
callbacks.onError = (error) => {
|
|
983
|
+
// Ignore abort errors from replaced streams (another-client or user-abort)
|
|
984
|
+
if (abortController.signal.aborted) {
|
|
985
|
+
const reason = abortController.signal.reason;
|
|
986
|
+
if (reason === 'another-client' || reason === 'user-abort') {
|
|
987
|
+
return;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const sdkError = parseSDKError(error, lang);
|
|
991
|
+
if (isResuming && isSessionNotFoundError(error)) {
|
|
992
|
+
emit('error', {
|
|
993
|
+
code: ERROR_CODES.SESSION_NOT_FOUND,
|
|
994
|
+
message: t('ws.error.sessionNotFound'),
|
|
995
|
+
});
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
emit('error', {
|
|
999
|
+
code: ERROR_CODES.CHAT_ERROR,
|
|
1000
|
+
message: sdkError.message,
|
|
1001
|
+
});
|
|
1002
|
+
// Notify via Telegram if no socket connected (or alwaysNotify enabled)
|
|
1003
|
+
if (notificationService.shouldNotify(stream.sockets.size)) {
|
|
1004
|
+
notificationService.notifyError(stream.sessionId, sdkError.message);
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
await chatService.sendMessageWithCallbacks(content, callbacks, chatOptions, canUseTool, (messageType) => {
|
|
1008
|
+
resetTimeout(`raw:${messageType}`);
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
catch (error) {
|
|
1012
|
+
const sdkError = parseSDKError(error, lang);
|
|
1013
|
+
if (sdkError instanceof AbortedError || abortController.signal.aborted) {
|
|
1014
|
+
if (abortController.signal.reason === 'user-abort' || abortController.signal.reason === 'another-client') {
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
emit('error', {
|
|
1018
|
+
code: ERROR_CODES.TIMEOUT_ERROR,
|
|
1019
|
+
message: t('ws.error.timeout'),
|
|
1020
|
+
});
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
if (isResuming && error instanceof Error && isSessionNotFoundError(error)) {
|
|
1024
|
+
emit('error', {
|
|
1025
|
+
code: ERROR_CODES.SESSION_NOT_FOUND,
|
|
1026
|
+
message: t('ws.error.sessionNotFound'),
|
|
1027
|
+
});
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
emit('error', {
|
|
1031
|
+
code: ERROR_CODES.CHAT_ERROR,
|
|
1032
|
+
message: sdkError.message,
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
finally {
|
|
1036
|
+
if (timeoutId) {
|
|
1037
|
+
clearTimeout(timeoutId);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
//# sourceMappingURL=websocket.js.map
|