UNPKG

@foundrole/ai-job-search-mcp

Version:

Run your job search from your AI assistant. Connect FoundRole to Claude, ChatGPT, Cursor, or any MCP client and search live jobs right away — no sign-up. Sign in once (your AI does it for you) to save and track applications on a Kanban board, set follow-u

204 lines 7.65 kB
import { readFileSync } from "fs"; import { dirname, join, resolve } from "path"; /** * Cross-platform version extractor for applications */ export class VersionExtractor { /** * Extracts version information from an executable path */ static async extractVersion(executablePath, processName) { const platform = process.platform; console.error(`[VERSION-EXTRACTOR] Extracting version for: ${executablePath} on ${platform}`); try { switch (platform) { case "darwin": return await this.extractMacOSVersion(executablePath, processName); case "win32": return await this.extractWindowsVersion(executablePath); case "linux": return await this.extractLinuxVersion(executablePath); default: return { error: `Unsupported platform: ${platform}`, source: "fallback", }; } } catch (error) { console.error(`[VERSION-EXTRACTOR] Error: ${String(error)}`); return { error: error instanceof Error ? error.message : String(error), source: "fallback", }; } } /** * Extracts version from macOS application bundles or executables */ static async extractMacOSVersion(executablePath, processName) { try { // Try to find .app or .xpc bundle const appBundlePath = this.findMacOSAppBundle(executablePath); if (appBundlePath) { return await this.extractFromPlist(appBundlePath); } // Fallback: try to parse version from path or process name if (processName) { const versionMatch = processName.match(/(\d+\.\d+(?:\.\d+)?)/); if (versionMatch && versionMatch[1]) { return { source: "fallback", version: versionMatch[1], }; } } return { error: "Could not find app bundle or extract version", source: "fallback", }; } catch (error) { return { error: error instanceof Error ? error.message : String(error), source: "fallback", }; } } /** * Extracts version from Windows PE executables */ static async extractWindowsVersion(executablePath) { try { // Dynamic import since win-version-info is Windows-only const winVersionInfo = await import("win-version-info"); const versionInfo = winVersionInfo.default(executablePath); if (versionInfo && versionInfo.FileVersion) { return { source: "executable", version: versionInfo.FileVersion, }; } if (versionInfo && versionInfo.ProductVersion) { return { source: "executable", version: versionInfo.ProductVersion, }; } return { error: "No version information found in PE file", source: "fallback", }; } catch (error) { return { error: error instanceof Error ? error.message : String(error), source: "fallback", }; } } /** * Extracts version from Linux ELF executables */ static async extractLinuxVersion(executablePath) { try { // Dynamic import since elfy might not work on all platforms const elfy = await import("elfy"); const elf = elfy.parse(readFileSync(executablePath)); // ELF files don't typically contain version info in a standard way // Try to find version in string sections if (elf.body && elf.body.sections) { for (const section of elf.body.sections) { if (section.name === ".rodata" || section.name === ".comment") { const content = section.data?.toString(); if (content) { const versionMatch = content.match(/(\d+\.\d+(?:\.\d+)?)/); if (versionMatch) { return { source: "executable", version: versionMatch[1], }; } } } } } return { error: "No version information found in ELF file", source: "fallback", }; } catch (error) { return { error: error instanceof Error ? error.message : String(error), source: "fallback", }; } } /** * Finds macOS .app or .xpc bundle path from executable path */ static findMacOSAppBundle(executablePath) { let currentPath = resolve(executablePath); // Walk up the directory tree looking for .app or .xpc bundle while (currentPath !== dirname(currentPath)) { if (currentPath.endsWith(".app") || currentPath.endsWith(".xpc")) { return currentPath; } currentPath = dirname(currentPath); } return null; } /** * Extracts version from macOS Info.plist file */ static async extractFromPlist(appBundlePath) { try { const plistPath = join(appBundlePath, "Contents", "Info.plist"); const plist = await import("plist"); const plistContent = readFileSync(plistPath, "utf8"); const parsed = plist.default ? plist.default.parse(plistContent) : plist.parse(plistContent); // Cast to PlistInfo interface for type-safe property access const plistObj = parsed; // Try different version keys const version = plistObj.CFBundleShortVersionString || plistObj.CFBundleVersion || plistObj.CFBundleVersionString; if (version) { console.error(`[VERSION-EXTRACTOR] Found version in plist: ${version}`); return { source: "plist", version: String(version), }; } return { error: "No version found in Info.plist", source: "fallback", }; } catch (error) { return { error: error instanceof Error ? error.message : String(error), source: "fallback", }; } } /** * Gets application info with proper version detection */ static async getApplicationInfo(executablePath, processName, fallbackVersion) { const versionResult = await this.extractVersion(executablePath, processName); const bundlePath = process.platform === "darwin" ? this.findMacOSAppBundle(executablePath) : null; return { executablePath, name: processName, version: versionResult.version || fallbackVersion || "unknown", ...(bundlePath && { bundlePath }), }; } } //# sourceMappingURL=version-extractor.js.map