Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions setup-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -466,9 +466,22 @@ else
log_warning "Claude Code CLI, npx, or jq not found, skipping MCP server registration"
fi

# Claude Code plugins (requires claude CLI)
# Claude Code plugins (requires claude CLI).
# Idempotent: cache the installed-plugins list ONCE before the loop and skip
# entries already present. CRITICAL: every `claude plugin install` call
# writes to ~/.claude/.claude.json. The CLI's deserialize-modify-serialize
# cycle does NOT preserve fields outside its internal struct — subscription
# metadata (`organizationType: claude_max`, `organizationRateLimitTier`),
# the `projects` map, and onboarding flags get silently dropped. Re-running
# `plugin install` for plugins that are already installed is the trigger
# for `.claude.json` truncation (75k -> 1.5k), which makes Claude Code
# prompt for re-authentication in every project (subscription state lost).
# Same idempotence pattern as MCP registration (line 447).
if command -v claude >/dev/null 2>&1; then
log_info "Installing Claude Code plugins..."
installed_plugins=$(claude plugin list 2>/dev/null || true)
plugins_added=0
plugins_skipped=0
for plugin in \
"claude-mem@thedotmack" \
"code-simplifier@claude-plugins-official" \
Expand All @@ -482,9 +495,15 @@ if command -v claude >/dev/null 2>&1; then
"code-review@claude-plugins-official" \
"commit-commands@claude-plugins-official" \
"pr-review-toolkit@claude-plugins-official"; do
claude plugin install "$plugin" >/dev/null 2>&1 || true
if printf '%s' "$installed_plugins" | grep -qF "$plugin"; then
plugins_skipped=$((plugins_skipped + 1))
else
if claude plugin install "$plugin" >/dev/null 2>&1; then
plugins_added=$((plugins_added + 1))
fi
fi
done
log_success "Claude Code plugins installed"
log_success "Claude Code plugins ready ($plugins_added added, $plugins_skipped already present)"
else
log_warning "Claude Code CLI not found, skipping plugin installation"
fi
Expand Down
20 changes: 18 additions & 2 deletions setup-windows.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,15 @@ if (-not ($claudeCmd -and $npxCmd)) {
}
}

# Claude Code plugins (requires claude CLI)
# Claude Code plugins (requires claude CLI).
# Idempotent: cache the installed-plugins list ONCE before the loop and skip
# entries already present. CRITICAL: every `claude plugin install` writes to
# %USERPROFILE%\.claude\.claude.json. The CLI does NOT preserve all fields
# on rewrite -- subscription metadata (organizationType, organizationRateLimitTier),
# the projects map, and onboarding flags get silently dropped. Re-running
# install for already-installed plugins triggers silent .claude.json truncation
# and forces re-authentication in every project. Same idempotence pattern as
# MCP registration above.
if ($claudeCmd) {
Write-Info "Installing Claude Code plugins..."
$plugins = @(
Expand All @@ -247,14 +255,22 @@ if ($claudeCmd) {
"commit-commands@claude-plugins-official",
"pr-review-toolkit@claude-plugins-official"
)
$installedPlugins = try { (& claude plugin list 2>$null) -join "`n" } catch { "" }
$pluginsAdded = 0
$pluginsSkipped = 0
foreach ($plugin in $plugins) {
if ($installedPlugins -match [regex]::Escape($plugin)) {
$pluginsSkipped++
continue
}
try {
& claude plugin install $plugin 2>$null | Out-Null
$pluginsAdded++
} catch {
# Silently continue if a plugin fails
}
}
Write-Success "Claude Code plugins installed"
Write-Success "Claude Code plugins ready ($pluginsAdded added, $pluginsSkipped already present)"
} else {
Write-Warn "Claude Code CLI not found, skipping plugin installation"
}
Expand Down
Loading