From 0a955c0b983e33ac7ce26e688ee46fd7d7e760bb Mon Sep 17 00:00:00 2001 From: Gary Trakhman Date: Wed, 11 Mar 2026 15:09:30 -0400 Subject: [PATCH] fix: support pi extensions from ~/.pi/agent/extensions/ (#51) Update buildResourceLoader to include ~/.pi/agent/extensions/ in additionalExtensionPaths, allowing GSD to discover and use extensions installed in pi's default location. This resolves extension loading issues when users have extensions installed in ~/.pi/agent/extensions/ instead of ~/.gsd/agent/extensions/. - resource-loader.ts: add piExtensionsDir to additionalExtensionPaths - app-smoke.test.ts: add test verifying the source includes .pi path --- src/resource-loader.ts | 15 +++++++++++---- src/tests/app-smoke.test.ts | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/resource-loader.ts b/src/resource-loader.ts index f26341d5a..d7595dd4d 100644 --- a/src/resource-loader.ts +++ b/src/resource-loader.ts @@ -1,4 +1,5 @@ import { DefaultResourceLoader } from '@mariozechner/pi-coding-agent' +import { homedir } from 'node:os' import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' import { dirname, join, resolve } from 'node:path' import { fileURLToPath } from 'node:url' @@ -52,10 +53,16 @@ export function initResources(agentDir: string): void { } /** - * Constructs a DefaultResourceLoader with no additionalExtensionPaths. - * Extensions are synced to agentDir by initResources() and pi auto-discovers - * them from ~/.gsd/agent/extensions/ via its normal agentDir scan. + * Constructs a DefaultResourceLoader that loads extensions from both + * ~/.gsd/agent/extensions/ (GSD's default) and ~/.pi/agent/extensions/ (pi's default). + * This allows users to use extensions from either location. */ export function buildResourceLoader(agentDir: string): DefaultResourceLoader { - return new DefaultResourceLoader({ agentDir }) + const piAgentDir = join(homedir(), '.pi', 'agent') + const piExtensionsDir = join(piAgentDir, 'extensions') + + return new DefaultResourceLoader({ + agentDir, + additionalExtensionPaths: [piExtensionsDir], + }) } diff --git a/src/tests/app-smoke.test.ts b/src/tests/app-smoke.test.ts index a54301cff..7e8e24181 100644 --- a/src/tests/app-smoke.test.ts +++ b/src/tests/app-smoke.test.ts @@ -366,3 +366,33 @@ test("gsd launches and loads extensions without errors", async () => { "no ERR_MODULE_NOT_FOUND", ); }); +/** + * 9. buildResourceLoader includes ~/.pi/agent/extensions in additionalExtensionPaths + */ +test("buildResourceLoader source includes ~/.pi/agent/extensions path", async () => { + const { join } = await import("node:path"); + + // Verify the source code includes the pi extensions path + const loaderSrc = readFileSync(join(projectRoot, "src", "resource-loader.ts"), "utf-8"); + + // Check that buildResourceLoader references ~/.pi/agent + assert.ok( + loaderSrc.includes(".pi"), + "resource-loader.ts references .pi directory" + ); + assert.ok( + loaderSrc.includes("additionalExtensionPaths"), + "resource-loader.ts uses additionalExtensionPaths" + ); + assert.ok( + loaderSrc.includes("homedir()"), + "resource-loader.ts uses homedir() to construct paths" + ); + + // Verify the function constructs the correct path + assert.match( + loaderSrc, + /join\(homedir\(\),\s*['"]\.pi['"],\s*['"]agent['"]\)/, + "buildResourceLoader constructs ~/.pi/agent path" + ); +});