@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.
Files changed (443) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/assets/skills/ppm/SKILL.md +1 -1
  3. package/assets/skills/ppm/references/http-api.md +5 -1
  4. package/dist/web/assets/{ai-resource-editor-DfCN7LjR.js → ai-resource-editor-37UxM2lK.js} +1 -1
  5. package/dist/web/assets/{angular-html-DkR4iCth.js → angular-html-2g8YGiJY.js} +1 -1
  6. package/dist/web/assets/{angular-ts-DcyL4Chx.js → angular-ts-BwSmoLfh.js} +1 -1
  7. package/dist/web/assets/{api-settings-DAk7D-NP.js → api-settings-BJTjIG4U.js} +1 -1
  8. package/dist/web/assets/{api-themes-BdQCjXQk.js → api-themes-DuLpbQFV.js} +1 -1
  9. package/dist/web/assets/{apl-BVlrVtjt.js → apl-B44SMKHp.js} +1 -1
  10. package/dist/web/assets/architecture-PBZL5I3N-gLlhsjM9.js +1 -0
  11. package/dist/web/assets/{astro-MjJlozLj.js → astro-E5620wek.js} +1 -1
  12. package/dist/web/assets/{audio-preview-DbFUkIzm.js → audio-preview-BG8uEB67.js} +1 -1
  13. package/dist/web/assets/{blade-DnJWi1fz.js → blade-D-VQWAHB.js} +1 -1
  14. package/dist/web/assets/{bsl-DCmJxSIz.js → bsl-Bq5qFzpU.js} +1 -1
  15. package/dist/web/assets/{cairo-C8dDenub.js → cairo-Cn9-ZKRa.js} +1 -1
  16. package/dist/web/assets/chat-tab-6G5LulPM.js +13 -0
  17. package/dist/web/assets/{cobol-DPx_nifl.js → cobol-IM3E3iCH.js} +1 -1
  18. package/dist/web/assets/code-editor-BlBFI3jn.js +10 -0
  19. package/dist/web/assets/{coffee-DvFzqhgN.js → coffee-24wG7ekn.js} +1 -1
  20. package/dist/web/assets/{conflict-editor-BAAffNdj.js → conflict-editor-CYZjqn46.js} +1 -1
  21. package/dist/web/assets/{cpp-BLJN0umi.js → cpp-DH9Cqt4g.js} +1 -1
  22. package/dist/web/assets/{crystal-BXR-9fGw.js → crystal-4nZYHhdi.js} +1 -1
  23. package/dist/web/assets/{csv-preview-DzhSC0fd.js → csv-preview-YxR9adj_.js} +1 -1
  24. package/dist/web/assets/{data-grid-overlay-editor-cOzDcGkl.js → data-grid-overlay-editor-DxdOKRAY.js} +1 -1
  25. package/dist/web/assets/{database-viewer-DxmL2veb.js → database-viewer-CrdTyPIN.js} +1 -1
  26. package/dist/web/assets/dialog-BpkAWOy8.js +1 -0
  27. package/dist/web/assets/{diff-viewer-DvXxlk47.js → diff-viewer-DiYj_kRC.js} +1 -1
  28. package/dist/web/assets/{docx-preview-DfjH-dIr.js → docx-preview-Dsrm2Hgu.js} +1 -1
  29. package/dist/web/assets/{edge-rWOlCmXT.js → edge-DTI9d2Qi.js} +1 -1
  30. package/dist/web/assets/{elixir-E7Y82okW.js → elixir-Ys0wioho.js} +1 -1
  31. package/dist/web/assets/{elm-DTPGbc-w.js → elm-Cihc9TAz.js} +1 -1
  32. package/dist/web/assets/{erb-DHqLHrE6.js → erb-BwYBWK2-.js} +1 -1
  33. package/dist/web/assets/{erlang-Byg0nNiV.js → erlang-CzlD_Joo.js} +1 -1
  34. package/dist/web/assets/{esm-DU7axMjq.js → esm-JLkfN0k-.js} +1 -1
  35. package/dist/web/assets/{extension-webview-wuMQ8pD7.js → extension-webview-B8ph2gI9.js} +1 -1
  36. package/dist/web/assets/{fortran-fixed-form-CY1n0Xf6.js → fortran-fixed-form-CT90EtSp.js} +1 -1
  37. package/dist/web/assets/{fsharp-_vEDSCJz.js → fsharp-LasxezlU.js} +1 -1
  38. package/dist/web/assets/{gdresource-B6XT0wAC.js → gdresource-XqgPdfiE.js} +1 -1
  39. package/dist/web/assets/{git-commit-Wk9ovq59.js → git-commit-CZBgPolw.js} +1 -1
  40. package/dist/web/assets/{git-log-panel-SPPYmbCr.js → git-log-panel-qIsOpM57.js} +1 -1
  41. package/dist/web/assets/{git-rebase-DSarGPvK.js → git-rebase-C2VzKDB1.js} +1 -1
  42. package/dist/web/assets/gitGraph-HDMCJU4V-BKGq--Jw.js +1 -0
  43. package/dist/web/assets/{glide-data-grid-BC0AHzMn.js → glide-data-grid-BrQskOnP.js} +8 -8
  44. package/dist/web/assets/{glimmer-js-CkYI35_P.js → glimmer-js-DfjWcOLD.js} +1 -1
  45. package/dist/web/assets/{glimmer-ts-BqmIZcds.js → glimmer-ts-DBldQATc.js} +1 -1
  46. package/dist/web/assets/{glsl-Be-yBCF5.js → glsl-CzNv1NPP.js} +1 -1
  47. package/dist/web/assets/{graphql-a5DrENHY.js → graphql-DDyLtQb4.js} +1 -1
  48. package/dist/web/assets/group-chat-tab-DYgRs0zS.js +1 -0
  49. package/dist/web/assets/{hack-BLAg20aD.js → hack-CtoYNYkC.js} +1 -1
  50. package/dist/web/assets/{haml-Dj6bGOQH.js → haml-CnBVap7G.js} +1 -1
  51. package/dist/web/assets/{handlebars-dmEa36Oh.js → handlebars-Dg51esUH.js} +1 -1
  52. package/dist/web/assets/{html-yacZYzSE.js → html-Ec2_evSy.js} +1 -1
  53. package/dist/web/assets/{html-derivative-lLi3-RNT.js → html-derivative-Cy-F7ZqL.js} +1 -1
  54. package/dist/web/assets/{http-1KaxcE4e.js → http-C236v8Tg.js} +1 -1
  55. package/dist/web/assets/{hurl-ST-dEEZR.js → hurl-0rMD2gPU.js} +1 -1
  56. package/dist/web/assets/{hxml-CpDtuq__.js → hxml-e5uS5jTD.js} +1 -1
  57. package/dist/web/assets/{image-preview-D_8o6OLx.js → image-preview-B9EWGEFv.js} +1 -1
  58. package/dist/web/assets/index-BYFXiFsa.css +2 -0
  59. package/dist/web/assets/index-BiHrB3KU.js +50 -0
  60. package/dist/web/assets/info-3K5VOQVL-BOhGriBF.js +1 -0
  61. package/dist/web/assets/{jinja-Cjw-evAn.js → jinja-DybFmhfq.js} +1 -1
  62. package/dist/web/assets/{jison-DfATMYoY.js → jison-hkHbixdZ.js} +1 -1
  63. package/dist/web/assets/{julia-DDCaxiqT.js → julia-QnxY6sRE.js} +1 -1
  64. package/dist/web/assets/{just-CJL529u6.js → just-1Rs-nm8g.js} +1 -1
  65. package/dist/web/assets/keybindings-store-CWi8IGEx.js +1 -0
  66. package/dist/web/assets/{latex-Zc4EpLpW.js → latex-jEBQqA7u.js} +1 -1
  67. package/dist/web/assets/{liquid-B_6KMNYS.js → liquid-DfJaZpxG.js} +1 -1
  68. package/dist/web/assets/{lua-BtS2idK7.js → lua-ti0Jr6-C.js} +1 -1
  69. package/dist/web/assets/{markdown-renderer-DVVx3WCU.js → markdown-renderer-B4rtk2Hq.js} +3 -3
  70. package/dist/web/assets/markdown-renderer-XIhxiUQq.js +1 -0
  71. package/dist/web/assets/{marko-Wk6LBnck.js → marko-DNj4AhPg.js} +1 -1
  72. package/dist/web/assets/{mdc-cRaXBrzL.js → mdc-DPFwQFe4.js} +1 -1
  73. package/dist/web/assets/mobile-bottom-sheet--5_YEewV.js +1 -0
  74. package/dist/web/assets/{nextflow-Bos2wvDV.js → nextflow-BUrFV5aB.js} +1 -1
  75. package/dist/web/assets/{nginx-DMlOwzdr.js → nginx-BrW9NdOb.js} +1 -1
  76. package/dist/web/assets/{nim-D2dZQA88.js → nim-DS_6PF2p.js} +1 -1
  77. package/dist/web/assets/notification-store-DEIj7OrE.js +1 -0
  78. package/dist/web/assets/{number-overlay-editor-Du_UgiD3.js → number-overlay-editor-CReXWiQ1.js} +1 -1
  79. package/dist/web/assets/packet-RMMSAZCW-CdLFnL8a.js +1 -0
  80. package/dist/web/assets/{panel-store-D6RV_ztx.js → panel-store-DnbT1c8L.js} +1 -1
  81. package/dist/web/assets/{pdf-preview-HTC73FyK.js → pdf-preview-Zl3KICd5.js} +1 -1
  82. package/dist/web/assets/{perl-C5-Z6fPn.js → perl-ytm9vKO_.js} +1 -1
  83. package/dist/web/assets/{php-BXNNhkMH.js → php-DWTD1Usw.js} +1 -1
  84. package/dist/web/assets/pie-UPGHQEXC-COC-h0zz.js +1 -0
  85. package/dist/web/assets/{trash-2-CbbD5QF1.js → plus-DcuJuDC3.js} +1 -1
  86. package/dist/web/assets/{postgres-viewer-pWjwP3GD.js → postgres-viewer-BTupZTmP.js} +3 -3
  87. package/dist/web/assets/{project-store-Cekcjcom.js → project-store-Sbnqc41N.js} +1 -1
  88. package/dist/web/assets/{pug-C1zf1yWy.js → pug-Bt7KL3_r.js} +1 -1
  89. package/dist/web/assets/{qml-OW58jGpD.js → qml-Dexdon5J.js} +1 -1
  90. package/dist/web/assets/radar-KQ55EAFF-CiCfdJNL.js +1 -0
  91. package/dist/web/assets/{razor-DzjSaobM.js → razor-DnYCSl0G.js} +1 -1
  92. package/dist/web/assets/{rst-RfuihOUW.js → rst-BEFYzwF8.js} +1 -1
  93. package/dist/web/assets/{ruby-CNO3pli1.js → ruby-BPaXFEjN.js} +1 -1
  94. package/dist/web/assets/{sas-DZY5BtXx.js → sas-CywiNBp8.js} +1 -1
  95. package/dist/web/assets/{scss--4g-REcN.js → scss-CGk0L6hN.js} +1 -1
  96. package/dist/web/assets/{settings-store-mWnY4Kt0.js → settings-store-DkRZhj-g.js} +2 -2
  97. package/dist/web/assets/settings-tab-BF069B1K.js +1 -0
  98. package/dist/web/assets/{shaderlab-Cu4sBiVn.js → shaderlab-Byjk0kH7.js} +1 -1
  99. package/dist/web/assets/{shellsession-DWzJfEv7.js → shellsession-DbA70QB6.js} +1 -1
  100. package/dist/web/assets/{soy-BnqE-5Ff.js → soy-Bm97kWiA.js} +1 -1
  101. package/dist/web/assets/sparkles-B3DmG8PJ.js +1 -0
  102. package/dist/web/assets/{sparql-Ctg__NhZ.js → sparql-CawLnniT.js} +1 -1
  103. package/dist/web/assets/{sql-query-editor-CJdpO95g.js → sql-query-editor-RwHY1p-a.js} +1 -1
  104. package/dist/web/assets/{sqlite-viewer-BgewX3tM.js → sqlite-viewer-3UxftoM7.js} +1 -1
  105. package/dist/web/assets/{stata-Qk2h66XW.js → stata-RifEDtNO.js} +1 -1
  106. package/dist/web/assets/{surrealql-8QEX7EfH.js → surrealql-DGRQa5Lm.js} +1 -1
  107. package/dist/web/assets/{svelte-D_mubC5-.js → svelte-w9Hb12aM.js} +1 -1
  108. package/dist/web/assets/system-monitor-tab-Ck1cIP7g.js +1 -0
  109. package/dist/web/assets/{tab-store-CcLQfu8H.js → tab-store-vn0viMOP.js} +1 -1
  110. package/dist/web/assets/{templ-C1jV0fsO.js → templ-BpUwjJXV.js} +1 -1
  111. package/dist/web/assets/{terminal-tab-DWncjHEA.js → terminal-tab-B9opPxft.js} +2 -2
  112. package/dist/web/assets/{tex-D_StFXy_.js → tex-DJFSsuTD.js} +1 -1
  113. package/dist/web/assets/tool-cards-C7iLwehG.js +7 -0
  114. package/dist/web/assets/treemap-KZPCXAKY-CZwuSCtA.js +1 -0
  115. package/dist/web/assets/{ts-tags-B5m47rEm.js → ts-tags-vp9Qvx2O.js} +1 -1
  116. package/dist/web/assets/{twig-C_br6GIl.js → twig-CoazxjRB.js} +1 -1
  117. package/dist/web/assets/{use-blob-url-DpDVcTeK.js → use-blob-url-DdXgVqfz.js} +1 -1
  118. package/dist/web/assets/use-is-mobile-CE6AamG6.js +1 -0
  119. package/dist/web/assets/{use-monaco-theme-Ch2jRiGj.js → use-monaco-theme-jtYkroys.js} +1 -1
  120. package/dist/web/assets/{vendor-mermaid-DP1CEcGn.js → vendor-mermaid-DPpYkrMf.js} +1 -1
  121. package/dist/web/assets/{video-preview-rWrNCfZX.js → video-preview-Ced_VIvq.js} +1 -1
  122. package/dist/web/assets/{vue-DQwCnLdr.js → vue-CnshsiXd.js} +1 -1
  123. package/dist/web/assets/{vue-html-T_EoGpPJ.js → vue-html-CZshynFp.js} +1 -1
  124. package/dist/web/assets/{vue-vine-DmxLqX50.js → vue-vine-C5gtp_T1.js} +1 -1
  125. package/dist/web/assets/{xml-Bs6Bw8is.js → xml-BEGJasgj.js} +1 -1
  126. package/dist/web/assets/{xsl-f5ZNhRCc.js → xsl-DXpRLjYk.js} +1 -1
  127. package/dist/web/index.html +21 -19
  128. package/dist/web/sw.js +1 -1
  129. package/package.json +1 -1
  130. package/schemas/ppm-config.schema.json +3 -3
  131. package/src/cli/commands/init.ts +8 -5
  132. package/src/providers/claude-agent-sdk-query-options.ts +57 -0
  133. package/src/providers/claude-agent-sdk.ts +21 -9
  134. package/src/server/routes/group-chat.ts +118 -9
  135. package/src/server/ws/chat.ts +91 -10
  136. package/src/services/account.service.ts +13 -7
  137. package/src/services/db.service.ts +31 -1
  138. package/src/services/group-chat/agent-runner.ts +15 -2
  139. package/src/services/group-chat/context-window.ts +15 -0
  140. package/src/services/group-chat/group-chat.service.ts +178 -79
  141. package/src/services/group-chat/group-chat.store.ts +30 -0
  142. package/src/services/group-chat/responder-router.ts +110 -0
  143. package/src/services/group-chat/transcript-archive.ts +18 -0
  144. package/src/services/group-chat/turn-engine.ts +183 -105
  145. package/src/services/jsonl-transcript-parser.ts +36 -0
  146. package/src/types/api.ts +4 -2
  147. package/src/types/chat.ts +8 -0
  148. package/src/types/config.ts +4 -9
  149. package/src/types/group-chat-ws.ts +2 -2
  150. package/src/types/group-chat.ts +33 -4
  151. package/src/web/components/chat/chat-tab.tsx +8 -0
  152. package/src/web/components/chat/message-input.tsx +27 -7
  153. package/src/web/components/chat/message-list.tsx +48 -3
  154. package/src/web/components/chat/model-thinking-selector-helpers.ts +33 -0
  155. package/src/web/components/chat/model-thinking-selector.tsx +189 -0
  156. package/src/web/components/group-chat/group-chat-tab.tsx +109 -14
  157. package/src/web/components/group-chat/group-create-dialog.tsx +10 -3
  158. package/src/web/components/group-chat/group-full-transcript-view.tsx +9 -8
  159. package/src/web/components/group-chat/group-member-edit-dialog.tsx +108 -0
  160. package/src/web/components/group-chat/group-member-roster.tsx +51 -23
  161. package/src/web/components/group-chat/group-message-item.tsx +45 -26
  162. package/src/web/components/group-chat/group-transcript-messages.tsx +126 -0
  163. package/src/web/components/layout/mobile-drawer-tab-bar.tsx +10 -0
  164. package/src/web/components/layout/nav-section-rail.tsx +8 -2
  165. package/src/web/components/layout/upgrade-button.tsx +33 -11
  166. package/src/web/components/settings/ai-settings-section.tsx +2 -0
  167. package/src/web/components/settings/proxy-test-section.tsx +3 -1
  168. package/src/web/hooks/use-chat.ts +45 -0
  169. package/src/web/hooks/use-group-chat.ts +8 -1
  170. package/src/web/lib/api-group-chat.ts +47 -4
  171. package/src/web/lib/sidebar-tabs/tab-registry.ts +3 -1
  172. package/dist/web/assets/architecture-PBZL5I3N-CqTF9Xn6.js +0 -1
  173. package/dist/web/assets/chat-tab-C6nMDb9l.js +0 -18
  174. package/dist/web/assets/code-editor-C38IIs_y.js +0 -10
  175. package/dist/web/assets/gitGraph-HDMCJU4V-X12vfQ3i.js +0 -1
  176. package/dist/web/assets/group-chat-tab-D20bF8q5.js +0 -1
  177. package/dist/web/assets/index-C1Q59prB.js +0 -50
  178. package/dist/web/assets/index-CMJ6whqq.css +0 -2
  179. package/dist/web/assets/info-3K5VOQVL-Bcz-Qhua.js +0 -1
  180. package/dist/web/assets/input-24Nf_edC.js +0 -1
  181. package/dist/web/assets/keybindings-store-TINaziU9.js +0 -1
  182. package/dist/web/assets/notification-store-DN8oDV7o.js +0 -1
  183. package/dist/web/assets/packet-RMMSAZCW-BTwjB70W.js +0 -1
  184. package/dist/web/assets/pie-UPGHQEXC-Cn-lrQYZ.js +0 -1
  185. package/dist/web/assets/radar-KQ55EAFF-Cmppm_Ia.js +0 -1
  186. package/dist/web/assets/settings-tab-BoRuss3O.js +0 -1
  187. package/dist/web/assets/sparkles-2ii4lR7b.js +0 -1
  188. package/dist/web/assets/system-monitor-tab-BA9gqJRW.js +0 -1
  189. package/dist/web/assets/treemap-KZPCXAKY-BLWus1wm.js +0 -1
  190. package/dist/web/assets/use-websocket-MvxbuTdy.js +0 -1
  191. /package/dist/web/assets/{abap-tkptwpsK.js → abap-wT6fgqwv.js} +0 -0
  192. /package/dist/web/assets/{actionscript-3-Di9TMGwg.js → actionscript-3-CqcHpPYj.js} +0 -0
  193. /package/dist/web/assets/{ada-CB9F079D.js → ada-DWE3Hn4E.js} +0 -0
  194. /package/dist/web/assets/{andromeeda-Dcl8jpb7.js → andromeeda-DpQ-y-Jt.js} +0 -0
  195. /package/dist/web/assets/{apache-D0Nk0qsH.js → apache-LRTUP4r3.js} +0 -0
  196. /package/dist/web/assets/{apex-mQIoWncD.js → apex-DwVeH5_h.js} +0 -0
  197. /package/dist/web/assets/{api-client-Dvzcc_EO.js → api-client-BK4NPNoY.js} +0 -0
  198. /package/dist/web/assets/{applescript-C6ljbcsI.js → applescript-DyQiO9JU.js} +0 -0
  199. /package/dist/web/assets/{apply-theme-ORrEdHKT.js → apply-theme-DxKsrDLA.js} +0 -0
  200. /package/dist/web/assets/{ara-WFqRPGPe.js → ara-Cf-OWd2S.js} +0 -0
  201. /package/dist/web/assets/{asciidoc-bNd8w4nf.js → asciidoc-gocbKcVK.js} +0 -0
  202. /package/dist/web/assets/{asm-BQ1_F580.js → asm-C3meb5HY.js} +0 -0
  203. /package/dist/web/assets/{aurora-x-Ciqs_Dbu.js → aurora-x-BYcXaCIg.js} +0 -0
  204. /package/dist/web/assets/{awk-GCR-6KZV.js → awk-BcT6nIdN.js} +0 -0
  205. /package/dist/web/assets/{ayu-dark-DxJXuj99.js → ayu-dark-CLZPoccg.js} +0 -0
  206. /package/dist/web/assets/{ayu-light-jvSyJWDV.js → ayu-light-CTyRQdS2.js} +0 -0
  207. /package/dist/web/assets/{ayu-mirage-Cg3BPO6H.js → ayu-mirage-DjqfqZdo.js} +0 -0
  208. /package/dist/web/assets/{ballerina-BPz4CrX6.js → ballerina-BCARR-zK.js} +0 -0
  209. /package/dist/web/assets/{bat-CSTs2hIG.js → bat-_yaRjWOb.js} +0 -0
  210. /package/dist/web/assets/{beancount-DMateAZX.js → beancount-BPESBMS9.js} +0 -0
  211. /package/dist/web/assets/{berry-9lXg0GRM.js → berry-BSLE-Sf8.js} +0 -0
  212. /package/dist/web/assets/{bibtex-DIbqmvFg.js → bibtex-CvUWWCVx.js} +0 -0
  213. /package/dist/web/assets/{bicep-02WGsoJ8.js → bicep--vcqqALZ.js} +0 -0
  214. /package/dist/web/assets/{bird2-BY0tbu3k.js → bird2-Clclqgh6.js} +0 -0
  215. /package/dist/web/assets/{c-jMBX_9Je.js → c-CSC2LwTp.js} +0 -0
  216. /package/dist/web/assets/{c3-B8JVbNjW.js → c3-Cl1_jUnm.js} +0 -0
  217. /package/dist/web/assets/{cadence-DUIf1tvL.js → cadence-BwAD7vSC.js} +0 -0
  218. /package/dist/web/assets/{catppuccin-frappe-FhUCVxex.js → catppuccin-frappe-hr0HKoFX.js} +0 -0
  219. /package/dist/web/assets/{catppuccin-latte-CzfrtmgL.js → catppuccin-latte-DXEIYlFO.js} +0 -0
  220. /package/dist/web/assets/{catppuccin-macchiato-6xL0lOtj.js → catppuccin-macchiato-B2zST7sA.js} +0 -0
  221. /package/dist/web/assets/{catppuccin-mocha-D39-xS3P.js → catppuccin-mocha-CvrdnYv9.js} +0 -0
  222. /package/dist/web/assets/{chevron-right-BBc6ATtm.js → chevron-right-DeUue2aK.js} +0 -0
  223. /package/dist/web/assets/{circle-question-mark-CveWaCux.js → circle-question-mark-PaJgx-3d.js} +0 -0
  224. /package/dist/web/assets/{clarity-D8TeGvoT.js → clarity-BeQd5TQD.js} +0 -0
  225. /package/dist/web/assets/{clojure-Dx_acSX7.js → clojure-Csdo0vb_.js} +0 -0
  226. /package/dist/web/assets/{cmake-CyeYPq8o.js → cmake-Cf0q7ddg.js} +0 -0
  227. /package/dist/web/assets/{code-7ZAlTvsm.js → code-TekEnDFM.js} +0 -0
  228. /package/dist/web/assets/{codeowners-DrTI0lmI.js → codeowners-CUEzlC7R.js} +0 -0
  229. /package/dist/web/assets/{codeql-CPkFxVW-.js → codeql-DxHyogQt.js} +0 -0
  230. /package/dist/web/assets/{common-lisp-B0k-3LTj.js → common-lisp-WLb-tAda.js} +0 -0
  231. /package/dist/web/assets/{coq-uygpo7to.js → coq-DFtMD6Wn.js} +0 -0
  232. /package/dist/web/assets/{csharp-DKUYGfSp.js → csharp-DEnvXVjs.js} +0 -0
  233. /package/dist/web/assets/{css-DoOUp7v4.js → css-DMPpCfkZ.js} +0 -0
  234. /package/dist/web/assets/{csv-B3YE13gi.js → csv-DTSgNSaP.js} +0 -0
  235. /package/dist/web/assets/{csv-parser-CB6bK93y.js → csv-parser-B_xNn07y.js} +0 -0
  236. /package/dist/web/assets/{cue-DViO2wvn.js → cue-BEmVIZmd.js} +0 -0
  237. /package/dist/web/assets/{cypher-4BMCIW5N.js → cypher-CncQVhvU.js} +0 -0
  238. /package/dist/web/assets/{d-BT_sTHas.js → d-BzUSBVex.js} +0 -0
  239. /package/dist/web/assets/{dark-plus-DVVXu-1N.js → dark-plus-mysFNRq2.js} +0 -0
  240. /package/dist/web/assets/{dart-DHz6f6_6.js → dart-BBu3nkcE.js} +0 -0
  241. /package/dist/web/assets/{data-grid-types-CWHnFOc-.js → data-grid-types-CzEQU9PJ.js} +0 -0
  242. /package/dist/web/assets/{database-BLht7BVM.js → database-COYAMZaw.js} +0 -0
  243. /package/dist/web/assets/{dax-ChYCjweK.js → dax-DcLVz9_9.js} +0 -0
  244. /package/dist/web/assets/{desktop-D6Lt4p04.js → desktop-DS2PdvoU.js} +0 -0
  245. /package/dist/web/assets/{diff-D8TDe4hP.js → diff-aUYk5Qys.js} +0 -0
  246. /package/dist/web/assets/{dist-B5ErTtYs.js → dist-Bn3E6I4R.js} +0 -0
  247. /package/dist/web/assets/{dist-D1CjMuoa.js → dist-Dxl3dqhC.js} +0 -0
  248. /package/dist/web/assets/{docker-Bsp0YbPx.js → docker-12Lj1QUD.js} +0 -0
  249. /package/dist/web/assets/{dotenv-B_7giSY_.js → dotenv-D-P4bzvl.js} +0 -0
  250. /package/dist/web/assets/{dracula-TrQL2iB5.js → dracula-C-eRNn4o.js} +0 -0
  251. /package/dist/web/assets/{dracula-soft-n2XOlgh-.js → dracula-soft-CBB1BI7O.js} +0 -0
  252. /package/dist/web/assets/{dream-maker-CdIEdhpT.js → dream-maker-C_j5A0r7.js} +0 -0
  253. /package/dist/web/assets/{edit-diff-preview-Cj6-iplb.js → edit-diff-preview-CRMu-6r1.js} +0 -0
  254. /package/dist/web/assets/{emacs-lisp-CSbixs6u.js → emacs-lisp-W54LT7rh.js} +0 -0
  255. /package/dist/web/assets/{everforest-dark-BuZahZYp.js → everforest-dark-B_ISUDeh.js} +0 -0
  256. /package/dist/web/assets/{everforest-light-DPH53z5H.js → everforest-light-CNUYa354.js} +0 -0
  257. /package/dist/web/assets/{fennel-B1-K_hlJ.js → fennel-DK82-oso.js} +0 -0
  258. /package/dist/web/assets/{file-exclamation-point-C-lL0g_E.js → file-exclamation-point-DBEC-Kst.js} +0 -0
  259. /package/dist/web/assets/{fish-Cy12Dbua.js → fish-CbJVJzQj.js} +0 -0
  260. /package/dist/web/assets/{fluent-B_82ys8E.js → fluent-Cug5cOL1.js} +0 -0
  261. /package/dist/web/assets/{fortran-free-form-BRQdNzZF.js → fortran-free-form-amHz32Zw.js} +0 -0
  262. /package/dist/web/assets/{gdscript-XBDmLUm9.js → gdscript-t_G6VYpv.js} +0 -0
  263. /package/dist/web/assets/{gdshader-DhVfB3u4.js → gdshader-DqZaHh4E.js} +0 -0
  264. /package/dist/web/assets/{genie-X3K29Y49.js → genie-CIJtFlZK.js} +0 -0
  265. /package/dist/web/assets/{gherkin-DKIx-6cX.js → gherkin-CalidqLY.js} +0 -0
  266. /package/dist/web/assets/{github-dark-Bf7zdp5s.js → github-dark-BG2xX0wa.js} +0 -0
  267. /package/dist/web/assets/{github-dark-default-DqsBBV11.js → github-dark-default-tDp_EOBs.js} +0 -0
  268. /package/dist/web/assets/{github-dark-dimmed-X2gqRz6w.js → github-dark-dimmed-DlSfPwW2.js} +0 -0
  269. /package/dist/web/assets/{github-dark-high-contrast-Z7tvbGX4.js → github-dark-high-contrast-qZM7j5KB.js} +0 -0
  270. /package/dist/web/assets/{github-light-BKxt-7zZ.js → github-light-CnvWTiyb.js} +0 -0
  271. /package/dist/web/assets/{github-light-default-B0liF4d4.js → github-light-default-Dy6OAt2Q.js} +0 -0
  272. /package/dist/web/assets/{github-light-high-contrast-F4encJwr.js → github-light-high-contrast-1BHQCOPl.js} +0 -0
  273. /package/dist/web/assets/{gleam-Pz2bHgBB.js → gleam-D-2cpXVX.js} +0 -0
  274. /package/dist/web/assets/{gn-CgmdNsPU.js → gn-C1cC4xLc.js} +0 -0
  275. /package/dist/web/assets/{gnuplot-qLNF5yZ9.js → gnuplot-2Gp459mV.js} +0 -0
  276. /package/dist/web/assets/{go-CSDUNhE7.js → go-BA1q0q8h.js} +0 -0
  277. /package/dist/web/assets/{groovy-B3NEnOHF.js → groovy-BlIa-VfI.js} +0 -0
  278. /package/dist/web/assets/{gruvbox-dark-hard-DcoftiUX.js → gruvbox-dark-hard-BMIwVwaJ.js} +0 -0
  279. /package/dist/web/assets/{gruvbox-dark-medium-D1wVSuD8.js → gruvbox-dark-medium-DxfuBW3n.js} +0 -0
  280. /package/dist/web/assets/{gruvbox-dark-soft-DWpunymH.js → gruvbox-dark-soft-_NSslDDi.js} +0 -0
  281. /package/dist/web/assets/{gruvbox-light-hard-rHMvyUdS.js → gruvbox-light-hard-CP5MIsL9.js} +0 -0
  282. /package/dist/web/assets/{gruvbox-light-medium-3O2KiXO7.js → gruvbox-light-medium-BTMursH0.js} +0 -0
  283. /package/dist/web/assets/{gruvbox-light-soft-lNlXJPwH.js → gruvbox-light-soft-Bv6zFoVX.js} +0 -0
  284. /package/dist/web/assets/{haskell-aaG3aC0h.js → haskell-Da8UeSv-.js} +0 -0
  285. /package/dist/web/assets/{haxe-CPcHhUDd.js → haxe-mcKlcxBa.js} +0 -0
  286. /package/dist/web/assets/{hcl-CMQNlR_4.js → hcl-BdZcx5JX.js} +0 -0
  287. /package/dist/web/assets/{hjson-DeuklPFj.js → hjson-pFXYbN4t.js} +0 -0
  288. /package/dist/web/assets/{hlsl-BI3hlsaM.js → hlsl-Z0II0KR8.js} +0 -0
  289. /package/dist/web/assets/{horizon-C7-gOcjs.js → horizon-CufN8DyP.js} +0 -0
  290. /package/dist/web/assets/{horizon-bright-Cxt9bRW7.js → horizon-bright-5qoQVyIY.js} +0 -0
  291. /package/dist/web/assets/{houston-DbF2G7iD.js → houston-DOFkQwep.js} +0 -0
  292. /package/dist/web/assets/{hy-DRG6Hs2I.js → hy-BVbDMDcG.js} +0 -0
  293. /package/dist/web/assets/{imba-CxKv_2TW.js → imba-DRM6LLS5.js} +0 -0
  294. /package/dist/web/assets/{ini-BiHsyCdO.js → ini-2KCnNvmz.js} +0 -0
  295. /package/dist/web/assets/{java-D3RZzgDB.js → java-BmvH-Ou1.js} +0 -0
  296. /package/dist/web/assets/{javascript-4FmSqG-T.js → javascript-B7VhU1Yc.js} +0 -0
  297. /package/dist/web/assets/{json-CjB236_E.js → json-X1pNk0n7.js} +0 -0
  298. /package/dist/web/assets/{json5-bkfO-Rco.js → json5-CJeEJPTg.js} +0 -0
  299. /package/dist/web/assets/{jsonc-BwaTeLyv.js → jsonc-C1haTBsf.js} +0 -0
  300. /package/dist/web/assets/{jsonl-CfxNSwGd.js → jsonl-wQ8-AJgs.js} +0 -0
  301. /package/dist/web/assets/{jsonnet-CQETCYrp.js → jsonnet-BrEjY3Xh.js} +0 -0
  302. /package/dist/web/assets/{jssm-D5o3Zzdz.js → jssm-C6LgYbOs.js} +0 -0
  303. /package/dist/web/assets/{jsx-BAMILPLo.js → jsx-B2cfD_Fb.js} +0 -0
  304. /package/dist/web/assets/{kanagawa-dragon-BhGVxu3R.js → kanagawa-dragon-6UCcJpLw.js} +0 -0
  305. /package/dist/web/assets/{kanagawa-lotus-FH4Y59ro.js → kanagawa-lotus-DOmfpsRg.js} +0 -0
  306. /package/dist/web/assets/{kanagawa-wave-eilvP9MB.js → kanagawa-wave-CpxmPE7N.js} +0 -0
  307. /package/dist/web/assets/{kdl-BQ-yvXUK.js → kdl-BrLEivmb.js} +0 -0
  308. /package/dist/web/assets/{kotlin-BuCx0-VT.js → kotlin-BO2FUnDB.js} +0 -0
  309. /package/dist/web/assets/{kusto-DAN_n_Cy.js → kusto-Cev1yiq9.js} +0 -0
  310. /package/dist/web/assets/{laserwave-Cq2BlxrT.js → laserwave-BlEkf-eH.js} +0 -0
  311. /package/dist/web/assets/{lean-Dhq7uXKw.js → lean-BLS3Xk2w.js} +0 -0
  312. /package/dist/web/assets/{less-CxaMQb8j.js → less-BXmcsqcq.js} +0 -0
  313. /package/dist/web/assets/{lib-MIEszzkI.js → lib-CxSBdrd7.js} +0 -0
  314. /package/dist/web/assets/{light-plus-B4sMAend.js → light-plus-DS6zriYl.js} +0 -0
  315. /package/dist/web/assets/{llvm-DQ6-B_6Y.js → llvm-C_wLnJgX.js} +0 -0
  316. /package/dist/web/assets/{log-Bb_vqvu7.js → log-Cg8pvmWi.js} +0 -0
  317. /package/dist/web/assets/{logo-BzfYv3A_.js → logo-C9-kEvPW.js} +0 -0
  318. /package/dist/web/assets/{luau-BnAeNR77.js → luau-NwaGugfZ.js} +0 -0
  319. /package/dist/web/assets/{make-B6IFuxpC.js → make-DBpJE-Z8.js} +0 -0
  320. /package/dist/web/assets/{markdown-Z0xi77Fn.js → markdown-B7ZTAu7B.js} +0 -0
  321. /package/dist/web/assets/{material-theme-1scy1SYn.js → material-theme-BsXH-Mss.js} +0 -0
  322. /package/dist/web/assets/{material-theme-darker-G-JykXQP.js → material-theme-darker-CW9OlIeY.js} +0 -0
  323. /package/dist/web/assets/{material-theme-lighter-BtKkCMVq.js → material-theme-lighter-D2PAh0Kw.js} +0 -0
  324. /package/dist/web/assets/{material-theme-ocean-irrDC89L.js → material-theme-ocean-Vz6DBVi3.js} +0 -0
  325. /package/dist/web/assets/{material-theme-palenight-Eq5_K4LM.js → material-theme-palenight-D-GleP3G.js} +0 -0
  326. /package/dist/web/assets/{matlab-BE3oCXZC.js → matlab-C7MYlMSn.js} +0 -0
  327. /package/dist/web/assets/{mdx-DYiuFTGw.js → mdx-FkOOX3Dq.js} +0 -0
  328. /package/dist/web/assets/{mermaid-DVlaEvtw.js → mermaid-C_9qw5it.js} +0 -0
  329. /package/dist/web/assets/{min-dark-DSkeTpQa.js → min-dark-BowNvxk2.js} +0 -0
  330. /package/dist/web/assets/{min-light-CFv2Q0uF.js → min-light-x8oWUmbL.js} +0 -0
  331. /package/dist/web/assets/{mipsasm-CiAFuZQ2.js → mipsasm-Dmi1AZOT.js} +0 -0
  332. /package/dist/web/assets/{mojo-ARshcaSQ.js → mojo-C6z7mry2.js} +0 -0
  333. /package/dist/web/assets/{monokai-CPTV-SOg.js → monokai-BQ4e_Hn0.js} +0 -0
  334. /package/dist/web/assets/{moonbit-D57B0dZr.js → moonbit-CEeNIoB4.js} +0 -0
  335. /package/dist/web/assets/{move-qgy3G_o9.js → move-bALfKUa7.js} +0 -0
  336. /package/dist/web/assets/{narrat-CZ3rC-oc.js → narrat-DX4JlAWT.js} +0 -0
  337. /package/dist/web/assets/{nextflow-groovy-BxxIOcI4.js → nextflow-groovy-CKQWtRkO.js} +0 -0
  338. /package/dist/web/assets/{night-owl-B1ryGCda.js → night-owl-D4PQd726.js} +0 -0
  339. /package/dist/web/assets/{night-owl-light-BZvNnvMF.js → night-owl-light-BQo_YHll.js} +0 -0
  340. /package/dist/web/assets/{nix-BVBQi8yv.js → nix-B1jThkGj.js} +0 -0
  341. /package/dist/web/assets/{nord-3NXw613h.js → nord-35quHUKo.js} +0 -0
  342. /package/dist/web/assets/{nushell-BMOLRalb.js → nushell-L6DbJTuL.js} +0 -0
  343. /package/dist/web/assets/{objective-c-AxruEUgh.js → objective-c-CTZ4bR2U.js} +0 -0
  344. /package/dist/web/assets/{objective-cpp-cFT0qRsD.js → objective-cpp-Dm1YDIdA.js} +0 -0
  345. /package/dist/web/assets/{ocaml-_8JH6O8J.js → ocaml-B3n__LGy.js} +0 -0
  346. /package/dist/web/assets/{odin-nwYvR0O6.js → odin-DmqZ8n3i.js} +0 -0
  347. /package/dist/web/assets/{one-dark-pro-C1LaYJaH.js → one-dark-pro-16_UaUig.js} +0 -0
  348. /package/dist/web/assets/{one-light-B7rMc__c.js → one-light-B-GGjWn5.js} +0 -0
  349. /package/dist/web/assets/{openscad-Cwes8bKO.js → openscad-DTFB9Sj6.js} +0 -0
  350. /package/dist/web/assets/{pascal-DMt-6tdZ.js → pascal-RcT1dQYN.js} +0 -0
  351. /package/dist/web/assets/{pkl-QBTyYQmB.js → pkl-Dr4yLQ_o.js} +0 -0
  352. /package/dist/web/assets/{plastic-BTSUp8Fk.js → plastic-hp2Nry0R.js} +0 -0
  353. /package/dist/web/assets/{plsql-DQv3IFXP.js → plsql-pFcO4WZ0.js} +0 -0
  354. /package/dist/web/assets/{po-CNwZx4tW.js → po-BkZ0_HvY.js} +0 -0
  355. /package/dist/web/assets/{poimandres-8Os7Qequ.js → poimandres-BcTrxj7f.js} +0 -0
  356. /package/dist/web/assets/{polar-b4yK8oD8.js → polar-DHK3q8FF.js} +0 -0
  357. /package/dist/web/assets/{postcss-sFctwpxx.js → postcss-Bv7WzijA.js} +0 -0
  358. /package/dist/web/assets/{powerquery-Cg_WrtuN.js → powerquery-DpaU_hW9.js} +0 -0
  359. /package/dist/web/assets/{powershell-C7Ifz95h.js → powershell-_Rqc0MGP.js} +0 -0
  360. /package/dist/web/assets/{prisma-Z52HUJzQ.js → prisma-wyegE8us.js} +0 -0
  361. /package/dist/web/assets/{prolog-DLqW-zR1.js → prolog-DspHCURv.js} +0 -0
  362. /package/dist/web/assets/{proto-BOIzxCCJ.js → proto-BOBiNGf5.js} +0 -0
  363. /package/dist/web/assets/{puppet-De7TjZIf.js → puppet-DfLvV8h2.js} +0 -0
  364. /package/dist/web/assets/{purescript-R76ou1WT.js → purescript-BY5ZSOZy.js} +0 -0
  365. /package/dist/web/assets/{python-Dprm0tNP.js → python-B758mMeg.js} +0 -0
  366. /package/dist/web/assets/{qmldir-Clp_jpNw.js → qmldir-C75bpHvy.js} +0 -0
  367. /package/dist/web/assets/{qss-eQPYYzSo.js → qss-DcLTlbLd.js} +0 -0
  368. /package/dist/web/assets/{r-CCcRHIf5.js → r-D0G_Y1P5.js} +0 -0
  369. /package/dist/web/assets/{racket-CzE472yp.js → racket-DTye_5qn.js} +0 -0
  370. /package/dist/web/assets/{raku-DQwXrTSi.js → raku-uJXBXkV0.js} +0 -0
  371. /package/dist/web/assets/{react-J9g6e3Rq.js → react-CorNPdie.js} +0 -0
  372. /package/dist/web/assets/{red-KCS6wyop.js → red-rs3HE3re.js} +0 -0
  373. /package/dist/web/assets/{reg-CcrAddUh.js → reg-DkTIaX7a.js} +0 -0
  374. /package/dist/web/assets/{regexp-DDbud-Ri.js → regexp-4TLSs4_m.js} +0 -0
  375. /package/dist/web/assets/{rel-99GDgaHp.js → rel-B0jumCjt.js} +0 -0
  376. /package/dist/web/assets/{resolve-theme-DJORYzKu.js → resolve-theme-CCoakF2E.js} +0 -0
  377. /package/dist/web/assets/{riscv-Dm2eNv0R.js → riscv-DtaWMlo0.js} +0 -0
  378. /package/dist/web/assets/{ron-CzFt0ygH.js → ron-BCPxwJD6.js} +0 -0
  379. /package/dist/web/assets/{rose-pine-Ck6lCrCP.js → rose-pine-CNryoqGi.js} +0 -0
  380. /package/dist/web/assets/{rose-pine-dawn-vtALRJNj.js → rose-pine-dawn-C-gJOQVP.js} +0 -0
  381. /package/dist/web/assets/{rose-pine-moon-DPto8qXw.js → rose-pine-moon-BdXSXpZh.js} +0 -0
  382. /package/dist/web/assets/{rosmsg-NtS6429H.js → rosmsg-CPG8X-D5.js} +0 -0
  383. /package/dist/web/assets/{rust-BjIXvF9h.js → rust-CxfW3ePx.js} +0 -0
  384. /package/dist/web/assets/{sass-CQ23wf5E.js → sass-D-7bxo_L.js} +0 -0
  385. /package/dist/web/assets/{save-DO5xjW95.js → save-BM4p9_9n.js} +0 -0
  386. /package/dist/web/assets/{scala-LfKLM143.js → scala-DyUsfHNc.js} +0 -0
  387. /package/dist/web/assets/{scheme-D3SLBXlF.js → scheme-ROgrwiO-.js} +0 -0
  388. /package/dist/web/assets/{sdbl-ODRd2rGN.js → sdbl-B1EAQWpp.js} +0 -0
  389. /package/dist/web/assets/{shellscript-3KB1G_oA.js → shellscript-HhmB_Ufy.js} +0 -0
  390. /package/dist/web/assets/{shield-check-m2QzZTuZ.js → shield-check-C3qYSU8a.js} +0 -0
  391. /package/dist/web/assets/{shield-off-DNn7VzJe.js → shield-off-D5tU7gQT.js} +0 -0
  392. /package/dist/web/assets/{slack-dark-DTtyWmIy.js → slack-dark-DnmSY72G.js} +0 -0
  393. /package/dist/web/assets/{slack-ochin-Bu0PApk3.js → slack-ochin-q97gHjcd.js} +0 -0
  394. /package/dist/web/assets/{smalltalk-haMT-Sbe.js → smalltalk-B-1waXvA.js} +0 -0
  395. /package/dist/web/assets/{snazzy-light-DXJzefE9.js → snazzy-light-C8yWDN2g.js} +0 -0
  396. /package/dist/web/assets/{solarized-dark-B6LyYa18.js → solarized-dark-ClVDEMJZ.js} +0 -0
  397. /package/dist/web/assets/{solarized-light-QLADebkv.js → solarized-light-Bts6CUIP.js} +0 -0
  398. /package/dist/web/assets/{solidity-mzfq1aDc.js → solidity-DYxwp0om.js} +0 -0
  399. /package/dist/web/assets/{splunk-CyH4RWBp.js → splunk-jK6-Sr06.js} +0 -0
  400. /package/dist/web/assets/{sql-CWVlT5D3.js → sql-DPpd8aUS.js} +0 -0
  401. /package/dist/web/assets/{ssh-config-DNvQJ1Qx.js → ssh-config-Bimb9LVr.js} +0 -0
  402. /package/dist/web/assets/{stylus-ByQQdtmf.js → stylus-B2DgJRJw.js} +0 -0
  403. /package/dist/web/assets/{swift-D1cpY4ow.js → swift-ChEH2nFL.js} +0 -0
  404. /package/dist/web/assets/{synthwave-84-BDF_-QiW.js → synthwave-84-DwSLbgAm.js} +0 -0
  405. /package/dist/web/assets/{system-verilog-BYrkMydC.js → system-verilog-DoVBMhJ8.js} +0 -0
  406. /package/dist/web/assets/{systemd-CQm3zyK0.js → systemd--Ux4VAYD.js} +0 -0
  407. /package/dist/web/assets/{table-CAVmgQMT.js → table-Di8pv2Y_.js} +0 -0
  408. /package/dist/web/assets/{talonscript-DMW5CzE1.js → talonscript-DQNx9nak.js} +0 -0
  409. /package/dist/web/assets/{tasl-BhFzMCr2.js → tasl-Bwy_Y9uD.js} +0 -0
  410. /package/dist/web/assets/{tcl-D7VEAF-9.js → tcl-Drea-2jA.js} +0 -0
  411. /package/dist/web/assets/{terraform-DdT5A0Vy.js → terraform-4rS5HoFk.js} +0 -0
  412. /package/dist/web/assets/{tokyo-night-WGLMM6Q9.js → tokyo-night-C9MqaxIn.js} +0 -0
  413. /package/dist/web/assets/{toml-CZ7ipXHZ.js → toml-tSgOSv42.js} +0 -0
  414. /package/dist/web/assets/{tsv-B1zVvoTr.js → tsv-BmL4O1Zx.js} +0 -0
  415. /package/dist/web/assets/{tsx-D4HwRUBq.js → tsx-BwzeA880.js} +0 -0
  416. /package/dist/web/assets/{turtle-B4r8KEJH.js → turtle-2DYvssFL.js} +0 -0
  417. /package/dist/web/assets/{typescript-BnHhxMtp.js → typescript-ZC-vonSh.js} +0 -0
  418. /package/dist/web/assets/{typespec-DP2q46GT.js → typespec-DkCEO45F.js} +0 -0
  419. /package/dist/web/assets/{typst-DFsD_yaD.js → typst-DAZdb2n6.js} +0 -0
  420. /package/dist/web/assets/{utils-CTg5uAYR.js → utils-CSCvNZxE.js} +0 -0
  421. /package/dist/web/assets/{v-Bji8hSVT.js → v-B_wsb4C1.js} +0 -0
  422. /package/dist/web/assets/{vala-D3TIgGmU.js → vala-BDBNS784.js} +0 -0
  423. /package/dist/web/assets/{vb-DvcxFS2q.js → vb-CuOoJSSa.js} +0 -0
  424. /package/dist/web/assets/{vendor-xterm-DfNMj6xt.js → vendor-xterm-CImj6i6Z.js} +0 -0
  425. /package/dist/web/assets/{verilog-Dy7cF35d.js → verilog-BCcOvOcc.js} +0 -0
  426. /package/dist/web/assets/{vesper-BzjwUv9J.js → vesper-vN8CREK5.js} +0 -0
  427. /package/dist/web/assets/{vhdl-DuFnFNmW.js → vhdl-CI8PoqeM.js} +0 -0
  428. /package/dist/web/assets/{viml-yAPgKlbz.js → viml-B66dNP1B.js} +0 -0
  429. /package/dist/web/assets/{vitesse-black-oSSQdyIZ.js → vitesse-black-0bGIaCfD.js} +0 -0
  430. /package/dist/web/assets/{vitesse-dark-BZxwPihB.js → vitesse-dark-Dk-RSXq-.js} +0 -0
  431. /package/dist/web/assets/{vitesse-light-uIigycvt.js → vitesse-light-BUsA5RhG.js} +0 -0
  432. /package/dist/web/assets/{vyper-CX3NAxm5.js → vyper-dNodzEa8.js} +0 -0
  433. /package/dist/web/assets/{wasm-Coen1MOg.js → wasm-BDxaNPCj.js} +0 -0
  434. /package/dist/web/assets/{wasm-D9td37qO.js → wasm-d6SE2_qm.js} +0 -0
  435. /package/dist/web/assets/{wenyan-lwNIHgk6.js → wenyan-D0h8Uz55.js} +0 -0
  436. /package/dist/web/assets/{wgsl-DQAzCfog.js → wgsl-vKs_vsvQ.js} +0 -0
  437. /package/dist/web/assets/{wikitext-DTXmt5NE.js → wikitext-BIWsPJit.js} +0 -0
  438. /package/dist/web/assets/{wit-Bdw_7WDH.js → wit-6vmKi2H3.js} +0 -0
  439. /package/dist/web/assets/{wolfram-DqyHDZ07.js → wolfram-zoNg6F1a.js} +0 -0
  440. /package/dist/web/assets/{x-C2VSAp7O.js → x-BsFLg-T8.js} +0 -0
  441. /package/dist/web/assets/{yaml-CPXhdByd.js → yaml-W95qP6-B.js} +0 -0
  442. /package/dist/web/assets/{zenscript-6s_i5zek.js → zenscript-BxircxDx.js} +0 -0
  443. /package/dist/web/assets/{zig-B2htezJ_.js → zig-DD79WQtz.js} +0 -0
@@ -637,12 +637,15 @@ function parseIdeOpenedFile(text: string): { idePath: string | null; cleanText:
637
637
  /** Parse user message content, extracting attached file paths and the actual text */
638
638
  function parseUserAttachments(content: string): { files: string[]; text: string } {
639
639
  // Match: [Attached file: /path] or [Attached files:\n/path1\n/path2\n]
640
- const singleMatch = content.match(/^\[Attached file: (.+?)\]\n\n?/);
640
+ // Trailing newlines are optional — an attachment-only message has the marker
641
+ // trimmed to the end of the string (extractTerminalBlocks trims), so the
642
+ // separator newlines may be absent.
643
+ const singleMatch = content.match(/^\[Attached file: (.+?)\]\n*/);
641
644
  if (singleMatch) {
642
645
  return { files: [singleMatch[1]!], text: content.slice(singleMatch[0].length) };
643
646
  }
644
647
 
645
- const multiMatch = content.match(/^\[Attached files:\n([\s\S]+?)\]\n\n?/);
648
+ const multiMatch = content.match(/^\[Attached files:\n([\s\S]+?)\]\n*/);
646
649
  if (multiMatch) {
647
650
  const files = multiMatch[1]!.split("\n").map((l) => l.trim()).filter(Boolean);
648
651
  return { files, text: content.slice(multiMatch[0].length) };
@@ -815,7 +818,7 @@ function UserBubble({ content, messageId, timestamp, projectName, onFork, onEdit
815
818
  expanded && "max-h-[50vh] overflow-y-auto",
816
819
  )}
817
820
  >
818
- {isSystemContext ? <TextWithFilePaths text={text} projectName={projectName} /> : text}
821
+ {isSystemContext ? <TextWithFilePaths text={text} projectName={projectName} /> : <TextWithLinks text={text} />}
819
822
  </div>
820
823
  )}
821
824
  {(isOverflowing || expanded) && (
@@ -1002,6 +1005,48 @@ function FilePathChip({ path, projectName }: { path: string; projectName?: strin
1002
1005
  );
1003
1006
  }
1004
1007
 
1008
+ /** Render plain text with http(s) URLs turned into clickable links. Preserves
1009
+ * whitespace/newlines via the surrounding `whitespace-pre-wrap` container. */
1010
+ function TextWithLinks({ text }: { text: string }) {
1011
+ const parts = useMemo(() => {
1012
+ const re = /(https?:\/\/[^\s<>()]+[^\s<>().,;:!?'"])/g;
1013
+ const result: { kind: "text" | "url"; value: string }[] = [];
1014
+ let last = 0;
1015
+ let m;
1016
+ while ((m = re.exec(text)) !== null) {
1017
+ if (m.index > last) result.push({ kind: "text", value: text.slice(last, m.index) });
1018
+ result.push({ kind: "url", value: m[1]! });
1019
+ last = m.index + m[0].length;
1020
+ }
1021
+ if (last < text.length) result.push({ kind: "text", value: text.slice(last) });
1022
+ return result;
1023
+ }, [text]);
1024
+
1025
+ // No URLs — return the raw string so nothing about the layout changes.
1026
+ if (parts.every((p) => p.kind === "text")) return <>{text}</>;
1027
+
1028
+ return (
1029
+ <>
1030
+ {parts.map((p, i) =>
1031
+ p.kind === "url" ? (
1032
+ <a
1033
+ key={i}
1034
+ href={p.value}
1035
+ target="_blank"
1036
+ rel="noopener noreferrer"
1037
+ className="text-primary underline underline-offset-2 hover:text-primary/80 break-all"
1038
+ onClick={(e) => e.stopPropagation()}
1039
+ >
1040
+ {p.value}
1041
+ </a>
1042
+ ) : (
1043
+ <span key={i}>{p.value}</span>
1044
+ ),
1045
+ )}
1046
+ </>
1047
+ );
1048
+ }
1049
+
1005
1050
  /** Render text with absolute file paths detected and turned into clickable chips */
1006
1051
  function TextWithFilePaths({ text, projectName }: { text: string; projectName?: string }) {
1007
1052
  const parts = useMemo(() => {
@@ -0,0 +1,33 @@
1
+ // Pure helpers for the unified model + thinking picker. Kept DOM-free so the
2
+ // label↔value mapping (the crash-prone "Extra"→"xhigh" contract) is unit-testable
3
+ // without a browser harness.
4
+ //
5
+ // SDK effort enum = low | medium | high | xhigh | max. The app UI shows "Extra"
6
+ // for the SDK value "xhigh"; the literal "extra" would crash the CLI subprocess,
7
+ // so it must NEVER appear as a value here.
8
+
9
+ export interface EffortOption {
10
+ label: string;
11
+ value: "low" | "medium" | "high" | "xhigh" | "max";
12
+ default?: boolean;
13
+ }
14
+
15
+ export const EFFORT_OPTIONS: EffortOption[] = [
16
+ { label: "Low", value: "low" },
17
+ { label: "Medium", value: "medium" },
18
+ { label: "High", value: "high", default: true },
19
+ { label: "Extra", value: "xhigh" },
20
+ { label: "Max", value: "max" },
21
+ ];
22
+
23
+ /** UI label for an effort value; falls back to the raw value when unknown. */
24
+ export function effortLabel(value: string | null | undefined): string {
25
+ if (!value) return "";
26
+ return EFFORT_OPTIONS.find((o) => o.value === value)?.label ?? value;
27
+ }
28
+
29
+ /** Chip text: model display, plus " · <Effort>" when an effort is set. */
30
+ export function chipLabel(modelDisplay: string, effortValue: string | null | undefined): string {
31
+ const eff = effortLabel(effortValue);
32
+ return eff ? `${modelDisplay} · ${eff}` : modelDisplay;
33
+ }
@@ -0,0 +1,189 @@
1
+ import { useState, useEffect, useRef, type ReactNode } from "react";
2
+ import { Check, Sparkles, Brain } from "lucide-react";
3
+ import { api, projectUrl } from "@/lib/api-client";
4
+ import { useIsMobile } from "@/hooks/use-is-mobile";
5
+ import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
6
+ import { EFFORT_OPTIONS, chipLabel } from "./model-thinking-selector-helpers";
7
+
8
+ interface ModelOption {
9
+ value: string;
10
+ label: string;
11
+ }
12
+
13
+ interface ModelThinkingSelectorProps {
14
+ model: string | null;
15
+ effort: string | null;
16
+ thinking: boolean;
17
+ onModelChange: (model: string) => void;
18
+ onEffortChange: (effort: string) => void;
19
+ onThinkingChange: (enabled: boolean) => void;
20
+ projectName: string;
21
+ providerId: string;
22
+ /** Locked while a turn is streaming (model/effort can't change mid-turn). */
23
+ disabled?: boolean;
24
+ }
25
+
26
+ /** Strip the leading "Claude " so the chip stays compact: "Claude Opus 5" → "Opus 5" */
27
+ function shortLabel(label: string): string {
28
+ return label.replace(/^Claude\s+/i, "");
29
+ }
30
+
31
+ const DEFAULT_EFFORT = EFFORT_OPTIONS.find((o) => o.default)!.value;
32
+
33
+ /**
34
+ * Unified model + thinking picker — one chip, one popup. Mirrors Anthropic's native
35
+ * picker: model list, effort levels (Extra→SDK "xhigh"), and a thinking on/off toggle.
36
+ * Desktop → absolute popover; mobile (<md) → bottom sheet with 44px targets.
37
+ */
38
+ export function ModelThinkingSelector({
39
+ model,
40
+ effort,
41
+ thinking,
42
+ onModelChange,
43
+ onEffortChange,
44
+ onThinkingChange,
45
+ projectName,
46
+ providerId,
47
+ disabled,
48
+ }: ModelThinkingSelectorProps) {
49
+ const [models, setModels] = useState<ModelOption[]>([]);
50
+ const [open, setOpen] = useState(false);
51
+ const panelRef = useRef<HTMLDivElement>(null);
52
+ const isMobile = useIsMobile();
53
+
54
+ useEffect(() => {
55
+ if (!projectName || !providerId) return;
56
+ api
57
+ .get<ModelOption[]>(`${projectUrl(projectName)}/chat/providers/${providerId}/models`)
58
+ .then(setModels)
59
+ .catch(() => {});
60
+ }, [projectName, providerId]);
61
+
62
+ useEffect(() => {
63
+ if (disabled) setOpen(false);
64
+ }, [disabled]);
65
+
66
+ // Desktop popover: close on click outside (mobile bottom sheet handles its own backdrop).
67
+ useEffect(() => {
68
+ if (!open || isMobile) return;
69
+ const handler = (e: MouseEvent) => {
70
+ if (panelRef.current && !panelRef.current.contains(e.target as Node)) setOpen(false);
71
+ };
72
+ document.addEventListener("mousedown", handler);
73
+ return () => document.removeEventListener("mousedown", handler);
74
+ }, [open, isMobile]);
75
+
76
+ const current = models.find((m) => m.value === model);
77
+ const modelDisplay = current ? shortLabel(current.label) : model ? shortLabel(model) : "Model";
78
+ const effortValue = effort ?? DEFAULT_EFFORT;
79
+ const showModelList = models.length > 1;
80
+ const chipText = chipLabel(modelDisplay, effortValue);
81
+
82
+ const pick = (fn: () => void) => {
83
+ fn();
84
+ if (!isMobile) setOpen(false);
85
+ };
86
+
87
+ const content = (
88
+ <div className="flex divide-x divide-border">
89
+ {/* Left column: model list */}
90
+ {showModelList && (
91
+ <div className="flex-1 min-w-0 py-1">
92
+ <SectionLabel>Model</SectionLabel>
93
+ {models.map((m) => (
94
+ <OptionRow key={m.value} active={m.value === model} onClick={() => pick(() => onModelChange(m.value))}>
95
+ <span className="flex-1 truncate">{shortLabel(m.label)}</span>
96
+ {m.value === model && <Check className="size-4 shrink-0 text-primary" />}
97
+ </OptionRow>
98
+ ))}
99
+ </div>
100
+ )}
101
+ {/* Right column: effort + thinking toggle */}
102
+ <div className="flex-1 min-w-0 py-1">
103
+ <SectionLabel>Effort</SectionLabel>
104
+ {EFFORT_OPTIONS.map((o) => (
105
+ <OptionRow key={o.value} active={o.value === effortValue} onClick={() => pick(() => onEffortChange(o.value))}>
106
+ <span className="flex-1 truncate">
107
+ {o.label}
108
+ {o.default && <span className="ml-2 text-xs text-text-subtle">Default</span>}
109
+ </span>
110
+ {o.value === effortValue && <Check className="size-4 shrink-0 text-primary" />}
111
+ </OptionRow>
112
+ ))}
113
+ <Separator />
114
+ <button
115
+ type="button"
116
+ onClick={() => onThinkingChange(!thinking)}
117
+ className="w-full flex items-center gap-3 px-3 min-h-[44px] text-left text-sm hover:bg-surface-elevated"
118
+ role="switch"
119
+ aria-checked={thinking}
120
+ >
121
+ <Brain className="size-4 shrink-0" />
122
+ <span className="flex-1">Thinking</span>
123
+ <span className={`inline-flex h-5 w-9 items-center rounded-full transition-colors ${thinking ? "bg-primary" : "bg-border"}`}>
124
+ <span className={`h-4 w-4 rounded-full bg-white transition-transform ${thinking ? "translate-x-4" : "translate-x-0.5"}`} />
125
+ </span>
126
+ </button>
127
+ </div>
128
+ </div>
129
+ );
130
+
131
+ return (
132
+ <div className="relative">
133
+ <button
134
+ type="button"
135
+ disabled={disabled}
136
+ onClick={(e) => {
137
+ e.stopPropagation();
138
+ if (!disabled) setOpen((v) => !v);
139
+ }}
140
+ className="inline-flex items-center gap-1.5 px-[9px] py-1 rounded-full text-[11.5px] text-primary bg-accent-wash border border-accent-wash-border hover:brightness-110 transition-[filter] disabled:opacity-50 disabled:cursor-default"
141
+ aria-label={`Model ${modelDisplay}, effort ${effortValue}${thinking ? ", thinking on" : ""}`}
142
+ title={disabled ? "Can't change while running" : chipText}
143
+ >
144
+ <Sparkles className="h-3.5 w-3.5 shrink-0" />
145
+ <span className="max-w-[140px] truncate">{chipText}</span>
146
+ {thinking && <Brain className="h-3 w-3 shrink-0" />}
147
+ </button>
148
+
149
+ {open && !disabled && (
150
+ isMobile ? (
151
+ <BottomSheet open={open} onClose={() => setOpen(false)}>
152
+ <div className="px-1 pb-2">{content}</div>
153
+ </BottomSheet>
154
+ ) : (
155
+ <div
156
+ ref={panelRef}
157
+ role="listbox"
158
+ aria-label="Model and thinking"
159
+ onMouseDown={(e) => e.stopPropagation()}
160
+ onClick={(e) => e.stopPropagation()}
161
+ className="absolute bottom-full left-0 mb-1 z-50 w-80 rounded-lg border border-border popover-solid shadow-[var(--shadow-panel)] max-h-[70vh] overflow-y-auto"
162
+ >
163
+ {content}
164
+ </div>
165
+ )
166
+ )}
167
+ </div>
168
+ );
169
+ }
170
+
171
+ function SectionLabel({ children }: { children: ReactNode }) {
172
+ return <div className="px-3 py-1.5 text-xs font-medium text-text-secondary">{children}</div>;
173
+ }
174
+
175
+ function Separator() {
176
+ return <div className="my-1 border-t border-border" />;
177
+ }
178
+
179
+ function OptionRow({ active, onClick, children }: { active: boolean; onClick: () => void; children: ReactNode }) {
180
+ return (
181
+ <button
182
+ type="button"
183
+ onClick={onClick}
184
+ className={`w-full flex items-center gap-3 px-3 min-h-[44px] text-left text-sm text-text-primary transition-colors hover:bg-surface-elevated ${active ? "bg-surface-elevated" : ""}`}
185
+ >
186
+ {children}
187
+ </button>
188
+ );
189
+ }
@@ -5,11 +5,14 @@ import { useProjectStore } from "@/stores/project-store";
5
5
  import { useIsMobile } from "@/hooks/use-is-mobile";
6
6
  import { useGroupChat } from "@/hooks/use-group-chat";
7
7
  import { Button } from "@/components/ui/button";
8
+ import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
8
9
  import { cn } from "@/lib/utils";
9
10
  import { GroupMessageItem } from "./group-message-item";
10
11
  import { GroupMemberRoster } from "./group-member-roster";
12
+ import { GroupMemberEditDialog, type MemberFormValues } from "./group-member-edit-dialog";
11
13
  import { GroupFullTranscriptView } from "./group-full-transcript-view";
12
- import type { GroupMessage } from "../../../types/group-chat";
14
+ import { getGroup, addGroupMember, updateGroupMember, removeGroupMember, updateGroupSettings } from "@/lib/api-group-chat";
15
+ import type { GroupMessage, GroupMember } from "../../../types/group-chat";
13
16
 
14
17
  interface GroupChatTabProps {
15
18
  metadata?: Record<string, unknown>;
@@ -31,20 +34,64 @@ export function GroupChatTab({ metadata }: GroupChatTabProps) {
31
34
  const [rosterOpen, setRosterOpen] = useState(false);
32
35
  const feedEndRef = useRef<HTMLDivElement>(null);
33
36
 
37
+ // Full roster (with persona/model) for management — the WS `members` only carry
38
+ // live status/color, so we fetch the editable detail separately and refetch on change.
39
+ const [roster, setRoster] = useState<GroupMember[]>([]);
40
+ const [cap, setCap] = useState<number | null>(null); // per-group reply-burst cap
41
+ const [rosterBusy, setRosterBusy] = useState(false);
42
+ const [rosterError, setRosterError] = useState<string | null>(null);
43
+ // `null` = dialog closed; `{ member: null }` = add; `{ member }` = edit.
44
+ const [editing, setEditing] = useState<{ member: GroupMember | null } | null>(null);
45
+
46
+ const reloadRoster = useCallback(async () => {
47
+ if (!groupId) return;
48
+ try { const g = await getGroup(groupId); setRoster(g.members); setCap(g.maxTurns); } catch { /* keep last */ }
49
+ }, [groupId]);
50
+
51
+ const handleCapChange = useCallback(async (n: number) => {
52
+ if (!groupId) return;
53
+ const clamped = Math.max(1, Math.min(50, Math.floor(n) || 1));
54
+ setCap(clamped);
55
+ try { await updateGroupSettings(groupId, { maxTurns: clamped }); }
56
+ catch { void reloadRoster(); }
57
+ }, [groupId, reloadRoster]);
58
+
59
+ useEffect(() => { setRoster([]); void reloadRoster(); }, [groupId, reloadRoster]);
60
+
34
61
  // Stick to bottom on new messages.
35
62
  useEffect(() => {
36
63
  feedEndRef.current?.scrollIntoView({ block: "end" });
37
64
  }, [messages.length, typing]);
38
65
 
66
+ // memberId → live status from the running burst (overlays the fetched roster).
67
+ const liveStatus = useMemo(() => new Map(members.map((m) => [m.id, m.status] as const)), [members]);
68
+
69
+ // Prefer the fetched roster (fresh after edits); fall back to WS members before load.
70
+ const metaSource = roster.length ? roster : members;
39
71
  const colorFor = useMemo(() => {
40
- const map = new Map(members.map((m) => [m.name, m.color]));
72
+ const map = new Map(metaSource.map((m) => [m.name, m.color]));
41
73
  return (name: string) => map.get(name) ?? null;
42
- }, [members]);
74
+ }, [metaSource]);
43
75
 
44
76
  const isLeader = useMemo(() => {
45
- const leaders = new Set(members.filter((m) => m.role === "leader").map((m) => m.name));
77
+ const leaders = new Set(metaSource.filter((m) => m.role === "leader").map((m) => m.name));
46
78
  return (name: string) => leaders.has(name);
47
- }, [members]);
79
+ }, [metaSource]);
80
+
81
+ const handleSubmitMember = useCallback(async (values: MemberFormValues) => {
82
+ if (!groupId) return;
83
+ if (editing?.member) await updateGroupMember(groupId, editing.member.id, values);
84
+ else await addGroupMember(groupId, values);
85
+ await reloadRoster();
86
+ }, [groupId, editing, reloadRoster]);
87
+
88
+ const handleRemoveMember = useCallback(async (m: GroupMember) => {
89
+ if (!groupId) return;
90
+ setRosterBusy(true); setRosterError(null);
91
+ try { await removeGroupMember(groupId, m.id); await reloadRoster(); }
92
+ catch (e) { setRosterError(e instanceof Error ? e.message : "Failed to remove member"); }
93
+ finally { setRosterBusy(false); }
94
+ }, [groupId, reloadRoster]);
48
95
 
49
96
  const handleSend = useCallback(() => {
50
97
  const content = draft.trim();
@@ -156,17 +203,65 @@ export function GroupChatTab({ metadata }: GroupChatTabProps) {
156
203
  </div>
157
204
  </div>
158
205
 
159
- {/* Roster — sidebar on desktop, drawer toggle on mobile */}
160
- {rosterOpen && (
161
- <div className={cn(
162
- "shrink-0 border-l border-border bg-panel",
163
- isMobile ? "absolute inset-y-0 right-0 z-20 w-64 shadow-xl" : "w-60",
164
- )}>
165
- <div className="flex h-11 items-center border-b border-border px-3 text-sm font-medium text-foreground">
206
+ {/* Roster — inline sidebar on desktop; bottom sheet on mobile (tap backdrop
207
+ or swipe down to dismiss, since the header toggle sits under an overlay). */}
208
+ {isMobile ? (
209
+ <BottomSheet open={rosterOpen} onClose={() => setRosterOpen(false)} className="flex max-h-[72vh] flex-col">
210
+ <div className="flex h-11 shrink-0 items-center px-4 text-sm font-medium text-foreground">
166
211
  Members
167
212
  </div>
168
- <GroupMemberRoster members={members} typing={typing} />
169
- </div>
213
+ <div className="min-h-0 overflow-y-auto">
214
+ {cap !== null && (
215
+ <label className="flex items-center gap-2 px-4 py-2 text-xs text-text-secondary">
216
+ <span>Reply cap</span>
217
+ <input type="number" min={1} max={50} value={cap}
218
+ onChange={(e) => handleCapChange(Number(e.target.value))}
219
+ className="w-14 rounded border border-border bg-background px-1.5 py-1 text-xs text-foreground" />
220
+ <span className="text-text-subtle">turns/msg</span>
221
+ </label>
222
+ )}
223
+ {rosterError && <p className="px-3 py-1 text-xs text-destructive">{rosterError}</p>}
224
+ <GroupMemberRoster
225
+ members={roster} liveStatus={liveStatus} typing={typing} busy={rosterBusy}
226
+ onAdd={() => setEditing({ member: null })} onEdit={(m) => setEditing({ member: m })} onRemove={handleRemoveMember}
227
+ />
228
+ </div>
229
+ </BottomSheet>
230
+ ) : (
231
+ rosterOpen && (
232
+ <div className="flex w-60 shrink-0 flex-col border-l border-border bg-panel">
233
+ <div className="flex h-11 shrink-0 items-center border-b border-border px-3 text-sm font-medium text-foreground">
234
+ Members
235
+ </div>
236
+ <div className="min-h-0 flex-1 overflow-y-auto">
237
+ {cap !== null && (
238
+ <label className="flex items-center gap-2 px-3 py-2 text-xs text-text-secondary">
239
+ <span>Reply cap</span>
240
+ <input type="number" min={1} max={50} value={cap}
241
+ onChange={(e) => handleCapChange(Number(e.target.value))}
242
+ className="w-14 rounded border border-border bg-background px-1.5 py-1 text-xs text-foreground" />
243
+ <span className="text-text-subtle">turns/msg</span>
244
+ </label>
245
+ )}
246
+ {rosterError && <p className="px-3 py-1 text-xs text-destructive">{rosterError}</p>}
247
+ <GroupMemberRoster
248
+ members={roster} liveStatus={liveStatus} typing={typing} busy={rosterBusy}
249
+ onAdd={() => setEditing({ member: null })} onEdit={(m) => setEditing({ member: m })} onRemove={handleRemoveMember}
250
+ />
251
+ </div>
252
+ </div>
253
+ )
254
+ )}
255
+
256
+ {editing && (
257
+ <GroupMemberEditDialog
258
+ key={editing.member?.id ?? "add"}
259
+ open
260
+ member={editing.member}
261
+ projectName={projectName}
262
+ onSubmit={handleSubmitMember}
263
+ onClose={() => setEditing(null)}
264
+ />
170
265
  )}
171
266
 
172
267
  <GroupFullTranscriptView groupId={groupId} message={transcriptMsg} onClose={() => setTranscriptMsg(null)} />
@@ -35,6 +35,7 @@ export function GroupCreateDialog({
35
35
  }: GroupCreateDialogProps) {
36
36
  const isMobile = useIsMobile();
37
37
  const [name, setName] = useState("");
38
+ const [cap, setCap] = useState(10); // reply-burst cap (max AI turns per message)
38
39
  const [leaderName, setLeaderName] = useState("Leader");
39
40
  const [leaderPersona, setLeaderPersona] = useState("");
40
41
  const [leaderModel, setLeaderModel] = useState<string | null>(null);
@@ -43,7 +44,7 @@ export function GroupCreateDialog({
43
44
  const [error, setError] = useState<string | null>(null);
44
45
 
45
46
  const reset = useCallback(() => {
46
- setName(""); setLeaderName("Leader"); setLeaderPersona(""); setLeaderModel(null);
47
+ setName(""); setCap(10); setLeaderName("Leader"); setLeaderPersona(""); setLeaderModel(null);
47
48
  setMembers([newMember()]); setError(null); setSubmitting(false);
48
49
  }, []);
49
50
 
@@ -79,14 +80,14 @@ export function GroupCreateDialog({
79
80
  setSubmitting(true);
80
81
  setError(null);
81
82
  try {
82
- const group = await createGroup({ projectName, projectPath, name: gName, members: roster });
83
+ const group = await createGroup({ projectName, projectPath, name: gName, maxTurns: cap, members: roster });
83
84
  onCreated(group);
84
85
  close();
85
86
  } catch (e) {
86
87
  setError(e instanceof Error ? e.message : "Failed to create group");
87
88
  setSubmitting(false);
88
89
  }
89
- }, [name, leaderName, leaderPersona, leaderModel, members, projectName, projectPath, onCreated, close]);
90
+ }, [name, cap, leaderName, leaderPersona, leaderModel, members, projectName, projectPath, onCreated, close]);
90
91
 
91
92
  const inputCls =
92
93
  "w-full min-h-[40px] rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-text-subtle focus:outline-none focus:ring-1 focus:ring-primary";
@@ -99,6 +100,12 @@ export function GroupCreateDialog({
99
100
  placeholder="e.g. Design Review" autoFocus />
100
101
  </div>
101
102
 
103
+ <div>
104
+ <label className="mb-1 block text-xs font-medium text-text-secondary">Reply cap (max AI turns per message, 1–50)</label>
105
+ <input type="number" min={1} max={50} className={inputCls} value={cap}
106
+ onChange={(e) => setCap(Math.max(1, Math.min(50, Number(e.target.value) || 1)))} />
107
+ </div>
108
+
102
109
  <div className="rounded-lg border border-border p-3">
103
110
  <p className="mb-2 text-xs font-semibold uppercase tracking-wide text-primary">Leader</p>
104
111
  <div className="flex flex-col gap-2">
@@ -3,7 +3,8 @@ import { Loader2 } from "lucide-react";
3
3
  import { useIsMobile } from "@/hooks/use-is-mobile";
4
4
  import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
5
5
  import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
6
- import { getTranscript } from "@/lib/api-group-chat";
6
+ import { getTranscript, type TranscriptResult } from "@/lib/api-group-chat";
7
+ import { GroupTranscriptMessages } from "./group-transcript-messages";
7
8
  import type { GroupMessage } from "../../../types/group-chat";
8
9
 
9
10
  interface GroupFullTranscriptViewProps {
@@ -16,7 +17,7 @@ interface GroupFullTranscriptViewProps {
16
17
  * Adaptive: centered dialog on desktop, bottom sheet on mobile. */
17
18
  export function GroupFullTranscriptView({ groupId, message, onClose }: GroupFullTranscriptViewProps) {
18
19
  const isMobile = useIsMobile();
19
- const [content, setContent] = useState<string | null>(null);
20
+ const [data, setData] = useState<TranscriptResult | null>(null);
20
21
  const [loading, setLoading] = useState(false);
21
22
  const [error, setError] = useState<string | null>(null);
22
23
 
@@ -25,11 +26,11 @@ export function GroupFullTranscriptView({ groupId, message, onClose }: GroupFull
25
26
  useEffect(() => {
26
27
  if (!message || !sessionRef) return;
27
28
  let cancelled = false;
28
- setContent(null);
29
+ setData(null);
29
30
  setError(null);
30
31
  setLoading(true);
31
32
  getTranscript(groupId, sessionRef)
32
- .then((res) => { if (!cancelled) setContent(res.content); })
33
+ .then((res) => { if (!cancelled) setData(res); })
33
34
  .catch((e) => { if (!cancelled) setError(e instanceof Error ? e.message : "Failed to load transcript"); })
34
35
  .finally(() => { if (!cancelled) setLoading(false); });
35
36
  return () => { cancelled = true; };
@@ -55,10 +56,10 @@ export function GroupFullTranscriptView({ groupId, message, onClose }: GroupFull
55
56
  )}
56
57
  </div>
57
58
  )}
58
- {!loading && !error && content != null && (
59
- <pre className="whitespace-pre-wrap break-words rounded-md bg-surface-elevated p-3 text-xs leading-relaxed text-text-secondary">
60
- {content}
61
- </pre>
59
+ {!loading && !error && data != null && (
60
+ <div className="px-1 py-1">
61
+ <GroupTranscriptMessages messages={data.messages} config={data.config} />
62
+ </div>
62
63
  )}
63
64
  </div>
64
65
  );
@@ -0,0 +1,108 @@
1
+ import { useState, useCallback } from "react";
2
+ import { Loader2 } from "lucide-react";
3
+ import { useIsMobile } from "@/hooks/use-is-mobile";
4
+ import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
5
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
6
+ import { Button } from "@/components/ui/button";
7
+ import { ModelSelector } from "@/components/chat/model-selector";
8
+ import type { GroupMember, MemberRole } from "../../../types/group-chat";
9
+
10
+ export interface MemberFormValues {
11
+ name: string;
12
+ persona: string | null;
13
+ model: string | null;
14
+ role: MemberRole;
15
+ }
16
+
17
+ interface Props {
18
+ open: boolean;
19
+ /** Editing an existing member, or null when adding a new one. */
20
+ member: GroupMember | null;
21
+ projectName: string;
22
+ providerId?: string;
23
+ onSubmit: (values: MemberFormValues) => Promise<void>;
24
+ onClose: () => void;
25
+ }
26
+
27
+ const inputCls =
28
+ "w-full min-h-[40px] rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground placeholder:text-text-subtle focus:outline-none focus:ring-1 focus:ring-primary";
29
+
30
+ export function GroupMemberEditDialog({ open, member, projectName, providerId = "claude", onSubmit, onClose }: Props) {
31
+ const isMobile = useIsMobile();
32
+ const [name, setName] = useState(member?.name ?? "");
33
+ const [persona, setPersona] = useState(member?.persona ?? "");
34
+ const [model, setModel] = useState<string | null>(member?.model ?? null);
35
+ const [isLeader, setIsLeader] = useState(member?.role === "leader");
36
+ const [submitting, setSubmitting] = useState(false);
37
+ const [error, setError] = useState<string | null>(null);
38
+
39
+ const handleSubmit = useCallback(async () => {
40
+ const n = name.trim();
41
+ if (!n) { setError("Name is required"); return; }
42
+ setSubmitting(true);
43
+ setError(null);
44
+ try {
45
+ await onSubmit({ name: n, persona: persona.trim() || null, model, role: isLeader ? "leader" : "member" });
46
+ onClose();
47
+ } catch (e) {
48
+ setError(e instanceof Error ? e.message : "Failed to save member");
49
+ setSubmitting(false);
50
+ }
51
+ }, [name, persona, model, isLeader, onSubmit, onClose]);
52
+
53
+ const alreadyLeader = member?.role === "leader";
54
+
55
+ const form = (
56
+ <div className="flex flex-col gap-3 px-1 py-1">
57
+ <input className={inputCls} value={name} onChange={(e) => setName(e.target.value)} placeholder="Member name" autoFocus />
58
+ <input className={inputCls} value={persona} onChange={(e) => setPersona(e.target.value)} placeholder="Persona (optional)" />
59
+ <ModelSelector value={model} onChange={setModel} projectName={projectName} providerId={providerId} />
60
+ <label className={cnLeader(alreadyLeader)}>
61
+ <input
62
+ type="checkbox"
63
+ className="size-4 accent-[var(--color-primary)]"
64
+ checked={isLeader}
65
+ disabled={alreadyLeader}
66
+ onChange={(e) => setIsLeader(e.target.checked)}
67
+ />
68
+ <span>{alreadyLeader ? "Leader (reassign from another member)" : "Set as leader"}</span>
69
+ </label>
70
+ {error && <p className="text-xs text-destructive">{error}</p>}
71
+ <div className="flex justify-end gap-2 pt-1">
72
+ <Button variant="outline" onClick={onClose} disabled={submitting}>Cancel</Button>
73
+ <Button onClick={handleSubmit} disabled={submitting}>
74
+ {submitting && <Loader2 className="mr-1.5 size-4 animate-spin" />}
75
+ {member ? "Save" : "Add member"}
76
+ </Button>
77
+ </div>
78
+ </div>
79
+ );
80
+
81
+ if (!open) return null;
82
+ const title = member ? "Edit member" : "Add member";
83
+
84
+ if (isMobile) {
85
+ return (
86
+ <BottomSheet open onClose={onClose} className="flex max-h-[90vh] flex-col">
87
+ <div className="flex min-h-0 flex-col px-4 pb-2">
88
+ <h2 className="mb-2 text-base font-semibold text-foreground">{title}</h2>
89
+ {form}
90
+ </div>
91
+ </BottomSheet>
92
+ );
93
+ }
94
+
95
+ return (
96
+ <Dialog open onOpenChange={(o) => { if (!o) onClose(); }}>
97
+ <DialogContent className="flex flex-col sm:max-w-md">
98
+ <DialogHeader><DialogTitle>{title}</DialogTitle></DialogHeader>
99
+ {form}
100
+ </DialogContent>
101
+ </Dialog>
102
+ );
103
+ }
104
+
105
+ /** Label styling for the leader checkbox row (dimmed when already leader). */
106
+ function cnLeader(disabled: boolean): string {
107
+ return `flex items-center gap-2 text-sm text-text-secondary ${disabled ? "opacity-60" : ""}`;
108
+ }