Files
bilin/docs/superpowers/plans/2026-07-08-bilin-w1-foundation.md
T
bing 64da95f7e1 docs: add Wave 1 foundation implementation plan for v1.2.0
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>
2026-07-08 14:23:19 +08:00

16 KiB
Raw Blame History

笔临 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;扩展 BookMetaBOOK_UPDATE_META;渲染进程新增 BookSettingsTabFocusMode overlay、ChapterMetaPanel;复用已有 volume.* / chapter.delete IPCchapter-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=9published_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.tsCURRENT_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 updateupdate()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.handlerBOOK_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.handlerAI_SESSION_EXPORT:读 messages,格式化 markdowndialog.showSaveDialog,写文件

  • Step 5: preloadbook.updateMeta 扩展;bookPrefs.get/setchapterTag.list/set/removeai.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.deleteloadBookssetView('home')
  • Step 2: RightPanelbook-settings panel 渲染 <BookSettingsTab />

  • Step 3: i18nbookSettings.* 键(中英)


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 错误
  • Step 2: 章节双击改名chapter-item onDoubleClick → input inline → chapter.update({ title })

  • Step 3: 章节删除 — 右键或 hover 图标 → confirm → chapter.deleterefreshChapters

  • Step 4: ChapterMetaPanel — 侧栏或状态栏按钮打开:

    • summary、story_time 输入
    • 标签 chips + 添加输入
    • word_count_threshold 数字
  • Step 5: 发布日期setPublishStatus 后本地 chapter 显示 published_at(只读)

  • Step 6: 字数阈值变色 — 状态栏 wordCount.chaptercurrentChapter.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: useAiStoreloadSessions(bookId, true) 加载含归档;归档会话 optgroup 或折叠区

  • Step 3: i18nai.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: FocusModeOverlayuseAppStore.focusMode boolean

    • true 时 #appfocus-mode classCSS 隐藏 sidebars/right-panel/topbar 非必要按钮)
    • Esc 或按钮退出
  • Step 2: App.tsxfocusMode 动作调用 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.tsxtoggleTTS:若正在朗读则 stop;否则读当前章 editor.getText() 或选区

  • Step 5: i18nfocus.* / 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.tsopenBookSettings(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