diff --git a/package.json b/package.json index 59311d9..404287f 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@tanstack/react-router": "^1.166.7", "@uiw/codemirror-theme-vscode": "^4.25.8", "@uiw/react-codemirror": "^4.25.8", + "ai": "^6.0.116", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", @@ -62,6 +63,7 @@ "@kevisual/kv-login": "^0.1.17", "@kevisual/query": "0.0.53", "@kevisual/types": "^0.0.12", + "@opencode-ai/sdk": "^1.2.26", "@tailwindcss/vite": "^4.2.1", "@tanstack/react-router-devtools": "^1.166.7", "@tanstack/router-plugin": "^1.166.7", diff --git a/src/pages/chat-dev/page.tsx b/src/pages/chat-dev/page.tsx new file mode 100644 index 0000000..95b059e --- /dev/null +++ b/src/pages/chat-dev/page.tsx @@ -0,0 +1,123 @@ +import { useEffect } from 'react'; +import { useSearch } from '@tanstack/react-router'; +import { useShallow } from 'zustand/react/shallow'; +import { BotIcon, FileIcon, FolderIcon } from 'lucide-react'; +import { useChatDevStore } from './store'; +import { BOT_KEYS, BotKey } from '@/pages/code-graph/store/bot-helper'; +import openclawSvg from '@/pages/code-graph/assets/openclaw.svg'; +import opencodePng from '@/pages/code-graph/assets/opencode.png'; +import { useCodeGraphStore } from '../code-graph/store'; +import { useLayoutStore } from '../auth/store'; + +const BOT_ICONS: Record = { + openclaw: openclawSvg, + opencode: opencodePng, +}; + +export const App = () => { + const { timestamp } = useSearch({ from: '/chat-dev' }); + const { question, engine, projectInfo, initFromTimestamp, setData } = useChatDevStore( + useShallow((s) => ({ + question: s.question, + engine: s.engine, + projectInfo: s.projectInfo, + initFromTimestamp: s.initFromTimestamp, + setData: s.setData, + })), + ); + const layoutStore = useLayoutStore(useShallow((s) => ({ + me: s.me, + }))); + const codeGraphStore = useCodeGraphStore(useShallow((s) => ({ + createQuestion: s.createQuestion, + init: s.init, + }))); + + useEffect(() => { + if (!layoutStore.me?.username) return; + codeGraphStore.init(layoutStore.me, { load: false }); + }, [layoutStore.me]); + useEffect(() => { + if (timestamp) { + initFromTimestamp(timestamp); + } + }, [timestamp]); + + const relativePath = projectInfo + ? (projectInfo.filepath || '').replace((projectInfo.projectPath || '') + '/', '') || '/' + : null; + const onSend = async () => { + if (projectInfo) { + const res = await codeGraphStore.createQuestion({ + question, + projectPath: projectInfo.projectPath, + engine, + }); + console.log(res); + } + } + return ( +
+
+ {/* 标题栏 */} +
+ + AI 助手 +
+ + {/* 内容区 */} +
+ {/* 节点信息 + Bot 切换 */} +
+ {relativePath && ( +
+ + + {relativePath} + +
+ )} + {projectInfo?.projectPath && !relativePath && ( +
+ + + {projectInfo.projectPath} + +
+ )} + {/* Bot 切换按钮组 */} +
+ {BOT_KEYS.map((key) => ( + + ))} +
+
+ + {/* 问题输入区 */} +