diff --git a/internal/skills/registry/registry.go b/internal/skills/registry/registry.go index 487e12ba3ac..2d2cfbda64e 100644 --- a/internal/skills/registry/registry.go +++ b/internal/skills/registry/registry.go @@ -31,7 +31,8 @@ const ( DefaultAgentID = "github-copilot" - claudeConfigDirEnv = "CLAUDE_CONFIG_DIR" + claudeConfigDirEnv = "CLAUDE_CONFIG_DIR" + piCodingAgentDirEnv = "PI_CODING_AGENT_DIR" sharedProjectSkillsDir = ".agents/skills" ) @@ -69,7 +70,7 @@ var Agents = []AgentHost{ ID: "codex", Name: "Codex", ProjectDir: sharedProjectSkillsDir, - UserDir: ".codex/skills", + UserDir: sharedProjectSkillsDir, }, { ID: "gemini-cli", @@ -415,8 +416,15 @@ func (h *AgentHost) InstallDir(scope Scope, gitRoot, homeDir string) (string, er } return filepath.Join(gitRoot, h.ProjectDir), nil case ScopeUser: - if h.ID == "claude-code" { - if configDir := os.Getenv(claudeConfigDirEnv); configDir != "" { + var configDirEnv string + switch h.ID { + case "claude-code": + configDirEnv = claudeConfigDirEnv + case "pi": + configDirEnv = piCodingAgentDirEnv + } + if configDirEnv != "" { + if configDir := os.Getenv(configDirEnv); configDir != "" { return filepath.Join(configDir, "skills"), nil } } diff --git a/internal/skills/registry/registry_test.go b/internal/skills/registry/registry_test.go index 8472ae3af21..39c6f3bcd88 100644 --- a/internal/skills/registry/registry_test.go +++ b/internal/skills/registry/registry_test.go @@ -44,6 +44,7 @@ func TestFindByID(t *testing.T) { func TestInstallDir(t *testing.T) { t.Setenv(claudeConfigDirEnv, "") + t.Setenv(piCodingAgentDirEnv, "") tests := []struct { name string @@ -90,7 +91,7 @@ func TestInstallDir(t *testing.T) { { name: "claude code user scope, respect env var", setup: func(t *testing.T) { - t.Setenv("CLAUDE_CONFIG_DIR", filepath.Join("/home", "monalisa", ".config", "claude")) + t.Setenv(claudeConfigDirEnv, filepath.Join("/home", "monalisa", ".config", "claude")) }, hostID: "claude-code", scope: ScopeUser, @@ -98,6 +99,25 @@ func TestInstallDir(t *testing.T) { homeDir: "/home/monalisa", wantDir: filepath.Join("/home", "monalisa", ".config", "claude", "skills"), }, + { + name: "pi user scope", + hostID: "pi", + scope: ScopeUser, + gitRoot: "/tmp/monalisa-repo", + homeDir: "/home/monalisa", + wantDir: filepath.Join("/home/monalisa", ".pi", "agent", "skills"), + }, + { + name: "pi user scope, respect env var", + setup: func(t *testing.T) { + t.Setenv(piCodingAgentDirEnv, filepath.Join("/home", "monalisa", ".config", "pi", "agent")) + }, + hostID: "pi", + scope: ScopeUser, + gitRoot: "/tmp/monalisa-repo", + homeDir: "/home/monalisa", + wantDir: filepath.Join("/home", "monalisa", ".config", "pi", "agent", "skills"), + }, { name: "cursor project scope", hostID: "cursor", @@ -114,6 +134,14 @@ func TestInstallDir(t *testing.T) { homeDir: "/home/monalisa", wantDir: filepath.Join("/tmp/monalisa-repo", ".agents", "skills"), }, + { + name: "codex user scope", + hostID: "codex", + scope: ScopeUser, + gitRoot: "/tmp/monalisa-repo", + homeDir: "/home/monalisa", + wantDir: filepath.Join("/home/monalisa", ".agents", "skills"), + }, { name: "gemini project scope", hostID: "gemini-cli", diff --git a/pkg/cmd/skills/install/install_test.go b/pkg/cmd/skills/install/install_test.go index 850f925f832..34f9188a855 100644 --- a/pkg/cmd/skills/install/install_test.go +++ b/pkg/cmd/skills/install/install_test.go @@ -1589,6 +1589,37 @@ func TestInstallRun(t *testing.T) { }, wantStdout: "Installed git-commit", }, + { + name: "respect pi coding agent dir env var for user scope", + setup: func(t *testing.T) { + t.Setenv("PI_CODING_AGENT_DIR", t.TempDir()) + }, + stubs: func(reg *httpmock.Registry) { + stubResolveVersion(reg, "monalisa", "skills-repo", "v1.0.0", "abc123") + stubDiscoverTree(reg, "monalisa", "skills-repo", "abc123", + singleSkillTreeJSON("git-commit", "treeSHA", "blobSHA")) + stubInstallFiles(reg, "monalisa", "skills-repo", "treeSHA", "blobSHA", gitCommitContent) + }, + opts: func(ios *iostreams.IOStreams, reg *httpmock.Registry) *InstallOptions { + t.Helper() + return &InstallOptions{ + IO: ios, + HttpClient: func() (*http.Client, error) { return &http.Client{Transport: reg}, nil }, + GitClient: &git.Client{RepoDir: t.TempDir()}, + SkillSource: "monalisa/skills-repo", + SkillName: "git-commit", + Agent: "pi", + Scope: "user", + ScopeChanged: true, + Telemetry: &telemetry.NoOpService{}, + } + }, + assert: func(t *testing.T) { + assert.FileExists(t, filepath.Join(os.Getenv("PI_CODING_AGENT_DIR"), "skills", "git-commit", "SKILL.md")) + assert.NoFileExists(t, filepath.Join(os.Getenv("HOME"), ".pi", "agent", "skills", "git-commit", "SKILL.md")) + }, + wantStdout: "Installed git-commit", + }, } for _, tt := range tests {