mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 04:10:47 +02:00
fix: correct adapters against real running providers (round 2)
Ran real backends in isolated environments (real Postgres-backed gbrain, live Sourcebot v6.5.0 with anonymous access, real graphify 0.9.23). All three now index + search end-to-end. Fixes: - gbrain: RESTORE `--strategy code` in refresh — round 1 removed it on a --help misread, which silently stopped code from ever being indexed. refresh now runs the verified two-pass (`sync`, then `sync --strategy code --full`). Pinned by a new test so the regression can't return. - sourcebot: an API key is NOT required for local use — anonymous access (FORCE_ENABLE_ANONYMOUS_ACCESS=true) serves /api/search keyless (verified). Key stays optional; only the messaging changed (anonymous-access first, key as fallback) plus a note that a local repo needs remote.origin.url to index. - graphify: correct the docstring — for CODE both `graphify <dir>` and `graphify update` are AST-only (no LLM); the LLM only renames clusters and ingests non-code, which our parser ignores. No LLM mode; local=true is correct. Docs: capability matrix + "Verified against real environments" updated to record all three proven end-to-end and to correct the two first-round mistakes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a524d860a8
commit
ab7989c6c1
@@ -90,11 +90,15 @@ export class GbrainProvider implements CodeProvider {
|
||||
|
||||
async refresh(source: SourceRef, opts: OpOptions = {}): Promise<SourceStatus> {
|
||||
assertEgressConsent(this, opts);
|
||||
// `gbrain sync` has no `--strategy` flag (verified against gbrain 0.42.x --help).
|
||||
this.#assertOk(spawnGbrain(["sync", "--source", source.id], {
|
||||
baseEnv: opts.env,
|
||||
timeout: opts.timeout ?? DEFAULT_TIMEOUT_MS,
|
||||
}));
|
||||
const timeout = opts.timeout ?? DEFAULT_TIMEOUT_MS;
|
||||
// Two passes, verified end-to-end against real Postgres-backed gbrain 0.42.56:
|
||||
// 1. default sync (markdown strategy) — indexes docs.
|
||||
// 2. `sync --strategy code` — the ACTUAL code-indexing pass. Without it code
|
||||
// is never indexed (the whole point of a code provider); `code-def` stays
|
||||
// "not_built" and search only finds incidental doc mentions. `--full`
|
||||
// forces it past the per-source checkpoint the markdown pass advanced.
|
||||
this.#assertOk(spawnGbrain(["sync", "--source", source.id], { baseEnv: opts.env, timeout }));
|
||||
this.#assertOk(spawnGbrain(["sync", "--source", source.id, "--strategy", "code", "--full"], { baseEnv: opts.env, timeout }));
|
||||
return this.status(source, opts);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
/**
|
||||
* Graphify adapter — real CLI integration (github.com/Graphify-Labs/graphify).
|
||||
*
|
||||
* Graphify is a LOCAL tree-sitter knowledge graph. The genuinely local, no-LLM
|
||||
* build is `graphify update <dir>` — it writes `<dir>/graphify-out/graph.json`
|
||||
* with NO embeddings and NO network (verified against graphify 0.9.23). NOTE:
|
||||
* the bare `graphify <dir>` build instead runs LLM semantic extraction (a gemini
|
||||
* backend needing an API key + network), so this adapter deliberately uses
|
||||
* `graphify update`, which keeps the "local, no egress consent" invariant true.
|
||||
* Graphify is a LOCAL tree-sitter knowledge graph. For CODE, `graphify <dir>`
|
||||
* and `graphify update <dir>` produce the SAME AST graph with NO LLM and NO
|
||||
* network (verified against graphify 0.9.23 — both emit `AST extraction on N
|
||||
* code files`, all node origins `ast`). The LLM backend (openai/gemini) is only
|
||||
* used to RENAME community clusters (`graphify label` / `cluster-only`) and to
|
||||
* ingest non-code docs (`graphify add`); it adds zero nodes/edges, and our parser
|
||||
* discards the `community=` field it touches — so an LLM mode would send code
|
||||
* off-machine for no change in search output, and is intentionally not offered.
|
||||
*
|
||||
* This adapter uses `graphify update <dir>` (writes `<dir>/graphify-out/graph.json`
|
||||
* and does clustering in one shot) and stays fully local — nothing leaves the
|
||||
* machine, so `local = true` and no egress consent is needed.
|
||||
*
|
||||
* Query is `graphify query "<q>" --graph <dir>/graphify-out/graph.json`; the
|
||||
* `--graph` flag points at the built graph so search never depends on cwd.
|
||||
|
||||
@@ -46,9 +46,11 @@ export interface SourcebotOptions {
|
||||
/** Path to the server's config.json (for register_source). Defaults to SOURCEBOT_CONFIG. */
|
||||
configPath?: string;
|
||||
/**
|
||||
* API key for the Sourcebot REST API. Defaults to SOURCEBOT_API_KEY. Sourcebot
|
||||
* v5 gates `/api/search` behind auth (`Authorization: Bearer <key>`); without
|
||||
* it, `search` gets HTTP 401. Generate one in Settings -> API Keys.
|
||||
* OPTIONAL API key for the Sourcebot REST API. Defaults to SOURCEBOT_API_KEY.
|
||||
* A local instance with anonymous access enabled
|
||||
* (`FORCE_ENABLE_ANONYMOUS_ACCESS=true`) serves `/api/search` with NO key —
|
||||
* verified keyless against a real Sourcebot v6.5.0. Only set a key when your
|
||||
* instance is login-gated; it is sent as `Authorization: Bearer <key>`.
|
||||
*/
|
||||
apiKey?: string;
|
||||
/** Injectable fetch for tests. */
|
||||
@@ -93,7 +95,12 @@ export class SourcebotProvider implements CodeProvider {
|
||||
return this.capabilities.has(capability);
|
||||
}
|
||||
|
||||
/** Add the repo as a local `git` connection in Sourcebot's config.json. */
|
||||
/**
|
||||
* Add the repo as a local `git` connection in Sourcebot's config.json.
|
||||
* NOTE: Sourcebot silently SKIPS a local repo that has no `remote.origin.url`
|
||||
* (logs "Skipping <path> - remote.origin.url not found"); a freshly `git init`'d
|
||||
* repo must set an origin before it will index.
|
||||
*/
|
||||
async registerSource(repo: RepoRef, opts: OpOptions = {}): Promise<SourceStatus> {
|
||||
assertEgressConsent(this, opts); // no-op when the server is loopback (local)
|
||||
if (!this.#configPath) {
|
||||
@@ -148,7 +155,7 @@ export class SourcebotProvider implements CodeProvider {
|
||||
opts.timeout ?? DEFAULT_TIMEOUT_MS,
|
||||
);
|
||||
if (res.status === 401 || res.status === 403) {
|
||||
return { id: "*", state: "unknown", partial: true, detail: "reachable but not authenticated (set SOURCEBOT_API_KEY)" };
|
||||
return { id: "*", state: "unknown", partial: true, detail: "reachable but login-gated (enable anonymous access with FORCE_ENABLE_ANONYMOUS_ACCESS=true for local use, or set SOURCEBOT_API_KEY)" };
|
||||
}
|
||||
return { id: "*", state: res.ok ? "ready" : "unknown", partial: true, detail: `HTTP ${res.status}` };
|
||||
} catch {
|
||||
@@ -168,7 +175,7 @@ export class SourcebotProvider implements CodeProvider {
|
||||
throw new CodeProviderError("PROVIDER_UNAVAILABLE", `Sourcebot unreachable at ${this.#baseUrl}: ${(err as Error).message}`, this.id);
|
||||
}
|
||||
if (res.status === 401 || res.status === 403) {
|
||||
throw new CodeProviderError("PROVIDER_UNAVAILABLE", `Sourcebot requires authentication; set SOURCEBOT_API_KEY (HTTP ${res.status})`, this.id);
|
||||
throw new CodeProviderError("PROVIDER_UNAVAILABLE", `Sourcebot is login-gated (HTTP ${res.status}); enable anonymous access (FORCE_ENABLE_ANONYMOUS_ACCESS=true) for local use, or set SOURCEBOT_API_KEY`, this.id);
|
||||
}
|
||||
if (!res.ok) throw new CodeProviderError("PROVIDER_ERROR", `Sourcebot ${path} returned HTTP ${res.status}`, this.id);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user