@vibe-forge/client 0.8.4 → 0.10.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.
- package/AGENTS.md +75 -0
- package/dist/assets/abap-DLDM7-KI.js +1 -0
- package/dist/assets/apex-DNDY2TF8.js +1 -0
- package/dist/assets/{arc-DCuZPvAs.js → arc-CCXV7u3V.js} +1 -1
- package/dist/assets/azcli-Y6nb8tq_.js +1 -0
- package/dist/assets/bat-BwHxbl9M.js +1 -0
- package/dist/assets/bicep-CFznDFnq.js +2 -0
- package/dist/assets/{blockDiagram-c4efeb88-C39d7-Bu.js → blockDiagram-c4efeb88-Bm52FmvT.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-jWPBJdeq.js → c4Diagram-c83219d4-C8tTEpcK.js} +1 -1
- package/dist/assets/cameligo-Bf6VGUru.js +1 -0
- package/dist/assets/channel-gq_WMRvv.js +1 -0
- package/dist/assets/{classDiagram-beda092f-Bo7Yvv2T.js → classDiagram-beda092f-CNAIBAH1.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-DfoCP9XM.js → classDiagram-v2-2358418a-BHeZAVdc.js} +1 -1
- package/dist/assets/clojure-Dnu-v4kV.js +1 -0
- package/dist/assets/clone-XxGY7A5N.js +1 -0
- package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/dist/assets/coffee-Bd8akH9Z.js +1 -0
- package/dist/assets/cpp-BbWJElDN.js +1 -0
- package/dist/assets/{createText-1719965b-8_Ez5rxh.js → createText-1719965b-BS2hLG8t.js} +1 -1
- package/dist/assets/csharp-Co3qMtFm.js +1 -0
- package/dist/assets/csp-D-4FJmMZ.js +1 -0
- package/dist/assets/css-DdJfP1eB.js +3 -0
- package/dist/assets/css.worker-BvV5MPou.js +93 -0
- package/dist/assets/cssMode-WHcTFAOU.js +1 -0
- package/dist/assets/cypher-cTPe9QuQ.js +1 -0
- package/dist/assets/dart-BOtBlQCF.js +1 -0
- package/dist/assets/dockerfile-BG73LgW2.js +1 -0
- package/dist/assets/ecl-BEgZUVRK.js +1 -0
- package/dist/assets/{edges-96097737-BEegO-R-.js → edges-96097737-C07f4iWA.js} +1 -1
- package/dist/assets/editor.worker-CKy7Pnvo.js +26 -0
- package/dist/assets/elixir-BkW5O-1t.js +1 -0
- package/dist/assets/{erDiagram-0228fc6a-derRgkLz.js → erDiagram-0228fc6a-BytsAWUs.js} +1 -1
- package/dist/assets/flow9-BeJ5waoc.js +1 -0
- package/dist/assets/{flowDb-c6c81e3f-ChtOxgsJ.js → flowDb-c6c81e3f-CQJkOpAs.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-Bm4ufmmA.js → flowDiagram-50d868cf-CD5Tng2S.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-DIBOANLV.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1-BRYLO-BL.js → flowchart-elk-definition-6af322e1-ylso-GWH.js} +1 -1
- package/dist/assets/freemarker2-U_9Jyyr3.js +3 -0
- package/dist/assets/fsharp-PahG7c26.js +1 -0
- package/dist/assets/{ganttDiagram-a2739b55-CbP6dzRO.js → ganttDiagram-a2739b55-Cg98bJx5.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-Du44v02s.js → gitGraphDiagram-82fe8481-7Yp4hz0N.js} +1 -1
- package/dist/assets/go-acbASCJo.js +1 -0
- package/dist/assets/{graph-0_VzJX6O.js → graph-Ig3nvzvL.js} +1 -1
- package/dist/assets/graphql-BxJiqAUM.js +1 -0
- package/dist/assets/handlebars-DQyCBwHe.js +1 -0
- package/dist/assets/hcl-DtV1sZF8.js +1 -0
- package/dist/assets/html-CNC2AT5k.js +1 -0
- package/dist/assets/html.worker-BLJhxQJQ.js +470 -0
- package/dist/assets/htmlMode-DlATk4xW.js +1 -0
- package/dist/assets/{index-5325376f-DLP7F7of.js → index-5325376f-C4zed9sb.js} +1 -1
- package/dist/assets/index-DRLsOoqb.css +32 -0
- package/dist/assets/index-Dbx0JG0p.js +1511 -0
- package/dist/assets/{infoDiagram-8eee0895-DY19rRl6.js → infoDiagram-8eee0895-C8oSBaFs.js} +1 -1
- package/dist/assets/ini-Kd9XrMLS.js +1 -0
- package/dist/assets/java-CXBNlu9o.js +1 -0
- package/dist/assets/javascript-9wv9uKW4.js +1 -0
- package/dist/assets/{journeyDiagram-c64418c1-4Asnwc86.js → journeyDiagram-c64418c1-D5kJldvy.js} +1 -1
- package/dist/assets/json.worker-usMZ-FED.js +58 -0
- package/dist/assets/jsonMode-45dv39mU.js +7 -0
- package/dist/assets/julia-cl7-CwDS.js +1 -0
- package/dist/assets/kotlin-s7OhZKlX.js +1 -0
- package/dist/assets/{layout-BILp7GjD.js → layout-DYNFLnIl.js} +1 -1
- package/dist/assets/less-9HpZscsL.js +2 -0
- package/dist/assets/lexon-OrD6JF1K.js +1 -0
- package/dist/assets/{line-D0Xqr8mi.js → line-1gvOYQYZ.js} +1 -1
- package/dist/assets/{linear-LpL8RZsq.js → linear-DHGm6Zdw.js} +1 -1
- package/dist/assets/liquid-BGoxrdXO.js +1 -0
- package/dist/assets/lspLanguageFeatures-CpCCXhrd.js +4 -0
- package/dist/assets/lua-Cyyb5UIc.js +1 -0
- package/dist/assets/m3-B8OfTtLu.js +1 -0
- package/dist/assets/markdown-BFxVWTOG.js +1 -0
- package/dist/assets/mdx-Dc2iMbEw.js +1 -0
- package/dist/assets/{mermaid.core-Bk0Y_0sz.js → mermaid.core-Cq2bBFF1.js} +6 -6
- package/dist/assets/{mindmap-definition-8da855dc-eCAgn5kY.js → mindmap-definition-8da855dc-y5l6GRVh.js} +1 -1
- package/dist/assets/mips-CiqrrVzr.js +1 -0
- package/dist/assets/msdax-DmeGPVcC.js +1 -0
- package/dist/assets/mysql-C_tMU-Nz.js +1 -0
- package/dist/assets/objective-c-BDtDVThU.js +1 -0
- package/dist/assets/pascal-vHIfCaH5.js +1 -0
- package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
- package/dist/assets/perl-Ub6l9XKa.js +1 -0
- package/dist/assets/pgsql-BlNEE0v7.js +1 -0
- package/dist/assets/php-BBUBE1dy.js +1 -0
- package/dist/assets/{pieDiagram-a8764435-BeGFFS1p.js → pieDiagram-a8764435-PNROcv9y.js} +1 -1
- package/dist/assets/pla-DSh2-awV.js +1 -0
- package/dist/assets/postiats-CocnycG-.js +1 -0
- package/dist/assets/powerquery-tScXyioY.js +1 -0
- package/dist/assets/powershell-COWaemsV.js +1 -0
- package/dist/assets/protobuf-Brw8urJB.js +2 -0
- package/dist/assets/pug-8SOpv6rk.js +1 -0
- package/dist/assets/python-DjYAge7h.js +1 -0
- package/dist/assets/qsharp-Bw9ernYp.js +1 -0
- package/dist/assets/{quadrantDiagram-1e28029f-tLqbYOHC.js → quadrantDiagram-1e28029f-CFJ3VPpp.js} +1 -1
- package/dist/assets/r-j7ic8hl3.js +1 -0
- package/dist/assets/razor-OIY8fx_i.js +1 -0
- package/dist/assets/redis-Bu5POkcn.js +1 -0
- package/dist/assets/redshift-Bs9aos_-.js +1 -0
- package/dist/assets/{requirementDiagram-08caed73-DCverr_g.js → requirementDiagram-08caed73-BpzDIINS.js} +1 -1
- package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
- package/dist/assets/ruby-zBfavPgS.js +1 -0
- package/dist/assets/rust-BzKRNQWT.js +1 -0
- package/dist/assets/{sankeyDiagram-a04cb91d-DidhF5PL.js → sankeyDiagram-a04cb91d-CH69-iIn.js} +1 -1
- package/dist/assets/sb-BBc9UKZt.js +1 -0
- package/dist/assets/scala-D9hQfWCl.js +1 -0
- package/dist/assets/scheme-BPhDTwHR.js +1 -0
- package/dist/assets/scss-CBJaRo0y.js +3 -0
- package/dist/assets/{sequenceDiagram-c5b8d532-CEKaiwTo.js → sequenceDiagram-c5b8d532-yBBEeVFU.js} +1 -1
- package/dist/assets/shell-DiJ1NA_G.js +1 -0
- package/dist/assets/solidity-Db0IVjzk.js +1 -0
- package/dist/assets/sophia-CnS9iZB_.js +1 -0
- package/dist/assets/sparql-CJmd_6j2.js +1 -0
- package/dist/assets/sql-ClhHkBeG.js +1 -0
- package/dist/assets/st-CHwy0fLd.js +1 -0
- package/dist/assets/{stateDiagram-1ecb1508-Cj9ZY7RH.js → stateDiagram-1ecb1508-BvF4sign.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-Gsmps-dk.js → stateDiagram-v2-c2b004d7-BeyT7Ghx.js} +1 -1
- package/dist/assets/{styles-b4e223ce-D7E8Th0j.js → styles-b4e223ce-C58zxmK6.js} +1 -1
- package/dist/assets/{styles-ca3715f6-tTC26Jsm.js → styles-ca3715f6-DCE5sFi5.js} +1 -1
- package/dist/assets/{styles-d45a18b0-Bf6oqNdR.js → styles-d45a18b0-CG-C1aM8.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-BxKi01m2.js → svgDrawCommon-b86b1483-F-K8GeDd.js} +1 -1
- package/dist/assets/swift-Bqt4WxQ4.js +3 -0
- package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
- package/dist/assets/tcl-Dm6ycUr_.js +1 -0
- package/dist/assets/{timeline-definition-faaaa080-D6PePEip.js → timeline-definition-faaaa080-DPv4uqVX.js} +1 -1
- package/dist/assets/ts.worker-DGHjMaqB.js +67731 -0
- package/dist/assets/tsMode-BtU8ZELV.js +11 -0
- package/dist/assets/twig-Csy3S7wG.js +1 -0
- package/dist/assets/typescript-CJHgISWo.js +1 -0
- package/dist/assets/typespec-Btyra-wh.js +1 -0
- package/dist/assets/vb-Db0cS2oM.js +1 -0
- package/dist/assets/wgsl-BTesnYfV.js +298 -0
- package/dist/assets/xml-C_TJw4Bi.js +1 -0
- package/dist/assets/{xychartDiagram-f5964ef8-BuP4qfXm.js → xychartDiagram-f5964ef8-BmXlhBzX.js} +1 -1
- package/dist/assets/yaml-BujeJOJ6.js +1 -0
- package/dist/favicon.svg +3 -3
- package/dist/index.html +2 -2
- package/package.json +14 -10
- package/public/favicon.svg +3 -3
- package/src/api/sessions.ts +36 -0
- package/src/api/workspace.ts +19 -0
- package/src/api.ts +4 -0
- package/src/components/NavRail.scss +9 -10
- package/src/components/ShortcutDisplay.scss +38 -0
- package/src/components/ShortcutDisplay.tsx +37 -0
- package/src/components/ShortcutTooltip.scss +36 -0
- package/src/components/ShortcutTooltip.tsx +84 -0
- package/src/components/Sidebar.scss +55 -13
- package/src/components/Sidebar.tsx +141 -52
- package/src/components/chat/AGENTS.md +163 -0
- package/src/components/chat/ChatHeader.scss +308 -49
- package/src/components/chat/ChatHeader.tsx +394 -80
- package/src/components/chat/ChatHistoryView.tsx +284 -69
- package/src/components/chat/ChatSettingsView.tsx +5 -3
- package/src/components/chat/ChatTimelineView.scss +3 -2
- package/src/components/chat/{sender/ThinkingStatus.tsx → ThinkingStatus.tsx} +1 -1
- package/src/components/chat/messages/MessageContextMenu.scss +145 -0
- package/src/components/chat/messages/MessageContextMenu.tsx +108 -0
- package/src/components/chat/messages/MessageContextMenuContent.tsx +87 -0
- package/src/components/chat/messages/MessageFooter.tsx +44 -24
- package/src/components/chat/messages/MessageItem.scss +147 -10
- package/src/components/chat/messages/MessageItem.tsx +378 -13
- package/src/components/chat/messages/build-message-context-menu-entries.ts +166 -0
- package/src/components/chat/messages/message-content-utils.ts +121 -0
- package/src/components/chat/messages/message-turns.ts +88 -0
- package/src/components/chat/messages/message-utils.ts +19 -1
- package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +86 -0
- package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.tsx +54 -0
- package/src/components/chat/sender/@components/adapter-select/AdapterSelectDropdown.scss +42 -0
- package/src/components/chat/sender/@components/effort-select/EffortSelectControl.scss +68 -0
- package/src/components/chat/sender/@components/effort-select/EffortSelectControl.tsx +137 -0
- package/src/components/chat/sender/@components/effort-select/EffortSelectDropdown.scss +96 -0
- package/src/components/chat/sender/@components/model-select/ModelSelectControl.scss +82 -0
- package/src/components/chat/sender/@components/model-select/ModelSelectControl.tsx +171 -0
- package/src/components/chat/sender/@components/model-select/ModelSelectMenu.scss +95 -0
- package/src/components/chat/sender/@components/model-select/ModelSelectMenuLabels.scss +144 -0
- package/src/components/chat/sender/@components/model-select/ModelSelectOptionLabel.tsx +109 -0
- package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +106 -0
- package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.tsx +156 -0
- package/src/components/chat/sender/@components/reference-actions/ReferenceActionsOption.scss +34 -0
- package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +111 -0
- package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +103 -0
- package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +47 -0
- package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +137 -0
- package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +178 -0
- package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +145 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.scss +47 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +121 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/monaco-runtime.ts +99 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-editor-handle.ts +48 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +209 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +24 -0
- package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +54 -0
- package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +80 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +71 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +118 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +99 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +87 -0
- package/src/components/chat/sender/@core/build-sender-controller-result.ts +119 -0
- package/src/components/chat/sender/@core/build-sender-toolbar.ts +122 -0
- package/src/components/chat/sender/@core/content-attachments.ts +76 -0
- package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +115 -0
- package/src/components/chat/sender/@core/get-sender-interaction-state.ts +18 -0
- package/src/components/chat/sender/@core/get-sender-runtime-state.ts +14 -0
- package/src/components/chat/sender/@core/interaction-request.ts +5 -0
- package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +155 -0
- package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +189 -0
- package/src/components/chat/sender/@hooks/use-sender-attachments.ts +143 -0
- package/src/components/chat/sender/@hooks/use-sender-autofocus.ts +34 -0
- package/src/components/chat/sender/@hooks/use-sender-completion.ts +62 -0
- package/src/components/chat/sender/@hooks/use-sender-composer-state.ts +34 -0
- package/src/components/chat/sender/@hooks/use-sender-controller.ts +193 -0
- package/src/components/chat/sender/@hooks/use-sender-focus-restore.ts +72 -0
- package/src/components/chat/sender/@hooks/use-sender-history.ts +79 -0
- package/src/components/chat/sender/@hooks/use-sender-keydown.ts +113 -0
- package/src/components/chat/sender/@hooks/use-sender-reference-actions.ts +191 -0
- package/src/components/chat/sender/@hooks/use-sender-reference-focus-restore.ts +21 -0
- package/src/components/chat/sender/@hooks/use-sender-refs.ts +19 -0
- package/src/components/chat/sender/@hooks/use-sender-select-overlays.ts +83 -0
- package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +78 -0
- package/src/components/chat/sender/@hooks/use-sender-submit.ts +81 -0
- package/src/components/chat/sender/@types/sender-composer.ts +19 -0
- package/src/components/chat/sender/@types/sender-editor.ts +12 -0
- package/src/components/chat/sender/@types/sender-props.ts +50 -0
- package/src/components/chat/sender/@types/sender-toolbar-types.ts +83 -0
- package/src/components/chat/sender/@types/sender-types.ts +21 -0
- package/src/components/chat/sender/@utils/sender-completion.ts +164 -0
- package/src/components/chat/sender/@utils/sender-constants.ts +18 -0
- package/src/components/chat/sender/@utils/sender-utils.ts +45 -0
- package/src/components/chat/sender/Sender.scss +8 -605
- package/src/components/chat/sender/Sender.tsx +54 -880
- package/src/components/chat/session-metadata.ts +55 -0
- package/src/components/chat/terminal/@hooks/use-terminal-instance.ts +152 -0
- package/src/components/chat/terminal/@hooks/use-terminal-session.ts +196 -0
- package/src/components/chat/terminal/ChatTerminalView.scss +62 -0
- package/src/components/chat/terminal/ChatTerminalView.tsx +114 -0
- package/src/components/chat/tools/core/ToolGroup.scss +7 -0
- package/src/components/chat/tools/core/ToolGroup.tsx +97 -56
- package/src/components/config/ConfigSectionForm.tsx +8 -1
- package/src/components/config/ConfigShortcutInput.tsx +9 -2
- package/src/components/config/configSchema.ts +12 -2
- package/src/components/config/record-editors/ModelServicesRecordEditor.tsx +0 -14
- package/src/components/dock-panel/DockPanel.scss +152 -0
- package/src/components/dock-panel/DockPanel.tsx +195 -0
- package/src/components/layout/AppShell.scss +40 -2
- package/src/components/layout/AppShell.tsx +25 -10
- package/src/components/sidebar/SessionContextMenu.scss +143 -0
- package/src/components/sidebar/SessionContextMenu.tsx +196 -0
- package/src/components/sidebar/SessionContextMenuContent.tsx +89 -0
- package/src/components/sidebar/SessionItem.scss +150 -67
- package/src/components/sidebar/SessionItem.tsx +183 -134
- package/src/components/sidebar/SessionList.scss +47 -17
- package/src/components/sidebar/SessionList.tsx +31 -16
- package/src/components/sidebar/SidebarHeader.scss +329 -49
- package/src/components/sidebar/SidebarHeader.tsx +108 -86
- package/src/components/sidebar/SidebarHeaderBatchActions.tsx +81 -0
- package/src/components/sidebar/SidebarHeaderSearchActions.tsx +176 -0
- package/src/components/sidebar/SidebarHeaderSelectField.tsx +24 -0
- package/src/components/sidebar/filter-utils.ts +23 -0
- package/src/components/workspace/ContextFilePicker.scss +64 -0
- package/src/components/workspace/ContextFilePicker.tsx +171 -0
- package/src/connectionManager.ts +4 -2
- package/src/hooks/chat/interaction-state.ts +104 -0
- package/src/hooks/chat/model-selector-data-builders.ts +146 -0
- package/src/hooks/chat/model-selector-data-option-utils.ts +62 -0
- package/src/hooks/chat/model-selector-data-types.ts +27 -0
- package/src/hooks/chat/model-selector-data.ts +109 -0
- package/src/hooks/chat/model-selector-recommendations.ts +69 -0
- package/src/hooks/chat/model-selector.ts +9 -0
- package/src/hooks/chat/use-chat-interaction.ts +13 -8
- package/src/hooks/chat/use-chat-model-adapter-selection.tsx +167 -164
- package/src/hooks/chat/use-chat-models.tsx +46 -23
- package/src/hooks/chat/use-chat-session-actions.ts +69 -23
- package/src/hooks/chat/use-chat-session-messages.ts +165 -60
- package/src/hooks/chat/use-chat-session.ts +34 -9
- package/src/hooks/chat/use-chat-view.ts +26 -6
- package/src/hooks/chat/use-composer-control-shortcuts.ts +69 -0
- package/src/hooks/chat/use-terminal-dock-visibility.ts +39 -0
- package/src/hooks/use-roving-focus-list.ts +104 -0
- package/src/hooks/use-sidebar-navigation.ts +9 -4
- package/src/hooks/use-sidebar-query-state.ts +79 -0
- package/src/main.tsx +6 -1
- package/src/resources/locales/en.json +151 -6
- package/src/resources/locales/zh.json +151 -6
- package/src/routes/ChatRoute.scss +159 -4
- package/src/routes/ChatRoute.tsx +43 -9
- package/src/runtime-config.ts +21 -0
- package/src/store/index.ts +1 -3
- package/src/styles/global.scss +12 -2
- package/src/utils/chat-links.ts +21 -0
- package/src/utils/copy.ts +18 -0
- package/src/utils/shortcutUtils.ts +111 -1
- package/src/vite-env.d.ts +1 -0
- package/src/ws.ts +6 -5
- package/vite.config.ts +71 -7
- package/dist/assets/channel-bLjHfx-Q.js +0 -1
- package/dist/assets/clone-upfY39Je.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-F66FzZTY.js +0 -1
- package/dist/assets/index-C1O04Df8.js +0 -557
- package/dist/assets/index-sE8VA1N7.css +0 -1
- package/src/components/chat/sender/CompletionMenu.scss +0 -70
- package/src/components/chat/sender/CompletionMenu.tsx +0 -58
- /package/src/components/chat/{sender/ThinkingStatus.scss → ThinkingStatus.scss} +0 -0
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
import './Sidebar.scss'
|
|
2
2
|
|
|
3
3
|
import { Button, Tooltip } from 'antd'
|
|
4
|
-
import {
|
|
4
|
+
import { useAtomValue } from 'jotai'
|
|
5
5
|
import React, { useMemo, useRef, useState } from 'react'
|
|
6
6
|
import { useTranslation } from 'react-i18next'
|
|
7
7
|
import useSWR from 'swr'
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import { useSidebarQueryState } from '#~/hooks/use-sidebar-query-state'
|
|
10
|
+
import type { SidebarSessionSortOrder } from '#~/hooks/use-sidebar-query-state'
|
|
11
|
+
import { getAdapterDisplay } from '#~/resources/adapters.js'
|
|
10
12
|
import type { Session } from '@vibe-forge/core'
|
|
11
|
-
import { deleteSession, updateSession } from '../api'
|
|
13
|
+
import { deleteSession, updateSession, updateSessionTitle } from '../api'
|
|
12
14
|
import { useGlobalShortcut } from '../hooks/useGlobalShortcut'
|
|
13
|
-
import {
|
|
15
|
+
import { isSidebarResizingAtom } from '../store/index'
|
|
14
16
|
import { formatShortcutLabel } from '../utils/shortcutUtils'
|
|
15
17
|
import { SessionList } from './sidebar/SessionList'
|
|
16
18
|
import { SidebarHeader } from './sidebar/SidebarHeader'
|
|
19
|
+
import { matchesAnyFilterPattern } from './sidebar/filter-utils'
|
|
20
|
+
|
|
21
|
+
const sortSessionsByOrder = (sessions: Session[], sortOrder: SidebarSessionSortOrder) => {
|
|
22
|
+
return [...sessions].sort((left, right) => {
|
|
23
|
+
const starredDelta = Number(right.isStarred === true) - Number(left.isStarred === true)
|
|
24
|
+
if (starredDelta !== 0) return starredDelta
|
|
25
|
+
|
|
26
|
+
const createdDelta = (left.createdAt ?? 0) - (right.createdAt ?? 0)
|
|
27
|
+
return sortOrder === 'asc' ? createdDelta : -createdDelta
|
|
28
|
+
})
|
|
29
|
+
}
|
|
17
30
|
|
|
18
31
|
export function Sidebar({
|
|
19
32
|
activeId,
|
|
@@ -26,19 +39,26 @@ export function Sidebar({
|
|
|
26
39
|
onDeletedSession?: (id: string, nextId?: string) => void
|
|
27
40
|
width: number
|
|
28
41
|
}) {
|
|
29
|
-
const {
|
|
30
|
-
|
|
42
|
+
const {
|
|
43
|
+
adapterFilters,
|
|
44
|
+
hasActiveFilterConditions,
|
|
45
|
+
hasActiveSearchControls,
|
|
46
|
+
isSidebarCollapsed,
|
|
47
|
+
searchQuery,
|
|
48
|
+
setSortOrder,
|
|
49
|
+
setAdapterFilters,
|
|
50
|
+
setSearchQuery,
|
|
51
|
+
setSidebarCollapsed,
|
|
52
|
+
setTagFilters,
|
|
53
|
+
sortOrder,
|
|
54
|
+
sortSelection,
|
|
55
|
+
tagFilters
|
|
56
|
+
} = useSidebarQueryState()
|
|
31
57
|
const isResizing = useAtomValue(isSidebarResizingAtom)
|
|
32
|
-
const [searchQuery, setSearchQuery] = useState('')
|
|
33
58
|
const [isBatchMode, setIsBatchMode] = useState(false)
|
|
34
59
|
const [selectedIds, setSelectedIds] = useState(new Set<string>())
|
|
60
|
+
const { t } = useTranslation()
|
|
35
61
|
const isMac = navigator.platform.includes('Mac')
|
|
36
|
-
const { values } = useQueryParams<{ tag: string }>({
|
|
37
|
-
keys: ['tag'],
|
|
38
|
-
defaults: { tag: '' },
|
|
39
|
-
omit: { tag: (value) => value === '' }
|
|
40
|
-
})
|
|
41
|
-
const tagFilter = values.tag.trim()
|
|
42
62
|
|
|
43
63
|
const { data: sessionsRes, mutate: mutateSessions } = useSWR<{ sessions: Session[] }>(
|
|
44
64
|
`/api/sessions`
|
|
@@ -62,24 +82,46 @@ export function Sidebar({
|
|
|
62
82
|
() => formatShortcutLabel(resolvedNewSessionShortcut, isMac),
|
|
63
83
|
[resolvedNewSessionShortcut, isMac]
|
|
64
84
|
)
|
|
85
|
+
const availableTags = useMemo(() => {
|
|
86
|
+
return Array.from(
|
|
87
|
+
new Set(
|
|
88
|
+
sessions.flatMap((session) => (session.tags ?? []).map((tag) => tag.trim()).filter(Boolean))
|
|
89
|
+
)
|
|
90
|
+
).sort((left, right) => left.localeCompare(right))
|
|
91
|
+
}, [sessions])
|
|
92
|
+
const availableAdapters = useMemo(() => {
|
|
93
|
+
return Array.from(
|
|
94
|
+
new Set(
|
|
95
|
+
sessions
|
|
96
|
+
.map((session) => session.adapter?.trim() ?? '')
|
|
97
|
+
.filter(Boolean)
|
|
98
|
+
)
|
|
99
|
+
).sort((left, right) => left.localeCompare(right))
|
|
100
|
+
}, [sessions])
|
|
65
101
|
|
|
66
102
|
const filteredSessions = useMemo(() => {
|
|
67
103
|
const query = searchQuery.trim().toLowerCase()
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
104
|
+
const visibleSessions = sessions.filter((s: Session) => {
|
|
105
|
+
if (!matchesAnyFilterPattern(s.tags ?? [], tagFilters)) return false
|
|
106
|
+
|
|
107
|
+
const adapterCandidates = [
|
|
108
|
+
s.adapter ?? '',
|
|
109
|
+
s.adapter != null && s.adapter !== '' ? getAdapterDisplay(s.adapter).title : ''
|
|
110
|
+
].filter(Boolean)
|
|
111
|
+
if (!matchesAnyFilterPattern(adapterCandidates, adapterFilters)) return false
|
|
112
|
+
|
|
73
113
|
if (!query) return true
|
|
74
114
|
return (
|
|
75
115
|
(s.title ?? '').toLowerCase().includes(query) ||
|
|
76
116
|
(s.lastMessage ?? '').toLowerCase().includes(query) ||
|
|
77
117
|
(s.lastUserMessage ?? '').toLowerCase().includes(query) ||
|
|
78
118
|
s.id.toLowerCase().includes(query) ||
|
|
79
|
-
(s.tags ?? []).some((tag: string) => tag.toLowerCase().includes(query))
|
|
119
|
+
(s.tags ?? []).some((tag: string) => tag.toLowerCase().includes(query)) ||
|
|
120
|
+
adapterCandidates.some((candidate) => candidate.toLowerCase().includes(query))
|
|
80
121
|
)
|
|
81
122
|
})
|
|
82
|
-
|
|
123
|
+
return sortSessionsByOrder(visibleSessions, sortOrder)
|
|
124
|
+
}, [adapterFilters, searchQuery, sessions, sortOrder, tagFilters])
|
|
83
125
|
|
|
84
126
|
async function handleCreateSession() {
|
|
85
127
|
onSelectSession({ id: '' } as Session, true)
|
|
@@ -137,13 +179,9 @@ export function Sidebar({
|
|
|
137
179
|
}
|
|
138
180
|
}
|
|
139
181
|
|
|
140
|
-
async function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
await mutateSessions()
|
|
144
|
-
} catch (err) {
|
|
145
|
-
console.error('Failed to update tags:', err)
|
|
146
|
-
}
|
|
182
|
+
async function handleRenameSession(id: string, title: string) {
|
|
183
|
+
await updateSessionTitle(id, title)
|
|
184
|
+
await mutateSessions()
|
|
147
185
|
}
|
|
148
186
|
|
|
149
187
|
const handleToggleSelect = (id: string) => {
|
|
@@ -189,6 +227,32 @@ export function Sidebar({
|
|
|
189
227
|
}
|
|
190
228
|
}
|
|
191
229
|
|
|
230
|
+
const handleBatchDelete = async () => {
|
|
231
|
+
try {
|
|
232
|
+
await Promise.all(Array.from(selectedIds).map(async (id: string) => deleteSession(id)))
|
|
233
|
+
await mutateSessions()
|
|
234
|
+
|
|
235
|
+
if (activeId && selectedIds.has(activeId)) {
|
|
236
|
+
const nextSession = sessions.find(s => !selectedIds.has(s.id))
|
|
237
|
+
onDeletedSession?.(activeId, nextSession?.id)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
setSelectedIds(new Set<string>())
|
|
241
|
+
setIsBatchMode(false)
|
|
242
|
+
} catch (err) {
|
|
243
|
+
console.error('Failed to batch delete sessions:', err)
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const handleBatchStar = async (isStarred: boolean) => {
|
|
248
|
+
try {
|
|
249
|
+
await Promise.all(Array.from(selectedIds).map(async (id: string) => updateSession(id, { isStarred })))
|
|
250
|
+
await mutateSessions()
|
|
251
|
+
} catch (err) {
|
|
252
|
+
console.error('Failed to batch update star status:', err)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
192
256
|
const toggleBatchMode = () => {
|
|
193
257
|
setIsBatchMode((prev: boolean) => !prev)
|
|
194
258
|
setSelectedIds(new Set<string>())
|
|
@@ -233,46 +297,43 @@ export function Sidebar({
|
|
|
233
297
|
}}
|
|
234
298
|
>
|
|
235
299
|
<SidebarHeader
|
|
300
|
+
adapterFilters={adapterFilters}
|
|
301
|
+
availableAdapters={availableAdapters}
|
|
302
|
+
hasActiveSearchControls={hasActiveSearchControls}
|
|
303
|
+
isSidebarCollapsed={isSidebarCollapsed}
|
|
236
304
|
searchQuery={searchQuery}
|
|
305
|
+
sortOrder={sortOrder}
|
|
306
|
+
sortSelection={sortSelection}
|
|
237
307
|
onSearchChange={setSearchQuery}
|
|
308
|
+
availableTags={availableTags}
|
|
309
|
+
tagFilters={tagFilters}
|
|
310
|
+
onSortOrderChange={setSortOrder}
|
|
311
|
+
onAdapterFilterChange={setAdapterFilters}
|
|
312
|
+
onTagFilterChange={setTagFilters}
|
|
238
313
|
isBatchMode={isBatchMode}
|
|
239
314
|
onToggleBatchMode={toggleBatchMode}
|
|
315
|
+
onToggleSidebarCollapsed={() => setSidebarCollapsed(!isSidebarCollapsed)}
|
|
240
316
|
selectedCount={selectedIds.size}
|
|
241
317
|
totalCount={filteredSessions.length}
|
|
242
318
|
onSelectAll={handleSelectAll}
|
|
243
319
|
onBatchArchive={() => {
|
|
244
320
|
void handleBatchArchive()
|
|
245
321
|
}}
|
|
322
|
+
onBatchDelete={() => {
|
|
323
|
+
void handleBatchDelete()
|
|
324
|
+
}}
|
|
325
|
+
onBatchStar={() => {
|
|
326
|
+
void handleBatchStar(true)
|
|
327
|
+
}}
|
|
246
328
|
isCreatingSession={isCreatingSession}
|
|
329
|
+
shortcutLabel={shortcutLabel}
|
|
330
|
+
createButtonRef={createBtnRef}
|
|
247
331
|
onCreateSession={() => {
|
|
248
332
|
void handleCreateSession()
|
|
249
333
|
}}
|
|
250
334
|
/>
|
|
251
|
-
<div className='sidebar-new-chat'>
|
|
252
|
-
<Tooltip title={isCreatingSession ? t('common.alreadyInNewChat') : undefined} placement='right'>
|
|
253
|
-
<Button
|
|
254
|
-
ref={createBtnRef}
|
|
255
|
-
className={`new-chat-btn ${isCreatingSession ? 'active' : ''}`}
|
|
256
|
-
type={isCreatingSession ? 'default' : 'primary'}
|
|
257
|
-
block
|
|
258
|
-
disabled={!!isCreatingSession}
|
|
259
|
-
onClick={() => {
|
|
260
|
-
void handleCreateSession()
|
|
261
|
-
}}
|
|
262
|
-
>
|
|
263
|
-
<span className='btn-content'>
|
|
264
|
-
<span className={`material-symbols-rounded ${isCreatingSession ? 'filled' : ''}`}>
|
|
265
|
-
{isCreatingSession ? 'chat_bubble' : 'send'}
|
|
266
|
-
</span>
|
|
267
|
-
<span>{isCreatingSession ? t('common.creatingChat') : t('common.newChat')}</span>
|
|
268
|
-
</span>
|
|
269
|
-
<span className='shortcut-tag'>
|
|
270
|
-
{shortcutLabel}
|
|
271
|
-
</span>
|
|
272
|
-
</Button>
|
|
273
|
-
</Tooltip>
|
|
274
|
-
</div>
|
|
275
335
|
<SessionList
|
|
336
|
+
hasActiveFilters={hasActiveFilterConditions}
|
|
276
337
|
sessions={filteredSessions}
|
|
277
338
|
activeId={activeId}
|
|
278
339
|
isBatchMode={isBatchMode}
|
|
@@ -281,11 +342,39 @@ export function Sidebar({
|
|
|
281
342
|
onSelectSession={onSelectSession}
|
|
282
343
|
onArchiveSession={handleArchiveSession}
|
|
283
344
|
onDeleteSession={handleDeleteSession}
|
|
345
|
+
onRenameSession={handleRenameSession}
|
|
284
346
|
onStarSession={handleStarSession}
|
|
285
|
-
onUpdateTags={handleUpdateTags}
|
|
286
347
|
onToggleSelect={handleToggleSelect}
|
|
287
348
|
/>
|
|
288
349
|
</div>
|
|
350
|
+
{isSidebarCollapsed && (
|
|
351
|
+
<div className='sidebar-collapsed-header'>
|
|
352
|
+
<Tooltip title={isCreatingSession ? t('common.alreadyInNewChat') : t('common.newChat')} placement='bottom'>
|
|
353
|
+
<Button
|
|
354
|
+
ref={createBtnRef}
|
|
355
|
+
className={`sidebar-collapsed-control ${isCreatingSession ? 'active' : ''}`}
|
|
356
|
+
type='text'
|
|
357
|
+
disabled={!!isCreatingSession}
|
|
358
|
+
onClick={() => {
|
|
359
|
+
void handleCreateSession()
|
|
360
|
+
}}
|
|
361
|
+
>
|
|
362
|
+
<span className={`material-symbols-rounded ${isCreatingSession ? 'filled' : ''}`}>
|
|
363
|
+
{isCreatingSession ? 'chat_bubble' : 'send'}
|
|
364
|
+
</span>
|
|
365
|
+
</Button>
|
|
366
|
+
</Tooltip>
|
|
367
|
+
<Tooltip title={t('common.expand')} placement='bottom'>
|
|
368
|
+
<Button
|
|
369
|
+
className='sidebar-collapsed-control'
|
|
370
|
+
type='text'
|
|
371
|
+
onClick={() => setSidebarCollapsed(false)}
|
|
372
|
+
>
|
|
373
|
+
<span className='material-symbols-rounded'>dock_to_right</span>
|
|
374
|
+
</Button>
|
|
375
|
+
</Tooltip>
|
|
376
|
+
</div>
|
|
377
|
+
)}
|
|
289
378
|
</div>
|
|
290
379
|
)
|
|
291
380
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Chat 组件维护说明
|
|
2
|
+
|
|
3
|
+
本目录承载聊天页内部视图。涉及消息级交互时,优先从这里读起,而不是只看顶层 route。
|
|
4
|
+
|
|
5
|
+
## 关键文件职责
|
|
6
|
+
|
|
7
|
+
- `ChatHistoryView.tsx`
|
|
8
|
+
- 会话消息列表的父层编排。
|
|
9
|
+
- 管理 `editingMessageId`。
|
|
10
|
+
- 负责“已有一条消息正在编辑”的冲突提示。
|
|
11
|
+
- 负责编辑期间隐藏底部主 sender。
|
|
12
|
+
- `messages/MessageItem.tsx`
|
|
13
|
+
- 单条消息渲染。
|
|
14
|
+
- 消息 footer 操作按钮。
|
|
15
|
+
- inline edit 的消息内挂载点。
|
|
16
|
+
- 原始文本复制逻辑。
|
|
17
|
+
- `messages/MessageFooter.tsx`
|
|
18
|
+
- 消息 footer 的统一承载层。
|
|
19
|
+
- 改 footer 文案或按钮时,优先改这里,不要散落到 `MessageItem`。
|
|
20
|
+
- `sender/Sender.tsx`
|
|
21
|
+
- 默认 sender 和 inline edit 共用的最外层装配入口。
|
|
22
|
+
- 只保留 sender 壳层、局部视图拼装和少量同目录引用,不再承载大段状态编排。
|
|
23
|
+
- `sender/Sender.scss`
|
|
24
|
+
- sender 和 inline edit 的共同样式来源。
|
|
25
|
+
- `sender/@components/`
|
|
26
|
+
- sender 私有的通用视图组件与子模块目录,例如 `sender-toolbar/`、`model-select/`。
|
|
27
|
+
- `sender/@core/`
|
|
28
|
+
- sender 私有的编排与纯逻辑,例如 toolbar bindings、content 组装、interaction 判断。
|
|
29
|
+
- `sender/@hooks/`
|
|
30
|
+
- sender 私有的状态编排、快捷键、focus restore、overlay 控制、提交逻辑等 hooks。
|
|
31
|
+
- `sender/@types/`
|
|
32
|
+
- sender 私有类型定义。
|
|
33
|
+
- `sender/@utils/`
|
|
34
|
+
- sender 私有常量与轻量工具函数。
|
|
35
|
+
- `ThinkingStatus.tsx`
|
|
36
|
+
- 聊天域可复用的状态提示组件,不再算 sender 私有视图。
|
|
37
|
+
- `../../dock-panel/DockPanel.tsx`
|
|
38
|
+
- 聊天页底部可复用 dock 面板壳层。
|
|
39
|
+
- 统一承载标题、meta、关闭动作和拖拽调高能力。
|
|
40
|
+
- terminal 以及后续其他底部面板优先复用这里,不要再各自复制一套 resize/header 逻辑。
|
|
41
|
+
- `../../components/workspace/ContextFilePicker.tsx`
|
|
42
|
+
- 工作区文件选择器;如果别的输入入口也要复用目录树选择,直接走这里。
|
|
43
|
+
|
|
44
|
+
## 消息级操作的当前约束
|
|
45
|
+
|
|
46
|
+
- assistant 消息不允许 fork;前端不显示按钮,后端也会拒绝。
|
|
47
|
+
- inline edit 必须复用 `Sender`,不要另造一套 textarea/composer。
|
|
48
|
+
- 编辑期间底部主 sender 必须隐藏,避免出现双输入源。
|
|
49
|
+
- 同一时间只允许一条消息进入编辑态;冲突时保留当前编辑器并提示用户。
|
|
50
|
+
- `复制原文` 复制的是原始 markdown/text,不是渲染后的可见 DOM 文本。
|
|
51
|
+
- 编辑确认按钮固定使用 `发送`,不要改回实现导向文案。
|
|
52
|
+
- 用户消息的 hover 操作按钮固定挂在消息左侧的独立 action rail,不要再塞回 footer 里挤占阅读流。
|
|
53
|
+
- assistant 消息的可见 footer 操作按钮只保留最后一条;更早的 assistant / tool 消息只能通过右键菜单触发操作。
|
|
54
|
+
- 消息级右键菜单必须同时兼容普通消息和工具调用块;`复制消息链接` 走 `#message-*` hash 锚点,落点要能直接滚动到对应消息位置,而不只是会话页。
|
|
55
|
+
- 消息级操作要始终基于原始 message id,而不是渲染拆分后的临时 id;`text/tool-group` 拆分只影响展示,不应影响 `edit / recall / fork / copy id / copy link`。
|
|
56
|
+
|
|
57
|
+
## Sender 结构约束
|
|
58
|
+
|
|
59
|
+
- sender 只是当前已按“前端模块通用组织规范”落地的一个示例,不是特殊规则来源。
|
|
60
|
+
- 通用规则入口:`../../../../.ai/rules/frontend-standard/module-organization.md`
|
|
61
|
+
- sender 目录不要长期平铺文件;模块根只保留入口和极少量顶层样式。
|
|
62
|
+
- sender 私有实现按 `@components / @core / @hooks / @types / @utils / @store` 分层。
|
|
63
|
+
- sender 的状态型 hooks 放在 `sender/@hooks/`,不要再回塞到 `Sender.tsx` 或平铺在模块根目录。
|
|
64
|
+
- sender 的纯逻辑和装配放在 `sender/@core/`,不要混进视图组件。
|
|
65
|
+
- sender 的类型定义统一放在 `sender/@types/`,不要散在 core 和 component 里。
|
|
66
|
+
- sender 中如果出现可跨页面或跨模块复用的组件,应提升到更公共的 `src/components/...` 目录,不继续留在 `sender/` 私有目录。
|
|
67
|
+
- sender 相关单文件应尽量收敛在 200 行以内;超过后优先拆视图子组件、hooks、utils、样式文件,而不是继续在原文件加条件分支。
|
|
68
|
+
- 子模块如果已经独立成形,例如 `model-select`、`reference-actions`、`sender-toolbar`,应建子目录,并在子目录内继续按职责拆分,而不是把新的辅助文件继续堆回 sender 根目录。
|
|
69
|
+
|
|
70
|
+
## Sender import 约定
|
|
71
|
+
|
|
72
|
+
- `Sender` 及其子组件按固定顺序组织 import:
|
|
73
|
+
1. 本文件样式
|
|
74
|
+
2. 第三方依赖
|
|
75
|
+
3. workspace 包
|
|
76
|
+
4. `#~/` 绝对路径
|
|
77
|
+
5. 当前目录相对路径
|
|
78
|
+
- 每个 group 之间保留一个空行。
|
|
79
|
+
- sender 目录内部,同子模块兄弟文件继续使用相对路径。
|
|
80
|
+
- sender 入口或跨子模块引用模块私有实现时,优先显式指向 `@components / @core / @hooks / @types / @utils / @store`,避免重新打平目录边界。
|
|
81
|
+
|
|
82
|
+
## 改动时容易漏掉的地方
|
|
83
|
+
|
|
84
|
+
### 1. i18n
|
|
85
|
+
|
|
86
|
+
- 新增或调整消息操作文案时,同时更新:
|
|
87
|
+
- `src/resources/locales/zh.json`
|
|
88
|
+
- `src/resources/locales/en.json`
|
|
89
|
+
|
|
90
|
+
### 2. 可编辑内容类型
|
|
91
|
+
|
|
92
|
+
- `Sender` 支持 `ChatMessageContent[]`,但 inline edit 只应该接受 `text / image`。
|
|
93
|
+
- 如果在 `MessageItem` 里直接把 `ChatMessageContent[]` 当成可编辑内容使用,`typecheck` 很容易在 `tool_use / tool_result` 分支上失败。
|
|
94
|
+
|
|
95
|
+
### 3. 真实界面验证
|
|
96
|
+
|
|
97
|
+
- 这块交互非常依赖真实布局、hover 和按钮语义。
|
|
98
|
+
- 只跑单测或后端测试不够;改完必须用真实 Chrome 回归。
|
|
99
|
+
|
|
100
|
+
### 4. 临时脚本脆弱性
|
|
101
|
+
|
|
102
|
+
- 浏览器验证不要强依赖易变按钮文案。
|
|
103
|
+
- 更稳妥的是依赖 `aria-label`、稳定类名或结构断言。
|
|
104
|
+
|
|
105
|
+
## Sender / 浮层调试经验
|
|
106
|
+
|
|
107
|
+
- `ChatHeader` 需要同时保留显式和隐藏两条调试入口:
|
|
108
|
+
- 右上角 `更多` 左边的 debug 状态按钮默认隐藏,只有当前 URL 已经带 `debug` query 时才显示;显示后点击按钮切换 URL 上的 `debug` query。
|
|
109
|
+
- debug 状态切换只在 `debug=true / debug=false` 之间切,不要通过按钮把 `debug` query 直接删掉。
|
|
110
|
+
- 标题支持隐藏调试入口:连续点击标题 5 次时,同样切换 URL 上的 `debug` 状态;不能只留在 console 里。
|
|
111
|
+
- 只要 URL 上存在 `debug` query,就视为 debug 模式:
|
|
112
|
+
- `debug=true` 才算真正开启调试模式;`debug=false` 只保留入口,不展示调试内容。
|
|
113
|
+
- 调试元信息展示在 `settings` 视图,不再展示在标题下面。
|
|
114
|
+
- 消息时间戳只在 `debug=true` 时展示。
|
|
115
|
+
- 后续如果继续精简 header 或 settings,也要保留这条 query 驱动的可见调试通路。
|
|
116
|
+
- `Sender.tsx` 同时组合了 `Tooltip`、`Popover`、`Select` 和自定义 trigger;一旦外层包装组件不透传 `ref` 或 DOM props,触发器很容易直接失效。
|
|
117
|
+
- 包装触发器时不要用无效 DOM 结构,例如 `span` 包 `div`;这类 nesting warning 往往伴随点击异常。
|
|
118
|
+
- 同一个控件如果既有 tooltip 又有 popup,popup 打开时要显式禁用 tooltip;否则 hover 层会抢事件或扰乱 focus。
|
|
119
|
+
- 自定义 select 箭头后,必须分别验证:
|
|
120
|
+
- 文本区能打开
|
|
121
|
+
- 箭头区能打开
|
|
122
|
+
- 关闭后 focus 回输入框
|
|
123
|
+
- sender 的颜色改动要谨慎收窄 selector,避免把下面这些一起误伤:
|
|
124
|
+
- 最高推理强度图标
|
|
125
|
+
- 权限菜单勾选图标
|
|
126
|
+
- 发送按钮
|
|
127
|
+
- disabled / hover / selected 态
|
|
128
|
+
- 通用 tooltip 的字号、min-height 这类全局表面样式,优先改 `src/styles/global.scss` 或主题配置,不要只在 sender 局部覆盖。
|
|
129
|
+
- 调 tooltip / popover / 主题样式后,先 reload 页面,再看 computed style 和 console warning;隐藏浮层节点和旧 bundle warning 很容易导致误判。
|
|
130
|
+
|
|
131
|
+
## Sender 最小回归清单
|
|
132
|
+
|
|
133
|
+
1. `更多` 主菜单能打开,权限二级菜单能展开。
|
|
134
|
+
2. 模型和推理强度的文本区、箭头区都能打开。
|
|
135
|
+
3. popup 打开时不会叠出自己的 tooltip。
|
|
136
|
+
4. popup 关闭后输入框重新获得 focus。
|
|
137
|
+
5. reload 后没有 React DOM nesting warning,也没有 Ant deprecation warning。
|
|
138
|
+
6. 同时检查浅色 / 深色主题下的 tooltip、勾选图标、推理强度图标和发送按钮。
|
|
139
|
+
|
|
140
|
+
## 推荐调试顺序
|
|
141
|
+
|
|
142
|
+
1. 先看 `ChatHistoryView.tsx`,确认父层状态是不是放对了。
|
|
143
|
+
2. 再看 `MessageItem.tsx`,确认消息级入口和 sender 挂载点。
|
|
144
|
+
3. 如涉及输入能力,再看 `Sender.tsx`。
|
|
145
|
+
4. 如涉及消息操作请求,再看 `src/hooks/chat/use-chat-session-actions.ts` 和 `src/api/sessions.ts`。
|
|
146
|
+
5. 最后回到真实 Chrome 做界面验证。
|
|
147
|
+
|
|
148
|
+
## 推荐回归命令
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
pnpm tools message-actions verify
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
如果需要只看最终结果,不看中间子命令输出:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
pnpm tools message-actions verify --quiet
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
进一步的经验和工具说明见:
|
|
161
|
+
|
|
162
|
+
- `../../../../../.ai/rules/maintenance/message-actions.md`
|
|
163
|
+
- `../../../../../.ai/rules/maintenance/tooling.md`
|