Summary
/sync-gbrain crashes fatally on the first run with:
gstack-gbrain-sync fatal: list.find is not a function. (In 'list.find((s) => s.id === sourceId)', 'list.find' is undefined)
The orchestrator never reaches any stage (code/memory/brain-sync) — it dies during planning.
Environment
- gstack: 1.40.0.0
- gbrain: 0.35.4.0 (engine: pglite, local-stdio)
- macOS (darwin arm64), bun 1.3.11
- Repo: a normal local git repo, freshly
git init'd, source not yet registered
Root cause
bin/gstack-gbrain-sync.ts → sourceLocalPath() (around line 292) calls
gbrain sources list --json and types/treats the result as a bare array:
const list = execGbrainJson<Array<{ id: string; local_path?: string }>>(
["sources", "list", "--json"],
{ baseEnv: env },
);
if (!list) return null;
const found = list.find((s) => s.id === sourceId); // ← list is not an array
But gbrain >= 0.19 wraps the listing in an object:
{ "sources": [ { "id": "default", "local_path": null, "page_count": 99, ... } ] }
So list.find is undefined → fatal. gstack pins gbrain 0.18.2
(bin/gstack-gbrain-install PINNED_COMMIT), so this only bites users who run
a newer gbrain — which is increasingly common since gbrain's own update path
moves ahead of the gstack pin.
Repro
- Run any gbrain >= 0.19 (
gbrain --version).
- In a git repo whose code source is not yet registered, run
/sync-gbrain
(or bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts).
- Fatal:
list.find is not a function.
Fix (verified locally)
Accept both the legacy array and the new { sources: [...] } shape:
const raw = execGbrainJson<
| Array<{ id: string; local_path?: string }>
| { sources?: Array<{ id: string; local_path?: string }> }
>(["sources", "list", "--json"], { baseEnv: env });
if (!raw) return null;
// gbrain <=0.18 returned a bare array; >=0.19 wraps it as { sources: [...] }.
const list = Array.isArray(raw) ? raw : (raw.sources ?? []);
const found = list.find((s) => s.id === sourceId);
return found?.local_path ?? null;
After this patch, /sync-gbrain runs 3/3 stages OK against gbrain 0.35.4.0
(code source registered + synced, memory import, brain-sync push).
sourceLocalPath() is the only execGbrainJson consumer in the file; other
gbrain interactions use spawnGbrain (exit-code based) and are unaffected.
Note /sync-gbrain SKILL.md Step 3 already does ... | jq '.sources[]',
so the wrapped shape is the expected one — only this helper was missed.
🤖 Generated with Claude Code
Summary
/sync-gbraincrashes fatally on the first run with:The orchestrator never reaches any stage (code/memory/brain-sync) — it dies during planning.
Environment
git init'd, source not yet registeredRoot cause
bin/gstack-gbrain-sync.ts→sourceLocalPath()(around line 292) callsgbrain sources list --jsonand types/treats the result as a bare array:But gbrain >= 0.19 wraps the listing in an object:
{ "sources": [ { "id": "default", "local_path": null, "page_count": 99, ... } ] }So
list.findisundefined→ fatal. gstack pins gbrain 0.18.2(
bin/gstack-gbrain-installPINNED_COMMIT), so this only bites users who runa newer gbrain — which is increasingly common since gbrain's own update path
moves ahead of the gstack pin.
Repro
gbrain --version)./sync-gbrain(or
bun run ~/.claude/skills/gstack/bin/gstack-gbrain-sync.ts).list.find is not a function.Fix (verified locally)
Accept both the legacy array and the new
{ sources: [...] }shape:After this patch,
/sync-gbrainruns 3/3 stages OK against gbrain 0.35.4.0(code source registered + synced, memory import, brain-sync push).
sourceLocalPath()is the onlyexecGbrainJsonconsumer in the file; othergbrain interactions use
spawnGbrain(exit-code based) and are unaffected.Note
/sync-gbrainSKILL.md Step 3 already does... | jq '.sources[]',so the wrapped shape is the expected one — only this helper was missed.
🤖 Generated with Claude Code