import { readFileSync } from "node:fs"; import { join, resolve } from "node:path"; import type { ToolInfo } from "@earendil-works/pi-coding-agent"; const CODEX_PACKAGE_NAME = "@howaboua/pi-codex-conversion"; const CODEX_NPM_SOURCE_PREFIX = `npm:${CODEX_PACKAGE_NAME}`; const NON_LOCAL_SOURCE_PREFIXES = ["npm:", "git:", "github:", "http:", "https:", "ssh:"] as const; export interface InheritedExtensionMetadata { extensionPaths: string[]; inheritedToolNames: string[]; } function isLocalPackageSource(source: unknown): source is string { if (typeof source !== "string") { return false; } const value = source.trim(); return !NON_LOCAL_SOURCE_PREFIXES.some((prefix) => value.startsWith(prefix)); } function hasNamedPackageManifest(baseDir: unknown): boolean { if (typeof baseDir !== "string" || baseDir.trim() === "") { return false; } try { const manifest = JSON.parse(readFileSync(join(baseDir, "package.json"), "utf8")) as unknown; return ( manifest !== null && typeof manifest === "object" && "name" in manifest && (manifest as { name?: unknown }).name === CODEX_PACKAGE_NAME ); } catch { return false; } } function isCodexConversionTool(tool: ToolInfo): boolean { const sourceInfo = tool.sourceInfo; if (sourceInfo?.origin !== "package") { return false; } if ( typeof sourceInfo.source === "string" && (sourceInfo.source.trim() === CODEX_NPM_SOURCE_PREFIX || sourceInfo.source.trim().startsWith(`${CODEX_NPM_SOURCE_PREFIX}@`)) ) { return true; } return isLocalPackageSource(sourceInfo.source) && hasNamedPackageManifest(sourceInfo.baseDir); } export function collectInheritedExtensionMetadata( allTools: readonly ToolInfo[], activeToolNames: readonly string[], ownExtensionPath: string, ): InheritedExtensionMetadata { const activeNames = new Set(activeToolNames); const extensionPaths = new Set(); const inheritedToolNames = new Set(); const resolvedOwnExtensionPath = resolve(ownExtensionPath); for (const tool of allTools) { const sourcePath = tool.sourceInfo?.path; if (typeof sourcePath !== "string" || sourcePath.trim() === "" || sourcePath.startsWith("<")) { continue; } if (resolve(sourcePath) === resolvedOwnExtensionPath) { continue; } const isConversionTool = isCodexConversionTool(tool); if (isConversionTool) { extensionPaths.add(sourcePath); inheritedToolNames.add(tool.name); continue; } if (activeNames.has(tool.name)) { extensionPaths.add(sourcePath); } } return { extensionPaths: [...extensionPaths], inheritedToolNames: [...inheritedToolNames], }; }