← back to daylenjeez__ccm

Function bodies 33 total

All specs Real LLM only Function bodies
readClaudeSettings function · typescript · L7-L10 (4 LOC)
src/claude.ts
export function readClaudeSettings(): Record<string, unknown> {
  if (!existsSync(SETTINGS_PATH)) return {};
  return JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
}
applyProfile function · typescript · L12-L26 (15 LOC)
src/claude.ts
export function applyProfile(settingsConfig: Record<string, unknown>): void {
  const current = readClaudeSettings();

  // 保留用户级字段,用 profile 的配置覆盖
  const preserved: Record<string, unknown> = {};
  const USER_FIELDS = ["language", "permissions"];
  for (const key of USER_FIELDS) {
    if (key in current) {
      preserved[key] = current[key];
    }
  }

  const merged = { ...preserved, ...settingsConfig };
  writeFileSync(SETTINGS_PATH, JSON.stringify(merged, null, 2));
}
getSettingsPath function · typescript · L28-L30 (3 LOC)
src/claude.ts
export function getSettingsPath(): string {
  return SETTINGS_PATH;
}
ask function · typescript · L18-L26 (9 LOC)
src/index.ts
function ask(question: string): Promise<string> {
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  return new Promise((resolve) => {
    rl.question(question, (answer) => {
      rl.close();
      resolve(answer.trim());
    });
  });
}
ensureStore function · typescript · L29-L36 (8 LOC)
src/index.ts
function ensureStore() {
  const store = getStore();
  if (!store) {
    console.log(chalk.yellow("尚未初始化,请先运行: ccm init"));
    process.exit(1);
  }
  return store;
}
formatEnv function · typescript · L39-L65 (27 LOC)
src/index.ts
function formatEnv(env: Record<string, string>): string {
  const lines: string[] = [];
  const order = [
    "ANTHROPIC_BASE_URL",
    "ANTHROPIC_MODEL",
    "ANTHROPIC_DEFAULT_OPUS_MODEL",
    "ANTHROPIC_DEFAULT_SONNET_MODEL",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL",
  ];
  for (const key of order) {
    if (key in env) {
      lines.push(`  ${chalk.gray(key)}: ${env[key]}`);
    }
  }
  // Show remaining keys (skip token for security)
  for (const [key, val] of Object.entries(env)) {
    if (!order.includes(key) && key !== "ANTHROPIC_AUTH_TOKEN") {
      lines.push(`  ${chalk.gray(key)}: ${val}`);
    }
  }
  if ("ANTHROPIC_AUTH_TOKEN" in env) {
    const token = env["ANTHROPIC_AUTH_TOKEN"];
    const masked = token.slice(0, 8) + "..." + token.slice(-4);
    lines.push(`  ${chalk.gray("ANTHROPIC_AUTH_TOKEN")}: ${masked}`);
  }
  return lines.join("\n");
}
levenshtein function · typescript · L68-L81 (14 LOC)
src/index.ts
function levenshtein(a: string, b: string): number {
  const la = a.length, lb = b.length;
  const dp: number[][] = Array.from({ length: la + 1 }, (_, i) =>
    Array.from({ length: lb + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0))
  );
  for (let i = 1; i <= la; i++) {
    for (let j = 1; j <= lb; j++) {
      dp[i][j] = a[i - 1] === b[j - 1]
        ? dp[i - 1][j - 1]
        : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
    }
  }
  return dp[la][lb];
}
About: code-quality intelligence by Repobility · https://repobility.com
findSuggestions function · typescript · L84-L105 (22 LOC)
src/index.ts
function findSuggestions(input: string, names: string[]): string[] {
  const lower = input.toLowerCase();

  // 1. exact case-insensitive match
  const exact = names.find((n) => n.toLowerCase() === lower);
  if (exact) return [exact];

  // 2. substring match (input is part of name, or name is part of input)
  const substring = names.filter(
    (n) => n.toLowerCase().includes(lower) || lower.includes(n.toLowerCase())
  );
  if (substring.length > 0) return substring;

  // 3. Levenshtein distance <= 3
  const fuzzy = names
    .map((n) => ({ name: n, dist: levenshtein(lower, n.toLowerCase()) }))
    .filter((x) => x.dist <= 3)
    .sort((a, b) => a.dist - b.dist)
    .map((x) => x.name);

  return fuzzy;
}
resolveAlias function · typescript · L108-L111 (4 LOC)
src/index.ts
function resolveAlias(input: string): string {
  const rc = readRc();
  return rc?.aliases?.[input] ?? input;
}
resolveProfile function · typescript · L114-L141 (28 LOC)
src/index.ts
function resolveProfile(store: ReturnType<typeof ensureStore>, input: string) {
  // 1. check alias first
  const resolved = resolveAlias(input);
  const profile = store.get(resolved);
  if (profile) return profile;

  // If alias resolved to something different but not found, mention it
  if (resolved !== input) {
    console.log(chalk.red(`别名 "${input}" 指向 "${resolved}",但该配置不存在`));
    return null;
  }

  const allNames = store.list().map((p) => p.name);
  const suggestions = findSuggestions(input, allNames);

  console.log(chalk.red(`配置 "${input}" 不存在`));
  if (suggestions.length === 1) {
    console.log(chalk.yellow(`你是不是想说: ${chalk.bold(suggestions[0])}?`));
  } else if (suggestions.length > 1) {
    console.log(chalk.yellow(`你是不是想说:`));
    for (const s of suggestions) {
      console.log(`  - ${chalk.bold(s)}`);
    }
  } else {
    console.log(chalk.gray("使用 ccm list 查看所有可用配置"));
  }
  return null;
}
ccSwitchExists function · typescript · L10-L12 (3 LOC)
src/store/cc-switch.ts
export function ccSwitchExists(): boolean {
  return existsSync(DB_PATH);
}
CcSwitchStore class · typescript · L14-L113 (100 LOC)
src/store/cc-switch.ts
export class CcSwitchStore implements DataStore {
  private db: Database.Database;

  constructor() {
    if (!existsSync(DB_PATH)) {
      throw new Error(`cc-switch 数据库不存在: ${DB_PATH}`);
    }
    this.db = new Database(DB_PATH);
  }

  list(): Profile[] {
    const rows = this.db
      .prepare(
        `SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' ORDER BY sort_index`
      )
      .all() as Array<{ id: string; name: string; settings_config: string }>;

    return rows.map((row) => ({
      id: row.id,
      name: row.name,
      settingsConfig: JSON.parse(row.settings_config),
    }));
  }

  get(name: string): Profile | undefined {
    const row = this.db
      .prepare(
        `SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' AND name = ?`
      )
      .get(name) as
      | { id: string; name: string; settings_config: string }
      | undefined;

    if (!row) return undefined;
    return {
      id: row.id,
      name: row
constructor method · typescript · L17-L22 (6 LOC)
src/store/cc-switch.ts
  constructor() {
    if (!existsSync(DB_PATH)) {
      throw new Error(`cc-switch 数据库不存在: ${DB_PATH}`);
    }
    this.db = new Database(DB_PATH);
  }
list method · typescript · L24-L36 (13 LOC)
src/store/cc-switch.ts
  list(): Profile[] {
    const rows = this.db
      .prepare(
        `SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' ORDER BY sort_index`
      )
      .all() as Array<{ id: string; name: string; settings_config: string }>;

    return rows.map((row) => ({
      id: row.id,
      name: row.name,
      settingsConfig: JSON.parse(row.settings_config),
    }));
  }
get method · typescript · L38-L53 (16 LOC)
src/store/cc-switch.ts
  get(name: string): Profile | undefined {
    const row = this.db
      .prepare(
        `SELECT id, name, settings_config FROM providers WHERE app_type = 'claude' AND name = ?`
      )
      .get(name) as
      | { id: string; name: string; settings_config: string }
      | undefined;

    if (!row) return undefined;
    return {
      id: row.id,
      name: row.name,
      settingsConfig: JSON.parse(row.settings_config),
    };
  }
Repobility — same analyzer, your code, free for public repos · /scan/
save method · typescript · L55-L71 (17 LOC)
src/store/cc-switch.ts
  save(name: string, settingsConfig: Record<string, unknown>): void {
    const existing = this.get(name);
    if (existing) {
      this.db
        .prepare(
          `UPDATE providers SET settings_config = ? WHERE app_type = 'claude' AND name = ?`
        )
        .run(JSON.stringify(settingsConfig), name);
    } else {
      const id = crypto.randomUUID();
      this.db
        .prepare(
          `INSERT INTO providers (id, app_type, name, settings_config, meta, created_at) VALUES (?, 'claude', ?, ?, '{}', ?)`
        )
        .run(id, name, JSON.stringify(settingsConfig), Date.now());
    }
  }
remove method · typescript · L73-L80 (8 LOC)
src/store/cc-switch.ts
  remove(name: string): boolean {
    const result = this.db
      .prepare(
        `DELETE FROM providers WHERE app_type = 'claude' AND name = ?`
      )
      .run(name);
    return result.changes > 0;
  }
getCurrent method · typescript · L82-L97 (16 LOC)
src/store/cc-switch.ts
  getCurrent(): string | undefined {
    if (!existsSync(SETTINGS_PATH)) return undefined;
    try {
      const settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
      const currentId = settings.currentProviderClaude;
      if (!currentId) return undefined;
      const row = this.db
        .prepare(
          `SELECT name FROM providers WHERE app_type = 'claude' AND id = ?`
        )
        .get(currentId) as { name: string } | undefined;
      return row?.name;
    } catch {
      return undefined;
    }
  }
setCurrent method · typescript · L99-L108 (10 LOC)
src/store/cc-switch.ts
  setCurrent(name: string): void {
    const profile = this.get(name);
    if (!profile) throw new Error(`配置 "${name}" 不存在`);

    if (existsSync(SETTINGS_PATH)) {
      const settings = JSON.parse(readFileSync(SETTINGS_PATH, "utf-8"));
      settings.currentProviderClaude = profile.id;
      writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2));
    }
  }
close method · typescript · L110-L112 (3 LOC)
src/store/cc-switch.ts
  close(): void {
    this.db.close();
  }
ensureDir function · typescript · L14-L18 (5 LOC)
src/store/standalone.ts
function ensureDir(): void {
  if (!existsSync(CCM_DIR)) {
    mkdirSync(CCM_DIR, { recursive: true });
  }
}
readConfig function · typescript · L20-L25 (6 LOC)
src/store/standalone.ts
function readConfig(): StandaloneConfig {
  if (!existsSync(CONFIG_PATH)) {
    return { profiles: {} };
  }
  return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
}
writeConfig function · typescript · L27-L30 (4 LOC)
src/store/standalone.ts
function writeConfig(config: StandaloneConfig): void {
  ensureDir();
  writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
}
Repobility · severity-and-effort ranking · https://repobility.com
StandaloneStore class · typescript · L32-L78 (47 LOC)
src/store/standalone.ts
export class StandaloneStore implements DataStore {
  list(): Profile[] {
    const config = readConfig();
    return Object.entries(config.profiles).map(([name, settingsConfig]) => ({
      id: name,
      name,
      settingsConfig,
    }));
  }

  get(name: string): Profile | undefined {
    const config = readConfig();
    const settingsConfig = config.profiles[name];
    if (!settingsConfig) return undefined;
    return { id: name, name, settingsConfig };
  }

  save(name: string, settingsConfig: Record<string, unknown>): void {
    const config = readConfig();
    config.profiles[name] = settingsConfig;
    writeConfig(config);
  }

  remove(name: string): boolean {
    const config = readConfig();
    if (!(name in config.profiles)) return false;
    delete config.profiles[name];
    if (config.current === name) {
      config.current = undefined;
    }
    writeConfig(config);
    return true;
  }

  getCurrent(): string | undefined {
    return readConfig().current;
  }

  set
list method · typescript · L33-L40 (8 LOC)
src/store/standalone.ts
  list(): Profile[] {
    const config = readConfig();
    return Object.entries(config.profiles).map(([name, settingsConfig]) => ({
      id: name,
      name,
      settingsConfig,
    }));
  }
get method · typescript · L42-L47 (6 LOC)
src/store/standalone.ts
  get(name: string): Profile | undefined {
    const config = readConfig();
    const settingsConfig = config.profiles[name];
    if (!settingsConfig) return undefined;
    return { id: name, name, settingsConfig };
  }
save method · typescript · L49-L53 (5 LOC)
src/store/standalone.ts
  save(name: string, settingsConfig: Record<string, unknown>): void {
    const config = readConfig();
    config.profiles[name] = settingsConfig;
    writeConfig(config);
  }
remove method · typescript · L55-L64 (10 LOC)
src/store/standalone.ts
  remove(name: string): boolean {
    const config = readConfig();
    if (!(name in config.profiles)) return false;
    delete config.profiles[name];
    if (config.current === name) {
      config.current = undefined;
    }
    writeConfig(config);
    return true;
  }
getCurrent method · typescript · L66-L68 (3 LOC)
src/store/standalone.ts
  getCurrent(): string | undefined {
    return readConfig().current;
  }
setCurrent method · typescript · L70-L77 (8 LOC)
src/store/standalone.ts
  setCurrent(name: string): void {
    const config = readConfig();
    if (!(name in config.profiles)) {
      throw new Error(`配置 "${name}" 不存在`);
    }
    config.current = name;
    writeConfig(config);
  }
readRc function · typescript · L12-L19 (8 LOC)
src/utils.ts
export function readRc(): RcConfig | undefined {
  if (!existsSync(RC_PATH)) return undefined;
  try {
    return JSON.parse(readFileSync(RC_PATH, "utf-8"));
  } catch {
    return undefined;
  }
}
Same scanner, your repo: https://repobility.com — Repobility
writeRc function · typescript · L21-L26 (6 LOC)
src/utils.ts
export function writeRc(rc: RcConfig): void {
  if (!existsSync(CCM_DIR)) {
    mkdirSync(CCM_DIR, { recursive: true });
  }
  writeFileSync(RC_PATH, JSON.stringify(rc, null, 2));
}
getStore function · typescript · L28-L37 (10 LOC)
src/utils.ts
export function getStore(): DataStore | null {
  const rc = readRc();
  if (!rc) return null;

  if (rc.mode === "cc-switch") {
    return new CcSwitchStore();
  } else {
    return new StandaloneStore();
  }
}