mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-24 10:39:57 +02:00
fix: detect PgBouncer transaction-mode pooler and set GBRAIN_PREPARE=true (#1435)
When gbrain connects through a PgBouncer transaction-mode pooler (port
6543), it auto-disables prepared statements. This breaks `gbrain search`
silently — the /sync-gbrain capability check fails and the GBrain Search
Guidance block never gets written to CLAUDE.md.
Three-layer fix:
1. **lib/gbrain-exec.ts** — `buildGbrainEnv()` now detects port 6543 in
the effective DATABASE_URL and sets `GBRAIN_PREPARE=true` in the env
passed to every gbrain spawn. This is the single chokepoint — all
gstack gbrain invocations inherit the fix. Caller can opt out with
`GBRAIN_PREPARE=false`.
2. **sync-gbrain/SKILL.md{,.tmpl}** — capability check now exports
`GBRAIN_PREPARE=true` explicitly and retries search up to 3x with 1s
delay for async index propagation under connection pooling.
3. **bin/gstack-gbrain-detect** — surfaces `gbrain_pooler_mode` field
("transaction" | "session" | null) in the preamble probe JSON so
/setup-gbrain and /sync-gbrain can advise users about pooler state.
Closes #1435
Built with [ClosedLoop.AI](https://closedloop.ai) | [GitHub](https://github.com/closedloop-ai/claude-plugins)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,8 @@
|
||||
* "gstack_brain_sync_mode": "off"|"artifacts-only"|"full",
|
||||
* "gstack_brain_git": true|false,
|
||||
* "gstack_artifacts_remote": "https://..." | "",
|
||||
* "gbrain_local_status": "ok"|"no-cli"|"missing-config"|"broken-config"|"broken-db"
|
||||
* "gbrain_local_status": "ok"|"no-cli"|"missing-config"|"broken-config"|"broken-db",
|
||||
* "gbrain_pooler_mode": "transaction"|"session"|null
|
||||
* }
|
||||
*
|
||||
* Backward compatibility (per plan codex #5): the 9 pre-existing fields stay
|
||||
@@ -42,6 +43,7 @@ import {
|
||||
resolveGbrainBin,
|
||||
readGbrainVersion,
|
||||
} from "../lib/gbrain-local-status";
|
||||
import { isTransactionModePooler } from "../lib/gbrain-exec";
|
||||
|
||||
const STATE_DIR = process.env.GSTACK_HOME || join(userHome(), ".gstack");
|
||||
const SCRIPT_DIR = __dirname;
|
||||
@@ -98,6 +100,17 @@ function detectConfig(): { exists: boolean; engine: "pglite" | "postgres" | null
|
||||
return { exists: true, engine: null };
|
||||
}
|
||||
|
||||
// --- pooler mode detection (#1435) ---
|
||||
//
|
||||
// Reads DATABASE_URL from ~/.gbrain/config.json and checks whether it targets
|
||||
// a PgBouncer transaction-mode pooler (port 6543). Surfaced so /sync-gbrain
|
||||
// and /setup-gbrain can advise users when search may require GBRAIN_PREPARE.
|
||||
function detectPoolerMode(): "transaction" | "session" | "unknown" | null {
|
||||
const parsed = tryReadJSON(GBRAIN_CONFIG) as { database_url?: string } | null;
|
||||
if (!parsed?.database_url) return null;
|
||||
return isTransactionModePooler(parsed.database_url) ? "transaction" : "session";
|
||||
}
|
||||
|
||||
// --- gbrain doctor health (any nonzero exit or non-"ok"/"warnings" status → false) ---
|
||||
//
|
||||
// Uses --fast to avoid hanging on a dead DB. Per the local-status classifier
|
||||
@@ -215,6 +228,7 @@ function main(): void {
|
||||
gstack_brain_git: detectBrainGit(),
|
||||
gstack_artifacts_remote: detectArtifactsRemote(),
|
||||
gbrain_local_status: localEngineStatus({ noCache }),
|
||||
gbrain_pooler_mode: detectPoolerMode(),
|
||||
};
|
||||
|
||||
process.stdout.write(JSON.stringify(out, null, 2) + "\n");
|
||||
|
||||
Reference in New Issue
Block a user