docs: devlog #012 + known-issues 3건 + VSIX v0.4.3 빌드 아티팩트
This commit is contained in:
@@ -645,3 +645,34 @@
|
|||||||
- **원인**: `ws` npm 패키지가 `.vscodeignore`의 `node_modules/**`에 의해 VSIX에서 제외됨. AG Electron에 `ws` 미포함. `globalThis.WebSocket`은 Node.js 22+에서만 사용 가능
|
- **원인**: `ws` npm 패키지가 `.vscodeignore`의 `node_modules/**`에 의해 VSIX에서 제외됨. AG Electron에 `ws` 미포함. `globalThis.WebSocket`은 Node.js 22+에서만 사용 가능
|
||||||
- **해결**: (1) `.vscodeignore`에 `!node_modules/ws/**` 추가하여 VSIX에 ws 번들, (2) 설치 후 수동으로 `node_modules/ws/`를 설치 경로에 복사
|
- **해결**: (1) `.vscodeignore`에 `!node_modules/ws/**` 추가하여 VSIX에 ws 번들, (2) 설치 후 수동으로 `node_modules/ws/`를 설치 경로에 복사
|
||||||
- **주의**: `package.json`에 `ws` dependency 추가 후 `npx vsce package` 시에도 `.vscodeignore`의 `!node_modules/ws/**` 없으면 번들 안 됨. `--no-dependencies` 플래그와 무관
|
- **주의**: `package.json`에 `ws` dependency 추가 후 `npx vsce package` 시에도 `.vscodeignore`의 `!node_modules/ws/**` 없으면 번들 안 됨. `--no-dependencies` 플래그와 무관
|
||||||
|
|
||||||
|
### [2026-03-17] WS Auth 실패 — 워크스페이스 settings 빈 값 override
|
||||||
|
- **증상**: Extension이 Hub에 연결 성공하지만 `Auth failed: Auth required` 반복. `registrationCode`가 항상 empty
|
||||||
|
- **원인**: `.vscode/settings.json`에 `"gravityBridge.registrationCode": ""`(빈 문자열)이 설정되어, 유저 설정(`%APPDATA%/Antigravity/User/settings.json`)의 올바른 값을 워크스페이스 설정이 **덮어쓰기**. VS Code 설정 우선순위: workspace > user
|
||||||
|
- **해결**: `.vscode/settings.json`의 `registrationCode`에 올바른 값 설정
|
||||||
|
- **주의**: VS Code `config.get()`은 워크스페이스에 빈 문자열이 있으면 유저 설정의 값을 무시함. 빈 값도 "설정됨"으로 취급. `hubUrl`은 워크스페이스에 정상 값이라 동작했지만 `registrationCode`만 빈 값이라 불일치 발생
|
||||||
|
|
||||||
|
### [2026-03-17] WS auth_fail 무한 재연결 — _cleanup() close 이벤트
|
||||||
|
- **증상**: `Auth failed` 후 "Don't reconnect" 주석에도 불구하고 60초마다 재연결 반복
|
||||||
|
- **원인**: `_cleanup()`이 `ws.close()` → close 이벤트 → `_onDisconnect()` → `_scheduleReconnect()` 체인 트리거. `shouldReconnect`를 false로 설정하지 않아 재연결 차단 안 됨
|
||||||
|
- **해결**: `auth_fail` 핸들러에서 `this.shouldReconnect = false`를 `_cleanup()` **이전에** 설정
|
||||||
|
- **주의**: `_cleanup()`은 WS를 닫으면서 이벤트 핸들러를 트리거하므로, 상태 변경은 반드시 `_cleanup()` 호출 전에 수행할 것
|
||||||
|
|
||||||
|
### [2026-03-17] initStepProbe workspaceUri 누락 — 세션 감지 완전 불능
|
||||||
|
- **증상**: POLL alive만 출력되고 SESSION-FILTER/SNAPSHOT 전혀 없음. Discord에 아무것도 도착 안 함
|
||||||
|
- **원인**: `initStepProbe()` 호출 시 `workspaceUri`와 `diffReviewMetadata` 미전달. `as BridgeContext` 캐스트가 누락 필드를 무시. `ctx.workspaceUri.replace()`에서 매 5초 TypeError. 에러가 `console.log`로만 기록되어 extension.log에 안 보임
|
||||||
|
- **해결**: `extension.ts` L1131에 `workspaceUri`, `diffReviewMetadata: new Map()` 추가
|
||||||
|
- **주의**: TypeScript `as` 캐스트는 런타임 검증 없음. 필수 필드 누락도 컴파일 에러 없이 통과. 에러 핸들러가 `ctx.logToFile` 대신 `console.log` 사용하면 extension.log에 안 남음
|
||||||
|
|
||||||
|
### [2026-03-17] WS dual-write — 채팅/승인 이중 발송
|
||||||
|
- **증상**: Discord 메시지가 2개씩 도착 (동일 내용)
|
||||||
|
- **원인**: `writeChatSnapshot`/`writePendingApproval`이 WS 전송 후 파일도 동시에 씀 (Phase 0 dual-write). Watcher가 파일도 읽어서 Discord로 보냄 → 같은 메시지 2번 전달
|
||||||
|
- **해결**: WS 연결 시 `return`으로 파일 쓰기 건너뛰기. 파일은 fallback 전용으로 변경
|
||||||
|
- **주의**: `writePendingApproval` 수정 시 diff_review metadata 캐싱 + memory dedup 로직이 WS 경로에서도 실행되어야 함
|
||||||
|
|
||||||
|
### [2026-03-17] Hub WS auto-approve Discord 알림 누락
|
||||||
|
- **증상**: auto-approve 활성화 상태에서 승인 요청이 자동 처리되지만 Discord에 아무 알림 없음 (텍스트만 전달)
|
||||||
|
- **원인**: `_auto_approve_via_hub()` (WS 경로)에서 Discord embed 미전송. 파일 기반 auto-approve (L617)은 "🤖 자동 승인됨" embed 전송하지만 Hub WS 경로 누락
|
||||||
|
- **해결**: `_auto_approve_via_hub()`에 Discord embed 전송 추가 (파일 경로와 동일 포맷)
|
||||||
|
- **주의**: bot.py는 서버에서 실행됨. 로컬 수정 후 반드시 git push → 서버 pull + 재시작
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
| 009 | 00:00~06:38 | Extension 모듈 분리 + Hub 통합 테스트 + VSIX v0.4.0 빌드 | `5f795b9` | ✅ |
|
| 009 | 00:00~06:38 | Extension 모듈 분리 + Hub 통합 테스트 + VSIX v0.4.0 빌드 | `5f795b9` | ✅ |
|
||||||
| 010 | 06:50~07:39 | 문서 전면 재작성 + 서버 배포 + WS 호환 수정 | `6ea3211` | ✅ |
|
| 010 | 06:50~07:39 | 문서 전면 재작성 + 서버 배포 + WS 호환 수정 | `6ea3211` | ✅ |
|
||||||
| 011 | 07:44~08:18 | VSIX v0.4.0 E2E 사전 검증 + WS 프록시 수정 | — | 🔧 |
|
| 011 | 07:44~08:18 | VSIX v0.4.0 E2E 사전 검증 + WS 프록시 수정 | — | 🔧 |
|
||||||
|
| 012 | 09:00~10:40 | VSIX v0.4.3 E2E 디버깅: workspaceUri 누락, 이중발송, auto-approve 알림 | `9523d13` | ✅ |
|
||||||
|
|
||||||
### #010 상세
|
### #010 상세
|
||||||
- **문서**: architecture.md(250줄), tech-stack.md(100줄), conventions.md(100줄) 전면 재작성 + Wiki 동기화
|
- **문서**: architecture.md(250줄), tech-stack.md(100줄), conventions.md(100줄) 전면 재작성 + Wiki 동기화
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ let activeTrajectoryId = '';
|
|||||||
const recentDiscordSentTexts = new Map();
|
const recentDiscordSentTexts = new Map();
|
||||||
function writeChatSnapshot(text) {
|
function writeChatSnapshot(text) {
|
||||||
try {
|
try {
|
||||||
// WS route (preferred)
|
// WS route (preferred) — skip file write to prevent duplicate Discord delivery
|
||||||
if (wsBridge && wsBridge.isConnected()) {
|
if (wsBridge && wsBridge.isConnected()) {
|
||||||
wsBridge.sendChat({
|
wsBridge.sendChat({
|
||||||
content: text,
|
content: text,
|
||||||
@@ -143,8 +143,12 @@ function writeChatSnapshot(text) {
|
|||||||
project_name: projectName,
|
project_name: projectName,
|
||||||
});
|
});
|
||||||
logToFile(`[SNAPSHOT-WS] sent (${text.length} chars)`);
|
logToFile(`[SNAPSHOT-WS] sent (${text.length} chars)`);
|
||||||
|
if (activeSessionId) {
|
||||||
|
(0, step_probe_1.writeRegistration)(activeSessionId);
|
||||||
}
|
}
|
||||||
// File route (fallback / Phase 0 dual-write)
|
return;
|
||||||
|
}
|
||||||
|
// File route (fallback — only when WS is NOT connected)
|
||||||
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
||||||
if (!fs.existsSync(snapshotDir)) {
|
if (!fs.existsSync(snapshotDir)) {
|
||||||
fs.mkdirSync(snapshotDir, { recursive: true });
|
fs.mkdirSync(snapshotDir, { recursive: true });
|
||||||
@@ -172,7 +176,7 @@ function writeChatSnapshot(text) {
|
|||||||
}
|
}
|
||||||
function writeChatSnapshotWithFiles(text, files) {
|
function writeChatSnapshotWithFiles(text, files) {
|
||||||
try {
|
try {
|
||||||
// WS route (preferred)
|
// WS route (preferred) — skip file write to prevent duplicate Discord delivery
|
||||||
if (wsBridge && wsBridge.isConnected()) {
|
if (wsBridge && wsBridge.isConnected()) {
|
||||||
wsBridge.sendChat({
|
wsBridge.sendChat({
|
||||||
content: text,
|
content: text,
|
||||||
@@ -181,8 +185,12 @@ function writeChatSnapshotWithFiles(text, files) {
|
|||||||
project_name: projectName,
|
project_name: projectName,
|
||||||
});
|
});
|
||||||
logToFile(`[SNAPSHOT-WS] sent with ${files.length} files (${text.length} chars)`);
|
logToFile(`[SNAPSHOT-WS] sent with ${files.length} files (${text.length} chars)`);
|
||||||
|
if (activeSessionId) {
|
||||||
|
(0, step_probe_1.writeRegistration)(activeSessionId);
|
||||||
}
|
}
|
||||||
// File route (fallback)
|
return;
|
||||||
|
}
|
||||||
|
// File route (fallback — only when WS is NOT connected)
|
||||||
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
const snapshotDir = path.join(bridgePath, 'chat_snapshots');
|
||||||
if (!fs.existsSync(snapshotDir)) {
|
if (!fs.existsSync(snapshotDir)) {
|
||||||
fs.mkdirSync(snapshotDir, { recursive: true });
|
fs.mkdirSync(snapshotDir, { recursive: true });
|
||||||
@@ -1141,6 +1149,8 @@ async function activate(context) {
|
|||||||
sawRunningAfterPending,
|
sawRunningAfterPending,
|
||||||
clickTrigger,
|
clickTrigger,
|
||||||
logToFile,
|
logToFile,
|
||||||
|
workspaceUri,
|
||||||
|
diffReviewMetadata: new Map(),
|
||||||
recentDiscordSentTexts,
|
recentDiscordSentTexts,
|
||||||
writeChatSnapshot,
|
writeChatSnapshot,
|
||||||
writeChatSnapshotWithFiles,
|
writeChatSnapshotWithFiles,
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
4
extension/package-lock.json
generated
4
extension/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gravity-bridge",
|
"name": "gravity-bridge",
|
||||||
"version": "0.4.0",
|
"version": "0.4.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "gravity-bridge",
|
"name": "gravity-bridge",
|
||||||
"version": "0.4.0",
|
"version": "0.4.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "gravity-bridge",
|
"name": "gravity-bridge",
|
||||||
"displayName": "Gravity Bridge",
|
"displayName": "Gravity Bridge",
|
||||||
"description": "Antigravity ↔ Discord 브리지 연동 확장",
|
"description": "Antigravity ↔ Discord 브리지 연동 확장",
|
||||||
"version": "0.4.0",
|
"version": "0.4.3",
|
||||||
"publisher": "variet",
|
"publisher": "variet",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.100.0"
|
"vscode": "^1.100.0"
|
||||||
|
|||||||
@@ -361,8 +361,11 @@ export class WSBridgeClient {
|
|||||||
this.logFn(`[WS] Auth failed: ${reason}`);
|
this.logFn(`[WS] Auth failed: ${reason}`);
|
||||||
// Clear session token if it was rejected
|
// Clear session token if it was rejected
|
||||||
this.sessionToken = '';
|
this.sessionToken = '';
|
||||||
|
// MUST set shouldReconnect=false BEFORE _cleanup(), because _cleanup()
|
||||||
|
// closes the WS → triggers close event → _onDisconnect() → _scheduleReconnect().
|
||||||
|
// Without this, auth failures cause infinite reconnect loops.
|
||||||
|
this.shouldReconnect = false;
|
||||||
this._cleanup();
|
this._cleanup();
|
||||||
// Don't reconnect on auth failure (needs manual fix)
|
|
||||||
this.handlers.onError?.(`Auth failed: ${reason}`);
|
this.handlers.onError?.(`Auth failed: ${reason}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user