Snapshot only committed extensions and publish the last-good marker atomically

This commit is contained in:
2026-11-08 07:00:39 +00:00
parent fcfaff6018
commit 8afab591fe
38 changed files with 535 additions and 117 deletions
+35 -5
View File
@@ -31486,7 +31486,7 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
const loaderGit = async (...args) => {
for (let attempt = 0; ; attempt++) {
try {
const result = await exec(["git", ...args], { cwd: repo, timeout: 120, signal: commands.signal });
const result = await exec(["git", ...args], { cwd: repo, signal: commands.signal });
if (result.code) throw new Error(result.stderr || `git exited ${result.code}`);
return result.stdout.trim();
} catch (error) {
@@ -31502,7 +31502,8 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
const publish2 = async () => {
await harness2.commit(async (tx) => Object.assign(await tx.doc(ExtensionState), state), context);
ops2.op_extension_status(JSON.stringify(state));
await fs.write("/src/sausage/.git/sausage-last-good", state.good ?? "");
await fs.write("/src/sausage/.git/sausage-last-good.tmp", state.good ?? "");
await fs.rename("/src/sausage/.git/sausage-last-good.tmp", "/src/sausage/.git/sausage-last-good");
};
const dispose = async (entries2) => {
for (const facet of entries2) for (const cleanup of facet.close) {
@@ -31592,8 +31593,19 @@ async function loadExtensions(harness2, registry2, storage2, models2, context, b
try {
await fs.stat(snapshot);
} catch {
await loaderGit("worktree", "prune");
await loaderGit("worktree", "add", "--detach", snapshot, sha);
const staging = `${snapshot}.tmp`, archive = `${snapshot}.tar`;
try {
await fs.mkdir(staging);
} catch (error) {
if (error.code !== "already_exists") throw error;
}
if (await loaderGit("ls-tree", "--name-only", sha, "extensions")) {
await loaderGit("archive", "--format=tar", `--output=${archive}`, sha, "extensions");
const result = await exec(["tar", "-xf", archive, "-C", staging], { cwd: repo, signal: commands.signal });
if (result.code) throw new Error(`tar: ${result.stderr || result.code}`);
await fs.remove(archive);
}
await fs.rename(staging, snapshot);
}
const modules = [];
for (const entry2 of await fs.list(`${snapshot}/extensions`).catch((error) => {
@@ -31720,6 +31732,9 @@ var harness = await Harness.open(storage, { models, registry, settings: { get ex
} } }, BACKGROUND_CONTEXT);
var root = await harness.root(BACKGROUND_CONTEXT, { agent: { model: { provider: "faux", modelId: "faux-1" } } });
globalThis.shared = { gate: Promise.withResolvers(), started: false, wait: false };
var markerWrite = fs.write;
var markerBlocked = Promise.withResolvers();
var markerRelease = Promise.withResolvers();
var loader = await loadExtensions(harness, registry, storage, models, BACKGROUND_CONTEXT);
harness.resume();
var turn = async () => {
@@ -31783,15 +31798,30 @@ return defineExtension({name:'demo',tools:[defineTool({name:'demo',description:'
globalThis.shared.gate.resolve();
assert((await running).includes("result A"), "Old call must finish on A");
assert((await turn()).includes("result C"), "Next call must use C");
await loader.reload();
fs.write = async (path, text) => {
if (path.includes("sausage-last-good")) {
fs.write = markerWrite;
await markerWrite(path, "");
markerBlocked.resolve();
await markerRelease.promise;
}
return markerWrite(path, text);
};
await git("/src/sausage", "update-ref", "refs/heads/main", b);
await until2(() => loader.state().current === b && !!loader.state().error);
assert((await exec(["extensions-revert"], { cwd: "/" })).code === 0, "Revert command");
await markerBlocked.promise;
const reverted = await exec(["extensions-revert"], { cwd: "/" });
markerRelease.resolve();
assert(reverted.code === 0, `Revert command: ${JSON.stringify(reverted)}`);
await until2(() => loader.state().current === c && !loader.state().error);
await git("/src/sausage", "update-ref", "refs/heads/main", b);
await until2(() => loader.state().current === b && !!loader.state().error);
await fs.write("/src/sausage/good.txt", c);
}
} finally {
markerRelease.resolve();
fs.write = markerWrite;
globalThis.shared.gate.resolve();
await loader.close();
await harness.close(BACKGROUND_CONTEXT);