UNPKG

dmux

Version:

Tmux pane manager with AI agent integration for parallel development workflows

236 lines 8.79 kB
import { execSync } from 'child_process'; import fs from 'fs/promises'; import { createRequire } from 'module'; const require = createRequire(import.meta.url); const packageJson = require('../package.json'); export class AutoUpdater { configFile; checkIntervalMs = 24 * 60 * 60 * 1000; // 24 hours constructor(configFile) { this.configFile = configFile; } async loadSettings() { try { const content = await fs.readFile(this.configFile, 'utf-8'); const config = JSON.parse(content); return config.updateSettings || { checkIntervalHours: 24, autoUpdateEnabled: true }; } catch { return { checkIntervalHours: 24, autoUpdateEnabled: true }; } } async saveSettings(settings) { let config = {}; try { const content = await fs.readFile(this.configFile, 'utf-8'); config = JSON.parse(content); } catch { } config.updateSettings = settings; config.lastUpdated = new Date().toISOString(); await fs.writeFile(this.configFile, JSON.stringify(config, null, 2)); } async shouldCheckForUpdates() { const settings = await this.loadSettings(); const now = Date.now(); if (!settings.lastCheckTime) { return true; } const intervalMs = (settings.checkIntervalHours || 24) * 60 * 60 * 1000; return now - settings.lastCheckTime > intervalMs; } async getLatestVersion() { try { // First try using npm view which is usually faster const result = execSync(`npm view ${packageJson.name} version`, { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 }).trim(); if (result && this.isValidVersion(result)) { return result; } } catch { // Fallback to npm registry API try { const response = await fetch(`https://registry.npmjs.org/${packageJson.name}/latest`, { method: 'GET', headers: { 'User-Agent': `${packageJson.name}/${packageJson.version}` } }); if (response.ok) { const data = await response.json(); if (data.version && this.isValidVersion(data.version)) { return data.version; } } } catch { // Network error or API unavailable } } return null; } isValidVersion(version) { return /^\d+\.\d+\.\d+/.test(version); } compareVersions(current, latest) { const currentParts = current.split('.').map(n => parseInt(n)); const latestParts = latest.split('.').map(n => parseInt(n)); for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) { const currentPart = currentParts[i] || 0; const latestPart = latestParts[i] || 0; if (latestPart > currentPart) return true; if (latestPart < currentPart) return false; } return false; } async detectInstallMethod() { try { // Check if dmux is globally installed and how // Method 1: Check npm global packages try { const npmGlobals = execSync('npm list -g --depth=0', { encoding: 'utf-8', stdio: 'pipe' }); if (npmGlobals.includes(`${packageJson.name}@`)) { return { packageManager: 'npm', installMethod: 'global' }; } } catch { } // Method 2: Check pnpm global packages try { const pnpmGlobals = execSync('pnpm list -g --depth=0', { encoding: 'utf-8', stdio: 'pipe' }); if (pnpmGlobals.includes(`${packageJson.name}@`)) { return { packageManager: 'pnpm', installMethod: 'global' }; } } catch { } // Method 3: Check yarn global packages try { const yarnGlobals = execSync('yarn global list --depth=0', { encoding: 'utf-8', stdio: 'pipe' }); if (yarnGlobals.includes(`${packageJson.name}@`)) { return { packageManager: 'yarn', installMethod: 'global' }; } } catch { } // Method 4: Check where dmux is installed by looking at the executable path try { const dmuxPath = execSync('which dmux', { encoding: 'utf-8', stdio: 'pipe' }).trim(); if (dmuxPath.includes('/.npm/') || dmuxPath.includes('/npm/')) { return { packageManager: 'npm', installMethod: 'global' }; } else if (dmuxPath.includes('/.pnpm/')) { return { packageManager: 'pnpm', installMethod: 'global' }; } else if (dmuxPath.includes('/.yarn/')) { return { packageManager: 'yarn', installMethod: 'global' }; } else if (dmuxPath.includes('/node_modules/.bin/')) { // Local installation return { packageManager: null, installMethod: 'local' }; } } catch { } return { packageManager: null, installMethod: 'unknown' }; } catch { return { packageManager: null, installMethod: 'unknown' }; } } async checkForUpdates() { const latestVersion = await this.getLatestVersion(); const currentVersion = packageJson.version; const { packageManager, installMethod } = await this.detectInstallMethod(); const hasUpdate = latestVersion ? this.compareVersions(currentVersion, latestVersion) : false; // Update last check time const settings = await this.loadSettings(); settings.lastCheckTime = Date.now(); await this.saveSettings(settings); return { currentVersion, latestVersion: latestVersion || 'unknown', hasUpdate, packageManager, installMethod }; } async performUpdate(updateInfo) { if (!updateInfo.hasUpdate || !updateInfo.packageManager || updateInfo.installMethod !== 'global') { return false; } try { let updateCommand; switch (updateInfo.packageManager) { case 'npm': updateCommand = `npm update -g ${packageJson.name}`; break; case 'pnpm': updateCommand = `pnpm update -g ${packageJson.name}`; break; case 'yarn': updateCommand = `yarn global upgrade ${packageJson.name}`; break; default: return false; } // Run the update command with a timeout execSync(updateCommand, { stdio: 'pipe', timeout: 60000 // 1 minute timeout }); // Verify the update was successful const newUpdateInfo = await this.checkForUpdates(); return newUpdateInfo.currentVersion === updateInfo.latestVersion; } catch { return false; } } async skipVersion(version) { const settings = await this.loadSettings(); settings.skipVersion = version; await this.saveSettings(settings); } async shouldShowUpdateNotification(updateInfo) { if (!updateInfo.hasUpdate) { return false; } const settings = await this.loadSettings(); // Don't show if user has disabled auto-updates if (settings.autoUpdateEnabled === false) { return false; } // Don't show if user has skipped this version if (settings.skipVersion === updateInfo.latestVersion) { return false; } return true; } async setAutoUpdateEnabled(enabled) { const settings = await this.loadSettings(); settings.autoUpdateEnabled = enabled; await this.saveSettings(settings); } } //# sourceMappingURL=AutoUpdater.js.map