mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(gateway): restore fresh dev bootstrap (#118003)
This commit is contained in:
committed by
GitHub
parent
8de3c11fae
commit
184c7a00fa
@@ -0,0 +1,44 @@
|
||||
// Proves a fresh dev gateway can replace the synthetic implicit roster through real config IO.
|
||||
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { resetConfigRuntimeState } from "../../config/config.js";
|
||||
import { withEnvAsync } from "../../test-utils/env.js";
|
||||
import { ensureDevGatewayConfig } from "./dev.js";
|
||||
|
||||
describe("ensureDevGatewayConfig integration", () => {
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
resetConfigRuntimeState();
|
||||
await Promise.all(tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })));
|
||||
});
|
||||
|
||||
it("writes the dedicated dev roster into a fresh state directory", async () => {
|
||||
const root = await mkdtemp(path.join(os.tmpdir(), "openclaw-dev-config-integration-"));
|
||||
tempDirs.push(root);
|
||||
const stateDir = path.join(root, "state");
|
||||
const configPath = path.join(stateDir, "openclaw.json");
|
||||
const workspace = path.join(root, "workspace");
|
||||
|
||||
await withEnvAsync(
|
||||
{
|
||||
OPENCLAW_CONFIG_PATH: configPath,
|
||||
OPENCLAW_STATE_DIR: stateDir,
|
||||
OPENCLAW_WORKSPACE_DIR: workspace,
|
||||
},
|
||||
async () => {
|
||||
resetConfigRuntimeState();
|
||||
await ensureDevGatewayConfig({});
|
||||
},
|
||||
);
|
||||
|
||||
const config = JSON.parse(await readFile(configPath, "utf8")) as {
|
||||
agents?: { entries?: Record<string, { default?: boolean; workspace?: string }> };
|
||||
};
|
||||
expect(config.agents?.entries).toEqual({
|
||||
dev: { default: true, workspace: `${workspace}-dev`, identity: expect.any(Object) },
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,7 @@ const mocks = vi.hoisted(() => ({
|
||||
configPath: "",
|
||||
workspace: "",
|
||||
nextConfig: undefined as unknown,
|
||||
writeOptions: undefined as unknown,
|
||||
replaceConfigFile: vi.fn(),
|
||||
}));
|
||||
|
||||
@@ -48,9 +49,12 @@ describe("ensureDevGatewayConfig", () => {
|
||||
mocks.configPath = path.join(tempDir, "openclaw.json");
|
||||
mocks.workspace = path.join(tempDir, "workspace");
|
||||
mocks.nextConfig = undefined;
|
||||
mocks.writeOptions = undefined;
|
||||
mocks.replaceConfigFile.mockReset();
|
||||
mocks.replaceConfigFile.mockImplementation(async (options: unknown) => {
|
||||
mocks.nextConfig = (options as { nextConfig: unknown }).nextConfig;
|
||||
const configOptions = options as { nextConfig: unknown; writeOptions?: unknown };
|
||||
mocks.nextConfig = configOptions.nextConfig;
|
||||
mocks.writeOptions = configOptions.writeOptions;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -76,5 +80,6 @@ describe("ensureDevGatewayConfig", () => {
|
||||
},
|
||||
});
|
||||
expect(OpenClawSchema.safeParse(mocks.nextConfig).success).toBe(true);
|
||||
expect(mocks.writeOptions).toEqual({ allowedAgentRosterRemovals: ["main"] });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { resolveWorkspaceTemplateSearchDirs } from "../../agents/workspace-templ
|
||||
import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js";
|
||||
import { handleReset } from "../../commands/onboard-helpers.js";
|
||||
import { createConfigIO, replaceConfigFile } from "../../config/config.js";
|
||||
import { LEGACY_IMPLICIT_AGENT_ID } from "../../routing/session-key.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
import { resolveUserPath, shortenHomePath } from "../../utils.js";
|
||||
|
||||
@@ -128,6 +129,9 @@ export async function ensureDevGatewayConfig(opts: { reset?: boolean }) {
|
||||
},
|
||||
},
|
||||
afterWrite: { mode: "auto" },
|
||||
// An absent config resolves to the implicit legacy agent before this full
|
||||
// replacement. Declare only that synthetic deletion; authored rosters stay protected.
|
||||
writeOptions: { allowedAgentRosterRemovals: [LEGACY_IMPLICIT_AGENT_ID] },
|
||||
});
|
||||
await ensureDevWorkspace(workspace);
|
||||
defaultRuntime.log(`Dev config ready: ${shortenHomePath(configPath)}`);
|
||||
|
||||
Reference in New Issue
Block a user