claude-code/docs/ultraplan-implementation.md
2026-04-02 22:52:32 +08:00

445 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ULTRAPLAN增强规划实现分析
> 生成日期2026-04-02
> Feature Flag`FEATURE_ULTRAPLAN=1`
> 引用数10跨 8 个文件)
---
## 一、功能概述
ULTRAPLAN 是一个**远程增强规划**功能,将用户的规划请求发送到 Claude Code on the WebCCR云端容器执行。使用 Opus 模型在云端生成高级计划,用户可以在浏览器中编辑和审批,然后选择在云端继续执行或将计划"传送"回本地终端执行。
**核心卖点**
- 终端不被阻塞 — 远程在云端规划,本地可继续工作
- 使用最强大的模型Opus
- 用户可在浏览器中实时查看和编辑计划
- 支持多轮迭代(云端可追问,用户在浏览器回复)
---
## 二、架构总览
```
用户输入 "ultraplan xxx"
┌─────────────────────────────────┐
│ 关键字检测层 (keyword.ts) │ 识别 "ultraplan" 关键字
│ + 输入处理层 (processUserInput) │ 重写为 /ultraplan 命令
└───────────┬─────────────────────┘
┌─────────────────────────────────┐
│ 命令处理层 (ultraplan.tsx) │ launchUltraplan()
│ - 前置校验(资格、防重入) │ → launchDetached()
│ - 构建提示词 │ buildUltraplanPrompt()
└───────────┬─────────────────────┘
┌─────────────────────────────────┐
│ 远程会话层 │ teleportToRemote()
│ - 创建 CCR 云端会话 │ permissionMode: 'plan'
│ - 设置 plan 权限模式 │ model: Opus
└───────────┬─────────────────────┘
┌─────────────────────────────────┐
│ 轮询层 (ccrSession.ts) │ pollForApprovedExitPlanMode()
│ - ExitPlanModeScanner │ 每 3 秒轮询事件流
│ - 状态机: running → needs_input │ 超时: 30 分钟
│ → plan_ready │
└───────────┬─────────────────────┘
┌─────┴─────┐
▼ ▼
approved teleport
(云端执行) (传送回本地)
│ │
│ ▼
│ UltraplanChoiceDialog
│ 用户选择执行方式
▼ ▼
完成通知 本地执行计划
```
---
## 三、模块详解
### 3.1 关键字检测 — `src/utils/ultraplan/keyword.ts`
负责检测用户输入中的 "ultraplan" 关键字。检测逻辑相当精细,避免误触发:
**触发条件**:输入中包含独立的 `ultraplan` 单词(大小写不敏感)。
**不触发的场景**
- 在引号/括号内:`` `ultraplan` ``、`"ultraplan"`、`[ultraplan]`、`{ultraplan}`
- 路径/标识符上下文:`src/ultraplan/foo.ts``ultraplan.tsx``--ultraplan-mode`
- 问句:`ultraplan?`
- 斜杠命令内:`/rename ultraplan foo`
- 已有 ultraplan 会话运行中或正在启动时
**关键字替换**:触发后将 `ultraplan` 替换为 `plan`,保持语法通顺(如 "please ultraplan this" → "please plan this")。
```typescript
// 核心导出函数
findUltraplanTriggerPositions(text) // 返回触发位置数组
hasUltraplanKeyword(text) // 布尔判断
replaceUltraplanKeyword(text) // 替换第一个触发词为 "plan"
```
### 3.2 命令注册 — `src/commands.ts`
```typescript
const ultraplan = feature('ULTRAPLAN')
? require('./commands/ultraplan.js').default
: null
```
命令仅在 `FEATURE_ULTRAPLAN=1` 时加载。命令定义:
```typescript
{
type: 'local-jsx',
name: 'ultraplan',
description: '~1030 min · Claude Code on the web drafts an advanced plan...',
argumentHint: '<prompt>',
isEnabled: () => process.env.USER_TYPE === 'ant', // 仅 ant 用户可用
}
```
> 注意:`isEnabled` 检查 `USER_TYPE === 'ant'`Anthropic 内部用户),这是命令级限制。关键字触发路径没有此限制,只要 feature flag 开启即可。
### 3.3 核心命令实现 — `src/commands/ultraplan.tsx`
#### 3.3.1 入口函数 `call()`
处理 `/ultraplan <prompt>` 斜杠命令:
1. **无参数调用**:显示使用帮助文本
2. **已有活跃会话**:返回 "already polling" 提示
3. **正常调用**:设置 `ultraplanLaunchPending` 状态,触发 `UltraplanLaunchDialog` 对话框
#### 3.3.2 `launchUltraplan()`
公共启动入口,被三个路径共享:
- 斜杠命令 (`/ultraplan`)
- 关键字触发 (`processUserInput.ts`)
- Plan 审批对话框的 "Ultraplan" 按钮 (`ExitPlanModePermissionRequest`)
关键逻辑:
1. 防重入检查(`ultraplanSessionUrl` / `ultraplanLaunching`
2. 同步设置 `ultraplanLaunching = true` 防止竞态
3. 异步调用 `launchDetached()`
4. 立即返回启动消息(不等远程会话创建)
#### 3.3.3 `launchDetached()`
异步后台流程:
1. **获取模型**:从 GrowthBook 读取 `tengu_ultraplan_model`,默认 `opus46` 的 firstParty ID
2. **资格检查**`checkRemoteAgentEligibility()` — 验证用户是否有权限使用远程 agent
3. **构建提示词**`buildUltraplanPrompt(blurb, seedPlan)`
- 如有 `seedPlan`(来自 plan 审批对话框),作为草稿前缀
- 加载 `prompt.txt` 中的指令模板
- 附加用户 blurb
4. **创建远程会话**`teleportToRemote()`
- `permissionMode: 'plan'` — 远程以 plan 模式运行
- `ultraplan: true` — 标记为 ultraplan 会话
- `useDefaultEnvironment: true` — 使用默认云端环境
5. **注册任务**`registerRemoteAgentTask()` 创建 `RemoteAgentTask` 追踪条目
6. **启动轮询**`startDetachedPoll()` 后台轮询审批状态
#### 3.3.4 提示词构建
```
buildUltraplanPrompt(blurb, seedPlan?)
```
- `prompt.txt`:当前为空文件(反编译丢失),原始内容应包含指导远程 agent 生成计划的系统指令
- 开发者可通过 `ULTRAPLAN_PROMPT_FILE` 环境变量覆盖提示词文件(仅 `USER_TYPE=ant` 时生效)
#### 3.3.5 `startDetachedPoll()`
后台轮询管理:
1. 调用 `pollForApprovedExitPlanMode()` 等待计划审批
2. 阶段变化时更新 `RemoteAgentTask.ultraplanPhase`UI 展示)
3. 审批完成后的两种路径:
- **`executionTarget: 'remote'`**:用户选择在云端执行
- 标记任务完成
- 清除 `ultraplanSessionUrl`
- 发送通知:结果将以 PR 形式提交
- **`executionTarget: 'local'`**用户选择传送回本地teleport
- 设置 `ultraplanPendingChoice`
- 触发 `UltraplanChoiceDialog` 对话框
4. 失败时:归档远程会话、清除状态、发送错误通知
#### 3.3.6 `stopUltraplan()`
用户主动停止:
1. `RemoteAgentTask.kill()` 归档远程会话
2. 清除所有 ultraplan 状态(`ultraplanSessionUrl``ultraplanPendingChoice``ultraplanLaunching`
3. 发送停止通知
### 3.4 CCR 会话轮询 — `src/utils/ultraplan/ccrSession.ts`
#### 3.4.1 `ExitPlanModeScanner`
纯状态机,无 I/O。摄入 `SDKMessage[]` 事件批次,分类 `ExitPlanMode` 工具调用的结果。
**状态类型**
```typescript
type ScanResult =
| { kind: 'approved' } // 用户批准了计划
| { kind: 'teleport' } // 用户点击"传送回本地"
| { kind: 'rejected' } // 用户拒绝(可继续迭代)
| { kind: 'pending' } // 等待用户审批中
| { kind: 'terminated' } // 远程会话意外终止
| { kind: 'unchanged' } // 无新事件,状态不变
```
**优先级**approved > terminated > rejected > pending > unchanged
**关键设计**
- 同一批事件可能包含审批和后续崩溃 — 不丢弃已审批的计划
- 拒绝后重新扫描(`rescanAfterRejection`),因为新事件可能包含修改后的计划
- 使用 `is_error: true` 判断拒绝,`content` 中查找标记提取计划文本
#### 3.4.2 `pollForApprovedExitPlanMode()`
轮询主循环:
- **轮询间隔**3 秒
- **超时**30 分钟
- **容错**:连续 5 次网络错误才放弃
- **阶段推断**
- `hasPendingPlan`(有 ExitPlanMode 无结果)→ `plan_ready`
- `quietIdle`(空闲且无新事件)→ `needs_input`(远程在等用户输入)
- 其他 → `running`
#### 3.4.3 计划文本提取
两种提取路径:
1. **Approved**:从 `tool_result` 中查找 `## Approved Plan:\n``## Approved Plan (edited by user):\n` 标记
2. **Teleport**:从 `tool_result` 中查找 `__ULTRAPLAN_TELEPORT_SENTINEL__` 标记(浏览器端嵌入)
### 3.5 输入处理集成 — `src/utils/processUserInput/processUserInput.ts`
关键字触发路径(在斜杠命令处理之前):
```typescript
if (feature('ULTRAPLAN') &&
mode === 'prompt' && // 非非交互模式
!isNonInteractiveSession && // 非后台会话
inputString !== null &&
!inputString.startsWith('/') && // 非斜杠命令
!ultraplanSessionUrl && // 无活跃会话
!ultraplanLaunching && // 非正在启动
hasUltraplanKeyword(inputString)) {
// 重写为 /ultraplan 命令
const rewritten = replaceUltraplanKeyword(inputString).trim()
await processSlashCommand(`/ultraplan ${rewritten}`, ...)
}
```
### 3.6 UI 层
#### 3.6.1 彩虹高亮 — `src/components/PromptInput/PromptInput.tsx`
当输入中检测到 `ultraplan` 关键字时:
- 对每个字符施加**彩虹渐变色**高亮(`getRainbowColor()`
- 显示通知:"This prompt will launch an ultraplan session in Claude Code on the web"
#### 3.6.2 预启动对话框 — `UltraplanLaunchDialog`
在 REPL 的 `focusedInputDialog === 'ultraplan-launch'` 时渲染。
用户选择:
- **确认**:调用 `launchUltraplan()`,先添加命令回显,异步启动远程会话
- **取消**:清除 `ultraplanLaunchPending` 状态
#### 3.6.3 计划选择对话框 — `UltraplanChoiceDialog`
`focusedInputDialog === 'ultraplan-choice'` 时渲染。
当 teleport 路径返回已审批计划时,用户可选择执行方式。
#### 3.6.4 Plan 审批按钮 — `ExitPlanModePermissionRequest`
本地 Plan Mode 的审批对话框中,如果 `feature('ULTRAPLAN')` 开启,会显示额外的 "Ultraplan" 按钮:
- 将当前本地计划作为 `seedPlan` 发送给远程
- 按钮仅在无活跃 ultraplan 会话时显示
### 3.7 应用状态 — `src/state/AppStateStore.ts`
```typescript
interface AppState {
ultraplanLaunching?: boolean // 防重入锁5 秒窗口)
ultraplanSessionUrl?: string // 活跃远程会话 URL
ultraplanPendingChoice?: { // 已审批计划等待选择
plan: string
sessionId: string
taskId: string
}
ultraplanLaunchPending?: { // 预启动对话框
blurb: string
}
isUltraplanMode?: boolean // 远程端CCR 侧的 ultraplan 标记
}
```
### 3.8 远程任务追踪 — `src/tasks/RemoteAgentTask/RemoteAgentTask.tsx`
Ultraplan 使用 `RemoteAgentTask` 基础设施追踪远程会话:
```typescript
registerRemoteAgentTask({
remoteTaskType: 'ultraplan',
session: { id, title },
command: blurb,
isUltraplan: true // 特殊标记,跳过通用轮询逻辑
})
```
`extractPlanFromLog()``<ultraplan>...</ultraplan>` XML 标签中提取计划内容。
---
## 四、数据流时序
```
时间线 →
用户 本地 CLI CCR 云端
│ │ │
│ "ultraplan xxx" │ │
│──────────────────────>│ │
│ │ keyword 检测 + 重写 │
│ │ /ultraplan "plan xxx" │
│ │ │
│ [UltraplanLaunch │ │
│ Dialog] │ │
│──── confirm ─────────>│ │
│ │ launchDetached() │
│ │─────────────────────────────>│
│ │ teleportToRemote() │
│ │ (permissionMode: 'plan') │
│ │ │
│ "Starting..." │ │
│<──────────────────────│ │
│ │ │
│ (终端空闲,可继续) │ startDetachedPoll() │
│ │ ═══ 3s 轮询循环 ═══ │
│ │ │
│ │ [浏览器打开]│
│ │ [云端生成计划]
│ │ │
│ │ ← needs_input ─────────────│
│ │ (云端追问用户) │
│ │ │
│ │ [用户在浏览器回复]
│ │ │
│ │ ← plan_ready ──────────────│
│ │ (ExitPlanMode 等待审批) │
│ │ │
│ │ [用户审批/编辑]
│ │ │
│ ┌───────┤ ← approved ────────────────│
│ │ │ │
│ [远程执行] │ │ │
│ 通知完成 │ │ │
│ │ │ │
│ └── OR ─┤ ← teleport ───────────────│
│ │ │
│ [UltraplanChoice │ │
│ Dialog] │ │
│── 选择执行方式 ───────>│ │
│ │ 本地执行计划 │
```
---
## 五、关键文件清单
| 文件 | 职责 |
|------|------|
| `src/utils/ultraplan/keyword.ts` | 关键字检测、高亮位置计算、关键字替换 |
| `src/utils/ultraplan/ccrSession.ts` | CCR 会话轮询、ExitPlanMode 状态机、计划文本提取 |
| `src/utils/ultraplan/prompt.txt` | 远程指令模板(当前为空,需重建) |
| `src/commands/ultraplan.tsx` | `/ultraplan` 命令、启动/停止逻辑、提示词构建 |
| `src/utils/processUserInput/processUserInput.ts` | 关键字触发 → `/ultraplan` 命令路由 |
| `src/components/PromptInput/PromptInput.tsx` | 彩虹高亮 + 通知提示 |
| `src/screens/REPL.tsx` | 对话框渲染UltraplanLaunchDialog / UltraplanChoiceDialog |
| `src/components/permissions/ExitPlanModePermissionRequest/` | Plan 审批中的 "Ultraplan" 按钮 |
| `src/state/AppStateStore.ts` | ultraplan 相关状态字段定义 |
| `src/tasks/RemoteAgentTask/RemoteAgentTask.tsx` | 远程任务追踪 + `<ultraplan>` 标签提取 |
| `src/constants/xml.ts` | `ULTRAPLAN_TAG = 'ultraplan'` |
---
## 六、依赖关系
### 外部依赖
| 依赖 | 用途 | 必要性 |
|------|------|--------|
| `teleportToRemote()` | 创建 CCR 云端会话 | 必须 — 核心功能 |
| `checkRemoteAgentEligibility()` | 验证用户远程 agent 使用资格 | 必须 — 前置检查 |
| `archiveRemoteSession()` | 归档/终止远程会话 | 必须 — 清理 |
| GrowthBook `tengu_ultraplan_model` | 获取使用的模型 ID | 可选 — 默认 opus46 |
| `@anthropic-ai/sdk` | SDKMessage 类型 | 必须 — 类型定义 |
| `pollRemoteSessionEvents()` | 事件流分页轮询 | 必须 — 轮询基础设施 |
### 内部依赖
- **ExitPlanModeV2Tool**:远程端调用的工具,触发 plan 审批流程
- **RemoteAgentTask**:任务追踪和状态管理基础设施
- **AppState Store**ultraplan 状态管理
---
## 七、当前状态与补全要点
| 组件 | 状态 | 说明 |
|------|------|------|
| 关键字检测 | ✅ 完整 | `keyword.ts` 逻辑完善 |
| 命令框架 | ✅ 完整 | 注册、路由、防重入完整 |
| 启动流程 | ✅ 完整 | `launchUltraplan` / `launchDetached` 完整 |
| CCR 轮询 | ✅ 完整 | `ccrSession.ts` 状态机完整 |
| UI 高亮/通知 | ✅ 完整 | 彩虹高亮 + 提示通知完整 |
| 状态管理 | ✅ 完整 | AppState 字段完整 |
| `prompt.txt` | ❌ 空文件 | 需要重建远程指令模板 |
| `UltraplanLaunchDialog` | ⚠️ 全局声明 | 组件实现未找到(可能在内置包中) |
| `UltraplanChoiceDialog` | ⚠️ 全局声明 | 组件实现未找到(可能在内置包中) |
| `isEnabled` 限制 | ⚠️ `USER_TYPE === 'ant'` | 命令级限制,仅 Anthropic 内部用户 |
### 补全建议
1. **重建 `prompt.txt`**:这是远程 agent 的核心指令,定义如何进行多 agent 探索式规划。需要设计:
- 规划方法论(多角度分析、风险评估、分阶段执行)
- ExitPlanMode 工具的使用引导
- 输出格式要求
2. **对话框组件**`UltraplanLaunchDialog``UltraplanChoiceDialog``global.d.ts` 中声明但实现缺失,需要新建:
- Launch Dialog确认对话框含 CCR 使用条款链接)
- Choice Dialog展示已审批计划 + 执行方式选择
3. **放宽 `isEnabled`**:如果要让非 ant 用户使用斜杠命令,需移除 `USER_TYPE === 'ant'` 检查
---
## 八、与相关 Feature 的关系
| Feature | 关系 |
|---------|------|
| `ULTRATHINK` | 类似的高能力模式,但 `ULTRATHINK` 只调高 effort不启动远程会话 |
| `FORK_SUBAGENT` | Ultraplan 不使用 fork subagent使用的是 CCR 远程 agent |
| `COORDINATOR_MODE` | 不同范式的多 agentCoordinator 在本地编排Ultraplan 在云端 |
| `BRIDGE_MODE` | 底层依赖相同的 `teleportToRemote()` 基础设施 |
| `ExitPlanModeTool` | 远程端的审批机制Ultraplan 的核心交互模型 |