Files
reverse-engineering-anything/tests/boundary/filesystem/opencodeLayeredUninstall.test.ts
T
morluto 953a7689df fix(uninstall): preserve layered OpenCode registrations (#7969)
* fix(uninstall): preflight layered OpenCode fallback

* fix(uninstall): preserve inherited foreign registration facts

* fix(uninstall): preflight legacy OpenCode layer removal
2026-10-29 10:07:27 +08:00

172 lines
5.6 KiB
TypeScript

import { access, mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { expect, it } from "vitest";
import {
runUninstall,
systemUninstallHost,
} from "../../../src/application/Uninstall.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
import { effectiveClientConfiguration } from "../../../src/application/ClientConfigurationFiles.js";
import { parseClientConfiguration } from "../../../src/application/ClientConfigurationDocument.js";
it.each(["native", "legacy"])(
"retains an owned %s lower layer when a foreign upper layer inherits its fields",
async (dialect) => {
const home = await createTestTempDirectory("rea-opencode-layered-foreign-");
const directory = join(home, ".config/opencode");
await mkdir(directory, { recursive: true });
const lower = join(directory, "opencode.json");
const upper = join(directory, "opencode.jsonc");
const owned = JSON.stringify(
dialect === "native"
? {
mcp: {
servers: {
rea: {
type: "local",
command: ["rea", "mcp"],
disabled: false,
},
},
},
}
: {
mcp: {
servers: {},
rea: { type: "local", command: ["rea", "mcp"], enabled: true },
},
},
);
const partial = JSON.stringify({
mcp: { servers: { rea: { command: ["/usr/bin/false"] } } },
});
await writeFile(lower, owned);
await writeFile(upper, partial);
const effective = async () =>
effectiveClientConfiguration(
await Promise.all(
[lower, upper].map(async (sourcePath) => ({
...parseClientConfiguration(
await readFile(sourcePath, "utf8"),
"opencode",
),
sourcePath,
})),
),
)?.servers.rea;
const before = await effective();
expect(before).toMatchObject({
type: "local",
command: ["/usr/bin/false"],
disabled: false,
});
const result = await runUninstall(
false,
systemUninstallHost(home, undefined, {
XDG_CONFIG_HOME: join(home, ".config"),
}),
);
expect(result.status).toBe("failed");
expect(result.items).toContainEqual(
expect.objectContaining({
name: "opencode",
status: "failed",
detail: expect.stringContaining("change an unowned"),
}),
);
expect(await readFile(lower, "utf8")).toBe(owned);
expect(await readFile(upper, "utf8")).toBe(partial);
expect(await effective()).toEqual(before);
},
);
it("preflights a foreign legacy registration across OpenCode layers before removal", async () => {
const home = await createTestTempDirectory("rea-opencode-layered-uninstall-");
const directory = join(home, ".config/opencode");
await mkdir(directory, { recursive: true });
const lower = join(directory, "opencode.json");
const upper = join(directory, "opencode.jsonc");
const legacy = JSON.stringify({
mcp: { rea: { type: "local", command: ["/usr/bin/false"], enabled: true } },
});
const native = JSON.stringify({
mcp: {
servers: {
rea: { type: "local", command: ["rea", "mcp"], disabled: false },
},
},
});
await writeFile(lower, legacy);
await writeFile(upper, native);
const environment = { XDG_CONFIG_HOME: join(home, ".config") };
const blocked = await runUninstall(
false,
systemUninstallHost(home, undefined, environment),
);
expect(blocked.status).toBe("failed");
expect(blocked.items).toContainEqual(
expect.objectContaining({
name: "opencode",
status: "failed",
detail: expect.stringContaining("V1"),
}),
);
expect(await readFile(lower, "utf8")).toBe(legacy);
expect(await readFile(upper, "utf8")).toBe(native);
await expect(access(`${lower}.rea.backup`)).rejects.toMatchObject({
code: "ENOENT",
});
await expect(access(`${upper}.rea.backup`)).rejects.toMatchObject({
code: "ENOENT",
});
await writeFile(lower, "{}\n");
const removed = await runUninstall(
false,
systemUninstallHost(home, undefined, environment),
);
expect(removed.status).toBe("complete");
expect(removed.items).toContainEqual(
expect.objectContaining({ name: "opencode", status: "removed" }),
);
expect(await readFile(upper, "utf8")).not.toContain('"rea"');
// Removing a shadowed owned registration does not activate a registration
// that was already selected from a later layer.
await writeFile(lower, native);
const foreignNative = JSON.stringify({
mcp: {
servers: {
rea: { type: "local", command: ["/usr/bin/false"], disabled: false },
},
},
});
await writeFile(upper, foreignNative);
const alreadyForeign = await runUninstall(
false,
systemUninstallHost(home, undefined, environment),
);
expect(alreadyForeign.status).toBe("complete");
expect(await readFile(lower, "utf8")).not.toContain('"rea"');
expect(await readFile(upper, "utf8")).toBe(foreignNative);
// The same control applies when the shadowed owned row uses V1 syntax.
await writeFile(
lower,
JSON.stringify({
mcp: {
servers: {},
rea: { type: "local", command: ["rea", "mcp"], enabled: true },
},
}),
);
const legacyAlreadyForeign = await runUninstall(
false,
systemUninstallHost(home, undefined, environment),
);
expect(legacyAlreadyForeign.status).toBe("complete");
expect(await readFile(lower, "utf8")).not.toContain('"rea"');
expect(await readFile(upper, "utf8")).toBe(foreignNative);
});