fix(ext,bot): Accept All WS regression + auto_approve dual-write — VSIX v0.4.5

This commit is contained in:
Variet Worker
2026-03-17 21:01:24 +09:00
parent 4e8ac8d6b7
commit 47cc838d9d
8 changed files with 158 additions and 11 deletions

View File

@@ -402,9 +402,27 @@ async function activate(context) {
wsBridge = new ws_client_1.WSBridgeClient(hubUrl, regCode, projectName, pcName, {
onResponse: (data) => {
logToFile(`[WS-RESPONSE] ${data.request_id?.substring(0, 12)} approved=${data.approved} step_type=${data.step_type || '(none)'}`);
// Direct approval — WS path has no pending file, so call tryApprovalStrategies directly
const approved = data.approved ?? true;
const stepType = data.step_type || '';
// ── diff_review: Accept all / Reject all (REGRESSION FIX) ──
// Previously only handled in processResponseFile (file-bridge path).
// WS path was missing this logic entirely, causing Accept All to fail.
if (stepType === 'diff_review') {
logToFile(`[WS-RESPONSE] diff_review detected — routing to handleDiffReviewResponse`);
(0, step_probe_1.handleDiffReviewResponse)({
request_id: data.request_id,
approved,
button_index: data.button_index,
step_type: stepType,
})
.then(result => {
logToFile(`[WS-RESPONSE] diff_review result: ${result}`);
(0, step_probe_1.resetPendingState)();
})
.catch(err => logToFile(`[WS-RESPONSE] diff_review error: ${err.message}`));
return;
}
// Normal approval — tryApprovalStrategies
const approvalCtx = (0, step_probe_1.getApprovalContext)();
logToFile(`[WS-RESPONSE] Triggering approval: approved=${approved} session=${approvalCtx.sessionId.substring(0, 8)} stepType=${stepType} stepIndex=${approvalCtx.stepIndex}`);
(0, step_probe_1.tryApprovalStrategies)(approved, approvalCtx.sessionId, stepType, approvalCtx.stepIndex)

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@
"name": "gravity-bridge",
"displayName": "Gravity Bridge",
"description": "Antigravity ↔ Discord 브리지 연동 확장",
"version": "0.4.4",
"version": "0.4.5",
"publisher": "variet",
"engines": {
"vscode": "^1.100.0"

View File

@@ -16,7 +16,7 @@ import * as path from 'path';
import * as os from 'os';
import * as cp from 'child_process';
import { WSBridgeClient, WSResponseData, WSCommandData } from './ws-client';
import { initStepProbe, BridgeContext, writePendingApproval, tryApprovalStrategies, writeRegistration, getApprovalContext, resetPendingState } from './step-probe';
import { initStepProbe, BridgeContext, writePendingApproval, tryApprovalStrategies, writeRegistration, getApprovalContext, resetPendingState, handleDiffReviewResponse } from './step-probe';
import { startHttpBridge, getDeterministicPort, HttpBridgeContext } from './http-bridge';
import { setupApprovalObserver } from './html-patcher';
import { watchCommandsDir, handleWSCommand, disposeCommandsWatcher, CommandHandlerContext } from './command-handler';
@@ -391,9 +391,29 @@ export async function activate(context: vscode.ExtensionContext) {
if (hubUrl) {
wsBridge = new WSBridgeClient(hubUrl, regCode, projectName, pcName, {
onResponse: (data: WSResponseData) => {
logToFile(`[WS-RESPONSE] ${data.request_id?.substring(0, 12)} approved=${data.approved} step_type=${data.step_type || '(none)'}`);
logToFile(`[WS-RESPONSE] ${data.request_id?.substring(0, 12)} approved=${data.approved} step_type=${data.step_type || '(none)'}`);
const approved = data.approved ?? true;
const stepType = data.step_type || '';
// ── diff_review: Accept all / Reject all (REGRESSION FIX) ──
// Previously only handled in processResponseFile (file-bridge path).
// WS path was missing this logic entirely, causing Accept All to fail.
if (stepType === 'diff_review') {
logToFile(`[WS-RESPONSE] diff_review detected — routing to handleDiffReviewResponse`);
handleDiffReviewResponse({
request_id: data.request_id,
approved,
button_index: data.button_index,
step_type: stepType,
})
.then(result => {
logToFile(`[WS-RESPONSE] diff_review result: ${result}`);
resetPendingState();
})
.catch(err => logToFile(`[WS-RESPONSE] diff_review error: ${err.message}`));
return;
}
// Normal approval — tryApprovalStrategies
const approvalCtx = getApprovalContext();
logToFile(`[WS-RESPONSE] Triggering approval: approved=${approved} session=${approvalCtx.sessionId.substring(0, 8)} stepType=${stepType} stepIndex=${approvalCtx.stepIndex}`);

View File

@@ -61,6 +61,100 @@ export function resetPendingState(): void {
ctx.sawRunningAfterPending = false;
}
/**
* Handle diff_review Accept all / Reject all response.
* Extracted so both WS onResponse (extension.ts) and processResponseFile can call it.
*
* This was previously only in processResponseFile (file-bridge path).
* When WS was added (v0.4.x), the onResponse handler skipped this logic entirely,
* causing Accept All to stop working — a regression.
*/
export async function handleDiffReviewResponse(data: {
request_id: string;
approved: boolean;
button_index?: number;
step_type?: string;
}): Promise<boolean> {
const btnIdx = data.button_index ?? -1;
const isAccept = btnIdx === 0 || (btnIdx === -1 && data.approved);
const cmd = isAccept
? 'antigravity.prioritized.agentAcceptAllInFile'
: 'antigravity.prioritized.agentRejectAllInFile';
ctx.logToFile(`[DIFF-REVIEW-WS] → ${isAccept ? 'ACCEPT' : 'REJECT'} (btnIdx=${btnIdx}, rid=${data.request_id?.substring(0, 12)})`);
let diffReviewDone = false;
let modifiedFiles: string[] = [];
// Load tracked step indices and modified files from memory cache or pending file
const trackedSteps: number[] = [];
const memMeta = ctx.diffReviewMetadata.get(data.request_id);
if (memMeta) {
trackedSteps.push(...memMeta.edit_step_indices);
modifiedFiles = memMeta.modified_files;
ctx.diffReviewMetadata.delete(data.request_id);
ctx.logToFile(`[DIFF-REVIEW-WS] loaded from memory: steps=[${trackedSteps.join(',')}] files=${modifiedFiles.length}`);
} else {
try {
const pf = path.join(ctx.bridgePath, 'pending', `${data.request_id}.json`);
if (fs.existsSync(pf)) {
const pd = JSON.parse(fs.readFileSync(pf, 'utf-8'));
if (pd.edit_step_indices) trackedSteps.push(...pd.edit_step_indices);
if (pd.modified_files) modifiedFiles = pd.modified_files;
}
} catch { }
}
// Strategy 1: VS Code command — open review panel + focus each file + accept/reject
try {
try {
await vscode.commands.executeCommand('antigravity.openReviewChanges');
ctx.logToFile(`[DIFF-REVIEW-WS] openReviewChanges OK`);
await new Promise(r => setTimeout(r, 500));
} catch { }
if (modifiedFiles.length > 0) {
for (const fp of modifiedFiles) {
try {
const uri = vscode.Uri.file(fp);
const doc = await vscode.workspace.openTextDocument(uri);
await vscode.window.showTextDocument(doc, { preview: false });
await new Promise(r => setTimeout(r, 300));
await vscode.commands.executeCommand(cmd);
ctx.logToFile(`[DIFF-REVIEW-WS] ✅ ${cmd} on ${fp.split(/[\\/]/).pop()} OK`);
diffReviewDone = true;
} catch (e: any) {
ctx.logToFile(`[DIFF-REVIEW-WS] per-file error on ${fp}: ${e.message?.substring(0, 80)}`);
}
}
} else {
await vscode.commands.executeCommand(cmd);
ctx.logToFile(`[DIFF-REVIEW-WS] ✅ ${cmd} executed (no file list)`);
diffReviewDone = true;
}
} catch (cmdErr: any) {
ctx.logToFile(`[DIFF-REVIEW-WS] Strategy 1 command error: ${cmdErr.message?.substring(0, 200)}`);
}
// Strategy 2: individual hunk accept/reject
if (!diffReviewDone) {
try {
const hunkCmd = isAccept
? 'antigravity.prioritized.agentAcceptFocusedHunk'
: 'antigravity.prioritized.agentRejectFocusedHunk';
await vscode.commands.executeCommand(hunkCmd);
ctx.logToFile(`[DIFF-REVIEW-WS] ✅ ${hunkCmd} fallback OK`);
diffReviewDone = true;
} catch (hunkErr: any) {
ctx.logToFile(`[DIFF-REVIEW-WS] hunk fallback error: ${hunkErr.message?.substring(0, 100)}`);
}
}
if (!diffReviewDone) {
ctx.logToFile(`[DIFF-REVIEW-WS] ❌ ALL strategies failed for rid=${data.request_id}`);
}
return diffReviewDone;
}
/**
* Write a registration file for the Bot to discover session → project mapping.
* Called automatically on first step event per session.