import { existsSync, readFileSync } from "fs"; import { homedir } from "os"; import { dirname, join, resolve } from "path"; import { fileURLToPath } from "url"; // ============================================================================= // Package Detection // ============================================================================= const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * Detect if we're running as a Bun compiled binary. * Bun binaries have import.meta.url containing "$bunfs" (Bun's virtual filesystem path) */ export const isBunBinary = import.meta.url.includes("$bunfs"); // ============================================================================= // Package Asset Paths (shipped with executable) // ============================================================================= /** * Get the base directory for resolving package assets (themes, package.json, README.md, CHANGELOG.md). * - For Bun binary: returns the directory containing the executable * - For Node.js (dist/): returns __dirname (the dist/ directory) * - For tsx (src/): returns parent directory (the package root) */ export function getPackageDir(): string { if (isBunBinary) { // Bun binary: process.execPath points to the compiled executable return dirname(process.execPath); } // Node.js: check if package.json exists in __dirname (dist/) or parent (src/ case) if (existsSync(join(__dirname, "package.json"))) { return __dirname; } // Running from src/ via tsx - go up one level to package root return dirname(__dirname); } /** * Get path to built-in themes directory (shipped with package) * - For Bun binary: theme/ next to executable * - For Node.js (dist/): dist/theme/ * - For tsx (src/): src/theme/ */ export function getThemesDir(): string { if (isBunBinary) { return join(dirname(process.execPath), "theme"); } // __dirname is either dist/ or src/ - theme is always a subdirectory return join(__dirname, "theme"); } /** Get path to package.json */ export function getPackageJsonPath(): string { return join(getPackageDir(), "package.json"); } /** Get path to README.md */ export function getReadmePath(): string { return resolve(join(getPackageDir(), "README.md")); } /** Get path to CHANGELOG.md */ export function getChangelogPath(): string { return resolve(join(getPackageDir(), "CHANGELOG.md")); } // ============================================================================= // App Config (from package.json piConfig) // ============================================================================= const pkg = JSON.parse(readFileSync(getPackageJsonPath(), "utf-8")); export const APP_NAME: string = pkg.piConfig?.name || "pi"; export const CONFIG_DIR_NAME: string = pkg.piConfig?.configDir || ".pi"; export const VERSION: string = pkg.version; // e.g., PI_CODING_AGENT_DIR or TAU_CODING_AGENT_DIR export const ENV_AGENT_DIR = `${APP_NAME.toUpperCase()}_CODING_AGENT_DIR`; // ============================================================================= // User Config Paths (~/.pi/agent/*) // ============================================================================= /** Get the agent config directory (e.g., ~/.pi/agent/) */ export function getAgentDir(): string { return process.env[ENV_AGENT_DIR] || join(homedir(), CONFIG_DIR_NAME, "agent"); } /** Get path to user's custom themes directory */ export function getCustomThemesDir(): string { return join(getAgentDir(), "themes"); } /** Get path to models.json */ export function getModelsPath(): string { return join(getAgentDir(), "models.json"); } /** Get path to oauth.json */ export function getOAuthPath(): string { return join(getAgentDir(), "oauth.json"); } /** Get path to settings.json */ export function getSettingsPath(): string { return join(getAgentDir(), "settings.json"); } /** Get path to tools directory */ export function getToolsDir(): string { return join(getAgentDir(), "tools"); } /** Get path to slash commands directory */ export function getCommandsDir(): string { return join(getAgentDir(), "commands"); } /** Get path to sessions directory */ export function getSessionsDir(): string { return join(getAgentDir(), "sessions"); } /** Get path to debug log file */ export function getDebugLogPath(): string { return join(getAgentDir(), `${APP_NAME}-debug.log`); }