feat: ship v0.6.0 with cockpit, knowledge base, and chapter bridge

Deliver P5 writer workflow: writing cockpit, manual knowledge CRUD with review, chapter bridge with optional AI, publish status, and stock buffer reminders.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 23:03:11 +08:00
parent 78f046890d
commit b33d2e7b34
45 changed files with 2389 additions and 29 deletions
+64 -2
View File
@@ -35,7 +35,14 @@ import type {
SnapshotType,
UpdateChapterParams,
Volume,
WordFreqResult
WordFreqResult,
KnowledgeEntry,
CreateKnowledgeInput,
KnowledgeStatus,
KnowledgeType,
CockpitSummary,
ChapterBridgeResult,
PublishStatus
} from '../shared/types'
const electronAPI = {
@@ -91,7 +98,13 @@ const electronAPI = {
targetVolumeId: string,
targetIndex: number
): Promise<IpcResult<Chapter>> =>
ipcRenderer.invoke(IPC.CHAPTER_MOVE_TO_VOLUME, { bookId, chapterId, targetVolumeId, targetIndex })
ipcRenderer.invoke(IPC.CHAPTER_MOVE_TO_VOLUME, { bookId, chapterId, targetVolumeId, targetIndex }),
setPublishStatus: (
bookId: string,
chapterId: string,
publishStatus: PublishStatus
): Promise<IpcResult<Chapter>> =>
ipcRenderer.invoke(IPC.CHAPTER_SET_PUBLISH_STATUS, { bookId, chapterId, publishStatus })
},
outline: {
list: (bookId: string): Promise<IpcResult<OutlineItem[]>> =>
@@ -408,6 +421,55 @@ const electronAPI = {
abort: (flowId: string): Promise<IpcResult<void>> =>
ipcRenderer.invoke(IPC.WIZARD_ABORT, { flowId })
},
knowledge: {
list: (
bookId: string,
filter?: { status?: KnowledgeStatus; type?: KnowledgeType; forgottenOnly?: boolean }
): Promise<IpcResult<KnowledgeEntry[]>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_LIST, { bookId, filter }),
create: (bookId: string, input: CreateKnowledgeInput): Promise<IpcResult<KnowledgeEntry>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_CREATE, { bookId, input }),
update: (
bookId: string,
id: string,
patch: Partial<CreateKnowledgeInput & { status: KnowledgeStatus }>
): Promise<IpcResult<KnowledgeEntry>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_UPDATE, { bookId, id, patch }),
delete: (bookId: string, id: string): Promise<IpcResult<void>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_DELETE, { bookId, id }),
approve: (bookId: string, id: string): Promise<IpcResult<KnowledgeEntry>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_APPROVE, { bookId, id }),
reject: (bookId: string, id: string): Promise<IpcResult<KnowledgeEntry>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_REJECT, { bookId, id }),
batchApprove: (bookId: string, ids: string[]): Promise<IpcResult<number>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_BATCH_APPROVE, { bookId, ids }),
createFromBookmark: (bookId: string, bookmarkId: string): Promise<IpcResult<KnowledgeEntry>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_CREATE_FROM_BOOKMARK, { bookId, bookmarkId }),
stats: (
bookId: string
): Promise<IpcResult<{ buried: number; resolved: number; forgotten: number }>> =>
ipcRenderer.invoke(IPC.KNOWLEDGE_STATS, { bookId })
},
cockpit: {
getSummary: (bookId: string, volumeId?: string): Promise<IpcResult<CockpitSummary>> =>
ipcRenderer.invoke(IPC.COCKPIT_SUMMARY, { bookId, volumeId }),
markSeen: (bookId: string): Promise<IpcResult<void>> =>
ipcRenderer.invoke(IPC.COCKPIT_MARK_SEEN, { bookId }),
shouldShowOnOpen: (bookId: string): Promise<IpcResult<boolean>> =>
ipcRenderer.invoke(IPC.COCKPIT_SHOULD_SHOW, { bookId })
},
bridge: {
get: (
bookId: string,
chapterId: string,
withAi?: boolean
): Promise<IpcResult<ChapterBridgeResult>> =>
ipcRenderer.invoke(IPC.BRIDGE_GET, { bookId, chapterId, withAi }),
dismiss: (bookId: string, chapterId: string): Promise<IpcResult<void>> =>
ipcRenderer.invoke(IPC.BRIDGE_DISMISS, { bookId, chapterId }),
shouldPrompt: (bookId: string, chapterId: string): Promise<IpcResult<boolean>> =>
ipcRenderer.invoke(IPC.BRIDGE_SHOULD_PROMPT, { bookId, chapterId })
},
wordfreq: {
analyze: (
bookId: string,