Covers schema v9, book settings, volume/chapter management UI, template context, AI session menu, focus mode, and TTS per master completion spec. Co-authored-by: Cursor <cursoragent@cursor.com>
16 KiB
笔临 Wave 1 基础治理 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: 交付 v1.2.0:清除 Wave 1 范围内全部 comingSoon 占位,补全书籍/分卷/章节管理 UI,模板变量自动填充,AI 会话管理,专注模式与 TTS 快捷键。
Architecture: schema v9 扩展 chapter_tags / published_at / book_preferences.always_show_cockpit;扩展 BookMeta 与 BOOK_UPDATE_META;渲染进程新增 BookSettingsTab、FocusMode overlay、ChapterMetaPanel;复用已有 volume.* / chapter.delete IPC;chapter-template 上下文从 outlines/settings 聚合。
Tech Stack: Electron 36、electron-vite、React 18、TypeScript、node:sqlite、Zustand、i18next、Vitest、Playwright
Spec: docs/superpowers/specs/2026-07-08-bilin-master-completion-design.md §5
Master Program: Wave 1/5 → v1.2.0
File Map
| 文件 | 职责 |
|---|---|
src/main/db/schema-v9.sql |
chapter_tags 表 |
src/main/db/migrate.ts |
CURRENT_VERSION=9,published_at/word_count_threshold |
src/main/db/repositories/chapter-tag.repo.ts |
章节标签 CRUD |
src/main/db/repositories/chapter.repo.ts |
published_at、summary、story_time、threshold 读写 |
src/main/services/book-registry.ts |
updateMeta 扩展 name/category/targetWordCount/coverPath/synopsis |
src/main/services/cockpit.service.ts |
always_show_cockpit 逻辑 |
src/main/ipc/handlers/book.handler.ts |
BOOK_UPDATE_META 扩展 |
src/main/ipc/handlers/chapter.handler.ts |
CHAPTER_TAG_*、published_at on setPublishStatus |
src/main/ipc/handlers/ai.handler.ts |
AI_SESSION_EXPORT |
src/shared/types.ts |
BookMeta、UpdateBookMetaParams、ChapterTag |
src/shared/ipc-channels.ts |
新 IPC 常量 |
src/preload/index.ts + electron-api.d.ts |
bookPrefs、chapterTags、sessionExport |
src/shared/chapter-template.ts |
buildTemplateContext() 含 outlineItem/characterList |
src/renderer/components/book/BookSettingsTab.tsx |
右栏书籍设置 |
src/renderer/components/chapter/ChapterMetaPanel.tsx |
summary/story_time/tags |
src/renderer/components/volume/VolumeContextMenu.tsx |
分卷右键 |
src/renderer/components/focus/FocusModeOverlay.tsx |
专注模式 |
src/renderer/lib/tts-controller.ts |
TTS 朗读 |
src/renderer/components/layout/RightPanel.tsx |
接入 BookSettingsTab |
src/renderer/components/layout/EditorLayout.tsx |
章双击改名、删除、meta、阈值变色 |
src/renderer/components/layout/TopBar.tsx |
日更进度条(细条) |
src/renderer/components/ai/AiSessionMenu.tsx |
会话重命名/归档/导出/删除 |
src/renderer/components/ai/AiPanel.tsx |
接入 AiSessionMenu |
src/renderer/components/wordfreq/WordFreqPanel.tsx |
命名检查入口 |
src/renderer/App.tsx |
focusMode / toggleTTS 快捷键 |
src/renderer/stores/useBookPrefsStore.ts |
alwaysShowCockpit |
public/locales/*/translation.json |
bookSettings / chapterMeta / focus / tts |
tests/main/chapter-template-context.test.ts |
UT outlineItem/characterList |
tests/main/chapter-tag.repo.test.ts |
IT 标签 |
e2e/book-settings.spec.ts |
E2E 书籍设置+删书 |
e2e/chapter-management.spec.ts |
E2E 章改名+删除 |
e2e/focus-tts.spec.ts |
E2E 专注+TTS |
e2e/chapter-template.spec.ts |
扩展 E2E-TEMPL-05 |
Task 1: Schema v9 + 类型扩展
Files:
-
Create:
src/main/db/schema-v9.sql -
Modify:
src/main/db/migrate.ts -
Modify:
src/shared/types.ts -
Modify:
src/shared/ipc-channels.ts -
Step 1: schema-v9.sql
CREATE TABLE IF NOT EXISTS chapter_tags (
chapter_id TEXT NOT NULL,
tag TEXT NOT NULL,
color TEXT DEFAULT '',
PRIMARY KEY (chapter_id, tag),
FOREIGN KEY (chapter_id) REFERENCES chapters(id) ON DELETE CASCADE
);
- Step 2: migrate.ts —
CURRENT_VERSION = 9,新增 block:
if (current < 9) {
tryAlter(db, 'ALTER TABLE chapters ADD COLUMN published_at TEXT DEFAULT NULL')
tryAlter(db, 'ALTER TABLE chapters ADD COLUMN word_count_threshold INTEGER DEFAULT NULL')
db.exec(schemaV9)
db.prepare('INSERT INTO schema_version (version, description) VALUES (?, ?)').run(9, 'W1 foundation')
}
- Step 3: types.ts — 扩展:
export interface BookMeta {
// existing...
coverPath?: string | null
synopsis?: string
}
export interface UpdateBookMetaParams {
name?: string
category?: string
targetWordCount?: number | null
coverPath?: string | null
synopsis?: string
lastChapterId?: string | null
status?: BookStatus
}
export interface ChapterTag {
chapterId: string
tag: string
color: string
}
// Chapter 已有 summary?, storyTime? — 确保 chapter.update IPC 接受它们
- Step 4: ipc-channels.ts
CHAPTER_TAG_LIST: 'chapter:tagList',
CHAPTER_TAG_SET: 'chapter:tagSet',
CHAPTER_TAG_REMOVE: 'chapter:tagRemove',
BOOK_PREFS_GET: 'book:prefsGet',
BOOK_PREFS_SET: 'book:prefsSet',
AI_SESSION_EXPORT: 'ai:sessionExport',
- Step 5: 运行
npm run build— 应通过
Task 2: Repository + BookRegistry 扩展
Files:
-
Create:
src/main/db/repositories/chapter-tag.repo.ts -
Modify:
src/main/db/repositories/chapter.repo.ts -
Modify:
src/main/services/book-registry.ts -
Modify:
src/main/services/cockpit.service.ts -
Step 1: ChapterTagRepository
export class ChapterTagRepository {
constructor(private db: SqliteDb) {}
list(chapterId: string): ChapterTag[] { /* SELECT */ }
set(chapterId: string, tag: string, color = ''): void { /* INSERT OR REPLACE */ }
remove(chapterId: string, tag: string): void { /* DELETE */ }
listAll(): ChapterTag[] { /* for book open */ }
}
- Step 2: chapter.repo update —
update()与setPublishStatus()支持summary,storyTime,wordCountThreshold,publishedAt:
setPublishStatus(id: string, publishStatus: PublishStatus): Chapter {
const patch: Parameters<typeof this.update>[1] = { publishStatus }
if (publishStatus === 'published') {
patch.publishedAt = new Date().toISOString()
}
return this.update(id, patch)
}
-
Step 3: book-registry.updateMeta — 签名改为
Partial<Pick<BookMeta, 'name' | 'category' | 'targetWordCount' | 'coverPath' | 'synopsis' | 'lastOpenedAt' | 'lastChapterId' | 'status'>> -
Step 4: cockpit.service
shouldShowOnOpen(): boolean {
const prefs = new BookPrefsRepository(this.db)
if (prefs.get('alwaysShowCockpit') === 'true') return true
return prefs.get('cockpitSeen') !== 'true'
}
- Step 5: UT
tests/main/chapter-tag.repo.test.ts— 创建章+标签+列表
Run: npm run test -- --run tests/main/chapter-tag.repo.test.ts
Task 3: IPC handlers + preload
Files:
-
Modify:
src/main/ipc/handlers/book.handler.ts -
Modify:
src/main/ipc/handlers/chapter.handler.ts -
Create:
src/main/ipc/handlers/book-prefs.handler.ts -
Modify:
src/main/ipc/handlers/ai.handler.ts -
Modify:
src/main/ipc/register.ts -
Modify:
src/preload/index.ts -
Modify:
src/shared/electron-api.d.ts -
Step 1: book.handler —
BOOK_UPDATE_META接受UpdateBookMetaParams -
Step 2: chapter.handler — 扩展
CHAPTER_UPDATE接受summary,storyTime,wordCountThreshold;新增:
ipcMain.handle(IPC.CHAPTER_TAG_LIST, (_e, { bookId, chapterId }) =>
wrap(() => new ChapterTagRepository(registry.getDb(bookId)).list(chapterId)))
// TAG_SET / TAG_REMOVE 同理
- Step 3: book-prefs.handler
ipcMain.handle(IPC.BOOK_PREFS_GET, (_e, { bookId, key }) =>
wrap(() => new BookPrefsRepository(registry.getDb(bookId)).get(key)))
ipcMain.handle(IPC.BOOK_PREFS_SET, (_e, { bookId, key, value }) =>
wrap(() => { new BookPrefsRepository(registry.getDb(bookId)).set(key, value) }))
-
Step 4: ai.handler —
AI_SESSION_EXPORT:读 messages,格式化 markdown,dialog.showSaveDialog,写文件 -
Step 5: preload —
book.updateMeta扩展;bookPrefs.get/set;chapterTag.list/set/remove;ai.session.export(bookId, sessionId, format) -
Step 6: build
npm run build
Task 4: 模板上下文 enrich
Files:
-
Modify:
src/shared/chapter-template.ts -
Modify:
src/renderer/components/chapter/TemplateQuickCreateModal.tsx -
Create:
tests/main/chapter-template-context.test.ts -
Step 1: 新增
buildTemplateContext()
export function buildTemplateContext(input: {
chapterTitle: string
penName: string
volumes: Volume[]
chapters: Chapter[]
outlines: OutlineItem[]
settings: SettingEntry[]
activeVolumeId: string | null
selectedChapterId?: string | null
}): TemplateContext {
const volChapters = input.chapters
.filter((c) => c.volumeId === input.activeVolumeId)
.sort((a, b) => a.sortOrder - b.sortOrder)
const chapterNumber = volChapters.length + 1
const outlineItem =
input.outlines.find((o) => o.chapterId === input.selectedChapterId)?.title ?? ''
const characterList = input.settings
.filter((s) => s.type === 'character')
.slice(0, 8)
.map((s) => s.name)
.join('、')
return {
chapterNumber,
chapterTitle: input.chapterTitle,
penName: input.penName,
date: new Date().toLocaleDateString('zh-CN'),
volumeName: input.volumes.find((v) => v.id === input.activeVolumeId)?.name ?? '',
previousChapterTitle: volChapters.at(-1)?.title ?? '',
outlineItem,
characterList
}
}
-
Step 2: TemplateQuickCreateModal — 用
buildTemplateContext替换内联buildContext -
Step 3: UT
it('UT-TEMPL-05: characterList from settings', () => {
const ctx = buildTemplateContext({ /* 2 characters */ })
expect(ctx.characterList).toContain('林远')
})
Run: npm run test -- --run tests/main/chapter-template-context.test.ts
Task 5: BookSettingsTab
Files:
-
Create:
src/renderer/components/book/BookSettingsTab.tsx -
Create:
src/renderer/stores/useBookPrefsStore.ts -
Modify:
src/renderer/components/layout/RightPanel.tsx -
Step 1: BookSettingsTab — 表单字段:
- 书名、分类、目标字数、简介(textarea)
- 封面:按钮选文件 → 存
userData/covers/{bookId}.jpg路径到 meta.coverPath - 「每次打开显示驾驶舱」checkbox →
bookPrefs.set('alwaysShowCockpit', 'true'|'false') - 危险区:删书 → confirm →
book.delete→loadBooks→setView('home')
-
Step 2: RightPanel —
book-settingspanel 渲染<BookSettingsTab /> -
Step 3: i18n —
bookSettings.*键(中英)
Task 6: 分卷右键 + 章节管理 UI
Files:
-
Create:
src/renderer/components/volume/VolumeContextMenu.tsx -
Create:
src/renderer/components/chapter/ChapterMetaPanel.tsx -
Modify:
src/renderer/components/layout/EditorLayout.tsx -
Step 1: VolumeContextMenu — 绑定分卷标题
onContextMenu:- 重命名:prompt →
volume.update - 编辑简述:prompt →
volume.update({ description }) - 删除:若卷内无章 →
volume.delete;有章则 toast 错误
- 重命名:prompt →
-
Step 2: 章节双击改名 —
chapter-itemonDoubleClick→ input inline →chapter.update({ title }) -
Step 3: 章节删除 — 右键或 hover 图标 → confirm →
chapter.delete→refreshChapters -
Step 4: ChapterMetaPanel — 侧栏或状态栏按钮打开:
- summary、story_time 输入
- 标签 chips + 添加输入
- word_count_threshold 数字
-
Step 5: 发布日期 —
setPublishStatus后本地 chapter 显示published_at(只读) -
Step 6: 字数阈值变色 — 状态栏
wordCount.chapter与currentChapter.wordCountThreshold比较,超则橙色 class
Task 7: AI 会话菜单
Files:
-
Create:
src/renderer/components/ai/AiSessionMenu.tsx -
Modify:
src/renderer/components/ai/AiPanel.tsx -
Modify:
src/renderer/stores/useAiStore.ts -
Step 1: AiSessionMenu — 会话选择器旁「⋯」按钮:
- 重命名 →
ai.session.update({ title }) - 归档/取消归档 →
{ archived: true/false } - 导出 → 子菜单 txt/md →
ai.session.export - 删除 → confirm →
ai.session.delete
- 重命名 →
-
Step 2: useAiStore —
loadSessions(bookId, true)加载含归档;归档会话 optgroup 或折叠区 -
Step 3: i18n —
ai.session.*
Task 8: 专注模式 + TTS
Files:
-
Create:
src/renderer/components/focus/FocusModeOverlay.tsx -
Create:
src/renderer/lib/tts-controller.ts -
Modify:
src/renderer/App.tsx -
Modify:
src/renderer/styles/layout.css -
Step 1: FocusModeOverlay —
useAppStore.focusModeboolean:- true 时
#app加focus-modeclass(CSS 隐藏 sidebars/right-panel/topbar 非必要按钮) - Esc 或按钮退出
- true 时
-
Step 2: App.tsx —
focusMode动作调用setFocusMode(true);再次按退出 -
Step 3: tts-controller.ts
export function speakText(text: string, lang = 'zh-CN'): void {
const u = new SpeechSynthesisUtterance(text)
u.lang = lang
window.speechSynthesis.cancel()
window.speechSynthesis.speak(u)
}
export function stopSpeaking(): void {
window.speechSynthesis.cancel()
}
-
Step 4: App.tsx —
toggleTTS:若正在朗读则 stop;否则读当前章editor.getText()或选区 -
Step 5: i18n —
focus.*/tts.*
Task 9: 占位清零 + 顶栏进度
Files:
-
Modify:
src/renderer/components/wordfreq/WordFreqPanel.tsx -
Modify:
src/renderer/components/layout/TopBar.tsx -
Modify:
src/renderer/stores/useAppStore.ts -
Step 1: WordFreqPanel — 底部按钮
onClick改为setNamingOpen(true)或触发 KnowledgePanel 命名检查(与NamingCheckModal联动) -
Step 2: TopBar — 在
top-spacer前加细进度条:- 读
useWritingStatsStore+dailyWordGoal goalProgress映射 width%;≥100% 绿色,≥80% 橙色
- 读
-
Step 3: 全局 grep
feature.comingSoon— Wave 1 范围内应无功能入口残留
Task 10: E2E + 版本 v1.2.0
Files:
-
Create:
e2e/book-settings.spec.ts -
Create:
e2e/chapter-management.spec.ts -
Create:
e2e/focus-tts.spec.ts -
Modify:
e2e/chapter-template.spec.ts -
Modify:
e2e/helpers.ts -
Modify:
package.json,README.md,SettingsPage.tsx -
Step 1: e2e/helpers.ts —
openBookSettings(page)helper -
Step 2: E2E-BOOK-01 — 改书名、勾选 always cockpit、删书
-
Step 3: E2E-CHAP-01 — 双击改标题、删除章
-
Step 4: E2E-FOCUS-01 — Ctrl+Alt+F 进入专注,Esc 退出
-
Step 5: E2E-TEMPL-05 — 模板含
{characterList}的自定义模板(设置页创建)→ 快速新建 → 编辑器含角色名 -
Step 6: 全量验证
npm run build
npm run test
npm run test:e2e -- e2e/book-settings.spec.ts e2e/chapter-management.spec.ts e2e/focus-tts.spec.ts e2e/chapter-template.spec.ts
-
Step 7: 版本 —
package.json/ README / Settings 关于页 → v1.2.0 -
Step 8: 勾选本 plan 全部 checkbox
Plan 自检
| Spec §5 要求 | Task |
|---|---|
| 5.1 书籍设置 Tab | Task 5 |
| 5.2 分卷管理 | Task 6 |
| 5.3 章节管理 | Task 6 |
| 5.4 模板变量 | Task 4 |
| 5.5 AI 会话 UI | Task 7 |
| 5.6 快捷键 | Task 8 |
| 5.7 用词分析 | Task 9 |
| 5.8 验收 E2E | Task 10 |
无 TBD 占位。
后续波次计划(待 W1 完成后编写)
| 文件 | 版本 |
|---|---|
docs/superpowers/plans/2026-07-08-bilin-w2-project-pack.md |
v1.3.0 |
docs/superpowers/plans/2026-07-08-bilin-w3-export-read.md |
v1.4.0 |
docs/superpowers/plans/2026-07-08-bilin-w4-creative-depth.md |
v1.5.0 |
docs/superpowers/plans/2026-07-08-bilin-w5-platform.md |
v2.0.0 |