import { homedir } from "node:os"; import { basename, isAbsolute, relative } from "node:path"; import { PACKAGE_NAME } from "./constants.ts"; import type { ResourceKind } from "./types.ts"; const COMPACT_PREFIXES = ["local:", "project:", "pkg:", "mcp:", "npm:", "git:", "http://", "https://"]; export function normalizeSearch(value: string | undefined): string { return (value ?? "") .toLowerCase() .replace(/[^a-z0-9\u4e00-\u9fff]+/g, " ") .trim(); } export function normalizeCommandName(name: string): string { return name.replace(/^\/+/, ""); } export function displayCommandName(name: string): string { return `/${normalizeCommandName(name)}`; } export function canonicalName(kind: ResourceKind, name: string): string { return kind === "command" ? normalizeCommandName(name) : name; } export function displayName(kind: ResourceKind, name: string): string { return kind === "command" ? displayCommandName(name) : name; } export function extractPackageNameFromPath(source: string): string | undefined { const match = source.replace(/\\/g, "/").match(/\/node_modules\/(.*)$/); if (!match) return undefined; const parts = match[1].split("/").filter(Boolean); if (parts.length === 0) return undefined; if (parts[0].startsWith("@")) { return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : parts[0]; } return parts[0]; } function stripRepeatedLocalPrefixes(value: string): string { let next = value; while (next.startsWith("local:local:")) { next = next.slice("local:".length); } return next; } function unwrapLocalWrappedCompactRef(value: string): string { if (!value.startsWith("local:")) return value; const inner = value.slice("local:".length); if (inner === "builtin" || inner === "sdk" || inner === "unknown") return inner; if (COMPACT_PREFIXES.filter((prefix) => prefix !== "local:").some((prefix) => inner.startsWith(prefix))) { return inner; } return value; } function isOwnPackageSource(source: string): boolean { return source.replace(/\\/g, "/").includes(PACKAGE_NAME); } export function compactSourceRef(source?: string): string { if (!source) return "unknown"; const normalized = unwrapLocalWrappedCompactRef(stripRepeatedLocalPrefixes(source.replace(/\\/g, "/"))); if (isOwnPackageSource(normalized)) return `pkg:${PACKAGE_NAME}`; if (normalized === "builtin" || normalized === "sdk" || normalized === "unknown") return normalized; if (COMPACT_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return normalized; const packageName = extractPackageNameFromPath(normalized); if (packageName) return `pkg:${packageName}`; if (isAbsolute(normalized)) { const homeRelative = relative(homedir(), normalized).replace(/\\/g, "/"); if (homeRelative && !homeRelative.startsWith("..")) { return `local:${homeRelative}`; } return `local:${basename(normalized)}`; } return `local:${normalized}`; } export function makeItemKey(kind: ResourceKind, name: string, sourceRef: string): string { return `${kind}:${sourceRef}:${canonicalName(kind, name)}`; }