feat(telemetry): wire TelemetryService + tray export (#7 v0.2.3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
altair823
2026-05-01 17:30:54 +09:00
parent dca6aed44e
commit fe24ff577f

View File

@@ -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();
}
}
);