@ebowwa/pkg-ops 0.1.22 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/package.json +4 -2
- package/scripts/check-or-build-rust.js +68 -0
package/dist/index.js
CHANGED
|
@@ -71,5 +71,5 @@ Examples:
|
|
|
71
71
|
pkg-ops audit
|
|
72
72
|
`)}async function _1(){let Y=process.argv.slice(2);if(Y.length===0||Y[0]==="--help"||Y[0]==="-h")O1(),process.exit(0);if(Y[0]==="--version"||Y[0]==="-v"){let Z=_();console.log(`pkg-ops ${Z.packages?.["@ebowwa/pkg-ops"]?.version??"0.1.0"}`),process.exit(0)}let $=Y[0],W=Y.slice(1);if($==="service"){if(W.length===0)console.error("Missing service subcommand"),console.error("Usage: pkg-ops service <start|stop|restart|status|logs|enable|disable> <name>"),process.exit(1);let Z=W[0],q=Q1.find((Q)=>Q.name===Z);if(!q)console.error(`Unknown service subcommand: ${Z}`),process.exit(1);await q.handler(W.slice(1));return}if($==="config"){if(W.length===0)console.error("Missing config subcommand"),console.error("Usage: pkg-ops config <show|set> [args...]"),process.exit(1);let Z=W[0],q=H1.find((Q)=>Q.name===Z);if(!q)console.error(`Unknown config subcommand: ${Z}`),process.exit(1);await q.handler(W.slice(1));return}let X=q1.find((Z)=>Z.name===$);if(!X)console.error(`Unknown command: ${$}`),console.error("Run 'pkg-ops --help' for usage"),process.exit(1);await X.handler(W)}var w1=process.argv[1]?.includes("pkg-ops");if(w1)_1().catch((Y)=>{console.error("Fatal error:",Y),process.exit(1)});export{M as updatePackageConfig,j0 as stopHealthServer,O as stopBridge,p0 as startHealthServer,U as startBridge,G0 as setActiveVersion,b as saveConfig,b0 as removePackageVersion,R0 as removePackageConfig,D as parsePackageSpec,_ as loadConfig,z as listManagedPackages,x0 as isVersionInstalled,K as isValidPackageName,M0 as getVersionCount,T as getServiceManager,D0 as getPackagesWithMultipleVersions,J as getPackageConfig,y0 as getInstalledVersions,v as getHealthServer,S as getConfigPath,W0 as getBridge,V0 as getActiveVersion,p as ensureConfigDir,I0 as addPackageVersion,f as ServiceManager,u as RustBridge,k as HealthServer};
|
|
73
73
|
|
|
74
|
-
//# debugId=
|
|
74
|
+
//# debugId=94AA821F33CC03D264756E2164756E21
|
|
75
75
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/config.ts", "
|
|
3
|
+
"sources": ["../src/index.ts", "../src/config.ts", "../node_modules/@ebowwa/installations/dist/systemd.js", "../src/service-manager.ts", "../src/bridge.ts", "../src/health-server.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"#!/usr/bin/env bun\n/**\n * PkgOps CLI\n *\n * Package operations CLI that installs @ebowwa/* npm packages\n * and manages systemd services.\n *\n * @example\n * ```bash\n * # Install a package\n * pkg-ops install @ebowwa/stack@0.7.12\n *\n * # Service management\n * pkg-ops service start stack\n * pkg-ops service status stack\n *\n * # Health check\n * pkg-ops health\n *\n * # List packages\n * pkg-ops list\n * ```\n */\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport {\n loadConfig,\n parsePackageSpec,\n isValidPackageName,\n getPackageConfig,\n updatePackageConfig,\n removePackageConfig,\n listManagedPackages,\n} from \"./config.js\";\nimport { ServiceManager, getServiceManager } from \"./service-manager.js\";\nimport { RustBridge, startBridge, stopBridge } from \"./bridge.js\";\nimport { startHealthServer, stopHealthServer, getHealthServer } from \"./health-server.js\";\nimport type { VerifyResult, AuditResult, BundleSize, InstalledPackageInfo } from \"./bridge.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface Command {\n name: string;\n description: string;\n usage: string;\n handler: (args: string[]) => Promise<void> | void;\n}\n\ninterface Subcommand {\n name: string;\n description: string;\n usage: string;\n handler: (args: string[]) => Promise<void> | void;\n}\n\n// ---------------------------------------------------------------------------\n// Package Management Commands\n// ---------------------------------------------------------------------------\n\nasync function handleInstall(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops install <package>[@version]\");\n process.exit(1);\n }\n\n const spec = args[0];\n const { name, version } = parsePackageSpec(spec);\n\n if (!isValidPackageName(name)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n console.log(`Installing ${name}@${version}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.install(name, version);\n\n if (result.success) {\n console.log(`Successfully installed ${name}@${result.version}`);\n if (result.previousVersion) {\n console.log(` Previous version: ${result.previousVersion}`);\n }\n\n // Update config (add version to versions map)\n const existingConfig = getPackageConfig(name);\n updatePackageConfig(name, {\n version: result.version,\n versions: {\n ...existingConfig?.versions,\n [result.version]: {\n installedAt: new Date().toISOString(),\n distSizeBytes: null,\n fileCount: null,\n },\n },\n service: name.replace(\"@ebowwa/\", \"\"),\n });\n\n // Start service if configured\n const config = getPackageConfig(name);\n if (config?.service && config.autoStart !== false) {\n const sm = getServiceManager();\n const startResult = await sm.start(config.service);\n if (startResult.success) {\n console.log(` Service ${config.service} started`);\n } else {\n console.warn(` Failed to start service: ${startResult.message}`);\n }\n }\n } else {\n console.error(`Failed to install ${name}: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(`Install failed:`, error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleUpdate(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops update <package>\");\n process.exit(1);\n }\n\n const packageName = args[0];\n\n if (!isValidPackageName(packageName)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n console.log(`Updating ${packageName}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.update(packageName);\n\n if (result.success) {\n console.log(`Successfully updated ${packageName} to ${result.version}`);\n if (result.previousVersion) {\n console.log(` Previous version: ${result.previousVersion}`);\n }\n\n // Update config (add version to versions map)\n const existingConfig = getPackageConfig(packageName);\n updatePackageConfig(packageName, {\n version: result.version,\n versions: {\n ...existingConfig?.versions,\n [result.version]: {\n installedAt: new Date().toISOString(),\n distSizeBytes: null,\n fileCount: null,\n },\n },\n service: packageName.replace(\"@ebowwa/\", \"\"),\n });\n\n // Restart service if running\n const sm = getServiceManager();\n const config = getPackageConfig(packageName);\n if (config?.service) {\n const status = await sm.status(config.service);\n if (status.active) {\n await sm.restart(config.service);\n console.log(` Service ${config.service} restarted`);\n }\n }\n } else {\n console.error(`Failed to update ${packageName}: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(`Update failed:`, error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleUpdateAll(_args: string[]): Promise<void> {\n console.log(\"Updating all managed packages...\");\n\n try {\n const bridge = await startBridge();\n const results = await bridge.updateAll();\n\n for (const result of results) {\n if (result.success) {\n console.log(`Updated ${result.version}`);\n } else {\n console.error(`Failed to update: ${result.message}`);\n }\n }\n } catch (error) {\n console.error(\"Update all failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleList(_args: string[]): Promise<void> {\n console.log(\"Installed packages:\\n\");\n\n try {\n const bridge = await startBridge();\n const packages = await bridge.list();\n\n if (packages.length === 0) {\n console.log(\" No packages installed\");\n return;\n }\n\n for (const pkg of packages) {\n const status = pkg.installed ? \"installed\" : \"not installed\";\n const service = pkg.service ? ` (service: ${pkg.service})` : \"\";\n console.log(` ${pkg.name}@${pkg.version} [${status}]${service}`);\n }\n } catch (error) {\n console.error(\"Failed to list packages:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleRollback(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops rollback <package>\");\n process.exit(1);\n }\n\n const packageName = args[0];\n\n console.log(`Rolling back ${packageName}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.rollback(packageName);\n\n if (result.success) {\n console.log(`Rolled back ${packageName} from ${result.currentVersion} to ${result.previousVersion}`);\n\n // Restart service if running\n const sm = getServiceManager();\n const config = getPackageConfig(packageName);\n if (config?.service) {\n const status = await sm.status(config.service);\n if (status.active) {\n await sm.restart(config.service);\n console.log(` Service ${config.service} restarted`);\n }\n }\n } else {\n console.error(`Rollback failed: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Rollback failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Service Management Commands\n// ---------------------------------------------------------------------------\n\nasync function handleServiceStart(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service start <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n console.log(`Starting ${serviceName}...`);\n const result = await sm.start(serviceName);\n\n if (result.success) {\n console.log(`Service ${serviceName} started`);\n } else {\n console.error(`Failed to start ${serviceName}: ${result.message}`);\n process.exit(1);\n }\n}\n\nasync function handleServiceStop(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service stop <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n console.log(`Stopping ${serviceName}...`);\n const result = await sm.stop(serviceName);\n\n if (result.success) {\n console.log(`Service ${serviceName} stopped`);\n } else {\n console.error(`Failed to stop ${serviceName}: ${result.message}`);\n process.exit(1);\n }\n}\n\nasync function handleServiceRestart(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service restart <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n console.log(`Restarting ${serviceName}...`);\n const result = await sm.restart(serviceName);\n\n if (result.success) {\n console.log(`Service ${serviceName} restarted`);\n } else {\n console.error(`Failed to restart ${serviceName}: ${result.message}`);\n process.exit(1);\n }\n}\n\nasync function handleServiceStatus(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service status <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n const info = await sm.info(serviceName);\n\n if (!info.exists) {\n console.log(`Service ${serviceName} not found`);\n return;\n }\n\n console.log(`Service: ${serviceName}`);\n console.log(` Loaded: ${info.status.loaded}`);\n console.log(` Active: ${info.status.active}`);\n console.log(` State: ${info.status.subState}`);\n console.log(` PID: ${info.status.mainPid || \"N/A\"}`);\n console.log(` Description: ${info.status.description || \"N/A\"}`);\n}\n\nasync function handleServiceLogs(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service logs <name> [--lines N]\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const linesIndex = args.indexOf(\"--lines\");\n const lines = linesIndex >= 0 && args[linesIndex + 1]\n ? parseInt(args[linesIndex + 1], 10)\n : 100;\n\n const sm = getServiceManager();\n const logs = await sm.logs(serviceName, { lines });\n\n console.log(logs);\n}\n\nasync function handleServiceEnable(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service enable <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n console.log(`Enabling ${serviceName}...`);\n const result = await sm.enable(serviceName);\n\n if (result.success) {\n console.log(`Service ${serviceName} enabled on boot`);\n } else {\n console.error(`Failed to enable ${serviceName}: ${result.message}`);\n process.exit(1);\n }\n}\n\nasync function handleServiceDisable(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops service disable <name>\");\n process.exit(1);\n }\n\n const serviceName = args[0];\n const sm = getServiceManager();\n\n console.log(`Disabling ${serviceName}...`);\n const result = await sm.disable(serviceName);\n\n if (result.success) {\n console.log(`Service ${serviceName} disabled from boot`);\n } else {\n console.error(`Failed to disable ${serviceName}: ${result.message}`);\n process.exit(1);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Health Commands\n// ---------------------------------------------------------------------------\n\nasync function handleHealth(args: string[]): Promise<void> {\n const serviceName = args[0];\n\n const healthServer = getHealthServer();\n if (!healthServer) {\n console.error(\"Health server not initialized\");\n process.exit(1);\n }\n\n const health = await healthServer.checkHealth(serviceName);\n\n if (!health) {\n console.log(\"Service not found\");\n return;\n }\n\n if (\"services\" in health) {\n // SystemHealth\n if (health.healthy) {\n console.log(\"All services healthy\");\n } else {\n console.log(\"Some services unhealthy\");\n }\n\n for (const service of health.services) {\n const icon = service.healthy ? \"OK\" : \"FAIL\";\n console.log(` [${icon}] ${service.name}: ${service.status.subState}`);\n }\n } else {\n // ServiceHealth\n const icon = health.healthy ? \"OK\" : \"FAIL\";\n console.log(`[${icon}] ${health.name}: ${health.status.subState}`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Config Commands\n// ---------------------------------------------------------------------------\n\nasync function handleConfigShow(_args: string[]): Promise<void> {\n const config = loadConfig();\n\n console.log(\"PkgOps Configuration\");\n console.log(`Config path: /etc/pkg-ops/config.json`);\n console.log(`Health port: ${config.healthPort}`);\n console.log(`Work dir: ${config.workDir}`);\n console.log(`Log level: ${config.logLevel}`);\n console.log(\"\\nPackages:\");\n\n const packages = listManagedPackages();\n if (packages.length === 0) {\n console.log(\" No packages configured\");\n return;\n }\n\n for (const { name, config: pkgConfig } of packages) {\n console.log(` ${name}:`);\n console.log(` Version: ${pkgConfig.version}`);\n if (pkgConfig.service) {\n console.log(` Service: ${pkgConfig.service}`);\n }\n if (pkgConfig.autoStart !== undefined) {\n console.log(` Auto-start: ${pkgConfig.autoStart}`);\n }\n }\n}\n\nasync function handleConfigSet(args: string[]): Promise<void> {\n if (args.length < 3) {\n console.error(\"Usage: pkg-ops config set <package> <key> <value>\");\n process.exit(1);\n }\n\n const packageName = args[0];\n const key = args[1];\n const value = args[2];\n\n if (!isValidPackageName(packageName)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n const config = getPackageConfig(packageName) ?? {\n version: \"latest\",\n versions: {},\n };\n\n // Handle different value types\n switch (key) {\n case \"version\":\n config.version = value;\n break;\n case \"service\":\n config.service = value;\n break;\n case \"autoStart\":\n config.autoStart = value === \"true\";\n break;\n default:\n console.error(`Unknown config key: ${key}`);\n console.error(\"Valid keys: version, service, autoStart\");\n process.exit(1);\n }\n\n updatePackageConfig(packageName, config);\n console.log(`Updated ${packageName}.${key} = ${value}`);\n}\n\n// ---------------------------------------------------------------------------\n// Verification & Audit Commands\n// ---------------------------------------------------------------------------\n\nasync function handleVerify(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops verify <package>\");\n process.exit(1);\n }\n\n const packageName = args[0];\n\n if (!isValidPackageName(packageName)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n console.log(`Verifying ${packageName}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.verify(packageName);\n\n console.log(`\\nPackage: ${result.packageName}@${result.version}`);\n console.log(` Status: ${result.success ? \"VALID\" : \"INVALID\"}`);\n console.log(` Dist exists: ${result.distExists ? \"Yes\" : \"No\"}`);\n if (result.checksum) {\n console.log(` Checksum: ${result.checksum}`);\n }\n console.log(` Message: ${result.message}`);\n } catch (error) {\n console.error(\"Verification failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleSyncStatus(args: string[]): Promise<void> {\n const localIndex = args.indexOf(\"--local\");\n const localPathIndex = args.indexOf(\"--local-path\");\n\n let localPath = \"./package.json\";\n if (localPathIndex >= 0 && args[localPathIndex + 1]) {\n localPath = args[localPathIndex + 1];\n }\n\n const showLocal = localIndex >= 0 || localPathIndex >= 0;\n\n try {\n const bridge = await startBridge();\n const vpsPackages = await bridge.getInstalledInfo();\n\n console.log(\"Sync Status: Local vs VPS\\n\");\n\n if (showLocal && existsSync(localPath)) {\n const localContent = readFileSync(localPath, \"utf-8\");\n const localPkg = JSON.parse(localContent);\n const deps = { ...localPkg.dependencies, ...localPkg.devDependencies };\n\n // Build a map of VPS packages\n const vpsMap = new Map<string, string>();\n for (const pkg of vpsPackages) {\n vpsMap.set(pkg.packageName, pkg.version);\n }\n\n // Compare local vs VPS\n for (const [name, localVersion] of Object.entries(deps)) {\n if (!name.startsWith(\"@ebowwa/\")) continue;\n\n const vpsVersion = vpsMap.get(name);\n const cleanLocal = (localVersion as string).replace(/^[\\^~]/, \"\");\n\n if (vpsVersion) {\n if (cleanLocal === vpsVersion) {\n console.log(` ${name}: local=${cleanLocal}, vps=${vpsVersion} (in sync)`);\n } else if (cleanLocal > vpsVersion) {\n console.log(` ${name}: local=${cleanLocal}, vps=${vpsVersion} (VPS behind)`);\n } else {\n console.log(` ${name}: local=${cleanLocal}, vps=${vpsVersion} (local behind)`);\n }\n vpsMap.delete(name);\n } else {\n console.log(` ${name}: local=${cleanLocal}, vps=not installed`);\n }\n }\n\n // Show VPS-only packages\n for (const [name, version] of vpsMap) {\n console.log(` ${name}: local=not in package.json, vps=${version}`);\n }\n } else {\n // Just show VPS installed versions\n if (vpsPackages.length === 0) {\n console.log(\" No packages installed on VPS\");\n } else {\n for (const pkg of vpsPackages) {\n const sizeInfo = pkg.distSizeBytes\n ? ` (${(pkg.distSizeBytes / 1024).toFixed(1)} KB)`\n : \"\";\n console.log(` ${pkg.packageName}@${pkg.version}${sizeInfo}`);\n }\n }\n }\n } catch (error) {\n console.error(\"Failed to get sync status:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleAudit(_args: string[]): Promise<void> {\n console.log(\"Running vulnerability scan...\\n\");\n\n try {\n const bridge = await startBridge();\n const results = await bridge.audit();\n\n if (results.length === 0) {\n console.log(\"No vulnerabilities found.\");\n return;\n }\n\n console.log(`Found ${results.length} vulnerability(es):\\n`);\n\n for (const vuln of results) {\n console.log(`[${vuln.severity.toUpperCase()}] ${vuln.packageName}`);\n console.log(` Vulnerability: ${vuln.vulnerability}`);\n console.log(` Description: ${vuln.description}`);\n console.log(\"\");\n }\n } catch (error) {\n console.error(\"Audit failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleScan(args: string[]): Promise<void> {\n // Alias for audit\n await handleAudit(args);\n}\n\nasync function handleSizes(_args: string[]): Promise<void> {\n console.log(\"Bundle sizes:\\n\");\n\n try {\n const bridge = await startBridge();\n const sizes = await bridge.getBundleSizes();\n\n if (sizes.length === 0) {\n console.log(\" No packages installed\");\n return;\n }\n\n // Print table header\n console.log(\" Package | Version | Dist Size\");\n console.log(\" --------------------------------|----------|-----------\");\n\n for (const pkg of sizes) {\n const name = pkg.packageName.padEnd(32);\n const version = pkg.version.padEnd(9);\n const sizeKB = (pkg.distSizeBytes / 1024).toFixed(1) + \" KB\";\n const files = pkg.fileCount ? ` (${pkg.fileCount} files)` : \"\";\n console.log(` ${name} | ${version} | ${sizeKB}${files}`);\n }\n } catch (error) {\n console.error(\"Failed to get bundle sizes:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Multi-Version Commands\n// ---------------------------------------------------------------------------\n\nasync function handleVersions(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops versions <package>\");\n process.exit(1);\n }\n\n const packageName = args[0];\n\n if (!isValidPackageName(packageName)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n try {\n const bridge = await startBridge();\n const versions = await bridge.listVersions(packageName);\n await stopBridge();\n\n if (versions.length === 0) {\n console.log(`No versions of ${packageName} installed.`);\n return;\n }\n\n console.log(`Installed versions for ${packageName}:\\n`);\n\n // Sort versions descending (newest first)\n const sorted = [...versions].sort((a, b) => b.installedAt.localeCompare(a.installedAt));\n\n for (const v of sorted) {\n const active = v.active ? \" [ACTIVE]\" : \"\";\n const size = v.distSizeBytes ? ` (${(v.distSizeBytes / 1024).toFixed(1)} KB)` : \"\";\n const date = new Date(v.installedAt).toLocaleString();\n console.log(` ${v.version}${active}${size}`);\n console.log(` Installed: ${date}`);\n if (v.fileCount) {\n console.log(` Files: ${v.fileCount}`);\n }\n }\n\n console.log(`\\nTotal: ${versions.length} version(s)`);\n } catch (error) {\n console.error(\"Failed to list versions:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleSwitch(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops switch <package>@<version>\");\n process.exit(1);\n }\n\n const spec = args[0];\n const { name, version } = parsePackageSpec(spec);\n\n if (!isValidPackageName(name)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n if (!version || version === \"latest\") {\n console.error(\"Error: Must specify a version to switch to (e.g., @ebowwa/stack@0.7.12)\");\n process.exit(1);\n }\n\n console.log(`Switching ${name} to version ${version}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.switchVersion(name, version);\n\n if (result.success) {\n console.log(`Switched ${name} from ${result.fromVersion} to ${result.toVersion}`);\n\n // Restart service if running\n const sm = getServiceManager();\n const config = getPackageConfig(name);\n if (config?.service) {\n const status = await sm.status(config.service);\n if (status.active) {\n await sm.restart(config.service);\n console.log(` Service ${config.service} restarted`);\n }\n }\n } else {\n console.error(`Switch failed: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Switch failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handlePrune(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops prune <package> [--keep N]\");\n process.exit(1);\n }\n\n const packageName = args[0];\n const keepIndex = args.indexOf(\"--keep\");\n const keepCount = keepIndex >= 0 && args[keepIndex + 1]\n ? parseInt(args[keepIndex + 1], 10)\n : 2; // Default: keep 2 versions\n\n if (!isValidPackageName(packageName)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n console.log(`Pruning ${packageName}, keeping ${keepCount} most recent version(s)...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.pruneVersions(packageName, keepCount);\n await stopBridge();\n\n if (result.success) {\n if (result.removedVersions.length === 0) {\n console.log(`No versions to remove (only ${result.keptVersions.length} installed).`);\n } else {\n console.log(`Removed ${result.removedVersions.length} version(s):`);\n for (const v of result.removedVersions) {\n console.log(` - ${v}`);\n }\n console.log(`Freed: ${(result.freedBytes / 1024).toFixed(1)} KB`);\n console.log(`Kept: ${result.keptVersions.join(\", \")}`);\n }\n } else {\n console.error(`Prune failed: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Prune failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleRemoveVersion(args: string[]): Promise<void> {\n if (args.length === 0) {\n console.error(\"Usage: pkg-ops remove-version <package>@<version>\");\n process.exit(1);\n }\n\n const spec = args[0];\n const { name, version } = parsePackageSpec(spec);\n\n if (!isValidPackageName(name)) {\n console.error(`Invalid package name. Only @ebowwa/* packages are supported.`);\n process.exit(1);\n }\n\n if (!version || version === \"latest\") {\n console.error(\"Error: Must specify a version to remove (e.g., @ebowwa/stack@0.7.12)\");\n process.exit(1);\n }\n\n // Check if trying to remove active version\n const config = getPackageConfig(name);\n if (config?.version === version) {\n console.error(`Error: Cannot remove active version ${version}. Switch to another version first.`);\n process.exit(1);\n }\n\n console.log(`Removing ${name}@${version}...`);\n\n try {\n const bridge = await startBridge();\n const result = await bridge.removeVersion(name, version);\n await stopBridge();\n\n if (result.success) {\n console.log(`Removed ${name}@${version}`);\n } else {\n console.error(`Remove failed: ${result.message}`);\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Remove failed:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\nasync function handleMultiVersionList(_args: string[]): Promise<void> {\n try {\n const bridge = await startBridge();\n const packages = await bridge.getMultiVersionPackages();\n await stopBridge();\n\n if (packages.length === 0) {\n console.log(\"No packages with multiple versions installed.\");\n return;\n }\n\n console.log(\"Packages with multiple versions:\\n\");\n\n for (const pkg of packages) {\n console.log(` ${pkg.packageName}:`);\n console.log(` Active: ${pkg.activeVersion}`);\n console.log(` Total: ${pkg.totalVersions} version(s)`);\n console.log(` Versions: ${pkg.versions.join(\", \")}`);\n console.log(\"\");\n }\n } catch (error) {\n console.error(\"Failed to list multi-version packages:\", error);\n process.exit(1);\n } finally {\n await stopBridge();\n }\n}\n\n// ---------------------------------------------------------------------------\n// CLI Entry Point\n// ---------------------------------------------------------------------------\n\nconst commands: Command[] = [\n // Package management\n { name: \"install\", description: \"Install an @ebowwa/* package\", usage: \"pkg-ops install <package>[@version]\", handler: handleInstall },\n { name: \"update\", description: \"Update a package to latest version\", usage: \"pkg-ops update <package>\", handler: handleUpdate },\n { name: \"update-all\", description: \"Update all managed packages\", usage: \"pkg-ops update-all\", handler: handleUpdateAll },\n { name: \"list\", description: \"List installed packages\", usage: \"pkg-ops list\", handler: handleList },\n { name: \"rollback\", description: \"Rollback a package to previous version\", usage: \"pkg-ops rollback <package>\", handler: handleRollback },\n // Multi-version management\n { name: \"versions\", description: \"List all installed versions of a package\", usage: \"pkg-ops versions <package>\", handler: handleVersions },\n { name: \"switch\", description: \"Switch to a specific installed version\", usage: \"pkg-ops switch <package>@<version>\", handler: handleSwitch },\n { name: \"prune\", description: \"Remove old versions, keeping N most recent\", usage: \"pkg-ops prune <package> [--keep N]\", handler: handlePrune },\n { name: \"remove-version\", description: \"Remove a specific version\", usage: \"pkg-ops remove-version <package>@<version>\", handler: handleRemoveVersion },\n { name: \"multi\", description: \"List packages with multiple versions\", usage: \"pkg-ops multi\", handler: handleMultiVersionList },\n // Service management\n { name: \"start\", description: \"Start a systemd service\", usage: \"pkg-ops service start <name>\", handler: handleServiceStart },\n { name: \"stop\", description: \"Stop a systemd service\", usage: \"pkg-ops service stop <name>\", handler: handleServiceStop },\n { name: \"restart\", description: \"Restart a systemd service\", usage: \"pkg-ops service restart <name>\", handler: handleServiceRestart },\n { name: \"status\", description: \"Get service status\", usage: \"pkg-ops service status <name>\", handler: handleServiceStatus },\n { name: \"logs\", description: \"View service logs\", usage: \"pkg-ops service logs <name> [--lines N]\", handler: handleServiceLogs },\n { name: \"enable\", description: \"Enable service on boot\", usage: \"pkg-ops service enable <name>\", handler: handleServiceEnable },\n { name: \"disable\", description: \"Disable service from boot\", usage: \"pkg-ops service disable <name>\", handler: handleServiceDisable },\n // Health\n { name: \"health\", description: \"Check health of all services\", usage: \"pkg-ops health [service]\", handler: handleHealth },\n // Config\n { name: \"config\", description: \"Show configuration\", usage: \"pkg-ops config show\", handler: handleConfigShow },\n { name: \"set-config\", description: \"Set a config value\", usage: \"pkg-ops config set <package> <key> <value>\", handler: handleConfigSet },\n // Verification & Audit\n { name: \"verify\", description: \"Verify package integrity\", usage: \"pkg-ops verify <package>\", handler: handleVerify },\n { name: \"sync-status\", description: \"Show local vs VPS version sync\", usage: \"pkg-ops sync-status [--local-path path]\", handler: handleSyncStatus },\n { name: \"audit\", description: \"Check for vulnerabilities\", usage: \"pkg-ops audit\", handler: handleAudit },\n { name: \"scan\", description: \"Alias for audit\", usage: \"pkg-ops scan\", handler: handleScan },\n { name: \"sizes\", description: \"Show bundle sizes\", usage: \"pkg-ops sizes\", handler: handleSizes },\n];\n\nconst serviceCommands: Subcommand[] = [\n { name: \"start\", description: \"Start a systemd service\", usage: \"pkg-ops service start <name>\", handler: handleServiceStart },\n { name: \"stop\", description: \"Stop a systemd service\", usage: \"pkg-ops service stop <name>\", handler: handleServiceStop },\n { name: \"restart\", description: \"Restart a systemd service\", usage: \"pkg-ops service restart <name>\", handler: handleServiceRestart },\n { name: \"status\", description: \"Get service status\", usage: \"pkg-ops service status <name>\", handler: handleServiceStatus },\n { name: \"logs\", description: \"View service logs\", usage: \"pkg-ops service logs <name> [--lines N]\", handler: handleServiceLogs },\n { name: \"enable\", description: \"Enable service on boot\", usage: \"pkg-ops service enable <name>\", handler: handleServiceEnable },\n { name: \"disable\", description: \"Disable service from boot\", usage: \"pkg-ops service disable <name>\", handler: handleServiceDisable },\n];\n\nconst configCommands: Subcommand[] = [\n { name: \"show\", description: \"Show configuration\", usage: \"pkg-ops config show\", handler: handleConfigShow },\n { name: \"set\", description: \"Set a config value\", usage: \"pkg-ops config set <package> <key> <value>\", handler: handleConfigSet },\n];\n\nfunction printHelp(): void {\n console.log(`\nPkgOps - Package operations CLI for VPS\n\nUsage:\n pkg-ops <command> [arguments]\n\nPackage Management:\n install <package>[@version] Install an @ebowwa/* package\n update <package> Update a package to latest version\n update-all Update all managed packages\n list List installed packages\n rollback <package> Rollback a package to previous version\n\nMulti-Version Management:\n versions <package> List all installed versions\n switch <package>@<version> Switch to a specific version\n prune <package> [--keep N] Remove old versions (default: keep 2)\n remove-version <pkg>@<ver> Remove a specific version\n multi List packages with multiple versions\n\nService Management:\n service start <name> Start a systemd service\n service stop <name> Stop a systemd service\n service restart <name> Restart a systemd service\n service status <name> Get service status\n service logs <name> [--lines N] View service logs\n service enable <name> Enable service on boot\n service disable <name> Disable service from boot\n\nHealth:\n health [service] Check health of all services or specific one\n\nVerification & Audit:\n verify <package> Verify package integrity\n sync-status [--local-path p] Show local vs VPS version sync\n audit Check for vulnerabilities\n scan Alias for audit\n sizes Show bundle sizes\n\nConfig:\n config show Show configuration\n config set <pkg> <key> <val> Set a config value\n\nOptions:\n --help, -h Show this help message\n --version, -v Show version\n\nExamples:\n pkg-ops install @ebowwa/stack@0.7.12\n pkg-ops service start stack\n pkg-ops health\n pkg-ops sync-status --local-path ./package.json\n pkg-ops verify @ebowwa/stack\n pkg-ops audit\n`);\n}\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n if (args.length === 0 || args[0] === \"--help\" || args[0] === \"-h\") {\n printHelp();\n process.exit(0);\n }\n\n if (args[0] === \"--version\" || args[0] === \"-v\") {\n const config = loadConfig();\n console.log(`pkg-ops ${config.packages?.[\"@ebowwa/pkg-ops\"]?.version ?? \"0.1.0\"}`);\n process.exit(0);\n }\n\n const commandName = args[0];\n const commandArgs = args.slice(1);\n\n // Handle service subcommands\n if (commandName === \"service\") {\n if (commandArgs.length === 0) {\n console.error(\"Missing service subcommand\");\n console.error(\"Usage: pkg-ops service <start|stop|restart|status|logs|enable|disable> <name>\");\n process.exit(1);\n }\n\n const subcommandName = commandArgs[0];\n const subcommand = serviceCommands.find((c) => c.name === subcommandName);\n\n if (!subcommand) {\n console.error(`Unknown service subcommand: ${subcommandName}`);\n process.exit(1);\n }\n\n await subcommand.handler(commandArgs.slice(1));\n return;\n }\n\n // Handle config subcommands\n if (commandName === \"config\") {\n if (commandArgs.length === 0) {\n console.error(\"Missing config subcommand\");\n console.error(\"Usage: pkg-ops config <show|set> [args...]\");\n process.exit(1);\n }\n\n const subcommandName = commandArgs[0];\n const subcommand = configCommands.find((c) => c.name === subcommandName);\n\n if (!subcommand) {\n console.error(`Unknown config subcommand: ${subcommandName}`);\n process.exit(1);\n }\n\n await subcommand.handler(commandArgs.slice(1));\n return;\n }\n\n // Handle regular commands\n const command = commands.find((c) => c.name === commandName);\n\n if (!command) {\n console.error(`Unknown command: ${commandName}`);\n console.error(\"Run 'pkg-ops --help' for usage\");\n process.exit(1);\n }\n\n await command.handler(commandArgs);\n}\n\n// Run CLI only when executed directly via bin (not when imported as library)\n// This check works after bundling where import.meta.main gets transformed\nconst isCliInvocation = process.argv[1]?.includes(\"pkg-ops\");\nif (isCliInvocation) {\n main().catch((error) => {\n console.error(\"Fatal error:\", error);\n process.exit(1);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports for library usage\n// ---------------------------------------------------------------------------\n\nexport {\n loadConfig,\n saveConfig,\n parsePackageSpec,\n isValidPackageName,\n getPackageConfig,\n updatePackageConfig,\n removePackageConfig,\n listManagedPackages,\n getConfigPath,\n ensureConfigDir,\n type PackageConfig,\n type PkgOpsConfig,\n} from \"./config.js\";\n\nexport {\n ServiceManager,\n getServiceManager,\n type ServiceInfo,\n type ServiceLogsOptions,\n} from \"./service-manager.js\";\n\nexport {\n RustBridge,\n startBridge,\n stopBridge,\n getBridge,\n type InstallResult,\n type PackageInfo,\n type RollbackResult,\n type VerifyResult,\n type AuditResult,\n type BundleSize,\n type InstalledPackageInfo,\n type VersionInfo,\n type SwitchResult,\n type PruneResult,\n} from \"./bridge.js\";\n\n// Multi-version config helpers\nexport {\n getInstalledVersions,\n isVersionInstalled,\n getActiveVersion,\n addPackageVersion,\n removePackageVersion,\n setActiveVersion,\n getVersionCount,\n getPackagesWithMultipleVersions,\n type VersionMetadata,\n} from \"./config.js\";\n\nexport {\n startHealthServer,\n stopHealthServer,\n getHealthServer,\n HealthServer,\n type HealthCheckResult,\n type ServiceHealth,\n type SystemHealth,\n} from \"./health-server.js\";\n\n",
|
|
6
6
|
"/**\n * Configuration management for PkgOps.\n *\n * Handles reading/writing config file at /etc/pkg-ops/config.json\n *\n * @example\n * ```typescript\n * import { loadConfig, saveConfig, getConfigPath } from \"@ebowwa/pkg-ops/config\";\n *\n * const config = await loadConfig();\n * console.log(config.packages);\n *\n * config.packages[\"@ebowwa/stack\"] = { version: \"0.7.13\", service: \"stack.service\" };\n * await saveConfig(config);\n * ```\n */\n\nimport { accessSync, constants, mkdirSync, readFileSync, writeFileSync, existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * Metadata for a single installed version.\n */\nexport interface VersionMetadata {\n /** ISO timestamp when this version was installed */\n installedAt: string;\n /** Size of the dist directory in bytes */\n distSizeBytes: number | null;\n /** Number of files in dist */\n fileCount: number | null;\n}\n\nexport interface PackageConfig {\n /** Currently active version (semver) */\n version: string;\n /** All installed versions with metadata */\n versions: Record<string, VersionMetadata>;\n /** Associated systemd service name (without .service suffix) */\n service?: string;\n /** Whether to auto-start the service after install */\n autoStart?: boolean;\n /** Custom environment variables for the service */\n environment?: Record<string, string>;\n}\n\nexport interface PkgOpsConfig {\n /** Managed packages */\n packages: Record<string, PackageConfig>;\n /** Health check HTTP port (default: 8914) */\n healthPort?: number;\n /** Working directory for installations (default: /root) */\n workDir?: string;\n /** Log level (default: \"info\") */\n logLevel?: \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_CONFIG: PkgOpsConfig = {\n packages: {},\n healthPort: 8914,\n workDir: \"/root\",\n logLevel: \"info\",\n};\n\nexport const CONFIG_DIR = \"/etc/pkg-ops\";\nexport const CONFIG_PATH = `${CONFIG_DIR}/config.json`;\n\n// ---------------------------------------------------------------------------\n// Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Get the config file path.\n * Respects PKG_OPS_CONFIG env override.\n */\nexport function getConfigPath(): string {\n return process.env.PKG_OPS_CONFIG ?? CONFIG_PATH;\n}\n\n/**\n * Ensure config directory exists (requires sudo on most systems).\n */\nexport function ensureConfigDir(): void {\n const configDir = dirname(getConfigPath());\n if (!existsSync(configDir)) {\n mkdirSync(configDir, { recursive: true, mode: constants.S_IRWXU | constants.S_IRGRP | constants.S_IXGRP });\n }\n}\n\n/**\n * Load configuration from file.\n * Returns default config if file doesn't exist.\n */\nexport function loadConfig(): PkgOpsConfig {\n const configPath = getConfigPath();\n\n try {\n if (!existsSync(configPath)) {\n return { ...DEFAULT_CONFIG };\n }\n\n const content = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(content);\n\n // Merge with defaults\n return {\n ...DEFAULT_CONFIG,\n ...parsed,\n };\n } catch (error) {\n console.error(`Failed to load config from ${configPath}:`, error);\n return { ...DEFAULT_CONFIG };\n }\n}\n\n/**\n * Save configuration to file.\n * Creates directory if it doesn't exist.\n */\nexport function saveConfig(config: PkgOpsConfig): void {\n const configPath = getConfigPath();\n ensureConfigDir();\n\n const content = JSON.stringify(config, null, 2);\n writeFileSync(configPath, content, {\n encoding: \"utf-8\",\n mode: constants.S_IRUSR | constants.S_IWUSR | constants.S_IRGRP,\n });\n}\n\n/**\n * Update a package in the config.\n */\nexport function updatePackageConfig(\n packageName: string,\n packageConfig: PackageConfig\n): PkgOpsConfig {\n const config = loadConfig();\n config.packages[packageName] = packageConfig;\n saveConfig(config);\n return config;\n}\n\n/**\n * Remove a package from the config.\n */\nexport function removePackageConfig(packageName: string): PkgOpsConfig {\n const config = loadConfig();\n delete config.packages[packageName];\n saveConfig(config);\n return config;\n}\n\n/**\n * Get a specific package config.\n */\nexport function getPackageConfig(packageName: string): PackageConfig | undefined {\n const config = loadConfig();\n return config.packages[packageName];\n}\n\n/**\n * List all managed packages.\n */\nexport function listManagedPackages(): Array<{ name: string; config: PackageConfig }> {\n const config = loadConfig();\n return Object.entries(config.packages).map(([name, cfg]) => ({ name, config: cfg }));\n}\n\n/**\n * Validate package name (must be @ebowwa/* scope).\n */\nexport function isValidPackageName(name: string): boolean {\n return name.startsWith(\"@ebowwa/\");\n}\n\n/**\n * Parse package specifier into name and version.\n * @example\n * parsePackageSpec(\"@ebowwa/stack@0.7.12\") => { name: \"@ebowwa/stack\", version: \"0.7.12\" }\n * parsePackageSpec(\"@ebowwa/stack\") => { name: \"@ebowwa/stack\", version: \"latest\" }\n */\nexport function parsePackageSpec(spec: string): { name: string; version: string } {\n const atIndex = spec.lastIndexOf(\"@\");\n if (atIndex <= 0) {\n // No version specified or scoped package without version\n return { name: spec, version: \"latest\" };\n }\n\n const name = spec.slice(0, atIndex);\n const version = spec.slice(atIndex + 1);\n\n if (!version) {\n return { name, version: \"latest\" };\n }\n\n return { name, version };\n}\n\n// ---------------------------------------------------------------------------\n// Multi-Version Helper Functions\n// ---------------------------------------------------------------------------\n\n/**\n * Get all installed versions for a package.\n */\nexport function getInstalledVersions(packageName: string): VersionMetadata[] {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n if (!pkgConfig?.versions) {\n return [];\n }\n return Object.entries(pkgConfig.versions).map(([version, meta]) => ({\n version,\n ...meta,\n }));\n}\n\n/**\n * Check if a specific version is installed.\n */\nexport function isVersionInstalled(packageName: string, version: string): boolean {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n return !!(pkgConfig?.versions?.[version]);\n}\n\n/**\n * Get the active version for a package.\n */\nexport function getActiveVersion(packageName: string): string | null {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n return pkgConfig?.version ?? null;\n}\n\n/**\n * Add a new version to the package config.\n */\nexport function addPackageVersion(\n packageName: string,\n version: string,\n metadata: Omit<VersionMetadata, \"installedAt\"> & { installedAt?: string }\n): void {\n const config = loadConfig();\n\n if (!config.packages[packageName]) {\n config.packages[packageName] = {\n version,\n versions: {},\n service: packageName.replace(\"@ebowwa/\", \"\"),\n autoStart: true,\n };\n }\n\n config.packages[packageName].versions[version] = {\n installedAt: metadata.installedAt ?? new Date().toISOString(),\n distSizeBytes: metadata.distSizeBytes ?? null,\n fileCount: metadata.fileCount ?? null,\n };\n\n saveConfig(config);\n}\n\n/**\n * Remove a version from the package config.\n * Returns true if the version was removed, false if it didn't exist.\n */\nexport function removePackageVersion(packageName: string, version: string): boolean {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n\n if (!pkgConfig?.versions?.[version]) {\n return false;\n }\n\n delete pkgConfig.versions[version];\n\n // If removing the active version, switch to the most recent remaining version\n if (pkgConfig.version === version) {\n const remainingVersions = Object.keys(pkgConfig.versions).sort((a, b) => {\n // Sort by installedAt descending (most recent first)\n const aTime = pkgConfig.versions[a]?.installedAt ?? \"\";\n const bTime = pkgConfig.versions[b]?.installedAt ?? \"\";\n return bTime.localeCompare(aTime);\n });\n\n if (remainingVersions.length > 0) {\n pkgConfig.version = remainingVersions[0];\n } else {\n // No versions left, remove the package entirely\n delete config.packages[packageName];\n }\n }\n\n saveConfig(config);\n return true;\n}\n\n/**\n * Set the active version for a package.\n * Returns true if successful, false if version not installed.\n */\nexport function setActiveVersion(packageName: string, version: string): boolean {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n\n if (!pkgConfig?.versions?.[version]) {\n return false;\n }\n\n pkgConfig.version = version;\n saveConfig(config);\n return true;\n}\n\n/**\n * Get the count of installed versions for a package.\n */\nexport function getVersionCount(packageName: string): number {\n const config = loadConfig();\n const pkgConfig = config.packages[packageName];\n return Object.keys(pkgConfig?.versions ?? {}).length;\n}\n\n/**\n * Get packages with multiple versions installed.\n */\nexport function getPackagesWithMultipleVersions(): Array<{\n name: string;\n activeVersion: string;\n totalVersions: number;\n versions: string[];\n}> {\n const config = loadConfig();\n const result: Array<{\n name: string;\n activeVersion: string;\n totalVersions: number;\n versions: string[];\n }> = [];\n\n for (const [name, pkgConfig] of Object.entries(config.packages)) {\n const versions = Object.keys(pkgConfig.versions ?? {});\n if (versions.length > 1) {\n result.push({\n name,\n activeVersion: pkgConfig.version,\n totalVersions: versions.length,\n versions: versions.sort((a, b) => b.localeCompare(a, undefined, { numeric: true })),\n });\n }\n }\n\n return result;\n}\n",
|
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
"/**\n * Health monitoring HTTP server.\n *\n * Provides an HTTP endpoint for health checks on port 8914 (configurable).\n *\n * @example\n * ```typescript\n * import { HealthServer, startHealthServer } from \"@ebowwa/pkg-ops/health-server\";\n *\n * // Start health server\n * const server = await startHealthServer(8914);\n *\n * // Custom health checks\n * server.addCheck(\"custom\", async () => ({\n * healthy: true,\n * message: \"Custom check passed\",\n * }));\n *\n * // Stop server\n * await server.stop();\n * ```\n */\n\nimport { createServer, type Server as HttpServer, type IncomingMessage, type ServerResponse } from \"http\";\nimport { getServiceManager, type ServiceStatus } from \"./service-manager.js\";\nimport { loadConfig, type PkgOpsConfig } from \"./config.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface HealthCheckResult {\n /** Whether the check passed */\n healthy: boolean;\n /** Human-readable message */\n message: string;\n /** Additional data */\n data?: Record<string, unknown>;\n}\n\nexport interface ServiceHealth {\n /** Service name */\n name: string;\n /** Whether the service is healthy */\n healthy: boolean;\n /** Service status */\n status: ServiceStatus;\n /** Last check timestamp */\n checkedAt: string;\n}\n\nexport interface SystemHealth {\n /** Overall health status */\n healthy: boolean;\n /** All services health */\n services: ServiceHealth[];\n /** System uptime in seconds */\n uptime: number;\n /** Timestamp of this check */\n timestamp: string;\n}\n\nexport type HealthCheckFn = () => Promise<HealthCheckResult> | HealthCheckResult;\n\n// ---------------------------------------------------------------------------\n// Health Server Class\n// ---------------------------------------------------------------------------\n\n/**\n * HTTP server for health monitoring.\n */\nexport class HealthServer {\n private server: HttpServer | null = null;\n private checks = new Map<string, HealthCheckFn>();\n private startTime = Date.now();\n private port: number;\n\n constructor(port: number = 8914) {\n this.port = port;\n }\n\n /**\n * Start the health server.\n */\n async start(): Promise<void> {\n if (this.server) {\n return;\n }\n\n return new Promise((resolve, reject) => {\n this.server = createServer((req, res) => this.handleRequest(req, res));\n\n this.server.on(\"error\", reject);\n\n this.server.listen(this.port, () => {\n console.log(`Health server listening on port ${this.port}`);\n this.server?.off(\"error\", reject);\n resolve();\n });\n });\n }\n\n /**\n * Stop the health server.\n */\n async stop(): Promise<void> {\n if (!this.server) {\n return;\n }\n\n return new Promise((resolve) => {\n this.server?.close(() => {\n this.server = null;\n resolve();\n });\n });\n }\n\n /**\n * Add a custom health check.\n */\n addCheck(name: string, check: HealthCheckFn): void {\n this.checks.set(name, check);\n }\n\n /**\n * Remove a health check.\n */\n removeCheck(name: string): void {\n this.checks.delete(name);\n }\n\n /**\n * Check health of all services or a specific service.\n * Public method for CLI usage.\n */\n async checkHealth(serviceName?: string): Promise<SystemHealth | ServiceHealth | null> {\n if (serviceName) {\n return this.getServiceHealth(serviceName);\n }\n return this.getSystemHealth();\n }\n\n // ---------------------------------------------------------------------------\n // Private Methods\n // ---------------------------------------------------------------------------\n\n private async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = req.url ?? \"/\";\n const method = req.method ?? \"GET\";\n\n try {\n if (method === \"GET\" && url === \"/health\") {\n const health = await this.getSystemHealth();\n this.sendJson(res, 200, health);\n } else if (method === \"GET\" && url.startsWith(\"/health/\")) {\n const serviceName = url.slice(8).replace(\".service\", \"\");\n const health = await this.getServiceHealth(serviceName);\n this.sendJson(res, health ? 200 : 404, health ?? { error: \"Service not found\" });\n } else if (method === \"GET\" && url === \"/ready\") {\n const health = await this.getSystemHealth();\n this.sendJson(res, health.healthy ? 200 : 503, { ready: health.healthy });\n } else if (method === \"GET\" && url === \"/live\") {\n this.sendJson(res, 200, { alive: true });\n } else {\n this.sendJson(res, 404, { error: \"Not found\" });\n }\n } catch (error) {\n console.error(\"Health check error:\", error);\n this.sendJson(res, 500, { error: \"Internal server error\" });\n }\n }\n\n private async getSystemHealth(): Promise<SystemHealth> {\n const config = loadConfig();\n const serviceManager = getServiceManager();\n\n const services: ServiceHealth[] = [];\n\n for (const [packageName, pkgConfig] of Object.entries(config.packages)) {\n if (!pkgConfig.service) continue;\n\n const status = await serviceManager.status(pkgConfig.service);\n const healthy = status.active && status.subState === \"running\";\n\n services.push({\n name: pkgConfig.service,\n healthy,\n status,\n checkedAt: new Date().toISOString(),\n });\n }\n\n // Run custom checks\n const customResults: Record<string, HealthCheckResult> = {};\n for (const [name, check] of this.checks) {\n try {\n customResults[name] = await check();\n } catch (error) {\n customResults[name] = {\n healthy: false,\n message: error instanceof Error ? error.message : \"Unknown error\",\n };\n }\n }\n\n const allHealthy = services.every((s) => s.healthy) &&\n Object.values(customResults).every((r) => r.healthy);\n\n return {\n healthy: allHealthy,\n services,\n uptime: Math.floor((Date.now() - this.startTime) / 1000),\n timestamp: new Date().toISOString(),\n };\n }\n\n private async getServiceHealth(serviceName: string): Promise<ServiceHealth | null> {\n const serviceManager = getServiceManager();\n\n const exists = await serviceManager.exists(serviceName);\n if (!exists) {\n return null;\n }\n\n const status = await serviceManager.status(serviceName);\n const healthy = status.active && status.subState === \"running\";\n\n return {\n name: serviceName,\n healthy,\n status,\n checkedAt: new Date().toISOString(),\n };\n }\n\n private sendJson(res: ServerResponse, statusCode: number, data: unknown): void {\n res.statusCode = statusCode;\n res.setHeader(\"Content-Type\", \"application/json\");\n res.end(JSON.stringify(data, null, 2));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton Instance\n// ---------------------------------------------------------------------------\n\nlet healthServer: HealthServer | null = null;\n\n/**\n * Start the health server with config port.\n */\nexport async function startHealthServer(port?: number): Promise<HealthServer> {\n const config = loadConfig();\n const actualPort = port ?? config.healthPort ?? 8914;\n\n if (!healthServer) {\n healthServer = new HealthServer(actualPort);\n }\n\n await healthServer.start();\n return healthServer;\n}\n\n/**\n * Stop the health server.\n */\nexport async function stopHealthServer(): Promise<void> {\n if (healthServer) {\n await healthServer.stop();\n healthServer = null;\n }\n}\n\n/**\n * Get the health server instance.\n */\nexport function getHealthServer(): HealthServer | null {\n return healthServer;\n}\n"
|
|
11
11
|
],
|
|
12
12
|
"mappings": "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",
|
|
13
|
-
"debugId": "
|
|
13
|
+
"debugId": "94AA821F33CC03D264756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ebowwa/pkg-ops",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Package operations CLI - installs @ebowwa/* npm packages and manages systemd services",
|
|
6
6
|
"bin": {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
+
"scripts",
|
|
17
18
|
"rust/src",
|
|
18
19
|
"rust/Cargo.toml",
|
|
19
20
|
"rust/Cargo.lock",
|
|
@@ -22,9 +23,10 @@
|
|
|
22
23
|
"scripts": {
|
|
23
24
|
"build": "bun build src/index.ts --outdir dist --target bun --sourcemap --minify && tsc --emitDeclarationOnly --declaration",
|
|
24
25
|
"build:rust": "cd rust && cargo build --release",
|
|
26
|
+
"postinstall": "node scripts/check-or-build-rust.js",
|
|
25
27
|
"dev": "bun run src/index.ts",
|
|
26
28
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"prepublishOnly": "bun run build"
|
|
29
|
+
"prepublishOnly": "bun run build && bun run build:rust"
|
|
28
30
|
},
|
|
29
31
|
"keywords": [
|
|
30
32
|
"package-operations",
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Postinstall script for @ebowwa/pkg-ops
|
|
4
|
+
*
|
|
5
|
+
* Checks if Rust binary exists, builds if missing.
|
|
6
|
+
* Gracefully skips if Rust toolchain not available.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
import { join, dirname } from "path";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const rootDir = join(__dirname, "..");
|
|
16
|
+
|
|
17
|
+
const BINARY_PATHS = [
|
|
18
|
+
join(rootDir, "rust", "target", "release", "pkg-ops-core"),
|
|
19
|
+
join(rootDir, "rust", "target", "release", "pkg-ops-core.exe"),
|
|
20
|
+
join(rootDir, "rust", "pkg-ops-core"),
|
|
21
|
+
join(rootDir, "rust", "pkg-ops-core.exe"),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function binaryExists() {
|
|
25
|
+
return BINARY_PATHS.some((p) => existsSync(p));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function hasRust() {
|
|
29
|
+
try {
|
|
30
|
+
execSync("rustc --version", { stdio: "ignore" });
|
|
31
|
+
return true;
|
|
32
|
+
} catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function buildRust() {
|
|
38
|
+
console.log("@ebowwa/pkg-ops: Building Rust binary...");
|
|
39
|
+
try {
|
|
40
|
+
execSync("cargo build --release", {
|
|
41
|
+
cwd: join(rootDir, "rust"),
|
|
42
|
+
stdio: "inherit",
|
|
43
|
+
});
|
|
44
|
+
console.log("@ebowwa/pkg-ops: Rust binary built successfully");
|
|
45
|
+
return true;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error("@ebowwa/pkg-ops: Failed to build Rust binary");
|
|
48
|
+
console.error(err.message);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Main
|
|
54
|
+
if (binaryExists()) {
|
|
55
|
+
console.log("@ebowwa/pkg-ops: Rust binary already exists");
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!hasRust()) {
|
|
60
|
+
console.log("@ebowwa/pkg-ops: Rust not installed, skipping native build");
|
|
61
|
+
console.log("@ebowwa/pkg-ops: Install Rust (https://rustup.rs) and run:");
|
|
62
|
+
console.log(" cd node_modules/@ebowwa/pkg-ops && bun run build:rust");
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!buildRust()) {
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|