From 21d04b17cdb01defe9bf9af4896531a1b52669f5 Mon Sep 17 00:00:00 2001 From: zhi Date: Thu, 5 Mar 2026 10:13:29 +0000 Subject: [PATCH] feat: add --uninstall support to install script - Add --uninstall flag to remove installed components - List items to be removed before confirmation - Remove pass_mgr binary, skills modules, and env config - Preserve admin key directory (warns user to remove manually) - Update PROJECT_PLAN.md with uninstall usage --- PROJECT_PLAN.md | 6 ++++ install.mjs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/PROJECT_PLAN.md b/PROJECT_PLAN.md index 0136023..a994590 100644 --- a/PROJECT_PLAN.md +++ b/PROJECT_PLAN.md @@ -286,6 +286,12 @@ node install.mjs --build-only # 跳过依赖检测 node install.mjs --skip-check + +# 卸载 +node install.mjs --uninstall + +# 从指定路径卸载 +node install.mjs --uninstall --prefix /usr/local ``` --- diff --git a/install.mjs b/install.mjs index 9365897..4b64a4d 100755 --- a/install.mjs +++ b/install.mjs @@ -8,6 +8,8 @@ * node install.mjs --prefix /usr/local * node install.mjs --build-only * node install.mjs --skip-check + * node install.mjs --uninstall + * node install.mjs --uninstall --prefix /usr/local */ import { execSync, spawn } from 'child_process'; @@ -27,6 +29,7 @@ const options = { buildOnly: args.includes('--build-only'), skipCheck: args.includes('--skip-check'), verbose: args.includes('--verbose') || args.includes('-v'), + uninstall: args.includes('--uninstall'), }; // Parse --prefix value @@ -589,9 +592,84 @@ function printSummary(env) { } // ============================================================================ -// Main +// Uninstall Function // ============================================================================ +async function uninstall(env) { + logStep(1, 'Uninstalling PaddedCell...'); + + const installDir = options.prefix || env.openclawDir; + const binDir = join(installDir, 'bin'); + const skillsDir = join(installDir, 'skills', 'paddedcell'); + const envFile = join(installDir, 'paddedcell.env'); + + const itemsToRemove = []; + + // Check what exists + const passMgrBinary = join(binDir, 'pass_mgr'); + if (existsSync(passMgrBinary)) { + itemsToRemove.push(passMgrBinary); + } + + if (existsSync(skillsDir)) { + itemsToRemove.push(skillsDir); + } + + if (existsSync(envFile)) { + itemsToRemove.push(envFile); + } + + if (itemsToRemove.length === 0) { + log('No installed components found.', 'yellow'); + return; + } + + log('The following items will be removed:', 'yellow'); + for (const item of itemsToRemove) { + log(` • ${item}`, 'reset'); + } + + // Ask for confirmation + const confirm = await prompt('\nAre you sure you want to uninstall? (y/N): '); + if (confirm.toLowerCase() !== 'y') { + log('Uninstall cancelled.', 'yellow'); + return; + } + + // Perform uninstall + for (const item of itemsToRemove) { + try { + if (item === passMgrBinary || item === envFile) { + execSync(`rm -f "${item}"`, { silent: true }); + logSuccess(`Removed: ${item}`); + } else { + execSync(`rm -rf "${item}"`, { silent: true }); + logSuccess(`Removed: ${item}`); + } + } catch (err) { + logError(`Failed to remove: ${item}`); + } + } + + // Check for admin key directory + const adminKeyDir = join(homedir(), '.pass_mgr'); + if (existsSync(adminKeyDir)) { + log('\n⚠️ Admin key directory found:', 'yellow'); + log(` ${adminKeyDir}`, 'cyan'); + log(' This contains your encryption keys. Remove manually if desired.', 'yellow'); + } + + console.log(''); + log('╔════════════════════════════════════════════════════════╗', 'cyan'); + log('║ PaddedCell Uninstall Complete ║', 'cyan'); + log('╚════════════════════════════════════════════════════════╝', 'cyan'); + console.log(''); + + log('Remember to remove the following from your shell profile:', 'yellow'); + log(` source ${envFile}`, 'cyan'); + console.log(''); +} + async function main() { console.log(''); log('╔════════════════════════════════════════════════════════╗', 'cyan'); @@ -601,6 +679,13 @@ async function main() { try { const env = detectEnvironment(); + + // Handle uninstall + if (options.uninstall) { + await uninstall(env); + process.exit(0); + } + checkDependencies(env); await buildComponents(env); await installComponents(env);