feat: add 'ccs update' command with smart update notifications

Add comprehensive update functionality with intelligent notification system.
Supports manual update checking, automatic notifications every 24h, and works
across npm and direct installations with proper error handling.

Closes #12
This commit is contained in:
Kai (Tam Nhu) Tran authored and kaitranntt committed 2025-11-18 01:19:28 -05:00
1 parent 31a21d13ad
commit d34dbcac1f
12 files changed
+686 -18

No files matched your search

+126 -1
View File
@@ -2,7 +2,7 @@
set -euo pipefail
# Version (updated by scripts/bump-version.sh)
CCS_VERSION="4.1.6"
CCS_VERSION="4.2.0"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
readonly PROFILES_JSON="$HOME/.ccs/profiles.json"
@@ -199,6 +199,7 @@ show_help() {
echo -e "${CYAN}Diagnostics:${RESET}"
echo -e " ${YELLOW}ccs doctor${RESET} Run health check and diagnostics"
echo -e " ${YELLOW}ccs sync${RESET} Sync delegation commands and skills"
echo -e " ${YELLOW}ccs update${RESET} Update CCS to latest version"
echo ""
echo -e "${CYAN}Flags:${RESET}"
@@ -591,6 +592,124 @@ sync_run() {
echo ""
}
# --- Update Command ---
update_run() {
echo ""
echo -e "${CYAN}Checking for updates...${RESET}"
echo ""
# Detect installation method
local install_method="direct"
if command -v npm &>/dev/null && npm list -g @kaitranntt/ccs &>/dev/null 2>&1; then
install_method="npm"
fi
# Fetch latest version from appropriate source
local latest_version=""
if command -v curl &>/dev/null; then
if [[ "$install_method" == "npm" ]]; then
# Check npm registry for npm installations
latest_version=$(curl -fsSL https://registry.npmjs.org/@kaitranntt/ccs/latest 2>/dev/null | \
grep '"version"' | head -1 | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([0-9.]+)".*/\1/')
else
# Check GitHub releases for direct installations
latest_version=$(curl -fsSL https://api.github.com/repos/kaitranntt/ccs/releases/latest 2>/dev/null | \
grep '"tag_name"' | sed -E 's/.*"v?([0-9.]+)".*/\1/')
fi
fi
if [[ -z "$latest_version" ]]; then
echo -e "${YELLOW}[!] Unable to check for updates${RESET}"
echo ""
echo "Try manually:"
if [[ "$install_method" == "npm" ]]; then
echo -e " ${YELLOW}npm install -g @kaitranntt/ccs@latest${RESET}"
else
echo -e " ${YELLOW}curl -fsSL ccs.kaitran.ca/install | bash${RESET}"
fi
echo ""
exit 1
fi
# Compare versions
if [[ "$latest_version" == "$CCS_VERSION" ]]; then
echo -e "${GREEN}[OK] You are already on the latest version (${CCS_VERSION})${RESET}"
echo ""
exit 0
fi
# Check if update available
local current_major=$(echo "$CCS_VERSION" | cut -d. -f1)
local current_minor=$(echo "$CCS_VERSION" | cut -d. -f2)
local current_patch=$(echo "$CCS_VERSION" | cut -d. -f3)
local latest_major=$(echo "$latest_version" | cut -d. -f1)
local latest_minor=$(echo "$latest_version" | cut -d. -f2)
local latest_patch=$(echo "$latest_version" | cut -d. -f3)
local is_newer=0
if [[ $latest_major -gt $current_major ]]; then
is_newer=1
elif [[ $latest_major -eq $current_major ]] && [[ $latest_minor -gt $current_minor ]]; then
is_newer=1
elif [[ $latest_major -eq $current_major ]] && [[ $latest_minor -eq $current_minor ]] && [[ $latest_patch -gt $current_patch ]]; then
is_newer=1
fi
if [[ $is_newer -eq 0 ]]; then
echo -e "${GREEN}[OK] You are on version ${CCS_VERSION} (latest is ${latest_version})${RESET}"
echo ""
exit 0
fi
echo -e "${YELLOW}[i] Update available: ${CCS_VERSION} → ${latest_version}${RESET}"
echo ""
# Perform update based on installation method
if [[ "$install_method" == "npm" ]]; then
echo -e "${CYAN}Updating via npm...${RESET}"
echo ""
if npm install -g @kaitranntt/ccs@latest; then
echo ""
echo -e "${GREEN}[OK] Update successful!${RESET}"
echo ""
echo -e "Run ${YELLOW}ccs --version${RESET} to verify"
echo ""
exit 0
else
echo ""
echo -e "${RED}[X] Update failed${RESET}"
echo ""
echo "Try manually:"
echo -e " ${YELLOW}npm install -g @kaitranntt/ccs@latest${RESET}"
echo ""
exit 1
fi
else
echo -e "${CYAN}Updating via installer...${RESET}"
echo ""
if curl -fsSL ccs.kaitran.ca/install | bash; then
echo ""
echo -e "${GREEN}[OK] Update successful!${RESET}"
echo ""
echo -e "Run ${YELLOW}ccs --version${RESET} to verify"
echo ""
exit 0
else
echo ""
echo -e "${RED}[X] Update failed${RESET}"
echo ""
echo "Try manually:"
echo -e " ${YELLOW}curl -fsSL ccs.kaitran.ca/install | bash${RESET}"
echo ""
exit 1
fi
fi
}
# --- Claude CLI Detection Logic ---
detect_claude_cli() {
@@ -1669,6 +1788,12 @@ if [[ $# -gt 0 ]] && [[ "${1}" == "sync" || "${1}" == "--sync" ]]; then
exit $?
fi
# Special case: update command
if [[ $# -gt 0 ]] && [[ "${1}" == "update" || "${1}" == "--update" ]]; then
update_run
exit $?
fi
# Run auto-recovery before main logic
auto_recover || {
msg_error "Auto-recovery failed. Check permissions."
+134 -1
View File
@@ -12,7 +12,7 @@ param(
$ErrorActionPreference = "Stop"
# Version (updated by scripts/bump-version.sh)
$CcsVersion = "4.1.6"
$CcsVersion = "4.2.0"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ConfigFile = if ($env:CCS_CONFIG) { $env:CCS_CONFIG } else { "$env:USERPROFILE\.ccs\config.json" }
$ProfilesJson = "$env:USERPROFILE\.ccs\profiles.json"
@@ -246,6 +246,7 @@ function Show-Help {
Write-ColorLine "Diagnostics:" "Cyan"
Write-ColorLine " ccs doctor Run health check and diagnostics" "Yellow"
Write-ColorLine " ccs sync Sync delegation commands and skills" "Yellow"
Write-ColorLine " ccs update Update CCS to latest version" "Yellow"
Write-Host ""
Write-ColorLine "Flags:" "Cyan"
@@ -1031,6 +1032,132 @@ function Sync-Run {
Write-Host ""
}
# --- Update Command ---
function Update-Run {
Write-Host ""
Write-Host "Checking for updates..." -ForegroundColor Cyan
Write-Host ""
# Detect installation method
$InstallMethod = "direct"
try {
$NpmList = npm list -g @kaitranntt/ccs 2>&1
if ($LASTEXITCODE -eq 0) {
$InstallMethod = "npm"
}
} catch {
# npm not available or not installed via npm
}
# Fetch latest version from appropriate source
$LatestVersion = ""
try {
if ($InstallMethod -eq "npm") {
# Check npm registry for npm installations
$Response = Invoke-RestMethod -Uri "https://registry.npmjs.org/@kaitranntt/ccs/latest" -TimeoutSec 5
$LatestVersion = $Response.version
} else {
# Check GitHub releases for direct installations
$Response = Invoke-RestMethod -Uri "https://api.github.com/repos/kaitranntt/ccs/releases/latest" -TimeoutSec 5
$LatestVersion = $Response.tag_name -replace '^v', ''
}
} catch {
Write-Host "[!] Unable to check for updates" -ForegroundColor Yellow
Write-Host ""
Write-Host "Try manually:"
if ($InstallMethod -eq "npm") {
Write-Host " npm install -g @kaitranntt/ccs@latest" -ForegroundColor Yellow
} else {
Write-Host " irm ccs.kaitran.ca/install | iex" -ForegroundColor Yellow
}
Write-Host ""
exit 1
}
# Compare versions
if ($LatestVersion -eq $CcsVersion) {
Write-Host "[OK] You are already on the latest version ($CcsVersion)" -ForegroundColor Green
Write-Host ""
exit 0
}
# Check if update available
$CurrentParts = $CcsVersion.Split('.')
$LatestParts = $LatestVersion.Split('.')
$IsNewer = $false
for ($i = 0; $i -lt 3; $i++) {
$Current = [int]$CurrentParts[$i]
$Latest = [int]$LatestParts[$i]
if ($Latest -gt $Current) {
$IsNewer = $true
break
} elseif ($Latest -lt $Current) {
break
}
}
if (-not $IsNewer) {
Write-Host "[OK] You are on version $CcsVersion (latest is $LatestVersion)" -ForegroundColor Green
Write-Host ""
exit 0
}
Write-Host "[i] Update available: $CcsVersion → $LatestVersion" -ForegroundColor Yellow
Write-Host ""
# Perform update based on installation method
if ($InstallMethod -eq "npm") {
Write-Host "Updating via npm..." -ForegroundColor Cyan
Write-Host ""
try {
npm install -g @kaitranntt/ccs@latest
if ($LASTEXITCODE -eq 0) {
Write-Host ""
Write-Host "[OK] Update successful!" -ForegroundColor Green
Write-Host ""
Write-Host "Run ccs --version to verify" -ForegroundColor Yellow
Write-Host ""
exit 0
} else {
throw "npm install failed"
}
} catch {
Write-Host ""
Write-Host "[X] Update failed" -ForegroundColor Red
Write-Host ""
Write-Host "Try manually:"
Write-Host " npm install -g @kaitranntt/ccs@latest" -ForegroundColor Yellow
Write-Host ""
exit 1
}
} else {
Write-Host "Updating via installer..." -ForegroundColor Cyan
Write-Host ""
try {
irm ccs.kaitran.ca/install | iex
Write-Host ""
Write-Host "[OK] Update successful!" -ForegroundColor Green
Write-Host ""
Write-Host "Run ccs --version to verify" -ForegroundColor Yellow
Write-Host ""
exit 0
} catch {
Write-Host ""
Write-Host "[X] Update failed" -ForegroundColor Red
Write-Host ""
Write-Host "Try manually:"
Write-Host " irm ccs.kaitran.ca/install | iex" -ForegroundColor Yellow
Write-Host ""
exit 1
}
}
}
# --- Auth Commands (Phase 3) ---
function Show-AuthHelp {
@@ -1519,6 +1646,12 @@ if ($RemainingArgs.Count -gt 0 -and ($RemainingArgs[0] -eq "sync" -or $Remaining
exit 0
}
# Special case: update command
if ($RemainingArgs.Count -gt 0 -and ($RemainingArgs[0] -eq "update" -or $RemainingArgs[0] -eq "--update")) {
Update-Run
exit 0
}
# Run auto-recovery before main logic
if (-not (Invoke-AutoRecovery)) {
Write-ErrorMsg "Auto-recovery failed. Check permissions."