pi-paths.ts
2001 bytes
1import { homedir } from "node:os";
2import { join, resolve } from "node:path";
3import type { SkillSource } from "../types.ts";
4
5export interface SkillRoot {
6 path: string;
7 source: SkillSource;
8 includeRootMarkdownFiles: boolean;
9}
10
11export function getAgentDir(): string {
12 const configured = process.env.PI_CODING_AGENT_DIR?.trim();
13 if (configured) return expandHome(configured);
14 return join(homedir(), ".pi", "agent");
15}
16
17export function getGlobalAgentsSkillDir(): string {
18 return join(homedir(), ".agents", "skills");
19}
20
21export function getSkillRoots(cwd: string): SkillRoot[] {
22 const resolvedCwd = resolve(cwd);
23 const userSkillRoot = join(getAgentDir(), "skills");
24 const globalSkillRoot = getGlobalAgentsSkillDir();
25 const projectSkillRoot = resolve(resolvedCwd, ".pi", "skills");
26 const projectLegacySkillRoot = resolve(resolvedCwd, ".agents", "skills");
27 const roots: SkillRoot[] = [
28 {
29 path: userSkillRoot,
30 source: { kind: "user", root: userSkillRoot },
31 includeRootMarkdownFiles: true,
32 },
33 {
34 path: globalSkillRoot,
35 source: { kind: "global", root: globalSkillRoot },
36 includeRootMarkdownFiles: false,
37 },
38 {
39 path: projectSkillRoot,
40 source: { kind: "project", root: projectSkillRoot },
41 includeRootMarkdownFiles: true,
42 },
43 // Pi also loads .agents/skills as a project skill directory. Root markdown
44 // files are ignored there; directories containing SKILL.md are discovered.
45 {
46 path: projectLegacySkillRoot,
47 source: { kind: "project-legacy", root: projectLegacySkillRoot },
48 includeRootMarkdownFiles: false,
49 },
50 ];
51
52 const seen = new Set<string>();
53 return roots.filter((root) => {
54 const key = resolve(root.path);
55 if (seen.has(key)) return false;
56 seen.add(key);
57 return true;
58 });
59}
60
61function expandHome(input: string): string {
62 if (input === "~") return homedir();
63 if (input.startsWith("~/")) return join(homedir(), input.slice(2));
64 return input;
65}