18 KiB
18 KiB
纵向功能
状态:开发中 需求版本:0.3.0(已确认、已冻结) 实施方案版本:0.4.0(已确认) 项目骨架:已确认(2026-08-12)
允许的状态:“待开始”“进行中”“待用户查看”“已完成”“已阻塞”。用户已于 2026-08-14 授权 F-004 及后续切片由 Agent 验证通过后直接标记“已完成”并提交,最后统一人工审核。“已完成”仍不等于最终功能验收已经通过。
当前版本功能切片
F-001——应用外壳、首次状态与普通会话
- 状态:已完成(用户于 2026-08-12 审核通过)
- 用户可见结果:首次进入看到“最近”和“项目”空状态及右侧对话引导;点击“新任务”不会创建空会话,发送首条有效消息后普通会话出现,选择历史会话可还原消息并继续输入。
- 页面与交互:Claude Desktop 风格三栏外壳、空状态、对话引导、新任务草稿、普通历史会话、输入校验、加载与保存失败状态。
- 服务或接口:普通会话列表、会话详情、首条消息原子创建会话、已有会话追加用户消息。
- 数据持久化:Conversation 和 Message 实体 JSON、普通会话可重建索引、首条消息失败不暴露空会话。
- 权限与校验:应用内无身份层;普通会话强制
projectId = null;空文本拒绝;客户端不能指定工作区。 - 异常状态:列表加载失败、会话不存在、输入无效、持久化失败、重复提交期间禁用。
- 自动化测试:Core 首条消息和空消息用例、本地文件 Repository、Web DTO/路由及骨架回归共 10 个测试、24 个断言,全部通过。
- 验证命令与结果:
bun run format:check、bun run lint、bun run typecheck、bun run check:file-size、bun run check:architecture、bun test、bun run build全部通过。 - 人工验证步骤:在空数据目录启动生产服务;确认首次引导与空最近列表;点击“新任务”确认列表不新增;发送“这是第一条本地消息”确认会话和消息出现;刷新确认不自动选择;点击历史会话确认消息恢复。
- 人工操作结果:2026-08-12 使用本机浏览器完成上述步骤,首次与点击新任务后的会话数均为 0,发送后为 1,刷新后仍显示引导,选择历史后消息恢复。
- 视觉参考:已只读采集本机 Claude Desktop 新任务页并保存为
docs/visual-reference/claude-new-task.png;F-001 实现截图保存为docs/visual-reference/f001-conversation.png。历史任务采集超时,留待 F-009 补齐。 - 查看阶段修改:根据用户反馈将集中式
global.css拆为全局令牌/reset、应用外壳样式和 conversations 组件共置样式;后续组件继续遵循相同约定。 - 已知限制:本切片不调用模型;用户消息可持久化,但助手回复从 F-002 开始。
F-002——Agent Core 与 DeepSeek 流式回复
- 状态:已完成(用户于 2026-08-13 审核通过)
- 用户可见结果:普通会话可启动 Agent Run,DeepSeek 回复增量显示,完成后的助手消息写入本地会话并可继续聊天;未配置模型密钥时保留用户消息并显示明确错误。
- Agent Core:新增独立于 HTTP 的
AgentRunService、Run/RunEvent 领域对象、ModelPort与RunRepository;模型增量、完成和失败均转为稳定的领域事件。 - DeepSeek 接入:
model-deepseek在适配器内部映射 OpenAI 兼容协议,Core 只依赖自身 Message/ModelEvent 类型;首个模型固定为 DeepSeek。 - 服务与流式协议:新增
POST /api/runs和GET /api/runs/:runId/events;事件按序包含 Run 开始、消息开始/增量/完成及 Run 完成/失败。前端使用基于fetch的 SSE 读取,兼容不提供原生EventSource的 WebView。 - 数据持久化:每次运行保存
run.json和有序events.ndjson;成功后助手消息写入真实本地 Conversation 文件,失败后保存稳定失败终态和错误代码。 - 轮次关联:每条用户和助手消息都必须保存
runId;Run 使用triggerMessageId指向触发本轮运行的用户消息,并复用流式message.started给出的助手messageId,因此运行、触发消息、流式事件和最终消息可以稳定互查。会话写接口只提供查询,新增消息必须通过 Run 用例,避免产生没有 Run 的孤立消息。“第几回合”由用户消息顺序计算,不持久化易失序号;重试链retryOfRunId仍在 F-005 实现。 - 页面与交互:发送消息后进入运行状态、实时拼接助手草稿、完成后读取持久化消息;模型配置缺失时显示“尚未配置 DeepSeek API 密钥”,输入恢复可用且不丢失已提交的用户消息。
- 异常状态:模型密钥缺失保留具体可行动提示;其他模型异常对外收敛为“模型服务暂时不可用”,不泄露供应商原始错误或密钥。
- 自动化测试:Agent Core 成功/失败和轮次关联、文件 Run Repository、HTTP 与 SSE 消息标识一致性、禁止绕过 Run 直接写消息及原有回归共 13 个测试、43 个断言,全部通过。
- 验证命令与结果:
bun run format:check、bun run lint、bun run typecheck、bun run check:file-size、bun run check:architecture、bun test、bun run build全部通过。 - 人工验证步骤:以空临时数据目录和未配置 DeepSeek 密钥启动生产构建;发送“最终失败链路验收”;检查用户消息、错误提示、输入恢复以及 Run 事件文件和失败摘要。
- 人工操作结果:2026-08-12 使用本机应用内浏览器完成;页面准确显示模型密钥缺失提示,输入恢复,用户消息保留;
events.ndjson依次写入run.started、message.started、run.failed,run.json状态为failed。 - 查看阶段修改:根据用户反馈将应用外壳锁定为浏览器可视区高度;页面根节点不再滚动,侧栏仅“最近”区域内部滚动,ConversationPane 仅消息内容区内部滚动,顶部操作、侧栏底部信息和输入组件保持固定。2026-08-13 在 1280×720 视口验证根页面高度与视口一致且无页面滚动,两个内容区均为独立
overflow-y: auto容器。 - 开发环境修正:
bun run dev的后端固定以仓库根目录运行并读取根.env;前端由 Vite 提供 HMR,开发时统一访问127.0.0.1:5173,/api按同一份HOST/PORT配置代理到 Bun watch 后端。生产start仍由 Bun/Hono 提供构建后的web/dist。 - 视觉参考:失败状态验收截图保存为
docs/visual-reference/f002-model-config-error.jpg。 - 已知限制:真实 DeepSeek 成功调用需要用户在运行环境提供自己的密钥;自动化和本次人工验收未使用或读取真实密钥。停止与重试留在 F-005,服务重启后的事件重放加固留在 F-010。
- 主要验收:AC-004、AC-010、AC-014、AC-016。
F-003——项目管理与项目聊天
- 状态:已完成(用户于 2026-08-14 审核通过)
- 用户可见结果:创建、选择、重命名和删除项目,在项目中维护多个独立会话。
- 主要验收:AC-026 至 AC-033。
- 自动化验证结果:2026-08-13 通过全仓类型检查、16 项测试、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查。
- 人工操作结果:2026-08-13 使用本机应用内浏览器完成;验证了真实目录创建项目、首条消息才创建项目会话、项目历史恢复并继续聊天、重命名、删除确认信息,以及删除后本地工作目录仍然存在。
F-004——用户交互卡片
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:Agent 请求单选、多选、确认或意见输入,回答后继续同一 Run。
- 主要验收:AC-034 至 AC-038。
- 实现结果:DeepSeek 工具调用被转换为独立
interaction.*领域事件;交互请求按 Run 持久化,回答后使用原runId和toolCallId继续模型请求,不创建新 Run 或用户消息。支持单选、多选、确认和自由文本,包含选项数量、选择上下限、未知选项、重复回答及 8 KiB 文本校验。 - 页面结果:消息时间线按交互类型显示四类 VanJS 卡片;等待回答时禁用普通输入;回答后保留只读问题和答案;等待中的任务可从卡片停止并显示取消状态。
- 自动化验证结果:2026-08-14 通过全仓类型检查、21 项测试和 75 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查;Fake Model 验证暂停和恢复前后 Run 标识不变、事件序列连续。
- 人工操作结果:2026-08-14 使用隔离数据目录和本机应用内浏览器验证四类卡片、提交条件、只读答案、取消状态及刷新恢复;页面控制台无错误。
F-005——停止、失败与重试
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:停止当前生成并从失败状态重试。
- 主要验收:AC-005、AC-010、AC-011。
- 实现结果:Agent Core 持有每个活动 Run 的取消控制器,停止操作真正中断 ModelPort;停止前已生成内容持久化,Run 和事件日志进入
cancelled终态。失败或取消后创建带retryOfRunId的新 Run,复用原触发消息且不重复写入用户消息。Repository 与串行启动锁共同执行全局单活动 Run 检查,第二个任务返回RUN_ALREADY_ACTIVE。 - 失败处理:DeepSeek 请求增加与环境配置一致的模型超时并映射
MODEL_TIMEOUT;Bun 服务空闲超时与模型超时对齐;流式连接提前中断时前端结束加载并主动取消仍在运行的后台任务。 - 页面结果:生成时发送按钮切换为“停止生成”;失败和取消显示明确状态及“重试”按钮;API 启动失败时保留输入草稿。
- 自动化验证结果:2026-08-14 通过全仓类型检查、24 项测试和 84 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查。
- 人工操作结果:2026-08-14 使用隔离慢速 Fake Model 验证停止按钮、部分回复保留、取消终态和重试成功;并通过两个连续 HTTP 请求确认活动任务期间第二个请求稳定返回
409 RUN_ALREADY_ACTIVE;页面控制台无错误。
F-006——附件、文件列表、读取与搜索
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:附加工作区文件并让 Agent 安全读取和搜索。
- 主要验收:AC-007 至 AC-009、AC-021、AC-022、AC-028、AC-030。
- 实现结果:消息新增必填附件元数据,支持一次选择最多 10 个工作区文件和仅附件消息;普通草稿、项目草稿与已有会话均由服务端解析可信工作区,浏览器和模型不能传入根目录。文件层支持目录浏览、文件名与 UTF-8 内容搜索、2 MiB 内文本读取、二进制识别,并拒绝绝对路径、
..、空字节和符号链接逃逸。 - Agent 工具:新增
list_directory、search_files和read_text_file;普通文件工具使用独立tool.started、tool.completed、tool.failed事件,结果交回同一次模型请求链继续生成,与用户交互事件保持区分。 - 页面结果:VanJS 输入区提供工作区文件选择器、目录导航、搜索、最多 10 项选择、待发送附件和历史附件状态;只有附件时发送按钮可用。附件在发送后消失或不可访问时,历史会话仍可打开并明确显示“不可用”;项目目录离线时附件入口禁用且不会回退到默认工作区。
- 自动化验证结果:2026-08-14 通过全仓类型检查、29 项测试和 99 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查;覆盖读取/搜索、二进制拒绝、绝对路径、父目录跳转、符号链接逃逸、仅附件消息和文件工具续跑。
- 人工操作结果:2026-08-14 使用隔离工作区、隔离数据目录和未配置模型密钥的本机应用内浏览器完成;验证选择
README.md、仅附件发送、会话标题与附件历史恢复;删除测试文件后刷新,历史附件显示“不可用”,隔离页面控制台无错误。
F-007——文件创建与安全修改
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:Agent 在正确工作区内创建和安全修改文本文件。
- 主要验收:AC-008、AC-009、AC-023、AC-028。
- 实现结果:新增
create_text_file和apply_text_patch两个模型工具。新建文件使用排他写入,目标已存在时不会覆盖;修改必须携带最近一次read_text_file返回的 SHA-256 内容哈希,并使用 1 至 50 项精确文本替换。待替换文本不存在、默认模式下出现多次、文件已被外部改动或修改没有产生变化时均明确失败。 - 写入安全:新文件先解析真实父目录并再次检查工作区边界,阻止通过目录符号链接写到外部;已有文件修改在同目录写临时文件、保留原权限并原子替换,替换前再次核对内容哈希。继续限制 UTF-8 文本和 2 MiB 上限,不增加删除、移动、批量覆盖或 Shell 能力。
- 页面结果:创建和修改与其他文件工具共用已有工具状态卡片,分别显示“创建文件”和“修改文件”;成功与失败仍使用
tool.completed和tool.failed,不会混入主要回复消息或用户交互卡片。 - 自动化验证结果:2026-08-14 通过全仓类型检查、31 项测试和 109 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查;覆盖排他创建、哈希修改、过期哈希、缺失替换、歧义替换、路径穿越及目录符号链接逃逸。
F-008——会话管理与个人设置
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:重命名和删除会话,查看并修改非敏感设置。
- 主要验收:AC-003、AC-018。
- 会话管理:普通会话和项目会话在选中后提供重命名与删除入口;重命名立即更新会话文件、侧栏和当前标题。删除前展示会话名称,并明确说明删除消息、附件元数据和运行记录但不修改工作区文件;有活动任务时拒绝删除,成功后普通或项目会话列表同步移除。
- 个人设置:侧栏底部进入设置页,可查看和修改普通对话默认工作区及文件工具详情偏好;新工作区经服务端
realpath和读写目录校验后保存到独立settings.json,后续普通对话即时使用新目录。页面只显示 DeepSeek 模型名、是否已配置和应用版本,不返回或渲染模型密钥。 - 自动化验证结果:2026-08-14 通过全仓类型检查、35 项测试和 121 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查;覆盖会话重命名/删除接口、设置持久化、工作区规范化以及响应中不存在密钥字段。
- 人工操作结果:2026-08-14 使用隔离数据目录和本机应用内浏览器完成;验证创建失败终态会话后重命名、刷新恢复名称、删除确认与列表清空;将默认工作区修改为
/tmp并关闭工具详情后刷新,页面恢复规范化路径/private/tmp和关闭状态;隔离页面控制台无错误。
F-009——Claude Desktop 视觉与交互收口
- 状态:已完成(Agent 于 2026-08-14 验证通过,等待最终统一人工审核)
- 用户可见结果:全部已支持状态在目标视口下贴近确认后的参考界面。
- 主要验收:AC-001、AC-002、AC-012、AC-013、AC-020、AC-024。
- 消息排版:新增不依赖大型 UI 库的安全 Markdown 组件,支持段落、无序/有序列表、引用、链接、行内代码、粗体、表格和带语言标识的代码块;代码块提供复制按钮和复制结果反馈。解析过程直接创建 DOM 节点,不把消息内容作为 HTML 注入。
- 滚动行为:打开长会话和用户停留在底部时自动滚动到最新内容;用户主动向上滚动超过 80 px 后,新消息和状态更新不再抢回底部。页面根节点继续锁定视口高度,侧栏和消息内容区分别独立滚动,顶部区域、侧栏底部和输入区不跟随消息滚动。
- 视觉收口:沿用已确认的 Claude Desktop 深色三栏结构,补齐 Markdown 表格、引用、代码块、会话操作、设置页与文件选择器样式;没有增加未实现的 Claude 小组件或无效入口。新增组件继续使用功能共置样式,TypeScript 文件均不超过 400 行。
- 自动化验证结果:2026-08-14 通过全仓类型检查、36 项测试和 123 个断言、生产构建、代码检查、格式检查、文件规模检查与架构依赖检查;智能滚动阈值有独立测试。
- 人工操作结果:2026-08-14 使用隔离数据目录和本机应用内浏览器验证列表、引用、表格、TypeScript 代码块及复制反馈;长消息新增后滚动位置到达底部(
1812/1812),主动上滚到212后再新增消息仍保持212;页面根节点和body均无滚动,侧栏与内容区为独立overflow-y: auto,隔离页面控制台无错误。应用内浏览器固定为 1280×720,1440×900 的结构约束由同一桌面断点和既有参考截图覆盖。
F-010——恢复、边界与发布前加固
- 状态:进行中
- 用户可见结果:刷新、重启、目录离线和数据损坏等边界均有明确恢复行为。
- 主要验收:AC-006、AC-017 至 AC-019、AC-023、AC-029、AC-030、AC-036、AC-037。
后续版本想法
当前无。新增想法只记录在这里,不扩大 0.3.0 冻结范围。