fix(extension): skip Antigravity ghost sessions in Fallback 2 to prevent trajectory not found infinite loop
This commit is contained in:
@@ -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
|
||||
@@ -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": "?„로?<3F>트 ?´ë¦„ (기본: git remote ?ˆí<CB86>¬ëª?"
|
||||
},
|
||||
"gravityBridge.hubUrl": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "WebSocket Hub URL (?? wss://your-server.com/ws)"
|
||||
},
|
||||
"gravityBridge.registrationCode": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Hub ?±ë¡<C3AB> 코드 (?œë²„?<3F>서 발급)"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": "^8.19.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user