@hienlh/ppm 0.17.16 → 0.17.18
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/CHANGELOG.md +19 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +5 -1
- package/dist/web/assets/{ai-resource-editor-CsossqDO.js → ai-resource-editor-BgWg-ty8.js} +1 -1
- package/dist/web/assets/{angular-html-CkxY2iBQ.js → angular-html-2g8YGiJY.js} +1 -1
- package/dist/web/assets/{angular-ts-BePeGkkC.js → angular-ts-BwSmoLfh.js} +1 -1
- package/dist/web/assets/{api-settings-DAk7D-NP.js → api-settings-BJTjIG4U.js} +1 -1
- package/dist/web/assets/{api-themes-84MT-XqR.js → api-themes-DuLpbQFV.js} +1 -1
- package/dist/web/assets/{apl-DBS7PWvB.js → apl-B44SMKHp.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-gLlhsjM9.js +1 -0
- package/dist/web/assets/{astro-Clbk1k4h.js → astro-E5620wek.js} +1 -1
- package/dist/web/assets/{audio-preview-DIkokvPM.js → audio-preview-CLn1LTxc.js} +1 -1
- package/dist/web/assets/{blade-BeBsBuGS.js → blade-D-VQWAHB.js} +1 -1
- package/dist/web/assets/{bsl-DYigT3JZ.js → bsl-Bq5qFzpU.js} +1 -1
- package/dist/web/assets/{cairo-BjpO78wI.js → cairo-Cn9-ZKRa.js} +1 -1
- package/dist/web/assets/chat-tab-tTUVo4G3.js +13 -0
- package/dist/web/assets/{cobol-CpuUx69s.js → cobol-IM3E3iCH.js} +1 -1
- package/dist/web/assets/code-editor-DMfUjdk5.js +10 -0
- package/dist/web/assets/{coffee-FoFd2Cxo.js → coffee-24wG7ekn.js} +1 -1
- package/dist/web/assets/{conflict-editor-Dqm1bkyL.js → conflict-editor-BosR4PW3.js} +3 -3
- package/dist/web/assets/{cpp-CO_nPfdr.js → cpp-DH9Cqt4g.js} +1 -1
- package/dist/web/assets/{crystal-D-UygAAF.js → crystal-4nZYHhdi.js} +1 -1
- package/dist/web/assets/{csv-preview-CvP4xzug.js → csv-preview-BqszurHp.js} +1 -1
- package/dist/web/assets/data-grid-overlay-editor-DxdOKRAY.js +1 -0
- package/dist/web/assets/data-grid-types-CzEQU9PJ.js +1 -0
- package/dist/web/assets/database-viewer-CiomoOU6.js +1 -0
- package/dist/web/assets/dialog-BpkAWOy8.js +1 -0
- package/dist/web/assets/{diff-viewer-BfWixe_z.js → diff-viewer-aOrOaGWx.js} +1 -1
- package/dist/web/assets/dist-Bn3E6I4R.js +11 -0
- package/dist/web/assets/{docx-preview-CguUoTKe.js → docx-preview-BAzpJdua.js} +1 -1
- package/dist/web/assets/{edge-BSzxzX11.js → edge-DTI9d2Qi.js} +1 -1
- package/dist/web/assets/{elixir-DH1-Mrep.js → elixir-Ys0wioho.js} +1 -1
- package/dist/web/assets/{elm-B0ln5J70.js → elm-Cihc9TAz.js} +1 -1
- package/dist/web/assets/{erb-GIz6NnlZ.js → erb-BwYBWK2-.js} +1 -1
- package/dist/web/assets/{erlang-B8MgYhib.js → erlang-CzlD_Joo.js} +1 -1
- package/dist/web/assets/esm-JLkfN0k-.js +2 -0
- package/dist/web/assets/{extension-webview-DTpFt1eL.js → extension-webview-CKUUvgOr.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-D_-TrK6U.js → fortran-fixed-form-CT90EtSp.js} +1 -1
- package/dist/web/assets/{fsharp-C9cLCk2b.js → fsharp-LasxezlU.js} +1 -1
- package/dist/web/assets/{gdresource-CsZ3lXwY.js → gdresource-XqgPdfiE.js} +1 -1
- package/dist/web/assets/{git-commit-xmq0KqrA.js → git-commit-CZBgPolw.js} +1 -1
- package/dist/web/assets/{git-log-panel-DUX7N5tN.js → git-log-panel-B6GFWhj4.js} +1 -1
- package/dist/web/assets/{git-rebase-D3O-jsSX.js → git-rebase-C2VzKDB1.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-BKGq--Jw.js +1 -0
- package/dist/web/assets/glide-data-grid-z9FPvRBG.js +138 -0
- package/dist/web/assets/{glimmer-js-g74gESrC.js → glimmer-js-DfjWcOLD.js} +1 -1
- package/dist/web/assets/{glimmer-ts-DF4aDWHT.js → glimmer-ts-DBldQATc.js} +1 -1
- package/dist/web/assets/{glsl-D5LmfW7l.js → glsl-CzNv1NPP.js} +1 -1
- package/dist/web/assets/{graphql-_KI4RuXL.js → graphql-DDyLtQb4.js} +1 -1
- package/dist/web/assets/group-chat-tab-Bu31mwmF.js +1 -0
- package/dist/web/assets/{hack-B1NaTC39.js → hack-CtoYNYkC.js} +1 -1
- package/dist/web/assets/{haml-DDFXadZ4.js → haml-CnBVap7G.js} +1 -1
- package/dist/web/assets/{handlebars-Bp-Jq3K9.js → handlebars-Dg51esUH.js} +1 -1
- package/dist/web/assets/{html-DyB9_5Tj.js → html-Ec2_evSy.js} +1 -1
- package/dist/web/assets/{html-derivative-CC60wi-3.js → html-derivative-Cy-F7ZqL.js} +1 -1
- package/dist/web/assets/{http-C-9qngH4.js → http-C236v8Tg.js} +1 -1
- package/dist/web/assets/{hurl-BtxgpNDs.js → hurl-0rMD2gPU.js} +1 -1
- package/dist/web/assets/{hxml-DOoOS9op.js → hxml-e5uS5jTD.js} +1 -1
- package/dist/web/assets/{image-preview-CZg6FQ3w.js → image-preview-CaX4gpN6.js} +1 -1
- package/dist/web/assets/index-4M24PSHW.js +50 -0
- package/dist/web/assets/index-BYFXiFsa.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BOhGriBF.js +1 -0
- package/dist/web/assets/{jinja-cN-150ao.js → jinja-DybFmhfq.js} +1 -1
- package/dist/web/assets/{jison-CqjsqPq5.js → jison-hkHbixdZ.js} +1 -1
- package/dist/web/assets/{julia-C-I5m8W4.js → julia-QnxY6sRE.js} +1 -1
- package/dist/web/assets/{just-CgsSW9zs.js → just-1Rs-nm8g.js} +1 -1
- package/dist/web/assets/keybindings-store-Cv-U85V6.js +1 -0
- package/dist/web/assets/{latex-BFzR9N2d.js → latex-jEBQqA7u.js} +1 -1
- package/dist/web/assets/{liquid-BWfr-_iC.js → liquid-DfJaZpxG.js} +1 -1
- package/dist/web/assets/{lua-DsXVun6g.js → lua-ti0Jr6-C.js} +1 -1
- package/dist/web/assets/{markdown-renderer-CiQkvWP_.js → markdown-renderer-BNXJygz9.js} +3 -3
- package/dist/web/assets/markdown-renderer-DCsEEdo7.js +1 -0
- package/dist/web/assets/{marko-DWBbo09n.js → marko-DNj4AhPg.js} +1 -1
- package/dist/web/assets/{mdc-CUMe9LOG.js → mdc-DPFwQFe4.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet--5_YEewV.js +1 -0
- package/dist/web/assets/{nextflow-CoYbADOm.js → nextflow-BUrFV5aB.js} +1 -1
- package/dist/web/assets/{nginx-z-JRZREw.js → nginx-BrW9NdOb.js} +1 -1
- package/dist/web/assets/{nim-Ci4LHyBm.js → nim-DS_6PF2p.js} +1 -1
- package/dist/web/assets/notification-store-DADt1gJH.js +1 -0
- package/dist/web/assets/{number-overlay-editor-lnnuUpPI.js → number-overlay-editor-CReXWiQ1.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-CdLFnL8a.js +1 -0
- package/dist/web/assets/{panel-store-D6RV_ztx.js → panel-store-DnbT1c8L.js} +1 -1
- package/dist/web/assets/{pdf-preview-B6ZqANpw.js → pdf-preview-DZzbm9A4.js} +1 -1
- package/dist/web/assets/{perl-pbDimKOO.js → perl-ytm9vKO_.js} +1 -1
- package/dist/web/assets/{php-B003E5v7.js → php-DWTD1Usw.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-COC-h0zz.js +1 -0
- package/dist/web/assets/{trash-2-CbbD5QF1.js → plus-DcuJuDC3.js} +1 -1
- package/dist/web/assets/postgres-viewer-BxpeiVkt.js +3 -0
- package/dist/web/assets/{project-store-Cekcjcom.js → project-store-Sbnqc41N.js} +1 -1
- package/dist/web/assets/{pug-AoueAWJo.js → pug-Bt7KL3_r.js} +1 -1
- package/dist/web/assets/{qml-CepxioQA.js → qml-Dexdon5J.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-CiCfdJNL.js +1 -0
- package/dist/web/assets/{razor-lIvU-Gu-.js → razor-DnYCSl0G.js} +1 -1
- package/dist/web/assets/{rst-Dn-dwElE.js → rst-BEFYzwF8.js} +1 -1
- package/dist/web/assets/{ruby-DmsD1Iz5.js → ruby-BPaXFEjN.js} +1 -1
- package/dist/web/assets/{sas-6IM2P4YP.js → sas-CywiNBp8.js} +1 -1
- package/dist/web/assets/{scss-RgYEZQqh.js → scss-CGk0L6hN.js} +1 -1
- package/dist/web/assets/{settings-store-BkSf4SPQ.js → settings-store-DkRZhj-g.js} +2 -2
- package/dist/web/assets/settings-tab-DJOhpW09.js +1 -0
- package/dist/web/assets/{shaderlab-B0MNEwt4.js → shaderlab-Byjk0kH7.js} +1 -1
- package/dist/web/assets/{shellsession-F8S4LrQI.js → shellsession-DbA70QB6.js} +1 -1
- package/dist/web/assets/{soy-DDlMbX7u.js → soy-Bm97kWiA.js} +1 -1
- package/dist/web/assets/sparkles-B3DmG8PJ.js +1 -0
- package/dist/web/assets/{sparql-kthmGAAe.js → sparql-CawLnniT.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BYNM0RRl.js → sql-query-editor-9TwIPvRj.js} +1 -1
- package/dist/web/assets/sqlite-viewer-D-3i_x28.js +1 -0
- package/dist/web/assets/{stata-Tfbew8La.js → stata-RifEDtNO.js} +1 -1
- package/dist/web/assets/{surrealql-C0LIGqRx.js → surrealql-DGRQa5Lm.js} +1 -1
- package/dist/web/assets/{svelte-CfTy8CGF.js → svelte-w9Hb12aM.js} +1 -1
- package/dist/web/assets/system-monitor-tab-CuVVp2wt.js +1 -0
- package/dist/web/assets/{tab-store-CcLQfu8H.js → tab-store-vn0viMOP.js} +1 -1
- package/dist/web/assets/{templ-V5H1Sbfy.js → templ-BpUwjJXV.js} +1 -1
- package/dist/web/assets/{terminal-tab-CK3lX-0Y.js → terminal-tab-DrSqSrdX.js} +2 -2
- package/dist/web/assets/{tex-C3H3uMZf.js → tex-DJFSsuTD.js} +1 -1
- package/dist/web/assets/tool-cards-CtE_JnF-.js +7 -0
- package/dist/web/assets/treemap-KZPCXAKY-CZwuSCtA.js +1 -0
- package/dist/web/assets/{ts-tags-7AXgG5YS.js → ts-tags-vp9Qvx2O.js} +1 -1
- package/dist/web/assets/{twig-BSyS38T3.js → twig-CoazxjRB.js} +1 -1
- package/dist/web/assets/{use-blob-url-CpyRr7Cx.js → use-blob-url-DdXgVqfz.js} +1 -1
- package/dist/web/assets/use-is-mobile-CE6AamG6.js +1 -0
- package/dist/web/assets/{use-monaco-theme-Jj2OxkAE.js → use-monaco-theme-BvzqffqR.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-DGOXKrJC.js → vendor-mermaid-DPpYkrMf.js} +193 -193
- package/dist/web/assets/{video-preview-BOHxkwKG.js → video-preview-DxdyVATR.js} +1 -1
- package/dist/web/assets/{vue-C4d_br9u.js → vue-CnshsiXd.js} +1 -1
- package/dist/web/assets/{vue-html-CGdoz4vW.js → vue-html-CZshynFp.js} +1 -1
- package/dist/web/assets/{vue-vine-CqNolQlN.js → vue-vine-C5gtp_T1.js} +1 -1
- package/dist/web/assets/{xml-UmCmu-Od.js → xml-BEGJasgj.js} +1 -1
- package/dist/web/assets/{xsl-DJG6USGh.js → xsl-DXpRLjYk.js} +1 -1
- package/dist/web/index.html +22 -20
- package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
- package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
- package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
- package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
- package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
- package/dist/web/sw.js +1 -1
- package/docs/journal/binary-self-upgrade-260724.md +66 -0
- package/nul/docs/claude-agent-sdk-reference.md +780 -0
- package/nul/docs/code-standards.md +1080 -0
- package/nul/docs/codebase-summary.md +916 -0
- package/nul/docs/deployment-guide.md +702 -0
- package/nul/docs/design-guidelines.md +767 -0
- package/nul/docs/extension-development-guide.md +629 -0
- package/nul/docs/journals/260414-1400-ext-git-graph-port-complete.md +147 -0
- package/nul/docs/journals/260414-1452-git-graph-faithful-port.md +144 -0
- package/nul/docs/journals/260414-1810-git-graph-ui-improvements-complete.md +261 -0
- package/nul/docs/journals/260414-2001-bundled-extensions.md +219 -0
- package/nul/docs/journals/260415-frontend-memory-optimization.md +73 -0
- package/nul/docs/lessons-learned.md +70 -0
- package/nul/docs/project-changelog.md +574 -0
- package/nul/docs/project-overview-pdr.md +205 -0
- package/nul/docs/project-roadmap.md +222 -0
- package/nul/docs/system-architecture.md +1961 -0
- package/package.json +1 -1
- package/packages/vscode-compat/node_modules/.bin/tsc.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsc.exe +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.bunx +0 -0
- package/packages/vscode-compat/node_modules/.bin/tsserver.exe +0 -0
- package/spike-group-channel.mjs +156 -0
- package/spike-group-chat.mjs +181 -0
- package/src/server/routes/group-chat.ts +118 -9
- package/src/services/group-chat/agent-runner.ts +15 -2
- package/src/services/group-chat/context-window.ts +15 -0
- package/src/services/group-chat/group-chat.service.ts +178 -79
- package/src/services/group-chat/group-chat.store.ts +30 -0
- package/src/services/group-chat/responder-router.ts +110 -0
- package/src/services/group-chat/transcript-archive.ts +18 -0
- package/src/services/group-chat/turn-engine.ts +183 -105
- package/src/services/jsonl-transcript-parser.ts +36 -0
- package/src/types/group-chat-ws.ts +2 -2
- package/src/types/group-chat.ts +33 -4
- package/src/web/components/group-chat/group-chat-tab.tsx +109 -14
- package/src/web/components/group-chat/group-create-dialog.tsx +10 -3
- package/src/web/components/group-chat/group-full-transcript-view.tsx +9 -8
- package/src/web/components/group-chat/group-member-edit-dialog.tsx +108 -0
- package/src/web/components/group-chat/group-member-roster.tsx +51 -23
- package/src/web/components/group-chat/group-message-item.tsx +45 -26
- package/src/web/components/group-chat/group-transcript-messages.tsx +126 -0
- package/src/web/components/layout/cloud-share-popover.tsx +10 -2
- package/src/web/components/layout/mobile-drawer-tab-bar.tsx +10 -0
- package/src/web/components/layout/mobile-drawer.tsx +26 -9
- package/src/web/components/layout/nav-section-rail.tsx +8 -2
- package/src/web/components/layout/upgrade-button.tsx +33 -11
- package/src/web/hooks/use-group-chat.ts +8 -1
- package/src/web/lib/api-group-chat.ts +47 -4
- package/src/web/lib/sidebar-tabs/tab-registry.ts +3 -1
- package/dist/web/assets/architecture-PBZL5I3N-NAS99xy0.js +0 -1
- package/dist/web/assets/chat-tab-Bh6l253v.js +0 -18
- package/dist/web/assets/click-outside-container-DXZVmhaX.js +0 -1
- package/dist/web/assets/code-editor-B7F-d4DK.js +0 -10
- package/dist/web/assets/data-grid-overlay-editor-CUlFsD-D.js +0 -1
- package/dist/web/assets/database-viewer-5oNTPgjF.js +0 -1
- package/dist/web/assets/dist-BsziT-tR.js +0 -11
- package/dist/web/assets/esm-CjVeOTNQ.js +0 -2
- package/dist/web/assets/gitGraph-HDMCJU4V-B4I3L4Sf.js +0 -1
- package/dist/web/assets/glide-data-grid-7vB1SNne.js +0 -138
- package/dist/web/assets/group-chat-tab-CNECY-zg.js +0 -1
- package/dist/web/assets/index-D2G6kmTs.js +0 -50
- package/dist/web/assets/index-DCmrZnq0.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-CBbbOe3C.js +0 -1
- package/dist/web/assets/input-24Nf_edC.js +0 -1
- package/dist/web/assets/keybindings-store-D8Cppv4w.js +0 -1
- package/dist/web/assets/notification-store-DOGxkWih.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-fr8-QSTF.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-Biu7_Pbb.js +0 -1
- package/dist/web/assets/postgres-viewer-B23xTCSs.js +0 -3
- package/dist/web/assets/radar-KQ55EAFF-CMtNRpK6.js +0 -1
- package/dist/web/assets/settings-tab-D5hAA1bY.js +0 -1
- package/dist/web/assets/sparkles-2ii4lR7b.js +0 -1
- package/dist/web/assets/sqlite-viewer-DW9f2Hqj.js +0 -1
- package/dist/web/assets/system-monitor-tab-B5f4pgdX.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-ZYVFjoaN.js +0 -1
- package/dist/web/assets/use-websocket-DrDBgIWU.js +0 -1
- /package/dist/web/assets/{abap-BZ3J5hF3.js → abap-wT6fgqwv.js} +0 -0
- /package/dist/web/assets/{actionscript-3-CkyGfT-8.js → actionscript-3-CqcHpPYj.js} +0 -0
- /package/dist/web/assets/{ada-CxNLBoe7.js → ada-DWE3Hn4E.js} +0 -0
- /package/dist/web/assets/{andromeeda-BPN5rsDz.js → andromeeda-DpQ-y-Jt.js} +0 -0
- /package/dist/web/assets/{apache-C1F5wHL6.js → apache-LRTUP4r3.js} +0 -0
- /package/dist/web/assets/{apex-BaNixdO-.js → apex-DwVeH5_h.js} +0 -0
- /package/dist/web/assets/{api-client-Dvzcc_EO.js → api-client-BK4NPNoY.js} +0 -0
- /package/dist/web/assets/{applescript-Cl_pdcch.js → applescript-DyQiO9JU.js} +0 -0
- /package/dist/web/assets/{apply-theme-ORrEdHKT.js → apply-theme-DxKsrDLA.js} +0 -0
- /package/dist/web/assets/{ara-B6UAE7M2.js → ara-Cf-OWd2S.js} +0 -0
- /package/dist/web/assets/{asciidoc-D9c9Twki.js → asciidoc-gocbKcVK.js} +0 -0
- /package/dist/web/assets/{asm-CNmtv7Y9.js → asm-C3meb5HY.js} +0 -0
- /package/dist/web/assets/{aurora-x-C9z-NyzR.js → aurora-x-BYcXaCIg.js} +0 -0
- /package/dist/web/assets/{awk-BfLHEnKa.js → awk-BcT6nIdN.js} +0 -0
- /package/dist/web/assets/{ayu-dark-Bn7trkt_.js → ayu-dark-CLZPoccg.js} +0 -0
- /package/dist/web/assets/{ayu-light-Dpya9hPf.js → ayu-light-CTyRQdS2.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-Cc0jfABD.js → ayu-mirage-DjqfqZdo.js} +0 -0
- /package/dist/web/assets/{ballerina-BtiCmN7T.js → ballerina-BCARR-zK.js} +0 -0
- /package/dist/web/assets/{bat-tmFM76zR.js → bat-_yaRjWOb.js} +0 -0
- /package/dist/web/assets/{beancount-BjPqRrcH.js → beancount-BPESBMS9.js} +0 -0
- /package/dist/web/assets/{berry-D0SQBxN2.js → berry-BSLE-Sf8.js} +0 -0
- /package/dist/web/assets/{bibtex-CkjRWQKr.js → bibtex-CvUWWCVx.js} +0 -0
- /package/dist/web/assets/{bicep-Bhq28Cxc.js → bicep--vcqqALZ.js} +0 -0
- /package/dist/web/assets/{bird2-DFGInYb3.js → bird2-Clclqgh6.js} +0 -0
- /package/dist/web/assets/{c-CP8cB4k_.js → c-CSC2LwTp.js} +0 -0
- /package/dist/web/assets/{c3-oRytyeWo.js → c3-Cl1_jUnm.js} +0 -0
- /package/dist/web/assets/{cadence-Inf1rGb7.js → cadence-BwAD7vSC.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DAzribQo.js → catppuccin-frappe-hr0HKoFX.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-B6Y_mCCQ.js → catppuccin-latte-DXEIYlFO.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-COLbYqVL.js → catppuccin-macchiato-B2zST7sA.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-DKWaML1B.js → catppuccin-mocha-CvrdnYv9.js} +0 -0
- /package/dist/web/assets/{chevron-right-BBc6ATtm.js → chevron-right-DeUue2aK.js} +0 -0
- /package/dist/web/assets/{circle-question-mark-CveWaCux.js → circle-question-mark-PaJgx-3d.js} +0 -0
- /package/dist/web/assets/{clarity-_ZLLrrsX.js → clarity-BeQd5TQD.js} +0 -0
- /package/dist/web/assets/{clojure-DWGVCg_P.js → clojure-Csdo0vb_.js} +0 -0
- /package/dist/web/assets/{cmake-Cwh3mug7.js → cmake-Cf0q7ddg.js} +0 -0
- /package/dist/web/assets/{code-7ZAlTvsm.js → code-TekEnDFM.js} +0 -0
- /package/dist/web/assets/{codeowners-BdV6CFYi.js → codeowners-CUEzlC7R.js} +0 -0
- /package/dist/web/assets/{codeql-NvupDIDf.js → codeql-DxHyogQt.js} +0 -0
- /package/dist/web/assets/{common-lisp-B-vtBh5k.js → common-lisp-WLb-tAda.js} +0 -0
- /package/dist/web/assets/{coq-M8-FTfiZ.js → coq-DFtMD6Wn.js} +0 -0
- /package/dist/web/assets/{csharp-B7Ugdtd-.js → csharp-DEnvXVjs.js} +0 -0
- /package/dist/web/assets/{css-86k3Z-YA.js → css-DMPpCfkZ.js} +0 -0
- /package/dist/web/assets/{csv-BX5XYhfH.js → csv-DTSgNSaP.js} +0 -0
- /package/dist/web/assets/{csv-parser-d56Fzpwc.js → csv-parser-B_xNn07y.js} +0 -0
- /package/dist/web/assets/{cue-B7099gQa.js → cue-BEmVIZmd.js} +0 -0
- /package/dist/web/assets/{cypher-D99mWVIu.js → cypher-CncQVhvU.js} +0 -0
- /package/dist/web/assets/{d-CFE8oQwh.js → d-BzUSBVex.js} +0 -0
- /package/dist/web/assets/{dark-plus-BEeeDwdg.js → dark-plus-mysFNRq2.js} +0 -0
- /package/dist/web/assets/{dart-HVSWGnI5.js → dart-BBu3nkcE.js} +0 -0
- /package/dist/web/assets/{database-BLht7BVM.js → database-COYAMZaw.js} +0 -0
- /package/dist/web/assets/{dax-DjDgSJkh.js → dax-DcLVz9_9.js} +0 -0
- /package/dist/web/assets/{desktop-B5A3i7J1.js → desktop-DS2PdvoU.js} +0 -0
- /package/dist/web/assets/{diff-CpTrlaE9.js → diff-aUYk5Qys.js} +0 -0
- /package/dist/web/assets/{dist-BSCgJs-V.js → dist-Dxl3dqhC.js} +0 -0
- /package/dist/web/assets/{docker-xBhmJeHj.js → docker-12Lj1QUD.js} +0 -0
- /package/dist/web/assets/{dotenv-DKKhLEv5.js → dotenv-D-P4bzvl.js} +0 -0
- /package/dist/web/assets/{dracula-CVwQuzra.js → dracula-C-eRNn4o.js} +0 -0
- /package/dist/web/assets/{dracula-soft-CG6mB-lf.js → dracula-soft-CBB1BI7O.js} +0 -0
- /package/dist/web/assets/{dream-maker-SC-IdYY3.js → dream-maker-C_j5A0r7.js} +0 -0
- /package/dist/web/assets/{edit-diff-preview-C50i1H63.js → edit-diff-preview-CRMu-6r1.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-CIBFq6W8.js → emacs-lisp-W54LT7rh.js} +0 -0
- /package/dist/web/assets/{everforest-dark-odRT_lec.js → everforest-dark-B_ISUDeh.js} +0 -0
- /package/dist/web/assets/{everforest-light-or1Voqjl.js → everforest-light-CNUYa354.js} +0 -0
- /package/dist/web/assets/{fennel-tQd1z3iu.js → fennel-DK82-oso.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-C-lL0g_E.js → file-exclamation-point-DBEC-Kst.js} +0 -0
- /package/dist/web/assets/{fish-DSuZQG0k.js → fish-CbJVJzQj.js} +0 -0
- /package/dist/web/assets/{fluent-D7xI8a8e.js → fluent-Cug5cOL1.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-BlAtcPd3.js → fortran-free-form-amHz32Zw.js} +0 -0
- /package/dist/web/assets/{gdscript-VsEQXBPm.js → gdscript-t_G6VYpv.js} +0 -0
- /package/dist/web/assets/{gdshader-iqHMOdwW.js → gdshader-DqZaHh4E.js} +0 -0
- /package/dist/web/assets/{genie-C4XU4g1a.js → genie-CIJtFlZK.js} +0 -0
- /package/dist/web/assets/{gherkin-C4nfQzAB.js → gherkin-CalidqLY.js} +0 -0
- /package/dist/web/assets/{github-dark-B_pbG3CC.js → github-dark-BG2xX0wa.js} +0 -0
- /package/dist/web/assets/{github-dark-default-kFbx7C95.js → github-dark-default-tDp_EOBs.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-CpVfQEqs.js → github-dark-dimmed-DlSfPwW2.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-DYKqQwZh.js → github-dark-high-contrast-qZM7j5KB.js} +0 -0
- /package/dist/web/assets/{github-light-gEYBmKaj.js → github-light-CnvWTiyb.js} +0 -0
- /package/dist/web/assets/{github-light-default-DVHfMPQ2.js → github-light-default-Dy6OAt2Q.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-ClVJDu-q.js → github-light-high-contrast-1BHQCOPl.js} +0 -0
- /package/dist/web/assets/{gleam-BLaPu7ft.js → gleam-D-2cpXVX.js} +0 -0
- /package/dist/web/assets/{gn-BKgerUyI.js → gn-C1cC4xLc.js} +0 -0
- /package/dist/web/assets/{gnuplot-cqJuEFb-.js → gnuplot-2Gp459mV.js} +0 -0
- /package/dist/web/assets/{go-B2EHdyD8.js → go-BA1q0q8h.js} +0 -0
- /package/dist/web/assets/{groovy-DdImoj8s.js → groovy-BlIa-VfI.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-DlwstAds.js → gruvbox-dark-hard-BMIwVwaJ.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-CiYEd1vd.js → gruvbox-dark-medium-DxfuBW3n.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-C-wEa4h4.js → gruvbox-dark-soft-_NSslDDi.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BqYmfna-.js → gruvbox-light-hard-CP5MIsL9.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CxmfalT2.js → gruvbox-light-medium-BTMursH0.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-DGWXXMCB.js → gruvbox-light-soft-Bv6zFoVX.js} +0 -0
- /package/dist/web/assets/{haskell-H_C_IuVb.js → haskell-Da8UeSv-.js} +0 -0
- /package/dist/web/assets/{haxe-CGNSMpeZ.js → haxe-mcKlcxBa.js} +0 -0
- /package/dist/web/assets/{hcl-B7bSTSQf.js → hcl-BdZcx5JX.js} +0 -0
- /package/dist/web/assets/{hjson-DlJ-glQZ.js → hjson-pFXYbN4t.js} +0 -0
- /package/dist/web/assets/{hlsl-CehW5SJN.js → hlsl-Z0II0KR8.js} +0 -0
- /package/dist/web/assets/{horizon-Beabcz2d.js → horizon-CufN8DyP.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BC87RXPa.js → horizon-bright-5qoQVyIY.js} +0 -0
- /package/dist/web/assets/{houston-Da7RFwUy.js → houston-DOFkQwep.js} +0 -0
- /package/dist/web/assets/{hy-m1H70w19.js → hy-BVbDMDcG.js} +0 -0
- /package/dist/web/assets/{imba-MExFsdAA.js → imba-DRM6LLS5.js} +0 -0
- /package/dist/web/assets/{ini-CJy_zmwy.js → ini-2KCnNvmz.js} +0 -0
- /package/dist/web/assets/{java-DqDFvJBH.js → java-BmvH-Ou1.js} +0 -0
- /package/dist/web/assets/{javascript-C3Wyv22X.js → javascript-B7VhU1Yc.js} +0 -0
- /package/dist/web/assets/{json-DnGBw_DZ.js → json-X1pNk0n7.js} +0 -0
- /package/dist/web/assets/{json5-CRN-zoN4.js → json5-CJeEJPTg.js} +0 -0
- /package/dist/web/assets/{jsonc-CKRUZNRo.js → jsonc-C1haTBsf.js} +0 -0
- /package/dist/web/assets/{jsonl-CGfD6FrH.js → jsonl-wQ8-AJgs.js} +0 -0
- /package/dist/web/assets/{jsonnet-nbFuDj0o.js → jsonnet-BrEjY3Xh.js} +0 -0
- /package/dist/web/assets/{jssm-D0ShzIqD.js → jssm-C6LgYbOs.js} +0 -0
- /package/dist/web/assets/{jsx-D27hbRbs.js → jsx-B2cfD_Fb.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-Ov3f8K0T.js → kanagawa-dragon-6UCcJpLw.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-CLyOqh-g.js → kanagawa-lotus-DOmfpsRg.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-Kj3dzabH.js → kanagawa-wave-CpxmPE7N.js} +0 -0
- /package/dist/web/assets/{kdl-DFF58Gu4.js → kdl-BrLEivmb.js} +0 -0
- /package/dist/web/assets/{kotlin-BM4PKaB4.js → kotlin-BO2FUnDB.js} +0 -0
- /package/dist/web/assets/{kusto-DrvHLCv5.js → kusto-Cev1yiq9.js} +0 -0
- /package/dist/web/assets/{laserwave-Db6i6ZkO.js → laserwave-BlEkf-eH.js} +0 -0
- /package/dist/web/assets/{lean-D0hEjzwk.js → lean-BLS3Xk2w.js} +0 -0
- /package/dist/web/assets/{less-BEj4npGG.js → less-BXmcsqcq.js} +0 -0
- /package/dist/web/assets/{lib-CBdlQ75W.js → lib-CxSBdrd7.js} +0 -0
- /package/dist/web/assets/{light-plus-DLIIbDea.js → light-plus-DS6zriYl.js} +0 -0
- /package/dist/web/assets/{llvm-DMt6umsO.js → llvm-C_wLnJgX.js} +0 -0
- /package/dist/web/assets/{log-BopvdtPW.js → log-Cg8pvmWi.js} +0 -0
- /package/dist/web/assets/{logo-CYSUFPFR.js → logo-C9-kEvPW.js} +0 -0
- /package/dist/web/assets/{luau-XC611HNO.js → luau-NwaGugfZ.js} +0 -0
- /package/dist/web/assets/{make-BMYZIfBj.js → make-DBpJE-Z8.js} +0 -0
- /package/dist/web/assets/{markdown-BLza5nvF.js → markdown-B7ZTAu7B.js} +0 -0
- /package/dist/web/assets/{material-theme-Uw27UfJW.js → material-theme-BsXH-Mss.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-dfqt8XBY.js → material-theme-darker-CW9OlIeY.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-CPtBTblV.js → material-theme-lighter-D2PAh0Kw.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-BfZgVqC-.js → material-theme-ocean-Vz6DBVi3.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DAZoVYg8.js → material-theme-palenight-D-GleP3G.js} +0 -0
- /package/dist/web/assets/{matlab-cSzmquiW.js → matlab-C7MYlMSn.js} +0 -0
- /package/dist/web/assets/{mdx-Dq0kW5VM.js → mdx-FkOOX3Dq.js} +0 -0
- /package/dist/web/assets/{mermaid-DoIKF0yS.js → mermaid-C_9qw5it.js} +0 -0
- /package/dist/web/assets/{min-dark-DyraimDU.js → min-dark-BowNvxk2.js} +0 -0
- /package/dist/web/assets/{min-light-Co9cbcUv.js → min-light-x8oWUmbL.js} +0 -0
- /package/dist/web/assets/{mipsasm-ph6cKgHn.js → mipsasm-Dmi1AZOT.js} +0 -0
- /package/dist/web/assets/{mojo-BBT0XwmY.js → mojo-C6z7mry2.js} +0 -0
- /package/dist/web/assets/{monokai-IP0T5Rtg.js → monokai-BQ4e_Hn0.js} +0 -0
- /package/dist/web/assets/{moonbit-B8cogNXl.js → moonbit-CEeNIoB4.js} +0 -0
- /package/dist/web/assets/{move-DkY26NtM.js → move-bALfKUa7.js} +0 -0
- /package/dist/web/assets/{narrat-rBs3byG0.js → narrat-DX4JlAWT.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-DkO9wMLP.js → nextflow-groovy-CKQWtRkO.js} +0 -0
- /package/dist/web/assets/{night-owl-jVR4lFji.js → night-owl-D4PQd726.js} +0 -0
- /package/dist/web/assets/{night-owl-light-fBYJ7s3U.js → night-owl-light-BQo_YHll.js} +0 -0
- /package/dist/web/assets/{nix-WX9oavu6.js → nix-B1jThkGj.js} +0 -0
- /package/dist/web/assets/{nord-Cf7G21Pu.js → nord-35quHUKo.js} +0 -0
- /package/dist/web/assets/{nushell-DQdzcJ1H.js → nushell-L6DbJTuL.js} +0 -0
- /package/dist/web/assets/{objective-c-JSO2uvZ-.js → objective-c-CTZ4bR2U.js} +0 -0
- /package/dist/web/assets/{objective-cpp-CZMGJ9Fb.js → objective-cpp-Dm1YDIdA.js} +0 -0
- /package/dist/web/assets/{ocaml-C4S4NSDo.js → ocaml-B3n__LGy.js} +0 -0
- /package/dist/web/assets/{odin-Y2jXCgVq.js → odin-DmqZ8n3i.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-dVIxuoJY.js → one-dark-pro-16_UaUig.js} +0 -0
- /package/dist/web/assets/{one-light-BQ1IKfD1.js → one-light-B-GGjWn5.js} +0 -0
- /package/dist/web/assets/{openscad-Bddw4I3z.js → openscad-DTFB9Sj6.js} +0 -0
- /package/dist/web/assets/{pascal-BKVXrzC1.js → pascal-RcT1dQYN.js} +0 -0
- /package/dist/web/assets/{pkl-BTd-YRsO.js → pkl-Dr4yLQ_o.js} +0 -0
- /package/dist/web/assets/{plastic-eiGvBIxV.js → plastic-hp2Nry0R.js} +0 -0
- /package/dist/web/assets/{plsql-C290tieP.js → plsql-pFcO4WZ0.js} +0 -0
- /package/dist/web/assets/{po-DyDwh0tx.js → po-BkZ0_HvY.js} +0 -0
- /package/dist/web/assets/{poimandres-B87zc_g-.js → poimandres-BcTrxj7f.js} +0 -0
- /package/dist/web/assets/{polar-Cdub1YMT.js → polar-DHK3q8FF.js} +0 -0
- /package/dist/web/assets/{postcss-BcI_3K0v.js → postcss-Bv7WzijA.js} +0 -0
- /package/dist/web/assets/{powerquery-OdMrkJSe.js → powerquery-DpaU_hW9.js} +0 -0
- /package/dist/web/assets/{powershell-C8auT6xg.js → powershell-_Rqc0MGP.js} +0 -0
- /package/dist/web/assets/{prisma-DIbVv8PA.js → prisma-wyegE8us.js} +0 -0
- /package/dist/web/assets/{prolog-DbTOH3Ld.js → prolog-DspHCURv.js} +0 -0
- /package/dist/web/assets/{proto-C4Cq2dCD.js → proto-BOBiNGf5.js} +0 -0
- /package/dist/web/assets/{puppet-DJp3uqum.js → puppet-DfLvV8h2.js} +0 -0
- /package/dist/web/assets/{purescript-CLsV4rPU.js → purescript-BY5ZSOZy.js} +0 -0
- /package/dist/web/assets/{python-2gBtEza2.js → python-B758mMeg.js} +0 -0
- /package/dist/web/assets/{qmldir-DfhULcua.js → qmldir-C75bpHvy.js} +0 -0
- /package/dist/web/assets/{qss-DK--VTTV.js → qss-DcLTlbLd.js} +0 -0
- /package/dist/web/assets/{r-BArBO2Sa.js → r-D0G_Y1P5.js} +0 -0
- /package/dist/web/assets/{racket-5mijHsVy.js → racket-DTye_5qn.js} +0 -0
- /package/dist/web/assets/{raku-ir0suElk.js → raku-uJXBXkV0.js} +0 -0
- /package/dist/web/assets/{react-J9g6e3Rq.js → react-CorNPdie.js} +0 -0
- /package/dist/web/assets/{red-DSecpIOT.js → red-rs3HE3re.js} +0 -0
- /package/dist/web/assets/{reg-Dp30FusS.js → reg-DkTIaX7a.js} +0 -0
- /package/dist/web/assets/{regexp-DXJnEM_6.js → regexp-4TLSs4_m.js} +0 -0
- /package/dist/web/assets/{rel-Dr483ozj.js → rel-B0jumCjt.js} +0 -0
- /package/dist/web/assets/{resolve-theme-DJORYzKu.js → resolve-theme-CCoakF2E.js} +0 -0
- /package/dist/web/assets/{riscv-ZfBy5IA1.js → riscv-DtaWMlo0.js} +0 -0
- /package/dist/web/assets/{ron-ZJ_CljGP.js → ron-BCPxwJD6.js} +0 -0
- /package/dist/web/assets/{rose-pine-CcW_eJ6G.js → rose-pine-CNryoqGi.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-v2l_UF-j.js → rose-pine-dawn-C-gJOQVP.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CNXkwf3D.js → rose-pine-moon-BdXSXpZh.js} +0 -0
- /package/dist/web/assets/{rosmsg-BMYMVW84.js → rosmsg-CPG8X-D5.js} +0 -0
- /package/dist/web/assets/{rust-BR-zJh5q.js → rust-CxfW3ePx.js} +0 -0
- /package/dist/web/assets/{sass-BukPOBFz.js → sass-D-7bxo_L.js} +0 -0
- /package/dist/web/assets/{save-DO5xjW95.js → save-BM4p9_9n.js} +0 -0
- /package/dist/web/assets/{scala-DUFY7D6D.js → scala-DyUsfHNc.js} +0 -0
- /package/dist/web/assets/{scheme-Dl-dNNxQ.js → scheme-ROgrwiO-.js} +0 -0
- /package/dist/web/assets/{sdbl-DdmlQhia.js → sdbl-B1EAQWpp.js} +0 -0
- /package/dist/web/assets/{shellscript-UyhrvGcd.js → shellscript-HhmB_Ufy.js} +0 -0
- /package/dist/web/assets/{shield-check-m2QzZTuZ.js → shield-check-C3qYSU8a.js} +0 -0
- /package/dist/web/assets/{shield-off-DNn7VzJe.js → shield-off-D5tU7gQT.js} +0 -0
- /package/dist/web/assets/{slack-dark-Cv6Szr-q.js → slack-dark-DnmSY72G.js} +0 -0
- /package/dist/web/assets/{slack-ochin-V6Ii3lAm.js → slack-ochin-q97gHjcd.js} +0 -0
- /package/dist/web/assets/{smalltalk-BUCv5G91.js → smalltalk-B-1waXvA.js} +0 -0
- /package/dist/web/assets/{snazzy-light-B67a78qi.js → snazzy-light-C8yWDN2g.js} +0 -0
- /package/dist/web/assets/{solarized-dark-ccWnfYyA.js → solarized-dark-ClVDEMJZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-C3WyRO5I.js → solarized-light-Bts6CUIP.js} +0 -0
- /package/dist/web/assets/{solidity-BFbRPNi_.js → solidity-DYxwp0om.js} +0 -0
- /package/dist/web/assets/{splunk-zdpwCJLE.js → splunk-jK6-Sr06.js} +0 -0
- /package/dist/web/assets/{sql-B2IPUsfz.js → sql-DPpd8aUS.js} +0 -0
- /package/dist/web/assets/{ssh-config-Co4cXifq.js → ssh-config-Bimb9LVr.js} +0 -0
- /package/dist/web/assets/{stylus-CmI75XY8.js → stylus-B2DgJRJw.js} +0 -0
- /package/dist/web/assets/{swift-Dfks9YQI.js → swift-ChEH2nFL.js} +0 -0
- /package/dist/web/assets/{synthwave-84-B3LERzNS.js → synthwave-84-DwSLbgAm.js} +0 -0
- /package/dist/web/assets/{system-verilog-BFvldiwl.js → system-verilog-DoVBMhJ8.js} +0 -0
- /package/dist/web/assets/{systemd-Cu4Vvgbu.js → systemd--Ux4VAYD.js} +0 -0
- /package/dist/web/assets/{table-CAVmgQMT.js → table-Di8pv2Y_.js} +0 -0
- /package/dist/web/assets/{talonscript-Bnq32pUB.js → talonscript-DQNx9nak.js} +0 -0
- /package/dist/web/assets/{tasl-Nwe2K3J1.js → tasl-Bwy_Y9uD.js} +0 -0
- /package/dist/web/assets/{tcl-zOnpywrl.js → tcl-Drea-2jA.js} +0 -0
- /package/dist/web/assets/{terraform-Bc9Vj-n3.js → terraform-4rS5HoFk.js} +0 -0
- /package/dist/web/assets/{tokyo-night-9_KyM8M2.js → tokyo-night-C9MqaxIn.js} +0 -0
- /package/dist/web/assets/{toml-ByH-fxOY.js → toml-tSgOSv42.js} +0 -0
- /package/dist/web/assets/{tsv-DrCnDClP.js → tsv-BmL4O1Zx.js} +0 -0
- /package/dist/web/assets/{tsx-B8LafSYr.js → tsx-BwzeA880.js} +0 -0
- /package/dist/web/assets/{turtle-DuyP_QCJ.js → turtle-2DYvssFL.js} +0 -0
- /package/dist/web/assets/{typescript-BTBJb5RD.js → typescript-ZC-vonSh.js} +0 -0
- /package/dist/web/assets/{typespec-DdOFo7M5.js → typespec-DkCEO45F.js} +0 -0
- /package/dist/web/assets/{typst-LYvnBWQu.js → typst-DAZdb2n6.js} +0 -0
- /package/dist/web/assets/{utils-CTg5uAYR.js → utils-CSCvNZxE.js} +0 -0
- /package/dist/web/assets/{v-BuBYA1_x.js → v-B_wsb4C1.js} +0 -0
- /package/dist/web/assets/{vala-vRIBYYe3.js → vala-BDBNS784.js} +0 -0
- /package/dist/web/assets/{vb-DwGi-IYM.js → vb-CuOoJSSa.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-i6SHFTfU.js → vendor-xterm-CImj6i6Z.js} +0 -0
- /package/dist/web/assets/{verilog-6B1X4G2-.js → verilog-BCcOvOcc.js} +0 -0
- /package/dist/web/assets/{vesper-Dw1y_Ae7.js → vesper-vN8CREK5.js} +0 -0
- /package/dist/web/assets/{vhdl-DK8JwBzJ.js → vhdl-CI8PoqeM.js} +0 -0
- /package/dist/web/assets/{viml-BTKIEIqm.js → viml-B66dNP1B.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BqqolhEg.js → vitesse-black-0bGIaCfD.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-B9JL5WQA.js → vitesse-dark-Dk-RSXq-.js} +0 -0
- /package/dist/web/assets/{vitesse-light-DYJKj2se.js → vitesse-light-BUsA5RhG.js} +0 -0
- /package/dist/web/assets/{vyper-D-jDI3WH.js → vyper-dNodzEa8.js} +0 -0
- /package/dist/web/assets/{wasm-1-GlNdpk.js → wasm-BDxaNPCj.js} +0 -0
- /package/dist/web/assets/{wasm-BBW4WmT2.js → wasm-d6SE2_qm.js} +0 -0
- /package/dist/web/assets/{wenyan-B6cM7sDO.js → wenyan-D0h8Uz55.js} +0 -0
- /package/dist/web/assets/{wgsl-FaHGQgko.js → wgsl-vKs_vsvQ.js} +0 -0
- /package/dist/web/assets/{wikitext-DtIyPUrk.js → wikitext-BIWsPJit.js} +0 -0
- /package/dist/web/assets/{wit-BMVRif5Y.js → wit-6vmKi2H3.js} +0 -0
- /package/dist/web/assets/{wolfram-DQsCGohn.js → wolfram-zoNg6F1a.js} +0 -0
- /package/dist/web/assets/{x-C2VSAp7O.js → x-BsFLg-T8.js} +0 -0
- /package/dist/web/assets/{yaml-C-Va56Gt.js → yaml-W95qP6-B.js} +0 -0
- /package/dist/web/assets/{zenscript-DdobKGI-.js → zenscript-BxircxDx.js} +0 -0
- /package/dist/web/assets/{zig-vqDFwj6q.js → zig-DD79WQtz.js} +0 -0
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type Group,
|
|
3
3
|
type GroupMember,
|
|
4
|
-
type
|
|
4
|
+
type BurstResult,
|
|
5
|
+
type BurstEndReason,
|
|
5
6
|
type TurnEngineDeps,
|
|
6
|
-
type TurnLoopResult,
|
|
7
|
-
type TerminationReason,
|
|
8
7
|
} from "../../types/group-chat.ts";
|
|
9
|
-
import { buildContextWindow,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
*
|
|
8
|
+
import { buildContextWindow, renderFull, DEFAULT_WINDOW } from "./context-window.ts";
|
|
9
|
+
import { dispatchParallel } from "./agent-runner.ts";
|
|
10
|
+
|
|
11
|
+
/** Max AI turns triggered by a single user message before yielding back to the user.
|
|
12
|
+
* Headroom for delegate → members report → leader wrap-up; the router ends earlier
|
|
13
|
+
* (returns none) when there's nothing left to add. */
|
|
14
|
+
export const REPLY_BURST_CAP = 10;
|
|
15
|
+
|
|
16
|
+
/** Matches @name mentions; unicode-aware so non-ASCII member names (e.g. "Bình") work. */
|
|
17
|
+
const MENTION_RE = /@([\p{L}\p{N}_]+)/u;
|
|
18
|
+
const MENTION_RE_G = /@([\p{L}\p{N}_]+)/gu;
|
|
19
|
+
/** Feed summary cap — the bus stores a short summary; full text lives in the member session. */
|
|
15
20
|
const SUMMARY_CAP = 600;
|
|
16
21
|
|
|
17
22
|
/** Cap a turn's text for the feed: first paragraph, bounded to SUMMARY_CAP. */
|
|
@@ -31,134 +36,207 @@ function leaderOf(members: GroupMember[]): GroupMember {
|
|
|
31
36
|
return leader;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (current === leader.name) {
|
|
42
|
-
const other = members.find((x) => x.role !== "leader");
|
|
43
|
-
return other?.name ?? leader.name;
|
|
39
|
+
/** Explicit @mentions of known members in the user's message (in order, deduped). */
|
|
40
|
+
export function parseMentions(userText: string, members: GroupMember[]): string[] {
|
|
41
|
+
const out: string[] = [];
|
|
42
|
+
const seen = new Set<string>();
|
|
43
|
+
for (const m of userText.matchAll(MENTION_RE_G)) {
|
|
44
|
+
const name = m[1]!;
|
|
45
|
+
if (!seen.has(name) && findMember(members, name)) { out.push(name); seen.add(name); }
|
|
44
46
|
}
|
|
45
|
-
return
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Who replies to a user message (legacy mention-following mode): each @mentioned member;
|
|
51
|
+
* if none mentioned, the leader answers. */
|
|
52
|
+
export function selectInitialResponders(userText: string, members: GroupMember[]): string[] {
|
|
53
|
+
const mentions = parseMentions(userText, members);
|
|
54
|
+
return mentions.length > 0 ? mentions : [leaderOf(members).name];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Next teammate to pull in from a reply's @mention, or null when the reply has no
|
|
58
|
+
* valid teammate mention (i.e. it was addressed to the user → end the burst). */
|
|
59
|
+
export function selectNextSpeaker(text: string, current: string, members: GroupMember[]): string | null {
|
|
60
|
+
const target = text.match(MENTION_RE)?.[1];
|
|
61
|
+
if (target && target !== current && findMember(members, target)) return target;
|
|
62
|
+
return null;
|
|
46
63
|
}
|
|
47
64
|
|
|
48
|
-
/** Build the per-turn prompt for `speaker
|
|
49
|
-
*
|
|
65
|
+
/** Build the per-turn prompt for `speaker`. Keep-alive sessions retain the member's own
|
|
66
|
+
* past turns natively, so inject only the shared-channel DELTA since it last spoke (full
|
|
67
|
+
* text). First turn ever → the recent window (+ rolling summary) as a cold start. No
|
|
68
|
+
* task/DONE language; the member must not hand off (a coordinator picks the next speaker). */
|
|
50
69
|
export function buildTurnContext(
|
|
51
70
|
group: Group,
|
|
52
71
|
speaker: GroupMember,
|
|
53
72
|
members: GroupMember[],
|
|
54
|
-
task: string,
|
|
55
73
|
deps: TurnEngineDeps,
|
|
56
|
-
opts: { window?: number
|
|
74
|
+
opts: { window?: number } = {},
|
|
57
75
|
): string {
|
|
58
76
|
const window = opts.window ?? DEFAULT_WINDOW;
|
|
59
77
|
const prior = deps.readMessages(group.id);
|
|
60
|
-
const { window: recent, rollingSummary } = buildContextWindow(prior, window);
|
|
61
78
|
const others = members.filter((m) => m.name !== speaker.name).map((m) => m.name).join(", ");
|
|
62
|
-
const isLeader = speaker.role === "leader";
|
|
63
79
|
const persona = speaker.persona ? `, ${speaker.persona}` : "";
|
|
64
80
|
|
|
81
|
+
// Last turn index this member itself produced (native memory covers ≤ this).
|
|
82
|
+
const lastSeen = prior.reduce(
|
|
83
|
+
(mx, m) => (m.fromMember === speaker.name && m.turnIndex > mx ? m.turnIndex : mx),
|
|
84
|
+
-1,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
let contextBlock: string;
|
|
88
|
+
if (lastSeen >= 0) {
|
|
89
|
+
const delta = prior.filter((m) => m.turnIndex > lastSeen);
|
|
90
|
+
contextBlock = `\nNEW SINCE YOU LAST SPOKE:\n${delta.length ? renderFull(delta) : "(nothing new)"}`;
|
|
91
|
+
} else {
|
|
92
|
+
const { window: recent, rollingSummary } = buildContextWindow(prior, window);
|
|
93
|
+
contextBlock =
|
|
94
|
+
(rollingSummary ? `\nEARLIER (summary):\n${rollingSummary}` : "") +
|
|
95
|
+
`\nGROUP CHAT (recent):\n${renderFull(recent)}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
65
98
|
const parts = [
|
|
66
|
-
`You are "${speaker.name}"${persona}.`,
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
isLeader
|
|
72
|
-
? (opts.forceFinal
|
|
73
|
-
? `You MUST finalize now: start your message with "DONE:" then the decision + 1 reason.`
|
|
74
|
-
: `If the team has converged, start with "DONE:" then the decision + 1 reason. Otherwise steer the discussion and @ someone.`)
|
|
75
|
-
: `Do NOT write "DONE:" — only the leader finalizes.`,
|
|
99
|
+
`You are "${speaker.name}"${persona}. You're chatting in a group with the user and your teammates: ${others}.`,
|
|
100
|
+
contextBlock,
|
|
101
|
+
`\nReply directly to the user, as yourself, in MAX 2 sentences — like a person in a group chat.`,
|
|
102
|
+
`Just give YOUR answer. Do NOT @mention teammates or hand off turns ("@X your turn", "over to you") — a coordinator decides who speaks next; handing off only creates loops.`,
|
|
103
|
+
`Do not narrate actions and never write "DONE".`,
|
|
76
104
|
];
|
|
77
105
|
return parts.filter(Boolean).join("\n");
|
|
78
106
|
}
|
|
79
107
|
|
|
80
|
-
/** Run
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
108
|
+
/** Run a bounded reply burst for the latest user message. When `deps.routeNextSpeaker`
|
|
109
|
+
* is provided, an LLM router picks the next speaker each turn (history-driven, allows
|
|
110
|
+
* AI↔AI silence, leader as fallback/moderator); otherwise it falls back to mention-
|
|
111
|
+
* following. Either way: user @mention is an absolute override, a user message always
|
|
112
|
+
* gets ≥1 reply, and total AI turns are capped. Emits only `kind:"chat"` messages. */
|
|
113
|
+
export async function runReplyBurst(
|
|
84
114
|
group: Group,
|
|
85
115
|
members: GroupMember[],
|
|
86
116
|
deps: TurnEngineDeps,
|
|
87
|
-
|
|
88
|
-
): Promise<
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
opts: { cap?: number; window?: number } = {},
|
|
118
|
+
): Promise<BurstResult> {
|
|
119
|
+
return deps.routeNextSpeakers
|
|
120
|
+
? runRoutedBurst(group, members, deps, opts)
|
|
121
|
+
: runMentionBurst(group, members, deps, opts);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Shared per-turn side effects: run the agent, persist + emit the message. */
|
|
125
|
+
async function runTurn(
|
|
126
|
+
group: Group, members: GroupMember[], deps: TurnEngineDeps,
|
|
127
|
+
name: string, turnIndex: number, window?: number,
|
|
128
|
+
): Promise<{ text: string; costUsd: number }> {
|
|
129
|
+
const member = findMember(members, name) ?? leaderOf(members);
|
|
130
|
+
const prompt = buildTurnContext(group, member, members, deps, { window });
|
|
131
|
+
deps.onTyping?.(name);
|
|
132
|
+
const result = await deps.runAgent(member, prompt);
|
|
133
|
+
const text = result.text ?? "";
|
|
134
|
+
const pull = selectNextSpeaker(text, name, members);
|
|
135
|
+
const msg = deps.appendMessage({
|
|
136
|
+
groupId: group.id,
|
|
137
|
+
fromMember: name,
|
|
138
|
+
toMember: pull,
|
|
139
|
+
kind: "chat",
|
|
140
|
+
summary: feedSummary(text),
|
|
141
|
+
// Full text for cross-member context injection (feed UI still shows `summary`).
|
|
142
|
+
data: { full: text },
|
|
143
|
+
fullSessionRef: member.sessionId,
|
|
144
|
+
turnIndex,
|
|
145
|
+
});
|
|
146
|
+
deps.onMessage?.(msg);
|
|
147
|
+
return { text, costUsd: result.usage?.costUsd ?? 0 };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Dedupe names, keeping order, dropping unknown members. */
|
|
151
|
+
function knownUnique(names: string[], members: GroupMember[]): string[] {
|
|
152
|
+
const out: string[] = [];
|
|
153
|
+
const seen = new Set<string>();
|
|
154
|
+
for (const n of names) {
|
|
155
|
+
if (!seen.has(n) && findMember(members, n)) { out.push(n); seen.add(n); }
|
|
156
|
+
}
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Router-driven turn-taking with PARALLEL batches: `deps.routeNextSpeakers` returns 0-N
|
|
161
|
+
* members to run concurrently this turn. User @mentions run first (absolute, in parallel);
|
|
162
|
+
* the first user-reply turn is forced to ≥1 (leader fallback); AI↔AI turns may end (empty →
|
|
163
|
+
* silence). Each batch member counts toward the cap; batches are bounded to the remaining cap. */
|
|
164
|
+
async function runRoutedBurst(
|
|
165
|
+
group: Group, members: GroupMember[], deps: TurnEngineDeps,
|
|
166
|
+
opts: { cap?: number; window?: number },
|
|
167
|
+
): Promise<BurstResult> {
|
|
168
|
+
const cap = opts.cap ?? REPLY_BURST_CAP;
|
|
169
|
+
const prior = deps.readMessages(group.id);
|
|
170
|
+
const lastUser = [...prior].reverse().find((m) => m.fromMember === "user");
|
|
171
|
+
let mentionQueue = parseMentions(lastUser?.summary ?? "", members);
|
|
172
|
+
let nextTurnIndex = (prior[prior.length - 1]?.turnIndex ?? -1) + 1;
|
|
173
|
+
|
|
91
174
|
let turns = 0;
|
|
175
|
+
let assistantTurns = 0;
|
|
92
176
|
let costUsd = 0;
|
|
93
|
-
let reason:
|
|
94
|
-
let finalText = "";
|
|
177
|
+
let reason: BurstEndReason = "no_more_mentions";
|
|
95
178
|
|
|
96
|
-
|
|
179
|
+
while (true) {
|
|
97
180
|
if (deps.shouldStop?.()) { reason = "stopped"; break; }
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
turns++;
|
|
107
|
-
costUsd += result.usage?.costUsd ?? 0;
|
|
108
|
-
const text = result.text ?? "";
|
|
109
|
-
|
|
110
|
-
const isDone = member.role === "leader" && DONE_RE.test(text);
|
|
111
|
-
const mention = text.match(MENTION_RE)?.[1] ?? null;
|
|
112
|
-
|
|
113
|
-
const msg = deps.appendMessage({
|
|
114
|
-
groupId: group.id,
|
|
115
|
-
fromMember: member.name,
|
|
116
|
-
toMember: isDone ? "all" : mention,
|
|
117
|
-
kind: isDone ? "final" : "chat",
|
|
118
|
-
summary: feedSummary(text),
|
|
119
|
-
fullSessionRef: member.sessionId,
|
|
120
|
-
turnIndex,
|
|
121
|
-
});
|
|
122
|
-
deps.onMessage?.(msg);
|
|
123
|
-
|
|
124
|
-
if (isDone) { reason = "leader_done"; return { reason, turns, costUsd }; }
|
|
125
|
-
|
|
126
|
-
if (costUsd >= group.maxCostUsd) { reason = "budget"; finalText = text; break; }
|
|
127
|
-
|
|
128
|
-
// If the next turn is the last, steer to the leader so it can finalize.
|
|
129
|
-
if (turnIndex >= group.maxTurns - 2) {
|
|
130
|
-
speaker = leader.name;
|
|
181
|
+
if (turns >= cap) { reason = "cap_reached"; break; }
|
|
182
|
+
|
|
183
|
+
const isUserTurn = assistantTurns === 0;
|
|
184
|
+
let names: string[];
|
|
185
|
+
if (mentionQueue.length > 0) {
|
|
186
|
+
// Explicit user @mentions → all of them reply in parallel (absolute override).
|
|
187
|
+
names = mentionQueue;
|
|
188
|
+
mentionQueue = [];
|
|
131
189
|
} else {
|
|
132
|
-
|
|
190
|
+
const history = deps.readMessages(group.id);
|
|
191
|
+
names = knownUnique(await deps.routeNextSpeakers!({ history, members, isUserTurn }), members);
|
|
192
|
+
if (names.length === 0) {
|
|
193
|
+
if (isUserTurn) names = [leaderOf(members).name]; // a user message always gets ≥1 reply
|
|
194
|
+
else break; // AI↔AI: nothing more to add → silence
|
|
195
|
+
}
|
|
133
196
|
}
|
|
134
|
-
}
|
|
135
197
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
deps.onMessage?.(finalMsg);
|
|
198
|
+
// Bound the parallel batch to the remaining cap.
|
|
199
|
+
names = names.slice(0, cap - turns);
|
|
200
|
+
// Pre-assign turn indices so concurrent appends stay ordered/collision-free.
|
|
201
|
+
const batch = names.map((name) => ({ name, turnIndex: nextTurnIndex++ }));
|
|
202
|
+
const results = await dispatchParallel(
|
|
203
|
+
batch.map((b) => () => runTurn(group, members, deps, b.name, b.turnIndex, opts.window)),
|
|
204
|
+
cap, // concurrency ≤ cap (≤ remaining) — bounded fan-out, rate-limit guard
|
|
205
|
+
);
|
|
206
|
+
turns += batch.length;
|
|
207
|
+
assistantTurns += batch.length;
|
|
208
|
+
for (const r of results) costUsd += r.costUsd;
|
|
209
|
+
}
|
|
149
210
|
|
|
150
211
|
return { reason, turns, costUsd };
|
|
151
212
|
}
|
|
152
213
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
214
|
+
/** Legacy conversational mode (no router): mentions → those members, else the leader;
|
|
215
|
+
* repliers may @pull teammates; stop when a reply addresses the user (no mention). */
|
|
216
|
+
async function runMentionBurst(
|
|
217
|
+
group: Group, members: GroupMember[], deps: TurnEngineDeps,
|
|
218
|
+
opts: { cap?: number; window?: number },
|
|
219
|
+
): Promise<BurstResult> {
|
|
220
|
+
const cap = opts.cap ?? REPLY_BURST_CAP;
|
|
221
|
+
const prior = deps.readMessages(group.id);
|
|
222
|
+
const lastUser = [...prior].reverse().find((m) => m.fromMember === "user");
|
|
223
|
+
const queue = selectInitialResponders(lastUser?.summary ?? "", members);
|
|
224
|
+
let nextTurnIndex = (prior[prior.length - 1]?.turnIndex ?? -1) + 1;
|
|
225
|
+
let turns = 0;
|
|
226
|
+
let costUsd = 0;
|
|
227
|
+
let reason: BurstEndReason = "no_more_mentions";
|
|
228
|
+
|
|
229
|
+
while (queue.length > 0) {
|
|
230
|
+
if (deps.shouldStop?.()) { reason = "stopped"; break; }
|
|
231
|
+
if (turns >= cap) { reason = "cap_reached"; break; }
|
|
232
|
+
|
|
233
|
+
const name = queue.shift()!;
|
|
234
|
+
const { text, costUsd: c } = await runTurn(group, members, deps, name, nextTurnIndex++, opts.window);
|
|
235
|
+
turns++;
|
|
236
|
+
costUsd += c;
|
|
237
|
+
const pull = selectNextSpeaker(text, name, members);
|
|
238
|
+
if (pull) queue.push(pull);
|
|
163
239
|
}
|
|
240
|
+
|
|
241
|
+
return { reason, turns, costUsd };
|
|
164
242
|
}
|
|
@@ -82,6 +82,8 @@ export function parseSessionMessage(
|
|
|
82
82
|
if (role === "assistant" && cleaned) {
|
|
83
83
|
events.push({ type: "text", content: cleaned, ...(parentId && { parentToolUseId: parentId }) });
|
|
84
84
|
}
|
|
85
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
86
|
+
events.push({ type: "thinking", content: block.thinking as string, ...(parentId && { parentToolUseId: parentId }) });
|
|
85
87
|
} else if (block.type === "tool_use") {
|
|
86
88
|
events.push({
|
|
87
89
|
type: "tool_use",
|
|
@@ -238,3 +240,37 @@ export async function parseJsonlTranscript(
|
|
|
238
240
|
(msg) => msg.content.trim().length > 0 || (msg.events && msg.events.length > 0),
|
|
239
241
|
);
|
|
240
242
|
}
|
|
243
|
+
|
|
244
|
+
/** Session input config surfaced in a transcript view. Fields are best-effort — the SDK
|
|
245
|
+
* scatters them across user/assistant records rather than a single init line. */
|
|
246
|
+
export interface TranscriptConfig {
|
|
247
|
+
model?: string;
|
|
248
|
+
cwd?: string;
|
|
249
|
+
gitBranch?: string;
|
|
250
|
+
version?: string;
|
|
251
|
+
permissionMode?: string;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Scan a transcript's records for the first-seen input-config values. Returns null when
|
|
255
|
+
* nothing recognizable is found. Defensive: never throws, ignores malformed lines. */
|
|
256
|
+
export async function parseTranscriptConfig(filePath: string): Promise<TranscriptConfig | null> {
|
|
257
|
+
let text: string;
|
|
258
|
+
try { text = await Bun.file(filePath).text(); } catch { return null; }
|
|
259
|
+
const cfg: TranscriptConfig = {};
|
|
260
|
+
for (const line of text.split("\n")) {
|
|
261
|
+
const trimmed = line.trim();
|
|
262
|
+
if (!trimmed) continue;
|
|
263
|
+
let e: Record<string, unknown>;
|
|
264
|
+
try { e = JSON.parse(trimmed); } catch { continue; }
|
|
265
|
+
if (cfg.cwd === undefined && typeof e.cwd === "string") cfg.cwd = e.cwd;
|
|
266
|
+
if (cfg.gitBranch === undefined && typeof e.gitBranch === "string") cfg.gitBranch = e.gitBranch;
|
|
267
|
+
if (cfg.version === undefined && typeof e.version === "string") cfg.version = e.version;
|
|
268
|
+
if (cfg.permissionMode === undefined && typeof e.permissionMode === "string") cfg.permissionMode = e.permissionMode as string;
|
|
269
|
+
if (cfg.model === undefined) {
|
|
270
|
+
const model = (e.message as Record<string, unknown> | undefined)?.model ?? e.model;
|
|
271
|
+
if (typeof model === "string" && model !== "<synthetic>") cfg.model = model;
|
|
272
|
+
}
|
|
273
|
+
if (cfg.model && cfg.cwd && cfg.gitBranch && cfg.version && cfg.permissionMode) break;
|
|
274
|
+
}
|
|
275
|
+
return Object.keys(cfg).length > 0 ? cfg : null;
|
|
276
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { GroupMessage, GroupStatus, MemberStatus,
|
|
1
|
+
import type { GroupMessage, GroupStatus, MemberStatus, BurstEndReason } from "./group-chat.ts";
|
|
2
2
|
|
|
3
3
|
/** Server → client group-chat WS events. */
|
|
4
4
|
export type GroupChatServerMessage =
|
|
@@ -7,7 +7,7 @@ export type GroupChatServerMessage =
|
|
|
7
7
|
| { type: "member_status"; memberId: string; status: MemberStatus }
|
|
8
8
|
| { type: "typing"; member: string }
|
|
9
9
|
| { type: "turn_done"; turnIndex: number }
|
|
10
|
-
| { type: "group_done"; reason:
|
|
10
|
+
| { type: "group_done"; reason: BurstEndReason; turns: number; costUsd: number }
|
|
11
11
|
| { type: "error"; message: string }
|
|
12
12
|
| { type: "ping" };
|
|
13
13
|
|
package/src/types/group-chat.ts
CHANGED
|
@@ -6,7 +6,9 @@ export type MemberRole = "leader" | "member";
|
|
|
6
6
|
export type MemberStatus = "idle" | "working" | "done" | "error";
|
|
7
7
|
export type MessageKind = "task" | "chat" | "status" | "completion" | "final";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
/** Per-group cap on AI turns per user message (the "reply burst" ceiling). Configurable
|
|
10
|
+
* per team; the router usually ends earlier by returning nobody. */
|
|
11
|
+
export const DEFAULT_MAX_TURNS = 10;
|
|
10
12
|
export const DEFAULT_MAX_COST_USD = 5.0;
|
|
11
13
|
|
|
12
14
|
export interface Group {
|
|
@@ -66,6 +68,16 @@ export interface AddMemberInput {
|
|
|
66
68
|
color?: string | null;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
/** Partial member update — only provided fields change. */
|
|
72
|
+
export interface UpdateMemberInput {
|
|
73
|
+
role?: MemberRole;
|
|
74
|
+
name?: string;
|
|
75
|
+
persona?: string | null;
|
|
76
|
+
agentType?: string | null;
|
|
77
|
+
model?: string | null;
|
|
78
|
+
color?: string | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
69
81
|
export interface AppendMessageInput {
|
|
70
82
|
groupId: string;
|
|
71
83
|
fromMember: string;
|
|
@@ -101,14 +113,31 @@ export interface TurnEngineDeps {
|
|
|
101
113
|
readMessages: (groupId: string, opts?: ReadMessagesOptions) => GroupMessage[];
|
|
102
114
|
/** Emit a turn to live listeners (WS broadcast). Optional. */
|
|
103
115
|
onMessage?: (message: GroupMessage) => void;
|
|
116
|
+
/** Signal that `member` is composing a reply (drives the typing indicator). Optional. */
|
|
117
|
+
onTyping?: (member: string) => void;
|
|
118
|
+
/** Pick who speaks NEXT given recent context; returns 0-N member names to run **in
|
|
119
|
+
* parallel** this turn. Empty = end the burst (no one else replies). `isUserTurn` is true
|
|
120
|
+
* only for the first reply to a fresh user message — on that turn the engine forces the
|
|
121
|
+
* leader if the router returns none (a user message always gets ≥1 reply). Members that
|
|
122
|
+
* must build on each other → return just one (sequential). When this dep is absent the
|
|
123
|
+
* engine falls back to mention-following (conversational mode). Optional. */
|
|
124
|
+
routeNextSpeakers?: (ctx: {
|
|
125
|
+
history: GroupMessage[];
|
|
126
|
+
members: GroupMember[];
|
|
127
|
+
isUserTurn: boolean;
|
|
128
|
+
}) => Promise<string[]>;
|
|
104
129
|
/** External stop signal (user Stop / abort). Checked before each turn. */
|
|
105
130
|
shouldStop?: () => boolean;
|
|
106
131
|
}
|
|
107
132
|
|
|
108
|
-
|
|
133
|
+
/** Why a conversational reply burst ended.
|
|
134
|
+
* - no_more_mentions: last reply addressed the user (no teammate @mention) → wait for user
|
|
135
|
+
* - cap_reached: hit the per-message AI-turn cap
|
|
136
|
+
* - stopped: external Stop / abort */
|
|
137
|
+
export type BurstEndReason = "no_more_mentions" | "cap_reached" | "stopped";
|
|
109
138
|
|
|
110
|
-
export interface
|
|
111
|
-
reason:
|
|
139
|
+
export interface BurstResult {
|
|
140
|
+
reason: BurstEndReason;
|
|
112
141
|
turns: number;
|
|
113
142
|
costUsd: number;
|
|
114
143
|
}
|
|
@@ -5,11 +5,14 @@ import { useProjectStore } from "@/stores/project-store";
|
|
|
5
5
|
import { useIsMobile } from "@/hooks/use-is-mobile";
|
|
6
6
|
import { useGroupChat } from "@/hooks/use-group-chat";
|
|
7
7
|
import { Button } from "@/components/ui/button";
|
|
8
|
+
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
8
9
|
import { cn } from "@/lib/utils";
|
|
9
10
|
import { GroupMessageItem } from "./group-message-item";
|
|
10
11
|
import { GroupMemberRoster } from "./group-member-roster";
|
|
12
|
+
import { GroupMemberEditDialog, type MemberFormValues } from "./group-member-edit-dialog";
|
|
11
13
|
import { GroupFullTranscriptView } from "./group-full-transcript-view";
|
|
12
|
-
import
|
|
14
|
+
import { getGroup, addGroupMember, updateGroupMember, removeGroupMember, updateGroupSettings } from "@/lib/api-group-chat";
|
|
15
|
+
import type { GroupMessage, GroupMember } from "../../../types/group-chat";
|
|
13
16
|
|
|
14
17
|
interface GroupChatTabProps {
|
|
15
18
|
metadata?: Record<string, unknown>;
|
|
@@ -31,20 +34,64 @@ export function GroupChatTab({ metadata }: GroupChatTabProps) {
|
|
|
31
34
|
const [rosterOpen, setRosterOpen] = useState(false);
|
|
32
35
|
const feedEndRef = useRef<HTMLDivElement>(null);
|
|
33
36
|
|
|
37
|
+
// Full roster (with persona/model) for management — the WS `members` only carry
|
|
38
|
+
// live status/color, so we fetch the editable detail separately and refetch on change.
|
|
39
|
+
const [roster, setRoster] = useState<GroupMember[]>([]);
|
|
40
|
+
const [cap, setCap] = useState<number | null>(null); // per-group reply-burst cap
|
|
41
|
+
const [rosterBusy, setRosterBusy] = useState(false);
|
|
42
|
+
const [rosterError, setRosterError] = useState<string | null>(null);
|
|
43
|
+
// `null` = dialog closed; `{ member: null }` = add; `{ member }` = edit.
|
|
44
|
+
const [editing, setEditing] = useState<{ member: GroupMember | null } | null>(null);
|
|
45
|
+
|
|
46
|
+
const reloadRoster = useCallback(async () => {
|
|
47
|
+
if (!groupId) return;
|
|
48
|
+
try { const g = await getGroup(groupId); setRoster(g.members); setCap(g.maxTurns); } catch { /* keep last */ }
|
|
49
|
+
}, [groupId]);
|
|
50
|
+
|
|
51
|
+
const handleCapChange = useCallback(async (n: number) => {
|
|
52
|
+
if (!groupId) return;
|
|
53
|
+
const clamped = Math.max(1, Math.min(50, Math.floor(n) || 1));
|
|
54
|
+
setCap(clamped);
|
|
55
|
+
try { await updateGroupSettings(groupId, { maxTurns: clamped }); }
|
|
56
|
+
catch { void reloadRoster(); }
|
|
57
|
+
}, [groupId, reloadRoster]);
|
|
58
|
+
|
|
59
|
+
useEffect(() => { setRoster([]); void reloadRoster(); }, [groupId, reloadRoster]);
|
|
60
|
+
|
|
34
61
|
// Stick to bottom on new messages.
|
|
35
62
|
useEffect(() => {
|
|
36
63
|
feedEndRef.current?.scrollIntoView({ block: "end" });
|
|
37
64
|
}, [messages.length, typing]);
|
|
38
65
|
|
|
66
|
+
// memberId → live status from the running burst (overlays the fetched roster).
|
|
67
|
+
const liveStatus = useMemo(() => new Map(members.map((m) => [m.id, m.status] as const)), [members]);
|
|
68
|
+
|
|
69
|
+
// Prefer the fetched roster (fresh after edits); fall back to WS members before load.
|
|
70
|
+
const metaSource = roster.length ? roster : members;
|
|
39
71
|
const colorFor = useMemo(() => {
|
|
40
|
-
const map = new Map(
|
|
72
|
+
const map = new Map(metaSource.map((m) => [m.name, m.color]));
|
|
41
73
|
return (name: string) => map.get(name) ?? null;
|
|
42
|
-
}, [
|
|
74
|
+
}, [metaSource]);
|
|
43
75
|
|
|
44
76
|
const isLeader = useMemo(() => {
|
|
45
|
-
const leaders = new Set(
|
|
77
|
+
const leaders = new Set(metaSource.filter((m) => m.role === "leader").map((m) => m.name));
|
|
46
78
|
return (name: string) => leaders.has(name);
|
|
47
|
-
}, [
|
|
79
|
+
}, [metaSource]);
|
|
80
|
+
|
|
81
|
+
const handleSubmitMember = useCallback(async (values: MemberFormValues) => {
|
|
82
|
+
if (!groupId) return;
|
|
83
|
+
if (editing?.member) await updateGroupMember(groupId, editing.member.id, values);
|
|
84
|
+
else await addGroupMember(groupId, values);
|
|
85
|
+
await reloadRoster();
|
|
86
|
+
}, [groupId, editing, reloadRoster]);
|
|
87
|
+
|
|
88
|
+
const handleRemoveMember = useCallback(async (m: GroupMember) => {
|
|
89
|
+
if (!groupId) return;
|
|
90
|
+
setRosterBusy(true); setRosterError(null);
|
|
91
|
+
try { await removeGroupMember(groupId, m.id); await reloadRoster(); }
|
|
92
|
+
catch (e) { setRosterError(e instanceof Error ? e.message : "Failed to remove member"); }
|
|
93
|
+
finally { setRosterBusy(false); }
|
|
94
|
+
}, [groupId, reloadRoster]);
|
|
48
95
|
|
|
49
96
|
const handleSend = useCallback(() => {
|
|
50
97
|
const content = draft.trim();
|
|
@@ -156,17 +203,65 @@ export function GroupChatTab({ metadata }: GroupChatTabProps) {
|
|
|
156
203
|
</div>
|
|
157
204
|
</div>
|
|
158
205
|
|
|
159
|
-
{/* Roster — sidebar on desktop
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
)}>
|
|
165
|
-
<div className="flex h-11 items-center border-b border-border px-3 text-sm font-medium text-foreground">
|
|
206
|
+
{/* Roster — inline sidebar on desktop; bottom sheet on mobile (tap backdrop
|
|
207
|
+
or swipe down to dismiss, since the header toggle sits under an overlay). */}
|
|
208
|
+
{isMobile ? (
|
|
209
|
+
<BottomSheet open={rosterOpen} onClose={() => setRosterOpen(false)} className="flex max-h-[72vh] flex-col">
|
|
210
|
+
<div className="flex h-11 shrink-0 items-center px-4 text-sm font-medium text-foreground">
|
|
166
211
|
Members
|
|
167
212
|
</div>
|
|
168
|
-
<
|
|
169
|
-
|
|
213
|
+
<div className="min-h-0 overflow-y-auto">
|
|
214
|
+
{cap !== null && (
|
|
215
|
+
<label className="flex items-center gap-2 px-4 py-2 text-xs text-text-secondary">
|
|
216
|
+
<span>Reply cap</span>
|
|
217
|
+
<input type="number" min={1} max={50} value={cap}
|
|
218
|
+
onChange={(e) => handleCapChange(Number(e.target.value))}
|
|
219
|
+
className="w-14 rounded border border-border bg-background px-1.5 py-1 text-xs text-foreground" />
|
|
220
|
+
<span className="text-text-subtle">turns/msg</span>
|
|
221
|
+
</label>
|
|
222
|
+
)}
|
|
223
|
+
{rosterError && <p className="px-3 py-1 text-xs text-destructive">{rosterError}</p>}
|
|
224
|
+
<GroupMemberRoster
|
|
225
|
+
members={roster} liveStatus={liveStatus} typing={typing} busy={rosterBusy}
|
|
226
|
+
onAdd={() => setEditing({ member: null })} onEdit={(m) => setEditing({ member: m })} onRemove={handleRemoveMember}
|
|
227
|
+
/>
|
|
228
|
+
</div>
|
|
229
|
+
</BottomSheet>
|
|
230
|
+
) : (
|
|
231
|
+
rosterOpen && (
|
|
232
|
+
<div className="flex w-60 shrink-0 flex-col border-l border-border bg-panel">
|
|
233
|
+
<div className="flex h-11 shrink-0 items-center border-b border-border px-3 text-sm font-medium text-foreground">
|
|
234
|
+
Members
|
|
235
|
+
</div>
|
|
236
|
+
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
237
|
+
{cap !== null && (
|
|
238
|
+
<label className="flex items-center gap-2 px-3 py-2 text-xs text-text-secondary">
|
|
239
|
+
<span>Reply cap</span>
|
|
240
|
+
<input type="number" min={1} max={50} value={cap}
|
|
241
|
+
onChange={(e) => handleCapChange(Number(e.target.value))}
|
|
242
|
+
className="w-14 rounded border border-border bg-background px-1.5 py-1 text-xs text-foreground" />
|
|
243
|
+
<span className="text-text-subtle">turns/msg</span>
|
|
244
|
+
</label>
|
|
245
|
+
)}
|
|
246
|
+
{rosterError && <p className="px-3 py-1 text-xs text-destructive">{rosterError}</p>}
|
|
247
|
+
<GroupMemberRoster
|
|
248
|
+
members={roster} liveStatus={liveStatus} typing={typing} busy={rosterBusy}
|
|
249
|
+
onAdd={() => setEditing({ member: null })} onEdit={(m) => setEditing({ member: m })} onRemove={handleRemoveMember}
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
)
|
|
254
|
+
)}
|
|
255
|
+
|
|
256
|
+
{editing && (
|
|
257
|
+
<GroupMemberEditDialog
|
|
258
|
+
key={editing.member?.id ?? "add"}
|
|
259
|
+
open
|
|
260
|
+
member={editing.member}
|
|
261
|
+
projectName={projectName}
|
|
262
|
+
onSubmit={handleSubmitMember}
|
|
263
|
+
onClose={() => setEditing(null)}
|
|
264
|
+
/>
|
|
170
265
|
)}
|
|
171
266
|
|
|
172
267
|
<GroupFullTranscriptView groupId={groupId} message={transcriptMsg} onClose={() => setTranscriptMsg(null)} />
|