diff --git a/docs/devlog/2026-04-08.md b/docs/devlog/2026-04-08.md index a6758a2..8b201c0 100644 --- a/docs/devlog/2026-04-08.md +++ b/docs/devlog/2026-04-08.md @@ -3,3 +3,4 @@ | NNN | HH:MM | 작업 설명 | 커밋해시 | 상태 | |---|---|---|---|---| | 001 | 05:18 | Gravity Bridge 무결성 롤백, SafeToAutoRun 메모리 누수 방지(LRU), UI 프리징(execSync) 제거 및 v0.5.15 배포 | `bf7db72` | ✅ | +| 002 | 05:45 | SafeToAutoRun 명령어의 불필요한 Pending 파일 생성 방지 (Discord 중복 알림 차단) 및 v0.5.16 배포 | ⏳ | ⏳ | diff --git a/docs/devlog/entries/20260408-002.md b/docs/devlog/entries/20260408-002.md new file mode 100644 index 0000000..08f62da --- /dev/null +++ b/docs/devlog/entries/20260408-002.md @@ -0,0 +1,17 @@ +# Gravity Bridge 중복 메시지 알림(SafeToAutoRun) 이슈 해결 + +- **시간**: 2026-04-08 05:40~05:45 +- **버전**: `v0.5.16` + +## 작업 사항 + +1. **단백한 백그라운드 메시지 지원 (중복 알림 제거)** + - 문제: 배경 실행 명령어(`SafeToAutoRun: true`)가 찰나의 순간 동안 `WAITING`에 진입하면서 익스텐션이 Pending 파일을 생성하고, 이를 봇이 즉시 처리하며 `🤖 자동 승인됨`이라는 불필요한 메시지가 중복으로 발송되고 있었음. (프록시 단에서 `💬 AI 대화 내용: ⚡ 자동 실행됨` 기록을 자체 발송하고 있어 중복 됨) + - 스텝 프로브(`step-probe.ts`)가 WAITING 상태를 감지하더라도, 해당 명령어의 플래그에 `SafeToAutoRun`이 true로 존재하면 Pending 파일을 일체 생성하지 않도록 스킵 처리를 추가 (`if (!safeToAutoRun)`) + - 이를 통해 봇(`bot.py`)으로 불필요한 Pending 요청이 가지 않게 차단되었으며, `🤖 자동 승인됨` 텍스트 스팸이 완전히 해결됨. + +2. **v0.5.15 잔재 코드 삭제** + - 어설프게 추가되었던 `🤖 [Background Execution]` 직접 Snapshot 생성 로직 삭제. + +## 미완료 +- 없음 (VSIX 배포/로컬 설치 완료) diff --git a/extension/package.json b/extension/package.json index 1f39e9c..d96ec09 100644 --- a/extension/package.json +++ b/extension/package.json @@ -2,7 +2,7 @@ "name": "gravity-bridge", "displayName": "Gravity Bridge", "description": "Antigravity ↔ Discord 브리지 연동 확장", - "version": "0.5.15", + "version": "0.5.16", "publisher": "variet", "engines": { "vscode": "^1.100.0" diff --git a/extension/src/step-probe.ts b/extension/src/step-probe.ts index 19bc3ce..74f56a0 100644 --- a/extension/src/step-probe.ts +++ b/extension/src/step-probe.ts @@ -343,9 +343,7 @@ function setupMonitor() { } autoRunSteps.add(actualIdx); const cmdText = tcArgs.CommandLine || tcArgs.command || tcArgs.Command || JSON.stringify(tcArgs); - const truncatedCmd = cmdText.length > 500 ? cmdText.substring(0, 500) + '...' : cmdText; ctx.logToFile(`[AUTO-RUN] step=${actualIdx} captured`); - ctx.writeChatSnapshot(`🤖 **[Background Execution]**\n\n\`\`\`bash\n${truncatedCmd}\n\`\`\``); } } catch { } } @@ -496,9 +494,11 @@ function setupMonitor() { const toolCall = oStep?.metadata?.toolCall; const toolName = toolCall?.name || (oStep.type || '').replace('CORTEX_STEP_TYPE_', '').toLowerCase(); let command = toolName; + let safeToAutoRun = false; if (toolCall?.argumentsJson) { try { const args = JSON.parse(toolCall.argumentsJson); + safeToAutoRun = args.SafeToAutoRun === true || args.safeToAutoRun === true; if (args.CommandLine) command = `${toolName}: ${args.CommandLine.substring(0, 1500)}`; else if (args.TargetFile) command = `${toolName}: ${args.TargetFile}`; else { @@ -521,6 +521,8 @@ function setupMonitor() { // Skip pending for workspace-less AG windows (project=default) if (ctx.projectName === 'default') { ctx.logToFile(`[STEP-PROBE] skip pending: ctx.projectName=default (no workspace)`); + } else if (safeToAutoRun) { + ctx.logToFile(`[STEP-PROBE] skip pending: SafeToAutoRun is true (step=${actualIndex})`); } else { // Always write pending — Bot decides auto-approve (prevents double-fire) writePendingApproval({ @@ -558,11 +560,13 @@ function setupMonitor() { const toolCall = step?.metadata?.toolCall; const toolName = toolCall?.name || stepType.replace('CORTEX_STEP_TYPE_', '').toLowerCase(); let command = toolName; + let safeToAutoRun = false; // Parse argumentsJson for command details if (toolCall?.argumentsJson) { try { const args = JSON.parse(toolCall.argumentsJson); + safeToAutoRun = args.SafeToAutoRun === true || args.safeToAutoRun === true; if (args.CommandLine) { command = `${toolName}: ${args.CommandLine.substring(0, 1500)}`; } else if (args.TargetFile) { @@ -588,6 +592,8 @@ function setupMonitor() { // Skip pending for workspace-less AG windows (project=default) if (ctx.projectName === 'default') { ctx.logToFile(`[STEP-PROBE] skip pending: ctx.projectName=default (no workspace)`); + } else if (safeToAutoRun) { + ctx.logToFile(`[STEP-PROBE] skip pending: SafeToAutoRun is true (step=${si})`); } else { // Always write pending — Bot decides auto-approve (prevents double-fire) writePendingApproval({ @@ -640,9 +646,11 @@ function setupMonitor() { const toolCall = oStep?.metadata?.toolCall; const toolName = toolCall?.name || (oStep.type || '').replace('CORTEX_STEP_TYPE_', '').toLowerCase(); let command = toolName; + let safeToAutoRun = false; if (toolCall?.argumentsJson) { try { const args = JSON.parse(toolCall.argumentsJson); + safeToAutoRun = args.SafeToAutoRun === true || args.safeToAutoRun === true; if (args.CommandLine) command = `${toolName}: ${args.CommandLine.substring(0, 1500)}`; else if (args.TargetFile) command = `${toolName}: ${args.TargetFile}`; else { @@ -658,7 +666,11 @@ function setupMonitor() { if (actualIndex > ctx.lastPendingStepIndex) ctx.lastPendingStepIndex = actualIndex; lastPendingTime = Date.now(); ctx.sawRunningAfterPending = false; - if (ctx.projectName !== 'default') { + if (ctx.projectName === 'default') { + ctx.logToFile(`[STEP-PROBE] skip pending: ctx.projectName=default`); + } else if (safeToAutoRun) { + ctx.logToFile(`[STEP-PROBE] skip pending: SafeToAutoRun is true (step=${actualIndex})`); + } else { writePendingApproval({ conversation_id: ctx.activeSessionId, command, diff --git a/install_vsix.py b/install_vsix.py deleted file mode 100644 index 260ebe4..0000000 --- a/install_vsix.py +++ /dev/null @@ -1,20 +0,0 @@ -import zipfile, shutil, os - -vsix = r"c:\Users\Variet-Worker\Desktop\gravity_control\extension\gravity-bridge-0.5.14.vsix" -dest = os.path.expanduser(r"~\.antigravity\extensions\variet.gravity-bridge-0.5.14") -tmp = r"C:\tmp\vsix_extract" - -if os.path.exists(tmp): - shutil.rmtree(tmp) -os.makedirs(tmp, exist_ok=True) - -with zipfile.ZipFile(vsix, 'r') as z: - z.extractall(tmp) - -src = os.path.join(tmp, "extension") -if os.path.exists(dest): - shutil.rmtree(dest) - -shutil.copytree(src, dest) -print(f"Installed to {dest}") -print("Files:", os.listdir(dest))