diff --git a/.agents/references/known-issues.md b/.agents/references/known-issues.md index beceb02..5c0590e 100644 --- a/.agents/references/known-issues.md +++ b/.agents/references/known-issues.md @@ -248,3 +248,6 @@ - **원인**: 1) UI 버튼 텍스트에 `keyboard_arrow_up` 등 머티리얼 아이콘 텍스트가 접착(`Always runkeyboard_arrow_up`)되어 정규식이 실패할 것을 우려해 단어 경계(`\b`)를 제거한 패치가 원인. 단어 경계가 사라지면서 `/Run/i` 패턴이 `Running1 command` 같은 다른 상태 텍스트 버튼에 오탐(False Positive)됨. 2) DOM 순서상 상태 텍스트 버튼이 앞서 있으므로 오탐된 버튼이 우선 클릭됨. - **해결**: `trigger-click` 로직 실행 전 버튼의 `textContent`에서 `keyboard_arrow_up` 등 알려진 꼬리 아이콘 문자열을 명시적으로 제거(strip)하고, 모든 트리거 정규식에 다시 단어 경계(`\b`)를 강제 삽입하여 오탐을 원천 차단함. - **주의**: UI 요소를 DOM에서 긁어올 때는 텍스트에 숨겨진 아이콘/웹폰트 리거쳐(ligatures)가 없는지 검토해야 함. 패턴 매칭 시 꼬리표를 먼저 제거하고 명확한 경계를 부여할 것. + +### [2026-04-10] [Extension] Ghost Session Hijack & Infinite Polling Loop (trajectory not found) +- **증상**: 신규 작업 시 '신호안들어와' (Discord로 릴레이 안 됨). 로그에 500 error trajectory not found 무한 반복.\n- **원인**: Antigravity가 작업하면서 brain/에 36글자 폴더를 생성하는데, Cascade가 아니므로 GetCascadeTrajectorySteps에서 500 에러를 냅니다. 하지만 이전 신규 세션 유실 방지 패치가 이 Ghost 세션을 RUNNING으로 강제 등록하면서, 활성 세션(activeSessionId)을 탈취하고 무한 에러 루프에 빠지게 만들었습니다.\n- **해결**: step-probe.ts에서 폴백 등록 시 error message에 'trajectory not found'가 포함되면 Ghost 세션으로 간주해 강제 등록(continue)을 건너뛰게 하고, Stall Probe 에러 catch에서도 UTF-8 에러가 아니면 stallProbed=true를 주어 재시도 무한 루프를 완전히 끊어냈습니다.\n- **주의**: uuid 길이(36자)만으로 디렉토리를 식별할 때 Antigravity와 Google Agent가 모호해질 수 있으므로, 반드시 Backend 응답의 확실한 에러(trajectory not found) 메시지로 예외 판별을 해야 합니다.\n \ No newline at end of file diff --git a/extension/package.json b/extension/package.json index de14ba8..7b216c3 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,89 +1,89 @@ { - "name": "gravity-bridge", - "displayName": "Gravity Bridge", - "description": "Discord-based unified approval system for Antigravity AI interactions.", - "version": "0.5.27", - "publisher": "variet", - "engines": { - "vscode": "^1.100.0" - }, - "categories": [ - "Other", - "Chat" - ], - "activationEvents": [ - "onStartupFinished" - ], - "main": "./out/extension.js", - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./ && node -e \"const fs=require('fs'),p=require('path');const s=p.join('src','sdk'),d=p.join('out','sdk');if(fs.existsSync(s)){fs.mkdirSync(d,{recursive:true});fs.readdirSync(s).forEach(f=>fs.copyFileSync(p.join(s,f),p.join(d,f)));console.log('SDK copied to out/sdk')};\"", - "watch": "tsc -watch -p ./" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "@types/vscode": "^1.100.0", - "typescript": "^5.3.0" - }, - "contributes": { - "chatParticipants": [ - { - "id": "gravity-bridge.gravity", - "name": "gravity", - "fullName": "Gravity Bridge", - "description": "대화 히스토리를 Discord로 전송 + AI 제어", - "isSticky": false - } - ], - "commands": [ - { - "command": "gravityBridge.start", - "title": "Gravity Bridge: Start" - }, - { - "command": "gravityBridge.stop", - "title": "Gravity Bridge: Stop" - }, - { - "command": "gravityBridge.approve", - "title": "Gravity Bridge: Approve Pending" - }, - { - "command": "gravityBridge.reject", - "title": "Gravity Bridge: Reject Pending" - }, - { - "command": "gravityBridge.connect", - "title": "Gravity Bridge: Connect Session" - } - ], - "configuration": { - "title": "Gravity Bridge", - "properties": { - "gravityBridge.bridgePath": { - "type": "string", - "default": "", - "description": "Bridge 디렉토리 경로 (기본: ~/.gemini/antigravity/bridge)" + "name": "gravity-bridge", + "displayName": "Gravity Bridge", + "description": "Discord-based unified approval system for Antigravity AI interactions.", + "version": "0.5.28", + "publisher": "variet", + "engines": { + "vscode": "^1.100.0" }, - "gravityBridge.projectName": { - "type": "string", - "default": "", - "description": "프로젝트 이름 (기본: git remote 레포명)" + "categories": [ + "Other", + "Chat" + ], + "activationEvents": [ + "onStartupFinished" + ], + "main": "./out/extension.js", + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./ \u0026\u0026 node -e \"const fs=require(\u0027fs\u0027),p=require(\u0027path\u0027);const s=p.join(\u0027src\u0027,\u0027sdk\u0027),d=p.join(\u0027out\u0027,\u0027sdk\u0027);if(fs.existsSync(s)){fs.mkdirSync(d,{recursive:true});fs.readdirSync(s).forEach(f=\u003efs.copyFileSync(p.join(s,f),p.join(d,f)));console.log(\u0027SDK copied to out/sdk\u0027)};\"", + "watch": "tsc -watch -p ./" }, - "gravityBridge.hubUrl": { - "type": "string", - "default": "", - "description": "WebSocket Hub URL (예: wss://your-server.com/ws)" - }, - "gravityBridge.registrationCode": { - "type": "string", - "default": "", - "description": "Hub 등록 코드 (서버에서 발급)" - } - } - } - }, - "dependencies": { - "ws": "^8.19.0" - } + "devDependencies": { + "@types/node": "^20.0.0", + "@types/vscode": "^1.100.0", + "typescript": "^5.3.0" + }, + "contributes": { + "chatParticipants": [ + { + "id": "gravity-bridge.gravity", + "name": "gravity", + "fullName": "Gravity Bridge", + "description": "????스?리?Discord??송 + AI ?어", + "isSticky": false + } + ], + "commands": [ + { + "command": "gravityBridge.start", + "title": "Gravity Bridge: Start" + }, + { + "command": "gravityBridge.stop", + "title": "Gravity Bridge: Stop" + }, + { + "command": "gravityBridge.approve", + "title": "Gravity Bridge: Approve Pending" + }, + { + "command": "gravityBridge.reject", + "title": "Gravity Bridge: Reject Pending" + }, + { + "command": "gravityBridge.connect", + "title": "Gravity Bridge: Connect Session" + } + ], + "configuration": { + "title": "Gravity Bridge", + "properties": { + "gravityBridge.bridgePath": { + "type": "string", + "default": "", + "description": "Bridge ?렉?리 경로 (기본: ~/.gemini/antigravity/bridge)" + }, + "gravityBridge.projectName": { + "type": "string", + "default": "", + "description": "?로?트 ?름 (기본: git remote ?포?" + }, + "gravityBridge.hubUrl": { + "type": "string", + "default": "", + "description": "WebSocket Hub URL (?? wss://your-server.com/ws)" + }, + "gravityBridge.registrationCode": { + "type": "string", + "default": "", + "description": "Hub ?록 코드 (?버?서 발급)" + } + } + } + }, + "dependencies": { + "ws": "^8.19.0" + } } diff --git a/extension/src/step-probe.ts b/extension/src/step-probe.ts index 8d6c5c5..5bb09d7 100644 --- a/extension/src/step-probe.ts +++ b/extension/src/step-probe.ts @@ -275,6 +275,18 @@ function setupMonitor() { } } catch (e: any) { if (pollCount <= 30) ctx.logToFile(`[POLL] Fallback 2 error for sid=${sid}: ${e.message}`); + // If trajectory explicitly does not exist, it might be an Antigravity or non-Cascade session directory. + if (e.message?.includes('trajectory not found')) { + continue; + } + // FIXED: known-issues "AI Response Missing for New Sessions" -> Force register to prevent session loss on proto/UTF-8 parse errors + allTraj.trajectorySummaries[sid] = { + status: 'CASCADE_RUN_STATUS_RUNNING', + stepCount: 1, // Assume progressing to allow loop delta>0 trigger + lastModifiedTime: new Date(brainDirs[i].time).toISOString(), + summary: 'Discovered via brain/ scan (Fallback Error)', + trajectoryMetadata: { workspaces: [{ workspaceFolderAbsoluteUri: ctx.workspaceUri.replace(/\\/g, '/') }] } + }; } } } @@ -772,6 +784,8 @@ function setupMonitor() { ctx.logToFile(`[STEP-PROBE] UTF-8 offset also failed: ${oe.message?.substring(0, 100)}`); ctx.stallProbed = true; // permanent error — block retry loop; resets on delta>0 } + } else { + ctx.stallProbed = true; // Not a UTF-8 error (e.g. trajectory not found), prevent infinite loop } } }