-
Notifications
You must be signed in to change notification settings - Fork 57
Expand file tree
/
Copy pathspawn.test.ts
More file actions
117 lines (96 loc) · 3.99 KB
/
Copy pathspawn.test.ts
File metadata and controls
117 lines (96 loc) · 3.99 KB
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { describe, expect, it, vi } from "vitest";
import { Logger } from "../../utils/logger";
const spawnMock = vi.hoisted(() => vi.fn());
vi.mock("node:child_process", () => ({ spawn: spawnMock }));
const { spawnCodexProcess } = await import("./spawn");
function makeFakeChild() {
return {
stdin: { destroy: vi.fn() },
stdout: { on: vi.fn(), destroy: vi.fn() },
stderr: { on: vi.fn(), destroy: vi.fn() },
on: vi.fn(),
kill: vi.fn(),
pid: 1234,
};
}
describe("spawnCodexProcess MCP disable args", () => {
it("disables bare-key servers but skips names codex's -c parser cannot express", () => {
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({
logger: new Logger({ debug: false }),
settings: {
mcpServerNames: ["simple", "with-dash", "my.server", "weird name"],
},
});
const args: string[] = spawnMock.mock.calls[0][1];
expect(args).toContain("mcp_servers.simple.enabled=false");
expect(args).toContain("mcp_servers.with-dash.enabled=false");
// A dotted or otherwise non-bare name would emit an override codex rejects,
// which crashes the whole session, so it is skipped (the server stays
// enabled, which is harmless).
expect(args.some((arg) => arg.includes("my.server"))).toBe(false);
expect(args.some((arg) => arg.includes("weird name"))).toBe(false);
});
});
describe("spawnCodexProcess developer instructions", () => {
it("passes guidance via developer_instructions to preserve the base prompt", () => {
spawnMock.mockClear();
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({
logger: new Logger({ debug: false }),
developerInstructions: "Follow PostHog signed-commit rules.",
});
const args: string[] = spawnMock.mock.calls[0][1];
expect(args).toContain(
'developer_instructions="Follow PostHog signed-commit rules."',
);
// The bare `instructions` and `model_instructions_file` keys replace Codex's
// model-optimized base prompt, so guidance must never go through them.
expect(args.some((arg) => arg.startsWith("instructions="))).toBe(false);
expect(args.some((arg) => arg.startsWith("model_instructions_file="))).toBe(
false,
);
});
it("escapes backslashes, newlines and quotes in developer_instructions", () => {
spawnMock.mockClear();
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({
logger: new Logger({ debug: false }),
developerInstructions: 'a\\b\n"c',
});
const args: string[] = spawnMock.mock.calls[0][1];
expect(args).toContain('developer_instructions="a\\\\b\\n\\"c"');
});
});
describe("spawnCodexProcess codex home", () => {
it("sets CODEX_HOME on the child env when provided", () => {
spawnMock.mockClear();
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({
logger: new Logger({ debug: false }),
codexHome: "/data/codex-home",
});
const env = spawnMock.mock.calls[0][2].env;
expect(env.CODEX_HOME).toBe("/data/codex-home");
});
it("does not inject CODEX_HOME when not provided", () => {
spawnMock.mockClear();
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({ logger: new Logger({ debug: false }) });
// Inherits the ambient value (if any) without the adapter adding its own.
const env = spawnMock.mock.calls[0][2].env;
expect(env.CODEX_HOME).toBe(process.env.CODEX_HOME);
});
});
describe("spawnCodexProcess electron env", () => {
it("keeps ELECTRON_RUN_AS_NODE=1 so PATH node shims stay in node mode", () => {
spawnMock.mockClear();
spawnMock.mockReturnValue(makeFakeChild());
spawnCodexProcess({ logger: new Logger({ debug: false }) });
// The desktop app's workspace-server puts a `node -> app binary` symlink
// on PATH. Dropping this var would make every `node` spawned under codex
// boot a full desktop app instance instead of running as node.
const env = spawnMock.mock.calls[0][2].env;
expect(env.ELECTRON_RUN_AS_NODE).toBe("1");
});
});