news 2026/9/13 10:09:57

CodexBar CLI 重构指南:JSON-only 错误模型、配置校验与 SettingsStore 拆分实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CodexBar CLI 重构指南:JSON-only 错误模型、配置校验与 SettingsStore 拆分实战

CodexBar CLI 重构指南:JSON-only 错误模型、配置校验与 SettingsStore 拆分实战

【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar

本文围绕 CodexBar 仓库内的 CLI 重构计划文档 展开,系统讲解其核心目标——让 CLI 在usage/cost等命令下输出纯 JSON 错误、实现逐 Provider 作用域的错误载荷、落地配置校验规则,以及如何通过SettingsStore 拆分控制文件规模。读完本文,你将掌握codexbar config validatecodexbar config dump等命令的实际用法、CodexBarConfigValidator的全部校验规则与错误码,并理解 CLI 错误上报管线的底层实现位置,可直接用于排查配置问题与二次开发。

一、重构背景与目标

CodexBar 的 CLI(入口见 Sources/CodexBarCLI/CLIEntry.swift)是一个基于 Commander 框架解析参数、按命令路径分发的 Swift 可执行程序。随着 Provider 数量增长(当前仓库Sources/CodexBarCore/Providers下已有数百个 Provider 实现文件),CLI 的错误处理、配置解析与设置存储逐渐暴露出三类问题:

  1. 错误输出不统一:部分路径向 stderr 写文本,部分路径混入日志,机器脚本难以稳定解析失败原因;
  2. 配置错误静默吞掉:无效的sourceregionapiKey字段只有在运行时才以模糊错误暴露;
  3. 文件体积膨胀CLIEntry.swiftSettingsStore.swift承担过多职责,单文件行数失控。

重构计划因此设定了五个目标(详见 docs/refactor/cli.md):

  • JSON-only:每个错误都以合法 JSON 输出到 stdout,不再混入 stderr 文本;
  • Per-provider errors:Provider 失败产出带 Provider 作用域的错误载荷;
  • Config validation:对无效字段、不支持的 source 模式、错误的 region 等给出显式告警;
  • Config parity:新增 CLI 命令用于校验(可选转储)配置;
  • SettingsStore split:文件控制在 500 行以内,明确划分 defaults 与 config 职责。

同时,重构保留了四条约束:Provider 顺序仍由配置providers[]数组顺序驱动;Provider 启停仍由配置enabled字段控制;Provider 密钥不做 Keychain 持久化;CLI 仍支持面向非 JSON 场景的文本输出。

二、JSON-only 错误模型:错误即数据

重构的核心约定是:usagecost命令的 JSON 输出始终是数组,错误不是单独的行外文本,而是数组内的载荷条目——正常条目携带usage/credits等数据,失败条目携带error字段。

2.1 全局/CLI 级错误形状

对于参数错误、配置加载失败这类与具体 Provider 无关的错误,使用固定的provider: "cli"source: "cli"标识:

{ "provider": "cli", "source": "cli", "error": { "code": 1, "message": "...", "kind": "config" } }

字段语义:

字段类型说明
providerstring固定为"cli",表示 CLI 自身错误
sourcestring固定为"cli",与 Provider 载荷中的auto/web/api等来源区分
error.codeint退出码,与进程退出码一致(见 Sources/CodexBarCLI/CLIExitCode.swift)
error.messagestring人类可读的错误描述
error.kindstring错误类别:args/config/provider/runtime(见 CLIErrorReporting.swift)

2.2 源码中的实现落点

错误上报的统一出口在 Sources/CodexBarCLI/CLIErrorReporting.swift:

  • makeCLIErrorProviderPayload(message:code:kind:)构造provider: "cli"ProviderPayloadsource写死为"cli"
  • makeProviderErrorPayload(provider:account:source:status:error:kind:)构造逐 Provider 作用域的错误载荷,provider使用真实的UsageProvidersource使用实际生效的ProviderSourceMode
  • exit(code:message:output:kind:)是唯一退出出口:当output.usesJSONOutput为真时,先打印 JSON 载荷数组再退出;否则才回退到 stderr 文本。这正对应计划中"路由所有退出到 JSON-aware reporter"的步骤 3。

ProviderPayload的结构定义在 Sources/CodexBarCLI/CLIPayloads.swift,包含provideraccountversionsourcestatususagecreditserror等可空字段,JSON 编码时未设置字段自动省略。

2.3 输出格式决策链

CLIOutputPreferences(Sources/CodexBarCLI/CLIOutputPreferences.swift)决定了"何时走 JSON":

  • usesJSONOutput=jsonOnly || format == .json
  • --json--json-only都是 JSON 快捷键,但--format显式值优先;
  • 从源码注释可见,usage --format toon是唯一的 TOON 特例:TOON 借用 JSON 获取/渲染管线,但错误/退出载荷也按 TOON 渲染,避免--format toon在早期失败时悄悄回退成 JSON。

CLIEntry.swift在解析命令前就通过CLIOutputPreferences.from(argv:)预先扫描 argv 中的--json-only/--json/--pretty/--format,这正是计划步骤 3"parse--json-onlyearly"的落地实现。

三、配置校验:CodexBarConfigValidator 全规则解析

计划步骤 1 要求新增CodexBarConfigIssueCodexBarConfigValidator,位于CodexBarCore/Config,且单文件控制在 500 行以内。这两者已实现于 Sources/CodexBarCore/Config/CodexBarConfigValidation.swift(约 324 行)。

3.1 问题模型

public enum CodexBarConfigIssueSeverity: String, Codable, Sendable { case warning case error } public struct CodexBarConfigIssue: Codable, Sendable, Equatable { public let severity: CodexBarConfigIssueSeverity public let provider: UsageProvider? public let field: String? public let code: String public let message: String }

每个问题包含五个字段:severitywarning/error)、provider(可空,全局问题为空)、field(如sourceapiKeyhooks.events[0].executable)、机器可读的code、人类可读的message

3.2 顶层校验流程

validate(_ config:)按三步执行:

  1. 版本检查config.version != CodexBarConfig.currentVersion(当前版本为 1,见 CodexBarConfig.swift)时报version_mismatch错误;
  2. 逐 Provider 校验:遍历config.providers,调用validateProvider
  3. Hooks 校验validateHooks检查事件规则数量上限、ID 唯一性、可执行文件绝对路径、阈值范围、超时范围与命令尺寸。

3.3 Provider 级校验规则(对应文档五条规则)

计划文档列出了五条核心规则,源码实现为更细的十二类检查:

计划规则源码错误码触发条件严重级
source必须在fetchPlan.sourceModesunsupported_source配置的source不在 Provider 描述符fetchPlan.sourceModeserror
apiKey仅当支持.apiapi_key_unused设置了apiKey但 Provider 不支持apisourcewarning
同上api_source_unsupportedsource == .api但 Provider 不支持apierror
同上api_key_missingsource == .api且需要 key,但未配置任何 API 凭据(含 tokenAccounts 兜底)warning
cookieSource仅当支持.web/.autocookie_source_unused设置cookieSource但 Provider 不用 web cookiewarning
同上cookie_header_unused设置cookieHeader但 Provider 不用 web cookiewarning
同上cookie_header_missingcookieSource == .manualcookieHeader缺失warning
region仅限 zai/minimax 等region_unused设置region但 Provider 描述符credentials.usesRegion为假warning
workspaceID仅限 opencode 等workspace_unused设置workspaceID但 Provider 无workspaceIDValidationOrderwarning
tokenAccounts仅在TokenAccountSupportCatalogtoken_accounts_unused设置tokenAccountsTokenAccountSupportCatalog.support(for:)返回 nilwarning
(额外)未知 Providerunsupported_providerproviders[].id无 first-party 实现error
(额外)secretKey误用secret_key_unused设置secretKey但 Provider 的credentials.usesSecretKey不为 true(仅 bedrock、doubao 使用)warning

注意:计划文档中 "region 仅用于 zai 或 minimax" 是对"当前已知使用 region 的 Provider"的概括,源码的实际判定依据是每个 Provider 描述符的credentials.usesRegion标志(validateRegion逻辑见 CodexBarConfigValidation.swift),因此支持 region 的 Provider 集合以注册表为准,这也是避免硬编码 Provider 名单的通用做法。

3.4 Hooks 校验规则

当配置包含hooks时(HooksConfig),以下错误码会被触发:

  • too_many_hook_rules:规则数超过HooksConfig.maximumRuleCount
  • duplicate_hook_id:规则 ID 重复;
  • invalid_hook_executable:可执行文件路径非空绝对路径;
  • invalid_hook_provider:规则绑定的 Provider 未识别;
  • invalid_hook_threshold:阈值必须 > 0 且 ≤ 1;
  • invalid_hook_timeout:超时必须在 0.1~300 秒之间;
  • invalid_hook_command_size:ID、参数或聚合命令尺寸超限。

测试用例可见 Tests/CodexBarTests/ConfigValidationTests.swift,其中reports unsafe hook rule fieldsreports hook workload limits直接断言了上述错误码集合。

四、CLI 命令:config validate 与 config dump

计划步骤 2 要求新增config validate命令,可选新增config dump。两者均已落地,命令注册在 CLIEntry.swift 的config子命令组中,分发逻辑在 CLIConfigCommand.swift。

4.1 codexbar config validate

校验当前配置文件并输出问题列表:

# 文本摘要(默认) codexbar config validate # JSON 数组输出(机器可读) codexbar config validate --json-only codexbar config validate --format json --pretty

行为细节(见 CLIConfigCommand.swift):

  • 加载配置后调用CodexBarConfigValidator.validate(config)
  • 文本模式:无问题时打印Config: OK;有问题时逐条打印[SEVERITY] provider (field): message,Provider 为空时显示config
  • JSON 模式:直接打印[CodexBarConfigIssue]数组(--pretty可美化);
  • 退出码:只要存在任一severity == .error的问题,进程以.failure退出;仅 warning 时仍以.success退出——这使config validate可直接用于 CI 门禁。

4.2 codexbar config dump

打印归一化后的配置 JSON:

codexbar config dump # 脱敏输出 codexbar config dump --show-secrets # 原始密钥(慎用)

源码中sanitizedForDump(showSecrets:)(CodexBarConfig.swift)在未指定--show-secrets时会把apiKeysecretKeycookieHeaderpluginSecretstokenAccounts中的 token 替换为[REDACTED],避免明文密钥进入日志或终端。

4.3 配套的 Provider 管理命令

同一个config子命令组还包含计划之外的实用命令(同样实现在 CLIConfigCommand.swift):

  • codexbar config providers:列出每个 Provider 的enabled/disabled状态及是否默认启用;
  • codexbar config enable --provider <name>/codexbar config disable --provider <name>:读写配置中的enabled字段并落盘;
  • codexbar config set-api-key --provider <name> [--api-key <key> | --stdin] [--no-enable]:为支持 API source 的 Provider 写入密钥,支持--stdin管道输入避免密钥进 shell 历史;z.ai 团队 token 还支持--label--usage-scope team--organization-id--workspace-id(仅--provider zai接受这些参数,源码见resolveConfigAPIKeyAccountOptions)。

需要注意:codexbar config set-api-key --provider codex会报错并提示改用--provider openai(见unsupportedAPIKeyErrorMessage),因为 Codex 与 OpenAI Platform 是不同 Provider 实例。

五、SettingsStore 拆分:defaults 与 config 的职责分离

计划步骤 5 要求把巨型SettingsStore.swift拆分为多个 <500 行文件。该拆分已在Sources/CodexBar/目录完成,当前布局为:

  • SettingsStore.swift:核心状态定义与基础能力;
  • SettingsStore+Config.swift:由配置(CodexBarConfig)支撑的计算属性;
  • SettingsStore+Defaults.swift:由默认值支撑的计算属性;
  • SettingsStore+ProviderDetection.swift:Provider 检测逻辑;
  • 另有 SettingsStore+TokenCost.swift、SettingsStore+TokenAccounts.swift、SettingsStore+MenuPreferences.swift、SettingsStore+MenuObservation.swift、SettingsStore+Sync.swift、SettingsStore+ConfigPersistence.swift 等按职责拆分的小文件。

这种"基础类型 + 领域扩展"的组织方式,让每个扩展文件只处理一类读取路径(config-backed / defaults-backed / 检测逻辑),配合.gitignore与格式化工具更容易维持行数上限。

六、Provider toggles 清理与约束保持

计划步骤 6 要求移除未使用的ProviderToggleStore及其测试,同时保留 legacy toggles 的迁移路径。之所以要保留迁移路径,是因为旧的启用/停用开关数据需要平滑并入新的providers[].enabled模型,避免用户升级后丢失启用状态。

约束方面,enabled与顺序的语义定义在 CodexBarConfig.swift:

  • providers[]数组顺序即 Provider 展示与处理顺序(orderedProviders());
  • enabledProviders(metadata:)在计算启用集合时,enabled缺省时回退到 Provider 元数据的defaultEnabled
  • normalized()会为配置中缺失的 first-party Provider 追加默认配置(alibaba token plan 例外地追加为chinaMainlandregion),保证"配置缺失条目不等于禁用"。

这些不变量有专门测试守护(Tests/CodexBarTests/下的 SettingsStore 相关测试),重构期间通过make test回归验证。

七、验证与回归清单

计划步骤 8 给出了完整的验证路径,结合仓库现状可归纳为:

# 单元测试与风格检查 make test swiftformat Sources Tests swiftlint --strict make check # 本地编译运行冒烟 ./Scripts/compile_and_run.sh # CLI 端到端验证 codexbar --json-only --provider codex # JSON-only 错误载荷 codexbar config validate --json-only # 校验输出 JSON 数组 codexbar config validate # 文本摘要 + 非零退出码(存在 error 时) codexbar config dump --pretty # 归一化配置转储(脱敏)

关键回归点:

  • CLI json-only 错误载荷(无效 source、无效 Provider 选择)——对应测试在 Tests/CodexBarTests/CLIProviderSelectionTests.swift 与 CLIOutputTests.swift;
  • 配置校验(bad region / source / apiKey 字段)——对应测试在 ConfigValidationTests.swift(共 492 行,覆盖 hooks 规则、Alibaba region、API 凭据等场景);
  • SettingsStore 顺序与 toggle 不变量继续通过。

八、总结

CodexBar 的 CLI 重构围绕"错误即 JSON 数据"与"配置可被机器校验"两条主线展开:ProviderPayload/CLIErrorReporting提供了统一的 JSON 错误载荷出口;CodexBarConfigValidatorCodexBarConfigIssue(severity/field/code/message)的形态覆盖了计划中的全部校验规则并扩展出 hooks 校验;config validate/config dump命令让配置问题在运行前即可被发现和排查;SettingsStore的职责拆分则保证了代码库的可维护性。如果你正在为 CLI 工具设计机器可解析的错误协议或配置校验层,本文涉及的错误码表格、校验触发条件与命令行为可直接作为参考蓝本。

【免费下载链接】CodexBarShow usage stats for OpenAI Codex and Claude Code, without having to login.项目地址: https://gitcode.com/GitHub_Trending/co/CodexBar

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 10:06:59

旧手机变服务器:Termux+宝塔面板+Docker实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 10:04:43

IIS强制HTTP跳转HTTPS的三种方案与常见问题排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 9:57:22

验证弹出的那0.5秒,你的流程正在经历什么

验证弹出的那0.5秒&#xff0c;你的流程正在经历什么 一个很少被讨论的细节&#xff1a;从验证弹出到你的流程「意识到验证存在」&#xff0c;中间发生了什么&#xff1f; 有卖家晒过自己的脚本日志&#xff1a;验证弹了47秒后脚本才报错退出。47秒里发生了什么&#xff1f;页…

作者头像 李华
网站建设 2026/9/13 9:55:49

用WorkBuddy将微信业主群升级为电梯运维数字中枢

1. 这不是“做个看板”&#xff0c;而是把业主群变成物业数字中枢的实操路径你有没有经历过&#xff1a;早上八点刚睁眼&#xff0c;手机弹出27条未读——全是电梯故障截图、视频、语音和带情绪的文字。3号楼东梯卡在2楼&#xff0c;4号楼西梯门关不严&#xff0c;5号楼北梯按钮…

作者头像 李华
网站建设 2026/9/13 9:52:02

无人机吊舱单目相机目标定位算法:坐标变换与测距的C++工程实践

简介&#xff1a;面向无人机视觉开发者、吊舱算法工程师及目标定位方向学习者&#xff0c;这份压缩包围绕“无人机吊舱单目相机目标定位”提供一套可运行、易扩展的C工程实现。工程采用模块化结构&#xff0c;含src、include、demo及CMakeLists构建配置&#xff0c;并附带使用说…

作者头像 李华