Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions apps/server/src/codexAppServerManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,35 @@ describe("startSession", () => {
manager.stopAll();
}
});

it("reports missing working directory instead of missing binary when cwd does not exist", async () => {
const manager = new CodexAppServerManager();
const events: Array<{ method: string; kind: string; message?: string }> = [];
manager.on("event", (event) => {
events.push({
method: event.method,
kind: event.kind,
...(event.message ? { message: event.message } : {}),
});
});

const missingCwd = path.join(os.tmpdir(), `t3code-nonexistent-${randomUUID()}`);
try {
await expect(
manager.startSession({
threadId: asThreadId("thread-cwd-missing"),
provider: "codex",
binaryPath: "codex",
cwd: missingCwd,
runtimeMode: "full-access",
}),
).rejects.toThrow(/Working directory.*does not exist/);
expect(events).toHaveLength(1);
expect(events[0]?.method).toBe("session/startFailed");
} finally {
manager.stopAll();
}
});
});

describe("sendTurn", () => {
Expand Down
9 changes: 9 additions & 0 deletions apps/server/src/codexAppServerManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type ChildProcessWithoutNullStreams, spawn, spawnSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import { EventEmitter } from "node:events";
import fs from "node:fs";
import readline from "node:readline";

import {
Expand Down Expand Up @@ -1553,6 +1554,14 @@ function assertSupportedCodexCliVersion(input: {
lower.includes("command not found") ||
lower.includes("not found")
) {
// Disambiguate: ENOENT can mean the binary is missing OR the cwd
// does not exist. Check the cwd in the error path so we surface
// the right message without a racy preflight.
try {
fs.accessSync(input.cwd);
} catch {
throw new Error(`Working directory '${input.cwd}' does not exist or is not accessible.`);
}
throw new Error(`Codex CLI (${input.binaryPath}) is not installed or not executable.`);
}
throw new Error(
Expand Down
Loading