@hienlh/ppm 0.17.16 → 0.17.18

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