fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(server): update standalone Codex installs with codex update - #5630

Closed
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update
Closed

fix(server): update standalone Codex installs with codex update#5630
hkarlsen06 wants to merge 3 commits into
pingdotgg:mainfrom
hkarlsen06:fix/codex-native-update

Conversation

@hkarlsen06

@hkarlsen06hkarlsen06 commented Aug 7, 2026

Copy link
Copy Markdown

Fixes the permanent "Codex still appears outdated" loop reported in #5629.

Problem

CodexDriver declared nativeUpdate: null. A Codex CLI installed with OpenAI's standalone installer lives at ~/.local/bin/codex and symlinks into ~/.codex/packages/standalone/releases/<ver>/bin/codex, which matches none of the package-manager heuristics in resolvePackageManagedProviderMaintenance. With the provider's default bare binaryPath of "codex", resolution then fell through to the fallback at providerMaintenance.ts:311, which assumes an unclassified install is npm-managed and reports canUpdate: true.

Clicking Update now therefore ran npm install -g @openai/codex@latest against an install npm does not own. The command exits 0, so providerMaintenanceRunner re-probed, still resolved the untouched standalone binary, still saw behind_latest, and recorded unchanged — surfacing "Provider still needs an update" on every attempt.

The silent half is worse than the loop: on a machine with no npm copy, that command creates a second Codex install the user never asked for, while the binary they actually run stays stale.

Fix

Declare Codex's native update path the way ClaudeDriver already does for the identical ~/.local/bin layout:

nativeUpdate: {executable: "codex",args: ["update"],lockKey: "codex-native",isCommandPath: isCodexNativeCommandPath,},

codex update is a first-class subcommand of the CLI. Because realCommandPath is already threaded through resolveProviderMaintenanceCapabilitiesEffect, the /.codex/packages/standalone/ clause matches through the symlink regardless of the link's name.

Tests

  • CodexExecutable.test.ts (new) — asserts standalone paths match and that npm, bun and Homebrew paths do not, so package-manager-owned installs keep being updated by their package manager.
  • providerMaintenance.test.ts — adds coverage for a native install matched only via realCommandPath through a symlink. That path had no test, and it is the mechanism this fix depends on.

apps/server suite: 1917 passed, 7 skipped, 0 failures. tsgo --noEmit, vp lint and vp fmt --check all clean.

Deliberately not fixed here

#5629 also describes a second defect: the providerMaintenance.ts:311 fallback treats "could not classify this install" as "assume npm" for bare-name binaryPath values, while the path-separator branch two lines below correctly declines to manual-only. Tightening it looked like a natural companion change, but it is not safe as-is.

A Windows npm global install resolves to %APPDATA%\npm\codex.cmd. realPath does not rewrite .cmd shims, and isNpmGlobalCommandPath requires a /node_modules/ segment, so that path matches nothing and currently reaches npm-global only through this fallback. Making the fallback stricter would silently take the update button away from Windows npm users.

Correcting that properly needs a Windows npm shim heuristic first, which felt like it belonged in its own PR with its own test matrix rather than riding along with a driver fix. Happy to follow up if maintainers want it.

Note on scope

isCodexNativeCommandPath matches ~/.local/bin/codex as well as the standalone release path, mirroring isClaudeNativeCommandPath. Native matching runs before the package-manager checks, so a Codex binary manually symlinked into ~/.local/bin from a bun or pnpm install would now be offered codex update instead of its package manager's command. That matches existing Claude behaviour, and codex update reports the owning install method rather than doing something destructive — but I'm happy to drop the ~/.local/bin clause and rely solely on /.codex/packages/standalone/ if you'd prefer the narrower match.


Note

Medium Risk
Changes which executable runs for provider updates and Codex maintenance classification; behavior is covered by new tests but affects update execution paths.

Overview
Fixes the outdated Codex loop for OpenAI’s standalone installer by treating those installs as native and offering codex update instead of npm install -g @openai/codex@latest.

Codex driver: Adds isCodexNativeCommandPath (paths under ~/.local/bin/codex / ~/.codex/packages/standalone/) and wires nativeUpdate with codex update, matching the Claude driver pattern.

Shared maintenance: Native update actions now spawn the resolved binary path (symlink or configured path), not the bare command name, so updates hit the install that was classified. Copyable update strings quote executable paths that contain spaces; spawn still uses unquoted argv.

Tests cover Codex path classification, symlink realPath matching, configured-vs-PATH binaries, and spaced paths.

Reviewed by Cursor Bugbot for commit d09a15d. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix codex update for standalone Codex installs detected by command path

  • Adds isCodexNativeCommandPath to classify a binary as a standalone Codex install when its path ends with /.local/bin/codex[.exe] or contains /.codex/packages/standalone/.
  • Wires a nativeUpdate config into the Codex driver that runs codex update when the binary matches the standalone layout, including symlink realpath resolution.
  • Updates the display command to quote tokens containing spaces, and sets the update executable to the resolved binary path rather than a bare command name.

Macroscope summarized d09a15d.

The Codex driver declared `nativeUpdate: null`, so a standalone install
(`~/.local/bin/codex` -> `~/.codex/packages/standalone/...`) matched none
of the package-manager heuristics and fell through to the bare-name
fallback in `resolvePackageManagedProviderMaintenance`, which assumes an
unclassified install is npm-managed.
One-click update then ran `npm install -g @openai/codex@latest`, which
updates a different install than the one being probed - creating one
outright when no npm copy existed. The post-update re-probe still read
the untouched standalone binary, still saw `behind_latest`, and recorded
`unchanged`, so the provider reported "still needs an update" on every
attempt.
Declare the native update path the way ClaudeDriver already does for the
identical `~/.local/bin` layout, so these installs are updated with
`codex update`.
Refs pingdotgg#5629
CopilotAI lite review requested due to automatic review settings August 7, 2026 16:50
@coderabbitai

coderabbitaiBot commented Aug 7, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 924ded13-bf31-4174-8cf9-846dd35308ee

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High

isCodexNativeCommandPath classifies a configured binary under /.codex/packages/standalone/ as native, but the nativeUpdate action always runs the bare command codex rather than the configured binaryPath. When the user points binaryPath at the standalone release binary and codex is absent from PATH (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded "codex" executable.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Drivers/CodexDriver.ts around line 84:
`isCodexNativeCommandPath` classifies a configured binary under `/.codex/packages/standalone/` as native, but the `nativeUpdate` action always runs the bare command `codex` rather than the configured `binaryPath`. When the user points `binaryPath` at the standalone release binary and `codex` is absent from `PATH` (or resolves to a different installation), the update fails or updates the wrong installation. The update command should use the configured binary path instead of the hardcoded `"codex"` executable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes an incorrect “Update now” loop for Codex when the CLI was installed via OpenAI’s standalone installer by teaching the server-side Codex driver to recognize that layout as “native-updatable” and to run codex update instead of defaulting to an npm-global update command.

Changes:

  • Add Codex native-update detection (isCodexNativeCommandPath) and wire nativeUpdate to run codex update.
  • Add unit tests for Codex native path matching to ensure package-manager installs remain package-manager-updated.
  • Extend maintenance capability resolution tests to ensure native detection works when only a symlink’s real path matches the native layout.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

FileDescription
apps/server/src/provider/providerMaintenance.test.tsAdds coverage ensuring native-update selection works via realCommandPath when a PATH-resolved symlink points into a native install layout.
apps/server/src/provider/Drivers/CodexExecutable.test.tsNew tests validating Codex standalone/native path matching and negative cases for npm/bun/Homebrew layouts.
apps/server/src/provider/Drivers/CodexDriver.tsImplements Codex native update capability (codex update) and adds a path matcher for standalone installs to avoid falling back to npm-global updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@macroscopeapp

macroscopeappBot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR enables a new update pathway for standalone Codex installs by configuring nativeUpdate (previously null) to run codex update. This introduces new runtime behavior affecting how the software is updated on user systems, which warrants human review for a feature change of this nature.

You can customize Macroscope's approvability policy. Learn more.

`makeNativeProviderMaintenanceCapabilities` took its executable from the
driver definition, so a native update always spawned the bare command
name and let PATH decide which binary it hit. Classification, meanwhile,
was performed on the configured `binaryPath`.
Those two disagree exactly when a provider is pointed at something other
than the first PATH match - the multi-install case this classification
exists to serve. A provider configured with an explicit standalone path
would be offered a one-click update that then self-updated whichever
install happened to be first on PATH, or failed outright when the bare
command was absent.
Pass the resolved command path through as the update executable, falling
back to the definition's bare name when nothing was resolved.
Refs pingdotgg#5629
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Aug 7, 2026
Comment threadapps/server/src/provider/providerMaintenance.ts
`makeProviderMaintenanceCapabilities` joined the executable and its args
with a space to build `command`, the string the UI shows and users copy
as the manual update. Now that native updates carry an absolute
executable path, an install under a directory containing spaces rendered
as a command that splits into the wrong tokens when pasted.
Quote tokens containing whitespace. Execution is unaffected either way -
the runner spawns `executable` with `args` as a list, and shell mode on
Windows already escapes through `escapeWindowsShellArg` - so this is
purely about the copyable string.
Refs pingdotgg#5629
@t3dotgg

Copy link
Copy Markdown
Member

Note

🤖 GPT-5.6 Sol responding on behalf of Theo

We're closing this PR as we clean up the T3 Code backlog. Thank you for taking the time to put this together.

We are keeping the standalone Codex update fix in the open #4065 instead of maintaining two implementations. The symlink detection, resolved binary coverage, and Windows npm-shim case from this PR remain useful input for that review.

If you believe we closed this in error, please reopen the PR and leave a comment explaining what we missed.

@t3dotggt3dotgg closed this Aug 28, 2026
@hkarlsen06
hkarlsen06 deleted the fix/codex-native-update branch September 1, 2026 20:25
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@hkarlsen06@t3dotgg