mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 01:45:32 +00:00
JSON.parse, JSONC parse, and native Claude Code keep the last duplicate object member, and parseClientConfiguration therefore validates the last one. The shared setup/uninstall serializer instead edited text through jsonc-parser's modify and findNodeAtLocation, which select the first matching member, so setup and uninstall on configurations with repeated server tables or rea members wrote into a shadowed member and failed readback. Locate every JSON text edit by the effective (last) member in one place, replacing the first-member modify path. Removing an effective member that shadows an earlier duplicate would activate that duplicate, whatever its ownership, so the serializer now returns a tagged shadowed_member failure and setup and uninstall refuse before writing a backup or the configuration. Fixes #4952 Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
101 lines
3.6 KiB
TypeScript
101 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
parseClientConfiguration,
|
|
serializeClientConfiguration,
|
|
withClientServers,
|
|
} from "./ClientConfigurationDocument.js";
|
|
|
|
const registration = { command: "rea", args: ["mcp"] };
|
|
|
|
const serializedText = (
|
|
...input: Parameters<typeof serializeClientConfiguration>
|
|
): string => {
|
|
const serialized = serializeClientConfiguration(...input);
|
|
if (!serialized.ok) throw new Error("TOML serialization was refused");
|
|
return serialized.value;
|
|
};
|
|
|
|
describe("TOML configuration source capacity", () => {
|
|
it.each(["\n", "\r\n"])(
|
|
"retains adjacent assignments and multiline values with %j breaks",
|
|
(newline) => {
|
|
const prefix = Array.from(
|
|
{ length: 128 },
|
|
(_, index) =>
|
|
`[foreign.entry_${index}]\nvalue = ${index}\nnote = """first\n# [mcp_servers.rea]\nlast"""\nitems = [\n${index},\n]\n`,
|
|
).join("");
|
|
// Include a BOM, an empty value, and a final statement without a newline.
|
|
const original =
|
|
"\uFEFF" +
|
|
`${prefix}[mcp_servers.rea]\ncommand = "previous"\n[tail]\nempty = ""\nlast = 7`.replaceAll(
|
|
"\n",
|
|
newline,
|
|
);
|
|
const parsed = parseClientConfiguration(original, "toml");
|
|
const desired = withClientServers(parsed, {
|
|
...parsed.servers,
|
|
rea: registration,
|
|
});
|
|
const configured = serializedText(desired, "toml", original);
|
|
expect(
|
|
configured.startsWith("\uFEFF" + prefix.replaceAll("\n", newline)),
|
|
).toBe(true);
|
|
expect(parseClientConfiguration(configured, "toml").document).toEqual(
|
|
desired,
|
|
);
|
|
const removed = serializedText(
|
|
withClientServers(parsed, {}),
|
|
"toml",
|
|
configured,
|
|
);
|
|
const expectedForeignDocument = { ...parsed.document };
|
|
delete expectedForeignDocument.mcp_servers;
|
|
expect(parseClientConfiguration(removed, "toml").document).toEqual(
|
|
expectedForeignDocument,
|
|
);
|
|
},
|
|
);
|
|
|
|
it("retains a large multiline foreign value inside an inline server table", () => {
|
|
const note = `first\n${"x\n".repeat(500_000)}last`;
|
|
const original = `mcp_servers = { other = {command="other",env={NOTE="""${note}"""}}}\n`;
|
|
const parsed = parseClientConfiguration(original, "toml");
|
|
const desired = withClientServers(parsed, {
|
|
...parsed.servers,
|
|
rea: registration,
|
|
});
|
|
const configured = serializedText(desired, "toml", original);
|
|
expect(configured).toContain(`NOTE="""${note}"""`);
|
|
expect(parseClientConfiguration(configured, "toml").document).toEqual(
|
|
desired,
|
|
);
|
|
const removed = serializedText(parsed.document, "toml", configured);
|
|
expect(removed).toContain(`NOTE="""${note}"""`);
|
|
expect(parseClientConfiguration(removed, "toml").document).toEqual(
|
|
parsed.document,
|
|
);
|
|
});
|
|
|
|
it("removes only REA from a large multiline Grok disabled-server list", () => {
|
|
const otherNames = '"other",\n'.repeat(500_000);
|
|
const original =
|
|
`disabled_mcp_servers = [\n"rea",\n${otherNames}]\n` +
|
|
'[mcp_servers.other]\ncommand = "other"\n';
|
|
const parsed = parseClientConfiguration(original, "grok");
|
|
const desired = withClientServers(parsed, {
|
|
...parsed.servers,
|
|
rea: registration,
|
|
});
|
|
const configured = serializedText(desired, "grok", original);
|
|
const result = parseClientConfiguration(configured, "grok");
|
|
expect(result.document.disabled_mcp_servers).toEqual(
|
|
Array<string>(500_000).fill("other"),
|
|
);
|
|
expect(result.servers).toEqual({
|
|
other: { command: "other" },
|
|
rea: registration,
|
|
});
|
|
});
|
|
});
|