Commit 8acca1d6 authored by AI-甘富林's avatar AI-甘富林

docs: 添加项目文档和样式分析报告

- 添加AGENTS.md代理使用指南
- 更新CLAUDE.md项目规范文档
- 添加会话卡片样式分析报告
- 补充docs/目录下的交接和设计文档
Co-Authored-By: 's avatarClaude Opus 4.7 <noreply@anthropic.com>
parent 353c90c1
# Repository Guidelines
## Project Structure & Module Organization
This repo is a Windows-first `pnpm` workspace. Core app code lives in `apps/` and shared libraries live in `packages/`.
- `apps/desktop`: Electron main process, preload bridge, packaging config, and desktop services.
- `apps/ui`: Vite + React renderer.
- `packages/shared-types`: shared IPC contracts and DTOs.
- `packages/gateway-client`: Gateway/WebSocket client logic.
- `packages/runtime-manager`: bundled runtime lifecycle management.
- `build/scripts`: PowerShell packaging and smoke-test scripts.
- `vendor/openclaw-runtime`: generated runtime payload placeholder; generated contents should not be committed.
- `dist/`: installer output and other generated artifacts.
## Build, Test, and Development Commands
Use Corepack so the workspace stays on the pinned `pnpm` version.
- `corepack pnpm install`: install workspace dependencies.
- `corepack pnpm dev`: start the UI and Electron shell together for local development.
- `corepack pnpm build`: build all workspace packages in dependency order.
- `corepack pnpm typecheck`: run `tsc --noEmit` across the workspace.
- `corepack pnpm package`: materialize the runtime payload, build packages, and create the Windows installer.
- `corepack pnpm smoke:installer`: run the packaged installer smoke test.
## Coding Style & Naming Conventions
The codebase uses strict TypeScript, ESM modules, and 2-space indentation. Prefer double quotes and trailing semicolon-free style, matching existing files.
- Use `PascalCase` for React components and service classes.
- Use `camelCase` for functions, variables, and helpers.
- Keep shared contracts in `packages/shared-types`.
- Keep renderer code behind the preload bridge; do not access secrets, runtime files, or child processes directly from `apps/ui`.
There is no separate ESLint/Prettier config at the root; `lint` currently maps to TypeScript type-checking.
## Testing Guidelines
Primary validation is workspace type-checking plus targeted PowerShell smoke scripts in `build/scripts/`.
- Run `corepack pnpm typecheck` before opening a PR.
- Run the relevant smoke script when touching packaging, startup, routing, or runtime bootstrap paths.
- Name new smoke scripts descriptively, following the existing `*-smoke.ps1` pattern.
## Commit & Pull Request Guidelines
Recent history follows Conventional Commits with scopes, for example `fix(desktop): ...` and `feat(desktop): ...`. Keep messages imperative and scoped to the area changed.
PRs should include a short summary, linked issue if applicable, validation commands run, and screenshots for visible UI changes. Call out packaging or runtime prerequisites when a reviewer needs a Windows machine or local OpenClaw setup to verify the change.
## UI Layout Guardrails
When editing `apps/ui/src/App.tsx` and `apps/ui/src/styles.css`, keep the renderer layout on a single, stable skeleton system.
- Do not mix two layout systems in the main renderer shell. The main workspace skeleton must be driven by stable semantic class names, not large Tailwind utility overrides in `App.tsx`.
- Keep the conversation workspace wired through the same structural classes every time: `conversation-shell`, `conversation-main-layout`, `conversation-content-area`, and `conversation-panel`.
- Do not redefine core layout classes multiple times in `styles.css`. In particular, keep only one final definition for `shell`, `sidebar`, `main-shell`, `page-topbar`, `content-area`, `conversation-panel`, `message-list`, and `composer-shell`.
- Scope conversation-only styling under `.conversation-shell ...` so chat-specific rules do not leak into plugins or settings pages.
- Preserve the two-column desktop structure: left sidebar, right workspace. Changes must not collapse the right workspace into a sidebar-like single-column page.
- Before removing or hiding UI controls, check whether smoke helpers, automation hooks, or renderer-side test utilities depend on those DOM nodes or selectors.
- Be careful with Chinese text encoding in UI files. Avoid introducing BOM or accidental encoding changes when patching `App.tsx`, `styles.css`, or other renderer text files.
- For UI skeleton changes, validate with `corepack pnpm typecheck` and `corepack pnpm build`, and manually confirm chat, experts, plugins, and settings still render with correct height and scrolling behavior.
## Response Style (Strict Rules)
You MUST follow these rules:
1. **Answer only the core question**
- Focus on the single question asked
- No extra explanations, assumptions, or added topics
- If unclear, ask a clarification question instead of guessing
2. **Be extremely concise**
- Default to minimal wording (prefer 3–5 sentences)
- Avoid long paragraphs and repetition
- If one sentence is enough, don’t use two
3. **No unnecessary expansion**
- Do NOT include background, theory, or history unless explicitly asked
- No extra analysis, comparisons, or suggestions
4. **Single-question rule**
- Handle only ONE question at a time
- If multiple questions are asked, answer the most important one and ask the user to split the rest
5. **Structured when helpful**
- Prefer short bullet points or steps
- Avoid verbose explanations
6. **User-controlled depth**
- Optionally end with:
“Let me know if you want more detail on any part.”
---
## Example Style
✔ Good:
- “Two reasons: 1) xxx 2) xxx”
- “Do these 3 steps: …”
✘ Avoid:
- Long explanations
- Extra background info
- Covering multiple directions at once
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Windows-first Electron desktop shell for a bundled OpenClaw runtime.
## Key Development Commands
- `corepack pnpm install`: Install workspace dependencies
- `corepack pnpm dev`: Start UI and Electron shell for local development
- `corepack pnpm build`: Build all workspace packages in dependency order
- `corepack pnpm typecheck`: Run TypeScript type-checking across the workspace
- `corepack pnpm lint`: Run linting (currently maps to type-checking)
- `corepack pnpm package`: Materialize runtime payload, build packages, and create Windows installer
- `corepack pnpm clean`: Run clean scripts for all packages
- `corepack pnpm smoke:installer`: Run packaged installer smoke test
## Project Structure
Monorepo using pnpm workspaces:
- `apps/desktop/`: Electron main process, preload bridge, packaging config
- `apps/ui/`: React + Vite renderer UI
- `packages/shared-types/`: Shared IPC contracts and DTOs
- `packages/gateway-client/`: Gateway/WebSocket client library
- `packages/runtime-manager/`: Local runtime lifecycle management
- `build/scripts/`: PowerShell packaging and smoke-test scripts
- `vendor/openclaw-runtime/`: Placeholder for bundled runtime payload
## High-Level Architecture
### Process Structure
- **Main Process** (`apps/desktop/src/main/`): Electron main process handling system operations, runtime management, and window creation
- **Preload Script** (`apps/desktop/src/preload/`): Secure bridge between renderer and main process
- **Renderer Process** (`apps/ui/src/`): React UI running in Electron's sandboxed renderer
### Communication Flow
UI → Preload (API bridge) → Main Process → Local Runtime (OpenClaw via runtime-manager)
### Runtime Architecture
The application bundles and manages a complete OpenClaw runtime environment:
- Node.js runtime
- Python runtime with dependencies
- Playwright Chromium browser
- OpenClaw package entry point
- Configuration files
## Package Management
- Uses `corepack pnpm` (version 10.0.0) to ensure consistent package management
- `pnpm-workspace.yaml` defines workspace boundaries
- `tsconfig.base.json` provides base TypeScript configuration with path aliases for packages
- Electron packaging configured via `electron-builder.yml`
## Important Architecture Notes
1. **Security Boundary**: Renderer process must communicate through the preload bridge - no direct access to secrets, filesystem, or child processes from UI
2. **Type Safety**: All packages use strict TypeScript, with shared contracts in `packages/shared-types`
3. **Build Order**: Packages are built in dependency order: shared-types → gateway-client → runtime-manager → ui → desktop
4. **Runtime Materialization**: `vendor/openclaw-runtime/` is generated during packaging by `build/scripts/materialize-runtime-payload.ps1`
5. **Installer**: Windows NSIS installer created by `electron-builder` with custom branding hooks
## Key Files to Know
- `apps/desktop/src/main/index.ts`: Electron entry point
- `apps/desktop/src/preload/index.ts`: Preload bridge API
- `apps/desktop/electron-builder.yml`: Packaging configuration
- `build/scripts/materialize-runtime-payload.ps1`: Runtime materialization script
- `apps/ui/src/App.tsx`: Main React component
- `packages/shared-types/src/index.ts`: Shared type definitions
## Testing Approach
- Type-checking: `corepack pnpm typecheck` (strict TypeScript)
- Smoke Tests: PowerShell scripts in `build/scripts/` testing installation, startup, routing, and runtime bootstrap
- CI/CD: GitLab CI with `typecheck_windows` and manual `package_windows_installer` jobs
## Coding Style
- Strict TypeScript
- ESM modules throughout
- 2-space indentation
- Double quotes, no trailing semicolons
- PascalCase for React components/classes
- camelCase for functions/variables
## UI Layout Guardrails
- Keep renderer layout on a single, stable skeleton system
- Do not mix layout systems; use stable semantic class names
- Preserve two-column desktop structure: left sidebar, right workspace
- Scope conversation-only styling under `.conversation-shell ...`
- Before removing/hiding UI controls, check smoke helpers and test utilities
When editing `apps/ui/src/App.tsx` and `apps/ui/src/styles.css`, keep the renderer layout on a single, stable skeleton system.
- Do not mix two layout systems in the main renderer shell. The main workspace skeleton must be driven by stable semantic class names, not large Tailwind utility overrides in `App.tsx`.
- Keep the conversation workspace wired through the same structural classes every time: `conversation-shell`, `conversation-main-layout`, `conversation-content-area`, and `conversation-panel`.
- Do not redefine core layout classes multiple times in `styles.css`. In particular, keep only one final definition for `shell`, `sidebar`, `main-shell`, `page-topbar`, `content-area`, `conversation-panel`, `message-list`, and `composer-shell`.
- Scope conversation-only styling under `.conversation-shell ...` so chat-specific rules do not leak into plugins or settings pages.
- Preserve the two-column desktop structure: left sidebar, right workspace. Changes must not collapse the right workspace into a sidebar-like single-column page.
- Before removing or hiding UI controls, check whether smoke helpers, automation hooks, or renderer-side test utilities depend on those DOM nodes or selectors.
- Be careful with Chinese text encoding in UI files. Avoid introducing BOM or accidental encoding changes when patching `App.tsx`, `styles.css`, or other renderer text files.
- For UI skeleton changes, validate with `corepack pnpm typecheck` and `corepack pnpm build`, and manually confirm chat, experts, plugins, and settings still render with correct height and scrolling behavior.
## Commit & PR Guidelines
- Follow Conventional Commits with scopes (e.g., `fix(desktop): ...`, `feat(ui): ...`)
- Keep messages imperative and scoped to area changed
- PRs should include summary, validation commands run, screenshots for UI changes
\ No newline at end of file
# 2026-04-21 桌面单实例续接记录
## 目标
本轮要落实的口径是:
- 已有客户端在运行时,再次启动不应继续跑第二个主流程
- 首实例应恢复/显示/聚焦原窗口
- 不应新增一轮 runtime/gateway 启动或冲突日志
对应自动验证命令:
```powershell
corepack pnpm smoke:desktop-single-instance
```
## 已完成
代码侧已落地以下改动:
- `apps/desktop/src/main/index.ts`
- 增加 `app.requestSingleInstanceLock()`
- 增加 `second-instance` 处理
- 增加主窗口跟踪与唤回逻辑:
- `mainWindow`
- `focusMainWindow()`
- `restoreOrCreateMainWindow()`
- `createTrackedMainWindow()`
- 增加单实例 smoke 辅助状态与输出:
- `QJCLAW_SMOKE_SINGLE_INSTANCE`
- `QJCLAW_SMOKE_SINGLE_INSTANCE_READY_PATH`
- `QJCLAW_SMOKE_SINGLE_INSTANCE_EVENT_PATH`
- `runSingleInstanceSmoke()`
- `secondInstanceEventCount`
- `lastSecondInstanceEventSnapshot`
- `activate` 事件改为统一走 `restoreOrCreateMainWindow("activate")`
- `build/scripts/desktop-single-instance-smoke.ps1`
- 已新增单实例 smoke 脚本
- 流程是:
- 起第一个 Electron 实例
- 等首实例写 `ready`
- 起第二个 Electron 实例
- 校验第二个实例快速退出
- 校验首实例收到 `second-instance`
- 校验窗口数仍为 `1`
- 校验 `Launching bundled runtime command` 次数不增加
- 校验日志中没有:
- `gateway already running`
- `Port 18889 is already in use`
- `schtasks /End /TN`
- `package.json`
- 已新增脚本:
- `smoke:desktop-single-instance`
- `build/scripts/README.md`
- 已登记 `desktop-single-instance-smoke.ps1`
## 已验证
- 已通过:
```powershell
corepack pnpm typecheck
```
结果:通过。
## 当前阻塞
自动 smoke 目前还没有跑通,阻塞点不是 TypeScript 编译,而是本机环境残留了多个无法在当前权限下结束的 `electron.exe`
已观察到的残留 PID:
- `10420`
- `19736`
- `23484`
- `23564`
- `23588`
- `23820`
- `24384`
现象:
- `corepack pnpm smoke:desktop-single-instance` 失败
- 失败点是首实例迟迟没有写出 `ready` 文件
- 手工尝试结束残留进程时,`taskkill` / `Stop-Process` 都报 `Access is denied`
- 在残留进程存在时,单实例锁环境不干净,自动验证结果不可信
失败输出里最关键的信息是:
- `First Electron instance never reported single-instance readiness.`
相关失败产物路径:
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\result.json`
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\result.json.trace.log`
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\logs\startup\startup-latest.log`
## 已尝试但未完成
已执行过这些命令,但因为权限问题未能清掉残留进程:
```powershell
taskkill /IM electron.exe /F /T
```
```powershell
Stop-Process -Id 10420,19736,23484,23564,23588,23820,24384 -Force
```
校验残留进程的命令:
```powershell
Get-Process electron -ErrorAction SilentlyContinue
```
当前结论:
- 代码改动已经在仓库里
- 当前最先要解决的是机器上的残留 Electron 进程
- 在这个问题解决前,不要把 smoke 失败直接归因到单实例代码本身
## 下次继续时先做什么
优先顺序:
1. 先清掉所有残留 `electron.exe`
2. 再确认 `Get-Process electron -ErrorAction SilentlyContinue` 没有输出
3. 再跑单实例 smoke
4. 若 smoke 仍失败,再根据 `.tmp` 里的 trace/log 继续定位
推荐命令:
```powershell
Get-Process electron -ErrorAction SilentlyContinue
```
如果仍杀不掉,直接重启机器。
重启或清理完成后先跑:
```powershell
corepack pnpm smoke:desktop-single-instance
```
如果还失败,再补跑:
```powershell
powershell -ExecutionPolicy Bypass -File build/scripts/startup-binding-smoke.ps1
```
目的:
- `desktop-single-instance-smoke` 用来验证单实例口径本身
- `startup-binding-smoke` 用来判断是不是更基础的桌面启动链路也有问题
## 继续排查时要看的文件
- `D:\qjclaw\apps\desktop\src\main\index.ts`
- `D:\qjclaw\build\scripts\desktop-single-instance-smoke.ps1`
- `D:\qjclaw\package.json`
- `D:\qjclaw\build\scripts\README.md`
失败时优先看:
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\result.json`
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\result.json.trace.log`
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\logs\startup\startup-latest.log`
- `D:\qjclaw\.tmp\desktop-single-instance-smoke\logs\runtime-manager.log`
## 当前工作区事实
和这次单实例相关的工作区改动包括:
- `apps/desktop/src/main/index.ts`
- `build/scripts/desktop-single-instance-smoke.ps1`
- `package.json`
- `build/scripts/README.md`
其中:
- `build/scripts/desktop-single-instance-smoke.ps1` 当前是新增文件
- 其余几个文件已有未提交改动
## 一句话结论
单实例代码和 smoke 脚本已经落地,`typecheck` 已通过;下次续接前先解决本机残留的高权限 `electron.exe`,否则自动验证不会有可信结果。
## 2026-04-21 最新进展补充
### 本轮已继续完成的代码侧工作
- `apps/desktop/src/main/index.ts`
- 已把单实例入口继续接完整:
- `app.requestSingleInstanceLock()`
- `second-instance` 接管并聚焦现有主窗口
- `mainWindow` 跟踪
- `focusMainWindow()`
- `restoreOrCreateMainWindow()`
- `createTrackedMainWindow()`
- 已补单实例 smoke 专用信号:
- `QJCLAW_SMOKE_SINGLE_INSTANCE`
- `QJCLAW_SMOKE_SINGLE_INSTANCE_READY_PATH`
- `QJCLAW_SMOKE_SINGLE_INSTANCE_EVENT_PATH`
- `runSingleInstanceSmoke()`
- 已补窗口状态与日志辅助信息:
- `secondInstanceEventCount`
- `lastSecondInstanceEventSnapshot`
- `mainWindowLoadState`
- `window.load-state` 启动日志
- 已在 smoke 模式下加:
- `app.disableHardwareAcceleration()`
- `build/scripts/desktop-single-instance-smoke.ps1`
- 已去掉对 `Start-Process` 返回 PID 的“提前失败”判断
- 现在不会因为 Electron 首个 PID 变化而误判首实例退出
### 本轮已执行的验证
已执行并通过:
```powershell
corepack pnpm --filter @qjclaw/desktop build
```
```powershell
corepack pnpm typecheck
```
已执行但失败:
```powershell
corepack pnpm smoke:desktop-single-instance
```
```powershell
powershell -ExecutionPolicy Bypass -File build/scripts/startup-binding-smoke.ps1
```
### 关键新结论
- 当前问题已经不能再只归因到“单实例 smoke 本身”
- `startup-binding-smoke` 也失败了,说明更底层的桌面启动链路本身就不稳定
- `startup-binding-smoke` 的失败点是:
- Electron 还没写出 smoke output 就退出了
- 退出码是 `-2147483645`
- `desktop-single-instance-smoke` 仍然失败,但现在可以确认:
- 不再是脚本盯着首个 PID 导致的误判
- 更像是首实例窗口/渲染链路没稳定进入可用状态
### 这轮看到的最关键日志现象
- 单实例 smoke 的 trace 只走到:
- `runSingleInstanceSmoke:start`
- 基础启动 smoke 的 trace 走到:
- `runSmokeTest:start`
- `runSmokeTest:renderer-loading`
- `runSmokeTest:loading-renderer-state`
- `startup-latest.log` 里,主窗口 load-state 目前只看到:
- `created`
- 没有继续看到:
- `did-start-loading`
- `dom-ready`
- `did-finish-load`
- `did-fail-load`
- `render-process-gone`
这说明:
- 主窗口创建是发生了的
- 但后续页面加载事件没有稳定落到日志里
- 现象更接近 Electron / Chromium 级别的启动异常或系统态残留干扰
### 运行时相关补充观察
- `runtime-manager.log` 里持续可见:
- `Launching bundled runtime command`
- `Bundled runtime direct spawn was blocked with EPERM; retrying via PowerShell wrapper.`
- `Bundled runtime failed to spawn: spawn EPERM`
这不是本轮唯一问题,但说明当前环境里还有额外权限限制噪音,不能把 smoke 失败简单归因到单实例代码。
### 当前机器状态的新结论
当前机器上确认有一颗高权限残留 `electron.exe`
- PID:`7216`
- Parent PID:`12892`
- 但父进程已经不存在
- `Get-Process` 结果里:
- `HandleCount = 0`
- `Path` 为空
- `StartTime = 2026/4/21 15:30:31`
已尝试但仍失败:
```powershell
taskkill /PID 7216 /F /T
```
```powershell
Stop-Process -Id 7216 -Force
```
以及通过 `schtasks``SYSTEM` 身份触发 `taskkill`
当前判断:
- 这颗进程已经接近“残留/僵尸进程”
- 继续在当前系统态下跑 smoke,结果不可信
- 最稳妥做法仍然是先重启机器
### 更新后的下次继续顺序
1. 先重启机器,清掉 PID `7216`
2. 重启后先确认:
```powershell
Get-Process electron -ErrorAction SilentlyContinue
```
3. 如果没有输出,先跑:
```powershell
powershell -ExecutionPolicy Bypass -File build/scripts/startup-binding-smoke.ps1
```
4. 如果基础启动 smoke 通过,再跑:
```powershell
corepack pnpm smoke:desktop-single-instance
```
5. 如果基础启动 smoke 仍失败,优先看:
- `D:\qjclaw\.tmp\startup-binding-smoke\result.json`
- `D:\qjclaw\.tmp\startup-binding-smoke\result.json.trace.log`
- `D:\qjclaw\.tmp\startup-binding-smoke\logs\startup\startup-latest.log`
- `D:\qjclaw\.tmp\startup-binding-smoke\logs\runtime-manager.log`
### 当前这轮最准确的一句话结论
单实例代码和单实例 smoke 已继续补强,但新的验证结果表明当前主要阻塞已经下沉到更底层的 Electron 启动链路与机器残留进程状态;在重启清掉高权限残留 `electron.exe` 之前,继续跑 smoke 不会有可信结果。
This diff is collapsed.
# qjclaw 聊天页与设置页 UI/交互整改方案
## Summary
基于项目现状,问题集中在三处:发送反馈弱、核心聊天交互缺失、设置页信息层级混乱。已确认的项目事实是:聊天输入当前仅支持 Ctrl/Cmd+Enter 发送;发送按钮只有静态箭头;消息气泡无复制入口;窗口为 frame: false 且只在局部头部区域可拖动;设置
页工作目录当前可编辑可保存;设置保存后只有顶部短暂提示,没有未保存提醒。
整改目标是把聊天主链路做成“可感知、可键盘操作、可恢复”,把设置页做成“只暴露真实可操作项、减少冗余说明、强化保存状态反馈”。
## 修改范围
- 前端主改动
- apps/ui/src/App.tsx
- apps/ui/src/styles.css
- 可能涉及的桌面壳配合确认
- apps/desktop/src/main/create-window.ts
- 不在本次范围
- IPC 协议与 SaveConfigInput 结构
- 后端配置存储逻辑
- 消息渲染内容格式化能力
- 插件页、专家页业务流程本身
## Key Changes
- 聊天发送区
- 将输入区改为标准 <form onSubmit> 提交。
- 输入规则改为 Enter 发送,Shift+Enter 换行,替代现有 Ctrl/Cmd+Enter。
- 重写发送按钮状态:
- 空闲态改成双蓝色火箭 >> 意象图标。
- 发送中显示橙色旋转圆环,不再只是灰掉。
- 禁用态保留轮廓和可读状态,不做纯灰块。
- 更新占位文案与提示语,避免继续显示旧的快捷键规则。
- 聊天消息区
- 在用户和助手消息气泡下方新增稳定工具栏,提供“复制”按钮。
- 点击复制后按钮短暂反馈“已复制”,随后恢复。
- 仅复制消息正文文本;思考中空消息、trace、状态卡、附件不纳入复制。
- 工具栏默认占位,避免 hover 出现造成消息跳动。
- 窗口拖拽
- 保留 frame: false,但补充稳定 drag 热区。
- 非对话页维持 page-topbar 可拖动,同时确保存在真实空白拖拽区域。
- 对话页在 conversation-panel-head 层增加更明确的 drag strip 或可拖区域。
- 所有按钮、输入框、状态芯片继续标记 no-drag,避免拖拽吞掉点击。
- 设置页
- 工作目录改为只读展示卡,不再提供编辑输入框和“保存工作区设置”按钮。
- 模型配置卡片精简文案,只保留卡片标题、状态、必要字段。
- api_key 等字段标签强化层级,提升与输入框的颜色和字重区分。
- 引入“未保存变更”脏状态:
- 任一 key 字段被修改后显示非阻断提示条“当前修改尚未保存,保存后生效”。
- 切换页面、离开设置页或关闭窗口时,如存在脏状态则弹确认。
- 保存成功后改为明确提示“已保存,新的配置将在后续执行中生效”。
- 视觉规范
- 延续当前浅色桌面工具基调,但降低装饰性,提升功能优先级。
- 重点强化三组对比:字段标签 vs 输入框、可编辑项 vs 只读项、空闲态按钮 vs 处理中按钮。
- 所有新增交互保留可见 focus 状态,满足键盘可达性。
## 风险点
- 输入行为变更风险
- 现有用户已习惯 Ctrl/Cmd+Enter,改为 Enter 直发后,可能误发送多行内容。
- 需要通过占位文案、辅助提示和 Shift+Enter 明示降低迁移成本。
- 如果 drag 区覆盖不准,会出现“按钮点不动”或“窗口仍拖不动”。
- 消息卡新增工具栏后,长消息、流式消息、trace 展开态可能出现间距不协调。
- 需要验证不同消息态下不会破坏对齐关系。
- 设置页脏状态风险
- 草稿值、已保存值、服务端返回值之间如果比较策略不一致,容易出现误报“未保存”或保存后仍然脏。
- 需统一以当前草稿与最新保存配置做精确比较。
- 工作目录只读化风险
- 当前 saveConfig() 仍会带上 workspacePath;前端隐藏编辑后要避免误导实现者继续保留无意义保存入口。
- 本次应只调整 UI 暴露,不触碰底层兼容字段。
- 提示反馈冲突风险
- 现有 infoText/errorText 顶部提示、发送态提示、设置未保存提示可能同时出现。
- 需要明确优先级和位置,避免提示堆叠。
## Public Interfaces / Behavior
- 输入行为从“Ctrl/Cmd+Enter 发送”调整为“Enter 发送,Shift+Enter 换行”。
- 消息项新增复制能力,但不修改消息数据协议;复制反馈优先由 UI 本地状态按 message.id 管理。
- 设置页新增未保存变更判断,但不新增后端字段,不修改 SaveConfigInput。
- 工作目录从可编辑配置项降级为只读展示项,前端不再提供对应保存入口。
## Test Plan
- 手工交互测试
- 聊天输入框按 Enter 可发送,按 Shift+Enter 仅换行。
- 发送中按钮显示橙色 spinner,且不可重复提交。
- 按钮空闲、禁用、发送中三种视觉状态清晰可分。
- 用户消息和助手消息的复制按钮都可用,复制结果与界面正文一致。
- 复制后按钮反馈正确,2 秒左右恢复。
- 长文本、多行文本、流式完成后的文本都能正确复制。
- 聊天页、设置页、插件页顶部都能稳定拖动窗口。
- 顶部按钮、会话按钮、输入框不会被拖拽区影响点击。
- 设置页任一 key 字段修改后出现未保存提示。
- 设置页保存成功后提示更新,未保存提示消失。
- 存在未保存变更时,切页、离开设置页、关闭窗口会触发确认。
- 工作目录区域仅展示,不可编辑,不再出现“保存工作区设置”。
- 样式与布局测试
- 验证 375px、768px、1024px、1440px 下聊天区和设置页不溢出。
- 验证消息气泡新增工具栏后,用户/助手左右对齐仍正确。
- 验证设置卡片字段标签对比度明显提升,标签与输入框层级可快速分辨。
- 验证 toast、错误提示、未保存提示不会互相遮挡。
- 可访问性测试
- Tab 顺序符合视觉顺序。
- 新增复制按钮、发送按钮、设置按钮都有可见 focus ring。
- aria-label 与按钮状态文案在发送中、复制后都正确。
- 颜色不是唯一状态指示,发送中和未保存状态同时有图形/文案辅助。
- 验证命令
- 运行 corepack pnpm typecheck
- 如改动影响桌面壳交互,补跑 corepack pnpm dev 进行窗口拖拽与聊天链路手测
## Assumptions
- 采用已确认默认方案:工作目录用只读展示,不使用只读输入框。
- “需要保存生效”采用非阻断提示为主,离开当前上下文时再弹确认。
- 复制按钮先做纯文本复制,不覆盖 trace、状态卡和附件。
- 主要改动集中在 apps/ui/src/App.tsx 与 apps/ui/src/styles.css,桌面壳仅做必要配合确认。
\ No newline at end of file
# 会话卡片 (Sidebar Session Card) 样式分析报告
## 分析日期
2024年4月24日
## 分析文件
`D:/qjclaw/apps/ui/src/styles.css`
---
## 问题总结
### 1. 重复样式定义
会话卡片样式被**重复定义了4次**,在不同位置有不同的属性配置:
- 行 495-512:基础样式 + 选中状态(符合设计系统)
- 行 2088-2091:极简样式(仅定义 padding 和 border-radius)
- 行 3160-3170:基础样式 + 选中状态(不符合设计系统,使用绿色系)
- 行 3322-3333:完整布局样式(固定高度、网格布局)
### 2. 颜色系统不一致
**最严重的问题**是第 3166-3170 行的选中状态样式完全使用了绿色系(青色):
```css
/* 错误的样式(行 3166-3170) */
.sidebar-session-card.active {
border-color: rgba(13, 148, 136, 0.18); /* 深青色 - 非主题色 */
background: linear-gradient(180deg, rgba(240, 251, 249, 0.98), rgba(236, 247, 245, 0.96)); /* 青绿色渐变 */
box-shadow: 0 12px 26px rgba(13, 148, 136, 0.06); /* 青绿色阴影 */
}
```
而设计系统的主色调应该是蓝紫色系:
```css
/* 正确的样式(行 508-512) */
.sidebar-session-card.active {
border-color: rgba(139, 92, 246, 0.2); /* 蓝紫色边框 - 符合设计系统 */
background: rgba(139, 92, 246, 0.05); /* 淡紫色背景 */
box-shadow: var(--shadow-sm); /* 设计系统阴影变量 */
}
```
### 3. 硬编码属性值过多
- **圆角**:使用 `12px``16px``14px` 等硬编码值,未统一使用 `--radius-md/lg/xl` 变量
- **间距**:使用 `6px``8px``10px` 等硬编码值,未统一使用 `--space-2/3/4` 变量
- **阴影**:部分使用自定义阴影值,未使用 `--shadow-*` 变量
- **背景**:使用 `rgba(247, 250, 255, 0.92)` 等硬编码值,未使用 `--color-bg-*` 变量
### 4. 缺少响应式设计
当前没有专门针对 `.sidebar-session-card` 的响应式样式,只对容器级别的组件(如 `.shell``.sidebar`)有响应式规则。
---
## 修复建议
### 方案一:合并并统一样式(推荐)
#### 统一基础样式
```css
.sidebar-session-card {
min-height: 40px;
height: 60px;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: var(--space-2);
align-items: center;
padding: var(--space-2);
border-radius: var(--radius-lg);
border: 1px solid transparent;
background: rgba(247, 250, 255, 0.92);
box-shadow: var(--shadow-xs);
transition: all 0.2s ease;
}
.sidebar-session-card.active {
border-color: var(--color-border-medium);
background: rgba(139, 92, 246, 0.05);
box-shadow: var(--shadow-sm);
}
```
#### 响应式适配
```css
/* 大屏幕 */
@media (min-width: 1200px) {
.sidebar-session-card {
padding: var(--space-3);
border-radius: var(--radius-xl);
}
}
/* 中等屏幕 */
@media (max-width: 1200px) {
.sidebar-session-card {
padding: var(--space-2);
border-radius: var(--radius-lg);
}
}
/* 小屏幕 */
@media (max-width: 720px) {
.sidebar-session-card {
height: auto;
min-height: 56px;
padding: var(--space-2);
border-radius: var(--radius-md);
}
}
```
### 方案二:快速修复(仅修正颜色)
至少将第 3166-3170 行的绿色系样式替换为蓝紫色系:
```css
.sidebar-session-card.active {
border-color: var(--color-border-medium); /* 替换 rgba(13, 148, 136, 0.18) */
background: rgba(139, 92, 246, 0.05); /* 替换青绿色渐变 */
box-shadow: var(--shadow-sm); /* 替换自定义阴影 */
}
```
---
## 设计系统变量查询表
### 蓝紫色系颜色变量
```css
:root {
/* 主色系 */
--color-primary-50: #F5F3FF; /* 超浅薰衣草 */
--color-primary-100: #EDE9FE; /* 浅薰衣草 */
--color-primary-500: #8B5CF6; /* 主色 - 薰衣草紫 */
--color-primary-600: #7C3AED; /* 深薰衣草紫 */
/* 边框颜色 */
--color-border-light: rgba(139, 92, 246, 0.12);
--color-border-medium: rgba(139, 92, 246, 0.2);
--color-border-strong: rgba(139, 92, 246, 0.3);
/* 背景颜色 */
--color-bg-primary: var(--color-primary-50);
--color-bg-surface: #FFFFFF;
--color-bg-overlay: rgba(255, 255, 255, 0.92);
/* 阴影 */
--shadow-xs: 0 1px 2px rgba(139, 92, 246, 0.05);
--shadow-sm: 0 2px 4px rgba(139, 92, 246, 0.08);
--shadow-md: 0 4px 8px rgba(139, 92, 246, 0.12);
/* 圆角 */
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
/* 间距 */
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
}
```
---
## 风险评估与注意事项
1. **样式覆盖问题**:由于有4处分散的样式定义,合并时需要确保新样式的优先级正确
2. **布局影响**:修改高度、padding等属性时,需要测试对侧边栏整体布局的影响
3. **浏览器兼容性**:使用CSS变量需要确保浏览器支持(现代浏览器均支持)
---
## 验证步骤
1. 备份原文件 `styles.css`
2. 实施修复方案
3. 启动开发服务器,测试会话卡片的显示
4. 检查选中状态的样式是否符合蓝紫渐变主题
5. 测试响应式布局是否正常
6. 确保所有功能按钮和交互效果正常工作
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment