@hienlh/ppm 0.18.2 → 0.18.3

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 +17 -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-3Zk3gYSZ.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-DvbbVMBi.js +15 -0
  22. package/dist/web/assets/{cobol-Q6YgysnI.js → cobol-Byn9FYKu.js} +1 -1
  23. package/dist/web/assets/code-editor-BKg7Li-L.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-CJNtovCh.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-BR6gCSZJ.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-DzuwuFSr.js} +1 -1
  32. package/dist/web/assets/diff-viewer-DL3_tISz.js +4 -0
  33. package/dist/web/assets/{docx-preview-Dd2nTW2v.js → docx-preview-BzgyssBV.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-CrrY1HbH.js +2 -0
  43. package/dist/web/assets/explorer-window-content-CvQPeiwU.js +1 -0
  44. package/dist/web/assets/{extension-webview-Dk_zyoXZ.js → extension-webview-DH1PfQF2.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-gUm4E3wo.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-D8J5lwUP.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-DihiQPSi.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-DOQBNgwl.js} +1 -1
  67. package/dist/web/assets/index-BtncTUyM.js +52 -0
  68. package/dist/web/assets/index-Bucbpby-.css +2 -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-AynYQVnV.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-BBlGpszb.js +1 -0
  79. package/dist/web/assets/{markdown-renderer-B4uL6GVA.js → markdown-renderer-CVGub2iS.js} +3 -3
  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-CSgc5JOk.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-1ksB0YwR.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-DSAkWbxY.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-DOiM_5Nv.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-D_oruJB9.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-PWpuw-O5.js +1 -0
  116. package/dist/web/assets/{sqlite-viewer-CZYDknNa.js → sqlite-viewer-1S6cwVWa.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-U0Jh9-2v.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-DSZL4GIj.js +1 -0
  123. package/dist/web/assets/{templ-DbG2y5yD.js → templ-Dv8zpKZW.js} +1 -1
  124. package/dist/web/assets/terminal-tab-uVhX8AGG.js +3 -0
  125. package/dist/web/assets/{tex-CeKQhrQG.js → tex-CsrOiqh1.js} +1 -1
  126. package/dist/web/assets/tool-cards-QuTCNfYR.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-DvmINdhI.js +1 -0
  133. package/dist/web/assets/use-websocket-DoZdQS0G.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-CzU09X0C.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 +44 -18
  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,108 @@
1
+ import { useEffect, useRef, useState, useCallback } from "react";
2
+ import { usePanelStore } from "@/stores/panel-store";
3
+ import {
4
+ RUN_IN_TERMINAL_EVENT,
5
+ RUN_IN_TERMINAL_ACK_EVENT,
6
+ type RunInTerminalDetail,
7
+ } from "@/lib/run-in-terminal";
8
+
9
+ interface UseTerminalCommandQueueOptions {
10
+ /** Tab ID — used to drop `pendingCommand` from persisted metadata once consumed. */
11
+ tabId?: string;
12
+ metadata?: Record<string, unknown>;
13
+ /** From `useTerminal` — the shell has printed its prompt and can take input. */
14
+ shellReady: boolean;
15
+ sendData: (data: string) => void;
16
+ focusTerminal: () => void;
17
+ containerRef: React.RefObject<HTMLDivElement | null>;
18
+ }
19
+
20
+ /**
21
+ * Smallest box treated as a real terminal. Not `> 0`: a terminal parked in the
22
+ * zero-sized tab pool (dock closed, tab inactive) still measures 8×8 from its own
23
+ * padding, and a hidden terminal claiming the command would swallow it silently.
24
+ */
25
+ const MIN_VISIBLE_PX = 40;
26
+
27
+ /** On screen? Must be laid out at a usable size and inside the viewport. */
28
+ function isOnScreen(el: HTMLElement | null): boolean {
29
+ if (!el) return false;
30
+ // `visibility: hidden` on the tab pool is the crisp signal where supported.
31
+ if (typeof el.checkVisibility === "function" && !el.checkVisibility({ visibilityProperty: true })) {
32
+ return false;
33
+ }
34
+ const r = el.getBoundingClientRect();
35
+ if (r.width < MIN_VISIBLE_PX || r.height < MIN_VISIBLE_PX) return false;
36
+ return r.bottom > 0 && r.right > 0 && r.top < window.innerHeight && r.left < window.innerWidth;
37
+ }
38
+
39
+ /**
40
+ * Type a command into this terminal, deferred until the shell can accept it.
41
+ *
42
+ * Fed from two directions: `metadata.pendingCommand` on a terminal that was just
43
+ * opened to carry the command, and the `ppm:run-in-terminal` event for a terminal
44
+ * already on screen. Both land in the same one-slot queue, which flushes once
45
+ * `shellReady` turns true — a shell still running its startup files drops
46
+ * anything typed at it, which is why the command cannot be sent on connect.
47
+ *
48
+ * The command is typed WITHOUT a trailing newline: the user reads it and presses
49
+ * Enter. Same semantics as a paste, so a multi-line block behaves like pasting one.
50
+ */
51
+ export function useTerminalCommandQueue({
52
+ tabId,
53
+ metadata,
54
+ shellReady,
55
+ sendData,
56
+ focusTerminal,
57
+ containerRef,
58
+ }: UseTerminalCommandQueueOptions): void {
59
+ /** Latest command awaiting a ready shell — latest wins, since queued commands
60
+ * typed back-to-back without a newline would merge into one garbled line. */
61
+ const pendingRef = useRef<string | null>(null);
62
+ /** Incremented per queued command so the flush effect re-runs on repeat clicks. */
63
+ const [revision, setRevision] = useState(0);
64
+
65
+ const queue = useCallback((command: string) => {
66
+ pendingRef.current = command;
67
+ setRevision((n) => n + 1);
68
+ }, []);
69
+
70
+ // Command handed over by whoever opened this tab. Stripped from the tab's
71
+ // metadata immediately: metadata is persisted to localStorage, and a page
72
+ // reload must not re-inject a command the user already dealt with.
73
+ const pendingCommand = metadata?.pendingCommand;
74
+ useEffect(() => {
75
+ if (typeof pendingCommand !== "string" || !pendingCommand) return;
76
+ queue(pendingCommand);
77
+ if (tabId) {
78
+ const rest = { ...(metadata ?? {}) };
79
+ delete rest.pendingCommand;
80
+ usePanelStore.getState().updateTab(tabId, { metadata: rest });
81
+ }
82
+ // `metadata` is intentionally not a dependency — the strip above already
83
+ // makes this fire exactly once per handed-over command.
84
+ // eslint-disable-next-line react-hooks/exhaustive-deps
85
+ }, [pendingCommand, tabId, queue]);
86
+
87
+ // Claim commands aimed at "whatever terminal the user is looking at".
88
+ useEffect(() => {
89
+ const onRun = (event: Event) => {
90
+ const detail = (event as CustomEvent<RunInTerminalDetail>).detail;
91
+ if (!detail?.command) return;
92
+ if (!isOnScreen(containerRef.current)) return;
93
+ queue(detail.command);
94
+ window.dispatchEvent(new Event(RUN_IN_TERMINAL_ACK_EVENT));
95
+ };
96
+ window.addEventListener(RUN_IN_TERMINAL_EVENT, onRun);
97
+ return () => window.removeEventListener(RUN_IN_TERMINAL_EVENT, onRun);
98
+ }, [containerRef, queue]);
99
+
100
+ useEffect(() => {
101
+ if (!shellReady) return;
102
+ const command = pendingRef.current;
103
+ if (!command) return;
104
+ pendingRef.current = null;
105
+ sendData(command);
106
+ focusTerminal();
107
+ }, [shellReady, revision, sendData, focusTerminal]);
108
+ }
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useRef, useCallback, useState } from "react";
2
2
  import { Terminal, type ITheme } from "@xterm/xterm";
3
+ import { withWsAuth } from "@/lib/ws-auth";
3
4
  import { FitAddon } from "@xterm/addon-fit";
4
5
  import { WebLinksAddon } from "@xterm/addon-web-links";
5
6
  import { WebglAddon } from "@xterm/addon-webgl";
@@ -21,6 +22,8 @@ function currentXtermTheme(): ITheme {
21
22
  interface UseTerminalOptions {
22
23
  sessionId: string;
23
24
  projectName?: string;
25
+ /** Absolute start directory for a brand-new shell; ignored when re-attaching to a session. */
26
+ cwd?: string;
24
27
  containerRef: React.RefObject<HTMLDivElement | null>;
25
28
  /** Stable tab ID for persisting session across reload */
26
29
  tabId?: string;
@@ -30,10 +33,14 @@ interface UseTerminalReturn {
30
33
  connected: boolean;
31
34
  reconnecting: boolean;
32
35
  exited: boolean;
36
+ /** True once the shell has printed its prompt and stopped writing — safe to inject input. */
37
+ shellReady: boolean;
33
38
  sendData: (data: string) => void;
34
39
  getSelection: () => string;
35
40
  /** Read buffer from last command start to current cursor (for "Send to Chat"). */
36
41
  getLastCommandOutput: () => string;
42
+ /** The prompt line the last command was typed on, empty until one is entered. */
43
+ getLastCommand: () => string;
37
44
  /** URLs present in the scrollback, most recent first. */
38
45
  getBufferUrls: () => string[];
39
46
  restart: () => void;
@@ -47,6 +54,11 @@ const URL_SCAN_MAX_ROWS = 5000;
47
54
  /** Quiet period before refitting to a new container size, in ms. */
48
55
  const RESIZE_SETTLE_MS = 100;
49
56
 
57
+ /** Quiet period after the last PTY output that means the prompt is printed and the shell is idle. */
58
+ const SHELL_READY_QUIET_MS = 250;
59
+ /** Upper bound on waiting for that prompt — a shell that prints nothing must not block input forever. */
60
+ const SHELL_READY_MAX_MS = 3000;
61
+
50
62
  const RESIZE_PREFIX = "\x01RESIZE:";
51
63
  const PING_MSG = "\x01PING";
52
64
  const PONG_MSG = "\x01PONG";
@@ -72,6 +84,10 @@ export function useTerminal(
72
84
  const [connected, setConnected] = useState(false);
73
85
  const [reconnecting, setReconnecting] = useState(false);
74
86
  const [exited, setExited] = useState(false);
87
+ /** A brand-new shell needs to finish booting before it accepts injected input. */
88
+ const [shellReady, setShellReady] = useState(false);
89
+ const readyQuietTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
90
+ const readyMaxTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
75
91
  // Restore persisted session ID from localStorage (survives page reload)
76
92
  const storageKey = options.tabId ? `ppm:terminal-session:${options.tabId}` : null;
77
93
  const initialSessionId = (() => {
@@ -83,6 +99,9 @@ export function useTerminal(
83
99
  const actualSessionId = useRef(initialSessionId);
84
100
  /** Absolute row where last command output starts (set when user presses Enter) */
85
101
  const commandStartRow = useRef(0);
102
+ /** Absolute row of the prompt line that command was typed on, -1 before any Enter.
103
+ * Output alone reads as an orphan in chat — the command is what gives it meaning. */
104
+ const commandRow = useRef(-1);
86
105
 
87
106
  const sendData = useCallback((data: string) => {
88
107
  const ws = wsRef.current;
@@ -91,6 +110,12 @@ export function useTerminal(
91
110
  }
92
111
  }, []);
93
112
 
113
+ /** Debounce PTY output: the shell counts as booted once it goes quiet. */
114
+ const noteOutput = useCallback(() => {
115
+ if (readyQuietTimer.current) clearTimeout(readyQuietTimer.current);
116
+ readyQuietTimer.current = setTimeout(() => setShellReady(true), SHELL_READY_QUIET_MS);
117
+ }, []);
118
+
94
119
  const getSelection = useCallback(() => {
95
120
  return termRef.current?.getSelection() ?? "";
96
121
  }, []);
@@ -111,6 +136,12 @@ export function useTerminal(
111
136
  return lines.join("\n");
112
137
  }, []);
113
138
 
139
+ const getLastCommand = useCallback(() => {
140
+ const term = termRef.current;
141
+ if (!term || commandRow.current < 0) return "";
142
+ return term.buffer.active.getLine(commandRow.current)?.translateToString(true).trimEnd() ?? "";
143
+ }, []);
144
+
114
145
  /**
115
146
  * Collect URLs from the scrollback.
116
147
  *
@@ -172,6 +203,7 @@ export function useTerminal(
172
203
  if (storageKey) { try { localStorage.removeItem(storageKey); } catch { /* */ } }
173
204
  reconnectAttempts.current = 0;
174
205
  setExited(false);
206
+ setShellReady(false);
175
207
  setConnected(false);
176
208
  setReconnecting(false);
177
209
  // connectWs will be called after this via setTimeout to allow state to settle
@@ -198,7 +230,8 @@ export function useTerminal(
198
230
  const projectName = options.projectName ?? "";
199
231
  // Use actual session ID from server on reconnect (not "new")
200
232
  const sid = actualSessionId.current;
201
- const path = `/ws/project/${encodeURIComponent(projectName)}/terminal/${sid}`;
233
+ const cwdQuery = sid === "new" && options.cwd ? `?cwd=${encodeURIComponent(options.cwd)}` : "";
234
+ const path = withWsAuth(`/ws/project/${encodeURIComponent(projectName)}/terminal/${sid}${cwdQuery}`);
202
235
  // Local dev over http: connect directly to backend (port 8081) to bypass
203
236
  // Vite's dev proxy which has unreliable WebSocket upgrade handling. Over https
204
237
  // (e.g. a Cloudflare tunnel) port 8081 isn't reachable and ws:// is blocked as
@@ -220,6 +253,11 @@ export function useTerminal(
220
253
  setConnected(true);
221
254
  setReconnecting(false);
222
255
  reconnectAttempts.current = 0;
256
+ // A re-attach lands on a shell that booted long ago; only a fresh session
257
+ // has to wait for a prompt.
258
+ if (actualSessionId.current === "new") setShellReady(false);
259
+ if (readyMaxTimer.current) clearTimeout(readyMaxTimer.current);
260
+ readyMaxTimer.current = setTimeout(() => setShellReady(true), SHELL_READY_MAX_MS);
223
261
  sendResize();
224
262
  };
225
263
 
@@ -255,6 +293,7 @@ export function useTerminal(
255
293
  // Not JSON, write as terminal output
256
294
  }
257
295
  }
296
+ noteOutput();
258
297
  term.write(event.data);
259
298
  }
260
299
  };
@@ -347,7 +386,8 @@ export function useTerminal(
347
386
  // When user presses Enter, mark next row as command output start
348
387
  if (data.includes("\r") || data.includes("\n")) {
349
388
  const buf = term.buffer.active;
350
- commandStartRow.current = buf.baseY + buf.cursorY + 1;
389
+ commandRow.current = buf.baseY + buf.cursorY;
390
+ commandStartRow.current = commandRow.current + 1;
351
391
  }
352
392
  const ws = wsRef.current;
353
393
  if (ws?.readyState === WebSocket.OPEN) {
@@ -399,6 +439,8 @@ export function useTerminal(
399
439
  clearInterval(heartbeatInterval);
400
440
  document.removeEventListener("visibilitychange", onVisibility);
401
441
  if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
442
+ if (readyQuietTimer.current) clearTimeout(readyQuietTimer.current);
443
+ if (readyMaxTimer.current) clearTimeout(readyMaxTimer.current);
402
444
  wsRef.current?.close();
403
445
  wsRef.current = null;
404
446
  term.dispose();
@@ -407,5 +449,5 @@ export function useTerminal(
407
449
  };
408
450
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
409
451
 
410
- return { connected, reconnecting, exited, sendData, getSelection, getLastCommandOutput, getBufferUrls, restart };
452
+ return { connected, reconnecting, exited, shellReady, sendData, getSelection, getLastCommandOutput, getLastCommand, getBufferUrls, restart };
411
453
  }
@@ -182,4 +182,13 @@ export const fsApi = {
182
182
  });
183
183
  return `/api/fs/raw?path=${q(path)}&download=true&dl_token=${q(token)}`;
184
184
  },
185
+
186
+ /**
187
+ * Target for a streamed `PUT` upload — `path` is the full destination file path. Not used
188
+ * through `request()`: the upload helper needs `XMLHttpRequest` for progress events, which
189
+ * `fetch` cannot give.
190
+ */
191
+ uploadUrl(path: string, overwrite: boolean): string {
192
+ return `/api/fs/upload?path=${q(path)}&overwrite=${overwrite ? "1" : "0"}`;
193
+ },
185
194
  };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Single-file upload over `XMLHttpRequest`. `fetch` gives no upload progress events, so the
3
+ * queue needs XHR for the per-file percentage the toast shows; everything else about the
4
+ * request (auth header, error shape) mirrors `fs-api.ts`'s `request()`.
5
+ */
6
+
7
+ import { getAuthToken } from "./api-client";
8
+ import { fsApi, FsError } from "./fs-api";
9
+
10
+ export interface UploadProgress {
11
+ loaded: number;
12
+ total: number;
13
+ }
14
+
15
+ interface UploadResponseBody {
16
+ ok?: boolean;
17
+ data?: { path: string; size: number };
18
+ error?: string;
19
+ code?: string;
20
+ }
21
+
22
+ /**
23
+ * Resolves with the uploaded `{ path, size }`. Rejects with `FsError` for a server refusal
24
+ * (409 `EEXIST`, 403 `EDENIED`, …) and a plain `Error` for a network failure — the caller
25
+ * tells them apart with `instanceof FsError`, same as every other `fs-api` call.
26
+ */
27
+ export function uploadFileXhr(
28
+ path: string,
29
+ file: File,
30
+ overwrite: boolean,
31
+ onProgress: (progress: UploadProgress) => void,
32
+ ): Promise<{ path: string; size: number }> {
33
+ return new Promise((resolve, reject) => {
34
+ const xhr = new XMLHttpRequest();
35
+ xhr.open("PUT", fsApi.uploadUrl(path, overwrite));
36
+ const token = getAuthToken();
37
+ if (token) xhr.setRequestHeader("Authorization", `Bearer ${token}`);
38
+ xhr.setRequestHeader("x-ppm-client", "web");
39
+
40
+ xhr.upload.onprogress = (e) => {
41
+ if (e.lengthComputable) onProgress({ loaded: e.loaded, total: e.total });
42
+ };
43
+
44
+ xhr.onload = () => {
45
+ let json: UploadResponseBody = {};
46
+ try {
47
+ json = JSON.parse(xhr.responseText);
48
+ } catch {
49
+ // Falls through to the status-based rejection below.
50
+ }
51
+ if (xhr.status >= 200 && xhr.status < 300 && json.ok !== false && json.data) {
52
+ resolve(json.data);
53
+ return;
54
+ }
55
+ reject(new FsError(json.error ?? `HTTP ${xhr.status}`, json.code ?? "EUNKNOWN", xhr.status));
56
+ };
57
+ xhr.onerror = () => reject(new Error("Network error during upload"));
58
+ xhr.onabort = () => reject(new DOMException("Upload aborted", "AbortError"));
59
+
60
+ xhr.send(file);
61
+ });
62
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * URL builders for media the browser fetches on its own (`<video src>`, `<audio src>`).
3
+ *
4
+ * Those elements cannot send an Authorization header, so the session token rides in
5
+ * the query string — the server only accepts `?token=` on these exact routes.
6
+ * Streaming straight from the URL (instead of fetching a blob first) lets the browser
7
+ * issue Range requests, so a multi-GB file starts playing immediately and seeking
8
+ * costs one small request.
9
+ */
10
+ import { api, getAuthToken, projectUrl } from "@/lib/api-client";
11
+
12
+ /** Absolute (`/x`, `C:\x`) paths belong to the whole-disk `/api/fs` routes, relative ones to the project. */
13
+ export function isExternalPath(filePath: string): boolean {
14
+ return /^(\/|[A-Za-z]:[/\\])/.test(filePath);
15
+ }
16
+
17
+ /** `/api/fs/<route>` or `/api/project/<name>/files/<route>` depending on the path kind. */
18
+ function mediaBase(route: "raw" | "transcode" | "probe", filePath: string, projectName: string): string {
19
+ const prefix = isExternalPath(filePath) ? "/api/fs" : `${projectUrl(projectName)}/files`;
20
+ return `${prefix}/${route}?path=${encodeURIComponent(filePath)}`;
21
+ }
22
+
23
+ function withToken(url: string): string {
24
+ const token = getAuthToken();
25
+ return token ? `${url}&token=${encodeURIComponent(token)}` : url;
26
+ }
27
+
28
+ /** Direct, Range-capable URL of the file as stored on disk. */
29
+ export function rawMediaUrl(filePath: string, projectName: string): string {
30
+ return withToken(mediaBase("raw", filePath, projectName));
31
+ }
32
+
33
+ /** Live ffmpeg → fragmented-MP4 stream starting at `start` seconds. */
34
+ export function transcodeMediaUrl(filePath: string, projectName: string, start = 0): string {
35
+ const base = mediaBase("transcode", filePath, projectName);
36
+ return withToken(start > 0 ? `${base}&start=${start.toFixed(3)}` : base);
37
+ }
38
+
39
+ export interface MediaProbeInfo {
40
+ transcodable: boolean;
41
+ encoder: string | null;
42
+ duration: number | null;
43
+ container: string | null;
44
+ video: { codec: string; width?: number; height?: number } | null;
45
+ audio: { codec: string } | null;
46
+ }
47
+
48
+ /** Ask the server what the file contains and whether it can transcode it. */
49
+ export function probeMedia(filePath: string, projectName: string): Promise<MediaProbeInfo> {
50
+ return api.get<MediaProbeInfo>(mediaBase("probe", filePath, projectName));
51
+ }
@@ -0,0 +1,22 @@
1
+ import { usePanelStore } from "@/stores/panel-store";
2
+ import { basename } from "@/lib/utils";
3
+
4
+ /**
5
+ * Open a shell in the bottom dock that starts in `dir` (absolute host path).
6
+ *
7
+ * Used by "Open in Terminal" in the OS explorer and the project tree. The dock
8
+ * reveals itself and the tab is titled after the folder so several folder
9
+ * terminals stay distinguishable. `projectName` keeps the tab scoped to the
10
+ * project when the folder belongs to one; explorer folders outside any project
11
+ * pass none and the server only receives the start directory.
12
+ */
13
+ export function openTerminalAt(dir: string, projectName?: string | null): string {
14
+ const title = basename(dir) || dir;
15
+ return usePanelStore.getState().openInDock({
16
+ type: "terminal",
17
+ title,
18
+ projectId: projectName ?? null,
19
+ closable: true,
20
+ metadata: { cwd: dir, ...(projectName ? { projectName } : {}) },
21
+ });
22
+ }
@@ -0,0 +1,55 @@
1
+ import { usePanelStore } from "@/stores/panel-store";
2
+
3
+ /**
4
+ * Deliver a shell command to a terminal.
5
+ *
6
+ * Two delivery paths, because a shell that is still booting cannot accept input:
7
+ * 1. A terminal already on screen answers the event synchronously and types the
8
+ * command right away — its shell is long past the prompt.
9
+ * 2. Nobody answers ⇒ open a terminal in the dock and hand the command over via
10
+ * `metadata.pendingCommand`. The tab holds it until its shell has printed a
11
+ * prompt (see `use-terminal-command-queue`), so the text is never swallowed
12
+ * by shell startup.
13
+ */
14
+ export const RUN_IN_TERMINAL_EVENT = "ppm:run-in-terminal";
15
+ export const RUN_IN_TERMINAL_ACK_EVENT = "ppm:run-in-terminal:ack";
16
+
17
+ export interface RunInTerminalDetail {
18
+ command: string;
19
+ projectName?: string | null;
20
+ }
21
+
22
+ /**
23
+ * Normalize a copied code block into terminal input: drop `$ ` prompt markers and
24
+ * the trailing newline, so the last line waits on the user's Enter instead of
25
+ * running itself.
26
+ */
27
+ export function normalizeTerminalCommand(text: string): string {
28
+ // A space after the `$` is required: `$HOME/bin/tool` starting a line is part of
29
+ // the command, not a prompt.
30
+ return text.replace(/^[ \t]*\$[ \t]+/gm, "").replace(/\s+$/, "");
31
+ }
32
+
33
+ export function runInTerminal(rawCommand: string, projectName?: string | null): void {
34
+ const command = normalizeTerminalCommand(rawCommand);
35
+ if (!command) return;
36
+
37
+ // Offer it to a live terminal first (dispatch is synchronous, so the ack lands
38
+ // before this returns).
39
+ let handled = false;
40
+ const onAck = () => { handled = true; };
41
+ window.addEventListener(RUN_IN_TERMINAL_ACK_EVENT, onAck);
42
+ window.dispatchEvent(
43
+ new CustomEvent<RunInTerminalDetail>(RUN_IN_TERMINAL_EVENT, { detail: { command, projectName } }),
44
+ );
45
+ window.removeEventListener(RUN_IN_TERMINAL_ACK_EVENT, onAck);
46
+ if (handled) return;
47
+
48
+ usePanelStore.getState().openInDock({
49
+ type: "terminal",
50
+ title: "Terminal",
51
+ projectId: projectName ?? null,
52
+ closable: true,
53
+ metadata: { ...(projectName ? { projectName } : {}), pendingCommand: command },
54
+ });
55
+ }
@@ -0,0 +1,118 @@
1
+ import { usePanelStore } from "@/stores/panel-store";
2
+ import type { Tab } from "@/stores/tab-store";
3
+
4
+ /**
5
+ * Deliver text (terminal output, and anything else worth quoting) to ONE chat:
6
+ * the one the user last selected.
7
+ *
8
+ * The event is addressed with `targetTabId` because every chat tab stays mounted
9
+ * — an unaddressed event is answered by all of them at once, so the same output
10
+ * lands as an attachment in every open chat.
11
+ */
12
+ export const SEND_TO_CHAT_EVENT = "ppm:send-to-chat";
13
+ export const SEND_TO_CHAT_ACK_EVENT = "ppm:send-to-chat:ack";
14
+
15
+ export interface SendToChatDetail {
16
+ text: string;
17
+ label?: string;
18
+ projectName?: string | null;
19
+ /** Only the chat tab with this id may consume the event. */
20
+ targetTabId?: string;
21
+ }
22
+
23
+ /** Wall-clock activation stamp written by the panel store on every tab activation. */
24
+ function lastActiveAt(tab: Tab): number {
25
+ return typeof tab.metadata?.lastActiveAt === "number" ? (tab.metadata.lastActiveAt as number) : -1;
26
+ }
27
+
28
+ /**
29
+ * The chat tab the user last selected.
30
+ *
31
+ * Ranked, highest first:
32
+ * 1. selected AND in the focused panel — with a split, the chat being worked in.
33
+ * 2. selected — its panel's active tab, so it is a chat actually on screen. The
34
+ * activation stamp alone is not enough: a chat opened programmatically carries
35
+ * a fresh stamp the user never chose, and a chat left behind another tab in its
36
+ * panel keeps its stamp long after it stopped being the one in view.
37
+ * 3. newest activation — the only ordering that compares across panels, and the
38
+ * answer when no chat is on screen at all.
39
+ *
40
+ * Chats of the given project always win over other projects' chats.
41
+ */
42
+ export function resolveSelectedChatTabId(projectName?: string | null): string | null {
43
+ const { panels, focusedPanelId } = usePanelStore.getState();
44
+
45
+ const chats = Object.values(panels).flatMap((p) =>
46
+ p.tabs
47
+ .filter((t) => t.type === "chat")
48
+ .map((t) => ({
49
+ tab: t,
50
+ selected: p.activeTabId === t.id,
51
+ focusedPanel: p.id === focusedPanelId,
52
+ })),
53
+ );
54
+ if (chats.length === 0) return null;
55
+
56
+ const sameProject = projectName
57
+ ? chats.filter((c) => c.tab.projectId === projectName || c.tab.metadata?.projectName === projectName)
58
+ : [];
59
+ const pool = sameProject.length > 0 ? sameProject : chats;
60
+
61
+ // Panel focus only separates chats that are BOTH on screen. For chats nobody has
62
+ // in view, the panel it happens to live in says nothing about which one the user
63
+ // picked last — only the stamp does.
64
+ const rank = (c: (typeof pool)[number]): [number, number] => [
65
+ c.selected ? (c.focusedPanel ? 2 : 1) : 0,
66
+ lastActiveAt(c.tab),
67
+ ];
68
+ const best = pool.reduce((a, b) => {
69
+ const [ra, rb] = [rank(a), rank(b)];
70
+ for (let i = 0; i < ra.length; i++) {
71
+ if (ra[i]! !== rb[i]!) return ra[i]! > rb[i]! ? a : b;
72
+ }
73
+ return a;
74
+ });
75
+ return best.tab.id;
76
+ }
77
+
78
+ /**
79
+ * Send `text` to the chat the user last selected, as an attachment chip, focusing
80
+ * that chat so the user sees it arrive.
81
+ *
82
+ * Falls back through: live tab answers the event → tab exists but is not mounted
83
+ * yet, so hand the text over as `pendingMessage` → no chat open at all, open one.
84
+ */
85
+ export function sendToChat(opts: { text: string; label?: string; projectName?: string | null }): void {
86
+ const { text, label, projectName } = opts;
87
+ if (!text.trim()) return;
88
+
89
+ const targetTabId = resolveSelectedChatTabId(projectName);
90
+ const store = usePanelStore.getState();
91
+
92
+ if (targetTabId) {
93
+ store.setActiveTab(targetTabId);
94
+
95
+ let handled = false;
96
+ const onAck = () => { handled = true; };
97
+ window.addEventListener(SEND_TO_CHAT_ACK_EVENT, onAck);
98
+ window.dispatchEvent(
99
+ new CustomEvent<SendToChatDetail>(SEND_TO_CHAT_EVENT, { detail: { text, label, projectName, targetTabId } }),
100
+ );
101
+ window.removeEventListener(SEND_TO_CHAT_ACK_EVENT, onAck);
102
+ if (handled) return;
103
+
104
+ // Lazy-mounted tab: it has no listener yet, so leave the text in its metadata
105
+ // for the composer to pick up on mount.
106
+ const tab = Object.values(store.panels).flatMap((p) => p.tabs).find((t) => t.id === targetTabId);
107
+ store.updateTab(targetTabId, { metadata: { ...tab?.metadata, pendingMessage: text } });
108
+ return;
109
+ }
110
+
111
+ store.openTab({
112
+ type: "chat",
113
+ title: "Chat",
114
+ projectId: null,
115
+ metadata: { ...(projectName ? { projectName } : {}), pendingMessage: text },
116
+ closable: true,
117
+ });
118
+ }
@@ -0,0 +1,13 @@
1
+ import { getAuthToken } from "@/lib/api-client";
2
+
3
+ /**
4
+ * Append the session token to a `/ws/...` path so the server can authenticate
5
+ * the upgrade. Browsers cannot set headers on WebSocket handshakes, so every
6
+ * socket (global, extensions, terminal, chat, group) carries it as a query
7
+ * parameter — one helper keeps the spelling identical to what the server reads.
8
+ */
9
+ export function withWsAuth(path: string): string {
10
+ const token = getAuthToken();
11
+ if (!token || /[?&]token=/.test(path)) return path;
12
+ return `${path}${path.includes("?") ? "&" : "?"}token=${encodeURIComponent(token)}`;
13
+ }
@@ -1,3 +1,5 @@
1
+ import { withWsAuth } from "@/lib/ws-auth";
2
+
1
3
  type MessageHandler = (data: MessageEvent) => void;
2
4
 
3
5
  const MAX_RECONNECT_DELAY = 30_000;
@@ -33,17 +35,20 @@ export class WsClient {
33
35
  this.cleanup();
34
36
 
35
37
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
38
+ // Every app socket is authenticated at upgrade time; the token is read fresh
39
+ // on each (re)connect so a re-login mid-session is picked up.
40
+ const path = this.url.startsWith("ws") ? this.url : withWsAuth(this.url);
36
41
  let fullUrl: string;
37
- if (this.url.startsWith("ws")) {
38
- fullUrl = this.url;
39
- } else if (import.meta.env.DEV && this.url.startsWith("/ws/") && window.location.protocol !== "https:") {
42
+ if (path.startsWith("ws")) {
43
+ fullUrl = path;
44
+ } else if (import.meta.env.DEV && path.startsWith("/ws/") && window.location.protocol !== "https:") {
40
45
  // Local dev over http: connect directly to backend (port 8081) to bypass
41
46
  // Vite's dev proxy which has unreliable WebSocket upgrade handling.
42
47
  // Over https (e.g. a Cloudflare tunnel) port 8081 isn't reachable and ws://
43
48
  // is blocked as mixed content, so fall through to same-origin wss:// proxy.
44
- fullUrl = `ws://${window.location.hostname}:8081${this.url}`;
49
+ fullUrl = `ws://${window.location.hostname}:8081${path}`;
45
50
  } else {
46
- fullUrl = `${protocol}//${window.location.host}${this.url}`;
51
+ fullUrl = `${protocol}//${window.location.host}${path}`;
47
52
  }
48
53
 
49
54
  this.ws = new WebSocket(fullUrl);
package/.release-run.sh DELETED
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Temporary runner: invokes the release script with bun on PATH. Deleted after use.
3
- export PATH="$HOME/.bun/bin:$PATH"
4
- cd /c/Users/PC/ppm || exit 1
5
- exec bash scripts/release.sh 0.18.2
@@ -1 +0,0 @@
1
- import"./vendor-markdown-Ls5AcU91.js";import"./vendor-ui-CaeeFO0B.js";import{i as e,n as t}from"./api-client-rTAGdEKo.js";export{t as api,e as projectUrl};
@@ -1 +0,0 @@
1
- import"./vendor-markdown-Ls5AcU91.js";import"./vendor-ui-CaeeFO0B.js";import"./api-client-rTAGdEKo.js";import{v as e}from"./api-settings-CAhcNpj5.js";export{e as updateDeviceName};
@@ -1 +0,0 @@
1
- import{K as e}from"./vendor-mermaid-C977xNeE.js";export{e as createArchitectureServices};
@@ -1 +0,0 @@
1
- import{x as e}from"./vendor-markdown-Ls5AcU91.js";import"./vendor-ui-CaeeFO0B.js";import{t}from"./createLucideIcon-D8pyde1A.js";import{t as n}from"./file-exclamation-point-COAwgNGw.js";import"./api-client-rTAGdEKo.js";import{t as r}from"./utils-B9H0d3Fh.js";import{Hn as i}from"./index-wd3FSHHn.js";import{t as a}from"./use-blob-url-DYtOHK7u.js";var o=t(`music`,[[`path`,{d:`M9 18V5l12-2v13`,key:`1jmyc2`}],[`circle`,{cx:`6`,cy:`18`,r:`3`,key:`fqmcym`}],[`circle`,{cx:`18`,cy:`16`,r:`3`,key:`1hluhg`}]]),s=e();function c({filePath:e,projectName:t}){let{blobUrl:c,error:l}=a(e,t);return l?(0,s.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-3 text-text-secondary`,children:[(0,s.jsx)(n,{className:`size-10 text-text-subtle`}),(0,s.jsx)(`p`,{className:`text-sm`,children:`Failed to load audio.`})]}):c?(0,s.jsxs)(`div`,{className:`flex flex-col items-center justify-center h-full gap-4 p-4 bg-surface`,children:[(0,s.jsx)(o,{className:`size-16 text-text-subtle`}),(0,s.jsx)(`p`,{className:`text-sm text-text-secondary truncate max-w-xs`,children:r(e)}),(0,s.jsx)(`audio`,{src:c,controls:!0,className:`w-full max-w-md`})]}):(0,s.jsx)(`div`,{className:`flex items-center justify-center h-full`,children:(0,s.jsx)(i,{className:`size-5 animate-spin text-text-subtle`})})}export{c as AudioPreview};