From 02b905f3f5b09b9e334b0e7103a8e539e56f71a0 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Fri, 10 Apr 2026 10:05:37 -0500 Subject: [PATCH 1/4] fix(gsd): resolve resource-loader import for deployed extensions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The relative import `../../../resource-loader.js` in auto.ts works from the source tree (src/resources/extensions/gsd/ → src/resource-loader.js) but breaks when extensions are deployed to ~/.gsd/agent/extensions/gsd/ (resolves to ~/.gsd/resource-loader.js which doesn't exist). Use createRequire to resolve the gsd-pi package root and import dist/resource-loader.js from there, which works in both source and deployed contexts. Regression introduced in #3899 (9ed543f1c8). --- src/resources/extensions/gsd/auto.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index 79b7fdc37..92ea79435 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -125,8 +125,9 @@ import { } from "./metrics.js"; import { setLogBasePath, logWarning, logError } from "./workflow-logger.js"; import { homedir } from "node:os"; -import { join } from "node:path"; +import { join, dirname } from "node:path"; import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs"; +import { createRequire } from "node:module"; import { atomicWriteSync } from "./atomic-write.js"; import { autoCommitCurrentBranch, @@ -1334,7 +1335,12 @@ export async function startAuto( // Re-sync managed resources on resume so long-lived auto sessions pick up // bundled extension updates before resume-time verification/state logic runs. const agentDir = process.env.GSD_CODING_AGENT_DIR || join(process.env.GSD_HOME || homedir(), ".gsd", "agent"); - const { initResources } = await import("../../../" + "resource-loader.js"); + // Resolve resource-loader from the gsd-pi package root — the relative + // "../../../resource-loader.js" path only works from the source tree but + // breaks when extensions are deployed to ~/.gsd/agent/extensions/gsd/. + const _req = createRequire(import.meta.url); + const pkgRoot = dirname(_req.resolve("gsd-pi/package.json")); + const { initResources } = await import(join(pkgRoot, "dist", "resource-loader.js")); initResources(agentDir); // Open the project DB before rebuild/derive so resume uses DB-backed // state instead of falling back to stale markdown parsing (#2940). From 41d4de1c328d7df6812d71093ff9400461c76f0c Mon Sep 17 00:00:00 2001 From: Jeremy Date: Fri, 10 Apr 2026 10:13:01 -0500 Subject: [PATCH 2/4] test(gsd): add regression test for resource-loader import path Verifies auto.ts does not use a relative import reaching above extensions/ for resource-loader (breaks on deployment to ~/.gsd/). Guards against regression of the fix for #3899. --- .../tests/resource-loader-import-path.test.ts | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts diff --git a/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts b/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts new file mode 100644 index 000000000..e8a5bfe85 --- /dev/null +++ b/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts @@ -0,0 +1,37 @@ +// GSD2 — Regression test for broken resource-loader import path +// Ensures auto.ts imports resource-loader via package resolution, not a +// relative path that breaks when deployed to ~/.gsd/agent/extensions/gsd/. + +import { describe, test } from "node:test"; +import assert from "node:assert/strict"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +const autoSrc = readFileSync(join(import.meta.dirname, "..", "auto.ts"), "utf-8"); + +describe("resource-loader import path", () => { + test("must not use relative import reaching above extensions/", () => { + // The old broken pattern: import("../../../" + "resource-loader.js") + // This resolves to ~/.gsd/resource-loader.js from deployed location, which + // doesn't exist. Regression introduced in #3899. + const brokenPattern = /import\(\s*["']\.\.\/\.\.\/\.\..*resource-loader/; + assert.ok( + !brokenPattern.test(autoSrc), + "auto.ts must not import resource-loader via relative path above extensions/ — " + + "breaks when deployed to ~/.gsd/agent/extensions/gsd/ (see #3899)", + ); + }); + + test("uses createRequire to resolve resource-loader from package root", () => { + // The fix uses createRequire to find gsd-pi/package.json, then imports + // dist/resource-loader.js from there — works in both source and deployed. + assert.ok( + autoSrc.includes('createRequire(import.meta.url)'), + "auto.ts should use createRequire to resolve resource-loader", + ); + assert.ok( + autoSrc.includes('resolve("gsd-pi/package.json")'), + "auto.ts should resolve gsd-pi package root via package.json", + ); + }); +}); From 6d9f02054d6d8ccf6344fc1fe0ae6aa5be56bb4d Mon Sep 17 00:00:00 2001 From: Jeremy Date: Fri, 10 Apr 2026 10:19:07 -0500 Subject: [PATCH 3/4] fix(test): update discord invite test path after docs reorganization The docs were moved from docs/what-is-pi/ to docs/dev/what-is-pi/ but the test path was not updated, causing CI to fail with ENOENT. --- src/resources/extensions/gsd/tests/discord-invite-links.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resources/extensions/gsd/tests/discord-invite-links.test.ts b/src/resources/extensions/gsd/tests/discord-invite-links.test.ts index 8b82d4749..dffe0af61 100644 --- a/src/resources/extensions/gsd/tests/discord-invite-links.test.ts +++ b/src/resources/extensions/gsd/tests/discord-invite-links.test.ts @@ -18,7 +18,7 @@ const VALID_INVITE = "https://discord.com/invite/nKXTsAcmbT"; /** Files that contain user-facing Discord invite links. */ const FILES_WITH_INVITE_LINKS: string[] = [ "README.md", - "docs/what-is-pi/15-pi-packages-the-ecosystem.md", + "docs/dev/what-is-pi/15-pi-packages-the-ecosystem.md", ]; describe("Discord invite links (#2699)", () => { From 9d477b4a2e63d9eb8eeed5b3ed33cbd1af949b77 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Fri, 10 Apr 2026 10:26:33 -0500 Subject: [PATCH 4/4] fix(ci): update FILE-SYSTEM-MAP.md path after docs reorganization The docs reorg moved FILE-SYSTEM-MAP.md from docs/ to docs/dev/ but pr-risk-check.mjs was not updated, causing the PR Risk Report CI job to fail on every PR. --- scripts/pr-risk-check.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pr-risk-check.mjs b/scripts/pr-risk-check.mjs index 18c88e02b..94b61f13b 100644 --- a/scripts/pr-risk-check.mjs +++ b/scripts/pr-risk-check.mjs @@ -20,7 +20,7 @@ import { createInterface } from 'readline'; const __dirname = dirname(fileURLToPath(import.meta.url)); const REPO_ROOT = resolve(__dirname, '..'); -const MAP_PATH = resolve(REPO_ROOT, 'docs/FILE-SYSTEM-MAP.md'); +const MAP_PATH = resolve(REPO_ROOT, 'docs/dev/FILE-SYSTEM-MAP.md'); // --------------------------------------------------------------------------- // Risk tier definitions