@vibe-forge/client 0.11.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.cjs +6 -11
- package/dist/assets/{arc-De_WjPJ3.js → arc-CbOXL0l9.js} +1 -1
- package/dist/assets/{blockDiagram-c4efeb88-C4aR2zTE.js → blockDiagram-c4efeb88-CqxINvsS.js} +1 -1
- package/dist/assets/{c4Diagram-c83219d4-BZH3rq_m.js → c4Diagram-c83219d4-BKazU0hb.js} +1 -1
- package/dist/assets/channel-Dnopc5A6.js +1 -0
- package/dist/assets/{classDiagram-beda092f-BzJgBrIK.js → classDiagram-beda092f-fAFX5BpB.js} +1 -1
- package/dist/assets/{classDiagram-v2-2358418a-5ZtXcnT3.js → classDiagram-v2-2358418a-w1VkNGJj.js} +1 -1
- package/dist/assets/clone-sQthahUA.js +1 -0
- package/dist/assets/{createText-1719965b-DUVvEtmR.js → createText-1719965b-CEinakVP.js} +1 -1
- package/dist/assets/{cssMode-GoTNjuXX.js → cssMode-DPqRki4y.js} +1 -1
- package/dist/assets/{edges-96097737-Dd7m4Cvs.js → edges-96097737-Cb0F1_3K.js} +1 -1
- package/dist/assets/{erDiagram-0228fc6a-DxqFlG_f.js → erDiagram-0228fc6a-C-N2fx-J.js} +1 -1
- package/dist/assets/{flowDb-c6c81e3f-DU0C5kCI.js → flowDb-c6c81e3f-D1Xz_8Gf.js} +1 -1
- package/dist/assets/{flowDiagram-50d868cf-Di1uDa_X.js → flowDiagram-50d868cf-DyPSZyAj.js} +1 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-OazrdWQO.js +1 -0
- package/dist/assets/{flowchart-elk-definition-6af322e1-CwG8aty5.js → flowchart-elk-definition-6af322e1-Dr1DDXwE.js} +1 -1
- package/dist/assets/{freemarker2-j39cqTlI.js → freemarker2-C3DvPFaK.js} +1 -1
- package/dist/assets/{ganttDiagram-a2739b55-baO_lzL-.js → ganttDiagram-a2739b55-DmvY1GRj.js} +1 -1
- package/dist/assets/{gitGraphDiagram-82fe8481-COoHjYMf.js → gitGraphDiagram-82fe8481-CoXfPYYi.js} +1 -1
- package/dist/assets/{graph-KxESr4M5.js → graph-BkDQy7Qt.js} +1 -1
- package/dist/assets/{handlebars-BgjdZO8G.js → handlebars-BcTFdqjl.js} +1 -1
- package/dist/assets/{html-Ba7tYObe.js → html-Dg-O6XFr.js} +1 -1
- package/dist/assets/{htmlMode-Bztvbig1.js → htmlMode-B_wqYWvn.js} +1 -1
- package/dist/assets/{index-5325376f-BMTAx2mL.js → index-5325376f-kxPTR3_e.js} +1 -1
- package/dist/assets/index-o93dlo92.css +32 -0
- package/dist/assets/{index-Pm_kLJvG.js → index-wkhI4dr6.js} +350 -329
- package/dist/assets/{infoDiagram-8eee0895-CC74qbHY.js → infoDiagram-8eee0895-BEvqkwPI.js} +1 -1
- package/dist/assets/{javascript-C1e1cllX.js → javascript-DhlOH8_z.js} +1 -1
- package/dist/assets/{journeyDiagram-c64418c1-C4MyOdE6.js → journeyDiagram-c64418c1-gKtLYmmp.js} +1 -1
- package/dist/assets/{jsonMode-BC98AlvF.js → jsonMode-DxTbF9OD.js} +1 -1
- package/dist/assets/{layout-CxAyTlr7.js → layout-CDaZEk6E.js} +1 -1
- package/dist/assets/{line-DhaUfI71.js → line-DNRQu8iq.js} +1 -1
- package/dist/assets/{linear-MYukzldK.js → linear-Cph9Z6_j.js} +1 -1
- package/dist/assets/{liquid-DahfJEYl.js → liquid-ByZ6JgRG.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-BWDJcswW.js → lspLanguageFeatures-DzvhkgnM.js} +1 -1
- package/dist/assets/{mdx-BELlF_FD.js → mdx-D8RGHTl6.js} +1 -1
- package/dist/assets/{mermaid.core-BrQnSGSY.js → mermaid.core-BgcryF__.js} +4 -4
- package/dist/assets/{mindmap-definition-8da855dc-B0FoxTiy.js → mindmap-definition-8da855dc-WrxK0FcB.js} +1 -1
- package/dist/assets/{pieDiagram-a8764435-Ddr2cjSL.js → pieDiagram-a8764435-VsZBsiQy.js} +1 -1
- package/dist/assets/{python--C9if_AD.js → python-CXVtk_cg.js} +1 -1
- package/dist/assets/{quadrantDiagram-1e28029f-BlEs7Mrl.js → quadrantDiagram-1e28029f-BVlgwOvU.js} +1 -1
- package/dist/assets/{razor-B9U9JxKn.js → razor-0tind7h2.js} +1 -1
- package/dist/assets/{requirementDiagram-08caed73-kEFOAu2v.js → requirementDiagram-08caed73-CpPMPoYp.js} +1 -1
- package/dist/assets/{sankeyDiagram-a04cb91d-BBghez8I.js → sankeyDiagram-a04cb91d-Cm5nnRmc.js} +1 -1
- package/dist/assets/{sequenceDiagram-c5b8d532-CJqgzdUE.js → sequenceDiagram-c5b8d532-DpMlJvJB.js} +1 -1
- package/dist/assets/{stateDiagram-1ecb1508-BER4XEI6.js → stateDiagram-1ecb1508-DU1zc7vq.js} +1 -1
- package/dist/assets/{stateDiagram-v2-c2b004d7-EBV2vSks.js → stateDiagram-v2-c2b004d7-D-0RgmAp.js} +1 -1
- package/dist/assets/{styles-b4e223ce-k0eswZsE.js → styles-b4e223ce-BSO-yNWV.js} +1 -1
- package/dist/assets/{styles-ca3715f6-Ckr7GA-0.js → styles-ca3715f6-CHnsn2Ro.js} +1 -1
- package/dist/assets/{styles-d45a18b0-C1bpSwV3.js → styles-d45a18b0-B-rVGjEq.js} +1 -1
- package/dist/assets/{svgDrawCommon-b86b1483-CDtKpGvy.js → svgDrawCommon-b86b1483-CA3Pl89f.js} +1 -1
- package/dist/assets/{timeline-definition-faaaa080-BeGR-vua.js → timeline-definition-faaaa080-BcihLR6s.js} +1 -1
- package/dist/assets/{tsMode-D_gJXIy3.js → tsMode-D9GGa5Ur.js} +1 -1
- package/dist/assets/{typescript-BoKcNXkN.js → typescript-BT9CK_EL.js} +1 -1
- package/dist/assets/{xml-DZvURlJ-.js → xml-DNO75J-T.js} +1 -1
- package/dist/assets/{xychartDiagram-f5964ef8-DxfeLuYV.js → xychartDiagram-f5964ef8-DJTwe32X.js} +1 -1
- package/dist/assets/{yaml-CTC8PAGY.js → yaml-7CVzhiP2.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +13 -10
- package/src/api/git.ts +12 -0
- package/src/api/sessions.ts +131 -4
- package/src/api/types.ts +2 -1
- package/src/api.ts +13 -0
- package/src/components/ArchiveView.scss +143 -54
- package/src/components/ArchiveView.tsx +181 -167
- package/src/components/CodeBlock.scss +5 -0
- package/src/components/ConfigView.scss +142 -31
- package/src/components/ConfigView.tsx +161 -86
- package/src/components/MarkdownContent.tsx +7 -0
- package/src/components/NavRail.scss +248 -0
- package/src/components/NavRail.tsx +80 -107
- package/src/components/NavRailCompact.tsx +107 -0
- package/src/components/NavRailCompactMoreSheet.tsx +141 -0
- package/src/components/ShortcutTooltip.tsx +4 -2
- package/src/components/Sidebar.scss +51 -0
- package/src/components/Sidebar.tsx +43 -16
- package/src/components/automation-view/RuleFormPanel.scss +40 -13
- package/src/components/automation-view/RuleSidebar.scss +73 -47
- package/src/components/automation-view/RuleSidebar.tsx +9 -13
- package/src/components/automation-view/RunHistoryPanel.scss +141 -13
- package/src/components/automation-view/RunHistoryPanel.tsx +203 -161
- package/src/components/automation-view/TaskList.scss +44 -13
- package/src/components/automation-view/TriggerList.scss +46 -14
- package/src/components/automation-view/index.scss +82 -10
- package/src/components/automation-view/index.tsx +108 -55
- package/src/components/benchmark-view/BenchmarkCasePanel.scss +36 -16
- package/src/components/benchmark-view/BenchmarkSidebar.scss +44 -22
- package/src/components/benchmark-view/BenchmarkSidebar.tsx +0 -6
- package/src/components/benchmark-view/BenchmarkView.scss +63 -20
- package/src/components/benchmark-view/index.tsx +71 -34
- package/src/components/chat/AGENTS.md +14 -2
- package/src/components/chat/ChatComposerCard.scss +77 -0
- package/src/components/chat/ChatComposerCard.tsx +59 -0
- package/src/components/chat/ChatHeader.scss +187 -0
- package/src/components/chat/ChatHeader.tsx +209 -57
- package/src/components/chat/ChatHistoryView.tsx +279 -52
- package/src/components/chat/ChatTimelineView.scss +94 -1
- package/src/components/chat/ChatTimelineView.tsx +42 -0
- package/src/components/chat/CurrentTodoList.scss +210 -200
- package/src/components/chat/CurrentTodoList.tsx +116 -48
- package/src/components/chat/NewSessionGuide.scss +139 -1
- package/src/components/chat/NewSessionGuide.tsx +57 -100
- package/src/components/chat/NewSessionGuideCompactPanel.tsx +130 -0
- package/src/components/chat/NewSessionGuideGrid.tsx +141 -0
- package/src/components/chat/QueuedMessagesCard.scss +195 -0
- package/src/components/chat/QueuedMessagesCard.tsx +170 -0
- package/src/components/chat/git-controls/BranchSwitcherDropdown.tsx +61 -56
- package/src/components/chat/git-controls/BranchSwitcherResults.tsx +167 -0
- package/src/components/chat/git-controls/BranchTreeEntries.tsx +99 -0
- package/src/components/chat/git-controls/ChatGitControls.scss +437 -5
- package/src/components/chat/git-controls/ChatGitControls.tsx +136 -109
- package/src/components/chat/git-controls/DraftGitControls.tsx +91 -0
- package/src/components/chat/git-controls/GitOperationsDropdown.tsx +10 -2
- package/src/components/chat/git-controls/GitWorktreeDropdown.tsx +301 -28
- package/src/components/chat/git-controls/git-branch-tree.ts +148 -0
- package/src/components/chat/git-controls/use-chat-draft-git-controls.ts +168 -0
- package/src/components/chat/git-controls/use-chat-git-controls.ts +76 -3
- package/src/components/chat/messages/MessageContextMenu.tsx +3 -1
- package/src/components/chat/messages/MessageItem.scss +78 -4
- package/src/components/chat/messages/MessageItem.tsx +47 -3
- package/src/components/chat/sender/@components/adapter-select/AdapterSelectControl.scss +23 -0
- package/src/components/chat/sender/@components/reference-actions/ReferenceActionsControl.scss +17 -0
- package/src/components/chat/sender/@components/reference-actions/ReferencePermissionActionsPopover.tsx +4 -1
- package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.scss +167 -30
- package/src/components/chat/sender/@components/sender-attachments/SenderAttachments.tsx +95 -23
- package/src/components/chat/sender/@components/sender-body/SenderBody.tsx +10 -0
- package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.scss +161 -45
- package/src/components/chat/sender/@components/sender-interaction-panel/SenderInteractionPanel.tsx +310 -71
- package/src/components/chat/sender/@components/sender-monaco-editor/SenderMonacoEditor.tsx +18 -0
- package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-editor.ts +86 -9
- package/src/components/chat/sender/@components/sender-monaco-editor/use-sender-monaco-theme.ts +52 -3
- package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.scss +110 -1
- package/src/components/chat/sender/@components/sender-submit-action/SenderSubmitAction.tsx +137 -17
- package/src/components/chat/sender/@components/sender-toolbar/SenderSelectBase.scss +21 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderSelectShared.scss +21 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.scss +63 -0
- package/src/components/chat/sender/@components/sender-toolbar/SenderToolbar.tsx +12 -6
- package/src/components/chat/sender/@core/build-sender-controller-result.ts +6 -0
- package/src/components/chat/sender/@core/build-sender-toolbar.ts +25 -2
- package/src/components/chat/sender/@core/create-sender-toolbar-handlers.ts +9 -2
- package/src/components/chat/sender/@core/get-sender-runtime-state.ts +1 -1
- package/src/components/chat/sender/@core/interaction-request.ts +2 -2
- package/src/components/chat/sender/@core/sender-toolbar-bindings.ts +28 -4
- package/src/components/chat/sender/@hooks/use-model-select-browser.tsx +4 -2
- package/src/components/chat/sender/@hooks/use-sender-controller.ts +56 -11
- package/src/components/chat/sender/@hooks/use-sender-keydown.ts +64 -0
- package/src/components/chat/sender/@hooks/use-sender-shortcuts.ts +16 -1
- package/src/components/chat/sender/@hooks/use-sender-submit.ts +16 -8
- package/src/components/chat/sender/@types/sender-props.ts +20 -3
- package/src/components/chat/sender/@types/sender-toolbar-types.ts +12 -1
- package/src/components/chat/sender/Sender.scss +4 -1
- package/src/components/chat/sender/Sender.tsx +3 -12
- package/src/components/chat/session-timeline-panel/EventList.scss +88 -0
- package/src/components/chat/session-timeline-panel/EventList.tsx +99 -47
- package/src/components/chat/session-timeline-panel/gantt.ts +23 -7
- package/src/components/chat/session-timeline-panel/git-graph.ts +6 -1
- package/src/components/chat/session-timeline-panel/index.scss +14 -1
- package/src/components/chat/session-timeline-panel/index.tsx +86 -10
- package/src/components/chat/session-timeline-panel/types.ts +4 -0
- package/src/components/chat/status-bar/ChatStatusBar.scss +27 -0
- package/src/components/chat/status-bar/ChatStatusBar.tsx +39 -0
- package/src/components/chat/terminal/ChatTerminalView.tsx +6 -0
- package/src/components/chat/tools/core/ToolCallBox.scss +19 -0
- package/src/components/chat/tools/core/ToolGroup.scss +32 -0
- package/src/components/chat/tools/task/components/TaskToolCard.scss +59 -1
- package/src/components/config/ConfigEditors.scss +20 -6
- package/src/components/config/ConfigFieldRow.scss +57 -17
- package/src/components/config/ConfigSectionForm.scss +10 -4
- package/src/components/config/ConfigSectionPanel.tsx +18 -11
- package/src/components/config/configSchema.ts +1 -0
- package/src/components/config/record-editors/RecordEditors.scss +42 -9
- package/src/components/dock-panel/DockPanel.scss +6 -2
- package/src/components/dock-panel/DockPanel.tsx +12 -16
- package/src/components/knowledge-base/KnowledgeBaseView.scss +180 -6
- package/src/components/knowledge-base/KnowledgeBaseView.tsx +98 -26
- package/src/components/knowledge-base/components/ActionButton.scss +4 -0
- package/src/components/knowledge-base/components/EmptyState.scss +5 -8
- package/src/components/knowledge-base/components/EntitiesTab.tsx +8 -2
- package/src/components/knowledge-base/components/EntityItem.scss +10 -3
- package/src/components/knowledge-base/components/FilterBar.scss +13 -2
- package/src/components/knowledge-base/components/FlowsTab.tsx +8 -2
- package/src/components/knowledge-base/components/KnowledgeBaseHeader.scss +2 -23
- package/src/components/knowledge-base/components/KnowledgeBaseHeader.tsx +0 -5
- package/src/components/knowledge-base/components/KnowledgeList.scss +15 -6
- package/src/components/knowledge-base/components/LoadingState.scss +4 -0
- package/src/components/knowledge-base/components/RuleItem.scss +86 -0
- package/src/components/knowledge-base/components/RuleItem.tsx +2 -0
- package/src/components/knowledge-base/components/RulesTab.tsx +8 -2
- package/src/components/knowledge-base/components/SectionHeader.scss +3 -18
- package/src/components/knowledge-base/components/SectionHeader.tsx +3 -7
- package/src/components/knowledge-base/components/SkillsTab.tsx +8 -3
- package/src/components/knowledge-base/components/SpecItem.scss +16 -7
- package/src/components/layout/@hooks/use-mobile-sidebar-modal.ts +190 -0
- package/src/components/layout/AppShell.scss +106 -6
- package/src/components/layout/AppShell.tsx +118 -10
- package/src/components/layout/PageShell.scss +41 -0
- package/src/components/layout/PageShell.tsx +32 -0
- package/src/components/layout/mobile-sidebar-constants.ts +1 -0
- package/src/components/nav-rail-compact-config.ts +114 -0
- package/src/components/nav-rail-items.tsx +181 -0
- package/src/components/sidebar/SessionContextMenu.tsx +3 -1
- package/src/components/sidebar/SessionItem.scss +62 -0
- package/src/components/sidebar/SessionItem.tsx +97 -52
- package/src/components/sidebar/SessionList.tsx +6 -0
- package/src/components/sidebar/SidebarHeader.scss +49 -0
- package/src/components/sidebar/SidebarHeader.tsx +27 -5
- package/src/components/sidebar/SidebarHeaderBatchActions.tsx +8 -4
- package/src/components/sidebar/SidebarHeaderSearchActions.tsx +6 -3
- package/src/components/sidebar/SidebarUtilityFooter.tsx +69 -0
- package/src/components/workspace/ContextFilePicker.tsx +12 -4
- package/src/hooks/chat/chat-session-workspace-draft.ts +25 -0
- package/src/hooks/chat/session-view-cache.ts +4 -1
- package/src/hooks/chat/use-chat-adapter.ts +5 -1
- package/src/hooks/chat/use-chat-model-adapter-selection.tsx +5 -1
- package/src/hooks/chat/use-chat-scroll.ts +24 -7
- package/src/hooks/chat/use-chat-session-actions.ts +118 -6
- package/src/hooks/chat/use-chat-session-messages.ts +20 -1
- package/src/hooks/chat/use-chat-session.ts +2 -0
- package/src/hooks/use-responsive-layout.ts +115 -0
- package/src/main.tsx +8 -0
- package/src/resources/adapters.ts +15 -0
- package/src/resources/locales/en.json +84 -1
- package/src/resources/locales/zh.json +84 -1
- package/src/routes/ChatRoute.scss +152 -9
- package/src/routes/ChatRoute.tsx +31 -34
- package/src/store/index.ts +2 -0
- package/dist/assets/channel-BvERb8WU.js +0 -1
- package/dist/assets/clone-B9_0v-6Y.js +0 -1
- package/dist/assets/flowDiagram-v2-4f6560a1-LpS8Kb00.js +0 -1
- package/dist/assets/index-C1oh0w9H.css +0 -32
- package/src/components/chat/ThinkingStatus.scss +0 -70
- package/src/components/chat/ThinkingStatus.tsx +0 -13
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatMessage } from '@vibe-forge/core'
|
|
1
|
+
import type { ChatMessage, SessionMessageQueueState } from '@vibe-forge/core'
|
|
2
2
|
import type { SessionInfo } from '@vibe-forge/types'
|
|
3
3
|
|
|
4
4
|
import type { ChatErrorState, InteractionRequestState } from './interaction-state'
|
|
@@ -6,6 +6,7 @@ import type { ChatErrorState, InteractionRequestState } from './interaction-stat
|
|
|
6
6
|
export interface ChatSessionViewSnapshot {
|
|
7
7
|
messages: ChatMessage[]
|
|
8
8
|
sessionInfo: SessionInfo | null
|
|
9
|
+
queuedMessages: SessionMessageQueueState
|
|
9
10
|
errorState: ChatErrorState | null
|
|
10
11
|
interactionRequest: InteractionRequestState | null
|
|
11
12
|
isHydrated: boolean
|
|
@@ -18,6 +19,7 @@ export const createChatSessionViewSnapshot = (
|
|
|
18
19
|
): ChatSessionViewSnapshot => ({
|
|
19
20
|
messages: value?.messages ?? [],
|
|
20
21
|
sessionInfo: value?.sessionInfo ?? null,
|
|
22
|
+
queuedMessages: value?.queuedMessages ?? { steer: [], next: [] },
|
|
21
23
|
errorState: value?.errorState ?? null,
|
|
22
24
|
interactionRequest: value?.interactionRequest ?? null,
|
|
23
25
|
isHydrated: value?.isHydrated ?? false
|
|
@@ -42,6 +44,7 @@ export const restoreChatSessionViewSnapshot = (snapshot?: ChatSessionViewSnapsho
|
|
|
42
44
|
return {
|
|
43
45
|
messages: restorable.messages,
|
|
44
46
|
sessionInfo: restorable.sessionInfo,
|
|
47
|
+
queuedMessages: restorable.queuedMessages,
|
|
45
48
|
errorState: restorable.errorState,
|
|
46
49
|
interactionRequest: restorable.interactionRequest,
|
|
47
50
|
isReady: restorable.isHydrated
|
|
@@ -57,7 +57,11 @@ export function useChatAdapter() {
|
|
|
57
57
|
alt: '',
|
|
58
58
|
'aria-hidden': true
|
|
59
59
|
})
|
|
60
|
-
:
|
|
60
|
+
: createElement('span', {
|
|
61
|
+
key: 'fallback-icon',
|
|
62
|
+
className: 'adapter-option__icon adapter-option__icon--fallback material-symbols-rounded',
|
|
63
|
+
'aria-hidden': true
|
|
64
|
+
}, 'deployed_code'),
|
|
61
65
|
createElement('span', { key: 'text', className: 'adapter-option__text' }, display.title)
|
|
62
66
|
])
|
|
63
67
|
}
|
|
@@ -410,7 +410,11 @@ export function useChatModelAdapterSelection({
|
|
|
410
410
|
alt: '',
|
|
411
411
|
'aria-hidden': true
|
|
412
412
|
})
|
|
413
|
-
:
|
|
413
|
+
: createElement('span', {
|
|
414
|
+
key: 'fallback-icon',
|
|
415
|
+
className: 'adapter-option__icon adapter-option__icon--fallback material-symbols-rounded',
|
|
416
|
+
'aria-hidden': true
|
|
417
|
+
}, 'deployed_code'),
|
|
414
418
|
createElement('span', { key: 'text', className: 'adapter-option__text' }, display.title)
|
|
415
419
|
])
|
|
416
420
|
}
|
|
@@ -6,6 +6,7 @@ export function useChatScroll({ contentVersion }: { contentVersion: number }) {
|
|
|
6
6
|
const messagesEndRef = useRef<HTMLDivElement>(null)
|
|
7
7
|
const messagesContainerRef = useRef<HTMLDivElement>(null)
|
|
8
8
|
const messagesContentRef = useRef<HTMLDivElement>(null)
|
|
9
|
+
const scrollTimeoutRef = useRef<number | null>(null)
|
|
9
10
|
const [showScrollBottom, setShowScrollBottom] = useState(false)
|
|
10
11
|
|
|
11
12
|
const updateScrollState = useCallback(() => {
|
|
@@ -15,16 +16,30 @@ export function useChatScroll({ contentVersion }: { contentVersion: number }) {
|
|
|
15
16
|
setShowScrollBottom(distanceToBottom > SCROLL_THRESHOLD)
|
|
16
17
|
}, [])
|
|
17
18
|
|
|
19
|
+
const clearScrollTimeout = useCallback(() => {
|
|
20
|
+
if (scrollTimeoutRef.current == null) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
window.clearTimeout(scrollTimeoutRef.current)
|
|
25
|
+
scrollTimeoutRef.current = null
|
|
26
|
+
}, [])
|
|
27
|
+
|
|
18
28
|
const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth') => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
clearScrollTimeout()
|
|
30
|
+
scrollTimeoutRef.current = window.setTimeout(() => {
|
|
31
|
+
const container = messagesContainerRef.current
|
|
32
|
+
scrollTimeoutRef.current = null
|
|
33
|
+
if (!container) {
|
|
34
|
+
return
|
|
25
35
|
}
|
|
36
|
+
|
|
37
|
+
container.scrollTo({
|
|
38
|
+
top: container.scrollHeight,
|
|
39
|
+
behavior
|
|
40
|
+
})
|
|
26
41
|
}, 50)
|
|
27
|
-
}, [])
|
|
42
|
+
}, [clearScrollTimeout])
|
|
28
43
|
|
|
29
44
|
useEffect(() => {
|
|
30
45
|
const container = messagesContainerRef.current
|
|
@@ -41,6 +56,8 @@ export function useChatScroll({ contentVersion }: { contentVersion: number }) {
|
|
|
41
56
|
updateScrollState()
|
|
42
57
|
}, [contentVersion, updateScrollState])
|
|
43
58
|
|
|
59
|
+
useEffect(() => clearScrollTimeout, [clearScrollTimeout])
|
|
60
|
+
|
|
44
61
|
return {
|
|
45
62
|
messagesEndRef,
|
|
46
63
|
messagesContainerRef,
|
|
@@ -4,9 +4,19 @@ import { useTranslation } from 'react-i18next'
|
|
|
4
4
|
import { useLocation, useNavigate } from 'react-router-dom'
|
|
5
5
|
import { useSWRConfig } from 'swr'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
branchSessionFromMessage,
|
|
9
|
+
createQueuedMessage,
|
|
10
|
+
createSession,
|
|
11
|
+
deleteQueuedMessage,
|
|
12
|
+
getApiErrorMessage,
|
|
13
|
+
moveQueuedMessage,
|
|
14
|
+
reorderQueuedMessages,
|
|
15
|
+
updateQueuedMessage
|
|
16
|
+
} from '#~/api.js'
|
|
8
17
|
import { connectionManager } from '#~/connectionManager.js'
|
|
9
|
-
import type { ChatMessageContent, Session } from '@vibe-forge/core'
|
|
18
|
+
import type { ChatMessageContent, Session, SessionQueuedMessageMode } from '@vibe-forge/core'
|
|
19
|
+
import type { ChatSessionWorkspaceDraft } from './chat-session-workspace-draft'
|
|
10
20
|
import type { ChatEffort } from './use-chat-effort'
|
|
11
21
|
import type { PermissionMode } from './use-chat-permission-mode'
|
|
12
22
|
|
|
@@ -17,6 +27,7 @@ export function useChatSessionActions({
|
|
|
17
27
|
effort,
|
|
18
28
|
permissionMode,
|
|
19
29
|
adapter,
|
|
30
|
+
workspaceDraft,
|
|
20
31
|
onClearMessages
|
|
21
32
|
}: {
|
|
22
33
|
session?: Session
|
|
@@ -25,6 +36,7 @@ export function useChatSessionActions({
|
|
|
25
36
|
effort: ChatEffort
|
|
26
37
|
permissionMode: PermissionMode
|
|
27
38
|
adapter?: string
|
|
39
|
+
workspaceDraft?: ChatSessionWorkspaceDraft
|
|
28
40
|
onClearMessages: () => void
|
|
29
41
|
}) {
|
|
30
42
|
const { message } = App.useApp()
|
|
@@ -61,7 +73,7 @@ export function useChatSessionActions({
|
|
|
61
73
|
setIsCreating(false)
|
|
62
74
|
}, [isCreating, session?.id])
|
|
63
75
|
|
|
64
|
-
const send = useCallback(async (text: string) => {
|
|
76
|
+
const send = useCallback(async (text: string, _mode?: SessionQueuedMessageMode) => {
|
|
65
77
|
if (text.trim() === '' || isThinking) return false
|
|
66
78
|
if (!hasAvailableModels) {
|
|
67
79
|
void message.warning(t('chat.modelConfigRequired'))
|
|
@@ -74,7 +86,13 @@ export function useChatSessionActions({
|
|
|
74
86
|
const { session: newSession } = await createSession(undefined, text.trim(), undefined, modelForQuery, {
|
|
75
87
|
effort: effort === 'default' ? undefined : effort,
|
|
76
88
|
permissionMode,
|
|
77
|
-
adapter
|
|
89
|
+
adapter,
|
|
90
|
+
workspace: workspaceDraft == null
|
|
91
|
+
? undefined
|
|
92
|
+
: {
|
|
93
|
+
createWorktree: workspaceDraft.createWorktree,
|
|
94
|
+
branch: workspaceDraft.branch
|
|
95
|
+
}
|
|
78
96
|
})
|
|
79
97
|
|
|
80
98
|
await insertSessionIntoCache(newSession)
|
|
@@ -103,12 +121,13 @@ export function useChatSessionActions({
|
|
|
103
121
|
navigateWithCurrentSearch,
|
|
104
122
|
effort,
|
|
105
123
|
permissionMode,
|
|
124
|
+
workspaceDraft,
|
|
106
125
|
modelForQuery,
|
|
107
126
|
session?.id,
|
|
108
127
|
t
|
|
109
128
|
])
|
|
110
129
|
|
|
111
|
-
const sendContent = useCallback(async (content: ChatMessageContent[]) => {
|
|
130
|
+
const sendContent = useCallback(async (content: ChatMessageContent[], _mode?: SessionQueuedMessageMode) => {
|
|
112
131
|
if (content.length === 0 || isThinking) return false
|
|
113
132
|
if (!hasAvailableModels) {
|
|
114
133
|
void message.warning(t('chat.modelConfigRequired'))
|
|
@@ -121,7 +140,13 @@ export function useChatSessionActions({
|
|
|
121
140
|
const { session: newSession } = await createSession(undefined, undefined, content, modelForQuery, {
|
|
122
141
|
effort: effort === 'default' ? undefined : effort,
|
|
123
142
|
permissionMode,
|
|
124
|
-
adapter
|
|
143
|
+
adapter,
|
|
144
|
+
workspace: workspaceDraft == null
|
|
145
|
+
? undefined
|
|
146
|
+
: {
|
|
147
|
+
createWorktree: workspaceDraft.createWorktree,
|
|
148
|
+
branch: workspaceDraft.branch
|
|
149
|
+
}
|
|
125
150
|
})
|
|
126
151
|
|
|
127
152
|
await insertSessionIntoCache(newSession)
|
|
@@ -150,6 +175,7 @@ export function useChatSessionActions({
|
|
|
150
175
|
message,
|
|
151
176
|
effort,
|
|
152
177
|
permissionMode,
|
|
178
|
+
workspaceDraft,
|
|
153
179
|
modelForQuery,
|
|
154
180
|
session?.id,
|
|
155
181
|
t
|
|
@@ -200,11 +226,97 @@ export function useChatSessionActions({
|
|
|
200
226
|
return runMessageAction(messageId, 'edit', { content })
|
|
201
227
|
}, [runMessageAction])
|
|
202
228
|
|
|
229
|
+
const enqueueContent = useCallback(async (mode: SessionQueuedMessageMode, content: ChatMessageContent[]) => {
|
|
230
|
+
if (session?.id == null || session.id === '') {
|
|
231
|
+
return false
|
|
232
|
+
}
|
|
233
|
+
if (content.length === 0) {
|
|
234
|
+
return false
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
await createQueuedMessage(session.id, mode, content)
|
|
239
|
+
return true
|
|
240
|
+
} catch (err) {
|
|
241
|
+
console.error(err)
|
|
242
|
+
void message.error(getApiErrorMessage(err, t('common.operationFailed')))
|
|
243
|
+
return false
|
|
244
|
+
}
|
|
245
|
+
}, [message, session?.id, t])
|
|
246
|
+
|
|
247
|
+
const updateQueuedContent = useCallback(async (queueId: string, content: ChatMessageContent[]) => {
|
|
248
|
+
if (session?.id == null || session.id === '') {
|
|
249
|
+
return false
|
|
250
|
+
}
|
|
251
|
+
if (content.length === 0) {
|
|
252
|
+
return false
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
try {
|
|
256
|
+
await updateQueuedMessage(session.id, queueId, content)
|
|
257
|
+
return true
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error(err)
|
|
260
|
+
void message.error(getApiErrorMessage(err, t('common.operationFailed')))
|
|
261
|
+
return false
|
|
262
|
+
}
|
|
263
|
+
}, [message, session?.id, t])
|
|
264
|
+
|
|
265
|
+
const removeQueuedContent = useCallback(async (queueId: string) => {
|
|
266
|
+
if (session?.id == null || session.id === '') {
|
|
267
|
+
return false
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
await deleteQueuedMessage(session.id, queueId)
|
|
272
|
+
return true
|
|
273
|
+
} catch (err) {
|
|
274
|
+
console.error(err)
|
|
275
|
+
void message.error(getApiErrorMessage(err, t('common.operationFailed')))
|
|
276
|
+
return false
|
|
277
|
+
}
|
|
278
|
+
}, [message, session?.id, t])
|
|
279
|
+
|
|
280
|
+
const moveQueuedContent = useCallback(async (queueId: string, mode: SessionQueuedMessageMode) => {
|
|
281
|
+
if (session?.id == null || session.id === '') {
|
|
282
|
+
return false
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
await moveQueuedMessage(session.id, queueId, mode)
|
|
287
|
+
return true
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error(err)
|
|
290
|
+
void message.error(getApiErrorMessage(err, t('common.operationFailed')))
|
|
291
|
+
return false
|
|
292
|
+
}
|
|
293
|
+
}, [message, session?.id, t])
|
|
294
|
+
|
|
295
|
+
const reorderQueuedContent = useCallback(async (mode: SessionQueuedMessageMode, ids: string[]) => {
|
|
296
|
+
if (session?.id == null || session.id === '') {
|
|
297
|
+
return false
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
await reorderQueuedMessages(session.id, mode, ids)
|
|
302
|
+
return true
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.error(err)
|
|
305
|
+
void message.error(getApiErrorMessage(err, t('common.operationFailed')))
|
|
306
|
+
return false
|
|
307
|
+
}
|
|
308
|
+
}, [message, session?.id, t])
|
|
309
|
+
|
|
203
310
|
return {
|
|
204
311
|
isCreating,
|
|
205
312
|
isThinking,
|
|
206
313
|
send,
|
|
207
314
|
sendContent,
|
|
315
|
+
enqueueContent,
|
|
316
|
+
updateQueuedContent,
|
|
317
|
+
removeQueuedContent,
|
|
318
|
+
moveQueuedContent,
|
|
319
|
+
reorderQueuedContent,
|
|
208
320
|
editMessage,
|
|
209
321
|
forkMessage,
|
|
210
322
|
interrupt,
|
|
@@ -3,7 +3,7 @@ import type { SetStateAction } from 'react'
|
|
|
3
3
|
import { useTranslation } from 'react-i18next'
|
|
4
4
|
import { useSWRConfig } from 'swr'
|
|
5
5
|
|
|
6
|
-
import type { AskUserQuestionParams, ChatMessage, Session, WSEvent } from '@vibe-forge/core'
|
|
6
|
+
import type { AskUserQuestionParams, ChatMessage, Session, SessionMessageQueueState, WSEvent } from '@vibe-forge/core'
|
|
7
7
|
import type { SessionInfo } from '@vibe-forge/types'
|
|
8
8
|
|
|
9
9
|
import { getSessionMessages } from '#~/api.js'
|
|
@@ -25,6 +25,8 @@ import type { ChatSessionViewSnapshot } from './session-view-cache'
|
|
|
25
25
|
import type { ChatEffort } from './use-chat-effort'
|
|
26
26
|
import type { PermissionMode } from './use-chat-permission-mode'
|
|
27
27
|
|
|
28
|
+
const EMPTY_QUEUED_MESSAGES: SessionMessageQueueState = { steer: [], next: [] }
|
|
29
|
+
|
|
28
30
|
const applyMessageEvent = (currentMessages: ChatMessage[], data: WSEvent) => {
|
|
29
31
|
if (data.type !== 'message') return currentMessages
|
|
30
32
|
const exists = currentMessages.find((msg) => msg.id === data.message.id)
|
|
@@ -71,6 +73,7 @@ export function useChatSessionMessages({
|
|
|
71
73
|
const { mutate } = useSWRConfig()
|
|
72
74
|
const [messagesState, setMessagesState] = useState<ChatMessage[]>([])
|
|
73
75
|
const [sessionInfo, setSessionInfo] = useState<SessionInfo | null>(null)
|
|
76
|
+
const [queuedMessages, setQueuedMessages] = useState<SessionMessageQueueState>({ steer: [], next: [] })
|
|
74
77
|
const [isReady, setIsReady] = useState(false)
|
|
75
78
|
const [errorState, setErrorState] = useState<ChatErrorState | null>(null)
|
|
76
79
|
const [retryCount, setRetryCount] = useState(0)
|
|
@@ -94,6 +97,7 @@ export function useChatSessionMessages({
|
|
|
94
97
|
patch: Partial<{
|
|
95
98
|
messages: ChatMessage[]
|
|
96
99
|
sessionInfo: SessionInfo | null
|
|
100
|
+
queuedMessages: SessionMessageQueueState
|
|
97
101
|
errorState: ChatErrorState | null
|
|
98
102
|
interactionRequest: InteractionRequestState | null
|
|
99
103
|
isHydrated: boolean
|
|
@@ -174,9 +178,11 @@ export function useChatSessionMessages({
|
|
|
174
178
|
code: latestFatalError.code
|
|
175
179
|
}
|
|
176
180
|
: null
|
|
181
|
+
const nextQueuedMessages = res.queuedMessages ?? EMPTY_QUEUED_MESSAGES
|
|
177
182
|
|
|
178
183
|
interactionRequestRef.current = restoredInteraction
|
|
179
184
|
setInteractionRequest(restoredInteraction)
|
|
185
|
+
setQueuedMessages(nextQueuedMessages)
|
|
180
186
|
setErrorState(nextErrorState)
|
|
181
187
|
|
|
182
188
|
for (const data of events) {
|
|
@@ -192,6 +198,7 @@ export function useChatSessionMessages({
|
|
|
192
198
|
updateSessionViewCache(sessionId, {
|
|
193
199
|
messages: currentMessages,
|
|
194
200
|
sessionInfo: currentSessionInfo,
|
|
201
|
+
queuedMessages: nextQueuedMessages,
|
|
195
202
|
errorState: nextErrorState,
|
|
196
203
|
interactionRequest: restoredInteraction,
|
|
197
204
|
isHydrated: true
|
|
@@ -238,6 +245,7 @@ export function useChatSessionMessages({
|
|
|
238
245
|
if (session?.id == null || session.id === '') {
|
|
239
246
|
setMessagesState([])
|
|
240
247
|
setSessionInfo(null)
|
|
248
|
+
setQueuedMessages(EMPTY_QUEUED_MESSAGES)
|
|
241
249
|
setIsReady(true)
|
|
242
250
|
setErrorState(null)
|
|
243
251
|
setInteractionRequest(null)
|
|
@@ -255,12 +263,14 @@ export function useChatSessionMessages({
|
|
|
255
263
|
|
|
256
264
|
setMessagesState(restoredState.messages)
|
|
257
265
|
setSessionInfo(restoredState.sessionInfo)
|
|
266
|
+
setQueuedMessages(restoredState.queuedMessages)
|
|
258
267
|
setErrorState(restoredState.errorState)
|
|
259
268
|
setInteractionRequest(restoredState.interactionRequest)
|
|
260
269
|
interactionRequestRef.current = restoredState.interactionRequest
|
|
261
270
|
setIsReady(restoredState.isReady)
|
|
262
271
|
isInitialLoadRef.current = !restoredState.isReady
|
|
263
272
|
|
|
273
|
+
void refreshHistory()
|
|
264
274
|
void refreshHistory()
|
|
265
275
|
|
|
266
276
|
return () => {
|
|
@@ -414,6 +424,14 @@ export function useChatSessionMessages({
|
|
|
414
424
|
return
|
|
415
425
|
}
|
|
416
426
|
|
|
427
|
+
if (data.type === 'session_queue_updated') {
|
|
428
|
+
setQueuedMessages(data.queue)
|
|
429
|
+
updateSessionViewCache(session.id, {
|
|
430
|
+
queuedMessages: data.queue
|
|
431
|
+
})
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
|
|
417
435
|
if (data.type === 'message') {
|
|
418
436
|
setMessages((current) => applyMessageEvent(current, data))
|
|
419
437
|
return
|
|
@@ -513,6 +531,7 @@ export function useChatSessionMessages({
|
|
|
513
531
|
messages: messagesState,
|
|
514
532
|
setMessages,
|
|
515
533
|
sessionInfo,
|
|
534
|
+
queuedMessages,
|
|
516
535
|
isReady,
|
|
517
536
|
errorState,
|
|
518
537
|
retryConnection,
|
|
@@ -44,6 +44,7 @@ export function useChatSession({
|
|
|
44
44
|
messages,
|
|
45
45
|
setMessages,
|
|
46
46
|
sessionInfo,
|
|
47
|
+
queuedMessages,
|
|
47
48
|
isReady,
|
|
48
49
|
errorState,
|
|
49
50
|
retryConnection,
|
|
@@ -110,6 +111,7 @@ export function useChatSession({
|
|
|
110
111
|
return {
|
|
111
112
|
messages,
|
|
112
113
|
sessionInfo,
|
|
114
|
+
queuedMessages,
|
|
113
115
|
interactionRequest,
|
|
114
116
|
isReady,
|
|
115
117
|
errorState,
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react'
|
|
2
|
+
|
|
3
|
+
const COMPACT_LAYOUT_QUERY = '(max-width: 960px)'
|
|
4
|
+
const TOUCH_INTERACTION_QUERY = '(hover: none), (pointer: coarse)'
|
|
5
|
+
|
|
6
|
+
export interface ResponsiveLayoutState {
|
|
7
|
+
isCompactLayout: boolean
|
|
8
|
+
isTouchInteraction: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const DEFAULT_RESPONSIVE_LAYOUT: ResponsiveLayoutState = {
|
|
12
|
+
isCompactLayout: false,
|
|
13
|
+
isTouchInteraction: false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const listeners = new Set<() => void>()
|
|
17
|
+
|
|
18
|
+
let compactMediaQuery: MediaQueryList | null = null
|
|
19
|
+
let touchMediaQuery: MediaQueryList | null = null
|
|
20
|
+
let currentSnapshot = DEFAULT_RESPONSIVE_LAYOUT
|
|
21
|
+
let mediaListenersInstalled = false
|
|
22
|
+
let removeMediaQueryListeners: (() => void) | null = null
|
|
23
|
+
|
|
24
|
+
const getMediaQueryMatch = (query: string) => {
|
|
25
|
+
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return window.matchMedia(query).matches
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const readResponsiveLayoutSnapshot = (): ResponsiveLayoutState => ({
|
|
33
|
+
isCompactLayout: compactMediaQuery?.matches ?? getMediaQueryMatch(COMPACT_LAYOUT_QUERY),
|
|
34
|
+
isTouchInteraction: touchMediaQuery?.matches ?? getMediaQueryMatch(TOUCH_INTERACTION_QUERY)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
const isSameResponsiveLayoutSnapshot = (
|
|
38
|
+
left: ResponsiveLayoutState,
|
|
39
|
+
right: ResponsiveLayoutState
|
|
40
|
+
) => left.isCompactLayout === right.isCompactLayout && left.isTouchInteraction === right.isTouchInteraction
|
|
41
|
+
|
|
42
|
+
const refreshResponsiveLayoutSnapshot = () => {
|
|
43
|
+
const nextSnapshot = readResponsiveLayoutSnapshot()
|
|
44
|
+
if (!isSameResponsiveLayoutSnapshot(currentSnapshot, nextSnapshot)) {
|
|
45
|
+
currentSnapshot = nextSnapshot
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return currentSnapshot
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const emitIfChanged = () => {
|
|
52
|
+
const nextSnapshot = readResponsiveLayoutSnapshot()
|
|
53
|
+
if (isSameResponsiveLayoutSnapshot(currentSnapshot, nextSnapshot)) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
currentSnapshot = nextSnapshot
|
|
58
|
+
listeners.forEach(listener => listener())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const addMediaQueryListener = (mediaQuery: MediaQueryList, listener: () => void) => {
|
|
62
|
+
if (typeof mediaQuery.addEventListener === 'function') {
|
|
63
|
+
mediaQuery.addEventListener('change', listener)
|
|
64
|
+
return () => mediaQuery.removeEventListener('change', listener)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
mediaQuery.addListener(listener)
|
|
68
|
+
return () => mediaQuery.removeListener(listener)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const ensureResponsiveLayoutListeners = () => {
|
|
72
|
+
if (
|
|
73
|
+
mediaListenersInstalled ||
|
|
74
|
+
typeof window === 'undefined' ||
|
|
75
|
+
typeof window.matchMedia !== 'function'
|
|
76
|
+
) {
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
compactMediaQuery = window.matchMedia(COMPACT_LAYOUT_QUERY)
|
|
81
|
+
touchMediaQuery = window.matchMedia(TOUCH_INTERACTION_QUERY)
|
|
82
|
+
currentSnapshot = refreshResponsiveLayoutSnapshot()
|
|
83
|
+
const removeCompactMediaQueryListener = addMediaQueryListener(compactMediaQuery, emitIfChanged)
|
|
84
|
+
const removeTouchMediaQueryListener = addMediaQueryListener(touchMediaQuery, emitIfChanged)
|
|
85
|
+
removeMediaQueryListeners = () => {
|
|
86
|
+
removeCompactMediaQueryListener()
|
|
87
|
+
removeTouchMediaQueryListener()
|
|
88
|
+
compactMediaQuery = null
|
|
89
|
+
touchMediaQuery = null
|
|
90
|
+
mediaListenersInstalled = false
|
|
91
|
+
}
|
|
92
|
+
mediaListenersInstalled = true
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const subscribeResponsiveLayout = (listener: () => void) => {
|
|
96
|
+
ensureResponsiveLayoutListeners()
|
|
97
|
+
listeners.add(listener)
|
|
98
|
+
return () => {
|
|
99
|
+
listeners.delete(listener)
|
|
100
|
+
if (listeners.size === 0) {
|
|
101
|
+
removeMediaQueryListeners?.()
|
|
102
|
+
removeMediaQueryListeners = null
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const getResponsiveLayoutSnapshot = () => refreshResponsiveLayoutSnapshot()
|
|
108
|
+
|
|
109
|
+
export function useResponsiveLayout() {
|
|
110
|
+
return useSyncExternalStore(
|
|
111
|
+
subscribeResponsiveLayout,
|
|
112
|
+
getResponsiveLayoutSnapshot,
|
|
113
|
+
() => DEFAULT_RESPONSIVE_LAYOUT
|
|
114
|
+
)
|
|
115
|
+
}
|
package/src/main.tsx
CHANGED
|
@@ -16,6 +16,14 @@ import { getClientBase, resolveDevDocumentTitle } from '#~/runtime-config.js'
|
|
|
16
16
|
|
|
17
17
|
import App from './App'
|
|
18
18
|
|
|
19
|
+
const gitRefLabel = import.meta.env.__VF_PROJECT_AI_GIT_REF_LABEL__ ?? ''
|
|
20
|
+
|
|
21
|
+
const appTitle = import.meta.env.DEV && gitRefLabel !== ''
|
|
22
|
+
? `Vibe Forge Web [${gitRefLabel}]`
|
|
23
|
+
: 'Vibe Forge Web'
|
|
24
|
+
|
|
25
|
+
document.title = appTitle
|
|
26
|
+
|
|
19
27
|
const root = createRoot(document.getElementById('root')!)
|
|
20
28
|
|
|
21
29
|
const clientBase = getClientBase()
|
|
@@ -3,6 +3,9 @@ import {
|
|
|
3
3
|
adapterIcon as claudeCodeIcon
|
|
4
4
|
} from '@vibe-forge/adapter-claude-code/icon'
|
|
5
5
|
import { adapterDisplayName as codexDisplayName, adapterIcon as codexIcon } from '@vibe-forge/adapter-codex/icon'
|
|
6
|
+
import { adapterDisplayName as copilotDisplayName, adapterIcon as copilotIcon } from '@vibe-forge/adapter-copilot/icon'
|
|
7
|
+
import { adapterDisplayName as geminiDisplayName, adapterIcon as geminiIcon } from '@vibe-forge/adapter-gemini/icon'
|
|
8
|
+
import { adapterDisplayName as kimiDisplayName, adapterIcon as kimiIcon } from '@vibe-forge/adapter-kimi/icon'
|
|
6
9
|
import {
|
|
7
10
|
adapterDisplayName as opencodeDisplayName,
|
|
8
11
|
adapterIcon as opencodeIcon
|
|
@@ -17,6 +20,18 @@ export const adapterDisplayMap = {
|
|
|
17
20
|
title: codexDisplayName,
|
|
18
21
|
icon: codexIcon
|
|
19
22
|
},
|
|
23
|
+
copilot: {
|
|
24
|
+
title: copilotDisplayName,
|
|
25
|
+
icon: copilotIcon
|
|
26
|
+
},
|
|
27
|
+
gemini: {
|
|
28
|
+
title: geminiDisplayName,
|
|
29
|
+
icon: geminiIcon
|
|
30
|
+
},
|
|
31
|
+
kimi: {
|
|
32
|
+
title: kimiDisplayName,
|
|
33
|
+
icon: kimiIcon
|
|
34
|
+
},
|
|
20
35
|
opencode: {
|
|
21
36
|
title: opencodeDisplayName,
|
|
22
37
|
icon: opencodeIcon
|