@vibe-forge/client 2.0.0 → 2.0.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 (347) hide show
  1. package/AGENTS.md +4 -1
  2. package/dist/assets/{arc-CbOXL0l9.js → arc-CqviK3HX.js} +1 -1
  3. package/dist/assets/{blockDiagram-c4efeb88-CqxINvsS.js → blockDiagram-c4efeb88-BEp50UHp.js} +1 -1
  4. package/dist/assets/{c4Diagram-c83219d4-BKazU0hb.js → c4Diagram-c83219d4-C5w55JzM.js} +1 -1
  5. package/dist/assets/channel-C6LTxxLg.js +1 -0
  6. package/dist/assets/{classDiagram-beda092f-fAFX5BpB.js → classDiagram-beda092f-CQJVtHEy.js} +1 -1
  7. package/dist/assets/{classDiagram-v2-2358418a-w1VkNGJj.js → classDiagram-v2-2358418a-B37Xl9jB.js} +1 -1
  8. package/dist/assets/clone-CG6ZcokX.js +1 -0
  9. package/dist/assets/{createText-1719965b-CEinakVP.js → createText-1719965b-9YwvWMdV.js} +1 -1
  10. package/dist/assets/{cssMode-DPqRki4y.js → cssMode-BX88r5f4.js} +1 -1
  11. package/dist/assets/{edges-96097737-Cb0F1_3K.js → edges-96097737-CNHoXVrD.js} +1 -1
  12. package/dist/assets/{erDiagram-0228fc6a-C-N2fx-J.js → erDiagram-0228fc6a-BoYldy0g.js} +1 -1
  13. package/dist/assets/{flowDb-c6c81e3f-D1Xz_8Gf.js → flowDb-c6c81e3f-CoPw_R-Q.js} +1 -1
  14. package/dist/assets/{flowDiagram-50d868cf-DyPSZyAj.js → flowDiagram-50d868cf-nCqbSXd-.js} +1 -1
  15. package/dist/assets/flowDiagram-v2-4f6560a1-CSZTI7GQ.js +1 -0
  16. package/dist/assets/{flowchart-elk-definition-6af322e1-Dr1DDXwE.js → flowchart-elk-definition-6af322e1-BwMuPTrV.js} +1 -1
  17. package/dist/assets/{freemarker2-C3DvPFaK.js → freemarker2-DUFDSvgj.js} +1 -1
  18. package/dist/assets/{ganttDiagram-a2739b55-DmvY1GRj.js → ganttDiagram-a2739b55-CLNH3S_C.js} +1 -1
  19. package/dist/assets/{gitGraphDiagram-82fe8481-CoXfPYYi.js → gitGraphDiagram-82fe8481-uDu1ectX.js} +1 -1
  20. package/dist/assets/{graph-BkDQy7Qt.js → graph-DuC4kt4I.js} +1 -1
  21. package/dist/assets/{handlebars-BcTFdqjl.js → handlebars-BSd4a6l9.js} +1 -1
  22. package/dist/assets/{html-Dg-O6XFr.js → html-H48gEjQd.js} +1 -1
  23. package/dist/assets/{htmlMode-B_wqYWvn.js → htmlMode-Nqw7-Nqh.js} +1 -1
  24. package/dist/assets/{index-5325376f-kxPTR3_e.js → index-5325376f-rnz0GXAT.js} +1 -1
  25. package/dist/assets/{index-wkhI4dr6.js → index-DeQLT67a.js} +398 -377
  26. package/dist/assets/index-DiOCtPLP.css +32 -0
  27. package/dist/assets/{infoDiagram-8eee0895-BEvqkwPI.js → infoDiagram-8eee0895-BsGB550b.js} +1 -1
  28. package/dist/assets/{javascript-DhlOH8_z.js → javascript-0g2herYV.js} +1 -1
  29. package/dist/assets/{journeyDiagram-c64418c1-gKtLYmmp.js → journeyDiagram-c64418c1-DLldlz0H.js} +1 -1
  30. package/dist/assets/{jsonMode-DxTbF9OD.js → jsonMode-CN5ZURMh.js} +1 -1
  31. package/dist/assets/{layout-CDaZEk6E.js → layout-QKUiDNJK.js} +1 -1
  32. package/dist/assets/{line-DNRQu8iq.js → line-CeP3XWjD.js} +1 -1
  33. package/dist/assets/{linear-Cph9Z6_j.js → linear-74cQVgWT.js} +1 -1
  34. package/dist/assets/{liquid-ByZ6JgRG.js → liquid-B6cRrfrb.js} +1 -1
  35. package/dist/assets/{lspLanguageFeatures-DzvhkgnM.js → lspLanguageFeatures-C5ogOh5E.js} +1 -1
  36. package/dist/assets/{mdx-D8RGHTl6.js → mdx-BBIy-KRj.js} +1 -1
  37. package/dist/assets/{mermaid.core-BgcryF__.js → mermaid.core-BhdbV0mr.js} +4 -4
  38. package/dist/assets/{mindmap-definition-8da855dc-WrxK0FcB.js → mindmap-definition-8da855dc-B67VKJuD.js} +1 -1
  39. package/dist/assets/{pieDiagram-a8764435-VsZBsiQy.js → pieDiagram-a8764435-Cxv9WY_E.js} +1 -1
  40. package/dist/assets/{python-CXVtk_cg.js → python-CBdGo8__.js} +1 -1
  41. package/dist/assets/{quadrantDiagram-1e28029f-BVlgwOvU.js → quadrantDiagram-1e28029f-BTkj65P_.js} +1 -1
  42. package/dist/assets/{razor-0tind7h2.js → razor-azKH0Dwj.js} +1 -1
  43. package/dist/assets/{requirementDiagram-08caed73-CpPMPoYp.js → requirementDiagram-08caed73-D4jVXpOT.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-a04cb91d-Cm5nnRmc.js → sankeyDiagram-a04cb91d-CXhutIA1.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-c5b8d532-DpMlJvJB.js → sequenceDiagram-c5b8d532-B56TTZlx.js} +1 -1
  46. package/dist/assets/{stateDiagram-1ecb1508-DU1zc7vq.js → stateDiagram-1ecb1508-Cs0plMcS.js} +1 -1
  47. package/dist/assets/{stateDiagram-v2-c2b004d7-D-0RgmAp.js → stateDiagram-v2-c2b004d7-LSJaXPJN.js} +1 -1
  48. package/dist/assets/{styles-b4e223ce-BSO-yNWV.js → styles-b4e223ce-UdXfHMuu.js} +1 -1
  49. package/dist/assets/{styles-ca3715f6-CHnsn2Ro.js → styles-ca3715f6-EuRy_hTu.js} +1 -1
  50. package/dist/assets/{styles-d45a18b0-B-rVGjEq.js → styles-d45a18b0-B24zVoK3.js} +1 -1
  51. package/dist/assets/{svgDrawCommon-b86b1483-CA3Pl89f.js → svgDrawCommon-b86b1483-B2S0NW3K.js} +1 -1
  52. package/dist/assets/{timeline-definition-faaaa080-BcihLR6s.js → timeline-definition-faaaa080-DFWKh9mU.js} +1 -1
  53. package/dist/assets/{tsMode-D9GGa5Ur.js → tsMode-FZsHWiOn.js} +1 -1
  54. package/dist/assets/{typescript-BT9CK_EL.js → typescript-CYdJ3s3D.js} +1 -1
  55. package/dist/assets/{xml-DNO75J-T.js → xml-C16X_hpZ.js} +1 -1
  56. package/dist/assets/{xychartDiagram-f5964ef8-DJTwe32X.js → xychartDiagram-f5964ef8-DyBiBYci.js} +1 -1
  57. package/dist/assets/{yaml-7CVzhiP2.js → yaml-CRjA4-Rj.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 +595 -28
  85. package/src/components/ConfigView.tsx +568 -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 +109 -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 +218 -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 +199 -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 +126 -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 +250 -121
  119. package/src/components/chat/NewSessionGuide.scss +274 -204
  120. package/src/components/chat/NewSessionGuide.tsx +40 -111
  121. package/src/components/chat/NewSessionGuideStarterList.tsx +187 -0
  122. package/src/components/chat/NewSessionGuideStarterSection.tsx +120 -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 +3 -2
  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 +18 -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 +245 -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 +24 -2
  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/ActionButton.scss +30 -4
  244. package/src/components/knowledge-base/components/ActionButton.tsx +13 -3
  245. package/src/components/knowledge-base/components/CreateSkillModal.tsx +59 -0
  246. package/src/components/knowledge-base/components/EmptyState.scss +4 -2
  247. package/src/components/knowledge-base/components/EntitiesTab.tsx +20 -20
  248. package/src/components/knowledge-base/components/EntityList.scss +3 -0
  249. package/src/components/knowledge-base/components/FilterBar.scss +1 -0
  250. package/src/components/knowledge-base/components/FilterBar.tsx +12 -8
  251. package/src/components/knowledge-base/components/FlowsTab.tsx +20 -20
  252. package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +7 -6
  253. package/src/components/knowledge-base/components/KnowledgeContentControls.tsx +35 -0
  254. package/src/components/knowledge-base/components/KnowledgeList.scss +14 -3
  255. package/src/components/knowledge-base/components/KnowledgeMobilePanel.tsx +122 -0
  256. package/src/components/knowledge-base/components/KnowledgeSidebar.tsx +97 -0
  257. package/src/components/knowledge-base/components/LoadingState.scss +2 -1
  258. package/src/components/knowledge-base/components/ProjectSkillsList.tsx +79 -0
  259. package/src/components/knowledge-base/components/RuleList.scss +3 -0
  260. package/src/components/knowledge-base/components/RulesTab.tsx +31 -30
  261. package/src/components/knowledge-base/components/SectionHeader.scss +13 -1
  262. package/src/components/knowledge-base/components/SectionHeader.tsx +5 -3
  263. package/src/components/knowledge-base/components/SkillArchiveInput.tsx +43 -0
  264. package/src/components/knowledge-base/components/SkillHubResultItem.tsx +112 -0
  265. package/src/components/knowledge-base/components/SkillMarketResults.tsx +98 -0
  266. package/src/components/knowledge-base/components/SkillMarketView.tsx +198 -0
  267. package/src/components/knowledge-base/components/SkillMarketView.types.ts +28 -0
  268. package/src/components/knowledge-base/components/SkillRegistryErrors.tsx +21 -0
  269. package/src/components/knowledge-base/components/SkillRegistryModal.tsx +74 -0
  270. package/src/components/knowledge-base/components/SkillsCliModal.tsx +154 -0
  271. package/src/components/knowledge-base/components/SkillsTab.scss +424 -0
  272. package/src/components/knowledge-base/components/SkillsTab.tsx +319 -35
  273. package/src/components/knowledge-base/components/SkillsTabActions.tsx +88 -0
  274. package/src/components/knowledge-base/components/SpecList.scss +3 -0
  275. package/src/components/knowledge-base/components/TabContent.scss +4 -3
  276. package/src/components/knowledge-base/components/skill-hub-utils.ts +108 -0
  277. package/src/components/knowledge-base/components/use-skill-market-filters.ts +37 -0
  278. package/src/components/knowledge-base/components/use-skill-market-query-input.ts +44 -0
  279. package/src/components/knowledge-base/components/use-skill-market-search.ts +49 -0
  280. package/src/components/knowledge-base/components/use-skill-registry-modal.ts +68 -0
  281. package/src/components/monaco/monaco-runtime.ts +44 -0
  282. package/src/components/monaco/use-monaco-theme.ts +63 -0
  283. package/src/components/nav-rail-account-actions.tsx +104 -0
  284. package/src/components/server-connection/ServerConnectionGate.scss +356 -0
  285. package/src/components/server-connection/ServerConnectionGate.tsx +238 -0
  286. package/src/components/server-connection/ServerConnectionProfileModal.tsx +145 -0
  287. package/src/components/server-connection/ServerConnectionProfiles.tsx +113 -0
  288. package/src/components/server-connection/ServerConnectionUrlInput.tsx +85 -0
  289. package/src/components/sidebar/SidebarHeader.scss +5 -41
  290. package/src/components/sidebar/SidebarHeader.tsx +74 -66
  291. package/src/components/sidebar/SidebarHeaderSearchActions.tsx +24 -28
  292. package/src/components/sidebar-list/SidebarListHeader.scss +246 -0
  293. package/src/components/sidebar-list/SidebarListHeader.tsx +146 -0
  294. package/src/components/workspace/ContextFilePicker.scss +9 -26
  295. package/src/components/workspace/ContextFilePicker.tsx +31 -113
  296. package/src/components/workspace/context-file-types.ts +36 -0
  297. package/src/components/workspace/project-file-tree/ProjectFileTree.scss +298 -0
  298. package/src/components/workspace/project-file-tree/ProjectFileTree.tsx +138 -0
  299. package/src/components/workspace/project-file-tree/ProjectFileTreeRow.tsx +167 -0
  300. package/src/components/workspace/project-file-tree/ProjectFileTreeRowContextMenu.tsx +106 -0
  301. package/src/components/workspace/project-file-tree/ProjectFileTreeRows.tsx +139 -0
  302. package/src/components/workspace/project-file-tree/project-file-tree-helpers.ts +101 -0
  303. package/src/components/workspace/project-file-tree/project-file-tree-icons.ts +93 -0
  304. package/src/components/workspace/project-file-tree/project-file-tree-types.ts +27 -0
  305. package/src/components/workspace/project-file-tree/use-project-file-tree-data.ts +197 -0
  306. package/src/components/workspace/project-file-tree/use-project-file-tree-selection.ts +144 -0
  307. package/src/hooks/chat/chat-session-target.ts +69 -0
  308. package/src/hooks/chat/chat-session-workspace-draft.ts +11 -4
  309. package/src/hooks/chat/interaction-state.ts +1 -0
  310. package/src/hooks/chat/optimistic-session-creation.ts +189 -0
  311. package/src/hooks/chat/use-chat-adapter-account-selection.tsx +156 -0
  312. package/src/hooks/chat/use-chat-route-bottom-panel.ts +181 -0
  313. package/src/hooks/chat/use-chat-route-deep-link-view.ts +33 -0
  314. package/src/hooks/chat/use-chat-session-actions.ts +259 -65
  315. package/src/hooks/chat/use-chat-session-messages.ts +71 -4
  316. package/src/hooks/chat/use-chat-session.ts +36 -1
  317. package/src/hooks/chat/workspace-file-panel-state.ts +43 -0
  318. package/src/hooks/session-subscription-cache.ts +25 -0
  319. package/src/hooks/use-chat-layout-query-state.ts +29 -0
  320. package/src/hooks/use-sender-header-query-state.ts +35 -0
  321. package/src/hooks/use-session-subscription.ts +17 -8
  322. package/src/i18n-resources.ts +44 -0
  323. package/src/i18n.ts +21 -6
  324. package/src/main.tsx +8 -0
  325. package/src/pwa.ts +46 -0
  326. package/src/resources/locales/en.json +729 -24
  327. package/src/resources/locales/zh.json +731 -26
  328. package/src/routes/ChatRoute.scss +105 -7
  329. package/src/routes/ChatRoute.tsx +11 -165
  330. package/src/routes/ChatRouteBottomPanel.tsx +47 -0
  331. package/src/routes/ChatRouteView.tsx +199 -0
  332. package/src/runtime-config.ts +155 -2
  333. package/src/server-connection-history.ts +179 -0
  334. package/src/store/index.ts +40 -0
  335. package/src/styles/global.scss +3 -0
  336. package/src/utils/mobile-viewport.ts +67 -0
  337. package/src/version-compatibility.ts +37 -0
  338. package/src/vite-env.d.ts +9 -0
  339. package/src/ws.ts +20 -9
  340. package/vite.config.ts +23 -1
  341. package/dist/assets/channel-Dnopc5A6.js +0 -1
  342. package/dist/assets/clone-sQthahUA.js +0 -1
  343. package/dist/assets/flowDiagram-v2-4f6560a1-OazrdWQO.js +0 -1
  344. package/dist/assets/index-o93dlo92.css +0 -32
  345. package/src/components/chat/NewSessionGuideCompactPanel.tsx +0 -130
  346. package/src/components/chat/NewSessionGuideGrid.tsx +0 -141
  347. package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +0 -114
@@ -76,6 +76,16 @@
76
76
  }
77
77
  }
78
78
 
79
+ .chat-header-git__split-main.ant-btn.ant-btn-text .ant-btn-icon,
80
+ .chat-header-git__split-toggle.ant-btn.ant-btn-text .ant-btn-icon,
81
+ .chat-header-git__trigger.ant-btn.ant-btn-text .ant-btn-icon {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ margin-inline-end: 0;
86
+ line-height: 1;
87
+ }
88
+
79
89
  .chat-header-git__split-main.ant-btn.ant-btn-text,
80
90
  .chat-header-git__trigger.ant-btn.ant-btn-text {
81
91
  min-width: 0;
@@ -167,7 +177,9 @@
167
177
 
168
178
  .chat-header-git__trigger-main {
169
179
  width: 100%;
180
+ height: 100%;
170
181
  justify-content: center;
182
+ align-items: center;
171
183
  gap: 0;
172
184
  }
173
185
 
@@ -188,6 +200,30 @@
188
200
  display: none;
189
201
  }
190
202
 
203
+ .chat-header-git__trigger-main {
204
+ width: 100%;
205
+ height: 100%;
206
+ justify-content: center;
207
+ align-items: center;
208
+ gap: 0;
209
+ }
210
+
211
+ .chat-header-git__trigger-chevron {
212
+ display: none;
213
+ }
214
+ }
215
+
216
+ .chat-header-git__trigger.ant-btn.ant-btn-text.chat-header-git__trigger--environment.is-compact {
217
+ width: 24px;
218
+ min-width: 24px;
219
+ padding: 0;
220
+ justify-content: center;
221
+ gap: 0;
222
+
223
+ .chat-header-git__trigger-label {
224
+ display: none;
225
+ }
226
+
191
227
  .chat-header-git__trigger-main {
192
228
  width: 100%;
193
229
  justify-content: center;
@@ -207,6 +243,7 @@
207
243
  min-width: 24px;
208
244
  padding: 0;
209
245
  justify-content: center;
246
+ align-items: center;
210
247
  gap: 0;
211
248
  border-radius: 6px;
212
249
 
@@ -224,6 +261,7 @@
224
261
  min-width: 24px;
225
262
  padding: 0;
226
263
  justify-content: center;
264
+ align-items: center;
227
265
  border-top-left-radius: 6px;
228
266
  border-bottom-left-radius: 6px;
229
267
  border-top-right-radius: 6px;
@@ -231,6 +269,25 @@
231
269
  }
232
270
  }
233
271
 
272
+ .chat-header-git__trigger.ant-btn.ant-btn-text.chat-header-git__trigger--worktree.is-compact
273
+ .chat-header-git__trigger-main
274
+ .material-symbols-rounded,
275
+ .chat-header-git__trigger.ant-btn.ant-btn-text.chat-header-git__trigger--branch.is-compact
276
+ .chat-header-git__trigger-main
277
+ .material-symbols-rounded,
278
+ .chat-header-git__split--operations.is-compact .material-symbols-rounded {
279
+ display: inline-flex;
280
+ align-items: center;
281
+ justify-content: center;
282
+ }
283
+
284
+ .chat-header-git__trigger.ant-btn.ant-btn-text.chat-header-git__trigger--worktree.is-compact
285
+ .chat-header-git__trigger-chevron,
286
+ .chat-header-git__trigger.ant-btn.ant-btn-text.chat-header-git__trigger--branch.is-compact
287
+ .chat-header-git__trigger-chevron {
288
+ display: none !important;
289
+ }
290
+
234
291
  .chat-header-git__separator {
235
292
  width: 1px;
236
293
  height: 12px;
@@ -267,6 +324,10 @@
267
324
  width: 236px;
268
325
  }
269
326
 
327
+ .chat-header-git__overlay--environment {
328
+ width: 236px;
329
+ }
330
+
270
331
  .chat-header-git__overlay--worktree-root {
271
332
  width: 228px;
272
333
  }
@@ -438,6 +499,10 @@
438
499
  overflow: hidden;
439
500
  }
440
501
 
502
+ .chat-header-git__empty--environment {
503
+ padding: 10px 0 4px;
504
+ }
505
+
441
506
  .chat-header-git__sections {
442
507
  display: flex;
443
508
  flex-direction: column;
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
5
5
  import type { ChatSessionWorkspaceDraft } from '#~/hooks/chat/chat-session-workspace-draft'
6
6
 
7
7
  import { BranchSwitcherDropdown } from './BranchSwitcherDropdown'
8
+ import { DraftWorktreeEnvironmentDropdown } from './DraftWorktreeEnvironmentDropdown'
8
9
  import { GitWorktreeDropdown } from './GitWorktreeDropdown'
9
10
  import { useChatDraftGitControls } from './use-chat-draft-git-controls'
10
11
 
@@ -52,6 +53,19 @@ export function DraftGitControls({
52
53
  }}
53
54
  />
54
55
 
56
+ <DraftWorktreeEnvironmentDropdown
57
+ compact={compact}
58
+ disabled={disabled}
59
+ placement={placement}
60
+ value={draft.worktreeEnvironment}
61
+ onChange={(worktreeEnvironment) => {
62
+ onChange({
63
+ ...draft,
64
+ worktreeEnvironment
65
+ })
66
+ }}
67
+ />
68
+
55
69
  <BranchSwitcherDropdown
56
70
  availableLocalBranches={git.availableLocalBranches}
57
71
  branchQuery={git.branchQuery}
@@ -0,0 +1,115 @@
1
+ import { Button, Dropdown, Empty } from 'antd'
2
+ import { useMemo } from 'react'
3
+ import { useTranslation } from 'react-i18next'
4
+ import useSWR from 'swr'
5
+
6
+ import { listWorktreeEnvironments } from '#~/api'
7
+ import { toDisplayEnvironmentName, toEnvironmentReference } from '#~/components/config/worktree-environment-panel-model'
8
+
9
+ export function DraftWorktreeEnvironmentDropdown({
10
+ compact = false,
11
+ disabled = false,
12
+ value,
13
+ placement = 'topLeft',
14
+ onChange
15
+ }: {
16
+ compact?: boolean
17
+ disabled?: boolean
18
+ value?: string
19
+ placement?: 'bottomLeft' | 'topLeft'
20
+ onChange: (value?: string) => void
21
+ }) {
22
+ const { t } = useTranslation()
23
+ const { data } = useSWR('worktree-environments', listWorktreeEnvironments, { revalidateOnFocus: false })
24
+ const environments = data?.environments ?? []
25
+ const selectedEnvironment = environments.find(environment => (
26
+ toEnvironmentReference(environment) === value || environment.id === value
27
+ ))
28
+ const triggerLabel = selectedEnvironment != null
29
+ ? toDisplayEnvironmentName(selectedEnvironment.id)
30
+ : value != null && value !== ''
31
+ ? toDisplayEnvironmentName(value)
32
+ : t('chat.sessionWorkspaceEnvironmentDefault')
33
+ const hasEnvironments = environments.length > 0
34
+
35
+ const menuRows = useMemo(() => (
36
+ <div className='chat-header-git__overlay chat-header-git__overlay--environment'>
37
+ <button
38
+ type='button'
39
+ className={`chat-header-git__menu-row ${value == null || value === '' ? 'is-active' : ''}`}
40
+ disabled={disabled}
41
+ onClick={() => onChange(undefined)}
42
+ >
43
+ <span className='chat-header-git__menu-row-main'>
44
+ <span className='chat-header-git__row-icon material-symbols-rounded'>settings_suggest</span>
45
+ <span className='chat-header-git__menu-row-title'>
46
+ {t('chat.sessionWorkspaceEnvironmentDefault')}
47
+ </span>
48
+ </span>
49
+ </button>
50
+
51
+ {hasEnvironments
52
+ ? environments.map((environment) => {
53
+ const environmentReference = toEnvironmentReference(environment)
54
+ const isActive = environmentReference === value || environment.id === value
55
+ return (
56
+ <button
57
+ type='button'
58
+ key={`${environment.source}:${environment.id}`}
59
+ className={`chat-header-git__menu-row ${isActive ? 'is-active' : ''}`}
60
+ disabled={disabled}
61
+ title={environment.path}
62
+ onClick={() => onChange(environmentReference)}
63
+ >
64
+ <span className='chat-header-git__menu-row-main'>
65
+ <span className='chat-header-git__row-icon material-symbols-rounded'>
66
+ {environment.isLocal ? 'person' : 'folder'}
67
+ </span>
68
+ <span className='chat-header-git__menu-row-title'>
69
+ {toDisplayEnvironmentName(environment.id)}
70
+ </span>
71
+ </span>
72
+ <span className='chat-header-git__menu-row-trailing'>
73
+ <span className='chat-header-git__menu-row-value'>
74
+ {environment.isLocal
75
+ ? t('chat.sessionWorkspaceEnvironmentLocal')
76
+ : t('chat.sessionWorkspaceEnvironmentProject')}
77
+ </span>
78
+ </span>
79
+ </button>
80
+ )
81
+ })
82
+ : (
83
+ <div className='chat-header-git__empty chat-header-git__empty--environment'>
84
+ <Empty
85
+ image={Empty.PRESENTED_IMAGE_SIMPLE}
86
+ description={t('chat.sessionWorkspaceNoEnvironments')}
87
+ />
88
+ </div>
89
+ )}
90
+ </div>
91
+ ), [disabled, environments, hasEnvironments, onChange, t, value])
92
+
93
+ return (
94
+ <Dropdown
95
+ placement={placement}
96
+ trigger={['click']}
97
+ dropdownRender={() => menuRows}
98
+ >
99
+ <Button
100
+ type='text'
101
+ disabled={disabled}
102
+ className={`chat-header-git__trigger chat-header-git__trigger--environment ${compact ? 'is-compact' : ''}`
103
+ .trim()}
104
+ title={selectedEnvironment?.path ?? triggerLabel}
105
+ aria-label={t('chat.sessionWorkspaceEnvironment')}
106
+ >
107
+ <span className='chat-header-git__trigger-main'>
108
+ <span className='material-symbols-rounded'>deployed_code</span>
109
+ <span className='chat-header-git__trigger-label'>{triggerLabel}</span>
110
+ </span>
111
+ <span className='chat-header-git__trigger-chevron material-symbols-rounded'>expand_more</span>
112
+ </Button>
113
+ </Dropdown>
114
+ )
115
+ }
@@ -85,6 +85,7 @@ function MessageItemComponent({
85
85
  const canCopy = copyableText != null
86
86
  const shouldShowAssistantActions = !isUser && showAssistantActions
87
87
  const showCompactActionMenu = isCompactLayout || isTouchInteraction
88
+ const shouldShowCompactActionMenu = showCompactActionMenu && (isUser || shouldShowAssistantActions)
88
89
 
89
90
  useEffect(() => {
90
91
  setIsSubmitting(false)
@@ -440,7 +441,7 @@ function MessageItemComponent({
440
441
  className={`${isUser ? 'chat-message-user' : 'chat-message-assistant'} ${isEditing ? 'is-editing' : ''} ${
441
442
  !isFirstInGroup ? 'consecutive' : ''
442
443
  } ${isActionsVisible ? 'is-actions-visible' : ''} ${isTargeted ? 'is-targeted' : ''} ${
443
- showCompactActionMenu ? 'has-compact-menu' : ''
444
+ shouldShowCompactActionMenu ? 'has-compact-menu' : ''
444
445
  }`}
445
446
  data-message-id={originalMessage.id}
446
447
  onPointerEnter={handleActionsPointerEnter}
@@ -477,7 +478,7 @@ function MessageItemComponent({
477
478
  </div>
478
479
  {!isEditing && (
479
480
  <MessageFooter msg={originalMessage} isUser={isUser}>
480
- {showCompactActionMenu
481
+ {shouldShowCompactActionMenu
481
482
  ? compactActionMenu
482
483
  : shouldShowAssistantActions
483
484
  ? actionButtons
@@ -7,12 +7,20 @@ import type { ChatHistoryStatusNotice } from './build-chat-history-status-notice
7
7
 
8
8
  export function MessageStatusNotice({
9
9
  notice,
10
- onRetryConnection
10
+ onRetryConnection,
11
+ onRetrySessionCreation
11
12
  }: {
12
13
  notice: ChatHistoryStatusNotice
13
14
  onRetryConnection: () => void
15
+ onRetrySessionCreation?: () => void
14
16
  }) {
15
17
  const { t } = useTranslation()
18
+ const actionLabel = notice.action === 'retry-session-creation'
19
+ ? t('chat.retrySessionCreation')
20
+ : t('chat.retryConnection')
21
+ const handleAction = notice.action === 'retry-session-creation'
22
+ ? onRetrySessionCreation
23
+ : onRetryConnection
16
24
 
17
25
  return (
18
26
  <div className={`message-status-notice message-status-notice--${notice.tone} ${notice.isMock ? 'is-mock' : ''}`}>
@@ -34,10 +42,10 @@ export function MessageStatusNotice({
34
42
  {notice.detail != null && notice.detail !== '' && (
35
43
  <div className='message-status-notice__detail'>{notice.detail}</div>
36
44
  )}
37
- {notice.action === 'retry-connection' && (
45
+ {notice.action != null && handleAction != null && (
38
46
  <div className='message-status-notice__actions'>
39
- <Button size='small' onClick={onRetryConnection}>
40
- {t('chat.retryConnection')}
47
+ <Button size='small' onClick={handleAction}>
48
+ {actionLabel}
41
49
  </Button>
42
50
  </div>
43
51
  )}
@@ -3,7 +3,7 @@ import type { ChatErrorState } from '#~/hooks/chat/interaction-state'
3
3
  type Translate = (key: string, options?: Record<string, unknown>) => string
4
4
 
5
5
  export interface ChatHistoryStatusNotice {
6
- action?: 'retry-connection'
6
+ action?: 'retry-connection' | 'retry-session-creation'
7
7
  detail?: string
8
8
  icon: string
9
9
  id: string
@@ -51,18 +51,23 @@ const createSessionNotice = (
51
51
  t: Translate,
52
52
  state: ChatErrorState,
53
53
  isMock = false
54
- ): ChatHistoryStatusNotice => ({
55
- detail: t('chat.sessionErrorHelp'),
56
- icon: 'error',
57
- id: isMock ? 'mock-session-error' : 'session-error',
58
- isMock,
59
- message: state.message,
60
- meta: state.code != null && state.code !== ''
61
- ? t('chat.sessionErrorCode', { code: state.code })
62
- : undefined,
63
- tone: 'error',
64
- title: t('chat.sessionErrorTitle')
65
- })
54
+ ): ChatHistoryStatusNotice => {
55
+ const isCreateFailure = state.action === 'retry-session-creation'
56
+
57
+ return {
58
+ ...(isMock || state.action == null ? {} : { action: state.action }),
59
+ detail: isCreateFailure ? t('chat.sessionCreateFailedHelp') : t('chat.sessionErrorHelp'),
60
+ icon: 'error',
61
+ id: isMock ? 'mock-session-error' : isCreateFailure ? 'session-create-failed' : 'session-error',
62
+ isMock,
63
+ message: state.message,
64
+ ...(!isCreateFailure && state.code != null && state.code !== ''
65
+ ? { meta: t('chat.sessionErrorCode', { code: state.code }) }
66
+ : {}),
67
+ tone: 'error',
68
+ title: isCreateFailure ? t('chat.sessionCreateFailedTitle') : t('chat.sessionErrorTitle')
69
+ }
70
+ }
66
71
 
67
72
  export const buildChatHistoryStatusNotices = ({
68
73
  errorState,
@@ -0,0 +1,18 @@
1
+ import type { ChatRenderItem } from './message-utils'
2
+
3
+ export function getLastAssistantActionAnchorId(renderItems: ChatRenderItem[]) {
4
+ const lastItem = renderItems[renderItems.length - 1]
5
+ if (lastItem?.type === 'tool-group') {
6
+ return null
7
+ }
8
+
9
+ for (let index = renderItems.length - 1; index >= 0; index -= 1) {
10
+ const item = renderItems[index]
11
+ if (item == null) continue
12
+ if (item.type === 'tool-group') continue
13
+ if (item.message.role === 'user') continue
14
+ return item.anchorId
15
+ }
16
+
17
+ return null
18
+ }
@@ -0,0 +1,19 @@
1
+ export {
2
+ buildConversationStarterInitialContent,
3
+ buildConversationStarterTargetDraft,
4
+ buildConversationStarterWorkspacePatch,
5
+ normalizeConversationStarterMode
6
+ } from './conversation-starter-apply'
7
+
8
+ export {
9
+ buildConversationStarterListItems,
10
+ getNewSessionGuideData,
11
+ partitionConversationStarterListItems
12
+ } from './new-session-guide-items'
13
+
14
+ export type {
15
+ ConversationStarterCollectionKey,
16
+ ConversationStarterListItem,
17
+ NewSessionGuideData,
18
+ PartitionConversationStarterListItemsResult
19
+ } from './new-session-guide-items'
@@ -0,0 +1,172 @@
1
+ import type { ConfigResponse, ConversationStarterConfig } from '@vibe-forge/types'
2
+
3
+ import { collectVisibleRecentKeys, filterUniqueStrings, orderItemsByPriorityKeys } from './new-session-guide-list-order'
4
+
5
+ export interface NewSessionGuideData {
6
+ announcements: string[]
7
+ startupPresets: ConversationStarterConfig[]
8
+ builtinActions: ConversationStarterConfig[]
9
+ }
10
+
11
+ export type ConversationStarterCollectionKey = 'startupPresets' | 'builtinActions'
12
+
13
+ export interface ConversationStarterListItem {
14
+ key: string
15
+ order: number
16
+ source: ConversationStarterCollectionKey
17
+ sourceIndex: number
18
+ starter: ConversationStarterConfig
19
+ }
20
+
21
+ export interface PartitionConversationStarterListItemsResult {
22
+ isSearchMode: boolean
23
+ favorites: ConversationStarterListItem[]
24
+ recentKeys: string[]
25
+ visibleRemaining: ConversationStarterListItem[]
26
+ totalRemainingCount: number
27
+ hiddenRemainingCount: number
28
+ }
29
+
30
+ const trimText = (value: string | undefined) => value?.trim() ?? ''
31
+
32
+ export const getNewSessionGuideData = (configRes?: ConfigResponse): NewSessionGuideData => {
33
+ const general = configRes?.sources?.merged?.general
34
+ const conversation = configRes?.sources?.merged?.conversation
35
+
36
+ return {
37
+ announcements: general?.announcements ?? [],
38
+ startupPresets: conversation?.startupPresets ?? [],
39
+ builtinActions: conversation?.builtinActions ?? []
40
+ }
41
+ }
42
+
43
+ const buildConversationStarterListItemKey = (
44
+ starter: ConversationStarterConfig,
45
+ source: ConversationStarterCollectionKey,
46
+ sourceIndex: number
47
+ ) => {
48
+ const id = trimText(starter.id)
49
+ if (id !== '') {
50
+ return `${source}:${id}`
51
+ }
52
+
53
+ const fingerprint = [
54
+ trimText(starter.title),
55
+ trimText(starter.target),
56
+ trimText(starter.prompt)
57
+ ].filter(value => value !== '')
58
+
59
+ if (fingerprint.length > 0) {
60
+ return `${source}:${fingerprint.join('|')}`
61
+ }
62
+
63
+ return `${source}:index:${sourceIndex}`
64
+ }
65
+
66
+ export const buildConversationStarterListItems = (
67
+ startupPresets: ConversationStarterConfig[],
68
+ builtinActions: ConversationStarterConfig[]
69
+ ): ConversationStarterListItem[] => {
70
+ let order = 0
71
+
72
+ return [
73
+ ...startupPresets.map((starter, sourceIndex) => ({
74
+ key: buildConversationStarterListItemKey(starter, 'startupPresets', sourceIndex),
75
+ order: order++,
76
+ source: 'startupPresets' as const,
77
+ sourceIndex,
78
+ starter
79
+ })),
80
+ ...builtinActions.map((starter, sourceIndex) => ({
81
+ key: buildConversationStarterListItemKey(starter, 'builtinActions', sourceIndex),
82
+ order: order++,
83
+ source: 'builtinActions' as const,
84
+ sourceIndex,
85
+ starter
86
+ }))
87
+ ]
88
+ }
89
+
90
+ const normalizeSearchQuery = (value: string) => value.trim().toLowerCase()
91
+
92
+ const buildConversationStarterSearchText = (item: ConversationStarterListItem) => {
93
+ const { starter } = item
94
+
95
+ return [
96
+ trimText(starter.title),
97
+ trimText(starter.description),
98
+ trimText(starter.prompt),
99
+ trimText(starter.target),
100
+ trimText(starter.targetLabel),
101
+ trimText(starter.targetDescription),
102
+ trimText(starter.model),
103
+ ...(starter.files?.map(path => trimText(path)) ?? []),
104
+ ...(starter.rules?.map(rule => trimText(rule)) ?? []),
105
+ ...(starter.skills?.map(skill => trimText(skill)) ?? [])
106
+ ]
107
+ .filter(value => value !== '')
108
+ .join(' ')
109
+ .toLowerCase()
110
+ }
111
+
112
+ export const partitionConversationStarterListItems = ({
113
+ items,
114
+ favoriteKeys,
115
+ recentKeys,
116
+ query,
117
+ remainingLimit
118
+ }: {
119
+ items: ConversationStarterListItem[]
120
+ favoriteKeys: string[]
121
+ recentKeys: string[]
122
+ query: string
123
+ remainingLimit: number
124
+ }): PartitionConversationStarterListItemsResult => {
125
+ const normalizedQuery = normalizeSearchQuery(query)
126
+ if (normalizedQuery !== '') {
127
+ const searchTerms = normalizedQuery.split(/\s+/).filter(term => term !== '')
128
+ const matchedItems = items.filter((item) => {
129
+ const searchText = buildConversationStarterSearchText(item)
130
+ return searchTerms.every(term => searchText.includes(term))
131
+ })
132
+
133
+ return {
134
+ isSearchMode: true,
135
+ favorites: [],
136
+ recentKeys: [],
137
+ visibleRemaining: matchedItems,
138
+ totalRemainingCount: matchedItems.length,
139
+ hiddenRemainingCount: 0
140
+ }
141
+ }
142
+
143
+ const favoriteSet = new Set(filterUniqueStrings(favoriteKeys))
144
+ const itemByKey = new Map(items.map(item => [item.key, item]))
145
+ const recentKeysByPriority = collectVisibleRecentKeys(recentKeys, new Set(itemByKey.keys()), 3)
146
+
147
+ const favorites = orderItemsByPriorityKeys(
148
+ items.filter(item => favoriteSet.has(item.key)),
149
+ recentKeysByPriority
150
+ )
151
+ const favoriteKeySet = new Set(favorites.map(item => item.key))
152
+ const recentRemainingKeys = recentKeysByPriority.filter(key => !favoriteKeySet.has(key))
153
+ const hiddenKeySet = new Set([...favoriteKeySet, ...recentRemainingKeys])
154
+ const remaining = orderItemsByPriorityKeys(
155
+ items.filter(item => !hiddenKeySet.has(item.key)),
156
+ []
157
+ )
158
+ const safeLimit = Math.max(0, remainingLimit)
159
+ const visibleRemaining = [
160
+ ...recentRemainingKeys.map(key => itemByKey.get(key)).filter(Boolean),
161
+ ...remaining
162
+ ] as ConversationStarterListItem[]
163
+
164
+ return {
165
+ isSearchMode: false,
166
+ favorites,
167
+ recentKeys: recentKeysByPriority,
168
+ visibleRemaining: visibleRemaining.slice(0, safeLimit),
169
+ totalRemainingCount: visibleRemaining.length,
170
+ hiddenRemainingCount: Math.max(0, visibleRemaining.length - safeLimit)
171
+ }
172
+ }
@@ -0,0 +1,58 @@
1
+ interface KeyedOrderedItem {
2
+ key: string
3
+ order: number
4
+ }
5
+
6
+ export const filterUniqueStrings = (values: string[]) => Array.from(new Set(values))
7
+
8
+ export const collectVisibleRecentKeys = (
9
+ recentKeys: string[],
10
+ validKeys: Set<string>,
11
+ limit: number
12
+ ) => {
13
+ const visibleKeys: string[] = []
14
+
15
+ for (const key of filterUniqueStrings(recentKeys)) {
16
+ if (!validKeys.has(key)) {
17
+ continue
18
+ }
19
+
20
+ visibleKeys.push(key)
21
+
22
+ if (visibleKeys.length >= limit) {
23
+ break
24
+ }
25
+ }
26
+
27
+ return visibleKeys
28
+ }
29
+
30
+ export const orderItemsByPriorityKeys = <T extends KeyedOrderedItem>(
31
+ items: T[],
32
+ priorityKeys: string[]
33
+ ) => {
34
+ if (priorityKeys.length === 0) {
35
+ return items
36
+ }
37
+
38
+ const priorityMap = new Map(priorityKeys.map((key, index) => [key, index]))
39
+
40
+ return [...items].sort((left, right) => {
41
+ const leftPriority = priorityMap.get(left.key)
42
+ const rightPriority = priorityMap.get(right.key)
43
+
44
+ if (leftPriority != null && rightPriority != null) {
45
+ return leftPriority - rightPriority
46
+ }
47
+
48
+ if (leftPriority != null) {
49
+ return -1
50
+ }
51
+
52
+ if (rightPriority != null) {
53
+ return 1
54
+ }
55
+
56
+ return left.order - right.order
57
+ })
58
+ }