diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 5e2ea5a4..87024624 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,13 +5,13 @@ }, "metadata": { "description": "Codex plugins to use in Claude Code for delegation and code review.", - "version": "1.0.5" + "version": "1.0.6" }, "plugins": [ { "name": "codex", "description": "Use Codex from Claude Code to review code or delegate tasks.", - "version": "1.0.5", + "version": "1.0.6", "author": { "name": "OpenAI" }, diff --git a/package-lock.json b/package-lock.json index 06f89225..0c919c3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openai/codex-plugin-cc", - "version": "1.0.5", + "version": "1.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@openai/codex-plugin-cc", - "version": "1.0.5", + "version": "1.0.6", "license": "Apache-2.0", "devDependencies": { "@types/node": "^25.5.0", diff --git a/package.json b/package.json index bfe52e01..b1d984d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openai/codex-plugin-cc", - "version": "1.0.5", + "version": "1.0.6", "private": true, "type": "module", "description": "Use Codex from Claude Code to review code or delegate tasks.", diff --git a/plugins/codex/.claude-plugin/plugin.json b/plugins/codex/.claude-plugin/plugin.json index 168b342d..e91e5238 100644 --- a/plugins/codex/.claude-plugin/plugin.json +++ b/plugins/codex/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "codex", - "version": "1.0.5", + "version": "1.0.6", "description": "Use Codex from Claude Code to review code or delegate tasks.", "author": { "name": "OpenAI" diff --git a/plugins/codex/scripts/lib/git.mjs b/plugins/codex/scripts/lib/git.mjs index 1749cfc8..c401f0ca 100644 --- a/plugins/codex/scripts/lib/git.mjs +++ b/plugins/codex/scripts/lib/git.mjs @@ -8,12 +8,13 @@ const MAX_UNTRACKED_BYTES = 24 * 1024; const DEFAULT_INLINE_DIFF_MAX_FILES = 2; const DEFAULT_INLINE_DIFF_MAX_BYTES = 256 * 1024; +// Git is directly executable on Windows. Repository-derived arguments must never pass through a shell. function git(cwd, args, options = {}) { - return runCommand("git", args, { cwd, ...options }); + return runCommand("git", args, { cwd, ...options, shell: false }); } function gitChecked(cwd, args, options = {}) { - return runCommandChecked("git", args, { cwd, ...options }); + return runCommandChecked("git", args, { cwd, ...options, shell: false }); } function listUniqueFiles(...groups) { diff --git a/plugins/codex/scripts/lib/process.mjs b/plugins/codex/scripts/lib/process.mjs index af28d1cf..dd8fc375 100644 --- a/plugins/codex/scripts/lib/process.mjs +++ b/plugins/codex/scripts/lib/process.mjs @@ -9,7 +9,7 @@ export function runCommand(command, args = [], options = {}) { input: options.input, maxBuffer: options.maxBuffer, stdio: options.stdio ?? "pipe", - shell: process.platform === "win32" ? (process.env.SHELL || true) : false, + shell: options.shell ?? (process.platform === "win32" ? (process.env.SHELL || true) : false), windowsHide: true }); diff --git a/tests/git.test.mjs b/tests/git.test.mjs index 14ff2576..5b5c266e 100644 --- a/tests/git.test.mjs +++ b/tests/git.test.mjs @@ -38,6 +38,35 @@ test("resolveReviewTarget falls back to branch diff when repo is clean", () => { assert.match(context.content, /Branch Diff/); }); +test("default branch names with special characters are passed to git literally", () => { + const cwd = makeTempDir(); + const branchName = "main&branch-helper&x"; + const helperOutputPath = path.join(cwd, "branch-helper-output"); + initGitRepo(cwd); + fs.writeFileSync(path.join(cwd, "branch-helper.cmd"), "@echo branch-helper>branch-helper-output\r\n"); + fs.writeFileSync(path.join(cwd, "app.js"), "console.log('base');\n"); + run("git", ["add", "app.js", "branch-helper.cmd"], { cwd }); + run("git", ["commit", "-m", "base"], { cwd }); + run("git", ["branch", "-m", branchName], { cwd, shell: false }); + run("git", ["update-ref", `refs/remotes/origin/${branchName}`, branchName], { cwd, shell: false }); + run("git", ["symbolic-ref", "refs/remotes/origin/HEAD", `refs/remotes/origin/${branchName}`], { + cwd, + shell: false + }); + run("git", ["checkout", "-b", "feature/test"], { cwd }); + fs.writeFileSync(path.join(cwd, "app.js"), "console.log('feature');\n"); + run("git", ["add", "app.js"], { cwd }); + run("git", ["commit", "-m", "feature"], { cwd }); + + const target = resolveReviewTarget(cwd, {}); + const context = collectReviewContext(cwd, target); + + assert.equal(target.mode, "branch"); + assert.equal(target.baseRef, branchName); + assert.match(context.content, /Branch Diff/); + assert.equal(fs.existsSync(helperOutputPath), false); +}); + test("resolveReviewTarget honors explicit base overrides", () => { const cwd = makeTempDir(); initGitRepo(cwd); diff --git a/tests/helpers.mjs b/tests/helpers.mjs index 945ae0e7..d6981197 100644 --- a/tests/helpers.mjs +++ b/tests/helpers.mjs @@ -18,7 +18,7 @@ export function run(command, args, options = {}) { env: options.env, encoding: "utf8", input: options.input, - shell: process.platform === "win32" && !path.isAbsolute(command), + shell: options.shell ?? (process.platform === "win32" && !path.isAbsolute(command)), windowsHide: true }); }