File size: 2,802 Bytes
f778c12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// Covers canonical dev gateway bootstrap config generation.
import { mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { OpenClawSchema } from "../../config/zod-schema.js";

const mocks = vi.hoisted(() => ({
  configPath: "",
  workspace: "",
  nextConfig: undefined as unknown,
  writeOptions: undefined as unknown,
  replaceConfigFile: vi.fn(),
}));

vi.mock("../../agents/workspace-templates.js", () => ({
  resolveWorkspaceTemplateSearchDirs: async () => [],
}));

vi.mock("../../agents/workspace.js", () => ({
  publishBootstrapFile: async () => true,
  resolveDefaultAgentWorkspaceDir: () => mocks.workspace,
}));

vi.mock("../../commands/onboard-helpers.js", () => ({
  handleReset: vi.fn(),
}));

vi.mock("../../config/config.js", () => ({
  createConfigIO: () => ({ configPath: mocks.configPath }),
  replaceConfigFile: (options: unknown) => mocks.replaceConfigFile(options),
}));

vi.mock("../../runtime.js", () => ({
  defaultRuntime: { log: vi.fn() },
}));

vi.mock("../../utils.js", () => ({
  resolveUserPath: (value: string) => value,
  shortenHomePath: (value: string) => value,
}));

const { ensureDevGatewayConfig } = await import("./dev.js");

describe("ensureDevGatewayConfig", () => {
  let tempDir = "";

  beforeEach(async () => {
    tempDir = await mkdtemp(path.join(os.tmpdir(), "openclaw-dev-config-"));
    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) => {
      const configOptions = options as { nextConfig: unknown; writeOptions?: unknown };
      mocks.nextConfig = configOptions.nextConfig;
      mocks.writeOptions = configOptions.writeOptions;
    });
  });

  afterEach(async () => {
    await rm(tempDir, { recursive: true, force: true });
  });

  it("writes a config that uses the canonical keyed agent entries shape", async () => {
    await ensureDevGatewayConfig({});
    const devWorkspace = `${mocks.workspace}-dev`;

    expect(mocks.nextConfig).toEqual({
      gateway: { mode: "local", bind: "loopback" },
      agents: {
        defaults: { workspace: devWorkspace, skipBootstrap: true },
        entries: {
          dev: {
            default: true,
            workspace: devWorkspace,
            identity: { name: "C3-PO", theme: "protocol droid", emoji: "🤖" },
          },
        },
      },
    });
    expect(OpenClawSchema.safeParse(mocks.nextConfig).success).toBe(true);
    expect(mocks.writeOptions).toEqual({ allowedAgentRosterRemovals: ["main"] });
  });
});