Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions bin/gstack-gbrain-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,14 @@ function gbrainSupportsSourcesRename(env?: NodeJS.ProcessEnv): boolean {
* helper can be exercised without a real gbrain CLI.
*/
export function sourceLocalPath(sourceId: string, env?: NodeJS.ProcessEnv): string | null {
const list = execGbrainJson<Array<{ id: string; local_path?: string }>>(
["sources", "list", "--json"],
{ baseEnv: env },
);
if (!list) return null;
const raw = execGbrainJson<
| Array<{ id: string; local_path?: string }>
| { sources?: Array<{ id: string; local_path?: string }> }
>(["sources", "list", "--json"], { baseEnv: env });
if (!raw) return null;
// gbrain v0.18.0+ returns {sources: [...]}; older versions returned a raw array.
// Defensive against both shapes so this works on any gbrain version.
const list = Array.isArray(raw) ? raw : raw.sources ?? [];
const found = list.find((s) => s.id === sourceId);
return found?.local_path ?? null;
}
Expand Down
28 changes: 26 additions & 2 deletions test/gstack-gbrain-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,24 @@ describe("sourceLocalPath", () => {
rmSync(bindir, { recursive: true, force: true });
});

it("returns local_path when the source exists", () => {
// gbrain v0.18.0+ returns {sources: [...]}; this is the live contract.
it("returns local_path when the source exists (gbrain v0.18.0+ wrapped shape)", () => {
makeShim(bindir, {
"sources list --json": {
stdout: JSON.stringify({
sources: [
{ id: "other-source", local_path: "/x" },
{ id: "target-id", local_path: "/repo/match" },
],
}),
},
});
expect(sourceLocalPath("target-id", envWithBindir(bindir))).toBe("/repo/match");
});

// Pre-v0.18.0 gbrain returned a raw array. Keep back-compat so the helper
// works regardless of which gbrain the user has on PATH.
it("returns local_path when the source exists (pre-v0.18.0 raw-array shape)", () => {
makeShim(bindir, {
"sources list --json": {
stdout: JSON.stringify([
Expand All @@ -824,7 +841,14 @@ describe("sourceLocalPath", () => {
expect(sourceLocalPath("target-id", envWithBindir(bindir))).toBe("/repo/match");
});

it("returns null when the source is missing", () => {
it("returns null when the source is missing (wrapped shape)", () => {
makeShim(bindir, {
"sources list --json": { stdout: JSON.stringify({ sources: [] }) },
});
expect(sourceLocalPath("missing-id", envWithBindir(bindir))).toBeNull();
});

it("returns null when the source is missing (raw-array shape)", () => {
makeShim(bindir, {
"sources list --json": { stdout: "[]" },
});
Expand Down