import { homedir } from "node:os"; import { resolve } from "node:path"; import { configLoader } from "../../src/shared/config"; import type { WorkspaceRootEntry } from "../../src/shared/config/types"; /** A workspace root with its path resolved to an absolute path. */ export interface WorkspaceRoot { path: string; alias?: string; } export function resolveTilde(path: string, cwd: string): string { return path.startsWith("~/") || path.startsWith("~\\") ? resolve(homedir(), path.slice(2)) : resolve(cwd, path); } /** Resolve configured root entries to absolute paths, dropping duplicates. */ export function resolveRoots( entries: readonly WorkspaceRootEntry[], cwd: string, ): WorkspaceRoot[] { const seen = new Set(); const roots: WorkspaceRoot[] = []; for (const entry of entries) { const path = resolveTilde(entry.path, cwd); if (seen.has(path)) continue; seen.add(path); roots.push({ path, ...(entry.alias ? { alias: entry.alias } : {}) }); } return roots; } export function formatWorkspaceRoots(roots: readonly WorkspaceRoot[]): string { if (roots.length === 0) return ""; const lines = roots.map( (r) => `- ${r.path}${r.alias ? ` (${r.alias})` : ""}`, ); return `\n\n## Workspace Roots\nIn addition to the current directory, these directories are also part of your workspace:\n${lines.join("\n")}`; } /** * Persist a root to the project guardrails config * (.pi/extensions/guardrails.json), mirroring how path-access persists * "always" grants. */ export async function persistRoot(entry: WorkspaceRootEntry): Promise { const raw = (configLoader.getRawConfig("local") ?? {}) as Record< string, unknown >; const workspaceRoots = (raw.workspaceRoots ?? {}) as Record; const existing = Array.isArray(workspaceRoots.roots) ? workspaceRoots.roots.filter( (item): item is WorkspaceRootEntry => typeof item === "object" && item !== null && typeof (item as { path?: unknown }).path === "string", ) : []; if (existing.some((item) => item.path === entry.path)) return; await configLoader.save("local", { ...raw, workspaceRoots: { ...workspaceRoots, roots: [...existing, entry], }, }); }