mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: Add version tracking and upgrade check system
- Add /version command to check installed and latest versions - Create version.json metadata file during installation - Pass version and branch info from install-remote.ps1 to Install-Claude.ps1 - Support version comparison and upgrade recommendations - Track installation mode (Global/Path) and source branch 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
212
.claude/commands/version.md
Normal file
212
.claude/commands/version.md
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
name: version
|
||||
description: Display version information and check for updates
|
||||
usage: /version
|
||||
examples:
|
||||
- /version
|
||||
allowed-tools: Bash(*)
|
||||
---
|
||||
|
||||
# Version Command (/version)
|
||||
|
||||
## Purpose
|
||||
Display local and global installation versions, check for the latest updates from GitHub, and provide upgrade recommendations.
|
||||
|
||||
## Execution Flow
|
||||
1. **Local Version Check**: Read version information from `./.claude/version.json` if it exists.
|
||||
2. **Global Version Check**: Read version information from `~/.claude/version.json` if it exists.
|
||||
3. **Fetch Remote Versions**: Use GitHub API to get the latest stable release tag and the latest commit hash from the main branch.
|
||||
4. **Compare & Suggest**: Compare installed versions with the latest remote versions and provide upgrade suggestions if applicable.
|
||||
|
||||
## Step 1: Check Local Version
|
||||
|
||||
### Check if local version.json exists
|
||||
```bash
|
||||
bash(test -f ./.claude/version.json && echo "found" || echo "not_found")
|
||||
```
|
||||
|
||||
### Read local version (if exists)
|
||||
```bash
|
||||
bash(cat ./.claude/version.json)
|
||||
```
|
||||
|
||||
### Extract version with jq (preferred)
|
||||
```bash
|
||||
bash(cat ./.claude/version.json | grep -o '"version": *"[^"]*"' | cut -d'"' -f4)
|
||||
```
|
||||
|
||||
### Extract installation date
|
||||
```bash
|
||||
bash(cat ./.claude/version.json | grep -o '"installation_date_utc": *"[^"]*"' | cut -d'"' -f4)
|
||||
```
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
Local Version: 3.2.1
|
||||
Installed: 2025-10-03T12:00:00Z
|
||||
```
|
||||
|
||||
## Step 2: Check Global Version
|
||||
|
||||
### Check if global version.json exists
|
||||
```bash
|
||||
bash(test -f ~/.claude/version.json && echo "found" || echo "not_found")
|
||||
```
|
||||
|
||||
### Read global version
|
||||
```bash
|
||||
bash(cat ~/.claude/version.json)
|
||||
```
|
||||
|
||||
### Extract version
|
||||
```bash
|
||||
bash(cat ~/.claude/version.json | grep -o '"version": *"[^"]*"' | cut -d'"' -f4)
|
||||
```
|
||||
|
||||
### Extract installation date
|
||||
```bash
|
||||
bash(cat ~/.claude/version.json | grep -o '"installation_date_utc": *"[^"]*"' | cut -d'"' -f4)
|
||||
```
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
Global Version: 3.2.1
|
||||
Installed: 2025-10-03T12:00:00Z
|
||||
```
|
||||
|
||||
## Step 3: Fetch Latest Stable Release
|
||||
|
||||
### Call GitHub API for latest release
|
||||
```bash
|
||||
bash(curl -fsSL "https://api.github.com/repos/catlog22/Claude-Code-Workflow/releases/latest" 2>/dev/null)
|
||||
```
|
||||
|
||||
### Extract tag name (version)
|
||||
```bash
|
||||
bash(curl -fsSL "https://api.github.com/repos/catlog22/Claude-Code-Workflow/releases/latest" 2>/dev/null | grep -o '"tag_name": *"[^"]*"' | head -1 | cut -d'"' -f4)
|
||||
```
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
Latest Stable: v3.2.2
|
||||
```
|
||||
|
||||
## Step 4: Fetch Latest Main Branch
|
||||
|
||||
### Call GitHub API for main branch
|
||||
```bash
|
||||
bash(curl -fsSL "https://api.github.com/repos/catlog22/Claude-Code-Workflow/branches/main" 2>/dev/null)
|
||||
```
|
||||
|
||||
### Extract commit SHA (short)
|
||||
```bash
|
||||
bash(curl -fsSL "https://api.github.com/repos/catlog22/Claude-Code-Workflow/branches/main" 2>/dev/null | grep -o '"sha": *"[^"]*"' | head -1 | cut -d'"' -f4 | cut -c1-7)
|
||||
```
|
||||
|
||||
**Output Format**:
|
||||
```
|
||||
Latest Dev: a1b2c3d
|
||||
```
|
||||
|
||||
## Step 5: Compare Versions and Suggest Upgrade
|
||||
|
||||
### Normalize versions (remove 'v' prefix)
|
||||
```bash
|
||||
bash(echo "v3.2.1" | sed 's/^v//')
|
||||
```
|
||||
|
||||
### Compare two versions
|
||||
```bash
|
||||
bash(printf "%s\n%s" "3.2.1" "3.2.2" | sort -V | tail -n 1)
|
||||
```
|
||||
|
||||
### Check if versions are equal
|
||||
```bash
|
||||
# If equal: Up to date
|
||||
# If remote newer: Upgrade available
|
||||
# If local newer: Development version
|
||||
```
|
||||
|
||||
**Output Scenarios**:
|
||||
|
||||
**Scenario 1: Up to date**
|
||||
```
|
||||
✅ You are on the latest stable version (3.2.1)
|
||||
```
|
||||
|
||||
**Scenario 2: Upgrade available**
|
||||
```
|
||||
⬆️ A newer stable version is available: v3.2.2
|
||||
Your version: 3.2.1
|
||||
|
||||
To upgrade:
|
||||
PowerShell: iex (iwr -useb https://raw.githubusercontent.com/catlog22/Claude-Code-Workflow/main/install-remote.ps1)
|
||||
Bash: bash <(curl -fsSL https://raw.githubusercontent.com/catlog22/Claude-Code-Workflow/main/install-remote.sh)
|
||||
```
|
||||
|
||||
**Scenario 3: Development version**
|
||||
```
|
||||
✨ You are running a development version (3.3.0-dev)
|
||||
This is newer than the latest stable release (v3.2.2)
|
||||
```
|
||||
|
||||
## Simple Bash Commands
|
||||
|
||||
### Basic Operations
|
||||
```bash
|
||||
# Check local version file
|
||||
bash(test -f ./.claude/version.json && cat ./.claude/version.json)
|
||||
|
||||
# Check global version file
|
||||
bash(test -f ~/.claude/version.json && cat ~/.claude/version.json)
|
||||
|
||||
# Extract version from JSON
|
||||
bash(cat version.json | grep -o '"version": *"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
# Extract date from JSON
|
||||
bash(cat version.json | grep -o '"installation_date_utc": *"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
# Fetch latest release
|
||||
bash(curl -fsSL "https://api.github.com/repos/catlog22/Claude-Code-Workflow/releases/latest")
|
||||
|
||||
# Extract tag name
|
||||
bash(curl -s https://api.github.com/repos/catlog22/Claude-Code-Workflow/releases/latest | grep -o '"tag_name": *"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
# Compare versions
|
||||
bash(printf "%s\n%s" "3.2.1" "3.2.2" | sort -V | tail -n 1)
|
||||
|
||||
# Remove 'v' prefix
|
||||
bash(echo "v3.2.1" | sed 's/^v//')
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### No installation found
|
||||
```
|
||||
WARNING: Claude Code Workflow not installed
|
||||
Install using:
|
||||
PowerShell: iex (iwr -useb https://raw.githubusercontent.com/catlog22/Claude-Code-Workflow/main/install-remote.ps1)
|
||||
```
|
||||
|
||||
### Network error
|
||||
```
|
||||
ERROR: Could not fetch latest version from GitHub
|
||||
Check your network connection
|
||||
```
|
||||
|
||||
### Invalid version.json
|
||||
```
|
||||
ERROR: version.json is invalid or corrupted
|
||||
```
|
||||
|
||||
## Design Notes
|
||||
|
||||
- Uses simple, direct bash commands instead of complex functions
|
||||
- Each step is independent and can be executed separately
|
||||
- Fallback to grep/sed for JSON parsing (no jq dependency required)
|
||||
- Network calls use curl with error suppression
|
||||
- Version comparison uses `sort -V` for accurate semantic versioning
|
||||
|
||||
## Related Commands
|
||||
- `/cli:cli-init` - Initialize CLI configurations
|
||||
- `/workflow:session:list` - List workflow sessions
|
||||
@@ -59,7 +59,11 @@ param(
|
||||
|
||||
[switch]$BackupAll,
|
||||
|
||||
[switch]$NoBackup
|
||||
[switch]$NoBackup,
|
||||
|
||||
[string]$SourceVersion = "",
|
||||
|
||||
[string]$SourceBranch = ""
|
||||
)
|
||||
|
||||
# Set encoding for proper Unicode support
|
||||
@@ -622,6 +626,37 @@ function Merge-DirectoryContents {
|
||||
return $true
|
||||
}
|
||||
|
||||
function Create-VersionJson {
|
||||
param(
|
||||
[string]$TargetClaudeDir,
|
||||
[string]$InstallationMode
|
||||
)
|
||||
|
||||
# Determine version from source or default
|
||||
$versionNumber = if ($SourceVersion) { $SourceVersion } else { $Version }
|
||||
$sourceBranch = if ($SourceBranch) { $SourceBranch } else { "unknown" }
|
||||
|
||||
# Create version.json content
|
||||
$versionInfo = @{
|
||||
version = $versionNumber
|
||||
installation_mode = $InstallationMode
|
||||
installation_path = $TargetClaudeDir
|
||||
installation_date_utc = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
source_branch = $sourceBranch
|
||||
}
|
||||
|
||||
$versionJsonPath = Join-Path $TargetClaudeDir "version.json"
|
||||
|
||||
try {
|
||||
$versionInfo | ConvertTo-Json | Out-File -FilePath $versionJsonPath -Encoding utf8 -Force
|
||||
Write-ColorOutput "Created version.json: $versionNumber ($InstallationMode)" $ColorSuccess
|
||||
return $true
|
||||
} catch {
|
||||
Write-ColorOutput "WARNING: Failed to create version.json: $($_.Exception.Message)" $ColorWarning
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Install-Global {
|
||||
Write-ColorOutput "Installing Claude Code Workflow System globally..." $ColorInfo
|
||||
|
||||
@@ -682,6 +717,10 @@ function Install-Global {
|
||||
Write-ColorOutput "Merging .gemini directory contents..." $ColorInfo
|
||||
$geminiMerged = Merge-DirectoryContents -Source $sourceGeminiDir -Destination $globalGeminiDir -Description ".gemini directory contents" -BackupFolder $backupFolder
|
||||
|
||||
# Create version.json in global .claude directory
|
||||
Write-ColorOutput "Creating version.json..." $ColorInfo
|
||||
Create-VersionJson -TargetClaudeDir $globalClaudeDir -InstallationMode "Global"
|
||||
|
||||
if ($backupFolder -and (Test-Path $backupFolder)) {
|
||||
$backupFiles = Get-ChildItem $backupFolder -Recurse -File -ErrorAction SilentlyContinue
|
||||
if (-not $backupFiles -or ($backupFiles | Measure-Object).Count -eq 0) {
|
||||
@@ -819,6 +858,14 @@ function Install-Path {
|
||||
Write-ColorOutput "Merging .gemini directory contents to local location..." $ColorInfo
|
||||
$geminiMerged = Merge-DirectoryContents -Source $sourceGeminiDir -Destination $localGeminiDir -Description ".gemini directory contents" -BackupFolder $backupFolder
|
||||
|
||||
# Create version.json in local .claude directory
|
||||
Write-ColorOutput "Creating version.json in local directory..." $ColorInfo
|
||||
Create-VersionJson -TargetClaudeDir $localClaudeDir -InstallationMode "Path"
|
||||
|
||||
# Also create version.json in global .claude directory
|
||||
Write-ColorOutput "Creating version.json in global directory..." $ColorInfo
|
||||
Create-VersionJson -TargetClaudeDir $globalClaudeDir -InstallationMode "Global"
|
||||
|
||||
if ($backupFolder -and (Test-Path $backupFolder)) {
|
||||
$backupFiles = Get-ChildItem $backupFolder -Recurse -File -ErrorAction SilentlyContinue
|
||||
if (-not $backupFiles -or ($backupFiles | Measure-Object).Count -eq 0) {
|
||||
|
||||
@@ -258,23 +258,25 @@ function Extract-Repository {
|
||||
|
||||
function Invoke-LocalInstaller {
|
||||
param(
|
||||
[string]$RepoDir
|
||||
[string]$RepoDir,
|
||||
[string]$VersionInfo = "",
|
||||
[string]$BranchInfo = ""
|
||||
)
|
||||
|
||||
|
||||
$installerPath = Join-Path $RepoDir "Install-Claude.ps1"
|
||||
|
||||
|
||||
if (-not (Test-Path $installerPath)) {
|
||||
Write-ColorOutput "ERROR: Install-Claude.ps1 not found" $ColorError
|
||||
return $false
|
||||
}
|
||||
|
||||
|
||||
Write-ColorOutput "Running local installer..." $ColorInfo
|
||||
Write-Host ""
|
||||
|
||||
|
||||
# Build parameters for local installer
|
||||
$params = @{}
|
||||
if ($Global) { $params["InstallMode"] = "Global" }
|
||||
if ($Directory) {
|
||||
if ($Directory) {
|
||||
$params["InstallMode"] = "Custom"
|
||||
$params["TargetPath"] = $Directory
|
||||
}
|
||||
@@ -282,11 +284,15 @@ function Invoke-LocalInstaller {
|
||||
if ($NoBackup) { $params["NoBackup"] = $NoBackup }
|
||||
if ($NonInteractive) { $params["NonInteractive"] = $NonInteractive }
|
||||
if ($BackupAll) { $params["BackupAll"] = $BackupAll }
|
||||
|
||||
|
||||
# Pass version and branch information
|
||||
if ($VersionInfo) { $params["SourceVersion"] = $VersionInfo }
|
||||
if ($BranchInfo) { $params["SourceBranch"] = $BranchInfo }
|
||||
|
||||
try {
|
||||
# Change to repo directory and run installer
|
||||
Push-Location $RepoDir
|
||||
|
||||
|
||||
if ($params.Count -gt 0) {
|
||||
$paramList = ($params.GetEnumerator() | ForEach-Object { "-$($_.Key) $($_.Value)" }) -join " "
|
||||
Write-ColorOutput "Executing: & `"$installerPath`" $paramList" $ColorInfo
|
||||
@@ -295,7 +301,7 @@ function Invoke-LocalInstaller {
|
||||
Write-ColorOutput "Executing: & `"$installerPath`"" $ColorInfo
|
||||
& $installerPath
|
||||
}
|
||||
|
||||
|
||||
Pop-Location
|
||||
return $true
|
||||
} catch {
|
||||
@@ -542,26 +548,32 @@ function Main {
|
||||
# Create temp directory
|
||||
$tempDir = Get-TempDirectory
|
||||
Write-ColorOutput "Temporary directory: $tempDir" $ColorInfo
|
||||
|
||||
|
||||
try {
|
||||
# Download repository
|
||||
$zipPath = Download-Repository -TempDir $tempDir -Version $Version -Branch $Branch -Tag $Tag
|
||||
if (-not $zipPath) {
|
||||
throw "Download failed"
|
||||
}
|
||||
|
||||
|
||||
# Extract repository
|
||||
$repoDir = Extract-Repository $zipPath $tempDir
|
||||
if (-not $repoDir) {
|
||||
throw "Extraction failed"
|
||||
}
|
||||
|
||||
# Run local installer
|
||||
$success = Invoke-LocalInstaller $repoDir
|
||||
|
||||
# Determine version and branch information to pass
|
||||
$versionToPass = if ($Tag) { $Tag } else { "latest" }
|
||||
$branchToPass = if ($Version -eq "branch") { $Branch } elseif ($Version -eq "latest") { "main" } elseif ($Tag) { $Tag } else { "main" }
|
||||
|
||||
Write-ColorOutput "Version info: $versionToPass (branch: $branchToPass)" $ColorInfo
|
||||
|
||||
# Run local installer with version information
|
||||
$success = Invoke-LocalInstaller -RepoDir $repoDir -VersionInfo $versionToPass -BranchInfo $branchToPass
|
||||
if (-not $success) {
|
||||
throw "Installation script failed"
|
||||
}
|
||||
|
||||
|
||||
Write-Host ""
|
||||
Write-ColorOutput "Remote installation completed successfully!" $ColorSuccess
|
||||
|
||||
|
||||
Reference in New Issue
Block a user