feat: ship v0.9.0 with pomodoro, achievements, and injection history
Add pomodoro timer with goal notifications, writing streak milestones, and knowledge injection logging with UI previews across AI writing flows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC } from '../../../shared/ipc-channels'
|
||||
import type { AchievementService } from '../../services/achievement.service'
|
||||
import { wrap } from '../result'
|
||||
|
||||
export function registerAchievementHandlers(achievement: AchievementService): void {
|
||||
ipcMain.handle(IPC.ACHIEVEMENT_LIST, (_e, { bookId }: { bookId: string }) =>
|
||||
wrap(() => achievement.listAchievements(bookId))
|
||||
)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import { checkInteractiveGate } from '../../services/interactive-gate.service'
|
||||
import { AutoWritingService } from '../../services/auto-writing.service'
|
||||
import { scheduleChapterExtraction } from '../../services/knowledge-extraction-runner'
|
||||
import { trackerFor } from '../../services/chapter-writing-tracker.service'
|
||||
import { recordKnowledgeInjection } from '../../services/knowledge-injection-runner'
|
||||
import type { WritingLogService } from '../../services/writing-log.service'
|
||||
import { InteractiveRepository } from '../../db/repositories/interactive.repo'
|
||||
import { wrap } from '../result'
|
||||
@@ -89,6 +90,12 @@ export function registerAutoHandlers(
|
||||
bookId,
|
||||
settings.get().penName
|
||||
)
|
||||
recordKnowledgeInjection(registry, bookId, {
|
||||
knowledgeIds: binding.knowledgeIds,
|
||||
flowMode: 'auto',
|
||||
flowId,
|
||||
chapterId: registry.getMeta(bookId)?.lastChapterId ?? undefined
|
||||
})
|
||||
return svc.enrichFlow(svc.confirmContext(flowId, payload))
|
||||
})
|
||||
)
|
||||
|
||||
@@ -3,19 +3,29 @@ import { IPC } from '../../../shared/ipc-channels'
|
||||
import { BookRegistryService } from '../../services/book-registry'
|
||||
import { CockpitService } from '../../services/cockpit.service'
|
||||
import type { GlobalSettingsService } from '../../services/global-settings'
|
||||
import type { AchievementService } from '../../services/achievement.service'
|
||||
import type { PomodoroDailyRepository } from '../../db/repositories/pomodoro-daily.repo'
|
||||
import type { WritingLogService } from '../../services/writing-log.service'
|
||||
import { wrap } from '../result'
|
||||
|
||||
export function registerCockpitHandlers(
|
||||
registry: BookRegistryService,
|
||||
settings: GlobalSettingsService,
|
||||
writingLogs: WritingLogService
|
||||
writingLogs: WritingLogService,
|
||||
achievementService: AchievementService,
|
||||
pomodoroDaily: PomodoroDailyRepository
|
||||
): void {
|
||||
ipcMain.handle(
|
||||
IPC.COCKPIT_SUMMARY,
|
||||
(_e, { bookId, volumeId }: { bookId: string; volumeId?: string }) =>
|
||||
wrap(() =>
|
||||
new CockpitService(registry.getDb(bookId), settings, writingLogs).getSummary(volumeId, bookId)
|
||||
new CockpitService(
|
||||
registry.getDb(bookId),
|
||||
settings,
|
||||
writingLogs,
|
||||
achievementService,
|
||||
pomodoroDaily
|
||||
).getSummary(volumeId, bookId)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import { checkInteractiveGate } from '../../services/interactive-gate.service'
|
||||
import { InteractiveWritingService } from '../../services/interactive-writing.service'
|
||||
import { scheduleChapterExtraction } from '../../services/knowledge-extraction-runner'
|
||||
import { trackerFor } from '../../services/chapter-writing-tracker.service'
|
||||
import { recordKnowledgeInjection } from '../../services/knowledge-injection-runner'
|
||||
import type { WritingLogService } from '../../services/writing-log.service'
|
||||
import { wrap } from '../result'
|
||||
|
||||
@@ -66,6 +67,12 @@ export function registerInteractiveHandlers(
|
||||
bookId,
|
||||
settings.get().penName
|
||||
)
|
||||
recordKnowledgeInjection(registry, bookId, {
|
||||
knowledgeIds: binding.knowledgeIds,
|
||||
flowMode: 'interactive',
|
||||
flowId,
|
||||
chapterId: registry.getMeta(bookId)?.lastChapterId ?? undefined
|
||||
})
|
||||
const flow = serviceFor(registry, bookId, aiClient).confirmContext(flowId, payload)
|
||||
return serviceFor(registry, bookId, aiClient).enrichFlow(flow)
|
||||
})
|
||||
|
||||
@@ -11,6 +11,7 @@ import type { AiClientService } from '../../services/ai-client.service'
|
||||
import type { GlobalSettingsService } from '../../services/global-settings'
|
||||
import { KnowledgeRepository } from '../../db/repositories/knowledge.repo'
|
||||
import { KnowledgeExtractionService } from '../../services/knowledge-extraction.service'
|
||||
import { KnowledgeInjectionService } from '../../services/knowledge-injection.service'
|
||||
import { KnowledgeRetrievalService } from '../../services/knowledge-retrieval.service'
|
||||
import { KnowledgeService } from '../../services/knowledge.service'
|
||||
import { wrap } from '../result'
|
||||
@@ -120,4 +121,15 @@ export function registerKnowledgeHandlers(
|
||||
return new KnowledgeService(registry.getDb(bookId)).batchApproveHighConfidence(t)
|
||||
})
|
||||
)
|
||||
|
||||
ipcMain.handle(
|
||||
IPC.KNOWLEDGE_LIST_INJECTIONS,
|
||||
(
|
||||
_e,
|
||||
{ bookId, entryId, limit }: { bookId: string; entryId: string; limit?: number }
|
||||
) =>
|
||||
wrap(() =>
|
||||
new KnowledgeInjectionService(registry.getDb(bookId)).listForEntry(entryId, limit ?? 50)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ipcMain } from 'electron'
|
||||
import { IPC } from '../../../shared/ipc-channels'
|
||||
import type { PomodoroService } from '../../services/pomodoro.service'
|
||||
import { wrap } from '../result'
|
||||
|
||||
export function registerPomodoroHandlers(pomodoro: PomodoroService): void {
|
||||
ipcMain.handle(IPC.POMODORO_START, (_e, { bookId }: { bookId: string }) =>
|
||||
wrap(() => pomodoro.start(bookId))
|
||||
)
|
||||
ipcMain.handle(IPC.POMODORO_PAUSE, () => wrap(() => pomodoro.pause()))
|
||||
ipcMain.handle(IPC.POMODORO_RESUME, () => wrap(() => pomodoro.resume()))
|
||||
ipcMain.handle(IPC.POMODORO_CANCEL, () => wrap(() => pomodoro.cancel()))
|
||||
ipcMain.handle(IPC.POMODORO_GET_STATE, () => wrap(() => pomodoro.getState()))
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import { GlobalSettingsService } from '../../services/global-settings'
|
||||
import { AiClientService } from '../../services/ai-client.service'
|
||||
import { buildFlowContextPayload, readFlowSystemPrompt } from '../../services/flow-context.util'
|
||||
import { WizardWritingService } from '../../services/wizard-writing.service'
|
||||
import { recordKnowledgeInjection } from '../../services/knowledge-injection-runner'
|
||||
import { InteractiveRepository } from '../../db/repositories/interactive.repo'
|
||||
import { wrap } from '../result'
|
||||
|
||||
@@ -99,6 +100,12 @@ export function registerWizardHandlers(
|
||||
bookId,
|
||||
settings.get().penName
|
||||
)
|
||||
recordKnowledgeInjection(registry, bookId, {
|
||||
knowledgeIds: binding.knowledgeIds,
|
||||
flowMode: 'wizard',
|
||||
flowId,
|
||||
chapterId: registry.getMeta(bookId)?.lastChapterId ?? undefined
|
||||
})
|
||||
const svc = serviceFor(registry, bookId, aiClient)
|
||||
return svc.enrichFlow(svc.confirmContext(flowId, payload))
|
||||
})
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { join } from 'path'
|
||||
import { app } from 'electron'
|
||||
import { GlobalSettingsService } from '../services/global-settings'
|
||||
import { BookRegistryService } from '../services/book-registry'
|
||||
import { SnapshotService } from '../services/snapshot.service'
|
||||
import { ShortcutManager } from '../shortcuts/manager'
|
||||
import { WritingLogRepository } from '../db/repositories/writing-log.repo'
|
||||
import { WritingMilestoneRepository } from '../db/repositories/writing-milestone.repo'
|
||||
import { PomodoroDailyRepository } from '../db/repositories/pomodoro-daily.repo'
|
||||
import { WritingLogService } from '../services/writing-log.service'
|
||||
import { GoalNotificationService } from '../services/goal-notification.service'
|
||||
import { AchievementService } from '../services/achievement.service'
|
||||
import { PomodoroService } from '../services/pomodoro.service'
|
||||
import { registerSettingsHandlers } from './handlers/settings.handler'
|
||||
import { registerBookHandlers } from './handlers/book.handler'
|
||||
import { registerChapterHandlers } from './handlers/chapter.handler'
|
||||
@@ -23,6 +27,8 @@ import { registerWizardHandlers } from './handlers/wizard.handler'
|
||||
import { registerKnowledgeHandlers } from './handlers/knowledge.handler'
|
||||
import { registerCockpitHandlers } from './handlers/cockpit.handler'
|
||||
import { registerWritingHandlers } from './handlers/writing.handler'
|
||||
import { registerPomodoroHandlers } from './handlers/pomodoro.handler'
|
||||
import { registerAchievementHandlers } from './handlers/achievement.handler'
|
||||
import { registerBridgeHandlers } from './handlers/bridge.handler'
|
||||
import { AiClientService } from '../services/ai-client.service'
|
||||
import { NetworkMonitorService } from '../services/network-monitor.service'
|
||||
@@ -36,7 +42,20 @@ export function registerIpc(): { settings: GlobalSettingsService; books: BookReg
|
||||
|
||||
const settings = new GlobalSettingsService(userData)
|
||||
const books = new BookRegistryService(userData)
|
||||
const writingLogs = new WritingLogService(new WritingLogRepository(userData), settings)
|
||||
const writingLogRepo = new WritingLogRepository(userData)
|
||||
const writingLogs = new WritingLogService(writingLogRepo, settings)
|
||||
const milestoneRepo = new WritingMilestoneRepository(writingLogRepo.getDb())
|
||||
const pomodoroDailyRepo = new PomodoroDailyRepository(writingLogRepo.getDb())
|
||||
const goalNotify = new GoalNotificationService(settings)
|
||||
const achievementService = new AchievementService(
|
||||
milestoneRepo,
|
||||
writingLogs,
|
||||
settings,
|
||||
goalNotify
|
||||
)
|
||||
writingLogs.setGoalHooks(achievementService, goalNotify)
|
||||
const pomodoro = new PomodoroService(writingLogs, pomodoroDailyRepo, settings, goalNotify)
|
||||
|
||||
shortcutManager = new ShortcutManager(settings)
|
||||
snapshotService = new SnapshotService(() => settings.get())
|
||||
networkMonitor = new NetworkMonitorService()
|
||||
@@ -57,8 +76,10 @@ export function registerIpc(): { settings: GlobalSettingsService; books: BookReg
|
||||
registerAutoHandlers(books, settings, aiClient, writingLogs)
|
||||
registerWizardHandlers(books, settings, aiClient)
|
||||
registerKnowledgeHandlers(books, settings, aiClient)
|
||||
registerCockpitHandlers(books, settings, writingLogs)
|
||||
registerCockpitHandlers(books, settings, writingLogs, achievementService, pomodoroDailyRepo)
|
||||
registerWritingHandlers(writingLogs)
|
||||
registerPomodoroHandlers(pomodoro)
|
||||
registerAchievementHandlers(achievementService)
|
||||
registerBridgeHandlers(books, aiClient)
|
||||
|
||||
return { settings, books, shortcuts: shortcutManager }
|
||||
|
||||
Reference in New Issue
Block a user