From 7187aea0a9c4adf9dd1d869f154e52fb939effd4 Mon Sep 17 00:00:00 2001 From: altair823 Date: Tue, 5 May 2026 00:42:50 +0900 Subject: [PATCH] =?UTF-8?q?hotfix(critical):=20single-instance=20lock=20?= =?UTF-8?q?=E2=80=94=20multi-process=20SQLite=20race=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dogfood 발견 — 앱 아이콘 클릭 시마다 새 process 가 떠서 트레이 아이콘 여러 개, SQLite 동시 접근 + AiWorker 중복 처리 + HealthChecker 중복 polling 등 **데이터 corruption 위험**. 원인: app.requestSingleInstanceLock() 호출 부재. Electron default 가 multi-instance 라 .exe 실행마다 별도 process. Fix: - app.requestSingleInstanceLock() 첫 줄에서 호출 - 두 번째 인스턴스 → app.quit() 즉시 종료 - 'second-instance' 이벤트 → 기존 inbox 창 restore + show + focus (사용자 의도는 "앱 보기" 라 가정) 게이트: typecheck 0 / 단위 413 / e2e 1 version: 0.2.4 → 0.2.5 (critical hotfix patch) Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 4 ++-- package.json | 2 +- src/main/index.ts | 21 +++++++++++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4ddafcc..a6ef275 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "inkling", - "version": "0.2.4", + "version": "0.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "inkling", - "version": "0.2.4", + "version": "0.2.5", "dependencies": { "better-sqlite3": "12.9.0", "electron-log": "5.2.0", diff --git a/package.json b/package.json index 473ff16..32a1d94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inkling", - "version": "0.2.4", + "version": "0.2.5", "private": true, "description": "Inkling — local-first 한 줄 보관 도구", "author": "altair823 ", diff --git a/src/main/index.ts b/src/main/index.ts index d102550..c892a87 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -36,6 +36,27 @@ import { DEFAULT_OLLAMA_ENDPOINT, DEFAULT_OLLAMA_MODEL } from '../shared/constan const HIDDEN_ARG = '--hidden'; const startedHidden = process.argv.includes(HIDDEN_ARG); +// CRITICAL — single-instance lock. 두 번째 .exe 실행 시 즉시 종료. +// 미적용 시 SQLite 동시 접근 + AiWorker 중복 처리 + HealthChecker 중복 polling 등 +// 데이터 corruption 위험. activate (Mac) / second-instance (Win/Linux) 이벤트로 +// 기존 inbox 창에 focus. +const gotLock = app.requestSingleInstanceLock(); +if (!gotLock) { + app.quit(); +} else { + app.on('second-instance', () => { + // 새 .exe 실행 또는 트레이 외 entry 시 기존 inbox 창 보이게 + const win = getInboxWindow(); + if (win) { + if (win.isMinimized()) win.restore(); + if (!win.isVisible()) win.show(); + win.focus(); + } else { + createInboxWindow(); + } + }); +} + app.whenReady().then(async () => { initLogger(); logger.info('app.start', {