From 880bb5823c77f261169fe86a4f2cd2944b4d9595 Mon Sep 17 00:00:00 2001 From: Chris Phillipson Date: Tue, 14 Jul 2026 13:06:58 -0700 Subject: [PATCH] fix(heal): harden healNatives against stale locations and opaque failures - Re-check each agentdb location with fs.existsSync immediately before installing: an upgrade earlier in the same sync can remove a location (agentic-flow/node_modules/agentdb vanished in the ruflo 3.29.0 tree), which previously surfaced as a spurious FAILED against a phantom path. - Include the tail of npm's stderr (capped, with exit-code fallback) in FAILED details for both agentdb locations and agentic-qe, so a real native-install failure is diagnosable from the sync output alone. --- src/lib/heal.mjs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/lib/heal.mjs b/src/lib/heal.mjs index 33aaab9e..82aad8d3 100644 --- a/src/lib/heal.mjs +++ b/src/lib/heal.mjs @@ -31,13 +31,21 @@ async function npmInstallInto(dir, spec) { export async function healNatives() { const details = []; for (const dir of agentdbLocations()) { + // Re-check right before installing: an upgrade earlier in the same sync + // can remove a location (e.g. agentic-flow/node_modules/agentdb, gone in + // the 3.29.0 tree) between enumeration and heal. + if (!fs.existsSync(dir)) continue; if (bsq3IsNative(dir)) continue; const r = await npmInstallInto(dir, 'better-sqlite3@^12'); - details.push(`${dir}: ${r.code === 0 && bsq3IsNative(dir) ? 'native installed' : 'FAILED'}`); + details.push(`${dir}: ${r.code === 0 && bsq3IsNative(dir) + ? 'native installed' + : `FAILED (${(r.stderr || `exit ${r.code}`).trim().split('\n').slice(-2).join(' ').slice(0, 200)})`}`); } if (fs.existsSync(aqeRoot()) && !bsq3IsNative(aqeRoot())) { const r = await npmInstallInto(aqeRoot(), 'better-sqlite3@^12'); - details.push(`agentic-qe: ${r.code === 0 && bsq3IsNative(aqeRoot()) ? 'native installed' : 'FAILED'}`); + details.push(`agentic-qe: ${r.code === 0 && bsq3IsNative(aqeRoot()) + ? 'native installed' + : `FAILED (${(r.stderr || `exit ${r.code}`).trim().split('\n').slice(-2).join(' ').slice(0, 200)})`}`); } return { ok: !details.some((d) => d.includes('FAILED')), detail: details.join('; ') || 'already native everywhere' }; }