mirror of
https://github.com/morluto/rea
synced 2026-10-26 06:16:17 -04:00
c592ea6bac
Set disabled to false in generated OpenCode V2 registrations so a lower-priority disabled entry cannot keep approved setup stale. Cover layered JSON/JSONC refreshes, idempotent setup and doctor readiness, exact backups, preserved lower settings, malformed-config refusal, and the exclusion of disabled registrations from automatic maintenance. Update the native V2 registration expectations. Fixes #3318
155 lines
4.9 KiB
TypeScript
155 lines
4.9 KiB
TypeScript
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { parse } from "jsonc-parser";
|
|
import { expect } from "vitest";
|
|
|
|
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
|
|
import { cliTest, type TestCli } from "../../support/cli/cliFixture.js";
|
|
|
|
const setupArguments = [
|
|
"setup",
|
|
"--client",
|
|
"opencode",
|
|
"--skill=false",
|
|
"--yes",
|
|
"--json",
|
|
];
|
|
|
|
const layeredOpenCode = async (
|
|
cli: TestCli,
|
|
disabled: boolean,
|
|
jsonc: boolean,
|
|
) => {
|
|
const home = await createTestTempDirectory("rea-opencode-v2-activation-");
|
|
const configurationHome = join(home, "config");
|
|
const directory = join(configurationHome, "opencode");
|
|
await mkdir(directory, { recursive: true });
|
|
const lower = join(directory, "config.json");
|
|
const upper = join(directory, jsonc ? "opencode.jsonc" : "opencode.json");
|
|
const other = { type: "local", command: ["other-server"], disabled: true };
|
|
const originalLower = JSON.stringify({
|
|
mcp: {
|
|
servers: {
|
|
rea: {
|
|
type: "local",
|
|
command: ["rea", "mcp"],
|
|
disabled,
|
|
environment: { REA_MCP_OUTPUT_SCHEMA_PROFILE: "off" },
|
|
},
|
|
other,
|
|
},
|
|
},
|
|
});
|
|
const originalUpper = `${jsonc ? "// Keep the user configuration comment.\n" : ""}${JSON.stringify(
|
|
{
|
|
mcp: { servers: {} },
|
|
theme: "system",
|
|
},
|
|
)}\n`;
|
|
await writeFile(lower, originalLower);
|
|
await writeFile(upper, originalUpper);
|
|
const run = (arguments_: readonly string[]) =>
|
|
cli.run({
|
|
arguments: arguments_,
|
|
cwd: home,
|
|
environment: {
|
|
HOME: home,
|
|
USERPROFILE: home,
|
|
XDG_CONFIG_HOME: configurationHome,
|
|
APPDATA: join(home, "appdata"),
|
|
LOCALAPPDATA: join(home, "localappdata"),
|
|
HOPPER_LAUNCHER_PATH: join(home, "absent-hopper"),
|
|
},
|
|
});
|
|
return { lower, upper, originalLower, originalUpper, other, run };
|
|
};
|
|
|
|
for (const disabled of [true, false]) {
|
|
for (const jsonc of [false, true]) {
|
|
cliTest(
|
|
`OpenCode V2 setup activates ${jsonc ? "JSONC" : "JSON"} over a lower disabled=${disabled} registration`,
|
|
async ({ cli }) => {
|
|
const fixture = await layeredOpenCode(cli, disabled, jsonc);
|
|
const setup = await fixture.run(setupArguments);
|
|
expect(setup.exitCode, setup.stdout).toBe(0);
|
|
expect(setup.json).toMatchObject({ status: "ready" });
|
|
const configured = await readFile(fixture.upper, "utf8");
|
|
expect(parse(configured)).toMatchObject({
|
|
mcp: {
|
|
servers: {
|
|
rea: {
|
|
type: "local",
|
|
},
|
|
},
|
|
},
|
|
theme: "system",
|
|
});
|
|
if (disabled)
|
|
expect(parse(configured).mcp.servers.rea.disabled).toBe(false);
|
|
if (jsonc)
|
|
expect(configured).toContain(
|
|
"// Keep the user configuration comment.",
|
|
);
|
|
expect(await readFile(fixture.lower, "utf8")).toBe(
|
|
fixture.originalLower,
|
|
);
|
|
expect(await readFile(`${fixture.upper}.rea.backup`, "utf8")).toBe(
|
|
fixture.originalUpper,
|
|
);
|
|
|
|
const repeated = await fixture.run(setupArguments);
|
|
expect(repeated.exitCode, repeated.stdout).toBe(0);
|
|
expect(repeated.json).toMatchObject({
|
|
status: "ready",
|
|
plannedActions: [],
|
|
appliedActions: [],
|
|
});
|
|
const doctor = await fixture.run([
|
|
"doctor",
|
|
"--client",
|
|
"opencode",
|
|
"--json",
|
|
]);
|
|
expect(doctor.exitCode, doctor.stdout).toBe(0);
|
|
expect(doctor.json).toMatchObject({
|
|
healthy: true,
|
|
identity: {
|
|
registrations: expect.arrayContaining([
|
|
expect.objectContaining({ client: "opencode", state: "aligned" }),
|
|
]),
|
|
},
|
|
});
|
|
expect(await readFile(fixture.upper, "utf8")).toBe(configured);
|
|
expect(await readFile(fixture.lower, "utf8")).toBe(
|
|
fixture.originalLower,
|
|
);
|
|
expect(
|
|
parse(await readFile(fixture.lower, "utf8")).mcp.servers.other,
|
|
).toEqual(fixture.other);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
cliTest(
|
|
"OpenCode V2 activation does not bypass a malformed lower configuration",
|
|
async ({ cli }) => {
|
|
const fixture = await layeredOpenCode(cli, true, true);
|
|
const malformed = "{ not json";
|
|
await writeFile(fixture.lower, malformed);
|
|
const setup = await fixture.run(setupArguments);
|
|
expect(setup.exitCode, setup.stdout).toBe(1);
|
|
expect(setup.json).toMatchObject({
|
|
status: "needs_human",
|
|
plannedActions: [],
|
|
appliedActions: [],
|
|
remediation: expect.stringContaining(fixture.lower),
|
|
});
|
|
expect(await readFile(fixture.lower, "utf8")).toBe(malformed);
|
|
expect(await readFile(fixture.upper, "utf8")).toBe(fixture.originalUpper);
|
|
await expect(access(`${fixture.upper}.rea.backup`)).rejects.toMatchObject({
|
|
code: "ENOENT",
|
|
});
|
|
},
|
|
);
|