a39e06ff07
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>
552 lines
24 KiB
TypeScript
552 lines
24 KiB
TypeScript
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'
|
|
import { IPC } from '../shared/ipc-channels'
|
|
import type {
|
|
KnowledgeSuggestOptions,
|
|
ScoredKnowledge,
|
|
ActionId,
|
|
Bookmark,
|
|
BookMeta,
|
|
BookOpenResult,
|
|
Chapter,
|
|
CreateBookParams,
|
|
GlobalSettings,
|
|
InspirationEntry,
|
|
AiContextBinding,
|
|
AiContextBuildResult,
|
|
AiConfig,
|
|
AiMessage,
|
|
AiSession,
|
|
NamingConflict,
|
|
AiStreamChunkEvent,
|
|
AiNetworkStatusEvent,
|
|
AutoRhythm,
|
|
AutoWritingConfig,
|
|
InteractiveFlow,
|
|
InteractiveGateResult,
|
|
InteractiveStreamChunkEvent,
|
|
PlotOption,
|
|
PlotSelection,
|
|
IpcResult,
|
|
LandmarkType,
|
|
OutlineItem,
|
|
OutlineStatus,
|
|
SearchResult,
|
|
SettingEntry,
|
|
SettingType,
|
|
Snapshot,
|
|
SnapshotType,
|
|
UpdateChapterParams,
|
|
Volume,
|
|
WordFreqResult,
|
|
KnowledgeEntry,
|
|
CreateKnowledgeInput,
|
|
KnowledgeStatus,
|
|
KnowledgeType,
|
|
CockpitSummary,
|
|
ChapterBridgeResult,
|
|
PublishStatus,
|
|
WritingStats,
|
|
KnowledgeExtractionResult
|
|
} from '../shared/types'
|
|
|
|
const electronAPI = {
|
|
window: {
|
|
minimize: (): Promise<void> => ipcRenderer.invoke(IPC.WINDOW_MINIMIZE),
|
|
maximize: (): Promise<void> => ipcRenderer.invoke(IPC.WINDOW_MAXIMIZE),
|
|
close: (): Promise<void> => ipcRenderer.invoke(IPC.WINDOW_CLOSE)
|
|
},
|
|
settings: {
|
|
get: (): Promise<IpcResult<GlobalSettings>> => ipcRenderer.invoke(IPC.SETTINGS_GET),
|
|
update: (partial: Partial<GlobalSettings>): Promise<IpcResult<GlobalSettings>> =>
|
|
ipcRenderer.invoke(IPC.SETTINGS_UPDATE, partial)
|
|
},
|
|
book: {
|
|
list: (): Promise<IpcResult<BookMeta[]>> => ipcRenderer.invoke(IPC.BOOK_LIST),
|
|
create: (params: CreateBookParams): Promise<IpcResult<BookMeta>> =>
|
|
ipcRenderer.invoke(IPC.BOOK_CREATE, params),
|
|
delete: (bookId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.BOOK_DELETE, { bookId }),
|
|
open: (bookId: string): Promise<IpcResult<BookOpenResult>> =>
|
|
ipcRenderer.invoke(IPC.BOOK_OPEN, { bookId }),
|
|
updateMeta: (
|
|
bookId: string,
|
|
patch: { lastChapterId?: string | null; status?: BookMeta['status'] }
|
|
): Promise<IpcResult<BookMeta>> => ipcRenderer.invoke(IPC.BOOK_UPDATE_META, { bookId, ...patch })
|
|
},
|
|
volume: {
|
|
create: (bookId: string, name: string): Promise<IpcResult<Volume>> =>
|
|
ipcRenderer.invoke(IPC.VOLUME_CREATE, { bookId, name }),
|
|
update: (
|
|
bookId: string,
|
|
volumeId: string,
|
|
patch: { name?: string; description?: string }
|
|
): Promise<IpcResult<Volume>> =>
|
|
ipcRenderer.invoke(IPC.VOLUME_UPDATE, { bookId, volumeId, ...patch }),
|
|
delete: (bookId: string, volumeId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.VOLUME_DELETE, { bookId, volumeId })
|
|
},
|
|
chapter: {
|
|
create: (bookId: string, volumeId: string, title: string): Promise<IpcResult<Chapter>> =>
|
|
ipcRenderer.invoke(IPC.CHAPTER_CREATE, { bookId, volumeId, title }),
|
|
get: (bookId: string, chapterId: string): Promise<IpcResult<Chapter>> =>
|
|
ipcRenderer.invoke(IPC.CHAPTER_GET, { bookId, chapterId }),
|
|
update: (params: UpdateChapterParams): Promise<IpcResult<Chapter>> =>
|
|
ipcRenderer.invoke(IPC.CHAPTER_UPDATE, params),
|
|
delete: (bookId: string, chapterId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.CHAPTER_DELETE, { bookId, chapterId }),
|
|
reorder: (bookId: string, volumeId: string, orderedIds: string[]): Promise<IpcResult<Chapter[]>> =>
|
|
ipcRenderer.invoke(IPC.CHAPTER_REORDER, { bookId, volumeId, orderedIds }),
|
|
moveToVolume: (
|
|
bookId: string,
|
|
chapterId: string,
|
|
targetVolumeId: string,
|
|
targetIndex: number
|
|
): Promise<IpcResult<Chapter>> =>
|
|
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[]>> =>
|
|
ipcRenderer.invoke(IPC.OUTLINE_LIST, { bookId }),
|
|
create: (
|
|
bookId: string,
|
|
title: string,
|
|
parentId?: string | null,
|
|
sortOrder?: number
|
|
): Promise<IpcResult<OutlineItem>> =>
|
|
ipcRenderer.invoke(IPC.OUTLINE_CREATE, { bookId, parentId, title, sortOrder }),
|
|
update: (
|
|
bookId: string,
|
|
id: string,
|
|
patch: Partial<{
|
|
title: string
|
|
description: string
|
|
status: OutlineStatus
|
|
expectedWordCount: number | null
|
|
chapterId: string | null
|
|
sortOrder: number
|
|
}>
|
|
): Promise<IpcResult<OutlineItem>> =>
|
|
ipcRenderer.invoke(IPC.OUTLINE_UPDATE, { bookId, id, patch }),
|
|
delete: (bookId: string, id: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.OUTLINE_DELETE, { bookId, id }),
|
|
move: (
|
|
bookId: string,
|
|
id: string,
|
|
parentId: string | null,
|
|
sortOrder: number
|
|
): Promise<IpcResult<OutlineItem>> =>
|
|
ipcRenderer.invoke(IPC.OUTLINE_MOVE, { bookId, id, parentId, sortOrder })
|
|
},
|
|
setting: {
|
|
list: (bookId: string, type?: SettingType): Promise<IpcResult<SettingEntry[]>> =>
|
|
ipcRenderer.invoke(IPC.SETTING_LIST, { bookId, type }),
|
|
create: (bookId: string, type: SettingType, name: string): Promise<IpcResult<SettingEntry>> =>
|
|
ipcRenderer.invoke(IPC.SETTING_CREATE, { bookId, type, name }),
|
|
update: (
|
|
bookId: string,
|
|
id: string,
|
|
patch: Partial<{ name: string; description: string; type: SettingType; properties: Record<string, unknown> }>
|
|
): Promise<IpcResult<SettingEntry>> =>
|
|
ipcRenderer.invoke(IPC.SETTING_UPDATE, { bookId, id, patch }),
|
|
delete: (bookId: string, id: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.SETTING_DELETE, { bookId, id }),
|
|
syncRefs: (bookId: string, id: string, chapterIds: string[]): Promise<IpcResult<SettingEntry>> =>
|
|
ipcRenderer.invoke(IPC.SETTING_SYNC_REFS, { bookId, id, chapterIds })
|
|
},
|
|
inspiration: {
|
|
list: (bookId: string): Promise<IpcResult<InspirationEntry[]>> =>
|
|
ipcRenderer.invoke(IPC.INSPIRATION_LIST, { bookId }),
|
|
create: (
|
|
bookId: string,
|
|
title?: string,
|
|
content?: string,
|
|
tags?: string[]
|
|
): Promise<IpcResult<InspirationEntry>> =>
|
|
ipcRenderer.invoke(IPC.INSPIRATION_CREATE, { bookId, title, content, tags }),
|
|
update: (
|
|
bookId: string,
|
|
id: string,
|
|
patch: Partial<{ title: string; content: string; tags: string[] }>
|
|
): Promise<IpcResult<InspirationEntry>> =>
|
|
ipcRenderer.invoke(IPC.INSPIRATION_UPDATE, { bookId, id, patch }),
|
|
delete: (bookId: string, id: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.INSPIRATION_DELETE, { bookId, id }),
|
|
convert: (
|
|
bookId: string,
|
|
id: string,
|
|
targetKind: 'outline' | 'setting',
|
|
settingType?: SettingType
|
|
): Promise<IpcResult<OutlineItem | SettingEntry>> =>
|
|
ipcRenderer.invoke(IPC.INSPIRATION_CONVERT, { bookId, id, targetKind, settingType })
|
|
},
|
|
snapshot: {
|
|
list: (bookId: string, chapterId: string): Promise<IpcResult<Snapshot[]>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_LIST, { bookId, chapterId }),
|
|
create: (
|
|
bookId: string,
|
|
chapterId: string,
|
|
type: SnapshotType,
|
|
name?: string,
|
|
content?: string
|
|
): Promise<IpcResult<Snapshot>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_CREATE, { bookId, chapterId, type, name, content }),
|
|
restore: (
|
|
bookId: string,
|
|
chapterId: string,
|
|
snapshotId: string
|
|
): Promise<IpcResult<Chapter>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_RESTORE, { bookId, chapterId, snapshotId }),
|
|
delete: (bookId: string, snapshotId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_DELETE, { bookId, snapshotId }),
|
|
startAutoSave: (bookId: string, chapterId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_START_AUTO, { bookId, chapterId }),
|
|
stopAutoSave: (bookId: string, chapterId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.SNAPSHOT_STOP_AUTO, { bookId, chapterId })
|
|
},
|
|
bookmark: {
|
|
list: (
|
|
bookId: string,
|
|
chapterId?: string,
|
|
resolved?: boolean
|
|
): Promise<IpcResult<Bookmark[]>> =>
|
|
ipcRenderer.invoke(IPC.BOOKMARK_LIST, { bookId, chapterId, resolved }),
|
|
create: (
|
|
bookId: string,
|
|
chapterId: string,
|
|
position: number,
|
|
label: string,
|
|
landmarkType?: LandmarkType
|
|
): Promise<IpcResult<Bookmark>> =>
|
|
ipcRenderer.invoke(IPC.BOOKMARK_CREATE, { bookId, chapterId, position, label, landmarkType }),
|
|
update: (
|
|
bookId: string,
|
|
id: string,
|
|
patch: Partial<{ label: string; position: number; landmarkType: LandmarkType }>
|
|
): Promise<IpcResult<Bookmark>> =>
|
|
ipcRenderer.invoke(IPC.BOOKMARK_UPDATE, { bookId, id, patch }),
|
|
resolve: (bookId: string, id: string, resolved: boolean): Promise<IpcResult<Bookmark>> =>
|
|
ipcRenderer.invoke(IPC.BOOKMARK_RESOLVE, { bookId, id, resolved }),
|
|
delete: (bookId: string, id: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.BOOKMARK_DELETE, { bookId, id })
|
|
},
|
|
search: {
|
|
query: (
|
|
bookId: string,
|
|
query: string,
|
|
options?: { regex?: boolean; caseSensitive?: boolean; matchWholeWord?: boolean }
|
|
): Promise<IpcResult<SearchResult[]>> =>
|
|
ipcRenderer.invoke(IPC.SEARCH_QUERY, { bookId, query, options }),
|
|
replace: (
|
|
bookId: string,
|
|
query: string,
|
|
replacement: string,
|
|
dryRun: boolean,
|
|
options?: { regex?: boolean; caseSensitive?: boolean }
|
|
): Promise<IpcResult<{ count: number; previews: SearchResult[] }>> =>
|
|
ipcRenderer.invoke(IPC.SEARCH_REPLACE, { bookId, query, replacement, dryRun, options }),
|
|
getHistory: (): Promise<IpcResult<string[]>> => ipcRenderer.invoke(IPC.SEARCH_GET_HISTORY),
|
|
saveHistory: (query: string): Promise<IpcResult<string[]>> =>
|
|
ipcRenderer.invoke(IPC.SEARCH_SAVE_HISTORY, { query })
|
|
},
|
|
ai: {
|
|
sessionList: (bookId: string, includeArchived?: boolean): Promise<IpcResult<AiSession[]>> =>
|
|
ipcRenderer.invoke(IPC.AI_SESSION_LIST, { bookId, includeArchived }),
|
|
sessionCreate: (bookId: string, title?: string, model?: string): Promise<IpcResult<AiSession>> =>
|
|
ipcRenderer.invoke(IPC.AI_SESSION_CREATE, { bookId, title, model }),
|
|
sessionUpdate: (
|
|
bookId: string,
|
|
sessionId: string,
|
|
patch: Partial<{ title: string; model: string; archived: boolean; context: AiContextBinding }>
|
|
): Promise<IpcResult<AiSession>> =>
|
|
ipcRenderer.invoke(IPC.AI_SESSION_UPDATE, { bookId, sessionId, patch }),
|
|
sessionDelete: (bookId: string, sessionId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.AI_SESSION_DELETE, { bookId, sessionId }),
|
|
messageList: (bookId: string, sessionId: string): Promise<IpcResult<AiMessage[]>> =>
|
|
ipcRenderer.invoke(IPC.AI_MESSAGE_LIST, { bookId, sessionId }),
|
|
chat: (
|
|
bookId: string,
|
|
sessionId: string,
|
|
content: string,
|
|
prompt?: string
|
|
): Promise<IpcResult<{ messageId: string }>> =>
|
|
ipcRenderer.invoke(IPC.AI_CHAT, { bookId, sessionId, content, prompt }),
|
|
abort: (messageId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.AI_ABORT, { messageId }),
|
|
buildContext: (
|
|
bookId: string,
|
|
binding: AiContextBinding
|
|
): Promise<IpcResult<AiContextBuildResult>> =>
|
|
ipcRenderer.invoke(IPC.AI_BUILD_CONTEXT, { bookId, binding }),
|
|
testConnection: (config?: AiConfig): Promise<IpcResult<{ ok: true }>> =>
|
|
ipcRenderer.invoke(IPC.AI_TEST_CONNECTION, { config }),
|
|
namingCheck: (bookId: string): Promise<IpcResult<NamingConflict[]>> =>
|
|
ipcRenderer.invoke(IPC.AI_NAMING_CHECK, { bookId })
|
|
},
|
|
interactive: {
|
|
checkGate: (bookId: string): Promise<IpcResult<InteractiveGateResult>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_CHECK_GATE, { bookId }),
|
|
getFlow: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow | null>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_GET_FLOW, { bookId, sessionId }),
|
|
start: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_START, { bookId, sessionId }),
|
|
confirmContext: (
|
|
bookId: string,
|
|
flowId: string,
|
|
binding: AiContextBinding
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_CONFIRM_CONTEXT, { bookId, flowId, binding }),
|
|
suggestPlots: (bookId: string, flowId: string): Promise<IpcResult<PlotOption[]>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_SUGGEST_PLOTS, { bookId, flowId }),
|
|
selectPlot: (
|
|
bookId: string,
|
|
flowId: string,
|
|
selection: PlotSelection
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_SELECT_PLOT, { bookId, flowId, selection }),
|
|
generateScene: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_GENERATE_SCENE, { bookId, flowId }),
|
|
resolveNaming: (
|
|
bookId: string,
|
|
flowId: string,
|
|
chosenName: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_RESOLVE_NAMING, { bookId, flowId, chosenName }),
|
|
refineScene: (
|
|
bookId: string,
|
|
flowId: string,
|
|
instruction: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_REFINE_SCENE, { bookId, flowId, instruction }),
|
|
acceptScene: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_ACCEPT_SCENE, { bookId, flowId }),
|
|
finishChapter: (
|
|
bookId: string,
|
|
flowId: string,
|
|
volumeId: string,
|
|
title?: string
|
|
): Promise<IpcResult<{ chapterId: string }>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_FINISH_CHAPTER, { bookId, flowId, volumeId, title }),
|
|
abort: (flowId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_ABORT, { flowId }),
|
|
getSceneDraft: (bookId: string, flowId: string): Promise<IpcResult<string>> =>
|
|
ipcRenderer.invoke(IPC.INTERACTIVE_GET_SCENE_DRAFT, { bookId, flowId })
|
|
},
|
|
auto: {
|
|
checkGate: (bookId: string): Promise<IpcResult<InteractiveGateResult>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_CHECK_GATE, { bookId }),
|
|
getFlow: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow | null>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_GET_FLOW, { bookId, sessionId }),
|
|
start: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_START, { bookId, sessionId }),
|
|
setGoal: (
|
|
bookId: string,
|
|
flowId: string,
|
|
config: Partial<AutoWritingConfig>
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_SET_GOAL, { bookId, flowId, config }),
|
|
confirmContext: (
|
|
bookId: string,
|
|
flowId: string,
|
|
binding: AiContextBinding
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_CONFIRM_CONTEXT, { bookId, flowId, binding }),
|
|
planScenes: (
|
|
bookId: string,
|
|
flowId: string,
|
|
contextSummary?: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_PLAN_SCENES, { bookId, flowId, contextSummary }),
|
|
generate: (
|
|
bookId: string,
|
|
flowId: string,
|
|
contextSummary?: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_GENERATE, { bookId, flowId, contextSummary }),
|
|
resolveNaming: (
|
|
bookId: string,
|
|
flowId: string,
|
|
chosenName: string,
|
|
contextSummary?: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_RESOLVE_NAMING, { bookId, flowId, chosenName, contextSummary }),
|
|
pause: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_PAUSE, { bookId, flowId }),
|
|
resume: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_RESUME, { bookId, flowId }),
|
|
handoffInteractive: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_HANDOFF_INTERACTIVE, { bookId, flowId }),
|
|
finishChapter: (
|
|
bookId: string,
|
|
flowId: string,
|
|
volumeId: string,
|
|
title?: string
|
|
): Promise<IpcResult<{ chapterId: string }>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_FINISH_CHAPTER, { bookId, flowId, volumeId, title }),
|
|
abort: (flowId: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_ABORT, { flowId }),
|
|
getSceneDraft: (bookId: string, flowId: string): Promise<IpcResult<string>> =>
|
|
ipcRenderer.invoke(IPC.AUTO_GET_SCENE_DRAFT, { bookId, flowId })
|
|
},
|
|
wizard: {
|
|
getFlow: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow | null>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_GET_FLOW, { bookId, sessionId }),
|
|
start: (bookId: string, sessionId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_START, { bookId, sessionId }),
|
|
setGoal: (
|
|
bookId: string,
|
|
flowId: string,
|
|
config: Partial<AutoWritingConfig>
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_SET_GOAL, { bookId, flowId, config }),
|
|
setRhythm: (
|
|
bookId: string,
|
|
flowId: string,
|
|
rhythm: AutoRhythm,
|
|
styleNote?: string
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_SET_RHYTHM, { bookId, flowId, rhythm, styleNote }),
|
|
setPov: (bookId: string, flowId: string, povSettingId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_SET_POV, { bookId, flowId, povSettingId }),
|
|
confirmContext: (
|
|
bookId: string,
|
|
flowId: string,
|
|
binding: AiContextBinding
|
|
): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_CONFIRM_CONTEXT, { bookId, flowId, binding }),
|
|
buildPreview: (
|
|
bookId: string,
|
|
flowId: string
|
|
): Promise<IpcResult<{ preview: string; flow: InteractiveFlow }>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_BUILD_PREVIEW, { bookId, flowId }),
|
|
startGenerate: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_START_GENERATE, { bookId, flowId }),
|
|
handoffInteractive: (bookId: string, flowId: string): Promise<IpcResult<InteractiveFlow>> =>
|
|
ipcRenderer.invoke(IPC.WIZARD_HANDOFF_INTERACTIVE, { bookId, flowId }),
|
|
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 }),
|
|
suggestContext: (
|
|
bookId: string,
|
|
opts?: KnowledgeSuggestOptions
|
|
): Promise<IpcResult<ScoredKnowledge[]>> =>
|
|
ipcRenderer.invoke(IPC.KNOWLEDGE_SUGGEST_CONTEXT, { bookId, opts }),
|
|
extractChapter: (
|
|
bookId: string,
|
|
chapterId: string
|
|
): Promise<IpcResult<KnowledgeExtractionResult>> =>
|
|
ipcRenderer.invoke(IPC.KNOWLEDGE_EXTRACT_CHAPTER, { bookId, chapterId }),
|
|
approveMerge: (bookId: string, pendingId: string): Promise<IpcResult<KnowledgeEntry>> =>
|
|
ipcRenderer.invoke(IPC.KNOWLEDGE_APPROVE_MERGE, { bookId, pendingId }),
|
|
saveMergeAsNew: (bookId: string, pendingId: string): Promise<IpcResult<KnowledgeEntry>> =>
|
|
ipcRenderer.invoke(IPC.KNOWLEDGE_SAVE_MERGE_AS_NEW, { bookId, pendingId }),
|
|
batchApproveHighConfidence: (
|
|
bookId: string,
|
|
threshold?: number
|
|
): Promise<IpcResult<number>> =>
|
|
ipcRenderer.invoke(IPC.KNOWLEDGE_BATCH_APPROVE_HIGH_CONFIDENCE, { bookId, threshold })
|
|
},
|
|
writing: {
|
|
getStats: (bookId: string): Promise<IpcResult<WritingStats>> =>
|
|
ipcRenderer.invoke(IPC.WRITING_GET_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,
|
|
scope: { kind: 'book' | 'volume' | 'chapter'; chapterId?: string; volumeId?: string }
|
|
): Promise<IpcResult<WordFreqResult>> =>
|
|
ipcRenderer.invoke(IPC.WORDFREQ_ANALYZE, { bookId, scope })
|
|
},
|
|
shortcut: {
|
|
getAll: (): Promise<IpcResult<Record<ActionId, string>>> =>
|
|
ipcRenderer.invoke(IPC.SHORTCUT_GET_ALL),
|
|
register: (action: ActionId, accelerator: string): Promise<IpcResult<void>> =>
|
|
ipcRenderer.invoke(IPC.SHORTCUT_REGISTER, { action, accelerator })
|
|
},
|
|
onShortcutTriggered: (callback: (action: ActionId) => void): (() => void) => {
|
|
const handler = (_event: IpcRendererEvent, payload: { action: ActionId }) => {
|
|
callback(payload.action)
|
|
}
|
|
ipcRenderer.on(IPC.SHORTCUT_TRIGGERED, handler)
|
|
return () => ipcRenderer.removeListener(IPC.SHORTCUT_TRIGGERED, handler)
|
|
},
|
|
onAiStreamChunk: (callback: (payload: AiStreamChunkEvent) => void): (() => void) => {
|
|
const handler = (_event: IpcRendererEvent, payload: AiStreamChunkEvent) => {
|
|
callback(payload)
|
|
}
|
|
ipcRenderer.on(IPC.AI_STREAM_CHUNK, handler)
|
|
return () => ipcRenderer.removeListener(IPC.AI_STREAM_CHUNK, handler)
|
|
},
|
|
onAiNetworkStatus: (callback: (payload: AiNetworkStatusEvent) => void): (() => void) => {
|
|
const handler = (_event: IpcRendererEvent, payload: AiNetworkStatusEvent) => {
|
|
callback(payload)
|
|
}
|
|
ipcRenderer.on(IPC.AI_NETWORK_STATUS, handler)
|
|
return () => ipcRenderer.removeListener(IPC.AI_NETWORK_STATUS, handler)
|
|
},
|
|
onInteractiveStreamChunk: (callback: (payload: InteractiveStreamChunkEvent) => void): (() => void) => {
|
|
const handler = (_event: IpcRendererEvent, payload: InteractiveStreamChunkEvent) => {
|
|
callback(payload)
|
|
}
|
|
ipcRenderer.on(IPC.INTERACTIVE_STREAM_CHUNK, handler)
|
|
return () => ipcRenderer.removeListener(IPC.INTERACTIVE_STREAM_CHUNK, handler)
|
|
}
|
|
}
|
|
|
|
contextBridge.exposeInMainWorld('electronAPI', electronAPI)
|
|
|
|
export type ElectronAPI = typeof electronAPI
|