feat(ipc): inbox handlers with v0.2 setIntent/dismissIntent/continuity
Task 21 of the slice plan. registerInboxApi binds every InboxApi method on the main side: inbox:list (paginated), inbox:updateAi (delegates to NoteRepository.updateUserAiFields which flips the *_edited_by_user flags), inbox:delete (routes through CaptureService so the media dir gets cleaned up), inbox:setIntent / inbox:dismissIntent (route through IntentService for input validation), inbox:continuity (Weekly Continuity snapshot), inbox:pendingCount, inbox:ollamaStatus (reads the cached HealthChecker.lastStatus()). pushNoteUpdated helper is exported so AiWorker.onUpdate (wired in Task 30) can fan note:updated events to the inbox renderer. Plan deviation: HealthChecker.ts was pulled forward from Task 29 because Task 21 imports it at compile time. The class is small and final; Task 29 commit only ships OllamaBanner.tsx. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
54
src/main/ipc/inboxApi.ts
Normal file
54
src/main/ipc/inboxApi.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { ipcMain, BrowserWindow } from 'electron';
|
||||
import type { NoteRepository } from '../repository/NoteRepository.js';
|
||||
import type { ContinuityService } from '../services/ContinuityService.js';
|
||||
import type { CaptureService } from '../services/CaptureService.js';
|
||||
import type { HealthChecker } from '../services/HealthChecker.js';
|
||||
import type { IntentService } from '../services/IntentService.js';
|
||||
import type { Note } from '@shared/types';
|
||||
|
||||
export interface InboxIpcDeps {
|
||||
repo: NoteRepository;
|
||||
continuity: ContinuityService;
|
||||
capture: CaptureService;
|
||||
health: HealthChecker;
|
||||
intent: IntentService;
|
||||
getInboxWindow: () => BrowserWindow | null;
|
||||
}
|
||||
|
||||
export function registerInboxApi(deps: InboxIpcDeps): void {
|
||||
ipcMain.handle('inbox:list', (_e, opts: { limit: number; cursor?: string }) =>
|
||||
deps.repo.list(opts)
|
||||
);
|
||||
|
||||
ipcMain.handle(
|
||||
'inbox:updateAi',
|
||||
(_e, arg: { noteId: string; fields: { title?: string; summary?: string; tags?: string[] } }) => {
|
||||
deps.repo.updateUserAiFields(arg.noteId, arg.fields);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle('inbox:delete', async (_e, noteId: string) => {
|
||||
await deps.capture.deleteNote(noteId);
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
'inbox:setIntent',
|
||||
(_e, arg: { noteId: string; text: string }) => {
|
||||
deps.intent.setIntent(arg.noteId, arg.text);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle('inbox:dismissIntent', (_e, noteId: string) => {
|
||||
deps.intent.dismissIntent(noteId);
|
||||
});
|
||||
|
||||
ipcMain.handle('inbox:continuity', () => deps.continuity.get());
|
||||
ipcMain.handle('inbox:pendingCount', () => deps.repo.getPendingCount());
|
||||
ipcMain.handle('inbox:ollamaStatus', () => deps.health.lastStatus());
|
||||
}
|
||||
|
||||
export function pushNoteUpdated(getWin: () => BrowserWindow | null, note: Note): void {
|
||||
const w = getWin();
|
||||
if (!w || w.isDestroyed()) return;
|
||||
w.webContents.send('note:updated', note);
|
||||
}
|
||||
13
src/main/services/HealthChecker.ts
Normal file
13
src/main/services/HealthChecker.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { InferenceProvider, HealthResult } from '../ai/InferenceProvider.js';
|
||||
|
||||
export class HealthChecker {
|
||||
private last: HealthResult = { ok: true };
|
||||
constructor(private provider: InferenceProvider) {}
|
||||
|
||||
async runOnce(): Promise<HealthResult> {
|
||||
this.last = await this.provider.healthCheck();
|
||||
return this.last;
|
||||
}
|
||||
|
||||
lastStatus(): HealthResult { return this.last; }
|
||||
}
|
||||
Reference in New Issue
Block a user