| 1 | import type { |
| 2 | FontSelection, |
| 3 | GenerateAddPagePayload, |
| 4 | GenerateChunkEvent, |
| 5 | GenerateRetryFailedPayload, |
| 6 | GenerateRetrySinglePagePayload, |
| 7 | GenerateStartPayload, |
| 8 | SessionPageEditAssessment, |
| 9 | ParseDocumentPlanPayload, |
| 10 | ParseImageReferencePayload, |
| 11 | ParsedDocumentPlanResult, |
| 12 | PrepareReferenceDocumentPayload, |
| 13 | PreparedReferenceDocumentResult, |
| 14 | SourceDocumentPlan, |
| 15 | SwitchSessionStylePayload, |
| 16 | RetrySessionStylePayload, |
| 17 | RetryDeckEditPayload, |
| 18 | PptxImportPayload, |
| 19 | PptxImportProgressPayload, |
| 20 | PptxImportResult, |
| 21 | UploadedAsset |
| 22 | } from '@shared/generation.js' |
| 23 | import type { UpdateAvailablePayload } from '@shared/app-update.js' |
| 24 | import type { SpeechConfig } from '@shared/speech' |
| 25 | import type { HistoryVersion, RollbackHistoryResult } from '@shared/history.js' |
| 26 | import type { HtmlThumbnailResourceType } from '@shared/thumbnail' |
| 27 | import type { IndexTransitionConfig, IndexTransitionType } from '@shared/index-transition.js' |
| 28 | import type { ElementAnimationConfig, ElementAnimationPatch } from '@shared/element-animation.js' |
| 29 | import type { |
| 30 | ThinkingStage, |
| 31 | ThinkingChatMessage, |
| 32 | ThinkingWorkspace, |
| 33 | ThinkingChatResult, |
| 34 | ThinkingPrepareGenerationResult, |
| 35 | ThinkingWorkspaceListItem |
| 36 | } from '@shared/thinking.js' |
| 37 | import type { |
| 38 | GeneratedImageAsset, |
| 39 | ImageGenerateResult, |
| 40 | ImageGeneratePayload, |
| 41 | ImagePromptGeneratePayload, |
| 42 | ImagePromptGenerateResult, |
| 43 | ImageGenerationHistoryRecord, |
| 44 | ImageModelConfig, |
| 45 | ImageModelProvider |
| 46 | } from '@shared/image-generation.js' |
| 47 | import type { ThinkingParameterMode } from '@shared/model-config.js' |
| 48 | import type { ExportProgressPayload } from '@shared/export-progress.js' |
| 49 | import type { PageMergeDisabledReason } from '@shared/page-merge' |
| 50 | import type { ModelUsagePeriod, ModelUsageStats } from '@shared/model-usage' |
| 51 | import type { SlideSizePresetId } from '@shared/slide-size' |
| 52 | import type { ParsedChartDataResult } from '@shared/chart-data' |
| 53 | import type { SessionMasterConfig, SessionMasterStatus } from '@shared/master' |
| 54 | import type { SessionLayoutLibrary, SessionLayoutLibraryStatus } from '@shared/layout-master' |
| 55 | |
| 56 | type IpcRendererLike = Window['electron']['ipcRenderer'] |
| 57 | |
| 58 | function getIpc(): IpcRendererLike { |
| 59 | const ipc = window.electron?.ipcRenderer |
| 60 | if (!ipc) { |
| 61 | const electronKeys = window.electron ? Object.keys(window.electron).join(', ') : 'none' |
| 62 | throw new Error(`Electron preload IPC is unavailable. window.electron keys: ${electronKeys}`) |
| 63 | } |
| 64 | return ipc |
| 65 | } |
| 66 | |
| 67 | export interface StyleCategory { |
| 68 | name: string |
| 69 | styles: Array<{ |
| 70 | id: string |
| 71 | label: string |
| 72 | description: string |
| 73 | source?: 'builtin' | 'custom' | 'override' |
| 74 | editable?: boolean |
| 75 | styleCase?: string |
| 76 | }> |
| 77 | } |
| 78 | |
| 79 | export interface StyleDetail { |
| 80 | id: string |
| 81 | styleKey?: string |
| 82 | label: string |
| 83 | name?: { |
| 84 | zh: string |
| 85 | en: string |
| 86 | } |
| 87 | description: string |
| 88 | aliases: string[] |
| 89 | styleSkill: string |
| 90 | source?: 'builtin' | 'custom' | 'override' |
| 91 | editable?: boolean |
| 92 | category?: string |
| 93 | version?: string |
| 94 | styleCase?: string |
| 95 | packageDir?: string |
| 96 | } |
| 97 | |
| 98 | export interface StyleListItem { |
| 99 | id: string |
| 100 | styleKey?: string |
| 101 | label: string |
| 102 | name?: { |
| 103 | zh: string |
| 104 | en: string |
| 105 | } |
| 106 | description: string |
| 107 | aliases?: string[] |
| 108 | category: string |
| 109 | source?: 'builtin' | 'custom' | 'override' |
| 110 | editable?: boolean |
| 111 | version?: string |
| 112 | styleCase?: string |
| 113 | packageDir?: string |
| 114 | favoriteAt?: number | null |
| 115 | previewPath?: string | null |
| 116 | thumbnailPath?: string | null |
| 117 | createdAt?: number |
| 118 | updatedAt?: number |
| 119 | } |
| 120 | |
| 121 | export interface HtmlThumbnailTask { |
| 122 | resourceType: HtmlThumbnailResourceType |
| 123 | resourceId: string |
| 124 | variant: string |
| 125 | status: 'queued' | 'running' | 'completed' | 'failed' |
| 126 | thumbnailPath: string | null |
| 127 | error?: string |
| 128 | } |
| 129 | |
| 130 | export interface StyleParseResult { |
| 131 | label: string |
| 132 | description: string |
| 133 | category: string |
| 134 | aliases: string[] |
| 135 | styleSkill: string |
| 136 | styleCase?: string |
| 137 | } |
| 138 | |
| 139 | export interface GenerateRunStateSnapshot { |
| 140 | sessionId: string |
| 141 | runId: string | null |
| 142 | status: 'idle' | 'queued' | 'running' | 'completed' | 'failed' | 'cancelled' |
| 143 | hasActiveRun: boolean |
| 144 | progress: number |
| 145 | totalPages: number |
| 146 | completedPageCount?: number |
| 147 | failedPageCount?: number |
| 148 | events: GenerateChunkEvent[] |
| 149 | error: string | null |
| 150 | startedAt: number | null |
| 151 | updatedAt: number | null |
| 152 | kind?: |
| 153 | | 'standard' |
| 154 | | 'template' |
| 155 | | 'retry' |
| 156 | | 'add-page' |
| 157 | | 'single-page-retry' |
| 158 | | 'edit' |
| 159 | | 'page-edit' |
| 160 | | 'deck-edit' |
| 161 | | 'style-switch' |
| 162 | | 'page-beautify' |
| 163 | targetPageId?: string |
| 164 | targetPageNumber?: number |
| 165 | activityKind?: |
| 166 | | 'page-edit' |
| 167 | | 'deck-edit' |
| 168 | | 'edit' |
| 169 | | 'style-switch' |
| 170 | | 'page-beautify' |
| 171 | | 'single-page-retry' |
| 172 | | 'addPage' |
| 173 | retryPayload?: GenerateStartPayload |
| 174 | } |
| 175 | |
| 176 | export interface StyleSwitchJobSnapshot { |
| 177 | sessionId: string |
| 178 | runId: string | null |
| 179 | status: 'idle' | 'running' | 'completed' | 'partial' | 'failed' | 'cancelled' |
| 180 | hasActiveRun: boolean |
| 181 | progress: number |
| 182 | totalPages: number |
| 183 | completedPageCount: number |
| 184 | failedPageCount: number |
| 185 | targetStyleId: string | null |
| 186 | targetStyleName: string | null |
| 187 | pages: Array<{ |
| 188 | pageId: string |
| 189 | pageNumber: number |
| 190 | title: string |
| 191 | status: 'pending' | 'running' | 'completed' | 'failed' |
| 192 | error: string | null |
| 193 | retryCount: number |
| 194 | }> |
| 195 | error: string | null |
| 196 | startedAt: number | null |
| 197 | updatedAt: number | null |
| 198 | kind: 'style-switch' |
| 199 | } |
| 200 | |
| 201 | export interface ExportDeckResult { |
| 202 | success: boolean |
| 203 | cancelled?: boolean |
| 204 | path?: string |
| 205 | warnings?: string[] |
| 206 | pageCount?: number |
| 207 | durationMs?: number |
| 208 | frameCount?: number |
| 209 | } |
| 210 | |
| 211 | export interface MergeSourceSessionSummary { |
| 212 | id: string |
| 213 | title: string |
| 214 | pageCount: number |
| 215 | slideSizeId: SlideSizePresetId |
| 216 | slideWidth: number |
| 217 | slideHeight: number |
| 218 | updatedAt: number |
| 219 | status: string |
| 220 | selectable: boolean |
| 221 | disabledReason?: PageMergeDisabledReason |
| 222 | } |
| 223 | |
| 224 | export interface MergeTemplateSourceSummary { |
| 225 | id: string |
| 226 | title: string |
| 227 | pageCount: number |
| 228 | slideSizeId: SlideSizePresetId |
| 229 | slideWidth: number |
| 230 | slideHeight: number |
| 231 | updatedAt: number |
| 232 | thumbnailPath: string | null |
| 233 | selectable: boolean |
| 234 | disabledReason?: PageMergeDisabledReason |
| 235 | isSource: boolean |
| 236 | } |
| 237 | |
| 238 | export interface MergeSourcePageSummary { |
| 239 | id: string |
| 240 | pageId: string |
| 241 | pageNumber: number |
| 242 | title: string |
| 243 | contentOutline?: string | null |
| 244 | slideSizeId: SlideSizePresetId |
| 245 | slideWidth: number |
| 246 | slideHeight: number |
| 247 | htmlPath?: string |
| 248 | sourceUrl?: string |
| 249 | status?: string |
| 250 | selectable: boolean |
| 251 | disabledReason?: PageMergeDisabledReason |
| 252 | } |
| 253 | |
| 254 | export interface ImportSessionFileResult { |
| 255 | success: boolean |
| 256 | cancelled?: boolean |
| 257 | sessionId?: string |
| 258 | title?: string |
| 259 | pageCount?: number |
| 260 | warnings?: string[] |
| 261 | } |
| 262 | |
| 263 | export interface HtmlEditorImportResult { |
| 264 | docId: string |
| 265 | title: string |
| 266 | htmlPath: string |
| 267 | sourcePath: string |
| 268 | designWidth: number |
| 269 | html: string |
| 270 | } |
| 271 | |
| 272 | export interface HtmlEditorAiMessage { |
| 273 | role: 'user' | 'assistant' |
| 274 | content: string |
| 275 | selectedElement?: HtmlEditorAiElementContext |
| 276 | } |
| 277 | |
| 278 | export interface HtmlEditorAiElementContext { |
| 279 | selector: string |
| 280 | label?: string |
| 281 | elementTag?: string |
| 282 | elementText?: string |
| 283 | html?: string |
| 284 | } |
| 285 | |
| 286 | export interface HtmlEditorAiEditBatch { |
| 287 | propertyEdits: Array<Record<string, unknown>> |
| 288 | textEdits: Array<Record<string, unknown>> |
| 289 | dragEdits: Array<Record<string, unknown>> |
| 290 | deletes: Array<Record<string, unknown>> |
| 291 | addElements: Array<Record<string, unknown>> |
| 292 | } |
| 293 | |
| 294 | export type HtmlEditorAiIntent = 'inspect' | 'redesign' | 'style' | 'layout' | 'content' | 'other' |
| 295 | |
| 296 | export interface HtmlEditorAiPlan { |
| 297 | intent: HtmlEditorAiIntent |
| 298 | target: string |
| 299 | summary: string |
| 300 | changes: string[] |
| 301 | confirmationQuestion: string |
| 302 | edits: HtmlEditorAiEditBatch |
| 303 | } |
| 304 | |
| 305 | export interface HtmlEditorAiHistoryMessage extends HtmlEditorAiMessage { |
| 306 | id: string |
| 307 | createdAt: number |
| 308 | intent?: HtmlEditorAiIntent |
| 309 | plan?: HtmlEditorAiPlan | null |
| 310 | requiresConfirmation?: boolean |
| 311 | } |
| 312 | |
| 313 | export type HtmlEditorFileImportResult = |
| 314 | | { cancelled: true; reason?: 'user-cancelled' | 'storage-not-configured' } |
| 315 | | ({ cancelled: false } & HtmlEditorImportResult) |
| 316 | |
| 317 | export interface TemplateListItem { |
| 318 | id: string |
| 319 | name: string |
| 320 | description: string |
| 321 | source: 'user' |
| 322 | pageCount: number |
| 323 | tags: string[] |
| 324 | slideSizeId?: import('@shared/slide-size').SlideSizePresetId |
| 325 | slideWidth?: number |
| 326 | slideHeight?: number |
| 327 | previewHtmlPath: string | null |
| 328 | thumbnailPath: string | null |
| 329 | previewPages: Array<{ |
| 330 | pageNumber: number |
| 331 | pageId: string |
| 332 | title: string |
| 333 | htmlPath: string |
| 334 | }> |
| 335 | createdAt: number |
| 336 | updatedAt: number |
| 337 | } |
| 338 | |
| 339 | export interface EnsureElementAnchorPayload { |
| 340 | sessionId?: string |
| 341 | htmlPath: string |
| 342 | pageId: string |
| 343 | selector: string |
| 344 | elementTag?: string |
| 345 | elementText?: string |
| 346 | reason?: 'inspect' | 'drag' | 'text-edit' |
| 347 | formula?: { |
| 348 | latex: string |
| 349 | html: string |
| 350 | displayMode: boolean |
| 351 | } |
| 352 | } |
| 353 | |
| 354 | export interface EnsureElementAnchorResult { |
| 355 | success: boolean |
| 356 | selector: string |
| 357 | blockId: string |
| 358 | changed: boolean |
| 359 | } |
| 360 | |
| 361 | export interface UploadAssetsPayload { |
| 362 | sessionId: string |
| 363 | files: Array<{ |
| 364 | path: string |
| 365 | name?: string |
| 366 | }> |
| 367 | } |
| 368 | |
| 369 | export interface UpdateElementLayoutPayload { |
| 370 | sessionId: string |
| 371 | htmlPath: string |
| 372 | pageId: string |
| 373 | selector: string |
| 374 | x: number |
| 375 | y: number |
| 376 | width?: number |
| 377 | height?: number |
| 378 | childUpdates?: Array<{ |
| 379 | path: number[] |
| 380 | width?: number |
| 381 | height?: number |
| 382 | }> |
| 383 | isAbsoluteMode?: boolean |
| 384 | } |
| 385 | |
| 386 | export interface UpdateElementPropertiesPayload { |
| 387 | sessionId: string |
| 388 | htmlPath: string |
| 389 | pageId: string |
| 390 | selector: string |
| 391 | patch: { |
| 392 | html?: string |
| 393 | text?: string |
| 394 | textTarget?: { |
| 395 | type: 'text-node' |
| 396 | parentSelector: string |
| 397 | textNodeIndex: number |
| 398 | text: string |
| 399 | } |
| 400 | style?: { |
| 401 | color?: string |
| 402 | fontSize?: string |
| 403 | fontWeight?: string |
| 404 | textAlign?: string |
| 405 | } |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | export interface CreateSessionPayload { |
| 410 | topic: string |
| 411 | styleId: string |
| 412 | modelConfigId?: string |
| 413 | pageCount?: number |
| 414 | slideSizeId?: import('@shared/slide-size').SlideSizePresetId |
| 415 | referenceDocumentPath?: string |
| 416 | fontSelection?: FontSelection |
| 417 | sourcePlan?: SourceDocumentPlan |
| 418 | } |
| 419 | |
| 420 | export interface SaveSessionAsNewPayload { |
| 421 | sessionId: string |
| 422 | title: string |
| 423 | } |
| 424 | |
| 425 | export interface SaveSessionAsNewResult { |
| 426 | sessionId: string |
| 427 | } |
| 428 | |
| 429 | export interface ModelConfig { |
| 430 | id: string |
| 431 | name: string |
| 432 | provider: 'anthropic' | 'openai' | 'openai-responses' | 'google' |
| 433 | model: string |
| 434 | apiKey: string |
| 435 | baseUrl: string |
| 436 | maxTokens: number |
| 437 | disableTemperature: boolean |
| 438 | thinkingParameterMode: ThinkingParameterMode |
| 439 | active: boolean |
| 440 | createdAt: number |
| 441 | updatedAt: number |
| 442 | } |
| 443 | |
| 444 | export type { GeneratedImageAsset, ImageModelConfig, ImageModelProvider } |
| 445 | |
| 446 | export interface UploadPrerequisitesResult { |
| 447 | ready: boolean |
| 448 | missing: Array<'storagePath' | 'activeModel' | 'apiKey' | 'model'> |
| 449 | message?: string |
| 450 | } |
| 451 | |
| 452 | export type FontRole = 'title' | 'body' |
| 453 | export type FontScript = 'latin' | 'cjk' |
| 454 | |
| 455 | export interface FontFileEntry { |
| 456 | file: string |
| 457 | weight: number |
| 458 | style: 'normal' | 'italic' |
| 459 | size?: number |
| 460 | sha256?: string |
| 461 | } |
| 462 | |
| 463 | export interface FontListItem { |
| 464 | id: string |
| 465 | family: string |
| 466 | source: 'google' | 'uploaded' |
| 467 | category: string |
| 468 | role: FontRole[] |
| 469 | scripts: FontScript[] |
| 470 | files?: FontFileEntry[] |
| 471 | createdAt?: number |
| 472 | updatedAt?: number |
| 473 | } |
| 474 | |
| 475 | export interface FontRegistryResponse { |
| 476 | googleFonts: FontListItem[] |
| 477 | userFonts: FontListItem[] |
| 478 | } |
| 479 | |
| 480 | export interface UploadFontPayload { |
| 481 | files: Array<{ |
| 482 | path: string |
| 483 | weight?: number |
| 484 | style?: 'normal' | 'italic' |
| 485 | }> |
| 486 | family: string |
| 487 | category?: string |
| 488 | role?: FontRole[] |
| 489 | scripts?: FontScript[] |
| 490 | } |
| 491 | |
| 492 | export const ipc = { |
| 493 | createSession: (payload: CreateSessionPayload) => |
| 494 | getIpc().invoke('session:create', payload) as Promise<{ sessionId: string }>, |
| 495 | listSessions: () => getIpc().invoke('session:list') as Promise<unknown[]>, |
| 496 | listMergeSourceSessions: (payload: { targetSessionId: string }) => |
| 497 | getIpc().invoke('session:listMergeSources', payload) as Promise<MergeSourceSessionSummary[]>, |
| 498 | listMergeSourcePages: (payload: { targetSessionId: string; sourceSessionId: string }) => |
| 499 | getIpc().invoke('session:listMergeSourcePages', payload) as Promise<MergeSourcePageSummary[]>, |
| 500 | mergeSessionPages: (payload: { |
| 501 | targetSessionId: string |
| 502 | sourceSessionId: string |
| 503 | sourcePageIds: string[] |
| 504 | }) => |
| 505 | getIpc().invoke('session:mergePages', payload) as Promise<{ |
| 506 | ok: true |
| 507 | generatedPages: Array<{ |
| 508 | id: string |
| 509 | pageNumber: number |
| 510 | pageId: string |
| 511 | title: string |
| 512 | contentOutline?: string | null |
| 513 | html: string |
| 514 | htmlPath: string |
| 515 | sourceUrl?: string |
| 516 | status?: string |
| 517 | error?: string | null |
| 518 | }> |
| 519 | insertedPageIds: string[] |
| 520 | selectedPageId: string |
| 521 | }>, |
| 522 | listMergeSourceTemplates: (payload: { targetSessionId: string }) => |
| 523 | getIpc().invoke('session:listMergeSourceTemplates', payload) as Promise< |
| 524 | MergeTemplateSourceSummary[] |
| 525 | >, |
| 526 | listMergeSourceTemplatePages: (payload: { targetSessionId: string; templateId: string }) => |
| 527 | getIpc().invoke('session:listMergeSourcePages', { |
| 528 | targetSessionId: payload.targetSessionId, |
| 529 | sourceType: 'template', |
| 530 | templateId: payload.templateId |
| 531 | }) as Promise<MergeSourcePageSummary[]>, |
| 532 | mergeTemplatePages: (payload: { |
| 533 | targetSessionId: string |
| 534 | templateId: string |
| 535 | sourcePageIds: string[] |
| 536 | }) => |
| 537 | getIpc().invoke('session:mergePages', { |
| 538 | targetSessionId: payload.targetSessionId, |
| 539 | sourceType: 'template', |
| 540 | templateId: payload.templateId, |
| 541 | sourcePageIds: payload.sourcePageIds |
| 542 | }) as Promise<{ |
| 543 | ok: true |
| 544 | generatedPages: Array<{ |
| 545 | id: string |
| 546 | pageNumber: number |
| 547 | pageId: string |
| 548 | title: string |
| 549 | contentOutline?: string | null |
| 550 | html: string |
| 551 | htmlPath: string |
| 552 | sourceUrl?: string |
| 553 | status?: string |
| 554 | error?: string | null |
| 555 | }> |
| 556 | insertedPageIds: string[] |
| 557 | selectedPageId: string |
| 558 | }>, |
| 559 | saveSessionAsNew: (payload: SaveSessionAsNewPayload): Promise<SaveSessionAsNewResult> => |
| 560 | getIpc().invoke('session:saveAsNew', payload) as Promise<SaveSessionAsNewResult>, |
| 561 | getSessionMaster: (payload: { sessionId: string }): Promise<SessionMasterStatus> => |
| 562 | getIpc().invoke('session:getMaster', payload) as Promise<SessionMasterStatus>, |
| 563 | saveSessionMaster: (payload: { |
| 564 | sessionId: string |
| 565 | config: SessionMasterConfig |
| 566 | }): Promise<SessionMasterStatus> => |
| 567 | getIpc().invoke('session:saveMaster', payload) as Promise<SessionMasterStatus>, |
| 568 | setSessionMasterPageOverride: (payload: { |
| 569 | sessionId: string |
| 570 | pageId: string |
| 571 | disabled: boolean |
| 572 | }): Promise<{ disabled: boolean }> => |
| 573 | getIpc().invoke('session:setMasterPageOverride', payload) as Promise<{ disabled: boolean }>, |
| 574 | getSessionLayoutLibrary: (payload: { sessionId: string }): Promise<SessionLayoutLibraryStatus> => |
| 575 | getIpc().invoke('session:getLayoutLibrary', payload) as Promise<SessionLayoutLibraryStatus>, |
| 576 | saveSessionLayoutLibrary: (payload: { |
| 577 | sessionId: string |
| 578 | library: SessionLayoutLibrary |
| 579 | }): Promise<SessionLayoutLibraryStatus> => |
| 580 | getIpc().invoke('session:saveLayoutLibrary', payload) as Promise<SessionLayoutLibraryStatus>, |
| 581 | getSession: (sessionId: string) => |
| 582 | getIpc().invoke('session:get', sessionId) as Promise<{ |
| 583 | session: unknown |
| 584 | messages: unknown[] |
| 585 | generatedPages: Array<{ |
| 586 | id: string |
| 587 | pageNumber: number |
| 588 | title: string |
| 589 | contentOutline?: string | null |
| 590 | html: string |
| 591 | htmlPath?: string |
| 592 | pageId?: string |
| 593 | sourceUrl?: string |
| 594 | status?: string |
| 595 | error?: string | null |
| 596 | }> |
| 597 | }>, |
| 598 | getIndexTransition: (sessionId: string) => |
| 599 | getIpc().invoke('session:getIndexTransition', { sessionId }) as Promise<IndexTransitionConfig>, |
| 600 | setIndexTransition: (payload: { |
| 601 | sessionId: string |
| 602 | type: IndexTransitionType |
| 603 | durationMs?: number |
| 604 | }) => |
| 605 | getIpc().invoke('session:setIndexTransition', payload) as Promise<{ |
| 606 | ok: boolean |
| 607 | transition: IndexTransitionConfig |
| 608 | }>, |
| 609 | migratePageOutlinesToSourceSkeletons: (payload: { sessionId: string }) => |
| 610 | getIpc().invoke('session:migratePageOutlinesToSourceSkeletons', payload) as Promise<{ |
| 611 | migrated: boolean |
| 612 | migratedCount: number |
| 613 | existingCount: number |
| 614 | }>, |
| 615 | reorderSessionPages: (payload: { |
| 616 | sessionId: string |
| 617 | orderedPageIds: string[] |
| 618 | selectedPageId?: string |
| 619 | }) => |
| 620 | getIpc().invoke('session:reorderPages', payload) as Promise<{ |
| 621 | ok: boolean |
| 622 | generatedPages: Array<{ |
| 623 | id: string |
| 624 | pageNumber: number |
| 625 | pageId: string |
| 626 | title: string |
| 627 | contentOutline?: string | null |
| 628 | html: string |
| 629 | htmlPath?: string |
| 630 | status?: string |
| 631 | error?: string | null |
| 632 | }> |
| 633 | selectedPageId: string | null |
| 634 | }>, |
| 635 | deleteSessionPages: (payload: { |
| 636 | sessionId: string |
| 637 | pageIds: string[] |
| 638 | selectedPageId?: string |
| 639 | }) => |
| 640 | getIpc().invoke('session:deletePages', payload) as Promise<{ |
| 641 | ok: boolean |
| 642 | generatedPages: Array<{ |
| 643 | id: string |
| 644 | pageNumber: number |
| 645 | pageId: string |
| 646 | title: string |
| 647 | contentOutline?: string | null |
| 648 | html: string |
| 649 | htmlPath?: string |
| 650 | status?: string |
| 651 | error?: string | null |
| 652 | }> |
| 653 | selectedPageId: string | null |
| 654 | }>, |
| 655 | createBlankSessionPage: (payload: { sessionId: string; sourcePageId: string }) => |
| 656 | getIpc().invoke('session:createBlankPage', payload) as Promise<{ |
| 657 | ok: boolean |
| 658 | generatedPages: Array<{ |
| 659 | id: string |
| 660 | pageNumber: number |
| 661 | pageId: string |
| 662 | title: string |
| 663 | contentOutline?: string | null |
| 664 | html: string |
| 665 | htmlPath?: string |
| 666 | status?: string |
| 667 | error?: string | null |
| 668 | }> |
| 669 | selectedPageId: string | null |
| 670 | }>, |
| 671 | duplicateSessionPage: (payload: { sessionId: string; sourcePageId: string }) => |
| 672 | getIpc().invoke('session:duplicatePage', payload) as Promise<{ |
| 673 | ok: boolean |
| 674 | generatedPages: Array<{ |
| 675 | id: string |
| 676 | pageNumber: number |
| 677 | pageId: string |
| 678 | title: string |
| 679 | contentOutline?: string | null |
| 680 | html: string |
| 681 | htmlPath?: string |
| 682 | status?: string |
| 683 | error?: string | null |
| 684 | }> |
| 685 | selectedPageId: string | null |
| 686 | }>, |
| 687 | updateSessionPageTitle: (payload: { sessionId: string; pageId: string; title: string }) => |
| 688 | getIpc().invoke('session:updatePageTitle', payload) as Promise<{ |
| 689 | ok: boolean |
| 690 | generatedPages: Array<{ |
| 691 | id: string |
| 692 | pageNumber: number |
| 693 | pageId: string |
| 694 | title: string |
| 695 | contentOutline?: string | null |
| 696 | html: string |
| 697 | htmlPath?: string |
| 698 | status?: string |
| 699 | error?: string | null |
| 700 | }> |
| 701 | selectedPageId: string | null |
| 702 | }>, |
| 703 | updateSessionPageOutline: (payload: { |
| 704 | sessionId: string |
| 705 | pageId: string |
| 706 | contentOutline: string |
| 707 | }) => |
| 708 | getIpc().invoke('session:updatePageOutline', payload) as Promise<{ |
| 709 | ok: boolean |
| 710 | generatedPages: Array<{ |
| 711 | id: string |
| 712 | pageNumber: number |
| 713 | pageId: string |
| 714 | title: string |
| 715 | contentOutline?: string | null |
| 716 | html: string |
| 717 | htmlPath?: string |
| 718 | status?: string |
| 719 | error?: string | null |
| 720 | }> |
| 721 | selectedPageId: string | null |
| 722 | }>, |
| 723 | getSessionMessages: (payload: { |
| 724 | sessionId: string |
| 725 | chatType: 'main' | 'page' |
| 726 | pageId?: string |
| 727 | }) => getIpc().invoke('session:getMessages', payload) as Promise<unknown[]>, |
| 728 | deleteSession: (sessionId: string) => |
| 729 | getIpc().invoke('session:delete', sessionId) as Promise<{ success: boolean }>, |
| 730 | updateSessionTitle: (payload: { sessionId: string; title: string }) => |
| 731 | getIpc().invoke('session:updateTitle', payload) as Promise<{ ok: boolean }>, |
| 732 | importSessionFile: () => |
| 733 | getIpc().invoke('session:importFile') as Promise<ImportSessionFileResult>, |
| 734 | importHtmlFile: () => |
| 735 | getIpc().invoke('html-editor:import') as Promise<HtmlEditorFileImportResult>, |
| 736 | listHtmlEditorMedia: (payload: { docId: string; mediaType: 'image' | 'video' }) => |
| 737 | getIpc().invoke('html-editor:listMedia', payload) as Promise<{ |
| 738 | assets: Array<{ fileName: string; filePath: string; relativePath: string; url: string }> |
| 739 | }>, |
| 740 | chooseAndImportHtmlMedia: (payload: { docId: string; mediaType: 'image' | 'video' }) => |
| 741 | getIpc().invoke('html-editor:chooseAndImportMedia', payload) as Promise< |
| 742 | | { cancelled: true } |
| 743 | | { cancelled: false; filePath: string; relativePath: string; url: string } |
| 744 | >, |
| 745 | ensureHtmlAnchor: (payload: { |
| 746 | html: string |
| 747 | pageId: string |
| 748 | selector: string |
| 749 | elementTag?: string |
| 750 | formula?: { latex?: unknown; html?: unknown; displayMode?: unknown } |
| 751 | }) => |
| 752 | getIpc().invoke('html-editor:ensureAnchor', payload) as Promise<{ |
| 753 | html: string |
| 754 | selector: string |
| 755 | blockId: string |
| 756 | changed: boolean |
| 757 | }>, |
| 758 | applyHtmlEdits: (payload: { |
| 759 | html: string |
| 760 | pageId: string |
| 761 | dragEdits?: unknown[] |
| 762 | textEdits?: unknown[] |
| 763 | propertyEdits?: unknown[] |
| 764 | deletes?: unknown[] |
| 765 | addElements?: unknown[] |
| 766 | }) => |
| 767 | getIpc().invoke('html-editor:applyEdits', payload) as Promise<{ |
| 768 | html: string |
| 769 | warnings: string[] |
| 770 | }>, |
| 771 | exportHtml: (payload: { html: string; suggestedName?: string }) => |
| 772 | getIpc().invoke('html-editor:export', payload) as Promise< |
| 773 | { cancelled: true } | { cancelled: false; path: string } |
| 774 | >, |
| 775 | cleanupHtmlEditor: (payload: { docId: string }) => |
| 776 | getIpc().invoke('html-editor:cleanup', payload) as Promise<{ ok: boolean }>, |
| 777 | openHtmlInBrowser: (payload: { docId: string }) => |
| 778 | getIpc().invoke('html-editor:openInBrowser', payload) as Promise<{ ok: boolean }>, |
| 779 | revealHtmlFile: (payload: { docId: string }) => |
| 780 | getIpc().invoke('html-editor:revealFile', payload) as Promise<{ ok: boolean }>, |
| 781 | listHtmlVersions: (payload: { docId: string }) => |
| 782 | getIpc().invoke('html-editor:listVersions', payload) as Promise<{ |
| 783 | versions: Array<{ id: string; commitSha: string; message: string; createdAt: number }> |
| 784 | }>, |
| 785 | restoreHtmlVersion: (payload: { docId: string; versionId: string }) => |
| 786 | getIpc().invoke('html-editor:restoreVersion', payload) as Promise<{ html: string }>, |
| 787 | listHtmlDocuments: () => |
| 788 | getIpc().invoke('html-editor:listDocuments') as Promise<{ |
| 789 | documents: Array<{ |
| 790 | id: string |
| 791 | title: string |
| 792 | sourcePath: string | null |
| 793 | htmlPath: string |
| 794 | designWidth: number |
| 795 | updatedAt: number |
| 796 | thumbnailPath: string | null |
| 797 | }> |
| 798 | }>, |
| 799 | openHtmlDocument: (payload: { docId: string }) => |
| 800 | getIpc().invoke('html-editor:openDocument', payload) as Promise<HtmlEditorFileImportResult>, |
| 801 | htmlEditorAiChat: (payload: { |
| 802 | documentId: string |
| 803 | documentTitle?: string |
| 804 | pageHtml?: string |
| 805 | selectedElement?: HtmlEditorAiElementContext |
| 806 | recentMessages?: HtmlEditorAiMessage[] |
| 807 | pendingPlan?: HtmlEditorAiPlan |
| 808 | userMessage: string |
| 809 | modelConfigId?: string |
| 810 | }) => |
| 811 | getIpc().invoke('html-editor:aiChat', payload) as Promise<{ |
| 812 | reply: string |
| 813 | model: string |
| 814 | intent: HtmlEditorAiIntent |
| 815 | plan: HtmlEditorAiPlan | null |
| 816 | requiresConfirmation: boolean |
| 817 | applied: boolean |
| 818 | appliedHtml?: string |
| 819 | warnings: string[] |
| 820 | }>, |
| 821 | listHtmlEditorMessages: (payload: { docId: string }) => |
| 822 | getIpc().invoke('html-editor:listMessages', payload) as Promise<{ |
| 823 | messages: HtmlEditorAiHistoryMessage[] |
| 824 | }>, |
| 825 | clearHtmlEditorMessages: (payload: { docId: string }) => |
| 826 | getIpc().invoke('html-editor:clearMessages', payload) as Promise<{ ok: boolean }>, |
| 827 | listTemplates: () => getIpc().invoke('templates:list') as Promise<{ items: TemplateListItem[] }>, |
| 828 | createTemplateFromSession: (payload: { |
| 829 | sessionId: string |
| 830 | name?: string |
| 831 | description?: string |
| 832 | tags?: string[] |
| 833 | }) => |
| 834 | getIpc().invoke('templates:createFromSession', payload) as Promise<{ |
| 835 | success: true |
| 836 | id: string |
| 837 | }>, |
| 838 | createSessionFromTemplate: (payload: { |
| 839 | templateId: string |
| 840 | title?: string |
| 841 | modelConfigId?: string |
| 842 | pageCount?: number |
| 843 | referenceDocumentPath?: string |
| 844 | sourcePlan?: SourceDocumentPlan |
| 845 | }) => |
| 846 | getIpc().invoke('templates:createSession', payload) as Promise<{ |
| 847 | success: true |
| 848 | sessionId: string |
| 849 | }>, |
| 850 | createEditableSessionFromTemplate: (payload: { |
| 851 | templateId: string |
| 852 | title?: string |
| 853 | modelConfigId?: string |
| 854 | }) => |
| 855 | getIpc().invoke('templates:createEditableSession', payload) as Promise<{ |
| 856 | success: true |
| 857 | sessionId: string |
| 858 | }>, |
| 859 | importPptxAsTemplate: (payload: { filePath: string; name?: string; modelConfigId?: string }) => |
| 860 | getIpc().invoke('templates:importPptx', payload) as Promise<{ |
| 861 | success: true |
| 862 | id: string |
| 863 | pageCount: number |
| 864 | warnings: string[] |
| 865 | }>, |
| 866 | updateTemplateMetadata: (payload: { |
| 867 | templateId: string |
| 868 | name: string |
| 869 | description?: string |
| 870 | tags?: string[] |
| 871 | }) => |
| 872 | getIpc().invoke('templates:updateMetadata', payload) as Promise<{ |
| 873 | success: true |
| 874 | item: TemplateListItem |
| 875 | }>, |
| 876 | deleteTemplate: (templateId: string) => |
| 877 | getIpc().invoke('templates:delete', templateId) as Promise<{ |
| 878 | success: true |
| 879 | deleted: boolean |
| 880 | }>, |
| 881 | startGenerate: (payload: GenerateStartPayload) => |
| 882 | getIpc().invoke('generate:start', payload) as Promise<{ |
| 883 | success: boolean |
| 884 | runId?: string |
| 885 | alreadyRunning?: boolean |
| 886 | queued?: boolean |
| 887 | }>, |
| 888 | assessPageEdit: (payload: GenerateStartPayload) => |
| 889 | getIpc().invoke('page-edit:assess', payload) as Promise< |
| 890 | SessionPageEditAssessment & { |
| 891 | reply: string |
| 892 | targetPageId: string |
| 893 | targetPageNumber?: number |
| 894 | } |
| 895 | >, |
| 896 | startPageEdit: (payload: GenerateStartPayload) => |
| 897 | getIpc().invoke('page-edit:start', payload) as Promise<{ |
| 898 | success: boolean |
| 899 | runId?: string |
| 900 | alreadyRunning?: boolean |
| 901 | }>, |
| 902 | getPageEditState: (sessionId: string) => |
| 903 | getIpc().invoke('page-edit:state', sessionId) as Promise<GenerateRunStateSnapshot>, |
| 904 | listActivePageEditRuns: () => |
| 905 | getIpc().invoke('page-edit:listActive') as Promise<GenerateRunStateSnapshot[]>, |
| 906 | cancelPageEdit: (sessionId: string) => |
| 907 | getIpc().invoke('page-edit:cancel', sessionId) as Promise<{ success: boolean }>, |
| 908 | startPageBeautify: (payload: { |
| 909 | sessionId: string |
| 910 | selectedPageId: string |
| 911 | modelConfigId?: string |
| 912 | layoutAudit?: string |
| 913 | }) => |
| 914 | getIpc().invoke('page-beautify:start', payload) as Promise<{ |
| 915 | success: boolean |
| 916 | runId?: string |
| 917 | alreadyRunning?: boolean |
| 918 | }>, |
| 919 | getPageBeautifyState: (sessionId: string) => |
| 920 | getIpc().invoke('page-beautify:state', sessionId) as Promise<GenerateRunStateSnapshot>, |
| 921 | listActivePageBeautifyRuns: () => |
| 922 | getIpc().invoke('page-beautify:listActive') as Promise<GenerateRunStateSnapshot[]>, |
| 923 | cancelPageBeautify: (sessionId: string) => |
| 924 | getIpc().invoke('page-beautify:cancel', sessionId) as Promise<{ success: boolean }>, |
| 925 | startDeckEdit: (payload: GenerateStartPayload) => |
| 926 | getIpc().invoke('deck-edit:start', payload) as Promise<{ |
| 927 | success: boolean |
| 928 | runId?: string |
| 929 | alreadyRunning?: boolean |
| 930 | }>, |
| 931 | getDeckEditState: (sessionId: string) => |
| 932 | getIpc().invoke('deck-edit:state', sessionId) as Promise<GenerateRunStateSnapshot>, |
| 933 | listActiveDeckEditRuns: () => |
| 934 | getIpc().invoke('deck-edit:listActive') as Promise<GenerateRunStateSnapshot[]>, |
| 935 | cancelDeckEdit: (sessionId: string) => |
| 936 | getIpc().invoke('deck-edit:cancel', sessionId) as Promise<{ success: boolean }>, |
| 937 | startStyleSwitch: (payload: SwitchSessionStylePayload) => |
| 938 | getIpc().invoke('style-switch:start', payload) as Promise<{ |
| 939 | success: boolean |
| 940 | runId?: string |
| 941 | styleId: string |
| 942 | unchanged?: boolean |
| 943 | alreadyRunning?: boolean |
| 944 | }>, |
| 945 | retryStyleSwitchPage: (payload: { |
| 946 | sessionId: string |
| 947 | failedRunId?: string |
| 948 | pageId: string |
| 949 | modelConfigId?: string |
| 950 | }) => |
| 951 | getIpc().invoke('style-switch:retryPage', payload) as Promise<{ |
| 952 | success: boolean |
| 953 | runId?: string |
| 954 | styleId: string |
| 955 | alreadyRunning?: boolean |
| 956 | }>, |
| 957 | retryFailedStyleSwitchPages: (payload: RetrySessionStylePayload) => |
| 958 | getIpc().invoke('style-switch:retryFailed', payload) as Promise<{ |
| 959 | success: boolean |
| 960 | runId?: string |
| 961 | styleId: string |
| 962 | alreadyRunning?: boolean |
| 963 | failedPageCount: number |
| 964 | }>, |
| 965 | getStyleSwitchState: (sessionId: string) => |
| 966 | getIpc().invoke('style-switch:state', sessionId) as Promise<StyleSwitchJobSnapshot>, |
| 967 | listActiveStyleSwitchRuns: () => |
| 968 | getIpc().invoke('style-switch:listActive') as Promise<StyleSwitchJobSnapshot[]>, |
| 969 | cancelStyleSwitch: (sessionId: string) => |
| 970 | getIpc().invoke('style-switch:cancel', sessionId) as Promise<{ success: boolean }>, |
| 971 | switchSessionStyle: (payload: SwitchSessionStylePayload) => |
| 972 | getIpc().invoke('style-switch:start', payload) as Promise<{ |
| 973 | success: boolean |
| 974 | runId?: string |
| 975 | styleId: string |
| 976 | unchanged?: boolean |
| 977 | alreadyRunning?: boolean |
| 978 | failedPageCount?: number |
| 979 | }>, |
| 980 | retrySessionStyle: (payload: RetrySessionStylePayload) => |
| 981 | getIpc().invoke('style-switch:retryFailed', payload) as Promise<{ |
| 982 | success: boolean |
| 983 | runId?: string |
| 984 | styleId: string |
| 985 | alreadyRunning?: boolean |
| 986 | failedPageCount: number |
| 987 | }>, |
| 988 | retryDeckEdit: (payload: RetryDeckEditPayload) => |
| 989 | getIpc().invoke('generate:retryDeckEdit', payload) as Promise<{ |
| 990 | success: boolean |
| 991 | runId?: string |
| 992 | alreadyRunning?: boolean |
| 993 | failedPageCount: number |
| 994 | }>, |
| 995 | startTemplateGenerate: (payload: GenerateStartPayload & { retry?: boolean }) => |
| 996 | getIpc().invoke('generate:startTemplate', payload) as Promise<{ |
| 997 | success: boolean |
| 998 | runId?: string |
| 999 | alreadyRunning?: boolean |
| 1000 | queued?: boolean |
| 1001 | }>, |
| 1002 | retryFailedPages: (payload: GenerateRetryFailedPayload) => |
| 1003 | getIpc().invoke('generate:retryFailedPages', payload) as Promise<{ |
| 1004 | success: boolean |
| 1005 | runId?: string |
| 1006 | alreadyRunning?: boolean |
| 1007 | queued?: boolean |
| 1008 | }>, |
| 1009 | addPage: (payload: GenerateAddPagePayload) => |
| 1010 | getIpc().invoke('generate:addPage', payload) as Promise<{ |
| 1011 | success: boolean |
| 1012 | runId?: string |
| 1013 | alreadyRunning?: boolean |
| 1014 | queued?: boolean |
| 1015 | }>, |
| 1016 | retrySinglePage: (payload: GenerateRetrySinglePagePayload) => |
| 1017 | getIpc().invoke('generate:retrySinglePage', payload) as Promise<{ |
| 1018 | success: boolean |
| 1019 | runId?: string |
| 1020 | alreadyRunning?: boolean |
| 1021 | queued?: boolean |
| 1022 | }>, |
| 1023 | getGenerateState: (sessionId: string) => |
| 1024 | getIpc().invoke('generate:state', sessionId) as Promise<GenerateRunStateSnapshot>, |
| 1025 | listActiveGenerateRuns: () => |
| 1026 | getIpc().invoke('generate:listActive') as Promise<GenerateRunStateSnapshot[]>, |
| 1027 | cancelGenerate: (sessionId: string) => |
| 1028 | getIpc().invoke('generate:cancel', sessionId) as Promise<{ success: boolean }>, |
| 1029 | listHistoryVersions: (payload: { sessionId: string; limit?: number }) => |
| 1030 | getIpc().invoke('history:listVersions', payload) as Promise<HistoryVersion[]>, |
| 1031 | rollbackToHistoryVersion: (payload: { sessionId: string; versionId: string }) => |
| 1032 | getIpc().invoke('history:rollbackToVersion', payload) as Promise<RollbackHistoryResult>, |
| 1033 | recordHistorySnapshot: (payload: { |
| 1034 | sessionId: string |
| 1035 | type?: 'generate' | 'edit' | 'addPage' | 'retry' | 'import' | 'rollback' | 'reorder' | 'delete' |
| 1036 | scope?: 'session' | 'deck' | 'page' | 'selector' | 'shell' |
| 1037 | prompt?: string |
| 1038 | metadata?: Record<string, unknown> |
| 1039 | }) => getIpc().invoke('history:recordSnapshot', payload) as Promise<unknown>, |
| 1040 | uploadAssets: (payload: UploadAssetsPayload) => |
| 1041 | getIpc().invoke('assets:upload', payload) as Promise<{ assets: UploadedAsset[] }>, |
| 1042 | prepareReferenceDocument: (payload: PrepareReferenceDocumentPayload) => |
| 1043 | getIpc().invoke( |
| 1044 | 'documents:prepareReference', |
| 1045 | payload |
| 1046 | ) as Promise<PreparedReferenceDocumentResult>, |
| 1047 | parseImageReferenceDocument: (payload: ParseImageReferencePayload) => |
| 1048 | getIpc().invoke( |
| 1049 | 'documents:parseImageReference', |
| 1050 | payload |
| 1051 | ) as Promise<PreparedReferenceDocumentResult>, |
| 1052 | parseDocumentPlan: (payload: ParseDocumentPlanPayload) => |
| 1053 | getIpc().invoke('documents:parsePlan', payload) as Promise<ParsedDocumentPlanResult>, |
| 1054 | importPptx: (payload: PptxImportPayload) => |
| 1055 | getIpc().invoke('pptx:import', payload) as Promise<PptxImportResult>, |
| 1056 | chooseAndUploadAssets: (sessionId: string, assetType: 'image' | 'video' = 'image') => |
| 1057 | getIpc().invoke('assets:chooseAndUpload', { sessionId, assetType }) as Promise<{ |
| 1058 | assets: UploadedAsset[] |
| 1059 | cancelled?: boolean |
| 1060 | }>, |
| 1061 | listAssets: (sessionId: string, assetType: 'image' | 'video') => |
| 1062 | getIpc().invoke('assets:list', { sessionId, assetType }) as Promise<{ |
| 1063 | assets: Array<{ fileName: string; relativePath: string; absolutePath: string }> |
| 1064 | }>, |
| 1065 | exportPdf: (sessionId: string) => |
| 1066 | getIpc().invoke('export:pdf', { sessionId }) as Promise<ExportDeckResult>, |
| 1067 | exportPng: (sessionId: string) => |
| 1068 | getIpc().invoke('export:png', { sessionId }) as Promise<ExportDeckResult>, |
| 1069 | exportLongImage: (sessionId: string) => |
| 1070 | getIpc().invoke('export:longImage', { sessionId }) as Promise<ExportDeckResult>, |
| 1071 | exportVideo: (sessionId: string, options?: { pageId?: string }) => |
| 1072 | getIpc().invoke('export:video', { sessionId, ...options }) as Promise<ExportDeckResult>, |
| 1073 | exportPptx: ( |
| 1074 | sessionId: string, |
| 1075 | options?: { |
| 1076 | imageOnly?: boolean |
| 1077 | embedFonts?: boolean | 'auto' | 'always' | 'never' |
| 1078 | pageId?: string |
| 1079 | } |
| 1080 | ) => getIpc().invoke('export:pptx', { sessionId, ...options }) as Promise<ExportDeckResult>, |
| 1081 | exportSlidePack: (sessionId: string) => |
| 1082 | getIpc().invoke('export:slidePack', { sessionId }) as Promise<ExportDeckResult>, |
| 1083 | exportSessionZip: (sessionId: string) => |
| 1084 | getIpc().invoke('export:sessionZip', { sessionId }) as Promise<ExportDeckResult>, |
| 1085 | exportOutlinesMarkdown: (sessionId: string) => |
| 1086 | getIpc().invoke('export:outlinesMarkdown', { sessionId }) as Promise<ExportDeckResult>, |
| 1087 | onExportProgress: (callback: (payload: ExportProgressPayload) => void): (() => void) => { |
| 1088 | const channel = 'export:progress' |
| 1089 | const handler = (_event: unknown, payload: unknown): void => |
| 1090 | callback(payload as ExportProgressPayload) |
| 1091 | getIpc().on(channel, handler) |
| 1092 | return () => getIpc().removeListener(channel, handler) |
| 1093 | }, |
| 1094 | getSettings: () => getIpc().invoke('settings:get') as Promise<Record<string, unknown>>, |
| 1095 | getModelUsage: (period: ModelUsagePeriod) => |
| 1096 | getIpc().invoke('settings:getModelUsage', period) as Promise<ModelUsageStats>, |
| 1097 | listModelConfigs: () => getIpc().invoke('settings:listModelConfigs') as Promise<ModelConfig[]>, |
| 1098 | listImageModelConfigs: () => getIpc().invoke('imageModels:list') as Promise<ImageModelConfig[]>, |
| 1099 | validateUploadPrerequisites: () => |
| 1100 | getIpc().invoke('settings:validateUploadPrerequisites') as Promise<UploadPrerequisitesResult>, |
| 1101 | listFonts: () => getIpc().invoke('fonts:list') as Promise<FontRegistryResponse>, |
| 1102 | uploadFont: (payload: UploadFontPayload) => |
| 1103 | getIpc().invoke('fonts:upload', payload) as Promise<{ success: true; font: FontListItem }>, |
| 1104 | updateFont: (payload: { |
| 1105 | id: string |
| 1106 | family?: string |
| 1107 | category?: string |
| 1108 | role?: FontRole[] |
| 1109 | scripts?: FontScript[] |
| 1110 | }) => getIpc().invoke('fonts:update', payload) as Promise<{ success: true; font: FontListItem }>, |
| 1111 | deleteFont: (fontId: string) => |
| 1112 | getIpc().invoke('fonts:delete', fontId) as Promise<{ success: true }>, |
| 1113 | revealFontsFolder: () => getIpc().invoke('fonts:revealFolder') as Promise<{ success: true }>, |
| 1114 | chooseFontFiles: () => |
| 1115 | getIpc().invoke('fonts:chooseFiles') as Promise<{ canceled: boolean; filePaths: string[] }>, |
| 1116 | loadFontPreviewCss: () => getIpc().invoke('fonts:previewCss') as Promise<string>, |
| 1117 | saveSettings: (settings: Record<string, unknown>) => |
| 1118 | getIpc().invoke('settings:save', settings) as Promise<{ success: boolean }>, |
| 1119 | upsertModelConfig: (payload: { |
| 1120 | id?: string |
| 1121 | name: string |
| 1122 | provider: 'anthropic' | 'openai' | 'openai-responses' | 'google' |
| 1123 | model: string |
| 1124 | apiKey: string |
| 1125 | baseUrl: string |
| 1126 | maxTokens?: number |
| 1127 | disableTemperature?: boolean |
| 1128 | thinkingParameterMode?: ThinkingParameterMode |
| 1129 | active?: boolean |
| 1130 | }) => |
| 1131 | getIpc().invoke('settings:upsertModelConfig', payload) as Promise<{ |
| 1132 | success: boolean |
| 1133 | id: string |
| 1134 | }>, |
| 1135 | setActiveModelConfig: (id: string) => |
| 1136 | getIpc().invoke('settings:setActiveModelConfig', id) as Promise<{ success: boolean }>, |
| 1137 | deleteModelConfig: (id: string) => |
| 1138 | getIpc().invoke('settings:deleteModelConfig', id) as Promise<{ success: boolean }>, |
| 1139 | upsertImageModelConfig: (payload: { |
| 1140 | id?: string |
| 1141 | name: string |
| 1142 | provider: ImageModelProvider |
| 1143 | active?: boolean |
| 1144 | modelConfig: string |
| 1145 | }) => |
| 1146 | getIpc().invoke('imageModels:upsert', payload) as Promise<{ |
| 1147 | success: boolean |
| 1148 | id: string |
| 1149 | }>, |
| 1150 | setActiveImageModelConfig: (id: string) => |
| 1151 | getIpc().invoke('imageModels:setActive', id) as Promise<{ success: boolean }>, |
| 1152 | deleteImageModelConfig: (id: string) => |
| 1153 | getIpc().invoke('imageModels:delete', id) as Promise<{ success: boolean }>, |
| 1154 | verifyImageModel: (payload: { provider: ImageModelProvider; modelConfig: string }) => |
| 1155 | getIpc().invoke('imageModels:verify', payload) as Promise<{ |
| 1156 | valid: boolean |
| 1157 | message?: string |
| 1158 | }>, |
| 1159 | verifyApiKey: (payload: { |
| 1160 | provider: string |
| 1161 | apiKey: string |
| 1162 | model: string |
| 1163 | baseUrl: string |
| 1164 | maxTokens?: number |
| 1165 | disableTemperature?: boolean |
| 1166 | thinkingParameterMode?: ThinkingParameterMode |
| 1167 | timeoutMs: number |
| 1168 | }) => |
| 1169 | getIpc().invoke('settings:verifyApiKey', payload) as Promise<{ |
| 1170 | valid: boolean |
| 1171 | message?: string |
| 1172 | }>, |
| 1173 | chooseStoragePath: () => |
| 1174 | getIpc().invoke('settings:chooseStoragePath') as Promise<{ |
| 1175 | path: string | null |
| 1176 | error?: string |
| 1177 | }>, |
| 1178 | generateImage: (payload: ImageGeneratePayload) => |
| 1179 | getIpc().invoke('images:generate', payload) as Promise<ImageGenerateResult>, |
| 1180 | generateImagePrompt: (payload: ImagePromptGeneratePayload) => |
| 1181 | getIpc().invoke('images:generatePrompt', payload) as Promise<ImagePromptGenerateResult>, |
| 1182 | listImageGenerationHistory: (payload: { sessionId: string; pageId: string }) => |
| 1183 | getIpc().invoke('images:listHistory', payload) as Promise<ImageGenerationHistoryRecord[]>, |
| 1184 | cancelImageGeneration: (sessionId: string) => |
| 1185 | getIpc().invoke('images:cancel', sessionId) as Promise<{ success: boolean }>, |
| 1186 | getImageGenerationState: (sessionId: string) => |
| 1187 | getIpc().invoke('images:getState', sessionId) as Promise<{ |
| 1188 | runId: string |
| 1189 | sessionId: string |
| 1190 | pageId: string |
| 1191 | progress: number |
| 1192 | label: string |
| 1193 | status: 'running' | 'completed' | 'failed' | 'cancelled' |
| 1194 | error: string | null |
| 1195 | updatedAt: number |
| 1196 | } | null>, |
| 1197 | getStyles: () => |
| 1198 | getIpc().invoke('styles:get') as Promise<{ |
| 1199 | categories: Record< |
| 1200 | string, |
| 1201 | Array<{ |
| 1202 | id: string |
| 1203 | label: string |
| 1204 | description: string |
| 1205 | source?: 'builtin' | 'custom' | 'override' |
| 1206 | editable?: boolean |
| 1207 | styleCase?: string |
| 1208 | }> |
| 1209 | > |
| 1210 | defaultStyle: string |
| 1211 | }>, |
| 1212 | getStyleDetail: (styleId: string) => |
| 1213 | getIpc().invoke('styles:getDetail', styleId) as Promise<StyleDetail>, |
| 1214 | listStyles: (payload?: { sessionId?: string }) => |
| 1215 | getIpc().invoke('styles:list', payload) as Promise<{ items: StyleListItem[] }>, |
| 1216 | generateStylePreview: (payload: { styleId: string; modelConfigId?: string }) => |
| 1217 | getIpc().invoke('styles:generatePreview', payload) as Promise<{ |
| 1218 | success: boolean |
| 1219 | previewPath: string |
| 1220 | thumbnailPath: string |
| 1221 | }>, |
| 1222 | setStyleFavorite: (payload: { styleId: string; favorite: boolean }) => |
| 1223 | getIpc().invoke('styles:setFavorite', payload) as Promise<{ |
| 1224 | success: boolean |
| 1225 | styleId: string |
| 1226 | favoriteAt: number | null |
| 1227 | }>, |
| 1228 | onHtmlThumbnailChanged: (callback: (task: HtmlThumbnailTask) => void): (() => void) => { |
| 1229 | const channel = 'thumbnails:changed' |
| 1230 | const handler = (_event: unknown, task: Parameters<typeof callback>[0]): void => callback(task) |
| 1231 | getIpc().on(channel, handler) |
| 1232 | return () => getIpc().removeListener(channel, handler) |
| 1233 | }, |
| 1234 | parseStyleFile: (payload: { filePath: string; modelConfigId?: string }) => |
| 1235 | getIpc().invoke('styles:parseFile', payload) as Promise<StyleParseResult>, |
| 1236 | parseStylePptx: (payload: { filePath: string; modelConfigId?: string }) => |
| 1237 | getIpc().invoke('styles:parsePptx', payload) as Promise<StyleParseResult>, |
| 1238 | parseStyleImage: (payload: { imageBase64: string; mimeType: string; modelConfigId?: string }) => |
| 1239 | getIpc().invoke('styles:parseImage', payload) as Promise<StyleParseResult>, |
| 1240 | importStylePackageZip: () => |
| 1241 | getIpc().invoke('styles:importPackageZip') as Promise<{ |
| 1242 | success: boolean |
| 1243 | cancelled?: boolean |
| 1244 | id: string |
| 1245 | source: 'custom' | 'override' |
| 1246 | }>, |
| 1247 | importStylePackageDirectory: () => |
| 1248 | getIpc().invoke('styles:importPackageDirectory') as Promise<{ |
| 1249 | success: boolean |
| 1250 | cancelled?: boolean |
| 1251 | id: string |
| 1252 | source: 'custom' | 'override' |
| 1253 | }>, |
| 1254 | exportStylePackageZip: (payload: { styleId: string }) => |
| 1255 | getIpc().invoke('styles:exportPackageZip', payload) as Promise<{ |
| 1256 | success: boolean |
| 1257 | canceled?: boolean |
| 1258 | filePath?: string |
| 1259 | }>, |
| 1260 | createStyle: (payload: { |
| 1261 | label: string |
| 1262 | description: string |
| 1263 | category?: string |
| 1264 | aliases?: string[] |
| 1265 | styleSkill: string |
| 1266 | styleCase?: string |
| 1267 | }) => |
| 1268 | getIpc().invoke('styles:create', payload) as Promise<{ |
| 1269 | success: boolean |
| 1270 | id: string |
| 1271 | source: 'custom' | 'override' |
| 1272 | }>, |
| 1273 | updateStyle: (payload: { |
| 1274 | id: string |
| 1275 | label: string |
| 1276 | description: string |
| 1277 | category?: string |
| 1278 | aliases?: string[] |
| 1279 | styleSkill: string |
| 1280 | styleCase?: string |
| 1281 | }) => |
| 1282 | getIpc().invoke('styles:update', payload) as Promise<{ |
| 1283 | success: boolean |
| 1284 | id: string |
| 1285 | source: 'custom' | 'override' |
| 1286 | }>, |
| 1287 | deleteStyle: (styleId: string) => |
| 1288 | getIpc().invoke('styles:delete', styleId) as Promise<{ |
| 1289 | success: boolean |
| 1290 | deleted: boolean |
| 1291 | }>, |
| 1292 | loadPreview: (htmlPath: string, sessionId?: string) => |
| 1293 | getIpc().invoke('preview:load', { htmlPath, sessionId }) as Promise<string>, |
| 1294 | loadPagePreview: (htmlPath: string, pageId: string, sessionId?: string) => |
| 1295 | getIpc().invoke('preview:loadPage', { htmlPath, pageId, sessionId }) as Promise<{ |
| 1296 | pageNumber: number |
| 1297 | pageId: string |
| 1298 | title: string |
| 1299 | html: string |
| 1300 | }>, |
| 1301 | updateElementLayout: (payload: UpdateElementLayoutPayload) => |
| 1302 | getIpc().invoke('drag-editor:update-element-layout', payload) as Promise<{ |
| 1303 | success: boolean |
| 1304 | }>, |
| 1305 | ensureElementAnchor: (payload: EnsureElementAnchorPayload) => |
| 1306 | getIpc().invoke('element-anchor:ensure', payload) as Promise<EnsureElementAnchorResult>, |
| 1307 | getElementAnimation: (payload: { |
| 1308 | sessionId: string |
| 1309 | htmlPath: string |
| 1310 | pageId: string |
| 1311 | selector: string |
| 1312 | }) => |
| 1313 | getIpc().invoke('element-animation:get', payload) as Promise<{ |
| 1314 | animation: ElementAnimationConfig | null |
| 1315 | }>, |
| 1316 | setElementAnimation: (payload: { |
| 1317 | sessionId: string |
| 1318 | htmlPath: string |
| 1319 | pageId: string |
| 1320 | selector: string |
| 1321 | patch: ElementAnimationPatch |
| 1322 | }) => |
| 1323 | getIpc().invoke('element-animation:set', payload) as Promise<{ |
| 1324 | success: boolean |
| 1325 | changed: boolean |
| 1326 | animation: ElementAnimationConfig | null |
| 1327 | }>, |
| 1328 | updateElementProperties: (payload: UpdateElementPropertiesPayload) => |
| 1329 | getIpc().invoke('text-editor:update-element-properties', payload) as Promise<{ |
| 1330 | success: boolean |
| 1331 | }>, |
| 1332 | deleteElement: (payload: { |
| 1333 | sessionId: string |
| 1334 | htmlPath: string |
| 1335 | pageId: string |
| 1336 | selector: string |
| 1337 | }) => |
| 1338 | getIpc().invoke('element-editor:delete-element', payload) as Promise<{ |
| 1339 | success: boolean |
| 1340 | }>, |
| 1341 | saveEditBatch: (payload: { |
| 1342 | sessionId: string |
| 1343 | htmlPath: string |
| 1344 | pageId: string |
| 1345 | dragEdits: unknown[] |
| 1346 | textEdits: unknown[] |
| 1347 | propertyEdits?: unknown[] |
| 1348 | deletes?: unknown[] |
| 1349 | addElements?: unknown[] |
| 1350 | prompt?: string |
| 1351 | }) => |
| 1352 | getIpc().invoke('edit:save-batch', payload) as Promise<{ |
| 1353 | success: boolean |
| 1354 | dragCount: number |
| 1355 | textCount: number |
| 1356 | propertyCount?: number |
| 1357 | deleteCount: number |
| 1358 | addCount: number |
| 1359 | warnings?: string[] |
| 1360 | }>, |
| 1361 | applySyncElementToAllPages: (payload: { |
| 1362 | sessionId: string |
| 1363 | htmlPath: string |
| 1364 | pageId: string |
| 1365 | sourceHtmlFragment: string |
| 1366 | syncElementId?: string |
| 1367 | sourceBlockId?: string |
| 1368 | }) => |
| 1369 | getIpc().invoke('element-editor:apply-sync-to-all-pages', payload) as Promise<{ |
| 1370 | success: boolean |
| 1371 | syncElementId: string |
| 1372 | changedCount: number |
| 1373 | insertedCount: number |
| 1374 | updatedCount: number |
| 1375 | }>, |
| 1376 | chooseAndParseChartData: () => |
| 1377 | getIpc().invoke('chart-data:choose-and-parse') as Promise<ParsedChartDataResult>, |
| 1378 | openFile: (filePath: string, sessionId?: string) => |
| 1379 | getIpc().invoke('file:open', { path: filePath, sessionId }) as Promise<string>, |
| 1380 | revealFile: (filePath: string, sessionId?: string) => |
| 1381 | getIpc().invoke('file:reveal', { path: filePath, sessionId }) as Promise<{ success: boolean }>, |
| 1382 | openInBrowser: (filePath: string, hash?: string, sessionId?: string) => |
| 1383 | getIpc().invoke('file:openInBrowser', { path: filePath, hash, sessionId }) as Promise<{ |
| 1384 | success: boolean |
| 1385 | }>, |
| 1386 | saveFile: (payload: { path: string; content: string; sessionId?: string }) => |
| 1387 | getIpc().invoke('file:save', payload) as Promise<{ success: boolean }>, |
| 1388 | onGenerateChunk: (callback: (chunk: GenerateChunkEvent) => void): (() => void) => { |
| 1389 | const channel = 'generate:chunk' |
| 1390 | const handler = (_event: unknown, chunk: unknown): void => callback(chunk as GenerateChunkEvent) |
| 1391 | getIpc().on(channel, handler) |
| 1392 | return () => getIpc().removeListener(channel, handler) |
| 1393 | }, |
| 1394 | onPptxImportProgress: (callback: (payload: PptxImportProgressPayload) => void): (() => void) => { |
| 1395 | const channel = 'pptx:import:progress' |
| 1396 | const handler = (_event: unknown, payload: unknown): void => |
| 1397 | callback(payload as PptxImportProgressPayload) |
| 1398 | getIpc().on(channel, handler) |
| 1399 | return () => getIpc().removeListener(channel, handler) |
| 1400 | }, |
| 1401 | onTemplatePptxImportProgress: ( |
| 1402 | callback: (payload: PptxImportProgressPayload) => void |
| 1403 | ): (() => void) => { |
| 1404 | const channel = 'templates:importPptx:progress' |
| 1405 | const handler = (_event: unknown, payload: unknown): void => |
| 1406 | callback(payload as PptxImportProgressPayload) |
| 1407 | getIpc().on(channel, handler) |
| 1408 | return () => getIpc().removeListener(channel, handler) |
| 1409 | }, |
| 1410 | onUpdateAvailable: (callback: (payload: UpdateAvailablePayload) => void): (() => void) => { |
| 1411 | const channel = 'app:update-available' |
| 1412 | const handler = (_event: unknown, payload: unknown): void => |
| 1413 | callback(payload as UpdateAvailablePayload) |
| 1414 | getIpc().on(channel, handler) |
| 1415 | return () => getIpc().removeListener(channel, handler) |
| 1416 | }, |
| 1417 | getAppVersion: () => |
| 1418 | getIpc().invoke('app:getVersion') as Promise<{ |
| 1419 | version: string |
| 1420 | }>, |
| 1421 | openPresentation: (payload: { sessionId: string; startIndex?: number }) => |
| 1422 | getIpc().invoke('presentation:open', payload) as Promise<{ success: boolean }>, |
| 1423 | generateSpeechScript: (sessionId: string, config: SpeechConfig & { currentPageId?: string }) => |
| 1424 | getIpc().invoke('speech:generateScript', { sessionId, ...config }) as Promise<{ |
| 1425 | success: boolean |
| 1426 | }>, |
| 1427 | getSpeechScript: (sessionId: string) => |
| 1428 | getIpc().invoke('speech:getScript', { sessionId }) as Promise<{ |
| 1429 | success: boolean |
| 1430 | script: string | null |
| 1431 | }>, |
| 1432 | openSpeechScriptFile: (sessionId: string) => |
| 1433 | getIpc().invoke('speech:openScriptFile', { sessionId }) as Promise<{ |
| 1434 | success: boolean |
| 1435 | path: string |
| 1436 | }>, |
| 1437 | clearSpeechScript: (sessionId: string) => |
| 1438 | getIpc().invoke('speech:clearScript', { sessionId }) as Promise<{ success: boolean }>, |
| 1439 | onSpeechProgress: ( |
| 1440 | callback: (payload: { sessionId: string; current: number; total: number }) => void |
| 1441 | ): (() => void) => { |
| 1442 | const channel = 'speech:progress' |
| 1443 | const handler = (_event: unknown, payload: unknown): void => |
| 1444 | callback(payload as { sessionId: string; current: number; total: number }) |
| 1445 | getIpc().on(channel, handler) |
| 1446 | return () => getIpc().removeListener(channel, handler) |
| 1447 | }, |
| 1448 | |
| 1449 | thinkingCreateWorkspace: () => |
| 1450 | getIpc().invoke('thinking:createWorkspace') as Promise<ThinkingWorkspace>, |
| 1451 | thinkingGetWorkspace: (thinkingId: string) => |
| 1452 | getIpc().invoke('thinking:getWorkspace', thinkingId) as Promise<ThinkingWorkspace>, |
| 1453 | thinkingGetLatestWorkspace: () => |
| 1454 | getIpc().invoke('thinking:getLatestWorkspace') as Promise<ThinkingWorkspace | null>, |
| 1455 | thinkingListWorkspaces: (payload?: { limit?: number }) => |
| 1456 | getIpc().invoke('thinking:listWorkspaces', payload || {}) as Promise< |
| 1457 | ThinkingWorkspaceListItem[] |
| 1458 | >, |
| 1459 | thinkingDeleteWorkspace: (thinkingId: string) => |
| 1460 | getIpc().invoke('thinking:deleteWorkspace', thinkingId) as Promise<{ success: boolean }>, |
| 1461 | thinkingRevealWorkspace: (thinkingId: string) => |
| 1462 | getIpc().invoke('thinking:revealWorkspace', thinkingId) as Promise<{ success: boolean }>, |
| 1463 | thinkingUpdatePageOutline: (payload: { |
| 1464 | thinkingId: string |
| 1465 | page: import('@shared/thinking').ThinkingPageOutlineUpdate |
| 1466 | }) => |
| 1467 | getIpc().invoke('thinking:updatePageOutline', payload) as Promise<{ |
| 1468 | success: boolean |
| 1469 | thinkingMd: string |
| 1470 | }>, |
| 1471 | thinkingUploadSources: (payload: { |
| 1472 | thinkingId: string |
| 1473 | files: Array<{ path: string; name?: string }> |
| 1474 | }) => |
| 1475 | getIpc().invoke('thinking:uploadSources', payload) as Promise<{ |
| 1476 | sources: Array<{ id: string; name: string; kind: string }> |
| 1477 | }>, |
| 1478 | thinkingRemoveSource: (payload: { thinkingId: string; sourceId: string }) => |
| 1479 | getIpc().invoke('thinking:removeSource', payload) as Promise<{ |
| 1480 | success: boolean |
| 1481 | removed: boolean |
| 1482 | }>, |
| 1483 | thinkingChat: (payload: { |
| 1484 | thinkingId: string |
| 1485 | modelConfigId?: string |
| 1486 | userMessage: string |
| 1487 | recentMessages?: ThinkingChatMessage[] |
| 1488 | attachments?: ThinkingChatMessage['attachments'] |
| 1489 | }) => getIpc().invoke('thinking:chat', payload) as Promise<ThinkingChatResult>, |
| 1490 | thinkingPrepareGeneration: (payload: { thinkingId: string }) => |
| 1491 | getIpc().invoke( |
| 1492 | 'thinking:prepareGeneration', |
| 1493 | payload |
| 1494 | ) as Promise<ThinkingPrepareGenerationResult>, |
| 1495 | onThinkingStreamThinking: ( |
| 1496 | callback: (payload: { |
| 1497 | thinkingId: string |
| 1498 | type: string |
| 1499 | toolName: string |
| 1500 | summary: string |
| 1501 | }) => void |
| 1502 | ): (() => void) => { |
| 1503 | const channel = 'thinking:stream:thinking' |
| 1504 | const handler = (_event: unknown, payload: unknown): void => |
| 1505 | callback(payload as { thinkingId: string; type: string; toolName: string; summary: string }) |
| 1506 | getIpc().on(channel, handler) |
| 1507 | return () => getIpc().removeListener(channel, handler) |
| 1508 | }, |
| 1509 | onThinkingStreamEnd: ( |
| 1510 | callback: (payload: { |
| 1511 | thinkingId: string |
| 1512 | reply: string |
| 1513 | thinkingMd: string |
| 1514 | contextMd: string |
| 1515 | stage: ThinkingStage |
| 1516 | }) => void |
| 1517 | ): (() => void) => { |
| 1518 | const channel = 'thinking:stream:end' |
| 1519 | const handler = (_event: unknown, payload: unknown): void => |
| 1520 | callback( |
| 1521 | payload as { |
| 1522 | thinkingId: string |
| 1523 | reply: string |
| 1524 | thinkingMd: string |
| 1525 | contextMd: string |
| 1526 | stage: ThinkingStage |
| 1527 | } |
| 1528 | ) |
| 1529 | getIpc().on(channel, handler) |
| 1530 | return () => getIpc().removeListener(channel, handler) |
| 1531 | } |
| 1532 | } |
| 1533 |