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:
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user