@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,12 +1,19 @@
|
|
|
1
1
|
import { memo } from "react";
|
|
2
|
+
import { Pencil, Trash2, UserPlus } from "lucide-react";
|
|
2
3
|
import { cn } from "@/lib/utils";
|
|
3
|
-
import type { MemberStatus } from "../../../types/group-chat";
|
|
4
|
-
import type { RosterMember } from "@/hooks/use-group-chat";
|
|
4
|
+
import type { GroupMember, MemberStatus } from "../../../types/group-chat";
|
|
5
5
|
|
|
6
6
|
interface GroupMemberRosterProps {
|
|
7
|
-
members:
|
|
7
|
+
members: GroupMember[];
|
|
8
|
+
/** memberId → live status (working/done/error) from the running burst. */
|
|
9
|
+
liveStatus: Map<string, MemberStatus>;
|
|
8
10
|
/** Member name → true when composing a turn. */
|
|
9
11
|
typing: Record<string, boolean>;
|
|
12
|
+
/** Disables actions while a mutation is in flight. */
|
|
13
|
+
busy?: boolean;
|
|
14
|
+
onAdd: () => void;
|
|
15
|
+
onEdit: (member: GroupMember) => void;
|
|
16
|
+
onRemove: (member: GroupMember) => void;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
const STATUS_DOT: Record<MemberStatus, string> = {
|
|
@@ -23,26 +30,17 @@ const STATUS_LABEL: Record<MemberStatus, string> = {
|
|
|
23
30
|
error: "Error",
|
|
24
31
|
};
|
|
25
32
|
|
|
26
|
-
/**
|
|
33
|
+
/** Editable roster: avatar + name + role/persona + live status; add/edit/remove. */
|
|
27
34
|
export const GroupMemberRoster = memo(function GroupMemberRoster({
|
|
28
|
-
members,
|
|
29
|
-
typing,
|
|
35
|
+
members, liveStatus, typing, busy, onAdd, onEdit, onRemove,
|
|
30
36
|
}: GroupMemberRosterProps) {
|
|
31
|
-
if (members.length === 0) {
|
|
32
|
-
return (
|
|
33
|
-
<div className="p-3 text-xs text-text-subtle">No members yet.</div>
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
37
|
return (
|
|
38
|
-
<
|
|
38
|
+
<div className="flex flex-col gap-0.5 p-2">
|
|
39
39
|
{members.map((m) => {
|
|
40
40
|
const isTyping = typing[m.name];
|
|
41
|
+
const status = liveStatus.get(m.id) ?? m.status;
|
|
41
42
|
return (
|
|
42
|
-
<
|
|
43
|
-
key={m.id}
|
|
44
|
-
className="flex items-center gap-2 rounded-md px-2 py-1.5"
|
|
45
|
-
>
|
|
43
|
+
<div key={m.id} className="group flex items-center gap-2 rounded-md px-2 py-1.5">
|
|
46
44
|
<span
|
|
47
45
|
className="flex size-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold text-white ring-2 ring-background"
|
|
48
46
|
style={{ backgroundColor: m.color ?? "var(--accent)" }}
|
|
@@ -59,18 +57,48 @@ export const GroupMemberRoster = memo(function GroupMemberRoster({
|
|
|
59
57
|
</span>
|
|
60
58
|
)}
|
|
61
59
|
</div>
|
|
62
|
-
<span className="text-[10px] text-text-subtle">
|
|
63
|
-
{isTyping ? "typing…" : STATUS_LABEL[
|
|
60
|
+
<span className="block truncate text-[10px] text-text-subtle">
|
|
61
|
+
{isTyping ? "typing…" : (m.persona || STATUS_LABEL[status])}
|
|
64
62
|
</span>
|
|
65
63
|
</div>
|
|
64
|
+
{/* Actions — always visible on touch; hover-reveal on pointer devices. */}
|
|
65
|
+
<div className="flex shrink-0 items-center gap-0.5 can-hover:opacity-0 can-hover:group-hover:opacity-100">
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
onClick={() => onEdit(m)}
|
|
69
|
+
disabled={busy}
|
|
70
|
+
aria-label={`Edit ${m.name}`}
|
|
71
|
+
className="flex size-8 items-center justify-center rounded-md text-text-subtle hover:bg-surface-elevated hover:text-foreground active:bg-surface-elevated disabled:opacity-40"
|
|
72
|
+
>
|
|
73
|
+
<Pencil className="size-3.5" />
|
|
74
|
+
</button>
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
onClick={() => onRemove(m)}
|
|
78
|
+
disabled={busy}
|
|
79
|
+
aria-label={`Remove ${m.name}`}
|
|
80
|
+
className="flex size-8 items-center justify-center rounded-md text-text-subtle hover:bg-surface-elevated hover:text-destructive active:bg-surface-elevated disabled:opacity-40"
|
|
81
|
+
>
|
|
82
|
+
<Trash2 className="size-3.5" />
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
66
85
|
<span
|
|
67
|
-
className={cn("size-2 shrink-0 rounded-full", STATUS_DOT[
|
|
68
|
-
title={STATUS_LABEL[
|
|
86
|
+
className={cn("size-2 shrink-0 rounded-full", STATUS_DOT[status])}
|
|
87
|
+
title={STATUS_LABEL[status]}
|
|
69
88
|
aria-hidden
|
|
70
89
|
/>
|
|
71
|
-
</
|
|
90
|
+
</div>
|
|
72
91
|
);
|
|
73
92
|
})}
|
|
74
|
-
|
|
93
|
+
|
|
94
|
+
<button
|
|
95
|
+
type="button"
|
|
96
|
+
onClick={onAdd}
|
|
97
|
+
disabled={busy}
|
|
98
|
+
className="mt-1 flex items-center gap-2 rounded-md px-2 py-2 text-xs font-medium text-primary hover:bg-surface-elevated active:bg-surface-elevated disabled:opacity-40"
|
|
99
|
+
>
|
|
100
|
+
<UserPlus className="size-4" /> Add member
|
|
101
|
+
</button>
|
|
102
|
+
</div>
|
|
75
103
|
);
|
|
76
104
|
});
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { memo, type ReactNode } from "react";
|
|
2
|
+
import { ScrollText } from "lucide-react";
|
|
2
3
|
import { cn } from "@/lib/utils";
|
|
4
|
+
import {
|
|
5
|
+
ContextMenu,
|
|
6
|
+
ContextMenuTrigger,
|
|
7
|
+
ContextMenuContent,
|
|
8
|
+
ContextMenuItem,
|
|
9
|
+
} from "@/components/ui/adaptive-context-menu";
|
|
3
10
|
import type { GroupMessage } from "../../../types/group-chat";
|
|
4
11
|
|
|
5
12
|
interface GroupMessageItemProps {
|
|
@@ -21,7 +28,10 @@ function initials(name: string): string {
|
|
|
21
28
|
|
|
22
29
|
function formatTime(ts: number): string {
|
|
23
30
|
try {
|
|
24
|
-
|
|
31
|
+
// The bus stores created_at in SECONDS (SQLite unixepoch()); Date expects ms.
|
|
32
|
+
// Normalize second-scale values so timestamps don't all collapse to one minute.
|
|
33
|
+
const ms = ts < 1e12 ? ts * 1000 : ts;
|
|
34
|
+
return new Date(ms).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
|
|
25
35
|
} catch {
|
|
26
36
|
return "";
|
|
27
37
|
}
|
|
@@ -30,7 +40,7 @@ function formatTime(ts: number): string {
|
|
|
30
40
|
/** Render body text with @mentions tinted in the mentioned member's color
|
|
31
41
|
* (falls back to the primary accent) so it's obvious who is being addressed. */
|
|
32
42
|
function withMentions(text: string, colorFor: (n: string) => string | null): ReactNode[] {
|
|
33
|
-
return text.split(/(
|
|
43
|
+
return text.split(/(@[\p{L}\p{N}_]+)/gu).map((part, i) => {
|
|
34
44
|
if (part.startsWith("@") && part.length > 1) {
|
|
35
45
|
const c = colorFor(part.slice(1));
|
|
36
46
|
return (
|
|
@@ -44,7 +54,7 @@ function withMentions(text: string, colorFor: (n: string) => string | null): Rea
|
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
/** Slack-style feed row: colored avatar + name accent per speaker, left color
|
|
47
|
-
* bar, "You" for the user, leader badge, highlighted @mentions
|
|
57
|
+
* bar, "You" for the user, leader badge, highlighted @mentions. */
|
|
48
58
|
export const GroupMessageItem = memo(function GroupMessageItem({
|
|
49
59
|
message,
|
|
50
60
|
colorFor,
|
|
@@ -55,18 +65,30 @@ export const GroupMessageItem = memo(function GroupMessageItem({
|
|
|
55
65
|
const displayName = isUser ? "You" : message.fromMember;
|
|
56
66
|
const accent = isUser ? "var(--color-primary)" : (colorFor(message.fromMember) ?? "var(--accent)");
|
|
57
67
|
const leader = !isUser && isLeader(message.fromMember);
|
|
58
|
-
const isFinal = message.kind === "final";
|
|
59
68
|
const summary = message.summary ?? "";
|
|
60
69
|
const target = message.toMember && message.toMember !== "all" ? message.toMember : null;
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
const row = (
|
|
63
72
|
<div
|
|
64
73
|
className={cn(
|
|
65
|
-
"flex gap-2.5 px-3 py-2 transition-colors hover:bg-surface-elevated/50",
|
|
74
|
+
"group relative flex gap-2.5 px-3 py-2 transition-colors hover:bg-surface-elevated/50",
|
|
66
75
|
isUser && "bg-primary/5",
|
|
67
76
|
)}
|
|
68
77
|
style={{ boxShadow: `inset 3px 0 0 0 ${accent}` }}
|
|
69
78
|
>
|
|
79
|
+
{/* Transcript (AI raw thinking / debug) — top-right icon, POINTER DEVICES ONLY,
|
|
80
|
+
revealed on hover. On touch it's hidden; use long-press → context menu instead. */}
|
|
81
|
+
{message.fullSessionRef && (
|
|
82
|
+
<button
|
|
83
|
+
type="button"
|
|
84
|
+
onClick={() => onViewFull(message)}
|
|
85
|
+
title="View full transcript (AI's raw thinking / debug)"
|
|
86
|
+
aria-label="View full transcript"
|
|
87
|
+
className="absolute right-1.5 top-1.5 hidden items-center rounded p-1 text-text-subtle/60 hover:bg-surface-elevated hover:text-text-secondary can-hover:group-hover:inline-flex"
|
|
88
|
+
>
|
|
89
|
+
<ScrollText className="size-3.5" />
|
|
90
|
+
</button>
|
|
91
|
+
)}
|
|
70
92
|
<div
|
|
71
93
|
className="mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full text-[11px] font-semibold text-white ring-2 ring-background"
|
|
72
94
|
style={{ backgroundColor: accent }}
|
|
@@ -75,7 +97,7 @@ export const GroupMessageItem = memo(function GroupMessageItem({
|
|
|
75
97
|
{initials(displayName)}
|
|
76
98
|
</div>
|
|
77
99
|
|
|
78
|
-
<div className="min-w-0 flex-1">
|
|
100
|
+
<div className="min-w-0 flex-1 can-hover:pr-6">
|
|
79
101
|
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5">
|
|
80
102
|
<span
|
|
81
103
|
className="text-sm font-semibold"
|
|
@@ -91,31 +113,28 @@ export const GroupMessageItem = memo(function GroupMessageItem({
|
|
|
91
113
|
{target && (
|
|
92
114
|
<span className="text-[11px] text-text-subtle">→ {target}</span>
|
|
93
115
|
)}
|
|
94
|
-
{isFinal && (
|
|
95
|
-
<span className="rounded-full bg-accent-wash px-1.5 py-px text-[10px] font-medium text-primary">
|
|
96
|
-
final
|
|
97
|
-
</span>
|
|
98
|
-
)}
|
|
99
116
|
<span className="text-[11px] text-text-subtle">{formatTime(message.createdAt)}</span>
|
|
100
117
|
</div>
|
|
101
118
|
|
|
102
|
-
<div className=
|
|
103
|
-
"mt-0.5 whitespace-pre-wrap break-words text-sm leading-relaxed text-text-secondary",
|
|
104
|
-
isFinal && "mt-1.5 rounded-md border border-accent-wash bg-accent-wash/40 px-3 py-2 text-foreground",
|
|
105
|
-
)}>
|
|
119
|
+
<div className="mt-0.5 whitespace-pre-wrap break-words text-sm leading-relaxed text-text-secondary">
|
|
106
120
|
{withMentions(summary, colorFor)}
|
|
107
121
|
</div>
|
|
108
|
-
|
|
109
|
-
{message.fullSessionRef && (
|
|
110
|
-
<button
|
|
111
|
-
type="button"
|
|
112
|
-
onClick={() => onViewFull(message)}
|
|
113
|
-
className="mt-1 inline-flex min-h-[44px] items-center text-xs font-medium text-primary hover:underline md:min-h-[32px]"
|
|
114
|
-
>
|
|
115
|
-
View full transcript
|
|
116
|
-
</button>
|
|
117
|
-
)}
|
|
118
122
|
</div>
|
|
119
123
|
</div>
|
|
120
124
|
);
|
|
125
|
+
|
|
126
|
+
// No transcript → plain row. Otherwise wrap so long-press (mobile) / right-click
|
|
127
|
+
// (desktop) opens a menu with the transcript action; the hover icon covers pointer.
|
|
128
|
+
if (!message.fullSessionRef) return row;
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<ContextMenu>
|
|
132
|
+
<ContextMenuTrigger asChild>{row}</ContextMenuTrigger>
|
|
133
|
+
<ContextMenuContent>
|
|
134
|
+
<ContextMenuItem onClick={() => onViewFull(message)}>
|
|
135
|
+
<ScrollText className="size-4" /> View full transcript
|
|
136
|
+
</ContextMenuItem>
|
|
137
|
+
</ContextMenuContent>
|
|
138
|
+
</ContextMenu>
|
|
139
|
+
);
|
|
121
140
|
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { ChevronRight, Brain, Settings2 } from "lucide-react";
|
|
3
|
+
import { MarkdownRenderer } from "@/components/shared/markdown-renderer";
|
|
4
|
+
import { ToolCard } from "@/components/chat/tool-cards";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import type { ChatMessage, ChatEvent } from "../../../types/chat";
|
|
7
|
+
import type { TranscriptConfig } from "@/lib/api-group-chat";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
messages: ChatMessage[];
|
|
11
|
+
config: TranscriptConfig | null;
|
|
12
|
+
projectName?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Read-only, chat-style render of an archived member transcript: text (markdown),
|
|
16
|
+
* collapsible thinking, tool calls with inputs + outputs, and the session input config.
|
|
17
|
+
* Deliberately minimal — no approvals / fork / version affordances. */
|
|
18
|
+
export function GroupTranscriptMessages({ messages, config, projectName }: Props) {
|
|
19
|
+
return (
|
|
20
|
+
<div className="flex flex-col gap-3">
|
|
21
|
+
{config && <ConfigBlock config={config} />}
|
|
22
|
+
{messages.map((m) => (
|
|
23
|
+
<div key={m.id} className="flex flex-col gap-1.5">
|
|
24
|
+
<span className="text-[10px] font-semibold uppercase tracking-wide text-text-subtle">
|
|
25
|
+
{m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : m.role}
|
|
26
|
+
</span>
|
|
27
|
+
<MessageBody message={m} projectName={projectName} />
|
|
28
|
+
</div>
|
|
29
|
+
))}
|
|
30
|
+
{messages.length === 0 && (
|
|
31
|
+
<p className="py-6 text-center text-sm text-text-subtle">Transcript is empty.</p>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function MessageBody({ message, projectName }: { message: ChatMessage; projectName?: string }) {
|
|
38
|
+
const events = message.events ?? [];
|
|
39
|
+
if (events.length === 0) {
|
|
40
|
+
return message.content.trim()
|
|
41
|
+
? <MarkdownRenderer content={message.content} />
|
|
42
|
+
: null;
|
|
43
|
+
}
|
|
44
|
+
// Match tool_result events to their tool_use by id (rendered inside the ToolCard).
|
|
45
|
+
const resultById = new Map<string, ChatEvent>();
|
|
46
|
+
for (const ev of events) {
|
|
47
|
+
if (ev.type === "tool_result" && ev.toolUseId) resultById.set(ev.toolUseId, ev);
|
|
48
|
+
}
|
|
49
|
+
return (
|
|
50
|
+
<div className="flex flex-col gap-2">
|
|
51
|
+
{events.map((ev, i) => {
|
|
52
|
+
if (ev.type === "text") {
|
|
53
|
+
return ev.content.trim() ? <MarkdownRenderer key={i} content={ev.content} /> : null;
|
|
54
|
+
}
|
|
55
|
+
if (ev.type === "thinking") {
|
|
56
|
+
return <ThinkingBlock key={i} content={ev.content} />;
|
|
57
|
+
}
|
|
58
|
+
if (ev.type === "tool_use") {
|
|
59
|
+
const result = ev.toolUseId ? resultById.get(ev.toolUseId) : undefined;
|
|
60
|
+
return <ToolCard key={i} tool={ev} result={result} completed={!!result} projectName={projectName} />;
|
|
61
|
+
}
|
|
62
|
+
return null; // tool_result rendered via its tool_use
|
|
63
|
+
})}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Collapsible reasoning block (collapsed by default). */
|
|
69
|
+
function ThinkingBlock({ content }: { content: string }) {
|
|
70
|
+
const [open, setOpen] = useState(false);
|
|
71
|
+
return (
|
|
72
|
+
<div className="rounded-md border border-border bg-surface-elevated/40">
|
|
73
|
+
<button
|
|
74
|
+
type="button"
|
|
75
|
+
onClick={() => setOpen((v) => !v)}
|
|
76
|
+
className="flex w-full items-center gap-1.5 px-2.5 py-1.5 text-xs text-text-subtle hover:text-text-secondary"
|
|
77
|
+
>
|
|
78
|
+
<ChevronRight className={cn("size-3.5 transition-transform", open && "rotate-90")} />
|
|
79
|
+
<Brain className="size-3.5" />
|
|
80
|
+
<span>Thinking</span>
|
|
81
|
+
</button>
|
|
82
|
+
{open && (
|
|
83
|
+
<div className="border-t border-border px-3 py-2 text-xs leading-relaxed text-text-secondary">
|
|
84
|
+
<MarkdownRenderer content={content} />
|
|
85
|
+
</div>
|
|
86
|
+
)}
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Collapsible input-config summary (model / cwd / branch / version / permission mode). */
|
|
92
|
+
function ConfigBlock({ config }: { config: TranscriptConfig }) {
|
|
93
|
+
const [open, setOpen] = useState(false);
|
|
94
|
+
const rows: Array<[string, string | undefined]> = [
|
|
95
|
+
["Model", config.model],
|
|
96
|
+
["Permission", config.permissionMode],
|
|
97
|
+
["CWD", config.cwd],
|
|
98
|
+
["Git branch", config.gitBranch],
|
|
99
|
+
["CLI version", config.version],
|
|
100
|
+
];
|
|
101
|
+
const shown = rows.filter(([, v]) => v);
|
|
102
|
+
if (shown.length === 0) return null;
|
|
103
|
+
return (
|
|
104
|
+
<div className="rounded-md border border-border bg-surface-elevated/40">
|
|
105
|
+
<button
|
|
106
|
+
type="button"
|
|
107
|
+
onClick={() => setOpen((v) => !v)}
|
|
108
|
+
className="flex w-full items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-text-secondary hover:text-foreground"
|
|
109
|
+
>
|
|
110
|
+
<ChevronRight className={cn("size-3.5 transition-transform", open && "rotate-90")} />
|
|
111
|
+
<Settings2 className="size-3.5" />
|
|
112
|
+
<span>Input config</span>
|
|
113
|
+
</button>
|
|
114
|
+
{open && (
|
|
115
|
+
<dl className="grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 border-t border-border px-3 py-2 text-xs">
|
|
116
|
+
{shown.map(([k, v]) => (
|
|
117
|
+
<div key={k} className="contents">
|
|
118
|
+
<dt className="text-text-subtle">{k}</dt>
|
|
119
|
+
<dd className="break-all font-mono text-text-secondary">{v}</dd>
|
|
120
|
+
</div>
|
|
121
|
+
))}
|
|
122
|
+
</dl>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
@@ -134,6 +134,11 @@ export function MobileDrawerTabBar({ tabs, activeId, onSelect, onReorder }: Prop
|
|
|
134
134
|
>
|
|
135
135
|
<Icon className="size-4" />
|
|
136
136
|
<span>{tab.shortLabel ?? tab.label}</span>
|
|
137
|
+
{tab.beta && (
|
|
138
|
+
<span className="absolute top-1 right-2 rounded-full bg-accent-wash px-1 text-[7px] font-bold uppercase leading-[1.4] tracking-wide text-primary">
|
|
139
|
+
beta
|
|
140
|
+
</span>
|
|
141
|
+
)}
|
|
137
142
|
</button>
|
|
138
143
|
);
|
|
139
144
|
})}
|
|
@@ -168,6 +173,11 @@ export function MobileDrawerTabBar({ tabs, activeId, onSelect, onReorder }: Prop
|
|
|
168
173
|
>
|
|
169
174
|
<Icon className="size-4 shrink-0" />
|
|
170
175
|
<span>{tab.label}</span>
|
|
176
|
+
{tab.beta && (
|
|
177
|
+
<span className="rounded-full bg-accent-wash px-1.5 py-px text-[9px] font-semibold uppercase tracking-wide text-primary">
|
|
178
|
+
beta
|
|
179
|
+
</span>
|
|
180
|
+
)}
|
|
171
181
|
</button>
|
|
172
182
|
);
|
|
173
183
|
})}
|
|
@@ -24,8 +24,8 @@ function Badge({ count }: { count: number }) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Section nav item: 38×38, active = tinted bg + inset accent bar + bolder icon.
|
|
27
|
-
function NavItem({ icon: Icon, label, active, badge, onClick, dragging, dropBefore, onDragStart, onDragOver, onDrop, onDragEnd }: {
|
|
28
|
-
icon: React.ElementType; label: string; active: boolean; badge?: number; onClick: () => void;
|
|
27
|
+
function NavItem({ icon: Icon, label, active, badge, beta, onClick, dragging, dropBefore, onDragStart, onDragOver, onDrop, onDragEnd }: {
|
|
28
|
+
icon: React.ElementType; label: string; active: boolean; badge?: number; beta?: boolean; onClick: () => void;
|
|
29
29
|
dragging?: boolean; dropBefore?: boolean;
|
|
30
30
|
onDragStart?: (e: React.DragEvent) => void;
|
|
31
31
|
onDragOver?: (e: React.DragEvent) => void;
|
|
@@ -51,6 +51,11 @@ function NavItem({ icon: Icon, label, active, badge, onClick, dragging, dropBefo
|
|
|
51
51
|
>
|
|
52
52
|
<Icon className="size-[18px]" strokeWidth={active ? 2.4 : 2} />
|
|
53
53
|
{badge != null && badge > 0 && <Badge count={badge} />}
|
|
54
|
+
{beta && (
|
|
55
|
+
<span className="absolute -top-0.5 -right-0.5 rounded-full bg-accent-wash px-1 text-[7px] font-bold uppercase leading-[1.4] tracking-wide text-primary shadow-sm">
|
|
56
|
+
beta
|
|
57
|
+
</span>
|
|
58
|
+
)}
|
|
54
59
|
{/* hover tooltip (pointer devices only) */}
|
|
55
60
|
<span className="pointer-events-none absolute left-[calc(100%+8px)] z-50 hidden can-hover:group-hover:block whitespace-nowrap rounded-md border border-border bg-surface-elevated px-2 py-1 text-xs font-medium text-foreground shadow-[0_4px_12px_rgba(0,0,0,.4)]">
|
|
56
61
|
{label}
|
|
@@ -155,6 +160,7 @@ export const NavSectionRail = memo(function NavSectionRail({ className }: { clas
|
|
|
155
160
|
label={tab.label}
|
|
156
161
|
active={sidebarActiveTab === tab.id}
|
|
157
162
|
badge={tab.id === "git" ? gitChangesCount : tab.id === "jira" ? jiraUnreadCount : tab.id === "history" ? historyUnreadCount : undefined}
|
|
163
|
+
beta={tab.beta}
|
|
158
164
|
onClick={() => handleTabClick(tab.id)}
|
|
159
165
|
dragging={dragId === tab.id}
|
|
160
166
|
dropBefore={dropId === tab.id && dragId !== tab.id}
|
|
@@ -81,6 +81,21 @@ async function reloadWhenServerReady() {
|
|
|
81
81
|
await clearCachesAndReload();
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Whether an /api/upgrade/apply failure actually means "the server is
|
|
86
|
+
* restarting", not "the upgrade failed". The self-replace tears the server down
|
|
87
|
+
* mid-request, so the response often never arrives cleanly: the connection
|
|
88
|
+
* drops (TypeError) or a proxy/tunnel in front returns a gateway error while the
|
|
89
|
+
* origin is briefly gone (502/503/504, or Cloudflare's 52x). Real upgrade
|
|
90
|
+
* failures come back as a JSON 500 with a specific message and won't match here.
|
|
91
|
+
*/
|
|
92
|
+
function looksLikeServerRestart(e: unknown): boolean {
|
|
93
|
+
if (e instanceof TypeError) return true; // dropped connection / fetch failure
|
|
94
|
+
const msg = (e as Error)?.message ?? "";
|
|
95
|
+
if (/fetch|network|failed to fetch|load failed/i.test(msg)) return true;
|
|
96
|
+
return /HTTP 5(0[234]|2\d)\b/.test(msg); // 502/503/504 + Cloudflare 520–529
|
|
97
|
+
}
|
|
98
|
+
|
|
84
99
|
/**
|
|
85
100
|
* Status-bar version chip. Shows the current version normally; when a new
|
|
86
101
|
* release is available it turns into an accent "update" button that opens a
|
|
@@ -150,14 +165,23 @@ export function UpgradeButton({ align = "right" }: { align?: "left" | "right" })
|
|
|
150
165
|
.finally(() => setNotesLoading(false));
|
|
151
166
|
}, [open, current, hasUpdate, isTest]);
|
|
152
167
|
|
|
168
|
+
// The server is restarting into the new version — stop showing "Updating…",
|
|
169
|
+
// switch to the reconnect state, and auto-reload once it's listening again
|
|
170
|
+
// (no manual click, and no raw 502 surfaced while the origin is briefly down).
|
|
171
|
+
const enterRestartWait = useCallback(() => {
|
|
172
|
+
setUpgrading(false);
|
|
173
|
+
setComplete(true);
|
|
174
|
+
setReloading(true);
|
|
175
|
+
reloadWhenServerReady();
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
153
178
|
const handleUpgrade = useCallback(async () => {
|
|
154
179
|
setUpgrading(true);
|
|
155
180
|
setOpen(false);
|
|
156
181
|
try {
|
|
157
182
|
const data = await api.post<UpgradeResult>("/api/upgrade/apply");
|
|
158
183
|
if (data.restart) {
|
|
159
|
-
|
|
160
|
-
setComplete(true);
|
|
184
|
+
enterRestartWait();
|
|
161
185
|
} else {
|
|
162
186
|
toast.info(data.message || "Upgrade installed. Restart PPM manually.");
|
|
163
187
|
setUpgrading(false);
|
|
@@ -165,18 +189,16 @@ export function UpgradeButton({ align = "right" }: { align?: "left" | "right" })
|
|
|
165
189
|
setDismissed(true);
|
|
166
190
|
}
|
|
167
191
|
} catch (e) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
setUpgrading(false);
|
|
173
|
-
setComplete(true);
|
|
192
|
+
if (looksLikeServerRestart(e)) {
|
|
193
|
+
// Expected: self-replace killed the server before the response flushed.
|
|
194
|
+
// The upgrade is in progress — wait for it, don't report a failure.
|
|
195
|
+
enterRestartWait();
|
|
174
196
|
} else {
|
|
175
197
|
toast.error(`Upgrade failed: ${(e as Error).message}`);
|
|
176
198
|
setUpgrading(false);
|
|
177
199
|
}
|
|
178
200
|
}
|
|
179
|
-
}, [availableVersion]);
|
|
201
|
+
}, [availableVersion, enterRestartWait]);
|
|
180
202
|
|
|
181
203
|
const handleDismiss = useCallback(() => {
|
|
182
204
|
if (availableVersion) sessionStorage.setItem(DISMISS_KEY_PREFIX + availableVersion, "1");
|
|
@@ -194,10 +216,10 @@ export function UpgradeButton({ align = "right" }: { align?: "left" | "right" })
|
|
|
194
216
|
onClick={() => { setReloading(true); reloadWhenServerReady(); }}
|
|
195
217
|
disabled={reloading}
|
|
196
218
|
className="flex items-center gap-1 px-1 rounded-sm text-success hover:brightness-110 transition-[filter] disabled:opacity-70"
|
|
197
|
-
title={reloading ? "
|
|
219
|
+
title={reloading ? "Applying update — reconnecting to the server…" : "Reload to apply the update"}
|
|
198
220
|
>
|
|
199
221
|
{reloading
|
|
200
|
-
? <><Loader2 className="size-3 animate-spin" />
|
|
222
|
+
? <><Loader2 className="size-3 animate-spin" /> Updating, reconnecting…</>
|
|
201
223
|
: <><RefreshCw className="size-3" /> Reload</>}
|
|
202
224
|
</button>
|
|
203
225
|
);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "@/components/ui/dialog";
|
|
9
9
|
|
|
10
10
|
const DEFAULT_MESSAGE = "Hello! Reply briefly.";
|
|
11
|
-
const DEFAULT_MODEL = "claude-opus-
|
|
11
|
+
const DEFAULT_MODEL = "claude-opus-5";
|
|
12
12
|
|
|
13
13
|
type EndpointFormat = "anthropic" | "openai";
|
|
14
14
|
|
|
@@ -159,10 +159,12 @@ function ProxyTestForm({ authKey, baseUrl }: ProxyTestDialogProps) {
|
|
|
159
159
|
onChange={(e) => setModel(e.target.value)}
|
|
160
160
|
className="h-8 w-full rounded-md border bg-background px-2 text-[11px]"
|
|
161
161
|
>
|
|
162
|
+
<option value="claude-opus-5">claude-opus-5</option>
|
|
162
163
|
<option value="claude-fable-5">claude-fable-5</option>
|
|
163
164
|
<option value="claude-opus-4-8">claude-opus-4-8</option>
|
|
164
165
|
<option value="claude-opus-4-7">claude-opus-4-7</option>
|
|
165
166
|
<option value="claude-opus-4-6">claude-opus-4-6</option>
|
|
167
|
+
<option value="claude-sonnet-5">claude-sonnet-5</option>
|
|
166
168
|
<option value="claude-sonnet-4-6">claude-sonnet-4-6</option>
|
|
167
169
|
<option value="claude-haiku-4-5">claude-haiku-4-5</option>
|
|
168
170
|
</select>
|
|
@@ -67,6 +67,14 @@ interface UseChatReturn {
|
|
|
67
67
|
model: string | null;
|
|
68
68
|
/** Switch the per-session model (persists + recreates query on next message) */
|
|
69
69
|
setModel: (model: string) => void;
|
|
70
|
+
/** Per-session effort override (null = provider default) */
|
|
71
|
+
effort: string | null;
|
|
72
|
+
/** Switch the per-session effort (low|medium|high|xhigh|max) */
|
|
73
|
+
setEffort: (effort: string) => void;
|
|
74
|
+
/** Whether per-session thinking is on */
|
|
75
|
+
thinking: boolean;
|
|
76
|
+
/** Toggle per-session thinking on/off */
|
|
77
|
+
setThinking: (enabled: boolean) => void;
|
|
70
78
|
/** Team activity state from WS events */
|
|
71
79
|
teamActivity: TeamActivityState;
|
|
72
80
|
/** All team messages (ref-backed, updated live) */
|
|
@@ -126,6 +134,11 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
126
134
|
// On a draft chat the WS doesn't exist, so set_model is lost — without this
|
|
127
135
|
// guard the initial session_state (provider default) clobbers the selection.
|
|
128
136
|
const pendingModelRef = useRef<string | null>(null);
|
|
137
|
+
const [effort, setEffortState] = useState<string | null>(null);
|
|
138
|
+
const effortRef = useRef<string | null>(null);
|
|
139
|
+
const [thinking, setThinkingState] = useState<boolean>(false);
|
|
140
|
+
// null = user hasn't chosen; don't send a value that would override provider config.
|
|
141
|
+
const thinkingRef = useRef<boolean | null>(null);
|
|
129
142
|
const prevSessionIdRef = useRef<string | null>(null);
|
|
130
143
|
const streamingContentRef = useRef("");
|
|
131
144
|
const streamingEventsRef = useRef<ChatEvent[]>([]);
|
|
@@ -657,6 +670,14 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
657
670
|
modelRef.current = state.model;
|
|
658
671
|
}
|
|
659
672
|
}
|
|
673
|
+
if (typeof state.effort === "string") {
|
|
674
|
+
setEffortState(state.effort);
|
|
675
|
+
effortRef.current = state.effort;
|
|
676
|
+
}
|
|
677
|
+
if (typeof state.thinking === "boolean") {
|
|
678
|
+
setThinkingState(state.thinking);
|
|
679
|
+
thinkingRef.current = state.thinking;
|
|
680
|
+
}
|
|
660
681
|
if (state.pendingApproval) {
|
|
661
682
|
setPendingApproval({
|
|
662
683
|
requestId: state.pendingApproval.requestId,
|
|
@@ -903,6 +924,8 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
903
924
|
priority: opts?.priority,
|
|
904
925
|
images: opts?.images,
|
|
905
926
|
...(modelRef.current && { model: modelRef.current }),
|
|
927
|
+
...(effortRef.current && { effort: effortRef.current }),
|
|
928
|
+
...(thinkingRef.current !== null && { thinking: thinkingRef.current }),
|
|
906
929
|
}));
|
|
907
930
|
},
|
|
908
931
|
[send],
|
|
@@ -918,6 +941,24 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
918
941
|
[send],
|
|
919
942
|
);
|
|
920
943
|
|
|
944
|
+
const setEffort = useCallback(
|
|
945
|
+
(nextEffort: string) => {
|
|
946
|
+
setEffortState(nextEffort); // optimistic
|
|
947
|
+
effortRef.current = nextEffort;
|
|
948
|
+
send(JSON.stringify({ type: "set_effort", effort: nextEffort }));
|
|
949
|
+
},
|
|
950
|
+
[send],
|
|
951
|
+
);
|
|
952
|
+
|
|
953
|
+
const setThinking = useCallback(
|
|
954
|
+
(enabled: boolean) => {
|
|
955
|
+
setThinkingState(enabled); // optimistic
|
|
956
|
+
thinkingRef.current = enabled;
|
|
957
|
+
send(JSON.stringify({ type: "set_thinking", enabled }));
|
|
958
|
+
},
|
|
959
|
+
[send],
|
|
960
|
+
);
|
|
961
|
+
|
|
921
962
|
const respondToApproval = useCallback(
|
|
922
963
|
(requestId: string, approved: boolean, data?: unknown) => {
|
|
923
964
|
send(
|
|
@@ -1104,6 +1145,10 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
1104
1145
|
sessionTitle,
|
|
1105
1146
|
model,
|
|
1106
1147
|
setModel,
|
|
1148
|
+
effort,
|
|
1149
|
+
setEffort,
|
|
1150
|
+
thinking,
|
|
1151
|
+
setThinking,
|
|
1107
1152
|
teamActivity,
|
|
1108
1153
|
teamMessages,
|
|
1109
1154
|
markTeamRead,
|
|
@@ -147,7 +147,14 @@ export function useGroupChat(groupId: string | null, projectName: string): UseGr
|
|
|
147
147
|
getFeed(groupId, { limit: 200 })
|
|
148
148
|
.then((res) => {
|
|
149
149
|
if (cancelled) return;
|
|
150
|
-
|
|
150
|
+
// Merge, don't clobber: a live WS message (e.g. the very first message on a
|
|
151
|
+
// brand-new group) can arrive BEFORE this fetch resolves. Keep any such live
|
|
152
|
+
// messages that the fetched snapshot doesn't already include.
|
|
153
|
+
setMessages((prev) => {
|
|
154
|
+
const fetchedIds = new Set(res.messages.map((m) => m.id));
|
|
155
|
+
const liveExtra = prev.filter((m) => !fetchedIds.has(m.id));
|
|
156
|
+
return [...res.messages, ...liveExtra];
|
|
157
|
+
});
|
|
151
158
|
})
|
|
152
159
|
.catch((e) => {
|
|
153
160
|
if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load feed");
|