feat: ship v0.8.0 with writing logs and AI knowledge extraction

Deliver P5.2 writing day logs, cockpit heatmap, streak tracking, and chapter knowledge auto-extraction with merge review.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 18:26:29 +08:00
parent f331ddae86
commit a39e06ff07
51 changed files with 1436 additions and 89 deletions
@@ -1,6 +1,6 @@
# 笔临 P5.2 写作日志 + AI 知识抽取 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.
> **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 (`- [x]`) syntax for tracking.
**Goal:** 交付 v0.8.0`writing_logs` 日更追踪(保存差分 + 成章补计)、驾驶舱热力图/连更、状态栏日更进度,以及 AI 章节知识自动抽取 + 合并审核增强,与 P6 注入形成上下游闭环。
@@ -62,7 +62,7 @@
- Modify: `src/main/services/global-settings.ts`
- Modify: `src/renderer/stores/useSettingsStore.ts`
- [ ] **Step 1: 扩展 types**
- [x] **Step 1: 扩展 types**
`src/shared/types.ts` 追加:
@@ -120,7 +120,7 @@ knowledgeAutoExtract?: boolean
knowledgeExtractConfidenceThreshold?: number
```
- [ ] **Step 2: IPC 通道**
- [x] **Step 2: IPC 通道**
```typescript
WRITING_GET_STATS: 'writing:getStats',
@@ -129,7 +129,7 @@ KNOWLEDGE_APPROVE_MERGE: 'knowledge:approveMerge',
KNOWLEDGE_BATCH_APPROVE_HIGH_CONFIDENCE: 'knowledge:batchApproveHighConfidence',
```
- [ ] **Step 3: global-settings 默认值**
- [x] **Step 3: global-settings 默认值**
```typescript
knowledgeAutoExtract: true,
@@ -138,9 +138,9 @@ knowledgeExtractConfidenceThreshold: 0.8,
`get()` merge 补默认。
- [ ] **Step 4: useSettingsStore 同步默认**
- [x] **Step 4: useSettingsStore 同步默认**
- [ ] **Step 5: build**
- [x] **Step 5: build**
```bash
npm run build
@@ -156,7 +156,7 @@ npm run build
- Modify: `src/main/db/repositories/knowledge.repo.ts`
- Create: `tests/main/migrate-v7.test.ts`
- [ ] **Step 1: schema-v7.sql**
- [x] **Step 1: schema-v7.sql**
```sql
CREATE TABLE IF NOT EXISTS chapter_writing_snapshots (
@@ -167,7 +167,7 @@ CREATE TABLE IF NOT EXISTS chapter_writing_snapshots (
);
```
- [ ] **Step 2: migrate.ts**
- [x] **Step 2: migrate.ts**
```typescript
import schemaV7 from './schema-v7.sql?raw'
@@ -183,7 +183,7 @@ if (current < 7) {
}
```
- [ ] **Step 3: knowledge.repo mapRow + createExtracted**
- [x] **Step 3: knowledge.repo mapRow + createExtracted**
更新 `mapRow` 读取三列;新增:
@@ -229,7 +229,7 @@ clearMergeTarget(id: string): KnowledgeEntry {
}
```
- [ ] **Step 4: migrate-v7 测试**
- [x] **Step 4: migrate-v7 测试**
```typescript
it('UT-MIG-07: v6 database migrates to v7 with snapshot table and knowledge columns', () => {
@@ -241,7 +241,7 @@ it('UT-MIG-07: v6 database migrates to v7 with snapshot table and knowledge colu
})
```
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/migrate-v7.test.ts
@@ -256,7 +256,7 @@ npm run test -- tests/main/migrate-v7.test.ts
- Create: `src/main/services/writing-log.service.ts`
- Create: `tests/main/writing-log.test.ts`
- [ ] **Step 1: WritingLogRepository**
- [x] **Step 1: WritingLogRepository**
全局 sqlite 路径 `join(userDataDir, 'writing_logs.sqlite')``migrate()` 建表;方法:
@@ -276,7 +276,7 @@ export function localDateString(d = new Date()): string {
}
```
- [ ] **Step 2: WritingLogService**
- [x] **Step 2: WritingLogService**
```typescript
export class WritingLogService {
@@ -301,7 +301,7 @@ export class WritingLogService {
}
```
- [ ] **Step 3: UT-LOG-01~04**
- [x] **Step 3: UT-LOG-01~04**
```typescript
it('UT-LOG-01: addToday accumulates +200', () => { /* ... */ })
@@ -309,7 +309,7 @@ it('UT-LOG-02: negative delta clamps at 0', () => { /* ... */ })
it('UT-LOG-04: streak counts consecutive goal-met days', () => { /* seed 3 days */ })
```
- [ ] **Step 4: 运行**
- [x] **Step 4: 运行**
```bash
npm run test -- tests/main/writing-log.test.ts
@@ -324,14 +324,14 @@ npm run test -- tests/main/writing-log.test.ts
- Create: `src/main/services/chapter-writing-tracker.service.ts`
- Modify: `tests/main/writing-log.test.ts`
- [ ] **Step 1: ChapterWritingSnapshotRepository**
- [x] **Step 1: ChapterWritingSnapshotRepository**
```typescript
get(chapterId: string): { loggedWordCount: number; finishSupplemented: boolean } | null
upsert(chapterId: string, loggedWordCount: number, finishSupplemented?: boolean): void
```
- [ ] **Step 2: ChapterWritingTracker**
- [x] **Step 2: ChapterWritingTracker**
```typescript
export class ChapterWritingTracker {
@@ -359,9 +359,9 @@ export class ChapterWritingTracker {
}
```
- [ ] **Step 3: UT-LOG-03 supplementOnFinish**
- [x] **Step 3: UT-LOG-03 supplementOnFinish**
- [ ] **Step 4: 运行测试**
- [x] **Step 4: 运行测试**
```bash
npm run test -- tests/main/writing-log.test.ts
@@ -378,7 +378,7 @@ npm run test -- tests/main/writing-log.test.ts
- Modify: `src/main/ipc/register.ts`
- Modify: `tests/main/writing-log.test.ts`IT-LOG-01
- [ ] **Step 1: register.ts 创建 WritingLogService 单例**
- [x] **Step 1: register.ts 创建 WritingLogService 单例**
```typescript
const writingLogs = new WritingLogService(new WritingLogRepository(userData), settings)
@@ -394,7 +394,7 @@ function trackerFor(registry: BookRegistryService, bookId: string, writingLogs:
}
```
- [ ] **Step 2: chapter.handler CHAPTER_UPDATE 后**
- [x] **Step 2: chapter.handler CHAPTER_UPDATE 后**
```typescript
wrap(() => {
@@ -406,7 +406,7 @@ wrap(() => {
})
```
- [ ] **Step 3: interactive/auto finishChapter 后**
- [x] **Step 3: interactive/auto finishChapter 后**
`finishChapter` 返回 `{ chapterId }` 后:
@@ -421,11 +421,11 @@ return result
抽取辅助放在 `src/main/services/knowledge-extraction-runner.ts`(避免 handler 膨胀)。
- [ ] **Step 4: IT-LOG-01**
- [x] **Step 4: IT-LOG-01**
两次 `CHAPTER_UPDATE` 模拟,断言 `writing_logs` 累计。
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/writing-log.test.ts
@@ -442,7 +442,7 @@ npm run test -- tests/main/writing-log.test.ts
- Modify: `src/preload/index.ts`
- Modify: `src/shared/electron-api.d.ts`
- [ ] **Step 1: CockpitService 注入 WritingLogService**
- [x] **Step 1: CockpitService 注入 WritingLogService**
```typescript
getSummary(activeVolumeId?: string, bookId?: string): CockpitSummary {
@@ -454,7 +454,7 @@ getSummary(activeVolumeId?: string, bookId?: string): CockpitSummary {
更新 `cockpit.handler.ts``bookId`
- [ ] **Step 2: writing.handler**
- [x] **Step 2: writing.handler**
```typescript
ipcMain.handle(IPC.WRITING_GET_STATS, (_e, { bookId }: { bookId: string }) =>
@@ -462,7 +462,7 @@ ipcMain.handle(IPC.WRITING_GET_STATS, (_e, { bookId }: { bookId: string }) =>
)
```
- [ ] **Step 3: preload**
- [x] **Step 3: preload**
```typescript
writing: {
@@ -471,7 +471,7 @@ writing: {
},
```
- [ ] **Step 4: build**
- [x] **Step 4: build**
```bash
npm run build
@@ -486,7 +486,7 @@ npm run build
- Create: `src/main/services/knowledge-extraction.service.ts`
- Create: `tests/main/knowledge-extraction.test.ts`
- [ ] **Step 1: knowledge-extraction-prompt.ts**
- [x] **Step 1: knowledge-extraction-prompt.ts**
```typescript
export function buildExtractionPrompt(
@@ -512,7 +512,7 @@ export function parseExtractionJson(raw: string): ExtractedKnowledgeItem[] {
}
```
- [ ] **Step 2: KnowledgeExtractionService**
- [x] **Step 2: KnowledgeExtractionService**
```typescript
export class KnowledgeExtractionService {
@@ -557,11 +557,11 @@ export class KnowledgeExtractionService {
}
```
- [ ] **Step 3: UT-EXT-01 / UT-EXT-02**
- [x] **Step 3: UT-EXT-01 / UT-EXT-02**
`parseExtractionJson` 测合法 JSON 与 `suggestedMergeId` 字段。
- [ ] **Step 4: 运行**
- [x] **Step 4: 运行**
```bash
npm run test -- tests/main/knowledge-extraction.test.ts -t "UT-EXT"
@@ -577,7 +577,7 @@ npm run test -- tests/main/knowledge-extraction.test.ts -t "UT-EXT"
- Modify: `src/preload/index.ts`
- Modify: `tests/main/knowledge-extraction.test.ts`
- [ ] **Step 1: KnowledgeService.approveMerge**
- [x] **Step 1: KnowledgeService.approveMerge**
```typescript
approveMerge(pendingId: string): KnowledgeEntry {
@@ -600,7 +600,7 @@ saveMergeAsNew(pendingId: string): KnowledgeEntry {
}
```
- [ ] **Step 2: knowledge.handler IPC**
- [x] **Step 2: knowledge.handler IPC**
```typescript
ipcMain.handle(IPC.KNOWLEDGE_EXTRACT_CHAPTER, (_e, { bookId, chapterId }) =>
@@ -617,9 +617,9 @@ ipcMain.handle(IPC.KNOWLEDGE_BATCH_APPROVE_HIGH_CONFIDENCE, (_e, { bookId, thres
)
```
- [ ] **Step 3: IT-EXT-01 / IT-EXT-02**240s
- [x] **Step 3: IT-EXT-01 / IT-EXT-02**240s
- [ ] **Step 4: IT-EXT-03** — 抽取 → approve → `KnowledgeRetrievalService.suggest` 含新条目
- [x] **Step 4: IT-EXT-03** — 抽取 → approve → `KnowledgeRetrievalService.suggest` 含新条目
---
@@ -631,11 +631,11 @@ ipcMain.handle(IPC.KNOWLEDGE_BATCH_APPROVE_HIGH_CONFIDENCE, (_e, { bookId, thres
- Modify: `src/renderer/components/layout/EditorLayout.tsx`
- Modify: `src/renderer/styles/layout.css`
- [ ] **Step 1: WritingHeatmap 组件**
- [x] **Step 1: WritingHeatmap 组件**
Props`heatmap: WritingDayLog[]`Canvas 13×7 格(52 周近似 365 天);四档颜色;`data-testid="cockpit-heatmap"`
- [ ] **Step 2: CockpitModal 扩展**
- [x] **Step 2: CockpitModal 扩展**
`cockpit-grid` 下方:
@@ -649,7 +649,7 @@ Props`heatmap: WritingDayLog[]`Canvas 13×7 格(52 周近似 365 天)
<WritingHeatmap heatmap={summary.writingStats?.heatmap ?? []} />
```
- [ ] **Step 3: EditorLayout 状态栏**
- [x] **Step 3: EditorLayout 状态栏**
```tsx
const writingStats = useWritingStatsStore() // 或 cockpit summary 缓存
@@ -662,7 +662,7 @@ const writingStats = useWritingStatsStore() // 或 cockpit summary 缓存
章节保存后 `writing.getStats` 刷新(监听 save 或轮询 `useBookStore` wordCount)。
- [ ] **Step 4: build 验证**
- [x] **Step 4: build 验证**
```bash
npm run build
@@ -681,28 +681,28 @@ npm run build
- Modify: `public/locales/zh-CN/translation.json`
- Modify: `public/locales/en/translation.json`
- [ ] **Step 1: KnowledgePanel 待审核增强**
- [x] **Step 1: KnowledgePanel 待审核增强**
- 卡片显示 `extractionConfidence` 百分比徽章
- `mergeTargetId` 时显示 `t('knowledge.mergeSuggest')` + `data-testid="knowledge-merge-review-{id}"`
- 工具栏按钮 `knowledge-batch-high-confidence`
- 工具栏「从当前章抽取」`knowledge-extract-current`(需 `selectedChapterId`
- [ ] **Step 2: KnowledgeEditorDialog 合并模式**
- [x] **Step 2: KnowledgeEditorDialog 合并模式**
props`mergeTarget?: KnowledgeEntry``initialPatch?: Partial<CreateKnowledgeInput>`
底部按钮:「确认更新」→ `approveMerge`;「作为新条目」→ `saveMergeAsNew` 后常规编辑。
- [ ] **Step 3: SettingsPage**
- [x] **Step 3: SettingsPage**
`settings-knowledge-auto-extract` 开关;`settings-extract-threshold` 数字输入。
- [ ] **Step 4: 章节抽取入口**
- [x] **Step 4: 章节抽取入口**
章节列表项或编辑器右键:`data-testid="chapter-extract-knowledge"``knowledge.extractChapter`
- [ ] **Step 5: i18n** — spec §9 全部键
- [x] **Step 5: i18n** — spec §9 全部键
---
@@ -716,13 +716,13 @@ props`mergeTarget?: KnowledgeEntry`、`initialPatch?: Partial<CreateKnowledge
- Modify: `src/renderer/components/settings/SettingsPage.tsx`about 版本)
- Modify: `docs/superpowers/plans/2026-07-07-bilin-p52-writing-logs-extraction.md`(勾选完成项)
- [ ] **Step 1: E2E-LOG-01 / E2E-LOG-02**
- [x] **Step 1: E2E-LOG-01 / E2E-LOG-02**
写 100 字保存 → 打开驾驶舱 → `cockpit-today-progress` 更新;`cockpit-heatmap` 可见。
- [ ] **Step 2: E2E-EXT-01 / E2E-EXT-02 / E2E-EXT-03**300s timeout on AI tests
- [x] **Step 2: E2E-EXT-01 / E2E-EXT-02 / E2E-EXT-03**300s timeout on AI tests
- [ ] **Step 3: 全量测试**
- [x] **Step 3: 全量测试**
```bash
npm run build
@@ -730,7 +730,7 @@ npm run test
npm run test:e2e -- e2e/writing-logs.spec.ts e2e/knowledge-extraction.spec.ts
```
- [ ] **Step 4: 版本 0.8.0**
- [x] **Step 4: 版本 0.8.0**
`package.json``README.md` 追加:
@@ -738,7 +738,7 @@ npm run test:e2e -- e2e/writing-logs.spec.ts e2e/knowledge-extraction.spec.ts
- 写作日志与热力图、AI 章节知识自动抽取(P5.2)
```
- [ ] **Step 5: Commit**
- [x] **Step 5: Commit**
```bash
git commit -m "feat: ship v0.8.0 with writing logs and AI knowledge extraction"