feat: ship v0.9.0 with pomodoro, achievements, and injection history

Add pomodoro timer with goal notifications, writing streak milestones, and knowledge injection logging with UI previews across AI writing flows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 19:15:52 +08:00
parent 255f1a99a0
commit d4122c8f95
53 changed files with 1679 additions and 80 deletions
@@ -1,6 +1,6 @@
# 笔临 P5.3 + P6.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.
> **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.9.0:§8 番茄钟(15/25/45)、连更里程碑徽章(7/30/100)、日更/番茄/里程碑通知;P6.1 写作流三模式知识注入历史记录与知识库反向链接 UI。
@@ -64,7 +64,7 @@
- Modify: `src/main/services/global-settings.ts`
- Modify: `src/renderer/stores/useSettingsStore.ts`
- [ ] **Step 1: 扩展 types**
- [x] **Step 1: 扩展 types**
```typescript
export type PomodoroDuration = 15 | 25 | 45
@@ -115,7 +115,7 @@ enableGoalNotifications?: boolean
dailyGoalNotifiedDate?: string // YYYY-MM-DD,防重复达标 Toast
```
- [ ] **Step 2: IPC 通道**
- [x] **Step 2: IPC 通道**
```typescript
POMODORO_START: 'pomodoro:start',
@@ -129,7 +129,7 @@ POMODORO_TICK: 'pomodoro:tick', // main → renderer push
GOAL_NOTIFICATION: 'goal:notification', // main → renderer push
```
- [ ] **Step 3: global-settings 默认值**
- [x] **Step 3: global-settings 默认值**
```typescript
pomodoroDurationMinutes: 25,
@@ -137,9 +137,9 @@ enableSystemNotifications: false,
enableGoalNotifications: true,
```
- [ ] **Step 4: useSettingsStore 同步**
- [x] **Step 4: useSettingsStore 同步**
- [ ] **Step 5: build**
- [x] **Step 5: build**
```bash
npm run build
@@ -155,7 +155,7 @@ npm run build
- Create: `src/main/db/repositories/pomodoro-daily.repo.ts`
- Create: `tests/main/achievement.test.ts`(先写 milestone repo 部分)
- [ ] **Step 1: writing-log.repo migrate 扩展**
- [x] **Step 1: writing-log.repo migrate 扩展**
`migrate()` 追加:
@@ -171,7 +171,7 @@ CREATE TABLE IF NOT EXISTS pomodoro_daily (
);
```
- [ ] **Step 2: WritingMilestoneRepository**
- [x] **Step 2: WritingMilestoneRepository**
```typescript
export class WritingMilestoneRepository {
@@ -182,7 +182,7 @@ export class WritingMilestoneRepository {
}
```
- [ ] **Step 3: PomodoroDailyRepository**
- [x] **Step 3: PomodoroDailyRepository**
```typescript
recordComplete(bookId: string, wordDelta: number, date?: string): void {
@@ -191,7 +191,7 @@ recordComplete(bookId: string, wordDelta: number, date?: string): void {
getTodayCount(bookId: string): number
```
- [ ] **Step 4: UT-ACH repo smoke**
- [x] **Step 4: UT-ACH repo smoke**
```typescript
it('UT-ACH-01: unlock streak_7 once', () => {
@@ -201,7 +201,7 @@ it('UT-ACH-01: unlock streak_7 once', () => {
})
```
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/achievement.test.ts -t "UT-ACH-01"
@@ -218,9 +218,9 @@ npm run test -- tests/main/achievement.test.ts -t "UT-ACH-01"
- Create: `tests/main/migrate-v8.test.ts`
- Create: `tests/main/knowledge-injection.test.ts`
- [ ] **Step 1: schema-v8.sql**(见 spec §3.2
- [x] **Step 1: schema-v8.sql**(见 spec §3.2
- [ ] **Step 2: migrate.ts**
- [x] **Step 2: migrate.ts**
```typescript
import schemaV8 from './schema-v8.sql?raw'
@@ -232,21 +232,21 @@ if (current < 8) {
}
```
- [ ] **Step 3: KnowledgeInjectionRepository**
- [x] **Step 3: KnowledgeInjectionRepository**
```typescript
insertBatch(rows: Array<Omit<KnowledgeInjectionLog, 'id' | 'injectedAt'>>): void
listForEntry(entryId: string, limit = 50): KnowledgeInjectionLog[]
```
- [ ] **Step 4: UT-MIG-08 + UT-INJ-01**
- [x] **Step 4: UT-MIG-08 + UT-INJ-01**
```typescript
it('UT-MIG-08: v7 database migrates to v8 with injection table', () => { /* ... */ })
it('UT-INJ-01: insertBatch creates 3 rows', () => { /* ... */ })
```
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/migrate-v8.test.ts tests/main/knowledge-injection.test.ts
@@ -260,7 +260,7 @@ npm run test -- tests/main/migrate-v8.test.ts tests/main/knowledge-injection.tes
- Create: `src/main/services/pomodoro.service.ts`
- Create: `tests/main/pomodoro.test.ts`
- [ ] **Step 1: PomodoroService 实现**
- [x] **Step 1: PomodoroService 实现**
```typescript
export class PomodoroService {
@@ -304,14 +304,14 @@ export class PomodoroService {
}
```
- [ ] **Step 2: UT-POM-01 / UT-POM-02**
- [x] **Step 2: UT-POM-01 / UT-POM-02**
```typescript
it('UT-POM-01: complete records word delta', () => { /* mock writingLogs */ })
it('UT-POM-02: start different book cancels previous', () => { /* ... */ })
```
- [ ] **Step 3: 运行**
- [x] **Step 3: 运行**
```bash
npm run test -- tests/main/pomodoro.test.ts
@@ -327,7 +327,7 @@ npm run test -- tests/main/pomodoro.test.ts
- Modify: `src/main/services/writing-log.service.ts`
- Modify: `tests/main/achievement.test.ts`
- [ ] **Step 1: GoalNotificationService**
- [x] **Step 1: GoalNotificationService**
```typescript
export class GoalNotificationService {
@@ -353,7 +353,7 @@ export class GoalNotificationService {
}
```
- [ ] **Step 2: AchievementService**
- [x] **Step 2: AchievementService**
```typescript
checkMilestones(bookId: string): WritingAchievement[] {
@@ -372,7 +372,7 @@ checkMilestones(bookId: string): WritingAchievement[] {
}
```
- [ ] **Step 3: WritingLogService.addToday 扩展**
- [x] **Step 3: WritingLogService.addToday 扩展**
`addToday` 返回后:
@@ -384,9 +384,9 @@ if (stats.dailyGoal > 0 && stats.todayWords >= stats.dailyGoal) {
this.achievementService.checkMilestones(bookId)
```
- [ ] **Step 4: UT-ACH-02 + IT-GOAL-01**
- [x] **Step 4: UT-ACH-02 + IT-GOAL-01**
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/achievement.test.ts
@@ -403,7 +403,7 @@ npm run test -- tests/main/achievement.test.ts
- Modify: `src/main/ipc/handlers/wizard.handler.ts`
- Modify: `tests/main/knowledge-injection.test.ts`
- [ ] **Step 1: KnowledgeInjectionService**
- [x] **Step 1: KnowledgeInjectionService**
```typescript
export class KnowledgeInjectionService {
@@ -424,7 +424,7 @@ export class KnowledgeInjectionService {
}
```
- [ ] **Step 2: interactive.handler 挂钩**
- [x] **Step 2: interactive.handler 挂钩**
`INTERACTIVE_CONFIRM_CONTEXT``buildFlowContextPayload` 成功后:
@@ -441,13 +441,13 @@ try {
}
```
- [ ] **Step 3: auto / wizard 同理**
- [x] **Step 3: auto / wizard 同理**
- [ ] **Step 4: IT-INJ-01**
- [x] **Step 4: IT-INJ-01**
直接调用 handler 或 service + 内存 DB,断言 `knowledge_injection_logs` 行数。
- [ ] **Step 5: 运行**
- [x] **Step 5: 运行**
```bash
npm run test -- tests/main/knowledge-injection.test.ts
@@ -466,9 +466,9 @@ npm run test -- tests/main/knowledge-injection.test.ts
- Modify: `src/preload/index.ts`
- Modify: `src/shared/electron-api.d.ts`
- [ ] **Step 1: pomodoro.handler + achievement.handler**
- [x] **Step 1: pomodoro.handler + achievement.handler**
- [ ] **Step 2: knowledge.handler**
- [x] **Step 2: knowledge.handler**
```typescript
ipcMain.handle(IPC.KNOWLEDGE_LIST_INJECTIONS, (_e, { bookId, entryId, limit }) =>
@@ -476,7 +476,7 @@ ipcMain.handle(IPC.KNOWLEDGE_LIST_INJECTIONS, (_e, { bookId, entryId, limit }) =
)
```
- [ ] **Step 3: register.ts 注入**
- [x] **Step 3: register.ts 注入**
```typescript
const goalNotify = new GoalNotificationService(settings, () => getMainWindow())
@@ -487,7 +487,7 @@ registerPomodoroHandlers(pomodoro)
registerAchievementHandlers(achievementService)
```
- [ ] **Step 4: preload**
- [x] **Step 4: preload**
```typescript
pomodoro: {
@@ -501,14 +501,14 @@ onPomodoroTick: (cb) => { ipcRenderer.on(IPC.POMODORO_TICK, cb); return () => ..
onGoalNotification: (cb) => { ipcRenderer.on(IPC.GOAL_NOTIFICATION, cb); return () => ... },
```
- [ ] **Step 5: CockpitService 扩展**
- [x] **Step 5: CockpitService 扩展**
```typescript
achievements: this.achievementService.listAchievements(bookId),
pomodoroTodayCount: this.pomodoroDaily.getTodayCount(bookId),
```
- [ ] **Step 6: build**
- [x] **Step 6: build**
```bash
npm run build
@@ -524,11 +524,11 @@ npm run build
- Modify: `src/renderer/App.tsx`(注册 onGoalNotification 全局 Toast
- Modify: `src/renderer/styles/layout.css`
- [ ] **Step 1: usePomodoroStore**
- [x] **Step 1: usePomodoroStore**
订阅 `onPomodoroTick`actions`start/pause/resume/cancel`
- [ ] **Step 2: EditorLayout 状态栏控件**
- [x] **Step 2: EditorLayout 状态栏控件**
```tsx
<div className="pomodoro-control" data-testid="pomodoro-control">
@@ -544,7 +544,7 @@ npm run build
</div>
```
- [ ] **Step 3: App.tsx goal notification**
- [x] **Step 3: App.tsx goal notification**
```typescript
useEffect(() => {
@@ -554,7 +554,7 @@ useEffect(() => {
}, [])
```
- [ ] **Step 4: build 验证**
- [x] **Step 4: build 验证**
```bash
npm run build
@@ -570,7 +570,7 @@ npm run build
- Modify: `public/locales/zh-CN/translation.json`
- Modify: `public/locales/en/translation.json`
- [ ] **Step 1: CockpitModal 成就区**
- [x] **Step 1: CockpitModal 成就区**
```tsx
{summary.achievements && summary.achievements.length > 0 && (
@@ -581,13 +581,13 @@ npm run build
</div>
```
- [ ] **Step 2: SettingsPage 三项设置**
- [x] **Step 2: SettingsPage 三项设置**
`settings-pomodoro-duration` / `settings-system-notifications` / `settings-goal-notifications`
- [ ] **Step 3: i18n**spec §7 全部键,中英)
- [x] **Step 3: i18n**spec §7 全部键,中英)
- [ ] **Step 4: build**
- [x] **Step 4: build**
```bash
npm run build
@@ -602,7 +602,7 @@ npm run build
- Modify: `src/renderer/components/knowledge/KnowledgeEditorDialog.tsx`
- Modify: `src/renderer/stores/useKnowledgeStore.ts`
- [ ] **Step 1: KnowledgePanel 加载注入预览**
- [x] **Step 1: KnowledgePanel 加载注入预览**
条目 render 时调用 `knowledge.listInjections(bookId, entry.id, 3)`(或 batch 加载 map)。
@@ -614,11 +614,11 @@ npm run build
</div>
```
- [ ] **Step 2: KnowledgeEditorDialog 完整历史**
- [x] **Step 2: KnowledgeEditorDialog 完整历史**
`data-testid="knowledge-injection-history"`;章节名点击 `switchTarget({ kind:'chapter', id })`
- [ ] **Step 3: build**
- [x] **Step 3: build**
```bash
npm run build
@@ -635,17 +635,17 @@ npm run build
- Modify: `README.md`
- Modify: `tests/main/migrate-v7.test.ts` 等(若 CURRENT_VERSION→8,期望版本改为 8
- [ ] **Step 1: E2E-GOAL-01~03**
- [x] **Step 1: E2E-GOAL-01~03**
- E2E-GOAL-01:设 dailyWordGoal=100,打字保存,断言 toast / status-daily-goal
- E2E-GOAL-02:通过测试 hook 或 seed API 写入 streak_7 milestone,打开驾驶舱断言 `cockpit-achievements`
- E2E-GOAL-03`POMODORO_TEST_SEC=3`,启动番茄,等待完成 Toast
- [ ] **Step 2: E2E-INJ-01**
- [x] **Step 2: E2E-INJ-01**
向导 confirm 知识上下文(可 stub 空 AI),断言 `knowledge-injection-preview-*` 可见。
- [ ] **Step 3: 全量测试**
- [x] **Step 3: 全量测试**
```bash
npm run build
@@ -653,11 +653,11 @@ npm run test
npm run test:e2e -- e2e/writing-goals.spec.ts e2e/knowledge-injection-history.spec.ts
```
- [ ] **Step 4: 版本 0.9.0**
- [x] **Step 4: 版本 0.9.0**
`package.json``README.md``SettingsPage` about 版本号。
- [ ] **Step 5: 更新 migrate-v2~v7 测试期望版本 → 8**(与 P5.2 v7 时同样处理)
- [x] **Step 5: 更新 migrate-v2~v7 测试期望版本 → 8**(与 P5.2 v7 时同样处理)
---