fix: missing ~/.ccs/.claude/ directory and ora v9 compatibility (v4.3.8) (#17)

* 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

* fix: handle ora v9 ES module compatibility

ora v9.0.0 is now an ES module, which requires using .default when
importing with CommonJS require(). This was causing "ora is not a
function" errors in doctor.js and installer utilities.

Changes:
- Updated ora import to use oraModule.default || oraModule
- Added fallback spinner implementation for when ora is unavailable
- Ensures compatibility with both ES and CommonJS module systems
- Fixes ccs doctor command and postinstall script

Tested:
- ccs doctor now works correctly with spinners
- postinstall successfully creates ~/.ccs/.claude/ and symlinks
- Fallback console.log works when ora is unavailable

* chore: update package-lock.json

* chore: bump version to 4.3.8

Version 4.3.8 - ora v9 Compatibility Release

Changes:
- Fixed ora v9 ES module compatibility issues
- Updated CHANGELOG with 4.3.8 release notes

Files updated:
- VERSION: 4.3.7 -> 4.3.8
- 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.8 release notes
This commit is contained in:
Kai (Tam Nhu) Tran
2025-11-22 20:07:15 -05:00
committed by GitHub
parent e97311cd3b
commit 7ea4448abf
11 changed files with 74 additions and 13 deletions
+14
View File
@@ -2,6 +2,20 @@
Format: [Keep a Changelog](https://keepachangelog.com/)
## [4.3.8] - 2025-11-23
### Fixed
- **ora v9 Compatibility**: Fixed "ora is not a function" errors in `ccs doctor` and installer utilities
- Properly handle ora v9+ ES module format when using CommonJS `require()`
- All spinner-based operations now work correctly with ora v9.0.0
### Technical Details
- ora v9+ is an ES module, requiring `.default` property access in CommonJS
- Updated import: `const oraModule = require('ora'); ora = oraModule.default || oraModule`
- Fallback spinner implementation ensures graceful degradation when ora is unavailable
- Affects: `bin/management/doctor.js`, `bin/utils/claude-dir-installer.js`, `bin/utils/claude-symlink-manager.js`
- Impact: `ccs doctor` command and postinstall scripts now work correctly with latest ora version
## [4.3.7] - 2025-11-23
### Fixed
+1 -1
View File
@@ -1 +1 @@
4.3.7
4.3.8
+22 -1
View File
@@ -6,7 +6,28 @@ const os = require('os');
const { spawn } = require('child_process');
const { colored } = require('../utils/helpers');
const { detectClaudeCli } = require('../utils/claude-detector');
const ora = require('ora');
// Make ora optional (might not be available during npm install postinstall)
// ora v9+ is an ES module, need to use .default for CommonJS
let ora = null;
try {
const oraModule = require('ora');
ora = oraModule.default || oraModule;
} catch (e) {
// ora not available, create fallback spinner that uses console.log
ora = function(text) {
return {
start: () => ({
succeed: (msg) => console.log(msg || `[OK] ${text}`),
fail: (msg) => console.log(msg || `[X] ${text}`),
warn: (msg) => console.log(msg || `[!] ${text}`),
info: (msg) => console.log(msg || `[i] ${text}`),
text: ''
})
};
};
}
const Table = require('cli-table3');
/**
+15 -2
View File
@@ -6,11 +6,24 @@ const path = require('path');
const os = require('os');
// Make ora optional (might not be available during npm install postinstall)
// ora v9+ is an ES module, need to use .default for CommonJS
let ora = null;
try {
ora = require('ora');
const oraModule = require('ora');
ora = oraModule.default || oraModule;
} catch (e) {
// ora not available, will use console.log instead
// ora not available, create fallback spinner that uses console.log
ora = function(text) {
return {
start: () => ({
succeed: (msg) => console.log(msg || `[OK] ${text}`),
fail: (msg) => console.log(msg || `[X] ${text}`),
warn: (msg) => console.log(msg || `[!] ${text}`),
info: (msg) => console.log(msg || `[i] ${text}`),
text: ''
})
};
};
}
const { colored } = require('./helpers');
+15 -2
View File
@@ -5,11 +5,24 @@ const path = require('path');
const os = require('os');
// Make ora optional (might not be available during npm install postinstall)
// ora v9+ is an ES module, need to use .default for CommonJS
let ora = null;
try {
ora = require('ora');
const oraModule = require('ora');
ora = oraModule.default || oraModule;
} catch (e) {
// ora not available, will use console.log instead
// ora not available, create fallback spinner that uses console.log
ora = function(text) {
return {
start: () => ({
succeed: (msg) => console.log(msg || `[OK] ${text}`),
fail: (msg) => console.log(msg || `[X] ${text}`),
warn: (msg) => console.log(msg || `[!] ${text}`),
info: (msg) => console.log(msg || `[i] ${text}`),
text: ''
})
};
};
}
const { colored } = require('./helpers');
+1 -1
View File
@@ -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.7"
$CcsVersion = "4.3.8"
# Try to read VERSION file for git installations
if ($ScriptDir) {
+1 -1
View File
@@ -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.7"
CCS_VERSION="4.3.8"
# Try to read VERSION file for git installations
if [[ -f "$SCRIPT_DIR/VERSION" ]]; then
+1 -1
View File
@@ -2,7 +2,7 @@
set -euo pipefail
# Version (updated by scripts/bump-version.sh)
CCS_VERSION="4.3.7"
CCS_VERSION="4.3.8"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly CONFIG_FILE="${CCS_CONFIG:-$HOME/.ccs/config.json}"
readonly PROFILES_JSON="$HOME/.ccs/profiles.json"
+1 -1
View File
@@ -12,7 +12,7 @@ param(
$ErrorActionPreference = "Stop"
# Version (updated by scripts/bump-version.sh)
$CcsVersion = "4.3.7"
$CcsVersion = "4.3.8"
$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"
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@kaitranntt/ccs",
"version": "4.3.5",
"version": "4.3.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@kaitranntt/ccs",
"version": "4.3.5",
"version": "4.3.7",
"hasInstallScript": true,
"license": "MIT",
"os": [
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@kaitranntt/ccs",
"version": "4.3.7",
"version": "4.3.8",
"description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6",
"keywords": [
"cli",