UNPKG

c9ai

Version:

Universal AI assistant with vibe-based workflows, hybrid cloud+local AI, and comprehensive tool integration

448 lines (392 loc) 13.8 kB
"use strict"; const { execSync } = require("node:child_process"); const fs = require("node:fs"); const path = require("node:path"); const os = require("node:os"); /** * Package Manager Detection System * Detects and interfaces with system package managers */ class PackageManagerDetector { constructor() { this.detectedManagers = new Map(); this.supportedManagers = this.initializeSupportedManagers(); } /** * Initialize configuration for supported package managers */ initializeSupportedManagers() { return { // Cross-platform managers "npm": { platforms: ["darwin", "linux", "win32"], checkCommand: "npm --version", searchCommand: "npm search {query}", installCommand: "npm install -g {package}", infoCommand: "npm info {package}", listCommand: "npm list -g --depth=0", updateCommand: "npm update -g {package}", removeCommand: "npm uninstall -g {package}", type: "language", ecosystem: "javascript" }, "pip": { platforms: ["darwin", "linux", "win32"], checkCommand: "pip --version", searchCommand: "pip search {query} || echo 'Search disabled'", installCommand: "pip install {package}", infoCommand: "pip show {package}", listCommand: "pip list", updateCommand: "pip install --upgrade {package}", removeCommand: "pip uninstall {package}", type: "language", ecosystem: "python" }, // macOS managers "brew": { platforms: ["darwin"], checkCommand: "brew --version", searchCommand: "brew search {query}", installCommand: "brew install {package}", infoCommand: "brew info {package}", listCommand: "brew list", updateCommand: "brew upgrade {package}", removeCommand: "brew uninstall {package}", type: "system", ecosystem: "homebrew" }, // Windows managers "choco": { platforms: ["win32"], checkCommand: "choco --version", searchCommand: "choco search {query}", installCommand: "choco install {package} -y", infoCommand: "choco info {package}", listCommand: "choco list --local-only", updateCommand: "choco upgrade {package} -y", removeCommand: "choco uninstall {package} -y", type: "system", ecosystem: "chocolatey" }, "winget": { platforms: ["win32"], checkCommand: "winget --version", searchCommand: "winget search {query}", installCommand: "winget install {package}", infoCommand: "winget show {package}", listCommand: "winget list", updateCommand: "winget upgrade {package}", removeCommand: "winget uninstall {package}", type: "system", ecosystem: "winget" }, // Linux managers "apt": { platforms: ["linux"], checkCommand: "apt --version", searchCommand: "apt search {query}", installCommand: "apt install {package} -y", infoCommand: "apt show {package}", listCommand: "apt list --installed", updateCommand: "apt upgrade {package} -y", removeCommand: "apt remove {package} -y", type: "system", ecosystem: "debian" }, "yum": { platforms: ["linux"], checkCommand: "yum --version", searchCommand: "yum search {query}", installCommand: "yum install {package} -y", infoCommand: "yum info {package}", listCommand: "yum list installed", updateCommand: "yum update {package} -y", removeCommand: "yum remove {package} -y", type: "system", ecosystem: "redhat" }, "dnf": { platforms: ["linux"], checkCommand: "dnf --version", searchCommand: "dnf search {query}", installCommand: "dnf install {package} -y", infoCommand: "dnf info {package}", listCommand: "dnf list installed", updateCommand: "dnf upgrade {package} -y", removeCommand: "dnf remove {package} -y", type: "system", ecosystem: "redhat" }, "pacman": { platforms: ["linux"], checkCommand: "pacman --version", searchCommand: "pacman -Ss {query}", installCommand: "pacman -S {package} --noconfirm", infoCommand: "pacman -Si {package}", listCommand: "pacman -Q", updateCommand: "pacman -S {package} --noconfirm", removeCommand: "pacman -R {package} --noconfirm", type: "system", ecosystem: "arch" }, // Universal Linux managers "snap": { platforms: ["linux"], checkCommand: "snap --version", searchCommand: "snap find {query}", installCommand: "snap install {package}", infoCommand: "snap info {package}", listCommand: "snap list", updateCommand: "snap refresh {package}", removeCommand: "snap remove {package}", type: "universal", ecosystem: "canonical" }, "flatpak": { platforms: ["linux"], checkCommand: "flatpak --version", searchCommand: "flatpak search {query}", installCommand: "flatpak install {package} -y", infoCommand: "flatpak info {package}", listCommand: "flatpak list", updateCommand: "flatpak update {package} -y", removeCommand: "flatpak uninstall {package} -y", type: "universal", ecosystem: "flatpak" }, // Additional language managers "cargo": { platforms: ["darwin", "linux", "win32"], checkCommand: "cargo --version", searchCommand: "cargo search {query}", installCommand: "cargo install {package}", infoCommand: "cargo search {package}", listCommand: "cargo install --list", updateCommand: "cargo install {package} --force", removeCommand: "cargo uninstall {package}", type: "language", ecosystem: "rust" }, "gem": { platforms: ["darwin", "linux", "win32"], checkCommand: "gem --version", searchCommand: "gem search {query}", installCommand: "gem install {package}", infoCommand: "gem info {package}", listCommand: "gem list", updateCommand: "gem update {package}", removeCommand: "gem uninstall {package}", type: "language", ecosystem: "ruby" } }; } /** * Detect all available package managers on the system */ async detectAll() { console.log("🔍 Detecting available package managers..."); const currentPlatform = os.platform(); const detected = []; for (const [name, config] of Object.entries(this.supportedManagers)) { // Skip if not supported on current platform if (!config.platforms.includes(currentPlatform)) { continue; } try { const info = await this.detectManager(name, config); if (info) { detected.push(info); this.detectedManagers.set(name, info); console.log(` ✅ ${name} v${info.version} (${info.type})`); } } catch (error) { // Manager not available - this is normal } } console.log(`✅ Found ${detected.length} package managers`); return detected; } /** * Detect a specific package manager */ async detectManager(name, config) { try { const output = execSync(config.checkCommand, { stdio: "pipe", timeout: 5000, encoding: "utf8" }); const version = this.extractVersion(output); return { name, version, type: config.type, ecosystem: config.ecosystem, platform: os.platform(), config: config, available: true, detectedAt: new Date().toISOString() }; } catch (error) { return null; } } /** * Extract version from command output */ extractVersion(output) { const patterns = [ /version (\d+\.\d+(?:\.\d+)?)/i, /v(\d+\.\d+(?:\.\d+)?)/i, /(\d+\.\d+(?:\.\d+)?)/, ]; for (const pattern of patterns) { const match = output.match(pattern); if (match) { return match[1]; } } return "unknown"; } /** * Get detected managers by type */ getManagersByType(type) { const managers = []; for (const manager of this.detectedManagers.values()) { if (manager.type === type) { managers.push(manager); } } return managers; } /** * Get the best package manager for a specific task */ getBestManager(criteria = {}) { const { type = null, // "system", "language", "universal" ecosystem = null, // "homebrew", "debian", "python", etc. preferredManager = null, task = null // "install", "search", "info" } = criteria; const available = Array.from(this.detectedManagers.values()); // Apply filters let filtered = available; if (type) { filtered = filtered.filter(m => m.type === type); } if (ecosystem) { filtered = filtered.filter(m => m.ecosystem === ecosystem); } if (preferredManager && this.detectedManagers.has(preferredManager)) { return this.detectedManagers.get(preferredManager); } // Score managers by preference return filtered.sort((a, b) => { // Prefer system package managers over language-specific if (a.type === "system" && b.type === "language") return -1; if (a.type === "language" && b.type === "system") return 1; // Platform-specific preferences const platform = os.platform(); if (platform === "darwin" && a.name === "brew") return -1; if (platform === "win32" && a.name === "winget") return -1; if (platform === "linux" && a.name === "apt") return -1; return 0; })[0]; } /** * Check if a specific package manager is available */ isAvailable(managerName) { return this.detectedManagers.has(managerName); } /** * Get package manager configuration */ getManagerConfig(managerName) { const manager = this.detectedManagers.get(managerName); return manager ? manager.config : null; } /** * Build command for a specific manager and operation */ buildCommand(managerName, operation, packageName, options = {}) { const manager = this.detectedManagers.get(managerName); if (!manager) { throw new Error(`Package manager '${managerName}' not available`); } const commandTemplate = manager.config[`${operation}Command`]; if (!commandTemplate) { throw new Error(`Operation '${operation}' not supported by ${managerName}`); } let command = commandTemplate.replace("{package}", packageName); command = command.replace("{query}", packageName); // Add options if (options.version) { if (managerName === "npm") { command = command.replace(packageName, `${packageName}@${options.version}`); } // Add version support for other managers as needed } return command; } /** * Get system statistics */ getStats() { const managers = Array.from(this.detectedManagers.values()); const stats = { total: managers.length, byType: { system: managers.filter(m => m.type === "system").length, language: managers.filter(m => m.type === "language").length, universal: managers.filter(m => m.type === "universal").length }, byPlatform: { [os.platform()]: managers.length }, ecosystems: [...new Set(managers.map(m => m.ecosystem))] }; return stats; } /** * Save detection results to cache */ async saveCache() { const cacheDir = path.join(process.cwd(), ".c9ai", "cache"); await fs.promises.mkdir(cacheDir, { recursive: true }); const cacheFile = path.join(cacheDir, "package-managers.json"); const cacheData = { platform: os.platform(), detectedAt: new Date().toISOString(), managers: Object.fromEntries(this.detectedManagers) }; await fs.promises.writeFile(cacheFile, JSON.stringify(cacheData, null, 2)); console.log(`📝 Cached package manager info to ${cacheFile}`); } /** * Load detection results from cache */ async loadCache() { const cacheFile = path.join(process.cwd(), ".c9ai", "cache", "package-managers.json"); try { const cacheData = await fs.promises.readFile(cacheFile, "utf8"); const cached = JSON.parse(cacheData); // Check if cache is recent (within 24 hours) and for same platform const cacheAge = Date.now() - new Date(cached.detectedAt).getTime(); if (cacheAge < 24 * 60 * 60 * 1000 && cached.platform === os.platform()) { console.log("📋 Using cached package manager detection"); for (const [name, manager] of Object.entries(cached.managers)) { this.detectedManagers.set(name, manager); } return Array.from(this.detectedManagers.values()); } } catch (error) { // Cache doesn't exist or is invalid } return null; } } module.exports = { PackageManagerDetector };