fix(forge): ne plus ecraser une completion acceptee au Tab (BUG-055)
CI / lint (push) Successful in 1m34s
CI / security (push) Successful in 1m1s
CI / test (push) Successful in 2m44s
CI / build (push) Successful in 57s
CI / e2e (push) Successful in 11m14s

This commit is contained in:
2026-09-17 09:00:35 -04:00
parent 61347e0f0b
commit 8b09093aca
14 changed files with 99 additions and 22 deletions
+11 -2
View File
@@ -275,14 +275,23 @@ test("utils.js detachInlineEditor tears the session down without re-rendering",
});
test("utils.js reloads the displayed document after an AI write", () => {
const fn = utilsSrc.match(/async function reloadExternalWrite\(vault, path\) \{([\s\S]*?)\n\}/);
const fn = utilsSrc.match(/async function reloadExternalWrite\(vault, path, force = false\) \{([\s\S]*?)\n\}/);
assert.ok(fn, "reloadExternalWrite not found");
assert.match(fn[1], /postMessage\(\{ type: 'parent-reload' \}, '\*'\)/);
assert.match(fn[1], /postMessage\(\{ type: 'parent-reload', force: !!force \}, '\*'\)/);
assert.match(fn[1], /suppressAutoSaveOnce = true;/);
assert.match(utilsSrc, /window\.addEventListener\("obsigate:file-written"/);
assert.match(utilsSrc, /if \(suppressAutoSaveOnce\) \{/, "autosave skipped on programmatic reload");
});
test("utils.js does not clobber unsaved edits on a non-forced reload (BUG-055)", () => {
const fn = utilsSrc.match(/async function reloadExternalWrite\(vault, path, force = false\) \{([\s\S]*?)\n\}/);
assert.ok(fn, "reloadExternalWrite not found");
// Guard before the CodeMirror dispatch
assert.match(fn[1], /if \(!force && dirtyDot && dirtyDot\.classList\.contains\("dirty"\)\) return;/);
// The AI write forces the reload past unsaved local changes
assert.match(utilsSrc, /reloadExternalWrite\(detail\.vault, detail\.path, true\);/);
});
test("sync.js forge-close goes through the shared close path", () => {
assert.ok(syncSrc.includes("import { closeEditor, reloadExternalWrite } from './utils.js';"), "utils import missing");
const handler = syncSrc.match(/if \(e\.data\.type === 'forge-close'\) \{([\s\S]*?)\n \}/);
+19
View File
@@ -202,6 +202,25 @@ test("Forge ghost text no longer mirrors the whole document", () => {
assert.ok(!FORGE_HTML.includes("ghostOverlay.innerHTML"), "the mirror overlay must be gone");
});
test("Forge ignores its own autosave reload while the buffer is dirty (BUG-055)", () => {
assert.ok(
FORGE_HTML.includes("if (!e.data.force && isDirty) return;"),
"parent-reload must not clobber unsaved local edits",
);
});
test("Forge cancels a pending ghost request when the prediction is accepted", () => {
const fn = FORGE_HTML.match(/function acceptGhost\(\) \{([\s\S]*?)\n \}/);
assert.ok(fn, "acceptGhost not found");
assert.match(fn[1], /clearTimeout\(_ghostTimer\)/);
});
test("Forge autosave keeps the buffer dirty if edits arrive during the request", () => {
const fn = FORGE_HTML.match(/function autoSave\(\) \{([\s\S]*?)\n \}/);
assert.ok(fn, "autoSave not found");
assert.match(fn[1], /if \(val\(\) !== content\) \{ scheduleAutoSave\(\); return; \}/);
});
// ── Summary ────────────────────────────────────────────────────────────────
console.log(`\n${testCount} passed, ${failCount} failed`);
process.exit(failCount > 0 ? 1 : 0);