From e97311cd3b00e825fa82dbf4ee059c257248979e Mon Sep 17 00:00:00 2001 From: "Kai (Tam Nhu) Tran" <61256810+kaitranntt@users.noreply.github.com> Date: Sat, 22 Nov 2025 19:43:50 -0500 Subject: [PATCH] fix: resolve missing ~/.ccs/.claude/ directory during npm install (v4.3.7) (#16) * fix(postinstall): make ora dependency optional to fix missing ~/.ccs/.claude/ directory The root cause was that `ora` module was not available during `npm install` when the postinstall script runs, causing both: - .claude/ directory copy to fail (ClaudeDirInstaller) - Symlink creation to fail (ClaudeSymlinkManager) This resulted in the ~/.ccs/.claude/ directory not being created. Changes: - Made ora import optional in ClaudeDirInstaller - Made ora import optional in ClaudeSymlinkManager - Both classes now gracefully fallback to console.log when ora is unavailable - Postinstall now successfully creates ~/.ccs/.claude/ and symlinks Tested: Clean install now properly creates all directories and symlinks * chore: bump version to 4.3.7 Version 4.3.7 - Postinstall Fix Release Changes: - Fixed missing ~/.ccs/.claude/ directory during npm install - Made ora dependency optional in installer utilities - Added CHANGELOG entry documenting the fix Files updated: - VERSION: 4.3.6 -> 4.3.7 - package.json: version updated - lib/ccs: version string updated - lib/ccs.ps1: version string updated - installers/install.sh: version string updated - installers/install.ps1: version string updated - CHANGELOG.md: added 4.3.7 release notes --- CHANGELOG.md | 14 ++++++++++++++ VERSION | 2 +- bin/utils/claude-dir-installer.js | 12 ++++++++++-- bin/utils/claude-symlink-manager.js | 12 ++++++++++-- installers/install.ps1 | 2 +- installers/install.sh | 2 +- lib/ccs | 2 +- lib/ccs.ps1 | 2 +- package.json | 2 +- 9 files changed, 40 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb2c9ab6..65f33af1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ Format: [Keep a Changelog](https://keepachangelog.com/) +## [4.3.7] - 2025-11-23 + +### Fixed +- **Postinstall Script**: Fixed missing `~/.ccs/.claude/` directory during `npm install` +- Made `ora` dependency optional in `ClaudeDirInstaller` and `ClaudeSymlinkManager` +- Postinstall script now gracefully handles missing `ora` module during installation +- Ensures `.claude/` directory and symlinks are properly created even when `ora` is unavailable + +### Technical Details +- Root cause: `ora` module not available during `npm install` postinstall execution +- Solution: Optional require with fallback to `console.log` when `ora` is unavailable +- Affects: `bin/utils/claude-dir-installer.js`, `bin/utils/claude-symlink-manager.js` +- Impact: All npm installations now properly create `~/.ccs/.claude/` and CCS symlinks + ## [4.3.6] - 2025-11-23 ### Added diff --git a/VERSION b/VERSION index 43270543..7e7f33c2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.3.6 +4.3.7 diff --git a/bin/utils/claude-dir-installer.js b/bin/utils/claude-dir-installer.js index a8f93e52..ed700916 100644 --- a/bin/utils/claude-dir-installer.js +++ b/bin/utils/claude-dir-installer.js @@ -4,7 +4,15 @@ const fs = require('fs'); const path = require('path'); const os = require('os'); -const ora = require('ora'); + +// Make ora optional (might not be available during npm install postinstall) +let ora = null; +try { + ora = require('ora'); +} catch (e) { + // ora not available, will use console.log instead +} + const { colored } = require('./helpers'); /** @@ -23,7 +31,7 @@ class ClaudeDirInstaller { * @param {boolean} silent - Suppress spinner output */ install(packageDir, silent = false) { - const spinner = silent ? null : ora('Copying .claude/ items to ~/.ccs/.claude/').start(); + const spinner = (silent || !ora) ? null : ora('Copying .claude/ items to ~/.ccs/.claude/').start(); try { // Auto-detect package directory if not provided diff --git a/bin/utils/claude-symlink-manager.js b/bin/utils/claude-symlink-manager.js index 93109d56..5146339d 100644 --- a/bin/utils/claude-symlink-manager.js +++ b/bin/utils/claude-symlink-manager.js @@ -3,7 +3,15 @@ const fs = require('fs'); const path = require('path'); const os = require('os'); -const ora = require('ora'); + +// Make ora optional (might not be available during npm install postinstall) +let ora = null; +try { + ora = require('ora'); +} catch (e) { + // ora not available, will use console.log instead +} + const { colored } = require('./helpers'); /** @@ -37,7 +45,7 @@ class ClaudeSymlinkManager { * Safe: backs up existing files before creating symlinks */ install(silent = false) { - const spinner = silent ? null : ora('Installing CCS items to ~/.claude/').start(); + const spinner = (silent || !ora) ? null : ora('Installing CCS items to ~/.claude/').start(); // Ensure ~/.ccs/.claude/ exists (should be shipped with package) if (!fs.existsSync(this.ccsClaudeDir)) { diff --git a/installers/install.ps1 b/installers/install.ps1 index 25dd8ce0..c5bcf135 100644 --- a/installers/install.ps1 +++ b/installers/install.ps1 @@ -31,7 +31,7 @@ $InstallMethod = if ($ScriptDir -and ((Test-Path "$ScriptDir\lib\ccs.ps1") -or ( # IMPORTANT: Update this version when releasing new versions! # This hardcoded version is used for standalone installations (irm | iex) # For git installations, VERSION file is read if available -$CcsVersion = "4.3.6" +$CcsVersion = "4.3.7" # Try to read VERSION file for git installations if ($ScriptDir) { diff --git a/installers/install.sh b/installers/install.sh index ae0d08b5..df5f30a8 100755 --- a/installers/install.sh +++ b/installers/install.sh @@ -32,7 +32,7 @@ fi # IMPORTANT: Update this version when releasing new versions! # This hardcoded version is used for standalone installations (curl | bash) # For git installations, VERSION file is read if available -CCS_VERSION="4.3.6" +CCS_VERSION="4.3.7" # Try to read VERSION file for git installations if [[ -f "$SCRIPT_DIR/VERSION" ]]; then diff --git a/lib/ccs b/lib/ccs index ab8025fa..fa3fd056 100755 --- a/lib/ccs +++ b/lib/ccs @@ -2,7 +2,7 @@ set -euo pipefail # Version (updated by scripts/bump-version.sh) -CCS_VERSION="4.3.6" +CCS_VERSION="4.3.7" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}" readonly PROFILES_JSON="$HOME/.ccs/profiles.json" diff --git a/lib/ccs.ps1 b/lib/ccs.ps1 index 347a5460..5549bd05 100644 --- a/lib/ccs.ps1 +++ b/lib/ccs.ps1 @@ -12,7 +12,7 @@ param( $ErrorActionPreference = "Stop" # Version (updated by scripts/bump-version.sh) -$CcsVersion = "4.3.6" +$CcsVersion = "4.3.7" $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" diff --git a/package.json b/package.json index cce30130..986dfc4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "4.3.6", + "version": "4.3.7", "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6", "keywords": [ "cli",