@vibe-forge/client 0.11.2 → 1.0.0

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 (232) hide show
  1. package/cli.cjs +6 -11
  2. package/dist/assets/{arc-De_WjPJ3.js → arc-CbOXL0l9.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-C4aR2zTE.js → blockDiagram-c4efeb88-CqxINvsS.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-BZH3rq_m.js → c4Diagram-c83219d4-BKazU0hb.js} +1 -1
  5. package/dist/assets/channel-Dnopc5A6.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-BzJgBrIK.js → classDiagram-beda092f-fAFX5BpB.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-5ZtXcnT3.js → classDiagram-v2-2358418a-w1VkNGJj.js} +1 -1
  8. package/dist/assets/clone-sQthahUA.js +1 -0
  9. package/dist/assets/{createText-1719965b-DUVvEtmR.js → createText-1719965b-CEinakVP.js} +1 -1
  10. package/dist/assets/{cssMode-GoTNjuXX.js → cssMode-DPqRki4y.js} +1 -1
  11. package/dist/assets/{edges-96097737-Dd7m4Cvs.js → edges-96097737-Cb0F1_3K.js} +1 -1
  12. package/dist/assets/{erDiagram-0228fc6a-DxqFlG_f.js → erDiagram-0228fc6a-C-N2fx-J.js} +1 -1
  13. package/dist/assets/{flowDb-c6c81e3f-DU0C5kCI.js → flowDb-c6c81e3f-D1Xz_8Gf.js} +1 -1
  14. package/dist/assets/{flowDiagram-50d868cf-Di1uDa_X.js → flowDiagram-50d868cf-DyPSZyAj.js} +1 -1
  15. package/dist/assets/flowDiagram-v2-4f6560a1-OazrdWQO.js +1 -0
  16. package/dist/assets/{flowchart-elk-definition-6af322e1-CwG8aty5.js → flowchart-elk-definition-6af322e1-Dr1DDXwE.js} +1 -1
  17. package/dist/assets/{freemarker2-j39cqTlI.js → freemarker2-C3DvPFaK.js} +1 -1
  18. package/dist/assets/{ganttDiagram-a2739b55-baO_lzL-.js → ganttDiagram-a2739b55-DmvY1GRj.js} +1 -1
  19. package/dist/assets/{gitGraphDiagram-82fe8481-COoHjYMf.js → gitGraphDiagram-82fe8481-CoXfPYYi.js} +1 -1
  20. package/dist/assets/{graph-KxESr4M5.js → graph-BkDQy7Qt.js} +1 -1
  21. package/dist/assets/{handlebars-BgjdZO8G.js → handlebars-BcTFdqjl.js} +1 -1
  22. package/dist/assets/{html-Ba7tYObe.js → html-Dg-O6XFr.js} +1 -1
  23. package/dist/assets/{htmlMode-Bztvbig1.js → htmlMode-B_wqYWvn.js} +1 -1
  24. package/dist/assets/{index-5325376f-BMTAx2mL.js → index-5325376f-kxPTR3_e.js} +1 -1
  25. package/dist/assets/index-o93dlo92.css +32 -0
  26. package/dist/assets/{index-Pm_kLJvG.js → index-wkhI4dr6.js} +350 -329
  27. package/dist/assets/{infoDiagram-8eee0895-CC74qbHY.js → infoDiagram-8eee0895-BEvqkwPI.js} +1 -1
  28. package/dist/assets/{javascript-C1e1cllX.js → javascript-DhlOH8_z.js} +1 -1
  29. package/dist/assets/{journeyDiagram-c64418c1-C4MyOdE6.js → journeyDiagram-c64418c1-gKtLYmmp.js} +1 -1
  30. package/dist/assets/{jsonMode-BC98AlvF.js → jsonMode-DxTbF9OD.js} +1 -1
  31. package/dist/assets/{layout-CxAyTlr7.js → layout-CDaZEk6E.js} +1 -1
  32. package/dist/assets/{line-DhaUfI71.js → line-DNRQu8iq.js} +1 -1
  33. package/dist/assets/{linear-MYukzldK.js → linear-Cph9Z6_j.js} +1 -1
  34. package/dist/assets/{liquid-DahfJEYl.js → liquid-ByZ6JgRG.js} +1 -1
  35. package/dist/assets/{lspLanguageFeatures-BWDJcswW.js → lspLanguageFeatures-DzvhkgnM.js} +1 -1
  36. package/dist/assets/{mdx-BELlF_FD.js → mdx-D8RGHTl6.js} +1 -1
  37. package/dist/assets/{mermaid.core-BrQnSGSY.js → mermaid.core-BgcryF__.js} +4 -4
  38. package/dist/assets/{mindmap-definition-8da855dc-B0FoxTiy.js → mindmap-definition-8da855dc-WrxK0FcB.js} +1 -1
  39. package/dist/assets/{pieDiagram-a8764435-Ddr2cjSL.js → pieDiagram-a8764435-VsZBsiQy.js} +1 -1
  40. package/dist/assets/{python--C9if_AD.js → python-CXVtk_cg.js} +1 -1
  41. package/dist/assets/{quadrantDiagram-1e28029f-BlEs7Mrl.js → quadrantDiagram-1e28029f-BVlgwOvU.js} +1 -1
  42. package/dist/assets/{razor-B9U9JxKn.js → razor-0tind7h2.js} +1 -1
  43. package/dist/assets/{requirementDiagram-08caed73-kEFOAu2v.js → requirementDiagram-08caed73-CpPMPoYp.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-a04cb91d-BBghez8I.js → sankeyDiagram-a04cb91d-Cm5nnRmc.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-c5b8d532-CJqgzdUE.js → sequenceDiagram-c5b8d532-DpMlJvJB.js} +1 -1
  46. package/dist/assets/{stateDiagram-1ecb1508-BER4XEI6.js → stateDiagram-1ecb1508-DU1zc7vq.js} +1 -1
  47. package/dist/assets/{stateDiagram-v2-c2b004d7-EBV2vSks.js → stateDiagram-v2-c2b004d7-D-0RgmAp.js} +1 -1
  48. package/dist/assets/{styles-b4e223ce-k0eswZsE.js → styles-b4e223ce-BSO-yNWV.js} +1 -1
  49. package/dist/assets/{styles-ca3715f6-Ckr7GA-0.js → styles-ca3715f6-CHnsn2Ro.js} +1 -1
  50. package/dist/assets/{styles-d45a18b0-C1bpSwV3.js → styles-d45a18b0-B-rVGjEq.js} +1 -1
  51. package/dist/assets/{svgDrawCommon-b86b1483-CDtKpGvy.js → svgDrawCommon-b86b1483-CA3Pl89f.js} +1 -1
  52. package/dist/assets/{timeline-definition-faaaa080-BeGR-vua.js → timeline-definition-faaaa080-BcihLR6s.js} +1 -1
  53. package/dist/assets/{tsMode-D_gJXIy3.js → tsMode-D9GGa5Ur.js} +1 -1
  54. package/dist/assets/{typescript-BoKcNXkN.js → typescript-BT9CK_EL.js} +1 -1
  55. package/dist/assets/{xml-DZvURlJ-.js → xml-DNO75J-T.js} +1 -1
  56. package/dist/assets/{xychartDiagram-f5964ef8-DxfeLuYV.js → xychartDiagram-f5964ef8-DJTwe32X.js} +1 -1
  57. package/dist/assets/{yaml-CTC8PAGY.js → yaml-7CVzhiP2.js} +1 -1
  58. package/dist/index.html +2 -2
  59. package/package.json +13 -10
  60. package/src/api/git.ts +12 -0
  61. package/src/api/sessions.ts +131 -4
  62. package/src/api/types.ts +2 -1
  63. package/src/api.ts +13 -0
  64. package/src/components/ArchiveView.scss +143 -54
  65. package/src/components/ArchiveView.tsx +181 -167
  66. package/src/components/CodeBlock.scss +5 -0
  67. package/src/components/ConfigView.scss +142 -31
  68. package/src/components/ConfigView.tsx +161 -86
  69. package/src/components/MarkdownContent.tsx +7 -0
  70. package/src/components/NavRail.scss +248 -0
  71. package/src/components/NavRail.tsx +80 -107
  72. package/src/components/NavRailCompact.tsx +107 -0
  73. package/src/components/NavRailCompactMoreSheet.tsx +141 -0
  74. package/src/components/ShortcutTooltip.tsx +4 -2
  75. package/src/components/Sidebar.scss +51 -0
  76. package/src/components/Sidebar.tsx +43 -16
  77. package/src/components/automation-view/RuleFormPanel.scss +40 -13
  78. package/src/components/automation-view/RuleSidebar.scss +73 -47
  79. package/src/components/automation-view/RuleSidebar.tsx +9 -13
  80. package/src/components/automation-view/RunHistoryPanel.scss +141 -13
  81. package/src/components/automation-view/RunHistoryPanel.tsx +203 -161
  82. package/src/components/automation-view/TaskList.scss +44 -13
  83. package/src/components/automation-view/TriggerList.scss +46 -14
  84. package/src/components/automation-view/index.scss +82 -10
  85. package/src/components/automation-view/index.tsx +108 -55
  86. package/src/components/benchmark-view/BenchmarkCasePanel.scss +36 -16
  87. package/src/components/benchmark-view/BenchmarkSidebar.scss +44 -22
  88. package/src/components/benchmark-view/BenchmarkSidebar.tsx +0 -6
  89. package/src/components/benchmark-view/BenchmarkView.scss +63 -20
  90. package/src/components/benchmark-view/index.tsx +71 -34
  91. package/src/components/chat/AGENTS.md +14 -2
  92. package/src/components/chat/ChatComposerCard.scss +77 -0
  93. package/src/components/chat/ChatComposerCard.tsx +59 -0
  94. package/src/components/chat/ChatHeader.scss +187 -0
  95. package/src/components/chat/ChatHeader.tsx +209 -57
  96. package/src/components/chat/ChatHistoryView.tsx +279 -52
  97. package/src/components/chat/ChatTimelineView.scss +94 -1
  98. package/src/components/chat/ChatTimelineView.tsx +42 -0
  99. package/src/components/chat/CurrentTodoList.scss +210 -200
  100. package/src/components/chat/CurrentTodoList.tsx +116 -48
  101. package/src/components/chat/NewSessionGuide.scss +139 -1
  102. package/src/components/chat/NewSessionGuide.tsx +57 -100
  103. package/src/components/chat/NewSessionGuideCompactPanel.tsx +130 -0
  104. package/src/components/chat/NewSessionGuideGrid.tsx +141 -0
  105. package/src/components/chat/QueuedMessagesCard.scss +195 -0
  106. package/src/components/chat/QueuedMessagesCard.tsx +170 -0
  107. package/src/components/chat/git-controls/BranchSwitcherDropdown.tsx +61 -56
  108. package/src/components/chat/git-controls/BranchSwitcherResults.tsx +167 -0
  109. package/src/components/chat/git-controls/BranchTreeEntries.tsx +99 -0
  110. package/src/components/chat/git-controls/ChatGitControls.scss +437 -5
  111. package/src/components/chat/git-controls/ChatGitControls.tsx +136 -109
  112. package/src/components/chat/git-controls/DraftGitControls.tsx +91 -0
  113. package/src/components/chat/git-controls/GitOperationsDropdown.tsx +10 -2
  114. package/src/components/chat/git-controls/GitWorktreeDropdown.tsx +301 -28
  115. package/src/components/chat/git-controls/git-branch-tree.ts +148 -0
  116. package/src/components/chat/git-controls/use-chat-draft-git-controls.ts +168 -0
  117. package/src/components/chat/git-controls/use-chat-git-controls.ts +76 -3
  118. package/src/components/chat/messages/MessageContextMenu.tsx +3 -1
  119. package/src/components/chat/messages/MessageItem.scss +78 -4
  120. package/src/components/chat/messages/MessageItem.tsx +47 -3
  121. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +23 -0
  122. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +17 -0
  123. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +4 -1
  124. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +167 -30
  125. package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +95 -23
  126. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +10 -0
  127. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +161 -45
  128. package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +310 -71
  129. package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +18 -0
  130. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +86 -9
  131. package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +52 -3
  132. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +110 -1
  133. package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +137 -17
  134. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +21 -0
  135. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +21 -0
  136. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +63 -0
  137. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +12 -6
  138. package/src/components/chat/sender/@core/build-sender-controller-result.ts +6 -0
  139. package/src/components/chat/sender/@core/build-sender-toolbar.ts +25 -2
  140. package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +9 -2
  141. package/src/components/chat/sender/@core/get-sender-runtime-state.ts +1 -1
  142. package/src/components/chat/sender/@core/interaction-request.ts +2 -2
  143. package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +28 -4
  144. package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +4 -2
  145. package/src/components/chat/sender/@hooks/use-sender-controller.ts +56 -11
  146. package/src/components/chat/sender/@hooks/use-sender-keydown.ts +64 -0
  147. package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +16 -1
  148. package/src/components/chat/sender/@hooks/use-sender-submit.ts +16 -8
  149. package/src/components/chat/sender/@types/sender-props.ts +20 -3
  150. package/src/components/chat/sender/@types/sender-toolbar-types.ts +12 -1
  151. package/src/components/chat/sender/Sender.scss +4 -1
  152. package/src/components/chat/sender/Sender.tsx +3 -12
  153. package/src/components/chat/session-timeline-panel/EventList.scss +88 -0
  154. package/src/components/chat/session-timeline-panel/EventList.tsx +99 -47
  155. package/src/components/chat/session-timeline-panel/gantt.ts +23 -7
  156. package/src/components/chat/session-timeline-panel/git-graph.ts +6 -1
  157. package/src/components/chat/session-timeline-panel/index.scss +14 -1
  158. package/src/components/chat/session-timeline-panel/index.tsx +86 -10
  159. package/src/components/chat/session-timeline-panel/types.ts +4 -0
  160. package/src/components/chat/status-bar/ChatStatusBar.scss +27 -0
  161. package/src/components/chat/status-bar/ChatStatusBar.tsx +39 -0
  162. package/src/components/chat/terminal/ChatTerminalView.tsx +6 -0
  163. package/src/components/chat/tools/core/ToolCallBox.scss +19 -0
  164. package/src/components/chat/tools/core/ToolGroup.scss +32 -0
  165. package/src/components/chat/tools/task/components/TaskToolCard.scss +59 -1
  166. package/src/components/config/ConfigEditors.scss +20 -6
  167. package/src/components/config/ConfigFieldRow.scss +57 -17
  168. package/src/components/config/ConfigSectionForm.scss +10 -4
  169. package/src/components/config/ConfigSectionPanel.tsx +18 -11
  170. package/src/components/config/configSchema.ts +1 -0
  171. package/src/components/config/record-editors/RecordEditors.scss +42 -9
  172. package/src/components/dock-panel/DockPanel.scss +6 -2
  173. package/src/components/dock-panel/DockPanel.tsx +12 -16
  174. package/src/components/knowledge-base/KnowledgeBaseView.scss +180 -6
  175. package/src/components/knowledge-base/KnowledgeBaseView.tsx +98 -26
  176. package/src/components/knowledge-base/components/ActionButton.scss +4 -0
  177. package/src/components/knowledge-base/components/EmptyState.scss +5 -8
  178. package/src/components/knowledge-base/components/EntitiesTab.tsx +8 -2
  179. package/src/components/knowledge-base/components/EntityItem.scss +10 -3
  180. package/src/components/knowledge-base/components/FilterBar.scss +13 -2
  181. package/src/components/knowledge-base/components/FlowsTab.tsx +8 -2
  182. package/src/components/knowledge-base/components/KnowledgeBaseHeader.scss +2 -23
  183. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +0 -5
  184. package/src/components/knowledge-base/components/KnowledgeList.scss +15 -6
  185. package/src/components/knowledge-base/components/LoadingState.scss +4 -0
  186. package/src/components/knowledge-base/components/RuleItem.scss +86 -0
  187. package/src/components/knowledge-base/components/RuleItem.tsx +2 -0
  188. package/src/components/knowledge-base/components/RulesTab.tsx +8 -2
  189. package/src/components/knowledge-base/components/SectionHeader.scss +3 -18
  190. package/src/components/knowledge-base/components/SectionHeader.tsx +3 -7
  191. package/src/components/knowledge-base/components/SkillsTab.tsx +8 -3
  192. package/src/components/knowledge-base/components/SpecItem.scss +16 -7
  193. package/src/components/layout/@hooks/use-mobile-sidebar-modal.ts +190 -0
  194. package/src/components/layout/AppShell.scss +106 -6
  195. package/src/components/layout/AppShell.tsx +118 -10
  196. package/src/components/layout/PageShell.scss +41 -0
  197. package/src/components/layout/PageShell.tsx +32 -0
  198. package/src/components/layout/mobile-sidebar-constants.ts +1 -0
  199. package/src/components/nav-rail-compact-config.ts +114 -0
  200. package/src/components/nav-rail-items.tsx +181 -0
  201. package/src/components/sidebar/SessionContextMenu.tsx +3 -1
  202. package/src/components/sidebar/SessionItem.scss +62 -0
  203. package/src/components/sidebar/SessionItem.tsx +97 -52
  204. package/src/components/sidebar/SessionList.tsx +6 -0
  205. package/src/components/sidebar/SidebarHeader.scss +49 -0
  206. package/src/components/sidebar/SidebarHeader.tsx +27 -5
  207. package/src/components/sidebar/SidebarHeaderBatchActions.tsx +8 -4
  208. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +6 -3
  209. package/src/components/sidebar/SidebarUtilityFooter.tsx +69 -0
  210. package/src/components/workspace/ContextFilePicker.tsx +12 -4
  211. package/src/hooks/chat/chat-session-workspace-draft.ts +25 -0
  212. package/src/hooks/chat/session-view-cache.ts +4 -1
  213. package/src/hooks/chat/use-chat-adapter.ts +5 -1
  214. package/src/hooks/chat/use-chat-model-adapter-selection.tsx +5 -1
  215. package/src/hooks/chat/use-chat-scroll.ts +24 -7
  216. package/src/hooks/chat/use-chat-session-actions.ts +118 -6
  217. package/src/hooks/chat/use-chat-session-messages.ts +20 -1
  218. package/src/hooks/chat/use-chat-session.ts +2 -0
  219. package/src/hooks/use-responsive-layout.ts +115 -0
  220. package/src/main.tsx +8 -0
  221. package/src/resources/adapters.ts +15 -0
  222. package/src/resources/locales/en.json +84 -1
  223. package/src/resources/locales/zh.json +84 -1
  224. package/src/routes/ChatRoute.scss +152 -9
  225. package/src/routes/ChatRoute.tsx +31 -34
  226. package/src/store/index.ts +2 -0
  227. package/dist/assets/channel-BvERb8WU.js +0 -1
  228. package/dist/assets/clone-B9_0v-6Y.js +0 -1
  229. package/dist/assets/flowDiagram-v2-4f6560a1-LpS8Kb00.js +0 -1
  230. package/dist/assets/index-C1oh0w9H.css +0 -32
  231. package/src/components/chat/ThinkingStatus.scss +0 -70
  232. package/src/components/chat/ThinkingStatus.tsx +0 -13
@@ -1,19 +1,68 @@
1
+ import * as monacoApi from 'monaco-editor'
2
+ import type { editor as MonacoEditorNamespace } from 'monaco-editor'
1
3
  import { useEffect, useState } from 'react'
2
4
 
3
- const getThemeName = () => (document.documentElement.classList.contains('dark') ? 'vs-dark' : 'vs')
5
+ const SENDER_MONACO_LIGHT_THEME = 'vf-sender-light'
6
+ const SENDER_MONACO_DARK_THEME = 'vf-sender-dark'
7
+ const HEX_COLOR_PATTERN = /^#(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i
8
+
9
+ const readCssColor = (styles: CSSStyleDeclaration, name: string, fallback: string) => {
10
+ const value = styles.getPropertyValue(name).trim()
11
+
12
+ if (HEX_COLOR_PATTERN.test(value)) {
13
+ return value
14
+ }
15
+
16
+ return fallback
17
+ }
18
+
19
+ const buildSenderMonacoTheme = (isDark: boolean): MonacoEditorNamespace.IStandaloneThemeData => {
20
+ const styles = window.getComputedStyle(document.documentElement)
21
+ const background = readCssColor(styles, '--bg-color', isDark ? '#141414' : '#ffffff')
22
+ const foreground = readCssColor(styles, '--text-color', isDark ? '#ffffff' : '#000000')
23
+ const placeholder = readCssColor(styles, '--placeholder-color', isDark ? '#575859' : '#9ca3af')
24
+ const primaryColor = readCssColor(styles, '--primary-color', isDark ? '#3b82f6' : '#2563eb')
25
+ const selectionBackground = readCssColor(styles, '--primary-soft-bg', isDark ? '#111b26' : '#eff6ff')
26
+
27
+ return {
28
+ base: isDark ? 'vs-dark' : 'vs',
29
+ colors: {
30
+ 'editor.background': background,
31
+ 'editor.foreground': foreground,
32
+ 'editor.inactiveSelectionBackground': selectionBackground,
33
+ 'editor.placeholder.foreground': placeholder,
34
+ 'editor.selectionBackground': selectionBackground,
35
+ 'editorCursor.foreground': primaryColor
36
+ },
37
+ inherit: false,
38
+ rules: []
39
+ }
40
+ }
41
+
42
+ const defineSenderMonacoTheme = (isDark: boolean) => {
43
+ const themeName = isDark ? SENDER_MONACO_DARK_THEME : SENDER_MONACO_LIGHT_THEME
44
+
45
+ monacoApi.editor.defineTheme(themeName, buildSenderMonacoTheme(isDark))
46
+
47
+ return themeName
48
+ }
49
+
50
+ const getThemeName = () => defineSenderMonacoTheme(document.documentElement.classList.contains('dark'))
4
51
 
5
52
  export const useSenderMonacoTheme = () => {
6
53
  const [themeName, setThemeName] = useState(getThemeName)
7
54
 
8
55
  useEffect(() => {
9
- const observer = new MutationObserver(() => {
56
+ const syncThemeName = () => {
10
57
  setThemeName(getThemeName())
11
- })
58
+ }
59
+ const observer = new MutationObserver(syncThemeName)
12
60
 
13
61
  observer.observe(document.documentElement, {
14
62
  attributes: true,
15
63
  attributeFilter: ['class']
16
64
  })
65
+ syncThemeName()
17
66
 
18
67
  return () => {
19
68
  observer.disconnect()
@@ -40,10 +40,20 @@
40
40
  color: var(--primary-color, #6366f1);
41
41
  border-color: var(--primary-color, #6366f1);
42
42
  }
43
- &.thinking {
43
+ &.stop {
44
44
  color: #fff;
45
45
  border-color: #dc2626;
46
46
  background: linear-gradient(180deg, #ef4444, #dc2626);
47
+
48
+ &:hover {
49
+ color: #fff;
50
+ border-color: #dc2626;
51
+ background: linear-gradient(180deg, #ef4444, #dc2626);
52
+ }
53
+
54
+ .material-symbols-rounded {
55
+ transform: none;
56
+ }
47
57
  }
48
58
  &.disabled {
49
59
  color: #9ca3af;
@@ -51,4 +61,103 @@
51
61
  border-color: var(--border-color);
52
62
  opacity: .72;
53
63
  }
64
+
65
+ &.blocked {
66
+ cursor: not-allowed;
67
+
68
+ &:hover {
69
+ color: #9ca3af;
70
+ border-color: var(--border-color);
71
+ background: color-mix(
72
+ in srgb,
73
+ var(--bg-color, #fff) 92%,
74
+ var(--sub-bg-color, #f3f4f6) 8%
75
+ );
76
+ }
77
+
78
+ .material-symbols-rounded {
79
+ transform: none;
80
+ }
81
+ }
82
+ }
83
+
84
+ .chat-confirm-btn.ant-btn {
85
+ height: var(--sender-control-height);
86
+ padding: 0 10px;
87
+ border-radius: var(--sender-control-radius);
88
+ border-color: var(--border-color);
89
+ background: var(--bg-color, #fff);
90
+ box-shadow: none;
91
+ display: inline-flex;
92
+ align-items: center;
93
+ gap: 4px;
94
+ font-size: 12px;
95
+ font-weight: 500;
96
+
97
+ .material-symbols-rounded {
98
+ font-size: 15px;
99
+ line-height: 1;
100
+ }
101
+
102
+ &:hover,
103
+ &:focus {
104
+ border-color: color-mix(
105
+ in srgb,
106
+ var(--primary-color, #2563eb) 38%,
107
+ var(--border-color) 62%
108
+ );
109
+ color: var(--text-color, #1f2937);
110
+ background: color-mix(
111
+ in srgb,
112
+ var(--bg-color, #fff) 90%,
113
+ var(--sub-bg-color, #eff6ff) 10%
114
+ );
115
+ }
116
+ }
117
+
118
+ .sender-send-tooltip {
119
+ display: flex;
120
+ flex-direction: column;
121
+ gap: 6px;
122
+ }
123
+
124
+ .sender-send-tooltip__row {
125
+ display: flex;
126
+ align-items: center;
127
+ gap: 8px;
128
+ }
129
+
130
+ .sender-send-tooltip__label {
131
+ min-width: 0;
132
+ color: inherit;
133
+ font-size: inherit;
134
+ line-height: 1.4;
135
+ }
136
+
137
+ .sender-send-tooltip-popover {
138
+ pointer-events: none;
139
+
140
+ .ant-tooltip-inner {
141
+ padding: 8px 10px !important;
142
+ }
143
+
144
+ .shortcut-display {
145
+ background: rgba(255, 255, 255, .12);
146
+ border-color: rgba(255, 255, 255, .16);
147
+ color: rgba(255, 255, 255, .92);
148
+ box-shadow: none;
149
+ flex: 0 0 auto;
150
+ }
151
+ }
152
+
153
+ @media (max-width: 960px) {
154
+ .chat-send-btn {
155
+ width: 24px;
156
+ min-width: 24px;
157
+ height: 24px;
158
+
159
+ .material-symbols-rounded {
160
+ font-size: 14px;
161
+ }
162
+ }
54
163
  }
@@ -1,9 +1,11 @@
1
1
  import '../sender-toolbar/SenderSelectShared.scss'
2
2
  import './SenderSubmitAction.scss'
3
3
 
4
- import { Button } from 'antd'
4
+ import type { SessionQueuedMessageMode } from '@vibe-forge/core'
5
+ import { Button, Tooltip } from 'antd'
5
6
  import { useTranslation } from 'react-i18next'
6
7
 
8
+ import { ShortcutDisplay } from '#~/components/ShortcutDisplay'
7
9
  import { ShortcutTooltip } from '#~/components/ShortcutTooltip'
8
10
 
9
11
  export function SenderSubmitAction({
@@ -11,29 +13,51 @@ export function SenderSubmitAction({
11
13
  submitLoading,
12
14
  submitLabel,
13
15
  hasComposerContent,
14
- hasSendText,
15
16
  modelUnavailable,
17
+ sendBlocked,
18
+ sendBlockedTooltip,
19
+ showConfirmInteractionAction,
20
+ confirmInteractionLabel,
16
21
  isThinking,
17
22
  resolvedSendShortcut,
23
+ queueSteerShortcut,
24
+ queueNextShortcut,
18
25
  isMac,
19
26
  onCancel,
27
+ onConfirmInteractionAction,
20
28
  onSend,
21
- onInterrupt
29
+ onStop
22
30
  }: {
23
31
  isInlineEdit: boolean
24
32
  submitLoading: boolean
25
33
  submitLabel?: string
26
34
  hasComposerContent: boolean
27
- hasSendText: boolean
28
35
  modelUnavailable: boolean
36
+ sendBlocked: boolean
37
+ sendBlockedTooltip?: string
38
+ showConfirmInteractionAction: boolean
39
+ confirmInteractionLabel?: string
29
40
  isThinking: boolean
30
41
  resolvedSendShortcut: string
42
+ queueSteerShortcut?: string
43
+ queueNextShortcut?: string
31
44
  isMac: boolean
32
45
  onCancel?: () => void
33
- onSend: () => void
34
- onInterrupt: () => void
46
+ onConfirmInteractionAction?: () => void
47
+ onSend: (mode?: SessionQueuedMessageMode) => void
48
+ onStop?: () => void
35
49
  }) {
36
50
  const { t } = useTranslation()
51
+ const showStopAction = isThinking && !hasComposerContent
52
+ const isSendDisabled = !showStopAction && (modelUnavailable || sendBlocked)
53
+ const handleSendClick = () => onSend()
54
+ const buttonClasses = [
55
+ 'chat-send-btn',
56
+ hasComposerContent && !isSendDisabled ? 'active' : '',
57
+ showStopAction ? 'stop' : '',
58
+ isSendDisabled ? 'disabled' : '',
59
+ sendBlocked ? 'blocked' : ''
60
+ ].filter(Boolean).join(' ')
37
61
 
38
62
  if (isInlineEdit) {
39
63
  return (
@@ -49,7 +73,7 @@ export function SenderSubmitAction({
49
73
  size='small'
50
74
  loading={submitLoading}
51
75
  disabled={!hasComposerContent}
52
- onClick={onSend}
76
+ onClick={handleSendClick}
53
77
  >
54
78
  {submitLabel ?? t('chat.send')}
55
79
  </Button>
@@ -57,23 +81,119 @@ export function SenderSubmitAction({
57
81
  )
58
82
  }
59
83
 
84
+ if (isThinking) {
85
+ if (showStopAction) {
86
+ return (
87
+ <Tooltip
88
+ title={
89
+ <div className='sender-send-tooltip'>
90
+ <div className='sender-send-tooltip__row'>
91
+ <span className='sender-send-tooltip__label'>{t('chat.queue.stopShortcutTooltip')}</span>
92
+ <ShortcutDisplay shortcut='esc' isMac={isMac} />
93
+ </div>
94
+ </div>
95
+ }
96
+ placement='top'
97
+ classNames={{ root: 'sender-send-tooltip-popover' }}
98
+ trigger={['hover']}
99
+ mouseEnterDelay={.3}
100
+ mouseLeaveDelay={.08}
101
+ arrow={false}
102
+ >
103
+ <div className='sender-control-tooltip-target'>
104
+ <div className={buttonClasses} onClick={onStop}>
105
+ <span className='material-symbols-rounded'>stop_circle</span>
106
+ </div>
107
+ </div>
108
+ </Tooltip>
109
+ )
110
+ }
111
+
112
+ return (
113
+ <Tooltip
114
+ title={
115
+ <div className='sender-send-tooltip'>
116
+ <div className='sender-send-tooltip__row'>
117
+ <span className='sender-send-tooltip__label'>{t('chat.queue.steerShortcutTooltip')}</span>
118
+ <ShortcutDisplay shortcut={queueSteerShortcut} isMac={isMac} />
119
+ </div>
120
+ <div className='sender-send-tooltip__row'>
121
+ <span className='sender-send-tooltip__label'>{t('chat.queue.nextShortcutTooltip')}</span>
122
+ <ShortcutDisplay shortcut={queueNextShortcut} isMac={isMac} />
123
+ </div>
124
+ </div>
125
+ }
126
+ placement='top'
127
+ classNames={{ root: 'sender-send-tooltip-popover' }}
128
+ trigger={['hover']}
129
+ mouseEnterDelay={.3}
130
+ mouseLeaveDelay={.08}
131
+ arrow={false}
132
+ >
133
+ <div className='sender-control-tooltip-target'>
134
+ <div className={buttonClasses} onClick={isSendDisabled ? undefined : handleSendClick}>
135
+ <span className='material-symbols-rounded'>send</span>
136
+ </div>
137
+ </div>
138
+ </Tooltip>
139
+ )
140
+ }
141
+
142
+ if (sendBlocked) {
143
+ return (
144
+ <>
145
+ <Tooltip
146
+ title={sendBlockedTooltip}
147
+ placement='top'
148
+ classNames={{ root: 'sender-send-tooltip-popover' }}
149
+ trigger={['hover']}
150
+ mouseEnterDelay={.3}
151
+ mouseLeaveDelay={.08}
152
+ arrow={false}
153
+ >
154
+ <div className='sender-control-tooltip-target'>
155
+ <div className={buttonClasses} onClick={handleSendClick}>
156
+ <span className='material-symbols-rounded'>send</span>
157
+ </div>
158
+ </div>
159
+ </Tooltip>
160
+
161
+ {showConfirmInteractionAction && onConfirmInteractionAction != null && (
162
+ <Tooltip
163
+ title={t('chat.permissionConfirmOptionTooltip')}
164
+ placement='top'
165
+ classNames={{ root: 'sender-send-tooltip-popover' }}
166
+ trigger={['hover']}
167
+ mouseEnterDelay={.3}
168
+ mouseLeaveDelay={.08}
169
+ arrow={false}
170
+ >
171
+ <Button
172
+ autoInsertSpace={false}
173
+ size='small'
174
+ type='default'
175
+ className='chat-confirm-btn'
176
+ onClick={onConfirmInteractionAction}
177
+ >
178
+ <span className='material-symbols-rounded'>task_alt</span>
179
+ <span>{confirmInteractionLabel ?? t('chat.permissionConfirmOption')}</span>
180
+ </Button>
181
+ </Tooltip>
182
+ )}
183
+ </>
184
+ )
185
+ }
186
+
60
187
  return (
61
188
  <ShortcutTooltip
62
189
  shortcut={resolvedSendShortcut}
63
190
  isMac={isMac}
64
191
  title={t('chat.sendShortcutTooltip')}
65
192
  targetClassName='sender-control-tooltip-target'
66
- enabled={!isThinking}
193
+ enabled
67
194
  >
68
- <div
69
- className={`chat-send-btn ${hasSendText && !modelUnavailable ? 'active' : ''} ${isThinking ? 'thinking' : ''} ${
70
- modelUnavailable ? 'disabled' : ''
71
- }`.trim()}
72
- onClick={modelUnavailable ? undefined : (isThinking ? onInterrupt : onSend)}
73
- >
74
- <span className='material-symbols-rounded'>
75
- {isThinking ? 'stop_circle' : 'send'}
76
- </span>
195
+ <div className={buttonClasses} onClick={isSendDisabled ? undefined : handleSendClick}>
196
+ <span className='material-symbols-rounded'>send</span>
77
197
  </div>
78
198
  </ShortcutTooltip>
79
199
  )
@@ -69,3 +69,24 @@
69
69
  opacity: .56;
70
70
  }
71
71
  }
72
+
73
+ @media (max-width: 960px) {
74
+ .model-select,
75
+ .effort-select {
76
+ .ant-select-arrow {
77
+ width: 20px;
78
+ min-width: 20px;
79
+ flex: 0 0 20px;
80
+ }
81
+
82
+ &.ant-select-single .ant-select-selector {
83
+ padding-left: 6px !important;
84
+ padding-inline-start: 6px !important;
85
+ }
86
+
87
+ .ant-select-selection-item,
88
+ .ant-select-selection-placeholder {
89
+ font-size: 11px;
90
+ }
91
+ }
92
+ }
@@ -116,3 +116,24 @@
116
116
  .adapter-select-tooltip-target--locked {
117
117
  cursor: help;
118
118
  }
119
+
120
+ @media (max-width: 960px) {
121
+ .sender-select-arrow {
122
+ font-size: 16px;
123
+ }
124
+
125
+ .model-select,
126
+ .effort-select,
127
+ .adapter-select {
128
+ font-size: 11px;
129
+
130
+ .ant-select-selector {
131
+ padding: 0 0 0 6px !important;
132
+ }
133
+
134
+ .ant-select-selection-item,
135
+ .ant-select-selection-placeholder {
136
+ font-size: 11px !important;
137
+ }
138
+ }
139
+ }
@@ -15,6 +15,7 @@
15
15
  align-items: center;
16
16
  gap: 12px;
17
17
  margin: 4px -6px -6px;
18
+ min-width: 0;
18
19
 
19
20
  .toolbar-left {
20
21
  display: flex;
@@ -29,6 +30,7 @@
29
30
  align-items: center;
30
31
  gap: 4px;
31
32
  flex-shrink: 0;
33
+ min-width: 0;
32
34
  }
33
35
 
34
36
  .toolbar-right--inline-edit {
@@ -92,8 +94,69 @@
92
94
 
93
95
  @media (max-width: 960px) {
94
96
  .chat-input-toolbar {
97
+ --sender-control-height: 24px;
98
+
99
+ gap: 6px;
100
+ flex-wrap: wrap;
101
+ justify-content: flex-start;
102
+ align-items: flex-start;
103
+ margin-top: 6px;
104
+ row-gap: 6px;
105
+
106
+ .toolbar-left {
107
+ gap: 6px;
108
+ flex-wrap: wrap;
109
+ width: 100%;
110
+ }
111
+
112
+ .toolbar-right {
113
+ gap: 6px;
114
+ margin-left: auto;
115
+ max-width: 100%;
116
+ }
117
+
95
118
  .toolbar-btn__text {
96
119
  display: none;
97
120
  }
121
+
122
+ .toolbar-btn {
123
+ min-height: var(--sender-control-height);
124
+
125
+ .material-symbols-rounded {
126
+ font-size: 16px;
127
+ }
128
+ }
129
+
130
+ .toolbar-btn__icon-shell {
131
+ width: var(--sender-control-height);
132
+ height: var(--sender-control-height);
133
+ }
134
+
135
+ .toolbar-right--inline-edit {
136
+ width: 100%;
137
+ justify-content: flex-end;
138
+ }
139
+ }
140
+
141
+ .sender-select-shell,
142
+ .sender-control-tooltip-target,
143
+ .adapter-select-tooltip-target {
144
+ min-width: 0;
145
+ max-width: 100%;
146
+ }
147
+
148
+ .model-select,
149
+ .effort-select {
150
+ max-width: min(100%, 196px);
151
+ }
152
+
153
+ .model-select .ant-select-selection-item,
154
+ .model-select .ant-select-selection-placeholder,
155
+ .effort-select .ant-select-selection-item,
156
+ .effort-select .ant-select-selection-placeholder {
157
+ min-width: 0;
158
+ overflow: hidden;
159
+ text-overflow: ellipsis;
160
+ white-space: nowrap;
98
161
  }
99
162
  }
@@ -36,6 +36,10 @@ export function SenderToolbar({
36
36
  />
37
37
 
38
38
  <div className='toolbar-left'>
39
+ {!state.isInlineEdit && (
40
+ <AdapterSelectControl state={state} data={data} handlers={handlers} />
41
+ )}
42
+
39
43
  <ReferenceActionsControl
40
44
  state={state}
41
45
  data={data}
@@ -63,23 +67,25 @@ export function SenderToolbar({
63
67
  </div>
64
68
 
65
69
  <div className={`toolbar-right ${state.isInlineEdit ? 'toolbar-right--inline-edit' : ''}`.trim()}>
66
- {!state.isInlineEdit && (
67
- <AdapterSelectControl state={state} data={data} handlers={handlers} />
68
- )}
69
-
70
70
  <SenderSubmitAction
71
71
  isInlineEdit={state.isInlineEdit}
72
72
  submitLoading={state.submitLoading}
73
73
  submitLabel={data.submitLabel}
74
74
  hasComposerContent={state.hasComposerContent}
75
- hasSendText={state.hasSendText}
76
75
  modelUnavailable={state.modelUnavailable}
76
+ sendBlocked={state.sendBlocked}
77
+ sendBlockedTooltip={state.sendBlockedTooltip}
78
+ showConfirmInteractionAction={state.showConfirmInteractionAction}
79
+ confirmInteractionLabel={data.confirmInteractionLabel}
77
80
  isThinking={state.isThinking}
78
81
  resolvedSendShortcut={state.resolvedSendShortcut}
82
+ queueSteerShortcut={data.composerControlShortcuts.queueSteer}
83
+ queueNextShortcut={data.composerControlShortcuts.queueNext}
79
84
  isMac={state.isMac}
80
85
  onCancel={handlers.onCancel}
86
+ onConfirmInteractionAction={handlers.onConfirmInteractionOption}
81
87
  onSend={handlers.onSend}
82
- onInterrupt={handlers.onInterrupt}
88
+ onStop={handlers.onInterrupt}
83
89
  />
84
90
  </div>
85
91
  </div>
@@ -60,6 +60,8 @@ export const buildSenderControllerResult = ({
60
60
  modelUnavailable,
61
61
  permissionContext,
62
62
  placeholder,
63
+ secondarySendShortcut,
64
+ onSecondarySendShortcut,
63
65
  editorRef,
64
66
  toolbar
65
67
  }: {
@@ -80,6 +82,8 @@ export const buildSenderControllerResult = ({
80
82
  reasons?: string[]
81
83
  }
82
84
  placeholder: string
85
+ secondarySendShortcut?: string
86
+ onSecondarySendShortcut?: () => void
83
87
  editorRef: MutableRefObject<SenderEditorHandle | null>
84
88
  toolbar: SenderControllerToolbar
85
89
  }) => ({
@@ -100,6 +104,8 @@ export const buildSenderControllerResult = ({
100
104
  interactionResponse,
101
105
  modelUnavailable,
102
106
  placeholder,
107
+ secondarySendShortcut,
108
+ onSecondarySendShortcut,
103
109
  onInputChange: completion.handleInputChange,
104
110
  onCursorChange: completion.handleCursorChange,
105
111
  onCancelContextPicker: () => {
@@ -17,10 +17,16 @@ export const buildSenderToolbar = ({
17
17
  isInlineEdit,
18
18
  isMac,
19
19
  isThinking,
20
+ sendBlocked,
21
+ sendBlockedTooltip,
22
+ showConfirmInteractionAction,
23
+ confirmInteractionLabel,
24
+ onConfirmInteractionOption,
20
25
  message,
21
26
  props,
22
27
  refs,
23
28
  referenceActions,
29
+ queuedMessageShortcuts,
24
30
  resolvedSendShortcut,
25
31
  selectOverlays,
26
32
  supportsEffort,
@@ -31,14 +37,22 @@ export const buildSenderToolbar = ({
31
37
  handleImageUpload: () => void
32
38
  handleOpenContextPicker: () => void
33
39
  }
34
- callbacks: { onSend: () => void }
40
+ callbacks: { onSend: (mode?: 'steer' | 'next') => void }
35
41
  composer: { input: string; pendingImageCount: number; pendingFileCount: number }
36
- composerControlShortcuts: SenderToolbarData['composerControlShortcuts']
42
+ composerControlShortcuts: Pick<
43
+ SenderToolbarData['composerControlShortcuts'],
44
+ 'switchEffort' | 'switchModel' | 'switchPermissionMode'
45
+ >
37
46
  focusRestore: { queueEditorFocusRestore: () => void }
38
47
  isBusy: boolean
39
48
  isInlineEdit: boolean
40
49
  isMac: boolean
41
50
  isThinking: boolean
51
+ sendBlocked: boolean
52
+ sendBlockedTooltip?: string
53
+ showConfirmInteractionAction: boolean
54
+ confirmInteractionLabel?: string
55
+ onConfirmInteractionOption?: () => void
42
56
  message: { warning: (content: ReactNode) => unknown }
43
57
  props: SenderProps
44
58
  refs: {
@@ -57,6 +71,7 @@ export const buildSenderToolbar = ({
57
71
  referenceMenuNavigation: SenderToolbarRefs['referenceMenuNavigation']
58
72
  permissionMenuNavigation: SenderToolbarRefs['permissionMenuNavigation']
59
73
  }
74
+ queuedMessageShortcuts: Pick<SenderToolbarData['composerControlShortcuts'], 'queueNext' | 'queueSteer'>
60
75
  resolvedSendShortcut: string
61
76
  selectOverlays: {
62
77
  showModelSelect: boolean
@@ -82,7 +97,9 @@ export const buildSenderToolbar = ({
82
97
  onModelChange: props.onModelChange,
83
98
  onToggleRecommendedModel: props.onToggleRecommendedModel,
84
99
  onPermissionModeChange: props.onPermissionModeChange,
100
+ onQueueModeChange: props.onQueueModeChange,
85
101
  onCancel: props.onCancel,
102
+ onConfirmInteractionOption,
86
103
  onSend: callbacks.onSend
87
104
  },
88
105
  composer,
@@ -95,6 +112,8 @@ export const buildSenderToolbar = ({
95
112
  modelSearchOptions: props.modelSearchOptions,
96
113
  permissionMode: props.permissionMode ?? 'default',
97
114
  permissionModeOptions: props.permissionModeOptions ?? [],
115
+ queueMode: props.queueMode ?? 'steer',
116
+ queuedMessageShortcuts,
98
117
  recommendedModelOptions: props.recommendedModelOptions,
99
118
  servicePreviewModelOptions: props.servicePreviewModelOptions,
100
119
  resolvedSendShortcut,
@@ -110,10 +129,14 @@ export const buildSenderToolbar = ({
110
129
  isInlineEdit,
111
130
  isMac,
112
131
  isThinking,
132
+ sendBlocked,
133
+ sendBlockedTooltip,
134
+ showConfirmInteractionAction,
113
135
  modelUnavailable: props.modelUnavailable,
114
136
  referenceActions,
115
137
  refs,
116
138
  selectOverlays,
139
+ confirmInteractionLabel,
117
140
  submitLabel: props.submitLabel,
118
141
  submitLoading: props.submitLoading === true,
119
142
  supportsEffort