mirror of
https://github.com/alirezarezvani/ClaudeForge.git
synced 2026-07-03 10:23:15 -04:00
e45065e8ba
User-facing documentation drifted behind several waves of feature work
(plugin manifest, hooks, sync command, --weekly, audit skills, Karpathy
skill, CLAUDE.local.md tier, layered hook config). Refresh + fix one
real install bug. Surgical edits only — no rewrites.
README.md:
- "What's New" block now reflects the plugin manifest, --weekly,
InstructionsLoaded hook, AGENTS.md interop, CLAUDE.local.md tier,
layered hook config, and the fail-closed guardian.
- "What's Included" expanded from 5 numbered bullets to a structured
list grouping the 5 skills (incl. three forked audit skills),
2 slash commands, 1 agent, and 3 hook scripts.
- Components Deep Dive: /sync-claude-md and the guardian's fail-closed
contract now documented.
- Project Status: 1.0.0 -> 2.1.0; Quick Stats updated to reflect
actual component counts.
- Acknowledgments: attribution to MIT-licensed forrestchang and
shanraisshan source repos for adapted patterns.
docs/ARCHITECTURE.md, docs/QUICK_START.md, docs/TROUBLESHOOTING.md,
docs/INSTALLATION.md, examples/modular-setup.md, examples/integration-
examples.md:
- Every "20-300 lines" / ">300 lines" / "exceeds 300 lines" reference
rewritten to the actual 150-line hard cap.
- Every ls/Remove-Item path that pointed at the legacy
~/.claude/commands/enhance-claude-md/ bundle now points at the
top-level enhance-claude-md.md + sync-claude-md.md files.
- integration-examples.md line-bounds shell guard now uses 20..150.
docs/CLAUDE.md:
- Install-verify ls list extended with the three new audit-skill
directories so docs match what install.sh actually creates.
install.sh + install.ps1 (REAL FIX, not just docs):
- The three forked audit skills (claude-md-drift-audit, link-check,
dependency-rescan) were registered in plugin.json but never copied
by the direct-install path. Both installers now iterate over them
after the karpathy-guidelines block, mirroring the same backup +
nested-duplicate-cleanup pattern. Banner section and uninstall
instructions list all 5 skills.
Verified:
- All 5 CLAUDE.md files in this repo still <= 150 lines after edits.
- install.sh passes bash -n syntax check.
- Plugin manifest still resolves all 8 referenced paths on disk.
- README invariants present: 2.1.0, --weekly, hooks/hooks.json,
both source-repo attributions, three audit skill names.
- Stale-claim sweep: zero "20-300" / ">300" / "exceeds 300" refs
remain in docs/ or examples/.
427 lines
17 KiB
PowerShell
427 lines
17 KiB
PowerShell
# ClaudeForge Installer for Windows
|
||
# PowerShell installation script
|
||
# Version: 2.0.0
|
||
|
||
#Requires -Version 5.1
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
# Colors for output
|
||
function Write-Info {
|
||
param([string]$Message)
|
||
Write-Host "ℹ $Message" -ForegroundColor Blue
|
||
}
|
||
|
||
function Write-Success {
|
||
param([string]$Message)
|
||
Write-Host "✓ $Message" -ForegroundColor Green
|
||
}
|
||
|
||
function Write-Warning {
|
||
param([string]$Message)
|
||
Write-Host "⚠ $Message" -ForegroundColor Yellow
|
||
}
|
||
|
||
function Write-Error-Custom {
|
||
param([string]$Message)
|
||
Write-Host "✗ $Message" -ForegroundColor Red
|
||
}
|
||
|
||
# Banner
|
||
Write-Host ""
|
||
Write-Host "╔════════════════════════════════════════╗" -ForegroundColor Blue
|
||
Write-Host "║ ║" -ForegroundColor Blue
|
||
Write-Host "║ " -NoNewline -ForegroundColor Blue
|
||
Write-Host "ClaudeForge Installer" -NoNewline -ForegroundColor Green
|
||
Write-Host " ║" -ForegroundColor Blue
|
||
Write-Host "║ ║" -ForegroundColor Blue
|
||
Write-Host "║ Automated CLAUDE.md Management Tool ║" -ForegroundColor Blue
|
||
Write-Host "║ Version 2.0.0 ║" -ForegroundColor Blue
|
||
Write-Host "║ ║" -ForegroundColor Blue
|
||
Write-Host "╚════════════════════════════════════════╝" -ForegroundColor Blue
|
||
Write-Host ""
|
||
|
||
# Check if running from correct directory or need to download
|
||
$RemoteInstall = $false
|
||
$OriginalDir = Get-Location
|
||
|
||
if (-not (Test-Path "skill") -or -not (Test-Path "command") -or -not (Test-Path "agent")) {
|
||
Write-Info "Installing from GitHub..."
|
||
$RemoteInstall = $true
|
||
|
||
# Create temporary directory
|
||
$TempDir = New-Item -ItemType Directory -Path ([System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.Guid]::NewGuid().ToString())) -Force
|
||
Set-Location $TempDir
|
||
|
||
Write-Info "Downloading ClaudeForge v2.0.0..."
|
||
|
||
# Download archive
|
||
$archiveUrl = "https://github.com/alirezarezvani/ClaudeForge/archive/refs/heads/main.zip"
|
||
$archivePath = Join-Path $TempDir "claudeforge.zip"
|
||
|
||
try {
|
||
Invoke-WebRequest -Uri $archiveUrl -OutFile $archivePath -UseBasicParsing
|
||
} catch {
|
||
Write-Error-Custom "Failed to download ClaudeForge. Please check your internet connection."
|
||
exit 1
|
||
}
|
||
|
||
Write-Info "Extracting files..."
|
||
Expand-Archive -Path $archivePath -DestinationPath $TempDir -Force
|
||
Set-Location (Join-Path $TempDir "ClaudeForge-main")
|
||
|
||
Write-Success "Downloaded ClaudeForge successfully"
|
||
}
|
||
|
||
# Check for Claude Code installation
|
||
Write-Info "Checking for Claude Code installation..."
|
||
|
||
$claudeDir = "$env:USERPROFILE\.claude"
|
||
if (-not (Test-Path $claudeDir)) {
|
||
Write-Warning "Claude Code user directory (~/.claude) not found."
|
||
Write-Info "Creating $claudeDir directory structure..."
|
||
New-Item -ItemType Directory -Path "$claudeDir\skills" -Force | Out-Null
|
||
New-Item -ItemType Directory -Path "$claudeDir\commands" -Force | Out-Null
|
||
New-Item -ItemType Directory -Path "$claudeDir\agents" -Force | Out-Null
|
||
Write-Success "Directory structure created"
|
||
}
|
||
|
||
# Check Claude Code version
|
||
function Check-ClaudeCodeVersion {
|
||
$version = $null
|
||
|
||
try {
|
||
$output = & claude --version 2>&1
|
||
if ($output -match '\d+\.\d+\.\d+') {
|
||
$version = $matches[0]
|
||
}
|
||
} catch {
|
||
Write-Warning "Could not detect Claude Code version"
|
||
Write-Info "ClaudeForge v2.0 requires Claude Code 2.1.0 or later"
|
||
Write-Info "Continuing with installation (compatibility not guaranteed)"
|
||
return $true
|
||
}
|
||
|
||
if ([string]::IsNullOrEmpty($version)) {
|
||
Write-Warning "Could not detect Claude Code version"
|
||
Write-Info "Continuing with installation (compatibility not guaranteed)"
|
||
return $true
|
||
}
|
||
|
||
$parts = $version.Split('.')
|
||
$major = [int]$parts[0]
|
||
$minor = [int]$parts[1]
|
||
|
||
if ($major -lt 2) {
|
||
Write-Error-Custom "Claude Code version $version is not supported"
|
||
Write-Error-Custom "Please upgrade to Claude Code 2.1.0 or later"
|
||
return $false
|
||
} elseif ($major -eq 2 -and $minor -lt 1) {
|
||
Write-Warning "Claude Code version $version may have limited features"
|
||
Write-Info "Recommended: Claude Code 2.1.4 or later for full hook support"
|
||
}
|
||
|
||
Write-Success "Claude Code version $version detected"
|
||
return $true
|
||
}
|
||
|
||
Write-Info "Checking Claude Code version..."
|
||
if (-not (Check-ClaudeCodeVersion)) {
|
||
exit 1
|
||
}
|
||
|
||
# Ask for installation scope
|
||
Write-Host ""
|
||
Write-Info "Where would you like to install ClaudeForge?"
|
||
Write-Host ""
|
||
Write-Host " " -NoNewline
|
||
Write-Host "1)" -ForegroundColor Green -NoNewline
|
||
Write-Host " User-level (~/.claude/) - Available in all Claude Code projects"
|
||
Write-Host " " -NoNewline
|
||
Write-Host "2)" -ForegroundColor Green -NoNewline
|
||
Write-Host " Project-level (./.claude/) - Available only in current project"
|
||
Write-Host ""
|
||
|
||
$validChoice = $false
|
||
while (-not $validChoice) {
|
||
$choice = Read-Host "Enter choice [1/2]"
|
||
switch ($choice) {
|
||
"1" {
|
||
$skillsDir = "$env:USERPROFILE\.claude\skills"
|
||
$commandsDir = "$env:USERPROFILE\.claude\commands"
|
||
$agentsDir = "$env:USERPROFILE\.claude\agents"
|
||
$scope = "user-level"
|
||
Write-Success "Installing at user-level (all projects)"
|
||
$validChoice = $true
|
||
}
|
||
"2" {
|
||
if ($RemoteInstall) {
|
||
$skillsDir = Join-Path $OriginalDir ".claude\skills"
|
||
$commandsDir = Join-Path $OriginalDir ".claude\commands"
|
||
$agentsDir = Join-Path $OriginalDir ".claude\agents"
|
||
} else {
|
||
$skillsDir = ".\.claude\skills"
|
||
$commandsDir = ".\.claude\commands"
|
||
$agentsDir = ".\.claude\agents"
|
||
}
|
||
$scope = "project-level"
|
||
Write-Success "Installing at project-level (current project only)"
|
||
$validChoice = $true
|
||
}
|
||
default {
|
||
Write-Error-Custom "Invalid choice. Please enter 1 or 2."
|
||
}
|
||
}
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Info "Installation will create:"
|
||
Write-Host " • Skill: $skillsDir\claudeforge-skill\"
|
||
Write-Host " • Skill: $skillsDir\karpathy-guidelines\"
|
||
Write-Host " • Skill: $skillsDir\claude-md-drift-audit\"
|
||
Write-Host " • Skill: $skillsDir\claude-md-link-check\"
|
||
Write-Host " • Skill: $skillsDir\claude-md-dependency-rescan\"
|
||
Write-Host " • Command: $commandsDir\enhance-claude-md.md"
|
||
Write-Host " • Command: $commandsDir\sync-claude-md.md"
|
||
Write-Host " • Agent: $agentsDir\claude-md-guardian.md"
|
||
Write-Host ""
|
||
|
||
# Confirm installation
|
||
$confirm = Read-Host "Proceed with installation? [Y/n]"
|
||
if ([string]::IsNullOrEmpty($confirm)) { $confirm = "Y" }
|
||
|
||
if ($confirm -notmatch "^[Yy]$") {
|
||
Write-Warning "Installation cancelled."
|
||
exit 0
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Info "Starting installation..."
|
||
Write-Host ""
|
||
|
||
# Create directories if they don't exist
|
||
New-Item -ItemType Directory -Path $skillsDir -Force | Out-Null
|
||
New-Item -ItemType Directory -Path $commandsDir -Force | Out-Null
|
||
New-Item -ItemType Directory -Path $agentsDir -Force | Out-Null
|
||
|
||
# Install skill
|
||
Write-Info "Installing ClaudeForge skill..."
|
||
$skillPath = "$skillsDir\claudeforge-skill"
|
||
if (Test-Path $skillPath) {
|
||
Write-Warning "Existing skill found. Creating backup..."
|
||
$backupName = "claudeforge-skill.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $skillPath -Destination "$skillsDir\$backupName" -Force
|
||
Write-Success "Backup created"
|
||
}
|
||
Copy-Item -Path "skill" -Destination $skillPath -Recurse -Force
|
||
Write-Success "Skill installed → $skillPath\"
|
||
|
||
# Install karpathy-guidelines as a separate top-level skill so it is
|
||
# discoverable as its own skill and applies to every project (not only
|
||
# during /enhance-claude-md runs).
|
||
Write-Info "Installing karpathy-guidelines skill..."
|
||
$karpathyPath = "$skillsDir\karpathy-guidelines"
|
||
if (Test-Path $karpathyPath) {
|
||
Write-Warning "Existing karpathy-guidelines skill found. Creating backup..."
|
||
$backupName = "karpathy-guidelines.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $karpathyPath -Destination "$skillsDir\$backupName" -Force
|
||
Write-Success "Backup created"
|
||
}
|
||
Copy-Item -Path "skill\karpathy-guidelines" -Destination $karpathyPath -Recurse -Force
|
||
# Remove the nested duplicate inside claudeforge-skill so the skill exists once.
|
||
$nestedKarpathy = "$skillPath\karpathy-guidelines"
|
||
if (Test-Path $nestedKarpathy) {
|
||
Remove-Item -Path $nestedKarpathy -Recurse -Force
|
||
}
|
||
Write-Success "Karpathy guidelines installed → $karpathyPath\"
|
||
|
||
# Install the forked task-style audit skills as separate top-level skills
|
||
# so each is invocable standalone and discoverable by /sync-claude-md --weekly.
|
||
$auditSkills = @("claude-md-drift-audit", "claude-md-link-check", "claude-md-dependency-rescan")
|
||
foreach ($auditSkill in $auditSkills) {
|
||
Write-Info "Installing $auditSkill skill..."
|
||
$auditTarget = "$skillsDir\$auditSkill"
|
||
if (Test-Path $auditTarget) {
|
||
Write-Warning "Existing $auditSkill skill found. Creating backup..."
|
||
$backupName = "$auditSkill.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $auditTarget -Destination "$skillsDir\$backupName" -Force
|
||
}
|
||
Copy-Item -Path "skill\$auditSkill" -Destination $auditTarget -Recurse -Force
|
||
$nestedAudit = "$skillPath\$auditSkill"
|
||
if (Test-Path $nestedAudit) {
|
||
Remove-Item -Path $nestedAudit -Recurse -Force
|
||
}
|
||
Write-Success "$auditSkill installed → $auditTarget\"
|
||
}
|
||
|
||
# Install slash commands. Each .md file in command/ becomes its own
|
||
# top-level command file so it registers as /<name>. README.md is skipped.
|
||
Write-Info "Installing slash commands..."
|
||
|
||
# Migrate legacy bundle directory if present.
|
||
$legacyBundle = "$commandsDir\enhance-claude-md"
|
||
if (Test-Path $legacyBundle) {
|
||
Write-Warning "Legacy command bundle found. Creating backup..."
|
||
$backupName = "enhance-claude-md.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $legacyBundle -Destination "$commandsDir\$backupName" -Force
|
||
Write-Success "Backup created"
|
||
}
|
||
|
||
Get-ChildItem -Path "command" -Filter "*.md" -File | Where-Object { $_.Name -ne "README.md" } | ForEach-Object {
|
||
$cmdTarget = Join-Path $commandsDir $_.Name
|
||
if (Test-Path $cmdTarget) {
|
||
Write-Warning "Existing $($_.Name) found. Creating backup..."
|
||
$backupName = "$($_.Name).backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $cmdTarget -Destination (Join-Path $commandsDir $backupName) -Force
|
||
}
|
||
Copy-Item -Path $_.FullName -Destination $cmdTarget -Force
|
||
Write-Success "Command installed → $cmdTarget"
|
||
}
|
||
|
||
# Install guardian agent
|
||
Write-Info "Installing claude-md-guardian agent..."
|
||
$agentPath = "$agentsDir\claude-md-guardian.md"
|
||
if (Test-Path $agentPath) {
|
||
Write-Warning "Existing agent found. Creating backup..."
|
||
$backupName = "claude-md-guardian.md.backup.$(Get-Date -Format 'yyyyMMdd_HHmmss')"
|
||
Move-Item -Path $agentPath -Destination "$agentsDir\$backupName" -Force
|
||
Write-Success "Backup created"
|
||
}
|
||
Copy-Item -Path "agent\claude-md-guardian.md" -Destination $agentPath -Force
|
||
Write-Success "Agent installed → $agentPath"
|
||
|
||
# Optional: Install quality hooks
|
||
Write-Host ""
|
||
$installHooks = Read-Host "Would you like to install quality hooks (pre-commit validation)? [y/N]"
|
||
if ([string]::IsNullOrEmpty($installHooks)) { $installHooks = "N" }
|
||
|
||
if ($installHooks -match "^[Yy]$") {
|
||
if ($scope -eq "project-level") {
|
||
Write-Info "Installing quality hooks..."
|
||
if ($RemoteInstall) {
|
||
$hooksDir = Join-Path $OriginalDir ".claude\hooks"
|
||
} else {
|
||
$hooksDir = ".claude\hooks"
|
||
}
|
||
New-Item -ItemType Directory -Path $hooksDir -Force | Out-Null
|
||
Copy-Item -Path "hooks\pre-commit.sh" -Destination "$hooksDir\" -Force
|
||
Write-Success "Quality hooks installed → $hooksDir\"
|
||
} else {
|
||
Write-Warning "Quality hooks can only be installed at project-level"
|
||
Write-Info "Run installer with option 2 in your project directory"
|
||
}
|
||
}
|
||
|
||
# Validate v2.1.4 compatibility
|
||
function Validate-V214Compatibility {
|
||
param(
|
||
[string]$skillsDir,
|
||
[string]$agentsDir
|
||
)
|
||
|
||
Write-Info "Validating v2.1.4 compatibility..."
|
||
|
||
$skillFile = Join-Path $skillsDir "claudeforge-skill\SKILL.md"
|
||
$agentFile = Join-Path $agentsDir "claude-md-guardian.md"
|
||
|
||
# Verify new syntax is present
|
||
if (-not (Select-String -Path $skillFile -Pattern "permissions:" -Quiet)) {
|
||
Write-Error-Custom "Skill missing v2.1.4 permissions syntax"
|
||
return $false
|
||
}
|
||
|
||
if (-not (Select-String -Path $agentFile -Pattern "permissions:" -Quiet)) {
|
||
Write-Error-Custom "Agent missing v2.1.4 permissions syntax"
|
||
return $false
|
||
}
|
||
|
||
# Check for hooks
|
||
if (Select-String -Path $agentFile -Pattern "hooks:" -Quiet) {
|
||
Write-Success "Guardian agent hooks configured"
|
||
} else {
|
||
Write-Warning "Guardian agent has no hooks (optional)"
|
||
}
|
||
|
||
Write-Success "v2.1.4 compatibility validated"
|
||
return $true
|
||
}
|
||
|
||
Write-Host ""
|
||
if (-not (Validate-V214Compatibility -skillsDir $skillsDir -agentsDir $agentsDir)) {
|
||
Write-Error-Custom "Installation validation failed"
|
||
exit 1
|
||
}
|
||
|
||
# Installation complete
|
||
Write-Host ""
|
||
Write-Host "╔════════════════════════════════════════╗" -ForegroundColor Green
|
||
Write-Host "║ ║" -ForegroundColor Green
|
||
Write-Host "║ Installation completed successfully!║" -ForegroundColor Green
|
||
Write-Host "║ ║" -ForegroundColor Green
|
||
Write-Host "╚════════════════════════════════════════╝" -ForegroundColor Green
|
||
Write-Host ""
|
||
|
||
# Next steps
|
||
Write-Info "Next steps:"
|
||
Write-Host ""
|
||
Write-Host " " -NoNewline
|
||
Write-Host "1." -ForegroundColor Green -NoNewline
|
||
Write-Host " Restart Claude Code (important!)"
|
||
Write-Host " " -NoNewline
|
||
Write-Host "2." -ForegroundColor Green -NoNewline
|
||
Write-Host " Navigate to your project directory"
|
||
Write-Host " " -NoNewline
|
||
Write-Host "3." -ForegroundColor Green -NoNewline
|
||
Write-Host " Run the command:"
|
||
Write-Host ""
|
||
Write-Host " /enhance-claude-md" -ForegroundColor Blue
|
||
Write-Host ""
|
||
Write-Host " " -NoNewline
|
||
Write-Host "4." -ForegroundColor Green -NoNewline
|
||
Write-Host " Follow the interactive prompts"
|
||
Write-Host ""
|
||
|
||
# Additional information
|
||
Write-Info "Documentation:"
|
||
Write-Host ""
|
||
Write-Host " • Quick Start: docs\QUICK_START.md"
|
||
Write-Host " • Installation: docs\INSTALLATION.md"
|
||
Write-Host " • Architecture: docs\ARCHITECTURE.md"
|
||
Write-Host " • Troubleshooting: docs\TROUBLESHOOTING.md"
|
||
Write-Host ""
|
||
Write-Host " • GitHub: https://github.com/alirezarezvani/ClaudeForge" -ForegroundColor Blue
|
||
Write-Host ""
|
||
|
||
# Uninstall instructions
|
||
Write-Info "To uninstall, run:"
|
||
Write-Host ""
|
||
if ($scope -eq "user-level") {
|
||
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claudeforge-skill"
|
||
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\karpathy-guidelines"
|
||
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-drift-audit"
|
||
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-link-check"
|
||
Write-Host " Remove-Item -Recurse -Force ~\.claude\skills\claude-md-dependency-rescan"
|
||
Write-Host " Remove-Item -Force ~\.claude\commands\enhance-claude-md.md"
|
||
Write-Host " Remove-Item -Force ~\.claude\commands\sync-claude-md.md"
|
||
Write-Host " Remove-Item -Force ~\.claude\agents\claude-md-guardian.md"
|
||
} else {
|
||
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claudeforge-skill"
|
||
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\karpathy-guidelines"
|
||
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-drift-audit"
|
||
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-link-check"
|
||
Write-Host " Remove-Item -Recurse -Force .\.claude\skills\claude-md-dependency-rescan"
|
||
Write-Host " Remove-Item -Force .\.claude\commands\enhance-claude-md.md"
|
||
Write-Host " Remove-Item -Force .\.claude\commands\sync-claude-md.md"
|
||
Write-Host " Remove-Item -Force .\.claude\agents\claude-md-guardian.md"
|
||
}
|
||
Write-Host ""
|
||
|
||
Write-Success "Thank you for installing ClaudeForge!"
|
||
Write-Host ""
|
||
|
||
# Cleanup temporary directory if remote install
|
||
if ($RemoteInstall) {
|
||
Set-Location $env:USERPROFILE
|
||
Remove-Item -Recurse -Force $TempDir -ErrorAction SilentlyContinue
|
||
}
|