
























@@ -0,0 +1,95 @@
1+import path from "node:path";
2+import { describe, expect, it, vi } from "vitest";
3+import type { CodexAppServerStartOptions } from "./config.js";
4+import {
5+resolveManagedCodexAppServerPaths,
6+resolveManagedCodexAppServerStartOptions,
7+} from "./managed-binary.js";
8+9+function startOptions(
10+commandSource: CodexAppServerStartOptions["commandSource"],
11+): CodexAppServerStartOptions {
12+return {
13+transport: "stdio",
14+command: "codex",
15+ commandSource,
16+args: ["app-server", "--listen", "stdio://"],
17+headers: {},
18+};
19+}
20+21+function managedCommandPath(root: string, platform: NodeJS.Platform): string {
22+return path.join(root, "node_modules", ".bin", platform === "win32" ? "codex.cmd" : "codex");
23+}
24+25+describe("managed Codex app-server binary", () => {
26+it("leaves explicit command overrides unchanged", async () => {
27+const explicitOptions = startOptions("config");
28+const pathExists = vi.fn(async () => false);
29+30+await expect(
31+resolveManagedCodexAppServerStartOptions(explicitOptions, {
32+platform: "darwin",
33+ pathExists,
34+}),
35+).resolves.toBe(explicitOptions);
36+expect(pathExists).not.toHaveBeenCalled();
37+});
38+39+it("resolves the plugin-local bundled Codex binary", async () => {
40+const pluginRoot = path.join("/tmp", "openclaw", "extensions", "codex");
41+const paths = resolveManagedCodexAppServerPaths({ platform: "darwin", pluginRoot });
42+const pathExists = vi.fn(async (filePath: string) => filePath === paths.commandPath);
43+44+await expect(
45+resolveManagedCodexAppServerStartOptions(startOptions("managed"), {
46+platform: "darwin",
47+ pluginRoot,
48+ pathExists,
49+}),
50+).resolves.toEqual({
51+ ...startOptions("managed"),
52+command: paths.commandPath,
53+commandSource: "resolved-managed",
54+});
55+expect(paths.commandPath).toBe(managedCommandPath(pluginRoot, "darwin"));
56+});
57+58+it("resolves Windows Codex command shims", () => {
59+const pluginRoot = path.win32.join("C:\\", "OpenClaw", "dist", "extensions", "codex");
60+const paths = resolveManagedCodexAppServerPaths({ platform: "win32", pluginRoot });
61+62+expect(paths.commandPath.endsWith(path.win32.join("node_modules", ".bin", "codex.cmd"))).toBe(
63+true,
64+);
65+});
66+67+it("finds Codex in the external runtime-deps install root used by packaged plugins", async () => {
68+const installRoot = path.join("/tmp", "openclaw-runtime-deps", "codex");
69+const pluginRoot = path.join(installRoot, "dist", "extensions", "codex");
70+const installedCommand = managedCommandPath(installRoot, "linux");
71+const pathExists = vi.fn(async (filePath: string) => filePath === installedCommand);
72+73+await expect(
74+resolveManagedCodexAppServerStartOptions(startOptions("managed"), {
75+platform: "linux",
76+ pluginRoot,
77+ pathExists,
78+}),
79+).resolves.toEqual({
80+ ...startOptions("managed"),
81+command: installedCommand,
82+commandSource: "resolved-managed",
83+});
84+});
85+86+it("fails clearly when bundled runtime deps did not stage Codex", async () => {
87+await expect(
88+resolveManagedCodexAppServerStartOptions(startOptions("managed"), {
89+platform: "darwin",
90+pluginRoot: path.join("/tmp", "openclaw", "extensions", "codex"),
91+pathExists: vi.fn(async () => false),
92+}),
93+).rejects.toThrow("Managed Codex app-server binary was not found");
94+});
95+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。