Skip to content

feat: add uninstall.sh to fully remove PAI from a system#944

Open
gabehamilton wants to merge 7 commits intodanielmiessler:mainfrom
gabehamilton:feat/uninstall-script
Open

feat: add uninstall.sh to fully remove PAI from a system#944
gabehamilton wants to merge 7 commits intodanielmiessler:mainfrom
gabehamilton:feat/uninstall-script

Conversation

@gabehamilton
Copy link

Summary

  • Adds uninstall.sh at the repo root and mirrored to Releases/v3.0/.claude/uninstall.sh
  • Covers every artifact created by the v3.0 installer: ~/.claude/, ~/.config/PAI/, LaunchAgent plist, voice server process on port 8888, shell aliases (zsh + fish), symlinks (~/.env, ~/.claude/.env), SwiftBar/BitBar plugins, and log files
  • Prompts for confirmation before each destructive step; supports --force flag for scripted/non-interactive use
  • ~/.env is only removed if it's a PAI-owned symlink — won't clobber a pre-existing file
  • Closing note instructs user to uninstall the Claude Code CLI separately (PAI doesn't own that binary)

Test plan

  • Run on a fresh PAI v3.0 install and verify all artifacts are removed
  • Run with --force and verify it skips all prompts
  • Verify ~/.env is left alone when it is not a PAI symlink
  • Verify shell alias is cleanly stripped from ~/.zshrc without leaving blank lines
  • Verify voice server LaunchAgent is unloaded before plist is deleted

🤖 Generated with Claude Code

gabehamilton and others added 7 commits March 11, 2026 19:08
Covers all installer-created artifacts: ~/.claude, ~/.config/PAI,
LaunchAgent plist, voice server process, shell aliases (zsh + fish),
symlinks (~/.env, ~/.claude/.env), SwiftBar/BitBar plugins, and log
files. Prompts for confirmation on each destructive step; supports
--force flag for scripted use.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
~/.claude/ is both PAI's install dir and Claude Code's config dir.
The previous script would rm -rf the whole thing. Now:

- Only PAI-owned dirs/files are removed (agents/, lib/, PAI-Install/,
  plugins/, skills/, VoiceServer/, install.sh, statusline-command.sh,
  README.md, CLAUDE.md, .gitignore)
- Mixed/user-data dirs (MEMORY/, plans/, hooks/, tasks/, teams/) are
  backed up first to ~/.pai-uninstall-backup-TIMESTAMP/ then offered
  for removal individually
- settings.json is backed up then surgically stripped of PAI keys
  (principal, daidentity, pai, counts, statusLine, PROJECTS_DIR)
  while preserving all Claude Code config (permissions, hooks, mcp, etc.)
- Claude Code-native files are never touched (.credentials.json,
  projects/, todos/, history.jsonl, statsig/, telemetry/, etc.)
- ~/.git is only removed if origin is the PAI/PAI repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previous version listed agents/, lib/, plugins/, CLAUDE.md, README.md,
and .gitignore as PAI-owned in the preview — all of which are also used
by Claude Code or users directly.

Now the script is fine-grained:
- "PAI-exclusive" section: only skills/, VoiceServer/, PAI-Install/,
  statusline-command.sh, LaunchAgent/log — things with no Claude Code
  equivalent
- "PAI files in shared dirs": removes the 13 known PAI agent files by
  name from agents/ (leaves any user-added agents); removes
  lib/migration/ specifically (cleans lib/ if then empty)
- install.sh: only removed if grep confirms it references PAI-Install/
- CLAUDE.md: only removed if it contains PAI marker text (unmodified)
- README.md, .gitignore: skipped entirely (too generic to claim)
- plugins/: moved to backup-and-confirm section (user may have
  installed plugins)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tirely

skills/: remove the 38 named PAI skills by directory name; any
user-installed skills (e.g. nano-banana) are left in place. The
skills/ dir itself is only removed if it becomes empty.

plugins/: removed from the script entirely. The plugins/ directory
is Claude Code's own plugin infrastructure (installed_plugins.json,
marketplaces/, cache/, blocklist.json) — PAI has no ownership of it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- PAI content (contains "SKILL.md", "This file does nothing", or
  "read skills/PAI"): removed
- Empty / whitespace-only (likely created by PAI): removed
- Contains user content: left alone with a warning

Both the preview and removal sections reflect the same logic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ks/, teams/

hooks/: remove the 21 named PAI .hook.ts files + README.md by list;
  remove handlers/ and lib/ subdirs entirely (100% PAI); leave any
  user-added files; remove hooks/ dir only if it empties out.

MEMORY/: remove PAI-shipped README.md (content check); auto-remove
  STATE/ (PAI runtime caches — not personal data); offer each user
  data subdir (LEARNING, WORK, RELATIONSHIP, SECURITY, VOICE) for
  removal individually with file counts.

plans/: all files are user-created; show count, offer dir removal.

tasks/ + teams/: PAI runtime tracking data; show item count, offer
  removal per directory.

Preview section updated to reflect the fine-grained breakdown.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the monolithic bash uninstall.sh with a structured TypeScript
engine matching the PAI installer's architecture:

  bootstrap shell → bun → PAI-Uninstall/main.ts → engine/ + cli/

Engine structure (PAI-Uninstall/):
- engine/types.ts     — UninstallState, StepId, EngineEvent, GetConfirm
- engine/constants.ts — PAI-owned names (agents, hooks, skills)
- engine/detect.ts    — scans filesystem for PAI artifacts
- engine/steps.ts     — 16 step definitions
- engine/actions.ts   — step implementations (all bash logic ported to TS)
- cli/display.ts      — ANSI colors, banner, detection preview, summary
- cli/prompts.ts      — readline confirmation prompts
- cli/index.ts        — CLI wizard with force-mode adapter
- main.ts             — thin entry point, --force flag

Key improvements over the bash version:
- settings.json cleanup now also strips PAI hook registrations, not just
  PAI-specific keys — fixes SessionStart/StopOrchestrator errors after
  uninstall where Claude Code can't find removed hook files
- Smart bootstrap: finds PAI-Uninstall/ adjacent (installed) or under
  Releases/v3.0/.claude/ (repo root)
- uninstall.sh at repo root falls back to Releases/ path automatically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gabehamilton gabehamilton marked this pull request as ready for review March 12, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant