# 笔临 P5 作家工作流 + 知识库 MVP 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.6.0:驾驶舱 + 存稿/更新计划 + 章间衔接(可选 AI)+ 知识库 MVP(手动 CRUD / 审核 / 伏笔追踪)。 **Architecture:** schema v6 新增 `knowledge_entries` / `book_preferences` / `chapter_bridge_dismiss`;`KnowledgeService` 负责 CRUD 与遗忘判定;`CockpitService` 只读聚合字数与存稿;`ChapterBridgeService` 提取相邻章片段 + 可选 `AiClientService`;渲染层 `CockpitModal` / `ChapterBridgeModal` / 重写 `KnowledgePanel`。测试 **禁止 Mock** AI 集成/E2E 打真实 LM Studio。 **Tech Stack:** Electron 36、electron-vite、React 18、TypeScript、node:sqlite、Zustand、Jotai、i18next、Vitest、Playwright **Spec:** `docs/superpowers/specs/2026-07-06-bilin-p5-workflow-knowledge-design.md` **LM Studio 默认:** `baseUrl=http://127.0.0.1:1234`,`model=gemma-4-e4b-it` --- ## File Map | 文件 | 职责 | |------|------| | `src/main/db/schema-v6.sql` | v6 DDL | | `src/main/db/migrate.ts` | v5→v6 | | `src/main/db/repositories/knowledge.repo.ts` | knowledge_entries CRUD | | `src/main/db/repositories/book-prefs.repo.ts` | book_preferences KV | | `src/main/db/repositories/bridge-dismiss.repo.ts` | chapter_bridge_dismiss | | `src/main/services/knowledge.service.ts` | 审核、遗忘判定、bookmark 同步 | | `src/main/services/cockpit.service.ts` | 驾驶舱聚合 | | `src/main/services/chapter-bridge.service.ts` | 衔接文本 + AI | | `src/main/db/repositories/chapter.repo.ts` | publish_status 读写 | | `src/main/ipc/handlers/knowledge.handler.ts` | knowledge IPC | | `src/main/ipc/handlers/cockpit.handler.ts` | cockpit IPC | | `src/main/ipc/handlers/bridge.handler.ts` | bridge IPC | | `src/main/ipc/register.ts` | 注册 handler | | `src/shared/types.ts` | KnowledgeEntry / CockpitSummary 等 | | `src/shared/ipc-channels.ts` | 新通道 | | `src/preload/index.ts` | knowledge / cockpit / bridge API | | `src/shared/electron-api.d.ts` | 类型 | | `src/renderer/stores/useKnowledgeStore.ts` | 知识库状态 | | `src/renderer/stores/useCockpitStore.ts` | 驾驶舱状态 | | `src/renderer/components/knowledge/KnowledgePanel.tsx` | 重写 | | `src/renderer/components/knowledge/KnowledgeEditorDialog.tsx` | 编辑对话框 | | `src/renderer/components/cockpit/CockpitModal.tsx` | 驾驶舱 UI | | `src/renderer/components/bridge/ChapterBridgeModal.tsx` | 衔接 UI | | `src/renderer/components/layout/TopBar.tsx` | 驾驶舱按钮 | | `src/renderer/components/layout/EditorLayout.tsx` | 发布状态、bridge 触发、statusbar | | `src/renderer/components/settings/SettingsPage.tsx` | updateSchedule | | `src/main/services/global-settings.ts` | 默认值扩展 | | `public/locales/zh-CN/translation.json` | 文案 | | `public/locales/en/translation.json` | 文案 | | `tests/main/migrate-v6.test.ts` | UT-MIG-06 | | `tests/main/knowledge.service.test.ts` | UT-KNOW-* | | `tests/main/cockpit.service.test.ts` | UT-COCK-01 | | `tests/main/chapter-bridge.test.ts` | UT-BRIDGE-01 / IT-BRIDGE-01 | | `e2e/cockpit-knowledge.spec.ts` | E2E-COCK-* / KNOW-* / BRIDGE-* / STOCK-* | --- ## Task 1: Schema v6 + 类型 + IPC 通道 **Files:** - Create: `src/main/db/schema-v6.sql` - Modify: `src/main/db/migrate.ts` - Modify: `src/shared/types.ts` - Modify: `src/shared/ipc-channels.ts` - Create: `tests/main/migrate-v6.test.ts` - Modify: `tests/main/migrate-v5.test.ts`(期望 version **6**) - [ ] **Step 1: 写迁移失败测试** `tests/main/migrate-v6.test.ts`: ```typescript import { describe, it, expect, afterEach } from 'vitest' import { DatabaseSync } from 'node:sqlite' import { migrate } from '../../src/main/db/migrate' import type { SqliteDb } from '../../src/main/db/types' describe('migrate v6', () => { let db: SqliteDb afterEach(() => db?.close()) it('UT-MIG-06: applies v6 on fresh database', () => { db = new DatabaseSync(':memory:') migrate(db) const version = db.prepare('SELECT MAX(version) AS v FROM schema_version').get() as { v: number } expect(version.v).toBe(6) const tables = db .prepare("SELECT name FROM sqlite_master WHERE type='table'") .all() as { name: string }[] expect(tables.some((t) => t.name === 'knowledge_entries')).toBe(true) expect(tables.some((t) => t.name === 'book_preferences')).toBe(true) expect(tables.some((t) => t.name === 'chapter_bridge_dismiss')).toBe(true) }) }) ``` - [ ] **Step 2: 运行确认 FAIL** ```bash npm run test -- tests/main/migrate-v6.test.ts ``` - [ ] **Step 3: 实现 schema v6** `src/main/db/schema-v6.sql`(与 spec §3.1 一致)。 `src/main/db/migrate.ts`: ```typescript import schemaV6 from './schema-v6.sql?raw' const CURRENT_VERSION = 6 // ... if (current < 6) { db.exec(schemaV6) db.prepare('INSERT INTO schema_version (version, description) VALUES (?, ?)').run(6, 'P5 knowledge/cockpit schema') } ``` `src/shared/types.ts` 新增: ```typescript export type KnowledgeType = 'character' | 'foreshadow' | 'location' | 'relationship' | 'fact' export type KnowledgeStatus = 'pending' | 'approved' | 'rejected' export type ForeshadowStatus = 'buried' | 'partial' | 'resolved' export type UpdateSchedule = 'daily' | 'alternate' | 'weekly' | 'none' export interface KnowledgeEntry { id: string type: KnowledgeType title: string content: string importance: number status: KnowledgeStatus foreshadowStatus?: ForeshadowStatus sourceChapterId?: string lastMentionChapterId?: string linkedBookmarkId?: string createdAt: string updatedAt: string } export interface CreateKnowledgeInput { type: KnowledgeType title: string content?: string importance?: number status?: KnowledgeStatus foreshadowStatus?: ForeshadowStatus sourceChapterId?: string lastMentionChapterId?: string linkedBookmarkId?: string } export interface CockpitSummary { totalWords: number volumeWords: number stockReadyCount: number stockThreshold: number foreshadowBuried: number foreshadowResolved: number foreshadowForgotten: number } export interface ChapterBridgeResult { previousChapterId: string | null previousTail: string currentHead: string aiSuggestion?: string } ``` 扩展 `GlobalSettings`: ```typescript updateSchedule: UpdateSchedule // default 'none' stockBufferThreshold: number // default 3 ``` 扩展 `Chapter`: ```typescript publishStatus?: PublishStatus ``` `src/shared/ipc-channels.ts` 追加 spec §4.1 全部通道。 - [ ] **Step 4: 更新 migrate-v5 期望 version 6;运行 PASS** ```bash npm run test -- tests/main/migrate-v5.test.ts tests/main/migrate-v6.test.ts ``` - [ ] **Step 5: Commit** ```bash git add src/main/db/schema-v6.sql src/main/db/migrate.ts src/shared/types.ts src/shared/ipc-channels.ts tests/main/migrate-v6.test.ts tests/main/migrate-v5.test.ts git commit -m "feat: add schema v6 for knowledge and cockpit workflow" ``` --- ## Task 2: Repository 层 **Files:** - Create: `src/main/db/repositories/knowledge.repo.ts` - Create: `src/main/db/repositories/book-prefs.repo.ts` - Create: `src/main/db/repositories/bridge-dismiss.repo.ts` - Modify: `src/main/db/repositories/chapter.repo.ts` - Create: `tests/main/knowledge.repo.test.ts` - [ ] **Step 1: UT-KNOW-01 失败测试** ```typescript it('UT-KNOW-01: CRUD and approve updates status', () => { const db = new DatabaseSync(':memory:') migrate(db) const repo = new KnowledgeRepository(db) const entry = repo.create({ type: 'foreshadow', title: '测灵石异常', foreshadowStatus: 'buried' }) expect(entry.status).toBe('pending') const approved = repo.update(entry.id, { status: 'approved' }) expect(approved.status).toBe('approved') db.close() }) ``` - [ ] **Step 2: 实现 KnowledgeRepository** ```typescript export class KnowledgeRepository { create(input: CreateKnowledgeInput): KnowledgeEntry { /* INSERT */ } get(id: string): KnowledgeEntry | null list(filter?: { status?: KnowledgeStatus; type?: KnowledgeType }): KnowledgeEntry[] update(id: string, patch: Partial<...>): KnowledgeEntry delete(id: string): void countByStatus(status: KnowledgeStatus): number } ``` `mapRow` 蛇形 ↔ 驼峰映射。 - [ ] **Step 3: BookPrefsRepository + BridgeDismissRepository** ```typescript // book-prefs.repo.ts get(key: string): string | null set(key: string, value: string): void // bridge-dismiss.repo.ts isDismissed(chapterId: string): boolean dismiss(chapterId: string): void ``` - [ ] **Step 4: ChapterRepository 扩展 publish_status** `mapRow` 增加 `publishStatus`;`update` patch 支持 `publishStatus`;新增: ```typescript setPublishStatus(id: string, publishStatus: PublishStatus): Chapter countByPublishStatus(status: PublishStatus): number getPreviousChapter(chapterId: string): Chapter | null // 按 sort_order 找上一章 ``` - [ ] **Step 5: 运行 PASS + Commit** ```bash npm run test -- tests/main/knowledge.repo.test.ts git commit -m "feat: add knowledge and bridge repositories with publish status" ``` --- ## Task 3: KnowledgeService **Files:** - Create: `src/main/services/knowledge.service.ts` - Create: `tests/main/knowledge.service.test.ts` - [ ] **Step 1: UT-KNOW-02 遗忘判定测试** ```typescript it('UT-KNOW-02: forgotten when sort_order gap >= 20', () => { // 创建 25 章,在第 1 章埋 foreshadow approved buried // latestOrder - mentionOrder >= 20 → forgotten count 1 }) ``` - [ ] **Step 2: UT-KNOW-03 bookmark 同步测试** ```typescript it('UT-KNOW-03: createFromBookmark creates pending entry', () => { const bm = bookmarkRepo.create(chapterId, 0, '测灵石发热', 'foreshadow') const entry = service.createFromBookmark(bm.id) expect(entry.status).toBe('pending') expect(entry.linkedBookmarkId).toBe(bm.id) }) ``` - [ ] **Step 3: 实现 KnowledgeService** ```typescript const FORGOTTEN_GAP = 20 export class KnowledgeService { list(filter?: { status?: KnowledgeStatus; type?: KnowledgeType; forgottenOnly?: boolean }) create(input: CreateKnowledgeInput): KnowledgeEntry update(id: string, patch: Partial): KnowledgeEntry delete(id: string): void approve(id: string): KnowledgeEntry reject(id: string): KnowledgeEntry batchApprove(ids: string[]): number createFromBookmark(bookmarkId: string): KnowledgeEntry getForeshadowStats(): { buried: number; resolved: number; forgotten: number } countPending(): number private isForgotten(entry: KnowledgeEntry): boolean { if (entry.type !== 'foreshadow' || entry.status !== 'approved' || entry.foreshadowStatus !== 'buried') return false const mentionId = entry.lastMentionChapterId ?? entry.sourceChapterId if (!mentionId) return false const mentionOrder = chapterRepo.get(mentionId)?.sortOrder ?? 0 const latestOrder = Math.max(...chapterRepo.list().map((c) => c.sortOrder), 0) return latestOrder - mentionOrder >= FORGOTTEN_GAP } } ``` - [ ] **Step 4: IT-KNOW-04 批量采纳** ```typescript it('IT-KNOW-04: batchApprove clears pending', () => { // create 3 pending → batchApprove → countPending === 0 }) ``` - [ ] **Step 5: 运行 PASS + Commit** ```bash npm run test -- tests/main/knowledge.service.test.ts git commit -m "feat: add KnowledgeService with foreshadow forgotten logic" ``` --- ## Task 4: CockpitService + GlobalSettings 扩展 **Files:** - Create: `src/main/services/cockpit.service.ts` - Modify: `src/main/services/global-settings.ts` - Create: `tests/main/cockpit.service.test.ts` - [ ] **Step 1: UT-COCK-01 测试** ```typescript it('UT-COCK-01: getSummary counts words and ready stock', () => { volRepo.create('卷一', 0) chapterRepo.create(volId, 'A', 0, '

hello world

') chapterRepo.setPublishStatus(chId, 'ready') const summary = service.getSummary(activeVolumeId) expect(summary.totalWords).toBeGreaterThan(0) expect(summary.stockReadyCount).toBe(1) }) ``` - [ ] **Step 2: 实现 CockpitService** ```typescript export class CockpitService { constructor( private db: SqliteDb, private settings: GlobalSettingsService ) {} getSummary(activeVolumeId?: string): CockpitSummary { const chapters = new ChapterRepository(this.db).list() const totalWords = chapters.reduce((s, c) => s + stripHtml(c.content).length, 0) const volumeWords = activeVolumeId ? chapters.filter((c) => c.volumeId === activeVolumeId).reduce(...) : totalWords const stockReadyCount = new ChapterRepository(this.db).countByPublishStatus('ready') const stats = new KnowledgeService(this.db).getForeshadowStats() const { stockBufferThreshold } = this.settings.get() return { totalWords, volumeWords, stockReadyCount, stockThreshold: stockBufferThreshold, ...stats } } shouldShowOnOpen(): boolean { return new BookPrefsRepository(this.db).get('cockpitSeen') !== 'true' } markSeen(): void { new BookPrefsRepository(this.db).set('cockpitSeen', 'true') } } ``` - [ ] **Step 3: global-settings defaults** ```typescript updateSchedule: 'none', stockBufferThreshold: 3, ``` `get()` merge 时补默认值。 - [ ] **Step 4: 运行 PASS + Commit** ```bash npm run test -- tests/main/cockpit.service.test.ts git commit -m "feat: add CockpitService and extend global settings" ``` --- ## Task 5: ChapterBridgeService **Files:** - Create: `src/main/services/chapter-bridge.service.ts` - Create: `tests/main/chapter-bridge.test.ts` - [ ] **Step 1: UT-BRIDGE-01 文本提取测试** ```typescript it('UT-BRIDGE-01: extracts tail and head', () => { const prev = chapterRepo.create(volId, '上一章', 0, '

' + '甲'.repeat(400) + '

') const cur = chapterRepo.create(volId, '本章', 1, '

开头内容

') const result = service.getBridgeSync(cur.id) // 无 AI 同步方法 expect(result.previousTail.length).toBeLessThanOrEqual(300) expect(result.previousTail.length).toBeGreaterThan(50) expect(result.currentHead).toContain('开头') }) ``` - [ ] **Step 2: 实现 ChapterBridgeService** ```typescript export class ChapterBridgeService { shouldPrompt(chapterId: string): boolean { if (dismissRepo.isDismissed(chapterId)) return false const ch = chapterRepo.get(chapterId) if (!ch || stripHtml(ch.content).length >= 200) return false return chapterRepo.getPreviousChapter(chapterId) !== null } extract(chapterId: string): ChapterBridgeResult { const prev = chapterRepo.getPreviousChapter(chapterId) const cur = chapterRepo.get(chapterId)! const prevText = prev ? stripHtml(prev.content) : '' const curText = stripHtml(cur.content) return { previousChapterId: prev?.id ?? null, previousTail: prevText.slice(-300), currentHead: curText.slice(0, 200) } } async getBridge(chapterId: string, withAi: boolean): Promise { const base = this.extract(chapterId) if (!withAi || !base.previousTail) return base try { const suggestion = await this.aiClient.chat([ { role: 'user', content: `你是连载小说编辑。上一章末尾:「${base.previousTail}」。本章开头:「${base.currentHead || '(尚未撰写)'}」。用 2-3 句话指出衔接是否顺畅,并给出一个开头方向建议。不要续写正文。` } ]) return { ...base, aiSuggestion: suggestion.trim() } } catch { return base } } dismiss(chapterId: string): void { dismissRepo.dismiss(chapterId) } } ``` - [ ] **Step 3: IT-BRIDGE-01(240s LM Studio)** ```typescript it('IT-BRIDGE-01: getBridge returns aiSuggestion from LM Studio', async () => { // 两章有内容 → getBridge(id, true) → aiSuggestion.length > 10 }, 240_000) ``` - [ ] **Step 4: 运行 PASS + Commit** ```bash npm run test -- tests/main/chapter-bridge.test.ts git commit -m "feat: add ChapterBridgeService with optional AI suggestion" ``` --- ## Task 6: IPC + Preload **Files:** - Create: `src/main/ipc/handlers/knowledge.handler.ts` - Create: `src/main/ipc/handlers/cockpit.handler.ts` - Create: `src/main/ipc/handlers/bridge.handler.ts` - Modify: `src/main/ipc/handlers/chapter.handler.ts` - Modify: `src/main/ipc/register.ts` - Modify: `src/preload/index.ts` - Modify: `src/shared/electron-api.d.ts` - [ ] **Step 1: 实现 handlers** 参照 `auto.handler.ts` 模式,`wrap(() => ...)`,`BookRegistryService.getDb(bookId)`。 `knowledge.handler.ts`:`list` / `create` / `update` / `delete` / `approve` / `reject` / `batchApprove` / `createFromBookmark` / `stats` `cockpit.handler.ts`:`getSummary(bookId, volumeId?)` / `markSeen` / `shouldShowOnOpen` `bridge.handler.ts`:`get(bookId, chapterId, withAi?)` / `dismiss` / `shouldPrompt` `chapter.handler.ts` 新增: ```typescript IPC.CHAPTER_SET_PUBLISH_STATUS → chapterRepo.setPublishStatus(chapterId, status) ``` - [ ] **Step 2: register.ts** ```typescript registerKnowledgeHandlers(books, settings) registerCockpitHandlers(books, settings) registerBridgeHandlers(books, settings, aiClient) ``` - [ ] **Step 3: preload 命名空间** ```typescript knowledge: { list, create, update, delete, approve, reject, batchApprove, createFromBookmark, stats }, cockpit: { getSummary, markSeen, shouldShowOnOpen }, bridge: { get, dismiss, shouldPrompt }, chapter: { /* 现有 */ setPublishStatus }, ``` - [ ] **Step 4: build 验证** ```bash npm run build ``` - [ ] **Step 5: Commit** ```bash git commit -m "feat: add knowledge cockpit bridge IPC and preload" ``` --- ## Task 7: KnowledgePanel UI **Files:** - Create: `src/renderer/stores/useKnowledgeStore.ts` - Create: `src/renderer/components/knowledge/KnowledgeEditorDialog.tsx` - Modify: `src/renderer/components/knowledge/KnowledgePanel.tsx` - Modify: `src/renderer/styles/layout.css` - [ ] **Step 1: useKnowledgeStore** ```typescript interface KnowledgeState { entries: KnowledgeEntry[] stats: { buried: number; resolved: number; forgotten: number } tab: 'pending' | 'all' | 'foreshadow' load: (bookId: string) => Promise setTab: (tab: ...) => void create / update / delete / approve / batchApprove openForgottenFilter: () => void // tab=foreshadow + forgottenOnly } ``` - [ ] **Step 2: KnowledgeEditorDialog** Radix Dialog 或现有 `.modal-overlay` 模式;字段:type select、title、content textarea、importance 1-5、foreshadowStatus(type=foreshadow 时)、sourceChapter select、「直接采纳」checkbox。 - [ ] **Step 3: 重写 KnowledgePanel** 布局见 spec §6.4;保留 `naming-check-open`;Tab 切换过滤列表;`data-testid` 与 spec 一致。 - [ ] **Step 4: CSS `.knowledge-panel` / `.kb-item` 对齐 ui_pc.html** - [ ] **Step 5: Commit** ```bash git commit -m "feat: implement KnowledgePanel with review workflow UI" ``` --- ## Task 8: CockpitModal + TopBar + 首次打开 **Files:** - Create: `src/renderer/stores/useCockpitStore.ts` - Create: `src/renderer/components/cockpit/CockpitModal.tsx` - Modify: `src/renderer/components/layout/TopBar.tsx` - Modify: `src/renderer/stores/useBookStore.ts`(openBook 后检查 cockpit) - Modify: `src/renderer/App.tsx` 或 `EditorLayout.tsx`(挂载 CockpitModal) - [ ] **Step 1: useCockpitStore** ```typescript loadSummary(bookId, volumeId?) open / close markSeen(bookId) shouldShowOnOpen(bookId): Promise ``` - [ ] **Step 2: CockpitModal** 加载 summary 展示卡片;按钮: - `cockpit-resume-edit` → close + 恢复 lastChapterId - `cockpit-bridge-check` → close + 打开 ChapterBridgeModal - `cockpit-forgotten-foreshadow` → close + `useKnowledgeStore.openForgottenFilter()` + 切 rightPanel knowledge - [ ] **Step 3: TopBar** 替换 `comingSoon` 为 `data-testid="topbar-cockpit"` → `useCockpitStore.open()` - [ ] **Step 4: 首次打开书籍** `useBookStore.openBook` 成功后: ```typescript if (await ipcCall(() => window.electronAPI.cockpit.shouldShowOnOpen(bookId))) { await ipcCall(() => window.electronAPI.cockpit.markSeen(bookId)) useCockpitStore.getState().open() } ``` - [ ] **Step 5: Commit** ```bash git commit -m "feat: add CockpitModal and first-open behavior" ``` --- ## Task 9: ChapterBridgeModal + EditorLayout 集成 **Files:** - Create: `src/renderer/components/bridge/ChapterBridgeModal.tsx` - Modify: `src/renderer/components/layout/EditorLayout.tsx` - Modify: `src/renderer/stores/useAppStore.ts`(bridgeOpen 状态,可选) - [ ] **Step 1: ChapterBridgeModal** 打开时 `bridge.get(bookId, chapterId, true)`;展示 tail/head/aiSuggestion;checkbox dismiss + `bridge-start-writing` 关闭。 - [ ] **Step 2: EditorLayout 自动触发** `switchTarget` 到 chapter 后: ```typescript const should = await ipcCall(() => window.electronAPI.bridge.shouldPrompt(chapterId)) if (should) setTimeout(() => setBridgeOpen(true), 500) ``` - [ ] **Step 3: 驾驶舱手动触发** CockpitModal `cockpit-bridge-check` 设置 `bridgeChapterId` 为当前章并打开 modal。 - [ ] **Step 4: Commit** ```bash git commit -m "feat: add ChapterBridgeModal with auto prompt on new chapter" ``` --- ## Task 10: 发布状态 + 存稿提醒 + 设置 **Files:** - Modify: `src/renderer/components/layout/EditorLayout.tsx` - Modify: `src/renderer/stores/useBookStore.ts` - Modify: `src/renderer/components/settings/SettingsPage.tsx` - [ ] **Step 1: 章节 publish 循环按钮** 在 `chapter-item` 内增加小图标按钮 `data-testid={`chapter-publish-${ch.id}`}`,点击循环 `draft → ready → published`,调用 `chapter.setPublishStatus`,刷新 chapters。 - [ ] **Step 2: StatusBar 存稿警告** EditorLayout `#editor-statusbar` 内: ```typescript const summary = await cockpit.getSummary(bookId, activeVolumeId) if (settings.updateSchedule !== 'none' && summary.stockReadyCount < summary.stockThreshold) { // 渲染 data-testid="status-stock-warning" } ``` 书籍打开时 load summary;publish 变更后 refresh。 - [ ] **Step 3: SettingsPage** 新增「更新计划」区块:`updateSchedule` select、`stockBufferThreshold` number input (1-20)。 - [ ] **Step 4: Commit** ```bash git commit -m "feat: add publish status UI stock warning and update schedule settings" ``` --- ## Task 11: 地标同步 + i18n **Files:** - Modify: `src/renderer/components/editor/TipTapEditor.tsx` 或 landmark 插入流程 - Modify: `public/locales/zh-CN/translation.json` - Modify: `public/locales/en/translation.json` - [ ] **Step 1: 插入 foreshadow 地标时 checkbox** 在 insert landmark 对话框(或插入后 toast 行动)增加「同步到知识库」;勾选则 `knowledge.createFromBookmark(bookmarkId)`。 若当前无独立 insert UI,在 `LandmarkModal` 或 TipTap landmark 命令回调中加 post-create hook。 - [ ] **Step 2: i18n 键** `cockpit.*`、`bridge.*`、`knowledge.*`、`publish.status.draft/ready/published`、`settings.updateSchedule.*`、`stock.warning` - [ ] **Step 3: Commit** ```bash git commit -m "feat: add foreshadow landmark sync and P5 i18n strings" ``` --- ## Task 12: E2E 测试 **Files:** - Create: `e2e/cockpit-knowledge.spec.ts` - [ ] **Step 1: 无 AI 门槛测试** ```typescript test('E2E-COCK-01: cockpit modal shows stats', async () => { /* openBookWithContent → topbar-cockpit → cockpit-total-words visible */ }) test('E2E-COCK-02: first open shows cockpit once', async () => { /* 开书两次 */ }) test('E2E-PUB-01: publish ready increases stock count', async () => { /* chapter-publish click → cockpit-stock-count */ }) test('E2E-KNOW-01: create approve knowledge entry', async () => { /* knowledge-new → pending tab → approve */ }) test('E2E-BRIDGE-01: new chapter triggers bridge modal', async () => { /* 新章 → bridge-previous-tail visible */ }) test('E2E-STOCK-01: low stock warning in statusbar', async () => { /* set threshold + schedule in settings, 0 ready chapters */ }) ``` - [ ] **Step 2: LM Studio 测试(300s)** ```typescript test('E2E-BRIDGE-02: bridge shows AI suggestion', async () => { test.setTimeout(300_000) // 两章有内容 → 手动打开 bridge → bridge-ai-suggestion 非空 }) test('E2E-KNOW-02: foreshadow landmark sync', async () => { /* 插入 foreshadow + sync */ }) ``` - [ ] **Step 3: 运行 E2E** ```bash npm run test:e2e -- e2e/cockpit-knowledge.spec.ts ``` - [ ] **Step 4: Commit** ```bash git commit -m "test: add P5 cockpit knowledge and bridge E2E specs" ``` --- ## Task 13: v0.6.0 交付 **Files:** - Modify: `package.json` - Modify: `README.md` - Modify: `src/renderer/components/settings/SettingsPage.tsx`(版本号展示) - Modify: `docs/superpowers/plans/2026-07-06-bilin-p5-workflow-knowledge.md`(勾选完成项) - [ ] **Step 1: 版本号 → `0.6.0`** - [ ] **Step 2: README 功能概览追加 P5** ```markdown - 驾驶舱:全书/本卷字数、存稿缓冲、伏笔摘要、快速入口(P5) - 知识库 MVP:手动条目、审核流、伏笔追踪、地标同步(P5) - 章间衔接:上下章片段 + 可选 AI 建议(P5) - 更新计划:发布状态、存稿阈值提醒(P5) ``` - [ ] **Step 3: 全量测试** ```bash npm run build npm run test npm run test:e2e ``` - [ ] **Step 4: Commit** ```bash git commit -m "feat: ship v0.6.0 with cockpit knowledge and chapter bridge" ``` --- ## Spec Coverage Checklist | Spec 要求 | Task | |-----------|------| | schema v6 三表 | Task 1 | | Knowledge CRUD / 审核 / 遗忘 | Task 2–3, 7 | | Cockpit 聚合 + 首次打开 | Task 4, 8 | | ChapterBridge + AI | Task 5, 9 | | publish_status UI | Task 10 | | updateSchedule / 存稿提醒 | Task 4, 10 | | 地标 foreshadow 同步 | Task 11 | | IPC / preload | Task 6 | | i18n | Task 11 | | 全部测试 ID | Task 1–5, 12 | | v0.6.0 DoD | Task 13 |