- electron-icon-builder + sharp devDep 추가
- assets/icon.svg → build/icon.{ico,icns,png} 산출 + git 추적
- electron-icon-builder 가 SVG 직접 input 안 받음 (Jimp MIME 에러) — sharp 로 SVG → PNG 1024 변환 후 input
- scripts/svg-to-png.mjs (sharp 사용 SVG→PNG) + scripts/finalize-icons.mjs (build/icons/ → build/ 정규 위치 정리)
- package.json build.{win,mac,linux}.icon 키 추가
- .gitignore: build/icons/ 와 build/icon-source.png (중간 산출물) 무시, build/icon.* 는 추적
- typecheck 0 errors + 472/472 단위 통과 유지 (회귀 없음)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 회색 placeholder div → <img src=inkling-media://...> 로 교체
- onClick 으로 inboxApi.openMedia(relPath) 호출 (현재는 InboxApi 인터페이스에 부재 → unknown cast 사용; Task 3 에서 정식 시그니처 추가 후 cast 제거 예정)
- alt='' 로 decorative 처리 (role=presentation), title 에 relPath 유지
- flex-wrap 추가 — 다수 이미지 시 줄바꿈
Tests: tests/unit/NoteCard.test.tsx 신규 2건 (img src 검증, click → openMedia 호출)
회귀: 468 → 470 pass
- registerSchemesAsPrivileged: inkling-media 스킴을 secure + supportFetchAPI + stream 으로 등록 (whenReady 이전 호출 필수).
- registerInklingMediaProtocol: profileDir/media 하위 파일을 raw URL traversal (.., %2e%2e) 검사 + normalize 후 mediaRoot 봉쇄로 이중 검증 후 readFile.
- inferMime: png/jpg/jpeg/gif/webp → image/*, 그 외 → application/octet-stream.
- src/main/index.ts: 모듈 import 직후 registerSchemesAsPrivileged(), whenReady 안 paths 결정 직후 registerInklingMediaProtocol(paths.profileDir).
- tests/unit/inklingMedia.test.ts: 8 unit (5 inferMime + 3 handler — valid/403/404). vitest 의 new Request() 가 url 을 normalize 하므로 raw url 보존을 위해 minimal mock req 사용.
- types.ts:119 stale "Task 25 cleanup" comment 제거 (Task 25 이미 완료)
- BackupSection.tsx 의 dead try/catch 제거 + status 단순화 — 모든 IPC 핸들러가 자체 try/catch + Notification 으로 결과 알림. 컴포넌트 status 는 진행 표시 보조용
- index.ts startup #45 autostart 진단 로그를 AutostartDiagnostic.collectAutostartState() 호출로 통합 — single source of truth (SettingsPage 진단 패널과 동일 데이터 소스)
460/460 pass, typecheck 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
v027 plan Task 7. zustand store 의 showSettings 를 사용하는 첫 컴포넌트.
4 섹션 (AI 제공자/자동 실행/백업·복원/정보) placeholder 와 헤더 + 돌아가기 버튼만.
실 콘텐츠는 후속 Task 8-11 에서 채움.
테스트 인프라 동시 추가 (v027 의 첫 React 컴포넌트 테스트):
- @testing-library/react + @testing-library/jest-dom + jsdom devDep 추가
- vitest.config: plugin-react 적용, include 에 .test.tsx 포함
- 환경 분리는 per-file `// @vitest-environment jsdom` directive 로 처리
(vitest 4.x 에서 environmentMatchGlobs 미지원 — 기존 .ts 단위 테스트는 node env 유지)
Round 1 reviewer 발견: B1 (#10) fix 가 dead code. NoteRepository.restoreNote
새 메서드는 unit test 만 호출, production path (CaptureService.restoreNote)
는 옛 repo.restore() 호출 → ai_status reset + pending_jobs INSERT 우회.
Fix:
- CaptureService.restoreNote 가 repo.restoreNote 호출
- before 의 ai_status 가 'failed' or 'pending' 이면 worker.enqueue(id) 도 호출
(in-memory queue 갱신 — restoreNote 가 DB 만 갱신하면 다음 app start 까지
처리 안 됨)
Round 1 Important 도 함께 처리.
단위 +2 cases (failed → enqueue, done → skip enqueue).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
createTray(callbacks: TrayCallbacks) 1-arg signature. 기존 10 positional 폐기.
TrayState 통합 (ollamaOk, todayCount, failedCount) — refreshTray({...partial})
1개 setter 로 일원화.
기존 refreshTrayOllama / refreshTrayFailedCount export 제거 — 호출자 모두
refreshTray({ ollamaOk: ... }) / refreshTray({ failedCount: ... }) 로 migrate.
module-scoped 개별 state 변수 (_failedCount 등) 제거.
backlog 4건 일괄: #4 (positional 폭주) / #23 (8 callbacks) / #26 (10 callbacks) /
#27 (refreshTrayFailedCount singleton). 다음 menu item 추가 시 callback
프로퍼티 추가만 — readability blocker 해소.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
if/else if 체인 끝에 const _exhaustive: never = ev — 새 telemetry kind
추가 시 본 함수 분기 누락을 컴파일 단계에서 catch.
silent fall-through 방지 — kind 추가 → typecheck 실패 → 강제 분기 추가.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
db.prepare().all() 의 row type cast s any[] / s unknown[] →
s Record<string, unknown>[] 일괄 통일. hydrate() signature 도 동일
(이미 그렇거나 갱신).
- TS strict 환경 친화 (any 보다 narrow)
- 향후 explicit row interface 추가 시 base 형 명확
- runtime 동작 변경 0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
기존 4-line narrowing 체인 (e.kind !== 'empty_trash' && ... && ...) 이
union 확장 시 길어짐 → hasNoteId(ev) type predicate 로 통합.
- telemetryEvents.ts: NO_NOTE_ID_KINDS Set + hasNoteId(ev): ev is ... export
- TelemetryService.test.ts: 2 narrowing callsite 단축
- 단위 +2 cases (noteId-bearing / noteId-less)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
추정 원인 (a)/(b)/(c):
- (a) Windows registry path mismatch (NSIS 설치 위치 변경)
- (b) electron path canonicalization
- (c) args 비교 mismatch — getLoginItemSettings 가 args 와 함께 read 해야 매치
Fix:
- tray.ts: getLoginItemSettings({ args: ['--hidden'] }) 명시 — 트레이 checkbox
의 checked 상태가 실제 LoginItem args 와 정합하게 비교
- index.ts firstRun 후: autostart.state 진단 로그 (withArgs vs noArgs 비교
+ executableWillLaunchAtLogin) — dogfood 에서 실제 동작 확인
Fix 가 충분하지 않으면 dogfood 로그 분석 후 v0.2.7 deeper fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #23 single-instance lock 의 second-instance handler 가 무조건 inbox 창
띄움. NSIS installer 직후 사용자 클릭 + autostart --hidden 동시 시도 시
두 번째가 hidden 이어도 창 띄워서 "트레이만" 의도 위반.
Fix: requestSingleInstanceLock 에 additionalData = { hidden: startedHidden }
전달, second-instance 콜백 signature (event, argv, cwd, additionalData) 의
4번째 인자에서 hidden flag 확인 → true 면 early return (창 안 띄움).
PR #23 round 1 reviewer Important deferred 처리.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
기존 UI 가 listTrash 200 limit 후 length 사용 → 350개 trash 시 dialog
"200개 영구 삭제" 표시되지만 실제 350 모두 삭제. 사용자 혼동 해소.
- NoteRepository.countTrashed() 신규 — SELECT COUNT(*) WHERE deleted_at IS NOT NULL
- IPC inbox:trashCount → countTrashed 사용
- 단위 +2 cases (>200 not capped, empty 0)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
restore 가 deleted_at = NULL 만 했음 → ai_status='failed' 인 노트는
영구 fail 상태로 복구. atomic transaction 안에서 ai_status='pending' reset
+ INSERT OR IGNORE INTO pending_jobs.
- failed → pending + pending_jobs 재처리 path 복구
- done 은 영향 X (이미 결과 있음)
- pending 은 pending_jobs 재생성 (defensive — trash 도중 jobs 미정상 상태 가능)
- 단위 +3 cases (failed/done/pending 각 케이스)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>