diff --git a/configs/nixos/modules/shell/pi/default.nix b/configs/nixos/modules/shell/pi/default.nix index 39889eb..2e80a6c 100644 --- a/configs/nixos/modules/shell/pi/default.nix +++ b/configs/nixos/modules/shell/pi/default.nix @@ -11,12 +11,10 @@ let cfg = config.modules.shell.pi; user = config.user.name; piDir = "${config.users.users.${user}.home}/.pi/agent"; - patchedPi = pkgs.pi-coding-agent.overrideAttrs (old: { - patches = (old.patches or [ ]) ++ [ - ./patches/pi-project-resource-ancestors.patch - ./patches/pi-tool-lookup-validation.patch - ]; - }); + forkedPi = pkgs.pi-coding-agent.overrideAttrs { + src = ../../../../../src/pi; + patches = [ ]; + }; in { options.modules.shell.pi = { @@ -28,7 +26,7 @@ in home-manager.users.${user} = { programs.pi-coding-agent = { enable = true; - package = patchedPi; + package = forkedPi; settings = { defaultProvider = "openai-codex"; diff --git a/configs/nixos/modules/shell/pi/patches/pi-project-resource-ancestors.patch b/configs/nixos/modules/shell/pi/patches/pi-project-resource-ancestors.patch deleted file mode 100644 index fc8ff64..0000000 --- a/configs/nixos/modules/shell/pi/patches/pi-project-resource-ancestors.patch +++ /dev/null @@ -1,140 +0,0 @@ -diff --git a/packages/coding-agent/src/core/package-manager.ts b/packages/coding-agent/src/core/package-manager.ts ---- a/packages/coding-agent/src/core/package-manager.ts -+++ b/packages/coding-agent/src/core/package-manager.ts -@@ -459,14 +459,14 @@ function findGitRepoRoot(startDir: string): string | null { - } - } - --function collectAncestorAgentsSkillDirs(startDir: string): string[] { -- const skillDirs: string[] = []; -+function collectAncestorConfigDirs(startDir: string, configDirName: string): string[] { -+ const configDirs: string[] = []; - const resolvedStartDir = resolve(startDir); - const gitRepoRoot = findGitRepoRoot(resolvedStartDir); - - let dir = resolvedStartDir; - while (true) { -- skillDirs.push(join(dir, ".agents", "skills")); -+ configDirs.push(join(dir, configDirName)); - if (gitRepoRoot && dir === gitRepoRoot) { - break; - } -@@ -477,7 +477,7 @@ function collectAncestorAgentsSkillDirs(startDir: string): string[] { - dir = parent; - } - -- return skillDirs; -+ return configDirs; - } - - function collectAutoPromptEntries(dir: string): string[] { -@@ -2388,16 +2388,13 @@ export class DefaultPackageManager implements PackageManager { - prompts: join(globalBaseDir, "prompts"), - themes: join(globalBaseDir, "themes"), - }; -- const projectDirs = { -- extensions: join(projectBaseDir, "extensions"), -- skills: join(projectBaseDir, "skills"), -- prompts: join(projectBaseDir, "prompts"), -- themes: join(projectBaseDir, "themes"), -- }; - const userAgentsSkillsDir = join(getHomeDir(), ".agents", "skills"); - const projectTrusted = this.settingsManager.isProjectTrusted(); -- const projectAgentsSkillDirs = projectTrusted -- ? collectAncestorAgentsSkillDirs(this.cwd).filter((dir) => resolve(dir) !== resolve(userAgentsSkillsDir)) -+ const projectConfigDirs = projectTrusted -+ ? collectAncestorConfigDirs(this.cwd, CONFIG_DIR_NAME).filter((dir) => resolve(dir) !== resolve(globalBaseDir)) -+ : []; -+ const projectAgentsDirs = projectTrusted -+ ? collectAncestorConfigDirs(this.cwd, ".agents").filter((dir) => resolve(dir) !== resolve(dirname(userAgentsSkillsDir))) - : []; - - const addResources = ( -@@ -2414,56 +2411,54 @@ export class DefaultPackageManager implements PackageManager { - } - }; - -- if (projectTrusted) { -- // Project extensions from .pi/ -+ // Project resources from .pi/ in cwd and ancestors. -+ for (const configDir of projectConfigDirs) { -+ const configMetadata: PathMetadata = { -+ ...projectMetadata, -+ baseDir: configDir, -+ }; - addResources( - "extensions", -- collectAutoExtensionEntries(projectDirs.extensions), -- projectMetadata, -+ collectAutoExtensionEntries(join(configDir, "extensions")), -+ configMetadata, - projectOverrides.extensions, -- projectBaseDir, -+ configDir, - ); -- -- // Project skills from .pi/ - addResources( - "skills", -- collectAutoSkillEntries(projectDirs.skills, "pi"), -- projectMetadata, -+ collectAutoSkillEntries(join(configDir, "skills"), "pi"), -+ configMetadata, - projectOverrides.skills, -- projectBaseDir, -+ configDir, -+ ); -+ addResources( -+ "prompts", -+ collectAutoPromptEntries(join(configDir, "prompts")), -+ configMetadata, -+ projectOverrides.prompts, -+ configDir, -+ ); -+ addResources( -+ "themes", -+ collectAutoThemeEntries(join(configDir, "themes")), -+ configMetadata, -+ projectOverrides.themes, -+ configDir, - ); - } - -- // Project skills from .agents/ (each with its own baseDir) -- for (const agentsSkillsDir of projectAgentsSkillDirs) { -- const agentsBaseDir = dirname(agentsSkillsDir); // the .agents directory -+ // Project skills from .agents/ in cwd and ancestors. -+ for (const agentsDir of projectAgentsDirs) { - const agentsMetadata: PathMetadata = { - ...projectMetadata, -- baseDir: agentsBaseDir, -+ baseDir: agentsDir, - }; - addResources( - "skills", -- collectAutoSkillEntries(agentsSkillsDir, "agents"), -+ collectAutoSkillEntries(join(agentsDir, "skills"), "agents"), - agentsMetadata, - projectOverrides.skills, -- agentsBaseDir, -- ); -- } -- -- if (projectTrusted) { -- addResources( -- "prompts", -- collectAutoPromptEntries(projectDirs.prompts), -- projectMetadata, -- projectOverrides.prompts, -- projectBaseDir, -- ); -- addResources( -- "themes", -- collectAutoThemeEntries(projectDirs.themes), -- projectMetadata, -- projectOverrides.themes, -- projectBaseDir, -+ agentsDir, - ); - } - diff --git a/configs/nixos/modules/shell/pi/patches/pi-tool-lookup-validation.patch b/configs/nixos/modules/shell/pi/patches/pi-tool-lookup-validation.patch deleted file mode 100644 index 27a1afa..0000000 --- a/configs/nixos/modules/shell/pi/patches/pi-tool-lookup-validation.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/packages/coding-agent/src/utils/tools-manager.ts b/packages/coding-agent/src/utils/tools-manager.ts ---- a/packages/coding-agent/src/utils/tools-manager.ts 2026-08-01 18:41:36.970496010 -0400 -+++ b/packages/coding-agent/src/utils/tools-manager.ts 2026-08-01 18:41:37.028186009 -0400 -@@ -74,8 +74,8 @@ - function commandExists(cmd: string): boolean { - try { - const result = spawnSync(cmd, ["--version"], { stdio: "pipe" }); -- // Check for ENOENT error (command not found) -- return result.error === undefined || result.error === null; -+ // Downloaded generic Linux binaries can exist but fail on NixOS before they print a version. -+ return (result.error === undefined || result.error === null) && result.status === 0; - } catch { - return false; - } -@@ -88,7 +87,7 @@ - - // Check our tools directory first - const localPath = join(TOOLS_DIR, config.binaryName + (platform() === "win32" ? ".exe" : "")); -- if (existsSync(localPath)) { -+ if (existsSync(localPath) && commandExists(localPath)) { - return localPath; - } - diff --git a/src/pi/packages/coding-agent/src/core/package-manager.ts b/src/pi/packages/coding-agent/src/core/package-manager.ts index d65386c..dc57e09 100644 --- a/src/pi/packages/coding-agent/src/core/package-manager.ts +++ b/src/pi/packages/coding-agent/src/core/package-manager.ts @@ -459,14 +459,14 @@ function findGitRepoRoot(startDir: string): string | null { } } -function collectAncestorAgentsSkillDirs(startDir: string): string[] { - const skillDirs: string[] = []; +function collectAncestorConfigDirs(startDir: string, configDirName: string): string[] { + const configDirs: string[] = []; const resolvedStartDir = resolve(startDir); const gitRepoRoot = findGitRepoRoot(resolvedStartDir); let dir = resolvedStartDir; while (true) { - skillDirs.push(join(dir, ".agents", "skills")); + configDirs.push(join(dir, configDirName)); if (gitRepoRoot && dir === gitRepoRoot) { break; } @@ -477,7 +477,7 @@ function collectAncestorAgentsSkillDirs(startDir: string): string[] { dir = parent; } - return skillDirs; + return configDirs; } function collectAutoPromptEntries(dir: string): string[] { @@ -2388,16 +2388,13 @@ export class DefaultPackageManager implements PackageManager { prompts: join(globalBaseDir, "prompts"), themes: join(globalBaseDir, "themes"), }; - const projectDirs = { - extensions: join(projectBaseDir, "extensions"), - skills: join(projectBaseDir, "skills"), - prompts: join(projectBaseDir, "prompts"), - themes: join(projectBaseDir, "themes"), - }; const userAgentsSkillsDir = join(getHomeDir(), ".agents", "skills"); const projectTrusted = this.settingsManager.isProjectTrusted(); - const projectAgentsSkillDirs = projectTrusted - ? collectAncestorAgentsSkillDirs(this.cwd).filter((dir) => resolve(dir) !== resolve(userAgentsSkillsDir)) + const projectConfigDirs = projectTrusted + ? collectAncestorConfigDirs(this.cwd, CONFIG_DIR_NAME).filter((dir) => resolve(dir) !== resolve(globalBaseDir)) + : []; + const projectAgentsDirs = projectTrusted + ? collectAncestorConfigDirs(this.cwd, ".agents").filter((dir) => resolve(dir) !== resolve(dirname(userAgentsSkillsDir))) : []; const addResources = ( @@ -2414,56 +2411,54 @@ export class DefaultPackageManager implements PackageManager { } }; - if (projectTrusted) { - // Project extensions from .pi/ - addResources( - "extensions", - collectAutoExtensionEntries(projectDirs.extensions), - projectMetadata, - projectOverrides.extensions, - projectBaseDir, - ); - - // Project skills from .pi/ - addResources( - "skills", - collectAutoSkillEntries(projectDirs.skills, "pi"), - projectMetadata, - projectOverrides.skills, - projectBaseDir, - ); - } - - // Project skills from .agents/ (each with its own baseDir) - for (const agentsSkillsDir of projectAgentsSkillDirs) { - const agentsBaseDir = dirname(agentsSkillsDir); // the .agents directory - const agentsMetadata: PathMetadata = { + // Project resources from .pi/ in cwd and ancestors. + for (const configDir of projectConfigDirs) { + const configMetadata: PathMetadata = { ...projectMetadata, - baseDir: agentsBaseDir, + baseDir: configDir, }; addResources( - "skills", - collectAutoSkillEntries(agentsSkillsDir, "agents"), - agentsMetadata, - projectOverrides.skills, - agentsBaseDir, + "extensions", + collectAutoExtensionEntries(join(configDir, "extensions")), + configMetadata, + projectOverrides.extensions, + configDir, + ); + addResources( + "skills", + collectAutoSkillEntries(join(configDir, "skills"), "pi"), + configMetadata, + projectOverrides.skills, + configDir, ); - } - - if (projectTrusted) { addResources( "prompts", - collectAutoPromptEntries(projectDirs.prompts), - projectMetadata, + collectAutoPromptEntries(join(configDir, "prompts")), + configMetadata, projectOverrides.prompts, - projectBaseDir, + configDir, ); addResources( "themes", - collectAutoThemeEntries(projectDirs.themes), - projectMetadata, + collectAutoThemeEntries(join(configDir, "themes")), + configMetadata, projectOverrides.themes, - projectBaseDir, + configDir, + ); + } + + // Project skills from .agents/ in cwd and ancestors. + for (const agentsDir of projectAgentsDirs) { + const agentsMetadata: PathMetadata = { + ...projectMetadata, + baseDir: agentsDir, + }; + addResources( + "skills", + collectAutoSkillEntries(join(agentsDir, "skills"), "agents"), + agentsMetadata, + projectOverrides.skills, + agentsDir, ); } diff --git a/src/pi/packages/coding-agent/src/utils/tools-manager.ts b/src/pi/packages/coding-agent/src/utils/tools-manager.ts index f040f52..2bcca47 100644 --- a/src/pi/packages/coding-agent/src/utils/tools-manager.ts +++ b/src/pi/packages/coding-agent/src/utils/tools-manager.ts @@ -72,8 +72,8 @@ const TOOLS: Record = { function commandExists(cmd: string): boolean { try { const result = spawnSync(cmd, ["--version"], { stdio: "pipe" }); - // Check for ENOENT error (command not found) - return result.error === undefined || result.error === null; + // Downloaded generic Linux binaries can exist but fail on NixOS before they print a version. + return (result.error === undefined || result.error === null) && result.status === 0; } catch { return false; } @@ -86,7 +86,7 @@ export function getToolPath(tool: "fd" | "rg"): string | null { // Check our tools directory first const localPath = join(TOOLS_DIR, config.binaryName + (platform() === "win32" ? ".exe" : "")); - if (existsSync(localPath)) { + if (existsSync(localPath) && commandExists(localPath)) { return localPath; }