diff --git a/.agents/references/known-issues.md b/.agents/references/known-issues.md new file mode 100644 index 0000000..29725d3 --- /dev/null +++ b/.agents/references/known-issues.md @@ -0,0 +1,101 @@ +# Known Issues & Lessons Learned + +> **이 파일은 SSOT(Single Source of Truth)입니다.** +> 디버깅이나 구현 전에 **반드시** 이 파일을 확인하세요. +> 세션 종료 시 새로 발견된 이슈를 이 파일에 추가합니다. + +--- + +## 포맷 + +각 항목은 아래 형식을 따릅니다: + +```markdown +### [날짜] [키워드] — 한줄 요약 +- **증상**: 무엇이 잘못되었는가 +- **원인**: 근본 원인 +- **해결**: 올바른 해결 방법 +- **주의**: 재발 방지를 위한 교훈 +``` + +--- + +## 공통 이슈 + +### [2026-03-08] PowerShell curl — Invoke-WebRequest 충돌 +- **증상**: `curl` 명령이 예상과 다른 응답 형식을 반환 +- **원인**: PowerShell에서 `curl`은 `Invoke-WebRequest`의 별칭 +- **해결**: **`curl.exe`**를 명시적으로 사용 +- **주의**: HTTP 관련 모든 명령에서 `curl.exe` 사용 필수 + +### [2026-03-08] PowerShell npm — 실행 정책 오류 +- **증상**: `npm run` 명령이 `실행 정책` 관련 오류로 실패 +- **원인**: PowerShell 스크립트 실행 정책이 제한적으로 설정됨 +- **해결**: `cmd /c npm run dev` 형식으로 cmd를 통해 실행 +- **주의**: npm 관련 명령은 항상 `cmd /c` 접두어 사용 권장 + +--- + +## 프로젝트별 이슈 + +> 아래에 프로젝트 특화 이슈를 추가하세요. + +### [2026-03-08] Antigravity Renderer Injection — Electron 캐시 차단 +- **증상**: workbench.html, workbench-jetski-agent.html에 ``** 방식으로 HTML에 직접 삽입 +- **주의**: `ag-bridge-ports.json`도 같은 이유로 XHR 로딩 불가. 모든 렌더러 스크립트/데이터는 HTML 인라인으로 전달해야 함 + +### [2026-03-08] Renderer 포트 디스커버리 — ag-bridge-ports.json XHR 실패 +- **증상**: `[GB Observer] Port discovery timeout after 2min` — 렌더러가 bridge 포트를 찾지 못함 +- **원인**: 렌더러 스크립트가 `./ag-bridge-ports.json`을 동기 XHR로 읽으려 하나, `vscode-file://` 프로토콜이 `.json` 파일 서빙 거부 +- **해결**: (1) 프로젝트명 해시 기반 **결정론적 포트** 사용 (`gravity_control→34332`), (2) 스크립트 생성 시 포트를 `HARDCODED_PORT=${port}`로 직접 삽입 +- **주의**: `server.listen(0)` 랜덤 포트 → 매 재시작마다 변경되어 렌더러와 불일치. 결정론적 포트는 `EADDRINUSE` 시 랜덤 폴백 필요 diff --git a/docs/devlog/2026-03-08.md b/docs/devlog/2026-03-08.md index 30ebeae..25b9f5a 100644 --- a/docs/devlog/2026-03-08.md +++ b/docs/devlog/2026-03-08.md @@ -16,3 +16,4 @@ | 12 | 11:30~14:35 | 승인 로직 정밀 디버깅: IDLE→stall 전환, lastModifiedTime 구분, RPC/Commands 전수 테스트, ResolveOutstandingSteps cancel 발견 | - | 🔧 | | 13 | 15:00~16:52 | Multi-window 격리 (v0.3.1→0.3.4): 세션 필터, per-project 포트, 등록 경쟁 조건 수정, DOM Observer 렌더러 디버깅 | - | 🔧 | | 14 | 17:01~17:38 | **근본 원인 발견**: product.json 체크섬 불일치 → vscode-file:// 원본 캐시 서빙. 체크섬 수동 업데이트로 수정 | - | 🔧 | +| 15 | 17:50~18:30 | **v0.3.5**: 포트 디스커버리 수정 (결정론적 포트 + 하드코딩), 인라인 스크립트 전환 (``), product.json 자동 체크섬 업데이트 | - | 🔧 | diff --git a/extension/gravity-bridge-0.2.0.vsix b/extension/gravity-bridge-0.2.0.vsix deleted file mode 100644 index bbd8c42..0000000 Binary files a/extension/gravity-bridge-0.2.0.vsix and /dev/null differ diff --git a/extension/out/extension.js b/extension/out/extension.js index ed03caa..8d7ee8d 100644 --- a/extension/out/extension.js +++ b/extension/out/extension.js @@ -51,6 +51,7 @@ const fs = __importStar(require("fs")); const path = __importStar(require("path")); const os = __importStar(require("os")); const cp = __importStar(require("child_process")); +const crypto = __importStar(require("crypto")); // ─── File-based logging (AI can read directly) ─── function logToFile(msg) { const ts = new Date().toISOString().replace('T', ' ').substring(0, 19); @@ -73,6 +74,7 @@ let statusBar; let bridgePath; let projectName; let isActive = false; +let deterministicPort = 0; // derived from projectName, consistent across restarts let watcher = null; let commandsWatcher = null; const sentPendingIds = new Set(); @@ -287,26 +289,44 @@ async function setupApprovalObserver() { logToFile('[OBSERVER] workbench.html patched (needs reload)'); } // Also patch workbench-jetski-agent.html (Antigravity's actual entry point!) + // IMPORTANT: vscode-file:// protocol does NOT serve custom .js files, + // so we INLINE the script content directly into the HTML. const scriptDir = path.dirname(scriptPath); const jetskiHtml = path.join(scriptDir, 'workbench-jetski-agent.html'); - const scriptBasename = path.basename(scriptPath); try { if (fs.existsSync(jetskiHtml)) { let html = fs.readFileSync(jetskiHtml, 'utf8'); - if (!html.includes(scriptBasename)) { - html = html.replace('', `\n\n\n\n`); - fs.writeFileSync(jetskiHtml, html, 'utf8'); - logToFile('[OBSERVER] workbench-jetski-agent.html PATCHED'); + // Remove old external script tag if present (from previous versions) + const oldScriptBasename = path.basename(scriptPath); + if (html.includes(`src="./${oldScriptBasename}"`)) { + html = html.replace(/\n?\n?\n${inlineMarkerEnd}`); + logToFile('[OBSERVER] jetski HTML inline script UPDATED'); } else { - logToFile('[OBSERVER] workbench-jetski-agent.html already has script tag'); + // First time: insert before + html = html.replace('', `\n${inlineMarkerStart}\n\n${inlineMarkerEnd}\n`); + logToFile('[OBSERVER] jetski HTML inline script INSERTED'); } + fs.writeFileSync(jetskiHtml, html, 'utf8'); } } catch (e) { logToFile(`[OBSERVER] jetski patch error: ${e.message}`); } } + // 4. Update product.json checksums so vscode-file:// serves our patched files + updateProductChecksums(); try { integration.enableAutoRepair(); } @@ -322,9 +342,78 @@ async function setupApprovalObserver() { logToFile(`[OBSERVER] setup error: ${err.message}`); } } +// ─── Product.json Checksum Auto-Update ─── +// vscode-file:// protocol validates SHA256 checksums in product.json. +// If a file's checksum doesn't match, Electron serves the ORIGINAL cached version. +// This function recalculates checksums for files we modify (HTML files with \n\n`); - fs.writeFileSync(jetskiHtml, html, 'utf8'); - logToFile('[OBSERVER] workbench-jetski-agent.html PATCHED'); - } else { - logToFile('[OBSERVER] workbench-jetski-agent.html already has script tag'); + + // Remove old external script tag if present (from previous versions) + const oldScriptBasename = path.basename(scriptPath); + if (html.includes(`src="./${oldScriptBasename}"`)) { + html = html.replace( + /\n?\n?\n${inlineMarkerEnd}`); + logToFile('[OBSERVER] jetski HTML inline script UPDATED'); + } else { + // First time: insert before + html = html.replace('', + `\n${inlineMarkerStart}\n\n${inlineMarkerEnd}\n`); + logToFile('[OBSERVER] jetski HTML inline script INSERTED'); + } + fs.writeFileSync(jetskiHtml, html, 'utf8'); } } catch (e: any) { logToFile(`[OBSERVER] jetski patch error: ${e.message}`); } } + // 4. Update product.json checksums so vscode-file:// serves our patched files + updateProductChecksums(); + try { integration.enableAutoRepair(); } catch { } setInterval(() => { try { integration.signalActive(); } catch { } }, 30_000); @@ -278,11 +308,86 @@ async function setupApprovalObserver() { } } +// ─── Product.json Checksum Auto-Update ─── +// vscode-file:// protocol validates SHA256 checksums in product.json. +// If a file's checksum doesn't match, Electron serves the ORIGINAL cached version. +// This function recalculates checksums for files we modify (HTML files with