Skip to content

Commit eaa01d6

Browse files
yarin-magclaude
andcommitted
feat: add uninstall scripts for macOS, Linux, and Windows
Adds scripts/uninstall.sh and scripts/uninstall.ps1 that reverse everything the installer does: stops services, removes auto-start (LaunchAgents / systemd / Scheduled Tasks), clears ANTHROPIC_BASE_URL, removes MCP registration and Claude Code hooks, and deletes the installation directory. README updated with one-liner uninstall commands. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fff88bb commit eaa01d6

4 files changed

Lines changed: 207 additions & 1 deletion

File tree

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ After installing, open **http://localhost:8787**.
2424

2525
---
2626

27+
## Uninstall
28+
29+
**macOS / Linux**
30+
```bash
31+
curl -fsSL https://raw.githubusercontent.com/yarin-mag/Marrionet/master/scripts/uninstall.sh | bash
32+
```
33+
34+
**Windows** (PowerShell)
35+
```powershell
36+
irm https://raw.githubusercontent.com/yarin-mag/Marrionet/master/scripts/uninstall.ps1 | iex
37+
```
38+
39+
This stops the running services, removes the MCP registration and hooks from Claude Code, clears the `ANTHROPIC_BASE_URL` environment variable, and deletes the installation directory.
40+
41+
---
42+
2743
## Development Setup
2844

2945
### Prerequisites

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "marionette",
33
"private": true,
4-
"version": "0.2.0",
4+
"version": "0.2.1",
55
"packageManager": "pnpm@9.0.0",
66
"workspaces": [
77
"apps/*",

scripts/uninstall.ps1

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Marionette uninstaller for Windows (PowerShell)
2+
# Usage: .\scripts\uninstall.ps1
3+
# or one-liner: irm https://raw.githubusercontent.com/yarin-mag/Marrionet/master/scripts/uninstall.ps1 | iex
4+
5+
$ErrorActionPreference = "Stop"
6+
7+
$InstallDir = "$env:LOCALAPPDATA\marionette"
8+
$ClaudeDir = "$env:USERPROFILE\.claude"
9+
$McpSettings = "$ClaudeDir\mcp_settings.json"
10+
$Settings = "$ClaudeDir\settings.json"
11+
12+
Write-Host "==> Uninstalling Marionette..."
13+
14+
# ── 1. Stop and remove scheduled tasks ───────────────────────────────────────
15+
foreach ($task in @("Marionette", "MarionetteProxy")) {
16+
try {
17+
Unregister-ScheduledTask -TaskName $task -Confirm:$false -ErrorAction Stop
18+
Write-Host "==> Removed scheduled task: $task"
19+
} catch {
20+
# task doesn't exist — skip
21+
}
22+
}
23+
24+
# ── 2. Remove ANTHROPIC_BASE_URL user environment variable ────────────────────
25+
$existing = [Environment]::GetEnvironmentVariable("ANTHROPIC_BASE_URL", "User")
26+
if ($null -ne $existing) {
27+
[Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", $null, "User")
28+
Remove-Item Env:ANTHROPIC_BASE_URL -ErrorAction SilentlyContinue
29+
Write-Host "==> Removed ANTHROPIC_BASE_URL user environment variable"
30+
}
31+
32+
# ── 3. Remove bin dir from user PATH ─────────────────────────────────────────
33+
$binDir = "$InstallDir\bin"
34+
$currentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
35+
if ($currentPath -like "*$binDir*") {
36+
$newPath = ($currentPath -split ";") | Where-Object { $_ -ne $binDir } | Where-Object { $_ -ne "" }
37+
$newPath = $newPath -join ";"
38+
[Environment]::SetEnvironmentVariable("PATH", $newPath, "User")
39+
$env:PATH = ($env:PATH -split ";") | Where-Object { $_ -ne $binDir } | Where-Object { $_ -ne "" }
40+
$env:PATH = $env:PATH -join ";"
41+
Write-Host "==> Removed $binDir from user PATH"
42+
}
43+
44+
# ── 4. Remove MCP server registration ────────────────────────────────────────
45+
if (Test-Path $McpSettings) {
46+
try {
47+
$mcp = Get-Content $McpSettings -Raw | ConvertFrom-Json -AsHashtable
48+
if ($mcp.ContainsKey("mcpServers") -and $mcp["mcpServers"].ContainsKey("marionette")) {
49+
$mcp["mcpServers"].Remove("marionette")
50+
$mcp | ConvertTo-Json -Depth 10 | Set-Content $McpSettings -Encoding UTF8
51+
Write-Host "==> Removed marionette MCP server from $McpSettings"
52+
}
53+
} catch {
54+
Write-Host "Warning: Could not update $McpSettings$_" -ForegroundColor Yellow
55+
}
56+
}
57+
58+
# ── 5. Remove hooks from Claude Code settings ─────────────────────────────────
59+
if (Test-Path $Settings) {
60+
try {
61+
$cfg = Get-Content $Settings -Raw | ConvertFrom-Json -AsHashtable
62+
if ($cfg.ContainsKey("hooks")) {
63+
foreach ($key in @("PreToolUse", "Stop", "Notification")) {
64+
$cfg["hooks"].Remove($key)
65+
}
66+
if ($cfg["hooks"].Count -eq 0) { $cfg.Remove("hooks") }
67+
$cfg | ConvertTo-Json -Depth 10 | Set-Content $Settings -Encoding UTF8
68+
Write-Host "==> Removed Marionette hooks from $Settings"
69+
}
70+
} catch {
71+
Write-Host "Warning: Could not update $Settings$_" -ForegroundColor Yellow
72+
}
73+
}
74+
75+
# ── 6. Remove install directory ───────────────────────────────────────────────
76+
if (Test-Path $InstallDir) {
77+
Remove-Item -Recurse -Force $InstallDir
78+
Write-Host "==> Removed $InstallDir"
79+
}
80+
81+
Write-Host ""
82+
Write-Host "✓ Marionette has been uninstalled."
83+
Write-Host " Restart your terminal for PATH changes to take effect."

scripts/uninstall.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env bash
2+
# Marionette uninstaller for macOS and Linux
3+
# Usage: bash scripts/uninstall.sh
4+
# or one-liner: curl -fsSL https://raw.githubusercontent.com/yarin-mag/Marrionet/master/scripts/uninstall.sh | bash
5+
set -euo pipefail
6+
7+
INSTALL_DIR="/usr/local/lib/marionette"
8+
BIN_LINK="/usr/local/bin/marionette"
9+
CLAUDE_DIR="$HOME/.claude"
10+
MCP_SETTINGS="$CLAUDE_DIR/mcp_settings.json"
11+
SETTINGS="$CLAUDE_DIR/settings.json"
12+
LOGS_DIR="$HOME/.marionette"
13+
14+
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
15+
case "$OS" in
16+
darwin) OS="macos" ;;
17+
linux) OS="linux" ;;
18+
*) echo "Unsupported OS: $OS" >&2; exit 1 ;;
19+
esac
20+
21+
echo "==> Uninstalling Marionette..."
22+
23+
# ── 1. Stop and remove auto-start ─────────────────────────────────────────────
24+
if [ "$OS" = "macos" ]; then
25+
APP_PLIST="$HOME/Library/LaunchAgents/com.marionette.app.plist"
26+
PROXY_PLIST="$HOME/Library/LaunchAgents/com.marionette.proxy.plist"
27+
if [ -f "$APP_PLIST" ]; then
28+
launchctl unload "$APP_PLIST" 2>/dev/null || true
29+
rm -f "$APP_PLIST"
30+
echo "==> Removed LaunchAgent: com.marionette.app"
31+
fi
32+
if [ -f "$PROXY_PLIST" ]; then
33+
launchctl unload "$PROXY_PLIST" 2>/dev/null || true
34+
rm -f "$PROXY_PLIST"
35+
echo "==> Removed LaunchAgent: com.marionette.proxy"
36+
fi
37+
elif [ "$OS" = "linux" ]; then
38+
systemctl --user disable --now marionette 2>/dev/null || true
39+
systemctl --user disable --now marionette-proxy 2>/dev/null || true
40+
SYSTEMD_DIR="$HOME/.config/systemd/user"
41+
rm -f "$SYSTEMD_DIR/marionette.service" "$SYSTEMD_DIR/marionette-proxy.service"
42+
systemctl --user daemon-reload 2>/dev/null || true
43+
echo "==> Removed systemd user services"
44+
fi
45+
46+
# ── 2. Remove ANTHROPIC_BASE_URL from shell rc files ──────────────────────────
47+
MARKER="# Added by Marionette"
48+
ENV_LINE='export ANTHROPIC_BASE_URL="http://localhost:8788"'
49+
for RC in "$HOME/.zshrc" "$HOME/.bashrc" "$HOME/.bash_profile"; do
50+
if [ -f "$RC" ] && grep -qF "$ENV_LINE" "$RC"; then
51+
perl -i -0pe "s/\n?\Q${MARKER}\E\n\Q${ENV_LINE}\E\n?//g" "$RC"
52+
echo "==> Removed ANTHROPIC_BASE_URL from $RC"
53+
fi
54+
done
55+
56+
# ── 3. Remove MCP server registration ─────────────────────────────────────────
57+
if [ -f "$MCP_SETTINGS" ] && command -v node &>/dev/null; then
58+
node -e "
59+
const fs = require('fs');
60+
const p = process.argv[1];
61+
try {
62+
const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
63+
if (cfg.mcpServers && cfg.mcpServers.marionette) {
64+
delete cfg.mcpServers.marionette;
65+
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
66+
console.log('==> Removed marionette MCP server from ' + p);
67+
}
68+
} catch (e) {}
69+
" "$MCP_SETTINGS"
70+
fi
71+
72+
# ── 4. Remove hooks from Claude Code settings ──────────────────────────────────
73+
if [ -f "$SETTINGS" ] && command -v node &>/dev/null; then
74+
node -e "
75+
const fs = require('fs');
76+
const p = process.argv[1];
77+
try {
78+
const cfg = JSON.parse(fs.readFileSync(p, 'utf8'));
79+
if (cfg.hooks) {
80+
['PreToolUse', 'Stop', 'Notification'].forEach(k => delete cfg.hooks[k]);
81+
if (Object.keys(cfg.hooks).length === 0) delete cfg.hooks;
82+
fs.writeFileSync(p, JSON.stringify(cfg, null, 2));
83+
console.log('==> Removed Marionette hooks from ' + p);
84+
}
85+
} catch (e) {}
86+
" "$SETTINGS"
87+
fi
88+
89+
# ── 5. Remove binary symlink and install directory ────────────────────────────
90+
if [ -L "$BIN_LINK" ] || [ -f "$BIN_LINK" ]; then
91+
sudo rm -f "$BIN_LINK"
92+
echo "==> Removed $BIN_LINK"
93+
fi
94+
if [ -d "$INSTALL_DIR" ]; then
95+
sudo rm -rf "$INSTALL_DIR"
96+
echo "==> Removed $INSTALL_DIR"
97+
fi
98+
99+
# ── 6. Remove logs directory ───────────────────────────────────────────────────
100+
if [ -d "$LOGS_DIR" ]; then
101+
rm -rf "$LOGS_DIR"
102+
echo "==> Removed $LOGS_DIR"
103+
fi
104+
105+
echo ""
106+
echo "✓ Marionette has been uninstalled."
107+
echo " Restart your terminal for shell changes to take effect."

0 commit comments

Comments
 (0)