fix(extension): diff_review steps=[] race condition — in-memory metadata cache (v0.3.13)
Root cause: Collector deletes pending file before Extension reads edit_step_indices. Fix: diffReviewMetadata Map caches step indices in Extension memory. Known issue added. Devlog entry 003.
This commit is contained in:
@@ -87,6 +87,9 @@ const sentPendingIds = new Set();
|
||||
// Map<string, number> = `${conversationId}:${stepIndex}` → creation timestamp
|
||||
const recentPendingSteps = new Map();
|
||||
const PENDING_MEMORY_TTL_MS = 60_000; // 60 seconds memory retention
|
||||
// In-memory cache for diff_review metadata (survives pending file deletion by Collector).
|
||||
// Map<request_id, { edit_step_indices, modified_files }>
|
||||
const diffReviewMetadata = new Map();
|
||||
// ─── Project Detection ───
|
||||
function detectProjectName() {
|
||||
const config = vscode.workspace.getConfiguration('gravityBridge');
|
||||
@@ -2622,22 +2625,35 @@ async function processResponseFile(filePath) {
|
||||
logToFile(`[RESPONSE] diff_review → ${isAccept ? 'ACCEPT' : 'REJECT'} (btnIdx=${btnIdx})`);
|
||||
let diffReviewDone = false;
|
||||
const targetSession = sessionId || activeSessionId;
|
||||
let modifiedFiles = []; // shared between Strategy 1 and 2
|
||||
// ── Strategy 1: AcknowledgeCascadeCodeEdit RPC ──
|
||||
// Accept/reject all pending code edits via protocol (no UI interaction needed)
|
||||
if (sdk) {
|
||||
try {
|
||||
// Get tracked step indices from pending data (or use all recent edit steps)
|
||||
// Get tracked step indices from in-memory cache FIRST (pending file may be deleted by Collector)
|
||||
const trackedSteps = [];
|
||||
const pendingDir = path.join(bridgePath, 'pending');
|
||||
try {
|
||||
const pendingFile = path.join(pendingDir, `${resp.request_id}.json`);
|
||||
if (fs.existsSync(pendingFile)) {
|
||||
const pd = JSON.parse(fs.readFileSync(pendingFile, 'utf-8'));
|
||||
if (pd.edit_step_indices)
|
||||
trackedSteps.push(...pd.edit_step_indices);
|
||||
}
|
||||
const memMeta = diffReviewMetadata.get(resp.request_id);
|
||||
if (memMeta) {
|
||||
trackedSteps.push(...memMeta.edit_step_indices);
|
||||
modifiedFiles = memMeta.modified_files;
|
||||
diffReviewMetadata.delete(resp.request_id); // cleanup
|
||||
logToFile(`[DIFF-REVIEW-RPC] loaded from memory: steps=[${trackedSteps.join(',')}] files=${modifiedFiles.length}`);
|
||||
}
|
||||
else {
|
||||
// Fallback: try pending file (may already be deleted)
|
||||
const pendingDir = path.join(bridgePath, 'pending');
|
||||
try {
|
||||
const pendingFile = path.join(pendingDir, `${resp.request_id}.json`);
|
||||
if (fs.existsSync(pendingFile)) {
|
||||
const pd = JSON.parse(fs.readFileSync(pendingFile, 'utf-8'));
|
||||
if (pd.edit_step_indices)
|
||||
trackedSteps.push(...pd.edit_step_indices);
|
||||
if (pd.modified_files)
|
||||
modifiedFiles = pd.modified_files;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
catch { }
|
||||
// If no tracked steps, use the step_index from the pending
|
||||
if (trackedSteps.length === 0 && pendingStepIndex > 0) {
|
||||
trackedSteps.push(pendingStepIndex);
|
||||
@@ -2665,17 +2681,7 @@ async function processResponseFile(filePath) {
|
||||
await new Promise(r => setTimeout(r, 500));
|
||||
}
|
||||
catch { }
|
||||
// Step 2b: Find modified files from pending data
|
||||
let modifiedFiles = [];
|
||||
try {
|
||||
const pendingFile = path.join(bridgePath, 'pending', `${resp.request_id}.json`);
|
||||
if (fs.existsSync(pendingFile)) {
|
||||
const pd = JSON.parse(fs.readFileSync(pendingFile, 'utf-8'));
|
||||
if (pd.modified_files)
|
||||
modifiedFiles = pd.modified_files;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
// Step 2b: Use modifiedFiles from Strategy 1 (already loaded from memory/file above)
|
||||
// Step 2c: Open and focus each modified file, then execute
|
||||
if (modifiedFiles.length > 0) {
|
||||
for (const filePath of modifiedFiles) {
|
||||
@@ -2967,9 +2973,19 @@ function writePendingApproval(data) {
|
||||
...(data.step_index !== undefined ? { step_index: data.step_index } : {}),
|
||||
...(data.source ? { source: data.source } : {}),
|
||||
...(buttons ? { buttons } : {}),
|
||||
...(data.modified_files ? { modified_files: data.modified_files } : {}),
|
||||
...(data.edit_step_indices && data.edit_step_indices.length > 0 ? { edit_step_indices: data.edit_step_indices } : {}),
|
||||
};
|
||||
fs.writeFileSync(path.join(pendingDir, `${id}.json`), JSON.stringify(payload, null, 2), 'utf-8');
|
||||
console.log(`Gravity Bridge: pending approval written → ${id}.json`);
|
||||
// Cache diff_review metadata in-memory (survives pending file deletion by Collector/Bot)
|
||||
if (data.step_type === 'diff_review' && (data.edit_step_indices?.length || data.modified_files?.length)) {
|
||||
diffReviewMetadata.set(id, {
|
||||
edit_step_indices: data.edit_step_indices || [],
|
||||
modified_files: data.modified_files || [],
|
||||
});
|
||||
logToFile(`[DIFF-REVIEW-CACHE] stored metadata for rid=${id}: steps=[${(data.edit_step_indices || []).join(',')}] files=${(data.modified_files || []).length}`);
|
||||
}
|
||||
// Record in memory dedup cache (survives file deletion by Collector/Bot)
|
||||
if (data.step_index !== undefined && data.conversation_id) {
|
||||
recentPendingSteps.set(`${data.conversation_id}:${data.step_index}`, nowMs);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user