cc-hub-cli 1.1.17 → 1.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +248 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command9 } from "commander";
|
|
5
5
|
import { createRequire } from "module";
|
|
6
6
|
|
|
7
7
|
// src/profiles/commands.ts
|
|
@@ -141,7 +141,7 @@ var MacOSDesktopApp = class {
|
|
|
141
141
|
if (fs2.existsSync(configLib)) return configLib;
|
|
142
142
|
return configLib;
|
|
143
143
|
}
|
|
144
|
-
findBinary() {
|
|
144
|
+
findBinary(pinnedVersion) {
|
|
145
145
|
debug(`desktop-app: searching for binary in ${this.supportDir}`);
|
|
146
146
|
const claudeCodeDir = path2.join(this.supportDir, "claude-code");
|
|
147
147
|
if (!fs2.existsSync(claudeCodeDir)) return void 0;
|
|
@@ -155,7 +155,17 @@ var MacOSDesktopApp = class {
|
|
|
155
155
|
}
|
|
156
156
|
if (versions.length === 0) return void 0;
|
|
157
157
|
versions.sort(sortSemverDesc);
|
|
158
|
-
|
|
158
|
+
let targetVersion = versions[0];
|
|
159
|
+
if (pinnedVersion) {
|
|
160
|
+
const match = versions.find((v) => v === pinnedVersion);
|
|
161
|
+
if (match) {
|
|
162
|
+
targetVersion = match;
|
|
163
|
+
debug(`desktop-app: using pinned version ${targetVersion}`);
|
|
164
|
+
} else {
|
|
165
|
+
warn(`desktop-app: pinned version ${pinnedVersion} not found locally; falling back to latest ${targetVersion}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const binary = path2.join(claudeCodeDir, targetVersion, "claude.app", "Contents", "MacOS", "claude");
|
|
159
169
|
debug(`desktop-app: found macOS binary ${binary}`);
|
|
160
170
|
return binary;
|
|
161
171
|
}
|
|
@@ -226,7 +236,7 @@ var WindowsDesktopApp = class {
|
|
|
226
236
|
const dir = this._findSupportDir();
|
|
227
237
|
return dir ? path2.join(dir, "local-agent-mode-sessions") : void 0;
|
|
228
238
|
}
|
|
229
|
-
findBinary() {
|
|
239
|
+
findBinary(_pinnedVersion) {
|
|
230
240
|
const win32Binary = path2.join(process.env.LOCALAPPDATA || "", "Programs", "Claude", "Claude.exe");
|
|
231
241
|
if (fs2.existsSync(win32Binary)) return win32Binary;
|
|
232
242
|
return void 0;
|
|
@@ -245,7 +255,7 @@ var NoOpDesktopApp = class {
|
|
|
245
255
|
getConfigLibrary() {
|
|
246
256
|
return void 0;
|
|
247
257
|
}
|
|
248
|
-
findBinary() {
|
|
258
|
+
findBinary(_pinnedVersion) {
|
|
249
259
|
return void 0;
|
|
250
260
|
}
|
|
251
261
|
};
|
|
@@ -700,7 +710,7 @@ function getKimiHeaders(claudeVersion) {
|
|
|
700
710
|
const stainlessOS = platform === "darwin" ? "MacOS" : platform === "win32" ? "Windows" : "Linux";
|
|
701
711
|
return {
|
|
702
712
|
"X-Stainless-OS": stainlessOS,
|
|
703
|
-
"X-Stainless-Package-Version": "1.1.
|
|
713
|
+
"X-Stainless-Package-Version": "1.1.18",
|
|
704
714
|
"X-Stainless-Runtime": "node",
|
|
705
715
|
"User-Agent": `claude-code/${claudeVersion}`
|
|
706
716
|
};
|
|
@@ -1016,12 +1026,25 @@ function getClaudeVersion() {
|
|
|
1016
1026
|
debug("binary-resolver: could not detect Claude version, using default");
|
|
1017
1027
|
return cachedVersion;
|
|
1018
1028
|
}
|
|
1029
|
+
function getPinnedVersion() {
|
|
1030
|
+
try {
|
|
1031
|
+
ensureSettingsFile();
|
|
1032
|
+
const settings2 = readJson(SETTINGS_FILE);
|
|
1033
|
+
if (settings2.minimumVersion && settings2.requiredMaximumVersion && settings2.minimumVersion === settings2.requiredMaximumVersion) {
|
|
1034
|
+
return settings2.minimumVersion;
|
|
1035
|
+
}
|
|
1036
|
+
return void 0;
|
|
1037
|
+
} catch {
|
|
1038
|
+
return void 0;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1019
1041
|
var SystemBinaryResolver = class {
|
|
1020
1042
|
constructor(app) {
|
|
1021
1043
|
this.app = app;
|
|
1022
1044
|
}
|
|
1023
1045
|
app;
|
|
1024
|
-
resolve() {
|
|
1046
|
+
resolve(pinnedVersion) {
|
|
1047
|
+
const pin = pinnedVersion ?? getPinnedVersion();
|
|
1025
1048
|
debug("binary-resolver: trying global 'claude' command");
|
|
1026
1049
|
try {
|
|
1027
1050
|
const result = spawnSync("claude", ["--version"], {
|
|
@@ -1030,12 +1053,22 @@ var SystemBinaryResolver = class {
|
|
|
1030
1053
|
});
|
|
1031
1054
|
if (result.status === 0) {
|
|
1032
1055
|
debug("binary-resolver: found global 'claude'");
|
|
1056
|
+
if (pin) {
|
|
1057
|
+
const currentVersion = getClaudeVersion();
|
|
1058
|
+
if (currentVersion !== pin) {
|
|
1059
|
+
warn(`binary-resolver: global claude version ${currentVersion} does not match pinned version ${pin}`);
|
|
1060
|
+
console.warn(`Warning: installed Claude version (${currentVersion}) does not match pinned version (${pin}).`);
|
|
1061
|
+
console.warn(`To install the pinned version, run: npm install -g @anthropic-ai/claude-code@${pin}`);
|
|
1062
|
+
} else {
|
|
1063
|
+
debug(`binary-resolver: global claude version matches pinned ${pin}`);
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1033
1066
|
return "claude";
|
|
1034
1067
|
}
|
|
1035
1068
|
} catch {
|
|
1036
1069
|
}
|
|
1037
1070
|
debug("binary-resolver: trying desktop app binary");
|
|
1038
|
-
const desktopBinary = this.app.findBinary();
|
|
1071
|
+
const desktopBinary = this.app.findBinary(pin);
|
|
1039
1072
|
if (desktopBinary) {
|
|
1040
1073
|
debug(`binary-resolver: found desktop binary at ${desktopBinary}`);
|
|
1041
1074
|
return desktopBinary;
|
|
@@ -2411,6 +2444,7 @@ _cc-hub() {
|
|
|
2411
2444
|
'session:Manage Claude Code sessions'
|
|
2412
2445
|
'provider:Manage provider types'
|
|
2413
2446
|
'cache:Manage Claude Code cache and backup files'
|
|
2447
|
+
'claude-version:Manage Claude Code CLI versions'
|
|
2414
2448
|
'completion:Print shell completion functions'
|
|
2415
2449
|
'help:Display help for a command'
|
|
2416
2450
|
)
|
|
@@ -2459,6 +2493,12 @@ _cc-hub() {
|
|
|
2459
2493
|
'troubleshoot:Launch Claude Code to troubleshoot a session file'
|
|
2460
2494
|
)
|
|
2461
2495
|
|
|
2496
|
+
local -a claude_version_subcmds
|
|
2497
|
+
claude_version_subcmds=(
|
|
2498
|
+
'list:List available Claude Code versions'
|
|
2499
|
+
'pin:Pin Claude Code to a specific version'
|
|
2500
|
+
)
|
|
2501
|
+
|
|
2462
2502
|
_cc_hub_profiles() {
|
|
2463
2503
|
local profiles_file="\${CLAUDE_PROFILES_FILE:-$HOME/.claude/profiles.json}"
|
|
2464
2504
|
if [[ -f "$profiles_file" ]]; then
|
|
@@ -2545,6 +2585,13 @@ _cc-hub() {
|
|
|
2545
2585
|
_arguments -C -S '(-i --interactive)'{-i,--interactive}'[Open an interactive Claude Code window instead of a one-shot prompt]'
|
|
2546
2586
|
fi
|
|
2547
2587
|
;;
|
|
2588
|
+
claude-version)
|
|
2589
|
+
if (( CURRENT == 2 )); then
|
|
2590
|
+
_describe -t claude-version-subcmds 'claude-version subcommand' claude_version_subcmds
|
|
2591
|
+
elif [[ $words[2] == "pin" ]]; then
|
|
2592
|
+
_arguments -C -S '--clear[Remove the version pin]' '*:version:'
|
|
2593
|
+
fi
|
|
2594
|
+
;;
|
|
2548
2595
|
esac
|
|
2549
2596
|
;;
|
|
2550
2597
|
esac
|
|
@@ -2598,7 +2645,7 @@ _cc-hub() {
|
|
|
2598
2645
|
COMPREPLY=()
|
|
2599
2646
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
2600
2647
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
2601
|
-
commands="profile use run hook session provider cache completion help"
|
|
2648
|
+
commands="profile use run hook session provider cache claude-version completion help"
|
|
2602
2649
|
|
|
2603
2650
|
local profile_subcmds="add update list view remove rename default sync export"
|
|
2604
2651
|
local provider_subcmds="list"
|
|
@@ -2606,6 +2653,7 @@ _cc-hub() {
|
|
|
2606
2653
|
local hooks_subcmds="list add remove enable disable"
|
|
2607
2654
|
local session_subcmds="list show search ps stats clean troubleshoot"
|
|
2608
2655
|
local cache_subcmds="restore"
|
|
2656
|
+
local claude_version_subcmds="list pin"
|
|
2609
2657
|
|
|
2610
2658
|
# Top-level command
|
|
2611
2659
|
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
@@ -2676,6 +2724,18 @@ _cc-hub() {
|
|
|
2676
2724
|
fi
|
|
2677
2725
|
fi
|
|
2678
2726
|
;;
|
|
2727
|
+
claude-version)
|
|
2728
|
+
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
2729
|
+
COMPREPLY=($(compgen -W "$claude_version_subcmds" -- "$cur"))
|
|
2730
|
+
elif [[ "\${COMP_WORDS[2]}" == "pin" ]]; then
|
|
2731
|
+
if [[ "$prev" == "--clear" ]]; then
|
|
2732
|
+
:
|
|
2733
|
+
else
|
|
2734
|
+
local pin_opts="--clear"
|
|
2735
|
+
COMPREPLY=($(compgen -W "$pin_opts" -- "$cur"))
|
|
2736
|
+
fi
|
|
2737
|
+
fi
|
|
2738
|
+
;;
|
|
2679
2739
|
esac
|
|
2680
2740
|
|
|
2681
2741
|
return 0
|
|
@@ -2696,6 +2756,7 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
|
|
|
2696
2756
|
'session:Manage Claude Code sessions'
|
|
2697
2757
|
'provider:Manage provider types'
|
|
2698
2758
|
'cache:Manage Claude Code cache and backup files'
|
|
2759
|
+
'claude-version:Manage Claude Code CLI versions'
|
|
2699
2760
|
'completion:Print shell completion functions'
|
|
2700
2761
|
'help:Display help for a command'
|
|
2701
2762
|
)
|
|
@@ -2705,6 +2766,7 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
|
|
|
2705
2766
|
$sessionSubcmds = @('list', 'show', 'search', 'ps', 'stats', 'clean', 'troubleshoot')
|
|
2706
2767
|
$cacheSubcmds = @('restore')
|
|
2707
2768
|
$providerSubcmds = @('list')
|
|
2769
|
+
$claudeVersionSubcmds = @('list', 'pin')
|
|
2708
2770
|
|
|
2709
2771
|
$tokens = $commandAst.CommandElements | ForEach-Object { $_.ToString() }
|
|
2710
2772
|
|
|
@@ -2750,6 +2812,16 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
|
|
|
2750
2812
|
return
|
|
2751
2813
|
}
|
|
2752
2814
|
}
|
|
2815
|
+
'claude-version' {
|
|
2816
|
+
if ($tokens.Count -eq 2 -or ($tokens.Count -eq 3 -and $wordToComplete -ne '')) {
|
|
2817
|
+
$claudeVersionSubcmds | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
|
|
2818
|
+
return
|
|
2819
|
+
}
|
|
2820
|
+
if ($tokens[2] -eq 'pin' -and $tokens.Count -ge 3) {
|
|
2821
|
+
$opts = @('--clear')
|
|
2822
|
+
$opts | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
|
|
2823
|
+
}
|
|
2824
|
+
}
|
|
2753
2825
|
'use' {
|
|
2754
2826
|
$opts = @('--built-in')
|
|
2755
2827
|
$opts | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
|
|
@@ -2915,8 +2987,8 @@ function killProcesses(pids) {
|
|
|
2915
2987
|
}
|
|
2916
2988
|
}
|
|
2917
2989
|
function cacheCommand() {
|
|
2918
|
-
const
|
|
2919
|
-
|
|
2990
|
+
const cache2 = new Command7("cache").description("Manage Claude Code cache and backup files");
|
|
2991
|
+
cache2.command("restore").description("Restore ~/.claude/.claude.json.backup to ~/.claude.json").action(safeAction(async () => {
|
|
2920
2992
|
const backupPath = path9.join(CLAUDE_DIR, ".claude.json.backup");
|
|
2921
2993
|
const targetPath = CLAUDE_JSON;
|
|
2922
2994
|
if (!fs8.existsSync(backupPath)) {
|
|
@@ -2938,7 +3010,169 @@ function cacheCommand() {
|
|
|
2938
3010
|
debug(`cache restore: restored ${backupPath} -> ${targetPath}`);
|
|
2939
3011
|
console.log(`Restored ${backupPath} -> ${targetPath}`);
|
|
2940
3012
|
}));
|
|
2941
|
-
return
|
|
3013
|
+
return cache2;
|
|
3014
|
+
}
|
|
3015
|
+
|
|
3016
|
+
// src/claude-version/commands.ts
|
|
3017
|
+
import { Command as Command8 } from "commander";
|
|
3018
|
+
import fs9 from "fs";
|
|
3019
|
+
import path10 from "path";
|
|
3020
|
+
|
|
3021
|
+
// src/claude-version/fetcher.ts
|
|
3022
|
+
var cache = null;
|
|
3023
|
+
var cacheTime = 0;
|
|
3024
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
3025
|
+
async function fetchChangelogVersions() {
|
|
3026
|
+
if (cache && Date.now() - cacheTime < CACHE_TTL_MS) {
|
|
3027
|
+
return cache;
|
|
3028
|
+
}
|
|
3029
|
+
const url = "https://code.claude.com/docs/en/changelog";
|
|
3030
|
+
const response = await fetch(url, {
|
|
3031
|
+
headers: {
|
|
3032
|
+
"User-Agent": `cc-hub/${"1.1.18"}`
|
|
3033
|
+
}
|
|
3034
|
+
});
|
|
3035
|
+
if (!response.ok) {
|
|
3036
|
+
throw new Error(`Failed to fetch changelog: ${response.status} ${response.statusText}`);
|
|
3037
|
+
}
|
|
3038
|
+
const html = await response.text();
|
|
3039
|
+
const versions = parseChangelogHtml(html);
|
|
3040
|
+
cache = versions;
|
|
3041
|
+
cacheTime = Date.now();
|
|
3042
|
+
return versions;
|
|
3043
|
+
}
|
|
3044
|
+
function parseChangelogHtml(html) {
|
|
3045
|
+
const results = [];
|
|
3046
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3047
|
+
const componentRegex = /label:\s*"(\d+\.\d+\.\d+)"[\s\S]*?description:\s*"([^"]{5,60})"/g;
|
|
3048
|
+
let match;
|
|
3049
|
+
while ((match = componentRegex.exec(html)) !== null) {
|
|
3050
|
+
const version2 = match[1];
|
|
3051
|
+
const date = match[2].trim();
|
|
3052
|
+
if (seen.has(version2)) continue;
|
|
3053
|
+
seen.add(version2);
|
|
3054
|
+
results.push({ version: version2, date });
|
|
3055
|
+
}
|
|
3056
|
+
const versionRegex = /<div[^>]*contenteditable=["']?false["']?[^>]*>(\d+\.\d+\.\d+)<\/div>/gi;
|
|
3057
|
+
while ((match = versionRegex.exec(html)) !== null) {
|
|
3058
|
+
const version2 = match[1];
|
|
3059
|
+
if (seen.has(version2)) continue;
|
|
3060
|
+
seen.add(version2);
|
|
3061
|
+
const startIdx = match.index + match[0].length;
|
|
3062
|
+
const snippet2 = html.slice(startIdx, startIdx + 500);
|
|
3063
|
+
const dateMatch = snippet2.match(/<p>([^<]{5,60})<\/p>/) || snippet2.match(/data-component-part=["']?update-description["']?[^>]*>([^<]{5,60})<\/div>/);
|
|
3064
|
+
const date = dateMatch ? dateMatch[1].trim() : "";
|
|
3065
|
+
results.push({ version: version2, date });
|
|
3066
|
+
}
|
|
3067
|
+
const headingRegex = /<h[23][^>]*>(\d+\.\d+\.\d+)[^<]*<\/h[23]>/gi;
|
|
3068
|
+
while ((match = headingRegex.exec(html)) !== null) {
|
|
3069
|
+
const version2 = match[1];
|
|
3070
|
+
if (seen.has(version2)) continue;
|
|
3071
|
+
seen.add(version2);
|
|
3072
|
+
const startIdx = match.index + match[0].length;
|
|
3073
|
+
const snippet2 = html.slice(startIdx, startIdx + 500);
|
|
3074
|
+
const dateMatch = snippet2.match(/<p>([^<]{5,60})<\/p>/);
|
|
3075
|
+
const date = dateMatch ? dateMatch[1].trim() : "";
|
|
3076
|
+
results.push({ version: version2, date });
|
|
3077
|
+
}
|
|
3078
|
+
return results;
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
// src/claude-version/utils.ts
|
|
3082
|
+
function getPinnedVersion2() {
|
|
3083
|
+
ensureSettingsFile();
|
|
3084
|
+
const settings2 = readJson(SETTINGS_FILE);
|
|
3085
|
+
return settings2.minimumVersion && settings2.requiredMaximumVersion && settings2.minimumVersion === settings2.requiredMaximumVersion ? settings2.minimumVersion : void 0;
|
|
3086
|
+
}
|
|
3087
|
+
function setPinnedVersion(version2) {
|
|
3088
|
+
ensureSettingsFile();
|
|
3089
|
+
const settings2 = readJson(SETTINGS_FILE);
|
|
3090
|
+
if (version2) {
|
|
3091
|
+
settings2.minimumVersion = version2;
|
|
3092
|
+
settings2.requiredMaximumVersion = version2;
|
|
3093
|
+
} else {
|
|
3094
|
+
delete settings2.minimumVersion;
|
|
3095
|
+
delete settings2.requiredMaximumVersion;
|
|
3096
|
+
}
|
|
3097
|
+
writeJson(SETTINGS_FILE, settings2);
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
// src/claude-version/commands.ts
|
|
3101
|
+
function claudeVersionCommand() {
|
|
3102
|
+
const cmd = new Command8("claude-version").description("Manage Claude Code CLI versions");
|
|
3103
|
+
cmd.command("list").description("List available Claude Code versions").action(safeAction(async () => {
|
|
3104
|
+
const [remoteVersions, installedVersion, pinnedVersion] = await Promise.all([
|
|
3105
|
+
fetchChangelogVersions().catch(() => []),
|
|
3106
|
+
Promise.resolve(getClaudeVersion()).catch(() => "unknown"),
|
|
3107
|
+
Promise.resolve(getPinnedVersion2())
|
|
3108
|
+
]);
|
|
3109
|
+
if (remoteVersions.length === 0) {
|
|
3110
|
+
console.log("Could not fetch remote versions. Showing installed version only.");
|
|
3111
|
+
console.log(`Installed: ${installedVersion}`);
|
|
3112
|
+
if (pinnedVersion) {
|
|
3113
|
+
console.log(`Pinned: ${pinnedVersion}`);
|
|
3114
|
+
}
|
|
3115
|
+
return;
|
|
3116
|
+
}
|
|
3117
|
+
console.log("Available Claude Code versions:");
|
|
3118
|
+
console.log("");
|
|
3119
|
+
const maxVersionLen = Math.max(...remoteVersions.map((v) => v.version.length), 10);
|
|
3120
|
+
const maxDateLen = Math.max(...remoteVersions.map((v) => v.date.length), 4);
|
|
3121
|
+
console.log(`${"Version".padEnd(maxVersionLen)} ${"Date".padEnd(maxDateLen)} Status`);
|
|
3122
|
+
console.log("-".repeat(maxVersionLen + maxDateLen + 10));
|
|
3123
|
+
for (const { version: version2, date } of remoteVersions.slice(0, 20)) {
|
|
3124
|
+
const markers = [];
|
|
3125
|
+
if (version2 === installedVersion) markers.push("installed");
|
|
3126
|
+
if (version2 === pinnedVersion) markers.push("pinned");
|
|
3127
|
+
const status = markers.length > 0 ? `(${markers.join(", ")})` : "";
|
|
3128
|
+
console.log(`${version2.padEnd(maxVersionLen)} ${(date || "\u2014").padEnd(maxDateLen)} ${status}`);
|
|
3129
|
+
}
|
|
3130
|
+
if (remoteVersions.length > 20) {
|
|
3131
|
+
console.log(`... and ${remoteVersions.length - 20} more versions`);
|
|
3132
|
+
}
|
|
3133
|
+
console.log("");
|
|
3134
|
+
console.log(`Installed: ${installedVersion}`);
|
|
3135
|
+
if (pinnedVersion) {
|
|
3136
|
+
console.log(`Pinned: ${pinnedVersion}`);
|
|
3137
|
+
} else {
|
|
3138
|
+
console.log("No version pinned (using latest)");
|
|
3139
|
+
}
|
|
3140
|
+
}));
|
|
3141
|
+
cmd.command("pin [version]").description("Pin Claude Code to a specific version (omit or --clear to unpin)").option("--clear", "Remove the version pin").action(safeAction(async (version2, opts) => {
|
|
3142
|
+
if (opts.clear || !version2) {
|
|
3143
|
+
setPinnedVersion(void 0);
|
|
3144
|
+
console.log("Version pin cleared. cc-hub will use the latest available Claude Code version.");
|
|
3145
|
+
return;
|
|
3146
|
+
}
|
|
3147
|
+
if (!/^\d+\.\d+\.\d+$/.test(version2)) {
|
|
3148
|
+
console.error(`Invalid version format: ${version2}. Expected format: x.y.z`);
|
|
3149
|
+
process.exit(1);
|
|
3150
|
+
}
|
|
3151
|
+
let localAvailable = false;
|
|
3152
|
+
if (process.platform === "darwin") {
|
|
3153
|
+
const desktopApp2 = new MacOSDesktopApp();
|
|
3154
|
+
const supportDir = desktopApp2.getSupportDir();
|
|
3155
|
+
if (supportDir) {
|
|
3156
|
+
const claudeCodeDir = path10.join(supportDir, "claude-code");
|
|
3157
|
+
if (fs9.existsSync(claudeCodeDir)) {
|
|
3158
|
+
const versions = fs9.readdirSync(claudeCodeDir).filter(
|
|
3159
|
+
(d) => fs9.existsSync(path10.join(claudeCodeDir, d, "claude.app", "Contents", "MacOS", "claude"))
|
|
3160
|
+
);
|
|
3161
|
+
localAvailable = versions.includes(version2);
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
setPinnedVersion(version2);
|
|
3166
|
+
console.log(`Pinned Claude Code version: ${version2}`);
|
|
3167
|
+
if (process.platform === "darwin" && !localAvailable) {
|
|
3168
|
+
console.warn(`Warning: version ${version2} is not installed in the desktop app. The pin will take effect once that version is available, or you can install it via:`);
|
|
3169
|
+
console.warn(` npm install -g @anthropic-ai/claude-code@${version2}`);
|
|
3170
|
+
} else if (process.platform !== "darwin") {
|
|
3171
|
+
console.log(`Note: on ${process.platform}, ensure the global install matches the pinned version:`);
|
|
3172
|
+
console.log(` npm install -g @anthropic-ai/claude-code@${version2}`);
|
|
3173
|
+
}
|
|
3174
|
+
}));
|
|
3175
|
+
return cmd;
|
|
2942
3176
|
}
|
|
2943
3177
|
|
|
2944
3178
|
// src/index.ts
|
|
@@ -2948,7 +3182,7 @@ ensureSettingsFile();
|
|
|
2948
3182
|
var settings = readJson(SETTINGS_FILE);
|
|
2949
3183
|
setLogLevel(settings._cc_hub_logLevel || "INFO");
|
|
2950
3184
|
installGlobalExceptionHandlers();
|
|
2951
|
-
var program = new
|
|
3185
|
+
var program = new Command9();
|
|
2952
3186
|
program.name("cc-hub").description("Manage Claude CLI profiles, hooks, and sessions").version(version);
|
|
2953
3187
|
program.addCommand(profileCommand());
|
|
2954
3188
|
program.addCommand(useCommand());
|
|
@@ -2959,6 +3193,7 @@ program.addCommand(completionCommand());
|
|
|
2959
3193
|
program.addCommand(providerCommand());
|
|
2960
3194
|
program.addCommand(proxyCommand());
|
|
2961
3195
|
program.addCommand(cacheCommand());
|
|
3196
|
+
program.addCommand(claudeVersionCommand());
|
|
2962
3197
|
try {
|
|
2963
3198
|
program.parse();
|
|
2964
3199
|
} catch (err) {
|