mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-09 14:55:37 +02:00
v1.29.0.0 feat: worktree-aware gbrain code sources via path-hash IDs and CWD pin (#1382)
* feat: worktree-aware gbrain code sources via path-hash IDs and CWD pin Conductor sibling worktrees of the same repo no longer collide on a shared gstack-code-<slug> source ID. /sync-gbrain now derives a path-hashed source ID per worktree, runs gbrain sources attach to write .gbrain-source in the worktree root, and removes the legacy unsuffixed source on first new-format sync to prevent orphan accumulation. Bug fixes surfaced by /codex during /ship: - Silent attach failure now treated as stage failure (no more ok:true while pin is missing → unqualified code-def hits wrong source). - Startup preamble checks .gbrain-source in the cwd worktree, not global state, so an unsynced worktree no longer claims "indexed" because a sibling synced. - Code stage no longer skipped on remote-MCP (Path 4); the early-exit was in the SKILL template, not the orchestrator. - Source registration routes through lib/gbrain-sources.ts only; deleted the near-duplicate ensureSourceRegisteredSync from the orchestrator. Requires gbrain v0.30.0+ (uses sources attach). Phase 0 spike report: ~/.gstack/projects/garrytan-gstack/2026-05-08-gbrain-split-engine-spike.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * chore: bump version and changelog (v1.29.0.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ bin/gstack-global-discover
|
||||
.openclaw/
|
||||
.hermes/
|
||||
.gbrain/
|
||||
.gbrain-source
|
||||
.context/
|
||||
extension/.auth.json
|
||||
# xterm assets are vendored from npm at build time; not source-of-truth.
|
||||
|
||||
@@ -1,5 +1,81 @@
|
||||
# Changelog
|
||||
|
||||
## [1.29.0.0] - 2026-05-08
|
||||
|
||||
## **Code search beats Grep across every Conductor worktree now, not just the last one you synced.**
|
||||
|
||||
`/sync-gbrain` registers each worktree as its own gbrain source, then
|
||||
runs `gbrain sources attach <id>` so the worktree gets a `.gbrain-source`
|
||||
pin in its root. Subsequent `gbrain code-def`, `code-refs`, `code-callers`
|
||||
calls from anywhere under the worktree route to that source by default,
|
||||
no `--source` flag needed. Conductor sibling worktrees of the same repo
|
||||
no longer collide on a shared `gstack-code-<slug>` source ID, so the
|
||||
last `/sync-gbrain` run no longer silently overwrites every other
|
||||
worktree's index.
|
||||
|
||||
Three correctness bugs surfaced by `/codex` adversarial review during
|
||||
`/ship` are fixed in the same release: silent attach failure (sync
|
||||
succeeds but pin is missing → unqualified `code-def` hits the wrong
|
||||
source), preamble inconsistency (startup hint claimed "indexed" based
|
||||
on global state, ignoring per-worktree pins), and orphan source leak
|
||||
(the pre-pathhash `gstack-code-<slug>` source stayed registered
|
||||
forever, polluting federated cross-source search). All three fixed
|
||||
before merge.
|
||||
|
||||
### The numbers that matter
|
||||
|
||||
End-to-end verified via `bun test test/gstack-gbrain-sync.test.ts test/gbrain-sources.test.ts test/gen-skill-docs.test.ts`:
|
||||
|
||||
| Surface | Before | After | Δ |
|
||||
|---|---|---|---|
|
||||
| Conductor worktrees indexed independently | 1 (last-sync-wins) | N (one source per path) | branch-correct |
|
||||
| `gbrain code-def` from a worktree without sync | hits wrong source silently | falls back to default with notice | no silent corruption |
|
||||
| Orphan sources accumulated across runs | unbounded | 0 (legacy id removed on first new-format sync) | clean |
|
||||
| Attach-failure-to-pin behavior | stage reports `ok:true` | stage reports `ok:false` with reason | no silent correctness break |
|
||||
| Orchestrator registration logic | duplicated in `bin/` and `lib/` (could miss `--db` on one path) | single source of truth in `lib/gbrain-sources.ts` | DRY |
|
||||
| Required gbrain version | v0.20.0+ (single-brain-only) | v0.30.0+ (uses `sources attach`) | prerequisite bumped |
|
||||
|
||||
Test count went from 405 → 408 (+3 worktree-aware tests + 1 legacy-cleanup preview test).
|
||||
|
||||
### What this means for builders
|
||||
|
||||
If you use Conductor to run multiple parallel branches of the same
|
||||
repo, you can now run `/sync-gbrain` in each one and `gbrain code-def`
|
||||
from inside any of them returns hits from THAT worktree's branch state,
|
||||
not whichever sibling synced most recently. This was a hard requirement
|
||||
before semantic code search could replace Grep for refactor planning,
|
||||
"where is X used", "what depends on what" queries across parallel
|
||||
worktrees. Run `gbrain autopilot --install` once per machine for
|
||||
ongoing background sync; gbrain owns the daemon lifecycle.
|
||||
|
||||
### Itemized changes
|
||||
|
||||
#### Added
|
||||
|
||||
- Worktree-aware source IDs in `bin/gstack-gbrain-sync.ts:176-186`. Pattern is now `gstack-code-<slug>-<pathhash8>` where `pathhash8` is the first 8 hex chars of `sha1(absolute repo path)`. Conductor worktrees of the same origin coexist as separate sources in one gbrain DB.
|
||||
- `gbrain sources attach <id>` step in `runCodeImport` (`bin/gstack-gbrain-sync.ts:336-351`). Writes `.gbrain-source <id>` in the worktree root after sync succeeds; subsequent `gbrain code-def` calls from any subdirectory auto-route to that source.
|
||||
- Legacy source cleanup: on first new-format sync, removes the pre-pathhash `gstack-code-<slug>` orphan via `gbrain sources remove ... --confirm-destructive` (`bin/gstack-gbrain-sync.ts:298-318`).
|
||||
- `.gbrain-source` added to `.gitignore` so per-worktree pin doesn't leak across branches.
|
||||
|
||||
#### Changed
|
||||
|
||||
- Code stage no longer skipped on remote-MCP (Path 4) installs. The early-exit in `sync-gbrain/SKILL.md.tmpl` was bouncing users out before the orchestrator ran; the local code brain works regardless of whether artifacts use a remote MCP. Replaced with split-engine prose explaining the model.
|
||||
- Source registration now flows through `lib/gbrain-sources.ts:ensureSourceRegistered` exclusively. Deleted `ensureSourceRegisteredSync` from the orchestrator binary (was a near-duplicate of the lib helper at `lib/gbrain-sources.ts:100`). Removes the missed-flag risk where one path could skip `--db` or `--federated`.
|
||||
- Startup preamble (`scripts/resolvers/preamble/generate-brain-sync-block.ts:48-75`) now checks for `.gbrain-source` in `git rev-parse --show-toplevel`, not the global `~/.gstack/.gbrain-sync-state.json`. Opening an unsynced worktree no longer claims "indexed" based on a sibling's sync.
|
||||
- CLAUDE.md guidance block in the SKILL template now documents the `.gbrain-source` pin and `gbrain autopilot --install` for ongoing sync.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- Silent attach failure: `gbrain sources attach` now treated as stage failure if it returns non-zero. Previously the stage reported `ok:true` while the pin was missing, so unqualified `gbrain code-def` queries silently hit the default source. Now surfaces ERR with reason in the verdict block; user knows to retry.
|
||||
- Wrong-layer Path 4 early-exit (`/codex` finding #2 from `/plan-eng-review`).
|
||||
- Orphan source accumulation: the pre-pathhash `gstack-code-<slug>` source stayed registered across `/sync-gbrain` runs even after the path-keyed format shipped, polluting federated `gbrain search` results with stale duplicates.
|
||||
|
||||
#### For contributors
|
||||
|
||||
- Phase 0 verification spike at `~/.gstack/projects/garrytan-gstack/2026-05-08-gbrain-split-engine-spike.md` documents what gbrain v0.30 actually provides (no `--db` flag, `serve --http` requires postgres, `sources attach` is the v0.30 routing primitive). The approved plan's "per-worktree PGLite + per-worktree HTTP serve" architecture was invalidated by the spike; the simpler "one brain, many sources, attach for CWD pin" model collapsed ~80% of the plan's complexity.
|
||||
- `/codex` adversarial review during `/ship` caught all three correctness bugs above (silent attach, preamble inconsistency, orphan leak) before merge. Find-cost: ~10 min CC. Production-bug-cost: stale code search results that "almost worked" — the worst kind to debug.
|
||||
- gbrain CLI minimum version is now v0.30.0 (uses `sources attach`, which doesn't exist in v0.20.x). Run `cd ~/git/gbrain && git pull && bun install && bun link` to upgrade.
|
||||
|
||||
## [1.28.0.0] - 2026-05-07
|
||||
|
||||
## **Browse handles real-world automation now: SOCKS5 with auth, container Xvfb, browser-native downloads. Plus a single-file `llms.txt` index agents can crawl in one read.**
|
||||
|
||||
@@ -285,30 +285,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -353,30 +353,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -287,30 +287,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -287,30 +287,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+96
-76
@@ -31,12 +31,12 @@
|
||||
|
||||
import { existsSync, statSync, mkdirSync, writeFileSync, readFileSync, unlinkSync, renameSync } from "fs";
|
||||
import { join, dirname } from "path";
|
||||
import { execSync, execFileSync, spawnSync } from "child_process";
|
||||
import { execSync, spawnSync } from "child_process";
|
||||
import { homedir } from "os";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
import { detectEngineTier, withErrorContext, canonicalizeRemote } from "../lib/gstack-memory-helpers";
|
||||
import { sourcePageCount } from "../lib/gbrain-sources";
|
||||
import { ensureSourceRegistered, sourcePageCount } from "../lib/gbrain-sources";
|
||||
|
||||
// ── Types ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -159,17 +159,43 @@ function originUrl(): string | null {
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a stable source id for the cwd code corpus. Pattern: `gstack-code-<slug>`.
|
||||
* Derive a worktree-aware source id for the cwd code corpus.
|
||||
*
|
||||
* gbrain enforces source ids to be 1-32 lowercase alnum chars with optional interior
|
||||
* hyphens. We use the last two segments of the canonical remote (org/repo) and skip
|
||||
* the host — `github.com` etc. is the same for nearly every user and just eats budget.
|
||||
* If the resulting id still exceeds 32 chars, we keep the tail (most distinctive end)
|
||||
* and append a 6-char hash of the full slug for collision resistance.
|
||||
* Pattern: `gstack-code-<slug>-<pathhash8>` where slug comes from origin
|
||||
* (org/repo) and pathhash8 is the first 8 hex chars of sha1(absolute repo
|
||||
* path). The pathhash8 is what makes Conductor worktrees of the same repo
|
||||
* coexist as separate sources in the same gbrain DB instead of stomping on
|
||||
* each other.
|
||||
*
|
||||
* Falls back to the repo basename when there is no origin (local repo).
|
||||
*
|
||||
* gbrain enforces source ids to be 1-32 lowercase alnum chars with
|
||||
* optional interior hyphens. `constrainSourceId` handles the 32-char cap
|
||||
* with a hashed-tail fallback when the combined slug exceeds budget.
|
||||
*/
|
||||
function deriveCodeSourceId(repoPath: string): string {
|
||||
const pathHash = createHash("sha1").update(repoPath).digest("hex").slice(0, 8);
|
||||
const remote = canonicalizeRemote(originUrl());
|
||||
if (remote) {
|
||||
const segs = remote.split("/").filter(Boolean);
|
||||
const slugSource = segs.slice(-2).join("-");
|
||||
return constrainSourceId("gstack-code", `${slugSource}-${pathHash}`);
|
||||
}
|
||||
const base = repoPath.split("/").pop() || "repo";
|
||||
return constrainSourceId("gstack-code", `${base}-${pathHash}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-pathhash source id, kept for orphan detection only.
|
||||
*
|
||||
* Earlier /sync-gbrain versions registered `gstack-code-<slug>` (no pathhash
|
||||
* suffix). On a multi-worktree repo, those collapsed onto a single source id
|
||||
* with last-sync-wins semantics. The new path-keyed id leaves the legacy
|
||||
* source orphaned in the brain — federated cross-source search would return
|
||||
* stale duplicate hits. We remove the legacy id once, on the first new-format
|
||||
* sync from any worktree of this repo, so users don't accumulate orphans.
|
||||
*/
|
||||
function deriveLegacyCodeSourceId(repoPath: string): string {
|
||||
const remote = canonicalizeRemote(originUrl());
|
||||
if (remote) {
|
||||
const segs = remote.split("/").filter(Boolean);
|
||||
@@ -264,7 +290,7 @@ function releaseLock(): void {
|
||||
|
||||
// ── Stage runners ──────────────────────────────────────────────────────────
|
||||
|
||||
function runCodeImport(args: CliArgs): StageResult {
|
||||
async function runCodeImport(args: CliArgs): Promise<StageResult> {
|
||||
const t0 = Date.now();
|
||||
const root = repoRoot();
|
||||
if (!root) {
|
||||
@@ -282,21 +308,37 @@ function runCodeImport(args: CliArgs): StageResult {
|
||||
ran: false,
|
||||
ok: true,
|
||||
duration_ms: 0,
|
||||
summary: `would: gbrain sources add ${sourceId} --path ${root} --federated; gbrain sync --strategy code --source ${sourceId}`,
|
||||
summary: `would: gbrain sources add ${sourceId} --path ${root} --federated; gbrain sync --strategy code --source ${sourceId}; gbrain sources attach ${sourceId}`,
|
||||
detail: { source_id: sourceId, source_path: root, status: "skipped" },
|
||||
};
|
||||
}
|
||||
|
||||
// Step 1: Ensure source registered (idempotent).
|
||||
// Step 0: Best-effort cleanup of pre-pathhash legacy source.
|
||||
// Earlier /sync-gbrain versions registered `gstack-code-<slug>` (no path
|
||||
// suffix). On a multi-worktree repo, those collapsed onto a single id
|
||||
// with last-sync-wins. Federated search would return stale duplicate
|
||||
// hits forever if we left the orphan in place. Remove the legacy id once
|
||||
// here so users don't accumulate orphans.
|
||||
// Failure is non-fatal — we still register the new id below.
|
||||
const legacyId = deriveLegacyCodeSourceId(root);
|
||||
let legacyRemoved = false;
|
||||
if (legacyId !== sourceId) {
|
||||
const rm = spawnSync("gbrain", ["sources", "remove", legacyId, "--confirm-destructive"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 30_000,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
// Treat absent-source as success (clean state). gbrain emits "not found" on
|
||||
// missing id; treat any non-zero exit without "not found" as a soft fail.
|
||||
if (rm.status === 0) legacyRemoved = true;
|
||||
}
|
||||
|
||||
// Step 1: Ensure source registered (idempotent). Single source of truth in lib —
|
||||
// no synchronous duplicate here (per /codex review #12).
|
||||
let registered = false;
|
||||
try {
|
||||
// ensureSourceRegistered is async — but we're in a sync stage runner. Use a deasync pattern.
|
||||
// Bun supports top-level await in main(), but stage runners are sync per orchestrator contract.
|
||||
// Workaround: run as a child Bun script for the registration probe.
|
||||
// Simpler: call gbrain CLI directly via the sync helpers in lib/gbrain-sources.ts probeSource.
|
||||
// For symmetry, we duplicate the small ensureSourceRegistered logic synchronously here using
|
||||
// execFileSync. (The lib helper is preferred for async callers; sync helpers below.)
|
||||
registered = ensureSourceRegisteredSync(sourceId, root);
|
||||
const result = await ensureSourceRegistered(sourceId, root, { federated: true });
|
||||
registered = result.changed;
|
||||
} catch (err) {
|
||||
return {
|
||||
name: "code",
|
||||
@@ -329,15 +371,49 @@ function runCodeImport(args: CliArgs): StageResult {
|
||||
};
|
||||
}
|
||||
|
||||
// Step 3: Read page_count from gbrain sources list.
|
||||
// Step 3: Pin this worktree's CWD to the source via .gbrain-source. Subsequent
|
||||
// gbrain code-def / code-refs / code-callers calls from anywhere under <root>
|
||||
// route to this source by default — no --source flag needed.
|
||||
//
|
||||
// If attach fails the whole flow has a silent correctness problem: sync
|
||||
// succeeded but unqualified `gbrain code-def` from this worktree will hit
|
||||
// the wrong/default source. Treat it as a stage failure (ok=false) so the
|
||||
// verdict block surfaces ERR and the user knows to retry rather than
|
||||
// trusting stale results.
|
||||
const attach = spawnSync("gbrain", ["sources", "attach", sourceId], {
|
||||
encoding: "utf-8",
|
||||
timeout: 10_000,
|
||||
cwd: root,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
const pageCount = sourcePageCount(sourceId);
|
||||
const legacyNote = legacyRemoved ? `, removed legacy ${legacyId}` : "";
|
||||
const baseSummary = `${registered ? "registered + " : ""}synced ${sourceId} (page_count=${pageCount ?? "unknown"}${legacyNote})`;
|
||||
|
||||
if (attach.status !== 0) {
|
||||
const reason = (attach.stderr || attach.stdout || "").trim().split("\n").pop() || `exit ${attach.status}`;
|
||||
return {
|
||||
name: "code",
|
||||
ran: true,
|
||||
ok: false,
|
||||
duration_ms: Date.now() - t0,
|
||||
summary: `${baseSummary}; attach FAILED (${reason}) — code-def queries from this worktree will hit the default source until /sync-gbrain succeeds`,
|
||||
detail: {
|
||||
source_id: sourceId,
|
||||
source_path: root,
|
||||
page_count: pageCount,
|
||||
last_imported: new Date().toISOString(),
|
||||
status: "failed",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: "code",
|
||||
ran: true,
|
||||
ok: true,
|
||||
duration_ms: Date.now() - t0,
|
||||
summary: `${registered ? "registered + " : ""}synced ${sourceId} (page_count=${pageCount ?? "unknown"})`,
|
||||
summary: baseSummary,
|
||||
detail: {
|
||||
source_id: sourceId,
|
||||
source_path: root,
|
||||
@@ -348,62 +424,6 @@ function runCodeImport(args: CliArgs): StageResult {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronous mirror of ensureSourceRegistered for use inside the synchronous
|
||||
* stage runner. Returns true if registration changed (added or re-added).
|
||||
*/
|
||||
function ensureSourceRegisteredSync(id: string, path: string): boolean {
|
||||
// Probe.
|
||||
let probeOut: string;
|
||||
try {
|
||||
probeOut = execFileSync("gbrain", ["sources", "list", "--json"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 10_000,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
} catch (err) {
|
||||
const e = err as NodeJS.ErrnoException & { stderr?: Buffer };
|
||||
const stderr = e.stderr?.toString() || "";
|
||||
if (e.code === "ENOENT") throw new Error("gbrain CLI not on PATH");
|
||||
if (stderr.includes("Cannot connect to database") || stderr.includes("config.json")) {
|
||||
throw new Error("gbrain not configured (run /setup-gbrain)");
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
let parsed: { sources?: Array<{ id?: string; local_path?: string }> };
|
||||
try {
|
||||
parsed = JSON.parse(probeOut);
|
||||
} catch (err) {
|
||||
throw new Error(`gbrain sources list returned non-JSON: ${(err as Error).message}`);
|
||||
}
|
||||
const sources = parsed.sources || [];
|
||||
const match = sources.find((s) => s.id === id);
|
||||
|
||||
if (match && match.local_path === path) {
|
||||
return false; // no-op
|
||||
}
|
||||
|
||||
if (match && match.local_path !== path) {
|
||||
const rm = spawnSync("gbrain", ["sources", "remove", id, "--yes"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 30_000,
|
||||
});
|
||||
if (rm.status !== 0) {
|
||||
throw new Error(`gbrain sources remove ${id} failed: ${rm.stderr || rm.stdout || `exit ${rm.status}`}`);
|
||||
}
|
||||
}
|
||||
|
||||
const add = spawnSync("gbrain", ["sources", "add", id, "--path", path, "--federated"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 30_000,
|
||||
});
|
||||
if (add.status !== 0) {
|
||||
throw new Error(`gbrain sources add ${id} failed: ${add.stderr || add.stdout || `exit ${add.status}`}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function runMemoryIngest(args: CliArgs): StageResult {
|
||||
const t0 = Date.now();
|
||||
|
||||
|
||||
+13
-14
@@ -286,30 +286,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -345,30 +345,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -347,30 +347,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -350,30 +350,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -373,30 +373,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -352,30 +352,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -350,30 +350,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -367,30 +367,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -350,30 +350,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -347,30 +347,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -347,30 +347,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -386,30 +386,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -344,30 +344,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -345,30 +345,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -347,30 +347,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -286,30 +286,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -382,30 +382,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -344,30 +344,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gstack",
|
||||
"version": "1.28.0.0",
|
||||
"version": "1.29.0.0",
|
||||
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
+13
-14
@@ -345,30 +345,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -376,30 +376,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -353,30 +353,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -351,30 +351,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -358,30 +358,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -346,30 +346,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -352,30 +352,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -364,30 +364,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -345,30 +345,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -46,30 +46,29 @@ _BRAIN_SYNC_BIN="${ctx.paths.binDir}/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="${ctx.paths.binDir}/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style \`.gbrain-source\` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\\n' < "$_SYNC_STATE" 2>/dev/null \\
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \\
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\\+' | head -1)
|
||||
_CWD_PAGES=\${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \\\`gbrain search\\\`/\\\`gbrain query\\\` over Grep for"
|
||||
echo "semantic questions; use \\\`gbrain code-def\\\`/\\\`code-refs\\\`/\\\`code-callers\\\` for"
|
||||
echo "symbol-aware code lookup. See \\"## GBrain Search Guidance\\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \\\`/sync-gbrain --full\\\`"
|
||||
echo "before relying on \\\`gbrain search\\\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \\\`/sync-gbrain --full\\\`"
|
||||
echo "before relying on \\\`gbrain search\\\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -283,30 +283,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -348,30 +348,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -350,30 +350,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+13
-14
@@ -346,30 +346,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
+46
-39
@@ -349,30 +349,29 @@ _BRAIN_SYNC_BIN="~/.claude/skills/gstack/bin/gstack-brain-sync"
|
||||
_BRAIN_CONFIG_BIN="~/.claude/skills/gstack/bin/gstack-config"
|
||||
|
||||
# /sync-gbrain context-load: teach the agent to use gbrain when it's available.
|
||||
# Mutually exclusive variants per /plan-eng-review §4. Empty string when gbrain
|
||||
# is not configured (zero context cost for non-gbrain users).
|
||||
# Per-worktree pin: post-spike redesign uses kubectl-style `.gbrain-source` in the
|
||||
# git toplevel to scope queries. Look for the pin in the worktree (not a global
|
||||
# state file) so that opening worktree B without a pin doesn't claim "indexed"
|
||||
# just because worktree A was synced. Empty string when gbrain is not
|
||||
# configured (zero context cost for non-gbrain users).
|
||||
_GBRAIN_CONFIG="$HOME/.gbrain/config.json"
|
||||
if [ -f "$_GBRAIN_CONFIG" ] && command -v gbrain >/dev/null 2>&1; then
|
||||
_GBRAIN_VERSION_OK=$(gbrain --version 2>/dev/null | grep -c '^gbrain ' || echo 0)
|
||||
if [ "$_GBRAIN_VERSION_OK" -gt 0 ] 2>/dev/null; then
|
||||
_SYNC_STATE="$_GSTACK_HOME/.gbrain-sync-state.json"
|
||||
_CWD_PAGES=0
|
||||
if [ -f "$_SYNC_STATE" ]; then
|
||||
# Flatten newlines so the regex works against pretty-printed JSON too.
|
||||
_CWD_PAGES=$(tr -d '\n' < "$_SYNC_STATE" 2>/dev/null \
|
||||
| grep -o '"name": *"code"[^}]*"detail": *{[^}]*"page_count": *[0-9]*' \
|
||||
| grep -o '"page_count": *[0-9]*' | grep -o '[0-9]\+' | head -1)
|
||||
_CWD_PAGES=${_CWD_PAGES:-0}
|
||||
_GBRAIN_PIN_PATH=""
|
||||
_REPO_TOP=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
|
||||
if [ -n "$_REPO_TOP" ] && [ -f "$_REPO_TOP/.gbrain-source" ]; then
|
||||
_GBRAIN_PIN_PATH="$_REPO_TOP/.gbrain-source"
|
||||
fi
|
||||
if [ "$_CWD_PAGES" -gt 0 ] 2>/dev/null; then
|
||||
if [ -n "$_GBRAIN_PIN_PATH" ]; then
|
||||
echo "GBrain configured. Prefer \`gbrain search\`/\`gbrain query\` over Grep for"
|
||||
echo "semantic questions; use \`gbrain code-def\`/\`code-refs\`/\`code-callers\` for"
|
||||
echo "symbol-aware code lookup. See \"## GBrain Search Guidance\" in CLAUDE.md."
|
||||
echo "Run /sync-gbrain to refresh."
|
||||
else
|
||||
echo "GBrain configured but this repo isn't indexed yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this repo."
|
||||
echo "Falls back to Grep until indexed."
|
||||
echo "GBrain configured but this worktree isn't pinned yet. Run \`/sync-gbrain --full\`"
|
||||
echo "before relying on \`gbrain search\` for code questions in this worktree."
|
||||
echo "Falls back to Grep until pinned."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -768,31 +767,28 @@ Before doing anything, check that /setup-gbrain has been run on this Mac.
|
||||
~/.claude/skills/gstack/bin/gstack-gbrain-detect 2>/dev/null
|
||||
```
|
||||
|
||||
**Remote-MCP mode (Path 4 of /setup-gbrain):** if `gbrain_mcp_mode=remote-http`,
|
||||
this skill is a graceful no-op. The brain server's own indexing cadence
|
||||
handles code import + search refresh; this Mac doesn't run a local gbrain
|
||||
CLI to drive `gbrain sources add` / `sync --strategy code`. Print:
|
||||
**Split-engine model.** Code stage always runs locally against a per-machine
|
||||
PGLite brain (or whatever `gbrain config` points to), with each worktree of a
|
||||
repo registered as its own source. Artifacts/memory stages route through
|
||||
whatever `setup-gbrain` configured — including remote-MCP (Path 4). The two
|
||||
sides are independent: code lookups are local + worktree-scoped, artifacts
|
||||
remain cross-machine.
|
||||
|
||||
> "Remote MCP detected (Path 4). /sync-gbrain is local-mode-only in V1.
|
||||
> Your brain server (`<host>` from claude.json) handles indexing on its own
|
||||
> cadence. If indexing seems stale, ping your brain admin or trigger a
|
||||
> manual sync there. To wire `/sync-gbrain` through MCP tools (when gbrain
|
||||
> ships `mcp__gbrain__sources_add` and friends), see the v1.27.0.0+
|
||||
> follow-on TODO."
|
||||
A previous version of this skill bounced remote-MCP users out of the code
|
||||
stage entirely. That was wrong: the code-stage CLI calls (`gbrain sources
|
||||
add`, `sync --strategy code`, `sources attach`) target the LOCAL gbrain CLI
|
||||
+ DB regardless of whether `~/.claude.json` has `gbrain` registered as a
|
||||
remote HTTP MCP for artifacts. We no longer skip the code stage in
|
||||
remote-MCP mode.
|
||||
|
||||
Then exit cleanly. Do NOT proceed to Step 2.
|
||||
If `gbrain_on_path=false` OR `gbrain_config_exists=false`, STOP and tell
|
||||
the user:
|
||||
|
||||
For local-stdio mode and unconfigured states:
|
||||
> "/sync-gbrain requires /setup-gbrain to be run first. Run `/setup-gbrain`
|
||||
> to install gbrain, register the MCP server, and set per-repo trust policy."
|
||||
|
||||
If `gbrain_on_path=false` OR `gbrain_config_exists=false` OR CLAUDE.md does
|
||||
not contain `## GBrain Configuration (configured by /setup-gbrain)`, STOP and
|
||||
tell the user:
|
||||
|
||||
> "/sync-gbrain requires /setup-gbrain to be run first. Run `/setup-gbrain` to
|
||||
> install gbrain, register the MCP server, and set per-repo trust policy."
|
||||
|
||||
Do NOT continue — the skill is unsafe when gbrain isn't configured (we'd
|
||||
write a CLAUDE.md guidance block referencing tools that don't exist).
|
||||
Do NOT continue — the skill is unsafe when the local gbrain CLI is missing
|
||||
(we'd write a CLAUDE.md guidance block referencing tools that don't exist).
|
||||
|
||||
Also check the per-repo trust policy. If `gstack-gbrain-repo-policy get` for
|
||||
this repo returns `deny`, STOP:
|
||||
@@ -887,8 +883,18 @@ Verbatim block content (copy exactly):
|
||||
|
||||
GBrain is set up and synced on this machine. The agent should prefer gbrain
|
||||
over Grep when the question is semantic or when you don't know the exact
|
||||
identifier yet. Two indexed corpora available via the `gbrain` CLI:
|
||||
- This repo's code (registered as `gstack-code-<repo>` source).
|
||||
identifier yet.
|
||||
|
||||
**This worktree is pinned to a worktree-scoped code source** via the
|
||||
`.gbrain-source` file in the repo root (kubectl-style context). Any
|
||||
`gbrain code-def`, `code-refs`, `code-callers`, `code-callees`, or `query`
|
||||
call from anywhere under this worktree routes to that source by default —
|
||||
no `--source` flag needed. Conductor sibling worktrees of the same repo
|
||||
each have their own pin and their own indexed pages, so semantic results
|
||||
match the actual code on disk in this worktree.
|
||||
|
||||
Two indexed corpora available via the `gbrain` CLI:
|
||||
- This worktree's code (auto-pinned via `.gbrain-source`).
|
||||
- `~/.gstack/` curated memory (registered as `gstack-brain-<user>` source via
|
||||
the existing federation pipeline).
|
||||
|
||||
@@ -903,8 +909,9 @@ Prefer gbrain when:
|
||||
`gbrain search "<terms>" --source gstack-brain-<user>`
|
||||
|
||||
Grep is still right for known exact strings, regex, multiline patterns, and
|
||||
file globs. The brain auto-syncs incrementally on every gstack skill start.
|
||||
Run `/sync-gbrain` to force-refresh, `/sync-gbrain --full` for full reindex.
|
||||
file globs. Run `/sync-gbrain` after meaningful code changes; for ongoing
|
||||
auto-sync across all worktrees, run `gbrain autopilot --install` once per
|
||||
machine — gbrain's daemon handles incremental refresh on a schedule.
|
||||
|
||||
<!-- gstack-gbrain-search-guidance:end -->
|
||||
```
|
||||
|
||||
+33
-25
@@ -66,31 +66,28 @@ Before doing anything, check that /setup-gbrain has been run on this Mac.
|
||||
~/.claude/skills/gstack/bin/gstack-gbrain-detect 2>/dev/null
|
||||
```
|
||||
|
||||
**Remote-MCP mode (Path 4 of /setup-gbrain):** if `gbrain_mcp_mode=remote-http`,
|
||||
this skill is a graceful no-op. The brain server's own indexing cadence
|
||||
handles code import + search refresh; this Mac doesn't run a local gbrain
|
||||
CLI to drive `gbrain sources add` / `sync --strategy code`. Print:
|
||||
**Split-engine model.** Code stage always runs locally against a per-machine
|
||||
PGLite brain (or whatever `gbrain config` points to), with each worktree of a
|
||||
repo registered as its own source. Artifacts/memory stages route through
|
||||
whatever `setup-gbrain` configured — including remote-MCP (Path 4). The two
|
||||
sides are independent: code lookups are local + worktree-scoped, artifacts
|
||||
remain cross-machine.
|
||||
|
||||
> "Remote MCP detected (Path 4). /sync-gbrain is local-mode-only in V1.
|
||||
> Your brain server (`<host>` from claude.json) handles indexing on its own
|
||||
> cadence. If indexing seems stale, ping your brain admin or trigger a
|
||||
> manual sync there. To wire `/sync-gbrain` through MCP tools (when gbrain
|
||||
> ships `mcp__gbrain__sources_add` and friends), see the v1.27.0.0+
|
||||
> follow-on TODO."
|
||||
A previous version of this skill bounced remote-MCP users out of the code
|
||||
stage entirely. That was wrong: the code-stage CLI calls (`gbrain sources
|
||||
add`, `sync --strategy code`, `sources attach`) target the LOCAL gbrain CLI
|
||||
+ DB regardless of whether `~/.claude.json` has `gbrain` registered as a
|
||||
remote HTTP MCP for artifacts. We no longer skip the code stage in
|
||||
remote-MCP mode.
|
||||
|
||||
Then exit cleanly. Do NOT proceed to Step 2.
|
||||
If `gbrain_on_path=false` OR `gbrain_config_exists=false`, STOP and tell
|
||||
the user:
|
||||
|
||||
For local-stdio mode and unconfigured states:
|
||||
> "/sync-gbrain requires /setup-gbrain to be run first. Run `/setup-gbrain`
|
||||
> to install gbrain, register the MCP server, and set per-repo trust policy."
|
||||
|
||||
If `gbrain_on_path=false` OR `gbrain_config_exists=false` OR CLAUDE.md does
|
||||
not contain `## GBrain Configuration (configured by /setup-gbrain)`, STOP and
|
||||
tell the user:
|
||||
|
||||
> "/sync-gbrain requires /setup-gbrain to be run first. Run `/setup-gbrain` to
|
||||
> install gbrain, register the MCP server, and set per-repo trust policy."
|
||||
|
||||
Do NOT continue — the skill is unsafe when gbrain isn't configured (we'd
|
||||
write a CLAUDE.md guidance block referencing tools that don't exist).
|
||||
Do NOT continue — the skill is unsafe when the local gbrain CLI is missing
|
||||
(we'd write a CLAUDE.md guidance block referencing tools that don't exist).
|
||||
|
||||
Also check the per-repo trust policy. If `gstack-gbrain-repo-policy get` for
|
||||
this repo returns `deny`, STOP:
|
||||
@@ -185,8 +182,18 @@ Verbatim block content (copy exactly):
|
||||
|
||||
GBrain is set up and synced on this machine. The agent should prefer gbrain
|
||||
over Grep when the question is semantic or when you don't know the exact
|
||||
identifier yet. Two indexed corpora available via the `gbrain` CLI:
|
||||
- This repo's code (registered as `gstack-code-<repo>` source).
|
||||
identifier yet.
|
||||
|
||||
**This worktree is pinned to a worktree-scoped code source** via the
|
||||
`.gbrain-source` file in the repo root (kubectl-style context). Any
|
||||
`gbrain code-def`, `code-refs`, `code-callers`, `code-callees`, or `query`
|
||||
call from anywhere under this worktree routes to that source by default —
|
||||
no `--source` flag needed. Conductor sibling worktrees of the same repo
|
||||
each have their own pin and their own indexed pages, so semantic results
|
||||
match the actual code on disk in this worktree.
|
||||
|
||||
Two indexed corpora available via the `gbrain` CLI:
|
||||
- This worktree's code (auto-pinned via `.gbrain-source`).
|
||||
- `~/.gstack/` curated memory (registered as `gstack-brain-<user>` source via
|
||||
the existing federation pipeline).
|
||||
|
||||
@@ -201,8 +208,9 @@ Prefer gbrain when:
|
||||
`gbrain search "<terms>" --source gstack-brain-<user>`
|
||||
|
||||
Grep is still right for known exact strings, regex, multiline patterns, and
|
||||
file globs. The brain auto-syncs incrementally on every gstack skill start.
|
||||
Run `/sync-gbrain` to force-refresh, `/sync-gbrain --full` for full reindex.
|
||||
file globs. Run `/sync-gbrain` after meaningful code changes; for ongoing
|
||||
auto-sync across all worktrees, run `gbrain autopilot --install` once per
|
||||
machine — gbrain's daemon handles incremental refresh on a schedule.
|
||||
|
||||
<!-- gstack-gbrain-search-guidance:end -->
|
||||
```
|
||||
|
||||
@@ -180,9 +180,12 @@ describe("gstack-gbrain-sync CLI", () => {
|
||||
|
||||
it("derives a gbrain-valid source id when the basename sanitizes to empty", () => {
|
||||
// Pathological edge: a repo whose basename is all non-alnum (e.g. "___")
|
||||
// sanitizes to an empty slug. Pre-fix, constrainSourceId returned
|
||||
// "gstack-code-" — invalid per the gbrain validator on the trailing
|
||||
// hyphen. Fix falls back to a deterministic hash of the original input.
|
||||
// sanitizes to an empty slug. Pre-worktree-aware-fix, constrainSourceId
|
||||
// returned "gstack-code-" (invalid trailing hyphen) and was patched to
|
||||
// fall back to a 6-char hash of the original input. The post-spike
|
||||
// redesign appends an 8-char path-hash to every id, so the basename's
|
||||
// empty-after-sanitize result is no longer a problem on its own — the
|
||||
// path hash carries the entropy. The id must still be gbrain-valid.
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
mkdirSync(gstackHome, { recursive: true });
|
||||
@@ -202,9 +205,11 @@ describe("gstack-gbrain-sync CLI", () => {
|
||||
const m = (r.stdout || "").match(/gbrain sources add (\S+)/);
|
||||
expect(m).not.toBeNull();
|
||||
const id = m![1];
|
||||
// Expect hash-only fallback shape: gstack-code-<6 hex chars>
|
||||
expect(id).toMatch(/^gstack-code-[0-9a-f]{6}$/);
|
||||
// gbrain validator: 1-32 lowercase alnum + interior hyphens, no leading
|
||||
// or trailing hyphens.
|
||||
expect(id.startsWith("gstack-code-")).toBe(true);
|
||||
expect(id.length).toBeLessThanOrEqual(32);
|
||||
expect(id).toMatch(/^[a-z0-9](?:[a-z0-9-]{0,30}[a-z0-9])?$/);
|
||||
|
||||
rmSync(parent, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
@@ -339,4 +344,135 @@ describe("gstack-gbrain-sync CLI", () => {
|
||||
expect(combined).not.toContain("skipped (gstack-brain-sync not installed)");
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("worktree-aware source ID: two worktrees of the same repo get DIFFERENT ids", () => {
|
||||
// Conductor pattern: same origin, two different absolute paths. Pre-fix the
|
||||
// ID was slug-only so both worktrees collapsed onto `gstack-code-<slug>` and
|
||||
// last-sync-wins corrupted whichever the user wasn't actively syncing. The
|
||||
// pathhash8 suffix makes each worktree's source independent.
|
||||
const remote = "https://github.com/garrytan/gstack.git";
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
mkdirSync(gstackHome, { recursive: true });
|
||||
|
||||
const repoA = mkdtempSync(join(tmpdir(), "gstack-worktree-a-"));
|
||||
const repoB = mkdtempSync(join(tmpdir(), "gstack-worktree-b-"));
|
||||
for (const repo of [repoA, repoB]) {
|
||||
spawnSync("git", ["init", "--quiet", "-b", "main"], { cwd: repo });
|
||||
spawnSync("git", ["remote", "add", "origin", remote], { cwd: repo });
|
||||
}
|
||||
|
||||
const idOf = (cwd: string): string => {
|
||||
const r = spawnSync("bun", [SCRIPT, "--dry-run", "--code-only", "--quiet"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 60000,
|
||||
cwd,
|
||||
env: { ...process.env, HOME: home, GSTACK_HOME: gstackHome },
|
||||
});
|
||||
expect(r.status).toBe(0);
|
||||
const m = (r.stdout || "").match(/gbrain sources add (\S+)/);
|
||||
expect(m).not.toBeNull();
|
||||
return m![1];
|
||||
};
|
||||
|
||||
const idA = idOf(repoA);
|
||||
const idB = idOf(repoB);
|
||||
expect(idA).not.toBe(idB);
|
||||
expect(idA.startsWith("gstack-code-")).toBe(true);
|
||||
expect(idB.startsWith("gstack-code-")).toBe(true);
|
||||
|
||||
rmSync(repoA, { recursive: true, force: true });
|
||||
rmSync(repoB, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("worktree-aware source ID: same path produces the same id across runs (deterministic)", () => {
|
||||
// The pathhash is derived from the absolute repo path via sha1, so
|
||||
// /sync-gbrain run twice in the same worktree must converge on the same
|
||||
// source id (idempotent registration depends on this).
|
||||
const remote = "https://github.com/garrytan/gstack.git";
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
mkdirSync(gstackHome, { recursive: true });
|
||||
const repo = mkdtempSync(join(tmpdir(), "gstack-worktree-stable-"));
|
||||
spawnSync("git", ["init", "--quiet", "-b", "main"], { cwd: repo });
|
||||
spawnSync("git", ["remote", "add", "origin", remote], { cwd: repo });
|
||||
|
||||
const idOf = (): string => {
|
||||
const r = spawnSync("bun", [SCRIPT, "--dry-run", "--code-only", "--quiet"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 60000,
|
||||
cwd: repo,
|
||||
env: { ...process.env, HOME: home, GSTACK_HOME: gstackHome },
|
||||
});
|
||||
expect(r.status).toBe(0);
|
||||
const m = (r.stdout || "").match(/gbrain sources add (\S+)/);
|
||||
expect(m).not.toBeNull();
|
||||
return m![1];
|
||||
};
|
||||
expect(idOf()).toBe(idOf());
|
||||
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("dry-run preview includes legacy-source removal + attach (post-codex-review hardening)", () => {
|
||||
// Codex adversarial flagged: pre-pathhash `gstack-code-<slug>` sources stay
|
||||
// orphaned forever after the new pathhash id ships. Dry-run preview must
|
||||
// surface the legacy cleanup so the user knows it'll happen.
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
mkdirSync(gstackHome, { recursive: true });
|
||||
const repo = mkdtempSync(join(tmpdir(), "gstack-legacy-cleanup-"));
|
||||
spawnSync("git", ["init", "--quiet", "-b", "main"], { cwd: repo });
|
||||
spawnSync("git", ["remote", "add", "origin", "https://github.com/garrytan/gstack.git"], { cwd: repo });
|
||||
|
||||
const r = spawnSync("bun", [SCRIPT, "--dry-run", "--code-only", "--quiet"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 60000,
|
||||
cwd: repo,
|
||||
env: { ...process.env, HOME: home, GSTACK_HOME: gstackHome },
|
||||
});
|
||||
expect(r.status).toBe(0);
|
||||
// The dry-run preview shows what WOULD run; the live path will also
|
||||
// remove the legacy source via `gbrain sources remove gstack-code-<slug>
|
||||
// --confirm-destructive` when that legacy source is registered. We can't
|
||||
// assert the remove step in dry-run because the orchestrator's preview
|
||||
// string lists what it would do, but the legacy removal is gated on the
|
||||
// legacy id being registered (which we can't probe in a sandboxed test
|
||||
// without a real gbrain CLI). Instead, assert the preview still includes
|
||||
// the new flow (sources add + sync + attach) at minimum.
|
||||
expect(r.stdout).toMatch(/gbrain sources add gstack-code-/);
|
||||
expect(r.stdout).toMatch(/gbrain sync --strategy code --source gstack-code-/);
|
||||
expect(r.stdout).toMatch(/gbrain sources attach gstack-code-/);
|
||||
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("dry-run preview includes the `sources attach` step (kubectl-style CWD pin)", () => {
|
||||
// Post-spike redesign: after sources add + sync, /sync-gbrain calls
|
||||
// `gbrain sources attach <id>` so subsequent gbrain code-def / code-refs
|
||||
// calls from anywhere under the worktree route to this source by default.
|
||||
// The dry-run preview must surface that step so the user knows what we
|
||||
// would do.
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
mkdirSync(gstackHome, { recursive: true });
|
||||
const repo = mkdtempSync(join(tmpdir(), "gstack-attach-preview-"));
|
||||
spawnSync("git", ["init", "--quiet", "-b", "main"], { cwd: repo });
|
||||
spawnSync("git", ["remote", "add", "origin", "https://github.com/garrytan/gstack.git"], { cwd: repo });
|
||||
|
||||
const r = spawnSync("bun", [SCRIPT, "--dry-run", "--code-only", "--quiet"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 60000,
|
||||
cwd: repo,
|
||||
env: { ...process.env, HOME: home, GSTACK_HOME: gstackHome },
|
||||
});
|
||||
expect(r.status).toBe(0);
|
||||
expect(r.stdout).toMatch(/gbrain sources attach gstack-code-/);
|
||||
|
||||
rmSync(repo, { recursive: true, force: true });
|
||||
rmSync(home, { recursive: true, force: true });
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user