Files
chainbase-labs__agentkey/scripts/uninstall.ps1
T
Bruce ab0dba7eb1 feat: rename @agentkey/mcp → @agentkey/cli in install scripts and docs (#47)
## Summary

Companion change to
[chainbase-labs/AgentKey-Server#32](https://github.com/chainbase-labs/AgentKey-Server/pull/32).
The npm package has been renamed; this PR updates everything users
actually see.

**User-facing**
- \`scripts/install.{sh,ps1}\`: \`MCP_PACKAGE\` / \`$McpPackage\` →
\`CLI_PACKAGE\` / \`$CliPackage\`
- \`scripts/uninstall.{sh,ps1}\`: sweep BOTH \`@agentkey/cli\` and
\`@agentkey/mcp\` so users upgrading from v0.x get a clean uninstall
- \`skills/agentkey/SKILL.md\`: setup command + manual-config JSON
example
- \`README.md\` + \`docs/README_zh.md\`: every \`npx @agentkey/mcp\`
command + the manual-config JSON examples (switched from stale stdio
shape to the remote-HTTP shape that \`--auth-login\` actually writes in
v1.0)

**Internal / protocol docs**
- \`SECURITY.md\`: file/network audit tables
- \`protocol/skill-meta-v1.md\`, \`docs/SERVER-IMPLEMENTATION.md\`:
clarify the protocol partner is AgentKey-Server's hosted \`/v1/mcp\`
endpoint, not a standalone npm package — these references were already
misleading before the rename
- \`.claude/CLAUDE.md\`: keep Claude-session guidance in sync

\`CHANGELOG.md\` left untouched (release-please manages history).

## Sequencing

Merge this PR **after** \`@agentkey/cli\` is published to npm —
otherwise the install scripts here will reference a package that doesn't
exist yet. Recommended order:

1. Merge
[AgentKey-Server#32](https://github.com/chainbase-labs/AgentKey-Server/pull/32)
2. \`cd cli && npm publish\` (first \`@agentkey/cli\` release at
\`1.0.0\`)
3. Merge this PR

## Test plan

- [ ] Verify \`npx -y @agentkey/cli --auth-login\` works end-to-end
after npm publish
- [ ] Verify \`scripts/uninstall.sh\` on a machine with
\`@agentkey/mcp\` globally installed cleans it up
- [ ] Spot-check the rendered README on GitHub for any missed references
2026-05-15 16:31:42 +08:00

353 lines
14 KiB
PowerShell
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#Requires -Version 5.1
<#
.SYNOPSIS
AgentKey uninstaller for Windows
.DESCRIPTION
Usage:
irm https://agentkey.app/uninstall.ps1 | iex
& ([scriptblock]::Create((irm https://agentkey.app/uninstall.ps1))) -KeepMarketplace
& ([scriptblock]::Create((irm https://agentkey.app/uninstall.ps1))) -ForceInRepo
Cleans up everything install.ps1 (and the legacy two-command flow) ever wrote:
1. Skill files in every agent (via `skills remove`)
2. MCP server entries (Claude Code / Claude Desktop / Cursor)
3. Plugin + marketplace caches
4. CLAUDE.md sections + npm/npx caches (legacy)
#>
[CmdletBinding()]
param(
[switch]$KeepMarketplace,
[switch]$ForceInRepo,
[switch]$SkipSkillRemove,
[switch]$Help
)
$ErrorActionPreference = 'Continue'
if ($Help) {
@'
AgentKey uninstaller (Windows)
Usage:
irm https://agentkey.app/uninstall.ps1 | iex
Parameters:
-KeepMarketplace Keep the Claude Code plugin marketplace registration
-ForceInRepo Allow running inside the AgentKey-Skill source repo
-SkipSkillRemove Skip 'npx skills remove' (only clean configs/caches)
-Help Show this help
'@
exit 0
}
# ── UI helpers ────────────────────────────────────────────────────────────
function Write-Step ($t) { Write-Host ''; Write-Host " $t" -ForegroundColor White }
function Write-Info ($t) { Write-Host " $t" -ForegroundColor Gray }
function Write-Ok ($t) { Write-Host "$t" -ForegroundColor Green }
function Write-Warn2($t) { Write-Host " ! $t" -ForegroundColor Yellow }
function Write-Skip ($t) { Write-Host " - $t" -ForegroundColor DarkGray }
function Write-Err ($t) { Write-Host "$t" -ForegroundColor Red }
# ── Safety rail ──────────────────────────────────────────────────────────
if ((Test-Path '.claude-plugin/plugin.json') -and -not $ForceInRepo) {
$content = Get-Content '.claude-plugin/plugin.json' -Raw -ErrorAction SilentlyContinue
if ($content -match '"name"\s*:\s*"agentkey"') {
Write-Host ''
Write-Host ' AgentKey — Uninstall' -ForegroundColor White
Write-Host ''
Write-Err 'Refusing to run inside the AgentKey-Skill source repo.'
Write-Host " Running here would wipe this repo's own .mcp.json and CLAUDE.md." -ForegroundColor DarkGray
Write-Host ' Re-run with -ForceInRepo if you really mean it.' -ForegroundColor DarkGray
Write-Host ''
exit 2
}
}
Write-Host ''
Write-Host ' AgentKey — Uninstall' -ForegroundColor White
Write-Host ' https://agentkey.app' -ForegroundColor DarkGray
# ── 1. Skill removal via skills CLI ──────────────────────────────────────
Write-Step '1. Skill files'
if ($SkipSkillRemove) {
Write-Skip 'Skipped (-SkipSkillRemove)'
} elseif (-not (Get-Command npx -ErrorAction SilentlyContinue)) {
Write-Warn2 "npx not found — skipping 'skills remove'"
Write-Host ' Manual: npx skills remove agentkey -g' -ForegroundColor DarkGray
} else {
# `skills remove` takes the **skill name** (`agentkey`), not the repo path.
# The CLI also exits 0 when nothing matches, so we inspect stdout instead.
Write-Info 'Running: npx -y skills remove agentkey -g -y'
$removeOutput = (& npx -y skills remove agentkey -g -y 2>&1) -join "`n"
if ($removeOutput -match 'Successfully removed') {
Write-Ok 'Skill removed from detected agents'
} elseif ($removeOutput -match 'No matching skills found') {
Write-Skip "Not registered with 'skills' CLI (already removed or installed via plugin marketplace)"
} else {
Write-Warn2 "'skills remove' produced unexpected output — some agents may still have skill files"
Write-Host ' Check manually: npx skills list -g' -ForegroundColor DarkGray
}
}
# ── 2. MCP config cleanup ────────────────────────────────────────────────
Write-Step '2. MCP server entries'
$home2 = [Environment]::GetFolderPath('UserProfile')
$mcpConfigs = @(
(Join-Path $home2 '.claude.json'), # Claude Code
(Join-Path $home2 '.cursor\mcp.json'), # Cursor
(Join-Path $env:APPDATA 'Claude\claude_desktop_config.json') # Claude Desktop
)
function Clean-McpConfig($path) {
if (-not (Test-Path $path)) {
Write-Skip "$([System.IO.Path]::GetFileName($path)) not found"
return
}
try {
$raw = Get-Content $path -Raw
$obj = $raw | ConvertFrom-Json
} catch {
Write-Warn2 "Could not parse $path — skipping"
return
}
$removed = 0
if ($obj.mcpServers) {
$keys = @($obj.mcpServers.PSObject.Properties.Name)
foreach ($k in $keys) {
if ($k -match 'agentkey') {
$obj.mcpServers.PSObject.Properties.Remove($k)
$removed++
}
}
}
# Per-project mcpServers (Claude Code ~/.claude.json shape)
if ($obj.projects) {
$projNames = @($obj.projects.PSObject.Properties.Name)
foreach ($pn in $projNames) {
$proj = $obj.projects.$pn
if ($proj.mcpServers) {
$pkeys = @($proj.mcpServers.PSObject.Properties.Name)
foreach ($k in $pkeys) {
if ($k -match 'agentkey') {
$proj.mcpServers.PSObject.Properties.Remove($k)
$removed++
}
}
}
}
}
if ($removed -gt 0) {
($obj | ConvertTo-Json -Depth 100) | Set-Content -Path $path -Encoding UTF8
Write-Ok "Removed $removed entry/entries from $path"
} else {
Write-Skip "No agentkey entry in $path"
}
}
foreach ($cfg in $mcpConfigs) { Clean-McpConfig $cfg }
# ── 3. Claude Code plugin registrations (legacy) ─────────────────────────
Write-Step '3. Claude Code plugin registrations (legacy)'
if (-not (Get-Command claude -ErrorAction SilentlyContinue)) {
Write-Skip 'Claude Code CLI not on PATH — nothing to do here'
} else {
$pluginList = & claude plugin list 2>$null
$markets = @()
if ($pluginList) {
$markets = $pluginList | Select-String -Pattern 'agentkey@[a-zA-Z0-9_-]+' -AllMatches |
ForEach-Object { $_.Matches.Value } | Sort-Object -Unique
}
if ($markets.Count -eq 0) {
Write-Skip 'No agentkey plugin registered'
} else {
foreach ($entry in $markets) {
$name = $entry.Split('@')[0]
Write-Info "Uninstalling $entry ..."
& claude plugin uninstall $name --scope user 2>$null
if ($LASTEXITCODE -eq 0) { Write-Ok "Removed $entry" }
else { Write-Warn2 "Could not remove $entry" }
}
}
$mcpList = & claude mcp list 2>$null
if ($mcpList -and ($mcpList -match '^agentkey')) {
Write-Info "Removing MCP server 'agentkey' via claude CLI ..."
& claude mcp remove agentkey 2>$null
if ($LASTEXITCODE -eq 0) { Write-Ok 'MCP server removed' }
else { Write-Warn2 'Could not remove MCP server via claude CLI' }
} else {
Write-Skip "No 'agentkey' MCP via claude CLI"
}
if ($KeepMarketplace) {
Write-Skip 'Marketplace removal skipped (-KeepMarketplace)'
} else {
$mktList = & claude plugin marketplace list 2>$null
$agentkeyMkts = @()
if ($mktList) {
$joined = $mktList -join "`n"
if ($joined -match '(AgentKey-Skill|chainbase-labs/AgentKey-Skill|agentkey-skill|chainbase-labs/agentkey)') {
$agentkeyMkts = $mktList | Select-String -Pattern '^\s*\s+([a-zA-Z0-9_-]+)' |
ForEach-Object { $_.Matches[0].Groups[1].Value }
}
}
if ($agentkeyMkts.Count -eq 0) {
Write-Skip 'No AgentKey marketplace entry'
} else {
foreach ($mkt in $agentkeyMkts) {
Write-Info "Removing marketplace '$mkt' ..."
& claude plugin marketplace remove $mkt 2>$null
if ($LASTEXITCODE -eq 0) { Write-Ok "Removed marketplace '$mkt'" }
else { Write-Warn2 "Could not remove marketplace '$mkt'" }
}
}
}
}
# ── 4. Plugin + marketplace caches ────────────────────────────────────────
Write-Step '4. Plugin / marketplace caches'
$cacheHits = @()
$pluginCache = Join-Path $home2 '.claude\plugins\cache'
if (Test-Path $pluginCache) {
$cacheHits += Get-ChildItem -Path $pluginCache -Directory -Filter 'agentkey*' -ErrorAction SilentlyContinue
}
$mktCache = Join-Path $home2 '.claude\plugins\marketplaces'
if (Test-Path $mktCache) {
$cacheHits += Get-ChildItem -Path $mktCache -Directory -Filter '*agentkey*' -ErrorAction SilentlyContinue
}
if ($cacheHits.Count -eq 0) {
Write-Skip 'No cache found'
} else {
foreach ($d in $cacheHits) {
Remove-Item -Recurse -Force $d.FullName -ErrorAction SilentlyContinue
Write-Ok "Removed $($d.FullName)"
}
}
# ── 5. CLAUDE.md cleanup (legacy) ─────────────────────────────────────────
Write-Step '5. CLAUDE.md sections (legacy)'
$mdChanged = $false
$candidates = @(
(Join-Path $home2 '.claude\CLAUDE.md'),
'.claude\CLAUDE.md',
'CLAUDE.md'
)
foreach ($md in $candidates) {
if (-not (Test-Path $md)) { continue }
$c = Get-Content $md -Raw
if ($c -notmatch '(AgentKey|agentkey|AGENTKEY)') { continue }
$c2 = [regex]::Replace($c, '\n# AgentKey\n.*?(?=\n# |\z)', '', 'Singleline')
$c2 = [regex]::Replace($c2, '\n[^\n]*(\.agentkey|agentkey.*activation\.md|agentkey.*SKILL\.md)[^\n]*', '', 'IgnoreCase')
if ($c2 -ne $c) {
Set-Content -Path $md -Value $c2 -Encoding UTF8
Write-Ok "Removed AgentKey section from $md"
$mdChanged = $true
}
}
if (-not $mdChanged) { Write-Skip 'No removable AgentKey section in CLAUDE.md' }
# ── 6. npm / npx caches ───────────────────────────────────────────────────
Write-Step '6. npm / npx caches'
if (Get-Command npm -ErrorAction SilentlyContinue) {
$globalList = & npm list -g --depth=0 2>$null
$removedAny = $false
# Sweep both the current package name and the legacy v0.x name so users
# who installed before the @agentkey/mcp → @agentkey/cli rename get a
# clean uninstall.
foreach ($pkg in @('@agentkey/cli', '@agentkey/mcp')) {
if ($globalList -and ($globalList -match [regex]::Escape($pkg))) {
Write-Info "Uninstalling global $pkg ..."
& npm uninstall -g $pkg 2>$null | Out-Null
if ($LASTEXITCODE -eq 0) { Write-Ok "Removed $pkg"; $removedAny = $true }
else { Write-Warn2 "Could not remove $pkg" }
}
}
if (-not $removedAny) {
Write-Skip 'No global @agentkey/cli or @agentkey/mcp installed'
}
} else {
Write-Skip 'npm not on PATH'
}
$npxCache = Join-Path $home2 '.npm\_npx'
if (Test-Path $npxCache) {
$hits = Get-ChildItem -Path $npxCache -Directory -Recurse -Depth 2 -ErrorAction SilentlyContinue |
Where-Object { $_.Name -match 'agentkey' }
if ($hits) {
$hits | ForEach-Object { Remove-Item -Recurse -Force $_.FullName -ErrorAction SilentlyContinue }
Write-Ok 'Cleared agentkey entries from npx cache'
} else {
Write-Skip 'No agentkey entries in npx cache'
}
} else {
Write-Skip 'No npx cache directory'
}
# ── 7. Residual plugin registries ─────────────────────────────────────────
Write-Step '7. Residual plugin registries'
$regs = @(
(Join-Path $home2 '.claude\plugins\installed_plugins.json'),
(Join-Path $home2 '.claude\plugins\known_marketplaces.json'),
(Join-Path $home2 '.claude\mcp-needs-auth-cache.json')
)
function Scrub-Agentkey($node) {
$removed = 0
if ($node -is [System.Management.Automation.PSCustomObject]) {
$keys = @($node.PSObject.Properties.Name)
foreach ($k in $keys) {
if ($k -match 'agentkey') {
$node.PSObject.Properties.Remove($k)
$removed++
} else {
$removed += Scrub-Agentkey $node.$k
}
}
} elseif ($node -is [System.Collections.IList]) {
# Rebuild list without agentkey items
$kept = New-Object System.Collections.ArrayList
foreach ($item in $node) {
$s = ($item | ConvertTo-Json -Depth 10 -Compress).ToLower()
if ($s -match 'agentkey') {
$removed++
} else {
$removed += Scrub-Agentkey $item
[void]$kept.Add($item)
}
}
return @{ removed = $removed; list = $kept }
}
return $removed
}
foreach ($reg in $regs) {
if (-not (Test-Path $reg)) { continue }
try {
$obj = Get-Content $reg -Raw | ConvertFrom-Json
} catch { continue }
$res = Scrub-Agentkey $obj
$n = if ($res -is [hashtable]) { $res.removed } else { $res }
if ($n -gt 0) {
($obj | ConvertTo-Json -Depth 100) | Set-Content -Path $reg -Encoding UTF8
Write-Ok "Cleaned $n entry/entries from $reg"
}
}
# ── Done ──────────────────────────────────────────────────────────────────
Write-Host ''
Write-Host ' ✓ Uninstall complete.' -ForegroundColor Green -NoNewline
Write-Host ' Restart your agent to apply changes.' -ForegroundColor White
Write-Host ''