Skip to content
Closed
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
21 changes: 21 additions & 0 deletions .github/workflows/pull-request-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
2 changes: 1 addition & 1 deletion plugins/codex/scripts/lib/app-server.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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
});

Expand Down
4 changes: 3 additions & 1 deletion plugins/codex/scripts/lib/process.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve Windows shims outside the checkout

When the plugin is run from an untrusted repository containing node.cmd or codex.cmd, shell: true delegates these bare command names to cmd.exe, whose normal lookup checks cwd before PATH; /codex:setup can therefore execute the repository's batch file as the user instead of the installed tool, and the changed app-server spawn does the same for codex. This newly exposes the SHELL=PowerShell users targeted by this change because PowerShell does not search the current directory by default, so resolve the intended shim from PATH to an absolute path before invoking it rather than relying on cmd lookup.

Useful? React with 👍 / 👎.

windowsHide: true
});

Expand Down
20 changes: 20 additions & 0 deletions tests/runtime.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down