chore: establish YCode replication baseline and TODO

This commit is contained in:
xiaohan.yuan committed 2026-10-17 02:43:49 +08:00
commit 6dc59f89ba
1118 files changed
+196002

No files matched your search

+185
View File
@@ -0,0 +1,185 @@
# YCode 落地方案
> 历史初始方案。当前运行架构优先使用 OMP RPC sidecar,自建网关保留为回退;现行目标是借助 REA 进行视觉、交互与功能 1:1 复刻。实际完成度见 `接手状态-2026-10-15.md`;本文件旧里程碑和排除项不作为缩减范围的依据。
**日期**:2026-10-14
**范围**:Electron 桌面应用 · 第一个里程碑 = 最小端到端闭环(能对话 + 能跑一个工具)· 自建 OpenAI 兼容网关
---
## 0. 前置决策(已确认)
| 项 | 决策 | 理由 |
| --- | --- | --- |
| 产品形态 | Electron 桌面应用 | 与对标形态一致,可复用同批开源 UI 栈 |
| 首里程碑 | 最小端到端闭环 | 一次打通 UI ↔ Agent ↔ 网关 ↔ 工具,最快验证价值 |
| 模型接入 | 自建网关(自有 API Key,OpenAI 兼容) | 协议可控、供应商可换、密钥不出主进程 |
| 产物策略 | **clean-room** | 不复制对标产品的源码 / CSS / 资源,只用其公开架构与交互模式 |
---
## 1. 目标架构
```
┌──────────────────────────────────────────────────────┐
│ Renderer(React 19 + Zustand) │
│ 对话区 · 右栏上下文 · 设置弹窗 │
│ ⚠ 无 Node / fs / 网络能力 │
└───────────────┬──────────────────────────────────────┘
│ contextBridge(preload 白名单 API)
│ invoke: config/session/chat
│ event : chat:event(流式增量)
┌───────────────▼──────────────────────────────────────┐
│ Main(Electron 主进程 · ESM) │
│ ├ ipc.ts 唯一对外边界 │
│ ├ config.ts safeStorage 加密 Key │
│ ├ sessions.ts 会话与消息持久化 │
│ ├ agent/loop.ts Agent 循环(模型 ↔ 工具) │
│ └ gateway/ 自建网关(OpenAI 兼容 + SSE) │
└───────────────┬──────────────────────────────────────┘
│ HTTPS Bearer(Key 只在此处出现)
▼
自有上游(OpenAI 兼容 /chat/completions)
```
### 关键设计点
1. **单向分层**:`renderer → preload → ipc → agent → gateway → 上游`。反向只有 `chat:event` 一条流式通道。
2. **密钥不出主进程**:渲染进程只能拿到 `{ hasApiKey, keyStorage }`,永远拿不到明文。
3. **循环与工具解耦**:`loop.ts` 只管编排,工具是纯函数 `(args, ctx) => ToolResult`,新增工具只需改 `tools/index.ts` 注册表。
4. **网关只管协议**:模型路由、上下文裁剪、重试策略不放网关,后续可独立演进。
---
## 2. 一次回合的完整链路
```
用户按 Enter
→ renderer: chat.send({sessionId, text})
→ ipc: 落库用户消息 + 占位助手消息,返回 {runId, assistantMessageId}
→ loop: 拼 system + 历史 + 本轮 → gateway.stream()
→ gateway: POST /chat/completions (stream:true) → 解析 SSE
├ delta.content → emit {type:'text'} → 界面逐字追加
└ delta.tool_calls → 按 index 归并分片
→ 若产生工具调用:
emit tool_call → 执行工具 → emit tool_result
→ 把 assistant(tool_calls) + tool(result) 回填上下文 → 继续下一轮
→ 无工具调用 → emit done → 更新助手消息终态
```
取消:`chat:cancel(runId)` → `AbortController.abort()` → 网关抛 `AbortError` → `emit cancelled`。
---
## 3. 里程碑拆解
### M1 · 最小端到端闭环(本次已落地)
- [x] Electron 壳(`contextIsolation: true` / `sandbox: true` / 无 `nodeIntegration`)
- [x] preload 白名单 API(CJS,因为沙盒要求)
- [x] 自建网关:OpenAI 兼容 + SSE 流式 + 流式工具调用组装
- [x] Agent 循环:多轮工具调用、终止条件、取消
- [x] 工具:`list_dir`、`read_file`(只读 + 工作区逃逸防护)
- [x] 配置持久化:`safeStorage` 加密 Key,明文降级时 UI 告警
- [x] 会话持久化 + 首条消息自动命名
- [x] 界面:会话列表 / 对话区 / 右栏上下文 / 设置弹窗 / 明暗主题
- [x] 类型检查 + 构建通过
### M2 · 体验与可靠性
- [ ] Markdown 渲染(代码高亮、表格、KaTeX)
- [ ] 消息级操作:复制、编辑重发、重新生成
- [ ] 工具卡分组折叠(连续调用合并成摘要)
- [ ] 断流重试与错误分类提示
- [ ] 会话搜索与重命名
### M3 · 能力扩展
- [ ] 工具扩展:`write_file` / `edit_file` / `run_shell`(带权限确认)
- [ ] 审批流:写操作与命令执行需用户确认
- [ ] MCP 客户端接入
- [ ] Skill 加载(`SKILL.md` 约定)
### M4 · 平台化
- [ ] 迁移到 SQLite
- [ ] 项目 / 工作目录多实例
- [ ] 右栏真实面板(产物预览、文件树、任务)
- [ ] 打包分发(electron-builder,Windows 优先)
---
## 4. 安全基线
| 风险 | 处置 |
| --- | --- |
| 渲染进程被注入后提权 | `sandbox: true`、无 `nodeIntegration`、CSP 限制 `script-src 'self'` |
| 密钥泄露 | 只在主进程;`safeStorage` 加密;日志不打印 |
| 工具越权读写 | 路径解析后做 `relative()` 逃逸检查,越界直接拒绝 |
| 外链钓鱼 | `setWindowOpenHandler` 一律 `deny` + `shell.openExternal` |
| 任意命令执行 | M1 **不提供** shell 工具;M3 引入时必须走审批 |
---
## 5. 视觉对齐依据(对标实测值)
配色与排版**不再自拟**,全部取自两项实测证据:
1. 真实 WorkBuddy 运行时布局实测 —— `docs/reference/workbuddy-chat-layout.md`(CDP computed style / 元素矩形)
2. 安装包 token 表 —— `tokens-Df-i-zsO.css`、`contexts-BkjwYSZT.css`
### 调色板(浅色)
| 用途 | 值 |
| --- | --- |
| 正文 / 主文字 | `#000` |
| 次级 / 三级文字 | `rgba(0,0,0,.7)` / `rgba(0,0,0,.5)` |
| 主背景 / 次背景 | `#fff` / `#f2f2f2` |
| hover / active | `#ebebeb` / `#e6e6e6` |
| 边框(主/次/三级) | `#e6e6e6` / `#ebebeb` / `#f2f2f2` |
| 品牌 / 成功 / 警告 / 危险 / 信息 | `#00c29a` / `#0cbf5b` / `#ff7800` / `#f64041` / `#3370ff` |
**注意:UI 主体是中性黑白灰,品牌绿只用于状态点缀**,不用于主按钮或大面积色块。
### 圆角与间距
- 圆角:`sm 4px` / `md 6px` / `lg 8px` / 气泡 `16px` / 输入框 `24px`
- 间距基准 4px;对话内容列左右内边距 `40px`
### 字号
| 角色 | 值 |
| --- | --- |
| caption / body | `12px` / `14px`(行高 18 / 21) |
| 用户气泡 | `13px` / 19px |
| Markdown 根 | `17.143px`,行高 `1.75`;段落 `.875em` → 15px / 26.25px |
| 代码块 | `12.857px` / 22.5px,padding `12px 16px` |
| 表头 | 底色 `#f7f7f7`,单元格 padding `8px 12px` |
### 结构尺寸
- 左栏 `280px`;对话内容列 `max-width 832px` 居中,左右 `padding 40px`(正文列 752px)
- 助手头部:`24px` 圆形标识 + `10px` 间距,行高 `24.5px`,名称 `14px/600`,下间距 `12px`
- 用户气泡:`#f2f2f2`、padding `8px 12px`、圆角 `16px 16px 0`、`min-width 40px`、`max-height 310px`
- 输入容器:`1px solid #e6e6e6`、圆角 `24px`、白底 + 双层轻阴影;编辑区 `min-height 64px`、横向 `padding 16px`;工具栏 `56px`、按钮 `32px`
- 滚动:消息列表 `flex:1 + min-height:0 + overflow-y:auto`,输入区 `flex-shrink:0` 固定底部
> 落地方式:CSS 使用**自有类名**(`.msg--assistant`、`.bubble` 等),仅取实测数值,
> 不复制对标产品的类名与样式表结构。
---
## 6. 与对标分析的关系
`docs/` 下三份分析报告(`WorkBuddy-AI-实现分析报告`、`WorkBuddy-AI-复刻可行性评估`、`WorkBuddy-UI复刻可行性评估`)用于**指导选型与交互模式**,不作为复制来源:
- 可用:组件划分思路、交互状态机、协议约定、开源库清单
- 不可用:对方源码、CSS、图标与图片资源、文案
---
## 7. 首次运行清单
1. `npm install && npm run dev`
2. ⚙ 设置:填 baseUrl / 模型名 / API Key;选工作目录
3. 提问「列出工作目录里有哪些文件」→ 应看到工具卡出现、执行、结果回填、模型总结