@vibe-forge/client 0.9.0 → 0.10.1

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 (301) hide show
  1. package/AGENTS.md +75 -0
  2. package/dist/assets/abap-DLDM7-KI.js +1 -0
  3. package/dist/assets/apex-DNDY2TF8.js +1 -0
  4. package/dist/assets/{arc-D9HxM0yv.js → arc-C1rWFTer.js} +1 -1
  5. package/dist/assets/azcli-Y6nb8tq_.js +1 -0
  6. package/dist/assets/bat-BwHxbl9M.js +1 -0
  7. package/dist/assets/bicep-CFznDFnq.js +2 -0
  8. package/dist/assets/{blockDiagram-c4efeb88-C_pTeiD4.js → blockDiagram-c4efeb88-DlZ9x70F.js} +1 -1
  9. package/dist/assets/{c4Diagram-c83219d4-_oYrCrLr.js → c4Diagram-c83219d4-BKKxi__y.js} +1 -1
  10. package/dist/assets/cameligo-Bf6VGUru.js +1 -0
  11. package/dist/assets/channel-F1aqMANO.js +1 -0
  12. package/dist/assets/{classDiagram-beda092f-9dnkgPhR.js → classDiagram-beda092f-CVGPySZq.js} +1 -1
  13. package/dist/assets/{classDiagram-v2-2358418a-BUIeZpdO.js → classDiagram-v2-2358418a-7kp8GVVj.js} +1 -1
  14. package/dist/assets/clojure-Dnu-v4kV.js +1 -0
  15. package/dist/assets/clone-B-GCuXNo.js +1 -0
  16. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  17. package/dist/assets/coffee-Bd8akH9Z.js +1 -0
  18. package/dist/assets/cpp-BbWJElDN.js +1 -0
  19. package/dist/assets/{createText-1719965b-DuRFplcD.js → createText-1719965b-Dykv8kT9.js} +1 -1
  20. package/dist/assets/csharp-Co3qMtFm.js +1 -0
  21. package/dist/assets/csp-D-4FJmMZ.js +1 -0
  22. package/dist/assets/css-DdJfP1eB.js +3 -0
  23. package/dist/assets/css.worker-BvV5MPou.js +93 -0
  24. package/dist/assets/cssMode-B59COYVW.js +1 -0
  25. package/dist/assets/cypher-cTPe9QuQ.js +1 -0
  26. package/dist/assets/dart-BOtBlQCF.js +1 -0
  27. package/dist/assets/dockerfile-BG73LgW2.js +1 -0
  28. package/dist/assets/ecl-BEgZUVRK.js +1 -0
  29. package/dist/assets/{edges-96097737-CTpq6Ih_.js → edges-96097737-CkZ1ZBro.js} +1 -1
  30. package/dist/assets/editor.worker-CKy7Pnvo.js +26 -0
  31. package/dist/assets/elixir-BkW5O-1t.js +1 -0
  32. package/dist/assets/{erDiagram-0228fc6a-CWFgdO1E.js → erDiagram-0228fc6a-281ADcRp.js} +1 -1
  33. package/dist/assets/flow9-BeJ5waoc.js +1 -0
  34. package/dist/assets/{flowDb-c6c81e3f-8Vdx29oZ.js → flowDb-c6c81e3f-BQjX_flP.js} +1 -1
  35. package/dist/assets/{flowDiagram-50d868cf-6S9wOVNl.js → flowDiagram-50d868cf-DMHZTjES.js} +1 -1
  36. package/dist/assets/flowDiagram-v2-4f6560a1-C5FzdVl1.js +1 -0
  37. package/dist/assets/{flowchart-elk-definition-6af322e1-DVcZ-ZBQ.js → flowchart-elk-definition-6af322e1-CI3yz4z8.js} +1 -1
  38. package/dist/assets/freemarker2-DWnWjibn.js +3 -0
  39. package/dist/assets/fsharp-PahG7c26.js +1 -0
  40. package/dist/assets/{ganttDiagram-a2739b55-DY1QSl-x.js → ganttDiagram-a2739b55-B3IING9L.js} +1 -1
  41. package/dist/assets/{gitGraphDiagram-82fe8481-BP08OBKL.js → gitGraphDiagram-82fe8481-CnArIr_T.js} +1 -1
  42. package/dist/assets/go-acbASCJo.js +1 -0
  43. package/dist/assets/{graph-D8GCszcN.js → graph-BZ1F0Yve.js} +1 -1
  44. package/dist/assets/graphql-BxJiqAUM.js +1 -0
  45. package/dist/assets/handlebars-C1QH9qTz.js +1 -0
  46. package/dist/assets/hcl-DtV1sZF8.js +1 -0
  47. package/dist/assets/html-D1NkqHjC.js +1 -0
  48. package/dist/assets/html.worker-BLJhxQJQ.js +470 -0
  49. package/dist/assets/htmlMode-DAZCE_rA.js +1 -0
  50. package/dist/assets/{index-5325376f-OOoAXU1u.js → index-5325376f-Da9zSHjA.js} +1 -1
  51. package/dist/assets/index-C0vjF3D0.js +1511 -0
  52. package/dist/assets/index-vzEbM21t.css +32 -0
  53. package/dist/assets/{infoDiagram-8eee0895-BHgkXjhJ.js → infoDiagram-8eee0895-DYbFvRM7.js} +1 -1
  54. package/dist/assets/ini-Kd9XrMLS.js +1 -0
  55. package/dist/assets/java-CXBNlu9o.js +1 -0
  56. package/dist/assets/javascript-CoMjGRHa.js +1 -0
  57. package/dist/assets/{journeyDiagram-c64418c1-BljInElp.js → journeyDiagram-c64418c1-Boebox0b.js} +1 -1
  58. package/dist/assets/json.worker-usMZ-FED.js +58 -0
  59. package/dist/assets/jsonMode-D__gAvuz.js +7 -0
  60. package/dist/assets/julia-cl7-CwDS.js +1 -0
  61. package/dist/assets/kotlin-s7OhZKlX.js +1 -0
  62. package/dist/assets/{layout-Cw-SwAFD.js → layout-CTcHNbHp.js} +1 -1
  63. package/dist/assets/less-9HpZscsL.js +2 -0
  64. package/dist/assets/lexon-OrD6JF1K.js +1 -0
  65. package/dist/assets/{line-Q-uZLuUr.js → line-4AwinCz2.js} +1 -1
  66. package/dist/assets/{linear-BahOnNn3.js → linear-CeSMLzJW.js} +1 -1
  67. package/dist/assets/liquid-DZF6egdE.js +1 -0
  68. package/dist/assets/lspLanguageFeatures-6K4lv5S2.js +4 -0
  69. package/dist/assets/lua-Cyyb5UIc.js +1 -0
  70. package/dist/assets/m3-B8OfTtLu.js +1 -0
  71. package/dist/assets/markdown-BFxVWTOG.js +1 -0
  72. package/dist/assets/mdx-Cnt4ka6w.js +1 -0
  73. package/dist/assets/{mermaid.core-BR0Qh3Rd.js → mermaid.core-B0yG5s4D.js} +6 -6
  74. package/dist/assets/{mindmap-definition-8da855dc-Brq2OJUZ.js → mindmap-definition-8da855dc-KJEvXMKj.js} +1 -1
  75. package/dist/assets/mips-CiqrrVzr.js +1 -0
  76. package/dist/assets/msdax-DmeGPVcC.js +1 -0
  77. package/dist/assets/mysql-C_tMU-Nz.js +1 -0
  78. package/dist/assets/objective-c-BDtDVThU.js +1 -0
  79. package/dist/assets/pascal-vHIfCaH5.js +1 -0
  80. package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  81. package/dist/assets/perl-Ub6l9XKa.js +1 -0
  82. package/dist/assets/pgsql-BlNEE0v7.js +1 -0
  83. package/dist/assets/php-BBUBE1dy.js +1 -0
  84. package/dist/assets/{pieDiagram-a8764435-uhYdiXro.js → pieDiagram-a8764435-17nFAXPJ.js} +1 -1
  85. package/dist/assets/pla-DSh2-awV.js +1 -0
  86. package/dist/assets/postiats-CocnycG-.js +1 -0
  87. package/dist/assets/powerquery-tScXyioY.js +1 -0
  88. package/dist/assets/powershell-COWaemsV.js +1 -0
  89. package/dist/assets/protobuf-Brw8urJB.js +2 -0
  90. package/dist/assets/pug-8SOpv6rk.js +1 -0
  91. package/dist/assets/python-DA3TtjDv.js +1 -0
  92. package/dist/assets/qsharp-Bw9ernYp.js +1 -0
  93. package/dist/assets/{quadrantDiagram-1e28029f-TwqtEe7e.js → quadrantDiagram-1e28029f-Dt4vubi-.js} +1 -1
  94. package/dist/assets/r-j7ic8hl3.js +1 -0
  95. package/dist/assets/razor-CWDJgvX_.js +1 -0
  96. package/dist/assets/redis-Bu5POkcn.js +1 -0
  97. package/dist/assets/redshift-Bs9aos_-.js +1 -0
  98. package/dist/assets/{requirementDiagram-08caed73-DSXnPRDS.js → requirementDiagram-08caed73-H6aDyDK-.js} +1 -1
  99. package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  100. package/dist/assets/ruby-zBfavPgS.js +1 -0
  101. package/dist/assets/rust-BzKRNQWT.js +1 -0
  102. package/dist/assets/{sankeyDiagram-a04cb91d-EADpJeAn.js → sankeyDiagram-a04cb91d-DxsVtbjI.js} +1 -1
  103. package/dist/assets/sb-BBc9UKZt.js +1 -0
  104. package/dist/assets/scala-D9hQfWCl.js +1 -0
  105. package/dist/assets/scheme-BPhDTwHR.js +1 -0
  106. package/dist/assets/scss-CBJaRo0y.js +3 -0
  107. package/dist/assets/{sequenceDiagram-c5b8d532-C8qXvt9z.js → sequenceDiagram-c5b8d532-BHa148XJ.js} +1 -1
  108. package/dist/assets/shell-DiJ1NA_G.js +1 -0
  109. package/dist/assets/solidity-Db0IVjzk.js +1 -0
  110. package/dist/assets/sophia-CnS9iZB_.js +1 -0
  111. package/dist/assets/sparql-CJmd_6j2.js +1 -0
  112. package/dist/assets/sql-ClhHkBeG.js +1 -0
  113. package/dist/assets/st-CHwy0fLd.js +1 -0
  114. package/dist/assets/{stateDiagram-1ecb1508-5W0ghy_S.js → stateDiagram-1ecb1508-DgwBm8LO.js} +1 -1
  115. package/dist/assets/{stateDiagram-v2-c2b004d7-BfwOQJw4.js → stateDiagram-v2-c2b004d7-BK7IQLVc.js} +1 -1
  116. package/dist/assets/{styles-b4e223ce-EkKH_ULb.js → styles-b4e223ce-DzW27Bc-.js} +1 -1
  117. package/dist/assets/{styles-ca3715f6-DwhrtqlU.js → styles-ca3715f6-Dex2GiLT.js} +1 -1
  118. package/dist/assets/{styles-d45a18b0-yqL8KH6x.js → styles-d45a18b0-B6fGtDKS.js} +1 -1
  119. package/dist/assets/{svgDrawCommon-b86b1483--5VjnjhC.js → svgDrawCommon-b86b1483-B4HYgfV5.js} +1 -1
  120. package/dist/assets/swift-Bqt4WxQ4.js +3 -0
  121. package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  122. package/dist/assets/tcl-Dm6ycUr_.js +1 -0
  123. package/dist/assets/{timeline-definition-faaaa080-CWOTwik9.js → timeline-definition-faaaa080--QSbWb25.js} +1 -1
  124. package/dist/assets/ts.worker-DGHjMaqB.js +67731 -0
  125. package/dist/assets/tsMode-ZM7ocZCH.js +11 -0
  126. package/dist/assets/twig-Csy3S7wG.js +1 -0
  127. package/dist/assets/typescript-CKWDmBCc.js +1 -0
  128. package/dist/assets/typespec-Btyra-wh.js +1 -0
  129. package/dist/assets/vb-Db0cS2oM.js +1 -0
  130. package/dist/assets/wgsl-BTesnYfV.js +298 -0
  131. package/dist/assets/xml-DuEUAzPi.js +1 -0
  132. package/dist/assets/{xychartDiagram-f5964ef8-CZg47H1t.js → xychartDiagram-f5964ef8-D09Zkv2K.js} +1 -1
  133. package/dist/assets/yaml-DL7QPRYk.js +1 -0
  134. package/dist/favicon.svg +3 -3
  135. package/dist/index.html +2 -2
  136. package/package.json +14 -10
  137. package/public/favicon.svg +3 -3
  138. package/src/api/sessions.ts +36 -0
  139. package/src/api/workspace.ts +19 -0
  140. package/src/api.ts +4 -0
  141. package/src/components/NavRail.scss +9 -10
  142. package/src/components/ShortcutDisplay.scss +38 -0
  143. package/src/components/ShortcutDisplay.tsx +37 -0
  144. package/src/components/ShortcutTooltip.scss +36 -0
  145. package/src/components/ShortcutTooltip.tsx +84 -0
  146. package/src/components/Sidebar.scss +55 -13
  147. package/src/components/Sidebar.tsx +141 -52
  148. package/src/components/chat/AGENTS.md +163 -0
  149. package/src/components/chat/ChatHeader.scss +308 -49
  150. package/src/components/chat/ChatHeader.tsx +394 -80
  151. package/src/components/chat/ChatHistoryView.tsx +353 -69
  152. package/src/components/chat/ChatSettingsView.tsx +5 -3
  153. package/src/components/chat/ChatTimelineView.scss +3 -2
  154. package/src/components/chat/{sender/ThinkingStatus.tsx → ThinkingStatus.tsx} +1 -1
  155. package/src/components/chat/messages/MessageContextMenu.scss +145 -0
  156. package/src/components/chat/messages/MessageContextMenu.tsx +108 -0
  157. package/src/components/chat/messages/MessageContextMenuContent.tsx +87 -0
  158. package/src/components/chat/messages/MessageFooter.tsx +44 -24
  159. package/src/components/chat/messages/MessageItem.scss +157 -10
  160. package/src/components/chat/messages/MessageItem.tsx +382 -13
  161. package/src/components/chat/messages/build-message-context-menu-entries.ts +166 -0
  162. package/src/components/chat/messages/message-content-utils.ts +121 -0
  163. package/src/components/chat/messages/message-turns.ts +88 -0
  164. package/src/components/chat/messages/message-utils.ts +19 -1
  165. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +86 -0
  166. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.tsx +54 -0
  167. package/src/components/chat/sender/@components/adapter-select/AdapterSelectDropdown.scss +42 -0
  168. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.scss +68 -0
  169. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.tsx +137 -0
  170. package/src/components/chat/sender/@components/effort-select/EffortSelectDropdown.scss +96 -0
  171. package/src/components/chat/sender/@components/model-select/ModelSelectControl.scss +82 -0
  172. package/src/components/chat/sender/@components/model-select/ModelSelectControl.tsx +171 -0
  173. package/src/components/chat/sender/@components/model-select/ModelSelectMenu.scss +95 -0
  174. package/src/components/chat/sender/@components/model-select/ModelSelectMenuLabels.scss +144 -0
  175. package/src/components/chat/sender/@components/model-select/ModelSelectOptionLabel.tsx +109 -0
  176. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +106 -0
  177. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.tsx +156 -0
  178. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsOption.scss +34 -0
  179. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +111 -0
  180. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +103 -0
  181. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +47 -0
  182. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +137 -0
  183. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +178 -0
  184. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +145 -0
  185. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.scss +47 -0
  186. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +121 -0
  187. package/src/components/chat/sender/@components/sender-monaco-editor/monaco-runtime.ts +99 -0
  188. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-editor-handle.ts +48 -0
  189. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +209 -0
  190. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +24 -0
  191. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +54 -0
  192. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +80 -0
  193. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +71 -0
  194. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +118 -0
  195. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +99 -0
  196. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +87 -0
  197. package/src/components/chat/sender/@core/build-sender-controller-result.ts +119 -0
  198. package/src/components/chat/sender/@core/build-sender-toolbar.ts +122 -0
  199. package/src/components/chat/sender/@core/content-attachments.ts +76 -0
  200. package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +115 -0
  201. package/src/components/chat/sender/@core/get-sender-interaction-state.ts +18 -0
  202. package/src/components/chat/sender/@core/get-sender-runtime-state.ts +14 -0
  203. package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +155 -0
  204. package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +189 -0
  205. package/src/components/chat/sender/@hooks/use-sender-attachments.ts +143 -0
  206. package/src/components/chat/sender/@hooks/use-sender-autofocus.ts +34 -0
  207. package/src/components/chat/sender/@hooks/use-sender-completion.ts +62 -0
  208. package/src/components/chat/sender/@hooks/use-sender-composer-state.ts +34 -0
  209. package/src/components/chat/sender/@hooks/use-sender-controller.ts +193 -0
  210. package/src/components/chat/sender/@hooks/use-sender-focus-restore.ts +72 -0
  211. package/src/components/chat/sender/@hooks/use-sender-history.ts +79 -0
  212. package/src/components/chat/sender/@hooks/use-sender-keydown.ts +113 -0
  213. package/src/components/chat/sender/@hooks/use-sender-reference-actions.ts +191 -0
  214. package/src/components/chat/sender/@hooks/use-sender-reference-focus-restore.ts +21 -0
  215. package/src/components/chat/sender/@hooks/use-sender-refs.ts +19 -0
  216. package/src/components/chat/sender/@hooks/use-sender-select-overlays.ts +83 -0
  217. package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +78 -0
  218. package/src/components/chat/sender/@hooks/use-sender-submit.ts +81 -0
  219. package/src/components/chat/sender/@types/sender-composer.ts +19 -0
  220. package/src/components/chat/sender/@types/sender-editor.ts +12 -0
  221. package/src/components/chat/sender/@types/sender-props.ts +50 -0
  222. package/src/components/chat/sender/@types/sender-toolbar-types.ts +83 -0
  223. package/src/components/chat/sender/@types/sender-types.ts +21 -0
  224. package/src/components/chat/sender/@utils/sender-completion.ts +164 -0
  225. package/src/components/chat/sender/@utils/sender-constants.ts +18 -0
  226. package/src/components/chat/sender/@utils/sender-utils.ts +45 -0
  227. package/src/components/chat/sender/Sender.scss +6 -737
  228. package/src/components/chat/sender/Sender.tsx +53 -921
  229. package/src/components/chat/session-metadata.ts +55 -0
  230. package/src/components/chat/terminal/@hooks/use-terminal-instance.ts +152 -0
  231. package/src/components/chat/terminal/@hooks/use-terminal-session.ts +196 -0
  232. package/src/components/chat/terminal/ChatTerminalView.scss +62 -0
  233. package/src/components/chat/terminal/ChatTerminalView.tsx +114 -0
  234. package/src/components/chat/tools/core/ToolGroup.scss +7 -0
  235. package/src/components/chat/tools/core/ToolGroup.tsx +94 -44
  236. package/src/components/config/ConfigSectionForm.tsx +8 -1
  237. package/src/components/config/ConfigShortcutInput.tsx +9 -2
  238. package/src/components/config/configSchema.ts +12 -2
  239. package/src/components/config/record-editors/ModelServicesRecordEditor.tsx +0 -14
  240. package/src/components/dock-panel/DockPanel.scss +152 -0
  241. package/src/components/dock-panel/DockPanel.tsx +195 -0
  242. package/src/components/layout/AppShell.scss +40 -2
  243. package/src/components/layout/AppShell.tsx +25 -10
  244. package/src/components/sidebar/SessionContextMenu.scss +143 -0
  245. package/src/components/sidebar/SessionContextMenu.tsx +196 -0
  246. package/src/components/sidebar/SessionContextMenuContent.tsx +89 -0
  247. package/src/components/sidebar/SessionItem.scss +150 -67
  248. package/src/components/sidebar/SessionItem.tsx +183 -134
  249. package/src/components/sidebar/SessionList.scss +47 -17
  250. package/src/components/sidebar/SessionList.tsx +31 -16
  251. package/src/components/sidebar/SidebarHeader.scss +329 -49
  252. package/src/components/sidebar/SidebarHeader.tsx +108 -86
  253. package/src/components/sidebar/SidebarHeaderBatchActions.tsx +81 -0
  254. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +176 -0
  255. package/src/components/sidebar/SidebarHeaderSelectField.tsx +24 -0
  256. package/src/components/sidebar/filter-utils.ts +23 -0
  257. package/src/components/workspace/ContextFilePicker.scss +64 -0
  258. package/src/components/workspace/ContextFilePicker.tsx +171 -0
  259. package/src/connectionManager.ts +4 -2
  260. package/src/hooks/chat/interaction-state.ts +67 -0
  261. package/src/hooks/chat/model-selector-data-builders.ts +146 -0
  262. package/src/hooks/chat/model-selector-data-option-utils.ts +62 -0
  263. package/src/hooks/chat/model-selector-data-types.ts +27 -0
  264. package/src/hooks/chat/model-selector-data.ts +109 -0
  265. package/src/hooks/chat/model-selector-recommendations.ts +69 -0
  266. package/src/hooks/chat/model-selector.ts +9 -0
  267. package/src/hooks/chat/use-chat-interaction.ts +13 -8
  268. package/src/hooks/chat/use-chat-model-adapter-selection.tsx +167 -164
  269. package/src/hooks/chat/use-chat-models.tsx +46 -23
  270. package/src/hooks/chat/use-chat-session-actions.ts +69 -23
  271. package/src/hooks/chat/use-chat-session-messages.ts +158 -60
  272. package/src/hooks/chat/use-chat-session.ts +34 -9
  273. package/src/hooks/chat/use-chat-view.ts +26 -6
  274. package/src/hooks/chat/use-composer-control-shortcuts.ts +69 -0
  275. package/src/hooks/chat/use-terminal-dock-visibility.ts +39 -0
  276. package/src/hooks/use-roving-focus-list.ts +104 -0
  277. package/src/hooks/use-sidebar-navigation.ts +9 -4
  278. package/src/hooks/use-sidebar-query-state.ts +79 -0
  279. package/src/main.tsx +6 -1
  280. package/src/resources/locales/en.json +140 -6
  281. package/src/resources/locales/zh.json +140 -6
  282. package/src/routes/ChatRoute.scss +159 -4
  283. package/src/routes/ChatRoute.tsx +72 -10
  284. package/src/runtime-config.ts +21 -0
  285. package/src/store/index.ts +1 -3
  286. package/src/styles/global.scss +12 -2
  287. package/src/utils/chat-links.ts +21 -0
  288. package/src/utils/copy.ts +18 -0
  289. package/src/utils/shortcutUtils.ts +111 -1
  290. package/src/vite-env.d.ts +1 -0
  291. package/src/ws.ts +6 -5
  292. package/vite.config.ts +71 -7
  293. package/dist/assets/channel-Di8KkPU4.js +0 -1
  294. package/dist/assets/clone-B065n6L-.js +0 -1
  295. package/dist/assets/flowDiagram-v2-4f6560a1-nj-oVLPK.js +0 -1
  296. package/dist/assets/index-BZe1Qtye.css +0 -1
  297. package/dist/assets/index-DV3eI2aD.js +0 -557
  298. package/src/components/chat/sender/CompletionMenu.scss +0 -70
  299. package/src/components/chat/sender/CompletionMenu.tsx +0 -58
  300. /package/src/components/chat/{sender/ThinkingStatus.scss → ThinkingStatus.scss} +0 -0
  301. /package/src/components/chat/sender/{interaction-request.ts → @core/interaction-request.ts} +0 -0
@@ -3,14 +3,20 @@ import './ToolGroup.scss'
3
3
  import type { ChatMessage, ChatMessageContent } from '@vibe-forge/core'
4
4
  import React, { useState } from 'react'
5
5
  import { useTranslation } from 'react-i18next'
6
+ import { useSearchParams } from 'react-router-dom'
7
+ import { MessageContextMenu } from '../../messages/MessageContextMenu'
6
8
  import { MessageFooter } from '../../messages/MessageFooter'
7
9
  import { ToolRenderer } from './ToolRenderer'
8
10
 
9
11
  interface ToolGroupProps {
12
+ anchorId: string
10
13
  items: {
11
14
  item: Extract<ChatMessageContent, { type: 'tool_use' }>
12
15
  resultItem?: Extract<ChatMessageContent, { type: 'tool_result' }>
13
16
  }[]
17
+ originalMessage: ChatMessage
18
+ sessionId?: string
19
+ targetToolUseId?: string
14
20
  footer?: {
15
21
  model?: string
16
22
  usage?: ChatMessage['usage']
@@ -20,39 +26,76 @@ interface ToolGroupProps {
20
26
  }
21
27
 
22
28
  function ToolGroupComponent({
29
+ anchorId,
23
30
  items,
31
+ originalMessage,
32
+ sessionId,
33
+ targetToolUseId,
24
34
  footer
25
35
  }: ToolGroupProps) {
26
36
  const { t } = useTranslation()
37
+ const [searchParams] = useSearchParams()
38
+ const isDebugMode = searchParams.get('debug') === 'true'
27
39
  const [expanded, setExpanded] = useState(false)
28
40
 
41
+ const lastItem = items[items.length - 1]
42
+ const otherItems = items.slice(0, -1)
43
+ const shouldForceExpand = targetToolUseId != null &&
44
+ targetToolUseId !== '' &&
45
+ otherItems.some(item => item.item.id === targetToolUseId)
46
+ const isExpanded = expanded || shouldForceExpand
47
+
29
48
  if (items.length === 0) return null
30
49
 
31
50
  // If only one item, just render it directly (wrapped in container for footer)
32
51
  if (items.length === 1) {
33
52
  return (
34
- <div className='tool-group-container'>
35
- <div className='tool-group-wrapper single-item'>
36
- <ToolRenderer
37
- item={items[0].item}
38
- resultItem={items[0].resultItem}
39
- />
40
- </div>
41
- {footer && (
42
- <div className='tool-group-footer-wrapper'>
43
- <MessageFooter msg={footer.originalMessage} isUser={false} />
53
+ <MessageContextMenu
54
+ anchorId={anchorId}
55
+ canEdit={false}
56
+ canFork={false}
57
+ canRecall={false}
58
+ isDebugMode={isDebugMode}
59
+ isEditing={false}
60
+ message={originalMessage}
61
+ sessionId={sessionId}
62
+ onFork={() => {}}
63
+ onRecall={() => {}}
64
+ onStartEditing={() => {}}
65
+ >
66
+ <div id={anchorId} className='tool-group-container'>
67
+ <div className='tool-group-wrapper single-item' data-tool-use-id={items[0].item.id}>
68
+ <ToolRenderer
69
+ item={items[0].item}
70
+ resultItem={items[0].resultItem}
71
+ />
44
72
  </div>
45
- )}
46
- </div>
73
+ {footer && isDebugMode && (
74
+ <div className='tool-group-footer-wrapper'>
75
+ <MessageFooter msg={footer.originalMessage} isUser={false} />
76
+ </div>
77
+ )}
78
+ </div>
79
+ </MessageContextMenu>
47
80
  )
48
81
  }
49
82
 
50
- const lastItem = items[items.length - 1]
51
- const otherItems = items.slice(0, -1)
52
-
53
83
  return (
54
- <div className='tool-group-container'>
55
- <div className='tool-group-wrapper card-style'>
84
+ <MessageContextMenu
85
+ anchorId={anchorId}
86
+ canEdit={false}
87
+ canFork={false}
88
+ canRecall={false}
89
+ isDebugMode={isDebugMode}
90
+ isEditing={false}
91
+ message={originalMessage}
92
+ sessionId={sessionId}
93
+ onFork={() => {}}
94
+ onRecall={() => {}}
95
+ onStartEditing={() => {}}
96
+ >
97
+ <div id={anchorId} className='tool-group-container'>
98
+ <div className='tool-group-wrapper card-style'>
56
99
  <div
57
100
  className='tool-group-header'
58
101
  onClick={() => setExpanded(!expanded)}
@@ -62,54 +105,61 @@ function ToolGroupComponent({
62
105
  <span>{t('chat.usedTools', { count: items.length })}</span>
63
106
  </div>
64
107
  <span className='material-symbols-rounded expand-icon'>
65
- {expanded ? 'expand_less' : 'expand_more'}
108
+ {isExpanded ? 'expand_less' : 'expand_more'}
66
109
  </span>
67
110
  </div>
68
111
 
69
- {expanded && (
112
+ {isExpanded && (
70
113
  <div className='tool-group-list'>
71
114
  {otherItems.map((it, idx) => (
72
- <ToolRenderer
73
- key={it.item.id || idx}
74
- item={it.item}
75
- resultItem={it.resultItem}
76
- />
115
+ <div key={it.item.id || idx} data-tool-use-id={it.item.id}>
116
+ <ToolRenderer
117
+ item={it.item}
118
+ resultItem={it.resultItem}
119
+ />
120
+ </div>
77
121
  ))}
78
122
  </div>
79
123
  )}
80
124
 
81
- {
82
- /* Always show the last item, but if expanded, it's just part of the list visually.
83
- If collapsed, it appears "below" the header.
84
- Actually, to make it look like "part of the list", we should just put it in the flow.
125
+ {
126
+ /* Always show the last item, but if expanded, it's just part of the list visually.
127
+ If collapsed, it appears "below" the header.
128
+ Actually, to make it look like "part of the list", we should just put it in the flow.
85
129
 
86
- When collapsed: Header + Last Item
87
- When expanded: Header + Other Items + Last Item
88
- */
89
- }
90
- <div className='tool-group-last-item'>
91
- <ToolRenderer
92
- item={lastItem.item}
93
- resultItem={lastItem.resultItem}
94
- />
95
- </div>
96
- </div>
130
+ When collapsed: Header + Last Item
131
+ When expanded: Header + Other Items + Last Item
132
+ */
133
+ }
134
+ <div className='tool-group-last-item' data-tool-use-id={lastItem.item.id}>
135
+ <ToolRenderer
136
+ item={lastItem.item}
137
+ resultItem={lastItem.resultItem}
138
+ />
139
+ </div>
97
140
 
98
- {footer && (
99
- <div className='tool-group-footer-wrapper'>
100
- <MessageFooter msg={footer.originalMessage} isUser={false} />
101
141
  </div>
102
- )}
103
- </div>
142
+
143
+ {footer && isDebugMode && (
144
+ <div className='tool-group-footer-wrapper'>
145
+ <MessageFooter msg={footer.originalMessage} isUser={false} />
146
+ </div>
147
+ )}
148
+ </div>
149
+ </MessageContextMenu>
104
150
  )
105
151
  }
106
152
 
107
153
  const areToolGroupPropsEqual = (prev: ToolGroupProps, next: ToolGroupProps) => {
154
+ if (prev.anchorId !== next.anchorId) return false
108
155
  if (prev.items.length !== next.items.length) return false
156
+ if (prev.targetToolUseId !== next.targetToolUseId) return false
109
157
  for (let i = 0; i < prev.items.length; i++) {
110
158
  if (prev.items[i].item !== next.items[i].item) return false
111
159
  if (prev.items[i].resultItem !== next.items[i].resultItem) return false
112
160
  }
161
+ if (prev.originalMessage !== next.originalMessage) return false
162
+ if (prev.sessionId !== next.sessionId) return false
113
163
  if (prev.footer == null && next.footer == null) return true
114
164
  if (prev.footer == null || next.footer == null) return false
115
165
  return prev.footer.originalMessage === next.footer.originalMessage &&
@@ -3,6 +3,7 @@ import './ConfigSectionForm.scss'
3
3
  import { Collapse, Empty, Input, InputNumber, Select, Slider, Switch } from 'antd'
4
4
  import type { ReactNode } from 'react'
5
5
 
6
+ import { normalizeSendShortcut, resolveSendShortcut } from '#~/utils/shortcutUtils'
6
7
  import { ComplexTextEditor, StringArrayEditor } from './ConfigEditors'
7
8
  import { FieldRow } from './ConfigFieldRow'
8
9
  import { ShortcutInput } from './ConfigShortcutInput'
@@ -297,11 +298,17 @@ export const SectionForm = ({
297
298
  }
298
299
  } else if (field.type === 'shortcut') {
299
300
  const isMac = navigator.platform.includes('Mac')
301
+ const rawValue = typeof valueToUse === 'string' ? valueToUse : ''
302
+ const isSendMessageShortcut = field.shortcutKind === 'sendMessage'
300
303
  control = (
301
304
  <ShortcutInput
302
- value={typeof valueToUse === 'string' ? valueToUse : ''}
305
+ value={rawValue}
306
+ displayValue={isSendMessageShortcut ? resolveSendShortcut(rawValue, isMac) : undefined}
303
307
  onChange={(next) => handleValueChange(next)}
304
308
  placeholder={t('config.editor.shortcutPlaceholder')}
309
+ normalizeShortcut={isSendMessageShortcut
310
+ ? (next) => normalizeSendShortcut(next, isMac)
311
+ : undefined}
305
312
  isMac={isMac}
306
313
  t={t}
307
314
  />
@@ -7,18 +7,23 @@ import { formatShortcutLabel, getShortcutFromEvent } from '../../utils/shortcutU
7
7
 
8
8
  export const ShortcutInput = ({
9
9
  value,
10
+ displayValue,
10
11
  onChange,
11
12
  placeholder,
13
+ normalizeShortcut,
12
14
  isMac,
13
15
  t
14
16
  }: {
15
17
  value: string
18
+ displayValue?: string
16
19
  onChange: (nextValue: string) => void
17
20
  placeholder: string
21
+ normalizeShortcut?: (nextValue: string) => string | null
18
22
  isMac: boolean
19
23
  t: (key: string) => string
20
24
  }) => {
21
- const label = value.trim() === '' ? '' : formatShortcutLabel(value, isMac)
25
+ const effectiveValue = (displayValue ?? value).trim()
26
+ const label = effectiveValue === '' ? '' : formatShortcutLabel(effectiveValue, isMac)
22
27
  return (
23
28
  <div className='config-shortcut-input'>
24
29
  <Input
@@ -33,8 +38,10 @@ export const ShortcutInput = ({
33
38
  }
34
39
  const nextShortcut = getShortcutFromEvent(event)
35
40
  if (nextShortcut == null) return
41
+ const normalizedShortcut = normalizeShortcut?.(nextShortcut) ?? nextShortcut
42
+ if (normalizedShortcut == null) return
36
43
  event.preventDefault()
37
- onChange(nextShortcut)
44
+ onChange(normalizedShortcut)
38
45
  }}
39
46
  />
40
47
  <Tooltip title={t('config.editor.clearShortcut')}>
@@ -20,6 +20,7 @@ export interface FieldSpec {
20
20
  path: string[]
21
21
  type: FieldValueType
22
22
  defaultValue: unknown
23
+ shortcutKind?: 'sendMessage'
23
24
  icon?: string
24
25
  options?: FieldOption[]
25
26
  placeholderKey?: string
@@ -312,6 +313,12 @@ export const configSchema: Record<string, FieldSpec[]> = {
312
313
  type: 'json',
313
314
  defaultValue: [],
314
315
  icon: 'extension'
316
+ },
317
+ {
318
+ path: ['marketplaces'],
319
+ type: 'json',
320
+ defaultValue: {},
321
+ icon: 'store'
315
322
  }
316
323
  ],
317
324
  mcp: [
@@ -329,7 +336,10 @@ export const configSchema: Record<string, FieldSpec[]> = {
329
336
  shortcuts: [
330
337
  { path: ['newSession'], type: 'shortcut', defaultValue: '', icon: 'add_comment' },
331
338
  { path: ['openConfig'], type: 'shortcut', defaultValue: '', icon: 'settings' },
332
- { path: ['sendMessage'], type: 'shortcut', defaultValue: '', icon: 'send' },
333
- { path: ['clearInput'], type: 'shortcut', defaultValue: '', icon: 'clear' }
339
+ { path: ['sendMessage'], type: 'shortcut', shortcutKind: 'sendMessage', defaultValue: '', icon: 'send' },
340
+ { path: ['clearInput'], type: 'shortcut', defaultValue: '', icon: 'clear' },
341
+ { path: ['switchModel'], type: 'shortcut', defaultValue: '', icon: 'model_training' },
342
+ { path: ['switchEffort'], type: 'shortcut', defaultValue: '', icon: 'psychology' },
343
+ { path: ['switchPermissionMode'], type: 'shortcut', defaultValue: '', icon: 'lock' }
334
344
  ]
335
345
  }
@@ -165,19 +165,6 @@ export const ModelServicesRecordEditor = ({
165
165
  t={t}
166
166
  />
167
167
  </FieldRow>
168
- <FieldRow
169
- title={t('config.fields.modelServices.item.modelsAlias.label')}
170
- description={t('config.fields.modelServices.item.modelsAlias.desc')}
171
- icon={getTypeIcon('object')}
172
- layout='stacked'
173
- >
174
- <ComplexTextEditor
175
- value={recordValue.modelsAlias ?? {}}
176
- onChange={(next) => {
177
- onChange({ ...value, [key]: { ...recordValue, modelsAlias: next } })
178
- }}
179
- />
180
- </FieldRow>
181
168
  <FieldRow
182
169
  title={t('config.fields.modelServices.item.timeoutMs.label')}
183
170
  description={t('config.fields.modelServices.item.timeoutMs.desc')}
@@ -262,7 +249,6 @@ export const ModelServicesRecordEditor = ({
262
249
  apiBaseUrl: '',
263
250
  apiKey: '',
264
251
  models: [],
265
- modelsAlias: {},
266
252
  timeoutMs: undefined,
267
253
  maxOutputTokens: undefined,
268
254
  extra: {}
@@ -0,0 +1,152 @@
1
+ .dock-panel {
2
+ flex: 0 0 var(--dock-panel-current-height, var(--dock-panel-height, 240px));
3
+ height: var(--dock-panel-current-height, var(--dock-panel-height, 240px));
4
+ min-height: 0;
5
+ max-height: var(--dock-panel-max-height, 520px);
6
+ position: relative;
7
+ display: flex;
8
+ flex-direction: column;
9
+ min-width: 0;
10
+ padding: var(--dock-panel-padding-top, 12px) 12px
11
+ var(--dock-panel-padding-bottom, 12px);
12
+ background-color: var(--bg-color);
13
+ border-top: 1px solid var(--dock-panel-border-color, var(--border-color));
14
+ gap: 6px;
15
+ overflow: hidden;
16
+ opacity: var(--dock-panel-opacity, 1);
17
+ transform: translateY(var(--dock-panel-translate-y, 0));
18
+ transition:
19
+ flex-basis .24s cubic-bezier(.22, 1, .36, 1),
20
+ height .24s cubic-bezier(.22, 1, .36, 1),
21
+ padding-top .24s cubic-bezier(.22, 1, .36, 1),
22
+ padding-bottom .24s cubic-bezier(.22, 1, .36, 1),
23
+ opacity .18s ease,
24
+ transform .24s cubic-bezier(.22, 1, .36, 1),
25
+ border-top-color .18s ease;
26
+
27
+ &.is-resizing {
28
+ cursor: row-resize;
29
+ }
30
+ }
31
+
32
+ .dock-panel.is-closing {
33
+ --dock-panel-current-height: 0px;
34
+ --dock-panel-padding-top: 0px;
35
+ --dock-panel-padding-bottom: 0px;
36
+ --dock-panel-border-color: transparent;
37
+ --dock-panel-opacity: 0;
38
+ --dock-panel-translate-y: 20px;
39
+ pointer-events: none;
40
+ }
41
+
42
+ .dock-panel__resize-handle {
43
+ display: flex;
44
+ align-items: center;
45
+ gap: 8px;
46
+ min-width: 0;
47
+ min-height: 24px;
48
+ margin: -12px -12px 0;
49
+ padding: 12px 12px 0;
50
+ cursor: row-resize;
51
+ flex-shrink: 0;
52
+ transition: opacity .18s ease;
53
+
54
+ &:hover {
55
+ opacity: .92;
56
+ }
57
+ }
58
+
59
+ .dock-panel__header-main {
60
+ display: inline-flex;
61
+ flex: 1 1 auto;
62
+ align-items: center;
63
+ gap: 6px;
64
+ min-width: 0;
65
+ overflow: hidden;
66
+ }
67
+
68
+ .dock-panel__title,
69
+ .dock-panel__meta {
70
+ display: inline-flex;
71
+ align-items: center;
72
+ min-width: 0;
73
+ height: 24px;
74
+ padding: 0 8px;
75
+ border-radius: 6px;
76
+ background-color: var(--sub-bg-color);
77
+ color: var(--text-color);
78
+ font-size: 12px;
79
+ line-height: 1;
80
+ white-space: nowrap;
81
+ overflow: hidden;
82
+ text-overflow: ellipsis;
83
+ }
84
+
85
+ .dock-panel__title {
86
+ font-weight: 600;
87
+ flex: 0 1 auto;
88
+ max-width: 100%;
89
+ }
90
+
91
+ .dock-panel__meta {
92
+ flex: 0 1 auto;
93
+ max-width: min(180px, 40%);
94
+ color: var(--sub-text-color);
95
+ font-family:
96
+ ui-monospace, sfmono-regular, 'SF Mono', menlo, consolas, monospace;
97
+ }
98
+
99
+ .dock-panel__header-spacer {
100
+ flex: 1;
101
+ min-width: 24px;
102
+ }
103
+
104
+ .dock-panel__header-actions {
105
+ display: inline-flex;
106
+ align-items: center;
107
+ gap: 6px;
108
+ }
109
+
110
+ .dock-panel__close-btn.ant-btn.ant-btn-text {
111
+ width: 24px;
112
+ height: 24px;
113
+ padding: 0;
114
+ border: none;
115
+ border-radius: 6px;
116
+ color: var(--sub-text-color, #6b7280);
117
+ display: inline-flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ transition: background-color .2s ease, color .2s ease;
121
+
122
+ .material-symbols-rounded {
123
+ font-size: 14px;
124
+ line-height: 1;
125
+ }
126
+
127
+ &:hover {
128
+ background-color: var(--nav-hover-bg, #f3f4f6);
129
+ color: var(--text-color, #111827);
130
+ }
131
+ }
132
+
133
+ .dock-panel__body {
134
+ flex: 1;
135
+ min-height: 0;
136
+ display: flex;
137
+ flex-direction: column;
138
+ }
139
+
140
+ .dock-panel__footer {
141
+ flex-shrink: 0;
142
+ }
143
+
144
+ html.dark .dock-panel__close-btn.ant-btn.ant-btn-text {
145
+ --nav-hover-bg: #1a1a1a;
146
+ }
147
+
148
+ @media (prefers-reduced-motion: reduce) {
149
+ .dock-panel {
150
+ transition: none;
151
+ }
152
+ }
@@ -0,0 +1,195 @@
1
+ import './DockPanel.scss'
2
+
3
+ import { Button } from 'antd'
4
+ import type { CSSProperties, PointerEvent as ReactPointerEvent, ReactNode } from 'react'
5
+ import { useEffect, useMemo, useRef, useState } from 'react'
6
+
7
+ const DEFAULT_PANEL_HEIGHT = 240
8
+
9
+ const clampPanelHeight = (height: number, minHeight: number, maxHeight: number) => {
10
+ return Math.min(Math.max(height, minHeight), Math.max(minHeight, maxHeight))
11
+ }
12
+
13
+ const shouldIgnoreResizePointerDown = (target: HTMLElement | null) => {
14
+ if (target == null) {
15
+ return false
16
+ }
17
+
18
+ return target.closest(
19
+ 'button, a, input, textarea, select, option, [role="button"], [data-dock-panel-no-resize="true"]'
20
+ ) != null
21
+ }
22
+
23
+ export function DockPanel({
24
+ enterMotion = 'slide-up',
25
+ children,
26
+ className,
27
+ closeLabel,
28
+ defaultHeight = DEFAULT_PANEL_HEIGHT,
29
+ footer,
30
+ isOpen = true,
31
+ maxHeight = 520,
32
+ meta,
33
+ minHeight = 180,
34
+ onClose,
35
+ resizeLabel,
36
+ storageKey,
37
+ title,
38
+ actions
39
+ }: {
40
+ enterMotion?: 'none' | 'slide-up'
41
+ actions?: ReactNode
42
+ children: ReactNode
43
+ className?: string
44
+ closeLabel?: string
45
+ defaultHeight?: number
46
+ footer?: ReactNode
47
+ isOpen?: boolean
48
+ maxHeight?: number
49
+ meta?: ReactNode
50
+ minHeight?: number
51
+ onClose?: () => void
52
+ resizeLabel: string
53
+ storageKey: string
54
+ title: ReactNode
55
+ }) {
56
+ const panelRef = useRef<HTMLDivElement | null>(null)
57
+ const resizeSessionRef = useRef<{ maxHeight: number; startHeight: number; startY: number } | null>(null)
58
+ const [isResizing, setIsResizing] = useState(false)
59
+ const [panelHeight, setPanelHeight] = useState(() => {
60
+ const storedHeight = Number(localStorage.getItem(storageKey))
61
+ return Number.isFinite(storedHeight) && storedHeight > 0
62
+ ? clampPanelHeight(storedHeight, minHeight, maxHeight)
63
+ : clampPanelHeight(defaultHeight, minHeight, maxHeight)
64
+ })
65
+
66
+ useEffect(() => {
67
+ localStorage.setItem(storageKey, String(panelHeight))
68
+ }, [panelHeight, storageKey])
69
+
70
+ useEffect(() => {
71
+ return () => {
72
+ document.body.style.cursor = ''
73
+ document.body.style.userSelect = ''
74
+ }
75
+ }, [])
76
+
77
+ useEffect(() => {
78
+ if (!isResizing) {
79
+ return
80
+ }
81
+
82
+ const handlePointerMove = (event: PointerEvent) => {
83
+ const resizeSession = resizeSessionRef.current
84
+ if (resizeSession == null) {
85
+ return
86
+ }
87
+
88
+ const nextHeight = clampPanelHeight(
89
+ resizeSession.startHeight + resizeSession.startY - event.clientY,
90
+ minHeight,
91
+ resizeSession.maxHeight
92
+ )
93
+
94
+ setPanelHeight(nextHeight)
95
+ }
96
+
97
+ const stopResizing = () => {
98
+ resizeSessionRef.current = null
99
+ setIsResizing(false)
100
+ document.body.style.cursor = ''
101
+ document.body.style.userSelect = ''
102
+ }
103
+
104
+ window.addEventListener('pointermove', handlePointerMove)
105
+ window.addEventListener('pointerup', stopResizing)
106
+ window.addEventListener('pointercancel', stopResizing)
107
+
108
+ return () => {
109
+ window.removeEventListener('pointermove', handlePointerMove)
110
+ window.removeEventListener('pointerup', stopResizing)
111
+ window.removeEventListener('pointercancel', stopResizing)
112
+ }
113
+ }, [isResizing, minHeight])
114
+
115
+ const handleResizePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {
116
+ if (shouldIgnoreResizePointerDown(event.target as HTMLElement | null)) {
117
+ return
118
+ }
119
+
120
+ event.preventDefault()
121
+
122
+ const panel = panelRef.current
123
+ const parent = panel?.parentElement
124
+ const parentHeight = parent?.getBoundingClientRect().height
125
+
126
+ resizeSessionRef.current = {
127
+ startY: event.clientY,
128
+ startHeight: panel?.getBoundingClientRect().height ?? panelHeight,
129
+ maxHeight: parentHeight != null ? Math.min(maxHeight, parentHeight - 96) : maxHeight
130
+ }
131
+
132
+ setIsResizing(true)
133
+ document.body.style.cursor = 'row-resize'
134
+ document.body.style.userSelect = 'none'
135
+ }
136
+
137
+ const panelStyle = useMemo(
138
+ () => ({
139
+ '--dock-panel-height': `${panelHeight}px`,
140
+ '--dock-panel-max-height': `${maxHeight}px`,
141
+ '--dock-panel-min-height': `${minHeight}px`
142
+ }),
143
+ [maxHeight, minHeight, panelHeight]
144
+ )
145
+
146
+ return (
147
+ <div
148
+ ref={panelRef}
149
+ className={`dock-panel ${isOpen && enterMotion === 'slide-up' ? 'is-entering-slide-up' : ''} ${
150
+ isOpen ? 'is-open' : 'is-closing'
151
+ } ${className ?? ''} ${isResizing ? 'is-resizing' : ''}`}
152
+ style={panelStyle as CSSProperties}
153
+ >
154
+ <div
155
+ className='dock-panel__resize-handle'
156
+ title={resizeLabel}
157
+ onPointerDown={handleResizePointerDown}
158
+ >
159
+ <div className='dock-panel__header-main'>
160
+ <span className='dock-panel__title'>{title}</span>
161
+ {meta != null && (
162
+ <span className='dock-panel__meta'>{meta}</span>
163
+ )}
164
+ </div>
165
+ <div className='dock-panel__header-spacer' />
166
+ {(actions != null || onClose != null) && (
167
+ <div className='dock-panel__header-actions'>
168
+ {actions}
169
+ {onClose != null && closeLabel != null && (
170
+ <Button
171
+ type='text'
172
+ className='dock-panel__close-btn'
173
+ data-dock-panel-no-resize='true'
174
+ icon={<span className='material-symbols-rounded'>close</span>}
175
+ title={closeLabel}
176
+ aria-label={closeLabel}
177
+ onClick={onClose}
178
+ />
179
+ )}
180
+ </div>
181
+ )}
182
+ </div>
183
+
184
+ <div className='dock-panel__body'>
185
+ {children}
186
+ </div>
187
+
188
+ {footer != null && (
189
+ <div className='dock-panel__footer'>
190
+ {footer}
191
+ </div>
192
+ )}
193
+ </div>
194
+ )
195
+ }