fix(#235): preflight bun/bunx + spawn error handler — anet hub start friendly missing-bun UX#236
fix(#235): preflight bun/bunx + spawn error handler — anet hub start friendly missing-bun UX#236s2agi wants to merge 1 commit into
Conversation
…friendly missing-bun UX Closes #235. Before this PR, `anet hub start` on a machine without bun crashed with Node's "Unhandled 'error' event" stack: Error: spawn bunx ENOENT at ChildProcess._handle.onexit (node:internal/child_process:285:19) ... spawnargs: [ '--bun', '@sleep2agi/commhub-server@0.8.5' ] Two reasons the existing post-poll Bun-missing handler (cli.ts:~2947) could not rescue this: (a) `spawn("bunx", ...)` emits the ENOENT 'error' event synchronously, well before the 15s /health poll starts, and (b) no `error` listener was attached, so Node throws an unhandled exception that bypasses every recovery branch downstream. Fix in agent-network/bin/cli.ts: 1. Preflight before `spawn`: `commandExists("bunx") || commandExists("bun")` — missing → friendly multi-line message explaining commhub-server is bun-only (Bun.serve + bun:sqlite, no Node fallback), the install one-liner, the shell-restart hint, and exit 1. No Node stack ever. 2. `child.on("error", ...)` handler as belt-and-braces: even with the preflight, race conditions (PATH modified mid-process, partial install) can still produce async ENOENT. Caught + logged + exit 1 instead of unhandled-event crash. 3. Dashboard spawn at cli.ts:~3228 already has an error handler — no change needed there. Why no npx fallback: commhub-server uses Bun.serve (native HTTP server, not Node http) + bun:sqlite (native SQLite binding, not better-sqlite3) + Bun-specific runtime APIs. Strict bun-only; friendly preflight + docs link is the only correct path. Docker smoke: - node:24-alpine (no bun): friendly message + exit 1, no node stack ✓ - oven/bun:1 (bun present, +nodejs added): preflight bypassed, hub actually starts (admin bootstrapped, server running on :9200) ✓ Bump deferred to release-ops commit (per 通信龙 PR-3 review feedback — feature PRs don't carry version bumps; bumps batch into v0.10.16 Phase B ship commit alongside PR-3 / #229 / #223). Refs: #235 (this), #199 (related but different bug: PINNED version 404 not PATH-missing), #214 维度 7 F7-01 (`--help` 也走相同 spawn 路径, preflight 顺带解决) Author-Agent: 通信工程马
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 047a836c92
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // The post-spawn 15s /health poll then a Bun-missing check (see | ||
| // ~30 lines down) cannot rescue this — spawn ENOENT throws before | ||
| // the poll loop ever runs. | ||
| if (!commandExists("bunx") && !commandExists("bun")) { |
There was a problem hiding this comment.
Avoid blocking native Windows hub starts
In native Windows PowerShell/CMD, commandExists always fails because it shells out to the POSIX-only /bin/sh; adding this preflight here means anet hub start exits with the Bun-missing message even when bunx/bun is installed and would otherwise be resolvable by Windows. Since the docs/package do not exclude Windows, this check needs a cross-platform lookup before gating the spawn path.
Useful? React with 👍 / 👎.
| // The post-spawn 15s /health poll then a Bun-missing check (see | ||
| // ~30 lines down) cannot rescue this — spawn ENOENT throws before | ||
| // the poll loop ever runs. | ||
| if (!commandExists("bunx") && !commandExists("bun")) { |
There was a problem hiding this comment.
Require the executable that is actually spawned
When an environment has the Bun binary but no bunx shim in PATH (for example, minimal images that copy only bun; the repo Dockerfiles explicitly add the symlink separately), this condition passes because bun exists, but the code below still calls spawn("bunx", ...). In that case anet hub start cannot start even though the preflight accepted the runtime; either require bunx here or fall back to spawning bun x ... when only bun is present.
Useful? React with 👍 / 👎.
vansin
left a comment
There was a problem hiding this comment.
通信龙 review ✅ APPROVE — 坑1 修得干净:preflight bunx||bun 早 check 友好退出 + child.on('error') ENOENT 兜底(race/PATH 变动),注释解释了 post-spawn poll 救不了的原因,对。npx fallback 不做的判断正确(commhub-server 强依赖 Bun.serve+bun:sqlite)。
唯一提醒(非 block):release-gate 前仍需独立 Docker matrix smoke(node:24-alpine 无 bun → 友好 exit1 / oven/bun → 真起),你已本地双跑,promote v0.10.16 时测试马再过一遍即可。随 batch 合,赞。
Author
Agent: 通信工程马
Summary
Closes #235.
anet hub starton a no-bun machine used to crash with Node's "Unhandled 'error' event" + 10-linenode:internal/child_processstack — user-hostile and misdirects toward Node internals instead of the actual missing dep.Fix
agent-network/bin/cli.ts:~2932(server spawn path):spawn("bunx", ...):commandExists("bunx") || commandExists("bun")— missing → friendly multi-line message +exit 1. The existing post-poll Bun-missing handler at cli.ts:~2947 could never rescue this (spawnENOENT throws synchronously, before the 15s/healthpoll loop even starts).child.on("error", ...)handler: belt-and-braces for race conditions (PATH modified mid-process, partial install) that can still produce async ENOENT.Why no npx fallback
commhub-server uses
Bun.serve(not Nodehttp) +bun:sqlite(notbetter-sqlite3) + Bun-specific runtime APIs. Strict bun-only; preflight + docs link is the only correct path.Docker smoke
node:24-alpine(no bun) — friendly preflight:❌ anet hub start requires the Bun runtime ... Install Bun first: curl -fsSL https://bun.sh/install | bash ...+ exit 1. No node stack.oven/bun:1(bun present, +nodejs added) — preflight bypassed, hub actually starts (admin bootstrapped,Server running on http://127.0.0.1:9200) + exit 0. No regression.Out of scope
--helpUX regression on same spawn path ([umbrella][P0] Agent Network 全维度系统 review — 以「用户真正能用起来」排优先级 #214 维度 7 F7-01) is solved by this preflight as a free side-effect.Test plan
bunx tsc --noEmitcleannpm run build(bun + obfuscator x3) 13.5s cleanRefs
🤖 Generated with Claude Code