diff --git a/registry/coder-labs/modules/codex/README.md b/registry/coder-labs/modules/codex/README.md index d37243353..553706543 100644 --- a/registry/coder-labs/modules/codex/README.md +++ b/registry/coder-labs/modules/codex/README.md @@ -13,7 +13,7 @@ Install and configure the [Codex CLI](https://github.com/openai/codex) in your w ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id openai_api_key = var.openai_api_key } @@ -33,7 +33,7 @@ locals { module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = local.codex_workdir openai_api_key = var.openai_api_key @@ -64,7 +64,7 @@ resource "coder_app" "codex" { ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" enable_ai_gateway = true @@ -88,7 +88,7 @@ When `enable_ai_gateway = true`, the module configures Codex to use the `aigatew ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id workdir = "/home/coder/project" openai_api_key = var.openai_api_key @@ -134,7 +134,7 @@ The module exposes the `scripts` output: an ordered list of `coder exp sync` nam ```tf module "codex" { source = "registry.coder.com/coder-labs/codex/coder" - version = "5.4.1" + version = "5.4.2" agent_id = coder_agent.main.id openai_api_key = var.openai_api_key } diff --git a/registry/coder-labs/modules/codex/main.test.ts b/registry/coder-labs/modules/codex/main.test.ts index daf348fa6..0e62c2533 100644 --- a/registry/coder-labs/modules/codex/main.test.ts +++ b/registry/coder-labs/modules/codex/main.test.ts @@ -285,6 +285,64 @@ describe("codex", async () => { expect(installerEnv).toContain("CODEX_NON_INTERACTIVE=1"); }); + test("standalone-code-mode-host-is-linked-and-tracks-upgrades", async () => { + const { id, scripts } = await setup({ skipCodexMock: true }); + const root = "/home/coder/.codex/packages/standalone"; + const binDir = "/home/coder/.local/bin"; + const scriptBinDir = "/home/coder/script-bin"; + for (const version of ["v1", "v2"]) { + const created = await execContainer(id, [ + "mkdir", + "-p", + `${root}/${version}/bin`, + ]); + expect(created.exitCode, created.stderr).toBe(0); + await writeExecutable({ + containerId: id, + filePath: `${root}/${version}/bin/codex`, + content: '#!/bin/sh\necho "codex test version"\n', + }); + await writeExecutable({ + containerId: id, + filePath: `${root}/${version}/bin/codex-code-mode-host`, + content: `#!/bin/sh\necho "${version}"\n`, + }); + } + const prepared = await execContainer(id, [ + "bash", + "-c", + `mkdir -p ${binDir} ${scriptBinDir} && + ln -s v1 ${root}/current && + ln -s ../../.codex/packages/standalone/current/bin/codex ${binDir}/codex`, + ]); + expect(prepared.exitCode).toBe(0); + const env = { + PATH: `${binDir}:/usr/local/bin:/usr/bin:/bin`, + CODER_SCRIPT_BIN_DIR: scriptBinDir, + }; + await runScripts(id, scripts, env); + await runScripts(id, scripts, env); + for (const version of ["v1", "v2"]) { + if (version === "v2") { + const upgraded = await execContainer(id, [ + "bash", + "-c", + `ln -sfn v2 ${root}/current`, + ]); + expect(upgraded.exitCode).toBe(0); + } + for (const dir of [binDir, scriptBinDir]) { + const result = await execContainer(id, [ + "bash", + "-c", + `${dir}/codex-code-mode-host`, + ]); + expect(result.exitCode).toBe(0); + expect(result.stdout.trim()).toBe(version); + } + } + }); + test("openai-api-key", async () => { const apiKey = "test-api-key-123"; const encodedApiKey = Buffer.from(apiKey).toString("base64"); diff --git a/registry/coder-labs/modules/codex/scripts/install.sh.tftpl b/registry/coder-labs/modules/codex/scripts/install.sh.tftpl index d29419576..3ee94539a 100644 --- a/registry/coder-labs/modules/codex/scripts/install.sh.tftpl +++ b/registry/coder-labs/modules/codex/scripts/install.sh.tftpl @@ -68,6 +68,32 @@ function ensure_codex_in_path() { local CODEX_DIR CODEX_DIR=$(dirname "$${CODEX_BIN}") + # The standalone installer may only link codex, leaving its code-mode helper + # in the package directory (https://github.com/openai/codex/issues/31831). + # Follow file symlinks without resolving the standalone/current directory so + # the helper continues to track the active release after an upgrade. + local CODEX_TARGET="$${CODEX_BIN}" + local LINK_TARGET + while [ -L "$${CODEX_TARGET}" ]; do + LINK_TARGET=$(readlink "$${CODEX_TARGET}") + case "$${LINK_TARGET}" in + /*) CODEX_TARGET="$${LINK_TARGET}" ;; + *) CODEX_TARGET="$(dirname "$${CODEX_TARGET}")/$${LINK_TARGET}" ;; + esac + done + + local CODEX_HOST + CODEX_HOST="$(dirname "$${CODEX_TARGET}")/codex-code-mode-host" + local BIN_DIR + if [ -x "$${CODEX_HOST}" ]; then + for BIN_DIR in "$${CODEX_DIR}" "$${CODER_SCRIPT_BIN_DIR:-}"; do + if [ -n "$${BIN_DIR}" ] && [ ! -e "$${BIN_DIR}/codex-code-mode-host" ] && [ ! -L "$${BIN_DIR}/codex-code-mode-host" ]; then + ln -s "$${CODEX_HOST}" "$${BIN_DIR}/codex-code-mode-host" + echo "Created symlink: $${BIN_DIR}/codex-code-mode-host -> $${CODEX_HOST}" + fi + done + fi + if [ -n "$${CODER_SCRIPT_BIN_DIR:-}" ] && [ ! -e "$${CODER_SCRIPT_BIN_DIR}/codex" ]; then ln -s "$${CODEX_BIN}" "$${CODER_SCRIPT_BIN_DIR}/codex" echo "Created symlink: $${CODER_SCRIPT_BIN_DIR}/codex -> $${CODEX_BIN}"