[Bug]: doctor reports "Everything looks good!" while the loaded extension is months behind the CLI
- Dominant language
- JavaScript
- Stars
- 29.3k
- Forks
- 2.9k
- Avg merge
- 15h 36m
- Merged PRs (30d)
- 70
Description
### Description
`opencli doctor` reports a fully green bridge while the loaded extension is months behind the CLI. Version compatibility is only ever checked in one direction — "does the CLI satisfy what the extension asks for" — and nothing checks whether the extension is new enough for the CLI.
`src/doctor.ts:186-205`:
```js
const extensionCompatRange = health.status?.extensionCompatRange;
if (extensionVersion && opts.cliVersion && extensionCompatRange) {
if (!satisfiesRange(opts.cliVersion, extensionCompatRange)) { /* issue */ }
} else if (extensionVersion && opts.cliVersion) {
// Fallback for older extensions that don't send compatRange
const extMajor = extensionVersion.split('.')[0];
const cliMajor = opts.cliVersion.split('.')[0];
if (extMajor !== cliMajor) { /* issue */ }
}
```
Both branches are structurally unable to flag a stale extension:
1. **Primary branch.** The extension declares `compatRange: ">=1.7.0"`. I extracted this from `dist/background.js` of both **v1.0.21 and v1.0.23** — the value is byte-identical. It is a floor on the *CLI* version and does not move when the extension is upgraded, so every CLI from 1.7.0 onward satisfies every recent extension. An extension from June passes on an August CLI.
2. **Fallback branch.** Extension versions are `1.0.x` and CLI versions are `1.8.x`, so `extMajor` is `"1"` and `cliMajor` is `"1"` — always equal. The comparison can never fire for any real version pair.
There is also no CLI-side floor to compare against: `grep -rn 'MIN_EXTENSION\|minExtensionVersion\|requiredExtensionVersion' src/` returns nothing. The CLI never states which extension version it needs.
The one mechanism that *would* have surfaced this — the "Extension update available" issue at `src/doctor.ts:209` — depends on `latestExtensionVersion`, which is separately broken by the cache bug in #2414. With both defects present there is no path by which any command reports a stale extension.
### Steps to Reproduce
1. Load the extension in Chrome via "Load unpacked" from a directory, e.g. `~/Applications/opencli/extension`.
2. Let the CLI self-update (which writes a newer extension to `~/.opencli/extension/opencli-extension`) while the Chrome-loaded directory stays at the older version. Chrome pins the path it was given, so it keeps serving the old build.
3. Run `opencli doctor`.
Observed on my machine with the loaded extension at **v1.0.21 (released 2026-06-28)** and CLI at **v1.8.7**:
```
[OK] Daemon: running on port 19825 (v1.8.7)
[OK] Extension: connected (v1.0.21)
[OK] Connectivity: connected in 0.0s
Everything looks good!
```
Meanwhile `~/.opencli/extension/opencli-extension/manifest.json` said `1.0.23`, and the two `dist/background.js` files had different checksums:
```
9312f894... ~/Applications/opencli/extension/dist/background.js (v1.0.21, loaded by Chrome)
2d48ea5a... ~/.opencli/extension/opencli-extension/dist/background.js (v1.0.23, written by self-update)
```
`doctor` prints the connected version `(v1.0.21)`, so the information needed to detect the problem is already in the report — it just is not compared against anything.
### Expected Behavior
`doctor` should flag a stale extension rather than reporting "Everything looks good!". Options, roughly in increasing order of invasiveness:
1. **CLI-side floor.** Have the CLI declare a minimum extension version (analogous to the extension's `compatRange`) and warn when the connected extension is below it. This is the symmetric counterpart of the existing check and catches genuine incompatibility rather than mere staleness.
2. **Compare against the bundled/downloaded extension.** The CLI already knows what it shipped or fetched into `~/.opencli/extension/opencli-extension`. Comparing the connected version against that local manifest needs no network and would have caught this exact case.
3. **Fix the fallback.** The `extMajor !== cliMajor` comparison compares two independently versioned artifacts and is dead code as written; it should either be removed or replaced with something meaningful.
I have deliberately not opened a PR for this one, since picking between these is a maintainer call about which artifact owns the compatibility contract. Happy to implement whichever direction you prefer.
A related diagnostic gap, if useful: because Chrome pins the unpacked directory path, a mismatch can persist even after the CLI updates itself. `doctor` could compare the connected extension version against the local extension checkout and, when they differ, point at the specific directory Chrome has loaded. Locating that path currently requires reading Chrome's own preferences:
```bash
python3 -c "
import json,os
p=os.path.expanduser('~/Library/Application Support/Google/Chrome/Default/Secure Preferences')
for k,v in (json.load(open(p))['extensions']['settings']).items():
if v.get('location')==4: print(v.get('manifest',{}).get('version'), v.get('path'))
"
```
### Impact
Silent and long-lived. On my machine the mismatch went unnoticed for roughly two months across daily use, with `doctor` green the whole time. The practical consequence is that bridge failures get misattributed: adapter commands intermittently fail against an old extension while the one diagnostic built to explain that says everything is fine, so debugging effort goes to the adapter, the daemon, or the site instead of the version skew.
This is also adjacent to two earlier attempts that were closed by their own authors without landing — #1914 (surface cached extension version when disconnected) and #2181 (point remediation at the local extension checkout) — so the gap has been noticed before but never fixed.
### Environment
- OpenCLI: 1.8.7 (source verified at `90d5070`)
- Extension: v1.0.21 loaded in Chrome vs v1.0.23 on disk at time of discovery; now both 1.0.23
- Chrome: 151.0.7922.174, extension loaded unpacked (`location: 4`)
- OS: macOS 26.5 (Darwin 25.5.0, arm64)
Contributor guide
Research direction
Start in src/doctor.ts:186-209 and trace the existing extension compatibility and update-availability checks, then inspect the local extension manifest under ~/.opencli/extension/opencli-extension. Confirm the reproduced mismatch between the connected extension version and the CLI’s known extension information. Done means doctor reliably flags a stale or incompatible extension instead of reporting everything is good.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100