mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-19 08:10:08 +02:00
fix(gbrain): probe CLI without command builtin
This commit is contained in:
@@ -429,15 +429,6 @@ function constrainSourceId(prefix: string, raw: string): string {
|
||||
return tail ? `${prefix}-${tail}-${hash}` : `${prefix}-${hash}`;
|
||||
}
|
||||
|
||||
function gbrainAvailable(): boolean {
|
||||
try {
|
||||
execSync("command -v gbrain", { stdio: "ignore" });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Lock file (D1) ─────────────────────────────────────────────────────────
|
||||
|
||||
interface LockInfo {
|
||||
@@ -529,9 +520,6 @@ async function runCodeImport(args: CliArgs): Promise<StageResult> {
|
||||
if (!root) {
|
||||
return { name: "code", ran: false, ok: true, duration_ms: 0, summary: "skipped (not in git repo)" };
|
||||
}
|
||||
if (!gbrainAvailable()) {
|
||||
return { name: "code", ran: false, ok: false, duration_ms: 0, summary: "skipped (gbrain CLI not in PATH)" };
|
||||
}
|
||||
|
||||
const sourceId = deriveCodeSourceId(root);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ import {
|
||||
rmSync,
|
||||
} from "fs";
|
||||
import { join, basename, dirname } from "path";
|
||||
import { execSync, execFileSync, spawnSync, spawn, type ChildProcess } from "child_process";
|
||||
import { execFileSync, spawnSync, spawn, type ChildProcess } from "child_process";
|
||||
import { homedir } from "os";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
@@ -809,7 +809,6 @@ let _gbrainAvailability: boolean | null = null;
|
||||
function gbrainAvailable(): boolean {
|
||||
if (_gbrainAvailability !== null) return _gbrainAvailability;
|
||||
try {
|
||||
execSync("command -v gbrain", { stdio: "ignore" });
|
||||
// Probe `--help` for the `import` subcommand. gbrain v0.20.0+ ships
|
||||
// `import <dir>` (batch markdown import via path-authoritative slugs).
|
||||
// If absent, we surface a single clean error here rather than failing
|
||||
|
||||
@@ -101,13 +101,13 @@ export function resolveGbrainBin(env?: NodeJS.ProcessEnv): string | null {
|
||||
if (_gbrainBinCache.has(key)) return _gbrainBinCache.get(key)!;
|
||||
let result: string | null = null;
|
||||
try {
|
||||
const out = execFileSync("sh", ["-c", "command -v gbrain"], {
|
||||
execFileSync("gbrain", ["--version"], {
|
||||
encoding: "utf-8",
|
||||
timeout: 2_000,
|
||||
stdio: ["ignore", "pipe", "ignore"],
|
||||
stdio: ["ignore", "ignore", "ignore"],
|
||||
env: e,
|
||||
});
|
||||
result = out.trim() || null;
|
||||
result = "gbrain";
|
||||
} catch {
|
||||
result = null;
|
||||
}
|
||||
@@ -266,4 +266,3 @@ export function localEngineStatus(opts: ClassifyOptions = {}): LocalEngineStatus
|
||||
writeCache(fresh, key);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import { describe, it, expect, beforeEach, afterEach } from "bun:test";
|
||||
import {
|
||||
mkdtempSync,
|
||||
writeFileSync,
|
||||
readFileSync,
|
||||
mkdirSync,
|
||||
rmSync,
|
||||
chmodSync,
|
||||
@@ -160,6 +161,16 @@ describe("lib/gbrain-local-status — five status cases", () => {
|
||||
restoreEnv = null;
|
||||
});
|
||||
|
||||
it("probes the gbrain executable directly instead of shelling through command -v", () => {
|
||||
const source = readFileSync(
|
||||
join(import.meta.dir, "..", "lib", "gbrain-local-status.ts"),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
expect(source).not.toContain('command -v gbrain');
|
||||
expect(source).toContain('execFileSync("gbrain", ["--version"]');
|
||||
});
|
||||
|
||||
it("returns 'no-cli' when gbrain is not on PATH", () => {
|
||||
env = makeEnv({ withGbrain: false });
|
||||
restoreEnv = applyEnv(env);
|
||||
|
||||
@@ -55,6 +55,13 @@ describe("gstack-gbrain-sync CLI", () => {
|
||||
expect(r.stderr).toContain("Unknown argument: --bogus");
|
||||
});
|
||||
|
||||
it("uses the shared local gbrain status classifier instead of shelling through command -v", () => {
|
||||
const source = readFileSync(SCRIPT, "utf-8");
|
||||
|
||||
expect(source).not.toContain('command -v gbrain');
|
||||
expect(source).toContain("localEngineStatus");
|
||||
});
|
||||
|
||||
it("--dry-run with --code-only reports the code import preview only", () => {
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
|
||||
@@ -421,6 +421,13 @@ esac
|
||||
}
|
||||
|
||||
describe("gstack-memory-ingest writer (gbrain v0.20+ batch `import` interface)", () => {
|
||||
it("probes the gbrain executable directly instead of shelling through command -v", () => {
|
||||
const source = readFileSync(SCRIPT, "utf-8");
|
||||
|
||||
expect(source).not.toContain('command -v gbrain');
|
||||
expect(source).toContain('execFileSync("gbrain", ["--help"]');
|
||||
});
|
||||
|
||||
it("invokes `gbrain import <dir> --no-embed --json` exactly once with hierarchical staging", () => {
|
||||
const home = makeTestHome();
|
||||
const gstackHome = join(home, ".gstack");
|
||||
|
||||
Reference in New Issue
Block a user