| 51 | * and a `codex` CLI whose `app-server` is the fake app-server fixture) and |
| 52 | * one cached plugin wrapping the self-contained stdio MCP fixture. */ |
| 53 | const makeCodexHome = (): string => { |
| 54 | const home = mkdtempSync(join(tmpdir(), "codex-home-e2e-")); |
| 55 | const wrapper = `#!/bin/sh\nexec node "${FIXTURE}" "$@"\n`; |
| 56 | |
| 57 | // The Computer Use app is the plugin-installed marker; the bridge never |
| 58 | // spawns it, so an empty executable is enough. |
| 59 | const clientDir = join( |
| 60 | home, |
| 61 | "computer-use", |
| 62 | "Codex Computer Use.app", |
| 63 | "Contents", |
| 64 | "SharedSupport", |
| 65 | "SkyComputerUseClient.app", |
| 66 | "Contents", |
| 67 | "MacOS", |
| 68 | ); |
| 69 | mkdirSync(clientDir, { recursive: true }); |
| 70 | writeFileSync(join(clientDir, "SkyComputerUseClient"), wrapper, { mode: 0o755 }); |
| 71 | |
| 72 | // The `codex` CLI the curated recipes spawn — resolved through PATH, so |
| 73 | // the scenario prepends this bin dir to the server's PATH. |
| 74 | mkdirSync(join(home, "bin"), { recursive: true }); |
| 75 | writeFileSync(join(home, "bin", "codex"), `#!/bin/sh\nexec node "${APP_SERVER_FIXTURE}" "$@"\n`, { |
| 76 | mode: 0o755, |
| 77 | }); |
| 78 | |
| 79 | // Chrome's bundled browser client, behind the `latest` symlink Codex keeps. |
| 80 | const chromeClient = join(home, CHROME_CLIENT_RELATIVE); |
| 81 | mkdirSync(join(chromeClient, ".."), { recursive: true }); |
| 82 | writeFileSync(chromeClient, "export const setupBrowserRuntime = async () => ({});\n"); |
| 83 | |
| 84 | const versionDir = join(home, "plugins", "cache", "personal", "echo-suite", "1.0.2"); |
| 85 | mkdirSync(join(versionDir, ".codex-plugin"), { recursive: true }); |
| 86 | mkdirSync(join(versionDir, "bin"), { recursive: true }); |
| 87 | writeFileSync( |
| 88 | join(versionDir, ".codex-plugin", "plugin.json"), |
| 89 | JSON.stringify({ |
| 90 | name: "echo-suite", |
| 91 | mcpServers: "./.mcp.json", |
| 92 | interface: { displayName: "Echo Suite", shortDescription: "Echo tools for e2e" }, |
| 93 | }), |
| 94 | ); |
| 95 | writeFileSync( |
| 96 | join(versionDir, ".mcp.json"), |
| 97 | JSON.stringify({ mcpServers: { "echo-suite": { command: "./bin/run", cwd: "." } } }), |
| 98 | ); |
| 99 | writeFileSync(join(versionDir, "bin", "run"), wrapper, { mode: 0o755 }); |
| 100 | |
| 101 | return home; |
| 102 | }; |
| 103 | |
| 104 | scenario( |
| 105 | "Local · Codex plugins are discovered from CODEX_HOME and add as one-click stdio presets", |