cc-hub-cli 1.1.13 → 1.1.14
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 +74 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -923,6 +923,9 @@ function fixJsonFile(filePath, fallback = {}) {
|
|
|
923
923
|
}
|
|
924
924
|
}
|
|
925
925
|
|
|
926
|
+
// src/profiles/commands.ts
|
|
927
|
+
import path5 from "path";
|
|
928
|
+
|
|
926
929
|
// src/profiles/runner.ts
|
|
927
930
|
import { spawnSync as spawnSync2, spawn } from "child_process";
|
|
928
931
|
var BUILT_IN_DEFAULT = "__builtin__";
|
|
@@ -1298,6 +1301,48 @@ function profileCommand() {
|
|
|
1298
1301
|
debug(`profile sync: wrote ${PROFILES_FILE}`);
|
|
1299
1302
|
console.log(`Synced ${names.length} profile(s) to the desktop app.`);
|
|
1300
1303
|
}));
|
|
1304
|
+
profile.command("export").description("Export a profile to a settings file").argument("<name>", "Profile name").action(safeAction((name) => {
|
|
1305
|
+
ensureProfilesFile();
|
|
1306
|
+
const data = readJson(PROFILES_FILE);
|
|
1307
|
+
const p = data.profiles[name];
|
|
1308
|
+
if (!p) {
|
|
1309
|
+
throw new Error(`Profile '${name}' not found.`);
|
|
1310
|
+
}
|
|
1311
|
+
ensureSettingsFile();
|
|
1312
|
+
const settings2 = readJson(SETTINGS_FILE);
|
|
1313
|
+
const exported = Object.fromEntries(
|
|
1314
|
+
Object.entries(settings2).filter(([key]) => !key.startsWith("_"))
|
|
1315
|
+
);
|
|
1316
|
+
const env = {
|
|
1317
|
+
...typeof exported.env === "object" && exported.env !== null ? exported.env : {}
|
|
1318
|
+
};
|
|
1319
|
+
if (p.token) env.ANTHROPIC_AUTH_TOKEN = p.token;
|
|
1320
|
+
if (p.url) env.ANTHROPIC_BASE_URL = p.url;
|
|
1321
|
+
const models = p.models || (p.model ? [p.model] : []);
|
|
1322
|
+
if (models.length > 0) {
|
|
1323
|
+
if (models[0]) {
|
|
1324
|
+
env.ANTHROPIC_DEFAULT_SONNET_MODEL = models[0];
|
|
1325
|
+
env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME = models[0];
|
|
1326
|
+
env.ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION = `Custom: ${models[0]}`;
|
|
1327
|
+
}
|
|
1328
|
+
if (models[1]) {
|
|
1329
|
+
env.ANTHROPIC_DEFAULT_OPUS_MODEL = models[1];
|
|
1330
|
+
env.ANTHROPIC_DEFAULT_OPUS_MODEL_NAME = models[1];
|
|
1331
|
+
env.ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION = `Custom: ${models[1]}`;
|
|
1332
|
+
}
|
|
1333
|
+
if (models[2]) {
|
|
1334
|
+
env.ANTHROPIC_DEFAULT_HAIKU_MODEL = models[2];
|
|
1335
|
+
env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME = models[2];
|
|
1336
|
+
env.ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION = `Custom: ${models[2]}`;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "1";
|
|
1340
|
+
env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
|
1341
|
+
exported.env = env;
|
|
1342
|
+
const exportPath = path5.join(CLAUDE_DIR, `settings.${name}.json`);
|
|
1343
|
+
writeJson(exportPath, exported);
|
|
1344
|
+
console.log(`Profile '${name}' exported to ${exportPath}`);
|
|
1345
|
+
}));
|
|
1301
1346
|
return profile;
|
|
1302
1347
|
}
|
|
1303
1348
|
function useCommand() {
|
|
@@ -1577,12 +1622,12 @@ function decodePath2(encoded) {
|
|
|
1577
1622
|
|
|
1578
1623
|
// src/sessions/stats.ts
|
|
1579
1624
|
import fs5 from "fs";
|
|
1580
|
-
import
|
|
1625
|
+
import path6 from "path";
|
|
1581
1626
|
function getDirSize(dir) {
|
|
1582
1627
|
let total = 0;
|
|
1583
1628
|
try {
|
|
1584
1629
|
for (const entry of fs5.readdirSync(dir, { withFileTypes: true })) {
|
|
1585
|
-
const fullPath =
|
|
1630
|
+
const fullPath = path6.join(dir, entry.name);
|
|
1586
1631
|
if (entry.isDirectory()) {
|
|
1587
1632
|
total += getDirSize(fullPath);
|
|
1588
1633
|
} else {
|
|
@@ -1606,7 +1651,7 @@ function formatSize(bytes) {
|
|
|
1606
1651
|
|
|
1607
1652
|
// src/sessions/utils.ts
|
|
1608
1653
|
import fs6 from "fs";
|
|
1609
|
-
import
|
|
1654
|
+
import path7 from "path";
|
|
1610
1655
|
function formatTimestamp(ms) {
|
|
1611
1656
|
const d = new Date(ms);
|
|
1612
1657
|
const pad = (n) => String(n).padStart(2, "0");
|
|
@@ -1615,7 +1660,7 @@ function formatTimestamp(ms) {
|
|
|
1615
1660
|
function findProjectDir(query) {
|
|
1616
1661
|
debug(`sessions: findProjectDir query="${query}"`);
|
|
1617
1662
|
const encoded = encodePath(query);
|
|
1618
|
-
if (fs6.existsSync(
|
|
1663
|
+
if (fs6.existsSync(path7.join(PROJECTS_DIR, encoded))) {
|
|
1619
1664
|
debug(`sessions: findProjectDir exact match ${encoded}`);
|
|
1620
1665
|
return encoded;
|
|
1621
1666
|
}
|
|
@@ -1693,10 +1738,10 @@ function findSessionFile(sessionQuery, projectQuery) {
|
|
|
1693
1738
|
if (!projDir) {
|
|
1694
1739
|
throw new Error(`No project matched: ${projectQuery}`);
|
|
1695
1740
|
}
|
|
1696
|
-
searchDirs.push(
|
|
1741
|
+
searchDirs.push(path7.join(PROJECTS_DIR, projDir));
|
|
1697
1742
|
} else {
|
|
1698
1743
|
try {
|
|
1699
|
-
searchDirs = fs6.readdirSync(PROJECTS_DIR).map((d) =>
|
|
1744
|
+
searchDirs = fs6.readdirSync(PROJECTS_DIR).map((d) => path7.join(PROJECTS_DIR, d));
|
|
1700
1745
|
} catch {
|
|
1701
1746
|
throw new Error(`No projects directory found at ${PROJECTS_DIR}`);
|
|
1702
1747
|
}
|
|
@@ -1712,7 +1757,7 @@ function findSessionFile(sessionQuery, projectQuery) {
|
|
|
1712
1757
|
for (const file of files) {
|
|
1713
1758
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
1714
1759
|
if (sessionId.toLowerCase().includes(sessionQuery.toLowerCase())) {
|
|
1715
|
-
matches.push({ filePath:
|
|
1760
|
+
matches.push({ filePath: path7.join(dir, file), project: path7.basename(dir) });
|
|
1716
1761
|
}
|
|
1717
1762
|
}
|
|
1718
1763
|
}
|
|
@@ -1720,7 +1765,7 @@ function findSessionFile(sessionQuery, projectQuery) {
|
|
|
1720
1765
|
return null;
|
|
1721
1766
|
}
|
|
1722
1767
|
if (matches.length > 1) {
|
|
1723
|
-
const lines = matches.map((m) => ` ${
|
|
1768
|
+
const lines = matches.map((m) => ` ${path7.basename(m.filePath)} in ${decodePath(m.project)}`).join("\n");
|
|
1724
1769
|
throw new Error(`Multiple sessions matched '${sessionQuery}':
|
|
1725
1770
|
${lines}
|
|
1726
1771
|
Use --project to disambiguate.`);
|
|
@@ -1731,7 +1776,7 @@ Use --project to disambiguate.`);
|
|
|
1731
1776
|
// src/sessions/commands.ts
|
|
1732
1777
|
import { Command as Command4 } from "commander";
|
|
1733
1778
|
import fs7 from "fs";
|
|
1734
|
-
import
|
|
1779
|
+
import path8 from "path";
|
|
1735
1780
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
1736
1781
|
function sessionCommand() {
|
|
1737
1782
|
const session = new Command4("session").description("Manage Claude Code sessions");
|
|
@@ -1748,14 +1793,14 @@ function sessionCommand() {
|
|
|
1748
1793
|
return;
|
|
1749
1794
|
}
|
|
1750
1795
|
dirs.sort((a, b) => {
|
|
1751
|
-
const statA = fs7.statSync(
|
|
1752
|
-
const statB = fs7.statSync(
|
|
1796
|
+
const statA = fs7.statSync(path8.join(PROJECTS_DIR, a));
|
|
1797
|
+
const statB = fs7.statSync(path8.join(PROJECTS_DIR, b));
|
|
1753
1798
|
return statB.mtimeMs - statA.mtimeMs;
|
|
1754
1799
|
});
|
|
1755
1800
|
let count = 0;
|
|
1756
1801
|
for (const projDir of dirs) {
|
|
1757
1802
|
if (count >= limit) break;
|
|
1758
|
-
const fullPath =
|
|
1803
|
+
const fullPath = path8.join(PROJECTS_DIR, projDir);
|
|
1759
1804
|
let nSessions = 0;
|
|
1760
1805
|
try {
|
|
1761
1806
|
nSessions = fs7.readdirSync(fullPath).filter((f) => f.endsWith(".jsonl")).length;
|
|
@@ -1779,7 +1824,7 @@ function sessionCommand() {
|
|
|
1779
1824
|
if (!projDir) {
|
|
1780
1825
|
throw new Error(`No project matched: ${project}`);
|
|
1781
1826
|
}
|
|
1782
|
-
const fullPath =
|
|
1827
|
+
const fullPath = path8.join(PROJECTS_DIR, projDir);
|
|
1783
1828
|
console.log(`Project: ${decodePath2(projDir)}`);
|
|
1784
1829
|
console.log(`Dir: ${fullPath}`);
|
|
1785
1830
|
console.log("");
|
|
@@ -1793,7 +1838,7 @@ function sessionCommand() {
|
|
|
1793
1838
|
return;
|
|
1794
1839
|
}
|
|
1795
1840
|
for (const file of files) {
|
|
1796
|
-
const filePath =
|
|
1841
|
+
const filePath = path8.join(fullPath, file);
|
|
1797
1842
|
const sessionId = file.replace(/\.jsonl$/, "");
|
|
1798
1843
|
let msgCount = 0;
|
|
1799
1844
|
try {
|
|
@@ -1843,7 +1888,7 @@ function sessionCommand() {
|
|
|
1843
1888
|
if (!projDir) {
|
|
1844
1889
|
throw new Error(`No project matched: ${opts.project}`);
|
|
1845
1890
|
}
|
|
1846
|
-
searchRoots = [{ root:
|
|
1891
|
+
searchRoots = [{ root: path8.join(PROJECTS_DIR, projDir), label: "" }];
|
|
1847
1892
|
}
|
|
1848
1893
|
const limit = parseInt(opts.limit, 10);
|
|
1849
1894
|
let count = 0;
|
|
@@ -1857,7 +1902,7 @@ function sessionCommand() {
|
|
|
1857
1902
|
}
|
|
1858
1903
|
for (const entry of entries) {
|
|
1859
1904
|
if (count >= limit) break;
|
|
1860
|
-
const fullPath =
|
|
1905
|
+
const fullPath = path8.join(dir, entry.name);
|
|
1861
1906
|
if (entry.isDirectory()) {
|
|
1862
1907
|
searchDir(fullPath, label, baseDir);
|
|
1863
1908
|
} else if (entry.name.endsWith(".jsonl")) {
|
|
@@ -1871,9 +1916,9 @@ function sessionCommand() {
|
|
|
1871
1916
|
const match = opts.ignoreCase ? line.toLowerCase().includes(query.toLowerCase()) : line.includes(query);
|
|
1872
1917
|
if (match) {
|
|
1873
1918
|
if (!found) {
|
|
1874
|
-
const relPath =
|
|
1875
|
-
const projEnc = relPath.split(
|
|
1876
|
-
const sessionId =
|
|
1919
|
+
const relPath = path8.relative(baseDir, fullPath);
|
|
1920
|
+
const projEnc = relPath.split(path8.sep)[0];
|
|
1921
|
+
const sessionId = path8.basename(fullPath, ".jsonl");
|
|
1877
1922
|
const projName = label ? projEnc : decodePath2(projEnc);
|
|
1878
1923
|
console.log(`${label}[${projName} \u2192 ${sessionId}]`);
|
|
1879
1924
|
found = true;
|
|
@@ -1925,7 +1970,7 @@ function sessionCommand() {
|
|
|
1925
1970
|
console.log(fmt("---", "----------", "-------", "---", ""));
|
|
1926
1971
|
for (const file of files) {
|
|
1927
1972
|
try {
|
|
1928
|
-
const data = JSON.parse(fs7.readFileSync(
|
|
1973
|
+
const data = JSON.parse(fs7.readFileSync(path8.join(SESSIONS_DIR, file), "utf-8"));
|
|
1929
1974
|
const pid = String(data.pid || "?");
|
|
1930
1975
|
const sessionId = data.sessionId || "?";
|
|
1931
1976
|
const cwd = data.cwd || "?";
|
|
@@ -1953,7 +1998,7 @@ function sessionCommand() {
|
|
|
1953
1998
|
const results = [];
|
|
1954
1999
|
try {
|
|
1955
2000
|
for (const entry of fs7.readdirSync(dir, { withFileTypes: true })) {
|
|
1956
|
-
const fullPath =
|
|
2001
|
+
const fullPath = path8.join(dir, entry.name);
|
|
1957
2002
|
if (entry.isDirectory()) results.push(...walk(fullPath));
|
|
1958
2003
|
else if (entry.name.endsWith(".jsonl")) results.push(fullPath);
|
|
1959
2004
|
}
|
|
@@ -2030,7 +2075,7 @@ function sessionCommand() {
|
|
|
2030
2075
|
return;
|
|
2031
2076
|
}
|
|
2032
2077
|
for (const entry of entries) {
|
|
2033
|
-
const fullPath =
|
|
2078
|
+
const fullPath = path8.join(dir, entry.name);
|
|
2034
2079
|
if (entry.isDirectory()) {
|
|
2035
2080
|
walk(fullPath);
|
|
2036
2081
|
} else if (entry.name.endsWith(".jsonl")) {
|
|
@@ -2136,6 +2181,7 @@ _cc-hub() {
|
|
|
2136
2181
|
'rename:Rename a profile'
|
|
2137
2182
|
'default:Set the default profile'
|
|
2138
2183
|
'sync:Synchronize all CLI profiles to the desktop app'
|
|
2184
|
+
'export:Export a profile to a settings file'
|
|
2139
2185
|
)
|
|
2140
2186
|
|
|
2141
2187
|
local -a hooks_subcmds
|
|
@@ -2190,7 +2236,7 @@ _cc-hub() {
|
|
|
2190
2236
|
profile)
|
|
2191
2237
|
if (( CURRENT == 2 )); then
|
|
2192
2238
|
_describe -t profile-subcmds 'profile subcommand' profile_subcmds
|
|
2193
|
-
elif [[ $words[2] == "view" || $words[2] == "remove" ]]; then
|
|
2239
|
+
elif [[ $words[2] == "view" || $words[2] == "remove" || $words[2] == "export" ]]; then
|
|
2194
2240
|
_cc_hub_profiles
|
|
2195
2241
|
elif [[ $words[2] == "default" ]]; then
|
|
2196
2242
|
_arguments -C -S '--built-in[Use official Anthropic models as default]' '*:profile:_cc_hub_profiles'
|
|
@@ -2299,7 +2345,7 @@ _cc-hub() {
|
|
|
2299
2345
|
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
2300
2346
|
commands="profile use run hook session provider cache completion help"
|
|
2301
2347
|
|
|
2302
|
-
local profile_subcmds="add update list view remove rename default sync"
|
|
2348
|
+
local profile_subcmds="add update list view remove rename default sync export"
|
|
2303
2349
|
local provider_subcmds="list"
|
|
2304
2350
|
local provider_types="anthropic openai"
|
|
2305
2351
|
local hooks_subcmds="list add remove enable disable"
|
|
@@ -2318,7 +2364,7 @@ _cc-hub() {
|
|
|
2318
2364
|
profile)
|
|
2319
2365
|
if [[ \${COMP_CWORD} -eq 2 ]]; then
|
|
2320
2366
|
COMPREPLY=($(compgen -W "$profile_subcmds" -- "$cur"))
|
|
2321
|
-
elif [[ "$prev" == "view" || "$prev" == "remove" ]]; then
|
|
2367
|
+
elif [[ "$prev" == "view" || "$prev" == "remove" || "$prev" == "export" ]]; then
|
|
2322
2368
|
_cc-hub_profiles
|
|
2323
2369
|
elif [[ "$prev" == "default" ]]; then
|
|
2324
2370
|
COMPREPLY=($(compgen -W "--built-in $(_cc-hub_profile_names)" -- "$cur"))
|
|
@@ -2399,7 +2445,7 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
|
|
|
2399
2445
|
'help:Display help for a command'
|
|
2400
2446
|
)
|
|
2401
2447
|
|
|
2402
|
-
$profileSubcmds = @('add', 'update', 'list', 'view', 'remove', 'rename', 'default', 'sync')
|
|
2448
|
+
$profileSubcmds = @('add', 'update', 'list', 'view', 'remove', 'rename', 'default', 'sync', 'export')
|
|
2403
2449
|
$hookSubcmds = @('list', 'add', 'remove', 'enable', 'disable')
|
|
2404
2450
|
$sessionSubcmds = @('list', 'show', 'search', 'ps', 'stats', 'clean', 'troubleshoot')
|
|
2405
2451
|
$cacheSubcmds = @('restore')
|
|
@@ -2533,7 +2579,7 @@ function proxyCommand() {
|
|
|
2533
2579
|
// src/cache/commands.ts
|
|
2534
2580
|
import { Command as Command7 } from "commander";
|
|
2535
2581
|
import fs8 from "fs";
|
|
2536
|
-
import
|
|
2582
|
+
import path9 from "path";
|
|
2537
2583
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
2538
2584
|
import { createInterface } from "readline/promises";
|
|
2539
2585
|
async function confirmPrompt(message) {
|
|
@@ -2608,7 +2654,7 @@ function killProcesses(pids) {
|
|
|
2608
2654
|
function cacheCommand() {
|
|
2609
2655
|
const cache = new Command7("cache").description("Manage Claude Code cache and backup files");
|
|
2610
2656
|
cache.command("restore").description("Restore ~/.claude/.claude.json.backup to ~/.claude.json").action(safeAction(async () => {
|
|
2611
|
-
const backupPath =
|
|
2657
|
+
const backupPath = path9.join(CLAUDE_DIR, ".claude.json.backup");
|
|
2612
2658
|
const targetPath = CLAUDE_JSON;
|
|
2613
2659
|
if (!fs8.existsSync(backupPath)) {
|
|
2614
2660
|
throw new Error(`Backup not found: ${backupPath}`);
|