数据截至 (上游 commit 7538cc96774b)
GUI 产品层:需求先行流水线与自动化编排
30 秒导读: 前面五章讲的是 runtime 怎么跑一个 turn。这一章讲 Electron 前端用这些 turn 拼出了什么产品——一条把"人写的需求"变成"可验收的代码改动"的流水线,外加写作工作台、工作流画布和一堆无人值守的远程入口。Kun 与普通 chat 客户端的区别,全在这一层。
1. 这是什么(零基础也能懂)
一句话定义: GUI 产品层 = 一组"围绕 agent 的工作流产品",它们都建立在同一个 runtime 之上,但各自定义了自己的落盘产物和闸门规则。
普通 chat 客户端的产物是聊天记录。Kun 的 GUI 产物是文件:
| 产品线 | 用户看到的东西 | 落到磁盘的产物 |
|---|---|---|
| 需求先行(SDD) | 需求编辑器 + 需求 AI 侧栏 | .kunsdd/requirements/<uuid>/ 整个目录 |
| 计划与 Todo | 右侧计划面板、Todo 面板 | .kunsdd/plan/<feature>.md |
| 会话工作台 | 时间线、审批气泡、变更审查 | 无(状态在 runtime 与 localStorage) |
| Write 写作台 | Markdown 所见即所得编辑器 | 用户自己的 .md / 导出的 HTML/PDF/图 |
| 工作流画布 | 节点连线的自动化编辑器 | 设置文件里的 workflow.workflows[] |
给谁用: 一个人要让 agent 改一个真实项目,又不想"提 一句话就让它乱改一通"。SDD 这条线的主张是:先把需求写清楚、写成结构化的验收标准,再让模型出计划,最后按计划施工、逐条验收。
一句话直觉: 把它当成给 AI 用的 Jira + PR 流程——需求有编号有状态,计划的每一步都必须标注"我在实现哪条需求",施工完还要回来打勾。
用起来什么样(一条最小主线):
- 在 Write 视图新建一份需求,写下"帮我把 Code/Write 两个按钮改成左右等宽";
- 点"下一步",GUI 把需求发给模型,模型调用
create_plan把实现计划写进一个GUI 事先预留好的文件; - 计划面板打开,计划里的
- [ ]步骤同步成当前会话的 Todo; - 点"开始施工",切回 agent 模式按计划改代码;
- 点"验收",agent 逐条核对验收标准,把
- [ ]改成- [x]。
本节不出现代码。下面开始拆。
2. 顶层全景(它大概怎么转)
怎么读这张图: 从上往下是一次需求的生命周期;虚线框是磁盘上的产物;所有向 runtime 的箭头都走 01 章那扇 HTTP/SSE 门,没有例外。
┌──────────────── Electron 渲染进程(产品层) ────────────────┐
│ │
用户 → │ ① 需求编辑器 ──→ ② 升级为计划 ──→ ③ 计划面板/Todo ──→ ④ 验收 │
│ │ │ │ │ │
└────────┼────────────────┼─────────────────┼───────────┼────┘
│ │ │ │
▼ ▼(带预留路径) ▼ ▼
┌────────────────────────────────────────────────────────────┐
│ Kun runtime(HTTP + SSE,见 01 章) │
│ turn 里挂 GuiPlanContext → 才放出 create_plan 工具 │
└────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌ 磁盘产物 ────────────────────────────────────────────────┐
│ .kunsdd/requirements/<uuid>/requirement.md trace.json │
│ .kunsdd/plan/sdd-<uuid>.md │
└───────────────────────────────────────────────────────────┘
旁路还有三条,它们不经过界面,但走同一扇门:
定时任务 ┐
工作流节点├─→ runPromptViaRuntime() ─→ POST /v1/threads → POST turns → 轮询结果
IM 机器人 ┘ (主进程,无人值守)
部件一句话职责:
| 部件 | 干什么 | 在哪个文件 |
|---|---|---|
| 需求草稿 store | 单写者持有当前 requirement.md 的内容与脏状态 | src/renderer/src/sdd/sdd-draft-store.ts |
| 追踪计算 | 把需求块 × 计划 covers × 线程 todo 合成覆盖率与状态 | src/renderer/src/sdd/sdd-trace-compute.ts |
| 计划控制器 | 预留计划路径、发计划 turn、加载计划、发验收/重规划 | src/renderer/src/components/workbench-plan-controller.ts |
create_plan 工具 | runtime 侧的写闸门,只准写预留路径 | kun/src/adapters/tool/create-plan-tool.ts |
| 事件消费 | 把 SSE 事件揉进时间线,含审批气泡与看门狗 | src/renderer/src/store/chat-store-runtime.ts |
| 工作流引擎 | 25 种节点的调度、插值、cron 与人工审批 | src/main/workflow-runtime.ts |
| 无头执行器 | 给定时/工作流/IM 用的 "建线程 → 发 turn → 轮询" | src/main/schedule-runtime-helpers.ts |
3. 需求先行流水线(SDD):本章主菜
3.1 先看落盘形状:一个 uuid 目录装下一切
SDD 的第一条设计决策是需求即目录:一条需求的正文、追踪快照、贴图、原型、对话记录全部收在同一个 uuid 目录里,删需求就是删一个目录。
.kunsdd/
├── requirements/
│ └── <uuid>/
│ ├── requirement.md ← 需求正文(唯一真源)
│ ├── trace.json ← 出计划那一刻的需求哈希快照
│ ├── img/ ← 粘贴/生成的图片
│ ├── proto/ ← 生成的交互原型(单文件 HTML)
│ └── chat/ ← 需求 AI 的会话记录 + meta.json
└── plan/
└── sdd-<uuid>.md ← 这条需求对应的实现计划
路径规则集中在一个共享模块里,渲染进程和主进程共用同一份判定
(src/shared/sdd.ts:19 buildSddDraftRelativePath、:23 isSddDraftRelativePath、
:44 sddRequirementUnitDir、:68 sddDraftTraceRelativePath)。
反向映射也在这里:给一个计划路径,能算回它属于哪条需求
(src/shared/sdd.ts:77 sddDraftRelativePathForPlanPath)——"验收"和"增量重规划"两个按钮就是靠它判断"这个计划是不是 SDD 出身"。
诚实提示: 克隆里自带的
.kunsdd/draft/<uuid>/requirement.md是已退役的旧布局。当前代码只认.kunsdd/requirements/,旧条目在注册表归一化时直接丢弃(src/renderer/src/sdd/sdd-draft-store.ts:136)。这两份自带样本也没有 R 块和 covers 标注,只能用来看"正文和计划长什么样",不能用来看追踪闭环。
3.2 闭环的地基:R-n 需求块与 covers 标注
要解决的小问题: 怎么让"需求"