@vibe-forge/client 2.0.0 → 3.0.0-alpha.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 (351) hide show
  1. package/AGENTS.md +4 -1
  2. package/dist/assets/{arc-CbOXL0l9.js → arc-1JbypnRY.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-CqxINvsS.js → blockDiagram-c4efeb88-jT5b9nId.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-BKazU0hb.js → c4Diagram-c83219d4-KNPh-1ta.js} +1 -1
  5. package/dist/assets/channel-pzvjJnfd.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-fAFX5BpB.js → classDiagram-beda092f-vvXuOT3F.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-w1VkNGJj.js → classDiagram-v2-2358418a-vH4j7skr.js} +1 -1
  8. package/dist/assets/clone-CtWwIeUb.js +1 -0
  9. package/dist/assets/{createText-1719965b-CEinakVP.js → createText-1719965b-COeSYnf3.js} +1 -1
  10. package/dist/assets/{cssMode-DPqRki4y.js → cssMode-Doc7QRKn.js} +1 -1
  11. package/dist/assets/{edges-96097737-Cb0F1_3K.js → edges-96097737-D09v6R_r.js} +1 -1
  12. package/dist/assets/{erDiagram-0228fc6a-C-N2fx-J.js → erDiagram-0228fc6a-CbZ6rfxl.js} +1 -1
  13. package/dist/assets/{flowDb-c6c81e3f-D1Xz_8Gf.js → flowDb-c6c81e3f-CnZOzhdk.js} +1 -1
  14. package/dist/assets/{flowDiagram-50d868cf-DyPSZyAj.js → flowDiagram-50d868cf-jv-xWM2p.js} +1 -1
  15. package/dist/assets/flowDiagram-v2-4f6560a1-BiyrkIKs.js +1 -0
  16. package/dist/assets/{flowchart-elk-definition-6af322e1-Dr1DDXwE.js → flowchart-elk-definition-6af322e1-D8pf677G.js} +1 -1
  17. package/dist/assets/{freemarker2-C3DvPFaK.js → freemarker2-CL0o23Gj.js} +1 -1
  18. package/dist/assets/{ganttDiagram-a2739b55-DmvY1GRj.js → ganttDiagram-a2739b55-BAPQzC4u.js} +1 -1
  19. package/dist/assets/{gitGraphDiagram-82fe8481-CoXfPYYi.js → gitGraphDiagram-82fe8481-BI2x71m0.js} +1 -1
  20. package/dist/assets/{graph-BkDQy7Qt.js → graph-CZK4Bjpq.js} +1 -1
  21. package/dist/assets/{handlebars-BcTFdqjl.js → handlebars-CCG38Pg6.js} +1 -1
  22. package/dist/assets/{html-Dg-O6XFr.js → html-BddshTWG.js} +1 -1
  23. package/dist/assets/{htmlMode-B_wqYWvn.js → htmlMode-xKXiYcDz.js} +1 -1
  24. package/dist/assets/{index-5325376f-kxPTR3_e.js → index-5325376f-BWMTD8RU.js} +1 -1
  25. package/dist/assets/{index-wkhI4dr6.js → index-CBe7kDkV.js} +398 -377
  26. package/dist/assets/index-MWOwVzqE.css +32 -0
  27. package/dist/assets/{infoDiagram-8eee0895-BEvqkwPI.js → infoDiagram-8eee0895-CR78btIF.js} +1 -1
  28. package/dist/assets/{javascript-DhlOH8_z.js → javascript-BPlRHPjg.js} +1 -1
  29. package/dist/assets/{journeyDiagram-c64418c1-gKtLYmmp.js → journeyDiagram-c64418c1-DZRv6FKz.js} +1 -1
  30. package/dist/assets/{jsonMode-DxTbF9OD.js → jsonMode-BYLVfdkf.js} +1 -1
  31. package/dist/assets/{layout-CDaZEk6E.js → layout-BtudyPU2.js} +1 -1
  32. package/dist/assets/{line-DNRQu8iq.js → line-DgHXrIhS.js} +1 -1
  33. package/dist/assets/{linear-Cph9Z6_j.js → linear-DtBoKICx.js} +1 -1
  34. package/dist/assets/{liquid-ByZ6JgRG.js → liquid-DxBlJk0W.js} +1 -1
  35. package/dist/assets/{lspLanguageFeatures-DzvhkgnM.js → lspLanguageFeatures-DmKVpmeH.js} +1 -1
  36. package/dist/assets/{mdx-D8RGHTl6.js → mdx-DrScsd-w.js} +1 -1
  37. package/dist/assets/{mermaid.core-BgcryF__.js → mermaid.core-Cj_NJ_lZ.js} +4 -4
  38. package/dist/assets/{mindmap-definition-8da855dc-WrxK0FcB.js → mindmap-definition-8da855dc-CMXbwtsc.js} +1 -1
  39. package/dist/assets/{pieDiagram-a8764435-VsZBsiQy.js → pieDiagram-a8764435-Bd6rfpJv.js} +1 -1
  40. package/dist/assets/{python-CXVtk_cg.js → python-Crbi7B7n.js} +1 -1
  41. package/dist/assets/{quadrantDiagram-1e28029f-BVlgwOvU.js → quadrantDiagram-1e28029f-H-FdBQn6.js} +1 -1
  42. package/dist/assets/{razor-0tind7h2.js → razor-DHyrzIfE.js} +1 -1
  43. package/dist/assets/{requirementDiagram-08caed73-CpPMPoYp.js → requirementDiagram-08caed73-BSyCVDSG.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-a04cb91d-Cm5nnRmc.js → sankeyDiagram-a04cb91d-S6E6BReg.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-c5b8d532-DpMlJvJB.js → sequenceDiagram-c5b8d532-BMHY4KMj.js} +1 -1
  46. package/dist/assets/{stateDiagram-1ecb1508-DU1zc7vq.js → stateDiagram-1ecb1508-BMrMw6XR.js} +1 -1
  47. package/dist/assets/{stateDiagram-v2-c2b004d7-D-0RgmAp.js → stateDiagram-v2-c2b004d7-B5SIFUb_.js} +1 -1
  48. package/dist/assets/{styles-b4e223ce-BSO-yNWV.js → styles-b4e223ce-DqiXwnx3.js} +1 -1
  49. package/dist/assets/{styles-ca3715f6-CHnsn2Ro.js → styles-ca3715f6-jNxW2Db8.js} +1 -1
  50. package/dist/assets/{styles-d45a18b0-B-rVGjEq.js → styles-d45a18b0-C4nlfLcZ.js} +1 -1
  51. package/dist/assets/{svgDrawCommon-b86b1483-CA3Pl89f.js → svgDrawCommon-b86b1483-FIWFuZfb.js} +1 -1
  52. package/dist/assets/{timeline-definition-faaaa080-BcihLR6s.js → timeline-definition-faaaa080-CEQDoqdf.js} +1 -1
  53. package/dist/assets/{tsMode-D9GGa5Ur.js → tsMode-DnNy3rE9.js} +1 -1
  54. package/dist/assets/{typescript-BT9CK_EL.js → typescript-YBZ4vw5B.js} +1 -1
  55. package/dist/assets/{xml-DNO75J-T.js → xml-BJGGYD70.js} +1 -1
  56. package/dist/assets/{xychartDiagram-f5964ef8-DJTwe32X.js → xychartDiagram-f5964ef8-DUNOFOk0.js} +1 -1
  57. package/dist/assets/{yaml-7CVzhiP2.js → yaml-BMY4mu5s.js} +1 -1
  58. package/dist/index.html +8 -3
  59. package/dist/manifest.webmanifest +30 -0
  60. package/dist/pwa-icon-192.png +0 -0
  61. package/dist/pwa-icon-512.png +0 -0
  62. package/dist/sw.js +105 -0
  63. package/index.html +6 -1
  64. package/package.json +13 -13
  65. package/public/manifest.webmanifest +30 -0
  66. package/public/pwa-icon-192.png +0 -0
  67. package/public/pwa-icon-512.png +0 -0
  68. package/public/sw.js +105 -0
  69. package/src/App.tsx +13 -1
  70. package/src/api/README.md +1 -0
  71. package/src/api/adapters.ts +63 -0
  72. package/src/api/auth-token.ts +51 -0
  73. package/src/api/auth.ts +46 -0
  74. package/src/api/automation.ts +10 -0
  75. package/src/api/base.ts +20 -17
  76. package/src/api/config.ts +5 -1
  77. package/src/api/knowledge.ts +59 -0
  78. package/src/api/sessions.ts +35 -3
  79. package/src/api/skill-hub.ts +126 -0
  80. package/src/api/workspace.ts +33 -1
  81. package/src/api/worktree-environments.ts +53 -0
  82. package/src/api.ts +62 -7
  83. package/src/client-build-info.ts +19 -0
  84. package/src/components/ConfigView.scss +596 -28
  85. package/src/components/ConfigView.tsx +569 -138
  86. package/src/components/NavRail.scss +1 -2
  87. package/src/components/NavRail.tsx +33 -3
  88. package/src/components/Sidebar.scss +0 -44
  89. package/src/components/Sidebar.tsx +110 -37
  90. package/src/components/auth/AuthGate.scss +79 -0
  91. package/src/components/auth/AuthGate.tsx +174 -0
  92. package/src/components/automation-view/@components/AutomationTaskComposer.tsx +220 -0
  93. package/src/components/automation-view/@components/AutomationTriggerRow.tsx +192 -0
  94. package/src/components/automation-view/@hooks/use-automation-startup-options-data.tsx +289 -0
  95. package/src/components/automation-view/@hooks/use-automation-startup-static-options.ts +51 -0
  96. package/src/components/automation-view/@utils/sender-model-options.tsx +52 -0
  97. package/src/components/automation-view/@utils/startup-options.ts +26 -0
  98. package/src/components/automation-view/AutomationEmptyGuide.tsx +61 -0
  99. package/src/components/automation-view/AutomationEmptyLanding.scss +165 -0
  100. package/src/components/automation-view/AutomationEmptyLanding.tsx +211 -0
  101. package/src/components/automation-view/AutomationRuleDetailPreview.tsx +179 -0
  102. package/src/components/automation-view/PanelTitleActions.tsx +66 -0
  103. package/src/components/automation-view/RuleFormPanel.scss +172 -49
  104. package/src/components/automation-view/RuleFormPanel.tsx +196 -91
  105. package/src/components/automation-view/RuleSidebar.scss +128 -41
  106. package/src/components/automation-view/RuleSidebar.tsx +173 -89
  107. package/src/components/automation-view/RunHistoryPanel.scss +307 -72
  108. package/src/components/automation-view/RunHistoryPanel.tsx +185 -165
  109. package/src/components/automation-view/TaskList.scss +130 -64
  110. package/src/components/automation-view/TaskList.tsx +15 -31
  111. package/src/components/automation-view/TriggerList.scss +87 -8
  112. package/src/components/automation-view/TriggerList.tsx +14 -173
  113. package/src/components/automation-view/index.scss +165 -37
  114. package/src/components/automation-view/index.tsx +174 -87
  115. package/src/components/automation-view/types.ts +13 -0
  116. package/src/components/chat/AGENTS.md +3 -1
  117. package/src/components/chat/ChatHeader.tsx +56 -33
  118. package/src/components/chat/ChatHistoryView.tsx +254 -123
  119. package/src/components/chat/NewSessionGuide.scss +274 -204
  120. package/src/components/chat/NewSessionGuide.tsx +46 -111
  121. package/src/components/chat/NewSessionGuideStarterList.tsx +190 -0
  122. package/src/components/chat/NewSessionGuideStarterSection.tsx +121 -0
  123. package/src/components/chat/bottom-dock-constants.ts +4 -0
  124. package/src/components/chat/conversation-starter-apply.ts +181 -0
  125. package/src/components/chat/git-controls/ChatGitControls.scss +65 -0
  126. package/src/components/chat/git-controls/DraftGitControls.tsx +14 -0
  127. package/src/components/chat/git-controls/DraftWorktreeEnvironmentDropdown.tsx +115 -0
  128. package/src/components/chat/messages/MessageItem.tsx +21 -6
  129. package/src/components/chat/messages/MessageStatusNotice.tsx +12 -4
  130. package/src/components/chat/messages/build-chat-history-status-notices.ts +18 -13
  131. package/src/components/chat/messages/message-action-utils.ts +29 -0
  132. package/src/components/chat/new-session-guide-config.ts +19 -0
  133. package/src/components/chat/new-session-guide-items.ts +172 -0
  134. package/src/components/chat/new-session-guide-list-order.ts +58 -0
  135. package/src/components/chat/sender/@components/account-select/AccountSelectControl.scss +112 -0
  136. package/src/components/chat/sender/@components/account-select/AccountSelectControl.tsx +280 -0
  137. package/src/components/chat/sender/@components/account-select/AccountSelectDropdown.scss +155 -0
  138. package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +51 -12
  139. package/src/components/chat/sender/@components/adapter-select/AdapterSelectDropdown.scss +14 -0
  140. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.scss +36 -0
  141. package/src/components/chat/sender/@components/effort-select/EffortSelectControl.tsx +17 -12
  142. package/src/components/chat/sender/@components/model-select/ModelSelectControl.scss +62 -0
  143. package/src/components/chat/sender/@components/model-select/ModelSelectControl.tsx +17 -12
  144. package/src/components/chat/sender/@components/model-select/ModelSelectMenu.scss +2 -0
  145. package/src/components/chat/sender/@components/model-select/ModelSelectMenuLabels.scss +24 -0
  146. package/src/components/chat/sender/@components/permission-mode-control/PermissionModeControl.scss +199 -0
  147. package/src/components/chat/sender/@components/permission-mode-control/PermissionModeControl.tsx +172 -0
  148. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +1 -10
  149. package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.tsx +16 -65
  150. package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +13 -1
  151. package/src/components/chat/sender/@components/sender-header-controls/SenderHeaderControls.tsx +157 -0
  152. package/src/components/chat/sender/@components/sender-monaco-editor/monaco-runtime.ts +1 -17
  153. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +18 -2
  154. package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +18 -1
  155. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +2 -0
  156. package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +40 -40
  157. package/src/components/chat/sender/@components/session-target/SenderSessionTargetBar.scss +215 -0
  158. package/src/components/chat/sender/@components/session-target/SenderSessionTargetBar.tsx +185 -0
  159. package/src/components/chat/sender/@core/build-sender-toolbar.ts +6 -0
  160. package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +21 -1
  161. package/src/components/chat/sender/@core/get-sender-runtime-state.ts +3 -2
  162. package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +12 -0
  163. package/src/components/chat/sender/@hooks/use-sender-controller.ts +56 -1
  164. package/src/components/chat/sender/@hooks/use-sender-reference-actions.ts +9 -66
  165. package/src/components/chat/sender/@types/sender-props.ts +18 -0
  166. package/src/components/chat/sender/@types/sender-toolbar-types.ts +8 -1
  167. package/src/components/chat/sender/@types/sender-types.ts +1 -3
  168. package/src/components/chat/sender/@utils/sender-constants.ts +1 -1
  169. package/src/components/chat/sender/Sender.scss +257 -2
  170. package/src/components/chat/sender/Sender.tsx +1 -0
  171. package/src/components/chat/status-bar/ChatStatusBar.scss +85 -0
  172. package/src/components/chat/status-bar/ChatStatusBar.tsx +48 -0
  173. package/src/components/chat/terminal/@components/TerminalManagerList.tsx +191 -0
  174. package/src/components/chat/terminal/@components/TerminalPane.scss +71 -0
  175. package/src/components/chat/terminal/@components/TerminalPane.tsx +137 -0
  176. package/src/components/chat/terminal/@components/TerminalPanelActions.tsx +75 -0
  177. package/src/components/chat/terminal/@hooks/use-terminal-instance.ts +36 -0
  178. package/src/components/chat/terminal/@hooks/use-terminal-session.ts +18 -21
  179. package/src/components/chat/terminal/@hooks/use-terminal-title-editor.ts +72 -0
  180. package/src/components/chat/terminal/@utils/terminal-keyboard.ts +141 -0
  181. package/src/components/chat/terminal/@utils/terminal-panes.ts +123 -0
  182. package/src/components/chat/terminal/ChatTerminalView.scss +310 -38
  183. package/src/components/chat/terminal/ChatTerminalView.tsx +151 -79
  184. package/src/components/chat/tools/core/ToolDiffViewer.tsx +3 -17
  185. package/src/components/chat/workspace-drawer/ChatWorkspaceDrawer.scss +778 -0
  186. package/src/components/chat/workspace-drawer/ChatWorkspaceDrawer.tsx +112 -0
  187. package/src/components/chat/workspace-drawer/ChatWorkspaceDrawerToolbar.tsx +183 -0
  188. package/src/components/chat/workspace-drawer/WorkspaceDrawerChangedFileRow.tsx +75 -0
  189. package/src/components/chat/workspace-drawer/WorkspaceDrawerChangedFiles.tsx +161 -0
  190. package/src/components/chat/workspace-drawer/WorkspaceDrawerChangedFolderTree.tsx +191 -0
  191. package/src/components/chat/workspace-drawer/WorkspaceDrawerTree.tsx +35 -0
  192. package/src/components/chat/workspace-drawer/WorkspaceDrawerTreeState.tsx +17 -0
  193. package/src/components/chat/workspace-drawer/changed-files-model.ts +152 -0
  194. package/src/components/chat/workspace-drawer/workspace-drawer-icons.ts +110 -0
  195. package/src/components/chat/workspace-file-editor/WorkspaceFileBreadcrumb.tsx +17 -0
  196. package/src/components/chat/workspace-file-editor/WorkspaceFileEditorView.scss +283 -0
  197. package/src/components/chat/workspace-file-editor/WorkspaceFileEditorView.tsx +165 -0
  198. package/src/components/chat/workspace-file-editor/WorkspaceFileTabs.tsx +135 -0
  199. package/src/components/chat/workspace-file-editor/use-workspace-file-editor-state.ts +113 -0
  200. package/src/components/chat/workspace-file-editor/workspace-file-editor-language.ts +55 -0
  201. package/src/components/composer-landing/ComposerLanding.scss +75 -0
  202. package/src/components/composer-landing/ComposerLanding.tsx +47 -0
  203. package/src/components/config/AGENTS.md +45 -0
  204. package/src/components/config/AdapterAccountsManager.scss +540 -0
  205. package/src/components/config/AdapterAccountsManager.tsx +846 -0
  206. package/src/components/config/AppSettingsPanel.tsx +85 -9
  207. package/src/components/config/ConfigAboutSection.scss +7 -1
  208. package/src/components/config/ConfigAboutSection.tsx +21 -3
  209. package/src/components/config/ConfigEditors.scss +12 -0
  210. package/src/components/config/ConfigFieldRow.scss +88 -4
  211. package/src/components/config/ConfigSectionForm.scss +88 -3
  212. package/src/components/config/ConfigSectionForm.tsx +948 -138
  213. package/src/components/config/ConfigSectionPanel.tsx +188 -12
  214. package/src/components/config/ConfigSourceSwitch.tsx +32 -18
  215. package/src/components/config/DetailCollectionFieldActions.tsx +63 -0
  216. package/src/components/config/DetailListField.tsx +413 -0
  217. package/src/components/config/McpServerItemEditor.tsx +154 -0
  218. package/src/components/config/RecommendedModelsItemEditor.tsx +146 -0
  219. package/src/components/config/WorktreeEnvironmentDetailView.tsx +126 -0
  220. package/src/components/config/WorktreeEnvironmentListView.tsx +126 -0
  221. package/src/components/config/WorktreeEnvironmentPanel.scss +430 -0
  222. package/src/components/config/WorktreeEnvironmentPanel.tsx +147 -0
  223. package/src/components/config/WorktreeEnvironmentScriptEditorCard.tsx +125 -0
  224. package/src/components/config/WorktreeEnvironmentScriptEditors.tsx +189 -0
  225. package/src/components/config/configConflict.ts +41 -0
  226. package/src/components/config/configDetail.ts +381 -0
  227. package/src/components/config/configSchema.ts +850 -179
  228. package/src/components/config/configUtils.ts +1 -1
  229. package/src/components/config/record-editors/RecordEditors.scss +187 -2
  230. package/src/components/config/record-editors/RecordJsonEditor.tsx +27 -2
  231. package/src/components/config/record-editors/SchemaObjectEditor.tsx +183 -0
  232. package/src/components/config/record-editors/SchemaRecordEditor.tsx +184 -0
  233. package/src/components/config/record-editors/index.tsx +2 -1
  234. package/src/components/config/record-editors/schemaRecordUtils.ts +55 -0
  235. package/src/components/config/use-worktree-environment-auto-save.ts +386 -0
  236. package/src/components/config/worktree-environment-panel-model.ts +108 -0
  237. package/src/components/dock-panel/DockPanel.scss +84 -17
  238. package/src/components/dock-panel/DockPanel.tsx +37 -34
  239. package/src/components/dock-panel/DockPanelHeader.tsx +65 -0
  240. package/src/components/dock-panel/use-dock-panel-fullscreen.ts +51 -0
  241. package/src/components/knowledge-base/KnowledgeBaseView.scss +276 -38
  242. package/src/components/knowledge-base/KnowledgeBaseView.tsx +252 -46
  243. package/src/components/knowledge-base/components/@hooks/use-skills-cli-modal-controller.ts +157 -0
  244. package/src/components/knowledge-base/components/@hooks/use-skills-tab-actions.ts +63 -0
  245. package/src/components/knowledge-base/components/ActionButton.scss +30 -4
  246. package/src/components/knowledge-base/components/ActionButton.tsx +13 -3
  247. package/src/components/knowledge-base/components/CreateSkillModal.tsx +59 -0
  248. package/src/components/knowledge-base/components/EmptyState.scss +4 -2
  249. package/src/components/knowledge-base/components/EntitiesTab.tsx +20 -20
  250. package/src/components/knowledge-base/components/EntityList.scss +3 -0
  251. package/src/components/knowledge-base/components/FilterBar.scss +1 -0
  252. package/src/components/knowledge-base/components/FilterBar.tsx +12 -8
  253. package/src/components/knowledge-base/components/FlowsTab.tsx +20 -20
  254. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +7 -6
  255. package/src/components/knowledge-base/components/KnowledgeContentControls.tsx +35 -0
  256. package/src/components/knowledge-base/components/KnowledgeList.scss +14 -3
  257. package/src/components/knowledge-base/components/KnowledgeMobilePanel.tsx +122 -0
  258. package/src/components/knowledge-base/components/KnowledgeSidebar.tsx +97 -0
  259. package/src/components/knowledge-base/components/LoadingState.scss +2 -1
  260. package/src/components/knowledge-base/components/ProjectSkillsList.tsx +79 -0
  261. package/src/components/knowledge-base/components/RuleList.scss +3 -0
  262. package/src/components/knowledge-base/components/RulesTab.tsx +31 -30
  263. package/src/components/knowledge-base/components/SectionHeader.scss +13 -1
  264. package/src/components/knowledge-base/components/SectionHeader.tsx +5 -3
  265. package/src/components/knowledge-base/components/SkillArchiveInput.tsx +43 -0
  266. package/src/components/knowledge-base/components/SkillHubResultItem.tsx +112 -0
  267. package/src/components/knowledge-base/components/SkillMarketResults.tsx +98 -0
  268. package/src/components/knowledge-base/components/SkillMarketView.tsx +198 -0
  269. package/src/components/knowledge-base/components/SkillMarketView.types.ts +28 -0
  270. package/src/components/knowledge-base/components/SkillRegistryErrors.tsx +21 -0
  271. package/src/components/knowledge-base/components/SkillRegistryModal.tsx +74 -0
  272. package/src/components/knowledge-base/components/SkillsCliModal.tsx +154 -0
  273. package/src/components/knowledge-base/components/SkillsTab.scss +424 -0
  274. package/src/components/knowledge-base/components/SkillsTab.tsx +166 -35
  275. package/src/components/knowledge-base/components/SkillsTabActions.tsx +88 -0
  276. package/src/components/knowledge-base/components/SpecList.scss +3 -0
  277. package/src/components/knowledge-base/components/TabContent.scss +4 -3
  278. package/src/components/knowledge-base/components/skill-hub-utils.ts +108 -0
  279. package/src/components/knowledge-base/components/use-skill-market-filters.ts +37 -0
  280. package/src/components/knowledge-base/components/use-skill-market-query-input.ts +44 -0
  281. package/src/components/knowledge-base/components/use-skill-market-search.ts +49 -0
  282. package/src/components/knowledge-base/components/use-skill-registry-modal.ts +68 -0
  283. package/src/components/monaco/monaco-runtime.ts +44 -0
  284. package/src/components/monaco/use-monaco-theme.ts +63 -0
  285. package/src/components/nav-rail-account-actions.tsx +104 -0
  286. package/src/components/server-connection/ServerConnectionGate.scss +356 -0
  287. package/src/components/server-connection/ServerConnectionGate.tsx +238 -0
  288. package/src/components/server-connection/ServerConnectionProfileModal.tsx +145 -0
  289. package/src/components/server-connection/ServerConnectionProfiles.tsx +113 -0
  290. package/src/components/server-connection/ServerConnectionUrlInput.tsx +85 -0
  291. package/src/components/sidebar/SidebarHeader.scss +5 -41
  292. package/src/components/sidebar/SidebarHeader.tsx +117 -91
  293. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +24 -28
  294. package/src/components/sidebar/sidebar-search-visibility.ts +18 -0
  295. package/src/components/sidebar-list/SidebarListHeader.scss +246 -0
  296. package/src/components/sidebar-list/SidebarListHeader.tsx +146 -0
  297. package/src/components/workspace/ContextFilePicker.scss +9 -26
  298. package/src/components/workspace/ContextFilePicker.tsx +31 -113
  299. package/src/components/workspace/context-file-types.ts +36 -0
  300. package/src/components/workspace/project-file-tree/ProjectFileTree.scss +298 -0
  301. package/src/components/workspace/project-file-tree/ProjectFileTree.tsx +138 -0
  302. package/src/components/workspace/project-file-tree/ProjectFileTreeRow.tsx +167 -0
  303. package/src/components/workspace/project-file-tree/ProjectFileTreeRowContextMenu.tsx +106 -0
  304. package/src/components/workspace/project-file-tree/ProjectFileTreeRows.tsx +139 -0
  305. package/src/components/workspace/project-file-tree/project-file-tree-helpers.ts +101 -0
  306. package/src/components/workspace/project-file-tree/project-file-tree-icons.ts +93 -0
  307. package/src/components/workspace/project-file-tree/project-file-tree-types.ts +27 -0
  308. package/src/components/workspace/project-file-tree/use-project-file-tree-data.ts +197 -0
  309. package/src/components/workspace/project-file-tree/use-project-file-tree-selection.ts +144 -0
  310. package/src/hooks/chat/chat-session-target.ts +69 -0
  311. package/src/hooks/chat/chat-session-workspace-draft.ts +11 -4
  312. package/src/hooks/chat/interaction-state.ts +1 -0
  313. package/src/hooks/chat/optimistic-session-creation.ts +189 -0
  314. package/src/hooks/chat/use-chat-adapter-account-selection.tsx +156 -0
  315. package/src/hooks/chat/use-chat-route-bottom-panel.ts +181 -0
  316. package/src/hooks/chat/use-chat-route-deep-link-view.ts +33 -0
  317. package/src/hooks/chat/use-chat-session-actions.ts +259 -65
  318. package/src/hooks/chat/use-chat-session-messages.ts +71 -4
  319. package/src/hooks/chat/use-chat-session.ts +36 -1
  320. package/src/hooks/chat/workspace-file-panel-state.ts +43 -0
  321. package/src/hooks/session-subscription-cache.ts +25 -0
  322. package/src/hooks/use-chat-layout-query-state.ts +29 -0
  323. package/src/hooks/use-sender-header-query-state.ts +35 -0
  324. package/src/hooks/use-session-subscription.ts +17 -8
  325. package/src/hooks/useQueryParams.ts +91 -23
  326. package/src/i18n-resources.ts +44 -0
  327. package/src/i18n.ts +21 -6
  328. package/src/main.tsx +8 -0
  329. package/src/pwa.ts +46 -0
  330. package/src/resources/locales/en.json +741 -24
  331. package/src/resources/locales/zh.json +743 -26
  332. package/src/routes/ChatRoute.scss +110 -7
  333. package/src/routes/ChatRoute.tsx +11 -165
  334. package/src/routes/ChatRouteBottomPanel.tsx +47 -0
  335. package/src/routes/ChatRouteView.tsx +199 -0
  336. package/src/runtime-config.ts +155 -2
  337. package/src/server-connection-history.ts +179 -0
  338. package/src/store/index.ts +151 -3
  339. package/src/styles/global.scss +3 -0
  340. package/src/utils/mobile-viewport.ts +67 -0
  341. package/src/version-compatibility.ts +37 -0
  342. package/src/vite-env.d.ts +9 -0
  343. package/src/ws.ts +20 -9
  344. package/vite.config.ts +23 -1
  345. package/dist/assets/channel-Dnopc5A6.js +0 -1
  346. package/dist/assets/clone-sQthahUA.js +0 -1
  347. package/dist/assets/flowDiagram-v2-4f6560a1-OazrdWQO.js +0 -1
  348. package/dist/assets/index-o93dlo92.css +0 -32
  349. package/src/components/chat/NewSessionGuideCompactPanel.tsx +0 -130
  350. package/src/components/chat/NewSessionGuideGrid.tsx +0 -141
  351. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +0 -114
@@ -1,10 +1,17 @@
1
1
  export type RuntimeEnv = Partial<{
2
+ __VF_PROJECT_AI_SERVER_BASE_URL__: string
2
3
  __VF_PROJECT_AI_SERVER_HOST__: string
3
4
  __VF_PROJECT_AI_SERVER_PORT__: string
4
5
  __VF_PROJECT_AI_SERVER_WS_PATH__: string
6
+ __VF_PROJECT_AI_CLIENT_MODE__: string
5
7
  __VF_PROJECT_AI_CLIENT_BASE__: string
8
+ __VF_PROJECT_AI_CLIENT_VERSION__: string
9
+ __VF_PROJECT_AI_CLIENT_COMMIT_HASH__: string
6
10
  }>
7
11
 
12
+ export const SERVER_BASE_URL_STORAGE_KEY = 'vf_server_base_url'
13
+ export const SERVER_CONNECTION_PICKER_STORAGE_KEY = 'vf_server_connection_picker_requested'
14
+
8
15
  export const resolveDevDocumentTitle = (
9
16
  baseTitle: string,
10
17
  input: {
@@ -57,6 +64,95 @@ const normalizePath = (value?: string) => {
57
64
  return next
58
65
  }
59
66
 
67
+ const normalizeServerHost = (value?: string) => {
68
+ const next = value?.trim()
69
+ if (next == null || next === '' || next === '0.0.0.0' || next === '::' || next === '[::]') {
70
+ return undefined
71
+ }
72
+ return next
73
+ }
74
+
75
+ const hasUrlProtocol = (value: string) => /^[a-z][a-z\d+.-]*:\/\//i.test(value)
76
+
77
+ const getStorage = () => {
78
+ try {
79
+ return globalThis.localStorage
80
+ } catch {
81
+ return undefined
82
+ }
83
+ }
84
+
85
+ const getBrowserProtocol = () => (
86
+ globalThis.location?.protocol === 'https:' ? 'https' : 'http'
87
+ )
88
+
89
+ const getClientMode = () => (
90
+ pickNonEmptyValue(
91
+ getRuntimeEnv().__VF_PROJECT_AI_CLIENT_MODE__,
92
+ import.meta.env.__VF_PROJECT_AI_CLIENT_MODE__,
93
+ import.meta.env.__VF_PROJECT_AI_CLIENT_DEPLOY_MODE__
94
+ )?.trim().toLowerCase()
95
+ )
96
+
97
+ export const normalizeServerBaseUrl = (value?: string) => {
98
+ const trimmed = value?.trim() ?? ''
99
+ if (trimmed === '') {
100
+ return undefined
101
+ }
102
+
103
+ const rawUrl = hasUrlProtocol(trimmed) ? trimmed : `${getBrowserProtocol()}://${trimmed}`
104
+ try {
105
+ const url = new URL(rawUrl)
106
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') {
107
+ return undefined
108
+ }
109
+ url.hash = ''
110
+ url.search = ''
111
+ return url.toString().replace(/\/$/, '')
112
+ } catch {
113
+ return undefined
114
+ }
115
+ }
116
+
117
+ export const createServerUrlFromBase = (baseUrl: string, path: string) => {
118
+ const normalizedBaseUrl = normalizeServerBaseUrl(baseUrl)
119
+ if (normalizedBaseUrl == null) {
120
+ throw new Error('Invalid server base URL')
121
+ }
122
+
123
+ const relativePath = path.replace(/^\/+/, '')
124
+ return new URL(relativePath, `${normalizedBaseUrl}/`).toString()
125
+ }
126
+
127
+ export const getStoredServerBaseUrl = () => (
128
+ normalizeServerBaseUrl(getStorage()?.getItem(SERVER_BASE_URL_STORAGE_KEY) ?? undefined)
129
+ )
130
+
131
+ export const setStoredServerBaseUrl = (value: string) => {
132
+ const normalized = normalizeServerBaseUrl(value)
133
+ if (normalized == null) {
134
+ return undefined
135
+ }
136
+ getStorage()?.setItem(SERVER_BASE_URL_STORAGE_KEY, normalized)
137
+ return normalized
138
+ }
139
+
140
+ export const clearStoredServerBaseUrl = () => {
141
+ getStorage()?.removeItem(SERVER_BASE_URL_STORAGE_KEY)
142
+ }
143
+
144
+ export const isStandaloneClientMode = () => {
145
+ const mode = getClientMode()
146
+ return mode === 'standalone' || mode === 'independent'
147
+ }
148
+
149
+ export const isDesktopClientMode = () => getClientMode() === 'desktop'
150
+
151
+ export const isServerConnectionManagedClientMode = () => {
152
+ const mode = getClientMode()
153
+ return mode === 'standalone' || mode === 'independent' || mode === 'desktop'
154
+ }
155
+
60
156
  export const getRuntimeEnv = (): RuntimeEnv => getGlobalRuntimeEnv() ?? {}
61
157
 
62
158
  export const resolveClientBase = (...values: Array<string | undefined>) => (
@@ -73,14 +169,71 @@ export const getClientBase = () => (
73
169
  )
74
170
 
75
171
  export const getServerHostEnv = () =>
76
- getRuntimeEnv().__VF_PROJECT_AI_SERVER_HOST__ ??
77
- import.meta.env.__VF_PROJECT_AI_SERVER_HOST__
172
+ normalizeServerHost(
173
+ getRuntimeEnv().__VF_PROJECT_AI_SERVER_HOST__ ??
174
+ import.meta.env.__VF_PROJECT_AI_SERVER_HOST__
175
+ )
78
176
 
79
177
  export const getServerPortEnv = () =>
80
178
  getRuntimeEnv().__VF_PROJECT_AI_SERVER_PORT__ ??
81
179
  import.meta.env.__VF_PROJECT_AI_SERVER_PORT__
82
180
 
181
+ export const getConfiguredServerBaseUrl = () => {
182
+ const configuredServerBaseUrl = normalizeServerBaseUrl(
183
+ getRuntimeEnv().__VF_PROJECT_AI_SERVER_BASE_URL__ ??
184
+ import.meta.env.__VF_PROJECT_AI_SERVER_BASE_URL__
185
+ )
186
+ if (configuredServerBaseUrl != null) {
187
+ return configuredServerBaseUrl
188
+ }
189
+
190
+ const serverHost = getServerHostEnv()
191
+ const serverPort = getServerPortEnv()?.trim()
192
+ if (serverHost == null || serverPort == null || serverPort === '') {
193
+ return undefined
194
+ }
195
+
196
+ return normalizeServerBaseUrl(`${serverHost}:${serverPort}`)
197
+ }
198
+
199
+ export const isServerConnectionPickerRequested = () => (
200
+ getStorage()?.getItem(SERVER_CONNECTION_PICKER_STORAGE_KEY) === 'true'
201
+ )
202
+
203
+ export const requestServerConnectionPicker = (
204
+ { clearCurrentServer = false }: { clearCurrentServer?: boolean } = {}
205
+ ) => {
206
+ if (clearCurrentServer) {
207
+ clearStoredServerBaseUrl()
208
+ }
209
+ getStorage()?.setItem(SERVER_CONNECTION_PICKER_STORAGE_KEY, 'true')
210
+ }
211
+
212
+ export const clearServerConnectionPickerRequest = () => {
213
+ getStorage()?.removeItem(SERVER_CONNECTION_PICKER_STORAGE_KEY)
214
+ }
215
+
83
216
  export const getServerWsPath = () =>
84
217
  normalizePath(
85
218
  getRuntimeEnv().__VF_PROJECT_AI_SERVER_WS_PATH__ ?? import.meta.env.__VF_PROJECT_AI_SERVER_WS_PATH__
86
219
  )
220
+
221
+ export const getServerBaseUrl = () => {
222
+ if (isServerConnectionManagedClientMode()) {
223
+ const storedServerBaseUrl = getStoredServerBaseUrl()
224
+ if (storedServerBaseUrl != null) {
225
+ return storedServerBaseUrl
226
+ }
227
+ }
228
+
229
+ const configuredServerBaseUrl = getConfiguredServerBaseUrl()
230
+ if (configuredServerBaseUrl != null) {
231
+ return configuredServerBaseUrl
232
+ }
233
+
234
+ const serverHost = getServerHostEnv() ?? globalThis.location?.hostname ?? 'localhost'
235
+ const serverPort = getServerPortEnv() ?? '8787'
236
+ return normalizeServerBaseUrl(`${serverHost}:${serverPort}`) ?? `${getBrowserProtocol()}://localhost:8787`
237
+ }
238
+
239
+ export const createServerUrl = (path: string) => createServerUrlFromBase(getServerBaseUrl(), path)
@@ -0,0 +1,179 @@
1
+ import { normalizeServerBaseUrl } from '#~/runtime-config'
2
+
3
+ export const SERVER_BASE_URL_HISTORY_STORAGE_KEY = 'vf_server_base_url_history'
4
+
5
+ export interface ServerConnectionProfile {
6
+ serverUrl: string
7
+ alias?: string
8
+ description?: string
9
+ authToken?: string
10
+ serverVersion?: string
11
+ createdAt: number
12
+ lastConnectedAt: number
13
+ }
14
+
15
+ export interface ServerConnectionProfileDetails {
16
+ alias?: string
17
+ description?: string
18
+ }
19
+
20
+ const getStorage = () => {
21
+ try {
22
+ return globalThis.localStorage
23
+ } catch {
24
+ return undefined
25
+ }
26
+ }
27
+
28
+ const normalizeOptionalText = (value: unknown) => {
29
+ const normalized = typeof value === 'string' ? value.trim() : ''
30
+ return normalized === '' ? undefined : normalized
31
+ }
32
+
33
+ const normalizeProfile = (value: unknown, fallbackTime: number): ServerConnectionProfile | undefined => {
34
+ if (typeof value === 'string') {
35
+ const serverUrl = normalizeServerBaseUrl(value)
36
+ return serverUrl == null ? undefined : {
37
+ serverUrl,
38
+ createdAt: fallbackTime,
39
+ lastConnectedAt: fallbackTime
40
+ }
41
+ }
42
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) return undefined
43
+
44
+ const record = value as Record<string, unknown>
45
+ const serverUrl = normalizeServerBaseUrl(record.serverUrl as string | undefined)
46
+ if (serverUrl == null) return undefined
47
+
48
+ const createdAt = typeof record.createdAt === 'number' ? record.createdAt : fallbackTime
49
+ const lastConnectedAt = typeof record.lastConnectedAt === 'number' ? record.lastConnectedAt : createdAt
50
+ const alias = normalizeOptionalText(record.alias)
51
+ const description = normalizeOptionalText(record.description)
52
+ const authToken = normalizeOptionalText(record.authToken)
53
+ const serverVersion = normalizeOptionalText(record.serverVersion)
54
+ return {
55
+ serverUrl,
56
+ createdAt,
57
+ lastConnectedAt,
58
+ ...(alias != null ? { alias } : {}),
59
+ ...(description != null ? { description } : {}),
60
+ ...(authToken != null ? { authToken } : {}),
61
+ ...(serverVersion != null ? { serverVersion } : {})
62
+ }
63
+ }
64
+
65
+ const sortProfiles = (profiles: ServerConnectionProfile[]) => (
66
+ [...profiles].sort((left, right) => right.lastConnectedAt - left.lastConnectedAt)
67
+ )
68
+
69
+ const saveProfiles = (profiles: ServerConnectionProfile[]) => {
70
+ const normalizedProfiles = sortProfiles(profiles)
71
+ getStorage()?.setItem(SERVER_BASE_URL_HISTORY_STORAGE_KEY, JSON.stringify(normalizedProfiles))
72
+ return normalizedProfiles
73
+ }
74
+
75
+ export const getServerConnectionProfiles = () => {
76
+ const raw = getStorage()?.getItem(SERVER_BASE_URL_HISTORY_STORAGE_KEY)
77
+ if (raw == null || raw.trim() === '') return []
78
+
79
+ try {
80
+ const parsed = JSON.parse(raw) as unknown
81
+ if (!Array.isArray(parsed)) return []
82
+
83
+ const profileByUrl = new Map<string, ServerConnectionProfile>()
84
+ const fallbackTime = Date.now()
85
+ for (const item of parsed) {
86
+ const profile = normalizeProfile(item, fallbackTime)
87
+ if (profile == null || profileByUrl.has(profile.serverUrl)) continue
88
+ profileByUrl.set(profile.serverUrl, profile)
89
+ }
90
+ return sortProfiles(Array.from(profileByUrl.values()))
91
+ } catch {
92
+ return []
93
+ }
94
+ }
95
+
96
+ export const getRecentServerBaseUrls = () => (
97
+ getServerConnectionProfiles().map(profile => profile.serverUrl)
98
+ )
99
+
100
+ export const rememberServerBaseUrl = (value: string, details: { serverVersion?: string } = {}) => {
101
+ const serverUrl = normalizeServerBaseUrl(value)
102
+ if (serverUrl == null) return getServerConnectionProfiles()
103
+
104
+ const now = Date.now()
105
+ const profiles = getServerConnectionProfiles()
106
+ const existing = profiles.find(profile => profile.serverUrl === serverUrl)
107
+ const nextProfile: ServerConnectionProfile = {
108
+ ...existing,
109
+ serverUrl,
110
+ createdAt: existing?.createdAt ?? now,
111
+ lastConnectedAt: now,
112
+ ...(normalizeOptionalText(details.serverVersion) != null
113
+ ? { serverVersion: normalizeOptionalText(details.serverVersion) }
114
+ : {})
115
+ }
116
+ return saveProfiles([
117
+ nextProfile,
118
+ ...profiles.filter(profile => profile.serverUrl !== serverUrl)
119
+ ])
120
+ }
121
+
122
+ export const updateServerConnectionProfile = (serverUrl: string, details: ServerConnectionProfileDetails) => {
123
+ const normalizedServerUrl = normalizeServerBaseUrl(serverUrl)
124
+ if (normalizedServerUrl == null) return getServerConnectionProfiles()
125
+
126
+ const now = Date.now()
127
+ const profiles = getServerConnectionProfiles()
128
+ const existing = profiles.find(profile => profile.serverUrl === normalizedServerUrl)
129
+ const alias = normalizeOptionalText(details.alias)
130
+ const description = normalizeOptionalText(details.description)
131
+ const { alias: _alias, description: _description, ...existingProfile } = existing ?? {}
132
+ return saveProfiles([
133
+ {
134
+ ...existingProfile,
135
+ serverUrl: normalizedServerUrl,
136
+ createdAt: existing?.createdAt ?? now,
137
+ lastConnectedAt: existing?.lastConnectedAt ?? now,
138
+ ...(alias != null ? { alias } : {}),
139
+ ...(description != null ? { description } : {})
140
+ },
141
+ ...profiles.filter(profile => profile.serverUrl !== normalizedServerUrl)
142
+ ])
143
+ }
144
+
145
+ export const removeServerConnectionProfile = (serverUrl: string) => {
146
+ const normalizedServerUrl = normalizeServerBaseUrl(serverUrl)
147
+ if (normalizedServerUrl == null) return getServerConnectionProfiles()
148
+ return saveProfiles(getServerConnectionProfiles().filter(profile => profile.serverUrl !== normalizedServerUrl))
149
+ }
150
+
151
+ export const getAuthTokenForServerUrl = (serverUrl: string) => (
152
+ getServerConnectionProfiles().find(profile => profile.serverUrl === normalizeServerBaseUrl(serverUrl))
153
+ ?.authToken
154
+ )
155
+
156
+ export const setAuthTokenForServerUrl = (serverUrl: string, token: string) => {
157
+ const normalizedToken = token.trim()
158
+ if (normalizedToken === '') return
159
+
160
+ const profiles = rememberServerBaseUrl(serverUrl)
161
+ const normalizedServerUrl = normalizeServerBaseUrl(serverUrl)
162
+ saveProfiles(
163
+ profiles.map(profile =>
164
+ profile.serverUrl === normalizedServerUrl ? { ...profile, authToken: normalizedToken } : profile
165
+ )
166
+ )
167
+ }
168
+
169
+ export const clearAuthTokenForServerUrl = (serverUrl: string) => {
170
+ const normalizedServerUrl = normalizeServerBaseUrl(serverUrl)
171
+ if (normalizedServerUrl == null) return getServerConnectionProfiles()
172
+ return saveProfiles(
173
+ getServerConnectionProfiles().map(profile => {
174
+ if (profile.serverUrl !== normalizedServerUrl) return profile
175
+ const { authToken: _authToken, ...nextProfile } = profile
176
+ return nextProfile
177
+ })
178
+ )
179
+ }
@@ -18,8 +18,156 @@ export const activeSessionIdAtom = atom<string | undefined>(undefined)
18
18
 
19
19
  // 主题模式: 'light' | 'dark' | 'system'
20
20
  export type ThemeMode = 'light' | 'dark' | 'system'
21
- export const themeAtom = atom<ThemeMode>(
22
- (localStorage.getItem('theme') as ThemeMode) || 'system'
21
+
22
+ const THEME_STORAGE_KEY = 'theme'
23
+
24
+ const isThemeMode = (value: string): value is ThemeMode => {
25
+ return value === 'light' || value === 'dark' || value === 'system'
26
+ }
27
+
28
+ const getStoredThemeMode = (): ThemeMode => {
29
+ try {
30
+ const raw = localStorage.getItem(THEME_STORAGE_KEY)
31
+ if (raw != null && isThemeMode(raw)) {
32
+ return raw
33
+ }
34
+ } catch {}
35
+
36
+ return 'system'
37
+ }
38
+
39
+ const themeBaseAtom = atom<ThemeMode>(getStoredThemeMode())
40
+
41
+ export const themeAtom = atom(
42
+ get => get(themeBaseAtom),
43
+ (_get, set, value: ThemeMode) => {
44
+ const nextValue = isThemeMode(value)
45
+ ? value
46
+ : 'system'
47
+
48
+ set(themeBaseAtom, nextValue)
49
+
50
+ try {
51
+ localStorage.setItem(THEME_STORAGE_KEY, nextValue)
52
+ } catch {}
53
+ }
23
54
  )
24
55
 
25
- export const showAnnouncementsAtom = atom(true)
56
+ const getStoredBoolean = (key: string, defaultValue: boolean) => {
57
+ try {
58
+ const raw = localStorage.getItem(key)
59
+ if (raw === 'true') return true
60
+ if (raw === 'false') return false
61
+ } catch {}
62
+
63
+ return defaultValue
64
+ }
65
+
66
+ const createStoredBooleanAtom = (storageKey: string, defaultValue: boolean) => {
67
+ const baseAtom = atom<boolean>(getStoredBoolean(storageKey, defaultValue))
68
+
69
+ return atom(
70
+ get => get(baseAtom),
71
+ (_get, set, value: boolean) => {
72
+ const nextValue = value === true
73
+ set(baseAtom, nextValue)
74
+
75
+ try {
76
+ localStorage.setItem(storageKey, String(nextValue))
77
+ } catch {}
78
+ }
79
+ )
80
+ }
81
+
82
+ const getStoredNonNegativeInteger = (key: string, defaultValue: number) => {
83
+ try {
84
+ const raw = localStorage.getItem(key)
85
+ if (raw == null || raw.trim() === '') return defaultValue
86
+
87
+ const parsed = Number(raw)
88
+ if (Number.isInteger(parsed) && parsed >= 0) {
89
+ return parsed
90
+ }
91
+ } catch {}
92
+
93
+ return defaultValue
94
+ }
95
+
96
+ const createStoredNonNegativeIntegerAtom = (storageKey: string, defaultValue: number) => {
97
+ const baseAtom = atom<number>(getStoredNonNegativeInteger(storageKey, defaultValue))
98
+
99
+ return atom(
100
+ get => get(baseAtom),
101
+ (_get, set, value: number) => {
102
+ const nextValue = Number.isInteger(value) && value >= 0
103
+ ? value
104
+ : defaultValue
105
+
106
+ set(baseAtom, nextValue)
107
+
108
+ try {
109
+ localStorage.setItem(storageKey, String(nextValue))
110
+ } catch {}
111
+ }
112
+ )
113
+ }
114
+
115
+ export type SenderHeaderDisplayMode = 'expanded' | 'collapsed'
116
+
117
+ const SENDER_HEADER_DISPLAY_STORAGE_KEY = 'vf_sender_header_default_display'
118
+
119
+ const isSenderHeaderDisplayMode = (
120
+ value: string
121
+ ): value is SenderHeaderDisplayMode => {
122
+ return value === 'expanded' || value === 'collapsed'
123
+ }
124
+
125
+ const getStoredSenderHeaderDisplayMode = (): SenderHeaderDisplayMode => {
126
+ try {
127
+ const raw = localStorage.getItem(SENDER_HEADER_DISPLAY_STORAGE_KEY)
128
+ if (raw != null && isSenderHeaderDisplayMode(raw)) {
129
+ return raw
130
+ }
131
+ } catch {}
132
+
133
+ return 'expanded'
134
+ }
135
+
136
+ const senderHeaderDisplayBaseAtom = atom<SenderHeaderDisplayMode>(
137
+ getStoredSenderHeaderDisplayMode()
138
+ )
139
+
140
+ export const senderHeaderDisplayAtom = atom(
141
+ get => get(senderHeaderDisplayBaseAtom),
142
+ (_get, set, value: SenderHeaderDisplayMode) => {
143
+ const nextValue = isSenderHeaderDisplayMode(value)
144
+ ? value
145
+ : 'expanded'
146
+
147
+ set(senderHeaderDisplayBaseAtom, nextValue)
148
+
149
+ try {
150
+ localStorage.setItem(SENDER_HEADER_DISPLAY_STORAGE_KEY, nextValue)
151
+ } catch {}
152
+ }
153
+ )
154
+
155
+ const SHOW_ANNOUNCEMENTS_STORAGE_KEY = 'vf_show_announcements'
156
+ const SHOW_NEW_SESSION_STARTER_LIST_STORAGE_KEY = 'vf_show_new_session_starter_list'
157
+ const SESSION_LIST_SEARCH_THRESHOLD_STORAGE_KEY = 'vf_session_list_search_threshold'
158
+ const DEFAULT_SESSION_LIST_SEARCH_THRESHOLD = 5
159
+
160
+ export const showAnnouncementsAtom = createStoredBooleanAtom(
161
+ SHOW_ANNOUNCEMENTS_STORAGE_KEY,
162
+ true
163
+ )
164
+
165
+ export const showNewSessionStarterListAtom = createStoredBooleanAtom(
166
+ SHOW_NEW_SESSION_STARTER_LIST_STORAGE_KEY,
167
+ true
168
+ )
169
+
170
+ export const sessionListSearchThresholdAtom = createStoredNonNegativeIntegerAtom(
171
+ SESSION_LIST_SEARCH_THRESHOLD_STORAGE_KEY,
172
+ DEFAULT_SESSION_LIST_SEARCH_THRESHOLD
173
+ )
@@ -28,6 +28,9 @@ html, body, #root, .ant-app {
28
28
  }
29
29
 
30
30
  :root {
31
+ --vf-visual-viewport-height: 100dvh;
32
+ --vf-keyboard-inset-bottom: 0px;
33
+
31
34
  --bg-color: #ffffff; /* 页面/主容器背景 */
32
35
  --sub-bg-color: #f6f6f6; /* 次级容器背景 */
33
36
  --sub-sub-bg-color: #e1e1e1; /* 更内层/弱化容器背景 */
@@ -0,0 +1,67 @@
1
+ const KEYBOARD_VISIBLE_THRESHOLD = 80
2
+
3
+ const focusableSelector = [
4
+ 'input',
5
+ 'textarea',
6
+ 'select',
7
+ '[contenteditable="true"]',
8
+ '[role="textbox"]'
9
+ ].join(',')
10
+
11
+ const getViewport = () => globalThis.visualViewport
12
+
13
+ const getFocusedInput = () => {
14
+ const activeElement = document.activeElement
15
+ if (!(activeElement instanceof HTMLElement)) return undefined
16
+ return activeElement.matches(focusableSelector) ? activeElement : undefined
17
+ }
18
+
19
+ const scrollFocusedInputIntoView = () => {
20
+ const focusedInput = getFocusedInput()
21
+ if (focusedInput == null) return
22
+
23
+ focusedInput.scrollIntoView({
24
+ block: 'center',
25
+ inline: 'nearest',
26
+ behavior: 'auto'
27
+ })
28
+ }
29
+
30
+ export const setupMobileViewport = () => {
31
+ if (typeof window === 'undefined') return
32
+
33
+ let scrollFrame = 0
34
+
35
+ const updateViewportVars = () => {
36
+ const viewport = getViewport()
37
+ const viewportHeight = viewport?.height ?? window.innerHeight
38
+ const viewportOffsetTop = viewport?.offsetTop ?? 0
39
+ const focusedInput = getFocusedInput()
40
+ const keyboardInset = viewport == null || focusedInput == null
41
+ ? 0
42
+ : Math.max(0, window.innerHeight - viewportHeight - viewportOffsetTop)
43
+
44
+ document.documentElement.style.setProperty('--vf-visual-viewport-height', `${Math.round(viewportHeight)}px`)
45
+ document.documentElement.style.setProperty('--vf-keyboard-inset-bottom', `${Math.round(keyboardInset)}px`)
46
+ document.documentElement.classList.toggle('has-mobile-keyboard', keyboardInset > KEYBOARD_VISIBLE_THRESHOLD)
47
+ }
48
+
49
+ const scheduleFocusedInputScroll = () => {
50
+ window.cancelAnimationFrame(scrollFrame)
51
+ scrollFrame = window.requestAnimationFrame(() => {
52
+ updateViewportVars()
53
+ scrollFocusedInputIntoView()
54
+ })
55
+ }
56
+
57
+ updateViewportVars()
58
+
59
+ getViewport()?.addEventListener('resize', scheduleFocusedInputScroll)
60
+ getViewport()?.addEventListener('scroll', scheduleFocusedInputScroll)
61
+ window.addEventListener('resize', scheduleFocusedInputScroll)
62
+ window.addEventListener('orientationchange', scheduleFocusedInputScroll)
63
+ document.addEventListener('focusin', scheduleFocusedInputScroll)
64
+ document.addEventListener('focusout', () => {
65
+ window.setTimeout(updateViewportVars, 120)
66
+ })
67
+ }
@@ -0,0 +1,37 @@
1
+ export interface ParsedSemver {
2
+ major: number
3
+ minor: number
4
+ patch: number
5
+ prerelease?: string
6
+ }
7
+
8
+ const SEMVER_PATTERN = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/
9
+
10
+ export const parseSemverVersion = (value: string | undefined): ParsedSemver | undefined => {
11
+ const match = value?.trim().match(SEMVER_PATTERN)
12
+ if (match == null) return undefined
13
+ return {
14
+ major: Number(match[1]),
15
+ minor: Number(match[2]),
16
+ patch: Number(match[3]),
17
+ ...(match[4] != null ? { prerelease: match[4] } : {})
18
+ }
19
+ }
20
+
21
+ export const areSemverVersionsCompatible = (
22
+ clientVersion: string | undefined,
23
+ serverVersion: string | undefined
24
+ ) => {
25
+ const client = parseSemverVersion(clientVersion)
26
+ const server = parseSemverVersion(serverVersion)
27
+ if (client == null || server == null) return false
28
+ if (client.prerelease != null || server.prerelease != null) {
29
+ return client.major === server.major &&
30
+ client.minor === server.minor &&
31
+ client.patch === server.patch &&
32
+ client.prerelease === server.prerelease
33
+ }
34
+ if (client.major !== server.major) return false
35
+ if (client.major === 0) return client.minor === server.minor
36
+ return true
37
+ }
package/src/vite-env.d.ts CHANGED
@@ -1,12 +1,17 @@
1
1
  /// <reference types="vite/client" />
2
2
 
3
3
  interface ImportMetaEnv {
4
+ readonly __VF_PROJECT_AI_SERVER_BASE_URL__: string
4
5
  readonly __VF_PROJECT_AI_SERVER_HOST__: string
5
6
  readonly __VF_PROJECT_AI_SERVER_PORT__: string
6
7
  readonly __VF_PROJECT_AI_SERVER_WS_PATH__: string
7
8
  readonly __VF_PROJECT_AI_CLIENT_HOST__: string
9
+ readonly __VF_PROJECT_AI_CLIENT_MODE__: string
10
+ readonly __VF_PROJECT_AI_CLIENT_DEPLOY_MODE__: string
8
11
  readonly __VF_PROJECT_AI_CLIENT_PORT__: string
9
12
  readonly __VF_PROJECT_AI_CLIENT_BASE__: string
13
+ readonly __VF_PROJECT_AI_CLIENT_VERSION__: string
14
+ readonly __VF_PROJECT_AI_CLIENT_COMMIT_HASH__: string
10
15
  readonly __VF_PROJECT_AI_DEV_GIT_REF__: string
11
16
  }
12
17
 
@@ -16,9 +21,13 @@ interface ImportMeta {
16
21
 
17
22
  interface Window {
18
23
  __VF_PROJECT_AI_RUNTIME_ENV__?: Partial<{
24
+ __VF_PROJECT_AI_SERVER_BASE_URL__: string
19
25
  __VF_PROJECT_AI_SERVER_HOST__: string
20
26
  __VF_PROJECT_AI_SERVER_PORT__: string
21
27
  __VF_PROJECT_AI_SERVER_WS_PATH__: string
28
+ __VF_PROJECT_AI_CLIENT_MODE__: string
22
29
  __VF_PROJECT_AI_CLIENT_BASE__: string
30
+ __VF_PROJECT_AI_CLIENT_VERSION__: string
31
+ __VF_PROJECT_AI_CLIENT_COMMIT_HASH__: string
23
32
  }>
24
33
  }