CC Start macOS 踩坑实录:Claude Code 多模型启动器的三个 Bug

date
May 26, 2026
slug
cc-start-macos-three-bugs-fix
status
Published
summary
在 macOS 上安装 CC Start 踩了三个坑并逐一修复
tags
Claude Code
macOS
Shell
Bug Fix
开源工具
type
Post
URL

CC Start macOS 踩坑实录:Claude Code 多模型启动器的三个 Bug

项目背景

CC Start 是一个 Claude Code 多模型启动器,fork 自 wandanan/cc_start,MIT 协议,核心功能很简单:
一条命令切换 Claude Code 使用的 AI 模型。
cc kimi    # 用 Kimi K2.5
cc qwen    # 用千问 3.5 Plus
cc glm     # 用 GLM 5
解决的痛点:简单任务用便宜的国产模型(GLM、MiniMax),复杂任务用 Claude/GPT,按需切换,省 token 钱。
技术上它就是个 Bash 脚本,扫描 ~/.claude/models/*.json 配置文件,用 claude --settings <config> 启动不同模型。还有个 Tauri 2 桌面端(仅 Windows),不过本文只涉及 CLI。

安全审计

在安装之前做了完整的源码审计(CLI 1184 行 + Rust 后端 764 行 + 前端 JS 1323 行 + NSIS 安装器 1220 行),结论:代码干净,无恶意行为。无硬编码密钥、无后门、无数据外传、无混淆代码,依赖全是主流库。
几个小注意点(非恶意,可改进):
  • Tauri CSP 设为 null(本地应用风险低)
  • API Key 明文 JSON 存本地
  • install.shcurl | bash 装 nvm

Bug 1:sed -i GNU vs BSD 不兼容

现象

macOS 上运行 install.sh,报错:
sed: 2: "...": undefined label '...'

原因

脚本里 3 处使用了 GNU sed 语法:
sed -i 's/\r$//' "$INSTALL_DIR/cc"
sed -i "s#\"$key\": \"[^\"]*\"#\"$key\": \"${val}\"#g" "$json_file"
macOS 自带 BSD sed,-i 参数必须跟一个备份后缀参数。GNU sed 的 -i 直接原地修改,但 BSD sed 把后面的 sed 命令当成了备份后缀,再把文件路径当 sed 命令解析,路径里有 t/Users/tbh9527/...)被解释成 sed 的 "test and branch" 指令,于是报 undefined label

修复

所有 sed -i 改成 sed -i ''(空字符串备份后缀 = 不创建备份):
# Before (GNU only)
sed -i 's/\r$//' "$INSTALL_DIR/cc"

# After (BSD + GNU compatible)
sed -i '' 's/\r$//' "$INSTALL_DIR/cc"
3 处都改,安装顺利通过。

Bug 2:Bash 3.2 不支持 declare -A

现象

安装成功后运行 ccs,报错:
declare: -A: invalid option

原因

脚本第 302-303 行:
declare -A MODELS
declare -A MODEL_DESCS
declare -A(关联数组/associative arrays)是 Bash 4.0 引入的特性。macOS 因为 GPLv3 协议问题,系统自带的 Bash 停留在 3.2.57(2007 年的版本),不支持关联数组。
虽然 shebang 写了 #!/usr/bin/env bash,但 PATH 里找到的还是 /bin/bash 3.2。

修复

brew install bash
安装 Homebrew 版 Bash 5.x 到 /opt/homebrew/bin/bashenv bash 自动优先使用新版本。
这是项目本身应该在文档里注明的 macOS 前置条件。

Bug 3:JSON 合并 awk 逻辑错误(最复杂的一个)

现象

Bash 5 装好后 ccs 能运行了,选择模型启动,Claude Code 报错:
Settings Error: Invalid or malformed JSON
指向一个临时文件 /private/var/folders/.../cc-settings-XXXXXX.json

原因

cc 脚本的 create_merged_settings() 函数负责合并全局 ~/.claude/settings.json 和 per-model 配置,生成一个临时 settings 文件给 claude --settings 使用。
我的 settings.json 没有 env 块:
{
  "model": "opus[1m]",
  "effortLevel": "high",
  "voiceEnabled": false
}
脚本第一个 awk 发现没有 env 块,原样复制。第二个 awk 应该在最后的 } 前插入 env 块,但有两个 bug
原始代码:
awk '
{ lines[NR] = $0 }
END {
    for (i = 1; i <= NR; i++) {
        if (i == NR && lines[i] ~ /^[[:space:]]*}/) {
            for (k = 1; k < i; k++) print lines[k]  # ← 打印 1~NR-1
            # ... insert env block ...
            print lines[i]
        } else {
            print lines[i]  # ← 也打印 1~NR-1
        }
    }
}' "$tmpfile"
for (i=1; i<=NR; i++) 遍历每一行。i=1 到 NR-1 时走 else 分支打印一遍;i=NR 时又用 for (k=1; k<i; k++) 打印一遍。每行输出了两次。
生成的"JSON":
{
  "model": "opus[1m]",
  "effortLevel": "high",
  "voiceEnabled": false
{
  "model": "opus[1m]",
  "effortLevel": "high",
  "voiceEnabled": false,
  "env": { ... }
}
即使不重复打印,还有两个逗号问题:
  1. voiceEnabled: false 后面没加逗号就接 "env": {
  1. env 块关闭用 },尾逗号),但它是最后一个字段,后面直接是 }
  "voiceEnabled": false     ← 缺逗号
  "env": {
    ...
  },                        ← 多余逗号
}

修复

重写第二段 awk,逻辑简化为:先给最后一个非空行补逗号,打印 1~NR-1 行,插入 env 块(无尾逗号),打印末尾 }
awk '
{ lines[NR] = $0 }
END {
    # 给最后一个非空行补逗号
    for (j = NR - 1; j >= 1; j--) {
        if (lines[j] !~ /^[[:space:]]*$/) {
            sub(/[[:space:]]*$/, "", lines[j])
            if (lines[j] !~ /,$/) lines[j] = lines[j] ","
            break
        }
    }
    # 打印除最后一行外的所有行
    for (i = 1; i < NR; i++) print lines[i]
    # 插入 env 块
    print "  \"env\": {"
    printf "    \"ANTHROPIC_AUTH_TOKEN\": \"%s\"", ak
    # ... 其他字段 ...
    print ""
    print "  }"
    # 打印最后的 }
    print lines[NR]
}' "$tmpfile"
修复后生成的 JSON:
{
  "model": "opus[1m]",
  "effortLevel": "high",
  "voiceEnabled": false,
  "env": {
    "ANTHROPIC_AUTH_TOKEN": "your-key",
    "ANTHROPIC_BASE_URL": "https://api.example.com",
    "ANTHROPIC_MODEL": "GLM-5.1",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "GLM-5.1",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "GLM-5.1",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "GLM-5.1"
  }
}
python3 -m json.tool 验证通过 ✅,Claude Code 正常启动。

额外发现:cc 命令名冲突

macOS 上 /usr/bin/cc 是 Clang C 编译器的符号链接。虽然 ~/.local/bin 在 PATH 中优先级更高,但 shell 可能有 hash 缓存。建议直接使用 ccs 命令(安装时已创建的软链接),避免混淆。

额外发现:ccs edit 保存位置

ccs edit kimi 修改的是 ~/.claude/models/kimi.json不是仓库里的 models/kimi.json。后者只是安装模板,install.sh 会把它复制到 ~/.claude/models/,之后编辑只改目标目录。如果在仓库目录下 cat models/kimi.json 查看,看到的是没变的模板,不是实际配置。

总结

根因都一样:项目在 Linux/Windows 上开发测试,没覆盖 macOS 环境。 sed -ideclare -A 是经典的 macOS shell 兼容性问题,JSON awk bug 则是纯逻辑错误但在有 env 块的 settings.json 上不会触发(大多数用户的 settings.json 已经有 env 块)。
对于想在 macOS 上使用 CC Start 的用户:
  1. brew install bash
  1. install.shcli/cc 里的 sed -i 改成 sed -i ''
  1. 如果你的 ~/.claude/settings.json 没有 env 块,需要修复 awk 合并逻辑
或者等上游合并修复 — 这些 fix 值得提 PR。

相关链接

© Ying Bun 2021 - 2026