@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
|
@@ -6,15 +6,22 @@ import {
|
|
|
6
6
|
listGroups,
|
|
7
7
|
deleteGroup,
|
|
8
8
|
addMember,
|
|
9
|
+
getMember,
|
|
10
|
+
updateMember,
|
|
11
|
+
removeMember,
|
|
9
12
|
listMembers,
|
|
10
13
|
readMessages,
|
|
14
|
+
setGroupMaxTurns,
|
|
11
15
|
} from "../../services/group-chat/group-chat.store.ts";
|
|
12
16
|
import { groupChatService } from "../../services/group-chat/group-chat.service.ts";
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
17
|
+
import { resolveTranscriptPath } from "../../services/group-chat/transcript-archive.ts";
|
|
18
|
+
import { parseJsonlTranscript, parseTranscriptConfig } from "../../services/jsonl-transcript-parser.ts";
|
|
19
|
+
import type { AddMemberInput, UpdateMemberInput } from "../../types/group-chat.ts";
|
|
15
20
|
|
|
16
21
|
/** Allowlist: group ids are UUIDs — alphanumeric + hyphens only. */
|
|
17
22
|
const VALID_GROUP_ID = /^[a-zA-Z0-9-]+$/;
|
|
23
|
+
/** Member ids are UUIDs too. */
|
|
24
|
+
const VALID_MEMBER_ID = /^[a-zA-Z0-9-]+$/;
|
|
18
25
|
/** Session refs are Claude session UUIDs. */
|
|
19
26
|
const VALID_SESSION_REF = /^[a-zA-Z0-9-]+$/;
|
|
20
27
|
|
|
@@ -79,6 +86,101 @@ groupChatRoutes.get("/:id", (c) => {
|
|
|
79
86
|
return c.json(ok({ ...group, members: listMembers(id) }));
|
|
80
87
|
});
|
|
81
88
|
|
|
89
|
+
// Group settings (reply-burst cap) -----------------------------------------
|
|
90
|
+
groupChatRoutes.patch("/:id", async (c) => {
|
|
91
|
+
const id = c.req.param("id");
|
|
92
|
+
if (!VALID_GROUP_ID.test(id)) return c.json(err("Invalid group id"), 400);
|
|
93
|
+
if (!getGroup(id)) return c.json(err("Group not found"), 404);
|
|
94
|
+
let body: { maxTurns?: number };
|
|
95
|
+
try { body = await c.req.json(); } catch { return c.json(err("Invalid JSON body"), 400); }
|
|
96
|
+
if (body.maxTurns !== undefined) {
|
|
97
|
+
const n = Math.floor(Number(body.maxTurns));
|
|
98
|
+
if (!Number.isFinite(n) || n < 1 || n > 50) return c.json(err("maxTurns must be 1–50"), 400);
|
|
99
|
+
setGroupMaxTurns(id, n);
|
|
100
|
+
}
|
|
101
|
+
return c.json(ok({ ...getGroup(id)!, members: listMembers(id) }));
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Member management (add / update / remove) -------------------------------
|
|
105
|
+
// Invariant: a group always has exactly one leader and at least one member.
|
|
106
|
+
|
|
107
|
+
groupChatRoutes.post("/:id/members", async (c) => {
|
|
108
|
+
const id = c.req.param("id");
|
|
109
|
+
if (!VALID_GROUP_ID.test(id)) return c.json(err("Invalid group id"), 400);
|
|
110
|
+
if (!getGroup(id)) return c.json(err("Group not found"), 404);
|
|
111
|
+
|
|
112
|
+
let body: { role?: string; name?: string; persona?: string; model?: string; color?: string };
|
|
113
|
+
try { body = await c.req.json(); } catch { return c.json(err("Invalid JSON body"), 400); }
|
|
114
|
+
const name = body.name?.trim();
|
|
115
|
+
if (!name) return c.json(err("member name is required"), 400);
|
|
116
|
+
const role = body.role === "leader" ? "leader" : "member";
|
|
117
|
+
|
|
118
|
+
// Promoting a new leader demotes the current one (keep exactly one leader).
|
|
119
|
+
if (role === "leader") {
|
|
120
|
+
for (const m of listMembers(id)) {
|
|
121
|
+
if (m.role === "leader") updateMember(m.id, { role: "member" });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const input: AddMemberInput = {
|
|
125
|
+
groupId: id, role, name,
|
|
126
|
+
persona: body.persona ?? null, model: body.model ?? null, color: body.color ?? null,
|
|
127
|
+
};
|
|
128
|
+
return c.json(ok(addMember(input)));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
groupChatRoutes.patch("/:id/members/:memberId", async (c) => {
|
|
132
|
+
const id = c.req.param("id");
|
|
133
|
+
const memberId = c.req.param("memberId");
|
|
134
|
+
if (!VALID_GROUP_ID.test(id) || !VALID_MEMBER_ID.test(memberId)) return c.json(err("Invalid id"), 400);
|
|
135
|
+
if (!getGroup(id)) return c.json(err("Group not found"), 404);
|
|
136
|
+
const member = getMember(memberId);
|
|
137
|
+
if (!member || member.groupId !== id) return c.json(err("Member not found"), 404);
|
|
138
|
+
|
|
139
|
+
let body: { role?: string; name?: string; persona?: string; model?: string; color?: string };
|
|
140
|
+
try { body = await c.req.json(); } catch { return c.json(err("Invalid JSON body"), 400); }
|
|
141
|
+
|
|
142
|
+
const patch: UpdateMemberInput = {};
|
|
143
|
+
if (body.name !== undefined) {
|
|
144
|
+
const n = body.name.trim();
|
|
145
|
+
if (!n) return c.json(err("member name cannot be empty"), 400);
|
|
146
|
+
patch.name = n;
|
|
147
|
+
}
|
|
148
|
+
if (body.persona !== undefined) patch.persona = body.persona || null;
|
|
149
|
+
if (body.model !== undefined) patch.model = body.model || null;
|
|
150
|
+
if (body.color !== undefined) patch.color = body.color || null;
|
|
151
|
+
|
|
152
|
+
if (body.role !== undefined) {
|
|
153
|
+
if (body.role !== "leader" && body.role !== "member") return c.json(err("invalid role"), 400);
|
|
154
|
+
if (body.role === "leader") {
|
|
155
|
+
// Demote the current leader(s) before promoting this member.
|
|
156
|
+
for (const m of listMembers(id)) {
|
|
157
|
+
if (m.role === "leader" && m.id !== memberId) updateMember(m.id, { role: "member" });
|
|
158
|
+
}
|
|
159
|
+
patch.role = "leader";
|
|
160
|
+
} else if (member.role === "leader") {
|
|
161
|
+
return c.json(err("promote another member to leader before demoting this one"), 400);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return c.json(ok(updateMember(memberId, patch)));
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
groupChatRoutes.delete("/:id/members/:memberId", async (c) => {
|
|
168
|
+
const id = c.req.param("id");
|
|
169
|
+
const memberId = c.req.param("memberId");
|
|
170
|
+
if (!VALID_GROUP_ID.test(id) || !VALID_MEMBER_ID.test(memberId)) return c.json(err("Invalid id"), 400);
|
|
171
|
+
const group = getGroup(id);
|
|
172
|
+
if (!group) return c.json(err("Group not found"), 404);
|
|
173
|
+
const member = getMember(memberId);
|
|
174
|
+
if (!member || member.groupId !== id) return c.json(err("Member not found"), 404);
|
|
175
|
+
|
|
176
|
+
const members = listMembers(id);
|
|
177
|
+
if (members.length <= 1) return c.json(err("a group needs at least one member"), 400);
|
|
178
|
+
if (member.role === "leader") return c.json(err("reassign the leader before removing this member"), 400);
|
|
179
|
+
await groupChatService.archiveMemberSession(group.name, member.sessionId);
|
|
180
|
+
removeMember(memberId);
|
|
181
|
+
return c.json(ok({ deleted: memberId }));
|
|
182
|
+
});
|
|
183
|
+
|
|
82
184
|
// Feed (windowed/paginated) ------------------------------------------------
|
|
83
185
|
groupChatRoutes.get("/:id/feed", (c) => {
|
|
84
186
|
const id = c.req.param("id");
|
|
@@ -93,8 +195,9 @@ groupChatRoutes.get("/:id/feed", (c) => {
|
|
|
93
195
|
return c.json(ok({ messages }));
|
|
94
196
|
});
|
|
95
197
|
|
|
96
|
-
// Archived transcript for a member session (powers "view full")
|
|
97
|
-
|
|
198
|
+
// Archived transcript for a member session (powers "view full") — parsed into
|
|
199
|
+
// chat-style messages (text/thinking/tool_use/tool_result) + input config.
|
|
200
|
+
groupChatRoutes.get("/:id/transcript", async (c) => {
|
|
98
201
|
const id = c.req.param("id");
|
|
99
202
|
if (!VALID_GROUP_ID.test(id)) return c.json(err("Invalid group id"), 400);
|
|
100
203
|
const group = getGroup(id);
|
|
@@ -104,9 +207,13 @@ groupChatRoutes.get("/:id/transcript", (c) => {
|
|
|
104
207
|
if (!sessionRef || !VALID_SESSION_REF.test(sessionRef)) {
|
|
105
208
|
return c.json(err("Invalid sessionRef"), 400);
|
|
106
209
|
}
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
|
|
210
|
+
const path = await resolveTranscriptPath(sessionRef, group.name);
|
|
211
|
+
if (path === null) return c.json(err("Transcript not found"), 404);
|
|
212
|
+
const [messages, config] = await Promise.all([
|
|
213
|
+
parseJsonlTranscript(path),
|
|
214
|
+
parseTranscriptConfig(path),
|
|
215
|
+
]);
|
|
216
|
+
return c.json(ok({ messages, config }));
|
|
110
217
|
});
|
|
111
218
|
|
|
112
219
|
// Send a message → starts / feeds the engine ------------------------------
|
|
@@ -150,11 +257,13 @@ groupChatRoutes.post("/:id/resume", async (c) => {
|
|
|
150
257
|
});
|
|
151
258
|
|
|
152
259
|
// Delete -------------------------------------------------------------------
|
|
153
|
-
groupChatRoutes.delete("/:id", (c) => {
|
|
260
|
+
groupChatRoutes.delete("/:id", async (c) => {
|
|
154
261
|
const id = c.req.param("id");
|
|
155
262
|
if (!VALID_GROUP_ID.test(id)) return c.json(err("Invalid group id"), 400);
|
|
156
263
|
if (!getGroup(id)) return c.json(err("Group not found"), 404);
|
|
157
|
-
|
|
264
|
+
// Archive member sessions (keep-alive means they live until now) BEFORE the store
|
|
265
|
+
// cascade removes the member rows.
|
|
266
|
+
await groupChatService.archiveAndForget(id);
|
|
158
267
|
deleteGroup(id);
|
|
159
268
|
return c.json(ok({ deleted: id }));
|
|
160
269
|
});
|
package/src/server/ws/chat.ts
CHANGED
|
@@ -3,27 +3,44 @@ import { providerRegistry } from "../../providers/registry.ts";
|
|
|
3
3
|
import { resolveProjectPath } from "../helpers/resolve-project.ts";
|
|
4
4
|
import { logSessionEvent } from "../../services/session-log.service.ts";
|
|
5
5
|
import { listSessions as sdkListSessions } from "@anthropic-ai/claude-agent-sdk";
|
|
6
|
-
import { getSessionTitle, incrementSessionUnread, clearSessionUnread, getSessionModel, setSessionModel, getSessionProvider } from "../../services/db.service.ts";
|
|
6
|
+
import { getSessionTitle, incrementSessionUnread, clearSessionUnread, getSessionModel, setSessionModel, getSessionProvider, getSessionEffort, setSessionEffort, getSessionThinking, setSessionThinking } from "../../services/db.service.ts";
|
|
7
|
+
import { VALID_EFFORT_VALUES } from "../../providers/claude-agent-sdk-query-options.ts";
|
|
7
8
|
import type { ChatWsClientMessage, SessionPhase } from "../../types/api.ts";
|
|
9
|
+
|
|
10
|
+
/** Budget passed to the SDK as maxThinkingTokens when the per-session Thinking toggle is ON. */
|
|
11
|
+
const DEFAULT_THINKING_BUDGET = 12000;
|
|
8
12
|
import { startWatching, stopWatching, onFileChange } from "../../services/file-watcher.service.ts";
|
|
9
13
|
import { bashOutputSpy } from "../../services/bash-output-spy.ts";
|
|
10
14
|
import { backgroundShellRegistry } from "../../services/background-shell-registry.ts";
|
|
11
15
|
import { basename } from "node:path";
|
|
12
16
|
import { configService } from "../../services/config.service.ts";
|
|
13
17
|
|
|
14
|
-
/** Resolve the
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (override) return override;
|
|
18
|
+
/** Resolve the SESSION's provider config — not the global default provider's.
|
|
19
|
+
* Otherwise a non-default provider's chat (e.g. codex) would inherit claude's values. */
|
|
20
|
+
function sessionProviderConfig(sessionId: string) {
|
|
18
21
|
const ai = configService.get("ai");
|
|
19
|
-
// Fall back to the SESSION's provider default model — not the global default
|
|
20
|
-
// provider's. Otherwise a non-default provider's chat (e.g. codex) would show
|
|
21
|
-
// the claude default model in the picker.
|
|
22
22
|
const pid = activeSessions.get(sessionId)?.providerId
|
|
23
23
|
?? chatService.getSession(sessionId)?.providerId
|
|
24
24
|
?? getSessionProvider(sessionId)
|
|
25
25
|
?? ai.default_provider ?? "claude";
|
|
26
|
-
return ai.providers[pid]
|
|
26
|
+
return ai.providers[pid];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Resolve the model shown in session_state: per-session override, else provider default. */
|
|
30
|
+
function resolveSessionModel(sessionId: string): string | undefined {
|
|
31
|
+
return getSessionModel(sessionId) ?? sessionProviderConfig(sessionId)?.model;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Resolve the effort shown in session_state: per-session override, else provider default. */
|
|
35
|
+
function resolveSessionEffort(sessionId: string): string | undefined {
|
|
36
|
+
return getSessionEffort(sessionId) ?? sessionProviderConfig(sessionId)?.effort;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Whether thinking is effectively ON: per-session override (>0) wins, else provider config budget. */
|
|
40
|
+
function resolveSessionThinkingEnabled(sessionId: string): boolean {
|
|
41
|
+
const v = getSessionThinking(sessionId);
|
|
42
|
+
if (v != null) return v > 0;
|
|
43
|
+
return (sessionProviderConfig(sessionId)?.thinking_budget_tokens ?? 0) > 0;
|
|
27
44
|
}
|
|
28
45
|
|
|
29
46
|
// Broadcast file changes to all WS clients for real-time editor reload
|
|
@@ -294,7 +311,11 @@ async function startSessionConsumer(sessionId: string, providerId: string, conte
|
|
|
294
311
|
broadcast(sessionId, { type: "phase_changed", phase: "connecting", elapsed });
|
|
295
312
|
}, 5_000);
|
|
296
313
|
|
|
297
|
-
|
|
314
|
+
// Per-session effort/thinking overrides (sticky, read fresh each turn). Null = inherit
|
|
315
|
+
// provider config: omit so the provider falls back. thinking 0 = explicit OFF (overrides config).
|
|
316
|
+
const effortOverride = getSessionEffort(sessionId) ?? undefined;
|
|
317
|
+
const thinkingBudget = getSessionThinking(sessionId);
|
|
318
|
+
for await (const event of chatService.sendMessage(providerId, sessionId, content, { permissionMode, images, ...(model && { model }), ...(effortOverride && { effort: effortOverride }), ...(thinkingBudget != null && { maxThinkingTokens: thinkingBudget }) })) {
|
|
298
319
|
eventCount++;
|
|
299
320
|
const ev = event as any;
|
|
300
321
|
const evType = ev.type ?? "unknown";
|
|
@@ -635,6 +656,8 @@ export const chatWebSocket = {
|
|
|
635
656
|
sessionTitle: session?.title || null,
|
|
636
657
|
compactStatus: existing.compactStatus ?? null,
|
|
637
658
|
model: resolveSessionModel(sessionId),
|
|
659
|
+
effort: resolveSessionEffort(sessionId),
|
|
660
|
+
thinking: resolveSessionThinkingEnabled(sessionId),
|
|
638
661
|
}));
|
|
639
662
|
|
|
640
663
|
// If actively streaming, send buffered turn events for reconnect sync
|
|
@@ -759,6 +782,8 @@ export const chatWebSocket = {
|
|
|
759
782
|
sessionTitle: chatService.getSession(sessionId)?.title || null,
|
|
760
783
|
compactStatus: entry.compactStatus ?? null,
|
|
761
784
|
model: resolveSessionModel(sessionId),
|
|
785
|
+
effort: resolveSessionEffort(sessionId),
|
|
786
|
+
thinking: resolveSessionThinkingEnabled(sessionId),
|
|
762
787
|
}));
|
|
763
788
|
if (entry.phase !== "idle") {
|
|
764
789
|
sendTurnEvents(sessionId, ws);
|
|
@@ -804,6 +829,14 @@ export const chatWebSocket = {
|
|
|
804
829
|
entry.model = parsed.model;
|
|
805
830
|
setSessionModel(sessionId, parsed.model);
|
|
806
831
|
}
|
|
832
|
+
// Effort/thinking picked on a draft chat (before the WS existed) ride along on the
|
|
833
|
+
// first message so they persist like the model does. Reject invalid effort ("extra").
|
|
834
|
+
if (parsed.effort && VALID_EFFORT_VALUES.includes(parsed.effort as typeof VALID_EFFORT_VALUES[number])) {
|
|
835
|
+
setSessionEffort(sessionId, parsed.effort);
|
|
836
|
+
}
|
|
837
|
+
if (typeof parsed.thinking === "boolean") {
|
|
838
|
+
setSessionThinking(sessionId, parsed.thinking ? DEFAULT_THINKING_BUDGET : 0);
|
|
839
|
+
}
|
|
807
840
|
|
|
808
841
|
// Intercept PPM-handled built-in commands (e.g. /skills, /version)
|
|
809
842
|
const content = parsed.content.trim();
|
|
@@ -913,6 +946,54 @@ export const chatWebSocket = {
|
|
|
913
946
|
sessionTitle: chatService.getSession(sessionId)?.title || null,
|
|
914
947
|
compactStatus: entry.compactStatus ?? null,
|
|
915
948
|
model: resolveSessionModel(sessionId),
|
|
949
|
+
effort: resolveSessionEffort(sessionId),
|
|
950
|
+
thinking: resolveSessionThinkingEnabled(sessionId),
|
|
951
|
+
}));
|
|
952
|
+
} else if (parsed.type === "set_effort") {
|
|
953
|
+
// Per-session effort override. Reject anything outside the SDK enum — notably
|
|
954
|
+
// "extra" (UI label maps to "xhigh"), which would crash the CLI subprocess.
|
|
955
|
+
if (!parsed.effort || !VALID_EFFORT_VALUES.includes(parsed.effort as typeof VALID_EFFORT_VALUES[number])) {
|
|
956
|
+
ws.send(JSON.stringify({ type: "error", message: `effort must be one of: ${VALID_EFFORT_VALUES.join(", ")}` }));
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
setSessionEffort(sessionId, parsed.effort);
|
|
960
|
+
const provider = providerRegistry.get(providerId);
|
|
961
|
+
// Abort only when idle-but-alive so the next turn recreates the query with the new
|
|
962
|
+
// effort (mirror set_model); never interrupt an active turn.
|
|
963
|
+
if ((provider?.hasStreamingSession?.(sessionId) ?? false) && entry.phase === "idle") {
|
|
964
|
+
provider?.abortQuery?.(sessionId, "set_effort");
|
|
965
|
+
}
|
|
966
|
+
logSessionEvent(sessionId, "INFO", `Effort switched to ${parsed.effort}`);
|
|
967
|
+
ws.send(JSON.stringify({
|
|
968
|
+
type: "session_state",
|
|
969
|
+
sessionId,
|
|
970
|
+
phase: entry.phase,
|
|
971
|
+
pendingApproval: entry.pendingApprovalEvent ?? null,
|
|
972
|
+
sessionTitle: chatService.getSession(sessionId)?.title || null,
|
|
973
|
+
compactStatus: entry.compactStatus ?? null,
|
|
974
|
+
model: resolveSessionModel(sessionId),
|
|
975
|
+
effort: resolveSessionEffort(sessionId),
|
|
976
|
+
thinking: resolveSessionThinkingEnabled(sessionId),
|
|
977
|
+
}));
|
|
978
|
+
} else if (parsed.type === "set_thinking") {
|
|
979
|
+
// Per-session thinking toggle → maxThinkingTokens. ON = DEFAULT_THINKING_BUDGET,
|
|
980
|
+
// OFF = 0 (explicit, overrides provider config). Abort idle like set_model.
|
|
981
|
+
setSessionThinking(sessionId, parsed.enabled ? DEFAULT_THINKING_BUDGET : 0);
|
|
982
|
+
const provider = providerRegistry.get(providerId);
|
|
983
|
+
if ((provider?.hasStreamingSession?.(sessionId) ?? false) && entry.phase === "idle") {
|
|
984
|
+
provider?.abortQuery?.(sessionId, "set_thinking");
|
|
985
|
+
}
|
|
986
|
+
logSessionEvent(sessionId, "INFO", `Thinking ${parsed.enabled ? "on" : "off"}`);
|
|
987
|
+
ws.send(JSON.stringify({
|
|
988
|
+
type: "session_state",
|
|
989
|
+
sessionId,
|
|
990
|
+
phase: entry.phase,
|
|
991
|
+
pendingApproval: entry.pendingApprovalEvent ?? null,
|
|
992
|
+
sessionTitle: chatService.getSession(sessionId)?.title || null,
|
|
993
|
+
compactStatus: entry.compactStatus ?? null,
|
|
994
|
+
model: resolveSessionModel(sessionId),
|
|
995
|
+
effort: resolveSessionEffort(sessionId),
|
|
996
|
+
thinking: resolveSessionThinkingEnabled(sessionId),
|
|
916
997
|
}));
|
|
917
998
|
} else if (parsed.type === "cancel") {
|
|
918
999
|
// Fully teardown streaming session — user must resume to continue
|
|
@@ -575,16 +575,19 @@ class AccountService {
|
|
|
575
575
|
if (!res.ok) {
|
|
576
576
|
const errorBody = await res.text().catch(() => "");
|
|
577
577
|
console.error(`[accounts] Refresh failed for ${accountId}: ${res.status} ${errorBody}`);
|
|
578
|
-
// invalid_grant or invalid_request = refresh token permanently dead → clear it so account becomes temporary
|
|
579
578
|
if (errorBody.includes("invalid_grant") || errorBody.includes("invalid_request")) {
|
|
580
|
-
//
|
|
579
|
+
// Another session/process may have refreshed (and rotated) the token between
|
|
580
|
+
// our read and this OAuth call — if the DB token is now fresh, this failure is stale.
|
|
581
581
|
const recheckAccount = this.getWithTokens(accountId);
|
|
582
582
|
if (recheckAccount?.expiresAt && recheckAccount.expiresAt - Math.floor(Date.now() / 1000) > 60) {
|
|
583
583
|
console.log(`[accounts] Refresh failed with invalid_grant but DB token is now fresh — another session refreshed it`);
|
|
584
584
|
return;
|
|
585
585
|
}
|
|
586
|
-
|
|
587
|
-
|
|
586
|
+
// Do NOT wipe the refresh token. On multi-device/multi-process setups the token is
|
|
587
|
+
// usually rotated elsewhere, not truly dead; clearing it bricks the local copy
|
|
588
|
+
// permanently with no recovery path (esp. for parked/disabled accounts). Preserve
|
|
589
|
+
// it so re-enable / re-import / re-sync can restore access.
|
|
590
|
+
console.warn(`[accounts] Refresh token rejected for ${account.email ?? accountId} — preserving token for recovery (not clearing)`);
|
|
588
591
|
}
|
|
589
592
|
if (disableOnFail) {
|
|
590
593
|
this.setDisabled(accountId);
|
|
@@ -743,9 +746,12 @@ class AccountService {
|
|
|
743
746
|
const accounts = this.list();
|
|
744
747
|
const nowS = Math.floor(Date.now() / 1000);
|
|
745
748
|
for (const acc of accounts) {
|
|
746
|
-
//
|
|
747
|
-
//
|
|
748
|
-
//
|
|
749
|
+
// Freeze disabled accounts: skip background refresh entirely.
|
|
750
|
+
// Refreshing rotates the OAuth refresh token; when the same account is
|
|
751
|
+
// shared across machines/processes the rotation races and one side gets
|
|
752
|
+
// invalid_grant, killing an account the user only meant to park. Leaving
|
|
753
|
+
// a disabled account untouched keeps its token intact until re-enabled.
|
|
754
|
+
if (acc.status === "disabled") continue;
|
|
749
755
|
if (!acc.expiresAt) continue;
|
|
750
756
|
if (acc.expiresAt - nowS > REFRESH_BUFFER_S) continue;
|
|
751
757
|
// Skip temporary accounts (no refresh token) — they can't be refreshed
|
|
@@ -3,7 +3,7 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import { mkdirSync, existsSync } from "node:fs";
|
|
4
4
|
import { encrypt, decrypt } from "../lib/account-crypto.ts";
|
|
5
5
|
import { getPpmDir } from "./ppm-dir.ts";
|
|
6
|
-
export const CURRENT_SCHEMA_VERSION =
|
|
6
|
+
export const CURRENT_SCHEMA_VERSION = 36;
|
|
7
7
|
|
|
8
8
|
let db: Database | null = null;
|
|
9
9
|
let dbProfile: string | null = null;
|
|
@@ -831,6 +831,12 @@ function runMigrations(database: Database): void {
|
|
|
831
831
|
PRAGMA user_version = 35;
|
|
832
832
|
`);
|
|
833
833
|
}
|
|
834
|
+
|
|
835
|
+
if (current < 36) {
|
|
836
|
+
try { database.exec("ALTER TABLE session_metadata ADD COLUMN effort TEXT"); } catch {}
|
|
837
|
+
try { database.exec("ALTER TABLE session_metadata ADD COLUMN thinking_budget INTEGER"); } catch {}
|
|
838
|
+
database.exec("PRAGMA user_version = 36;");
|
|
839
|
+
}
|
|
834
840
|
}
|
|
835
841
|
|
|
836
842
|
// ---------------------------------------------------------------------------
|
|
@@ -1023,6 +1029,30 @@ export function setSessionModel(sessionId: string, model: string): void {
|
|
|
1023
1029
|
).run(sessionId, model);
|
|
1024
1030
|
}
|
|
1025
1031
|
|
|
1032
|
+
/** Per-session effort override; null when session uses provider default */
|
|
1033
|
+
export function getSessionEffort(sessionId: string): string | null {
|
|
1034
|
+
const row = getDb().query("SELECT effort FROM session_metadata WHERE session_id = ?").get(sessionId) as { effort: string | null } | null;
|
|
1035
|
+
return row?.effort ?? null;
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
export function setSessionEffort(sessionId: string, effort: string): void {
|
|
1039
|
+
getDb().query(
|
|
1040
|
+
"INSERT INTO session_metadata (session_id, effort) VALUES (?, ?) ON CONFLICT(session_id) DO UPDATE SET effort = excluded.effort",
|
|
1041
|
+
).run(sessionId, effort);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
/** Per-session thinking budget (maxThinkingTokens); null = thinking OFF / use provider default */
|
|
1045
|
+
export function getSessionThinking(sessionId: string): number | null {
|
|
1046
|
+
const row = getDb().query("SELECT thinking_budget FROM session_metadata WHERE session_id = ?").get(sessionId) as { thinking_budget: number | null } | null;
|
|
1047
|
+
return row?.thinking_budget ?? null;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
export function setSessionThinking(sessionId: string, budget: number | null): void {
|
|
1051
|
+
getDb().query(
|
|
1052
|
+
"INSERT INTO session_metadata (session_id, thinking_budget) VALUES (?, ?) ON CONFLICT(session_id) DO UPDATE SET thinking_budget = excluded.thinking_budget",
|
|
1053
|
+
).run(sessionId, budget);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1026
1056
|
// ---------------------------------------------------------------------------
|
|
1027
1057
|
// Unread tracking
|
|
1028
1058
|
// ---------------------------------------------------------------------------
|
|
@@ -10,8 +10,8 @@ export interface ChatBackend {
|
|
|
10
10
|
providerId: string,
|
|
11
11
|
sessionId: string,
|
|
12
12
|
prompt: string,
|
|
13
|
-
opts?: { permissionMode?: string; signal?: AbortSignal },
|
|
14
|
-
): AsyncIterable<{ type: string; content?: string; costUsd?: number; usage?: { costUsd?: number } }>;
|
|
13
|
+
opts?: { permissionMode?: string; signal?: AbortSignal; model?: string; oneMContext?: boolean },
|
|
14
|
+
): AsyncIterable<{ type: string; content?: string; message?: string; costUsd?: number; usage?: { costUsd?: number } }>;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export interface AgentRunResult {
|
|
@@ -38,12 +38,25 @@ export async function runAgentTurn(
|
|
|
38
38
|
|
|
39
39
|
const events = backend.sendMessage(providerId, member.sessionId, prompt, {
|
|
40
40
|
permissionMode: "bypassPermissions",
|
|
41
|
+
// Honor the member's configured model (e.g. haiku); falls back to the provider
|
|
42
|
+
// default when unset. Without this the turn always used the provider default.
|
|
43
|
+
model: member.model ?? undefined,
|
|
44
|
+
// Group turns are short/windowed — never request the 1M-context beta. If the user's
|
|
45
|
+
// config has context_1m on, the [1m] model suffix triggers "long context beta not
|
|
46
|
+
// available for this subscription" (HTTP 400). Opt out here (like the router).
|
|
47
|
+
oneMContext: false,
|
|
41
48
|
signal: opts.signal,
|
|
42
49
|
});
|
|
43
50
|
|
|
44
51
|
for await (const ev of events) {
|
|
45
52
|
if (opts.signal?.aborted) break;
|
|
46
53
|
if (ev.type === "text") full += ev.content ?? "";
|
|
54
|
+
else if (ev.type === "error") {
|
|
55
|
+
// Provider errors (auth, rate limit, crash) are terminal for this turn.
|
|
56
|
+
// Throw so the turn loop aborts and surfaces the error to the UI instead
|
|
57
|
+
// of appending an empty message and looping to the turn cap.
|
|
58
|
+
throw new Error(ev.message || `agent turn failed for ${member.name}`);
|
|
59
|
+
}
|
|
47
60
|
else if (ev.type === "done") {
|
|
48
61
|
costUsd = ev.costUsd ?? ev.usage?.costUsd;
|
|
49
62
|
break;
|
|
@@ -41,3 +41,18 @@ export function renderWindow(window: GroupMessage[]): string {
|
|
|
41
41
|
if (window.length === 0) return "(channel empty)";
|
|
42
42
|
return window.map(line).join("\n");
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
/** Full turn text stored on the bus (`data.full`), falling back to the short feed
|
|
46
|
+
* summary for legacy rows that predate full-text storage. */
|
|
47
|
+
export function fullText(m: GroupMessage): string {
|
|
48
|
+
const full = (m.data as { full?: string } | null)?.full;
|
|
49
|
+
return typeof full === "string" && full.length > 0 ? full : (m.summary ?? "");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Render messages using FULL text (not the 600-char feed clip) for prompt injection. */
|
|
53
|
+
export function renderFull(messages: GroupMessage[]): string {
|
|
54
|
+
if (messages.length === 0) return "(channel empty)";
|
|
55
|
+
return messages
|
|
56
|
+
.map((m) => `${m.fromMember} -> ${m.toMember ?? "all"}: ${fullText(m)}`.trim())
|
|
57
|
+
.join("\n");
|
|
58
|
+
}
|