Reload daemon configuration without restarting (#3365)
* feat(daemon): reload configuration without restarting Keep config validation, reloadability classification, override handling, and atomic runtime application inside the daemon so local and remote clients share one authoritative workflow. * fix(daemon): preserve reload resource ownership Keep every materialized provider client under daemon-lifetime ownership and classify speech overrides from resolved providers. Restore the complete WebSocket config-store test contract exposed by CI.
This commit is contained in:
@@ -23,6 +23,7 @@ import { createRequire } from "node:module";
|
||||
import { mkdtemp, readFile, rm, writeFile } from "fs/promises";
|
||||
import { tmpdir } from "os";
|
||||
import { dirname, join } from "path";
|
||||
import YAML from "yaml";
|
||||
import { runLocalPaseo } from "./helpers/local-cli.ts";
|
||||
|
||||
console.log("=== Daemon Commands ===\n");
|
||||
@@ -276,6 +277,44 @@ try {
|
||||
assert.strictEqual(pairingPayload.relayEnabled, true, "pairing should use live relay state");
|
||||
assert.match(pairingPayload.url, /#offer=/, "pairing should use the live daemon offer");
|
||||
|
||||
const reloadConfig = JSON.parse(await readFile(configPath, "utf-8"));
|
||||
reloadConfig.daemon = {
|
||||
...reloadConfig.daemon,
|
||||
listen: process.platform === "win32" ? `${listen}-changed` : `${listen}.changed`,
|
||||
browserTools: { enabled: true },
|
||||
};
|
||||
await writeFile(configPath, `${JSON.stringify(reloadConfig, null, 2)}\n`, "utf-8");
|
||||
const nestedReload = await daemonCommand(["reload", "--host", listen, "--json"]);
|
||||
assert.strictEqual(nestedReload.exitCode, 0, nestedReload.stderr);
|
||||
assert.deepStrictEqual(JSON.parse(nestedReload.stdout), {
|
||||
appliedPaths: ["daemon.browserTools.enabled"],
|
||||
restartRequiredPaths: [],
|
||||
overrideControlledPaths: ["daemon.listen"],
|
||||
});
|
||||
|
||||
reloadConfig.daemon.browserTools.enabled = false;
|
||||
await writeFile(configPath, `${JSON.stringify(reloadConfig, null, 2)}\n`, "utf-8");
|
||||
const aliasReload = await runLocalPaseo(["reload", "--host", listen, "--json"], {
|
||||
PASEO_HOME: paseoHome,
|
||||
});
|
||||
assert.strictEqual(aliasReload.exitCode, 0, aliasReload.stderr);
|
||||
assert.deepStrictEqual(JSON.parse(aliasReload.stdout), {
|
||||
appliedPaths: ["daemon.browserTools.enabled"],
|
||||
restartRequiredPaths: [],
|
||||
overrideControlledPaths: [],
|
||||
});
|
||||
|
||||
const yamlReload = await daemonCommand(["reload", "--host", listen, "--format", "yaml"]);
|
||||
assert.strictEqual(yamlReload.exitCode, 0, yamlReload.stderr);
|
||||
assert.deepStrictEqual(YAML.parse(yamlReload.stdout), {
|
||||
appliedPaths: [],
|
||||
restartRequiredPaths: [],
|
||||
overrideControlledPaths: [],
|
||||
});
|
||||
|
||||
const humanReload = await daemonCommand(["reload", "--host", listen]);
|
||||
assert.match(humanReload.stdout, /Configuration reloaded\./);
|
||||
|
||||
const foreignHome = await mkdtemp(join(tmpdir(), "paseo-test-foreign-home-"));
|
||||
try {
|
||||
await writeFile(
|
||||
|
||||
Reference in New Issue
Block a user