fix(embed): use Array.isArray guard for agent data in OpenCode embed#482
Conversation
The OpenCode embed (built from anomalyco/opencode@114eb4244, v1.2.15) crashes with `TypeError: .filter is not a function` when the running OpenCode binary (v1.3.0) restarts. Root cause: when the server instance is disposed, the embed re-bootstraps and calls GET /agent. If the server responds with an empty body during startup, the SDK client returns {data: {}} (empty object). The upstream code guards with `x.data ?? []`, but nullish coalescing only catches null/undefined — an empty object `{}` is truthy and passes through. Calling `.filter()` on `{}` throws because objects lack Array methods. Fix: patch the embed build to use `Array.isArray()` guards instead of `??` in two locations: - local.tsx: `(Array.isArray(sync.data.agent) ? sync.data.agent : []).filter(...)` - bootstrap.ts: `setStore("agent", Array.isArray(x.data) ? x.data : [])` Patches are applied by `scripts/build-opencode-embed.sh` step 2b after git checkout but before the Vite build, using portable perl -pi -e so they survive rebuilds and work on both macOS and Linux CI.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThe build script now injects two in-place compatibility patches into the vendored OpenCode embed source before dependency install/build, adding Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
scripts/build-opencode-embed.sh (1)
114-125: Consider verifying that patches were actually applied.The perl substitutions silently succeed even if zero matches are found. If upstream refactors these lines (e.g., renames
sync.data.agentor changes thesetStorecall signature), the patches won't match and the build will proceed without the fix—causing the original crash to resurface at runtime.🛡️ Suggested patch verification
perl -pi -e \ 's/sync\.data\.agent\.filter\(/(Array.isArray(sync.data.agent) ? sync.data.agent : []).filter(/g' \ "${LOCAL_TSX}" -echo "[opencode-embed] Patched local.tsx: Array.isArray guard on agent filter" +if grep -q 'Array\.isArray(sync\.data\.agent)' "${LOCAL_TSX}"; then + echo "[opencode-embed] Patched local.tsx: Array.isArray guard on agent filter" +else + echo "[opencode-embed] ERROR: local.tsx patch did not apply — upstream may have changed." + exit 1 +fi perl -pi -e \ 's/input\.setStore\("agent",\s*x\.data\s*\?\?\s*\[\]\)/input.setStore("agent", Array.isArray(x.data) ? x.data : [])/g' \ "${BOOTSTRAP_TS}" -echo "[opencode-embed] Patched bootstrap.ts: Array.isArray guard on agent store" +if grep -q 'Array\.isArray(x\.data)' "${BOOTSTRAP_TS}"; then + echo "[opencode-embed] Patched bootstrap.ts: Array.isArray guard on agent store" +else + echo "[opencode-embed] ERROR: bootstrap.ts patch did not apply — upstream may have changed." + exit 1 +fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@scripts/build-opencode-embed.sh` around lines 114 - 125, The current perl substitutions for the patterns containing "sync.data.agent.filter" and 'input.setStore("agent", x.data ?? [])' may be no-ops if upstream changed those lines; after each patch command (targeting sync.data.agent.filter and input.setStore("agent", x.data ?? [])), add a verification step that checks the file for the new guarded form (Array.isArray(...)) and fail the script if the expected replacement wasn't applied so the CI/build stops (e.g., grep for "Array.isArray(sync.data.agent" and 'input.setStore("agent", Array.isArray(x.data)' or count replacements and exit non-zero when zero), ensuring you reference the exact symbols "sync.data.agent.filter" and 'input.setStore("agent", x.data ?? [])' to locate the original lines and the guarded forms to verify.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@scripts/build-opencode-embed.sh`:
- Around line 114-125: The current perl substitutions for the patterns
containing "sync.data.agent.filter" and 'input.setStore("agent", x.data ?? [])'
may be no-ops if upstream changed those lines; after each patch command
(targeting sync.data.agent.filter and input.setStore("agent", x.data ?? [])),
add a verification step that checks the file for the new guarded form
(Array.isArray(...)) and fail the script if the expected replacement wasn't
applied so the CI/build stops (e.g., grep for "Array.isArray(sync.data.agent"
and 'input.setStore("agent", Array.isArray(x.data)' or count replacements and
exit non-zero when zero), ensuring you reference the exact symbols
"sync.data.agent.filter" and 'input.setStore("agent", x.data ?? [])' to locate
the original lines and the guarded forms to verify.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: acf2a670-5b40-4698-9dd5-c95a711dd2f7
📒 Files selected for processing (1)
scripts/build-opencode-embed.sh
Address CodeRabbit review: perl substitutions silently succeed on zero matches. Add grep verification after each patch to fail the build early if upstream refactors the target lines.
Summary
TypeError: .filter is not a functiononsync.data.agentUnexpected token '<', "<!DOCTYPE"... is not valid JSONwhen fetchingmanifest.jsonRoot Cause
The embed is built from
anomalyco/opencode@114eb4244(OpenCode v1.2.15) but Spacebot runs against the installed OpenCode binary (tested with v1.2.20 and v1.3.0).When the OpenCode server restarts (triggering a
server.instance.disposedSSE event), the embed re-bootstraps and callsGET /agent. If the server responds with an empty body during startup, the SDK client (client.gen.ts) returns{data: {}}(empty object):The upstream code guards with
x.data ?? [](nullish coalescing), but??only catchesnull/undefined. An empty object{}is truthy and passes through. Calling.filter()on{}throws because plain objects lack Array methods.Fix
Patches the embed build script (
scripts/build-opencode-embed.shstep 2b) to applyArray.isArray()guards instead of??in two locations after git checkout but before the Vite build:local.tsxsync.data.agent.filter(...)(Array.isArray(sync.data.agent) ? sync.data.agent : []).filter(...)bootstrap.tssetStore("agent", x.data ?? [])setStore("agent", Array.isArray(x.data) ? x.data : [])Patches use
perl -pi -efor macOS + Linux portability and are idempotent (safe to re-run).OpenCode Versions Tested
anomalyco/opencode@114eb4244(v1.2.15-based)Both versions return a valid JSON array from
GET /agent, but during server restarts the response may be empty, triggering the SDK's{}fallback.Test plan
just preflightpassesjust gate-prpasses (697 tests, all green)manifest.jsonserves correctly, embed loadsArray.isArrayguard in built bundle via grep