@hienlh/ppm 0.18.2 → 0.18.4

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 (517) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/CLAUDE.md +1 -0
  3. package/assets/skills/ppm/SKILL.md +1 -1
  4. package/assets/skills/ppm/references/http-api.md +6 -1
  5. package/dist/web/assets/{ai-resource-editor-B6CODu6u.js → ai-resource-editor-Bb-NNlp1.js} +1 -1
  6. package/dist/web/assets/{angular-html-C-Kjr43S.js → angular-html-jfMqUuRd.js} +1 -1
  7. package/dist/web/assets/{angular-ts-CaDDbZqm.js → angular-ts-wytn9PMm.js} +1 -1
  8. package/dist/web/assets/api-client-CzABTreM.js +1 -0
  9. package/dist/web/assets/{api-settings-CAhcNpj5.js → api-settings-DfNRPr1q.js} +1 -1
  10. package/dist/web/assets/api-settings-DlcoR5QT.js +1 -0
  11. package/dist/web/assets/{api-themes-CAjg_Bt9.js → api-themes-CEyYK7AK.js} +1 -1
  12. package/dist/web/assets/{apl-B1WsQFAb.js → apl-i-ahKx6O.js} +1 -1
  13. package/dist/web/assets/architecture-PBZL5I3N-Bs7wzj-W.js +1 -0
  14. package/dist/web/assets/arrow-right-DubGFkN8.js +1 -0
  15. package/dist/web/assets/{astro-Bdnz7nVp.js → astro-DVBCJfG6.js} +1 -1
  16. package/dist/web/assets/audio-preview-DG2Tw0cO.js +1 -0
  17. package/dist/web/assets/{blade-B2euh8sS.js → blade-BHlL8SqU.js} +1 -1
  18. package/dist/web/assets/{bsl-GNeMaxd0.js → bsl-D-UOfR1F.js} +1 -1
  19. package/dist/web/assets/button-B4MWPjWj.js +1 -0
  20. package/dist/web/assets/{cairo-D7G0W7-s.js → cairo-Bn6rucli.js} +1 -1
  21. package/dist/web/assets/chat-tab-CgAv-crh.js +15 -0
  22. package/dist/web/assets/{cobol-Q6YgysnI.js → cobol-Byn9FYKu.js} +1 -1
  23. package/dist/web/assets/code-editor-bX4jlgMy.js +10 -0
  24. package/dist/web/assets/{coffee-BjufWxVc.js → coffee-DjBl4gm-.js} +1 -1
  25. package/dist/web/assets/{conflict-editor-DnSltcyC.js → conflict-editor-B6hVffX3.js} +3 -3
  26. package/dist/web/assets/{context-menu-q-RHHAWz.js → context-menu-DkQdt6YA.js} +1 -1
  27. package/dist/web/assets/{cpp-CqWU0gCR.js → cpp-CKzic-3E.js} +1 -1
  28. package/dist/web/assets/{crystal-ylayVajF.js → crystal-Bkg-Ly_g.js} +1 -1
  29. package/dist/web/assets/{csv-preview-DnaFdgOB.js → csv-preview-hL4Z9HS5.js} +1 -1
  30. package/dist/web/assets/{data-grid-overlay-editor-BzPfsCfd.js → data-grid-overlay-editor-B1mTl3KS.js} +1 -1
  31. package/dist/web/assets/{database-viewer-C7uLy8Z1.js → database-viewer-CTK5kMaA.js} +1 -1
  32. package/dist/web/assets/diff-viewer-DZxnANY4.js +4 -0
  33. package/dist/web/assets/{docx-preview-Dd2nTW2v.js → docx-preview-CrAc7Qjv.js} +1 -1
  34. package/dist/web/assets/download-D9UYwY0-.js +1 -0
  35. package/dist/web/assets/{edge-DX4NxQfh.js → edge-DVbZnd3Y.js} +1 -1
  36. package/dist/web/assets/{edit-diff-preview-DfX-9om9.js → edit-diff-preview-HTZPC9VP.js} +1 -1
  37. package/dist/web/assets/{elixir-CSh3NjbV.js → elixir-Dwi8Wu7W.js} +1 -1
  38. package/dist/web/assets/{elm-DBzwFYq9.js → elm-DtIv-HXJ.js} +1 -1
  39. package/dist/web/assets/{erb-yxVOb8aB.js → erb-D3HEDz1x.js} +1 -1
  40. package/dist/web/assets/{erlang-5XIDkYrM.js → erlang-2MjTCzGz.js} +1 -1
  41. package/dist/web/assets/{esm-DO4el2OJ.js → esm-CZ8B8Ba2.js} +1 -1
  42. package/dist/web/assets/explorer-body-DykJXCTw.js +2 -0
  43. package/dist/web/assets/explorer-window-content-NS8Y0v8c.js +1 -0
  44. package/dist/web/assets/{extension-webview-Dk_zyoXZ.js → extension-webview-D6eywKPN.js} +1 -1
  45. package/dist/web/assets/{fortran-fixed-form-D4tE5VWY.js → fortran-fixed-form-BLyAtyPM.js} +1 -1
  46. package/dist/web/assets/{fsharp-By8soj6-.js → fsharp-Bxbn_gbr.js} +1 -1
  47. package/dist/web/assets/{gdresource-DoSwM7Hv.js → gdresource-sFMY4D2Q.js} +1 -1
  48. package/dist/web/assets/{git-commit-_ZiciHIx.js → git-commit-BzB9Lio5.js} +1 -1
  49. package/dist/web/assets/{git-log-panel-BLQSy6rC.js → git-log-panel-DAogZ9QV.js} +1 -1
  50. package/dist/web/assets/{git-rebase-C3Y5N9-s.js → git-rebase-CKSVd848.js} +1 -1
  51. package/dist/web/assets/gitGraph-HDMCJU4V-D7i54kbM.js +1 -0
  52. package/dist/web/assets/glide-data-grid-DxfJRN-r.js +138 -0
  53. package/dist/web/assets/{glimmer-js-BPBTXVlC.js → glimmer-js-BY8aExAJ.js} +1 -1
  54. package/dist/web/assets/{glimmer-ts-BQSZdy_D.js → glimmer-ts-Bak54dBX.js} +1 -1
  55. package/dist/web/assets/{glsl-CbQdxpU-.js → glsl-nR2eaJQe.js} +1 -1
  56. package/dist/web/assets/{graphql-GMlKikpY.js → graphql-CGPPFAU6.js} +1 -1
  57. package/dist/web/assets/group-chat-tab-DkVi6qL2.js +1 -0
  58. package/dist/web/assets/{hack-DyshcLec.js → hack-CXIMX-Ol.js} +1 -1
  59. package/dist/web/assets/{haml-rqCqWzsq.js → haml-tPY-9Pfm.js} +1 -1
  60. package/dist/web/assets/{handlebars-BCKwSWjR.js → handlebars-BuW1LT7T.js} +1 -1
  61. package/dist/web/assets/{html-Cg29xPR1.js → html-bgVcwZ-t.js} +1 -1
  62. package/dist/web/assets/{html-derivative-geltIVg8.js → html-derivative-D6-IxTgn.js} +1 -1
  63. package/dist/web/assets/{http-pG7Vp237.js → http-CJ1zyB-h.js} +1 -1
  64. package/dist/web/assets/{hurl-Di3Uu_Mc.js → hurl-CmoT7l3T.js} +1 -1
  65. package/dist/web/assets/{hxml-CRy4lbv8.js → hxml-CztOsL8o.js} +1 -1
  66. package/dist/web/assets/{image-preview-KubLSLNO.js → image-preview-Byjx8MoL.js} +1 -1
  67. package/dist/web/assets/index-Bucbpby-.css +2 -0
  68. package/dist/web/assets/index-CcN0TBm4.js +52 -0
  69. package/dist/web/assets/info-3K5VOQVL-BV41AzR9.js +1 -0
  70. package/dist/web/assets/{jinja-C8GyVnvd.js → jinja-B1pq3jJq.js} +1 -1
  71. package/dist/web/assets/{jison-BywnqPn6.js → jison-D8B5pCwA.js} +1 -1
  72. package/dist/web/assets/{julia-DTrO3T3B.js → julia-D0K3bwpU.js} +1 -1
  73. package/dist/web/assets/{just-CA3KSHPi.js → just-B9Jlddu-.js} +1 -1
  74. package/dist/web/assets/keybindings-store-DJIHqbLM.js +1 -0
  75. package/dist/web/assets/{latex-BC5xUMpc.js → latex-BPJSSE6j.js} +1 -1
  76. package/dist/web/assets/{liquid-Chd8tSyQ.js → liquid-lv10fo4U.js} +1 -1
  77. package/dist/web/assets/{lua-DHaEtwLv.js → lua-PNuaIBEF.js} +1 -1
  78. package/dist/web/assets/{markdown-renderer-B4uL6GVA.js → markdown-renderer-CXlEe3ma.js} +3 -3
  79. package/dist/web/assets/markdown-renderer-pYznJDbh.js +1 -0
  80. package/dist/web/assets/{marko-Desx_bC-.js → marko-Du3frD6X.js} +1 -1
  81. package/dist/web/assets/{mdc-DahWHc1t.js → mdc-BeDVcFRl.js} +1 -1
  82. package/dist/web/assets/media-url-C5vA0ha9.js +1 -0
  83. package/dist/web/assets/{mobile-bottom-sheet-BQt45q9T.js → mobile-bottom-sheet-CS3XMwFw.js} +1 -1
  84. package/dist/web/assets/mobile-explorer-sheet-BuqBlP3o.js +1 -0
  85. package/dist/web/assets/{nextflow-3A7lutCA.js → nextflow-DkcXP71s.js} +1 -1
  86. package/dist/web/assets/{nginx-XQda6Hdy.js → nginx-C5n8N_bt.js} +1 -1
  87. package/dist/web/assets/{nim-DHqlpwP1.js → nim-CIhyfs-A.js} +1 -1
  88. package/dist/web/assets/notification-store-Bcl5efY2.js +1 -0
  89. package/dist/web/assets/{number-overlay-editor-DgZtViPO.js → number-overlay-editor-NgOsWJ7x.js} +1 -1
  90. package/dist/web/assets/packet-RMMSAZCW-CaJoP44m.js +1 -0
  91. package/dist/web/assets/{panel-store-s6Qx49RK.js → panel-store-DCD82zc1.js} +1 -1
  92. package/dist/web/assets/{pdf-preview-xZQVUtaV.js → pdf-preview-F2DWVB85.js} +1 -1
  93. package/dist/web/assets/{perl-M-ncjACb.js → perl-Cf31sZYE.js} +1 -1
  94. package/dist/web/assets/{php-CKIajrZi.js → php-Dzl_MDIW.js} +1 -1
  95. package/dist/web/assets/pie-UPGHQEXC-DSGZmNw2.js +1 -0
  96. package/dist/web/assets/plus-DmjC2iRB.js +1 -0
  97. package/dist/web/assets/{postgres-viewer-Ds0FxBel.js → postgres-viewer-KZqPYfOB.js} +3 -3
  98. package/dist/web/assets/{project-store-DyaEpHVG.js → project-store-B8BkHXy5.js} +1 -1
  99. package/dist/web/assets/{pug-DO0u_gO4.js → pug-CxSYHrB3.js} +1 -1
  100. package/dist/web/assets/{qml-UEje1PAA.js → qml-DlEjGhwN.js} +1 -1
  101. package/dist/web/assets/radar-KQ55EAFF-Be4VUTs0.js +1 -0
  102. package/dist/web/assets/{razor-lCs5T1Ib.js → razor-KVt5uW14.js} +1 -1
  103. package/dist/web/assets/{rst-CZX_O0z4.js → rst-D5BwNTnw.js} +1 -1
  104. package/dist/web/assets/{ruby-idycVAyE.js → ruby-D5fejQwd.js} +1 -1
  105. package/dist/web/assets/run-in-terminal-B8TDtaM_.js +1 -0
  106. package/dist/web/assets/{sas-o5gTfUwp.js → sas-Bj7B1CB2.js} +1 -1
  107. package/dist/web/assets/{scss-CRTk3iBQ.js → scss-BB0CUoCL.js} +1 -1
  108. package/dist/web/assets/send-to-chat-CuBAVC8l.js +1 -0
  109. package/dist/web/assets/{settings-store-ChqHdT2V.js → settings-store-CY-4_U3H.js} +2 -2
  110. package/dist/web/assets/settings-tab-Khj-w6Sr.js +1 -0
  111. package/dist/web/assets/{shaderlab-3e5ln8ci.js → shaderlab-BdjEZUMc.js} +1 -1
  112. package/dist/web/assets/{shellsession-CGQjQ75I.js → shellsession-Bp1OA1rR.js} +1 -1
  113. package/dist/web/assets/{soy-CxY0VwX2.js → soy-DlYz3wsC.js} +1 -1
  114. package/dist/web/assets/{sparql-CBAGAFuq.js → sparql-CdfII5Jd.js} +1 -1
  115. package/dist/web/assets/sql-query-editor-Cp0_e2P1.js +1 -0
  116. package/dist/web/assets/{sqlite-viewer-CZYDknNa.js → sqlite-viewer-CIv3sagZ.js} +1 -1
  117. package/dist/web/assets/{stata-BoezhOvk.js → stata-BvUA6GUW.js} +1 -1
  118. package/dist/web/assets/{surrealql-CHEzAhu7.js → surrealql--DLNbTyI.js} +1 -1
  119. package/dist/web/assets/{svelte-y6xtu2zX.js → svelte-CBfSsG4n.js} +1 -1
  120. package/dist/web/assets/system-monitor-tab-CrssTOf4.js +1 -0
  121. package/dist/web/assets/{tab-store-C42sktPo.js → tab-store-DAsvpx4t.js} +1 -1
  122. package/dist/web/assets/team-member-window-content-D-hXax3c.js +1 -0
  123. package/dist/web/assets/{templ-DbG2y5yD.js → templ-Dv8zpKZW.js} +1 -1
  124. package/dist/web/assets/terminal-tab-BIQDG-Ti.js +3 -0
  125. package/dist/web/assets/{tex-CeKQhrQG.js → tex-CsrOiqh1.js} +1 -1
  126. package/dist/web/assets/tool-cards-Dx-Rrpri.js +8 -0
  127. package/dist/web/assets/treemap-KZPCXAKY-Cu2zgbxU.js +1 -0
  128. package/dist/web/assets/{ts-tags-iKKOXJjG.js → ts-tags-3T98k4EJ.js} +1 -1
  129. package/dist/web/assets/{twig-DK8Vrp-G.js → twig-u6QZ45FH.js} +1 -1
  130. package/dist/web/assets/{use-blob-url-DYtOHK7u.js → use-blob-url-BmlYYZ8L.js} +1 -1
  131. package/dist/web/assets/use-is-mobile-B8FA4kQf.js +1 -0
  132. package/dist/web/assets/use-monaco-theme-Djp1_fKi.js +1 -0
  133. package/dist/web/assets/use-websocket-CCYA9-a2.js +1 -0
  134. package/dist/web/assets/{vendor-mermaid-C977xNeE.js → vendor-mermaid-Bg4vE8QA.js} +1 -1
  135. package/dist/web/assets/video-preview-cvjNMjWA.js +1 -0
  136. package/dist/web/assets/{vue-JkIEObMV.js → vue-CxIsxtwn.js} +1 -1
  137. package/dist/web/assets/{vue-html-D8SqnU86.js → vue-html-BGL5qnuH.js} +1 -1
  138. package/dist/web/assets/{vue-vine-DJj7N4WD.js → vue-vine-DHPh_gMr.js} +1 -1
  139. package/dist/web/assets/{xml-C-00w9Rv.js → xml-C-vM2m7J.js} +1 -1
  140. package/dist/web/assets/{xsl-CVdCwPHV.js → xsl-DvTXNwuO.js} +1 -1
  141. package/dist/web/index.html +21 -20
  142. package/dist/web/sw.js +1 -1
  143. package/docs/codebase-summary.md +1 -0
  144. package/package.json +1 -1
  145. package/scripts/dev-quick-tunnel-retry.mjs +51 -0
  146. package/src/providers/claude-agent-sdk.ts +6 -0
  147. package/src/server/helpers/media-route-handlers.ts +66 -0
  148. package/src/server/helpers/range-file-response.ts +86 -0
  149. package/src/server/index.ts +24 -17
  150. package/src/server/middleware/auth.ts +3 -2
  151. package/src/server/routes/files.ts +40 -7
  152. package/src/server/routes/fs-browse.ts +43 -5
  153. package/src/server/routes/fs-upload.ts +32 -0
  154. package/src/server/routes/teams.ts +34 -0
  155. package/src/server/ws/chat.ts +64 -16
  156. package/src/server/ws/team-inbox-watcher.ts +61 -22
  157. package/src/server/ws/terminal.ts +24 -6
  158. package/src/services/fs-ops/fs-ops-upload.service.ts +120 -0
  159. package/src/services/media-transcode/ffmpeg-capabilities.ts +89 -0
  160. package/src/services/media-transcode/media-probe.ts +63 -0
  161. package/src/services/media-transcode/transcode-stream.ts +129 -0
  162. package/src/services/subagent-transcript-merger.ts +1 -1
  163. package/src/services/team-member-activity/member-activity.service.ts +117 -0
  164. package/src/services/team-member-activity/outbound-message-scanner.ts +121 -0
  165. package/src/services/team-member-activity/subagent-transcript-index.ts +95 -0
  166. package/src/services/team-member-activity/transcript-tail-summary.ts +125 -0
  167. package/src/shared/background-agent-status.ts +79 -0
  168. package/src/types/api.ts +1 -0
  169. package/src/types/chat.ts +6 -1
  170. package/src/web/components/chat/chat-history-bar.tsx +4 -2
  171. package/src/web/components/chat/chat-tab.tsx +1 -0
  172. package/src/web/components/chat/message-input.tsx +13 -6
  173. package/src/web/components/chat/mini-markdown.tsx +17 -0
  174. package/src/web/components/chat/send-message-card.tsx +134 -0
  175. package/src/web/components/chat/send-message-parse.ts +159 -0
  176. package/src/web/components/chat/team-activity-panel.tsx +107 -121
  177. package/src/web/components/chat/team-member-activity-row.tsx +92 -0
  178. package/src/web/components/chat/team-member-list.tsx +43 -0
  179. package/src/web/components/chat/team-member-window-content.tsx +97 -0
  180. package/src/web/components/chat/team-message-badges.ts +18 -0
  181. package/src/web/components/chat/team-message-list.tsx +88 -0
  182. package/src/web/components/chat/team-message-preview.ts +87 -0
  183. package/src/web/components/chat/tool-cards.tsx +100 -23
  184. package/src/web/components/editor/audio-preview.tsx +6 -7
  185. package/src/web/components/editor/video-player/use-video-keyboard-shortcuts.ts +62 -0
  186. package/src/web/components/editor/video-player/video-player-controls.tsx +103 -0
  187. package/src/web/components/editor/video-player/video-player.tsx +190 -0
  188. package/src/web/components/editor/video-player/video-settings-menu.tsx +92 -0
  189. package/src/web/components/editor/video-player/video-transform.ts +49 -0
  190. package/src/web/components/editor/video-preview.tsx +75 -14
  191. package/src/web/components/explorer/file-tree.tsx +6 -0
  192. package/src/web/components/explorer/tree-node-context-menu.tsx +5 -1
  193. package/src/web/components/floating-window/window-content-registry.ts +5 -0
  194. package/src/web/components/floating-window/window-store-types.ts +1 -1
  195. package/src/web/components/os-explorer/actions/explorer-actions-upload.ts +96 -0
  196. package/src/web/components/os-explorer/actions/use-explorer-actions.ts +23 -2
  197. package/src/web/components/os-explorer/actions/use-explorer-upload-actions.tsx +41 -0
  198. package/src/web/components/os-explorer/dnd/use-drop-transfer.tsx +10 -1
  199. package/src/web/components/os-explorer/dnd/use-entry-row-dnd.ts +8 -1
  200. package/src/web/components/os-explorer/dnd/use-external-file-drop.ts +84 -0
  201. package/src/web/components/os-explorer/dnd/use-path-drop-target.ts +46 -3
  202. package/src/web/components/os-explorer/explorer-body.tsx +1 -1
  203. package/src/web/components/os-explorer/explorer-context-menu.tsx +10 -0
  204. package/src/web/components/os-explorer/explorer-dialogs.tsx +2 -0
  205. package/src/web/components/os-explorer/explorer-sidebar.tsx +10 -5
  206. package/src/web/components/os-explorer/explorer-toolbar.tsx +32 -2
  207. package/src/web/components/os-explorer/mobile/mobile-bottom-toolbar.tsx +5 -1
  208. package/src/web/components/os-explorer/upload/collect-dropped-entries.ts +81 -0
  209. package/src/web/components/os-explorer/upload/upload-queue.ts +79 -0
  210. package/src/web/components/os-explorer/upload/use-upload-picker.tsx +74 -0
  211. package/src/web/components/os-explorer/views/column-row.tsx +3 -1
  212. package/src/web/components/os-explorer/views/column-view-column.tsx +6 -1
  213. package/src/web/components/os-explorer/views/icons-view-tile.tsx +1 -1
  214. package/src/web/components/os-explorer/views/icons-view.tsx +5 -1
  215. package/src/web/components/os-explorer/views/list-row.tsx +1 -1
  216. package/src/web/components/os-explorer/views/list-view.tsx +5 -1
  217. package/src/web/components/shared/markdown-code-block.tsx +3 -7
  218. package/src/web/components/terminal/terminal-tab.tsx +19 -25
  219. package/src/web/hooks/use-chat.ts +77 -15
  220. package/src/web/hooks/use-team-activity-feed.ts +92 -0
  221. package/src/web/hooks/use-terminal-command-queue.ts +108 -0
  222. package/src/web/hooks/use-terminal.ts +45 -3
  223. package/src/web/lib/fs-api.ts +9 -0
  224. package/src/web/lib/fs-upload-xhr.ts +62 -0
  225. package/src/web/lib/media-url.ts +51 -0
  226. package/src/web/lib/open-terminal-at.ts +22 -0
  227. package/src/web/lib/run-in-terminal.ts +55 -0
  228. package/src/web/lib/send-to-chat.ts +118 -0
  229. package/src/web/lib/ws-auth.ts +13 -0
  230. package/src/web/lib/ws-client.ts +10 -5
  231. package/.release-run.sh +0 -5
  232. package/dist/web/assets/api-client-CaRE4HYh.js +0 -1
  233. package/dist/web/assets/api-settings-DBcXfeJ8.js +0 -1
  234. package/dist/web/assets/architecture-PBZL5I3N-B4J2-O8Q.js +0 -1
  235. package/dist/web/assets/audio-preview-BkNAEqcB.js +0 -1
  236. package/dist/web/assets/chat-tab-B-MEsHYp.js +0 -13
  237. package/dist/web/assets/code-editor-bC1KAEUA.js +0 -10
  238. package/dist/web/assets/dialog-CkI7rwrh.js +0 -1
  239. package/dist/web/assets/diff-viewer-BwElk4q9.js +0 -4
  240. package/dist/web/assets/explorer-body-DzdXBlWw.js +0 -2
  241. package/dist/web/assets/explorer-window-content-Dgl1WTNs.js +0 -1
  242. package/dist/web/assets/gitGraph-HDMCJU4V-CtQ3yXN-.js +0 -1
  243. package/dist/web/assets/glide-data-grid-QZ_fgjIa.js +0 -138
  244. package/dist/web/assets/group-chat-tab-BbdVlKFv.js +0 -1
  245. package/dist/web/assets/index-D-xwjNyX.css +0 -2
  246. package/dist/web/assets/index-wd3FSHHn.js +0 -52
  247. package/dist/web/assets/info-3K5VOQVL-Cg0mIJn9.js +0 -1
  248. package/dist/web/assets/keybindings-store-Bp_c_C3z.js +0 -1
  249. package/dist/web/assets/markdown-renderer-2asl-3Kk.js +0 -1
  250. package/dist/web/assets/mobile-explorer-sheet-LWUDaNBV.js +0 -1
  251. package/dist/web/assets/notification-store-BasUnpt7.js +0 -1
  252. package/dist/web/assets/packet-RMMSAZCW-D79vAFR_.js +0 -1
  253. package/dist/web/assets/pie-UPGHQEXC-DYUOH68U.js +0 -1
  254. package/dist/web/assets/plus-9LatwJMx.js +0 -1
  255. package/dist/web/assets/radar-KQ55EAFF-B1eznNtd.js +0 -1
  256. package/dist/web/assets/settings-tab-vhatQ51-.js +0 -1
  257. package/dist/web/assets/sql-query-editor-BblB2Imt.js +0 -1
  258. package/dist/web/assets/system-monitor-tab-D8dy-RT_.js +0 -1
  259. package/dist/web/assets/terminal-tab-CfD22q5x.js +0 -3
  260. package/dist/web/assets/tool-cards-DNgw1yI6.js +0 -7
  261. package/dist/web/assets/treemap-KZPCXAKY-SeI2TxLs.js +0 -1
  262. package/dist/web/assets/use-is-mobile-DnFSkUG2.js +0 -1
  263. package/dist/web/assets/use-monaco-theme-DEbn-QT3.js +0 -1
  264. package/dist/web/assets/video-preview-DcUaFYyv.js +0 -1
  265. package/src/web/components/chat/team-activity-popover.tsx +0 -202
  266. /package/dist/web/assets/{abap-DrMyiWmK.js → abap-C1K0-wzc.js} +0 -0
  267. /package/dist/web/assets/{actionscript-3-BlSOyi0y.js → actionscript-3-CJhQVjLA.js} +0 -0
  268. /package/dist/web/assets/{ada-B_m96icB.js → ada-Bt8r9fME.js} +0 -0
  269. /package/dist/web/assets/{andromeeda-Ch3vOiZB.js → andromeeda-DF1I8qi3.js} +0 -0
  270. /package/dist/web/assets/{apache-CdsaXc1n.js → apache-CnlleE6P.js} +0 -0
  271. /package/dist/web/assets/{apex-0AnsBevk.js → apex-j0C6Xmk6.js} +0 -0
  272. /package/dist/web/assets/{api-client-rTAGdEKo.js → api-client-BSB14J4w.js} +0 -0
  273. /package/dist/web/assets/{applescript-CSxLolzy.js → applescript-DO7AnO8U.js} +0 -0
  274. /package/dist/web/assets/{apply-theme-CMQXnUAa.js → apply-theme-CNj1iA-v.js} +0 -0
  275. /package/dist/web/assets/{ara-DXZS0jA5.js → ara-i83AydZj.js} +0 -0
  276. /package/dist/web/assets/{asciidoc-DDy3pH2A.js → asciidoc-DbBA6-sF.js} +0 -0
  277. /package/dist/web/assets/{asm-Bd17hhqg.js → asm-B5S47Rgr.js} +0 -0
  278. /package/dist/web/assets/{aurora-x-C62HJRs-.js → aurora-x-De_IaSKw.js} +0 -0
  279. /package/dist/web/assets/{awk-Cc-nazni.js → awk-CfyLHXqS.js} +0 -0
  280. /package/dist/web/assets/{ayu-dark-BsfmNWCU.js → ayu-dark-DTLdZ1Si.js} +0 -0
  281. /package/dist/web/assets/{ayu-light-BZ4HLa4X.js → ayu-light-DTOfkzhu.js} +0 -0
  282. /package/dist/web/assets/{ayu-mirage-Bhyjyiqr.js → ayu-mirage-DsAECCMv.js} +0 -0
  283. /package/dist/web/assets/{ballerina-QiWgir3v.js → ballerina-CumGp9A7.js} +0 -0
  284. /package/dist/web/assets/{bat-DxtlkwN3.js → bat-Ca2SBbYN.js} +0 -0
  285. /package/dist/web/assets/{beancount-Bt21X7M_.js → beancount-CqyXBwwF.js} +0 -0
  286. /package/dist/web/assets/{berry-Cksre7lO.js → berry-yl-kJr_H.js} +0 -0
  287. /package/dist/web/assets/{bibtex-DkakgDlR.js → bibtex-DoFFszjV.js} +0 -0
  288. /package/dist/web/assets/{bicep-8crmcyXU.js → bicep-CWPi4nfK.js} +0 -0
  289. /package/dist/web/assets/{bird2-CewQ2I_Z.js → bird2-DXew-ut0.js} +0 -0
  290. /package/dist/web/assets/{bot-nk1k3ELu.js → bot-CunPuEdW.js} +0 -0
  291. /package/dist/web/assets/{c-C_6zE8Ha.js → c-clbySDvd.js} +0 -0
  292. /package/dist/web/assets/{c3-DLWB9-dp.js → c3-B65jvSM1.js} +0 -0
  293. /package/dist/web/assets/{cadence-D8qYS6pR.js → cadence-Cm8tQTHN.js} +0 -0
  294. /package/dist/web/assets/{can-open-in-ppm-BzVXoV-d.js → can-open-in-ppm-Cu-XYIgu.js} +0 -0
  295. /package/dist/web/assets/{catppuccin-frappe-Bh95lNRy.js → catppuccin-frappe-DLeGslh_.js} +0 -0
  296. /package/dist/web/assets/{catppuccin-latte-C1PlN3G0.js → catppuccin-latte-CR5GeHws.js} +0 -0
  297. /package/dist/web/assets/{catppuccin-macchiato-CldtgdK4.js → catppuccin-macchiato-p-XgjxhP.js} +0 -0
  298. /package/dist/web/assets/{catppuccin-mocha-BiwqxX9A.js → catppuccin-mocha-B8QOAZLl.js} +0 -0
  299. /package/dist/web/assets/{clarity-CGiU22jY.js → clarity-DPulbvKH.js} +0 -0
  300. /package/dist/web/assets/{clojure-COIC3doh.js → clojure-DFuWS20u.js} +0 -0
  301. /package/dist/web/assets/{cmake-DWUEQfHv.js → cmake-DejCqcu4.js} +0 -0
  302. /package/dist/web/assets/{codeowners-BNHiAQea.js → codeowners-BwAyqWIH.js} +0 -0
  303. /package/dist/web/assets/{codeql-BuKaoS0j.js → codeql-DgSwFjqI.js} +0 -0
  304. /package/dist/web/assets/{common-lisp-D5IKbxsd.js → common-lisp-CxIVJCtf.js} +0 -0
  305. /package/dist/web/assets/{coq-BMVS-p94.js → coq-DLSjSnmf.js} +0 -0
  306. /package/dist/web/assets/{csharp-DMlbXbM4.js → csharp-C1HHzXBp.js} +0 -0
  307. /package/dist/web/assets/{css-CjkJC89X.js → css-VXsMY--y.js} +0 -0
  308. /package/dist/web/assets/{csv-DoNVBBf0.js → csv-BEbcJdHz.js} +0 -0
  309. /package/dist/web/assets/{csv-parser-DHvoTjMF.js → csv-parser-r-Nk1oHT.js} +0 -0
  310. /package/dist/web/assets/{cue-DoTRbBg-.js → cue-BkDnFqUD.js} +0 -0
  311. /package/dist/web/assets/{cypher-DVsNdTT3.js → cypher-1cMqojSQ.js} +0 -0
  312. /package/dist/web/assets/{d-EX7BBSrv.js → d-BnYjRXtH.js} +0 -0
  313. /package/dist/web/assets/{dark-plus-P_YTHwlh.js → dark-plus-XfbaH7kZ.js} +0 -0
  314. /package/dist/web/assets/{dart-Do-rgU4S.js → dart-Ca7s-8hK.js} +0 -0
  315. /package/dist/web/assets/{data-grid-types-CUx8cusN.js → data-grid-types-BXwlFMzs.js} +0 -0
  316. /package/dist/web/assets/{dax-DxOieacu.js → dax-CmuOw-mY.js} +0 -0
  317. /package/dist/web/assets/{desktop-CvdV7SBf.js → desktop-C2gJ6Ovb.js} +0 -0
  318. /package/dist/web/assets/{diff-CNOetGen.js → diff-BCEo1Ej7.js} +0 -0
  319. /package/dist/web/assets/{dist-CMfLpPW_.js → dist-CUPbqNnL.js} +0 -0
  320. /package/dist/web/assets/{dist-DduBIVkD.js → dist-DOlBnxFX.js} +0 -0
  321. /package/dist/web/assets/{docker-DAlG4_q-.js → docker-DN2jlyAh.js} +0 -0
  322. /package/dist/web/assets/{dotenv-Dh3qf6yx.js → dotenv-NExMY2kS.js} +0 -0
  323. /package/dist/web/assets/{dracula-baAGmJYG.js → dracula-B9lbE01y.js} +0 -0
  324. /package/dist/web/assets/{dracula-soft-l7ZIyums.js → dracula-soft-CMBBfKF_.js} +0 -0
  325. /package/dist/web/assets/{dream-maker-DeRjdBn8.js → dream-maker-DEyDwFsd.js} +0 -0
  326. /package/dist/web/assets/{emacs-lisp-CB05-jQA.js → emacs-lisp-D_qP2zS6.js} +0 -0
  327. /package/dist/web/assets/{everforest-dark-CT-llQBT.js → everforest-dark-DbHa2U-p.js} +0 -0
  328. /package/dist/web/assets/{everforest-light-ByPJkTT7.js → everforest-light-BISkJchP.js} +0 -0
  329. /package/dist/web/assets/{fennel-CeMarbvn.js → fennel-6B22SfJR.js} +0 -0
  330. /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-a8f3_w7a.js} +0 -0
  331. /package/dist/web/assets/{fish-BYrt6Xtb.js → fish-CubIIvJD.js} +0 -0
  332. /package/dist/web/assets/{fluent-Cr5VcAwh.js → fluent-DF55zQ09.js} +0 -0
  333. /package/dist/web/assets/{fortran-free-form-DQmKtrLa.js → fortran-free-form-DvOu8jAt.js} +0 -0
  334. /package/dist/web/assets/{gdscript-QTDKjzhY.js → gdscript-DCPxdLpq.js} +0 -0
  335. /package/dist/web/assets/{gdshader-Chr-5UYt.js → gdshader-CTZ381FO.js} +0 -0
  336. /package/dist/web/assets/{genie-kWHMWnt0.js → genie-C_QDtvgU.js} +0 -0
  337. /package/dist/web/assets/{gherkin-DtEBQFUo.js → gherkin-BcvK42tF.js} +0 -0
  338. /package/dist/web/assets/{github-dark-B5aiUta2.js → github-dark-C9afs_4w.js} +0 -0
  339. /package/dist/web/assets/{github-dark-default-BkxtsTqR.js → github-dark-default-CKGVrl3Z.js} +0 -0
  340. /package/dist/web/assets/{github-dark-dimmed-B9QjR_0K.js → github-dark-dimmed-C3dQZ_LC.js} +0 -0
  341. /package/dist/web/assets/{github-dark-high-contrast-D6bO-5c0.js → github-dark-high-contrast-DW78QukY.js} +0 -0
  342. /package/dist/web/assets/{github-light-Cg2ZW_CJ.js → github-light-BnP2dznS.js} +0 -0
  343. /package/dist/web/assets/{github-light-default-eD7qUVlQ.js → github-light-default-C2fPZzPG.js} +0 -0
  344. /package/dist/web/assets/{github-light-high-contrast-CFnlSVjd.js → github-light-high-contrast-BzIuUFR2.js} +0 -0
  345. /package/dist/web/assets/{gleam-BpYoOqIT.js → gleam-BpeKwEIO.js} +0 -0
  346. /package/dist/web/assets/{gn-BxwtZPau.js → gn-nUb_Mit0.js} +0 -0
  347. /package/dist/web/assets/{gnuplot-CRyiZDfl.js → gnuplot-D7I0v20p.js} +0 -0
  348. /package/dist/web/assets/{go-Dw1Qx94W.js → go-D7Qqska7.js} +0 -0
  349. /package/dist/web/assets/{groovy-zq_SbWk-.js → groovy-DS-pne5-.js} +0 -0
  350. /package/dist/web/assets/{gruvbox-dark-hard-DbbNy8-Q.js → gruvbox-dark-hard-C0W01fsq.js} +0 -0
  351. /package/dist/web/assets/{gruvbox-dark-medium-BQZ7Kj6C.js → gruvbox-dark-medium-Bqo6fQbg.js} +0 -0
  352. /package/dist/web/assets/{gruvbox-dark-soft-vNavErXi.js → gruvbox-dark-soft-D-XSM_fu.js} +0 -0
  353. /package/dist/web/assets/{gruvbox-light-hard-AOFbCd7i.js → gruvbox-light-hard-IVAwMJRl.js} +0 -0
  354. /package/dist/web/assets/{gruvbox-light-medium-DqtxND6H.js → gruvbox-light-medium-38ATiG7i.js} +0 -0
  355. /package/dist/web/assets/{gruvbox-light-soft-Cg0basu6.js → gruvbox-light-soft-DnZr3c_0.js} +0 -0
  356. /package/dist/web/assets/{haskell-CcsmcOez.js → haskell-uQcywkDH.js} +0 -0
  357. /package/dist/web/assets/{haxe-BimYY9X4.js → haxe-c6bI4_GT.js} +0 -0
  358. /package/dist/web/assets/{hcl-CTrXCK40.js → hcl-CQXTiEXq.js} +0 -0
  359. /package/dist/web/assets/{hjson-CmqqU6Qg.js → hjson-ChETf2bz.js} +0 -0
  360. /package/dist/web/assets/{hlsl-CuJtX_uf.js → hlsl-BMC4JGoE.js} +0 -0
  361. /package/dist/web/assets/{horizon-BGeSjDYJ.js → horizon-BusFlhLW.js} +0 -0
  362. /package/dist/web/assets/{horizon-bright-GYMgd3R0.js → horizon-bright-2oD0Mz7W.js} +0 -0
  363. /package/dist/web/assets/{houston--JD_5r2q.js → houston-DdbbjqFg.js} +0 -0
  364. /package/dist/web/assets/{hy-C9ILOiqk.js → hy-D_SOuqw9.js} +0 -0
  365. /package/dist/web/assets/{image-gallery-BWFpZAAP.js → image-gallery-CrM5fHKy.js} +0 -0
  366. /package/dist/web/assets/{imba-B6F3yus5.js → imba-BxLOHO5I.js} +0 -0
  367. /package/dist/web/assets/{ini-BfkQswMZ.js → ini-ox-CFcg0.js} +0 -0
  368. /package/dist/web/assets/{java-DEH5avQ1.js → java-Bzo8yIal.js} +0 -0
  369. /package/dist/web/assets/{javascript-Dr4yHuV2.js → javascript-DHuz9VXn.js} +0 -0
  370. /package/dist/web/assets/{json-BuR35ewf.js → json-0_y80FD5.js} +0 -0
  371. /package/dist/web/assets/{json5-Ny9ZiJAC.js → json5-CEQ50pGM.js} +0 -0
  372. /package/dist/web/assets/{jsonc-zYVuoZkR.js → jsonc-CfrLEAKA.js} +0 -0
  373. /package/dist/web/assets/{jsonl-B9xthb_H.js → jsonl-fKbrANC2.js} +0 -0
  374. /package/dist/web/assets/{jsonnet-CCoLJbMP.js → jsonnet-DKbkPaQ2.js} +0 -0
  375. /package/dist/web/assets/{jssm-W0GDlQXi.js → jssm-Dxxx1Hqu.js} +0 -0
  376. /package/dist/web/assets/{jsx-BrLJpWC-.js → jsx-DlJL-Oj3.js} +0 -0
  377. /package/dist/web/assets/{kanagawa-dragon-CuVwt_MO.js → kanagawa-dragon-CwN4SV1c.js} +0 -0
  378. /package/dist/web/assets/{kanagawa-lotus-B3W_617P.js → kanagawa-lotus-BHltayiE.js} +0 -0
  379. /package/dist/web/assets/{kanagawa-wave-CEx4MP5W.js → kanagawa-wave-D-KXPjw6.js} +0 -0
  380. /package/dist/web/assets/{kdl-DilRejnB.js → kdl-DvtoJdFo.js} +0 -0
  381. /package/dist/web/assets/{kotlin-Bq5JtKaa.js → kotlin-CTS4MLcx.js} +0 -0
  382. /package/dist/web/assets/{kusto-Bhp2KYog.js → kusto-HtSE_sKm.js} +0 -0
  383. /package/dist/web/assets/{laserwave-WA_7c5hu.js → laserwave-DaXZG9ge.js} +0 -0
  384. /package/dist/web/assets/{lean-AEGcXwS-.js → lean-BYtGUfWx.js} +0 -0
  385. /package/dist/web/assets/{less-NPqH-26u.js → less-BoxmU_Mk.js} +0 -0
  386. /package/dist/web/assets/{lib-BFetOULu.js → lib-BzxL1ARZ.js} +0 -0
  387. /package/dist/web/assets/{libesm-tR4XlhMj.js → libesm-ah-mr-sh.js} +0 -0
  388. /package/dist/web/assets/{light-plus-B4xW7cgY.js → light-plus-Bt5CyUuo.js} +0 -0
  389. /package/dist/web/assets/{llvm-CPyWNcDE.js → llvm-CSdk9q9V.js} +0 -0
  390. /package/dist/web/assets/{log-CeQmiQSz.js → log-B-kp_3CL.js} +0 -0
  391. /package/dist/web/assets/{logo-BO0VrjBm.js → logo-DdIsXFDO.js} +0 -0
  392. /package/dist/web/assets/{luau-B6GT9kA1.js → luau-DUBpLlzQ.js} +0 -0
  393. /package/dist/web/assets/{make-CwfmN7e_.js → make-B3JVjoW_.js} +0 -0
  394. /package/dist/web/assets/{markdown-Bbe4FlLp.js → markdown-Seon0vHs.js} +0 -0
  395. /package/dist/web/assets/{material-theme-iD9XbfsB.js → material-theme-Nq-ChX1P.js} +0 -0
  396. /package/dist/web/assets/{material-theme-darker-u7M3XGe7.js → material-theme-darker-CPV4ayXJ.js} +0 -0
  397. /package/dist/web/assets/{material-theme-lighter-BGdI48zn.js → material-theme-lighter-0kyjYqEd.js} +0 -0
  398. /package/dist/web/assets/{material-theme-ocean-_mk62F5q.js → material-theme-ocean-DGpAp5co.js} +0 -0
  399. /package/dist/web/assets/{material-theme-palenight-CxFbDyAu.js → material-theme-palenight-B0AUn0NG.js} +0 -0
  400. /package/dist/web/assets/{matlab-Z0RUE3V_.js → matlab-C2waytxs.js} +0 -0
  401. /package/dist/web/assets/{mdx-BZ5wPYzV.js → mdx-DAis6R6I.js} +0 -0
  402. /package/dist/web/assets/{mermaid-CY1_aP-h.js → mermaid-_rnT2YGD.js} +0 -0
  403. /package/dist/web/assets/{min-dark-DKWtxOre.js → min-dark-BSSjchUB.js} +0 -0
  404. /package/dist/web/assets/{min-light-e1iwHDfP.js → min-light-DomAFQsa.js} +0 -0
  405. /package/dist/web/assets/{mipsasm-BiDfQ4ir.js → mipsasm-bBgtvPyG.js} +0 -0
  406. /package/dist/web/assets/{mojo-DteFEHsj.js → mojo-Cp9BayW0.js} +0 -0
  407. /package/dist/web/assets/{monokai-BgPbE9xZ.js → monokai-CL_9gbmn.js} +0 -0
  408. /package/dist/web/assets/{moonbit-mEbRp-mA.js → moonbit-BS_fcr-P.js} +0 -0
  409. /package/dist/web/assets/{move-CogqZw7A.js → move-C79AH45U.js} +0 -0
  410. /package/dist/web/assets/{narrat-BD2qjmy1.js → narrat-CJ5s3BDf.js} +0 -0
  411. /package/dist/web/assets/{nextflow-groovy-BNX8GOD_.js → nextflow-groovy-ZHa4JrPJ.js} +0 -0
  412. /package/dist/web/assets/{night-owl-ed3GbziD.js → night-owl-Jkf9zFQK.js} +0 -0
  413. /package/dist/web/assets/{night-owl-light-B0j7O0Wn.js → night-owl-light-DRPeaG5J.js} +0 -0
  414. /package/dist/web/assets/{nix-DFDbcQQm.js → nix-D2Jet9DN.js} +0 -0
  415. /package/dist/web/assets/{nord-D93TxEQi.js → nord-CREVs22j.js} +0 -0
  416. /package/dist/web/assets/{nushell-3_H_XKja.js → nushell-CAiDi_mR.js} +0 -0
  417. /package/dist/web/assets/{objective-c-BM3u6nlm.js → objective-c-CVkmJkC1.js} +0 -0
  418. /package/dist/web/assets/{objective-cpp-DZ73h42g.js → objective-cpp-DIKDO1Ly.js} +0 -0
  419. /package/dist/web/assets/{ocaml-B1PU5gmh.js → ocaml-R9qtGQhs.js} +0 -0
  420. /package/dist/web/assets/{odin-D14L6aRL.js → odin-DTYNQqVr.js} +0 -0
  421. /package/dist/web/assets/{one-dark-pro-Bj-94Z8v.js → one-dark-pro-BSLWUJn5.js} +0 -0
  422. /package/dist/web/assets/{one-light-DTdGWyOZ.js → one-light-DbkRXG3t.js} +0 -0
  423. /package/dist/web/assets/{openscad-Ciq554Sj.js → openscad-BlPcSnmT.js} +0 -0
  424. /package/dist/web/assets/{pascal-Bfd4qdGi.js → pascal-B1Y46ZZB.js} +0 -0
  425. /package/dist/web/assets/{pkl-CTurDUfj.js → pkl-BhJSJbFv.js} +0 -0
  426. /package/dist/web/assets/{plastic-BLQfZXQp.js → plastic-BzxsCTpi.js} +0 -0
  427. /package/dist/web/assets/{plsql-DyYfP9kQ.js → plsql-DBba7dyP.js} +0 -0
  428. /package/dist/web/assets/{po-CgXdT8vQ.js → po-BvgLlnNo.js} +0 -0
  429. /package/dist/web/assets/{poimandres-DOg5fK6s.js → poimandres-DUaI_1JP.js} +0 -0
  430. /package/dist/web/assets/{polar-Dv4aoL6X.js → polar-C7uILwJn.js} +0 -0
  431. /package/dist/web/assets/{postcss-DxugHnJD.js → postcss-BgJlpFdw.js} +0 -0
  432. /package/dist/web/assets/{powerquery-CR3kzRyX.js → powerquery-Dn1MIpZu.js} +0 -0
  433. /package/dist/web/assets/{powershell-BE91xJQB.js → powershell-Bo-DYzOS.js} +0 -0
  434. /package/dist/web/assets/{prisma-B_3yUlRQ.js → prisma-CTLs5IdT.js} +0 -0
  435. /package/dist/web/assets/{prolog-DcT781Ht.js → prolog-QRGun3eG.js} +0 -0
  436. /package/dist/web/assets/{proto-CSf-w5k2.js → proto-B7PI7apn.js} +0 -0
  437. /package/dist/web/assets/{puppet-CLGO6QWl.js → puppet-CBq0tLrP.js} +0 -0
  438. /package/dist/web/assets/{purescript-Bah2McKd.js → purescript-DFewOQb2.js} +0 -0
  439. /package/dist/web/assets/{python-DUH8qy7N.js → python-iWuxKXvT.js} +0 -0
  440. /package/dist/web/assets/{qmldir-YIsHnjKq.js → qmldir-cXiW3AsF.js} +0 -0
  441. /package/dist/web/assets/{qss-CLmoVNA4.js → qss-DASwAbBL.js} +0 -0
  442. /package/dist/web/assets/{r-Pon-b-vz.js → r-TU2eaIPw.js} +0 -0
  443. /package/dist/web/assets/{racket-BA09P5Kg.js → racket-SkRKqrLY.js} +0 -0
  444. /package/dist/web/assets/{raku-DlpzU7Fe.js → raku-D31lthkZ.js} +0 -0
  445. /package/dist/web/assets/{react-w6wINGnd.js → react-I_EwPIZi.js} +0 -0
  446. /package/dist/web/assets/{red-l7VuCR6d.js → red-CTcQZevb.js} +0 -0
  447. /package/dist/web/assets/{reg-g_k7gQEr.js → reg-D8YAsTGf.js} +0 -0
  448. /package/dist/web/assets/{regexp-CT17B7I7.js → regexp-CD2uvAWx.js} +0 -0
  449. /package/dist/web/assets/{rel-DkPCS7Bp.js → rel-CAaI-1fg.js} +0 -0
  450. /package/dist/web/assets/{resolve-theme-DdB7Yo5Z.js → resolve-theme-CJvkL8hU.js} +0 -0
  451. /package/dist/web/assets/{riscv-CYuFTw30.js → riscv-DR-hJVIj.js} +0 -0
  452. /package/dist/web/assets/{ron-cY7u_yEu.js → ron-CuUCJ0n4.js} +0 -0
  453. /package/dist/web/assets/{rose-pine-Cr_h_Ubo.js → rose-pine-aFHxW48i.js} +0 -0
  454. /package/dist/web/assets/{rose-pine-dawn-rRewaSZg.js → rose-pine-dawn-Bqz2sBRY.js} +0 -0
  455. /package/dist/web/assets/{rose-pine-moon-3VX5Xwca.js → rose-pine-moon-wqyh0an4.js} +0 -0
  456. /package/dist/web/assets/{rosmsg-Du4ie5PU.js → rosmsg-CI1ywimO.js} +0 -0
  457. /package/dist/web/assets/{rust-B7xWL-Eh.js → rust-p7Imk4G_.js} +0 -0
  458. /package/dist/web/assets/{sass-oXbOG8de.js → sass-C8JfaqCV.js} +0 -0
  459. /package/dist/web/assets/{save-C4z1p51e.js → save-DRPrDfTt.js} +0 -0
  460. /package/dist/web/assets/{scala-nlZJhKHf.js → scala-DNxCW1By.js} +0 -0
  461. /package/dist/web/assets/{scheme-FZ9_Zy8D.js → scheme-BYuUPJoL.js} +0 -0
  462. /package/dist/web/assets/{sdbl-D_lyvXiu.js → sdbl-DbPeJPUr.js} +0 -0
  463. /package/dist/web/assets/{shellscript-DRWRboAd.js → shellscript-DMiHlR3q.js} +0 -0
  464. /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-8GObuUAn.js} +0 -0
  465. /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-egKAZEwR.js} +0 -0
  466. /package/dist/web/assets/{slack-dark-BGk2uVHu.js → slack-dark-C4xGcQXI.js} +0 -0
  467. /package/dist/web/assets/{slack-ochin-PAoSX041.js → slack-ochin-BzgRt_wm.js} +0 -0
  468. /package/dist/web/assets/{smalltalk-qP0zvICo.js → smalltalk-LDeL9PYH.js} +0 -0
  469. /package/dist/web/assets/{snazzy-light-B7uccpH6.js → snazzy-light-CXE7a5j_.js} +0 -0
  470. /package/dist/web/assets/{solarized-dark-CbICLZs3.js → solarized-dark-DgUhY74x.js} +0 -0
  471. /package/dist/web/assets/{solarized-light-CprWhyjj.js → solarized-light-DD9C-H-9.js} +0 -0
  472. /package/dist/web/assets/{solidity-B7pcm2K6.js → solidity-CAbDB4D4.js} +0 -0
  473. /package/dist/web/assets/{splunk-Co2LL4J_.js → splunk-kQREPfIc.js} +0 -0
  474. /package/dist/web/assets/{sql-cETIdGnT.js → sql-CBzeNAD8.js} +0 -0
  475. /package/dist/web/assets/{ssh-config-DETG6JCD.js → ssh-config-L1euxrsM.js} +0 -0
  476. /package/dist/web/assets/{stylus-tmTre2-O.js → stylus-DvBnYniP.js} +0 -0
  477. /package/dist/web/assets/{swift-BeKQbULV.js → swift-DF5NDQp6.js} +0 -0
  478. /package/dist/web/assets/{synthwave-84-eCL4-Xdn.js → synthwave-84-DbBhB_Hq.js} +0 -0
  479. /package/dist/web/assets/{system-verilog-CviwWvEx.js → system-verilog-D8s2ZW_k.js} +0 -0
  480. /package/dist/web/assets/{systemd-WuoFIbBS.js → systemd-a5-XZJsG.js} +0 -0
  481. /package/dist/web/assets/{table-CHmxuh6M.js → table-BX2ZrJfM.js} +0 -0
  482. /package/dist/web/assets/{talonscript-B9VBu7VI.js → talonscript-BLa0URTW.js} +0 -0
  483. /package/dist/web/assets/{tasl-CN7r11ky.js → tasl-DIoV4XcC.js} +0 -0
  484. /package/dist/web/assets/{tcl-e1cdhe3h.js → tcl-ztYAdXfQ.js} +0 -0
  485. /package/dist/web/assets/{terraform-BEP0mfa_.js → terraform-DvpCCiOZ.js} +0 -0
  486. /package/dist/web/assets/{tokyo-night-BfA_dA37.js → tokyo-night-BkHlYUv0.js} +0 -0
  487. /package/dist/web/assets/{toml-BrDIfNnt.js → toml-acIrxos6.js} +0 -0
  488. /package/dist/web/assets/{tsv-CyfGyE4i.js → tsv-BJB5EVCT.js} +0 -0
  489. /package/dist/web/assets/{tsx-BrFA8Iwf.js → tsx-B1MmXGT3.js} +0 -0
  490. /package/dist/web/assets/{turtle-9GBtR0mP.js → turtle-DFceTiqd.js} +0 -0
  491. /package/dist/web/assets/{typescript-BuTRZ65V.js → typescript-Dz9wU5Y1.js} +0 -0
  492. /package/dist/web/assets/{typespec-CRiNNRXF.js → typespec-CPuYZijj.js} +0 -0
  493. /package/dist/web/assets/{typst-CmpTnnkl.js → typst-CfsCIYv8.js} +0 -0
  494. /package/dist/web/assets/{utils-B9H0d3Fh.js → utils-DoY4yTP-.js} +0 -0
  495. /package/dist/web/assets/{v-DnIi2aab.js → v-CGo0jcXA.js} +0 -0
  496. /package/dist/web/assets/{vala-B7VxCNZP.js → vala-AsSR0hrb.js} +0 -0
  497. /package/dist/web/assets/{vb-DGoQ3pBT.js → vb-C7tvbXv1.js} +0 -0
  498. /package/dist/web/assets/{vendor-xterm-ClRVIJ-k.js → vendor-xterm-BeaIjRrv.js} +0 -0
  499. /package/dist/web/assets/{verilog-zGOC4qwV.js → verilog--a33ND-p.js} +0 -0
  500. /package/dist/web/assets/{vesper-DXR9-06q.js → vesper-B_Z0h4pn.js} +0 -0
  501. /package/dist/web/assets/{vhdl-CCO0oz0l.js → vhdl-CWL5dZPN.js} +0 -0
  502. /package/dist/web/assets/{viml-Dxwr-QNN.js → viml-BglmT14Y.js} +0 -0
  503. /package/dist/web/assets/{vitesse-black-Bhah7RxE.js → vitesse-black-RKFsSqQI.js} +0 -0
  504. /package/dist/web/assets/{vitesse-dark-CGK6XVwc.js → vitesse-dark-D7zDWNmc.js} +0 -0
  505. /package/dist/web/assets/{vitesse-light-ne5kfw8h.js → vitesse-light-MAp87W5b.js} +0 -0
  506. /package/dist/web/assets/{vyper-ErDFqVoP.js → vyper-CgCBYg1G.js} +0 -0
  507. /package/dist/web/assets/{wasm-DtWvUWGr.js → wasm-BOG7ZeTT.js} +0 -0
  508. /package/dist/web/assets/{wasm-Bd258nS1.js → wasm-Bwl4txwp.js} +0 -0
  509. /package/dist/web/assets/{wenyan-EZe1IEYT.js → wenyan-DpShPKXZ.js} +0 -0
  510. /package/dist/web/assets/{wgsl-B1o5_I_9.js → wgsl-BakcCblK.js} +0 -0
  511. /package/dist/web/assets/{wikitext-C_rwp8An.js → wikitext-NroRWVAO.js} +0 -0
  512. /package/dist/web/assets/{wit-gbYtF3rY.js → wit-B5CM2pg6.js} +0 -0
  513. /package/dist/web/assets/{wolfram-DrcQFe2n.js → wolfram-7MTFBJpR.js} +0 -0
  514. /package/dist/web/assets/{x-B1qHmLdR.js → x-BcqfTY_7.js} +0 -0
  515. /package/dist/web/assets/{yaml-CzDAObLX.js → yaml-Bwr01G2K.js} +0 -0
  516. /package/dist/web/assets/{zenscript-B-J1phtg.js → zenscript-Dj8GATvi.js} +0 -0
  517. /package/dist/web/assets/{zig-BlzNia0O.js → zig-LAE-fbS-.js} +0 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Turns an OS `Files` drop (or a picked `FileList`) into a flat list of `{file, relativePath}`
3
+ * pairs, walking nested folders when the browser exposes `webkitGetAsEntry`. Falls back to a
4
+ * flat `dataTransfer.files` list — no relative path beyond the bare name — on a browser that
5
+ * never implemented the entries API.
6
+ */
7
+
8
+ export interface DroppedEntry {
9
+ file: File;
10
+ /** Forward-slash path relative to the drop target, including the file's own name. A flat
11
+ * drop (no folder) is just the bare file name. */
12
+ relativePath: string;
13
+ }
14
+
15
+ /**
16
+ * Reject directory traversal and normalise separators. A dropped folder's real
17
+ * `FileSystemEntry.fullPath` never contains `..`, but a rebuilt/spoofed `DataTransfer` (or a
18
+ * test) might, and this is the one seam every path this module produces passes through.
19
+ * Returns `null` when nothing safe is left (empty, or only `..`/`.` segments).
20
+ */
21
+ export function sanitizeRelativePath(raw: string): string | null {
22
+ const unified = raw.replace(/\\/g, "/").replace(/^\/+/, "");
23
+ const segments = unified.split("/").filter((segment) => segment.length > 0 && segment !== ".");
24
+ if (segments.length === 0 || segments.some((segment) => segment === "..")) return null;
25
+ return segments.join("/");
26
+ }
27
+
28
+ function readEntryAsFile(entry: FileSystemFileEntry): Promise<File> {
29
+ return new Promise((resolve, reject) => entry.file(resolve, reject));
30
+ }
31
+
32
+ /** `readEntries` only ever returns one batch per call — the empty batch that signals the end
33
+ * is itself the loop's exit condition, not a sentinel value. */
34
+ function readAllEntries(reader: FileSystemDirectoryReader): Promise<FileSystemEntry[]> {
35
+ return new Promise((resolve, reject) => {
36
+ const all: FileSystemEntry[] = [];
37
+ const readNextBatch = () => {
38
+ reader.readEntries((batch) => {
39
+ if (batch.length === 0) { resolve(all); return; }
40
+ all.push(...batch);
41
+ readNextBatch();
42
+ }, reject);
43
+ };
44
+ readNextBatch();
45
+ });
46
+ }
47
+
48
+ async function walk(entry: FileSystemEntry, out: DroppedEntry[]): Promise<void> {
49
+ if (entry.isFile) {
50
+ const relativePath = sanitizeRelativePath(entry.fullPath);
51
+ if (!relativePath) return;
52
+ out.push({ file: await readEntryAsFile(entry as FileSystemFileEntry), relativePath });
53
+ return;
54
+ }
55
+ if (entry.isDirectory) {
56
+ const reader = (entry as FileSystemDirectoryEntry).createReader();
57
+ for (const child of await readAllEntries(reader)) await walk(child, out);
58
+ }
59
+ }
60
+
61
+ /** Entry point: prefers the entries API (nested folders survive), falls back to a flat list. */
62
+ export async function collectDroppedEntries(dataTransfer: DataTransfer): Promise<DroppedEntry[]> {
63
+ const entries = Array.from(dataTransfer.items ?? [])
64
+ .filter((item) => item.kind === "file" && typeof item.webkitGetAsEntry === "function")
65
+ .map((item) => item.webkitGetAsEntry())
66
+ .filter((entry): entry is FileSystemEntry => entry != null);
67
+
68
+ if (entries.length > 0) {
69
+ const out: DroppedEntry[] = [];
70
+ for (const entry of entries) await walk(entry, out);
71
+ return out;
72
+ }
73
+
74
+ // No entries API (or every item resolved to null) — flat files only, no folder structure.
75
+ const flat: DroppedEntry[] = [];
76
+ for (const file of Array.from(dataTransfer.files)) {
77
+ const relativePath = sanitizeRelativePath(file.name);
78
+ if (relativePath) flat.push({ file, relativePath });
79
+ }
80
+ return flat;
81
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Bounded-concurrency runner for a batch of uploads, aggregating byte-level progress across
3
+ * every in-flight job (not just completed ones) so one large file streaming for a while does
4
+ * not make the overall percentage look stuck.
5
+ *
6
+ * Pure and DOM-free on purpose — `job.run` is the only place XHR/fetch appears, so this file
7
+ * is unit-testable without a browser.
8
+ */
9
+
10
+ export interface UploadJob<T> {
11
+ id: string;
12
+ /** Byte size, for weighting this job's share of the aggregate progress. */
13
+ size: number;
14
+ run(onProgress: (bytesLoaded: number) => void): Promise<T>;
15
+ }
16
+
17
+ export interface UploadQueueProgress {
18
+ completed: number;
19
+ total: number;
20
+ bytesLoaded: number;
21
+ bytesTotal: number;
22
+ }
23
+
24
+ export interface UploadQueueResult<T> {
25
+ id: string;
26
+ ok: boolean;
27
+ value?: T;
28
+ error?: unknown;
29
+ }
30
+
31
+ /**
32
+ * Runs `jobs` with at most `concurrency` in flight at once. Results are returned in the same
33
+ * order as `jobs`, regardless of which finished first — callers that report per-file outcomes
34
+ * need that order to line up with what they queued.
35
+ */
36
+ export async function runUploadQueue<T>(
37
+ jobs: UploadJob<T>[],
38
+ concurrency: number,
39
+ onProgress: (progress: UploadQueueProgress) => void,
40
+ ): Promise<UploadQueueResult<T>[]> {
41
+ const bytesTotal = jobs.reduce((sum, job) => sum + job.size, 0);
42
+ const loaded = new Array<number>(jobs.length).fill(0);
43
+ const results = new Array<UploadQueueResult<T>>(jobs.length);
44
+ let completed = 0;
45
+
46
+ const report = () => {
47
+ onProgress({
48
+ completed,
49
+ total: jobs.length,
50
+ bytesLoaded: loaded.reduce((sum, n) => sum + n, 0),
51
+ bytesTotal,
52
+ });
53
+ };
54
+
55
+ let nextIndex = 0;
56
+ async function worker(): Promise<void> {
57
+ for (;;) {
58
+ const index = nextIndex++;
59
+ if (index >= jobs.length) return;
60
+ const job = jobs[index]!;
61
+ try {
62
+ const value = await job.run((bytesLoaded) => {
63
+ loaded[index] = bytesLoaded;
64
+ report();
65
+ });
66
+ results[index] = { id: job.id, ok: true, value };
67
+ } catch (error) {
68
+ results[index] = { id: job.id, ok: false, error };
69
+ }
70
+ loaded[index] = job.size;
71
+ completed++;
72
+ report();
73
+ }
74
+ }
75
+
76
+ const workerCount = Math.max(1, Math.min(concurrency, jobs.length));
77
+ await Promise.all(Array.from({ length: workerCount }, worker));
78
+ return results;
79
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Backs the toolbar/context-menu/mobile "Upload…" actions: a hidden native file input the
3
+ * button clicks programmatically, so the browser's own picker chrome is used instead of a
4
+ * custom one. A second hidden input with the non-standard `webkitdirectory` attribute gives
5
+ * folder uploads on the browsers that support it (Chromium, Safari) — Firefox never
6
+ * implemented it, and `supportsFolderPicker` is what lets a caller hide that trigger there
7
+ * instead of offering a picker that silently behaves like a flat file picker.
8
+ */
9
+
10
+ import { useRef, type ChangeEvent, type ReactNode } from "react";
11
+ import type { DroppedEntry } from "./collect-dropped-entries";
12
+
13
+ export interface UploadPicker {
14
+ supportsFolderPicker: boolean;
15
+ openFilePicker(): void;
16
+ openFolderPicker(): void;
17
+ /** Render this once anywhere in the tree — the inputs are visually hidden. */
18
+ inputs: ReactNode;
19
+ }
20
+
21
+ /** Non-standard but present on Chromium/WebKit's `<input>`; absent from the DOM lib types. */
22
+ interface DirectoryPickerInputProps {
23
+ webkitdirectory?: string;
24
+ }
25
+
26
+ export function useUploadPicker(onFiles: (entries: DroppedEntry[]) => void): UploadPicker {
27
+ const fileInputRef = useRef<HTMLInputElement>(null);
28
+ const folderInputRef = useRef<HTMLInputElement>(null);
29
+ const supportsFolderPicker =
30
+ typeof document !== "undefined" && "webkitdirectory" in document.createElement("input");
31
+
32
+ const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
33
+ const files = e.target.files;
34
+ // Clears the value so picking the exact same file/folder again still fires `onChange`.
35
+ e.target.value = "";
36
+ if (!files || files.length === 0) return;
37
+ const entries: DroppedEntry[] = Array.from(files).map((file) => ({
38
+ file,
39
+ // The folder picker sets `webkitRelativePath` ("folder/sub/file.txt"); a plain file
40
+ // picker leaves it empty, so the bare name is the relative path.
41
+ relativePath: (file as File & { webkitRelativePath?: string }).webkitRelativePath || file.name,
42
+ }));
43
+ onFiles(entries);
44
+ };
45
+
46
+ return {
47
+ supportsFolderPicker,
48
+ openFilePicker: () => fileInputRef.current?.click(),
49
+ openFolderPicker: () => folderInputRef.current?.click(),
50
+ inputs: (
51
+ <>
52
+ <input
53
+ ref={fileInputRef}
54
+ type="file"
55
+ multiple
56
+ hidden
57
+ onChange={handleChange}
58
+ data-testid="explorer-upload-file-input"
59
+ />
60
+ {supportsFolderPicker && (
61
+ <input
62
+ ref={folderInputRef}
63
+ {...({ webkitdirectory: "" } satisfies DirectoryPickerInputProps)}
64
+ type="file"
65
+ multiple
66
+ hidden
67
+ onChange={handleChange}
68
+ data-testid="explorer-upload-folder-input"
69
+ />
70
+ )}
71
+ </>
72
+ ),
73
+ };
74
+ }
@@ -36,7 +36,9 @@ export function ColumnRow({ entry, selected, currentDir, hasClipboard, isPinned,
36
36
  // Column view has no multi-select — a drag always carries just this one entry.
37
37
  // Spring-load is Column view's own drill-in gesture (`onSelect` already navigates for a
38
38
  // directory), so a rested hover reaches a deep folder without dropping first.
39
- const dnd = useEntryRowDnd({ entry, dragPaths: [entry.path], run: actions.transferInto, springLoad: onSelect });
39
+ const dnd = useEntryRowDnd({
40
+ entry, dragPaths: [entry.path], run: actions.transferInto, springLoad: onSelect, onFiles: actions.uploadInto,
41
+ });
40
42
  return (
41
43
  <ContextMenu>
42
44
  <ContextMenuTrigger asChild>
@@ -61,7 +61,12 @@ export function ColumnViewColumn({
61
61
  // The column's own empty area is a drop target for its own directory — dropping below the
62
62
  // last row of an ancestor column moves/copies into that ancestor, not just the deepest one.
63
63
  // Mobile's single full-width column never gets one: no drag source can ever start on touch.
64
- const backgroundDrop = usePathDropTarget({ targetDir: path, run: actions.transferInto, disabled: fullWidth });
64
+ const backgroundDrop = usePathDropTarget({
65
+ targetDir: path,
66
+ run: actions.transferInto,
67
+ onFiles: actions.uploadInto,
68
+ disabled: fullWidth,
69
+ });
65
70
 
66
71
  return (
67
72
  <div
@@ -42,7 +42,7 @@ export const IconsViewTile = memo(function IconsViewTile(props: IconsViewTilePro
42
42
  // A drag carries whatever a context menu would act on: the selection when this tile is
43
43
  // part of it, otherwise just this tile.
44
44
  const dragPaths = useMemo(() => menuTargets.map((target) => target.path), [menuTargets]);
45
- const dnd = useEntryRowDnd({ entry, dragPaths, run: actions.transferInto });
45
+ const dnd = useEntryRowDnd({ entry, dragPaths, run: actions.transferInto, onFiles: actions.uploadInto });
46
46
  return (
47
47
  <ContextMenu>
48
48
  <ContextMenuTrigger asChild>
@@ -76,7 +76,11 @@ export function IconsView({
76
76
  const creating = slice.inlineEdit?.kind === "new-file" || slice.inlineEdit?.kind === "new-folder";
77
77
  // The view background is the current directory itself — a tile already claims the drop
78
78
  // (and stops the event) when it is a directory, so this only ever fires over empty space.
79
- const backgroundDrop = usePathDropTarget({ targetDir: slice.path, run: actions.transferInto });
79
+ const backgroundDrop = usePathDropTarget({
80
+ targetDir: slice.path,
81
+ run: actions.transferInto,
82
+ onFiles: actions.uploadInto,
83
+ });
80
84
 
81
85
  const onGridKeyDown = (event: KeyboardEvent) => {
82
86
  if (event.altKey || event.ctrlKey || event.metaKey) return;
@@ -44,7 +44,7 @@ export const ListRow = memo(function ListRow(props: ListRowProps) {
44
44
  // A drag carries whatever a context menu would act on: the selection when this row is part
45
45
  // of it, otherwise just this row.
46
46
  const dragPaths = useMemo(() => menuTargets.map((target) => target.path), [menuTargets]);
47
- const dnd = useEntryRowDnd({ entry, dragPaths, run: actions.transferInto });
47
+ const dnd = useEntryRowDnd({ entry, dragPaths, run: actions.transferInto, onFiles: actions.uploadInto });
48
48
  return (
49
49
  <ContextMenu>
50
50
  <ContextMenuTrigger asChild>
@@ -62,7 +62,11 @@ export function ListView({
62
62
  const creating = slice.inlineEdit?.kind === "new-file" || slice.inlineEdit?.kind === "new-folder";
63
63
  // The view background is the current directory itself — a row already claims the drop
64
64
  // (and stops the event) when it is a directory, so this only ever fires over empty space.
65
- const backgroundDrop = usePathDropTarget({ targetDir: slice.path, run: actions.transferInto });
65
+ const backgroundDrop = usePathDropTarget({
66
+ targetDir: slice.path,
67
+ run: actions.transferInto,
68
+ onFiles: actions.uploadInto,
69
+ });
66
70
 
67
71
  const toggleSort = (key: SortKey) =>
68
72
  setPrefs({ sort: { key, dir: sort.key === key && sort.dir === "asc" ? "desc" : "asc" } });
@@ -1,8 +1,8 @@
1
1
  import { useState, useEffect, useRef, type ReactNode } from "react";
2
2
  import { useMdContext, FILE_EXT_RE, GLOB_CHARS_RE } from "./markdown-context";
3
- import { useTabStore } from "@/stores/tab-store";
4
3
  import { highlightToHtml, highlightSync, getActiveShikiTheme } from "@/theme/adapters/shiki-adapter";
5
4
  import { copyToClipboard } from "@/lib/clipboard";
5
+ import { runInTerminal } from "@/lib/run-in-terminal";
6
6
 
7
7
  /**
8
8
  * Shiki-highlighted HTML for a code block. Returns null while streaming or
@@ -64,7 +64,6 @@ function hastToText(node: any): string {
64
64
  /** Pre — code block wrapper with mermaid detection, Shiki highlighting, action buttons */
65
65
  export function MdPre({ children, node, ...rest }: any) {
66
66
  const { codeActions, projectName, isStreaming } = useMdContext();
67
- const openTab = useTabStore((s) => s.openTab);
68
67
 
69
68
  const codeNode = node?.children?.[0];
70
69
  const langClass = (codeNode?.properties?.className ?? []).find((c: string) => c.startsWith("language-"));
@@ -92,12 +91,9 @@ export function MdPre({ children, node, ...rest }: any) {
92
91
  <ActionBtn title="Copy" icon={<CopyIcon />} activeIcon={<CheckIcon />} onClick={() => void copyToClipboard(text)} />
93
92
  {isBash && projectName && (
94
93
  <ActionBtn
95
- title="Run in terminal"
94
+ title="Send to terminal"
96
95
  icon={<PlayIcon />}
97
- onClick={() => {
98
- void copyToClipboard(text.replace(/^\$\s*/gm, ""));
99
- openTab({ type: "terminal", title: "Terminal", metadata: { projectName }, projectId: projectName, closable: true });
100
- }}
96
+ onClick={() => runInTerminal(text, projectName)}
101
97
  />
102
98
  )}
103
99
  </div>
@@ -1,13 +1,14 @@
1
1
  import { useRef, useEffect, useState, useCallback, memo } from "react";
2
2
  import { useTerminal } from "@/hooks/use-terminal";
3
3
  import { useTerminalTouchSelection } from "@/hooks/use-terminal-touch-selection";
4
+ import { useTerminalCommandQueue } from "@/hooks/use-terminal-command-queue";
5
+ import { sendToChat } from "@/lib/send-to-chat";
4
6
  import { cn } from "@/lib/utils";
5
7
  import { copyToClipboard } from "@/lib/clipboard";
6
8
  import { RotateCcw, MessageSquare } from "lucide-react";
7
9
  import "@xterm/xterm/css/xterm.css";
8
10
  import { toast } from "sonner";
9
11
 
10
- import { usePanelStore } from "@/stores/panel-store";
11
12
  import { TerminalMobileToolbar } from "./terminal-mobile-toolbar";
12
13
  import { TerminalLinksSheet } from "./terminal-links-sheet";
13
14
 
@@ -19,9 +20,10 @@ interface TerminalTabProps {
19
20
  export const TerminalTab = memo(function TerminalTab({ metadata, tabId }: TerminalTabProps) {
20
21
  const sessionId = (metadata?.sessionId as string) ?? "new";
21
22
  const projectName = metadata?.projectName as string | undefined;
23
+ const cwd = metadata?.cwd as string | undefined;
22
24
  const containerRef = useRef<HTMLDivElement>(null);
23
25
 
24
- const { connected, reconnecting, exited, sendData, getSelection, getLastCommandOutput, getBufferUrls, restart } = useTerminal({ sessionId, projectName, containerRef, tabId });
26
+ const { connected, reconnecting, exited, shellReady, sendData, getSelection, getLastCommandOutput, getLastCommand, getBufferUrls, restart } = useTerminal({ sessionId, projectName, cwd, containerRef, tabId });
25
27
  const [ctrlMode, setCtrlMode] = useState(false);
26
28
  const [selectMode, setSelectMode] = useState(false);
27
29
  const [linksOpen, setLinksOpen] = useState(false);
@@ -35,6 +37,10 @@ export const TerminalTab = memo(function TerminalTab({ metadata, tabId }: Termin
35
37
  termElement?.focus();
36
38
  }, []);
37
39
 
40
+ // "Run in terminal" (chat code blocks) types its command in here, waiting for
41
+ // the shell to finish booting first.
42
+ useTerminalCommandQueue({ tabId, metadata, shellReady, sendData, focusTerminal, containerRef });
43
+
38
44
  // Raising the soft keyboard needs focus() to run inside a gesture the browser
39
45
  // recognises, and xterm's own mousedown handling does not reliably qualify.
40
46
  // Capture-phase `touchend` runs before xterm's handlers and is unambiguously a
@@ -100,33 +106,21 @@ export const TerminalTab = memo(function TerminalTab({ metadata, tabId }: Termin
100
106
  }
101
107
  }, [sendData, focusTerminal]);
102
108
 
109
+ // Output without the command that produced it reads as an orphan in chat, so the
110
+ // prompt line goes along with it. A selection is sent verbatim — the user already
111
+ // picked exactly what they meant.
103
112
  const handleSendToChat = useCallback(() => {
104
113
  const selection = getSelection();
105
- const text = selection || getLastCommandOutput();
106
- if (!text.trim()) return;
107
- const codeBlock = "```bash\n" + text + "\n```";
114
+ const body = selection || getLastCommandOutput();
115
+ if (!body.trim()) return;
116
+ const command = selection ? "" : getLastCommand();
117
+ const transcript = command ? `${command}\n${body}` : body;
118
+ const codeBlock = "```bash\n" + transcript + "\n```";
108
119
  const label = selection ? "Terminal selection" : "Terminal output";
109
120
 
110
- // Try to inject into an already-open chat tab as attachment chip
111
- let handled = false;
112
- const handler = () => { handled = true; };
113
- window.addEventListener("ppm:send-to-chat:ack", handler, { once: true });
114
- window.dispatchEvent(new CustomEvent("ppm:send-to-chat", { detail: { text: codeBlock, label, projectName } }));
115
- window.removeEventListener("ppm:send-to-chat:ack", handler);
116
-
117
- if (handled) {
118
- toast.success("Sent to chat", { duration: 1500 });
119
- } else {
120
- // No chat tab mounted — open a new one with the content as initialValue
121
- usePanelStore.getState().openTab({
122
- type: "chat",
123
- title: "Chat",
124
- projectId: null,
125
- metadata: { projectName, pendingMessage: codeBlock },
126
- closable: true,
127
- });
128
- }
129
- }, [getSelection, getLastCommandOutput, projectName]);
121
+ sendToChat({ text: codeBlock, label, projectName });
122
+ toast.success("Sent to chat", { duration: 1500 });
123
+ }, [getSelection, getLastCommandOutput, getLastCommand, projectName]);
130
124
 
131
125
  const isMobile = typeof window !== "undefined" && "ontouchstart" in window;
132
126
 
@@ -7,6 +7,7 @@ import { usePanelStore } from "@/stores/panel-store";
7
7
  import { playNotificationSound } from "@/lib/notification-sounds";
8
8
  import { toast } from "sonner";
9
9
  import type { ChatMessage, ChatEvent } from "../../types/chat";
10
+ import type { BackgroundAgentStatus } from "../../shared/background-agent-status";
10
11
  import type { ChatWsServerMessage, SessionPhase, BackgroundShell, VersionGroup } from "../../types/api";
11
12
  import { useBackgroundOutputStore } from "../stores/background-output-store";
12
13
 
@@ -210,6 +211,22 @@ export function useChat(sessionId: string | null, providerId = "claude", project
210
211
  updateTeamActivity();
211
212
  }, [updateTeamActivity]);
212
213
 
214
+ /** Merge a team's on-disk message history into the activity buffer. */
215
+ const loadTeamDetail = useCallback(async (teamName: string) => {
216
+ try {
217
+ const res = await api.get<any>(`/api/teams/${encodeURIComponent(teamName)}`);
218
+ if (!res?.messages) return;
219
+ const existing = teamActivityRef.current.messages;
220
+ const newMsgs = (res.messages as any[]).filter(
221
+ (m: any) => !existing.some((e) => e.timestamp === m.timestamp && e.from === m.from)
222
+ );
223
+ existing.push(...newMsgs);
224
+ existing.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
225
+ if (existing.length > 500) existing.splice(0, existing.length - 500);
226
+ updateTeamActivity();
227
+ } catch { /* team deleted or unreadable */ }
228
+ }, [updateTeamActivity]);
229
+
213
230
  // Derived state
214
231
  const isStreaming = phase !== "idle";
215
232
 
@@ -316,6 +333,37 @@ export function useChat(sessionId: string | null, providerId = "claude", project
316
333
  }
317
334
  }, [flushMessages]);
318
335
 
336
+ /**
337
+ * Stamp a backgrounded Agent/Task card with its terminal state.
338
+ *
339
+ * The card may live in either half of the transcript: the streaming buffer when the agent
340
+ * finishes inside the turn that spawned it, or a finalized message when it outlives that
341
+ * turn — which is the common case, and the one that used to leave a green check on a
342
+ * still-running agent.
343
+ */
344
+ const markSubagentStatus = useCallback((toolUseId: string, status: BackgroundAgentStatus) => {
345
+ const isTarget = (e: ChatEvent) =>
346
+ e.type === "tool_use" && (e.tool === "Agent" || e.tool === "Task") && (e as any).toolUseId === toolUseId;
347
+
348
+ const idx = streamingEventsRef.current.findIndex(isTarget);
349
+ if (idx !== -1) {
350
+ streamingEventsRef.current[idx] = { ...streamingEventsRef.current[idx]!, bgStatus: status } as ChatEvent;
351
+ syncMessages();
352
+ return;
353
+ }
354
+
355
+ setMessages((prev) => {
356
+ let mi = -1;
357
+ for (let i = prev.length - 1; i >= 0; i--) {
358
+ if (prev[i]!.events?.some(isTarget)) { mi = i; break; }
359
+ }
360
+ if (mi === -1) return prev;
361
+ const msg = prev[mi]!;
362
+ const events = msg.events!.map((e) => (isTarget(e) ? { ...e, bgStatus: status } as ChatEvent : e));
363
+ return [...prev.slice(0, mi), { ...msg, events }, ...prev.slice(mi + 1)];
364
+ });
365
+ }, [syncMessages]);
366
+
319
367
  /** Process a single stream event — reused by live events and turn_events replay */
320
368
  const processStreamEvent = useCallback((data: unknown) => {
321
369
  const ev = data as any;
@@ -536,20 +584,8 @@ export function useChat(sessionId: string | null, providerId = "claude", project
536
584
  const teamName = ev.teamName as string;
537
585
  if (teamName) {
538
586
  teamActivityRef.current.teamNames.add(teamName);
539
- // Fetch full team data from REST
540
- api.get<any>(`/api/teams/${encodeURIComponent(teamName)}`).then((res: any) => {
541
- if (res?.messages) {
542
- const existing = teamActivityRef.current.messages;
543
- const newMsgs = (res.messages as any[]).filter(
544
- (m: any) => !existing.some((e) => e.timestamp === m.timestamp && e.from === m.from)
545
- );
546
- existing.push(...newMsgs);
547
- existing.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
548
- if (existing.length > 500) existing.splice(0, existing.length - 500);
549
- }
550
- updateTeamActivity();
551
- }).catch(() => {});
552
587
  updateTeamActivity();
588
+ void loadTeamDetail(teamName);
553
589
  }
554
590
  break;
555
591
  }
@@ -593,6 +629,15 @@ export function useChat(sessionId: string | null, providerId = "claude", project
593
629
  break;
594
630
  }
595
631
 
632
+ case "subagent_status": {
633
+ // A backgrounded Agent finished. Its card has shown a spinner since the launch ack
634
+ // (see isAsyncAgentLaunchAck) — stamp the terminal state so it can settle.
635
+ const tuId = ev.toolUseId as string | undefined;
636
+ const status = ev.status as BackgroundAgentStatus | undefined;
637
+ if (tuId && status) markSubagentStatus(tuId, status);
638
+ break;
639
+ }
640
+
596
641
  case "background_registry": {
597
642
  const shells = (ev.shells as BackgroundShell[]) ?? [];
598
643
  backgroundShellsRef.current = shells;
@@ -656,7 +701,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
656
701
  break;
657
702
  }
658
703
  }
659
- }, [routeToParent, routeToFinalizedParent, syncMessages]);
704
+ }, [routeToParent, routeToFinalizedParent, syncMessages, markSubagentStatus, updateTeamActivity, loadTeamDetail]);
660
705
 
661
706
  const handleMessage = useCallback((event: MessageEvent) => {
662
707
  let data: ChatWsServerMessage;
@@ -914,6 +959,23 @@ export function useChat(sessionId: string | null, providerId = "claude", project
914
959
  setTeamActivity(EMPTY_TEAM_ACTIVITY);
915
960
  setTeamMessages([]);
916
961
 
962
+ // Rehydrate the team from disk. team_detected only arrives live and its replay
963
+ // buffer is cleared at every turn boundary, so without this a reload — or any
964
+ // later turn — drops the team UI even while the team is still running.
965
+ if (sessionId) {
966
+ api.get<any[]>("/api/teams").then((teams) => {
967
+ if (cancelled || !Array.isArray(teams)) return;
968
+ // Only the team named after this session. The global list carries other
969
+ // sessions' teams and nothing on disk attributes those to a session, so
970
+ // matching by name is what keeps one session's team out of another's UI.
971
+ const mine = teams.filter((t: any) => (t?.name ?? t?.team_name) === sessionId);
972
+ if (mine.length === 0) return;
973
+ teamActivityRef.current.teamNames.add(sessionId);
974
+ updateTeamActivity();
975
+ void loadTeamDetail(sessionId);
976
+ }).catch(() => {});
977
+ }
978
+
917
979
  // Snapshot the previous session's message ids. On a same-tab session swap
918
980
  // (edit→fork / version switch) a queued send may append optimistic + live
919
981
  // streaming messages BEFORE this history fetch resolves. We drop exactly the
@@ -970,7 +1032,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
970
1032
  return () => {
971
1033
  cancelled = true;
972
1034
  };
973
- }, [sessionId, providerId, projectName]);
1035
+ }, [sessionId, providerId, projectName, updateTeamActivity, loadTeamDetail]);
974
1036
 
975
1037
  const sendMessage = useCallback(
976
1038
  (content: string, opts?: { permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }> }) => {
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Poll a team's per-member activity while the panel is open.
3
+ *
4
+ * The team inboxes cannot say who is working — every member reads "active"
5
+ * forever there. `/api/teams/:name/activity` derives it from the agent
6
+ * transcripts instead, and also returns the replies teammates sent back, which
7
+ * no inbox holds. Polling only runs while `enabled`, so a closed panel costs
8
+ * nothing.
9
+ */
10
+
11
+ import { useCallback, useEffect, useRef, useState } from "react";
12
+ import { api } from "@/lib/api-client";
13
+
14
+ /** Fast enough that a working teammate looks live, slow enough to stay cheap. */
15
+ const POLL_INTERVAL_MS = 5_000;
16
+
17
+ export type MemberWorkState = "working" | "paused" | "no-transcript";
18
+
19
+ export interface TeamMemberActivity {
20
+ name: string;
21
+ workState: MemberWorkState;
22
+ agentType?: string;
23
+ model?: string;
24
+ description?: string;
25
+ toolUseId?: string;
26
+ startedAt?: string;
27
+ lastEventAt?: string;
28
+ lastTool?: string;
29
+ lastToolArg?: string;
30
+ lastNarrative?: string;
31
+ sizeBytes: number;
32
+ }
33
+
34
+ export interface OutboundTeamMessage {
35
+ from: string;
36
+ to: string;
37
+ text: string;
38
+ summary?: string;
39
+ timestamp: string;
40
+ }
41
+
42
+ export interface TeamActivityFeed {
43
+ members: TeamMemberActivity[];
44
+ outbound: OutboundTeamMessage[];
45
+ loading: boolean;
46
+ /** Re-fetch now, for the panel's refresh button. */
47
+ refresh: () => void;
48
+ }
49
+
50
+ export function useTeamActivityFeed(teamName: string, enabled: boolean): TeamActivityFeed {
51
+ const [members, setMembers] = useState<TeamMemberActivity[]>([]);
52
+ const [outbound, setOutbound] = useState<OutboundTeamMessage[]>([]);
53
+ const [loading, setLoading] = useState(false);
54
+ // Survives re-renders so a poll that resolves after teardown is discarded.
55
+ const cancelledRef = useRef(false);
56
+
57
+ const fetchActivity = useCallback(async (team: string) => {
58
+ if (!team) return;
59
+ setLoading(true);
60
+ try {
61
+ const res = await api.get<{ members?: TeamMemberActivity[]; outbound?: OutboundTeamMessage[] }>(
62
+ `/api/teams/${encodeURIComponent(team)}/activity`,
63
+ );
64
+ if (cancelledRef.current) return;
65
+ setMembers(res?.members ?? []);
66
+ setOutbound(res?.outbound ?? []);
67
+ } catch {
68
+ /* keep the last good snapshot rather than blanking the list */
69
+ } finally {
70
+ if (!cancelledRef.current) setLoading(false);
71
+ }
72
+ }, []);
73
+
74
+ useEffect(() => {
75
+ cancelledRef.current = false;
76
+ if (!enabled || !teamName) {
77
+ // Drop the previous team's rows so a reopen never shows stale members.
78
+ setMembers([]);
79
+ setOutbound([]);
80
+ return () => { cancelledRef.current = true; };
81
+ }
82
+ void fetchActivity(teamName);
83
+ const timer = setInterval(() => void fetchActivity(teamName), POLL_INTERVAL_MS);
84
+ return () => {
85
+ cancelledRef.current = true;
86
+ clearInterval(timer);
87
+ };
88
+ }, [teamName, enabled, fetchActivity]);
89
+
90
+ const refresh = useCallback(() => void fetchActivity(teamName), [fetchActivity, teamName]);
91
+ return { members, outbound, loading, refresh };
92
+ }