mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 20:30:47 +02:00
fix: persist indexed repo per provider and detect installs honestly
search was running in cwd and missing the repo you indexed. Persist the indexed path per provider in the selection store and resolve it back so `search` reads the same graph `index` built. Graphify availability now checks `graphify --version` (installed = selectable) instead of "a graph already exists here", and the CLI keys Graphify sources on the repo path. 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
f0f13998d8
commit
6686202be9
@@ -29,6 +29,7 @@ import {
|
|||||||
resolveSelectedProvider,
|
resolveSelectedProvider,
|
||||||
setConsent,
|
setConsent,
|
||||||
setProvider,
|
setProvider,
|
||||||
|
setRoot,
|
||||||
type CodeProviderId,
|
type CodeProviderId,
|
||||||
} from "../lib/code-intelligence";
|
} from "../lib/code-intelligence";
|
||||||
|
|
||||||
@@ -98,11 +99,15 @@ async function cmdIndex(pathArg: string | undefined): Promise<void> {
|
|||||||
if (!provider!.local && !consented) {
|
if (!provider!.local && !consented) {
|
||||||
fail(`${provider!.label} would send this repo's content off the machine. Run \`gstack-code-intelligence consent ${repoPath}\` first.`);
|
fail(`${provider!.label} would send this repo's content off the machine. Run \`gstack-code-intelligence consent ${repoPath}\` first.`);
|
||||||
}
|
}
|
||||||
const repo = { id: basename(repoPath), path: repoPath };
|
// Graphify keys sources on the repo path; GBrain/Sourcebot on a short id.
|
||||||
|
const sourceId = provider!.id === "graphify" ? repoPath : basename(repoPath);
|
||||||
|
const repo = { id: sourceId, path: repoPath };
|
||||||
try {
|
try {
|
||||||
const registered = await provider!.registerSource(repo, { consented });
|
const registered = await provider!.registerSource(repo, { consented });
|
||||||
out(`registered ${repo.id} with ${provider!.label} (${registered.state})`);
|
out(`registered ${repo.id} with ${provider!.label} (${registered.state})`);
|
||||||
const refreshed = await provider!.refresh({ id: registered.id }, { consented });
|
const refreshed = await provider!.refresh({ id: registered.id }, { consented });
|
||||||
|
// Remember which repo this provider indexed so `search` reads the same graph.
|
||||||
|
setRoot(provider!.id, repoPath);
|
||||||
out(`indexed: ${refreshed.state}${refreshed.itemCount != null ? ` (${refreshed.itemCount} items)` : ""}`);
|
out(`indexed: ${refreshed.state}${refreshed.itemCount != null ? ` (${refreshed.itemCount} items)` : ""}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleProviderError(err, provider!.label);
|
handleProviderError(err, provider!.label);
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export {
|
|||||||
setProvider,
|
setProvider,
|
||||||
setConsent,
|
setConsent,
|
||||||
hasConsent,
|
hasConsent,
|
||||||
|
setRoot,
|
||||||
|
getRoot,
|
||||||
type Selection,
|
type Selection,
|
||||||
} from "./selection";
|
} from "./selection";
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -15,9 +15,9 @@
|
|||||||
|
|
||||||
import { localEngineStatus } from "../gbrain-local-status";
|
import { localEngineStatus } from "../gbrain-local-status";
|
||||||
import { GbrainProvider } from "./gbrain-adapter";
|
import { GbrainProvider } from "./gbrain-adapter";
|
||||||
import { GraphifyProvider, type GraphifyOptions } from "./graphify-adapter";
|
import { GraphifyProvider, graphifyInstalled, type GraphifyOptions } from "./graphify-adapter";
|
||||||
import { SourcebotProvider, type SourcebotOptions } from "./sourcebot-adapter";
|
import { SourcebotProvider, type SourcebotOptions } from "./sourcebot-adapter";
|
||||||
import { readSelection } from "./selection";
|
import { readSelection, getRoot } from "./selection";
|
||||||
import type { CodeProvider, CodeProviderId } from "./contract";
|
import type { CodeProvider, CodeProviderId } from "./contract";
|
||||||
|
|
||||||
/** Recommendation order — GBrain first. */
|
/** Recommendation order — GBrain first. */
|
||||||
@@ -34,8 +34,12 @@ export function providerById(id: CodeProviderId, opts: PickerOptions = {}): Code
|
|||||||
switch (id) {
|
switch (id) {
|
||||||
case "gbrain":
|
case "gbrain":
|
||||||
return new GbrainProvider();
|
return new GbrainProvider();
|
||||||
case "graphify":
|
case "graphify": {
|
||||||
return new GraphifyProvider({ env: opts.env, ...opts.graphify });
|
// Default the graph root to the repo Graphify last indexed, so `search`
|
||||||
|
// reads the same graph `index` built (not whatever cwd happens to be).
|
||||||
|
const root = opts.graphify?.root ?? getRoot("graphify", opts.env);
|
||||||
|
return new GraphifyProvider({ env: opts.env, ...opts.graphify, ...(root ? { root } : {}) });
|
||||||
|
}
|
||||||
case "sourcebot":
|
case "sourcebot":
|
||||||
return new SourcebotProvider({ env: opts.env, ...opts.sourcebot });
|
return new SourcebotProvider({ env: opts.env, ...opts.sourcebot });
|
||||||
}
|
}
|
||||||
@@ -65,14 +69,17 @@ export async function detectAvailable(opts: PickerOptions = {}): Promise<Availab
|
|||||||
const gbrainStatus = localEngineStatus({ env: opts.env });
|
const gbrainStatus = localEngineStatus({ env: opts.env });
|
||||||
const gbrainOk = gbrainStatus === "ok" || gbrainStatus === "timeout";
|
const gbrainOk = gbrainStatus === "ok" || gbrainStatus === "timeout";
|
||||||
|
|
||||||
let graphifyOk = false;
|
// Available = the CLI is installed and selectable (NOT "a graph already exists
|
||||||
let graphifyDetail = "graphify CLI not installed";
|
// here"). A freshly installed Graphify with no graph yet is still available.
|
||||||
try {
|
const graphifyOk = graphifyInstalled(opts.env);
|
||||||
const s = await new GraphifyProvider({ env: opts.env, ...opts.graphify }).status();
|
let graphifyDetail = "graphify CLI not installed (pip install graphifyy, Python >= 3.10)";
|
||||||
graphifyOk = s.state === "ready";
|
if (graphifyOk) {
|
||||||
graphifyDetail = graphifyOk ? "graph indexed in this repo" : "installed; no graph in this repo yet";
|
try {
|
||||||
} catch {
|
const s = await new GraphifyProvider({ env: opts.env, ...opts.graphify }).status();
|
||||||
graphifyOk = false;
|
graphifyDetail = s.state === "ready" ? "installed; graph built in this repo" : "installed; run `index` to build a graph";
|
||||||
|
} catch {
|
||||||
|
graphifyDetail = "installed";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let sourcebotOk = false;
|
let sourcebotOk = false;
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export interface Selection {
|
|||||||
provider: CodeProviderId | null;
|
provider: CodeProviderId | null;
|
||||||
/** Absolute repo path → consented. */
|
/** Absolute repo path → consented. */
|
||||||
consents: Record<string, boolean>;
|
consents: Record<string, boolean>;
|
||||||
|
/** Provider id → the absolute repo path it last indexed (so search finds it). */
|
||||||
|
roots: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EMPTY: Selection = { provider: null, consents: {} };
|
const EMPTY: Selection = { provider: null, consents: {}, roots: {} };
|
||||||
|
|
||||||
function storePath(env: NodeJS.ProcessEnv = process.env): string {
|
function storePath(env: NodeJS.ProcessEnv = process.env): string {
|
||||||
const home = env.GSTACK_HOME || join(env.HOME || homedir(), ".gstack");
|
const home = env.GSTACK_HOME || join(env.HOME || homedir(), ".gstack");
|
||||||
@@ -35,6 +37,7 @@ export function readSelection(env: NodeJS.ProcessEnv = process.env): Selection {
|
|||||||
return {
|
return {
|
||||||
provider: raw.provider ?? null,
|
provider: raw.provider ?? null,
|
||||||
consents: raw.consents && typeof raw.consents === "object" ? raw.consents : {},
|
consents: raw.consents && typeof raw.consents === "object" ? raw.consents : {},
|
||||||
|
roots: raw.roots && typeof raw.roots === "object" ? raw.roots : {},
|
||||||
};
|
};
|
||||||
} catch {
|
} catch {
|
||||||
return { ...EMPTY };
|
return { ...EMPTY };
|
||||||
@@ -66,3 +69,15 @@ export function setConsent(repoPath: string, consented: boolean, env: NodeJS.Pro
|
|||||||
export function hasConsent(repoPath: string, env: NodeJS.ProcessEnv = process.env): boolean {
|
export function hasConsent(repoPath: string, env: NodeJS.ProcessEnv = process.env): boolean {
|
||||||
return readSelection(env).consents[resolve(repoPath)] === true;
|
return readSelection(env).consents[resolve(repoPath)] === true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Record the repo path a provider last indexed, so search reads the same graph. */
|
||||||
|
export function setRoot(provider: CodeProviderId, repoPath: string, env: NodeJS.ProcessEnv = process.env): Selection {
|
||||||
|
const current = readSelection(env);
|
||||||
|
const next: Selection = { ...current, roots: { ...current.roots, [provider]: resolve(repoPath) } };
|
||||||
|
write(next, env);
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoot(provider: CodeProviderId, env: NodeJS.ProcessEnv = process.env): string | undefined {
|
||||||
|
return readSelection(env).roots[provider];
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user