import { existsSync, readFileSync } from "node:fs"; import { homedir } from "node:os"; import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; export type ExtensionSourceKind = | "user-npm" | "user-git" | "project-npm" | "project-local" | "local-path" | "unknown"; export interface ExtensionIdentity { packageName: string; version: string; sourcePath: string; sourceKind: ExtensionSourceKind; installedUserVersion?: string; } export const UNKNOWN_EXTENSION_IDENTITY: ExtensionIdentity = { packageName: "intent-petri", version: "development", sourcePath: "unknown", sourceKind: "unknown", }; export function classifyExtensionSource( sourcePath: string, cwd = process.cwd(), home = homedir(), ): ExtensionSourceKind { const source = resolve(sourcePath); const userNpm = resolve(home, ".pi", "agent", "npm", "node_modules", "intent-petri"); const userGit = resolve(home, ".pi", "agent", "git"); const project = resolve(cwd); const projectNpm = resolve(project, ".pi", "npm", "node_modules", "intent-petri"); if (source === userNpm || source.startsWith(`${userNpm}/`)) return "user-npm"; if (source === projectNpm || source.startsWith(`${projectNpm}/`)) return "project-npm"; if (source === userGit || source.startsWith(`${userGit}/`)) return "user-git"; if (source === project || source.startsWith(`${project}/`)) return "project-local"; return "local-path"; } function packageVersion(path: string): { name: string; version: string } | undefined { if (!existsSync(path)) return undefined; try { const value = JSON.parse(readFileSync(path, "utf8")) as { name?: unknown; version?: unknown }; if (typeof value.name !== "string" || typeof value.version !== "string") return undefined; return { name: value.name, version: value.version }; } catch { return undefined; } } export function shouldLoadExtension(identity: ExtensionIdentity, preferLocal: boolean): boolean { if (!preferLocal && identity.sourceKind === "project-local" && identity.installedUserVersion) return false; if (preferLocal && (identity.sourceKind === "user-npm" || identity.sourceKind === "project-npm")) return false; return true; } export function detectExtensionIdentity( metaUrl: string, cwd = process.cwd(), home = homedir(), ): ExtensionIdentity { const sourcePath = fileURLToPath(metaUrl); const packageRoot = dirname(dirname(sourcePath)); const ownPackage = packageVersion(join(packageRoot, "package.json")); const installedPackage = packageVersion( join(home, ".pi", "agent", "npm", "node_modules", "intent-petri", "package.json"), ); return { packageName: ownPackage?.name ?? "intent-petri", version: ownPackage?.version ?? "development", sourcePath, sourceKind: classifyExtensionSource(sourcePath, cwd, home), ...(installedPackage ? { installedUserVersion: installedPackage.version } : {}), }; }