Skip to content

fix(codex): make plugin install failures triageable and skip unsupported CLIs - #1024

Draft
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-code/codex-plugin-install-diagnostics
Draft

fix(codex): make plugin install failures triageable and skip unsupported CLIs#1024
posthog[bot] wants to merge 1 commit into
mainfrom
posthog-code/codex-plugin-install-diagnostics

Conversation

@posthog

@posthog posthog Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Problem

CodexMCPClient.installPlugin() captured its exception from result.stderr alone. spawnSync reports failure three different ways — a spawn-level error, a non-zero status, or a terminating signal — and Codex sometimes writes the reason to stdout instead. Every one of those arrived in error tracking as a bare Codex plugin install failed: with nothing after it, so the dominant failure mode was untriageable.

Two real bugs were hiding behind that noise:

  • supportsPlugin() only checked command -v codex, so users on a Codex CLI predating plugin marketplace were offered a plugin install that cannot work — it fails with unexpected argument 'marketplace' found and was reported as a crash. They finish the wizard but silently never get the PostHog plugin.
  • The stale-cache retry hardcoded ~/.codex, but Codex resolves its state directory from CODEX_HOME. For anyone with a custom Codex home it deleted the wrong directory and re-failed. isPluginInstalled() had the same blind spot.

Changes

All in codex.ts:

  • Fold error, status, signal, stderr and stdout into the captured message, with a placeholder so the tail is never empty.
  • Skip the capture entirely for failures that aren't wizard bugs: an out-of-date CLI, a user interrupt (Ctrl-C during the marketplace clone), and transient network/TLS errors while Codex clones the repo.
  • Probe codex --help for a plugin subcommand in supportsPlugin(), cached per client. Note that probing codex plugin --help does not work: clap short-circuits on --help, so an older CLI prints top-level help and exits 0. The command list is the reliable signal.
  • Resolve the state directory from CODEX_HOME ?? ~/.codex in both isPluginInstalled() and the stale-cache retry.

Test plan

Unit tests: 30 pass in codex.test.ts (11 new, covering each blank-message path, the non-actionable skips, the --help probe, and CODEX_HOME). typecheck shows the same 36 pre-existing errors as a clean tree, none in codex.ts; eslint clean. Full suite matches baseline exactly (87 failed files / 29 failed tests before and after — pre-existing, build artifacts absent in the sandbox).

Verified against real Codex binaries rather than only mocks, driving the actual module:

  • Reproduced all four blank-tail paths against real spawnSync: spawn ENOENT, EACCES, SIGINT, and error-on-stdout each produced exactly Codex plugin install failed: before the change.
  • Installed @openai/codex@0.81.0 (old) and @openai/codex@0.146.0 (current). Old CLI: codex --help lists no plugin command and plugin marketplace add exits 2 with unexpected argument 'marketplace'supportsPlugin() now returns false and installPlugin() captures nothing. Current CLI: plugin is listed → supportsPlugin() returns true.
  • Confirmed Codex genuinely honours CODEX_HOME, and that a real plugin marketplace add writes [marketplaces.posthog] to $CODEX_HOME/config.toml and the cache to $CODEX_HOME/.tmp/marketplaces/posthog — the two paths this PR now resolves correctly.

LLM context

Authored by Claude Code from a PostHog error-tracking inbox report. One correction to the report's framing worth recording: it stated 415 of 545 occurrences carry an empty message. Querying the class directly, truly blank is 161/545 (137 users). The next-largest bucket, 178 occurrences, is the Codex npm wrapper crashing when its vendored binary is missing — those do carry stderr text. The --help probe incidentally silences those too, since a broken wrapper fails --help as well.


Created with PostHog Desktop from this inbox report.

…ted CLIs

`CodexMCPClient.installPlugin()` built its captured exception from `result.stderr`
alone. `spawnSync` reports failure three different ways — a spawn-level `error`,
a non-zero `status`, or a terminating `signal` — and Codex sometimes writes the
reason to stdout, so all of those surfaced as a bare `Codex plugin install
failed: ` with nothing after it.

- Fold `error`, `status`, `signal`, stderr and stdout into the captured message,
  with a placeholder so the tail is never empty.
- Skip the capture for failures that are not wizard bugs: an out-of-date Codex
  CLI, a user interrupt (Ctrl-C during the marketplace clone), and transient
  network/TLS errors while Codex clones the repo.
- Probe `codex --help` for a `plugin` subcommand in `supportsPlugin()` so users
  on an older CLI are not offered a plugin install that cannot work. Probing
  `codex plugin --help` does not work — clap short-circuits on `--help` and an
  older CLI prints top-level help with exit 0.
- Resolve the Codex state directory from `CODEX_HOME` (falling back to
  `~/.codex`) in both `isPluginInstalled()` and the stale-cache retry, which
  previously hardcoded `~/.codex` and so cleared the wrong directory.

cwd: /tmp/workspace/repos/posthog/wizard

Generated-By: PostHog Code
Task-Id: b5afd218-55b9-42a7-aac4-bb22b666082d
@github-actions

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci basic-integration
  • /wizard-ci mcp-analytics
  • /wizard-ci revenue
  • /wizard-ci self-driving

Test an individual app:

  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
Show more apps
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit

Results will be posted here when complete.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants