@hienlh/ppm 0.17.15 → 0.17.17
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 +23 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +5 -1
- package/dist/web/assets/{ai-resource-editor-DfCN7LjR.js → ai-resource-editor-37UxM2lK.js} +1 -1
- package/dist/web/assets/{angular-html-DkR4iCth.js → angular-html-2g8YGiJY.js} +1 -1
- package/dist/web/assets/{angular-ts-DcyL4Chx.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-BdQCjXQk.js → api-themes-DuLpbQFV.js} +1 -1
- package/dist/web/assets/{apl-BVlrVtjt.js → apl-B44SMKHp.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-gLlhsjM9.js +1 -0
- package/dist/web/assets/{astro-MjJlozLj.js → astro-E5620wek.js} +1 -1
- package/dist/web/assets/{audio-preview-DbFUkIzm.js → audio-preview-BG8uEB67.js} +1 -1
- package/dist/web/assets/{blade-DnJWi1fz.js → blade-D-VQWAHB.js} +1 -1
- package/dist/web/assets/{bsl-DCmJxSIz.js → bsl-Bq5qFzpU.js} +1 -1
- package/dist/web/assets/{cairo-C8dDenub.js → cairo-Cn9-ZKRa.js} +1 -1
- package/dist/web/assets/chat-tab-6G5LulPM.js +13 -0
- package/dist/web/assets/{cobol-DPx_nifl.js → cobol-IM3E3iCH.js} +1 -1
- package/dist/web/assets/code-editor-BlBFI3jn.js +10 -0
- package/dist/web/assets/{coffee-DvFzqhgN.js → coffee-24wG7ekn.js} +1 -1
- package/dist/web/assets/{conflict-editor-BAAffNdj.js → conflict-editor-CYZjqn46.js} +1 -1
- package/dist/web/assets/{cpp-BLJN0umi.js → cpp-DH9Cqt4g.js} +1 -1
- package/dist/web/assets/{crystal-BXR-9fGw.js → crystal-4nZYHhdi.js} +1 -1
- package/dist/web/assets/{csv-preview-DzhSC0fd.js → csv-preview-YxR9adj_.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-cOzDcGkl.js → data-grid-overlay-editor-DxdOKRAY.js} +1 -1
- package/dist/web/assets/{database-viewer-DxmL2veb.js → database-viewer-CrdTyPIN.js} +1 -1
- package/dist/web/assets/dialog-BpkAWOy8.js +1 -0
- package/dist/web/assets/{diff-viewer-DvXxlk47.js → diff-viewer-DiYj_kRC.js} +1 -1
- package/dist/web/assets/{docx-preview-DfjH-dIr.js → docx-preview-Dsrm2Hgu.js} +1 -1
- package/dist/web/assets/{edge-rWOlCmXT.js → edge-DTI9d2Qi.js} +1 -1
- package/dist/web/assets/{elixir-E7Y82okW.js → elixir-Ys0wioho.js} +1 -1
- package/dist/web/assets/{elm-DTPGbc-w.js → elm-Cihc9TAz.js} +1 -1
- package/dist/web/assets/{erb-DHqLHrE6.js → erb-BwYBWK2-.js} +1 -1
- package/dist/web/assets/{erlang-Byg0nNiV.js → erlang-CzlD_Joo.js} +1 -1
- package/dist/web/assets/{esm-DU7axMjq.js → esm-JLkfN0k-.js} +1 -1
- package/dist/web/assets/{extension-webview-wuMQ8pD7.js → extension-webview-B8ph2gI9.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-CY1n0Xf6.js → fortran-fixed-form-CT90EtSp.js} +1 -1
- package/dist/web/assets/{fsharp-_vEDSCJz.js → fsharp-LasxezlU.js} +1 -1
- package/dist/web/assets/{gdresource-B6XT0wAC.js → gdresource-XqgPdfiE.js} +1 -1
- package/dist/web/assets/{git-commit-Wk9ovq59.js → git-commit-CZBgPolw.js} +1 -1
- package/dist/web/assets/{git-log-panel-SPPYmbCr.js → git-log-panel-qIsOpM57.js} +1 -1
- package/dist/web/assets/{git-rebase-DSarGPvK.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-BC0AHzMn.js → glide-data-grid-BrQskOnP.js} +8 -8
- package/dist/web/assets/{glimmer-js-CkYI35_P.js → glimmer-js-DfjWcOLD.js} +1 -1
- package/dist/web/assets/{glimmer-ts-BqmIZcds.js → glimmer-ts-DBldQATc.js} +1 -1
- package/dist/web/assets/{glsl-Be-yBCF5.js → glsl-CzNv1NPP.js} +1 -1
- package/dist/web/assets/{graphql-a5DrENHY.js → graphql-DDyLtQb4.js} +1 -1
- package/dist/web/assets/group-chat-tab-DYgRs0zS.js +1 -0
- package/dist/web/assets/{hack-BLAg20aD.js → hack-CtoYNYkC.js} +1 -1
- package/dist/web/assets/{haml-Dj6bGOQH.js → haml-CnBVap7G.js} +1 -1
- package/dist/web/assets/{handlebars-dmEa36Oh.js → handlebars-Dg51esUH.js} +1 -1
- package/dist/web/assets/{html-yacZYzSE.js → html-Ec2_evSy.js} +1 -1
- package/dist/web/assets/{html-derivative-lLi3-RNT.js → html-derivative-Cy-F7ZqL.js} +1 -1
- package/dist/web/assets/{http-1KaxcE4e.js → http-C236v8Tg.js} +1 -1
- package/dist/web/assets/{hurl-ST-dEEZR.js → hurl-0rMD2gPU.js} +1 -1
- package/dist/web/assets/{hxml-CpDtuq__.js → hxml-e5uS5jTD.js} +1 -1
- package/dist/web/assets/{image-preview-D_8o6OLx.js → image-preview-B9EWGEFv.js} +1 -1
- package/dist/web/assets/index-BYFXiFsa.css +2 -0
- package/dist/web/assets/index-BiHrB3KU.js +50 -0
- package/dist/web/assets/info-3K5VOQVL-BOhGriBF.js +1 -0
- package/dist/web/assets/{jinja-Cjw-evAn.js → jinja-DybFmhfq.js} +1 -1
- package/dist/web/assets/{jison-DfATMYoY.js → jison-hkHbixdZ.js} +1 -1
- package/dist/web/assets/{julia-DDCaxiqT.js → julia-QnxY6sRE.js} +1 -1
- package/dist/web/assets/{just-CJL529u6.js → just-1Rs-nm8g.js} +1 -1
- package/dist/web/assets/keybindings-store-CWi8IGEx.js +1 -0
- package/dist/web/assets/{latex-Zc4EpLpW.js → latex-jEBQqA7u.js} +1 -1
- package/dist/web/assets/{liquid-B_6KMNYS.js → liquid-DfJaZpxG.js} +1 -1
- package/dist/web/assets/{lua-BtS2idK7.js → lua-ti0Jr6-C.js} +1 -1
- package/dist/web/assets/{markdown-renderer-DVVx3WCU.js → markdown-renderer-B4rtk2Hq.js} +3 -3
- package/dist/web/assets/markdown-renderer-XIhxiUQq.js +1 -0
- package/dist/web/assets/{marko-Wk6LBnck.js → marko-DNj4AhPg.js} +1 -1
- package/dist/web/assets/{mdc-cRaXBrzL.js → mdc-DPFwQFe4.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet--5_YEewV.js +1 -0
- package/dist/web/assets/{nextflow-Bos2wvDV.js → nextflow-BUrFV5aB.js} +1 -1
- package/dist/web/assets/{nginx-DMlOwzdr.js → nginx-BrW9NdOb.js} +1 -1
- package/dist/web/assets/{nim-D2dZQA88.js → nim-DS_6PF2p.js} +1 -1
- package/dist/web/assets/notification-store-DEIj7OrE.js +1 -0
- package/dist/web/assets/{number-overlay-editor-Du_UgiD3.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-HTC73FyK.js → pdf-preview-Zl3KICd5.js} +1 -1
- package/dist/web/assets/{perl-C5-Z6fPn.js → perl-ytm9vKO_.js} +1 -1
- package/dist/web/assets/{php-BXNNhkMH.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-pWjwP3GD.js → postgres-viewer-BTupZTmP.js} +3 -3
- package/dist/web/assets/{project-store-Cekcjcom.js → project-store-Sbnqc41N.js} +1 -1
- package/dist/web/assets/{pug-C1zf1yWy.js → pug-Bt7KL3_r.js} +1 -1
- package/dist/web/assets/{qml-OW58jGpD.js → qml-Dexdon5J.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-CiCfdJNL.js +1 -0
- package/dist/web/assets/{razor-DzjSaobM.js → razor-DnYCSl0G.js} +1 -1
- package/dist/web/assets/{rst-RfuihOUW.js → rst-BEFYzwF8.js} +1 -1
- package/dist/web/assets/{ruby-CNO3pli1.js → ruby-BPaXFEjN.js} +1 -1
- package/dist/web/assets/{sas-DZY5BtXx.js → sas-CywiNBp8.js} +1 -1
- package/dist/web/assets/{scss--4g-REcN.js → scss-CGk0L6hN.js} +1 -1
- package/dist/web/assets/{settings-store-mWnY4Kt0.js → settings-store-DkRZhj-g.js} +2 -2
- package/dist/web/assets/settings-tab-BF069B1K.js +1 -0
- package/dist/web/assets/{shaderlab-Cu4sBiVn.js → shaderlab-Byjk0kH7.js} +1 -1
- package/dist/web/assets/{shellsession-DWzJfEv7.js → shellsession-DbA70QB6.js} +1 -1
- package/dist/web/assets/{soy-BnqE-5Ff.js → soy-Bm97kWiA.js} +1 -1
- package/dist/web/assets/sparkles-B3DmG8PJ.js +1 -0
- package/dist/web/assets/{sparql-Ctg__NhZ.js → sparql-CawLnniT.js} +1 -1
- package/dist/web/assets/{sql-query-editor-CJdpO95g.js → sql-query-editor-RwHY1p-a.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-BgewX3tM.js → sqlite-viewer-3UxftoM7.js} +1 -1
- package/dist/web/assets/{stata-Qk2h66XW.js → stata-RifEDtNO.js} +1 -1
- package/dist/web/assets/{surrealql-8QEX7EfH.js → surrealql-DGRQa5Lm.js} +1 -1
- package/dist/web/assets/{svelte-D_mubC5-.js → svelte-w9Hb12aM.js} +1 -1
- package/dist/web/assets/system-monitor-tab-Ck1cIP7g.js +1 -0
- package/dist/web/assets/{tab-store-CcLQfu8H.js → tab-store-vn0viMOP.js} +1 -1
- package/dist/web/assets/{templ-C1jV0fsO.js → templ-BpUwjJXV.js} +1 -1
- package/dist/web/assets/{terminal-tab-DWncjHEA.js → terminal-tab-B9opPxft.js} +2 -2
- package/dist/web/assets/{tex-D_StFXy_.js → tex-DJFSsuTD.js} +1 -1
- package/dist/web/assets/tool-cards-C7iLwehG.js +7 -0
- package/dist/web/assets/treemap-KZPCXAKY-CZwuSCtA.js +1 -0
- package/dist/web/assets/{ts-tags-B5m47rEm.js → ts-tags-vp9Qvx2O.js} +1 -1
- package/dist/web/assets/{twig-C_br6GIl.js → twig-CoazxjRB.js} +1 -1
- package/dist/web/assets/{use-blob-url-DpDVcTeK.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-Ch2jRiGj.js → use-monaco-theme-jtYkroys.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-DP1CEcGn.js → vendor-mermaid-DPpYkrMf.js} +1 -1
- package/dist/web/assets/{video-preview-rWrNCfZX.js → video-preview-Ced_VIvq.js} +1 -1
- package/dist/web/assets/{vue-DQwCnLdr.js → vue-CnshsiXd.js} +1 -1
- package/dist/web/assets/{vue-html-T_EoGpPJ.js → vue-html-CZshynFp.js} +1 -1
- package/dist/web/assets/{vue-vine-DmxLqX50.js → vue-vine-C5gtp_T1.js} +1 -1
- package/dist/web/assets/{xml-Bs6Bw8is.js → xml-BEGJasgj.js} +1 -1
- package/dist/web/assets/{xsl-f5ZNhRCc.js → xsl-DXpRLjYk.js} +1 -1
- package/dist/web/index.html +21 -19
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/schemas/ppm-config.schema.json +3 -3
- package/src/cli/commands/init.ts +8 -5
- package/src/providers/claude-agent-sdk-query-options.ts +57 -0
- package/src/providers/claude-agent-sdk.ts +21 -9
- package/src/server/routes/group-chat.ts +118 -9
- package/src/server/ws/chat.ts +91 -10
- package/src/services/account.service.ts +13 -7
- package/src/services/db.service.ts +31 -1
- 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/api.ts +4 -2
- package/src/types/chat.ts +8 -0
- package/src/types/config.ts +4 -9
- package/src/types/group-chat-ws.ts +2 -2
- package/src/types/group-chat.ts +33 -4
- package/src/web/components/chat/chat-tab.tsx +8 -0
- package/src/web/components/chat/message-input.tsx +27 -7
- package/src/web/components/chat/message-list.tsx +48 -3
- package/src/web/components/chat/model-thinking-selector-helpers.ts +33 -0
- package/src/web/components/chat/model-thinking-selector.tsx +189 -0
- 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/mobile-drawer-tab-bar.tsx +10 -0
- package/src/web/components/layout/nav-section-rail.tsx +8 -2
- package/src/web/components/layout/upgrade-button.tsx +33 -11
- package/src/web/components/settings/ai-settings-section.tsx +2 -0
- package/src/web/components/settings/proxy-test-section.tsx +3 -1
- package/src/web/hooks/use-chat.ts +45 -0
- 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-CqTF9Xn6.js +0 -1
- package/dist/web/assets/chat-tab-C6nMDb9l.js +0 -18
- package/dist/web/assets/code-editor-C38IIs_y.js +0 -10
- package/dist/web/assets/gitGraph-HDMCJU4V-X12vfQ3i.js +0 -1
- package/dist/web/assets/group-chat-tab-D20bF8q5.js +0 -1
- package/dist/web/assets/index-C1Q59prB.js +0 -50
- package/dist/web/assets/index-CMJ6whqq.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-Bcz-Qhua.js +0 -1
- package/dist/web/assets/input-24Nf_edC.js +0 -1
- package/dist/web/assets/keybindings-store-TINaziU9.js +0 -1
- package/dist/web/assets/notification-store-DN8oDV7o.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BTwjB70W.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-Cn-lrQYZ.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-Cmppm_Ia.js +0 -1
- package/dist/web/assets/settings-tab-BoRuss3O.js +0 -1
- package/dist/web/assets/sparkles-2ii4lR7b.js +0 -1
- package/dist/web/assets/system-monitor-tab-BA9gqJRW.js +0 -1
- package/dist/web/assets/treemap-KZPCXAKY-BLWus1wm.js +0 -1
- package/dist/web/assets/use-websocket-MvxbuTdy.js +0 -1
- /package/dist/web/assets/{abap-tkptwpsK.js → abap-wT6fgqwv.js} +0 -0
- /package/dist/web/assets/{actionscript-3-Di9TMGwg.js → actionscript-3-CqcHpPYj.js} +0 -0
- /package/dist/web/assets/{ada-CB9F079D.js → ada-DWE3Hn4E.js} +0 -0
- /package/dist/web/assets/{andromeeda-Dcl8jpb7.js → andromeeda-DpQ-y-Jt.js} +0 -0
- /package/dist/web/assets/{apache-D0Nk0qsH.js → apache-LRTUP4r3.js} +0 -0
- /package/dist/web/assets/{apex-mQIoWncD.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-C6ljbcsI.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-WFqRPGPe.js → ara-Cf-OWd2S.js} +0 -0
- /package/dist/web/assets/{asciidoc-bNd8w4nf.js → asciidoc-gocbKcVK.js} +0 -0
- /package/dist/web/assets/{asm-BQ1_F580.js → asm-C3meb5HY.js} +0 -0
- /package/dist/web/assets/{aurora-x-Ciqs_Dbu.js → aurora-x-BYcXaCIg.js} +0 -0
- /package/dist/web/assets/{awk-GCR-6KZV.js → awk-BcT6nIdN.js} +0 -0
- /package/dist/web/assets/{ayu-dark-DxJXuj99.js → ayu-dark-CLZPoccg.js} +0 -0
- /package/dist/web/assets/{ayu-light-jvSyJWDV.js → ayu-light-CTyRQdS2.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-Cg3BPO6H.js → ayu-mirage-DjqfqZdo.js} +0 -0
- /package/dist/web/assets/{ballerina-BPz4CrX6.js → ballerina-BCARR-zK.js} +0 -0
- /package/dist/web/assets/{bat-CSTs2hIG.js → bat-_yaRjWOb.js} +0 -0
- /package/dist/web/assets/{beancount-DMateAZX.js → beancount-BPESBMS9.js} +0 -0
- /package/dist/web/assets/{berry-9lXg0GRM.js → berry-BSLE-Sf8.js} +0 -0
- /package/dist/web/assets/{bibtex-DIbqmvFg.js → bibtex-CvUWWCVx.js} +0 -0
- /package/dist/web/assets/{bicep-02WGsoJ8.js → bicep--vcqqALZ.js} +0 -0
- /package/dist/web/assets/{bird2-BY0tbu3k.js → bird2-Clclqgh6.js} +0 -0
- /package/dist/web/assets/{c-jMBX_9Je.js → c-CSC2LwTp.js} +0 -0
- /package/dist/web/assets/{c3-B8JVbNjW.js → c3-Cl1_jUnm.js} +0 -0
- /package/dist/web/assets/{cadence-DUIf1tvL.js → cadence-BwAD7vSC.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-FhUCVxex.js → catppuccin-frappe-hr0HKoFX.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-CzfrtmgL.js → catppuccin-latte-DXEIYlFO.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-6xL0lOtj.js → catppuccin-macchiato-B2zST7sA.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-D39-xS3P.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-D8TeGvoT.js → clarity-BeQd5TQD.js} +0 -0
- /package/dist/web/assets/{clojure-Dx_acSX7.js → clojure-Csdo0vb_.js} +0 -0
- /package/dist/web/assets/{cmake-CyeYPq8o.js → cmake-Cf0q7ddg.js} +0 -0
- /package/dist/web/assets/{code-7ZAlTvsm.js → code-TekEnDFM.js} +0 -0
- /package/dist/web/assets/{codeowners-DrTI0lmI.js → codeowners-CUEzlC7R.js} +0 -0
- /package/dist/web/assets/{codeql-CPkFxVW-.js → codeql-DxHyogQt.js} +0 -0
- /package/dist/web/assets/{common-lisp-B0k-3LTj.js → common-lisp-WLb-tAda.js} +0 -0
- /package/dist/web/assets/{coq-uygpo7to.js → coq-DFtMD6Wn.js} +0 -0
- /package/dist/web/assets/{csharp-DKUYGfSp.js → csharp-DEnvXVjs.js} +0 -0
- /package/dist/web/assets/{css-DoOUp7v4.js → css-DMPpCfkZ.js} +0 -0
- /package/dist/web/assets/{csv-B3YE13gi.js → csv-DTSgNSaP.js} +0 -0
- /package/dist/web/assets/{csv-parser-CB6bK93y.js → csv-parser-B_xNn07y.js} +0 -0
- /package/dist/web/assets/{cue-DViO2wvn.js → cue-BEmVIZmd.js} +0 -0
- /package/dist/web/assets/{cypher-4BMCIW5N.js → cypher-CncQVhvU.js} +0 -0
- /package/dist/web/assets/{d-BT_sTHas.js → d-BzUSBVex.js} +0 -0
- /package/dist/web/assets/{dark-plus-DVVXu-1N.js → dark-plus-mysFNRq2.js} +0 -0
- /package/dist/web/assets/{dart-DHz6f6_6.js → dart-BBu3nkcE.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CWHnFOc-.js → data-grid-types-CzEQU9PJ.js} +0 -0
- /package/dist/web/assets/{database-BLht7BVM.js → database-COYAMZaw.js} +0 -0
- /package/dist/web/assets/{dax-ChYCjweK.js → dax-DcLVz9_9.js} +0 -0
- /package/dist/web/assets/{desktop-D6Lt4p04.js → desktop-DS2PdvoU.js} +0 -0
- /package/dist/web/assets/{diff-D8TDe4hP.js → diff-aUYk5Qys.js} +0 -0
- /package/dist/web/assets/{dist-B5ErTtYs.js → dist-Bn3E6I4R.js} +0 -0
- /package/dist/web/assets/{dist-D1CjMuoa.js → dist-Dxl3dqhC.js} +0 -0
- /package/dist/web/assets/{docker-Bsp0YbPx.js → docker-12Lj1QUD.js} +0 -0
- /package/dist/web/assets/{dotenv-B_7giSY_.js → dotenv-D-P4bzvl.js} +0 -0
- /package/dist/web/assets/{dracula-TrQL2iB5.js → dracula-C-eRNn4o.js} +0 -0
- /package/dist/web/assets/{dracula-soft-n2XOlgh-.js → dracula-soft-CBB1BI7O.js} +0 -0
- /package/dist/web/assets/{dream-maker-CdIEdhpT.js → dream-maker-C_j5A0r7.js} +0 -0
- /package/dist/web/assets/{edit-diff-preview-Cj6-iplb.js → edit-diff-preview-CRMu-6r1.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-CSbixs6u.js → emacs-lisp-W54LT7rh.js} +0 -0
- /package/dist/web/assets/{everforest-dark-BuZahZYp.js → everforest-dark-B_ISUDeh.js} +0 -0
- /package/dist/web/assets/{everforest-light-DPH53z5H.js → everforest-light-CNUYa354.js} +0 -0
- /package/dist/web/assets/{fennel-B1-K_hlJ.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-Cy12Dbua.js → fish-CbJVJzQj.js} +0 -0
- /package/dist/web/assets/{fluent-B_82ys8E.js → fluent-Cug5cOL1.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-BRQdNzZF.js → fortran-free-form-amHz32Zw.js} +0 -0
- /package/dist/web/assets/{gdscript-XBDmLUm9.js → gdscript-t_G6VYpv.js} +0 -0
- /package/dist/web/assets/{gdshader-DhVfB3u4.js → gdshader-DqZaHh4E.js} +0 -0
- /package/dist/web/assets/{genie-X3K29Y49.js → genie-CIJtFlZK.js} +0 -0
- /package/dist/web/assets/{gherkin-DKIx-6cX.js → gherkin-CalidqLY.js} +0 -0
- /package/dist/web/assets/{github-dark-Bf7zdp5s.js → github-dark-BG2xX0wa.js} +0 -0
- /package/dist/web/assets/{github-dark-default-DqsBBV11.js → github-dark-default-tDp_EOBs.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-X2gqRz6w.js → github-dark-dimmed-DlSfPwW2.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-Z7tvbGX4.js → github-dark-high-contrast-qZM7j5KB.js} +0 -0
- /package/dist/web/assets/{github-light-BKxt-7zZ.js → github-light-CnvWTiyb.js} +0 -0
- /package/dist/web/assets/{github-light-default-B0liF4d4.js → github-light-default-Dy6OAt2Q.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-F4encJwr.js → github-light-high-contrast-1BHQCOPl.js} +0 -0
- /package/dist/web/assets/{gleam-Pz2bHgBB.js → gleam-D-2cpXVX.js} +0 -0
- /package/dist/web/assets/{gn-CgmdNsPU.js → gn-C1cC4xLc.js} +0 -0
- /package/dist/web/assets/{gnuplot-qLNF5yZ9.js → gnuplot-2Gp459mV.js} +0 -0
- /package/dist/web/assets/{go-CSDUNhE7.js → go-BA1q0q8h.js} +0 -0
- /package/dist/web/assets/{groovy-B3NEnOHF.js → groovy-BlIa-VfI.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-DcoftiUX.js → gruvbox-dark-hard-BMIwVwaJ.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-D1wVSuD8.js → gruvbox-dark-medium-DxfuBW3n.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-DWpunymH.js → gruvbox-dark-soft-_NSslDDi.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-rHMvyUdS.js → gruvbox-light-hard-CP5MIsL9.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-3O2KiXO7.js → gruvbox-light-medium-BTMursH0.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-lNlXJPwH.js → gruvbox-light-soft-Bv6zFoVX.js} +0 -0
- /package/dist/web/assets/{haskell-aaG3aC0h.js → haskell-Da8UeSv-.js} +0 -0
- /package/dist/web/assets/{haxe-CPcHhUDd.js → haxe-mcKlcxBa.js} +0 -0
- /package/dist/web/assets/{hcl-CMQNlR_4.js → hcl-BdZcx5JX.js} +0 -0
- /package/dist/web/assets/{hjson-DeuklPFj.js → hjson-pFXYbN4t.js} +0 -0
- /package/dist/web/assets/{hlsl-BI3hlsaM.js → hlsl-Z0II0KR8.js} +0 -0
- /package/dist/web/assets/{horizon-C7-gOcjs.js → horizon-CufN8DyP.js} +0 -0
- /package/dist/web/assets/{horizon-bright-Cxt9bRW7.js → horizon-bright-5qoQVyIY.js} +0 -0
- /package/dist/web/assets/{houston-DbF2G7iD.js → houston-DOFkQwep.js} +0 -0
- /package/dist/web/assets/{hy-DRG6Hs2I.js → hy-BVbDMDcG.js} +0 -0
- /package/dist/web/assets/{imba-CxKv_2TW.js → imba-DRM6LLS5.js} +0 -0
- /package/dist/web/assets/{ini-BiHsyCdO.js → ini-2KCnNvmz.js} +0 -0
- /package/dist/web/assets/{java-D3RZzgDB.js → java-BmvH-Ou1.js} +0 -0
- /package/dist/web/assets/{javascript-4FmSqG-T.js → javascript-B7VhU1Yc.js} +0 -0
- /package/dist/web/assets/{json-CjB236_E.js → json-X1pNk0n7.js} +0 -0
- /package/dist/web/assets/{json5-bkfO-Rco.js → json5-CJeEJPTg.js} +0 -0
- /package/dist/web/assets/{jsonc-BwaTeLyv.js → jsonc-C1haTBsf.js} +0 -0
- /package/dist/web/assets/{jsonl-CfxNSwGd.js → jsonl-wQ8-AJgs.js} +0 -0
- /package/dist/web/assets/{jsonnet-CQETCYrp.js → jsonnet-BrEjY3Xh.js} +0 -0
- /package/dist/web/assets/{jssm-D5o3Zzdz.js → jssm-C6LgYbOs.js} +0 -0
- /package/dist/web/assets/{jsx-BAMILPLo.js → jsx-B2cfD_Fb.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BhGVxu3R.js → kanagawa-dragon-6UCcJpLw.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-FH4Y59ro.js → kanagawa-lotus-DOmfpsRg.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-eilvP9MB.js → kanagawa-wave-CpxmPE7N.js} +0 -0
- /package/dist/web/assets/{kdl-BQ-yvXUK.js → kdl-BrLEivmb.js} +0 -0
- /package/dist/web/assets/{kotlin-BuCx0-VT.js → kotlin-BO2FUnDB.js} +0 -0
- /package/dist/web/assets/{kusto-DAN_n_Cy.js → kusto-Cev1yiq9.js} +0 -0
- /package/dist/web/assets/{laserwave-Cq2BlxrT.js → laserwave-BlEkf-eH.js} +0 -0
- /package/dist/web/assets/{lean-Dhq7uXKw.js → lean-BLS3Xk2w.js} +0 -0
- /package/dist/web/assets/{less-CxaMQb8j.js → less-BXmcsqcq.js} +0 -0
- /package/dist/web/assets/{lib-MIEszzkI.js → lib-CxSBdrd7.js} +0 -0
- /package/dist/web/assets/{light-plus-B4sMAend.js → light-plus-DS6zriYl.js} +0 -0
- /package/dist/web/assets/{llvm-DQ6-B_6Y.js → llvm-C_wLnJgX.js} +0 -0
- /package/dist/web/assets/{log-Bb_vqvu7.js → log-Cg8pvmWi.js} +0 -0
- /package/dist/web/assets/{logo-BzfYv3A_.js → logo-C9-kEvPW.js} +0 -0
- /package/dist/web/assets/{luau-BnAeNR77.js → luau-NwaGugfZ.js} +0 -0
- /package/dist/web/assets/{make-B6IFuxpC.js → make-DBpJE-Z8.js} +0 -0
- /package/dist/web/assets/{markdown-Z0xi77Fn.js → markdown-B7ZTAu7B.js} +0 -0
- /package/dist/web/assets/{material-theme-1scy1SYn.js → material-theme-BsXH-Mss.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-G-JykXQP.js → material-theme-darker-CW9OlIeY.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BtKkCMVq.js → material-theme-lighter-D2PAh0Kw.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-irrDC89L.js → material-theme-ocean-Vz6DBVi3.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-Eq5_K4LM.js → material-theme-palenight-D-GleP3G.js} +0 -0
- /package/dist/web/assets/{matlab-BE3oCXZC.js → matlab-C7MYlMSn.js} +0 -0
- /package/dist/web/assets/{mdx-DYiuFTGw.js → mdx-FkOOX3Dq.js} +0 -0
- /package/dist/web/assets/{mermaid-DVlaEvtw.js → mermaid-C_9qw5it.js} +0 -0
- /package/dist/web/assets/{min-dark-DSkeTpQa.js → min-dark-BowNvxk2.js} +0 -0
- /package/dist/web/assets/{min-light-CFv2Q0uF.js → min-light-x8oWUmbL.js} +0 -0
- /package/dist/web/assets/{mipsasm-CiAFuZQ2.js → mipsasm-Dmi1AZOT.js} +0 -0
- /package/dist/web/assets/{mojo-ARshcaSQ.js → mojo-C6z7mry2.js} +0 -0
- /package/dist/web/assets/{monokai-CPTV-SOg.js → monokai-BQ4e_Hn0.js} +0 -0
- /package/dist/web/assets/{moonbit-D57B0dZr.js → moonbit-CEeNIoB4.js} +0 -0
- /package/dist/web/assets/{move-qgy3G_o9.js → move-bALfKUa7.js} +0 -0
- /package/dist/web/assets/{narrat-CZ3rC-oc.js → narrat-DX4JlAWT.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-BxxIOcI4.js → nextflow-groovy-CKQWtRkO.js} +0 -0
- /package/dist/web/assets/{night-owl-B1ryGCda.js → night-owl-D4PQd726.js} +0 -0
- /package/dist/web/assets/{night-owl-light-BZvNnvMF.js → night-owl-light-BQo_YHll.js} +0 -0
- /package/dist/web/assets/{nix-BVBQi8yv.js → nix-B1jThkGj.js} +0 -0
- /package/dist/web/assets/{nord-3NXw613h.js → nord-35quHUKo.js} +0 -0
- /package/dist/web/assets/{nushell-BMOLRalb.js → nushell-L6DbJTuL.js} +0 -0
- /package/dist/web/assets/{objective-c-AxruEUgh.js → objective-c-CTZ4bR2U.js} +0 -0
- /package/dist/web/assets/{objective-cpp-cFT0qRsD.js → objective-cpp-Dm1YDIdA.js} +0 -0
- /package/dist/web/assets/{ocaml-_8JH6O8J.js → ocaml-B3n__LGy.js} +0 -0
- /package/dist/web/assets/{odin-nwYvR0O6.js → odin-DmqZ8n3i.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-C1LaYJaH.js → one-dark-pro-16_UaUig.js} +0 -0
- /package/dist/web/assets/{one-light-B7rMc__c.js → one-light-B-GGjWn5.js} +0 -0
- /package/dist/web/assets/{openscad-Cwes8bKO.js → openscad-DTFB9Sj6.js} +0 -0
- /package/dist/web/assets/{pascal-DMt-6tdZ.js → pascal-RcT1dQYN.js} +0 -0
- /package/dist/web/assets/{pkl-QBTyYQmB.js → pkl-Dr4yLQ_o.js} +0 -0
- /package/dist/web/assets/{plastic-BTSUp8Fk.js → plastic-hp2Nry0R.js} +0 -0
- /package/dist/web/assets/{plsql-DQv3IFXP.js → plsql-pFcO4WZ0.js} +0 -0
- /package/dist/web/assets/{po-CNwZx4tW.js → po-BkZ0_HvY.js} +0 -0
- /package/dist/web/assets/{poimandres-8Os7Qequ.js → poimandres-BcTrxj7f.js} +0 -0
- /package/dist/web/assets/{polar-b4yK8oD8.js → polar-DHK3q8FF.js} +0 -0
- /package/dist/web/assets/{postcss-sFctwpxx.js → postcss-Bv7WzijA.js} +0 -0
- /package/dist/web/assets/{powerquery-Cg_WrtuN.js → powerquery-DpaU_hW9.js} +0 -0
- /package/dist/web/assets/{powershell-C7Ifz95h.js → powershell-_Rqc0MGP.js} +0 -0
- /package/dist/web/assets/{prisma-Z52HUJzQ.js → prisma-wyegE8us.js} +0 -0
- /package/dist/web/assets/{prolog-DLqW-zR1.js → prolog-DspHCURv.js} +0 -0
- /package/dist/web/assets/{proto-BOIzxCCJ.js → proto-BOBiNGf5.js} +0 -0
- /package/dist/web/assets/{puppet-De7TjZIf.js → puppet-DfLvV8h2.js} +0 -0
- /package/dist/web/assets/{purescript-R76ou1WT.js → purescript-BY5ZSOZy.js} +0 -0
- /package/dist/web/assets/{python-Dprm0tNP.js → python-B758mMeg.js} +0 -0
- /package/dist/web/assets/{qmldir-Clp_jpNw.js → qmldir-C75bpHvy.js} +0 -0
- /package/dist/web/assets/{qss-eQPYYzSo.js → qss-DcLTlbLd.js} +0 -0
- /package/dist/web/assets/{r-CCcRHIf5.js → r-D0G_Y1P5.js} +0 -0
- /package/dist/web/assets/{racket-CzE472yp.js → racket-DTye_5qn.js} +0 -0
- /package/dist/web/assets/{raku-DQwXrTSi.js → raku-uJXBXkV0.js} +0 -0
- /package/dist/web/assets/{react-J9g6e3Rq.js → react-CorNPdie.js} +0 -0
- /package/dist/web/assets/{red-KCS6wyop.js → red-rs3HE3re.js} +0 -0
- /package/dist/web/assets/{reg-CcrAddUh.js → reg-DkTIaX7a.js} +0 -0
- /package/dist/web/assets/{regexp-DDbud-Ri.js → regexp-4TLSs4_m.js} +0 -0
- /package/dist/web/assets/{rel-99GDgaHp.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-Dm2eNv0R.js → riscv-DtaWMlo0.js} +0 -0
- /package/dist/web/assets/{ron-CzFt0ygH.js → ron-BCPxwJD6.js} +0 -0
- /package/dist/web/assets/{rose-pine-Ck6lCrCP.js → rose-pine-CNryoqGi.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-vtALRJNj.js → rose-pine-dawn-C-gJOQVP.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-DPto8qXw.js → rose-pine-moon-BdXSXpZh.js} +0 -0
- /package/dist/web/assets/{rosmsg-NtS6429H.js → rosmsg-CPG8X-D5.js} +0 -0
- /package/dist/web/assets/{rust-BjIXvF9h.js → rust-CxfW3ePx.js} +0 -0
- /package/dist/web/assets/{sass-CQ23wf5E.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-LfKLM143.js → scala-DyUsfHNc.js} +0 -0
- /package/dist/web/assets/{scheme-D3SLBXlF.js → scheme-ROgrwiO-.js} +0 -0
- /package/dist/web/assets/{sdbl-ODRd2rGN.js → sdbl-B1EAQWpp.js} +0 -0
- /package/dist/web/assets/{shellscript-3KB1G_oA.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-DTtyWmIy.js → slack-dark-DnmSY72G.js} +0 -0
- /package/dist/web/assets/{slack-ochin-Bu0PApk3.js → slack-ochin-q97gHjcd.js} +0 -0
- /package/dist/web/assets/{smalltalk-haMT-Sbe.js → smalltalk-B-1waXvA.js} +0 -0
- /package/dist/web/assets/{snazzy-light-DXJzefE9.js → snazzy-light-C8yWDN2g.js} +0 -0
- /package/dist/web/assets/{solarized-dark-B6LyYa18.js → solarized-dark-ClVDEMJZ.js} +0 -0
- /package/dist/web/assets/{solarized-light-QLADebkv.js → solarized-light-Bts6CUIP.js} +0 -0
- /package/dist/web/assets/{solidity-mzfq1aDc.js → solidity-DYxwp0om.js} +0 -0
- /package/dist/web/assets/{splunk-CyH4RWBp.js → splunk-jK6-Sr06.js} +0 -0
- /package/dist/web/assets/{sql-CWVlT5D3.js → sql-DPpd8aUS.js} +0 -0
- /package/dist/web/assets/{ssh-config-DNvQJ1Qx.js → ssh-config-Bimb9LVr.js} +0 -0
- /package/dist/web/assets/{stylus-ByQQdtmf.js → stylus-B2DgJRJw.js} +0 -0
- /package/dist/web/assets/{swift-D1cpY4ow.js → swift-ChEH2nFL.js} +0 -0
- /package/dist/web/assets/{synthwave-84-BDF_-QiW.js → synthwave-84-DwSLbgAm.js} +0 -0
- /package/dist/web/assets/{system-verilog-BYrkMydC.js → system-verilog-DoVBMhJ8.js} +0 -0
- /package/dist/web/assets/{systemd-CQm3zyK0.js → systemd--Ux4VAYD.js} +0 -0
- /package/dist/web/assets/{table-CAVmgQMT.js → table-Di8pv2Y_.js} +0 -0
- /package/dist/web/assets/{talonscript-DMW5CzE1.js → talonscript-DQNx9nak.js} +0 -0
- /package/dist/web/assets/{tasl-BhFzMCr2.js → tasl-Bwy_Y9uD.js} +0 -0
- /package/dist/web/assets/{tcl-D7VEAF-9.js → tcl-Drea-2jA.js} +0 -0
- /package/dist/web/assets/{terraform-DdT5A0Vy.js → terraform-4rS5HoFk.js} +0 -0
- /package/dist/web/assets/{tokyo-night-WGLMM6Q9.js → tokyo-night-C9MqaxIn.js} +0 -0
- /package/dist/web/assets/{toml-CZ7ipXHZ.js → toml-tSgOSv42.js} +0 -0
- /package/dist/web/assets/{tsv-B1zVvoTr.js → tsv-BmL4O1Zx.js} +0 -0
- /package/dist/web/assets/{tsx-D4HwRUBq.js → tsx-BwzeA880.js} +0 -0
- /package/dist/web/assets/{turtle-B4r8KEJH.js → turtle-2DYvssFL.js} +0 -0
- /package/dist/web/assets/{typescript-BnHhxMtp.js → typescript-ZC-vonSh.js} +0 -0
- /package/dist/web/assets/{typespec-DP2q46GT.js → typespec-DkCEO45F.js} +0 -0
- /package/dist/web/assets/{typst-DFsD_yaD.js → typst-DAZdb2n6.js} +0 -0
- /package/dist/web/assets/{utils-CTg5uAYR.js → utils-CSCvNZxE.js} +0 -0
- /package/dist/web/assets/{v-Bji8hSVT.js → v-B_wsb4C1.js} +0 -0
- /package/dist/web/assets/{vala-D3TIgGmU.js → vala-BDBNS784.js} +0 -0
- /package/dist/web/assets/{vb-DvcxFS2q.js → vb-CuOoJSSa.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-DfNMj6xt.js → vendor-xterm-CImj6i6Z.js} +0 -0
- /package/dist/web/assets/{verilog-Dy7cF35d.js → verilog-BCcOvOcc.js} +0 -0
- /package/dist/web/assets/{vesper-BzjwUv9J.js → vesper-vN8CREK5.js} +0 -0
- /package/dist/web/assets/{vhdl-DuFnFNmW.js → vhdl-CI8PoqeM.js} +0 -0
- /package/dist/web/assets/{viml-yAPgKlbz.js → viml-B66dNP1B.js} +0 -0
- /package/dist/web/assets/{vitesse-black-oSSQdyIZ.js → vitesse-black-0bGIaCfD.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-BZxwPihB.js → vitesse-dark-Dk-RSXq-.js} +0 -0
- /package/dist/web/assets/{vitesse-light-uIigycvt.js → vitesse-light-BUsA5RhG.js} +0 -0
- /package/dist/web/assets/{vyper-CX3NAxm5.js → vyper-dNodzEa8.js} +0 -0
- /package/dist/web/assets/{wasm-Coen1MOg.js → wasm-BDxaNPCj.js} +0 -0
- /package/dist/web/assets/{wasm-D9td37qO.js → wasm-d6SE2_qm.js} +0 -0
- /package/dist/web/assets/{wenyan-lwNIHgk6.js → wenyan-D0h8Uz55.js} +0 -0
- /package/dist/web/assets/{wgsl-DQAzCfog.js → wgsl-vKs_vsvQ.js} +0 -0
- /package/dist/web/assets/{wikitext-DTXmt5NE.js → wikitext-BIWsPJit.js} +0 -0
- /package/dist/web/assets/{wit-Bdw_7WDH.js → wit-6vmKi2H3.js} +0 -0
- /package/dist/web/assets/{wolfram-DqyHDZ07.js → wolfram-zoNg6F1a.js} +0 -0
- /package/dist/web/assets/{x-C2VSAp7O.js → x-BsFLg-T8.js} +0 -0
- /package/dist/web/assets/{yaml-CPXhdByd.js → yaml-W95qP6-B.js} +0 -0
- /package/dist/web/assets/{zenscript-6s_i5zek.js → zenscript-BxircxDx.js} +0 -0
- /package/dist/web/assets/{zig-B2htezJ_.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
|
+
}
|
package/src/types/api.ts
CHANGED
|
@@ -23,9 +23,11 @@ export type TerminalWsMessage =
|
|
|
23
23
|
|
|
24
24
|
/** WebSocket message types (chat) */
|
|
25
25
|
export type ChatWsClientMessage =
|
|
26
|
-
| { type: "message"; content: string; permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>; model?: string }
|
|
26
|
+
| { type: "message"; content: string; permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>; model?: string; effort?: string; thinking?: boolean }
|
|
27
27
|
| { type: "cancel" }
|
|
28
28
|
| { type: "set_model"; model: string }
|
|
29
|
+
| { type: "set_effort"; effort: string }
|
|
30
|
+
| { type: "set_thinking"; enabled: boolean }
|
|
29
31
|
| { type: "approval_response"; requestId: string; approved: boolean; reason?: string; data?: unknown }
|
|
30
32
|
| { type: "kill_background_shell"; shellId: string }
|
|
31
33
|
| { type: "ready" };
|
|
@@ -57,7 +59,7 @@ export type ChatWsServerMessage =
|
|
|
57
59
|
| { type: "error"; message: string }
|
|
58
60
|
| { type: "account_info"; accountId: string; accountLabel: string }
|
|
59
61
|
| { type: "phase_changed"; phase: SessionPhase; elapsed?: number }
|
|
60
|
-
| { type: "session_state"; sessionId: string; phase: SessionPhase; pendingApproval: { requestId: string; tool: string; input: unknown } | null; sessionTitle: string | null; model?: string }
|
|
62
|
+
| { type: "session_state"; sessionId: string; phase: SessionPhase; pendingApproval: { requestId: string; tool: string; input: unknown } | null; sessionTitle: string | null; model?: string; effort?: string; thinking?: boolean }
|
|
61
63
|
| { type: "turn_events"; events: unknown[] }
|
|
62
64
|
| { type: "title_updated"; title: string }
|
|
63
65
|
| { type: "compact_status"; status: "compacting" | "done" }
|
package/src/types/chat.ts
CHANGED
|
@@ -4,8 +4,16 @@ export interface SendMessageOpts {
|
|
|
4
4
|
images?: Array<{ data: string; mediaType: string }>;
|
|
5
5
|
/** Per-session model override; falls back to provider config model when absent */
|
|
6
6
|
model?: string;
|
|
7
|
+
/** Override the provider's 1M-context setting for this call (false = never add the
|
|
8
|
+
* [1m] suffix). Used by lightweight calls (e.g. the group-chat router) whose small
|
|
9
|
+
* model may not support a 1M window. Falls back to provider config when absent. */
|
|
10
|
+
oneMContext?: boolean;
|
|
7
11
|
/** Per-query turn cap; falls back to provider config max_turns when absent */
|
|
8
12
|
maxTurns?: number;
|
|
13
|
+
/** Per-session effort override (low|medium|high|xhigh|max); falls back to provider config */
|
|
14
|
+
effort?: string;
|
|
15
|
+
/** Per-session thinking budget → SDK maxThinkingTokens; falls back to provider config */
|
|
16
|
+
maxThinkingTokens?: number;
|
|
9
17
|
}
|
|
10
18
|
|
|
11
19
|
export interface AIProvider {
|
package/src/types/config.ts
CHANGED
|
@@ -67,7 +67,7 @@ export interface AIProviderConfig {
|
|
|
67
67
|
api_key_env?: string;
|
|
68
68
|
api_key?: string;
|
|
69
69
|
base_url?: string;
|
|
70
|
-
effort?: "low" | "medium" | "high" | "max";
|
|
70
|
+
effort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
71
71
|
max_turns?: number;
|
|
72
72
|
max_budget_usd?: number;
|
|
73
73
|
thinking_budget_tokens?: number;
|
|
@@ -97,7 +97,7 @@ export const DEFAULT_CONFIG: PpmConfig = {
|
|
|
97
97
|
claude: {
|
|
98
98
|
type: "agent-sdk",
|
|
99
99
|
api_key_env: "ANTHROPIC_API_KEY",
|
|
100
|
-
model: "claude-opus-
|
|
100
|
+
model: "claude-opus-5",
|
|
101
101
|
effort: "high",
|
|
102
102
|
max_turns: 1000,
|
|
103
103
|
permission_mode: "bypassPermissions",
|
|
@@ -120,8 +120,8 @@ export const DEFAULT_CONFIG: PpmConfig = {
|
|
|
120
120
|
};
|
|
121
121
|
|
|
122
122
|
const VALID_TYPES = ["agent-sdk", "cli", "mock"] as const;
|
|
123
|
-
const VALID_EFFORTS = ["low", "medium", "high"] as const;
|
|
124
|
-
const VALID_MODELS = ["claude-fable-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"] as const;
|
|
123
|
+
const VALID_EFFORTS = ["low", "medium", "high", "xhigh", "max"] as const;
|
|
124
|
+
const VALID_MODELS = ["claude-opus-5", "claude-fable-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5"] as const;
|
|
125
125
|
/** Allowed CLI commands for CLI providers (prevents command injection) */
|
|
126
126
|
const VALID_CLI_COMMANDS = ["cursor-agent", "codex", "gemini"] as const;
|
|
127
127
|
/** Only these values are allowed for default_provider in config */
|
|
@@ -241,12 +241,7 @@ export function sanitizeConfig(config: PpmConfig): boolean {
|
|
|
241
241
|
dirty = true;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
// Downgrade "max" effort → "high" (not available for Claude.ai subscribers)
|
|
245
244
|
for (const provider of Object.values(config.ai.providers)) {
|
|
246
|
-
if ((provider as any).effort === "max") {
|
|
247
|
-
provider.effort = "high";
|
|
248
|
-
dirty = true;
|
|
249
|
-
}
|
|
250
245
|
// Fix invalid permission_mode
|
|
251
246
|
if (provider.permission_mode != null && !["default", "acceptEdits", "plan", "bypassPermissions"].includes(provider.permission_mode)) {
|
|
252
247
|
provider.permission_mode = "bypassPermissions";
|
|
@@ -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
|
}
|
|
@@ -112,6 +112,10 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
112
112
|
sessionTitle,
|
|
113
113
|
model,
|
|
114
114
|
setModel,
|
|
115
|
+
effort,
|
|
116
|
+
setEffort,
|
|
117
|
+
thinking,
|
|
118
|
+
setThinking,
|
|
115
119
|
sendMessage,
|
|
116
120
|
respondToApproval,
|
|
117
121
|
cancelStreaming,
|
|
@@ -681,6 +685,10 @@ export function ChatTab({ metadata, tabId }: ChatTabProps) {
|
|
|
681
685
|
onProviderChange={!sessionId ? setProviderId : undefined}
|
|
682
686
|
model={model}
|
|
683
687
|
onModelChange={setModel}
|
|
688
|
+
effort={effort}
|
|
689
|
+
onEffortChange={setEffort}
|
|
690
|
+
thinking={thinking}
|
|
691
|
+
onThinkingChange={setThinking}
|
|
684
692
|
/>
|
|
685
693
|
)}
|
|
686
694
|
</div>
|
|
@@ -7,7 +7,7 @@ import { isImageFile } from "@/lib/file-support";
|
|
|
7
7
|
import { AttachmentChips } from "./attachment-chips";
|
|
8
8
|
import { ModeSelector, getModeLabel, getModeIcon } from "./mode-selector";
|
|
9
9
|
import { ProviderSelector } from "./provider-selector";
|
|
10
|
-
import {
|
|
10
|
+
import { ModelThinkingSelector } from "./model-thinking-selector";
|
|
11
11
|
import type { SlashItem } from "./slash-command-picker";
|
|
12
12
|
import type { FileNode } from "../../../types/project";
|
|
13
13
|
import { useFileStore } from "@/stores/file-store";
|
|
@@ -69,6 +69,14 @@ interface MessageInputProps {
|
|
|
69
69
|
model?: string | null;
|
|
70
70
|
/** Model change handler — undefined when no active session */
|
|
71
71
|
onModelChange?: (model: string) => void;
|
|
72
|
+
/** Current per-session effort (null = provider default) */
|
|
73
|
+
effort?: string | null;
|
|
74
|
+
/** Effort change handler */
|
|
75
|
+
onEffortChange?: (effort: string) => void;
|
|
76
|
+
/** Current per-session thinking on/off */
|
|
77
|
+
thinking?: boolean;
|
|
78
|
+
/** Thinking toggle handler */
|
|
79
|
+
onThinkingChange?: (enabled: boolean) => void;
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
export const MessageInput = memo(function MessageInput({
|
|
@@ -96,6 +104,10 @@ export const MessageInput = memo(function MessageInput({
|
|
|
96
104
|
onProviderChange,
|
|
97
105
|
model,
|
|
98
106
|
onModelChange,
|
|
107
|
+
effort,
|
|
108
|
+
onEffortChange,
|
|
109
|
+
thinking,
|
|
110
|
+
onThinkingChange,
|
|
99
111
|
}: MessageInputProps) {
|
|
100
112
|
// Uncontrolled textarea: value lives in DOM + ref, not React state.
|
|
101
113
|
// Only `hasText` state triggers re-renders (empty↔non-empty for send button).
|
|
@@ -700,9 +712,13 @@ export const MessageInput = memo(function MessageInput({
|
|
|
700
712
|
/>
|
|
701
713
|
)}
|
|
702
714
|
{onModelChange && projectName && (
|
|
703
|
-
<
|
|
704
|
-
|
|
705
|
-
|
|
715
|
+
<ModelThinkingSelector
|
|
716
|
+
model={model ?? null}
|
|
717
|
+
effort={effort ?? null}
|
|
718
|
+
thinking={thinking ?? false}
|
|
719
|
+
onModelChange={onModelChange}
|
|
720
|
+
onEffortChange={onEffortChange ?? (() => {})}
|
|
721
|
+
onThinkingChange={onThinkingChange ?? (() => {})}
|
|
706
722
|
projectName={projectName}
|
|
707
723
|
providerId={providerId ?? "claude"}
|
|
708
724
|
disabled={isStreaming}
|
|
@@ -795,9 +811,13 @@ export const MessageInput = memo(function MessageInput({
|
|
|
795
811
|
/>
|
|
796
812
|
)}
|
|
797
813
|
{onModelChange && projectName && (
|
|
798
|
-
<
|
|
799
|
-
|
|
800
|
-
|
|
814
|
+
<ModelThinkingSelector
|
|
815
|
+
model={model ?? null}
|
|
816
|
+
effort={effort ?? null}
|
|
817
|
+
thinking={thinking ?? false}
|
|
818
|
+
onModelChange={onModelChange}
|
|
819
|
+
onEffortChange={onEffortChange ?? (() => {})}
|
|
820
|
+
onThinkingChange={onThinkingChange ?? (() => {})}
|
|
801
821
|
projectName={projectName}
|
|
802
822
|
providerId={providerId ?? "claude"}
|
|
803
823
|
disabled={isStreaming}
|