feat: batch wiki-fication of 00_Raw data

Applied double-save rule: Master Archive + Specialized Mapping for Skybound, Datacollector, and Frontend Mastery.
This commit is contained in:
Antigravity Agent
2026-04-25 22:52:01 +09:00
parent 44f1f2140b
commit df275f935b
90 changed files with 3371 additions and 0 deletions
@@ -0,0 +1,60 @@
# Datacollector - 인증 복구 후 자동 재개 상태 전환 수정
- 작성 시각: 2026-04-25 22:39:30 KST
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
- 관련 파일: `src/components/AgentDashboard.tsx`, `src/lib/engine.ts`
## 상황
NotebookLM 인증 복구 로직을 강화했지만, 화면에서는 여전히 `CONTINUE MISSION` 버튼을 사용자가 눌러야 다음 큐가 이어지는 것처럼 보였다.
사용자 관찰:
- 작업은 일부 완료됨.
- 큐에는 아직 작업이 많이 남아 있음.
- 헤더 상태가 `IDLE`로 보임.
- `CONTINUE MISSION` 버튼이 사용자의 수동 클릭을 기다림.
## 원인
프론트엔드 상태 전환에 빈틈이 있었다.
`AgentDashboard``useEffect``status !== 'running'`일 때 `KnowledgeEngine.stop()`을 호출한다. 그런데 기존 `stop()`은 내부 실행 플래그만 끄는 것이 아니라 항상 Zustand 상태까지 `idle`로 바꿨다.
그 결과 인증 오류 등으로 `paused` 상태를 유지해야 하는 경우에도 React effect를 지나면서 `paused -> idle`로 바뀌었다. 이렇게 되면 앱은 "복구 후 자동 재개 가능한 일시정지"가 아니라 "사용자가 다시 Continue를 눌러야 하는 대기 상태"처럼 동작했다.
## 조치
`src/lib/engine.ts`:
- `stop(updateStatus = true)` 형태로 변경했다.
- 내부 엔진만 멈춰야 할 때는 UI 상태를 덮어쓰지 않도록 했다.
`src/components/AgentDashboard.tsx`:
- `status !== 'running'` effect에서는 `engine.stop(false)`를 호출하도록 변경했다.
- `status === 'paused'`이고 큐가 남아 있으면 NotebookLM 연결 확인 후 자동으로 `running`으로 되돌리는 auto-resume effect를 추가했다.
- 기존 버그로 이미 `idle`에 갇힌 화면도 구제하기 위해, 수동 정지나 작업 완료 로그가 없는 `idle + 남은 큐` 상태도 복구 가능한 멈춤으로 보고 자동 재개하도록 보강했다.
- 중복 자동 재개를 막기 위해 `autoResumeRef` 잠금을 추가했다.
## 검증
다음 검증을 완료했다.
```bash
npm run lint
curl -sS -I http://127.0.0.1:3000
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
```
결과:
- TypeScript 검사 통과
- 프론트엔드 서버 응답 정상
- NotebookLM 브리지 연결 확인 `success: true`
## 운영 메모
앞으로 인증 복구나 연결 복구로 인해 `paused` 상태가 되면 앱이 NotebookLM 연결을 확인하고 자동으로 다음 큐를 이어서 실행한다.
사용자가 직접 `STOP / PAUSE`를 누른 경우는 기존처럼 `idle`로 유지되므로, 수동 정지는 자동 재개 대상이 아니다.
@@ -0,0 +1,72 @@
# Datacollector Bridge Connection Refused Run Script Fix
Date: 2026-04-25 21:07:52 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
사용자가 앱 실행 후 `POST http://127.0.0.1:3002/api/check-connection net::ERR_CONNECTION_REFUSED` 오류를 확인했다.
이는 NotebookLM 인증 실패가 아니라 MCP Bridge 서버가 실행되지 않아 브라우저가 `3002` 포트에 연결하지 못한 상태였다.
## Root Cause
실행 경로가 여러 개였고 일부 경로는 프런트엔드 Vite 서버만 실행했다.
- `run_mac.command`: Bridge와 Vite를 함께 실행
- `run_app.sh`: Vite만 실행
- `npm run dev`: Vite만 실행
따라서 `run_app.sh` 또는 `npm run dev`로 앱을 켜면 UI는 열리지만 `/api/check-connection` 요청을 받을 Bridge 서버가 없어 `ERR_CONNECTION_REFUSED`가 발생했다.
## Changes Made
수정 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/run_app.sh`
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/api.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
핵심 변경:
- `run_app.sh`가 Bridge 서버와 Vite 서버를 함께 실행하도록 변경
- `run_app.sh` 시작 시 기존 `3000`, `3002` 포트 프로세스를 정리
- 종료 시 Bridge 백그라운드 프로세스도 함께 종료하도록 trap 추가
- README의 실행 안내를 `npm run dev` 단독에서 `./run_mac.command` 또는 `npm run start-full`로 변경
- `src/lib/api.ts``bridgeFetch()` 추가
- Bridge 연결 실패 시 `Failed to fetch` 대신 “Bridge 서버가 실행되지 않았다”는 안내 메시지를 표시하도록 변경
- `VITE_BRIDGE_URL`로 Bridge 주소를 override할 수 있게 함
## Verification
실행한 검증:
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
npm run build
```
검증 결과:
- 브리지 문법 체크 통과
- TypeScript 타입체크 통과
- Vite 프로덕션 빌드 통과
## Operational Note
앞으로 앱은 아래 방식으로 실행해야 한다.
```bash
./run_mac.command
```
또는 수동으로 두 서버를 같이 실행한다.
```bash
npm run start-full
```
`npm run dev`만 실행하면 프런트엔드만 뜨므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
@@ -0,0 +1,177 @@
# Datacollector Codebase Structure Review and Initial Risk Assessment
Date: 2026-04-25 20:38:01 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
Knowledge Vault: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
## Summary
이 문서는 Datacollector 프로젝트의 첫 구조 파악 및 초기 코드 리뷰 결과를 정리한 기록이다.
이번 검토의 목적은 이후 기능 개발 전에 현재 시스템의 책임 분리, 실행 흐름, 외부 의존성, 그리고 우선적으로 손봐야 할 위험 요소를 이해하는 데 있다.
현재 프로젝트는 단순한 프런트엔드 앱이 아니라, React 기반 UI와 Zustand 상태 저장소, 자율 실행 엔진, 그리고 NotebookLM MCP 및 로컬 LM을 연결하는 Express 브리지 서버가 결합된 자동화 연구 도구 형태로 구성되어 있다.
## High-Level Architecture
전체 흐름은 아래와 같다.
`React UI -> Zustand Store -> KnowledgeEngine -> Express Bridge -> NotebookLM MCP / Local LM / GitHub / Wiki Storage`
핵심 책임 분리는 다음과 같이 이해했다.
- `src/components/AgentDashboard.tsx`
사용자 인터페이스, 미션 시작/중지/재개, 설정 입력, 로그 표시, 수동 커밋 등 상호작용 담당
- `src/store/agentStore.ts`
앱 전체 설정값과 실행 상태를 보관하는 단일 전역 상태 저장소
- `src/lib/engine.ts`
큐를 소비하며 연구, 합성, 링크 추출, 다음 토픽 확장을 반복하는 자율 엔진
- `src/lib/gemini.ts`
NotebookLM 미연결 시 사용하는 로컬 LM 프롬프트 생성 및 응답 파싱
- `src/lib/github.ts`
결과 Markdown을 GitHub 저장소의 `00_Raw/` 경로로 업로드
- `scripts/mcp_bridge.mjs`
NotebookLM MCP 서버와 통신하는 지속 프로세스형 브리지 서버
## Execution Flow
실행 흐름은 다음 순서로 이해했다.
1. 사용자가 `AgentDashboard`에서 주제를 입력하고 미션을 시작한다.
2. 주제와 설정이 `agentStore`에 기록되고 상태가 `running`으로 바뀐다.
3. `status` 변경을 감지한 UI가 `KnowledgeEngine` 싱글톤을 시작한다.
4. `KnowledgeEngine`는 큐의 첫 항목을 읽고 현재 깊이와 루트 주제를 기준으로 처리 여부를 결정한다.
5. NotebookLM 연결 상태가 좋으면 브리지 서버를 통해 리서치와 합성을 수행한다.
6. NotebookLM이 없으면 로컬 LM 프록시(`/api/lm`)를 통해 대체 연구를 진행한다.
7. 생성된 Markdown에서 위키 링크를 추출해 다음 큐를 구성한다.
8. 결과는 pending commits, completed 목록, 로컬 위키 Raw 저장소 등에 반영된다.
## Current Structure Notes
이번 시점에서 구조적으로 눈에 띈 특징은 다음과 같다.
- 상태 관리가 거의 전부 Zustand store 하나에 집중되어 있어 흐름 추적은 쉽다.
- 대신 엔진과 UI가 store를 매우 직접적으로 공유해서 결합도가 높다.
- NotebookLM 경로와 Local LM 경로가 모두 존재해 fallback 전략은 분명하다.
- 브리지 서버가 프런트엔드 백엔드이자 외부 도구 래퍼 역할까지 함께 맡고 있어 책임이 넓다.
- 문서 저장 흐름이 GitHub 업로드와 로컬 위키 저장으로 이중화되어 있다.
## Review Findings
### 1. Sensitive secrets are persisted in browser storage
`githubToken``notebookLmCookies`가 Zustand persist 설정에 포함되어 있어 브라우저 localStorage에 평문으로 저장된다.
이 방식은 세션 쿠키나 GitHub 토큰 같은 민감 정보의 저장 위치로는 안전하지 않다.
관련 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
영향:
- 같은 브라우저 프로필을 사용하는 다른 코드나 도구가 정보에 접근할 수 있다.
- 장기적으로 토큰 유출 위험이 커진다.
### 2. Bridge server is exposed too broadly
브리지 서버는 `0.0.0.0:3002`로 열리고 CORS도 전부 허용한다.
또한 `/api/lm`은 클라이언트가 전달한 임의의 URL로 요청을 프록시할 수 있다.
관련 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
영향:
- 로컬 개발용으로는 편하지만, 같은 네트워크 안에서 예상하지 않은 접근 통로가 될 수 있다.
- 사실상 무인증 프록시처럼 동작할 여지가 있다.
### 3. Environment portability is weak
MCP 실행 파일 경로와 위키 저장 경로가 절대경로로 하드코딩되어 있다.
관련 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
영향:
- 다른 개발자 머신, 다른 사용자 계정, 다른 운영체제에서 그대로 실행하기 어렵다.
- 배포보다는 특정 개인 작업 환경에 강하게 종속된다.
### 4. Manual handoff state is not fully cleared
`resolveManualNext`가 store에 함수 형태로 저장되는데, `clearState()`에서 정리되지 않는다.
수동 합성 대기 중 reset 또는 새 미션 시작이 발생하면 상태 꼬임 가능성이 있다.
관련 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
영향:
- 이전 미션의 대기 상태가 다음 미션에 잔존할 수 있다.
- UI 버튼 상태와 실제 엔진 대기 상태가 어긋날 수 있다.
### 5. API endpoint usage is duplicated and hardcoded
프런트엔드에는 이미 Vite 프록시가 설정되어 있지만, UI와 엔진 코드 곳곳에서 `http://127.0.0.1:3002`를 직접 호출하고 있다.
관련 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
영향:
- 포트 변경이나 배포 환경 변경 시 수정 지점이 늘어난다.
- 런타임 경로 설정이 한 군데에서 관리되지 않는다.
## Validation Performed
이번 검토 중 아래 확인을 수행했다.
- 저장소 파일 구조 및 진입점 확인
- UI, store, engine, bridge, GitHub, Local LM 계층 코드 확인
- `npm run lint` 실행
검증 결과:
- TypeScript 타입체크는 현재 통과했다.
## Suggested Next Priorities
우선순위는 아래 순서가 적절하다.
1. 민감 정보 저장 방식을 localStorage 바깥으로 이동하거나 최소한 분리
2. 브리지 서버 바인딩 범위와 CORS 정책 축소
3. 절대경로를 환경변수 또는 설정 파일로 치환
4. `resolveManualNext`를 포함한 미션 종료 정리 로직 강화
5. API 베이스 URL을 단일 설정 지점으로 통합
## Working Agreement For Future Notes
사용자 요청에 따라, 앞으로 Datacollector 관련 조사/분석/리뷰 결과는 가능하면 이 지식 창고 경로에 계속 기록한다.
기본 원칙:
- 위치: `/Volumes/Data/project/Antigravity/Wiki/00_Raw`
- 파일명: `YYYY-MM-DD-<Project>_<Topic>.md` 또는 기존 저장소 관례와 유사한 읽기 쉬운 영어 제목
- 내용: 작업 목적, 파악한 구조, 핵심 발견사항, 다음 액션을 포함
## Source Files Reviewed
- `/Volumes/Data/project/Antigravity/Datacollector/README.md`
- `/Volumes/Data/project/Antigravity/Datacollector/package.json`
- `/Volumes/Data/project/Antigravity/Datacollector/vite.config.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/main.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/src/App.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/gemini.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_caller.py`
@@ -0,0 +1,74 @@
# Datacollector Local Wiki Save Only Output Mode
Date: 2026-04-25 20:50:41 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
Datacollector의 생성 결과 저장 방식을 GitHub 업로드 중심에서 로컬 Wiki 저장 전용으로 정리했다.
앞으로 앱에서 생성되는 연구 문서는 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 저장되고, Git 업로드는 사용자가 나중에 별도로 한 번에 처리하는 운영 방식으로 둔다.
## Previous Behavior
기존 흐름은 결과 생성 후 두 경로가 동시에 존재했다.
- 로컬 Wiki Raw 폴더에 자동 저장
- `pendingCommits`에 결과를 쌓고 UI의 `BATCH COMMIT` 버튼으로 GitHub 업로드 가능
이 방식은 앱 안에 GitHub 토큰과 저장소 설정을 유지해야 했고, 사용자가 의도하지 않아도 Git 업로드 기능이 계속 노출되는 구조였다.
## New Behavior
새 흐름은 다음과 같다.
1. 연구 결과 Markdown 생성
2. `savedReports`에 프리뷰용 로컬 캐시 저장
3. 브리지 서버의 `/api/wiki/save`를 통해 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`에 Markdown 파일 저장
4. GitHub 업로드 버튼이나 토큰 설정 없이 완료
GitHub 업로드는 앱이 수행하지 않는다.
## Changes Made
수정 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/src/store/agentStore.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/engine.ts`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
삭제 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/src/lib/github.ts`
핵심 변경:
- `githubToken`, `githubRepoUrl` 상태 제거
- `pendingCommits` 제거
- `addPendingCommit`, `clearPendingCommits` 제거
- `savedReports``addSavedReport` 추가
- `BATCH COMMIT` 버튼 제거
- 설정 모달의 GitHub Wiki Sync 섹션 제거
- `.env.example`의 GitHub 설정 제거
- 생성 결과는 기존 Wiki 저장 API를 통해 로컬 Raw 폴더에만 저장
## Verification
실행한 검증:
```bash
npm run lint
npm run build
```
검증 결과:
- TypeScript 타입체크 통과
- Vite 프로덕션 빌드 통과
## Notes
로컬 Wiki 저장은 기존 브리지 서버의 `/api/wiki/save` 라우트를 그대로 사용한다.
저장 대상 경로는 현재 브리지 서버에 하드코딩된 `/Volumes/Data/project/Antigravity/Wiki/00_Raw`이다.
추후 이 경로도 `.env` 설정으로 분리하면 다른 머신이나 폴더 구조에서도 더 쉽게 운영할 수 있다.
@@ -0,0 +1,50 @@
# Datacollector Mac Windows Launcher Scripts
Date: 2026-04-25 21:09:42 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
Datacollector 실행 시 Vite 프런트엔드만 뜨고 MCP Bridge 서버가 뜨지 않아 `ERR_CONNECTION_REFUSED`가 발생할 수 있었다.
이를 막기 위해 맥용과 윈도우용 실행 파일을 명확히 정리했다.
## Main Launchers
- macOS: `/Volumes/Data/project/Antigravity/Datacollector/run_mac.command`
- Windows: `/Volumes/Data/project/Antigravity/Datacollector/run_win.bat`
두 실행 파일 모두 아래를 수행한다.
1. 프로젝트 폴더로 이동
2. `node_modules`가 없으면 `npm install`
3. 기존 `3000`, `3002` 포트 프로세스 정리
4. MCP Bridge 서버 실행
5. Vite 앱 실행
## Compatibility Wrappers
기존 실행 파일과의 호환성을 위해 아래 파일은 메인 실행 파일로 위임하도록 단순화했다.
- `run_app.sh` -> `run_mac.command`
- `run_app.bat` -> `run_win.bat`
## Verification
실행한 검증:
```bash
bash -n run_mac.command
bash -n run_app.sh
npm run lint
```
검증 결과:
- macOS shell script 문법 통과
- TypeScript 타입체크 통과
## Operational Note
앞으로 맥에서는 `run_mac.command`, 윈도우에서는 `run_win.bat`만 실행하면 된다.
`npm run dev` 단독 실행은 프런트엔드만 켜므로 NotebookLM, Wiki save, 인증 복구 API가 동작하지 않는다.
@@ -0,0 +1,68 @@
# Datacollector - NotebookLM 인증 브라우저 유지 및 오래된 .env 쿠키 우선순위 문제 해결
- 작성 시각: 2026-04-25 21:31:00 KST
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
- 관련 파일: `scripts/mcp_bridge.mjs`, `auth_mac.command`, `auth_win.bat`, `.env.example`
## 상황
앱에서 `/api/check-connection` 호출이 500으로 실패했고, 화면에는 다음과 같은 메시지가 반복되었다.
- `Authentication expired`
- `인증 자동 복구 실패. 브라우저 로그인이 필요한 상태일 수 있습니다.`
- `MCP initialized: true, pending: 0`
사용자는 NotebookLM 인증 중 Chrome이 열렸다가 닫히는 점을 보고, 인증 브라우저를 유지해야 하는 것 아니냐고 질문했다.
## 확인한 내용
`notebooklm-mcp-auth` 소스 확인 결과, 기본 자동 실행 모드는 인증 후 자신이 띄운 Chrome 프로세스를 종료한다. 반면 `--no-auto-launch --port ... --user-data-dir ...` 모드는 이미 떠 있는 Chrome 디버깅 세션에 붙기 때문에 인증 브라우저를 유지할 수 있다.
브리지에서 Chrome을 유지하도록 바꾼 뒤 인증 CLI는 성공했다. 하지만 MCP 서버의 `notebook_list`는 여전히 `Authentication expired`를 반환했다.
추가 확인 결과, `.env`에 예전 `NOTEBOOKLM_COOKIES` 값이 남아 있었다. `scripts/mcp_bridge.mjs``dotenv/config`를 로드한 뒤 MCP 서버를 자식 프로세스로 실행하면서 이 오래된 환경변수 쿠키가 `~/.notebooklm-mcp/auth.json`의 최신 인증 캐시보다 우선 적용되고 있었다.
즉 실제 핵심 원인은 다음 조합이었다.
- 인증 CLI는 최신 쿠키를 `~/.notebooklm-mcp/auth.json`에 정상 저장함.
- 브리지는 `.env`의 오래된 `NOTEBOOKLM_COOKIES`를 MCP 자식 프로세스에 전달함.
- MCP 서버는 캐시 파일보다 환경변수를 우선 사용함.
- 결과적으로 새 인증 후에도 MCP는 계속 오래된 쿠키로 NotebookLM API를 호출함.
## 조치
`scripts/mcp_bridge.mjs`에서 기본적으로 MCP 자식 프로세스와 인증 CLI 자식 프로세스에 `NOTEBOOKLM_COOKIES`, `NOTEBOOKLM_CSRF_TOKEN`, `NOTEBOOKLM_SESSION_ID`를 넘기지 않도록 수정했다.
명시적으로 환경변수 인증을 사용해야 할 경우에는 `.env`에 아래 값을 둔다.
```env
USE_NOTEBOOKLM_ENV_AUTH="true"
```
기본값은 `false`이며, 이 경우 `notebooklm-mcp-auth`가 생성한 `~/.notebooklm-mcp/auth.json` 캐시를 우선 사용한다.
또한 `auth_mac.command`, `auth_win.bat`는 별도 Chrome 프로필과 디버깅 포트를 사용해 NotebookLM 인증 브라우저를 열어두는 방식으로 변경했다.
## 검증
다음 검증을 완료했다.
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
```
결과:
```json
{"success":true,"count":0}
```
직접 Python MCP 클라이언트로도 같은 인증 캐시를 사용해 `list_notebooks` 호출이 성공했고, 노트북 89개를 읽는 것을 확인했다.
## 운영 메모
앞으로는 `.env`에 오래된 `NOTEBOOKLM_COOKIES`가 남아 있어도 기본 브리지 실행에는 영향을 주지 않는다. 다만 혼란을 줄이려면 장기적으로 `.env`에서 `NOTEBOOKLM_COOKIES` 줄을 삭제하거나 주석 처리하는 것이 좋다.
NotebookLM 인증용 Chrome 창은 닫지 않는 것이 좋다. 인증이 풀렸을 때 브리지가 같은 디버깅 포트의 Chrome 세션에 붙어 자동 복구를 시도할 수 있다.
@@ -0,0 +1,85 @@
# Datacollector NotebookLM Automatic Auth Recovery
Date: 2026-04-25 20:47:05 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
컴퓨터 포맷 이후 NotebookLM MCP 인증이 자주 실패하고, 20-30분마다 `auth_mac.command`를 수동 실행해야 하는 문제가 있었다.
이번 작업에서는 인증 만료 시 브리지 서버가 자동으로 복구를 시도하도록 개선했다.
## Root Cause Hypothesis
기존 구조는 MCP 서버의 `refresh_auth` 도구 호출에만 의존했다.
하지만 포맷 이후 로컬 토큰 저장 위치나 Chrome 세션 상태가 달라지면서 `refresh_auth`만으로 복구되지 않는 상황이 발생할 수 있다.
사용자가 직접 실행하던 파일은 다음 명령의 래퍼였다.
```bash
/Users/g1nation_mac/.local/bin/notebooklm-mcp-auth
```
따라서 자동 복구 흐름에도 이 CLI 인증 명령을 포함시키는 것이 가장 직접적인 개선 방향이다.
## Changes Made
수정 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/.env.example`
핵심 변경:
- 브리지 서버가 `.env`를 읽도록 `dotenv/config`를 추가했다.
- `AUTH_PATH`, `AUTH_ARGS`, `AUTH_TIMEOUT_MS`, `AUTH_REFRESH_INTERVAL_MS` 설정을 추가했다.
- MCP 인증 에러 발생 시 `refresh_auth`를 먼저 시도한다.
- `refresh_auth` 실패 시 MCP 프로세스를 재시작하고 다시 갱신을 시도한다.
- 그래도 실패하면 `notebooklm-mcp-auth` CLI를 브리지 서버가 직접 실행한다.
- CLI 인증 후 MCP 프로세스를 재시작해 새 토큰을 읽게 만든다.
- 장시간 실행 중에는 15분 간격으로 요청이 없는 시점에 인증 상태를 사전 갱신한다.
- UI 안내 문구를 수동 재인증 중심에서 자동 복구 중심으로 수정했다.
## Runtime Behavior
새 인증 복구 순서:
1. NotebookLM MCP 요청 실패
2. 에러 메시지가 인증 관련인지 판단
3. `refresh_auth` 호출
4. MCP 프로세스 재시작 후 `refresh_auth` 재시도
5. `notebooklm-mcp-auth` CLI 자동 실행
6. MCP 프로세스 재시작
7. 원래 실패했던 NotebookLM 요청 재시도
주기적 갱신:
- 기본 간격: 15분
- 설정값: `AUTH_REFRESH_INTERVAL_MS=900000`
- 진행 중인 MCP 요청이 있을 때는 건드리지 않고 건너뛴다.
## Verification
실행한 검증:
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
npm run bridge
curl -s http://127.0.0.1:3002/api/health
```
검증 결과:
- `node --check` 통과
- TypeScript 타입체크 통과
- 브리지 서버 시작 성공
- MCP 서버 초기화 성공
- `/api/health`에서 `connected: true`, `version: 3.3.0`, `authPath` 확인
## Notes
완전히 백그라운드 인증이 가능한지는 Google/Chrome 세션 상태에 의존한다.
브라우저 로그인이 만료되어 실제 사용자 로그인이 필요한 상태라면 자동 CLI 실행도 브라우저 로그인을 요구할 수 있다.
다만 기존처럼 매번 사용자가 batch 파일을 직접 실행하는 흐름보다, 일반적인 토큰 만료와 MCP refresh 실패 상황은 브리지 서버가 먼저 복구하도록 개선되었다.
@@ -0,0 +1,60 @@
# Datacollector - NotebookLM 자동 재인증 검증 강화 및 동시 복구 잠금
- 작성 시각: 2026-04-25 22:17:33 KST
- 프로젝트: `/Volumes/Data/project/Antigravity/Datacollector`
- 관련 파일: `scripts/mcp_bridge.mjs`
## 상황
인증 브라우저 유지와 오래된 `.env` 쿠키 우선순위 문제를 해결한 뒤에도, 실제 작업 중 인증이 풀렸을 때 완전히 자동으로 재인증되지 않는 문제가 남아 있었다.
화면에서는 작업은 진행되지만 사용자가 기대한 "인증 만료 감지 -> 자동 재인증 -> 원래 작업 재시도" 흐름이 안정적으로 보장되지 않았다.
## 원인
브리지에는 자동 복구 로직이 있었지만 두 가지 빈틈이 있었다.
- `refresh_auth` 호출이 성공해도 실제 NotebookLM API 호출이 가능한지 검증하지 않았다.
- `/api/re-auth``/api/check-connection` 같은 요청이 동시에 들어오면 각각 MCP 재시작과 인증 복구를 시도해서 프로세스 재시작 경합이 생길 수 있었다.
추가로 인증 오류 판별 문자열에 `expired`, `RPC Error 16`, `csrf`, `만료` 같은 케이스가 충분히 포함되지 않아 일부 인증 만료 메시지가 일반 오류로 처리될 가능성이 있었다.
## 조치
`scripts/mcp_bridge.mjs`에서 다음을 수정했다.
- 재인증 성공 기준을 `refresh_auth` 성공이 아니라 실제 `notebook_list` 호출 성공으로 강화했다.
- 인증 만료 감지 시 `refreshAuth({ allowExternalAuth: true })`를 통해 자동 CLI 인증 복구까지 이어지도록 정리했다.
- 주기적 인증 점검도 필요 시 외부 인증 CLI 복구를 허용하도록 변경했다.
- `_refreshAuthPromise` 잠금을 추가해 동시 재인증/재시작 요청이 서로 충돌하지 않게 했다.
- 인증 오류 감지 키워드에 `expired`, `rpc error 16`, `csrf`, `unauthorized`, `forbidden`, `인증`, `만료`를 추가했다.
## 검증
다음 검증을 완료했다.
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
curl -sS -X POST http://127.0.0.1:3002/api/re-auth
curl -sS -X POST http://127.0.0.1:3002/api/check-connection
```
결과:
- `/api/re-auth`: `success: true`
- `/api/check-connection`: `success: true`
또한 `/api/re-auth``/api/check-connection`을 동시에 호출해도 둘 다 성공하는 것을 확인했다.
## 운영 메모
이제 인증이 풀린 상태에서 NotebookLM MCP 호출이 인증 오류를 반환하면 브리지가 다음 순서로 자동 복구한다.
1. MCP의 `refresh_auth` 실행
2. 실제 `notebook_list` 호출로 인증 유효성 검증
3. 실패 시 MCP 프로세스 재시작 후 재검증
4. 그래도 실패하면 `notebooklm-mcp-auth` CLI 실행
5. 인증 캐시 정리 후 MCP 재시작 및 실제 호출 검증
NotebookLM 브라우저 세션이 완전히 로그아웃된 상태라면 자동 CLI도 브라우저 로그인을 요구할 수 있다. 이 경우 사용자가 열린 NotebookLM Chrome 창에서 로그인만 해두면 이후 자동 복구가 다시 이어질 수 있다.
@@ -0,0 +1,84 @@
# Datacollector NotebookLM Connection Guard and MCP Restart Fix
Date: 2026-04-25 21:02:35 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
실행 중 NotebookLM 연결 체크가 500 에러를 반환한 뒤에도 미션이 계속 시작되어 Local LM fallback으로 넘어가고, 결국 `Local LM returned an empty or invalid response` 에러가 발생했다.
또한 브리지의 MCP 재시작 로직에서 자동 재시작과 수동 재시작이 겹쳐 여러 `notebooklm-mcp` 프로세스가 남는 문제가 확인되었다.
## Observed Errors
브라우저 콘솔:
```text
:3000/favicon.ico 404 (Not Found)
127.0.0.1:3002/api/check-connection 500 (Internal Server Error)
```
앱 로그:
```text
NotebookLM 연결 실패: 인증 자동 복구 실패...
GENERAL MODE
ENGINE ERROR Local LM returned an empty or invalid response.
```
## Root Causes
1. `testNotebookLmConnection()`이 성공 여부를 반환하지 않았다.
2. `handleStart`, `handleResume`, `handleGlobalResume`이 연결 실패 후에도 그대로 `running` 상태로 넘어갔다.
3. `restart()`가 MCP 프로세스 종료 이벤트를 기다리지 않고 바로 새 프로세스를 띄울 수 있었다.
4. `close` 이벤트의 자동 재시작이 수동 재시작과 겹쳐 MCP 하위 프로세스가 누적될 수 있었다.
5. favicon 파일이 없어서 브라우저가 `/favicon.ico` 기본 요청을 404로 표시했다.
## Changes Made
수정 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
- `/Volumes/Data/project/Antigravity/Datacollector/index.html`
추가 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/public/favicon.svg`
핵심 변경:
- `testNotebookLmConnection()``Promise<boolean>`을 반환하도록 변경
- NotebookLM 연결 실패 시 신규 미션 시작, 개별 재개, 전체 재개를 보류
- 연결 실패 후 Local LM fallback으로 자동 진행되는 흐름 차단
- MCP 프로세스를 종료할 때 `close` 이벤트를 기다리는 `_stopCurrentProcess()` 추가
- 재시작 중 자동 재시작이 중복 실행되지 않도록 제어
- 재시작 테스트 후 MCP 하위 프로세스가 하나만 남는지 확인
- SVG favicon 추가 및 `index.html`에 명시
## Verification
실행한 검증:
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
npm run build
npm run bridge
curl -s http://127.0.0.1:3002/api/health
curl -s -X POST http://127.0.0.1:3002/api/restart
```
검증 결과:
- 브리지 문법 체크 통과
- TypeScript 타입체크 통과
- Vite 빌드 통과
- 브리지 시작 성공
- `/api/health` 응답 정상
- `/api/restart``notebooklm-mcp` 프로세스가 하나만 남는 것 확인
## Operational Note
현재 실행 중이던 오래된 브리지와 누적된 MCP 하위 프로세스는 종료했다.
앱은 다시 실행해야 새 브리지 로직이 적용된다.
@@ -0,0 +1,70 @@
# Datacollector NotebookLM Progress Visibility and Auth Diagnosis
Date: 2026-04-25 21:17:24 KST
Project: Datacollector
Repository: `/Volumes/Data/project/Antigravity/Datacollector`
## Summary
사용자가 UI에서 `NotebookLM 연결 상태 점검 중...` 로그만 반복되고 실제 진행 상황을 알 수 없다고 보고했다.
확인 결과 앱이 프로젝트 생성 단계까지 가지 못하고 있었으며, 원인은 NotebookLM 연결 확인 단계에서 MCP 인증이 만료 상태로 판단되기 때문이었다.
## Observed State
확인한 상태:
- Vite 서버 `3000` 실행 중
- MCP Bridge 서버 `3002` 실행 중
- `notebooklm-mcp` 프로세스 실행 중
- `/api/health` 응답 가능
- `/api/check-connection`은 NotebookLM 인증 만료 오류 반환
브리지 로그상 자동 인증 CLI는 Chrome을 열고 로그인 및 토큰 추출까지 수행했다.
그러나 MCP 서버는 이후에도 `Authentication expired`로 판단하여 NotebookLM notebook list 호출에 실패했다.
## Changes Made
수정 파일:
- `/Volumes/Data/project/Antigravity/Datacollector/scripts/mcp_bridge.mjs`
- `/Volumes/Data/project/Antigravity/Datacollector/src/components/AgentDashboard.tsx`
핵심 변경:
- MCP 초기화 타임아웃 추가: `MCP_INIT_TIMEOUT_MS`
- NotebookLM 연결 확인 타임아웃 추가: `MCP_HEALTH_TIMEOUT_MS`
- `/api/health`에 상세 상태 추가
- `initialized`, `processRunning`, `processPid`, `pendingRequests`, `authStatus` 노출
- 인증 CLI 진행 단계(`starting`, `running`, `restarting`, `success`, `failed`) 추적
- UI 연결 점검 중 5초마다 Bridge/MCP/auth 진행 상태 로그 출력
- 중복 연결 점검 요청은 기존 Promise를 재사용하도록 변경
## Verification
실행한 검증:
```bash
node --check scripts/mcp_bridge.mjs
npm run lint
npm run build
curl -sS --max-time 5 http://127.0.0.1:3002/api/health
curl -sS --max-time 25 -X POST -H 'Content-Type: application/json' -d '{}' http://127.0.0.1:3002/api/check-connection
```
검증 결과:
- 브리지 문법 체크 통과
- TypeScript 타입체크 통과
- Vite 빌드 통과
- Bridge/MCP 프로세스는 실행됨
- NotebookLM 연결 확인은 인증 만료 오류로 실패
## Current Diagnosis
현재 문제는 앱 실행이나 Bridge 연결 문제가 아니라 NotebookLM MCP 인증 상태 문제다.
자동 인증 CLI가 토큰을 저장해도 MCP 서버가 계속 만료로 판단하므로, 다음 단계에서는 NotebookLM MCP 패키지의 인증 저장 형식 또는 권장 인증 방식(`--file` 모드 등)을 확인해야 한다.
## Operational Note
확인용으로 실행했던 Bridge/Vite/MCP 프로세스는 종료했다.
새 진행 상태 로그를 보려면 앱을 `run_mac.command`로 다시 실행해야 한다.