diff --git a/tests/doc/dev-guide.md b/tests/doc/dev-guide.md deleted file mode 100644 index 59604207..00000000 --- a/tests/doc/dev-guide.md +++ /dev/null @@ -1,105 +0,0 @@ -# 开发指南 - -## 启动开发环境 - -```bash -./docs/script/start-dev.sh -``` - -浏览器打开 `http://localhost:1420` - -## 测试覆盖 - -### 新增测试 - -| 测试文件 | 测试数 | 覆盖内容 | -|----------|:---:|------| -| `desktop/src/components/chat/PlantUMLRenderer.test.tsx` | 5 | SVG 渲染、预览弹窗、空 SVG 回退、错误状态 | -| `src/server/__tests__/workspace-service.test.ts` | +1 | 软连接检测专项测试 | - -### 适配测试 - -| 测试文件 | 适配内容 | -|----------|----------| -| `desktop/src/stores/workspacePanelStore.test.ts` | `showHidden` 参数、`isSymlink` 字段 | -| `desktop/src/components/workspace/WorkspacePanel.test.tsx` | `isSymlink` 类型、`showHidden` 参数 | -| `src/server/__tests__/sessions.test.ts` | `isSymlink` 字段 | - -### 已知 Flaky 测试(与本次改动无关) - -- `WorkspacePanel > opens to all files when the current turn has no changed files` -- `WorkspacePanel > lazy loads the root tree...` -- `WorkspacePanel > can expand long file previews...` -- `workspacePanelStore > opens preview tabs...`(前提交 `showHidden` 参数导致 spy 调用次数变化) -- `H5AccessService > enable generates a token...`(环境依赖) - -### 运行测试 - -```bash -# 桌面端 -cd desktop && bun run lint && bun run test -- --run - -# 服务端 -cd .. && bun run check:server -``` - -## 数据流 - -### 文件树加载 - -``` -WorkspacePanel UI 点击展开 - → workspacePanelStore.toggleTreeNode(sessionId, path) - → workspacePanelStore.loadTree(sessionId, path, { showHidden }) - → sessionsApi.getWorkspaceTree(sessionId, path, showHidden) - → GET /api/sessions/{id}/workspace/tree?showHidden=... - → workspaceService.readTree(sessionId, relativePath, { showHidden }) - → fs.readdir({ withFileTypes: true }) - → filter + map → WorkspaceTreeEntry { name, path, isDirectory, isSymlink } -``` - -### 文件监听 - -``` -ws/handler.ts open() - → workspaceService.startWatcher(sessionId, workDir) - → fs.watch(workDir, { recursive: true }) - → 200ms debounce - → sendToSession({ type: 'file_changed', sessionId, path }) - → workspacePanelStore handleFileChanged() - → 刷新展开的树节点 + 刷新匹配的预览标签 - -ws/handler.ts close() - → workspaceService.stopWatcher(sessionId) -``` - -### PlantUML 渲染 - -``` -MarkdownRenderer (识别 @startuml 代码块) - → PlantUMLRenderer - → POST /api/settings/plantuml/render { code } - → handlePlantumlRender - → spawn('java', ['-Djava.awt.headless=true', '-jar', jarPath, '-tsvg', '-pipe']) - → stdin @startuml...@enduml → stdout SVG - → DOMPurify.sanitize(svg) - → dangerouslySetInnerHTML -``` - -### KaTeX 渲染 - -``` -MarkdownRenderer (marked 解析) - → 识别 $...$ (inline) / $$...$$ (block) - → katex.renderToString(tex, { throwOnError: false }) - → 替换 marked HTML 占位符 - → dangerouslySetInnerHTML -``` - -## API 端点 - -| 方法 | 路径 | 说明 | 改动 | -|------|------|------|------| -| POST | `/api/settings/plantuml/render` | PlantUML 渲染(pipe 模式) | 后端重写 | -| GET | `/api/sessions/{id}/workspace/tree` | 文件树(增加 `showHidden` 参数) | 参数新增 | -| WS | `file_changed` | 文件变化通知 | 消息类型新增 | diff --git a/tests/doc/feature-demo.md b/tests/doc/feature-demo.md deleted file mode 100644 index 9e23b9b7..00000000 --- a/tests/doc/feature-demo.md +++ /dev/null @@ -1,253 +0,0 @@ -# 功能集成测试文档 - -> 本文档用于验证 `feature/workspace-enhancements` 分支的全部新增功能: -> 隐藏文件控制、软连接显示、Mermaid 流程图、PlantUML 图表、KaTeX 公式渲染。 - ---- - -## 一、Mermaid 流程图 - -### 1.1 文件树加载流程 - -```mermaid -graph TD - A[用户点击展开目录] --> B{是否为目录?} - B -->|是| C[workspacePanelStore.toggleTreeNode] - B -->|否| D[workspacePanelStore.openPreview] - C --> E[loadTree: sessionId, path, showHidden] - E --> F[GET /api/sessions/:id/workspace/tree] - F --> G[workspaceService.readTree] - G --> H[fs.readdir withFileTypes] - H --> I{entry 是否为 symlink?} - I -->|是| J[标记 isSymlink: true] - I -->|否| K[标记 isSymlink: false] - J --> L[UI 显示 link 图标] - K --> L - L --> M["返回 WorkspaceTreeEntry[]"] - M --> N["React 渲染文件树"] -``` - -### 1.2 文件监听流程 - -```mermaid -sequenceDiagram - participant Client as 前端 - participant WS as WebSocket Server - participant Watcher as fs.watch - participant Store as workspacePanelStore - - Client->>WS: WebSocket 连接建立 - WS->>Watcher: startWatcher(sessionId, workDir) - Note over Watcher: fs.watch(workDir, recursive:true) - - Watcher-->>WS: 文件变更事件 - Note over WS: 200ms 防抖 - WS->>Client: { type: 'file_changed', sessionId, path } - - Client->>Store: handleFileChanged(sessionId, path) - Store->>Store: 刷新展开的树节点 - Store->>Store: 刷新匹配的预览标签 - Client->>WS: WebSocket 断开 - WS->>Watcher: stopWatcher(sessionId) -``` - ---- - -## 二、PlantUML 图表 - -### 2.1 系统架构图 - -```plantuml -@startuml -!theme plain - -package "桌面端 (desktop/)" { - component [React App] as React - component [PlantUMLRenderer] as PUML - component [MermaidRenderer] as MMD - component [MarkdownRenderer] as MD -} - -package "服务端 (src/server/)" { - component [API Server :3456] as API - component [PlantUML Pipe] as Pipe - component [WebSocket] as WS -} - -package "后端渲染" { - component [Java JVM] as Java - component [plantuml.jar] as Jar -} - -React --> MD : Markdown 解析 -MD --> PUML : @startuml 代码块 -MD --> MMD : mermaid 代码块 -PUML --> API : POST /api/settings/plantuml/render -API --> Pipe : spawn java -jar -pipe -Pipe --> Java : stdin @startuml...@enduml -Java --> Jar : 渲染 -Jar --> Java : SVG -Java --> Pipe : stdout -Pipe --> API : SVG string -API --> PUML : { svg: "..." } -PUML --> React : DOMPurify.sanitize + dangerouslySetInnerHTML -WS --> React : file_changed 消息 - -@enduml -``` - -### 2.2 组件生命周期 - -```plantuml -@startuml -state "空闲" as Idle -state "加载中" as Loading -state "渲染失败" as Error -state "渲染成功" as Success -state "回退代码块" as Fallback - -[*] --> Idle : 组件挂载 -Idle --> Loading : code prop 变化 -Loading --> Success : SVG 返回 -Loading --> Error : 渲染异常 -Loading --> Fallback : SVG 为 null(无 jar 配置) -Success --> Loading : code 再次变化 -Error --> Loading : code 再次变化 -Fallback --> Loading : code 再次变化 - -@enduml -``` - ---- - -## 三、KaTeX 公式渲染 - -### 3.1 行内公式 - -爱因斯坦质能方程:$E = mc^2$ - -欧拉公式:$e^{i\pi} + 1 = 0$ - -二次方程求根公式:$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$ - -### 3.2 块级公式 - -**贝叶斯定理:** - -$$ -P(A|B) = \frac{P(B|A) \cdot P(A)}{P(B)} -$$ - -**傅里叶变换:** - -$$ -\hat{f}(\xi) = \int_{-\infty}^{\infty} f(x) \cdot e^{-2\pi i x \xi} \, dx -$$ - -**矩阵乘法复杂度分析:** - -$$ -C_{i,j} = \sum_{k=1}^{n} A_{i,k} \cdot B_{k,j} \quad \Rightarrow \quad O(n^3) -$$ - -**梯度下降更新规则:** - -$$ -\theta_{t+1} = \theta_t - \eta \cdot \nabla_{\theta} J(\theta_t) -$$ - ---- - -## 四、代码块展示 - -### 4.1 TypeScript — 软连接检测 - -```typescript -// src/server/services/workspaceService.ts -export type WorkspaceTreeEntry = { - name: string - path: string - isDirectory: boolean - isSymlink: boolean -} - -function readTree(sessionId: string, relativePath = '', showHidden = false) { - const entries = await fs.readdir(resolvedPath, { withFileTypes: true }) - return entries - .filter(filterByShowHidden(showHidden)) - .sort(directoriesFirst) - .map((entry) => ({ - name: entry.name, - path: buildRelativePath(entry), - isDirectory: entry.isDirectory(), - isSymlink: entry.isSymbolicLink(), - })) -} -``` - -### 4.2 React 组件 — PlantUML 渲染 - -```tsx -// desktop/src/components/chat/PlantUMLRenderer.tsx -export function PlantUMLRenderer({ code }: Props) { - const [svg, setSvg] = useState(null) - const [loading, setLoading] = useState(true) - const [error, setError] = useState(null) - - useEffect(() => { - api.post('/api/settings/plantuml/render', { code }) - .then((result) => { - if (result.svg) { - setSvg(DOMPurify.sanitize(result.svg, { - ADD_TAGS: ['foreignObject'], - USE_PROFILES: { svg: true, svgFilters: true }, - })) - } - }) - .catch((e) => setError(e.message)) - .finally(() => setLoading(false)) - }, [code]) - - if (loading) return - if (error) return - if (!svg) return - return
-} -``` - -### 4.3 Shell 脚本 — 启动命令 - -```bash -#!/usr/bin/env bash -# docs/script/start-dev.sh — 一键启动开发环境 - -SERVER_PORT=3456 - -echo "==> 启动后端..." -bun run src/server/index.ts & -SERVER_PID=$! - -sleep 2 - -echo "==> 启动前端..." -cd desktop && bun run dev & -DESKTOP_PID=$! - -# 清理 -trap "kill $SERVER_PID $DESKTOP_PID" EXIT -wait -``` - ---- - -## 五、软连接测试 - -本目录下包含两个软连接,用于验证文件树的 `isSymlink` 显示功能: - -| 软连接 | 目标 | -|--------|------| -| `symlink-summary` | `~/工作总结` | -| `symlink-ai-summary` | `~/个人总结/AI使用总结/ai使用分析/中英文 思维链对比分析_20260511.md` | - -> 在文件树中展开本目录,软连接条目旁应显示 `🔗` 图标。 - \ No newline at end of file diff --git a/tests/doc/feature-summary.md b/tests/doc/feature-summary.md deleted file mode 100644 index 6b8fd590..00000000 --- a/tests/doc/feature-summary.md +++ /dev/null @@ -1,124 +0,0 @@ -# 功能改动说明 - -## 分支:feature/workspace-enhancements - -### 一、文件树增强 - -#### 1.1 隐藏文件控制 - -**入口**:文件树工具栏 `👁` 按钮 - -**行为**: -- 默认关闭(`showHiddenFiles: false`),不显示 `.` 开头的文件/目录 -- 开启后仅过滤 `.git`,其余隐藏文件可见 -- 状态通过 `workspacePanelStore.showHiddenFiles` 管理 -- 传递给后端 `readTree` 的 `showHidden` 参数 - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `src/server/services/workspaceService.ts` | `readTree` 添加 `showHidden` 参数,默认 `false` 过滤 `.` 前缀,`true` 仅过滤 `.git` | -| `src/server/api/sessions.ts` | 从 query string 读取 `showHidden` 参数传给 `readTree` | -| `desktop/src/api/sessions.ts` | `getWorkspaceTree` 添加 `showHidden` 参数,拼接到请求 query | -| `desktop/src/stores/workspacePanelStore.ts` | 添加 `showHiddenFiles` 状态 + `toggleShowHiddenFiles` 方法,`loadTree` 传递参数 | -| `desktop/src/components/workspace/WorkspacePanel.tsx` | 工具栏区域添加 `👁` 按钮 | - -#### 1.2 软连接支持 - -**行为**: -- 文件树中软连接条目显示 `🔗` (link) 图标 -- 通过 `Dirent.isSymbolicLink()` 检测,无需额外 stat 调用 - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `src/server/services/workspaceService.ts` | `WorkspaceTreeEntry` 添加 `isSymlink: boolean`,`readTree` 中调用 `entry.isSymbolicLink()` | -| `desktop/src/api/sessions.ts` | 前端 `WorkspaceTreeEntry` 类型同步添加 `isSymlink` | -| `desktop/src/components/workspace/WorkspacePanel.tsx` | 文件节点和目录节点添加 `link` 图标(`isSymlink` 为 `true` 时) | - -#### 1.3 文件监听 - -**行为**: -- WebSocket 连接建立后,对会话 workDir 启动 `fs.watch({ recursive: true })` -- 文件变化 200ms 防抖后通过 `sendToSession` 推送 `{ type: 'file_changed', sessionId, path }` -- 前端收到后自动刷新展开的树节点和预览标签 -- 不监听 `node_modules` - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `src/server/ws/events.ts` | `ServerMessage` 添加 `file_changed` 消息类型 | -| `src/server/services/workspaceService.ts` | 新增 `startWatcher(sessionId, workDir)` / `stopWatcher(sessionId)` 方法 | -| `src/server/ws/handler.ts` | `open()` 中启动 watcher,`close()` 中停止 watcher | -| `desktop/src/stores/workspacePanelStore.ts` | 注册 `file_changed` handler,刷新树和预览标签 | - ---- - -### 二、PlantUML 渲染 - -#### 2.1 前端渲染组件 - -**行为**: -- Markdown 中 `@@@plantuml` / `@startuml ... @enduml` 代码块自动渲染为 SVG 图表 -- 渲染结果经过 `DOMPurify.sanitize()` 安全清洗 -- 渲染失败时显示错误信息 - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `desktop/src/components/chat/PlantUMLRenderer.tsx` | 渲染组件:调用后端 API 获取 SVG,DOMPurify 清洗,error 状态 | -| `desktop/src/components/markdown/MarkdownRenderer.tsx` | 添加 `shouldRenderAsPlantUML` 判定,分发到 PlantUMLRenderer | -| `desktop/src/components/chat/PlantUMLRenderer.test.tsx` | 5 个测试:SVG 渲染、头部、预览弹窗、空 SVG 回退、错误状态 | - -#### 2.2 后端 Pipe 渲染 - -**行为**: -- 从 `execFile + 临时文件` 改为 `spawn -pipe` 模式 -- stdin 写入 PlantUML 源码,stdout 读取 SVG -- `-Djava.awt.headless=true` 避免 macOS Dock 图标 -- 去掉临时文件 I/O - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `src/server/api/settings.ts` | `handlePlantumlRender` 改用 `spawn('java', ['-Djava.awt.headless=true', '-jar', jarPath, '-tsvg', '-pipe'])` | - ---- - -### 三、KaTeX 公式渲染 - -**行为**: -- Markdown 中 `$...$` 行内公式和 `$$...$$` 块级公式自动渲染 -- 通过 `marked` 标记扩展在渲染 Pipeline 中处理 - -**涉及文件**: - -| 文件 | 改动 | -|------|------| -| `desktop/src/components/markdown/MarkdownRenderer.tsx` | 添加 KaTeX 渲染逻辑,`katex.renderToString` 处理行内/块级公式 | - ---- - -### 四、开发工具 - -#### 4.1 start-dev.sh - -**位置**:`docs/script/start-dev.sh` - -**行为**: -- 启动后端 `bun run src/server/index.ts` (port 3456) -- 启动前端 `cd desktop && bun run dev` (Vite port 1420) -- 浏览器打开 `http://localhost:1420` - -#### 4.2 Vite Proxy - -**位置**:`desktop/vite.config.ts` - -**行为**: -- `/api/*`, `/health` → `http://127.0.0.1:3456` -- `/ws` → `ws://127.0.0.1:3456` diff --git a/tests/doc/symlink-ai-summary b/tests/doc/symlink-ai-summary deleted file mode 120000 index 3b5f42ba..00000000 --- a/tests/doc/symlink-ai-summary +++ /dev/null @@ -1 +0,0 @@ -/Users/yangzexuan/个人总结/AI使用总结/ai使用分析/中英文 思维链对比分析_20260511.md \ No newline at end of file diff --git a/tests/doc/symlink-summary b/tests/doc/symlink-summary deleted file mode 120000 index 7a30806b..00000000 --- a/tests/doc/symlink-summary +++ /dev/null @@ -1 +0,0 @@ -/Users/yangzexuan/工作总结 \ No newline at end of file