# 设计说明

## 1. 问题

Pi 的 agent 在一次运行结束、真正停稳后不会自行继续。长任务因此经常停在“刚做完一小步”的位置；聊天历史又会随上下文压缩丢失目标和证据。更麻烦的是，模型可以在没有证据时报告完成。

`pi-auto-continue` 只解决这三个问题：

1. **节拍**：在 `agent_settled` 时追加下一阶段消息，让 PDCA 循环继续。
2. **记忆**：把 `plan/<主题>.md` 作为外部事实源，每轮回灌锚点。
3. **门禁**：用 OKR / 地图 / Check 三道门阻止无证据收口。

扩展不替模型思考，不新开 session，不派 subagent，也不改写计划文件。

## 2. 统一模型

```text
信念（SWOT）→ 承诺（OKR）→ 路径（地图）→ 实验（PDCA）→ 证据
   ↑                                              │
   └────────────── 用证据更新信念 ←──────────────┘
```

四个框架回答四个问题：

- **SWOT**：我们现在相信什么？S 已被证据支持，W 尚未验证，O 是最省力的验证机会，T 是最可能推翻计划的风险。
- **OKR**：这一轮要改变什么可观测的结果？O 是一句话的用户价值，KR 是可证伪的结果（基线 → 目标），不是任务清单。
- **用户故事地图**：用户按什么顺序感知到改变？顶层是切片，第一片是最小端到端价值闭环。
- **PDCA**：怎样用最小代价验证假设？Plan 更新假设，Do 只动一个变量，Check 用可复跑证据证伪，Act 按证据标准化或改写计划。

三个操作性定义：

- 价值 = 用户可感知的状态改变。
- 证据 = 可复跑的行为结果，或可观测的 KR 指标 / 用户反馈。
- 完成 = 每个承诺都有证据，或已被显式取消并留下理由。

## 3. 运行流程

```text
user / auto message
        │
        ▼
before_agent_start ── 注入 3 条价值循环原则（promptGuidelines）
        │
        ▼
agent run ── tool calls ── assistant 最后一行报 [PDCA] 阶段
        │
        ▼
agent_settled ── 真正停稳、无自动重试 / 压缩 / 排队
        │
        ├─ 无计划文件 → 最多引导一次 → 静默
        ├─ complete + 所有门通过 → 收口
        ├─ aborted / error → 暂停
        ├─ 超限 / 会话过大 / 卡住 → 暂停或压缩重置
        └─ 否则 → 同一 session 追加一条用户消息 → 下一阶段
```

### 为什么用 `agent_settled`

`agent_end` 之后 Pi 还可能自动重试、自动压缩重试、消费排队的 follow-up。`agent_settled` 才是“真的没有后续、正在等用户输入”的时刻。扩展只在这里动作，避免和 Pi 自己的恢复机制抢跑。

### 阶段协议

模型每轮回复最后一行报告：

```text
[PDCA] plan      更新假设与下一步
[PDCA] do        执行一个最小变量，有实际动作
[PDCA] check     用可复跑证据验证（Do 后必须 Check）
[PDCA] act       按证据收口：标准化，或改写计划
[PDCA] complete  所有承诺有证据 / 地图与 OKR 已收口 / Do 后 Check 过
[PDCA] blocked: <原因>
```

扩展取回复中最后一个标记作为本轮结论；代码块里的示例标记会被忽略。旧 `@坐标` 后缀、`[MAP]` 行、`[PLAN] working/complete/blocked` 仍兼容。

## 4. 计划文件

扩展只读 `plan/` 下最新修改的 `*.md`（`plan.md` 除外），按 mtime 缓存解析结果，一次读取同时解析 SWOT / OKR / 地图。

- **SWOT**：`## SWOT` 下 `S：` / `W：` / `O：` / `T：` 各取第一行；大小写兼容。
- **OKR**：`## 目标（Objective）` 取第一句；`## 关键结果（Key Results）` 解析勾选清单与进度数字。
- **地图**：`## 用户故事地图` 解析缩进树；收口只看叶子，取消子树整体跳过。
- **容错**：勾选兼容 `-` / `*` / `+`；`- [x]` 完成，`- [-]` 取消；分隔线结束段落。
- **事实源消失即清空**：`plan/` 没有计划文件时清空解析状态，不用陈旧 OKR / 地图做判定。

扩展不写回任何内容。模型负责维护计划；扩展只负责解析、回灌、守门。

## 5. 三道收口门

`[PDCA] complete` 必须同时满足：

1. **Check 门**：自上次 Do 之后 Check 过。
2. **OKR 门**：没有未达成的 KR。
3. **地图门**：没有未完成的叶子。

未过时，扩展把**所有**未过的门合并成一条消息，而不是一轮修一个。KR / 地图未完成时，模型必须选一条路并写回计划：

- 做完 → `- [x]`
- 砍掉 → `- [-]`（取消：理由）
- 改写 → 改 KR（仍须可度量、是结果不是任务）

这就是“OKR 不撒谎 / 地图不撒谎”。

## 6. 失败与恢复

- **卡住**：连续 `stuck` 轮没有任何工具调用 → 压缩历史，要求重新 Plan；最多 `reset` 次。
- **上下文预算**：超过 `compact-at` 先压缩再续跑；压缩已无法降低时不再每轮重试。
- **会话体积**：超过 `session-mb` 暂停并建议 `/new`；计划已落盘，重开可继续。
- **用户中止 / 运行错误**：暂停自动续跑，避免误以为还在工作。
- **blocked**：不把不确定性交回用户，要求模型做一个可回退的决定并写进计划。

## 7. 消息原则

模型面对的消息遵循同一套语气：

- 先给正向反馈，再给下一步；降低启动摩擦。
- 一次只推一个变量，只推对 KR 证据影响最大的下一步。
- 失败是证据，不是失败；卡住说明假设太大、证据太远，动作是切小循环。
- 需要拍板时选最合理、可回退、风险最低的默认方案，并记录理由。
- 收口被拦下时，一次说清所有门；不用“看起来没问题”代替可复跑证据。

## 8. 测试策略

测试不 mock 内部函数，而是用 Node 内置 `node:test` 驱动扩展工厂：

1. 用临时 `plan/` 目录写入计划。
2. mock `ExtensionAPI` / `ExtensionContext`。
3. 触发 `session_start` → `agent_start` → `tool_execution_start` → `agent_settled`。
4. 断言 `sendUserMessage` 收到的文本和 UI 通知。

测试文件是原生 TypeScript，由 Node 的 type stripping 直接执行，不需要构建步骤。这样验证的是模型真实看到的价值，而不是实现细节。
