{"owner":"EcoPasteHub","repo":"EcoPaste","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\n> 本文件是本项目 AI 编码工具的**单一真相源**。其它工具入口若存在，只应引用本文件，不要重复维护规则。\n> 分阶段 backlog 已迁移到 `.trellis/tasks/`，每个任务的 PRD 与研究资料以 Trellis task 为准。\n\nEcoPaste 是跨平台剪贴板管理器，采用 Rust-First 的 Tauri 架构。\n\n## 快速原则\n\n- **Rust-First**：业务、系统能力、数据库与持久化优先放 Rust；前端只做展示与交互。\n- **仅支持 macOS + Windows**：不要新增 Linux 代码、依赖、构建产物或文档承诺。\n- **已发布版本按发布数据处理**：数据结构、配置格式、默认值和 migration 变更必须有明确迁移策略，不再直接覆盖已发布数据契约。\n- **主动演进当前项目**：实现新能力时以当前代码、产品需求和平台约束为准，把当前仓库作为唯一实现基线。\n- **尊重 dirty worktree**：不要回滚或覆盖非本轮改动；需要动到已修改文件时先读清楚。\n- **提交与推送分支策略**：需要推送代码且当前分支是 `master` 时，自动新建工作分支，在新分支提交并推送；当前分支不是 `master` 时，先询问用户是在当前分支提交并推送，还是新建分支后提交并推送。\n\n## 技术栈\n\n| 维度 | 选型                                            |\n| ---- | ----------------------------------------------- |\n| 桌面 | Tauri v2                                        |\n| 前端 | React 19 + Ant Design v6 + UnoCSS `presetWind4` |\n| 状态 | Valtio（仅 UI 状态与设置镜像）                  |\n| 后端 | Rust + sqlx + SQLite                            |\n| 构建 | Vite + pnpm                                     |\n| 质量 | Biome、rustfmt、clippy、cargo test              |\n\n## 架构边界\n\n**必须在 Rust 实现**\n\n- 剪贴板监听、写回剪贴板、模拟粘贴，以及监听回环抑制。\n- 所有数据库读写、SQLite FTS5 搜索、历史记录清理。\n- 内容类型识别：URL、email、color、path。\n- 窗口定位计算、OS 级键盘钩子、全局快捷键、托盘、自启。\n- 图片落盘、缩略图、文件元信息读取、设置项持久化。\n- Rust 侧直接展示给用户的短文案（托盘、原生右键菜单、命令返回 toast）走 `i18n/` 模块；日志与内部错误上下文不走这里。\n\n**保留在前端**\n\n- 组件渲染、虚拟滚动、瀑布流、动画、列表选中态。\n- 主题视觉应用、CSS 变量注入、前端 i18n 文案渲染（Rust 侧文案见上）。\n- HTML sanitize 与预览、RTF 渲染、Markdown 渲染。\n- 普通键盘交互；Windows 主窗口收不到键时走 Rust `keyboard/` 事件。\n\n**跨端契约**\n\n- 前端通过 `#[tauri::command]` 调 Rust，Rust 用 `emit` 通知刷新。\n- 事件名用 `domain://action`，如 `clipboard://updated`、`settings://updated`、`window://visibility`、`keyboard://nav`。\n- 命令名、事件名、channel/storage key 等跨端或多处复用字面量必须集中维护：Rust 模块常量 + `src/constants/` 同步更新。\n\n## 目录约定\n\n```text\nsrc-tauri/\n  src/\n    commands/   # tauri command 入口，只做校验与转发\n    db/         # sqlx 仓储、连接池、模型\n    clipboard/  # 剪贴板读写、监听、内容识别\n    window/     # 窗口管理、定位、平台特化\n    keystroke/  # 模拟粘贴按键注入\n    keyboard/   # OS 级键盘钩子（仅 windows）\n    mouse/      # 全局鼠标钩子，主窗口失焦隐藏（仅 windows）\n    shortcut/   # 全局快捷键\n    tray/       # 托盘菜单\n    menu/       # 列表项右键菜单（macOS muda / Windows webview 窗）\n    drag_out/   # OS 级拖出（文件/图片/文本拖到外部应用）\n    backup/     # .ecopastebak 历史备份导出与接收\n    i18n/       # Rust 侧用户可见文案（托盘、菜单、命令 toast）\n    autostart/  # 开机自启\n    settings/   # 设置模型与持久化\n    core/       # 错误类型、路径、prevent_default（setup 在 lib.rs）\n  migrations/\nsrc/            # 前端 components/pages/stores/hooks/locales/utils\n```\n\n## 常用命令\n\n```bash\npnpm install\npnpm tauri dev\npnpm tauri build\npnpm lint\npnpm format\n\ncd src-tauri\ncargo fmt\ncargo clippy -- -D warnings\ncargo test\n```\n\n## Rust 约定\n\n- 命令与仓储函数使用 `async`，返回 `Result<T, AppError>`；`AppError` 序列化为 `{ kind, message }`。\n- `message` 写用户可读根因，不加 `\"xxx failed: {err}\"` 动作前缀；动作上下文由前端 toast label 拼接，技术上下文写日志。\n- 错误处理用 `thiserror` 定义错误类型、`anyhow` 做内部传播、`tauri-plugin-log` 记录上下文。\n- 数据库使用 Tauri `State<SqlitePool>`；不要每次新建连接。\n- Cargo 依赖版本不要写 patch 级完整版本；所有依赖优先写主版本号，如 `\"2\"`，确需收窄时最多写到 minor，如 `\"0.9\"`，除非有明确锁定原因。\n- SQL 用 `sqlx::query` / `query_as`，不用 `query!` 宏，避免维护离线缓存。\n- 已发布版本的 schema 变更必须新增 migration；已发布 migration 不回改。\n- 改 schema 时同步检查所有 `SELECT`、`INSERT`、`UPDATE`、`bind`、测试结构体字面量；`query_as` 字段不匹配可能表现为 UI 空结果。\n- 表必须有 `created_at` / `updated_at`，类型 `TEXT NOT NULL`；剪贴板 `updated_at` 表示内容重新使用时间，收藏、置顶、备注等元数据更新不要刷新它。\n- `commands/` 保持薄层：参数校验 + 调用下层模块，不写业务逻辑。\n- 平台代码用 `#[cfg(target_os = \"macos\")]` / `#[cfg(target_os = \"windows\")]` 隔离；新增能力两端同步实现，或显式标注 TODO。\n\n## 前端约定\n\n**React 与组件**\n\n- 组件用 `FC<Props>`；函数体内解构 `props`，不要在参数处解构。\n- 解构时需要透传剩余字段就用 `...rest` 收尾。\n- React 19 优先用 Actions、`use`、`useOptimistic`、ref as prop；不要新增 `forwardRef`。\n- JSX 事件回调提取为命名函数；单一动作用动词名，通用事件用 `handleXxx`。\n- 箭头函数一律使用 `{}` 和显式 `return`；不要单表达式隐式返回。\n- `useEffect` 只写同步副作用；异步初始化用 `useMount` + `useUnmount`，清理句柄用 `useRef`。\n\n**状态、数据与平台 API**\n\n- Valtio 只存 UI 状态和设置镜像；业务数据从 Rust command 拉取，不在前端建数据库副本。\n- 异步统一 `async` / `await` + `try` / `catch`；不要 `.then()` / `.catch()` / `.finally()` 链式写法。\n- 表达未定义用 `void 0`，不要写 `undefined`。\n- 日志统一走 `@/utils/log`，禁止裸 `console.*`。\n- 平台与环境判断统一从 `@/utils/is` 引入。\n- 当前窗口统一用 `getCurrentWebviewWindow()`，不要用 `getCurrentWindow()`。\n\n**样式与 UI**\n\n- 优先使用 Ant Design v6 组件；prop 命名用 `open` / `checked` / `disabled` / `onClick`。\n- 自定义 antd 内部结构优先用组件 `classNames` / `styles` 语义槽位；谨慎使用 `.ant-*` 全局覆盖。\n- 样式使用 UnoCSS；条件 className 统一用 `cn from \"@/utils/cn\"` + 对象语法，不拼模板字符串或 `+`。\n- 颜色只能用 antd token 映射类，如 `text-ant-secondary`、`bg-ant-container`、`border-ant-border`；需要新颜色先扩 `src/unocss/presetAntdColors.ts`。\n- 普通文本继承全局 `text-ant-text`；次级信息优先 `text-ant-secondary`，更浅层级需有明确设计理由。\n- 字号用标准语义字号：`text-xs`、`text-sm`、`text-base`、`text-lg`；不要用 `text-3` / `text-3.5`。\n- 尺寸走 wind4 数字制（1 = 4px），如 `p-1.5`、`gap-2`、`rounded-2.5`、`w-36`；不要写任意 px 类或 inline px。\n- 主题通过根部 `ConfigProvider` 的 `theme.algorithm` 切换，同时把 `light` / `dark` 类同步到 `<html>`。\n\n**内容与列表**\n\n- i18n 文案必须同步补齐 `zh-CN`（默认）和 `en-US`。\n- 列表使用 `react-virtuoso` 虚拟滚动。\n- HTML 内容必须经 DOMPurify sanitize 再渲染。\n\n## 通用代码规范\n\n- 非显然函数 / 方法上方写文档注释：TS/JS 用多行 JSDoc，Rust 用连续 `///`；getter/setter、显然一行包装、纯字面量常量可省。\n- 优先早返回，避免把主流程包进嵌套 `if`。\n- hooks、变量声明、副作用、不同语义阶段和 `return` 前用空行分组。\n- 函数体内少写注释；只解释隐藏约束、反直觉行为或规避原因。\n- 不写历史残留注释，不引用 TODO 阶段号或外部行号。\n- 不做超出当前需求的抽象、兼容垫片或提前优化；React hook / 工具函数遇到真实复杂度再抽象。\n- 提交信息用单行 Conventional Commits，如 `feat:`、`fix:`、`refactor:`、`docs:`。\n- 改 UI 后必须实际操作验证主路径与边界，不只靠类型检查。\n\n## 外部文档\n\n- Ant Design v6：<https://ant.design/components/overview-cn> · <https://ant.design/docs/react/customize-theme-cn>\n- UnoCSS：<https://unocss.dev/> · <https://unocss.dev/presets/wind4>\n- Tauri v2：<https://tauri.app/llms-full.txt>\n\n<!-- TRELLIS:START -->\n\n# Trellis Instructions\n\nThese instructions are for AI assistants working in this project.\n\nThis project is managed by Trellis. The working knowledge you need lives under `.trellis/`:\n\n- `.trellis/workflow.md` — development phases, when to create tasks, skill routing\n- `.trellis/spec/` — package- and layer-scoped coding guidelines (read before writing code in a given layer)\n- `.trellis/workspace/` — per-developer journals and session traces\n- `.trellis/tasks/` — active and archived tasks (PRDs, research, jsonl context)\n\nIf a Trellis command is available on your platform (e.g. `/trellis:finish-work`, `/trellis:continue`), prefer it over manual steps. Not every platform exposes every command.\n\nIf you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:\n\n- `.agents/skills/` — reusable Trellis skills\n- `.codex/agents/` — optional custom subagents\n\nManaged by Trellis. Edits outside this block are preserved; edits inside may be overwritten by a future `trellis update`.\n\n<!-- TRELLIS:END -->\n"},"files":{"AGENTS.md":"# AGENTS.md\n\n> 本文件是本项目 AI 编码工具的**单一真相源**。其它工具入口若存在，只应引用本文件，不要重复维护规则。\n> 分阶段 backlog 已迁移到 `.trellis/tasks/`，每个任务的 PRD 与研究资料以 Trellis task 为准。\n\nEcoPaste 是跨平台剪贴板管理器，采用 Rust-First 的 Tauri 架构。\n\n## 快速原则\n\n- **Rust-First**：业务、系统能力、数据库与持久化优先放 Rust；前端只做展示与交互。\n- **仅支持 macOS + Windows**：不要新增 Linux 代码、依赖、构建产物或文档承诺。\n- **已发布版本按发布数据处理**：数据结构、配置格式、默认值和 migration 变更必须有明确迁移策略，不再直接覆盖已发布数据契约。\n- **主动演进当前项目**：实现新能力时以当前代码、产品需求和平台约束为准，把当前仓库作为唯一实现基线。\n- **尊重 dirty worktree**：不要回滚或覆盖非本轮改动；需要动到已修改文件时先读清楚。\n- **提交与推送分支策略**：需要推送代码且当前分支是 `master` 时，自动新建工作分支，在新分支提交并推送；当前分支不是 `master` 时，先询问用户是在当前分支提交并推送，还是新建分支后提交并推送。\n\n## 技术栈\n\n| 维度 | 选型                                            |\n| ---- | ----------------------------------------------- |\n| 桌面 | Tauri v2                                        |\n| 前端 | React 19 + Ant Design v6 + UnoCSS `presetWind4` |\n| 状态 | Valtio（仅 UI 状态与设置镜像）                  |\n| 后端 | Rust + sqlx + SQLite                            |\n| 构建 | Vite + pnpm                                     |\n| 质量 | Biome、rustfmt、clippy、cargo test              |\n\n## 架构边界\n\n**必须在 Rust 实现**\n\n- 剪贴板监听、写回剪贴板、模拟粘贴，以及监听回环抑制。\n- 所有数据库读写、SQLite FTS5 搜索、历史记录清理。\n- 内容类型识别：URL、email、color、path。\n- 窗口定位计算、OS 级键盘钩子、全局快捷键、托盘、自启。\n- 图片落盘、缩略图、文件元信息读取、设置项持久化。\n- Rust 侧直接展示给用户的短文案（托盘、原生右键菜单、命令返回 toast）走 `i18n/` 模块；日志与内部错误上下文不走这里。\n\n**保留在前端**\n\n- 组件渲染、虚拟滚动、瀑布流、动画、列表选中态。\n- 主题视觉应用、CSS 变量注入、前端 i18n 文案渲染（Rust 侧文案见上）。\n- HTML sanitize 与预览、RTF 渲染、Markdown 渲染。\n- 普通键盘交互；Windows 主窗口收不到键时走 Rust `keyboard/` 事件。\n\n**跨端契约**\n\n- 前端通过 `#[tauri::command]` 调 Rust，Rust 用 `emit` 通知刷新。\n- 事件名用 `domain://action`，如 `clipboard://updated`、`settings://updated`、`window://visibility`、`keyboard://nav`。\n- 命令名、事件名、channel/storage key 等跨端或多处复用字面量必须集中维护：Rust 模块常量 + `src/constants/` 同步更新。\n\n## 目录约定\n\n```text\nsrc-tauri/\n  src/\n    commands/   # tauri command 入口，只做校验与转发\n    db/         # sqlx 仓储、连接池、模型\n    clipboard/  # 剪贴板读写、监听、内容识别\n    window/     # 窗口管理、定位、平台特化\n    keystroke/  # 模拟粘贴按键注入\n    keyboard/   # OS 级键盘钩子（仅 windows）\n    mouse/      # 全局鼠标钩子，主窗口失焦隐藏（仅 windows）\n    shortcut/   # 全局快捷键\n    tray/       # 托盘菜单\n    menu/       # 列表项右键菜单（macOS muda / Windows webview 窗）\n    drag_out/   # OS 级拖出（文件/图片/文本拖到外部应用）\n    backup/     # .ecopastebak 历史备份导出与接收\n    i18n/       # Rust 侧用户可见文案（托盘、菜单、命令 toast）\n    autostart/  # 开机自启\n    settings/   # 设置模型与持久化\n    core/       # 错误类型、路径、prevent_default（setup 在 lib.rs）\n  migrations/\nsrc/            # 前端 components/pages/stores/hooks/locales/utils\n```\n\n## 常用命令\n\n```bash\npnpm install\npnpm tauri dev\npnpm tauri build\npnpm lint\npnpm format\n\ncd src-tauri\ncargo fmt\ncargo clippy -- -D warnings\ncargo test\n```\n\n## Rust 约定\n\n- 命令与仓储函数使用 `async`，返回 `Result<T, AppError>`；`AppError` 序列化为 `{ kind, message }`。\n- `message` 写用户可读根因，不加 `\"xxx failed: {err}\"` 动作前缀；动作上下文由前端 toast label 拼接，技术上下文写日志。\n- 错误处理用 `thiserror` 定义错误类型、`anyhow` 做内部传播、`tauri-plugin-log` 记录上下文。\n- 数据库使用 Tauri `State<SqlitePool>`；不要每次新建连接。\n- Cargo 依赖版本不要写 patch 级完整版本；所有依赖优先写主版本号，如 `\"2\"`，确需收窄时最多写到 minor，如 `\"0.9\"`，除非有明确锁定原因。\n- SQL 用 `sqlx::query` / `query_as`，不用 `query!` 宏，避免维护离线缓存。\n- 已发布版本的 schema 变更必须新增 migration；已发布 migration 不回改。\n- 改 schema 时同步检查所有 `SELECT`、`INSERT`、`UPDATE`、`bind`、测试结构体字面量；`query_as` 字段不匹配可能表现为 UI 空结果。\n- 表必须有 `created_at` / `updated_at`，类型 `TEXT NOT NULL`；剪贴板 `updated_at` 表示内容重新使用时间，收藏、置顶、备注等元数据更新不要刷新它。\n- `commands/` 保持薄层：参数校验 + 调用下层模块，不写业务逻辑。\n- 平台代码用 `#[cfg(target_os = \"macos\")]` / `#[cfg(target_os = \"windows\")]` 隔离；新增能力两端同步实现，或显式标注 TODO。\n\n## 前端约定\n\n**React 与组件**\n\n- 组件用 `FC<Props>`；函数体内解构 `props`，不要在参数处解构。\n- 解构时需要透传剩余字段就用 `...rest` 收尾。\n- React 19 优先用 Actions、`use`、`useOptimistic`、ref as prop；不要新增 `forwardRef`。\n- JSX 事件回调提取为命名函数；单一动作用动词名，通用事件用 `handleXxx`。\n- 箭头函数一律使用 `{}` 和显式 `return`；不要单表达式隐式返回。\n- `useEffect` 只写同步副作用；异步初始化用 `useMount` + `useUnmount`，清理句柄用 `useRef`。\n\n**状态、数据与平台 API**\n\n- Valtio 只存 UI 状态和设置镜像；业务数据从 Rust command 拉取，不在前端建数据库副本。\n- 异步统一 `async` / `await` + `try` / `catch`；不要 `.then()` / `.catch()` / `.finally()` 链式写法。\n- 表达未定义用 `void 0`，不要写 `undefined`。\n- 日志统一走 `@/utils/log`，禁止裸 `console.*`。\n- 平台与环境判断统一从 `@/utils/is` 引入。\n- 当前窗口统一用 `getCurrentWebviewWindow()`，不要用 `getCurrentWindow()`。\n\n**样式与 UI**\n\n- 优先使用 Ant Design v6 组件；prop 命名用 `open` / `checked` / `disabled` / `onClick`。\n- 自定义 antd 内部结构优先用组件 `classNames` / `styles` 语义槽位；谨慎使用 `.ant-*` 全局覆盖。\n- 样式使用 UnoCSS；条件 className 统一用 `cn from \"@/utils/cn\"` + 对象语法，不拼模板字符串或 `+`。\n- 颜色只能用 antd token 映射类，如 `text-ant-secondary`、`bg-ant-container`、`border-ant-border`；需要新颜色先扩 `src/unocss/presetAntdColors.ts`。\n- 普通文本继承全局 `text-ant-text`；次级信息优先 `text-ant-secondary`，更浅层级需有明确设计理由。\n- 字号用标准语义字号：`text-xs`、`text-sm`、`text-base`、`text-lg`；不要用 `text-3` / `text-3.5`。\n- 尺寸走 wind4 数字制（1 = 4px），如 `p-1.5`、`gap-2`、`rounded-2.5`、`w-36`；不要写任意 px 类或 inline px。\n- 主题通过根部 `ConfigProvider` 的 `theme.algorithm` 切换，同时把 `light` / `dark` 类同步到 `<html>`。\n\n**内容与列表**\n\n- i18n 文案必须同步补齐 `zh-CN`（默认）和 `en-US`。\n- 列表使用 `react-virtuoso` 虚拟滚动。\n- HTML 内容必须经 DOMPurify sanitize 再渲染。\n\n## 通用代码规范\n\n- 非显然函数 / 方法上方写文档注释：TS/JS 用多行 JSDoc，Rust 用连续 `///`；getter/setter、显然一行包装、纯字面量常量可省。\n- 优先早返回，避免把主流程包进嵌套 `if`。\n- hooks、变量声明、副作用、不同语义阶段和 `return` 前用空行分组。\n- 函数体内少写注释；只解释隐藏约束、反直觉行为或规避原因。\n- 不写历史残留注释，不引用 TODO 阶段号或外部行号。\n- 不做超出当前需求的抽象、兼容垫片或提前优化；React hook / 工具函数遇到真实复杂度再抽象。\n- 提交信息用单行 Conventional Commits，如 `feat:`、`fix:`、`refactor:`、`docs:`。\n- 改 UI 后必须实际操作验证主路径与边界，不只靠类型检查。\n\n## 外部文档\n\n- Ant Design v6：<https://ant.design/components/overview-cn> · <https://ant.design/docs/react/customize-theme-cn>\n- UnoCSS：<https://unocss.dev/> · <https://unocss.dev/presets/wind4>\n- Tauri v2：<https://tauri.app/llms-full.txt>\n\n<!-- TRELLIS:START -->\n\n# Trellis Instructions\n\nThese instructions are for AI assistants working in this project.\n\nThis project is managed by Trellis. The working knowledge you need lives under `.trellis/`:\n\n- `.trellis/workflow.md` — development phases, when to create tasks, skill routing\n- `.trellis/spec/` — package- and layer-scoped coding guidelines (read before writing code in a given layer)\n- `.trellis/workspace/` — per-developer journals and session traces\n- `.trellis/tasks/` — active and archived tasks (PRDs, research, jsonl context)\n\nIf a Trellis command is available on your platform (e.g. `/trellis:finish-work`, `/trellis:continue`), prefer it over manual steps. Not every platform exposes every command.\n\nIf you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:\n\n- `.agents/skills/` — reusable Trellis skills\n- `.codex/agents/` — optional custom subagents\n\nManaged by Trellis. Edits outside this block are preserved; edits inside may be overwritten by a future `trellis update`.\n\n<!-- TRELLIS:END -->\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md\n\n> 本文件是本项目 AI 编码工具的**单一真相源**。其它工具入口若存在，只应引用本文件，不要重复维护规则。\n> 分阶段 backlog 已迁移到 `.trellis/tasks/`，每个任务的 PRD 与研究资料以 Trellis task 为准。\n\nEcoPaste 是跨平台剪贴板管理器，采用 Rust-First 的 Tauri 架构。\n\n## 快速原则\n\n- **Rust-First**：业务、系统能力、数据库与持久化优先放 Rust；前端只做展示与交互。\n- **仅支持 macOS + Windows**：不要新增 Linux 代码、依赖、构建产物或文档承诺。\n- **已发布版本按发布数据处理**：数据结构、配置格式、默认值和 migration 变更必须有明确迁移策略，不再直接覆盖已发布数据契约。\n- **主动演进当前项目**：实现新能力时以当前代码、产品需求和平台约束为准，把当前仓库作为唯一实现基线。\n- **尊重 dirty worktree**：不要回滚或覆盖非本轮改动；需要动到已修改文件时先读清楚。\n- **提交与推送分支策略**：需要推送代码且当前分支是 `master` 时，自动新建工作分支，在新分支提交并推送；当前分支不是 `master` 时，先询问用户是在当前分支提交并推送，还是新建分支后提交并推送。\n\n## 技术栈\n\n| 维度 | 选型                                            |\n| ---- | ----------------------------------------------- |\n| 桌面 | Tauri v2                                        |\n| 前端 | React 19 + Ant Design v6 + UnoCSS `presetWind4` |\n| 状态 | Valtio（仅 UI 状态与设置镜像）                  |\n| 后端 | Rust + sqlx + SQLite                            |\n| 构建 | Vite + pnpm                                     |\n| 质量 | Biome、rustfmt、clippy、cargo test              |\n\n## 架构边界\n\n**必须在 Rust 实现**\n\n- 剪贴板监听、写回剪贴板、模拟粘贴，以及监听回环抑制。\n- 所有数据库读写、SQLite FTS5 搜索、历史记录清理。\n- 内容类型识别：URL、email、color、path。\n- 窗口定位计算、OS 级键盘钩子、全局快捷键、托盘、自启。\n- 图片落盘、缩略图、文件元信息读取、设置项持久化。\n- Rust 侧直接展示给用户的短文案（托盘、原生右键菜单、命令返回 toast）走 `i18n/` 模块；日志与内部错误上下文不走这里。\n\n**保留在前端**\n\n- 组件渲染、虚拟滚动、瀑布流、动画、列表选中态。\n- 主题视觉应用、CSS 变量注入、前端 i18n 文案渲染（Rust 侧文案见上）。\n- HTML sanitize 与预览、RTF 渲染、Markdown 渲染。\n- 普通键盘交互；Windows 主窗口收不到键时走 Rust `keyboard/` 事件。\n\n**跨端契约**\n\n- 前端通过 `#[tauri::command]` 调 Rust，Rust 用 `emit` 通知刷新。\n- 事件名用 `domain://action`，如 `clipboard://updated`、`settings://updated`、`window://visibility`、`keyboard://nav`。\n- 命令名、事件名、channel/storage key 等跨端或多处复用字面量必须集中维护：Rust 模块常量 + `src/constants/` 同步更新。\n\n## 目录约定\n\n```text\nsrc-tauri/\n  src/\n    commands/   # tauri command 入口，只做校验与转发\n    db/         # sqlx 仓储、连接池、模型\n    clipboard/  # 剪贴板读写、监听、内容识别\n    window/     # 窗口管理、定位、平台特化\n    keystroke/  # 模拟粘贴按键注入\n    keyboard/   # OS 级键盘钩子（仅 windows）\n    mouse/      # 全局鼠标钩子，主窗口失焦隐藏（仅 windows）\n    shortcut/   # 全局快捷键\n    tray/       # 托盘菜单\n    menu/       # 列表项右键菜单（macOS muda / Windows webview 窗）\n    drag_out/   # OS 级拖出（文件/图片/文本拖到外部应用）\n    backup/     # .ecopastebak 历史备份导出与接收\n    i18n/       # Rust 侧用户可见文案（托盘、菜单、命令 toast）\n    autostart/  # 开机自启\n    settings/   # 设置模型与持久化\n    core/       # 错误类型、路径、prevent_default（setup 在 lib.rs）\n  migrations/\nsrc/            # 前端 components/pages/stores/hooks/locales/utils\n```\n\n## 常用命令\n\n```bash\npnpm install\npnpm tauri dev\npnpm tauri build\npnpm lint\npnpm format\n\ncd src-tauri\ncargo fmt\ncargo clippy -- -D warnings\ncargo test\n```\n\n## Rust 约定\n\n- 命令与仓储函数使用 `async`，返回 `Result<T, AppError>`；`AppError` 序列化为 `{ kind, message }`。\n- `message` 写用户可读根因，不加 `\"xxx failed: {err}\"` 动作前缀；动作上下文由前端 toast label 拼接，技术上下文写日志。\n- 错误处理用 `thiserror` 定义错误类型、`anyhow` 做内部传播、`tauri-plugin-log` 记录上下文。\n- 数据库使用 Tauri `State<SqlitePool>`；不要每次新建连接。\n- Cargo 依赖版本不要写 patch 级完整版本；所有依赖优先写主版本号，如 `\"2\"`，确需收窄时最多写到 minor，如 `\"0.9\"`，除非有明确锁定原因。\n- SQL 用 `sqlx::query` / `query_as`，不用 `query!` 宏，避免维护离线缓存。\n- 已发布版本的 schema 变更必须新增 migration；已发布 migration 不回改。\n- 改 schema 时同步检查所有 `SELECT`、`INSERT`、`UPDATE`、`bind`、测试结构体字面量；`query_as` 字段不匹配可能表现为 UI 空结果。\n- 表必须有 `created_at` / `updated_at`，类型 `TEXT NOT NULL`；剪贴板 `updated_at` 表示内容重新使用时间，收藏、置顶、备注等元数据更新不要刷新它。\n- `commands/` 保持薄层：参数校验 + 调用下层模块，不写业务逻辑。\n- 平台代码用 `#[cfg(target_os = \"macos\")]` / `#[cfg(target_os = \"windows\")]` 隔离；新增能力两端同步实现，或显式标注 TODO。\n\n## 前端约定\n\n**React 与组件**\n\n- 组件用 `FC<Props>`；函数体内解构 `props`，不要在参数处解构。\n- 解构时需要透传剩余字段就用 `...rest` 收尾。\n- React 19 优先用 Actions、`use`、`useOptimistic`、ref as prop；不要新增 `forwardRef`。\n- JSX 事件回调提取为命名函数；单一动作用动词名，通用事件用 `handleXxx`。\n- 箭头函数一律使用 `{}` 和显式 `return`；不要单表达式隐式返回。\n- `useEffect` 只写同步副作用；异步初始化用 `useMount` + `useUnmount`，清理句柄用 `useRef`。\n\n**状态、数据与平台 API**\n\n- Valtio 只存 UI 状态和设置镜像；业务数据从 Rust command 拉取，不在前端建数据库副本。\n- 异步统一 `async` / `await` + `try` / `catch`；不要 `.then()` / `.catch()` / `.finally()` 链式写法。\n- 表达未定义用 `void 0`，不要写 `undefined`。\n- 日志统一走 `@/utils/log`，禁止裸 `console.*`。\n- 平台与环境判断统一从 `@/utils/is` 引入。\n- 当前窗口统一用 `getCurrentWebviewWindow()`，不要用 `getCurrentWindow()`。\n\n**样式与 UI**\n\n- 优先使用 Ant Design v6 组件；prop 命名用 `open` / `checked` / `disabled` / `onClick`。\n- 自定义 antd 内部结构优先用组件 `classNames` / `styles` 语义槽位；谨慎使用 `.ant-*` 全局覆盖。\n- 样式使用 UnoCSS；条件 className 统一用 `cn from \"@/utils/cn\"` + 对象语法，不拼模板字符串或 `+`。\n- 颜色只能用 antd token 映射类，如 `text-ant-secondary`、`bg-ant-container`、`border-ant-border`；需要新颜色先扩 `src/unocss/presetAntdColors.ts`。\n- 普通文本继承全局 `text-ant-text`；次级信息优先 `text-ant-secondary`，更浅层级需有明确设计理由。\n- 字号用标准语义字号：`text-xs`、`text-sm`、`text-base`、`text-lg`；不要用 `text-3` / `text-3.5`。\n- 尺寸走 wind4 数字制（1 = 4px），如 `p-1.5`、`gap-2`、`rounded-2.5`、`w-36`；不要写任意 px 类或 inline px。\n- 主题通过根部 `ConfigProvider` 的 `theme.algorithm` 切换，同时把 `light` / `dark` 类同步到 `<html>`。\n\n**内容与列表**\n\n- i18n 文案必须同步补齐 `zh-CN`（默认）和 `en-US`。\n- 列表使用 `react-virtuoso` 虚拟滚动。\n- HTML 内容必须经 DOMPurify sanitize 再渲染。\n\n## 通用代码规范\n\n- 非显然函数 / 方法上方写文档注释：TS/JS 用多行 JSDoc，Rust 用连续 `///`；getter/setter、显然一行包装、纯字面量常量可省。\n- 优先早返回，避免把主流程包进嵌套 `if`。\n- hooks、变量声明、副作用、不同语义阶段和 `return` 前用空行分组。\n- 函数体内少写注释；只解释隐藏约束、反直觉行为或规避原因。\n- 不写历史残留注释，不引用 TODO 阶段号或外部行号。\n- 不做超出当前需求的抽象、兼容垫片或提前优化；React hook / 工具函数遇到真实复杂度再抽象。\n- 提交信息用单行 Conventional Commits，如 `feat:`、`fix:`、`refactor:`、`docs:`。\n- 改 UI 后必须实际操作验证主路径与边界，不只靠类型检查。\n\n## 外部文档\n\n- Ant Design v6：<https://ant.design/components/overview-cn> · <https://ant.design/docs/react/customize-theme-cn>\n- UnoCSS：<https://unocss.dev/> · <https://unocss.dev/presets/wind4>\n- Tauri v2：<https://tauri.app/llms-full.txt>\n\n<!-- TRELLIS:START -->\n\n# Trellis Instructions\n\nThese instructions are for AI assistants working in this project.\n\nThis project is managed by Trellis. The working knowledge you need lives under `.trellis/`:\n\n- `.trellis/workflow.md` — development phases, when to create tasks, skill routing\n- `.trellis/spec/` — package- and layer-scoped coding guidelines (read before writing code in a given layer)\n- `.trellis/workspace/` — per-developer journals and session traces\n- `.trellis/tasks/` — active and archived tasks (PRDs, research, jsonl context)\n\nIf a Trellis command is available on your platform (e.g. `/trellis:finish-work`, `/trellis:continue`), prefer it over manual steps. Not every platform exposes every command.\n\nIf you're using Codex or another agent-capable tool, additional project-scoped helpers may live in:\n\n- `.agents/skills/` — reusable Trellis skills\n- `.codex/agents/` — optional custom subagents\n\nManaged by Trellis. Edits outside this block are preserved; edits inside may be overwritten by a future `trellis update`.\n\n<!-- TRELLIS:END -->\n","category":"root","tokens":1636}]}