203 lines
9.7 KiB
Markdown
203 lines
9.7 KiB
Markdown
# Observer Script 개발 가이드 — SSOT
|
||
|
||
> **이 문서는 Observer 코드 변경 전 반드시 확인하는 SSOT입니다.**
|
||
> 모든 Observer 관련 설계, 배포, 제약사항이 이 문서에 있습니다.
|
||
|
||
---
|
||
|
||
## 1. Observer 코드 특성
|
||
|
||
### 1.1 실행 환경
|
||
- Observer는 **workbench-jetski-agent.html**에 인라인 `<script>`로 삽입됨
|
||
- **AG Native의 Electron 렌더러 프로세스**에서 실행 (VS Code extension host가 아님)
|
||
- 렌더러는 **strict mode 아님** (확인 필요), 하지만 V8 parser는 일부 strict-like 규칙 적용
|
||
- `generateApprovalObserverScript(port)` 함수가 **TypeScript template literal**로 스크립트 생성
|
||
|
||
### 1.2 코드 작성 규칙 (위반 시 Observer 전체 크래시)
|
||
|
||
| 규칙 | 이유 | 예시 |
|
||
|------|------|------|
|
||
| **for 루프 안에 function 선언 금지** | V8 strict mode error | `var fn = function(){}` 사용 |
|
||
| **문자열 리터럴에 특수문자 금지** | template literal 이스케이핑 깨짐 | `'??'` → `'MAX'` |
|
||
| **regex에 `\\s` 등 이스케이프 금지** | template literal이 `\\\\s` → `\\s` (리터럴) | 문자열 비교 사용 |
|
||
| **ES6+ 구문 금지** | 구 V8 호환 | `var` 사용, `let/const/arrow` 금지 |
|
||
| **배포 전 SYNTAX CHECK 필수** | Observer 크래시 방지 | 아래 검증 명령어 참조 |
|
||
|
||
### 1.3 필수 검증 명령어 (모든 빌드 전 실행)
|
||
```powershell
|
||
npm.cmd run compile; node -e "const {generateApprovalObserverScript}=require('./out/observer-script'); let s=generateApprovalObserverScript(18080); try { new Function(s); console.log('SYNTAX OK'); } catch(e) { console.log('ERROR:', e.message); }"
|
||
```
|
||
**SYNTAX OK가 나오지 않으면 절대 배포하지 않는다.**
|
||
|
||
### 1.4 배포 전 자기검증 체크리스트 (MANDATORY)
|
||
**재시작을 요구하기 전 반드시 다음을 모두 통과해야 한다:**
|
||
|
||
1. [ ] **SYNTAX CHECK 통과**: `new Function(s)` → `SYNTAX OK`
|
||
2. [ ] **수정 방향 검증**: 이 수정이 문제를 해결하는 올바른 접근인지 스스로 2번 재검증
|
||
3. [ ] **template literal 규칙 위반 없음**: regex 이스케이프, 특수문자, function 선언 등
|
||
4. [ ] **변경 범위 최소화**: 불필요한 코드 포함 여부 확인
|
||
5. [ ] **재시작 사유 명시**: 사용자에게 (a) 무엇을 수정했고 (b) 왜 재시작이 필요한지 1~2줄로 설명
|
||
6. [ ] **재시작 횟수 명시**: Observer 변경 = 2회, Extension host만 변경 = 1회
|
||
7. [ ] **log() relay 필터 확인**: 새 로그 키워드 추가 시 log() 함수의 키워드 필터에도 추가했는지 확인 (섹션 3.5 참조)
|
||
8. [ ] **regex E2E 테스트**: Observer에서 사용하는 새 regex는 생성된 코드에서 직접 실행하여 매칭 검증
|
||
9. [ ] **구현 전 가정 검증**: 새 접근을 코딩하기 전에, 핵심 가정이 성립하는지 로그 1줄로 먼저 확인 (예: "Step Probe가 WAITING을 볼 수 있는가?" → `STEP-PROBE.*WAITING` 로그 검색)
|
||
|
||
**정당한 사유 없이 재시작을 요구하지 않는다.**
|
||
**DOM 구조를 먼저 파악하고 설계한 후 코드를 작성한다.**
|
||
**시행착오식(trial-and-error) 접근을 하지 않는다.**
|
||
**추측으로 코딩하지 않는다. 로그/데이터로 확인한 사실에 기반하여 코딩한다.**
|
||
|
||
---
|
||
|
||
## 2. 배포 프로세스
|
||
|
||
### 2.1 Observer 코드가 포함된 변경
|
||
Observer 코드 변경은 **extension host 코드 변경보다 비용이 높다**:
|
||
|
||
```
|
||
VSIX 빌드 → VSIX 설치 → AG 재시작 #1 (extension이 HTML 패치)
|
||
→ AG 재시작 #2 (패치된 HTML 로드) → Observer 실행
|
||
```
|
||
|
||
**총 2번 AG 재시작 필요**
|
||
|
||
### 2.2 Extension host 코드만 변경 (approval-handler, http-bridge 등)
|
||
```
|
||
VSIX 빌드 → VSIX 설치 → AG 재시작 #1 → 즉시 적용
|
||
```
|
||
|
||
**1번 AG 재시작 필요**
|
||
|
||
### 2.3 VSIX 설치 확인
|
||
```powershell
|
||
Get-ChildItem "$env:USERPROFILE\.vscode\extensions" -Filter "*gravity*" -Directory |
|
||
ForEach-Object { $j = Get-Content (Join-Path $_.FullName "package.json") | ConvertFrom-Json; "$($_.Name): v$($j.version)" }
|
||
```
|
||
|
||
### 2.4 HTML 패치 확인 (Observer 코드가 반영되었는지)
|
||
```powershell
|
||
Select-String -Path "$env:LOCALAPPDATA\Programs\Antigravity\resources\app\out\vs\code\electron-browser\workbench\workbench-jetski-agent.html" -Pattern "검색할_함수명" -Quiet
|
||
```
|
||
|
||
---
|
||
|
||
## 3. AG Native DOM 구조
|
||
|
||
### 3.1 Chat Panel (Observer가 접근 가능)
|
||
- 위치: `document.querySelector('#conversation')` 또는 `document.querySelector('[class*="conversation"]')`
|
||
- AI 응답 블록: `.leading-relaxed.select-text`
|
||
- 사용자 메시지 블록: `.select-text.rounded-lg` (v0.5.74+)
|
||
- Thinking 블록: 조상에 `max-h-[200px]` 클래스 있음 → 필터링
|
||
|
||
### 3.2 승인 버튼 — "Always run" (v0.5.93 BTN-DOM-DUMP 확인)
|
||
|
||
실제 DOM 구조 (v0.5.92 로그로 확인):
|
||
- d0: button.flex.cursor-pointer (Always run 버튼)
|
||
- d1: div.min-w-0
|
||
- d2: div.flex.items-center.justify-between.rounded-b.border-t (버튼 바)
|
||
- d3: div (이름 없는 컨테이너)
|
||
- div.mb-1 = "Running command" (헤더)
|
||
- div.flex = "❯ gravity_control > ..." (실제 명령어, plain div!)
|
||
- div.flex = "Always run Cancel" (버튼들)
|
||
|
||
> 명령어는 pre.font-mono나 code가 아닌 plain div.flex에 있음.
|
||
> v30: "Running command" div의 형제를 탐색하여 프롬프트 마커 뒤의 명령어 추출.
|
||
|
||
- "Retry" 버튼: button 태그, chat panel 내
|
||
|
||
### 3.3 Diff Review (Accept all / Reject all) — Observer 접근 불가
|
||
- 에디터 webview에 렌더링, Observer document에서 접근 불가
|
||
- 해결: Extension host에서 antigravity.acceptAgentStep 명령 실행
|
||
|
||
### 3.4 DOM 렌더링 타이밍
|
||
- "Always run" 버튼이 DOM에 나타날 때 명령어 div도 함께 렌더링됨
|
||
- v30의 "Running command" div 탐색은 즉시 성공
|
||
|
||
### 3.5 log() relay 필터 규칙
|
||
Observer의 log() 함수는 키워드 필터로 일부 로그만 extension.log에 relay.
|
||
새 로그 키워드 추가 시 반드시 필터도 함께 수정해야 함.
|
||
|
||
현재 필터 키워드 (v0.5.92+):
|
||
CV-CLASSES, CV-CHILDREN, child[, CV found, Conversation view,
|
||
BEACON, ERROR, chat relay, user-cls,
|
||
CONTEXT, BTN-DOM, DEFERRED, DETECTED
|
||
|
||
---
|
||
|
||
## 4. 파일 경로 매핑
|
||
|
||
| 항목 | 경로 |
|
||
|------|------|
|
||
| AG 설치 경로 | `$env:LOCALAPPDATA\Programs\Antigravity\` |
|
||
| workbench HTML | `...\resources\app\out\vs\code\electron-browser\workbench\workbench-jetski-agent.html` |
|
||
| Extension 로그 | `$env:USERPROFILE\.gemini\antigravity\bridge\extension.log` |
|
||
| Pending 파일 | `$env:USERPROFILE\.gemini\antigravity\bridge\pending\*.json` |
|
||
| Response 파일 | `$env:USERPROFILE\.gemini\antigravity\bridge\response\*.json` |
|
||
| VSIX extensions | `$env:USERPROFILE\.vscode\extensions\variet.gravity-bridge-*\` |
|
||
| HTTP Bridge 포트 | 34332 (또는 `getDeterministicPort('gravity_control')`) |
|
||
| Discord 채널 | `#ag-gravity_control` (ID: 1483082084540223663) |
|
||
|
||
---
|
||
|
||
## 5. 과거 실수 및 교훈
|
||
|
||
### 5.1 VSIX 미설치 (v0.5.78~83)
|
||
- **증상**: 빌드만 하고 `code --install-extension` 실행 안 함
|
||
- **결과**: 설치된 버전이 v0.5.50, 모든 수정사항 미적용
|
||
- **교훈**: 빌드 후 반드시 `code --install-extension *.vsix --force` 실행
|
||
- **확인**: `Get-ChildItem "$env:USERPROFILE\.vscode\extensions" -Filter "*gravity*"`
|
||
|
||
### 5.2 function 선언 → Observer 크래시 (v0.5.84~86)
|
||
- **증상**: `function _isGenericDesc(d){}` 를 for 루프 내부에 선언
|
||
- **결과**: Observer 전체 크래시, chat relay + auto-approve 중단
|
||
- **교훈**: `var fn = function(){}` 사용, 배포 전 SYNTAX CHECK 필수
|
||
|
||
### 5.3 깨진 문자열 리터럴 (v0.5.86)
|
||
- **증상**: `{tag:'??',...}` (특수문자가 따옴표 깨뜨림)
|
||
- **결과**: SYNTAX ERROR, Observer 미작동
|
||
- **교훈**: template literal 안에서 특수문자/이모지 사용 주의
|
||
|
||
### 5.4 regex 이스케이핑 실패 (v0.5.83~84)
|
||
- **증상**: `/Always\\s+run/` → 생성 시 `\\s` (리터럴 백슬래시+s)로 출력
|
||
- **결과**: "Always run" 매칭 실패
|
||
- **교훈**: template literal 안에서 regex 대신 **문자열 비교** 사용
|
||
|
||
### 5.5 _from_ws 파일 무한 누적 (v0.5.78~84)
|
||
- **증상**: response 파일에 `_from_ws: true` 마커 → processResponseFile이 스킵 → 영원히 삭제 안 됨
|
||
- **결과**: 3초마다 4개 파일 × SKIP 로그 → 로그 스팸, 다른 처리 방해
|
||
- **교훈**: 보존 파일에는 반드시 **TTL(자동 만료)** 추가
|
||
|
||
---
|
||
|
||
## 6. 디버깅 체크리스트
|
||
|
||
### Observer가 작동하지 않을 때
|
||
1. `extension.log`에서 `setup complete` 확인 → Observer 로드 여부
|
||
2. `OBSERVER-LOG` 패턴 검색 → 스캔 활동 여부
|
||
3. `HTTP-REQ` 검색 → HTTP bridge에 요청 도달 여부
|
||
4. **SYNTAX CHECK** 실행 → 생성 스크립트 문법 검증
|
||
5. `SKIP _from_ws` 반복 확인 → stale response 파일 정리
|
||
|
||
### Discord에 메시지가 안 올 때
|
||
1. `POST /chat` 검색 → chat relay 전송 여부
|
||
2. `WS.*send` 검색 → WebSocket 전송 여부
|
||
3. Discord API로 직접 확인: `node extension/scratch/discord_read.js`
|
||
4. stale response 파일 확인: `Get-ChildItem $env:USERPROFILE\.gemini\antigravity\bridge\response\*.json`
|
||
|
||
---
|
||
|
||
## 7. 버전 히스토리 요약
|
||
|
||
| 버전 | 핵심 변경 | 결과 |
|
||
|------|----------|------|
|
||
| v0.5.50 | 기본 릴레이 시스템 | ✅ 안정 |
|
||
| v0.5.78 | `_from_ws` 마커 (Retry 보존) | ✅ 작동 (TTL 미구현) |
|
||
| v0.5.79 | sibling 탐색 + thinking 필터 | ✅ 작동 |
|
||
| v0.5.80~81 | Accept all offsetParent 완화 | ❌ 구조적 불가 (에디터 webview) |
|
||
| v0.5.82 | 버튼 셀렉터 확장 + ACCEPT-SCAN | 진단용 |
|
||
| v0.5.83 | DEFERRED 컨텍스트 500ms | regex 이스케이핑 실패 |
|
||
| v0.5.84 | regex → 문자열 비교 | function 선언 크래시 |
|
||
| v0.5.85 | `_from_ws` TTL 60초 | ✅ stale 정리 |
|
||
| v0.5.86 | function → var expression | 깨진 문자열 미발견 |
|
||
| v0.5.87 | 깨진 문자열 2건 수정 | ✅ SYNTAX OK |
|