From 48a11ff077da32ba1bb41e619dc7c1796f7ed1b3 Mon Sep 17 00:00:00 2001 From: kurihada Date: Wed, 17 Dec 2025 19:36:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20:new=20=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E5=91=BD=E4=BB=A4=E5=88=9B=E5=BB=BA=E6=96=B0=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Core: 新增 :new/:n 命令返回 new_session action - Server: 处理 new_session action 创建新会话 - UI: useChat 添加 onSessionSwitch 回调 - Web/Desktop: ChatPage 和 App 实现会话切换逻辑 --- .../core/src/system-commands/builtin/index.ts | 4 +++- .../core/src/system-commands/builtin/new.ts | 22 +++++++++++++++++++ packages/desktop/src/pages/Chat.tsx | 4 ++++ packages/server/src/ws.ts | 14 +++++++++++- packages/ui/src/hooks/useChat.ts | 13 +++++++++-- packages/web/src/App.tsx | 6 +++++ packages/web/src/pages/Chat.tsx | 4 ++++ 7 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/system-commands/builtin/new.ts diff --git a/packages/core/src/system-commands/builtin/index.ts b/packages/core/src/system-commands/builtin/index.ts index d0758bb..2152d76 100644 --- a/packages/core/src/system-commands/builtin/index.ts +++ b/packages/core/src/system-commands/builtin/index.ts @@ -4,12 +4,14 @@ import type { SystemCommand } from '../types.js'; import { clearCommand } from './clear.js'; +import { newCommand } from './new.js'; /** * 所有内置系统命令 */ export const builtinSystemCommands: SystemCommand[] = [ clearCommand, + newCommand, ]; -export { clearCommand }; +export { clearCommand, newCommand }; diff --git a/packages/core/src/system-commands/builtin/new.ts b/packages/core/src/system-commands/builtin/new.ts new file mode 100644 index 0000000..f0d372a --- /dev/null +++ b/packages/core/src/system-commands/builtin/new.ts @@ -0,0 +1,22 @@ +/** + * :new 系统命令 + * + * 创建新会话并切换到新会话 + */ + +import type { SystemCommand } from '../types.js'; + +export const newCommand: SystemCommand = { + name: 'new', + description: '创建新会话并切换', + aliases: ['n'], + execute: async (_context) => { + // 实际的创建操作由 Server 层处理 + // 这里只返回操作指令 + return { + success: true, + message: '正在创建新会话...', + action: { type: 'new_session' }, + }; + }, +}; diff --git a/packages/desktop/src/pages/Chat.tsx b/packages/desktop/src/pages/Chat.tsx index 4742048..ae5fe77 100644 --- a/packages/desktop/src/pages/Chat.tsx +++ b/packages/desktop/src/pages/Chat.tsx @@ -16,6 +16,8 @@ import { interface ChatPageProps { sessionId: string; onSessionUpdated?: (sessionId: string, name: string) => void; + /** 切换会话回调(如 :new 命令创建新会话) */ + onSessionSwitch?: (newSessionId: string) => void; // 工具栏按钮 showFileBrowser?: boolean; onToggleFileBrowser?: () => void; @@ -31,6 +33,7 @@ interface ChatPageProps { export function ChatPage({ sessionId, onSessionUpdated, + onSessionSwitch, showFileBrowser, onToggleFileBrowser, onOpenConfig, @@ -55,6 +58,7 @@ export function ChatPage({ console.error('Chat error:', error); }, onSessionUpdated, + onSessionSwitch, onConfigError: (error) => { toast.error(error.message, { duration: 10000, diff --git a/packages/server/src/ws.ts b/packages/server/src/ws.ts index 558c1ee..6b7b5be 100644 --- a/packages/server/src/ws.ts +++ b/packages/server/src/ws.ts @@ -322,7 +322,19 @@ async function handleSystemCommand(sessionId: string, content: string): Promise< sessionManager.updateStatus(sessionId, 'idle'); break; } - // 可以在这里添加其他操作类型的处理 + + case 'new_session': { + // 获取当前会话信息以复用配置 + const currentSession = sessionManager.get(sessionId); + const workdir = currentSession?.workdir || process.cwd(); + + // 创建新会话 + const newSession = await sessionManager.create({ workdir }); + + // 更新 action 中的 sessionId + result.action = { type: 'new_session', sessionId: newSession.id }; + break; + } } } diff --git a/packages/ui/src/hooks/useChat.ts b/packages/ui/src/hooks/useChat.ts index 3680720..dc104f1 100644 --- a/packages/ui/src/hooks/useChat.ts +++ b/packages/ui/src/hooks/useChat.ts @@ -33,6 +33,8 @@ interface UseChatOptions { onSessionUpdated?: (sessionId: string, name: string) => void; /** 配置错误回调(如 API Key 未配置) */ onConfigError?: (error: ConfigErrorPayload) => void; + /** 切换会话回调(如 :new 命令创建新会话) */ + onSessionSwitch?: (newSessionId: string) => void; } interface ChatState { @@ -52,7 +54,7 @@ interface ChatState { currentSubagent: SubagentState | null; } -export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdated, onConfigError }: UseChatOptions) { +export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdated, onConfigError, onSessionSwitch }: UseChatOptions) { const [state, setState] = useState({ messages: [], isConnected: false, @@ -77,10 +79,12 @@ export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdate const onSessionNotFoundRef = useRef(onSessionNotFound); const onSessionUpdatedRef = useRef(onSessionUpdated); const onConfigErrorRef = useRef(onConfigError); + const onSessionSwitchRef = useRef(onSessionSwitch); onErrorRef.current = onError; onSessionNotFoundRef.current = onSessionNotFound; onSessionUpdatedRef.current = onSessionUpdated; onConfigErrorRef.current = onConfigError; + onSessionSwitchRef.current = onSessionSwitch; // 加载历史消息 const loadMessages = useCallback(async () => { @@ -572,7 +576,7 @@ export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdate success: boolean; message?: string; error?: string; - action?: { type: string }; + action?: { type: string; sessionId?: string }; }; // 处理清空消息操作 @@ -585,6 +589,11 @@ export function useChat({ sessionId, onError, onSessionNotFound, onSessionUpdate })); } + // 处理新建会话操作 + if (payload.success && payload.action?.type === 'new_session' && payload.action.sessionId) { + onSessionSwitchRef.current?.(payload.action.sessionId); + } + // 如果有错误,通过 onError 回调通知 if (!payload.success && payload.error) { onErrorRef.current?.(new Error(payload.error)); diff --git a/packages/web/src/App.tsx b/packages/web/src/App.tsx index 9a572a4..a5b09c3 100644 --- a/packages/web/src/App.tsx +++ b/packages/web/src/App.tsx @@ -103,6 +103,11 @@ export function App() { setSessionTitleUpdate({ sessionId, name }); }, []); + // 会话切换回调(:new 命令创建新会话后切换) + const handleSessionSwitch = useCallback((newSessionId: string) => { + setCurrentSessionId(newSessionId); + }, []); + // 处理面板宽度调整 const handleResize = useCallback((delta: number) => { setIdePanelWidth((prev) => { @@ -159,6 +164,7 @@ export function App() { sessionId={currentSessionId} onSessionNotFound={handleSessionNotFound} onSessionUpdated={handleSessionUpdated} + onSessionSwitch={handleSessionSwitch} responsive onOpenCommands={() => setShowCommands(true)} onOpenMCP={() => setShowMCP(true)} diff --git a/packages/web/src/pages/Chat.tsx b/packages/web/src/pages/Chat.tsx index 5231168..06b7fa2 100644 --- a/packages/web/src/pages/Chat.tsx +++ b/packages/web/src/pages/Chat.tsx @@ -22,6 +22,8 @@ interface ChatPageProps { sessionId: string; onSessionNotFound?: () => void; onSessionUpdated?: (sessionId: string, name: string) => void; + /** 切换会话回调(如 :new 命令创建新会话) */ + onSessionSwitch?: (newSessionId: string) => void; responsive?: boolean; // 工具栏按钮 onOpenCommands?: () => void; @@ -39,6 +41,7 @@ export function ChatPage({ sessionId, onSessionNotFound, onSessionUpdated, + onSessionSwitch, responsive = false, onOpenCommands, onOpenMCP, @@ -74,6 +77,7 @@ export function ChatPage({ }, onSessionNotFound, onSessionUpdated, + onSessionSwitch, onConfigError: (error) => { toast.error(error.message, { duration: 10000,