cc-hub-cli 1.1.6 → 1.1.7

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.
Files changed (2) hide show
  1. package/dist/index.js +197 -35
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -254,6 +254,14 @@ var NoOpDesktopApp = class {
254
254
  import fs3 from "fs";
255
255
  import path3 from "path";
256
256
  import { randomUUID } from "crypto";
257
+ var ANTHROPIC_ALIASES = ["claude-sonnet-4-5", "claude-opus-4-7", "claude-haiku-4-5-20251001"];
258
+ function isAnthropicModel(model) {
259
+ const anthropicAliases = ["opus", "sonnet", "haiku", "best", "default", "opusplan", "opus[1m]", "sonnet[1m]"];
260
+ const lower = model.toLowerCase();
261
+ if (anthropicAliases.includes(lower)) return true;
262
+ if (lower.startsWith("claude-")) return true;
263
+ return false;
264
+ }
257
265
  function toDesktopProfile(p) {
258
266
  const models = p.models || (p.model ? [p.model] : []);
259
267
  const isAnthropic = p.provider === "anthropic" || !p.provider && !p.url;
@@ -263,13 +271,24 @@ function toDesktopProfile(p) {
263
271
  inferenceModels: models.map((m) => ({ name: m, supports1m: true }))
264
272
  };
265
273
  }
266
- return {
274
+ const mappings = [];
275
+ const mappedModels = models.map((m, index) => {
276
+ if (isAnthropicModel(m)) return m;
277
+ const alias = ANTHROPIC_ALIASES[Math.min(index, ANTHROPIC_ALIASES.length - 1)];
278
+ mappings.push({ alias, actual: m });
279
+ return alias;
280
+ });
281
+ const result = {
267
282
  inferenceProvider: "gateway",
268
283
  inferenceGatewayBaseUrl: p.url || void 0,
269
284
  inferenceGatewayApiKey: p.token || void 0,
270
285
  inferenceGatewayAuthScheme: "bearer",
271
- inferenceModels: models.map((m) => ({ name: m, supports1m: true }))
286
+ inferenceModels: mappedModels.map((m) => ({ name: m, supports1m: true }))
272
287
  };
288
+ if (mappings.length > 0) {
289
+ result.inferenceModelMappings = mappings;
290
+ }
291
+ return result;
273
292
  }
274
293
  var DesktopProfileSyncer = class {
275
294
  constructor(app) {
@@ -471,6 +490,7 @@ function fixJsonFile(filePath, fallback = {}) {
471
490
  const raw = fs4.readFileSync(filePath, "utf-8");
472
491
  try {
473
492
  JSON.parse(raw);
493
+ fs4.mkdirSync(CLAUDE_DIR, { recursive: true });
474
494
  fs4.copyFileSync(filePath, backupPath);
475
495
  return;
476
496
  } catch {
@@ -500,14 +520,24 @@ function fixJsonFile(filePath, fallback = {}) {
500
520
  warn(`Fixed invalid JSON in ${path4.basename(filePath)}.`);
501
521
  console.error(`Fixed invalid JSON in ${path4.basename(filePath)}.`);
502
522
  } catch {
523
+ let restored = false;
503
524
  if (fs4.existsSync(backupPath)) {
504
- fs4.copyFileSync(backupPath, filePath);
505
- warn(`Restored ${path4.basename(filePath)} from backup.`);
506
- console.error(`Restored ${path4.basename(filePath)} from backup.`);
507
- } else {
525
+ try {
526
+ const backupRaw = fs4.readFileSync(backupPath, "utf-8");
527
+ JSON.parse(backupRaw);
528
+ fs4.copyFileSync(backupPath, filePath);
529
+ restored = true;
530
+ warn(`Restored ${path4.basename(filePath)} from backup.`);
531
+ console.error(`Restored ${path4.basename(filePath)} from backup.`);
532
+ } catch {
533
+ error(`Backup ${path4.basename(backupPath)} is also corrupt; using fallback.`);
534
+ console.error(`Backup ${path4.basename(backupPath)} is also corrupt; using fallback.`);
535
+ }
536
+ }
537
+ if (!restored) {
508
538
  writeJson(filePath, fallback);
509
- error(`Could not fix ${path4.basename(filePath)}, no backup found, reset to default.`);
510
- console.error(`Could not fix ${path4.basename(filePath)}, no backup found, reset to default.`);
539
+ error(`Could not fix ${path4.basename(filePath)}, no valid backup found, reset to default.`);
540
+ console.error(`Could not fix ${path4.basename(filePath)}, no valid backup found, reset to default.`);
511
541
  }
512
542
  }
513
543
  }
@@ -518,6 +548,9 @@ import { spawnSync as spawnSync2, spawn } from "child_process";
518
548
  // src/provider/index.ts
519
549
  import { Command } from "commander";
520
550
 
551
+ // src/provider/server.ts
552
+ import http from "http";
553
+
521
554
  // src/provider/transform.ts
522
555
  function sanitizeToolId(id) {
523
556
  let sanitized = id.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -675,7 +708,7 @@ function transformOpenAIResponseToAnthropic(openaiResponse, originalModel) {
675
708
  id: openaiResponse.id ?? `msg_${Date.now()}`,
676
709
  type: "message",
677
710
  role: "assistant",
678
- model: openaiResponse.model ?? originalModel,
711
+ model: originalModel,
679
712
  content,
680
713
  stop_reason: finishMap[choice.finish_reason] ?? "end_turn",
681
714
  stop_sequence: null,
@@ -743,8 +776,7 @@ data: ${JSON.stringify(data)}
743
776
  }
744
777
 
745
778
  // src/provider/server.ts
746
- import http from "http";
747
- async function startOpenAIProxy(targetUrl, apiKey, model, models = []) {
779
+ async function startOpenAIProxy(targetUrl, apiKey, model, models = [], modelMappings = {}) {
748
780
  const base = targetUrl.replace(/\/+$/, "");
749
781
  const server = http.createServer(async (req, res) => {
750
782
  debug(`Proxy request: ${req.method} ${req.url}`);
@@ -770,7 +802,9 @@ async function startOpenAIProxy(targetUrl, apiKey, model, models = []) {
770
802
  return;
771
803
  }
772
804
  const isStream = !!parsed.stream;
773
- const openaiBody = transformAnthropicToOpenAI({ ...parsed, stream: false });
805
+ const requestModel = parsed.model ?? model;
806
+ const actualModel = modelMappings[requestModel] || requestModel;
807
+ const openaiBody = transformAnthropicToOpenAI({ ...parsed, model: actualModel, stream: false });
774
808
  if (isStream) {
775
809
  res.writeHead(200, {
776
810
  "Content-Type": "text/event-stream",
@@ -875,6 +909,17 @@ var PROVIDERS = [
875
909
  description: "Embedded proxy \u2014 translates Anthropic requests to OpenAI Chat Completions format"
876
910
  }
877
911
  ];
912
+ var ANTHROPIC_ALIASES2 = ["claude-sonnet-4-5", "claude-opus-4-7", "claude-haiku-4-5-20251001"];
913
+ function isAnthropicModel2(model) {
914
+ const anthropicAliases = ["opus", "sonnet", "haiku", "best", "default", "opusplan", "opus[1m]", "sonnet[1m]"];
915
+ const lower = model.toLowerCase();
916
+ if (anthropicAliases.includes(lower)) return true;
917
+ if (lower.startsWith("claude-")) return true;
918
+ return false;
919
+ }
920
+ function collect(value, previous) {
921
+ return previous.concat([value]);
922
+ }
878
923
  function providerCommand() {
879
924
  const cmd = new Command("provider").description("Manage provider types");
880
925
  cmd.command("list").description("List available provider types").action(safeAction(() => {
@@ -887,8 +932,51 @@ function providerCommand() {
887
932
  }));
888
933
  return cmd;
889
934
  }
935
+ function proxyCommand() {
936
+ return new Command("proxy").description("Start a standalone OpenAI proxy for the desktop app").option("--profile <name>", "Use configuration from a saved profile").option("-u, --url <url>", "Upstream base URL (e.g., https://api.openai.com)").option("-k, --api-key <key>", "Upstream API key").option("-m, --model <model>", "Default model", "gpt-4o").option("--mapping <mapping>", "Model alias mapping (format: alias:actual, can be used multiple times)", collect, []).action(safeAction(async (opts) => {
937
+ let targetUrl = opts.url || "https://api.openai.com";
938
+ let apiKey = opts.apiKey || "";
939
+ let defaultModel = opts.model || "gpt-4o";
940
+ let models = [];
941
+ const modelMappings = {};
942
+ if (opts.profile) {
943
+ ensureProfilesFile();
944
+ const data = readJson(PROFILES_FILE);
945
+ const p = data.profiles[opts.profile];
946
+ if (!p) {
947
+ throw new Error(`Profile '${opts.profile}' not found.`);
948
+ }
949
+ targetUrl = p.url || targetUrl;
950
+ apiKey = p.token || apiKey;
951
+ models = p.models || (p.model ? [p.model] : []);
952
+ defaultModel = models[0] || defaultModel;
953
+ models.forEach((m, i) => {
954
+ if (!isAnthropicModel2(m)) {
955
+ const alias = ANTHROPIC_ALIASES2[Math.min(i, ANTHROPIC_ALIASES2.length - 1)];
956
+ modelMappings[alias] = m;
957
+ }
958
+ });
959
+ } else {
960
+ for (const m of opts.mapping) {
961
+ const [alias, actual] = m.split(":");
962
+ if (alias && actual) {
963
+ modelMappings[alias] = actual;
964
+ }
965
+ }
966
+ models = [defaultModel];
967
+ }
968
+ const { baseUrl, stop } = await startOpenAIProxy(targetUrl, apiKey, defaultModel, models, modelMappings);
969
+ console.log(`Proxy running at ${baseUrl}`);
970
+ console.log("Press Ctrl+C to stop");
971
+ process.on("SIGINT", () => {
972
+ stop();
973
+ process.exit(0);
974
+ });
975
+ }));
976
+ }
890
977
 
891
978
  // src/profiles/runner.ts
979
+ var BUILT_IN_DEFAULT = "__builtin__";
892
980
  function resolveClaudeBinary() {
893
981
  return createBinaryResolver().resolve();
894
982
  }
@@ -962,7 +1050,8 @@ function execClaude(profileName, p, extraArgs) {
962
1050
  p.url || "https://api.openai.com",
963
1051
  p.token || "",
964
1052
  firstModel || "gpt-4o",
965
- allModels
1053
+ allModels,
1054
+ {}
966
1055
  ).then(({ baseUrl, stop }) => {
967
1056
  env.ANTHROPIC_BASE_URL = baseUrl;
968
1057
  debug(`execClaude: proxy running at ${baseUrl}`);
@@ -985,6 +1074,22 @@ function execClaude(profileName, p, extraArgs) {
985
1074
  process.exit(result.status ?? 1);
986
1075
  }
987
1076
  }
1077
+ function execClaudeBuiltIn(extraArgs) {
1078
+ const binary = resolveClaudeBinary();
1079
+ const cmd = [binary, ...extraArgs];
1080
+ const env = {
1081
+ ...process.env,
1082
+ CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "1",
1083
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1"
1084
+ };
1085
+ info(`Launching Claude with built-in official models: binary=${binary}`);
1086
+ const result = spawnSync2(cmd[0], cmd.slice(1), {
1087
+ stdio: "inherit",
1088
+ env,
1089
+ shell: process.platform === "win32"
1090
+ });
1091
+ process.exit(result.status ?? 1);
1092
+ }
988
1093
 
989
1094
  // src/profiles/commands.ts
990
1095
  function maskToken(token) {
@@ -994,10 +1099,10 @@ function maskToken(token) {
994
1099
  }
995
1100
  function formatModels(p) {
996
1101
  if (p.models && p.models.length > 0) {
997
- const nonAnthropicModels = p.models.filter((m) => !isAnthropicModel(m));
1102
+ const nonAnthropicModels = p.models.filter((m) => !isAnthropicModel3(m));
998
1103
  const parts = [];
999
1104
  p.models.forEach((m, i) => {
1000
- if (!isAnthropicModel(m)) {
1105
+ if (!isAnthropicModel3(m)) {
1001
1106
  const aliasIndex = nonAnthropicModels.indexOf(m);
1002
1107
  if (aliasIndex === 0) parts.push(`${m} (sonnet)`);
1003
1108
  else if (aliasIndex === 1) parts.push(`${m} (opus)`);
@@ -1015,20 +1120,20 @@ function formatModels(p) {
1015
1120
  }
1016
1121
  return p.model || "(unset)";
1017
1122
  }
1018
- function isAnthropicModel(model) {
1123
+ function isAnthropicModel3(model) {
1019
1124
  const anthropicAliases = ["opus", "sonnet", "haiku", "best", "default", "opusplan", "opus[1m]", "sonnet[1m]"];
1020
1125
  const lower = model.toLowerCase();
1021
1126
  if (anthropicAliases.includes(lower)) return true;
1022
1127
  if (lower.startsWith("claude-")) return true;
1023
1128
  return false;
1024
1129
  }
1025
- function collect(value, previous) {
1130
+ function collect2(value, previous) {
1026
1131
  return previous.concat([value]);
1027
1132
  }
1028
1133
  function profileCommand() {
1029
1134
  const profile = new Command2("profile").description("Manage Claude CLI profiles");
1030
1135
  const syncer = createProfileSyncer();
1031
- profile.command("add").description("Add or update a profile").argument("<name>", "Profile name").option("-m, --model <model>", "Model ID - can be used multiple times (max 3)", collect, []).option("-t, --token <token>", "API key / token").option("-u, --url <url>", "Base URL").option("-p, --provider <provider>", "Provider type: anthropic (default) or openai").action(safeAction((name, opts) => {
1136
+ profile.command("add").description("Add or update a profile").argument("<name>", "Profile name").option("-m, --model <model>", "Model ID - can be used multiple times (max 3)", collect2, []).option("-t, --token <token>", "API key / token").option("-u, --url <url>", "Base URL").option("-p, --provider <provider>", "Provider type: anthropic (default) or openai").action(safeAction((name, opts) => {
1032
1137
  const models = opts.model && opts.model.length > 0 ? opts.model : void 0;
1033
1138
  if (models && models.length > 3) {
1034
1139
  throw new Error("Error: A profile can have at most 3 models.");
@@ -1050,7 +1155,7 @@ function profileCommand() {
1050
1155
  debug(`profile add: wrote ${PROFILES_FILE}`);
1051
1156
  console.log(`Profile '${name}' saved.`);
1052
1157
  }));
1053
- profile.command("update").description("Update fields of an existing profile").argument("<name>", "Profile name (must already exist)").option("-m, --model <model>", "Model ID - can be used multiple times", collect, []).option("-d, --delete-model <model>", "Remove model ID - can be used multiple times", collect, []).option("-t, --token <token>", "API key / token").option("-u, --url <url>", "Base URL").option("-p, --provider <provider>", "Provider type").action(safeAction((name, opts) => {
1158
+ profile.command("update").description("Update fields of an existing profile").argument("<name>", "Profile name (must already exist)").option("-m, --model <model>", "Model ID - can be used multiple times", collect2, []).option("-d, --delete-model <model>", "Remove model ID - can be used multiple times", collect2, []).option("-t, --token <token>", "API key / token").option("-u, --url <url>", "Base URL").option("-p, --provider <provider>", "Provider type").action(safeAction((name, opts) => {
1054
1159
  ensureProfilesFile();
1055
1160
  const data = readJson(PROFILES_FILE);
1056
1161
  if (!data.profiles[name]) {
@@ -1142,6 +1247,9 @@ function profileCommand() {
1142
1247
  profile.command("view").description("View full details of a profile (token unmasked)").argument("<name>", "Profile name").option("-j, --json", "Output as JSON").action(safeAction((name, opts) => {
1143
1248
  ensureProfilesFile();
1144
1249
  const data = readJson(PROFILES_FILE);
1250
+ if (name === BUILT_IN_DEFAULT) {
1251
+ throw new Error(`'${BUILT_IN_DEFAULT}' is not a stored profile. Use 'cc-hub run --built-in' or 'cc-hub use --built-in' for official Anthropic models.`);
1252
+ }
1145
1253
  const p = data.profiles[name];
1146
1254
  if (!p) {
1147
1255
  throw new Error(`Profile '${name}' not found.`);
@@ -1153,10 +1261,10 @@ function profileCommand() {
1153
1261
  console.log(`Name: ${name}`);
1154
1262
  console.log(`Model: ${p.model || "(unset)"}`);
1155
1263
  if (p.models && p.models.length > 0) {
1156
- const nonAnthropicModels = p.models.filter((m) => !isAnthropicModel(m));
1264
+ const nonAnthropicModels = p.models.filter((m) => !isAnthropicModel3(m));
1157
1265
  console.log(`Models:`);
1158
1266
  for (const m of p.models) {
1159
- if (!isAnthropicModel(m)) {
1267
+ if (!isAnthropicModel3(m)) {
1160
1268
  const aliasIndex = nonAnthropicModels.indexOf(m);
1161
1269
  let alias = "";
1162
1270
  if (aliasIndex === 0) alias = " (sonnet)";
@@ -1203,9 +1311,19 @@ function profileCommand() {
1203
1311
  writeJson(PROFILES_FILE, data);
1204
1312
  console.log(`Profile '${oldName}' renamed to '${newName}'.`);
1205
1313
  }));
1206
- profile.command("default").description("Set the default profile").argument("<name>", "Profile name to set as default").action(safeAction((name) => {
1314
+ profile.command("default").description("Set the default profile").option("--built-in", "Use official Anthropic models as default").argument("[name]", "Profile name to set as default (required unless --built-in)").action(safeAction((name, opts) => {
1207
1315
  ensureProfilesFile();
1208
1316
  const data = readJson(PROFILES_FILE);
1317
+ if (opts.builtIn) {
1318
+ data.default = BUILT_IN_DEFAULT;
1319
+ writeJson(PROFILES_FILE, data);
1320
+ debug(`profile default: wrote ${PROFILES_FILE}`);
1321
+ console.log("Default set to built-in official Anthropic models.");
1322
+ return;
1323
+ }
1324
+ if (!name) {
1325
+ throw new Error("Profile name is required. Use --built-in for official Anthropic models.");
1326
+ }
1209
1327
  if (!data.profiles[name]) {
1210
1328
  throw new Error(`Profile '${name}' not found.`);
1211
1329
  }
@@ -1228,6 +1346,7 @@ function profileCommand() {
1228
1346
  return;
1229
1347
  }
1230
1348
  for (const name of names) {
1349
+ if (name === BUILT_IN_DEFAULT) continue;
1231
1350
  const p = data.profiles[name];
1232
1351
  debug(`profile sync: syncing '${name}' to desktop`);
1233
1352
  syncer.sync(name, p);
@@ -1240,9 +1359,19 @@ function profileCommand() {
1240
1359
  }
1241
1360
  function useCommand() {
1242
1361
  const syncer = createProfileSyncer();
1243
- return new Command2("use").description("Set a profile as the default").argument("<name>", "Profile name").action(safeAction((name) => {
1362
+ return new Command2("use").description("Set a profile as the default").option("--built-in", "Use official Anthropic models as default").argument("[name]", "Profile name (required unless --built-in)").action(safeAction((name, opts) => {
1244
1363
  ensureProfilesFile();
1245
1364
  const data = readJson(PROFILES_FILE);
1365
+ if (opts.builtIn) {
1366
+ data.default = BUILT_IN_DEFAULT;
1367
+ writeJson(PROFILES_FILE, data);
1368
+ debug(`use: wrote ${PROFILES_FILE}`);
1369
+ console.log("Default set to built-in official Anthropic models.");
1370
+ return;
1371
+ }
1372
+ if (!name) {
1373
+ throw new Error("Profile name is required. Use --built-in for official Anthropic models.");
1374
+ }
1246
1375
  if (!data.profiles[name]) {
1247
1376
  throw new Error(`Profile '${name}' not found.`);
1248
1377
  }
@@ -1255,10 +1384,14 @@ function useCommand() {
1255
1384
  }));
1256
1385
  }
1257
1386
  function runCommand() {
1258
- return new Command2("run").description("Launch Claude Code using the default or a specified profile").allowUnknownOption().argument("[args...]", "Optional profile name followed by extra arguments").action(safeAction((args) => {
1387
+ return new Command2("run").description("Launch Claude Code using the default or a specified profile").option("--built-in", "Use official Anthropic models (no custom profile)").allowUnknownOption().argument("[args...]", "Optional profile name followed by extra arguments").action(safeAction((args, opts) => {
1259
1388
  fixJsonFile(CLAUDE_JSON);
1260
1389
  ensureProfilesFile();
1261
1390
  const data = readJson(PROFILES_FILE);
1391
+ if (opts.builtIn) {
1392
+ execClaudeBuiltIn(args);
1393
+ return;
1394
+ }
1262
1395
  let profileName = "";
1263
1396
  let claudeArgs;
1264
1397
  if (args.length > 0 && data.profiles[args[0]]) {
@@ -1268,8 +1401,12 @@ function runCommand() {
1268
1401
  profileName = data.default || "";
1269
1402
  claudeArgs = args;
1270
1403
  }
1404
+ if (profileName === BUILT_IN_DEFAULT) {
1405
+ execClaudeBuiltIn(claudeArgs);
1406
+ return;
1407
+ }
1271
1408
  if (!profileName) {
1272
- throw new Error("No default profile set. Use 'cc-hub use <name>' first.");
1409
+ throw new Error("No default profile set. Use 'cc-hub use <name>' or 'cc-hub use --built-in' first.");
1273
1410
  }
1274
1411
  const p = data.profiles[profileName];
1275
1412
  debug(`run: launching claude with profile '${profileName}', args=[${claudeArgs.join(", ")}]`);
@@ -2025,7 +2162,7 @@ _cc-hub() {
2025
2162
  local -a commands
2026
2163
  commands=(
2027
2164
  'profile:Manage Claude CLI profiles'
2028
- 'use:Launch Claude Code with a saved profile'
2165
+ 'use:Set a profile as the default'
2029
2166
  'run:Launch Claude Code using the default or a specified profile'
2030
2167
  'hook:Manage Claude Code hooks in settings.json'
2031
2168
  'session:Manage Claude Code sessions'
@@ -2104,8 +2241,10 @@ _cc-hub() {
2104
2241
  profile)
2105
2242
  if (( CURRENT == 2 )); then
2106
2243
  _describe -t profile-subcmds 'profile subcommand' profile_subcmds
2107
- elif [[ $words[2] == "view" || $words[2] == "remove" || $words[2] == "default" ]]; then
2244
+ elif [[ $words[2] == "view" || $words[2] == "remove" ]]; then
2108
2245
  _cc_hub_profiles
2246
+ elif [[ $words[2] == "default" ]]; then
2247
+ _arguments -C -S '--built-in[Use official Anthropic models as default]' '*:profile:_cc_hub_profiles'
2109
2248
  elif [[ $words[2] == "rename" ]]; then
2110
2249
  if (( CURRENT == 3 )); then
2111
2250
  _cc_hub_profiles
@@ -2137,7 +2276,7 @@ _cc-hub() {
2137
2276
  fi
2138
2277
  ;;
2139
2278
  use|run)
2140
- _cc_hub_profiles
2279
+ _arguments -C -S '--built-in[Use official Anthropic models (no custom profile)]' '*:profile:_cc_hub_profiles'
2141
2280
  ;;
2142
2281
  hook)
2143
2282
  if (( CURRENT == 2 )); then
@@ -2160,20 +2299,22 @@ compdef _cc-hub cc-hub
2160
2299
  `;
2161
2300
 
2162
2301
  // src/complete/bash.ts
2163
- var BASH_COMPLETION = `_cc-hub_profiles() {
2302
+ var BASH_COMPLETION = `_cc-hub_profile_names() {
2164
2303
  local profiles_file="\${CLAUDE_PROFILES_FILE:-$HOME/.claude/profiles.json}"
2165
2304
  if [[ -f "$profiles_file" ]]; then
2166
- local names
2167
- names=$(command python3 -c "
2305
+ command python3 -c "
2168
2306
  import json
2169
2307
  data = json.load(open('$profiles_file'))
2170
2308
  for name in data.get('profiles', {}):
2171
2309
  print(name)
2172
- " 2>/dev/null)
2173
- COMPREPLY=($(compgen -W "$names" -- "\${cur}"))
2310
+ " 2>/dev/null
2174
2311
  fi
2175
2312
  }
2176
2313
 
2314
+ _cc-hub_profiles() {
2315
+ COMPREPLY=($(compgen -W "$(_cc-hub_profile_names)" -- "\${cur}"))
2316
+ }
2317
+
2177
2318
  _cc-hub_models_for_profile() {
2178
2319
  local profile_name="$1"
2179
2320
  local profiles_file="\${CLAUDE_PROFILES_FILE:-$HOME/.claude/profiles.json}"
@@ -2222,8 +2363,10 @@ _cc-hub() {
2222
2363
  profile)
2223
2364
  if [[ \${COMP_CWORD} -eq 2 ]]; then
2224
2365
  COMPREPLY=($(compgen -W "$profile_subcmds" -- "$cur"))
2225
- elif [[ "$prev" == "view" || "$prev" == "remove" || "$prev" == "default" ]]; then
2366
+ elif [[ "$prev" == "view" || "$prev" == "remove" ]]; then
2226
2367
  _cc-hub_profiles
2368
+ elif [[ "$prev" == "default" ]]; then
2369
+ COMPREPLY=($(compgen -W "--built-in $(_cc-hub_profile_names)" -- "$cur"))
2227
2370
  elif [[ "$prev" == "rename" ]]; then
2228
2371
  _cc-hub_profiles
2229
2372
  elif [[ "$prev" == "profile" ]]; then
@@ -2249,7 +2392,11 @@ _cc-hub() {
2249
2392
  fi
2250
2393
  ;;
2251
2394
  use|run)
2252
- _cc-hub_profiles
2395
+ if [[ "$prev" == "--built-in" ]]; then
2396
+ :
2397
+ else
2398
+ COMPREPLY=($(compgen -W "--built-in $(_cc-hub_profile_names)" -- "$cur"))
2399
+ fi
2253
2400
  ;;
2254
2401
  hook)
2255
2402
  if [[ \${COMP_CWORD} -eq 2 ]]; then
@@ -2311,6 +2458,10 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
2311
2458
  $profileSubcmds | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
2312
2459
  return
2313
2460
  }
2461
+ if ($tokens[2] -eq 'default' -and $tokens.Count -ge 3) {
2462
+ $opts = @('--built-in')
2463
+ $opts | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
2464
+ }
2314
2465
  }
2315
2466
  'hook' {
2316
2467
  if ($tokens.Count -eq 2 -or ($tokens.Count -eq 3 -and $wordToComplete -ne '')) {
@@ -2330,6 +2481,16 @@ var POWERSHELL_COMPLETION = `Register-ArgumentCompleter -Native -CommandName cc-
2330
2481
  return
2331
2482
  }
2332
2483
  }
2484
+ 'use' {
2485
+ $opts = @('--built-in')
2486
+ $opts | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
2487
+ return
2488
+ }
2489
+ 'run' {
2490
+ $opts = @('--built-in')
2491
+ $opts | ForEach-Object { if ($_ -like "$wordToComplete*") { $_ } }
2492
+ return
2493
+ }
2333
2494
  }
2334
2495
  }`;
2335
2496
 
@@ -2369,6 +2530,7 @@ program.addCommand(hooksCommand());
2369
2530
  program.addCommand(sessionCommand());
2370
2531
  program.addCommand(completionCommand());
2371
2532
  program.addCommand(providerCommand());
2533
+ program.addCommand(proxyCommand());
2372
2534
  try {
2373
2535
  program.parse();
2374
2536
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-hub-cli",
3
- "version": "1.1.6",
3
+ "version": "1.1.7",
4
4
  "description": "Manage Claude CLI profiles, hooks, and sessions",
5
5
  "type": "module",
6
6
  "bin": {