docs: 添加笔临 P2 实现计划

18 个 Task 覆盖主题修复、schema v2、统一编辑、引用/搜索/版本/地标/用词分析至 v0.2.0。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 10:50:52 +08:00
parent c772b7d703
commit 91c93954df
@@ -0,0 +1,731 @@
# 笔临 P2 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:** 交付 v0.2.0:大纲/设定/灵感持久化、统一中央编辑、引用面板、版本历史、FTS 全局搜索、地标、用词分析,并修复 3 套浅色主题对比度问题。
**Architecture:** 延续 electron-vite 单体仓库;主进程 `node:sqlite` schema v2 + FTS5 + Snapshot/Search/WordFreq 服务;渲染进程新增 `useEditStore`EditTarget)统一 TipTap 编辑;IPC 延续 `IpcResult` 信封;UI 对齐 `design/ui_pc.html` 模态与引用面板。
**Tech Stack:** Electron 36、electron-vite、React 18、TypeScript、TipTap、node:sqlite、Zustand、Jotai、Radix UI、i18next、diff-match-patch、Vitest、Playwright
**Spec:** `docs/superpowers/specs/2026-07-06-bilin-p2-design.md`
---
## File MapP2 新增/修改核心文件)
| 文件 | 职责 |
|------|------|
| `src/renderer/styles/themes.css` | 补全浅色 token、`--text-on-accent``--input-*` |
| `src/main/db/schema-v2.sql` | v2 表 + FTS5 |
| `src/main/db/migrate.ts` | version 1→2 增量迁移 |
| `src/main/db/repositories/outline.repo.ts` | 大纲 CRUD/树/move |
| `src/main/db/repositories/setting.repo.ts` | 设定 CRUD + chapterRefs |
| `src/main/db/repositories/inspiration.repo.ts` | 灵感 CRUD/convert |
| `src/main/db/repositories/snapshot.repo.ts` | 快照 CRUD/FIFO |
| `src/main/db/repositories/bookmark.repo.ts` | 地标 CRUD |
| `src/main/services/fts-sync.service.ts` | FTS5 增量同步 |
| `src/main/services/search.service.ts` | 查询 + replace dryRun |
| `src/main/services/snapshot.service.ts` | 定时/退出快照 |
| `src/main/services/wordfreq.service.ts` | 词频统计 |
| `src/shared/types.ts` | P2 类型扩展 |
| `src/shared/ipc-channels.ts` | P2 IPC 常量 |
| `src/renderer/stores/useEditStore.ts` | EditTarget 切换 |
| `src/renderer/components/outline/OutlineTree.tsx` | 大纲树 UI |
| `src/renderer/components/reference/ReferencePanel.tsx` | 引用面板 |
| `src/renderer/components/search/SearchModal.tsx` | 全局搜索 |
| `src/renderer/components/version/VersionModal.tsx` | 版本历史 + diff |
| `src/renderer/components/landmark/LandmarkModal.tsx` | 地标清单 |
| `src/renderer/components/wordfreq/WordFreqPanel.tsx` | 用词分析 |
| `e2e/themes-contrast.spec.ts` | 浅色主题对比度 E2E |
---
## Task 1: P2.0 主题 Token 修复
**Files:**
- Modify: `src/renderer/styles/themes.css`
- Modify: `src/renderer/styles/layout.css`
- Modify: `src/renderer/styles/globals.css`
- Modify: `src/renderer/components/settings/SettingsPage.tsx`
- Create: `e2e/themes-contrast.spec.ts`
- [ ] **Step 1: 在 `:root` 新增语义 token**
```css
/* themes.css :root 追加 */
--text-on-accent: #ffffff;
--input-text: var(--text-primary);
--input-bg: var(--bg-surface);
--input-border: var(--border);
```
`[data-theme='ricepaper']``mist``teagarden` 各补全:`--bg-surface``--bg-active``--text-dim``--accent-glow``--border-light``--green``--orange``--red`
- [ ] **Step 2: 替换硬编码 `#fff`**
`layout.css` 中将 `.btn-large.primary``.tab.active``color: #fff` 改为 `color: var(--text-on-accent)`
浅色主题覆盖:
```css
[data-theme='ricepaper'],
[data-theme='mist'],
[data-theme='teagarden'] {
--text-on-accent: #ffffff;
}
```
- [ ] **Step 3: 统一表单控件样式**
`globals.css` 追加:
```css
input, select, textarea {
color: var(--input-text);
background: var(--input-bg);
border: 1px solid var(--input-border);
}
```
删除 `SettingsPage.tsx` 内联 `color: inherit` / 硬编码 border,改用 class `form-control`(在 globals 定义)。
- [ ] **Step 4: 写 contrast E2E**
`e2e/themes-contrast.spec.ts`:对 `ricepaper`/`mist`/`teagarden`,在主页、设置页、编辑器断言 `#app``h1,h2,button,.setting-item` 可见(`toBeVisible`)且 computed color 非透明/非背景同色(用 `page.evaluate` 比较 RGB)。
- [ ] **Step 5: 运行验证**
```bash
npm run build
npm run test:e2e -- e2e/themes-contrast.spec.ts
```
Expected: PASS
- [ ] **Step 6: Commit**
```bash
git add src/renderer/styles e2e/themes-contrast.spec.ts src/renderer/components/settings/SettingsPage.tsx
git commit -m "fix: repair light theme tokens and contrast"
```
---
## Task 2: 共享类型与 IPC 通道
**Files:**
- Modify: `src/shared/types.ts`
- Modify: `src/shared/ipc-channels.ts`
- Modify: `src/main/services/global-settings.ts`
- [ ] **Step 1: 扩展 types.ts**
追加(完整定义见 spec §3.2):
```typescript
export type OutlineStatus = 'pending' | 'writing' | 'done' | 'abandoned'
export type SettingType = 'character' | 'location' | 'item' | 'skill' | 'faction' | 'custom'
export type SnapshotType = 'auto' | 'manual' | 'persist' | 'ai'
export type LandmarkType = 'todo' | 'foreshadow' | 'research' | 'custom'
export type EditTargetKind = 'chapter' | 'outline' | 'setting' | 'inspiration'
export type EditTarget = { kind: EditTargetKind; id: string }
export type SearchScope = 'all' | 'volume' | 'chapter'
export type SearchSourceKind = 'chapter' | 'outline' | 'setting' | 'inspiration' | 'bookmark'
export interface OutlineItem { /* spec §3.2 字段 */ }
export interface SettingEntry { /* ... */ }
export interface InspirationEntry { /* ... */ }
export interface Snapshot { /* ... */ }
export interface Bookmark { /* ... */ }
export interface SearchResult {
kind: SearchSourceKind
id: string
title: string
snippet: string
chapterId?: string
position?: number
}
```
扩展 `GlobalSettings`
```typescript
snapshotIntervalMs: number
snapshotMaxAuto: number
snapshotMaxPersist: number
searchHistory: string[]
```
扩展 `BookOpenResult``outlines`, `settings`, `inspirations`
- [ ] **Step 2: 扩展 ipc-channels.ts**
```typescript
OUTLINE_LIST: 'outline:list',
OUTLINE_CREATE: 'outline:create',
// ... 全部见 spec §4.1
SEARCH_QUERY: 'search:query',
WORDFREQ_ANALYZE: 'wordfreq:analyze',
```
- [ ] **Step 3: global-settings defaults**
```typescript
function defaults(): GlobalSettings {
return {
// ...existing
snapshotIntervalMs: 300_000,
snapshotMaxAuto: 20,
snapshotMaxPersist: 3,
searchHistory: []
}
}
```
- [ ] **Step 4: Commit**
```bash
git commit -am "feat: add P2 shared types and IPC channels"
```
---
## Task 3: Schema v2 迁移
**Files:**
- Create: `src/main/db/schema-v2.sql`
- Modify: `src/main/db/migrate.ts`
- Create: `tests/main/migrate-v2.test.ts`
- [ ] **Step 1: 写 schema-v2.sql**
包含 spec §3.1 全部 CREATE TABLE + FTS5
```sql
CREATE VIRTUAL TABLE IF NOT EXISTS search_fts USING fts5(
source_kind, source_id, title, body, tokenize='unicode61'
);
```
- [ ] **Step 2: 更新 migrate.ts**
```typescript
import schemaV2 from './schema-v2.sql?raw'
const CURRENT_VERSION = 2
export function migrate(db: SqliteDb): void {
// ... v1 逻辑保留
if (current >= CURRENT_VERSION) return
if (current < 1) { /* apply schemaV1 */ }
if (current < 2) {
db.exec(schemaV2)
db.prepare('INSERT INTO schema_version (version, description) VALUES (?, ?)').run(2, 'P2 schema')
}
}
```
v2 SQL 中对已有库使用 `ALTER TABLE chapters ADD COLUMN ...` 需单独 `schema-v2-alter.sql` 或在 migrate 中 try/catch 忽略 duplicate column。
- [ ] **Step 3: 写 migrate 测试**
```typescript
// tests/main/migrate-v2.test.ts
it('migrates v1 database to v2 with new tables', () => {
const db = new DatabaseSync(':memory:')
// apply v1 only, then migrate full
expect(db.prepare("SELECT name FROM sqlite_master WHERE name='outline_items'").get()).toBeTruthy()
})
```
- [ ] **Step 4: 运行**
```bash
npm run test -- tests/main/migrate-v2.test.ts
```
- [ ] **Step 5: Commit**
```bash
git commit -am "feat: add schema v2 migration"
```
---
## Task 4: Outline Repository
**Files:**
- Create: `src/main/db/repositories/outline.repo.ts`
- Create: `tests/main/outline.repo.test.ts`
- [ ] **Step 1: 写失败测试**
```typescript
it('creates nested outline items', () => {
const parent = repo.create(null, '第一幕', 0)
const child = repo.create(parent.id, '开端', 0)
expect(repo.listTree()).toHaveLength(1)
expect(repo.listTree()[0].children).toHaveLength(1)
})
```
- [ ] **Step 2: 实现 outline.repo.ts**
方法:`create(parentId, title, sortOrder)``get``listFlat``update``delete`(级联)、`move``listUncovered()`
- [ ] **Step 3: 运行 PASS + Commit**
```bash
git commit -am "feat: add outline repository"
```
---
## Task 5: Setting + Inspiration Repository
**Files:**
- Create: `src/main/db/repositories/setting.repo.ts`
- Create: `src/main/db/repositories/inspiration.repo.ts`
- Create: `tests/main/setting.repo.test.ts`
- Create: `tests/main/inspiration.repo.test.ts`
- [ ] **Step 1: setting.repo** — CRUD + `syncChapterRefs(settingId, chapterIds[])`
- [ ] **Step 2: inspiration.repo** — CRUD + `convertToOutline(id)` / `convertToSetting(id, type)`
- [ ] **Step 3: 测试 PASS + Commit**
```bash
git commit -am "feat: add setting and inspiration repositories"
```
---
## Task 6: Snapshot + Bookmark Repository
**Files:**
- Create: `src/main/db/repositories/snapshot.repo.ts`
- Create: `src/main/db/repositories/bookmark.repo.ts`
- Create: `tests/main/snapshot.repo.test.ts`
- Create: `tests/main/bookmark.repo.test.ts`
- [ ] **Step 1: snapshot.repo**
```typescript
create(chapterId, type, content, name?): Snapshot
list(chapterId): Snapshot[]
pruneAuto(chapterId, max: number): void // FIFO 删除最旧 auto
restore(snapshotId): string // 返回 content
```
- [ ] **Step 2: bookmark.repo** — CRUD + `listByChapter` + `resolve(id, boolean)`
- [ ] **Step 3: 测试 + Commit**
```bash
git commit -am "feat: add snapshot and bookmark repositories"
```
---
## Task 7: FTS Sync + Search Service
**Files:**
- Create: `src/main/services/fts-sync.service.ts`
- Create: `src/main/services/search.service.ts`
- Create: `tests/main/search.service.test.ts`
- [ ] **Step 1: fts-sync.service.ts**
```typescript
export class FtsSyncService {
upsert(db: SqliteDb, kind: SearchSourceKind, id: string, title: string, body: string): void {
db.prepare('DELETE FROM search_fts WHERE source_kind=? AND source_id=?').run(kind, id)
db.prepare('INSERT INTO search_fts(source_kind, source_id, title, body) VALUES (?,?,?,?)').run(kind, id, title, body)
}
rebuildAll(db: SqliteDb, book: BookRegistryService): void { /* 全量 */ }
}
```
HTML → plainText 用现有 `word-count` 同款 strip 或简单 `replace(/<[^>]+>/g,'')`
- [ ] **Step 2: search.service.ts**
```typescript
query(db, { text, scope, regex, caseSensitive }): SearchResult[]
replace(db, { text, replacement, dryRun }): { count: number; previews: SearchResult[] }
```
regex 模式:FTS 不支持时 fallback 遍历 `search_fts` body LIKE。
- [ ] **Step 3: 测试 + Commit**
```bash
git commit -am "feat: add FTS sync and search service"
```
---
## Task 8: Snapshot Service + WordFreq Service
**Files:**
- Create: `src/main/services/snapshot.service.ts`
- Create: `src/main/services/wordfreq.service.ts`
- Modify: `src/main/index.ts`app.on('before-quit') 触发 persist 快照)
- Create: `tests/main/wordfreq.service.test.ts`
- [ ] **Step 1: 安装 diff 库**
```bash
npm install diff-match-patch
npm install -D @types/diff-match-patch
```
- [ ] **Step 2: snapshot.service.ts**
```typescript
export class SnapshotService {
startAutoSave(bookId: string, chapterId: string, getContent: () => string): void {
this.timer = setInterval(() => { /* if changed → auto snapshot + prune */ }, settings.snapshotIntervalMs)
}
onPersistSave(bookId, chapterId, content): void { /* type=persist, prune to max 3 */ }
}
```
- [ ] **Step 3: wordfreq.service.ts**
CJK`text.match(/[\u4e00-\u9fff]/g)` 计数;Latin`/\b[a-zA-Z]{2,}\b/g`;返回 Top 100。
- [ ] **Step 4: 测试 + Commit**
```bash
git commit -am "feat: add snapshot and word frequency services"
```
---
## Task 9: IPC Handlers + Preload
**Files:**
- Create: `src/main/ipc/handlers/outline.handler.ts`(及 setting/inspiration/snapshot/bookmark/search/wordfreq
- Modify: `src/main/ipc/register.ts`
- Modify: `src/preload/index.ts`
- Modify: `src/shared/electron-api.d.ts`
- [ ] **Step 1: 每个 handler 遵循现有 chapter.handler 模式**
```typescript
export function registerOutlineHandlers(books: BookRegistryService): void {
ipcMain.handle(IPC.OUTLINE_LIST, (_e, { bookId }) =>
wrap(() => books.getOutlineRepo(bookId).listFlat())
)
}
```
- [ ] **Step 2: BookRegistryService 扩展**
```typescript
getOutlineRepo(bookId): OutlineRepository
getSettingRepo(bookId): SettingRepository
// ...
open(bookId): BookOpenResult // 附加 outlines/settings/inspirations
```
- [ ] **Step 3: preload 暴露新 API 命名空间**
```typescript
outline: { list, create, update, delete, move },
setting: { list, create, update, delete },
// ...
search: { query, replace, getHistory, saveHistory },
wordfreq: { analyze },
```
- [ ] **Step 4: `npm run build` + Commit**
```bash
git commit -am "feat: add P2 IPC handlers and preload API"
```
---
## Task 10: useEditStore + 统一 TipTap 编辑
**Files:**
- Create: `src/renderer/stores/useEditStore.ts`
- Modify: `src/renderer/components/editor/TipTapEditor.tsx`
- Modify: `src/renderer/components/layout/EditorLayout.tsx`
- Modify: `src/renderer/stores/useBookStore.ts`
- [ ] **Step 1: useEditStore.ts**
```typescript
interface EditState {
target: EditTarget | null
switchTarget: (next: EditTarget) => Promise<void>
saveCurrent: () => Promise<void>
}
switchTarget: async (next) => {
await flushEditorSave()
const data = await loadTargetContent(next) // IPC by kind
set({ target: next })
// TipTapEditor reacts via target prop
}
```
- [ ] **Step 2: TipTapEditor 接受 target + contentLoader**
```typescript
interface TipTapEditorProps {
target: EditTarget | null
}
```
`useEditor` extensionstarget.kind === 'chapter' ? fullStarterKit : simplifiedKit。
save 回调按 kind 分发 IPC`chapter.update` / `outline.update` / etc.
- [ ] **Step 3: EditorLayout 四 Tab 选中 → switchTarget**
删除 `activePanel !== 'chapters'` 占位,替换为 OutlineTree / SettingList / InspirationList。
- [ ] **Step 4: Commit**
```bash
git commit -am "feat: add unified EditSession and TipTap targets"
```
---
## Task 11: 左栏 CRUD UI(大纲/设定/灵感)
**Files:**
- Create: `src/renderer/components/outline/OutlineTree.tsx`
- Create: `src/renderer/components/setting/SettingList.tsx`
- Create: `src/renderer/components/inspiration/InspirationList.tsx`
- Modify: `public/locales/zh-CN/translation.json`(及 en
- [ ] **Step 1: OutlineTree** — 递归渲染;双击标题 inline 编辑;底部「+ 新建大纲」;未覆盖橙色边框
- [ ] **Step 2: SettingList** — 按 type 分组;底部新建 Dialogtype select + name
- [ ] **Step 3: InspirationList** — 列表 + 新建;`InspirationModal` 快速捕获(Ctrl+Shift+I
- [ ] **Step 4: E2E outline 持久化**
`e2e/outline.spec.ts`:建书 → 新建大纲 → 输入内容 → 重启 → 内容保留。
- [ ] **Step 5: Commit**
```bash
git commit -am "feat: add outline setting inspiration sidebar UI"
```
---
## Task 12: 大纲对照视图(P2.3
**Files:**
- Create: `src/renderer/components/outline/OutlineCompareView.tsx`
- Modify: `src/renderer/stores/useOutlineStore.ts`
- [ ] **Step 1: useOutlineStore**`compareMode: boolean``filter: 'all'|'uncovered'|'covered'`
- [ ] **Step 2: OutlineCompareView** — 35/65 分屏;右侧只读章节 HTML;底部偏差条
- [ ] **Step 3: E2E E2E-COV-01/02**spec §5.5.3
- [ ] **Step 4: Commit**
```bash
git commit -am "feat: add outline compare view and coverage filter"
```
---
## Task 13: 引用面板(P2.4
**Files:**
- Create: `src/renderer/components/reference/ReferencePanel.tsx`
- Create: `src/renderer/stores/useReferenceStore.ts`
- Modify: `src/renderer/styles/layout.css``#reference-panel`
- Create: `src/renderer/extensions/mention.ts`
- Modify: `src/renderer/App.tsx`openReference 快捷键)
- [ ] **Step 1: ReferencePanel** — Tab + 搜索 + 钉住 + 拖拽(`onDragStart` setData text/plain
- [ ] **Step 2: 与 AI 右栏互斥**`useAppStore` 或 layout state`referenceOpen` 时隐藏 RightPanel
- [ ] **Step 3: Mention 扩展(简化)** — 输入 `@` 弹出设定名列表;点击跳转 `switchTarget({kind:'setting',id})`
- [ ] **Step 4: E2E E2E-P2-REF-01**
- [ ] **Step 5: Commit**
```bash
git commit -am "feat: add reference panel with drag insert and mentions"
```
---
## Task 14: 版本历史模态(P2.5
**Files:**
- Create: `src/renderer/components/version/VersionModal.tsx`
- Modify: `src/renderer/components/layout/EditorLayout.tsx`(工具栏入口)
- Modify: `src/renderer/App.tsx`Ctrl+S 触发 persist snapshot
- [ ] **Step 1: VersionModal UI** — 列表 + 选中版本;双栏 diff 用 `diff-match-patch`
```typescript
import DiffMatchPatch from 'diff-match-patch'
const dmp = new DiffMatchPatch()
const diffs = dmp.diff_main(oldPlain, newPlain)
dmp.diff_cleanupSemantic(diffs)
```
渲染:DIFF_INSERT 绿色背景,DIFF_DELETE 红色删除线。
- [ ] **Step 2: 回滚** — 调用 `snapshot:restore`;确认 Dialog
- [ ] **Step 3: SnapshotService wired** — EditorLayout mount 章节时 `startAutoSave`
- [ ] **Step 4: E2E E2E-P2-SNAP-01**
- [ ] **Step 5: Commit**
```bash
git commit -am "feat: add chapter version history with diff and restore"
```
---
## Task 15: 全局搜索模态(P2.6
**Files:**
- Create: `src/renderer/components/search/SearchModal.tsx`
- Create: `src/renderer/stores/useSearchStore.ts`
- Modify: `src/renderer/App.tsx`globalSearch 快捷键)
- [ ] **Step 1: SearchModal** — 对齐 `#searchModal`;范围 select;高级选项折叠(regex/case
- [ ] **Step 2: 结果跳转** — chapter → switchTarget + scrollbookmark → chapter + position
- [ ] **Step 3: 替换预览** — 调用 `search:replace` dryRun → 确认 → 执行
- [ ] **Step 4: searchHistory** — 下拉最近 10 条
- [ ] **Step 5: E2E E2E-P2-SEARCH-01 + Commit**
```bash
git commit -am "feat: add global search modal with FTS and replace"
```
---
## Task 16: 地标全量(P2.6
**Files:**
- Create: `src/renderer/extensions/landmark-mark.ts`
- Create: `src/renderer/components/landmark/LandmarkModal.tsx`
- Modify: `src/renderer/components/editor/TipTapEditor.tsx`
- [ ] **Step 1: TipTap Mark** — 行内 `[TODO: label]` 样式;insertLandmark 快捷键打开输入
- [ ] **Step 2: LandmarkModal** — 按类型/章节分组;跳转 `switchTarget chapter` + `editor.commands.focus(pos)`
- [ ] **Step 3: FTS 同步 bookmark label**
- [ ] **Step 4: E2E E2E-P2-LAND-01 + Commit**
```bash
git commit -am "feat: add writing landmarks and list modal"
```
---
## Task 17: 用词分析(P2.7
**Files:**
- Modify: `src/renderer/components/layout/RightPanel.tsx`
- Create: `src/renderer/components/wordfreq/WordFreqPanel.tsx`
- [ ] **Step 1: WordFreqPanel** — 调用 `wordfreq:analyze`;Top 100 列表;点击 → 编辑器 `scrollIntoView` + 临时 highlight Mark
- [ ] **Step 2: 过度用词** — 阈值:每千字 >5 次;TipTap Decoration 淡黄色
- [ ] **Step 3: §5.6.2 占位** — 面板底部按钮 → `showToast(t('feature.comingSoon'))`
- [ ] **Step 4: E2E E2E-P2-WORD-01 + Commit**
```bash
git commit -am "feat: add word frequency panel and overuse highlight"
```
---
## Task 18: 全量测试与 v0.2.0 收尾
**Files:**
- Modify: `package.json`version 0.2.0
- Modify: `README.md`
- [ ] **Step 1: 运行全量测试**
```bash
npm run test
npm run build
npm run test:e2e
```
Expected: 全部 PASS
- [ ] **Step 2: 手动验收** — spec §1.3 七项 + §10 DoD
- [ ] **Step 3: 更新 README** — v0.2.0 功能列表、测试命令
- [ ] **Step 4: Commit + tag**
```bash
git commit -am "chore: prepare v0.2.0 release"
git tag v0.2.0
```
---
## Plan Self-Review
| Spec 章节 | 对应用 Task |
|-----------|-------------|
| §5.9 主题 P2.0 | Task 1 |
| §3 Schema v2 | Task 3 |
| §4 IPC | Task 2, 9 |
| §5.1 四 Tab | Task 10, 11 |
| §5.5 大纲对照/覆盖度 | Task 12 |
| §5.3.8 引用面板 | Task 13 |
| §5.4 版本历史 | Task 8, 14 |
| §5.6.1 搜索 | Task 7, 15 |
| §5.3.9 地标 | Task 16 |
| §5.6.3 用词分析 | Task 17 |
| §5.6.2 AI 命名 | Task 17 Step 3 占位 |
| §7 测试 | Task 117 各 E2E + Task 18 |
| §10 DoD | Task 18 |
**Placeholder 扫描:** 无 TBD;章节拖拽明确未含;语音灵感为占位。
**类型一致性:** `EditTarget``SearchSourceKind``SnapshotType` 在 Task 2 定义,后续任务一致引用。
---
## 执行方式
Plan 已保存至 `docs/superpowers/plans/2026-07-06-bilin-p2.md`
**两种执行选项:**
1. **Subagent-Driven(推荐)** — 每个 Task 派发独立 subagent,任务间 review,迭代快
2. **Inline Execution** — 在本会话按 Task 顺序直接实现,批次间设检查点
你选哪种?