feat(ollama): index 부팅 + IPC + preload + types (v0.2.3.1)

- index.ts: SettingsService.load() 후 endpoint/model 결정 (settings > env > default)
- IPC: inbox:loadOllamaSettings + inbox:saveOllamaSettings
  - save: 임시 provider 로 healthCheck 통과 시에만 영속화 + holder.replace
  - 기존 in-flight generate 는 abort?.() (optional method)
- preload + InboxApi shared types

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
altair823
2026-05-04 23:36:46 +09:00
parent d1f36250e7
commit cee39a90aa
4 changed files with 43 additions and 5 deletions

View File

@@ -30,6 +30,7 @@ import { ExportService } from './services/ExportService.js';
import { ImportService } from './services/ImportService.js';
import { SyncService } from './services/SyncService.js';
import { TelemetryService } from './services/TelemetryService.js';
import { SettingsService } from './services/SettingsService.js';
const HIDDEN_ARG = '--hidden';
const startedHidden = process.argv.includes(HIDDEN_ARG);
@@ -64,12 +65,23 @@ app.whenReady().then(async () => {
const continuity = new ContinuityService(db);
const intent = new IntentService(repo);
const resolvedEndpoint = process.env.INKLING_OLLAMA_ENDPOINT ?? 'http://localhost:11434';
const settingsSvc = new SettingsService(paths.profileDir);
const settings = await settingsSvc.load();
const resolvedEndpoint = settings.ollama?.endpoint
?? process.env.INKLING_OLLAMA_ENDPOINT
?? 'http://localhost:11434';
const resolvedModel = settings.ollama?.model ?? 'gemma4:e4b';
logger.info('ai.endpoint', {
endpoint: resolvedEndpoint,
fromEnv: process.env.INKLING_OLLAMA_ENDPOINT !== undefined
model: resolvedModel,
source: settings.ollama?.endpoint
? 'settings'
: (process.env.INKLING_OLLAMA_ENDPOINT ? 'env' : 'default')
});
const provider = new LocalOllamaProvider({ endpoint: resolvedEndpoint });
const provider = new LocalOllamaProvider({ endpoint: resolvedEndpoint, model: resolvedModel });
const providerHolder = new ProviderHolder(provider);
const health = new HealthChecker(providerHolder, {
onUpdate: (status) => {
@@ -116,7 +128,7 @@ app.whenReady().then(async () => {
registerCaptureApi(capture, getQuickCaptureWindow);
registerInboxApi({
repo, continuity, capture, health, intent,
getInboxWindow
getInboxWindow, settings: settingsSvc, providerHolder
});
const hotkeys = new HotkeyService();

View File

@@ -8,6 +8,9 @@ import type { HealthChecker } from '../services/HealthChecker.js';
import type { IntentService } from '../services/IntentService.js';
import type { Note } from '@shared/types';
import type { HealthResult } from '../ai/InferenceProvider.js';
import { LocalOllamaProvider } from '../ai/LocalOllamaProvider.js';
import type { SettingsService } from '../services/SettingsService.js';
import type { ProviderHolder } from '../ai/ProviderHolder.js';
export interface InboxIpcDeps {
repo: NoteRepository;
@@ -16,6 +19,8 @@ export interface InboxIpcDeps {
health: HealthChecker;
intent: IntentService;
getInboxWindow: () => BrowserWindow | null;
settings: SettingsService;
providerHolder: ProviderHolder;
}
export function registerInboxApi(deps: InboxIpcDeps): void {
@@ -142,6 +147,23 @@ export function registerInboxApi(deps: InboxIpcDeps): void {
ipcMain.handle('inbox:dismissRecall', (_e, id: string) => deps.capture.dismissRecall(id));
ipcMain.handle('inbox:emitRecallShown', (_e, id: string) => deps.capture.emitRecallShown(id));
ipcMain.handle('inbox:emitRecallSnoozed', (_e, id: string) => deps.capture.emitRecallSnoozed(id));
ipcMain.handle('inbox:loadOllamaSettings', async () => {
const s = await deps.settings.load();
return s.ollama ?? null;
});
ipcMain.handle('inbox:saveOllamaSettings', async (_e, value: { endpoint: string; model: string }) => {
// 검증: 새 인스턴스로 healthCheck
const trial = new LocalOllamaProvider({ endpoint: value.endpoint, model: value.model });
const r = await trial.healthCheck();
if (!r.ok) return { ok: false, reason: r.reason ?? 'unknown' };
await deps.settings.setOllama(value);
deps.providerHolder.get().abort?.();
deps.providerHolder.replace(trial);
// HealthChecker 의 다음 polling cycle (~60s) 에 새 endpoint 반영
return { ok: true };
});
}
export function pushNoteUpdated(getWin: () => BrowserWindow | null, note: Note): void {

View File

@@ -44,7 +44,9 @@ const api: InklingApi = {
markRecallOpened: (id: string) => ipcRenderer.invoke('inbox:markRecallOpened', id),
dismissRecall: (id: string) => ipcRenderer.invoke('inbox:dismissRecall', id),
emitRecallShown: (id: string) => ipcRenderer.invoke('inbox:emitRecallShown', id),
emitRecallSnoozed: (id: string) => ipcRenderer.invoke('inbox:emitRecallSnoozed', id)
emitRecallSnoozed: (id: string) => ipcRenderer.invoke('inbox:emitRecallSnoozed', id),
loadOllamaSettings: () => ipcRenderer.invoke('inbox:loadOllamaSettings'),
saveOllamaSettings: (v: { endpoint: string; model: string }) => ipcRenderer.invoke('inbox:saveOllamaSettings', v)
}
};

View File

@@ -89,6 +89,8 @@ export interface InboxApi {
dismissRecall(id: string): Promise<{ note: Note }>;
emitRecallShown(id: string): Promise<void>;
emitRecallSnoozed(id: string): Promise<void>;
loadOllamaSettings(): Promise<{ endpoint: string; model: string } | null>;
saveOllamaSettings(v: { endpoint: string; model: string }): Promise<{ ok: true } | { ok: false; reason: string }>;
}
export interface InklingApi {