import { resolve } from "jsr:@std/path"; import { Confirm } from "jsr:@cliffy/prompt@1.0.0-rc.7/confirm"; import { Select } from "jsr:@cliffy/prompt@1.0.0-rc.7/select"; interface UninstallArgs { yes?: boolean; pluginDir?: string; } async function confirmUninstall() { const consent = await Confirm.prompt({ message: `Uninstalling this plugin will remove all files associated with this plugin from the specified vault. Your settings cannot be recovered! If you are okay with this, please confirm:`, default: false, }); if (!consent) { console.info("Aborting uninstallation"); Deno.exit(0); } else { console.info("Uninstallation confirmed. Continuing"); } } export async function uninstallPlugin(args: UninstallArgs, vault?: string) { const cwd = args.pluginDir ? resolve(Deno.cwd(), args.pluginDir) : Deno.cwd(); const manifestText = await Deno.readTextFile(resolve(cwd, "manifest.json")); const manifest = JSON.parse(manifestText); if (vault) { if (!args.yes) { await confirmUninstall(); } const pluginPath = resolve(cwd, vault, ".obsidian", "plugins", manifest.id); try { await Deno.lstat(pluginPath); } catch (err) { if (err instanceof Deno.errors.NotFound) { console.error(`Could not find a plugin folder at path ${pluginPath}`); Deno.exit(1); } throw err; } console.info("Plugin found. Removing"); try { await Deno.remove(pluginPath, { recursive: true }); } catch (err) { throw err; } console.info(`Plugin successfully removed from vault with path ${vault}`); Deno.exit(0); } console.info("No vault specified. Checking installation history"); const kv = await Deno.openKv(); const vaults: string[] = []; const entries = kv.list({ prefix: ["installed-plugins", manifest.id], }); for await (const entry of entries) { vaults.push(entry.value); } if (vaults.length === 0) { console.info("No vaults found. Nothing to do"); Deno.exit(0); } else if (vaults.length === 1) { const vaultPath = vaults.shift(); console.info( `Only one vault found. Proceeding with vault path: ${vaultPath}`, ); await uninstallPlugin(args, vaultPath); } const selectedVault = await Select.prompt({ message: "Select a vault to uninstall plugin:", options: vaults.map((path) => ({ value: path, })), }); if (!selectedVault) { console.info("No vault selected. Nothing to do"); Deno.exit(0); } console.info(`Proceeding with vault path: ${selectedVault}`); await uninstallPlugin(args, selectedVault); }