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
+20
View File
@@ -32,6 +32,10 @@ interface KnowledgeState {
approve: (bookId: string, id: string) => Promise<void>
reject: (bookId: string, id: string) => Promise<void>
batchApprove: (bookId: string, ids: string[]) => Promise<void>
extractChapter: (bookId: string, chapterId: string) => Promise<void>
approveMerge: (bookId: string, pendingId: string) => Promise<void>
saveMergeAsNew: (bookId: string, pendingId: string) => Promise<void>
batchApproveHighConfidence: (bookId: string, threshold?: number) => Promise<void>
filteredEntries: () => KnowledgeEntry[]
}
@@ -82,6 +86,22 @@ export const useKnowledgeStore = create<KnowledgeState>((set, get) => ({
await ipcCall(() => window.electronAPI.knowledge.batchApprove(bookId, ids))
await get().load(bookId)
},
extractChapter: async (bookId, chapterId) => {
await ipcCall(() => window.electronAPI.knowledge.extractChapter(bookId, chapterId))
await get().load(bookId)
},
approveMerge: async (bookId, pendingId) => {
await ipcCall(() => window.electronAPI.knowledge.approveMerge(bookId, pendingId))
await get().load(bookId)
},
saveMergeAsNew: async (bookId, pendingId) => {
await ipcCall(() => window.electronAPI.knowledge.saveMergeAsNew(bookId, pendingId))
await get().load(bookId)
},
batchApproveHighConfidence: async (bookId, threshold) => {
await ipcCall(() => window.electronAPI.knowledge.batchApproveHighConfidence(bookId, threshold))
await get().load(bookId)
},
filteredEntries: () => {
const { entries, tab, forgottenOnly } = get()
let list = entries
+2
View File
@@ -24,6 +24,8 @@ export const useSettingsStore = create<SettingsState>((set, get) => ({
namingIgnoreWords: [] as string[],
knowledgeAutoSuggest: true,
knowledgeSuggestTopN: 8,
knowledgeAutoExtract: true,
knowledgeExtractConfidenceThreshold: 0.8,
loaded: false,
load: async () => {
const data = await ipcCall(() => window.electronAPI.settings.get())
@@ -0,0 +1,16 @@
import { create } from 'zustand'
import type { WritingStats } from '@shared/types'
import { ipcCall } from '@renderer/lib/ipc-client'
interface WritingStatsState {
stats: WritingStats | null
refresh: (bookId: string) => Promise<void>
}
export const useWritingStatsStore = create<WritingStatsState>((set) => ({
stats: null,
refresh: async (bookId) => {
const stats = await ipcCall(() => window.electronAPI.writing.getStats(bookId))
set({ stats })
}
}))