fix(setup): configure an empty Hermes config.yaml (#1983)

* fix(setup): treat an empty Hermes config.yaml as a new document

YAML parses an empty file to null, so Hermes configuration was checked
as an object before the shared empty-file rule and rejected. Setup then
failed its readback gate for a zero-byte config.yaml, although a missing
file is configured and the Hermes serializer already writes a fresh
document for empty original text. Apply the empty-file rule before the
Hermes YAML parse, as #1117 did for JSON clients.

* test(setup): configure an empty Hermes config.yaml

Configure zero-byte and newline-only config.yaml files through the
real filesystem workflow, then read the registration back as aligned.
This commit is contained in:
Vinícius Andrade 2026-10-11 21:41:07 -03:00 committed by GitHub
parent a149d183ef
commit 43f9c39dfb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 2 deletions

View File

@ -104,11 +104,11 @@ const parseDocument = (
// comments, trailing commas, a BOM, or an empty existing file must be
// rejected instead of registering into a document Pi cannot load.
if (format === "pi") return objectSchema.parse(JSON.parse(text));
// Hermes stores MCP servers in `mcp_servers` inside a YAML document.
if (format === "hermes") return objectSchema.parse(parseYaml(text));
// An empty file, which some clients create before any server is added,
// holds no settings to preserve.
if (isEmptyClientConfigurationText(text)) return {};
// Hermes stores MCP servers in `mcp_servers` inside a YAML document.
if (format === "hermes") return objectSchema.parse(parseYaml(text));
const errors: ParseError[] = [];
// Accept a UTF-8 BOM without shifting diagnostics or editing the original text.
const jsonText = text.startsWith("\uFEFF") ? ` ${text.slice(1)}` : text;

View File

@ -185,4 +185,28 @@ mcp_servers:
},
});
});
it.each(["", "\n"])(
"configures an empty config.yaml %j as a new document",
async (original) => {
const { home, client } = await hermesClient();
await writeFile(client.configPath, original);
expect(
(await configureClientConfiguration(client, {}, command)).status,
).toBe("configured");
expect(parseYaml(await readFile(client.configPath, "utf8"))).toEqual({
mcp_servers: {
rea: { command: command[0], args: command.slice(1), enabled: true },
},
});
expect(
(
await readClientRegistrationStatuses(home, undefined, {
platform: process.platform,
environment: {},
})
).find(({ client: name }) => name === "hermes"),
).toMatchObject({ state: "aligned", command });
},
);
});