From fe24ff577fd3a1742e16f8b973bd5b068340df2d Mon Sep 17 00:00:00 2001 From: altair823 Date: Fri, 1 May 2026 17:30:54 +0900 Subject: [PATCH] feat(telemetry): wire TelemetryService + tray export (#7 v0.2.3) Co-Authored-By: Claude Sonnet 4.6 --- src/main/index.ts | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index ab2de69..a0a0160 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -28,6 +28,7 @@ import { BackupService } from './services/BackupService.js'; import { ExportService } from './services/ExportService.js'; import { ImportService } from './services/ImportService.js'; import { SyncService } from './services/SyncService.js'; +import { TelemetryService } from './services/TelemetryService.js'; const HIDDEN_ARG = '--hidden'; const startedHidden = process.argv.includes(HIDDEN_ARG); @@ -43,6 +44,9 @@ app.whenReady().then(async () => { const paths = resolveProfilePaths('default'); + const telemetry = new TelemetryService(join(paths.profileDir, 'telemetry'), () => new Date(), 14, { silent: true }); + void telemetry.cleanupOldFiles().then((r) => logger.info('telemetry.cleanup', { removed: r.removed.length })); + if (app.isPackaged && process.platform === 'win32') { const initFlag = join(paths.profileDir, '.autostart-init'); if (!existsSync(initFlag)) { @@ -72,7 +76,8 @@ app.whenReady().then(async () => { // F4-C: AI 처리 완료 = 새 캡처가 inbox 에 합류한 시점, tray 도 즉시 갱신. refreshTray(repo.countToday()); }, - logger + logger, + telemetry }); const notify = new NotificationService({ @@ -84,7 +89,8 @@ app.whenReady().then(async () => { const capture = new CaptureService(repo, store, { enqueue: (id) => worker.enqueue(id), - celebrate: (id) => notify.celebrate(id) + celebrate: (id) => notify.celebrate(id), + telemetry }); registerCaptureApi(capture, getQuickCaptureWindow); @@ -283,6 +289,35 @@ app.whenReady().then(async () => { logger.warn('sync.exception', { reason: String(e) }); new Notification({ title: 'Inkling', body: '동기화를 완료하지 못했습니다.', silent: true }).show(); } + }, + /* runExportTelemetry */ async () => { + const win = getInboxWindow(); + const dialogOpts: Electron.OpenDialogOptions = { + title: '사용 로그를 내보낼 폴더 선택', + message: '선택한 폴더에 events.jsonl + stats.md 가 생성됩니다. raw_text/요약/제목/태그 이름은 미포함입니다.', + buttonLabel: '여기로 내보내기', + properties: ['openDirectory', 'createDirectory'] + }; + const result = win + ? await dialog.showOpenDialog(win, dialogOpts) + : await dialog.showOpenDialog(dialogOpts); + if (result.canceled || result.filePaths.length === 0) return; + try { + const r = await telemetry.exportTo(result.filePaths[0]!); + logger.info('telemetry.export', { eventCount: r.eventCount, outDir: result.filePaths[0] }); + new Notification({ + title: 'Inkling', + body: `사용 로그 내보내기 완료 — ${r.eventCount}개 이벤트`, + silent: true + }).show(); + } catch (e) { + logger.warn('telemetry.export.failed', { reason: String(e) }); + new Notification({ + title: 'Inkling', + body: '사용 로그 내보내기를 완료하지 못했습니다.', + silent: true + }).show(); + } } );