From cc90f6761d2c57a9b799c30a8971ac2d53f7e17b Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 25 Apr 2026 13:30:48 -0700 Subject: [PATCH] fix(browse): lazy GSTACK_HOME resolution in domain-skills Module-level constants (GLOBAL_FILE, derived path) were evaluated at module-load and cached. When E2E and unit tests run in the same Bun test pass and set GSTACK_HOME differently, the second test sees the first test's path. Switch to lazy gstackHome() / globalFile() / projectFile() helpers so process.env mutations take effect. Mirrors the pattern already used in telemetry.ts. Co-Authored-By: Claude Opus 4.7 (1M context) --- browse/src/domain-skills.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/browse/src/domain-skills.ts b/browse/src/domain-skills.ts index 002968c8..b68c031f 100644 --- a/browse/src/domain-skills.ts +++ b/browse/src/domain-skills.ts @@ -62,11 +62,16 @@ export interface DomainSkillRow { const PROMOTE_THRESHOLD = 3; -const GSTACK_HOME = process.env.GSTACK_HOME || path.join(os.homedir(), '.gstack'); -const GLOBAL_FILE = path.join(GSTACK_HOME, 'global-domain-skills.jsonl'); +function gstackHome(): string { + return process.env.GSTACK_HOME || path.join(os.homedir(), '.gstack'); +} + +function globalFile(): string { + return path.join(gstackHome(), 'global-domain-skills.jsonl'); +} function projectFile(slug: string): string { - return path.join(GSTACK_HOME, 'projects', slug, 'learnings.jsonl'); + return path.join(gstackHome(), 'projects', slug, 'learnings.jsonl'); } // ─── Hostname normalization (T3) ────────────────────────────── @@ -222,7 +227,7 @@ export async function readSkill(host: string, projectSlug: string): Promise { const normalized = normalizeHost(host); - const file = scope === 'project' ? projectFile(projectSlug) : GLOBAL_FILE; + const file = scope === 'project' ? projectFile(projectSlug) : globalFile(); const rows = await readRows(file); const matching = rows.filter((r) => r.host === normalized && r.scope === scope && !r.tombstone); if (matching.length < 2) { @@ -384,7 +389,7 @@ export async function rollbackSkill(host: string, projectSlug: string, scope: Sk */ export async function listSkills(projectSlug: string): Promise<{ project: DomainSkillRow[]; global: DomainSkillRow[] }> { const projectRows = await readRows(projectFile(projectSlug)); - const globalRows = await readRows(GLOBAL_FILE); + const globalRows = await readRows(globalFile()); const projectLatest = Array.from(resolveLatest(projectRows).values()); const globalLatest = Array.from(resolveLatest(globalRows).values()).filter((r) => r.state === 'global'); return { project: projectLatest, global: globalLatest }; @@ -395,7 +400,7 @@ export async function listSkills(projectSlug: string): Promise<{ project: Domain */ export async function deleteSkill(host: string, projectSlug: string, scope: SkillScope = 'project'): Promise { const normalized = normalizeHost(host); - const file = scope === 'project' ? projectFile(projectSlug) : GLOBAL_FILE; + const file = scope === 'project' ? projectFile(projectSlug) : globalFile(); const rows = await readRows(file); const latest = resolveLatest(rows); const current = latest.get(`${scope}::${normalized}`);