# AutoRDO Web 工作台 Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 落地 Axhub 原型 `autorodo-web`:粘贴素材 → 复制 AutoRDO 清洗提示词 → 粘回初稿 → 按需求分页确认待确认并回填描述 → 填写优先级/标签/提交部门/提交人 → 一键复制 YunxiaoPMapp 多条记录需求提示词。 **Architecture:** 纯函数放在原型内 `lib/`(解析初稿、出题回填、拼提示词、识别部门/提交人),UI 为三步工作台(React + OneOS V2 Token)。MVP 不连云效、不嵌 OCR/ASR;Cursor 往返靠剪贴板。预留 `agentAdapter` 接口形状供组织 Agent。 **Tech Stack:** React + TypeScript(Axhub Make 原型)、Vitest、OneOS V2(`oneos-ds-tokens.css` + `UIComponents` 按需)、`PrototypeAnnotationHost`。 **Spec:** [docs/superpowers/specs/2026-07-25-autorodo-web-design.md](../specs/2026-07-25-autorodo-web-design.md) --- ## 文件结构(锁定) | 路径 | 职责 | |------|------| | `src/prototypes/autorodo-web/lib/types.ts` | 需求稿、待确认点、元数据、步骤状态类型 | | `src/prototypes/autorodo-web/lib/parseDraft.ts` | 解析粘回的 AutoRDO Markdown → `RequirementDraft[]` | | `src/prototypes/autorodo-web/lib/parseDraft.test.ts` | 解析单测 | | `src/prototypes/autorodo-web/lib/applyAnswer.ts` | 选择题/补充 → 回填描述、消待确认 | | `src/prototypes/autorodo-web/lib/applyAnswer.test.ts` | 回填单测 | | `src/prototypes/autorodo-web/lib/buildCleanPrompt.ts` | 步骤 1 清洗提示词 | | `src/prototypes/autorodo-web/lib/buildRecordPrompt.ts` | 步骤 3 YunxiaoPMapp 多条口令 | | `src/prototypes/autorodo-web/lib/buildRecordPrompt.test.ts` | 上报词单测 | | `src/prototypes/autorodo-web/lib/inferMeta.ts` | 从原文推断提交部门/提交人 | | `src/prototypes/autorodo-web/lib/inferMeta.test.ts` | 推断单测 | | `src/prototypes/autorodo-web/lib/agentAdapter.ts` | 预留 `clean` / `record` 接口类型(MVP 空实现) | | `src/prototypes/autorodo-web/lib/clipboard.ts` | `navigator.clipboard.writeText` 封装 | | `src/prototypes/autorodo-web/lib/pendingQuestions.ts` | 从「待确认」文案生成选择题选项(词典摘要常量) | | `src/prototypes/autorodo-web/components/StepPaste.tsx` | 步骤 1 UI | | `src/prototypes/autorodo-web/components/StepConfirm.tsx` | 步骤 2 UI | | `src/prototypes/autorodo-web/components/StepExport.tsx` | 步骤 3 UI | | `src/prototypes/autorodo-web/AutorodoWebApp.tsx` | 三步状态机主壳 | | `src/prototypes/autorodo-web/index.tsx` | 入口 `@name` + AnnotationHost | | `src/prototypes/autorodo-web/style.css` | 布局与触控样式 | | `src/prototypes/autorodo-web/annotation-source.json` | 标注目录 | | `src/prototypes/autorodo-web/.spec/requirements-prd.md` | AutoPRD | | `src/prototypes/autorodo-web/.spec/confirm-flow.md` | 确认与回填规则全文 | | `src/resources/prd/autorodo-web-autoprd.md` | PRD 副本(若项目惯例需要) | | 修改 `.axhub/make/project.json` | 注册原型(若 Make 未自动发现) | | 修改 `~/.cursor/skills/YunxiaoPMapp` + 项目内副本 | 记录需求解析四字段(Task 8,可同迭代或紧随) | **不放入 `src/common/`**:逻辑仅本原型使用,避免污染公共层。 --- ### Task 1: 类型 + parseDraft + 单测 **Files:** - Create: `src/prototypes/autorodo-web/lib/types.ts` - Create: `src/prototypes/autorodo-web/lib/parseDraft.ts` - Create: `src/prototypes/autorodo-web/lib/parseDraft.test.ts` - [ ] **Step 1: 写入类型** ```ts // src/prototypes/autorodo-web/lib/types.ts export type Priority = '紧急' | '高' | '中' | '低'; export type RequirementMeta = { priority: Priority | ''; tags: string[]; submitDept: string; submitter: string; titleKind: '新增' | '优化' | ''; }; export type PendingItem = { id: string; raw: string; question: string; options: string[]; resolved: boolean; answer?: string; }; export type RequirementDraft = { index: number; title: string; description: string; pendings: PendingItem[]; meta: RequirementMeta; confirmed: boolean; }; export type WizardStep = 1 | 2 | 3; ``` - [ ] **Step 2: 写失败单测(多条 + 待确认)** ```ts // src/prototypes/autorodo-web/lib/parseDraft.test.ts import { describe, it, expect } from 'vitest'; import { parseAutorodoDraft } from './parseDraft'; const SAMPLE = `共 2 条 ### 1 ## 原始诉求(AutoRDO) **标题**:合同台账批量导出 **描述**: 在租赁合同台账支持批量导出 待确认: - 导出范围未说明 ### 2 ## 原始诉求(AutoRDO) **标题**:证照到期提醒 **描述**: 调整证照到期提醒口径 待确认: 无 `; describe('parseAutorodoDraft', () => { it('splits multiple requirements and pending items', () => { const list = parseAutorodoDraft(SAMPLE); expect(list).toHaveLength(2); expect(list[0].title).toContain('合同台账'); expect(list[0].pendings).toHaveLength(1); expect(list[0].pendings[0].raw).toContain('导出范围'); expect(list[1].pendings).toHaveLength(0); expect(list[1].confirmed).toBe(true); }); }); ``` - [ ] **Step 3: 跑测确认失败** Run: `npx vitest run src/prototypes/autorodo-web/lib/parseDraft.test.ts` Expected: FAIL(模块不存在或 `parseAutorodoDraft` 未定义) - [ ] **Step 4: 实现解析** ```ts // src/prototypes/autorodo-web/lib/parseDraft.ts import type { RequirementDraft, PendingItem, RequirementMeta } from './types'; const emptyMeta = (): RequirementMeta => ({ priority: '', tags: [], submitDept: '', submitter: '', titleKind: '', }); function parsePendings(block: string, reqIndex: number): PendingItem[] { const m = block.match(/待确认[::]\s*([\s\S]*?)(?=\n###|\n##\s*原始诉求|$)/); if (!m) return []; const body = m[1].trim(); if (!body || body === '无') return []; const lines = body .split('\n') .map((l) => l.replace(/^[-*•\d.、)\s]+/, '').trim()) .filter(Boolean); return lines.map((raw, i) => ({ id: `r${reqIndex}-p${i}`, raw, question: raw, options: [], resolved: false, })); } export function parseAutorodoDraft(md: string): RequirementDraft[] { const parts = md.split(/(?=^###\s*\d+)/m).filter((p) => /原始诉求(AutoRDO)/.test(p) || /\*\*标题\*\*/.test(p)); const chunks = parts.length > 0 ? parts : md.includes('**标题**') ? [md] : []; return chunks.map((chunk, index) => { const title = (chunk.match(/\*\*标题\*\*[::]\s*(.+)/)?.[1] ?? '').trim(); const descMatch = chunk.match(/\*\*描述\*\*[::]\s*\n?([\s\S]*?)(?=\n待确认|$)/); const description = (descMatch?.[1] ?? '').trim(); const pendings = parsePendings(chunk, index); return { index, title, description, pendings, meta: emptyMeta(), confirmed: pendings.length === 0, }; }); } ``` - [ ] **Step 5: 跑测确认通过** Run: `npx vitest run src/prototypes/autorodo-web/lib/parseDraft.test.ts` Expected: PASS - [ ] **Step 6: Commit**(仅当用户要求提交时执行;否则跳过所有 Commit 步骤) ```bash git add src/prototypes/autorodo-web/lib/types.ts src/prototypes/autorodo-web/lib/parseDraft.ts src/prototypes/autorodo-web/lib/parseDraft.test.ts git commit -m "$(cat <<'EOF' feat(autorodo-web): add AutoRDO draft parser and types EOF )" ``` --- ### Task 2: applyAnswer + pendingQuestions **Files:** - Create: `src/prototypes/autorodo-web/lib/applyAnswer.ts` - Create: `src/prototypes/autorodo-web/lib/applyAnswer.test.ts` - Create: `src/prototypes/autorodo-web/lib/pendingQuestions.ts` - [ ] **Step 1: 写回填单测** ```ts import { describe, it, expect } from 'vitest'; import { applyPendingAnswer } from './applyAnswer'; import type { RequirementDraft } from './types'; const base: RequirementDraft = { index: 0, title: '合同台账批量导出', description: '在租赁合同台账支持批量导出\n导出范围:待确认', pendings: [ { id: 'r0-p0', raw: '导出范围未说明', question: '导出范围指什么?', options: ['当前筛选结果', '全部合同', '仅勾选行'], resolved: false, }, ], meta: { priority: '', tags: [], submitDept: '', submitter: '', titleKind: '' }, confirmed: false, }; describe('applyPendingAnswer', () => { it('merges answer into description and marks pending resolved', () => { const next = applyPendingAnswer(base, 'r0-p0', '当前筛选结果'); expect(next.pendings[0].resolved).toBe(true); expect(next.pendings[0].answer).toBe('当前筛选结果'); expect(next.description).toContain('当前筛选结果'); expect(next.description).not.toMatch(/导出范围:待确认/); expect(next.confirmed).toBe(true); }); }); ``` - [ ] **Step 2: 跑测确认失败** Run: `npx vitest run src/prototypes/autorodo-web/lib/applyAnswer.test.ts` Expected: FAIL - [ ] **Step 3: 实现 applyAnswer + 简易出题** ```ts // applyAnswer.ts import type { RequirementDraft } from './types'; export function applyPendingAnswer( draft: RequirementDraft, pendingId: string, answer: string, ): RequirementDraft { const pendings = draft.pendings.map((p) => p.id === pendingId ? { ...p, resolved: true, answer: answer.trim() } : p, ); const hit = draft.pendings.find((p) => p.id === pendingId); let description = draft.description; if (hit) { const label = hit.raw.replace(/未说明|待确认|不清楚/g, '').trim() || hit.raw; if (/待确认/.test(description)) { description = description.replace(/待确认/g, answer.trim()); } else { description = `${description.replace(/\s+$/, '')}\n${label}:${answer.trim()}`; } } const confirmed = pendings.every((p) => p.resolved); return { ...draft, description, pendings, confirmed }; } // pendingQuestions.ts — MVP:关键词启发式;无匹配则「是 / 否 / 需补充」 export function buildOptionsForPending(raw: string): { question: string; options: string[] } { if (/导出范围|范围/.test(raw)) { return { question: '「导出范围」指什么?', options: ['当前筛选结果', '全部数据', '仅勾选行'], }; } if (/模块|归属/.test(raw)) { return { question: '归属哪个业务模块?', options: ['租赁合同管理', '车辆管理', '证照管理', '还车应结款'], }; } return { question: raw.endsWith('?') || raw.endsWith('?') ? raw : `${raw}?`, options: ['确认按原文理解', '暂不纳入本需求', '需文字补充'], }; } export function enrichPendingsWithQuestions(draft: RequirementDraft): RequirementDraft { return { ...draft, pendings: draft.pendings.map((p) => { const q = buildOptionsForPending(p.raw); return { ...p, question: q.question, options: q.options }; }), }; } ``` 在 `parseAutorodoDraft` 返回前对每条调用 `enrichPendingsWithQuestions`,或在 UI 粘回后统一 enrich(二选一,推荐 UI 粘回后调用,保持 parse 纯净)。 - [ ] **Step 4: 跑测确认通过** Run: `npx vitest run src/prototypes/autorodo-web/lib/applyAnswer.test.ts` Expected: PASS - [ ] **Step 5: Commit**(用户要求时) --- ### Task 3: inferMeta + buildCleanPrompt + buildRecordPrompt **Files:** - Create: `src/prototypes/autorodo-web/lib/inferMeta.ts` - Create: `src/prototypes/autorodo-web/lib/inferMeta.test.ts` - Create: `src/prototypes/autorodo-web/lib/buildCleanPrompt.ts` - Create: `src/prototypes/autorodo-web/lib/buildRecordPrompt.ts` - Create: `src/prototypes/autorodo-web/lib/buildRecordPrompt.test.ts` - Create: `src/prototypes/autorodo-web/lib/clipboard.ts` - Create: `src/prototypes/autorodo-web/lib/agentAdapter.ts` - [ ] **Step 1: inferMeta 单测** ```ts import { describe, it, expect } from 'vitest'; import { inferSubmitMeta } from './inferMeta'; describe('inferSubmitMeta', () => { it('detects dept and person from free text', () => { const r = inferSubmitMeta('业务管理组张三反馈:合同导出不好用'); expect(r.submitDept).toMatch(/业务/); expect(r.submitter).toContain('张三'); }); }); ``` - [ ] **Step 2: 实现 inferMeta** ```ts const DEPT_PATTERNS = [ /(?:提交部门|部门)[::]\s*([^\s,,;;]+)/, /(业务管理组|产品部|安全部|运营部|财务部|技术部)/, ]; const PERSON_PATTERNS = [ /(?:提交人|反馈人|提出人)[::]\s*([^\s,,;;]+)/, /@([\u4e00-\u9fa5]{2,4})/, /([\u4e00-\u9fa5]{2,4})反馈/, ]; export function inferSubmitMeta(text: string): { submitDept: string; submitter: string } { let submitDept = ''; let submitter = ''; for (const re of DEPT_PATTERNS) { const m = text.match(re); if (m?.[1]) { submitDept = m[1]; break; } } for (const re of PERSON_PATTERNS) { const m = text.match(re); if (m?.[1]) { submitter = m[1]; break; } } return { submitDept, submitter }; } ``` - [ ] **Step 3: buildRecordPrompt 单测 + 实现** ```ts // buildRecordPrompt.test.ts import { describe, it, expect } from 'vitest'; import { buildYunxiaoRecordPrompt } from './buildRecordPrompt'; import type { RequirementDraft } from './types'; const one: RequirementDraft = { index: 0, title: '合同台账批量导出', description: '在租赁合同台账支持按筛选结果批量导出 Excel', pendings: [], meta: { priority: '中', tags: ['租赁合同'], submitDept: '产品部', submitter: '王冕', titleKind: '新增', }, confirmed: true, }; describe('buildYunxiaoRecordPrompt', () => { it('includes priority tags dept submitter', () => { const text = buildYunxiaoRecordPrompt([one]); expect(text).toContain('YunxiaoPMapp'); expect(text).toContain('记录需求:【新增】合同台账批量导出'); expect(text).toContain('优先级=中'); expect(text).toContain('标签=租赁合同'); expect(text).toContain('提交部门=产品部'); expect(text).toContain('提交人=王冕'); expect(text).toContain('推进至=暂不推进'); }); it('throws when meta incomplete', () => { expect(() => buildYunxiaoRecordPrompt([{ ...one, meta: { ...one.meta, submitter: '' } }]), ).toThrow(/提交人/); }); }); ``` ```ts // buildRecordPrompt.ts import type { RequirementDraft } from './types'; export function metaComplete(d: RequirementDraft): boolean { const m = d.meta; return Boolean( m.priority && m.tags.length > 0 && m.submitDept.trim() && m.submitter.trim() && m.titleKind, ); } export function buildYunxiaoRecordPrompt(drafts: RequirementDraft[]): string { for (const d of drafts) { if (!d.confirmed) throw new Error(`需求 ${d.index + 1} 仍有未确认项`); if (!metaComplete(d)) throw new Error(`需求 ${d.index + 1} 缺少优先级/标签/提交部门/提交人/类型`); } const lines = drafts.map((d) => { const title = `【${d.meta.titleKind}】${d.title.replace(/^【(?:新增|优化)】/, '')}`; const tags = d.meta.tags.join('、'); return `记录需求:${title};描述=${d.description.replace(/\n/g, ' ')};优先级=${d.meta.priority};标签=${tags};提交部门=${d.meta.submitDept};提交人=${d.meta.submitter};推进至=暂不推进`; }); return [ 'YunxiaoPMapp', '请按下列条目依次记录需求;每条保持独立,不要合并。', '', ...lines, ].join('\n'); } ``` ```ts // buildCleanPrompt.ts export function buildCleanPrompt(payload: { text: string; attachmentNames: string[]; }): string { const files = payload.attachmentNames.length > 0 ? `附件:${payload.attachmentNames.join('、')}(请用多模态识读图/语音内容)` : '附件:无'; return [ 'AutoRDO', '请按 AutoRDO 规则清洗下列素材:多条独立诉求拆成多份;提炼标题与书面描述;不确定处标「待确认」;描述无结尾句号。', files, '', '—— 素材开始 ——', payload.text.trim() || '(仅附件,无正文)', '—— 素材结束 ——', ].join('\n'); } ``` ```ts // clipboard.ts export async function copyText(text: string): Promise { await navigator.clipboard.writeText(text); } // agentAdapter.ts export type CleanRequest = { text: string; attachmentNames: string[] }; export type RecordRequest = { drafts: import('./types').RequirementDraft[] }; /** MVP:未接组织 Agent;后续替换实现即可 */ export const agentAdapter = { async clean(_req: CleanRequest): Promise { return null; }, async record(_req: RecordRequest): Promise { return null; }, }; ``` - [ ] **Step 4: 跑全部 lib 单测** Run: `npx vitest run src/prototypes/autorodo-web/lib` Expected: 全部 PASS - [ ] **Step 5: Commit**(用户要求时) --- ### Task 4: 原型壳 + 步骤 1 UI **Files:** - Create: `src/prototypes/autorodo-web/index.tsx` - Create: `src/prototypes/autorodo-web/AutorodoWebApp.tsx` - Create: `src/prototypes/autorodo-web/style.css` - Create: `src/prototypes/autorodo-web/components/StepPaste.tsx` - Create: `src/prototypes/autorodo-web/annotation-source.json`(先最小目录) - Modify: `.axhub/make/project.json`(若启动后未出现在列表则补注册) 前置:Read `src/resources/design-system/DESIGN.md`(Token、触控 ≥44px、禁止原生 select)。 - [ ] **Step 1: 入口与主壳骨架** ```tsx // index.tsx /** * @name AutoRDO 需求清洗工作台 */ import './style.css'; import '../../../resources/design-system/oneos-ds-tokens.css'; import React from 'react'; import { PrototypeAnnotationHost } from '../../common/prototype-annotation-host'; import type { AnnotationSourceDocument } from '@axhub/annotation'; import annotationSourceDocument from './annotation-source.json'; import { AutorodoWebApp } from './AutorodoWebApp'; export default function AutorodoWebEntry() { return ( <> ); } ``` `AutorodoWebApp`:左侧步骤 1/2/3;`step` state;步骤 1 渲染 `StepPaste`。 - [ ] **Step 2: StepPaste** - contentEditable 或 textarea 接收粘贴;`onPaste` 收集 `clipboardData.files`(image/*、audio/*)为附件名列表(原型阶段可用 File.name,不上传) - 按钮「确认并复制清洗提示词」→ `buildCleanPrompt` + `copyText`;toast「已复制,请粘到 Cursor 跑 AutoRDO」 - 可选 checkbox「粘贴后自动复制」(默认关) - 控件:优先 `V2` 封装;按钮 min-height 44px - [ ] **Step 3: 本地预览** Run: 打开 Make 预览 `/prototypes/autorodo-web` Expected: 能粘贴、点确认后剪贴板为 AutoRDO 提示词 - [ ] **Step 4: Commit**(用户要求时) --- ### Task 5: 步骤 2 确认 UI **Files:** - Create: `src/prototypes/autorodo-web/components/StepConfirm.tsx` - Modify: `src/prototypes/autorodo-web/AutorodoWebApp.tsx` - [ ] **Step 1: 粘回区 + 解析** - textarea「粘回 AutoRDO 初稿」 - 按钮「解析初稿」→ `parseAutorodoDraft` → `enrichPendingsWithQuestions` → 对每条 `inferSubmitMeta(description + title)` 预填 meta - Pill 切换需求 index - [ ] **Step 2: 左右分栏确认** - 左:标题(可编辑)+ 描述(只读展示实时稿) - 右:当前未解决 pending;单选 options;补充 input;「确认并下一题」调用 `applyPendingAnswer` - 元数据:优先级四选一;标签用可增删 chip(自由输入 MVP);提交部门/提交人 input;类型 新增/优化 - 全部 confirmed 且 `metaComplete` 后可进步骤 3 - [ ] **Step 3: 手动验收路径** 1. 粘贴 Task1 SAMPLE 初稿 2. 答完题后描述含答案且无「待确认」 3. 填齐元数据 - [ ] **Step 4: Commit**(用户要求时) --- ### Task 6: 步骤 3 导出 + 样式打磨 **Files:** - Create: `src/prototypes/autorodo-web/components/StepExport.tsx` - Modify: `style.css`、`AutorodoWebApp.tsx` - [ ] **Step 1: StepExport** - 预览 `buildYunxiaoRecordPrompt(drafts)` - 「一键复制上报提示词」 - 「复制定稿 Markdown」(输出多份已确认 `## 原始诉求(AutoRDO)`,待确认:无) - 错误态:捕获 throw,页面内提示缺哪条哪字段 - [ ] **Step 2: 响应式** - ≤767px:步骤条顶置;确认区改为上下堆叠;触控 ≥44px;正文 ≥14px - [ ] **Step 3: 预览验收** 全路径走通:粘贴 → 复制清洗词 →(模拟)粘回 SAMPLE → 确认 → 复制上报词,粘贴到文本编辑器检查字段齐全。 - [ ] **Step 4: Commit**(用户要求时) --- ### Task 7: AutoPRD + 标注 + 导航同步 **Files:** - Create: `src/prototypes/autorodo-web/.spec/confirm-flow.md` - Create: `src/prototypes/autorodo-web/.spec/requirements-prd.md` - Create: `src/resources/prd/autorodo-web-autoprd.md`(与 PRD 同步) - Modify: `annotation-source.json`(产品需求说明节点) - [ ] **Step 1: 写 confirm-flow.md** 含:判定顺序表、前置条件、数据源(粘回 Markdown / 本地启发式选项)、用户可见结果、标明未接真 API。 - [ ] **Step 2: 写 requirements-prd.md** 按 oneos-autoprd 结构:总览/目标/边界/角色/用户故事(起点→运作→闭环)/验收;链到 `confirm-flow.md`。 - [ ] **Step 3: 同步标注与导航** ```bash npm run nav:sync -- --prototype autorodo-web --note "新增 AutoRDO 网页清洗与云效上报提示词工作台" ``` - [ ] **Step 4: Commit**(用户要求时) --- ### Task 8: YunxiaoPMapp 消费四字段(Skill 扩展) **Files:** - Modify: `~/.claude/skills/YunxiaoPMapp/references/commands.md`(及项目 `.cursor` / `.claude` 同步副本) - Modify: YunxiaoPMapp `SKILL.md` 记录需求参数说明 - 可选:`references/record-meta-fields.md` 新文件 - [ ] **Step 1: 文档约定口令字段** 在口令面增加: ```text 记录需求:…;优先级=紧急|高|中|低;标签=…;提交部门=…;提交人=…;推进至=… ``` 说明:网页上报词已带齐时,**禁止**再 Plan 重复问这四项(除非缺省);缺省则仍问。 - [ ] **Step 2: 实现侧** 若现有 live 脚本已支持 priority/tag:把提交部门/提交人映射到云效字段(查 `runtime-ids.json`;未验证字段则先写入描述尾部 `提交部门/提交人`,并在文档标明「字段 ID 待验证」)。 - [ ] **Step 3: 与网页联调** 用步骤 3 复制出的提示词在 Cursor 跑一次「记录需求」(测试项目或 dry-run 策略按团队惯例)。 - [ ] **Step 4: Commit**(用户要求时) --- ## 规格覆盖自检 | Spec 要求 | Task | |-----------|------| | 粘贴文/图/语音 + 复制清洗词 | 4 | | 粘回初稿 + 分页确认 + 回填 | 1,2,5 | | 优先级/标签/部门/提交人 | 3,5,6 | | 一键 Yunxiao 多条口令 | 3,6 | | 预留组织 Agent | 3 `agentAdapter` | | AutoPRD / 业务规则文档 | 7 | | Yunxiao 消费四字段 | 8 | | 不直连云效 / 无 OCR | 全程遵守 | --- ## 执行说明 - 所有 **Commit 步骤默认跳过**,除非用户明确要求提交。 - Task 8 可与 Task 4–7 并行由另一会话做;网页 MVP 以 Task 1–7 为可演示闭环(上报词已含四字段,即使 Skill 暂未写入云效自定义字段,口令仍可用于人工/后续 Skill)。 --- Plan complete and saved to `docs/superpowers/plans/2026-07-25-autorodo-web.md`. **两种执行方式:** 1. **Subagent-Driven(推荐)** — 每任务开新子代理,任务间复核,迭代快 2. **Inline Execution** — 本会话按 executing-plans 连续执行,设检查点 要哪一种?