From 6209163900beb7497391f8dfc35e2c7d362f23b8 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 24 Apr 2026 07:51:46 -0700 Subject: [PATCH] v1.12.2.0 fix: /setup-gbrain day-two fixes (MCP scope, version parse, gh repo create order, smoke test) (#1187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: parse gbrain --version without "gbrain" prefix Installer's D19 PATH-shadow check compared `expected_version` from package.json against `actual_version` from `gbrain --version`. The output is "gbrain 0.18.2" with a literal prefix; `tr -d '[:space:]'` left "gbrain0.18.2" which never matched "0.18.2", causing every fresh install to exit 3 with a false-positive shadowing error. Use `awk '{print $NF}'` to grab just the last whitespace-separated token before stripping whitespace. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(brain-init): drop --source flag before git init gstack-brain-init used `gh repo create --source $GSTACK_HOME` before running `git init` on that directory. gh requires --source to point at an existing git repo, so the call fails with "not a git repository" on first run. The fallback path (gh repo view) could only recover if the repo was somehow pre-created — which it wasn't. Fix: omit --source from `gh repo create`. The script's later steps (git init, remote add, push) wire up the remote explicitly. Co-Authored-By: Claude Opus 4.7 (1M context) * fix(setup-gbrain): smoke test command + MCP user scope with absolute path Three Step 5a/9 defects found running /setup-gbrain end-to-end: 1. Step 9 smoke test used `gbrain put_page --title ... --tags ...`, which doesn't exist. The real command is `gbrain put ` with body piped on stdin. Updated to match. 2. Step 5a registered MCP with `claude mcp add gbrain -- gbrain serve`. Default scope is local (per-workspace), so other projects never saw gbrain. Cross-session memory is the whole point — user scope is correct. 3. Step 5a passed `gbrain` by bare name, relying on PATH being resolved when Claude Code spawns the subprocess. Fragile across shell configs. Use absolute path from `command -v gbrain` with ~/.bun/bin/gbrain fallback. Also: remove any stale local-scope registration before re-adding, and tell the user that open Claude Code sessions need a restart to see the new mcp__gbrain__* tools (loaded at session start, not mid-session). Co-Authored-By: Claude Opus 4.7 (1M context) * chore: bump version and changelog (v1.12.1.0) Also updates test/gstack-brain-init-gh-mock.test.ts to match the fixed behavior of bin/gstack-brain-init (the assertion previously required `--source`, which was the bug being fixed in 04185d8f). Co-Authored-By: Claude Opus 4.7 (1M context) * docs: tighten CHANGELOG entry for v1.12.1.0 Shorter, matter-of-fact list of the fixes. No preamble. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 15 ++++++++++++++ VERSION | 2 +- bin/gstack-brain-init | 5 ++++- bin/gstack-gbrain-install | 2 +- package.json | 2 +- setup-gbrain/SKILL.md | 28 ++++++++++++++++++++------ setup-gbrain/SKILL.md.tmpl | 28 ++++++++++++++++++++------ test/gstack-brain-init-gh-mock.test.ts | 6 ++++-- 8 files changed, 70 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8fda72d1..d7ec612c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [1.12.2.0] - 2026-04-24 + +## **`/setup-gbrain` polish: PATH parsing, repo init order, MCP user scope.** + +Small refinements to the /setup-gbrain onboarding path. + +### Fixed +- `bin/gstack-gbrain-install`: parse `gbrain --version` output with `awk '{print $NF}'` so the D19 PATH-shadow check compares just the version number. +- `bin/gstack-brain-init`: omit `--source` from `gh repo create`. Later steps handle `git init` + remote setup explicitly. +- `setup-gbrain` Step 9: smoke test uses `gbrain put ` with body piped on stdin. +- `setup-gbrain` Step 5a: MCP registers with `--scope user` and an absolute path to the gbrain binary, so `mcp__gbrain__*` tools are available in every Claude Code session on the machine. + +### Changed +- `test/gstack-brain-init-gh-mock.test.ts`: asserts `--source` is absent from the `gh repo create` call. + ## [1.12.1.0] - 2026-04-24 ## **Plan-mode review skills run the review directly, no more "exit and rerun" prompt.** diff --git a/VERSION b/VERSION index 2255ba16..b3dd6a99 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.1.0 +1.12.2.0 diff --git a/bin/gstack-brain-init b/bin/gstack-brain-init index 6399c12c..3ed48559 100755 --- a/bin/gstack-brain-init +++ b/bin/gstack-brain-init @@ -86,7 +86,10 @@ if [ -z "$REMOTE_URL" ]; then read -r REPLY || REPLY="" if [ -z "$REPLY" ]; then echo "Creating GitHub repo: $DEFAULT_NAME ..." - if ! gh repo create "$DEFAULT_NAME" --private --description "gstack session memory" --source "$GSTACK_HOME" 2>/dev/null; then + # Note: --source omitted intentionally. gh requires --source to point at + # an existing git repo, but we don't init $GSTACK_HOME until after the + # remote is chosen. Create bare, then fetch URL. + if ! gh repo create "$DEFAULT_NAME" --private --description "gstack session memory" 2>/dev/null; then # Maybe the repo already exists; try to fetch its URL. REMOTE_URL=$(gh repo view "$DEFAULT_NAME" --json sshUrl -q .sshUrl 2>/dev/null || echo "") if [ -z "$REMOTE_URL" ]; then diff --git a/bin/gstack-gbrain-install b/bin/gstack-gbrain-install index c5bfa991..c247ff2d 100755 --- a/bin/gstack-gbrain-install +++ b/bin/gstack-gbrain-install @@ -151,7 +151,7 @@ if ! command -v gbrain >/dev/null 2>&1; then fail "bun link completed but 'gbrain' is not on PATH. Ensure ~/.bun/bin is in your PATH." fi -actual_version=$(gbrain --version 2>/dev/null | head -1 | tr -d '[:space:]' || true) +actual_version=$(gbrain --version 2>/dev/null | head -1 | awk '{print $NF}' | tr -d '[:space:]' || true) if [ -z "$actual_version" ]; then fail "gbrain is on PATH but 'gbrain --version' produced no output — the binary may be broken." fi diff --git a/package.json b/package.json index 3f6a0e00..89af11ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.12.1.0", + "version": "1.12.2.0", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/setup-gbrain/SKILL.md b/setup-gbrain/SKILL.md index 9db96bd4..639ab11b 100644 --- a/setup-gbrain/SKILL.md +++ b/setup-gbrain/SKILL.md @@ -1283,17 +1283,33 @@ doctor output and STOP. Only if `which claude` resolves. Ask: "Give Claude Code a typed tool surface for gbrain? (recommended yes)" -If yes: +If yes, register at **user scope** with an **absolute path** to the gbrain +binary. User scope makes the MCP available in every Claude Code session on +this machine, not just the current workspace. Absolute path avoids PATH +resolution issues when Claude Code spawns `gbrain serve` as a subprocess. ```bash -claude mcp add gbrain -- gbrain serve -claude mcp list | grep gbrain # verify +GBRAIN_BIN=$(command -v gbrain) +[ -z "$GBRAIN_BIN" ] && GBRAIN_BIN="$HOME/.bun/bin/gbrain" +claude mcp add --scope user gbrain -- "$GBRAIN_BIN" serve +claude mcp list | grep gbrain # verify: should show "✓ Connected" +``` + +If the user already had a local-scope registration from an earlier run, +remove it first so both scopes don't conflict: +```bash +claude mcp remove gbrain 2>/dev/null || true ``` If `claude` is not on PATH: emit "MCP registration skipped — this skill is Claude-Code-targeted; register `gbrain serve` in your agent's MCP config manually." Continue to step 6. +**Heads-up for the user:** an already-open Claude Code session will not +pick up the new MCP tools until restart. Tell them: "Restart any open +Claude Code sessions to see `mcp__gbrain__*` tools — they're loaded at +session start, not mid-session." + --- ## Step 6: Per-remote policy (D3 triad, gated repo-import) @@ -1368,9 +1384,9 @@ Find-and-replace (or append) this section in CLAUDE.md: ## Step 9: Smoke test ```bash -gbrain put_page --title "setup-gbrain smoke test" --tags "meta" \ - <<<"Set up on $(date)" -gbrain search "smoke test" | grep -i "setup-gbrain smoke test" +SLUG="setup-gbrain-smoke-test-$(date +%s)" +echo "Set up on $(date). Smoke test for /setup-gbrain." | gbrain put "$SLUG" +gbrain search "smoke test" | grep -i "$SLUG" ``` Confirms the round trip. On failure, surface `gbrain doctor --json` output diff --git a/setup-gbrain/SKILL.md.tmpl b/setup-gbrain/SKILL.md.tmpl index 1abe7a46..685e15e0 100644 --- a/setup-gbrain/SKILL.md.tmpl +++ b/setup-gbrain/SKILL.md.tmpl @@ -285,17 +285,33 @@ doctor output and STOP. Only if `which claude` resolves. Ask: "Give Claude Code a typed tool surface for gbrain? (recommended yes)" -If yes: +If yes, register at **user scope** with an **absolute path** to the gbrain +binary. User scope makes the MCP available in every Claude Code session on +this machine, not just the current workspace. Absolute path avoids PATH +resolution issues when Claude Code spawns `gbrain serve` as a subprocess. ```bash -claude mcp add gbrain -- gbrain serve -claude mcp list | grep gbrain # verify +GBRAIN_BIN=$(command -v gbrain) +[ -z "$GBRAIN_BIN" ] && GBRAIN_BIN="$HOME/.bun/bin/gbrain" +claude mcp add --scope user gbrain -- "$GBRAIN_BIN" serve +claude mcp list | grep gbrain # verify: should show "✓ Connected" +``` + +If the user already had a local-scope registration from an earlier run, +remove it first so both scopes don't conflict: +```bash +claude mcp remove gbrain 2>/dev/null || true ``` If `claude` is not on PATH: emit "MCP registration skipped — this skill is Claude-Code-targeted; register `gbrain serve` in your agent's MCP config manually." Continue to step 6. +**Heads-up for the user:** an already-open Claude Code session will not +pick up the new MCP tools until restart. Tell them: "Restart any open +Claude Code sessions to see `mcp__gbrain__*` tools — they're loaded at +session start, not mid-session." + --- ## Step 6: Per-remote policy (D3 triad, gated repo-import) @@ -370,9 +386,9 @@ Find-and-replace (or append) this section in CLAUDE.md: ## Step 9: Smoke test ```bash -gbrain put_page --title "setup-gbrain smoke test" --tags "meta" \ - <<<"Set up on $(date)" -gbrain search "smoke test" | grep -i "setup-gbrain smoke test" +SLUG="setup-gbrain-smoke-test-$(date +%s)" +echo "Set up on $(date). Smoke test for /setup-gbrain." | gbrain put "$SLUG" +gbrain search "smoke test" | grep -i "$SLUG" ``` Confirms the round trip. On failure, surface `gbrain doctor --json` output diff --git a/test/gstack-brain-init-gh-mock.test.ts b/test/gstack-brain-init-gh-mock.test.ts index 7d3e85c8..ff7d98cb 100644 --- a/test/gstack-brain-init-gh-mock.test.ts +++ b/test/gstack-brain-init-gh-mock.test.ts @@ -134,8 +134,10 @@ describe('gstack-brain-init uses gh CLI when present + authed', () => { expect(createCall).toContain('gstack-brain-testuser'); expect(createCall).toContain('--private'); expect(createCall).toContain('--description'); - expect(createCall).toContain('--source'); - expect(createCall).toContain(tmpHome); + // --source is intentionally omitted: gh requires the source dir to already + // be a git repo, but brain-init doesn't `git init $GSTACK_HOME` until later. + // Creating bare and wiring up the remote explicitly avoids that ordering bug. + expect(createCall).not.toContain('--source'); }); test('falls back to gh repo view when create reports already-exists', () => {