diff --git a/.github/workflows/pull-request-ci.yml b/.github/workflows/pull-request-ci.yml index ebcff0b65..09bbd0fd7 100644 --- a/.github/workflows/pull-request-ci.yml +++ b/.github/workflows/pull-request-ci.yml @@ -33,3 +33,24 @@ jobs: - name: Run build run: npm run build + + windows-shim: + name: Windows CLI shim + runs-on: windows-latest + timeout-minutes: 10 + + steps: + - name: Check out repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up Node.js + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 + with: + node-version: 22 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Verify npm shim with PowerShell SHELL + run: node --test --test-name-pattern="Windows setup and tasks use the .cmd shim when SHELL is PowerShell" tests/runtime.test.mjs diff --git a/README.md b/README.md index 937a3037b..448ca6623 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,8 @@ That means: - it uses the same local authentication state - it uses the same repository checkout and machine-local environment +On Windows, the plugin runs npm's `codex.cmd` shim through the Windows command shell. This works when PowerShell script execution policy blocks `codex.ps1`; no policy change is needed. Run `/codex:setup` to check the CLI and app server. + ### Will it use the same Codex config I already have? Yes. If you already use Codex, the plugin picks up the same [configuration](#common-configurations). diff --git a/plugins/codex/scripts/lib/app-server.mjs b/plugins/codex/scripts/lib/app-server.mjs index 72b30a764..b3da832f5 100644 --- a/plugins/codex/scripts/lib/app-server.mjs +++ b/plugins/codex/scripts/lib/app-server.mjs @@ -191,7 +191,7 @@ class SpawnedCodexAppServerClient extends AppServerClientBase { cwd: this.cwd, env: this.options.env ?? process.env, stdio: ["pipe", "pipe", "pipe"], - shell: process.platform === "win32" ? (process.env.SHELL || true) : false, + shell: process.platform === "win32", windowsHide: true }); diff --git a/plugins/codex/scripts/lib/process.mjs b/plugins/codex/scripts/lib/process.mjs index dd8fc3751..58cdf18c6 100644 --- a/plugins/codex/scripts/lib/process.mjs +++ b/plugins/codex/scripts/lib/process.mjs @@ -9,7 +9,9 @@ export function runCommand(command, args = [], options = {}) { input: options.input, maxBuffer: options.maxBuffer, stdio: options.stdio ?? "pipe", - shell: options.shell ?? (process.platform === "win32" ? (process.env.SHELL || true) : false), + // Windows npm shims are .cmd files. Let Node use the Windows command shell + // rather than SHELL, which may point to PowerShell and select codex.ps1. + shell: options.shell ?? (process.platform === "win32"), windowsHide: true }); diff --git a/tests/runtime.test.mjs b/tests/runtime.test.mjs index 8f276835b..bed781b63 100644 --- a/tests/runtime.test.mjs +++ b/tests/runtime.test.mjs @@ -44,6 +44,26 @@ test("setup reports ready when fake codex is installed and authenticated", () => assert.equal(payload.sessionRuntime.mode, "direct"); }); +test("Windows setup and tasks use the .cmd shim when SHELL is PowerShell", { skip: process.platform !== "win32" }, () => { + const repo = makeTempDir(); + const binDir = makeTempDir(); + installFakeCodex(binDir); + fs.writeFileSync(path.join(binDir, "codex.ps1"), "throw 'PowerShell shim must not run'\r\n"); + initGitRepo(repo); + fs.writeFileSync(path.join(repo, "README.md"), "hello\n"); + run("git", ["add", "README.md"], { cwd: repo }); + run("git", ["commit", "-m", "init"], { cwd: repo }); + const env = { ...buildEnv(binDir), SHELL: "powershell.exe" }; + + const setup = run("node", [SCRIPT, "setup", "--json"], { cwd: repo, env }); + assert.equal(setup.status, 0, setup.stderr); + assert.equal(JSON.parse(setup.stdout).codex.available, true); + + const task = run("node", [SCRIPT, "task", "check Windows shim"], { cwd: repo, env }); + assert.equal(task.status, 0, task.stderr); + assert.match(task.stdout, /Handled the requested task/); +}); + test("setup is ready without npm when Codex is already installed and authenticated", () => { const binDir = makeTempDir(); installFakeCodex(binDir);