alibaba / alibaba/open-code-review
ocr command becomes unavailable during npm auto-upgrade (binary gap window + Windows file lock)
- Dominant language
- Go
- Stars
- 24.4k
- Forks
- 1.8k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 105
Description
### OpenCodeReview Version
`v1.8.5` (reproduced on current main, commit `3b9c5e7`)
### Operating System
- macOS (Apple Silicon)
- Windows
- Linux (x86_64)
(All three platforms are affected; Windows is the worst case.)
### Installation Method
npm (global)
### LLM Provider
Other OpenAI-compatible endpoint
### Bug Description
When `ocr` is installed globally via npm, the `ocr` command becomes unavailable while the background auto-upgrade runs (`scripts/update.js` executing `npm i -g`), failing with:
```
[ERROR] OpenCodeReview binary not found. Run: npm install -g @alibaba-group/open-code-review
```
The root cause is that the auto-upgrade uses a "delete-then-install" approach, leaving a window where the native binary is missing on disk. Any `ocr` invocation during that window fails because `resolveNativeBinary()` returns `null`.
Upgrade flow (`bin/ocr.js` + `scripts/update.js`):
1. `bin/ocr.js:43-51` — on every `ocr` run, `scripts/update.js` is spawned as a detached background process.
2. `scripts/update.js:164` — when a newer version is found, it runs `spawnSync("npm", ["i", "-g", `${pkgName}@${latestVersion}`])` to reinstall globally.
3. npm reinstalls by first removing the old platform package `@alibaba-group/ocr-` (which contains `bin/opencodereview`), then downloading and installing the new one.
4. During the "remove old → install new" gap in step 3, `resolveNativeBinary()` in `scripts/platform.js:36` finds neither the platform-package binary nor the legacy `bin/opencodereview` path, and returns `null`.
5. This hits the `if (!resolved)` branch at `bin/ocr.js:12-17`, which prints the error and `exit(1)`.
The window length depends on network download speed (the platform package ships a multi-MB binary), and can last from a few seconds to tens of seconds.
**Additional Windows-only problem**: `ocr.js:54` immediately `spawnSync`s the native binary right after spawning the detached upgrader. This means `opencodereview.exe` is still running when the background `npm i -g` tries to delete/replace it. Windows refuses to remove a running `.exe` (EBUSY/EPERM), so the upgrade fails and can leave the install in a broken "old binary deleted, new binary not yet written" state, making `ocr` **permanently unavailable** until a manual `npm i -g` repairs it.
### Steps to Reproduce
```console
# 1. Install an older version globally
$ npm i -g @alibaba-group/open-code-review@
# 2. Wait for / trigger the background upgrade (run any ocr command, 18-min cooldown elapsed)
$ ocr version
# 3. While the background npm i -g is still running, keep invoking ocr
# (during the gap between old binary removal and new binary install)
$ ocr version
[ERROR] OpenCodeReview binary not found. Run: npm install -g @alibaba-group/open-code-review
```
On Windows it's easiest to reproduce: keep an `ocr review` running for a while (binary in execution) while the background upgrade triggers — `npm i -g` then fails because the file is locked.
### Expected Behavior
Auto-upgrade should never make `ocr` unavailable at any point in time. The upgrade should be transparent to the user — either keep the old binary until the new one is verified ready (atomic replace / install-then-remove), or on Windows detect that the binary is in use and wait for the foreground process to exit before replacing, rather than failing outright and leaving a broken install behind.
### Logs / Error Output
```shell
$ ocr version
[ERROR] OpenCodeReview binary not found. Run: npm install -g @alibaba-group/open-code-review
```
On Windows, when `npm i -g` fails it also writes the `~/.opencodereview/update-available` hint (`scripts/update.js:173`), causing every subsequent `ocr` run to print the upgrade nudge (compounds with #697).
### Additional Context
Relevant code locations:
- `bin/ocr.js:43-51` — detached background spawn of `update.js`
- `bin/ocr.js:12-17` — hard-fail branch when binary is not found
- `bin/ocr.js:54` — concurrent background upgrade and foreground binary execution
- `scripts/update.js:164` — `npm i -g` global reinstall (non-atomic delete-then-install)
- `scripts/platform.js:36-58` — `resolveNativeBinary()` lookup logic
Related issue: #697 (upgrade nudge shown even when already on the latest version) — this compounds with the present bug.
Possible fix directions:
1. Have the background upgrade download to a temporary location first and do an atomic `rename(2)` swap after checksum verification, eliminating the delete-then-install gap.
2. On Windows, detect that the binary is in use and wait for the foreground process to exit before replacing (or use a post-restart self-replacement / launcher strategy).
3. During the gap window, when `resolveNativeBinary()` can't find the binary, fall back to a cached copy of the last binary (e.g. kept under `~/.opencodereview/`) instead of hard-failing.
Contributor guide
Assessment
This issue has not been assessed yet.