cockpit-tools Documentation

通用 AI IDE 账号管理工具:支持 Antigravity / Codex / GitHub Copilot / Windsurf / Kiro / Cursor / Gemini-cli / CodeBuddy,多账号切换、配额监控、自动唤醒与多开实例管理。 🚀 Universal AI IDE...

RAW Doc

Technical Documentation: jlcodes99/cockpit-tools

ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference

Overview (`README.md`)

Cockpit Tools

English · Portuguese (BR) · 简体中文




一款通用的 AI IDE 账号管理工具,目前支持 Antigravity IDE、Codex、GitHub Copilot、Windsurf、Kiro、Cursor、Grok CLI、CodeBuddy、CodeBuddy CN、Qoder、Trae、TRAE SOLO、Trae CN、TRAE SOLO CN、Zed 和 ZCode,并支持多账号多实例并行运行。

本工具旨在帮助用户高效管理多个 AI IDE 账号,支持一键切换、配额监控、自动唤醒与应用多开并行运行,助您充分利用不同账号的资源。

功能:一键切号 · 多账号管理 · 应用多开 · 配额监控 · 唤醒任务 · 插件联动 · GitHub Copilot 管理 · Windsurf 管理 · Kiro 管理 · Cursor 管理 · Grok CLI 管理 · CodeBuddy 管理 · CodeBuddy CN 管理 · Qoder 管理 · Trae 套件管理 · Zed 管理 · ZCode 管理

语言:支持 18 种语言

🇺🇸 English · 🇨🇳 简体中文 · 繁體中文 · 🇯🇵 日本語 · 🇩🇪 Deutsch · 🇪🇸 Español · 🇫🇷 Français · 🇮🇹 Italiano · 🇰🇷 한국어 · 🇧🇷 Português · 🇷🇺 Русский · 🇹🇷 Türkçe · 🇵🇱 Polski · 🇨🇿 Čeština · 🇸🇦 العربية · 🇻🇳 Tiếng Việt · 🇮🇩 Bahasa Indonesia

官方支持平台:macOS、Windows、Linux。


赞助商

APIKEY.FUN 是一家专业的企业级 AI 中转站,致力于为企业和个人开发者提供稳定、高效、低成本的 AI 模型 API 接入服务。平台支持 Claude、OpenAI、Gemini 等主流热门模型,价格低至官方原价的 7%。通过本项目 专属链接 注册,还可享受最高 充值永久 95 折 专属优惠。
感谢 APIMart 赞助了本项目!APIMart 是专注 AI 图片/视频生成的低价 API 平台,GPT-Image-2 低至 $0.006/张,1 美元可出图 160+ 张。图片、视频一套异步 API 通吃,提交任务拿 ID、回调取结果,跑批万张不超时、换模型不改代码。按量付费、无月费,通过此注册链接注册即可开用。
RoxyBrowser(Roxy浏览器) 是面向多账号运营与 AI 自动化场景的指纹浏览器,支持独立浏览器指纹环境、Cookie / 存储隔离、Roxy 原生住宅 IP、团队协作与 API / MCP 自动化能力,适合需要管理 AI 账号矩阵、降低账号关联风险、提升长期使用稳定性的用户。通过 Cockpit 邀请链接 注册或购买,可享受 10% 粉丝折扣。

功能概览

1. 仪表盘 (Dashboard)

全新的可视化仪表盘,为您提供一站式的状态概览:

  • 十六平台支持:同时展示 Antigravity IDE、Codex、GitHub Copilot、Windsurf、Kiro、Cursor、Grok CLI、CodeBuddy、CodeBuddy CN、Qoder、Trae、TRAE SOLO、Trae CN、TRAE SOLO CN、Zed 与 ZCode 的账号状态
  • 配额监控:实时查看各模型剩余配额、重置时间
  • 快捷操作:一键刷新、一键唤醒
  • 可视化进度:直观的进度条展示配额消耗情况

2. Antigravity IDE 账号管理

  • 一键切号:一键切换当前使用的账号,无需手动登录登出
  • 多种导入:支持 OAuth 授权、Refresh Token、插件同步
  • 唤醒任务:定时唤醒 AI 模型,提前触发配额重置周期

(唤醒任务)

2.1 Antigravity IDE 应用多开

支持同一平台多账号多实例并行运行。比如同时打开两个 Antigravity IDE,分别绑定不同账号,分别处理不同项目,互不影响。

  • 独立账号:每个实例绑定不同账号并独立运行
  • 并行项目:多实例同时处理不同任务/项目
  • 参数隔离:支持自定义实例目录与启动参数

3. Codex 账号管理

  • 专属支持:专为 Codex 优化的账号管理体验
  • 配额展示:清晰展示 Hourly 和 Weekly 配额状态
  • 计划识别:自动识别账号 Plan 类型 (Basic, Plus, Team 等)
  • API 服务:新安装及首次升级默认使用「Rust 原生」,之后保留用户的选择,可在 API 服务页面或快捷面板切回内置 Go CLIProxyAPI sidecar。Rust 在宿主内实现 Responses 的 HTTP/SSE/WebSocket 与 compact,以及 Chat Completions、Claude、Gemini、Ollama 兼容接口,两引擎共用账号池、代理和配置。Go 继续负责协议转换、自动重试和上游传输,由 Go 管理的本地无界面辅助进程复用 Rust 会话内核,持久实例网关不依赖主窗口存活。对于 Codex 账号请求,Go 与 Rust 在同一网关范围内共享 Session、Thread、子 Agent 和上游状态的账号归属及历史;不同 profile 的实例网关保持隔离。切换引擎保留 Base URL 和 API Key,但会重启服务并可能中断活动请求。
  • 请求身份对照:Go 与 Rust 的请求记录「详情」可对照客户端原始 Session-Id、Thread-Id,以及每次上游尝试使用的请求头、账号和传输方式。关闭或清除正文快照仍保留这些本地诊断信息;客户端未提供与历史未采集分别显示,不按当前配置补填旧记录。这些头值不代表上游已接收请求。
  • 自动续接上下文:Go 的 Codex 账号请求与 Rust 默认自动尝试续接历史对话,支持切换引擎和账号,缺少本地归属记录不再单独阻断请求。调用方、账号池权限及 profile 隔离继续生效。完整 Responses 历史原样保留,包括 reasoning、compaction、工具与子 Agent 密文及 item.id/call_id;不解密、不丢弃,也不以摘要替代。完整自包含 input 可在授权目标账号建立新的上游 Session/Thread,保留客户端 Thread;增量请求继续使用有效上游状态、完整检查点或 WebSocket 历史,缺失上下文或上游明确拒绝时仍可能失败并保留原历史。两引擎在转发完整官方 Agent 通信工具调用前登记消息密文归属;缺少记录的历史通信密文也自动尝试续接,新的续接归属仅在有效完整响应后保存。两引擎共用本地 codex_native_api/identity.sqlite 明文/密文历史缓存,实例网关使用各 profile 隔离目录内的 native-identity.sqlite,独立于正文诊断/快照开关。缓存上限为每个检查点 8 MiB、总计 64 MiB 和 128 个检查点,淘汰不删除会话或密文归属。重放可能增加输入 token,上游对跨账号密文的接受情况仍待真实请求验证。失败不覆盖已成功代次,已成功代次在切换引擎和重启后保留;新的上游对话不改变目标账号身份。
  • 语音反代:支持 Codex backend 实时语音路由与 /transcribe 转写入口,并提供 /v1/audio/transcriptions、/v1/audio/translations、/v1/audio/speech 及无 /v1 的别名。OAuth 转写使用 ChatGPT backend:兼容入口支持 file、language 和 JSON/纯文本返回,model 仅作为兼容字段,实际模型由 backend 决定;字幕时间戳、流式转写及其他音频操作需使用支持相应接口的 API Key 供应商。原生 /transcribe 请求保留原有 multipart 参数,供应商侧未指定模型时使用 gpt-4o-mini-transcribe。请求上限为 26 MiB,超时为 2 分钟,音频内容不写入请求快照。只处理实际发送到本地网关的请求;客户端仍直连官方转写服务或自行限制麦克风时,不会因设置模型供应商而自动改走本地网关。

3.1 Codex 应用多开

Codex 同样支持多账号多实例并行运行。比如同时打开两个 Codex,分别绑定不同账号,分别处理不同项目,互不影响。

  • 独立账号:每个实例绑定不同账号并独立运行
  • 并行项目:多实例同时处理不同任务/项目
  • 参数隔离:支持自定义实例目录与启动参数

4. GitHub Copilot 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入
  • 配额视图:展示 Inline Suggestions / Chat messages 使用情况与重置时间
  • 订阅识别:自动识别 Free / Individual / Pro / Business / Enterprise 等计划类型
  • 批量管理:支持标签与批量操作

4.1 GitHub Copilot 应用多开

基于 VS Code 的 Copilot 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

5. Windsurf 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入与本地导入
  • 配额视图:展示 Plan、User Prompt credits、Add-on prompt credits 与周期信息
  • 批量管理:支持标签与批量操作
  • 切号注入:支持切号后注入并启动 Windsurf

5.1 Windsurf 应用多开

支持 Windsurf 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

6. Kiro 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入与本地导入
  • 配额视图:展示 Plan、User Prompt credits、Add-on prompt credits 与周期信息
  • 批量管理:支持标签与批量操作
  • 切号注入:支持切号后注入并启动 Kiro

6.1 Kiro 应用多开

支持 Kiro 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

7. Cursor 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入与本地导入
  • 配额视图:展示 Total Usage、Auto + Composer、API Usage、On-Demand 与周期信息
  • 批量管理:支持标签与批量操作
  • 切号注入:支持切号后注入并启动 Cursor

7.1 Cursor 应用多开

支持 Cursor 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

8. Grok CLI 账号管理

  • OAuth 授权:支持 xAI 官方 OIDC device flow,在浏览器完成验证后自动保存账号
  • API Key 与第三方接口:支持官方 xAI API Key,也支持配置 OpenAI 兼容的第三方 Base URL 与模型 ID;配置写入账号专属 config.toml,密钥只在启动对应 CLI 进程时通过环境变量注入
  • 导入与脱敏导出:可从默认 ~/.grok/auth.json 或指定 JSON 导入官方凭据;账号页导出及通用账号备份均不含 access token/refresh token,不能用于恢复登录,迁移时需单独导入官方 auth.json
  • 真实切号:将选中账号按 Grok CLI 官方 registry 格式写回默认 ~/.grok/auth.json,并保留文件中其他 registry scope
  • 配额与套餐:查询官方 billing/user/subscriptions 接口,展示周期、用量、产品配额和套餐原始值,并记录 Grok Code 访问能力
  • Token 维护:支持 access token 自动刷新、refresh token rotation 与配额预警

8.1 Grok CLI 多实例

Grok CLI 默认实例通常直接沿用官方 ~/.grok 目录,启动时不设置 GROK_HOME;受管实例使用独立目录。API Key 账号(含第三方接口)为避免被官方 OAuth session 抢占凭据优先级,也始终通过账号专属 GROK_HOME 启动。

  • 账号绑定:默认实例可跟随当前账号,每个受管实例可绑定不同账号
  • 运行隔离:受管实例的 auth.json、config.toml、工作目录与启动参数互相独立
  • 终端启停:支持生成或执行终端启动命令、停止实例与批量关闭
  • 目录保护:非默认实例目录仅允许位于默认受管根目录;删除时移入回收站,历史配置中的外部目录只解除登记且不会被写入或删除

9. CodeBuddy 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入
  • 配额视图:支持配额查询、周期信息与加量包展示
  • 批量管理:支持标签与批量操作
  • 切号注入:支持切号后注入并启动 CodeBuddy

8.1 CodeBuddy 应用多开

支持 CodeBuddy 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

10. CodeBuddy CN 账号管理

  • 账号导入:支持 OAuth 授权、Token/JSON 导入与本机客户端导入
  • 配额视图:展示套餐与用量状态,并支持跳转官方网页查看配额详情
  • 批量管理:支持标签与批量操作
  • 切号注入:支持切号后按客户端本地认证存储规则注入并启动 CodeBuddy CN

9.1 CodeBuddy CN 应用多开

支持 CodeBuddy CN 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

11. Qoder 账号管理

  • 账号导入:支持本机导入与 JSON 导入
  • 配额视图:展示 Credits 使用、剩余额度与套餐原始值
  • 批量管理:支持标签、筛选、导出与批量删除/刷新
  • 切号注入:支持切号后注入并启动 Qoder

10.1 Qoder 应用多开

支持 Qoder 多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

12. Trae 账号管理

  • 账号导入:支持本机导入与 JSON 导入
  • 配额视图:展示套餐原始值、美元消耗/总额度与重置时间
  • 批量管理:支持标签、筛选、导出与批量删除/刷新
  • Trae 套件:支持 Trae、TRAE SOLO、Trae CN、TRAE SOLO CN 默认客户端的本机导入与切号注入,默认独立展示,可在顶部布局中手动分组
  • 切号注入:支持切号后按各客户端真实落盘规则写回并启动目标客户端

11.1 Trae 应用多开

支持原 Trae 客户端多实例管理,支持独立配置与生命周期控制。

  • 独立配置:每个实例拥有独立的用户目录
  • 快速启停:一键启动/停止/强制关闭实例
  • 窗口管理:支持打开实例窗口与批量关闭

13. Zed 账号管理

  • 账号导入:支持官方 OAuth 授权、JSON 导入与本机当前登录状态导入
  • 配额视图:展示订阅状态、Edit Predictions、Token Spend、Spend Limit 与账期结束时间
  • 批量管理:支持标签、筛选、导出与批量删除/刷新
  • 切号注入:支持切号后按 Zed 客户端真实落盘规则应用账号,并可按需重启官方客户端

14. ZCode 账号管理

  • 官方登录:关闭 ZCode 后,可在 Cockpit 内置授权窗口完成 Z.ai 或 BigModel OAuth;窗口直接拦截 zcode:// 官方回调并保存账号
  • 导入导出:支持读取本机 ~/.zcode/v2/credentials.json 加密凭据、JSON 导入导出与账号备份
  • 配额视图:查询订阅套餐与按模型拆分的额度,并保留套餐原始值
  • 批量管理:支持标签、搜索、套餐筛选、导出与批量删除/刷新
  • 真实切号:按 ZCode 官方凭据格式加密并回写默认客户端登录数据

13.1 ZCode 应用多开

支持 ZCode 多实例管理,每个受管实例使用独立的 Electron 用户数据、会话数据和 ZCode 数据目录。

  • 账号绑定:每个实例可绑定不同账号,也可跟随当前账号
  • 独立运行:实例凭据和业务数据互相隔离
  • 生命周期管理:支持启动、停止、聚焦与批量关闭实例

15. 通用设置

  • 个性化设置:主题切换、语言设置、自动刷新间隔
  • 平台配置:统一管理 Grok CLI / CodeBuddy CN / Qoder / Trae 套件 / Zed / ZCode 等平台配置与配额预警

安全性与隐私(简明版)

下面是最关心的几个问题,尽量用直白语言说明:

  • 这是本地桌面工具:不需要单独注册平台账号,也不依赖项目自建云端来存你的账号列表。
  • 数据主要保存在本机:
    • ~/.cockpit_tools:各平台账号、公共配置、日志、备份与实例配置;开发环境使用 ~/.cockpit_tools_dev,COCKPIT_TOOLS_DATA_DIR 可指定自定义目录
    • 已有安装会在后台自动为 ~/.antigravity_cockpit / ~/.antigravity_cockpit_dev 建立新名称的兼容入口(Unix 符号链接 / Windows 目录联接),无需手动迁移。旧物理目录和已有实例路径保留,两入口读写同一数据;当前会话保持原路径,后续启动使用新入口。无法建立链接时继续使用旧目录;新旧均为独立目录时保留旧目录,不自动合并或覆盖
    • 受管实例默认位于公共目录的 instances/<平台>;Windows 部分平台的实例位于 %APPDATA%\.cockpit_tools\instances\<平台>,其旧目录同样自动兼容;自定义目录保持原样
    • ~/.codex:Codex 官方当前登录 auth.json
    • ~/.grok:Grok CLI 官方默认实例与当前登录 auth.json
    • ~/.zcode/v2:ZCode 官方当前登录加密凭据与配额缓存
    • 系统应用数据目录下 com.jlcodes.cockpit-tools:宿主应用的 WebView 状态等;历史 com.antigravity.cockpit-tools 目录仅用于旧数据兼容导入
  • Grok CLI 凭据不加密:access token/refresh token 以明文 JSON 保存在本机,主要依赖操作系统账号隔离与本地文件权限保护;Unix 系统上凭据目录设为 0700、凭据文件设为 0600。脱敏导出不包含 token,不能作为登录备份
  • WebSocket 默认仅本机访问:监听 127.0.0.1,默认端口 19528,可在设置中关闭或改端口。
  • 什么时候会联网:OAuth 登录、Token 刷新、配额查询、版本更新检查等官方接口请求。
  • macOS 隐私权限弹窗说明:在 Cockpit Tools 中启动 Codex/agent 后,如果 agent 执行的 shell 命令访问桌面、文稿、下载、照片等受保护目录,macOS 可能会把权限请求显示为“Cockpit Tools 想要访问……”。这是因为这些命令是 Cockpit Tools 启动的子进程,系统会把权限归因到宿主应用;这不等同于 Cockpit Tools 主程序主动扫描这些目录。是否允许取决于你是否信任当前 agent 任务和它将要执行的命令;不确定时可以选择拒绝,或先把项目放在普通工作目录中运行。
  • 实用安全建议:
    1. 不使用插件联动时,可关闭 WebSocket 服务。
    2. 不要把用户目录直接打包分享;备份前注意脱敏 token 文件。
    3. 在公共或共用电脑上,使用后删除账号并退出应用。

WebSocket 账号切换 API

request.switch_account 支持明确选择 Antigravity 客户端。未传 runtime_target,或传 "antigravity_ide",保持原有 IDE 切号流程及现有启动/无感双通道设置;不会读取前端选择的客户端。

切换 Antigravity 桌面版及使用同一系统凭据的 agy CLI,可发送:

json
{"type":"request.switch_account","payload":{"account_id":"<account-id>","request_id":"x","runtime_target":"antigravity","launch_on_switch":false}}
  • runtime_target: "antigravity":复用桌面版切号认证规则;2.0 及以上版本写入系统凭据,旧版写入本地 SQLite 登录状态。只有真实凭据写入成功后才更新当前账号、默认实例绑定并通知切号结果。
  • launch_on_switch:仅用于 "antigravity",默认 false;不关闭或启动客户端,已运行桌面版可能需下次启动才使用新账号。显式传 true 才执行与桌面版 UI 相同的关闭、写入、重启流程。IDE 请求不要传此字段,继续使用现有设置。
  • request_id:可选,传入后返回对应的 response.success 或 response.error。不支持的目标、凭据写入失败或并发桌面切号会返回错误,不报告成功;凭据已切换但启动失败会明确报告启动错误。无效目标返回 WS_SWITCH_TARGET_INVALID,在 IDE 请求中传启动策略返回 WS_SWITCH_LAUNCH_POLICY_INVALID;并发桌面切号返回 ANTIGRAVITY_SWITCH_BUSY,账号准备超时返回 ANTIGRAVITY_SWITCH_PREPARATION_TIMEOUT。
  • ANTIGRAVITY_SWITCH_STATE_SAVE_FAILED 表示客户端凭据已切换,但 Tools 当前账号状态保存失败,请重试切号。默认实例绑定更新保留原有尽力保存行为,失败会记录日志。

设置项说明(小白版)

如果你只想“能用、稳定、不折腾”,优先按“推荐值”设置即可。

通用设置

设置项 这是做什么的(通俗) 推荐值 什么时候改
显示语言 改界面文字语言 你最熟悉的语言 只在看不懂时改
应用主题 改亮色/暗色外观 跟随系统 长时间夜间使用可改深色
窗口关闭行为 点关闭按钮后的动作 每次询问 想后台常驻选“最小化到托盘”
Antigravity IDE 自动刷新配额 后台定时更新 Antigravity IDE 配额 5~10 分钟 账号多、想更实时可改 2 分钟
Codex 自动刷新配额 后台定时更新 Codex 配额 5~10 分钟 同上
GitHub Copilot 自动刷新配额 后台定时更新 GitHub Copilot 配额 5~10 分钟 同上
Windsurf 自动刷新配额 后台定时更新 Windsurf 配额 5~10 分钟 同上
Kiro 自动刷新配额 后台定时更新 Kiro 配额 5~10 分钟 同上
Cursor 自动刷新配额 后台定时更新 Cursor 配额 5~10 分钟 同上
Grok CLI 自动刷新配额 后台定时刷新 token 并更新配额 5~10 分钟 同上
CodeBuddy 自动刷新配额 后台定时更新 CodeBuddy 配额 5~10 分钟 同上
CodeBuddy CN 自动刷新配额 后台定时更新 CodeBuddy CN 配额 5~10 分钟 同上
Qoder 自动刷新配额 后台定时更新 Qoder 配额 5~10 分钟 同上
Trae 自动刷新配额 后台定时更新 Trae 套件账号配额 5~10 分钟 同上
Zed 自动刷新配额 后台定时更新 Zed 配额 5~10 分钟 同上
数据目录 存账号与配置文件的位置 默认即可 仅用于排查、备份
Antigravity IDE/Codex/VS Code/Windsurf/Kiro/Cursor/Grok CLI/CodeBuddy/CodeBuddy CN/Qoder/Trae/Zed/OpenCode 启动路径 指定应用可执行文件位置 留空(自动检测) 自动检测失败、或你装在自定义路径时
切换 Codex 时自动重启 OpenCode 切换 Codex 后自动同步 OpenCode 账号信息 使用 OpenCode 就开启;不用就关闭 频繁切号且需要 OpenCode 同步时开启

补充说明:

  • 自动刷新间隔越小,请求越频繁;若你更关注稳定,间隔可适当拉大。
  • 当启用“配额重置唤醒”相关任务时,部分刷新间隔会有最小值限制(界面会提示)。

网络服务设置

设置项 这是做什么的(通俗) 推荐值 风险/注意点
WebSocket 服务 给本机插件/客户端实时通信用 不用插件联动就关闭 开启后仍是本机 127.0.0.1 访问
首选端口 WebSocket 监听端口 默认 19528 若端口冲突可改,保存后需重启应用
当前运行端口 实际已使用端口 只读查看 配置端口被占用时会自动回退到其它端口

三套推荐配置(直接抄)

  1. 稳定省心:自动刷新 10 分钟 + WebSocket 关闭(不用插件时)+ 路径保持默认。
  2. 高频切号:自动刷新 2~5 分钟 + 需要联动时开启 WebSocket + OpenCode 联动开启。
  3. 安全优先:WebSocket 关闭 + 不共享用户目录 + 定期清理不再使用的账号。

安装指南 (Installation)

选项 A: 手动下载 (推荐)

前往 GitHub Releases 下载对应系统的安装包:

  • macOS: .dmg (Apple Silicon & Intel)
  • Windows: .msi(推荐)、.exe,或 x64-portable.zip(解压即用,无需安装)

Windows 便携包解压后直接运行其中的 Cockpit Tools.exe(或同名主程序)。系统需要 Windows 10/11 的 Microsoft Edge WebView2 Runtime;账号和配置仍按当前 Windows 用户目录保存,不会随 ZIP 文件夹自动迁移。

  • Linux: .deb (Debian/Ubuntu)、.rpm 或 .AppImage (通用)

选项 B: Homebrew 安装 (macOS)

需要先安装 Homebrew。

bash
brew tap jlcodes99/cockpit-tools https://github.com/jlcodes99/cockpit-tools
brew install --cask cockpit-tools

如果遇到 macOS “应用已损坏”或无法打开,也可以使用 --no-quarantine 安装:

bash
brew install --cask --no-quarantine cockpit-tools

如果提示已存在应用(例如:already an App at '/Applications/Cockpit Tools.app'),请先删除旧版本再安装:

bash
rm -rf "/Applications/Cockpit Tools.app"
brew install --cask cockpit-tools

或者直接强制覆盖安装:

bash
brew install --cask --force cockpit-tools

🛠️ 常见问题排查 (Troubleshooting)

macOS 提示“应用已损坏,无法打开”?

由于 macOS 的安全机制,非 App Store 下载的应用可能会触发此提示。当前开源发布流程尚未接入 Apple Developer ID 签名和公证,因此部分系统版本会显示更严格的 Gatekeeper 提示。您可以按照以下步骤快速修复:

  1. 命令行修复 (推荐):
    打开终端,执行以下命令:

    bash
    sudo xattr -rd com.apple.quarantine "/Applications/Cockpit Tools.app"

    注意: 如果您修改了应用名称,请在命令中相应调整路径。

  2. 或者: 在“系统设置” -> “隐私与安全性”中点击“仍要打开”。


开发与构建

前置要求

  • Node.js v18+
  • npm v9+
  • Rust(Tauri 运行时)

安装依赖

bash
npm install

开发模式

bash
npm run tauri dev

构建产物

bash
npm run tauri build

Star History


💬 交流群

新建 Telegram 畅聊群:点击加入

微信(个人):


☕ 赞助项目

如果不介意,请 ☕ 赞赏支持一下

您的每一份支持都是对开源项目最大的鼓励!无论金额大小,都代表着您对这个项目的认可。


致谢

  • Antigravity 账号切号逻辑参考:Antigravity-Manager
  • Codex API 服务集成 CLIProxyAPI,Codex Live WebRTC/sideband、Responses WebSocket 状态安全、canonical token accounting v2、Multi-Agent V2 兼容、Grok CLI 账号与 OAuth、Grok apply_patch 协议兼容,以及账号池错误分类与状态恢复边界参考其开源实现:router-for-me/CLIProxyAPI(MIT)
  • Codex、Claude CLI 与 Claude Desktop Gateway 第三方供应商预设、模型映射,以及从会话 JSONL 汇总真实用量的方向参考:CC Switch
  • Claude 可选登录 helper 运行时基于:Electron
  • Codex 账号代理使用 Mihomo 独立进程处理受支持的 Clash 节点与分组,节点参数、嵌套分组与内置阻断策略的配置语义、本地连接日志接口以及健康检查与故障转移设计参考其官方源码和文档;内核由用户主动下载或导入,宿主安装包不内置,不代表官方合作关系。

感谢以上项目作者的开源贡献!如果这些项目对你有帮助,也请给他们点个 ⭐ Star 支持一下!


许可证

本项目默认采用 CC BY-NC-SA 4.0 许可协议(署名-非商业性使用-相同方式共享)。

  • 允许:个人学习、研究、非商业场景下的使用与修改(需保留署名并遵循同协议分享要求)。
  • 不允许:任何未获授权的商业使用(含企业内部商业目的、对外商业服务、付费产品集成、二次分发售卖等)。
  • 商业授权:如需商业使用,请联系作者获取单独书面商业授权与报价。

免责声明

本项目仅供个人学习和研究使用。使用本项目即表示您同意:

  • 未获得作者书面商业授权前,不将本项目用于任何商业用途
  • 承担使用本项目的所有风险和责任
  • 遵守相关服务条款和法律法规

项目作者对因使用本项目而产生的任何直接或间接损失不承担责任。


Overview (`tests/codex-profile-copy/README.md`)

Codex profile 复制回归测试

此独立 Rust 测试包直接编译宿主的 codex_profile_copy.rs,覆盖 SQLite WAL 快照、会话路径与本机项目映射、分页历史和索引边界、来源保护、目标重叠以及取消后重试。

在项目根目录运行:

powershell
cargo test --manifest-path tests/codex-profile-copy/Cargo.toml --locked --lib

Windows 的路径写法由对应条件测试覆盖;Unix 的权限与链接测试仅在 Unix 上执行。宿主的创建流程、登记锁并发与取消行为另由 codex_instance_profile_copy_tests.rs 验证。测试只读写隔离的临时夹具,不启动客户端或操作图形界面。


Overview (`vendor/tao/README.md`)







Cross-platform application window creation library in Rust that supports all major platforms like
Windows, macOS, Linux, iOS and Android. Built for you, maintained for Tauri.

Cargo Features

TAO provides the following features, which can be enabled in your Cargo.toml file:

  • serde: Enables serialization/deserialization of certain types with Serde.

Platform-specific notes

Android

This library makes use of the ndk-rs crates, refer to that repo for more documentation.

Running on an Android device needs a dynamic system library, add this to Cargo.toml:

toml
[[example]]
name = "request_redraw_threaded"
crate-type = ["cdylib"]

And add this to the example file to add the native activity glue:

rust
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
fn main() {
    ...
}

And run the application with cargo apk run --example request_redraw_threaded

Linux

Gtk and its related libraries are used to build the support of Linux. Be sure to install following packages before building:

Arch Linux / Manjaro:

bash
sudo pacman -S gtk3

Debian / Ubuntu:

bash
sudo apt install libgtk-3-dev

Acknowledgement

This is a fork of winit which replaces Linux's port to Gtk.
In the future, we want to make these features more modular as separate crates. So we can switch back to winit and also benefit the whole community.

Partners

For the complete list of sponsors please visit our website and Open Collective.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/README.md`)

CLI Proxy API

English | 中文 | 日本語

If you want to use CLIProxyAPI on your desktop, we recommend our EasyCLIProxyAPI desktop client. It provides a graphical configuration UI, automatic updates, system tray integration, and one-click start/stop for the CLIProxyAPI service.

CLIProxyAPI is a proxy server that provides OpenAI/Gemini/Claude/Codex/Grok compatible API interfaces for CLI.

You can access the following providers locally and with multiple CLI accounts through any OpenAI (including Responses), Gemini (including Interactions), or Claude-compatible client or SDK.

Provider Description
Kimi series models (Kimi K3, Kimi K2.7 Code, etc.). Kimi K3 is Moonshot AI’s most capable model and the world’s first open 3T-class model. With 2.8 trillion parameters, native vision, and a 1-million-token context window, K3 is built for long-horizon coding, knowledge work, and reasoning. CLIProxyAPI supports Kimi through OAuth or compatible API interfaces. Try the Kimi Code subscription, or get an API key from the Kimi Open Platform. Thanks to Kimi for supporting CLIProxyAPI and the open-source community!
OpenAI GPT series models (GPT 5.6, GPT 6.1 Sol, etc.). GPT-5.6 sets a new quality and efficiency baseline for complex production workflows. GPT-5.6 is especially token-efficient and improves frontend aesthetics, including layout, visual hierarchy, and design judgment.
Anthropic Claude series models (Claude Fable, Claude Opus, Claude Sonnet, etc.). Claude Fable 5 is Anthropic's most capable widely released model, built for the most demanding reasoning and long-horizon agentic work.
Google Gemini series models (Gemini 3.5 Flash, Gemini 3.1 Pro, etc.). Gemini 3.5 Flash provides sustained frontier-level intelligence optimized for real-world tasks at a higher speed and lower cost. Designed for the agentic era, it excels at sub-agent deployment, multi-step workflows, and long-horizon tasks at scale. This model is particularly effective for rapid agentic loops involving complex coding cycles and iterations.
xAI Grok series models (Grok 4.5, Grok Composer 2.5 Fast, etc.). Grok 4.5 is SpaceXAI's frontier model built for coding, agentic tasks, and knowledge work. It was trained in SpaceXAI's data centers in Memphis with new datasets spanning science, engineering, and math.

Thanks to PackyCode for sponsoring this project!

PackyCode is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more.

PackyCode provides special discounts for our software users: register using this link and enter the "cliproxyapi" promo code during recharge to get 10% off.


Thanks to AICodeMirror for sponsoring this project! AICodeMirror provides official high-stability relay services for Claude Code / Codex / Gemini, with enterprise-grade concurrency, fast invoicing, and 24/7 dedicated technical support. Claude Code / Codex / Gemini official channels at 38% / 2% / 9% of original price, with extra discounts on top-ups! AICodeMirror offers special benefits for CLIProxyAPI users: register via this link to enjoy 20% off your first top-up, and enterprise customers can get up to 25% off!
Huge thanks to BmoPlus for sponsoring this project! BmoPlus is a highly reliable AI account provider built strictly for heavy AI users and developers. They offer rock-solid, ready-to-use accounts and official top-up services for ChatGPT Plus / ChatGPT Pro (Full Warranty) / Claude Pro / Super Grok / Gemini Pro. By registering and ordering through BmoPlus - Premium AI Accounts & Top-ups, users can unlock the mind-blowing rate of 10% of the official GPT subscription price (90% OFF)!
Thanks to VisionCoder for supporting this project. VisionCoder Developer Platform is a reliable and efficient API relay service provider, offering access to mainstream AI models such as Claude Code, Codex, and Gemini. It helps developers and teams integrate AI capabilities more easily and improve productivity. Additionally, VisionCoder now offers retail channels for Claude Max 200 and GPT Pro 200 premium accounts, providing users with instant access to top-tier AI computing power and features.
Thanks to APIKEY.FUN for sponsoring this project! APIKEY.FUN is a professional enterprise-grade AI relay platform dedicated to providing stable, efficient, and low-cost AI model API access for enterprises and individual developers. The platform supports popular mainstream models such as Claude, OpenAI, and Gemini, with prices as low as 7% of the official price. Register through this project's exclusive link to enjoy a special permanent 5% top-up discount.
RunAPI is an efficient and stable API platform—an alternative to OpenRouter. A single API Key gives you access to 150+ leading models, including OpenAI, Claude, Gemini, DeepSeek, Grok, and more, at prices as low as 10% of the original (up to 90% off), with exceptional stability. It's seamlessly compatible with tools like Claude Code, OpenClaw, and others. RunAPI offers an exclusive perk for CPA users: register and contact an administrator to claim ¥7 in free credit.
CyberPay was founded in 2021. We are committed to providing stable, efficient, and secure payment settlement solutions for AI industry merchants. Working with us helps your website platform solve Alipay and WeChat payment collection needs. We support business cooperation for selling GPT, Gemini, Claude, and Codex accounts, relay platforms, and other related services, helping merchants address payment collection challenges. Contact us to start your path to growth.
Thanks to Claude API for sponsoring this project! Claude API is an official-channel API provider focused on Claude models. Built on Anthropic official keys and AWS Bedrock official channels, it provides a stable integration experience for Claude Code and Agent applications, supports the full Claude model family, and preserves official capabilities such as Tool Use and long context. The service is not reverse-engineered and does not downgrade model capabilities, making it suitable for heavy Claude Code users, Agent engineers, and enterprise technical teams. Register through the Exclusive link and contact customer support to claim free test credits. Invoicing and team onboarding are also supported.
Thanks to Code0 for sponsoring this project! code0.ai is an AI coding workspace for developers and technical teams, bringing together mainstream Agent coding capabilities such as Claude Code and Codex. It supports common development scenarios including code generation, project understanding, debugging, code review, and documentation. It is suitable for independent developers, Agent engineers, open-source maintainers, and enterprise R&D teams, with invoicing and team onboarding supported. Register through the Exclusive link and contact customer support to claim free test credits and experience a more efficient AI coding workflow.
FennoAI is a stable and efficient API relay service provider, currently focused on Codex relay services. It is compatible with OpenAI and Anthropic protocols and can flexibly integrate with mainstream coding tools such as Codex, Claude Code, and OpenCode. It can reliably support enterprise-grade demand of hundreds of billions of tokens per day, with B2B settlement and invoicing available for both domestic and overseas entities. FennoAI offers an exclusive benefit for CLIProxyAPI users: purchase a subscription through the exclusive link and receive $50 worth of Coding Plan credits for just $1.99. Referral rewards are also available: earn up to 20% commission when invited friends make a purchase. The more friends you invite, the greater the rewards.
Thanks to Qiniu Cloud AI for sponsoring this project! Qiniu Cloud AI is an enterprise-grade large-model MaaS platform under Qiniu Cloud (02567.HK). It provides one-stop access to 150+ mainstream global models, is compatible with protocols from major global model providers, and covers full-modal processing capabilities for text, image, audio, video, and files. It serves more than 1.69 million enterprise and developer users. Exclusive benefits: enterprise users can claim 12 million free tokens, and invite friends to earn up to tens of billions of tokens.
Thanks to Cubence for sponsoring this project! Cubence is a reliable and efficient API relay service provider, offering relay services for Claude Code, Codex, Gemini, and more. Cubence provides special discounts for our software users: register using this link and enter the "CLIPROXYAPI" promo code during recharge to get 10% off.
Thanks to FastAIToken for sponsoring this project! FastAIToken is an AI API aggregation platform built for developers, focused on speed and stability. It supports leading AI models including OpenAI, Claude, Gemini, and more. With a 1:1 recharge ratio (¥1 = $1 in API credits), developers can access the world's top AI models at lower cost and with greater convenience. Telegram Support GroupThe platform offers multiple channels to suit different needs: an ultra-low-cost 0.02× OpenAI promotional tier (limited time), OpenAI channels starting from 0.25×, 0.7× Claude with 95% fixed cache, and 1.2× Claude Max channels. It also provides a public status page displaying real-time availability, latency, and operational status for every channel, ensuring transparent and reliable service. In addition, FastAIToken offers 24/7 human technical support (no bots) for rapid response to developers' needs. For enterprise customers, dedicated SLA-backed channel pools are available with guaranteed stability, contract support, invoicing, and dedicated maintenance.
Thanks to LMU (灵眸 AI) for sponsoring this project! LMU is an Anthropic- and OpenAI-compatible relay for Claude Code, Codex, and other coding agents, covering both domestic models (DeepSeek, GLM, Qwen, and more) and major overseas providers. Point ANTHROPIC_BASE_URL at the LMU endpoint and connect over the standard /v1/messages API with no code changes. Real-world Prompt Cache hit rates run above 90% in Claude Code sessions, cutting long-session costs. Unused recharge balance is refundable on request. Enterprise plans include grouped, team-managed API keys with configurable IP/quota limits, rate windows, and expiry, plus traffic monitoring and invoicing. Register through the LMU CLIProxyAPI exclusive link to claim free test credits.
Worried about diluted or downgraded models, or opaque pricing? Infistar.ai, a globally leading model aggregation service, verifies every model it offers through real API calls. Its supply comes from official APIs and official account pools, with load balancing across more than 10,000 supply routes to ensure low latency and stability during peak periods. It covers leading models worldwide, including ChatGPT, Claude, Gemini, Grok, GLM, DeepSeek, Kimi, Qwen, and MiniMax, with full-modal capabilities spanning text, video, images, embeddings, reranking, and more. Pricing and usage are transparent, clear, and easy to inspect, with models available from as little as 10% of official prices. CLIProxyAPI users can register and try the service through the exclusive entry. Invitation link: https://infistar.ai/register?aff=FQKC6J6R&ref_source=link
Bestproxy provides high-purity residential IPs with dedicated one-IP-per-account support. 🟡Residential Proxy - $0.5/GB;🟡Static Residential Proxy - Starting at $3/IP;🟡Unlimited Residential Proxy - Starting at $67/Day. ✅Get Free Trial.

Overview

  • OpenAI/Gemini/Claude/Grok compatible API endpoints for CLI models
  • OpenAI Codex support (GPT models) via OAuth login
  • Claude Code support via OAuth login
  • Grok Build support via OAuth login
  • Streaming, non-streaming, and WebSocket responses where supported
  • Function calling/tools support
  • Multimodal input support (text and images)
  • Multiple accounts with round-robin load balancing (Gemini, OpenAI, Claude, Grok)
  • Simple CLI authentication flows (Gemini, OpenAI, Claude, Grok)
  • Generative Language API Key support
  • AI Studio Build multi-account load balancing
  • Claude Code multi-account load balancing
  • OpenAI Codex multi-account load balancing
  • Grok Build multi-account load balancing
  • OpenAI-compatible upstream providers via config (e.g., OpenRouter)
  • Reusable Go SDK for embedding the proxy (see docs/sdk-usage.md)

Getting Started

CLIProxyAPI Guides: https://help.router-for.me/

Management API

see MANAGEMENT_API.md

Usage Statistics

Since v6.10.0, CLIProxyAPI and CPAMC no longer ship built-in usage statistics. If you need usage statistics, use:

[CPA Usage Keeper](https://github.com/Willxup/cpa-usage-keeper)

Standalone persistence and visualization service for CLIProxyAPI, with periodic data sync, SQLite storage, aggregate APIs, and a built-in dashboard for usage and statistics.

[CPA-Manager-Plus](https://github.com/seakee/CPA-Manager-Plus)

Full CLIProxyAPI management center with request-level monitoring and cost estimates. CPA-Manager tracks collected requests by account, model, channel, latency, status, and token usage; estimates cost with editable model prices and one-click LiteLLM price sync; persists events in SQLite; and provides Codex account-pool operations with batch inspection, quota detection, unhealthy account discovery, cleanup suggestions, and one-click execution for day-to-day multi-account maintenance.

SDK Docs

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Who is with us?

Those projects are based on CLIProxyAPI:

[vibeproxy](https://github.com/automazeio/vibeproxy)

Native macOS menu bar app to use your Claude Code & ChatGPT subscriptions with AI coding tools - no API keys needed

[Subtitle Translator](https://github.com/VjayC/SRT-Subtitle-Translator-Validator)

A cross-platform desktop and web app to translate and validate SRT subtitles using your existing LLM subscriptions (Gemini, ChatGPT, Claude, etc.) via CLIProxyAPI - no API keys needed.

[CCS (Claude Code Switch)](https://github.com/kaitranntt/ccs)

CLI wrapper for instant switching between multiple Claude accounts and alternative models (Gemini, Codex, Antigravity) via CLIProxyAPI OAuth - no API keys needed

[Quotio](https://github.com/nguyenphutrong/quotio)

Native macOS menu bar app that unifies Claude, Gemini, OpenAI, and Antigravity subscriptions with real-time quota tracking and smart auto-failover for AI coding tools like Claude Code, OpenCode, and Droid - no API keys needed.

[ProxyPilot](https://github.com/Finesssee/ProxyPilot)

Windows-native CLIProxyAPI fork with TUI, system tray, and multi-provider OAuth for AI coding tools - no API keys needed.

[Claude Proxy VSCode](https://github.com/uzhao/claude-proxy-vscode)

VSCode extension for quick switching between Claude Code models, featuring integrated CLIProxyAPI as its backend with automatic background lifecycle management.

[ZeroLimit](https://github.com/0xtbug/zero-limit)

Windows desktop app built with Tauri + React for monitoring AI coding assistant quotas via CLIProxyAPI. Track usage across Gemini, Claude, OpenAI Codex, and Antigravity accounts with real-time dashboard, system tray integration, and one-click proxy control - no API keys needed.

[CPA-XXX Panel](https://github.com/ferretgeek/CPA-X)

A lightweight web admin panel for CLIProxyAPI with health checks, resource monitoring, real-time logs, auto-update, request statistics and pricing display. Supports one-click installation and systemd service.

[CLIProxyAPI Tray](https://github.com/kitephp/CLIProxyAPI_Tray)

A Windows tray application implemented using PowerShell scripts, without relying on any third-party libraries. The main features include: automatic creation of shortcuts, silent running, password management, channel switching (Main / Plus), and automatic downloading and updating.

[霖君](https://github.com/wangdabaoqq/LinJun)

霖君 is a cross-platform desktop application for managing AI programming assistants, supporting macOS, Windows, and Linux systems. Unified management of Claude Code, Gemini, OpenAI Codex, and other AI coding tools, with local proxy for multi-account quota tracking and one-click configuration.

[CLIProxyAPI Dashboard](https://github.com/itsmylife44/cliproxyapi-dashboard)

A modern web-based management dashboard for CLIProxyAPI built with Next.js, React, and PostgreSQL. Features real-time log streaming, structured configuration editing, API key management, OAuth provider integration for Claude/Gemini/Codex, usage analytics, container management, and config sync with OpenCode via companion plugin - no manual YAML editing needed.

[All API Hub](https://github.com/qixing-jk/all-api-hub)

Browser extension for one-stop management of New API-compatible relay site accounts, featuring balance and usage dashboards, auto check-in, one-click key export to common apps, in-page API availability testing, and channel/model sync and redirection. It integrates with CLIProxyAPI through the Management API for one-click provider import and config sync.

[Shadow AI](https://github.com/HEUDavid/shadow-ai)

Shadow AI is an AI assistant tool designed specifically for restricted environments. It provides a stealthy operation
mode without windows or traces, and enables cross-device AI Q&A interaction and control via the local area network (
LAN). Essentially, it is an automated collaboration layer of "screen/audio capture + AI inference + low-friction delivery",
helping users to immersively use AI assistants across applications on controlled devices or in restricted environments.

[ProxyPal](https://github.com/buddingnewinsights/proxypal)

Cross-platform desktop app (macOS, Windows, Linux) wrapping CLIProxyAPI with a native GUI. Connects Claude, ChatGPT, Gemini, GitHub Copilot, and custom OpenAI-compatible endpoints with usage analytics, request monitoring, and auto-configuration for popular coding tools - no API keys needed.

[CLIProxyAPI Quota Inspector](https://github.com/AllenReder/CLIProxyAPI-Quota-Inspector)

Ready-to-use cross-platform quota inspector for CLIProxyAPI, supporting per-account codex 5h/7d quota windows, plan-based sorting, status coloring, and multi-account summary analytics.

[CLIProxy Pool Watch](https://github.com/murasame612/CLIProxyPoolWidget)

Native macOS SwiftUI app for monitoring ChatGPT/Codex account quotas in CLIProxyAPI pools. Displays account availability, Plus-base capacity, 5-hour and weekly quota bars, plan weights, and restore forecasts through the Management API.

[Panopticon](https://github.com/eltmon/panopticon-cli)

Multi-agent orchestration for AI coding assistants. Runs CLIProxyAPI as a local sidecar so its agents can drive GPT models through a ChatGPT subscription, pointing Claude Code at an Anthropic-compatible endpoint with no OpenAI API key required.

[Tunnel Agent](https://github.com/Villoh/tunnel-agent)

Windows desktop UI that manages CLIProxyAPI and Perplexity WebUI Scraper from a single interface, inspired by Quotio and VibeProxy. Connect OAuth providers (Claude, Gemini, Codex, Kimi, Antigravity), custom API keys, and Perplexity session accounts, then point any coding agent at the local endpoint.

[Quotio Desktop](https://github.com/xiaocoss/quotio-desktop)

Cross-platform (Tauri) port of Quotio for Windows, macOS and Linux. Manages a pool of AI accounts (Codex, Claude Code, GitHub Copilot, Gemini, Antigravity, Kiro, Cursor, Trae, GLM) through CLIProxyAPI, with per-account 5-hour/weekly quota bars, Codex rate-limit reset credits with one-click reset, smart scheduling, usage statistics, and multi-instance Codex — no API keys needed.

[Universal Chat Provider](https://github.com/maxdewald/vscode-universal-chat-provider)

VS Code extension that brings your Claude, ChatGPT/Codex, Antigravity, Grok, and Kimi subscriptions into GitHub Copilot Chat as native language models — and can power your Git commit messages, chat titles, and summaries too. Runs CLIProxyAPI in a fully managed background lifecycle (download, verify, supervise) shared across all windows, so it's zero-setup. No API keys needed, just OAuth.

[CPA-Tray-Powershell](https://github.com/IQ-Director/CPA-Tray-Powershell)

A PowerShell-based Windows system tray launcher for CLIProxyAPI. It supports running in the background without a console window, opening the management page, keeping the backend running after the management window closes, and reopening the page from the tray. It also supports checking for CLIProxyAPI updates on startup, SHA-256 verification with rollback, one-click CLIProxyAPI restart and update, PID-validated process management, and safe service shutdown.

[Grok Search MCP](https://github.com/MapleMapleCat/Grok_Search_Mcp)

An HTTP-only Model Context Protocol server that uses a CLIProxyAPI deployment to provide Grok-powered real-time web search, X/Twitter search, and model discovery to MCP clients. It adds MCP transport, client API-key management, quotas, usage tracking, and a web administration panel.

[AIUsage](https://github.com/sylearn/AIUsage)

Native macOS SwiftUI dashboard for AI subscriptions and coding proxies. It manages official CLIProxyAPI releases end to end (download, verify, supervise, update, and roll back), unifies OAuth accounts and live models, and connects one gateway to Codex, Claude Code/Science, OpenCode, or OpenAI/Anthropic/Gemini clients, with optional LAN access.

[Claude Dialects](https://github.com/stefandevo/claude-dialects)

Run multiple native-feeling Claude Code commands, each powered by a different model (Codex, GLM, Kimi, Gemini, Grok, MiniMax, DeepSeek, Cursor, Copilot, Claude). Every dialect launches the real Claude Code interface with its own isolated config, history, ports, and an embedded CLIProxyAPI instance linked through the Go SDK — no separate proxy install. macOS only. Learn more at claude-dialects.cc.

[!NOTE]
If you developed a project based on CLIProxyAPI, please open a PR to add it to this list.

More choices

Those projects are ports of CLIProxyAPI or inspired by it:

[9Router](https://github.com/decolua/9router)

A Next.js implementation inspired by CLIProxyAPI, easy to install and use, built from scratch with format translation (OpenAI/Claude/Gemini/Ollama), combo system with auto-fallback, multi-account management with exponential backoff, a Next.js web dashboard, and support for CLI tools (Cursor, Claude Code, Cline, RooCode) - no API keys needed.

[OmniRoute](https://github.com/diegosouzapw/OmniRoute)

Never stop coding. Smart routing to FREE & low-cost AI models with automatic fallback.

OmniRoute is an AI gateway for multi-provider LLMs: an OpenAI-compatible endpoint with smart routing, load balancing, retries, and fallbacks. Add policies, rate limits, caching, and observability for reliable, cost-aware inference.

[Codex Switch](https://github.com/9ycrooked/CodexSwitch)

This is a tool built with Tauri 2 + Vue 3 for managing multiple OpenAI Codex desktop accounts. Switch between saved ChatGPT/Codex certification profiles, check 5-hour and weekly quota usage in real time, verify token health, view active account details, and import or save auth.json files without manual copying.

[!NOTE]
If you have developed a port of CLIProxyAPI or a project inspired by it, please open a PR to add it to this list.

License

This project is licensed under the MIT License - see the LICENSE file for details.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/README.md`)

Standard Dynamic Library Plugin Examples

This directory contains standard dynamic library plugin examples for the CLIProxyAPI C ABI.

Layout

  • simple/: full provider-native skeleton that declares every supported capability.
  • model/: model capability only.
  • auth/: auth provider capability only.
  • frontend-auth/: frontend auth provider capability only.
  • frontend-auth-exclusive/: frontend auth provider that becomes the only request authentication provider when selected.
  • executor/: executor capability only.
  • protocol-format/: minimal executor focused on input/output format declarations.
  • request-translator/: request translation capability only.
  • request-normalizer/: request normalization capability only.
  • codex-service-tier/: Go-only request normalizer that sets Codex gpt-5.6-sol requests to the priority service tier when enabled.
  • request-lifecycle/: Go-only request admission example with concurrency control, active HTTP termination, and terminal callbacks.
  • scheduler/: Go-only scheduler that can select a configured auth ID, delegate to a built-in scheduler, or deny picks.
  • claude-web-search-router/: ModelRouter + executor for Claude Code built-in web_search (antigravity / codex / xai / Tavily). See claude-web-search-router/README.md.
  • response-translator/: response translation capability only.
  • response-normalizer/: response normalization capability only.
  • thinking/: thinking applier capability only.
  • usage/: usage observer capability only.
  • cli/: command-line capability only.
  • management-api/: Management API and resource capability only.
  • host-callback/: minimal plugin resource that demonstrates host callbacks.
  • host-callback-auth-files/: Go-only plugin resource that calls host auth file callbacks.
  • host-model-callback/: Go-only plugin resource that calls the host model execution callbacks.

Most standard capability examples contain go/, c/, and rust/ subdirectories. Specialized examples may provide only the implementation language they need.

Codex Service Tier

codex-service-tier declares the request normalization capability. When fast is true, it sets service_tier to priority for requests where req.ToFormat is codex and req.Model is gpt-5.6-sol.

yaml
plugins:
  configs:
    codex-service-tier:
      enabled: true
      priority: 1
      fast: false

Request Lifecycle

request-lifecycle combines request_interceptor with request_lifecycle_plugin. It acquires a concurrency slot before auth selection, can return a custom 403 or 429 response without contacting an upstream model, and releases admitted slots from request.complete on success, failure, rejection, or cancellation.

yaml
plugins:
  configs:
    request-lifecycle:
      enabled: true
      priority: 100
      max_concurrency: 2
      reject_keyword: "blocked"

See request-lifecycle/README.md for build instructions and lifecycle semantics.

Host Auth Files Callback

host-callback-auth-files declares the Management API capability and exposes a browser resource named Host Auth Files. The resource demonstrates host.auth.list, host.auth.get (physical JSON file), host.auth.get_runtime, and host.auth.save.

yaml
plugins:
  configs:
    host-callback-auth-files:
      enabled: true
      priority: 1

See host-callback-auth-files/README.md for URL examples.

Host Model Callback

host-model-callback declares the Management API capability and exposes a browser resource named Host Model Callback. The resource calls host.model.execute for non-streaming requests and host.model.execute_stream plus host.model.stream_read for streaming requests. It demonstrates explicit stream close with host.model.stream_close and an implicit_close=true option for RPC-scope host cleanup.

When the resource forwards its host_callback_id, CPA identifies the plugin that initiated the host model callback and skips that same plugin's interceptors for the nested execution. This makes host model callbacks non-recursive for the caller while allowing other plugins to intercept the nested request.

yaml
plugins:
  configs:
    host-model-callback:
      enabled: true
      priority: 1

The default example model is gpt-5.6-sol, but the request succeeds only when the current CPA model and auth configuration can route that model.

Scheduler

scheduler declares the scheduler capability. It can select a configured auth ID from the candidate list, delegate to the built-in fill-first or round-robin scheduler, or reject picks when deny is true.

yaml
plugins:
  configs:
    scheduler:
      enabled: true
      priority: 1
      auth_id: ""
      delegate: ""
      deny: false

auth_id selects a matching candidate when delegate is empty. delegate accepts "", fill-first, or round-robin; other non-empty values leave the pick unhandled. deny returns a scheduler error.

Build All Examples

bash
make -C examples/plugin list
make -C examples/plugin build

Artifacts are written to examples/plugin/bin.

Notes

protocol-format uses a minimal executor because format declarations belong to executor capabilities.

host-callback uses a minimal plugin resource because host callbacks are invoked from plugin methods and are not standalone capabilities.

Menu resources returned by management.register through the resources field are exposed by CPA under /v0/resource/plugins//.... Authenticated plugin Management API routes remain under /v0/management/....


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/realtime-openai-go/README.md`)

OpenAI Go SDK Realtime Voice Example

This example sends spoken audio to CLIProxyAPI and saves the model's spoken reply as a WAV file.

It uses the official github.com/openai/openai-go/v3 SDK to create a short-lived Realtime client secret. The official Go SDK currently exposes the Realtime REST resources but does not provide a WebSocket connection helper, so github.com/gorilla/websocket is used for the standard Realtime audio events.

Prerequisites

  1. Start CLIProxyAPI with at least one working ChatGPT/Codex OAuth credential.
  2. Configure a proxy API key in config.yaml.
  3. Use Go 1.26 or newer.
  4. Prepare a PCM WAV file with these exact properties:
    • 24,000 Hz sample rate
    • 16-bit signed PCM
    • mono
    • little-endian

Convert an existing recording with FFmpeg:

bash
ffmpeg -i recording.m4a -ar 24000 -ac 1 -c:a pcm_s16le question.wav

Run

bash
cd examples/realtime-openai-go

OPENAI_BASE_URL="http://127.0.0.1:8317/v1" \
OPENAI_API_KEY="your-proxy-api-key" \
OPENAI_REALTIME_MODEL="gpt-realtime-2.1" \
OPENAI_REALTIME_INPUT_WAV="question.wav" \
OPENAI_REALTIME_OUTPUT_WAV="response.wav" \
go run .

Expected output:

text
Loaded question.wav (2.4s, 115200 PCM bytes)
Connected to ws://127.0.0.1:8317/v1/realtime?model=gpt-realtime-2.1 using model gpt-realtime-2.1 and voice marin
Sent 2.4s of speech audio
Assistant transcript: The connection is working correctly.
Saved spoken response to response.wav (1.8s, 86400 PCM bytes)

Play the response:

bash
# macOS
afplay response.wav

# Linux
aplay response.wav

# Cross-platform with FFmpeg
ffplay -autoexit response.wav

Environment variables

Variable Required Default Description
OPENAI_API_KEY Yes — API key configured for CLIProxyAPI.
OPENAI_REALTIME_INPUT_WAV Yes — Input speech WAV file. It must be 24kHz, 16-bit, mono PCM.
OPENAI_REALTIME_OUTPUT_WAV No response.wav Destination for the spoken response.
OPENAI_BASE_URL No http://127.0.0.1:8317/v1 CLIProxyAPI OpenAI-compatible base URL. /v1 is added when the URL has no path.
OPENAI_REALTIME_MODEL No gpt-realtime-2.1 Standard Realtime model name. CLIProxyAPI uses it for the upstream standard WebSocket while selecting a compatible Codex OAuth credential internally.
OPENAI_REALTIME_VOICE No marin Realtime output voice. Other common values include cedar, alloy, ash, coral, and echo.
OPENAI_REALTIME_INSTRUCTIONS No Short spoken response instruction Session instructions attached to the client secret.
OPENAI_REALTIME_DEBUG No false Print every received Realtime server event.

Audio flow

  1. The official OpenAI Go SDK calls POST /v1/realtime/client_secrets with an audio session configured for 24kHz PCM input and output.
  2. The returned local ek_... credential authenticates the /v1/realtime WebSocket.
  3. Input WAV samples are sent in 200ms input_audio_buffer.append chunks.
  4. The client sends input_audio_buffer.commit and response.create.
  5. Base64 response.output_audio.delta events are decoded and written to the output WAV.

The client secret returned by CLIProxyAPI is local to that proxy instance and is not valid against api.openai.com.

Test

bash
go test -race ./...

The test starts an in-process HTTP/WebSocket server and verifies client-secret configuration, input audio streaming, output audio decoding, and WAV generation.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/claude-web-search-router/README.md`)

Claude Code Web Search Router (ModelRouter example)

This plugin demonstrates ModelRouter on Claude Code built-in web_search requests (see temp/1.json in the repo root for a captured request/response).

What it detects

  • Inbound protocol claude / anthropic
  • tools[] with type web_search_20250305 or web_search_20260209
  • Optional Claude Code heuristics: system text like “web search tool use”, or user text
    Perform a web search for the query: …

Routes (`route` config)

Value Behavior
fallback (default) Plugin executor runs antigravity → codex → xai → tavily (built-ins via host.model.*, Tavily in-plugin). On 429/503/502, tries the next backend in the same request. Backends that fail often are deprioritized on later requests (in-memory penalty; no extra config).
antigravity_google / codex_web_search / xai_web_search / tavily Same orchestration for that backend’s chain member(s): execution retry + penalty apply when multiple backends are eligible.
default_provider default_provider + optional default_provider_model via built-in AuthManager (not orchestrated).
Routing for fallback requires at least one runnable backend (providers in AvailableProviders where needed, resolvable antigravity model, or tavily_api_keys).

xAI web search notes (aligned with upstream docs)

  • Model: xAI documents grok-4.3 for server-side web_search. This example sets TargetModel to grok-4.3 when xai_model is empty (do not forward claude-sonnet-4-6 to xAI).
  • Request shape: Responses API input + tools[] with "type": "web_search". Optional filters.allowed_domains / filters.excluded_domains (max 5 each, mutually exclusive).
  • Claude mapping today: internal/translator/codex/claude copies Claude allowed_domains → filters.allowed_domains. Claude blocked_domains is not mapped to excluded_domains yet.
  • Executor: xai_executor normalizes tools (drops unsupported external_web_access if present) and posts to /responses.
  • Response: Citations / server tool metadata come back through OpenAI Responses SSE and are converted toward Claude server_tool_use / web_search_tool_result where the response translator supports it.

Configuration

Plugin config lives under plugins.configs.claude-web-search-router (key must match the plugin name). Load the shared library via plugins.path.

Tries antigravity → codex → xai → tavily; configure tavily_api_keys so the last step can succeed when built-in providers are missing or unavailable.

yaml
plugins:
  path:
    - /absolute/path/to/examples/plugin/bin/claude-web-search-router-go.dylib
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: fallback
      antigravity_model: "" # empty: registry lookup, then first supports_web_search
      codex_model: "gpt-5.4-mini"
      xai_model: "grok-4.3"
      tavily_api_keys:
        - "tvly-xxxxxxxx"
        # - "tvly-yyyyyyyy" # optional: round-robin
      require_web_search_only: true

Omit route to use the same default (fallback).

Minimal fallback (Tavily as last resort only)

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: fallback
      tavily_api_keys:
        - "tvly-xxxxxxxx"
      require_web_search_only: true

Single backend (no fallback)

Antigravity only:

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: antigravity_google
      antigravity_model: "gemini-3.1-flash-lite"
      require_web_search_only: true

Codex only:

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: codex_web_search
      codex_model: "gpt-5.4-mini"
      require_web_search_only: true

xAI only:

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: xai_web_search
      xai_model: "grok-4.3"
      require_web_search_only: true

Tavily only (plugin executor):

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: tavily
      tavily_api_keys:
        - "tvly-xxxxxxxx"
      require_web_search_only: true

Built-in provider via default_provider:

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: true
      priority: 20
      route: default_provider
      default_provider: claude
      default_provider_model: ""
      require_web_search_only: true

Disable or relax detection

yaml
plugins:
  configs:
    claude-web-search-router:
      enabled: false # plugin declines; host may use default Claude path

# Or keep enabled but allow mixed tool lists:
    claude-web-search-router:
      enabled: true
      route: fallback
      require_web_search_only: false

Config field reference

Field Description
enabled false → Handled: false for all web_search matches
priority Host plugin order for ModelRouter (higher runs earlier; see main repo plugins docs)
route fallback (default), antigravity_google, codex_web_search, xai_web_search, tavily, default_provider
antigravity_model Antigravity execution model; never the client Claude model name
codex_model Codex model; empty → gpt-5.4-mini
xai_model xAI model; empty → grok-4.3
default_provider / default_provider_model Used when route=default_provider
tavily_api_keys Required for route=tavily or fallback last step
require_web_search_only true matches Claude Code–style exclusive web_search tools

Build

bash
make -C examples/plugin bin/claude-web-search-router-go.dylib

Use .so on Linux and .dll on Windows. Point plugins.path at the built artifact.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/codex-service-tier/README.md`)

Codex Service Tier Plugin

This plugin is a request normalizer for Codex outbound requests.

When the plugin is enabled and fast is set to true, it sets the top-level service_tier field to priority for requests where:

  • req.ToFormat is codex
  • req.Model is gpt-5.6-sol

Requests that do not match these conditions are returned unchanged.

Configuration

Add the plugin under plugins.configs:

yaml
plugins:
  configs:
    codex-service-tier:
      enabled: true
      priority: 1
      fast: false

fast is a boolean field. Set it to true to enable priority service tier shaping for matching Codex gpt-5.6-sol requests.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/frontend-auth-exclusive/README.md`)

Frontend Auth Exclusive Plugin Example

This example registers a frontend auth provider with frontend_auth_provider_exclusive: true.

When enabled and selected, this provider becomes the only request authentication provider. Built-in config API keys and other frontend auth providers do not authenticate requests while this provider is active.

The example accepts requests that include:

http
X-Example-Frontend-Auth: exclusive

Build:

bash
cd examples/plugin/frontend-auth-exclusive/go
go build -buildmode=c-shared -o /tmp/cliproxy-frontend-auth-exclusive.dylib .

Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/host-callback-auth-files/README.md`)

Host Callback Auth Files Plugin

This Go-only plugin demonstrates how a plugin-owned browser resource can call the host auth file callbacks:

  • host.auth.list
  • host.auth.get
  • host.auth.get_runtime
  • host.auth.save

Purpose and Scope

The plugin registers a Management API resource named Host Auth Files at /status. CPA exposes it under:

text
/v0/resource/plugins/host-callback-auth-files/status

The resource reads URL query parameters, calls the host auth callbacks, and renders the result in HTML. It does not implement executor, translator, auth provider, or scheduler capabilities.

Build

From this directory:

bash
cd go
go build -buildmode=c-shared -o host-callback-auth-files.dylib .
rm -f host-callback-auth-files.dylib host-callback-auth-files.h

Use the platform extension expected by your target system:

  • .dylib on macOS
  • .so on Linux
  • .dll on Windows

Configuration

Build the dynamic library and place it under the configured plugin directory with a basename that matches the plugin ID. For example, plugins/host-callback-auth-files.dylib maps to plugins.configs.host-callback-auth-files.

yaml
plugins:
  enabled: true
  dir: "plugins"
  configs:
    host-callback-auth-files:
      enabled: true
      priority: 1

This plugin does not define plugin-specific configuration fields.

Resource URL Examples

List all auth files:

text
http://localhost:8080/v0/resource/plugins/host-callback-auth-files/status?op=list

Read physical JSON by auth index:

text
http://localhost:8080/v0/resource/plugins/host-callback-auth-files/status?op=get&auth_index=<AUTH_INDEX>

Read runtime info by auth index:

text
http://localhost:8080/v0/resource/plugins/host-callback-auth-files/status?op=runtime&auth_index=<AUTH_INDEX>

Save physical JSON:

text
http://localhost:8080/v0/resource/plugins/host-callback-auth-files/status?op=save&name=example-auth.json&json=%7B%22type%22%3A%22gemini%22%2C%22email%22%3A%22demo%40example.com%22%2C%22api_key%22%3A%22demo-key%22%7D

Parameters

  • op: one of list, get, runtime, save. Default is list.
  • auth_index: required for get and runtime.
  • name: required for save. Must end with .json.
  • json: required for save. Must be valid JSON.

Notes

  • host.auth.get returns the physical auth file JSON.
  • host.auth.get_runtime returns runtime credential metadata.
  • host.auth.save writes the JSON to the auth directory and upserts the runtime auth record.

Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/host-model-callback/README.md`)

Host Model Callback Plugin

This Go-only plugin demonstrates how a plugin-owned browser resource can call the host model execution callbacks instead of sending any external HTTP request itself.

Purpose and Scope

The plugin registers a Management API resource named Host Model Callback at /status. CPA exposes it under:

text
/v0/resource/plugins/host-model-callback/status

The resource examples are query-based. The resource reads URL query parameters, builds an OpenAI-compatible chat request, and calls:

  • host.model.execute for non-streaming model execution.
  • host.model.execute_stream, host.model.stream_read, and host.model.stream_close for streaming execution.

This example is intentionally limited to host model callbacks. It does not implement an executor, translator, normalizer, auth provider, scheduler, or any direct outbound HTTP client.

Build

From this directory:

bash
cd go
go build -buildmode=c-shared -o host-model-callback.dylib .
rm -f host-model-callback.dylib host-model-callback.h

Use the platform extension expected by your target system:

  • .dylib on macOS
  • .so on Linux
  • .dll on Windows

Configuration

Build the dynamic library and place it under the configured plugin directory with a basename that matches the plugin ID. For example, plugins/host-model-callback.dylib maps to plugins.configs.host-model-callback.

yaml
plugins:
  enabled: true
  dir: "plugins"
  configs:
    host-model-callback:
      enabled: true
      priority: 1

This plugin does not define plugin-specific configuration fields.

Resource URL Examples

Non-streaming request with defaults:

text
http://localhost:8080/v0/resource/plugins/host-model-callback/status

Non-streaming request with explicit protocol and prompt:

text
http://localhost:8080/v0/resource/plugins/host-model-callback/status?entry_protocol=openai&exit_protocol=openai&model=gpt-5.6-sol&prompt=Say%20hello%20in%20one%20sentence

Streaming request with explicit close:

text
http://localhost:8080/v0/resource/plugins/host-model-callback/status?stream=true&model=gpt-5.6-sol&prompt=Write%20three%20short%20tokens

Streaming request that relies on RPC-scope implicit close:

text
http://localhost:8080/v0/resource/plugins/host-model-callback/status?stream=true&implicit_close=true

The default model ID is gpt-5.6-sol to match the current nearby Codex example documentation and code. It is only an example model identifier; the request succeeds only when your CPA configuration can route that model.

Parameters

  • entry_protocol: inbound client protocol passed to the host model execution path. The default is openai.
  • exit_protocol: target provider protocol passed to the host model execution path. The default is openai.
  • model: model identifier passed in the host model execution request. The default is gpt-5.6-sol; availability depends on the configured model registry and auth records.
  • stream: boolean flag. The default is false; set stream=true to use host.model.execute_stream.
  • prompt: text used to build the default OpenAI-compatible request body.
  • body: optional JSON string in the URL query used as the raw model request body. When body is provided, it replaces the generated body.
  • alt: optional alternate route or mode suffix passed through the host model request.
  • implicit_close: streaming-only boolean flag. The default is false.

The generated default body is OpenAI-compatible:

json
{
  "model": "gpt-5.6-sol",
  "stream": false,
  "messages": [
    {
      "role": "user",
      "content": "Summarize host model callbacks in one short sentence."
    }
  ]
}

For example, a URL-encoded body query value can provide the raw OpenAI-compatible request:

text
http://localhost:8080/v0/resource/plugins/host-model-callback/status?body=%7B%22model%22%3A%22gpt-5.6-sol%22%2C%22stream%22%3Afalse%2C%22messages%22%3A%5B%7B%22role%22%3A%22user%22%2C%22content%22%3A%22Say%20hello%20in%20one%20sentence%22%7D%5D%7D

Stream Close Semantics

By default, streaming mode explicitly closes the host-owned stream with host.model.stream_close through a deferred close call. This is the preferred pattern for plugins because it releases stream resources as soon as the plugin has finished reading.

When implicit_close=true is set, the plugin intentionally skips the explicit close call. CPA injects host_callback_id into the management.handle request, and this example forwards that callback ID to host.model.execute_stream so the host can close the stream when the management.handle RPC callback scope returns. This mode exists only to demonstrate host cleanup behavior; normal plugin code should explicitly close streams it opens.

Recursion Guard

This example forwards the host_callback_id received from management.handle when it calls host.model.execute or host.model.execute_stream. CPA uses that callback scope to identify the plugin that initiated the host model callback and skips that same plugin's request, response, and stream interceptors for the nested model execution.

Host model callbacks are therefore not recursive for the caller. Other enabled plugins can still intercept the nested request.

Billing and Usage

The callback uses the existing CPA model executor path. Usage collection, request accounting, and billing metadata are handled by the same executor and usage reporter path as normal proxied requests. The callback layer does not bill twice and does not create an additional usage record by itself.

Error Handling and Troubleshooting

The page displays the model status, response headers, body, stream chunks, close mode, and any callback error returned by the host envelope.

Common issues:

  • host model executor is unavailable: the host model executor path is not initialized for this plugin callback context.
  • unsupported model or provider-specific routing errors: the model value is not routable with the current CPA model/auth configuration.
  • host.model.execute requires stream=false: non-stream execution was called with a streaming request.
  • host.model.execute_stream requires stream=true: streaming execution was called without stream=true.
  • Empty or partial stream output: inspect the page error section and host logs; upstream stream errors are returned through host.model.stream_read.

Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/request-lifecycle/README.md`)

Request Lifecycle Plugin

This Go dynamic-library plugin demonstrates request admission, active termination, and exactly-once terminal lifecycle handling. It requires a host that supports plugin RPC schema version 2 or newer.

It declares two optional capabilities:

  • request_interceptor: acquires a concurrency slot in request.intercept_before and can terminate the request before any upstream executor runs.
  • request_lifecycle_plugin: releases the slot in request.complete for successful, failed, rejected, and canceled requests.

The host passes the same RequestID to request interception, response interception, stream interception, and the terminal RequestCompletion event.

Behavior

  • Allows at most max_concurrency requests in flight.
  • Returns a custom 429 JSON response with Retry-After: 1 when the limit is reached.
  • Returns a custom 403 JSON response when the raw request body contains reject_keyword.
  • Does not send terminated requests to an upstream model.
  • Releases only request IDs that were previously admitted, so rejected requests and duplicate terminal events do not underflow the counter.

Configuration

yaml
plugins:
  enabled: true
  configs:
    request-lifecycle:
      enabled: true
      priority: 100
      max_concurrency: 2
      reject_keyword: "blocked"

Set reject_keyword to an empty string to disable keyword rejection.

Build

From the repository root on macOS:

bash
mkdir -p plugins/darwin/$(go env GOARCH)
go build -buildmode=c-shared \
  -o plugins/darwin/$(go env GOARCH)/request-lifecycle.dylib \
  ./examples/plugin/request-lifecycle/go
rm -f plugins/darwin/$(go env GOARCH)/request-lifecycle.h

Use .so on Linux or FreeBSD and .dll on Windows.

The output filename is the plugin ID, so the example artifact must be named request-lifecycle for the configuration above.

Relevant RPC Methods

text
plugin.register
plugin.reconfigure
request.intercept_before
request.intercept_after
request.complete

request.complete is an observational callback. The host schedules it asynchronously so a blocked plugin cannot delay response delivery, logs callback errors, and uses a context detached from downstream cancellation so a canceled request can still release its slot.


Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/scheduler/README.md`)

Scheduler Plugin

This plugin demonstrates the CLIProxyAPI C ABI scheduler capability from Go.

It implements:

  • plugin.register
  • plugin.reconfigure
  • scheduler.pick

The plugin can select a configured auth ID, delegate routing to a built-in scheduler, or reject scheduler picks.

Configuration

Add the plugin under plugins.configs:

yaml
plugins:
  configs:
    scheduler:
      enabled: true
      priority: 1
      auth_id: ""
      delegate: ""
      deny: false

Fields:

  • auth_id: selects this auth ID when it appears in the scheduler candidates.
  • delegate: delegates selection to a built-in scheduler. Supported values are "", fill-first, and round-robin.
  • deny: returns a scheduler error when set to true.

Behavior:

  • When deny is true, the plugin returns an error envelope with code scheduler_denied.
  • When delegate is fill-first or round-robin, the plugin returns DelegateBuiltin and marks the pick as handled.
  • When delegate is any other non-empty value, the plugin leaves the pick unhandled.
  • When delegate is empty and auth_id exists in the candidates, the plugin returns that auth ID and marks the pick as handled.
  • When no rule matches, the plugin leaves the pick unhandled.

Build

From this directory:

bash
cd go
go build -buildmode=c-shared -o /tmp/cliproxy-scheduler-plugin.so .
rm -f /tmp/cliproxy-scheduler-plugin.so /tmp/cliproxy-scheduler-plugin.h

Overview (`sidecars/cockpit-cliproxy/third_party/CLIProxyAPI/examples/plugin/simple/README.md`)

Example Standard Dynamic Library Plugin

This is the full mixed-capability skeleton. For single-capability examples, see ../README.md.

This directory is the reference skeleton for the current standard dynamic library plugin ABI. The ABI is language-neutral: the host loads a native dynamic library, calls cliproxy_plugin_init, and then exchanges JSON envelopes through a stable C function table.

This directory contains complete Go, C, and Rust implementations of the same mixed-capability sample. The Go sample uses -buildmode=c-shared; the C sample uses CMake; the Rust sample uses a cdylib crate.

Entry Point

Every plugin must export:

c
int cliproxy_plugin_init(const cliproxy_host_api* host, cliproxy_plugin_api* plugin);

The plugin fills cliproxy_plugin_api with:

c
int call(char* method, uint8_t* request, size_t request_len, cliproxy_buffer* response);
void free_buffer(void* ptr, size_t len);
void shutdown(void);

The host provides cliproxy_host_api with:

c
int call(void* host_ctx, char* method, uint8_t* request, size_t request_len, cliproxy_buffer* response);
void free_buffer(void* ptr, size_t len);

The C ABI never passes Go interfaces, Go slices, Go maps, Go channels, context.Context, or Go errors.

JSON Envelope

Successful responses use:

json
{
  "ok": true,
  "result": {}
}

Errors use:

json
{
  "ok": false,
  "error": {
    "code": "invalid_request",
    "message": "request is invalid"
  }
}

Raw byte fields are encoded as base64 by JSON.

Capabilities

plugin.register and plugin.reconfigure return metadata and capability flags. This sample declares the full provider-native surface:

  • model provider
  • model registrar
  • auth provider
  • frontend auth provider
  • executor
  • request and response transforms
  • thinking applier
  • usage observer
  • command-line plugin
  • Management API plugin

Executor plugins must declare executor_input_formats and executor_output_formats in their capability block. The host passes requests through directly when the client protocol is declared by the executor. Otherwise, the host translates the inbound request into one declared input format and translates the executor response back to the client protocol. This example declares chat-completions for both lists, so non-chat-completions protocols are translated by the host. The host also accepts the existing internal aliases openai, openai-response, and claude for Chat Completions, Responses, and Anthropic protocols.

The host keeps the existing precedence rules: native logic wins, plugins fill gaps, and higher-priority plugins run before lower-priority plugins.

Layout

  • go/: full mixed-capability Go implementation.
  • c/: full mixed-capability C implementation with no external dependencies.
  • rust/: full mixed-capability Rust implementation with no external dependencies.

All three implementations parse incoming JSON requests for the methods where request content matters. Auth methods persist the raw request payload as StorageJSON; request and response transforms echo the inbound Body; Thinking decodes Body and appends plugin_example_thinking; executor methods use request fields such as Model, Format, and Payload; Usage keeps an in-process count.

Build

Build from the repository root.

Build all plugin examples:

bash
make -C examples/plugin build

Artifacts are written to examples/plugin/bin as simple-go, simple-c, and simple-rust with the current platform dynamic-library extension.

Manual Go build on macOS:

bash
mkdir -p plugins/darwin/$(go env GOARCH)
go build -buildmode=c-shared -o plugins/darwin/$(go env GOARCH)/simple-go.dylib ./examples/plugin/simple/go
rm -f plugins/darwin/$(go env GOARCH)/simple-go.h

Manual C build on macOS:

bash
mkdir -p plugins/darwin/$(go env GOARCH)
cmake -S examples/plugin/simple/c -B /tmp/cliproxy-simple-c-build -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=$PWD/plugins/darwin/$(go env GOARCH)
cmake --build /tmp/cliproxy-simple-c-build

Manual Rust build on macOS:

bash
mkdir -p plugins/darwin/$(go env GOARCH)
cd examples/plugin/simple/rust
CARGO_TARGET_DIR=/tmp/cliproxy-simple-rust-target cargo build --release --locked
cp /tmp/cliproxy-simple-rust-target/release/libcliproxy_simple_rust.dylib ../../../../plugins/darwin/$(go env GOARCH)/simple-rust.dylib

For Linux, FreeBSD, or Windows, keep the same source directory and use the platform extension selected by examples/plugin/Makefile.

The plugin ID is the dynamic library basename without the platform extension. Makefile-built artifacts map to plugins.configs.simple-go, plugins.configs.simple-c, and plugins.configs.simple-rust.

Discovery

The host searches:

text
plugins/<GOOS>/<GOARCH>
plugins

Accepted extensions are:

  • .so on Linux and FreeBSD
  • .dylib on macOS
  • .dll on Windows

Plugin IDs must match:

text
[A-Za-z0-9][A-Za-z0-9._-]{0,127}

Configuration

Dynamic plugins are disabled by default.

yaml
plugins:
  enabled: true
  dir: "plugins"
  configs:
    simple-go:
      enabled: true
      priority: 1
      config1: true
      config2: "string"
      config3: 3
      mode: "safe"

plugins.configs. is passed to plugin.register or plugin.reconfigure as normalized YAML bytes inside the JSON request.

Host HTTP Bridge

Plugins can call host functionality through host.call. The HTTP bridge method is:

text
host.http.do

The host still performs the real HTTP request, so proxy handling, transport policy, auth context, and request logging stay under host control.

Management API

The native plugin management endpoints are:

text
GET /v0/management/plugins
DELETE /v0/management/plugins/{pluginID}
PATCH /v0/management/plugins/{pluginID}/enabled
GET /v0/management/plugins/{pluginID}/config
PUT /v0/management/plugins/{pluginID}/config
PATCH /v0/management/plugins/{pluginID}/config

Plugin-owned Management API routes are registered through the routes field of management.register and handled through management.handle.

Browser-navigable menu resources are registered through the resources field of management.register. CPA exposes those resources under /v0/resource/plugins//...; for example, a plugin with ID example and resource path /status is served as /v0/resource/plugins/example/status.

Trust Boundary

Standard dynamic library plugins are trusted in-process code. Panic recovery can protect host-managed calls, but it cannot prevent a plugin from exiting the process, corrupting memory, mutating global process state, or leaking secrets. Install only plugins you trust as much as the service binary.

Verification

Current platform sample builds:

bash
make -C examples/plugin list
make -C examples/plugin build
find examples/plugin/bin -maxdepth 1 -type f | wc -l
make -C examples/plugin clean

After changing Go code in this repository, also run:

bash
go build -o test-output ./cmd/server && rm test-output

CODEX API SERVICE HANDOFF (`docs/CODEX_API_SERVICE_HANDOFF.md`)

Codex API Service Handoff

Scope

This note describes the local service shown in the UI as Codex API Service.
It is not a hosted Cockpit API. The desktop application creates a local,
authenticated OpenAI-compatible gateway and can redirect Codex profiles to it.

The repository was imported from jlcodes99/cockpit-tools at commit
9525a2b5fc519874d42213e6cac9cc90fd38ae82 on 2026-07-14.

Architecture

text
Codex CLI / selected Codex profile
  -> auth.json + config.toml injected by Cockpit
  -> http://localhost:<configured-port>/v1
  -> native Rust engine by default (optional cockpit-cliproxy sidecar)
  -> selected Codex OAuth credentials or configured provider API key
  -> OpenAI Codex upstream or provider upstream

React page -> Tauri invoke -> Rust collection/runtime -> native engine (default)
                                                    -> Go sidecar (optional)

Production traffic uses the selected engine:

  • New installations default to the host's native Rust engine. The first upgrade
    atomically migrates existing collections to native and records
    nativeGatewayDefaultMigrated. Later explicit choices, including Go, survive
    restarts and unrelated configuration writes.
  • When Go is selected, Rust materializes config and credentials and starts the
    bundled cockpit-cliproxy executable.
  • CodexLocalAccessGatewayMode::Legacy is not selectable. Persisted global
    collections are migrated before runtime startup; no active request is switched
    by the migration.
  • The retired in-process gateway is compiled only under #[cfg(test)] as a test
    oracle (codex_local_access_recovery.rs). Do not route production traffic
    through it; it is distinct from the new native engine in codex_native_api.

Source Ownership

Area Primary files Responsibility
UI src/pages/CodexApiServicePage.tsx, src/components/CodexLocalAccessModal.tsx Service screen, account/key/routing controls, test panel and usage views.
UI bridge src/services/codexLocalAccessService.ts Typed wrappers around the Tauri commands. Keep camelCase payload names aligned with Rust command arguments.
Contract src/types/codexLocalAccess.ts, src-tauri/src/models/codex_local_access.rs Frontend/Rust state and configuration schema. Rust uses serde(rename_all = "camelCase").
Commands src-tauri/src/commands/codex.rs Tauri command boundary; commands are registered in src-tauri/src/lib.rs.
Service coordinator src-tauri/src/modules/codex_local_access.rs Persistence, profile takeover, sidecar lifecycle, routing, quotas, request logs and tests.
Sidecar sidecars/cockpit-cliproxy/main.go Go HTTP gateway based on CLIProxyAPI SDK. Receives generated config and manifest.
Native engine src-tauri/src/modules/codex_native_api/, codex_local_access_native.rs Rust protocol implementation and host account/routing integration.

Runtime Flow

  1. The UI reads state through codex_local_access_get_state and changes it via
    codex_local_access_* commands.
  2. Rust persists a CodexLocalAccessCollection, synchronizes GatewayRuntime,
    and calls ensure_gateway_matches_runtime when a gateway-relevant setting
    changes.
  3. Native mode starts the host engine directly. In Go mode,
    prepare_sidecar_launch_config writes the sidecar config.json,
    manifest.json, credentials below auths/, and quota-reserve state. A stable
    fingerprint decides whether the process must be restarted.
  4. The selected engine authenticates the client key, applies model visibility/alias rules,
    selects an account, and sends the upstream request. It reports diagnostics and
    usage back to Rust.
  5. Activating the service backs up the target profile before writing a managed
    Codex account bundle (auth.json and config.toml). Disabling restores saved
    profile state.

HTTP Surface

The Rust proxy recognizes these client paths; the sidecar is expected to preserve
the same client contract:

  • /v1/models
  • /v1/chat/completions
  • /v1/responses and /v1/responses/compact
  • /backend-api/codex/*, including responses WebSocket traffic
  • /v1/images/generations and /v1/images/edits

The default bind is loopback (127.0.0.1). The user can choose LAN scope
(0.0.0.0), which expands exposure but still requires a generated API key. Client
Base URL host can be localhost or 127.0.0.1; preserve this when rewriting a
profile, especially for WSL.

Routing And Safety Rules

  • Account pools support auto, random distribution, single-account, quota/plan/
    expiry ordering, and custom priority/weight/backup routing. Random distribution
    shuffles eligible accounts for each new request; a session-affinity binding still
    wins for an existing conversation.
  • Session affinity is enabled by default. Routing also observes cooldown and
    account-health state; retries are bounded by the configured credential count and
    delay.
  • Named API keys can be disabled, limited by allowed/excluded models, and assigned
    a model prefix. The primary collection key remains for backward compatibility.
  • Bound OAuth quota reserve can exclude an OAuth account when its fresh hourly or
    weekly quota snapshot drops below the configured threshold. A failed refresh is
    fail-closed for that reserve decision.
  • Model aliases and filters affect both model discovery and request rewriting.
    Update both paths together and test an alias plus a rejected model.
  • Image behavior is separately configurable: enabled, images-only, or disabled.
    Image requests and image tool injection have their own validation path. The
    sidecar tracks in-flight image jobs by selected auth. maxConcurrentImageRequests
    configures the number of job slots per account (default 1, range 1-16).
    It selects an eligible account with the fewest jobs and queues later image
    requests locally until a slot is released when a request ends.
    Image requests bypass session-affinity cache so a prior text/image request
    cannot pin new image jobs to an already busy account.
  • immediateSseResponse is disabled by default. In sidecar mode it commits a
    200 OK SSE response with an ignored : accepted comment before the upstream
    stream opens. This also applies to streaming image generation and edits. Once
    HTTP headers are committed, upstream-open failures are sent as SSE error
    events and cannot change the HTTP status.

Persistent Artifacts And Logs

Artifact paths are derived from the application data directory in
codex_local_access.rs; do not hard-code an OS-specific profile path.

  • codex_local_access.json: durable collection and service configuration.
  • codex_local_access_stats.json: summarized counters/recent events.
  • codex_local_access_logs.sqlite: queryable request/usage records.
  • codex_local_access_takeover_backups.json: profile restoration data.
  • codex_local_access_sidecar/: generated sidecar config.json, manifest.json,
    auth files, and quota-reserve state.
  • codex_provider_gateway_sidecars/: isolated generated gateways for direct
    external model providers.

Use logger::log_codex_api_info, log_codex_api_warn, and
log_codex_api_error for Rust service messages. The sidecar emits request
diagnostic and usage payloads; inspect its generated manifest only locally because
it can contain credentials.

Debug Checklist

  1. Call codex_local_access_get_state: confirm collection.enabled, running,
    baseUrl, lastError, selected account count, mode, and port.
  2. Verify the configured port is free or use codex_local_access_kill_port only
    after identifying the owning process.
  3. In sidecar mode, inspect generated config/manifest for port, bind host, key
    policy, account auth files, and a fresh fingerprint. Never paste their secrets
    into issues, docs, or commits.
  4. Run the built-in codex_local_access_test or chat test, then query request logs
    using codex_local_access_query_request_logs. Correlate request ID, account,
    API key, status, error category, and upstream transport.
  5. If Codex itself does not use the gateway, inspect the target profile's managed
    auth.json and config.toml, then check the saved takeover backup before any
    manual reset. For WSL, verify the resolved WSL access plan and relay.
  6. For account rotation faults, check eligibility, quota reserve, cooldown/health,
    account-model restrictions, and session affinity before changing retry limits.

Coding Conventions

  • TypeScript uses React function components, async service wrappers, camelCase
    payloads, and explicit types from src/types.
  • Rust uses Result<T, String> at Tauri boundaries, async lifecycle functions,
    serialized camelCase model fields, and structured helper functions in the module.
  • Keep persistence changes backward compatible: all new serialized fields need a
    serde(default) migration story.
  • Keep secrets out of logs. Redact proxy URLs and API keys; generated runtime files
    are local artifacts, not test fixtures.
  • Add focused tests next to the behavior. Existing coverage is concentrated in the
    bottom #[cfg(test)] module of codex_local_access.rs, the Go sidecar tests,
    and tests/codexLocalAccessAccounts.test.ts.

Completed And Next Work

Completed: repository import, source map, service-flow review, and this handoff
document.

Before implementing a change, identify whether it belongs to the UI contract, the
generated sidecar contract, or both. Test both the OpenAI-compatible request path
and Codex profile takeover/restore whenever the change affects activation, keys,
base URLs, models, routing, or credentials.


CODEX MIXED MODEL ROUTING DESIGN (`docs/CODEX_MIXED_MODEL_ROUTING_DESIGN.md`)

Codex Desktop Mixed Model Routing Design

Status

  • Repository baseline: upstream/main at 18055d05, Cockpit Tools v1.3.34.
  • Scope: local work-in-progress implementation on codex/mixed-model-routing.
  • Isolation: the feature is default-off and has only been exercised with the
    development data directory; the installed Cockpit Tools profile is unchanged.
  • Decision: the feature is feasible as an opt-in extension of the existing
    cockpit-cliproxy sidecar. It does not require a custom codex-server or a
    second Codex app-server.

User Goal

One Codex Desktop instance keeps one directly signed-in ChatGPT/Codex subscription
account, while selected models use configured third-party API accounts:

text
gpt-5.6-sol          -> directly signed-in subscription OAuth
cpa/gpt-5.6-sol      -> CPA API, upstream model gpt-5.6-sol
cpa/grok-4.6     -> CPA API, upstream model grok-4.6
deepseek/deepseek-v4-flash -> DeepSeek API

The source is determined by the full client-visible model ID. A GPT model under
an API namespace is still an API model. It must never silently fall back to the
subscription route.

Current Architecture

Cockpit Tools currently has four relevant layers:

mermaid
flowchart LR
  UI[React / Vite UI]
  Rust[Tauri / Rust instance and account management]
  Sidecar[cockpit-cliproxy Go sidecar]
  AppServer[Official Codex app-server]
  Official[ChatGPT Codex subscription upstream]
  Provider[Third-party provider / CPA]

  UI --> Rust
  Rust -->|writes auth.json, config.toml, catalog| AppServer
  AppServer -->|OpenAI-compatible HTTP| Sidecar
  Sidecar --> Official
  Sidecar --> Provider

Important current behavior:

  1. An instance has one bind_account_id in
    src-tauri/src/models/instance.rs.
  2. API Key accounts may bind an OAuth account. Cockpit then writes OAuth identity
    and an API provider override into the same profile. This is identity dual-track,
    but requests still use one instance-wide model_provider.
  3. The profile takeover implementation already backs up and restores managed
    auth.json and config.toml state.
  4. cockpit-cliproxy already reads the request JSON model, validates the model,
    selects OAuth credentials, calls Provider Gateway endpoints, translates
    Responses/Chat Completions, streams responses, and records usage diagnostics.
  5. A current apiKeySpec chooses either OAuth execution or one
    ProviderGateway for the whole client key. It does not choose by model.

Feasibility Assessment

Feasible without another app-server

The official Codex app-server already owns conversation state, rollout files,
tool approvals, shell execution, fork/archive behavior, and model selection. The
selected model is included in the HTTP request body received by the sidecar.
Therefore the egress decision can be made after the app-server has chosen the
model and before the upstream request is sent.

Running two app-servers would create unnecessary state ownership problems:

  • conversation and rollout synchronization;
  • duplicate approval/tool state;
  • cancellation and streaming ownership;
  • fork/archive consistency;
  • OAuth refresh-token competition;
  • recovery after either server exits.

The design keeps exactly one official app-server.

Confirmed reusable capabilities

  • Model IDs allow /, so names such as cpa/gpt-5.6-sol pass Cockpit catalog
    validation.
  • The sidecar receives the actual selected model in request JSON.
  • Provider Gateway already supports model rewrite, request translation, streaming,
    vision capability checks, and provider header isolation.
  • Profile takeover already has backup and restoration behavior.
  • Sidecar OAuth auth files intentionally exclude refresh_token; Cockpit remains
    the token authority and avoids competing with the official client for a
    one-time refresh token.

Validation status

  • Confirmed by automated tests:
    • slash-namespaced IDs are preserved in the managed catalog and resolved by the
      sidecar;
    • bare models use the isolated OAuth route while namespaced models use the API
      route;
    • OAuth access-token updates reach a running sidecar without copying the
      refresh token;
    • partial profile takeover failure restores the previous profile snapshot.
  • Still required before production readiness:
  1. Confirm Codex Desktop can complete a real slash-namespaced request through a
    disposable desktop instance.
  2. Confirm compaction behavior for API-routed models.
  3. Confirm capability behavior for Responses WebSocket, web search, image input,
    image generation, and realtime endpoints.

Proposed Architecture

mermaid
flowchart TD
  Desktop[Codex Desktop]
  AppServer[One official app-server]
  LocalProvider[codex_local_access provider]
  Router[Model route resolver in cockpit-cliproxy]
  OAuth[OAuth executor and account selector]
  Gateway[Provider Gateway executor]
  Subscription[chatgpt.com/backend-api/codex]
  CPA[CPA / third-party API]

  Desktop --> AppServer
  AppServer --> LocalProvider
  LocalProvider --> Router
  Router -->|bare model: gpt-5.6-sol| OAuth
  OAuth --> Subscription
  Router -->|namespace: cpa/*, strip cpa/| Gateway
  Gateway --> CPA

The instance remains logged in with the existing bound OAuth account. Cockpit
changes only the model HTTP egress by pointing the instance at one local sidecar.

Persistent Data Model

Do not overload bind_account_id.

  • bind_account_id: the direct login identity. When mixed routing is enabled it
    must resolve to an OAuth subscription account.
  • model_routing: independent API egress configuration.

Proposed Rust shape:

rust
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CodexInstanceModelRouting {
    #[serde(default)]
    pub enabled: bool,
    #[serde(default = "default_model_routing_version")]
    pub version: u32,
    #[serde(default)]
    pub routes: Vec<CodexInstanceApiRoute>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CodexInstanceApiRoute {
    pub id: String,
    pub namespace: String,
    pub provider_account_id: String,
    #[serde(default = "default_true")]
    pub enabled: bool,
}

Add model_routing with #[serde(default, skip_serializing_if = "Option::is_none")]
to both InstanceProfile and DefaultInstanceSettings. Existing stores deserialize
without migration, and disabled or absent routing uses the exact current launch
path.

Validation rules:

  • mixed routing is Desktop App only in the first release;
  • bind_account_id must be a real OAuth account, not API Service, Provider Gateway,
    API Key, Agent Identity, or an unbound profile;
  • every route account must be an enabled API Key account with a usable Base URL,
    API key, wire API, and non-empty model catalog;
  • namespaces are lowercase, unique, 2-32 characters, and match
    [a-z0-9][a-z0-9_-]*;
  • reserved namespaces include official, subscription, openai, codex, and
    internal Cockpit model IDs;
  • deleting or disabling an API account leaves the instance configuration visible
    but invalid. Launch fails with a precise validation error until repaired;
  • failure policy is fixed to strict in v1 and is not user-configurable.

Generated Sidecar Contract

Keep the existing API key behavior untouched when modelRouting is absent.

Proposed manifest extension:

json
{
  "apiKeys": [
    {
      "id": "instance_mixed_123",
      "key": "local-client-secret",
      "enabled": true,
      "accountIds": ["oauth-account-id"],
      "modelRouting": {
        "defaultRoute": "oauth",
        "failurePolicy": "strict",
        "routes": [
          {
            "id": "route-cpa",
            "namespace": "cpa",
            "providerAccountId": "api-account-id",
            "providerGateway": {
              "baseUrl": "https://cpa.example/v1",
              "apiKey": "secret",
              "wireApi": "responses",
              "upstreamModels": ["gpt-5.6-sol", "grok-4.6"]
            }
          }
        ]
      }
    }
  ]
}

The frontend never receives provider secrets. Rust resolves provider_account_id
to the current account record and materializes the generated manifest only in the
local sidecar runtime directory with hardened permissions.

Request Routing Algorithm

Routing must happen before the existing provider-wide canonicalization removes
information from the client model ID.

text
1. Authenticate the local client API key.
2. Parse the raw request model.
3. Remove only the API key's outer modelPrefix, if configured.
4. If modelRouting is absent, execute the existing code unchanged.
5. If the model starts with a configured namespace plus "/":
   a. select that API route;
   b. strip exactly one namespace prefix;
   c. reject an empty upstream model;
   d. verify the upstream model is in that route's provider catalog;
   e. execute through that route's Provider Gateway.
6. If the model contains a namespace that is missing, disabled, or invalid:
   return model_route_not_available. Never fall back to OAuth.
7. Otherwise treat it as a bare model:
   a. verify it is visible as an official/subscription model;
   b. select only the bound OAuth account;
   c. execute through the existing OAuth path.
8. Record both clientModel and upstreamModel plus route kind/id.

Examples:

Client model Route Upstream model
gpt-5.6-sol OAuth subscription gpt-5.6-sol
cpa/gpt-5.6-sol CPA Provider Gateway gpt-5.6-sol
cpa/grok-4.6 CPA Provider Gateway grok-4.6
missing/gpt-5.6-sol error none

Do not use heuristic routing such as "all GPT goes official". Namespace ownership
is the routing contract.

Model Catalog and Model Management UI

The source should be visible in the existing model manager without adding source
metadata to Codex's catalog JSON. Cockpit can derive the source from the model ID
and active instance routes.

Instance edit page

Insert a new section between 绑定账号 and 自定义启动参数:

text
模型路由
  [toggle] 混合模型路由(实验)

  登录渠道
  [email protected]    订阅 OAuth    正常

  API 渠道
  CPA       namespace: cpa       2 models       正常     [编辑] [删除]
  DeepSeek  namespace: deepseek  2 models       正常     [编辑] [删除]

  [+ 添加 API 渠道]

Behavior:

  • default is off;
  • enabling requires an OAuth account in the existing account selector;
  • API channel picker lists API Key accounts only;
  • namespace is suggested from provider ID/name and remains editable;
  • save performs local validation but does not modify a running instance silently;
  • a running instance shows 保存并重启 or 仅保存,稍后生效;
  • the instance list continues to show the OAuth login account and adds a compact
    混合路由 status next to it. It must not display CPA as the login identity.

Model manager

Add a 来源 column:

展示名 模型 ID 来源 推理强度 上下文与压缩
5.6 Sol gpt-5.6-sol 订阅 跟随官方 跟随模型
5.6 Sol CPA cpa/gpt-5.6-sol CPA 跟随官方 跟随模型
Grok 4.6 CPA cpa/grok-4.6 CPA 跟随官方 516K/460K

When adding a model, use a source selector:

text
来源: [订阅 | API 渠道]

订阅:
  model ID = gpt-5.6-sol

API 渠道:
  channel = CPA
  upstream model = grok-4.6
  generated model ID = cpa/grok-4.6

The generated namespaced ID is editable only through the channel namespace or
upstream model fields, preventing accidental route/source mismatch.

Route-derived UI states:

  • 订阅: no configured namespace prefix;
  • provider name: prefix matches one enabled route;
  • 路由缺失: prefix exists in the model ID but no route owns it;
  • 账号不可用: route exists but its provider account is missing/disabled;
  • 模型不存在: upstream model is no longer in the provider account catalog.

Lifecycle and Rollback

Launch

mermaid
sequenceDiagram
  participant UI
  participant Rust
  participant Token as Token Authority
  participant Sidecar
  participant App as Codex Desktop

  UI->>Rust: Start instance
  Rust->>Rust: Validate mixed routing config
  Rust->>Token: Preflight bound OAuth account
  Token-->>Rust: Fresh access token snapshot
  Rust->>Rust: Backup profile takeover state
  Rust->>Rust: Build mixed collection + manifest + catalog
  Rust->>Sidecar: Start isolated sidecar
  Sidecar-->>Rust: ready + health result
  Rust->>Rust: Write codex_local_access profile provider
  Rust->>App: Launch official Codex Desktop

The safer order is sidecar-ready before launching Codex. If sidecar startup or
health validation fails, restore the profile backup and do not start the app.

Update while running

Do not rewrite an active sidecar manifest in place. Save the desired instance
configuration, then perform an explicit controlled restart:

  1. stop Codex Desktop for that instance;
  2. stop the instance sidecar;
  3. build a new sidecar directory and manifest atomically;
  4. start and probe the new sidecar;
  5. apply profile takeover and restart Codex;
  6. remove the old runtime directory only after success.

Disable or delete

  • stop only the sidecar owned by that profile and routing configuration;
  • restore the existing takeover backup;
  • remove only Cockpit-managed model catalog/provider fields;
  • preserve unrelated user config.toml keys and existing user changes;
  • if restore fails, keep the backup and show a blocking recovery action;
  • disabling mixed routing must not disable the global API Service or other
    Provider Gateway instances.

OAuth Token Refresh

The isolated mixed sidecar must not receive a refresh token. Add a profile-sidecar
credential refresh coordinator:

  1. runtime state records profile_dir, sidecar_auth_dir, and OAuth account IDs;
  2. before access-token expiry, Rust calls the existing managed-account refresh;
  3. Rust atomically rewrites the matching sidecar auth file;
  4. the sidecar file watcher reloads the access token;
  5. refresh errors update instance route health but do not switch to an API route;
  6. stopping the sidecar cancels its refresh task.

This avoids refresh-token races and prevents a mixed instance from working only
until the initial access token expires.

Endpoint Capability Policy

The primary target is Codex Desktop text/coding traffic over POST Responses.
Other endpoints require explicit behavior:

Capability Subscription model API model v1 policy
POST /v1/responses OAuth Provider Gateway
Streaming Responses OAuth stream Provider stream/translation
Tool schemas and tool output existing path existing provider translation path
Image input official capability provider capability/vision route
POST /v1/responses/compact OAuth provider only when declared; otherwise strict error
Responses WebSocket supported when enabled disabled in v1 unless provider explicitly supports it
alpha/search web search OAuth unsupported in v1 unless an API route implements it
Codex Live / Realtime OAuth only unsupported in v1
Image generation/edit endpoints OAuth policy separate provider capability, not inferred from text routing

For the first implementation, disable prefer_websockets for the entire mixed
instance unless per-model WebSocket routing is implemented. SSE remains the
consistent transport for both routes.

Compaction must never fall back from an API model to OAuth because that would send
third-party conversation content to the subscription upstream. Unsupported
capabilities fail clearly and remain visible in the UI.

CPA and Privacy Boundary

CPA and cockpit-cliproxy are not byte-for-byte blind tunnels. They parse and may
transform the complete request/response JSON to handle model names, Responses vs
Chat Completions, tool schemas, images, streaming, retries, and usage. They do not
perform model inference, but they can technically see conversation content and
tool parameters.

Cockpit's request-log database should continue to store metadata only. Add two
hardening rules for mixed routing:

  • persist routeKind, routeId, providerAccountId, clientModel, and
    upstreamModel, but never prompt or response bodies;
  • sanitize and bound stored error_message so an upstream error cannot echo and
    persist request content. Full raw upstream bodies may only appear in an explicit,
    temporary debug mode and must be redacted before issue export.

Provider requests must use a newly created HTTP request with:

  • only the route's API key in Authorization;
  • no OAuth bearer token or Chatgpt-Account-Id;
  • only the existing allowlisted diagnostic headers;
  • no unrelated provider headers from another route.

Health and Diagnostics

Add a per-instance route health result:

text
subscription: ready / token_refresh_due / auth_failed
cpa: ready / account_missing / catalog_empty / provider_unreachable / auth_failed
deepseek: ready / capability_limited / provider_unreachable

Launch health checks should validate configuration and local sidecar readiness.
They should not send a paid model request automatically. The UI can provide an
explicit 测试路由 command that sends a minimal user-authorized request and
shows:

  • client model;
  • resolved route and provider;
  • upstream model;
  • protocol;
  • latency and HTTP status;
  • no prompt/response body in persistent diagnostics.

Compatibility Guardrails

  1. model_routing absent or disabled executes the current code path without a
    mixed sidecar or new catalog behavior.
  2. Existing OAuth-only, API Key, API Service, Provider Gateway, CLI, DeepSeek
    direct/CDP, and account-pool modes remain valid.
  3. V1 rejects mixed routing for CLI launch mode rather than changing CLI behavior.
  4. Existing ProviderGateway manifest fields remain supported; modelRouting is
    additive.
  5. All new Rust fields use serde defaults and optional serialization.
  6. No automatic migration converts an existing CPA instance into mixed mode.
  7. No fallback crosses trust boundaries. Route errors are explicit.

Test Matrix

Go sidecar unit tests

  • bare official model resolves to OAuth;
  • cpa/gpt-5.6-sol resolves to CPA and rewrites body model to gpt-5.6-sol;
  • third-party GPT never selects OAuth;
  • missing/disabled namespace returns model_route_not_available;
  • route catalogs are merged into /v1/models with namespaced IDs;
  • duplicate/reserved namespaces are rejected;
  • provider and OAuth headers never cross routes;
  • API route errors do not trigger OAuth retry;
  • route diagnostics include client and upstream models;
  • mixed mode absent preserves current tests unchanged.

Rust tests

  • old instance stores deserialize with no routing config;
  • mixed config validation accepts OAuth + API route and rejects every invalid
    account combination;
  • generated manifest contains no route when disabled;
  • generated manifest materializes current provider secrets only at runtime;
  • profile takeover backup/restore is idempotent;
  • sidecar startup failure restores profile state;
  • token refresh rewrites all active profile-sidecar auth files for that account;
  • stopping one instance does not stop another instance's sidecar;
  • deleting an API account marks dependent routes invalid without deleting them.

Frontend tests

  • toggle defaults off;
  • API routes are hidden when off and preserved when toggled back on before save;
  • OAuth/API account pickers use the correct account types;
  • source column derives subscription/API/missing states correctly;
  • API model creation generates the namespace ID;
  • running instance save presents restart choices;
  • validation errors prevent save and focus the affected route/model.

Local end-to-end acceptance

Use a new isolated test instance. Do not modify the user's current default or CPA
instances.

  1. gpt-5.6-sol completes through the signed-in subscription account.
  2. cpa/gpt-5.6-sol completes through CPA.
  3. cpa/grok-4.6 completes through CPA.
  4. Route logs prove the selected route and upstream model for each request.
  5. Continue one conversation while switching models and verify history remains in
    one app-server thread.
  6. Verify shell, apply_patch, approvals, cancellation, fork, archive, restore,
    sub-agent, image input, and session reopen.
  7. Force/await OAuth access-token refresh and verify the running instance continues.
  8. Exercise a long context to observe compaction behavior.
  9. Disable mixed routing and verify the profile restores and ordinary Cockpit
    instance operations still work.

Delivery Phases

Phase 0: technical spike

  • add sidecar-only route resolution behind an internal development flag;
  • use a fake local upstream to prove namespace stripping and header isolation;
  • run one real slash-model request through a disposable Codex Desktop instance;
  • verify token refresh and compaction before committing to the full UI.

Phase 1: hidden experimental implementation

  • persistent instance routing schema;
  • Rust mixed collection/manifest builder;
  • sidecar strict model router;
  • isolated lifecycle and token-refresh coordinator;
  • no public UI beyond a guarded developer switch.

Phase 2: instance and model UI

  • instance route editor;
  • model source column and source-aware add flow;
  • route health, restart confirmation, and diagnostics;
  • localization and frontend tests.

Phase 3: capability expansion

  • per-model Responses WebSocket support;
  • provider compact/search capabilities;
  • optional image-generation routes;
  • CLI support only after Desktop behavior is stable.

Bridge Fallback

A custom CODEX_CLI_PATH bridge or separate CodexSplit-style server remains a
fallback, not the first implementation. Use it only if the technical spike proves
that the official app-server rewrites namespaced models before the sidecar, does
not send the selected model reliably, or requires an unhookable transport path.

The bridge has a larger blast radius because it replaces or wraps app-server
startup and protocol handling. The current sidecar route design preserves more of
Cockpit Tools and the official Codex client unchanged.

Final Recommendation

Proceed with the sidecar-based design, but treat Phase 0 as a mandatory go/no-go
gate. The central architecture is sound; the highest-risk items are long-running
OAuth token delivery and capability parity, not basic model routing. Keep the
feature default-off, Desktop-only, strict-failure, and isolated to a disposable
test instance until the acceptance matrix passes.


CODEX RESERVE COMPATIBILITY (`docs/CODEX_RESERVE_COMPATIBILITY.md`)

Codex Luna Reserve compatibility

Verified source

Inspected the installed official client on 2026-09-05:

  • Application: /Applications/ChatGPT.app
  • Bundle identifier: com.openai.codex
  • Version: 26.901.31953 (build 7868)
  • Archive: Contents/Resources/app.asar
  • Relevant entries: webview/assets/app-initial-caa927532ffb.js and
    webview/assets/app-primary-37ff25fd4643.js
  • The bundled Contents/Resources/codex model JSON has a Luna entry but no
    dedicated gpt-reserve entry. This is a bundled fallback, not an account's
    live server model catalog.

Official behavior

gpt-reserve is the request ID for temporary Luna Reserve, not an ordinary
permanent model choice. The client requires eligible ChatGPT authentication,
matching account/user/plan data, a compatible client version, and official
feature gates (including reserve_enabled). Its activation predicate includes:

javascript
const reserveAllowed = status.additional_rate_limits?.some(
  ({ limit_name, rate_limit }) =>
    limit_name === "gpt-reserve" && rate_limit?.allowed === true,
);
const active = status.rate_limit_upsell?.banner_type === "luna_reserve"
  && status.rate_limit?.allowed === false
  && reserveAllowed === true;

The picker looks for gpt-reserve, falling back to gpt-5.6-luna, then copies
that entry with the request model set to gpt-reserve. It displays the entry's
Luna name with a moon indicator. The sidebar calls the allowance "Luna Reserve".
The original model and reasoning effort are remembered and restored when the
mode ends; selecting Reserve does not replace the persisted advanced-model
default. API-key authentication does not satisfy the official activation gate.

Cockpit's explicitly approved manual-selection design

Unlike the official automatic fallback UI, Cockpit exposes a permanent
Luna Reserve choice (gpt-reserve) for manual selection. This intentional
product difference was approved by the user on 2026-09-05.

  • API Service and managed catalogs list Reserve regardless of whether any account
    is currently eligible. Saved managed lists also gain the option; existing
    entries and the user's default remain unchanged. Explicit API model allowlists,
    exclusions and prefixes still apply.
  • Listing and model admission are separate from account selection. A request
    keeps the literal gpt-reserve ID (apart from explicit user aliases). Only
    scoped OAuth accounts satisfying all three quota predicates in the example
    above may be selected. Ordinary accounts and eligible accounts outside the
    client's API key scope cannot be used as fallback. Missing quota data fails
    closed. Authentication, disablement and runtime cooldown checks still apply.
  • No eligible account means a normal account-pool error; there is no automatic
    switch to Luna, Astra or another model. Server acceptance remains authoritative.
  • If a dedicated model template is absent, capabilities derive from the existing
    Luna template. A supplied dedicated template takes precedence. The display name
    is "Luna Reserve" to distinguish it from ordinary Luna.
  • No fixed compaction threshold is introduced. Explicit user context settings
    remain explicit, and disabling the visible-model override uses the existing
    removal path.
  • Neither the official installation nor official feature gates are patched. A
    local API-key session is not made to impersonate ChatGPT authentication or to
    activate the official moon indicator or automatic quota fallback.

The bundled Luna metadata can differ from account-specific server metadata.
This implementation preserves the currently integrated Luna template; it does
not claim separate official Reserve limits or copy all fields from a new
official bundle into unrelated models.


☕ Support this Project

If you find this project useful, you can support its development by making a donation.

Your support is greatly appreciated! ❤️


💰 Crypto Donation

  • ETH Address: 0xc75d68fe59e4b44904b1CAa1Da4FDfEddD780aef

  • SOLANA Address: 6yNHzh6e3LLbYrJZg7ayhNZyCKazQZTTYWnfz9i87Zeo


🙏 Acknowledgments

Every bit of support motivates me to keep improving this project. Thank you for your generosity!


📝 Note

  • Donations are completely voluntary and do not affect your ability to use any features of this project.
  • If you have any questions or suggestions, please feel free to give feedback via GitHub Issues.

☕ 赞助支持

感谢您使用 Cockpit Tools!

如果这个项目对您有帮助,欢迎通过以下方式赞助项目的持续开发和维护:


💝 赞助方式

支付宝

微信支付

💰 Crypto Donation

  • ETH Address: 0xc75d68fe59e4b44904b1CAa1Da4FDfEddD780aef

  • SOLANA Address: 6yNHzh6e3LLbYrJZg7ayhNZyCKazQZTTYWnfz9i87Zeo


🙏 致谢

您的每一份支持都是对开源项目最大的鼓励!

无论金额大小,都代表着您对这个项目的认可。感谢您的慷慨!


📝 说明

  • 赞助完全自愿,不影响您使用本项目的任何功能
  • 如有任何问题或建议,欢迎通过 GitHub Issues 反馈

☕ Apoie este projeto

Se você achar este projeto útil, pode apoiar o seu desenvolvimento fazendo uma doação.

Seu apoio é muito apreciado! ❤️


💰 Doação em Criptomoedas

  • ETH Address: 0xc75d68fe59e4b44904b1CAa1Da4FDfEddD780aef

  • SOLANA Address: 6yNHzh6e3LLbYrJZg7ayhNZyCKazQZTTYWnfz9i87Zeo


🙏 Agradecimentos

Todo apoio me motiva a continuar aprimorando este projeto. Obrigado pela sua generosidade!


📝 Observação

  • As doações são totalmente voluntárias e não afetam sua capacidade de usar nenhum recurso deste projeto.

  • Se você tiver alguma dúvida ou sugestão, sinta-se à vontade para enviar seu feedback através de GitHub Issues.


TAURI BUILD GUIDE (`docs/TAURI_BUILD_GUIDE.md`)

Cockpit Tools 编译与打包硬性规范(避坑备忘录)

【血的教训 · 严禁违背】
绝对禁止在本项目中直接执行 cargo build --release 来试图构建发布可执行文件!


核心故障现象与根因

1. 现象("编译了一个 debug 的主页面没有的白屏程序")

如果直接在根目录或 src-tauri 目录执行 cargo build --release --bin cockpit-tools:

  • 生成的 cockpit-tools.exe 大小仅约 88 MB(正常包含前端的二进制约为 93.6 MB,缺失整整 5.3 MB 的前端静态资源);
  • 打开程序后,主窗口是一个纯白空白窗口(内存占用仅 13 MB,正常渲染的主界面内存占用在 80~200 MB 以上);
  • 根因:Tauri 项目在 tauri.conf.json 中配置了 "devUrl": "http://localhost:1420"。直接使用 cargo build 时,Tauri 宏会保留开发期配置,将 Webview 指向开发服务器 http://localhost:1420;而此时本地根本没有启动 Vite 开发服务器,导致窗口载入失败全白!

2. 为什么开发者/AI 容易误入歧途?

  • 在 Windows 环境下,cargo.exe 位于用户目录 %USERPROFILE%\.cargo\bin,有时未被包含在全局 Shell 的 PATH 中;
  • 运行 npm run tauri build 时,Tauri CLI 尝试调用 cargo metadata,若 PATH 缺失会报错:program not found;
  • 很多人一看到这个报错,偷懒直接用绝对路径去跑 $env:USERPROFILE\.cargo\bin\cargo.exe build --release,从而掉入**无主页面(白屏)**的致命陷阱!

唯一正确的发布编译命令

本项目已在 scripts/tauri.cjs 中配置了工具链自愈逻辑(自动寻找 %USERPROFILE%\.cargo\bin、Go\bin 以及 Visual Studio 的 vcvars64.bat):

1. 编译并打包单可执行文件(推荐日常部署):

powershell
npm run tauri build -- --no-bundle
  • 该命令会自动触发 beforeBuildCommand(即 npm run build,编译 TS 与 Vite 前端到 dist/);
  • 自动剔除 devUrl,强制将 frontendDist(dist/ 中的 HTML/CSS/JS)内嵌打包至二进制中;
  • 产物路径:target/release/cockpit-tools.exe(大小约 93.6 MB)。

2. 构建包含完整安装包(NSIS / MSI):

powershell
npm run tauri build

二进制有效性三步自检(动刀后必验)

在将新生成的 cockpit-tools.exe 复制到部署目录 C:\Users\zouta\AppData\Local\Cockpit Tools\ 前,必须按如下标准自检:

  1. 体积核对:
    • 包含前端的正常体积:≥ 93 MB(如 93,607,936 字节);
    • 若只有 88 MB,说明犯错走了直接 cargo build,严禁发布!
  2. 进程拉起内存检查:
    • 运行后执行 Get-Process -Name cockpit-tools;
    • 正常加载前端的主进程 WorkingSet 必须达到 80 MB 以上;若只有 13 MB,必定是白屏!
  3. 子进程检查:
    • 正常运行必须伴随 msedgewebview2.exe 的渲染进程启动。

Build Wsl2 Ubuntu24 (`docs/build-wsl2-ubuntu24.md`)

Ubuntu 24.04 编译指导

本文档用于在 Ubuntu 24.04 环境中本地编译 Cockpit Tools。WSL2 的 Ubuntu 24.04 也按本文档执行。

注意:项目官方发布目标是 macOS 和 Windows,Linux/Ubuntu 不是官方发布目标。本文档用于本地验证和自用构建。

兼容性声明:当前 Linux/Ubuntu 仅验证 Ubuntu 24.04 LTS。Ubuntu 20.04 缺少当前构建需要的 WebKitGTK 4.1、OpenSSL 3 与较新的 glibc,不支持;Ubuntu 26 尚未完成兼容性验证,遇到问题需提供日志后再判断。

系统要求

操作系统:

bash
cat /etc/os-release
uname -a

确认输出中包含 Ubuntu 24.04:

text
VERSION_ID="24.04"

如果在 WSL2 中编译,可额外确认:

bash
grep -i microsoft /proc/version

仓库目录约定:

text
~/codes/cockpit-tools

Node.js 要求:

text
nvm 0.40.4
Node.js 24
npm 9+

Rust 要求:

text
Rust stable
Cargo 可用

Tauri Linux 编译要求:

text
GTK 3
WebKitGTK 4.1
AppIndicator
OpenSSL
pkg-config
基础 C/C++ 编译工具链

安装依赖

可选:如果 Ubuntu 官方源下载速度慢,可以使用阿里云 Ubuntu 镜像加速系统依赖下载:

bash
sudo cp /etc/apt/sources.list.d/ubuntu.sources \
  /etc/apt/sources.list.d/ubuntu.sources.ubuntu24-build-bak

sudo sed -i \
  's#http://archive.ubuntu.com/ubuntu/#https://mirrors.aliyun.com/ubuntu/#g; s#http://security.ubuntu.com/ubuntu/#https://mirrors.aliyun.com/ubuntu/#g; s#https://mirrors.tuna.tsinghua.edu.cn/ubuntu/#https://mirrors.aliyun.com/ubuntu/#g' \
  /etc/apt/sources.list.d/ubuntu.sources

sudo apt-get update

安装 Ubuntu/Tauri 系统依赖:

bash
sudo apt-get update

sudo apt-get install -y \
  build-essential \
  ca-certificates \
  curl \
  file \
  git \
  pkg-config \
  wget \
  libssl-dev \
  libgtk-3-dev \
  libwebkit2gtk-4.1-dev \
  libayatana-appindicator3-dev \
  librsvg2-dev \
  libxdo-dev

检查 GTK 和 WebKitGTK:

bash
pkg-config --modversion gtk+-3.0
pkg-config --modversion webkit2gtk-4.1

把仓库 clone 到 ~/codes:

bash
mkdir -p ~/codes
cd ~/codes

if [ ! -d cockpit-tools/.git ]; then
  git clone https://github.com/jlcodes99/cockpit-tools.git cockpit-tools
fi

cd ~/codes/cockpit-tools
test -f package.json && test -f src-tauri/tauri.conf.json && pwd

安装 Rust stable。如果已经安装过 Rust stable,并且 rustc --version、cargo --version 都能正常输出,可以跳过安装命令,只保留版本检查:

bash
if ! command -v cargo >/dev/null 2>&1; then
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
    | sh -s -- -y --profile minimal --default-toolchain stable
fi

. "$HOME/.cargo/env"

rustc --version
cargo --version

如果 Rust 已安装但版本较旧,更新 stable 工具链:

bash
rustup update stable
rustup default stable
rustc --version
cargo --version

安装或更新 nvm 到 0.40.4,并安装 Node.js 24。如果已经安装过 nvm 0.40.4 和 Node.js 24,可以跳过安装命令,只保留版本检查:

bash
export NVM_DIR="$HOME/.nvm"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

. "$NVM_DIR/nvm.sh"
nvm --version
nvm install 24
nvm use 24
nvm alias default 24

node -v
npm -v

如果 nvm 已安装但版本不是 0.40.4,重新执行上面的 nvm 安装命令即可更新。

确认 nvm 是 0.40.4:

bash
test "$(nvm --version)" = "0.40.4" && echo "nvm 0.40.4 OK"

确认 Node.js 是 24:

bash
node -e '
const major = Number(process.versions.node.split(".")[0]);
if (major !== 24) {
  console.error(`Node.js ${process.versions.node} is not 24.x.`);
  process.exit(1);
}
console.log(`Node.js ${process.versions.node} OK`);
'

依赖安装完成后,关闭当前 shell 窗口,重新打开一个 Ubuntu 24.04 shell 窗口。这样 nvm 和 Cargo 的环境变量会从 shell 启动脚本自动加载,后面的命令可以更短。

新 shell 窗口打开后执行:

bash
cd ~/codes/cockpit-tools

node -v
npm -v
nvm --version
cargo --version

确认 node -v 输出为 v24.x.x,nvm --version 输出为 0.40.4 后,再继续下面的编译步骤。

进行编译

以下命令默认都在新打开的 shell 中执行,并且当前目录是:

bash
cd ~/codes/cockpit-tools

安装前端依赖:

bash
npm ci --cache .npm-cache

不要用 sudo npm ... 编译项目。sudo 可能会切到系统自带的旧 Node.js,导致 Vite 报错。

编译前检查 Rust / Node.js 版本是否匹配本文档要求:

bash
node - <<'NODE'
const major = Number(process.versions.node.split(".")[0]);
if (major !== 24) {
  console.error(`Node.js ${process.versions.node} is not 24.x.`);
  process.exit(1);
}
console.log(`Node.js ${process.versions.node} OK`);
NODE

cargo --version

本地 Ubuntu 24.04 编译时,先临时关闭 Tauri updater artifacts。

原因:src-tauri/tauri.conf.json 中配置了:

json
"createUpdaterArtifacts": true

本地通常没有发布签名私钥。保持该配置会在打包完成后失败:

text
A public key has been found, but no private key.
Make sure to set TAURI_SIGNING_PRIVATE_KEY environment variable.

编译前先备份配置并临时关闭:

bash
cp src-tauri/tauri.conf.json src-tauri/tauri.conf.json.ubuntu24-build-bak

node - <<'NODE'
const fs = require("fs");
const file = "src-tauri/tauri.conf.json";
const config = JSON.parse(fs.readFileSync(file, "utf8"));

if (!config.bundle) {
  config.bundle = {};
}

config.bundle.createUpdaterArtifacts = false;
fs.writeFileSync(file, `${JSON.stringify(config, null, 2)}\n`);
NODE

确认已经关闭:

bash
node - <<'NODE'
const fs = require("fs");
const config = JSON.parse(fs.readFileSync("src-tauri/tauri.conf.json", "utf8"));
console.log(config.bundle.createUpdaterArtifacts);
process.exit(config.bundle.createUpdaterArtifacts === false ? 0 : 1);
NODE

输出应为:

text
false

执行完整编译和打包:

bash
npm run tauri build

首次编译会下载 Rust crates,release 构建可能需要十几分钟。后续增量编译会快很多。

如果编译失败,先更新 Rust stable 和 Node.js 24,再重新安装 npm 包并重试:

bash
rustup update stable
rustup default stable

nvm install 24
nvm use 24
nvm alias default 24

npm ci --cache .npm-cache
npm run tauri build

编译成功后检查二进制:

bash
ls -lh target/release/cockpit-tools

检查安装包:

bash
find target/release/bundle -maxdepth 2 -type f -printf '%p %s bytes\n'

常见产物:

text
target/release/bundle/deb/Cockpit Tools_0.22.20_amd64.deb
target/release/bundle/rpm/Cockpit Tools-0.22.20-1.x86_64.rpm
target/release/bundle/appimage/Cockpit Tools_0.22.20_amd64.AppImage

如果只想验证二进制能否编译,不需要生成 deb/rpm/AppImage:

bash
npm run tauri -- build --no-bundle

编译完成后恢复 tauri.conf.json:

bash
mv src-tauri/tauri.conf.json.ubuntu24-build-bak src-tauri/tauri.conf.json

确认配置没有留下临时改动:

bash
git diff -- src-tauri/tauri.conf.json

如果没有输出,说明配置已恢复。

开发模式

以下命令默认都在新打开的 shell 中执行,并且当前目录是:

bash
cd ~/codes/cockpit-tools

开发模式会启动 Vite dev server 和 Tauri 应用:

bash
npm run tauri dev

Codex Account Proxy Design (`docs/codex-account-proxy-design.md`)

Codex 账号独立代理(开发中)

目标与边界

  • 仅普通 OAuth 账号;与 Free/Plus/Pro/Team 套餐无关。排除 API Key、模型供应商、Agent Identity、Web Session 与待授权账号。
  • 卡片及表格的「重置」旁放「代理」,不放到底部操作栏;「更多」保留集中管理入口。
  • 用户主动绑定后才生效;未绑定账号维持现有行为。不修改系统代理,不自动迁移或复制登录数据。
  • 保存、运行、出口测试是三个不同状态,不能互相代替。测试服务只收到测试网络请求,不得带账号 Token。
  • 请求失败不静默直连;用户解除绑定或删除绑定来源后,才回到原有代理选择规则。

当前实现与尚未完成项

迁移至 Mihomo 时保留已有来源和账号绑定,不主动联网迁移。旧版导入时被判为不兼容且未保存完整节点配置的条目,需要用户刷新订阅或重新导入后才能按 Mihomo 重新解析;已有可用绑定通过运行时兼容转换继续使用,首次需要主动安装 Mihomo。

已接入:账号入口与资格校验、直接 HTTP/HTTPS/SOCKS5/SOCKS5h 地址校验、隐藏凭据输入、显式出口检测(连接 5 秒、请求 12 秒、出口请求保护 13 秒、含读取与内核启动的整体保护 25 秒、最多 4 并发)、IP/耗时/时间显示。输入变化或离开代理页面不保留过期测试结果。检测进行中可点「取消检测」,离开代理页面也会停止当前账号的检测;取消后不改为直连。运行态面板会显示账号隧道和桌面转接处于空闲、启动中、运行或已停止,不把进程存活当成连通证明。账号文件使用项目既有加密存储,响应统一输出 egress_proxy 协议/服务器/端口摘要;egress_proxy_url 仅在加密账号文件内部和用户主动写入的请求中存在。普通账号导出也只包含摘要,不携带代理凭据,重新导入后需重新配置代理。

节点资源添加、订阅导入、绑定和检测先检查 Mihomo 就绪,再执行实际操作;独立进程内核缺失、损坏或正在安装时保留现有配置并提示安装或修复。节点解析器已经注册,临时节点检测接入独立进程运行层:版本固定检查、随机本地认证、回环 mixed 入站、stdin 配置、8 秒启动超时(另有 3 秒版本检查)、句柄释放时 kill_on_drop、显式停止等待回收、Windows CREATE_NO_WINDOW。运行时不搜索 PATH、不隐式下载安装。内核缺失会明确报错。新增用户主动安装到应用用户目录的路径;兼容既有可执行文件旁、proxy-engine/ 以及 macOS 安装包 Contents/Resources/proxy-engine/ 查找。主安装包不内置内核。

账号运行态现有实现:每账号异步互斥(全局注册锁不跨 I/O)、最多 4 个并发启动、写入新节点前先启动候选、失败保留旧绑定、同步配置生成器只读取已准备的隧道。Token 刷新、额度/重置、订阅查询与宿主上游 HTTP 入口已接入账号代理构建器;无绑定时保留原构建器行为。账号删除释放关联隧道,宿主退出同步向全部登记的内核发送停止信号。集中管理已加入搜索、绑定筛选、链接/表单输入、脱敏摘要;保存后替换输入框清空。

新增授权入口为主动选择:未选择时继续原 OAuth 流程;选择后先取消旧会话,再用输入的代理启动内置 WebView。直接无认证的 HTTP/SOCKS5 地址不依赖节点内核;其他链接通过临时回环转接,WebView 只接收不含凭据的本机地址。临时代理仅保存在内存,持久化 OAuth 状态只记录 proxy_required;重启后丢失转接的会话先作废,不允许换成直连完成令牌交换。授权窗口的弹出新窗口请求会被拒绝,以免从未受控的窗口绕过代理;若登录站点要求弹窗,用户需取消该入口并自行选择原登录方式。令牌交换使用同一代理;代理失效时返回错误。所选代理与新令牌在账号首次保存时一起落盘,此后首次配额查询使用已绑定的代理。当前 macOS 构建未启用 Tauri 的 WebView 代理能力,因此该入口禁用;设备码验证页和外部浏览器不属于受控入口。

代理页面可读取当前账号最近 8 条已完成的本地 API 服务请求,只返回时间、模型、成功状态、HTTP 状态和耗时。它不读取错误正文、密钥或请求内容,也不把历史请求记录当作当前出口证明。实际出口 IP 仍以用户主动进行的限时出口检测为准。

桌面客户端在启动时已有生效代理的情况下,统一接入按账号分配的固定 socks5://127.0.0.1: 入口;端口记录持久化,宿主重启后优先复用。新连接重新解析账号绑定和统一代理,已建立连接保留原出口直至结束。解绑后旧监听继续服务运行中的客户端;再次启动会重新检查绑定,没有生效代理时不再注入该入口,恢复原有代理环境变量和 PAC 参数。启动时未绑定代理的客户端首次绑定后仍需重启。入口只承接 TCP、只监听回环且没有本地认证,不构成本机用户之间的访问控制。入口创建失败会按现有行为不注入代理参数,客户端继续启动,不能据此证明该次启动使用了代理。

调用链覆盖核对(2026-09-25)

以下是源码与代码级测试的覆盖结论,不代表已连接真实远端节点或完成各平台实机验收。共同优先级为「账号独立绑定 > 统一代理 > 对应通道原有出口」;仅符合资格的普通 OAuth 账号参与。

通道 当前接入点与边界
本地 API 服务 Rust 上游请求使用 codex_proxy_runtime::client_builder;Go sidecar 从账号认证文件的 proxy_url 接入 HTTP、WebSocket 与 Token 刷新,启动前准备所需代理。全局服务通过重载机制更新代理配置。
额度查询、已有账号 Token 刷新 先解析该账号生效代理,再构建请求客户端;统一代理读取异常向上传播,不视为已关闭。仅 refresh token 的无账号导入仍沿用原路径。
默认桌面实例、切号并启动 启动事务按目标绑定账号获取固定入口,平台启动器注入代理环境变量和 Electron 参数;默认实例进程识别仍使用默认上下文。
多开桌面实例 按该实例绑定账号解析出口;macOS、Windows、Linux 启动分支均有注入路径,Windows 后台进程继续隐藏控制台。
CLI 实例模式 当前启动命令只设置 profile 的 CODEX_HOME,没有注入账号或统一代理环境变量;不纳入桌面代理覆盖承诺。
实例专属 provider gateway 启动时准备其 OAuth 账号出口;凭据写穿前也需准备代理状态。现有 Go runtime 没有启动认证文件 watcher,单独写文件不证明运行中网关已采用新出口;不承诺统一代理变更对它即时热生效。
OAuth 登录网页 受管代理登录由平台能力决定;macOS 当前未启用 WebView 代理,外部浏览器和设备码网页不受该入口控制。

统一代理状态文件不存在才表示首次关闭;格式缺失、损坏、解密或读取失败保留为可重试错误,不覆盖账号独立绑定,也不生成新的密钥来替换无法读取的旧数据。检测期间切换账号会取消旧请求、释放新账号的操作状态并丢弃迟到结果。删除来源后回读账号列表及当前账号,部分解绑或回读失败保留重试入口。

尚未达到交付标准:长期运行重启和配置变更后现有消费者同步、跨平台内核安装与恢复验收、完整请求路径审计与集成测试、运行态错误分类和上述边界的用户可见说明。离线打包配置已加入目标架构、归档与文件哈希校验,但现有清单 distributionApproved: false 会阻止生成引擎资源配置;正式包仍未附带 Mihomo。不得把当前直接代理/测试的通过视为全部目标完成。

页面内按需安装

  • 内核卡始终出现在代理页面,包括没有 OAuth 账号的情况。进入页面只读取本地状态,不查询网络或自动下载安装;固定支持版本为 Mihomo 1.19.31,显示平台归档名、下载大小、已安装版本。已安装仅代表本地内核状态,不作为代理连通证明。
  • 「下载并安装」从官方 GitHub release 下载;「本地导入」选择对应官方 ZIP/gz,文件不会上传。两种入口采用同一套归档校验和安装流程,安装位置为应用用户目录,不修改系统代理、不发送账号 Token。
  • 任务显示下载/导入字节进度,校验、解压和首次启动检查使用不定进度,避免下载完成被误认为安装完成。首次启动检查独立限制为 30 秒,日常运行版本查询仍为 3 秒;除最终原子启用阶段外可取消。启动超时、执行失败、版本不匹配与归档校验失败分别反馈;日志仅记录错误类型、系统错误码或退出状态,不记录路径、子进程输出及凭据。没有静默更新,重新安装的版本由宿主支持清单决定,不声称总是上游最新版。
  • 离开页面不停止安装;重新进入读取后台任务状态。前端读取状态单飞、每个等待者 10 秒超时、进行中 800ms 串行轮询,卸载后清理定时器和状态回写;读取失败保留上次结果并明确显示状态未知,不假装未安装。
  • 后端只返回固定短错误码,前端只映射本地翻译文案,不显示原始异常、选择文件路径或代理凭据。下载失败可本地导入归档;本地校验不需要联网。

历史按需安装验证记录(sing-box,2026-09-23)

以下仅记录旧 sing-box 实现的验证,不代表本次 Mihomo 迁移已通过同样验证。

  • macOS dev 现场在 22:44:44 开始系统执行检查,22:44:47 记录检查被信号中断及暂存文件已不存在,与安装器 3 秒版本检查超时、随后清理暂存目录一致。此前 ENGINE_INSTALL_VERIFY 丢失了具体原因,并错误映射为压缩包失败。不能仅凭此证明 dev 专属或安全检查最终必定放行;Apple 文档说明系统首次运行会进行安全评估。安装器不修改系统安全策略或移除隔离属性。

  • 针对此现场增加慢启动、超时、执行失败、版本不匹配与取消后进程回收测试。更新后 cargo check -p cockpit-tools、完整 Rust 测试(1443 通过、7 项显式环境测试忽略)、官方本地归档独立安装/重装测试(另行启用并通过)、前端服务测试(5 通过)、TypeScript、18 种语言与差异检查均通过。测试使用隔离临时目录;原生安装窗口的安全检查现场及 Windows/Linux 本次未复测。

  • 安装器常规测试覆盖官方清单、HTTPS 重定向范围、跨进程锁、取消/启用竞态、超时后禁止发布、损坏归档保留旧指针、残留暂存目录恢复、不可变版本记录与运行租约。归档测试覆盖 tar/zip、SHA-256、路径穿越、链接、重复文件、Windows DLL、取消和超时。

  • 在临时目录使用当前 macOS ARM64 官方归档完成真实导入与重新安装,并完成官方 GitHub 下载→校验→解包→版本执行检查→原子启用的代码级测试;两项通过,未写入用户内核目录或账号配置。

  • 使用真实前端组件和模拟 IPC 验证零账号入口、安装进度、取消及完成状态,检查中文浅色与德语深色窄窗口。Windows/Linux 和原生 Tauri 文件选择器尚未进行实机验收。

历史本地内核验证记录(sing-box,2026-09-23)

  • 官方 macOS ARM64 发布归档 sing-box-1.14.1-darwin-arm64.tar.gz SHA-256:b9024642ef7b4848252df5469b7f60ef3c18bb5e217a16a0934f0174f8ad11b4。从 GitHub 发布页核对后下载,未纳入安装包或系统路径。
  • 临时验证路径:/tmp/cockpit-sing-box-verify.oxz9mD/sing-box-1.14.1-darwin-arm64/sing-box。路径是本机临时产物,不可用于正式配置。
  • 当时复验方式(仅适用于迁移前代码):设置 COCKPIT_TEST_SING_BOX 为独立核验过的该版本二进制,执行 cargo test --manifest-path src-tauri/Cargo.toml --lib codex_proxy_engine::tests::real_engine -- --ignored。这些可选外部二进制测试不替代常规测试;不设置路径就不能宣称其通过。
  • 已验证 stdin、随机 SOCKS 认证、本地模拟 HTTP 转发和停止后端口释放;配置 check 不等于真实远端节点连通,也不等于跨平台启动验证。
  • 本轮用上述本地二进制执行 codex_proxy_engine::tests::real_engine 的 3 项代码级集成测试,覆盖常见节点配置、桌面转接的认证代理和进程回收;未连接用户的实际远端节点。

sidecar 认证文件通过私有原子写入替换,不生成明文 .bak;Unix 临时文件从创建起使用 0600,同步或撤销时会清理历史认证备份。

Mihomo 内核迁移(2026-09-24)

  • 固定支持 Mihomo v1.19.31。当前按需安装、运行和本地导入均使用 Mihomo;已安装的 sing-box 不会被误判为可用的新内核。首次使用需用户主动安装或导入,页面读取不触发下载。
  • 每账号独立回环入口与认证、单飞、启动超时、失败不直连、Windows CREATE_NO_WINDOW 和退出回收继续保留。配置经 -f - 从 stdin 输入,凭据不写入配置文件、命令行参数或日志;运行中仍需私有内核工作目录。
  • 已有账号绑定与来源保存不自动重写;旧配置在使用时适配新内核。无法等价处理的参数应明确拒绝,不得静默删除。用户解除绑定或删除绑定来源后回到原有代理规则;源配置更新仍需重新绑定才能应用。
  • 新内核接入不等于所有 Clash 配置均可原样执行:宿主仍控制监听、DNS 和路由,不导入系统代理、TUN、规则、脚本或外部 provider,不开放远程控制面板。节点、分组及证书选项按下述边界处理。
  • 上述改动的验证结论以本次测试为准;文档中的 2026-09-23 sing-box 记录仅为历史证据,不能计作 Mihomo 配置或连通性验证。Windows/Linux 真机运行、原生文件选择器和远端节点连通性仍需分别验收。

公开资料:版本发布页、版本源码、节点配置、分组配置。URI 输入继续参考 Shadowsocks SIP002 和 Hysteria2 URI 规范;出口检测使用 ipify。

分发审查(未完成)

当前采用用户主动下载或导入官方归档的独立进程方式,宿主安装包不内置 Mihomo;此变更不是发版授权,也不是修改主项目许可证的授权。

Mihomo 对应版本的 LICENSE 是分发审查依据。独立进程不自动免除分发义务。附带二进制前仍须核对目标平台及校验和、第三方声明、许可证文本、对应源码提供方式、构建记录、依赖许可证与安装包签名流程。

官方归档与摘要记录于 sidecars/mihomo/upstream-assets.json。离线校验命令 node scripts/verify-proxy-engine-archive.cjs <rust-target> <archive-path> 只验证,不代表允许打包分发。显式准备使用 COCKPIT_PROXY_ENGINE_TARGET=<rust-target> COCKPIT_PROXY_ENGINE_ARCHIVE=<verified-archive> npm run proxy-engine:prepare;未设置时不联网下载,不改变宿主开发流程。

凭据缓存边界

原始代理字段不再随账号列表写入浏览器 localStorage;读取旧缓存时清除该字段并尽力回写。缓存失败不影响账号显示,后端刷新后才恢复绑定摘要,摘要可缓存。启动注入日志不再输出代理 URL 原文。后端账号响应只含脱敏摘要;检测已保存配置使用 proxy_url: null 加账号 ID。加密保存及历史账号加密迁移使用专用存储序列化路径,以免脱敏改动丢失原凭据。

此项是账号专属配置而非平台全局开关,因此不复制到“通用设置”。卡片/表格入口与“更多→代理管理”都进入同一独立页面,共享协议校验、保存和回读接口。

独立页面与界面参考

  • 代理管理和顶部布局均使用宿主页签导航,共享页签顺序与顶部/更多位置配置。卡片入口携带账号 ID 导航到同一代理页。已有布局保留原页签顺序,新增页面缺少配置时默认放入更多。

  • 页面采用可搜索账号侧栏、连接摘要、配置操作区、运行与请求区。小窗口下账号列表改为横向列表,页面正文正常滚动。草稿仅在页面内存中保留,离开页面会清除草稿并取消检测。

  • 账号侧栏提供「批量选择」模式:勾选或全选当前筛选结果后,可把同一节点或分组批量绑定到这些账号,也可批量解除绑定;代理资源页提供「绑定到多个账号」的反向入口。批量绑定复用同一套来源/分组/节点选择与出口检测,默认跳过已使用该节点的账号,确认批量绑定后默认覆盖其他现有绑定,执行前提示覆盖数量,不再提供「仅处理未绑定的账号」选项,部分失败逐账号展示原因,并在弹框错误区提示和自动定位。取消只停止后续写入,正在执行的写入仍同步实际结果,结束后恢复操作;出口检测期间禁用来源切换和批量提交。批量写入的仍是每个账号各自的绑定,不引入隐式继承或共享隧道。

  • 参考 Carbon 侧栏导航原则 支持账号频繁切换,使用本项目色彩、圆角与按钮样式。

  • 参考 Tailscale 控制台的搜索与状态筛选 缩小账号列表,同时明确区分绑定、进程运行和出口检测。

  • 代码验证覆盖类型、构建、布局偏好迁移/回读、代理数据边界与翻译检查。用户明确授权后,使用真实组件、项目样式和虚构账号数据在本地浏览器进行视觉验收,覆盖浅色/深色、中文/德语、1200×800、900×600 和 700×600 视口,以及表单、错误定位、账号切换和更多导航;未连接真实代理或修改真实账号绑定。

  • 视觉细节参考 Linear 界面层级与尺度 和 Vercel Geist 空状态:统一页头、面板和控件尺度;无可用 OAuth 账号时使用静态连接示意、说明和返回账号入口,不渲染无用的空筛选器。装饰图形不表示真实运行状态。

验证要求

  • 正反解析、非法编码/重复参数/凭据脱敏、账号资格前后端一致。
  • 本地模拟代理证明出口检测走所选代理、不携带账户请求头;失败不触达直连目标。
  • 真内核配置检查与本地协议服务集成,异常退出/并发启动/超时回收。
  • 生命周期与 Token 刷新、配额、唤醒、API 服务、客户端/CLI 启动链路的逐项核对。
  • TypeScript、翻译三项检查、弹框尺寸严格检查、Rust 编译与测试;未经授权不操作图形界面。

订阅与统一代理资源

  • 代理资源与账号绑定为同一独立页面的页签。零账号也可导入资源;用户选择来源、节点或分组,再明确绑定到某个普通 OAuth 账号。已有链接/手动字段入口仍保留。
  • 支持 HTTPS 订阅下载、Clash YAML proxies/proxy-groups、纯节点链接及 Base64 列表。协议转换依据 Mihomo 节点与分组文档。不导入订阅中的系统代理、TUN、规则、脚本或外部 provider;不调用第三方转换网站。
  • 手动选择组必须明确选择成员,嵌套选择沿可达关系选择;select、url-test、fallback 与 load-balance 分组由 Mihomo 原生执行,保留受支持的 lazy、timeout 与 strategy;relay 不支持。只有通过宿主成员引用、配置与安全边界校验的组才能绑定;不支持的组保留可浏览的组内节点。不在代理失败时自动转为直连。
  • 账号保存的是本次选中资源的不可变配置快照,经现有账号加密存储落盘;资源来源更新/删除不修改已有账号或运行隧道。要采用新版节点配置,用户需要重新绑定并按既有提示重启相关客户端。该边界也避免同名节点重排/删除引起静默换出口。
  • 资源存入 codex-proxy-sources.json,使用现有 AES-256-GCM 本地存储与私密原子替换;本地密钥沿用账号存储。IPC 只返回来源/节点/分组显示元数据,不返回订阅 URL、outbound、密码或内部快照。账号导出和浏览器缓存继续只包含脱敏摘要,导出后需重新配置代理。
  • 订阅下载只接受 HTTPS、最多三次同源重定向、2 MiB 解压后响应上限、8 秒连接及30秒请求超时,外层操作45秒上限;不附带账号 Token 或 Cookie。下载使用宿主正常网络路径,可能受用户既有系统/TUN/环境代理影响。外部 provider 不递归下载。最多32个来源、4路下载/解析和4路检测;同一来源刷新与同订阅URL导入单飞。
  • 导入/刷新/出口检测可取消;取消或超时撤销后台工作提交权限,进入原子保存后不再接受取消。慢磁盘工作不占异步运行线程;读取失败不会显示伪空资源或覆盖旧文件。来源失败保留旧节点和明确错误,可重试。
  • 自动刷新默认关闭,由用户对来源开启后每6小时检查,后台维护不阻塞启动或页面。失败记录最近尝试,避免每分钟重试。关闭自动刷新不会改已有账号代理。
  • 资源隧道的当前节点来自仅监听127.0.0.1、随机认证密钥的 Mihomo 控制接口,状态读取最多2秒,释放运行态锁后发起,禁止重定向与系统代理。查询失败不把保存的组名冒充实际选中节点。该控制接口没有外部控制面板或远程下载。
  • 本能力是账号代理资源,不属于平台全局设置,因此仅放在代理页面;通用设置和平台设置弹框不新增重复设置。
  • 首次创建共享加密密钥使用跨进程非阻塞锁与私密原子发布,避免零账号导入订阅与首次保存账号竞争覆盖密钥;已有密钥读取路径不新增等待。
  • 迁移前历史代码验证(sing-box,不代表 Mihomo 验证):TypeScript 类型检查、23项相关前端测试、18语言检查、Vite 构建、cargo check、Rust 全量库测试(1478通过、11项需特定环境的测试默认忽略)、git diff --check。主动运行真实订阅下载与解析,以及官方 sing-box 1.14.1 配置检查:72个节点/28个分组,其中59个节点/19个手动分组可选,59个节点配置全部通过内核检查;不代表已完成到供应商节点的真实连接。私密诊断文件已删除,订阅密钥未进入项目文件或日志。未操作图形界面验证新流程,未在 Windows/Linux 真机验证。

订阅格式协商与兼容反馈

  • 订阅下载以 clash.meta/CockpitTools 声明所需格式,保留应用标识。部分服务端对旧 Clash 标识只返回传统协议子集;这是服务端格式协商差异,不能靠前端列表补齐。当前使用 Mihomo 内核处理受支持配置,但兼容标识本身不能保证服务端返回完整配置。
  • 手动选择组保留全部可浏览成员,但允许用户明确选择可用分支;不支持的策略、直连成员和不可用节点不能被实际绑定。自动测速组仍严格验证所有成员,避免悄悄改变分组策略。
  • 节点与分组错误仅输出预设短码,由界面翻译为原因,不直接展示未知字段值、原始订阅、服务端响应或节点密码。
  • 新导入的受支持 Clash 节点保留原生 Mihomo 参数,旧快照的 TLS/ECH 等字段在运行时适配;不再以旧 sing-box 转换能力判断所有 Clash 节点。未知或超出宿主管理边界的选项仍明确拒绝,不静默删除 ECH、关闭证书校验或改用公共 DNS;要求跳过证书验证的节点需用户单独明确授权。实际握手仍依赖有效的 DNS 记录和上游服务,原生配置被保留不等于已验证远端连通。

导入与选择交互

  • 来源名称不必填写:订阅优先读取 profile-title(含 Base64)或 Content-Disposition 的文件名,回退为域名,不使用带凭据的 URL 路径/查询参数。单代理默认使用协议及端点,多代理使用本地化列表名称;来源可在导入后改名。标题拒绝路径、URL 与明显凭据信息,且不使用原始异常作界面文案。
  • 粘贴支持订阅地址、节点 URI、多行代理及 host:port:username:password、username:password@host:port、host:port@username:password。省略协议时使用界面明确显示的协议;协议偏好可保存在浏览器,凭据不可保存。无协议输入无法推断服务器实际协议,歧义格式必须指定排列方式。
  • 预览只做本地解析,返回名称、协议、端点、是否含认证及错误行;不返回用户名/密码。错误默认阻止整个导入,只有用户主动选择跳过后才保存有效条目。重复判断包含完整节点配置与凭据,不按名称去重;有分组的配置保留成员引用。
  • 选择区采用「当前节点/所选出口 → 代理组 → 节点」布局,自定义下拉菜单支持搜索、按原序/名称/延迟排序,节点名称旁显示协议和延迟徽章。批量检测过程中保持列表顺序,结束后再排序。未检测或已取消显示 -,检测中显示转圈,失败和超时单独标记。
  • 分组选择可浏览直接子组及其下级节点;手动组沿已选成员逐层展开,自动组可选“按组策略”或固定节点。当前节点只取与已保存绑定匹配的内核运行态,不把临时测速中最快的节点当成实际选择;未启动或未保存时显示草稿出口。分组、节点问题在选择区内按具体成员说明,循环、成员缺失、选项不支持和证书许可各自区分。
  • 未选分组时可直接选节点,不因打开或回显选择而自动测速。选组策略后仍须完成所需手动子组选择并保存。不支持的分组仍可展开诊断及选择可用节点;待证书许可节点可进入草稿,但未明确允许前不得测速或保存绑定。
  • 当前选择是草稿,点击绑定才写入账号;来源改名、测速和筛选不会重新绑定账号,已绑定配置继续保持快照行为。
  • 保存账号绑定(含批量绑定和快捷切换)、统一代理及来源默认项只要求本地配置有效、所需内核就绪与本地写入成功,不把公网 IP 检测作为保存前提。账号节点绑定仍准备本地内核运行态,失败时保留旧配置;保存成功不代表已验证连通。用户可独立发起出口检测,超时或失败明确提示但不撤销已保存配置。

单节点和组内延迟检测

  • 仅用户触发:页面/弹框打开、已有绑定回显、来源切换或更新、忙碌状态结束均不自动测速。点击分组后检测该组及其下级分组的受支持节点;点击子组仅检测该子树,点击单节点仅检测该节点,不追加浏览父组、其他已选成员或无关分组。去重后最多并发3个,不自动修改节点选择或路由。
  • 切换所选项会取消旧批次;分组旁的手动测速按钮使用相同子树范围。保留各节点延迟、检测状态和取消按钮,不显示“测速 n / 总数”总进度。点击选择优先复用一分钟内的成功结果,手动测速按钮可强制重新检测。
  • 使用独立临时 Mihomo 的原生 /proxies/account-node/delay 接口,临时配置开启 unified-delay,展示内核返回的延迟,不再混合宿主的 HTTP/HTTPS 请求计时。组内检测使用所选组的健康检查 URL;未指定时使用 http://www.gstatic.com/generate_204。测试按 Mihomo URLTest 的 HEAD 请求及连接复用语义执行;控制器只走认证的本机连接,禁止重定向和继承代理,不发送账号 Token、Cookie。数字不是下载带宽、ICMP 延迟或账号业务可达性保证,也不保证与另一内核进程同一时刻测得的数字完全一致。
  • 每节点整个后端检测(包含读取和临时内核准备)最多10秒。取消停止排队及进行中的请求;关闭页面/更换来源取消旧批次,迟到结果丢弃,临时内核在取消和超时后释放。
  • 结果仅存在页面内存,关联来源 ID、配置 revision、测速分组和节点 ID;同一节点在不同组中的测试地址可能不同,缓存不能跨组复用。更新/改名等 revision 变化时清除旧结果。检测使用独立临时进程,不改变账号内核的节点选择与健康检查结果;出口 IP 检测仍使用单独的 ipify 流程。
  • 参考:Clash Verge Rev 的当前节点卡片、代理组/节点下拉、延迟徽章、稳定排序及原生延迟接口调用方式,以及 src-tauri/src/config/prfitem.rs 订阅文件名处理;来源已在中英文 README 致谢。

节点证书选项与来源网络兼容

  • Clash 订阅的 skip-cert-verify: true 保留为待批准节点,初次导入不允许绑定/检测。选择节点或分组后列出需要此选项的节点及其影响,由用户明确允许;组级操作按来源 revision 校验后一次性批准该子树中原本声明此选项的节点,不删除坏成员或更改组策略。循环/缺失成员使整组授权失败且不部分写入。绑定快照记录获批节点,不能通过向快照注入跳过证书验证参数来绕过声明。禁用后新绑定/检测被阻止,已有单账号独立绑定保持原快照,应重新绑定才改变;引用该来源的统一代理则沿用来源变更同步流程。
  • 本地读取按当前解析规则在内存中重验保留的节点原文,保留既有明确许可,不隐式刷新订阅或修改账号绑定。老解析记录缺少可重验原文时显示“需要刷新订阅”,只有用户点击刷新才下载并重新解析。并发更新导致 revision 失效时只重读本地目录数据,用户确认新显示的选项后再重试授权。
  • 刷新订阅只为同 ID 且完整 outbound 完全相同的节点保留批准,凭据、地址或其他节点配置变化则重新要求用户允许。解析异常、证书真实失败和订阅声明不校验是不同状态,不混为一谈。
  • 网络设置字段仍保存在加密来源与账号绑定快照中(缺省关闭),界面不再提供入口;历史数据中已启用的来源继续使用 Cloudflare https://1.1.1.1/dns-query(验证服务端 IP 证书,不跳过校验),支持 ECH 的 HTTPS 记录查询,DoH 查询保留系统现有路由(可能经过其他代理的 TUN/VPN)。旧来源、旧账号快照中的 interface 可读取,但不再绑定节点出站,重新保存后也不再写入。Mihomo 使用 redir-host 返回真实地址以避免本地 fake-IP,不开启本地 DNS 监听,不启用备用 DNS 或 GeoIP 回退。
  • 账号与资源页面提示:其他代理软件的 TUN/VPN 可能再次接管账号出口,建议关闭后使用独立节点;用户仍可继续绑定并测试。出口检测只验证本次请求,不能保证后续全部请求。普通流程不要求用户选择物理网卡,也不自动判断外部 TUN/VPN 是否接管了流量。系统 DNS、路由和其他代理配置均不修改。
  • 引擎仅产生 error 级 stderr,后台按最多4096字节一行分类为固定错误码,原始内容不记录、不持久化、不返回 IPC;任务随 tunnel 销毁。请求超时与目标异常另行分类。
  • 当前配置依据:Mihomo DNS 与通用节点参数;旧 sing-box 配置仅用于兼容已有保存数据。

Mihomo 迁移验证(2026-09-24)

  • 固定官方 Mihomo v1.19.31;Windows x64 ZIP 与 macOS ARM64 GZIP 的 SHA-256、离线准备通过。macOS 官方归档在隔离目录中的真实安装与重装测试通过,不修改用户安装目录或账号。
  • Rust 全量库测试 1500 项通过、0 失败、13 项需额外环境的测试默认忽略;随后新增的旧 v1 绑定凭据/TLS 批准、SSH 身份与 SNI 别名两项测试单独通过。
  • 显式使用已核验的 macOS Mihomo 二进制运行 5 项集成测试:常见节点配置(含 gRPC)、原生 XHTTP/HY2 端口跳跃/SS 插件与 fallback/load-balance 配置、认证转发与停止回收、桌面认证转接、控制 API 认证及分组实际选中节点。均通过;配置校验不等于远端节点连通。
  • cargo check、TypeScript、Vite 构建、18 语言检查、弹框尺寸严格检查、14 项前端目录服务测试、6 项归档脚本测试与 git diff --check 通过。
  • 未操作图形界面;未进行 Windows/Linux 内核实机运行或用户真实远端节点验收。未提交、打标签或发布。

节点分组回显

绑定快照的可选 groupId 保存选择节点时的分组上下文,仅影响界面回显,不改变出站节点或自动分组策略。账号页、资源页及批量绑定共用该字段。后端保存前校验分组及成员关系;旧快照可继续读取,缺失记录或订阅中分组已失效时显示全部节点,不按订阅顺序猜测分组。

代理预览与账号列表

账号卡片和表格的代理入口打开紧凑预览,显示当前绑定、实际节点、运行记录和近期请求。点击“切换节点”打开独立弹框,预览保持挂载并暂时不可交互;来源、分组和节点为草稿选择,只有点击保存才更改账号绑定。新弹框的标题、关闭按钮和保存/取消区固定,长内容由正文滚动;错误留在当前弹框。取消或关闭丢弃草稿并停止临时测速,保存成功则关闭切换弹框、刷新原预览,并把焦点还给切换按钮。Escape 仅关闭最上层,点击遮罩不关闭。代理管理页账号列表复用普通账号订阅徽章的样式,但显示后端原始订阅标识,不显示额度;同时展示绑定状态与脱敏节点摘要。


Codex Proxy Reference Plan (`docs/codex-proxy-reference-plan.md`)

Codex 代理策略与热切换改造参考

2026-09-24 产品目标与实施参考。此文档记录已确认的方向、建议的默认行为和验收边界。第一部分是本轮已落地的实现与验证结果(见文末「实施状态」),其余章节保留原始方案与验收清单;尚未完成或未验证的部分在文末单独列出,不要把它们当作已完成能力对外描述。

固定的上游源码

两个仓库独立放在本项目同级目录,均以浅克隆检出标签;不会进入本项目 Git 提交,也不作为运行时源码依赖。

项目 本地目录(相对本项目根目录) 标签 / commit 用途
Mihomo ../mihomo v1.19.31 / ab405bad5beeeac8b003bb01f60f134f6df54471 当前采用的运行内核;参考分组、健康检查、故障转移与控制 API 的实际行为
sing-box ../sing-box v1.14.1 / 1ac1a339cb1223e9c70eae14c44411c75033c02d 仅参考自动测速的空闲策略、切换容差和已有连接处理;当前运行内核仍为 Mihomo

阅读入口(路径相对对应的上游仓库根目录):

问题 Mihomo 源码 sing-box 对照
主备故障转移 adapter/outboundgroup/fallback.go、adapter/outboundgroup/groupbase.go —
自动测速及防频繁切换 adapter/outboundgroup/urltest.go protocol/group/urltest.go、option/group.go
手动选择与负载均衡 adapter/outboundgroup/selector.go、adapter/outboundgroup/loadbalance.go protocol/group/selector.go
周期健康检查与失败触发复测 adapter/provider/healthcheck.go、adapter/outboundgroup/parser.go common/urltest/urltest.go
运行态、节点切换与主动检测 hub/route/proxies.go、hub/route/groups.go —

上游行为还应以对应版本的分组文档、控制 API和源码共同确认;升级内核版本时重新核对,不直接套用当前结论。

代理客户端 UI 参考源码

以下三个 UI 仓库也已浅克隆到本项目同级目录。下列结论来自所列 commit 的页面与组件源码,不只依据用户提供的 Clash Verge 截图;尚未运行这些客户端进行逐屏操作验证。截图用于确认用户期望的视觉方向,不能当作当前 Clash Verge Rev 版本的逐像素规格。

项目 本地目录 / commit 已核对的 UI 与交互入口
Clash Verge Rev ../clash-verge-rev / 04d74ac48fa46999158cfd248bf2a6e1c062c075 src/pages/_navigation-meta.ts、src/pages/profiles.tsx、src/components/profile/profile-item.tsx、src/components/profile/profile-box.tsx、src/pages/proxies.tsx、src/components/proxy/proxy-groups.tsx、src/components/proxy/proxy-item.tsx、src/components/proxy/use-filter-sort.ts、src/hooks/use-proxy-selection.ts、src/pages/home.tsx、src/pages/connections.tsx、src/pages/logs.tsx
Hiddify ../hiddify-app / 276a7effb0046a039220a745022563740968c0b8 lib/features/home/widget/home_page.dart、lib/features/proxy/active/active_proxy_card.dart、lib/features/profile/overview/profiles_page.dart、lib/features/profile/add/add_profile_modal.dart、lib/features/proxy/overview/proxies_overview_page.dart、lib/features/proxy/widget/proxy_tile.dart
FlClash ../FlClash / c7be7023d33615cb624148d41414f80a7d96cede lib/views/navigation.dart、lib/views/profiles/profiles.dart、lib/views/proxies/proxies.dart、lib/views/proxies/tab.dart、lib/views/proxies/list.dart、lib/views/proxies/card.dart

对照源码后可直接复用的交互原则:Clash Verge Rev 的订阅页把链接导入、粘贴、新建、当前选中、单项/批量更新与更新中状态放在同一工作区;订阅卡片展示用量和到期信息,ProfileBox 以左边框标记选中。代理页把组、成员、筛选/排序和单项/整组延迟测试放在一起;点击成员会通过 selectNodeForGroup 立即修改其全局运行组,旧连接清理是可选行为。首页按卡片分展示当前代理与流量,连接页可看活动/已关闭连接并搜索排序,日志页可暂停、筛选和调整顺序。Hiddify 的首页把当前配置、连接操作和实际代理/IP集中显示,添加资源走短路径,代理列表按宽度排布并提供排序与批量测速。FlClash 的资源卡片提供选中、更新、详情和更多操作;代理页可在组页签与列表之间切换、回到已选节点,并把节点点击与延迟测试分开。这些是源码可确认的行为,不是对界面运行结果的声称。

不能照搬其“点击订阅或节点就立即改变全局代理”的语义:本项目允许多个账号同时使用不同出口。资源卡片点击只定位和查看来源;节点点击只更新当前账号的绑定草稿;确认区展示账号、旧出口、新出口、固定/跟随模式与受影响的新连接,用户确认后才写入绑定。实时连接、日志、测速也须支持按账号和通道查看,不能把全局统计误报成当前账号的数据。Hiddify 的 LICENSE.md 对相似名称和界面有额外限制;三个项目的源码、素材或高度相似的视觉实现若要复用,均需先核对相应许可证。当前方案只参考信息架构与交互方法。

我们已有的边界

  • 宿主在 codex_account_proxy.rs 解析账号与统一代理;codex_unified_proxy.rs 保存统一代理引用和快照;codex_proxy_catalog_binding.rs 将订阅组转成 Mihomo 分组;codex_proxy_engine.rs 启动每账号内核并读取当前节点。
  • codex_proxy_runtime.rs 管理账号、桌面和 sidecar 隧道;codex_instance.rs 与 process_launch_candidates.rs 在桌面客户端启动时注入代理环境变量和 Electron --proxy-server。运行中的 Electron 不会自动重新读取启动参数。
  • codex_proxy_desktop_router.rs 已实现按账号的固定本地入口:端口记录持久化并优先复用,启动时只对已有生效出口的账号注入,换节点/策略/解绑与统一代理变化按新连接生效。桌面入口、账号请求通道、API 服务网关仍是不同消费者,必须分别验收;未绑定账号首次绑定后仍需一次重启。
  • 前端 defaultProxySelections 曾为 select 分组隐式选择订阅顺序里的首个受支持成员,与后端 codex_proxy_catalog_binding.rs「提交时必须有明确 selections」以及本文档「手动选择组必须明确选择成员」不一致。三处现已统一:select 必须由用户逐层显式选择成员,已保存的成员只用于回显,不会替用户改选。
  • 当前资源删除弹框只显示通用提示,未列出实际关联账号;codex_proxy_catalog_remove 先逐个解绑账号再删除来源,失败可能留下部分解绑状态。新策略、来源默认值与统一代理加入后,影响面还会扩大。
  • 当前账号卡片的代理快捷入口打开 CodexAccountProxyPreview,弹框里又有选择、检测和绑定,与 CodexEgressProxyPage 形成两套完整操作入口。资源页的“选择账号”只把草稿赋给此前选中的账号;用户随后切换账号会清空草稿。资源页“批量绑定”则预选所有将发生变化的账号。
  • 当前账号概览以是否保存独立绑定显示“已绑定/未绑定”,未独立绑定但正在继承统一代理的账号仍显示“未绑定”;绿色绑定状态也不能证明出口可用。CodexProxyRuntimeStatusPanel 只用本地进程状态表示运行态。统一代理读取失败被吞掉时,页面可能一直显示“加载中”。
  • 当前订阅“自动更新”只更新来源,账号绑定仍持有快照,需要用户重新绑定;提示埋在资源页。现有活动日志主要覆盖 Mihomo 通道,无鉴权的直接 HTTP/SOCKS 代理不支持同一日志捕获;桌面、账号请求和 API 服务网关的状态展示也不完整。
  • 当前 OAuth 首次添加代理需单独输入地址,不能从已导入资源中选择;重新授权隐藏该选项,macOS 的受管登录窗口代理选项禁用。受管客户端启动走账号代理与 OAuth 登录网页/Token 交换走代理是两项能力,应分别实现和说明。

目标行为与分工

1. 出口优先级

用户已确认:账号自身绑定 > 统一代理 > 原有默认出口。只有符合代理资格的普通 OAuth 账号参与。开启、修改和关闭统一代理不得覆盖账号文件中的独立绑定;取消账号绑定后可继承统一代理,关闭统一代理后回到原有默认出口。桌面、账号请求、授权相关请求和 API 服务网关须调用同一生效规则,并核对各自是否真的支持动态更新。

OAuth 账号绑定后的受管客户端启动必须遵守该优先级:将已有 OAuth 账号绑定到实例、切号并启动、默认实例启动和多开实例启动时,先以目标账号 ID 解析生效代理;有账号代理就使用账号代理,没有才考虑统一代理和原有默认出口。启动事务的凭据预检、刷新和重新授权状态机应沿用同一目标账号上下文,不能启动时误取当前账号或另一个实例的出口。代理尚未准备好时展示可重试错误,不能为了把客户端打开而静默直连。此要求指客户端启动及随后由受管通路发出的新连接,不等于 OAuth 授权网页已走代理。

OAuth 授权代理是单独能力:重新授权已有账号时,受宿主管理的登录窗口、授权回调后的 Token 交换及首次账号请求应使用该账号的生效代理,并按平台及步骤分别验证;本地回调仍监听本机。首次添加尚不存在的 OAuth 账号时没有可读取的账号绑定,应允许用户在启动授权前从代理资源中显式选择一个临时出口,授权成功后再由用户决定是否保存为该账号绑定;没有选择时走现有默认授权路径,不推测或借用其他账号代理。外部系统浏览器、设备授权或受平台限制的登录窗口若无法由宿主控制出口,须明确标出受影响的步骤和可用替代路径,不能宣称整个 OAuth 流程都已走代理。

2. 分组选择

分组 预期语义 后续处理
select 用户固定选择一个成员;不会因成员故障自动换到下一个 新绑定要求用户明确选成员,或使用该来源已保存且在界面可见的默认成员;保留旧绑定已保存的选择。不能把“首个受支持”描述成故障转移。嵌套 select 每层都要有选择。
fallback 按成员顺序选可用节点;故障后由 Mihomo 选择备用 作为需要稳定主备出口时的推荐模式;保留订阅顺序,明确健康检查地址、间隔和超时。
url-test 选择测得较快的节点 保留 tolerance 防止微小延迟变化反复切换;作为用户可选模式。
load-balance 按策略分配新连接,不存在单一当前节点 保留为高级选项,界面不可假称单一出口 IP。

新策略或默认选择不得自动改写已有账号绑定;只有用户主动绑定组、选择“跟随来源默认”或切换策略后才改变其出口。已有账号的升级路径与回退行为必须测试。

3. 自建代理策略与来源默认值

  • 除订阅自带分组外,允许用户创建有名称的代理策略:从一个或多个来源勾选若干节点,调整主备顺序,并选择 select、fallback、url-test 或 load-balance。账号代理和统一代理都可引用同一策略定义;每个账号可继续独立覆盖。手动 HTTP/SOCKS 节点也可作为策略成员。创建、编辑、复制、停用及删除策略都在代理管理独立页面内完成。
  • 策略保存稳定的来源 ID、节点 ID、成员顺序和配置版本,并以加密快照提供运行时使用;不能只靠易变的节点显示名称关联。导入、订阅刷新和配置重建需校验协议支持、重复成员、嵌套循环、节点数量、鉴权和未受信证书选项。多跳/relay 等额外模式只在当前内核版本和跨协议行为核实后开放,不把“上游能解析”当作本项目已支持。
  • 策略设置包含健康检查地址、预期响应状态、间隔、超时、懒检测、测速切换容差,以及主节点恢复后的回切规则。提供合理预设和高级设置;保存前显示将采用的节点顺序与策略类型,不把单节点伪装成有故障转移能力的策略。
  • 每个代理来源可保存一个默认节点、原生分组或自建策略。账号选中来源时,选择器自动带入草稿;用户仍可改选,只有点击确认绑定才写入账号。对于 select 默认分组,必须同时明确默认成员;对于自动分组,默认项是整个组,不固定其当前选中节点。
  • 账号绑定提供两种清楚标注的方式:固定绑定保存当前选择及快照;跟随来源默认保存对来源默认项的引用。修改来源默认值只影响后续新绑定与主动选择“跟随”的账号;既有固定绑定不变。跟随账号的更新须通过固定入口对新连接生效,失败时显示“待生效/失效”且不得静默改走直连。
  • 订阅刷新后,已绑定的固定快照保持旧配置,直到用户主动更新;选择跟随来源默认的账号按其明确授权尝试新配置。节点消失时,自建多节点策略可继续使用仍有效的成员并显示“降级”;手动固定节点或全部成员消失则显示失效,不悄悄选另一节点。来源默认项失效时提醒用户重新选择。

4. 健康检查与故障转移

  • 让 Mihomo 原生 fallback、url-test 和 provider 健康检查承担选路;宿主不复制测速排序与故障计数算法。宿主负责受支持配置校验、内核状态、账号隔离和可解释的 UI 状态。
  • 检测 URL、预期状态码、间隔、超时、lazy、tolerance、失败复测策略应有明确默认值和上限;不要让每个账号的每个后台入口重复创建探测任务。检查地址的成功只证明该地址在该节点上可达,另保留面向实际目标服务的手动出口 IP 与连通性检测,两种结果分别展示。
  • 网络接口切换、系统睡眠唤醒、内核意外退出、订阅更新和主节点恢复时,应触发有去重、限频与超时的复检;允许手动重试。避免频繁健康波动导致节点来回切换,展示最近一次切换的时间、旧/新节点和原因。
  • Mihomo fallback 在所有成员健康检查均失败时仍会尝试组内第一个成员(见 fallback.go 的 findAliveProxy);empty-fallback: REJECT 只处理成员列表为空,不能被当作“全部失活就拒绝”的保证。我们的要求是不得偷偷改走 DIRECT,并对连接失败或状态不确定如实呈现。若产品需要严格的“全部失活立即拒绝”,需单独设计并验证,不能只靠 empty-fallback。
  • 自动切换作用于新连接;已建立的 TCP/WebSocket 连接不保证无感迁移。失败的业务请求是否重试,仍由其调用方决定。参考 sing-box 的 interrupt_exist_connections,默认应保留已有连接,只有明确产品需求才主动中断。

5. 固定入口与运行中换代理

  • 每个账号给桌面客户端一个尽可能稳定的 127.0.0.1 本地入口。端口属于账号入口,不属于某个节点或某次 Mihomo 进程;修改绑定时不要让运行中客户端继续指向已经退出的随机端口。新版本受管启动的客户端,首次绑定、换节点、切策略、解绑及统一代理变化都应让新连接无需重启直接生效。
  • 先验证新配置及候选隧道可启动,再原子切换新连接的目标;旧隧道要等已有连接结束或达到明确的回收期限再停止。失败时保留旧配置和可用通道,不静默直连。
  • 同账号多实例要复用同一个入口;不同账号必须隔离。处理端口冲突、宿主重启后的端口恢复、后台监听异常、内核崩溃与重新拉起。不能只根据账号 ID 算一个端口就声称“永久固定”:端口可能被其他进程占用,需要持久化分配或明确的重启/错误反馈。
  • 首次启用与升级边界(已实现):启动时只为已有生效出口(账号独立绑定或统一代理)的账号安装固定入口。未绑定账号若也被注入本地入口,会替代应用全局代理环境变量、用户自定义 --proxy-server/PAC 参数与系统代理,属于静默改变出口,因此这类账号保持原有启动参数,首次绑定后需要重启一次客户端;之后换节点、换策略、解绑与统一代理变化都不再要求重启。端口记录持久化在应用数据目录,宿主重启优先复用;入口创建失败时不注入代理参数,客户端照常启动。若将来要覆盖「启动时未绑定 → 运行中首次绑定」,必须先按实例捕获并复现原出口(含 PAC 与系统代理)或提供用户明确开启的开关,不能默认注入。外部自行启动且不受宿主管理的客户端不在这一保证范围内。
  • API 服务网关、sidecar 认证文件与桌面入口是不同通路。保存成功不等于网关已完成重载;需要可观察的生效状态、超时和失败反馈。订阅刷新、统一代理开关和用户手动绑定同时发生时,过期异步结果不得覆盖更新的配置。
  • 保存流程要区分“用户选择已保存”“候选配置验证中”“新出口已生效”“生效失败”;启动或检测失败时保留旧的可用出口并给出重试入口。原先没有可用代理且用户已要求使用代理时应失败,不得暗中退回直连。后台准备不能卡住账号页展示和操作。

6. 统计、日志与交互

  • 展示维度为账号 → 当前绑定/策略 → 实际节点,同时按桌面、账号请求、API 服务网关等通道标明来源。账号卡片显示出口状态、当前节点、最近切换和错误摘要;代理管理独立页面展示节点健康矩阵、策略成员、活动连接、实时曲线和可筛选日志。来源详情可设置默认项并预览会被带入的账号草稿。
  • 数据包括实时上传/下载速度、会话累计与可选历史累计流量、活动连接数、每连接上传/下载、成功/失败次数、最近健康检查、探测延迟、实际请求耗时、故障和恢复次数、最近切换原因。Mihomo 控制 API 的 /traffic、/connections、/logs、/proxies/.../delay 可作为来源;直连代理和固定入口自身的指标由宿主补充。内核重启会重置其计数,宿主须按进程代次合并并避免跨通道重复计数。
  • 探测延迟、请求连接/响应耗时与传输速度分别命名;测速通过不等于目标服务可用,运行进程存活不等于代理连接成功。负载均衡组没有唯一“当前出口节点”。统计只覆盖经过本应用受管入口的流量,不声称覆盖系统 TUN/VPN 或全部 Codex 网络请求。
  • 日志与连接详情隐藏凭据、Token、完整 URL、敏感查询参数和不必要的源地址;有界内存保存,历史持久化及详细捕获由用户主动开启并可清除。提供脱敏导出与可见的记录范围;不可为了显示图表而长期高频轮询,页面不可见时降频或停止订阅。
  • UI 将“健康检查中、可用、不可用、部分节点失效、策略待生效、运行通道中断、状态未知”分别表示;失败就近提示并可重试,不用单个绿色标签混合“配置已保存”和“网络可用”。

7. 删除来源、订阅或策略时的影响预览

  • 点击删除订阅/来源前,先由后端按最新持久化状态汇总直接绑定该来源的账号、跟随其默认值的账号、引用其中节点的自建策略、统一代理及受影响的运行实例。弹框列出账号名称/数量、策略名称、当前是否正在使用;大量结果可滚动且标题与取消、确认按钮始终可达。没有依赖也应明确显示“无关联账号/策略”。
  • 弹框必须说明每类对象删除后的具体结果:直接绑定或跟随该来源默认值的账号会解除该绑定,然后按“账号绑定 > 统一代理 > 原有默认出口”重新解析,可能走统一代理、全局/系统代理或直连;引用该源的统一代理会关闭;来源默认项会消失。多节点策略若仍有其他有效成员,明确显示剩余成员并进入“降级”状态;若只剩失效成员,策略与引用账号标记失效且停止使用,不能静默换成无关节点或直连。仍在传输的连接遵守排空规则,新连接按删除后的结果处理。
  • 删除确认区应明确显示“将解除绑定的账号数、将降级/失效的策略数、将改变出口的运行实例数”,并提供“取消”“先去调整绑定”“确认删除”。无依赖时可简化文案。确认前重新核对来源版本和依赖摘要;若影响名单在弹框打开后变化,更新预览并要求重新确认,避免按过期影响范围删除。
  • 后端尽量使用可恢复的删除事务:先准备依赖变更和回退信息,再提交来源及引用更新,随后触发网关/桌面路由刷新。失败不得假装成功或显示伪空列表;若无法原子完成,保留来源并明确列出已更改和未更改账号,提供安全重试/恢复。删除成功后 UI 刷新受影响账号、策略与统一代理状态,不只刷新资源列表。
  • 删除单个节点或自建策略也需要相同的依赖预览。订阅自动刷新删除节点属于后台维护,不弹阻塞框;保留固定绑定的旧快照并标记来源已变化,跟随默认和自建策略按明确的降级/失效规则更新并通知。

8. 交互复核:把“选代理”变成可理解的账号任务

优先收敛为一条主路径:选账号 → 看实际生效出口 → 选择来源默认项或改选策略/节点 → 查看将改变的内容 → 绑定 → 看生效状态。资源页负责导入、更新、测速与设置默认项;账号卡片快捷入口直接进入同一代理管理页并定位账号,不再打开另一个可编辑的完整弹框。首次没有资源时,在原账号上下文中引导导入,导入后返回该账号的绑定草稿,不要求用户重新寻找账号。高级参数、原始日志和内核安装细节按需展开;TUN/VPN 冲突提示在检测异常或用户查看网络说明时突出展示,不让所有账号的日常操作始终被同一段警示占据。

视觉和易用性要求:

  • 代理工作台以 Clash Verge Rev 已核对的订阅、代理、概览与诊断页面源码为主要交互参考,并用用户提供的 Clash Verge「订阅」截图校准导航层级、留白、卡片密度和状态呈现。接入宿主时仍复用项目现有的页面注册、按钮、输入框与状态规范,统一间距、字体层级、圆角、图标和颜色;不要出现浏览器原生下拉框或按钮。页面第一屏突出“当前出口”和一个主要操作,健康详情、内核管理、技术说明与日志放在次级区域。
  • 常用场景尽量只需“选账号、确认推荐出口、绑定”三次核心决策;有来源默认项时直接带入草稿。测速是可选验证,不应成为所有绑定的强制前置步骤。高级策略和参数按需展开,首次使用者不需要先理解 select、fallback、Mihomo 或本地端口才能完成绑定。
  • 一屏只保留一个明确的主按钮;“测试”“取消”“解绑”等次级或危险操作在位置、样式和文案上区分。显示“旧出口 → 新出口”与生效范围,保存后给就地反馈;失败保留原选择并在操作位置说明原因与重试方法,不让用户返回列表猜是否成功。
  • 来源、分组、节点按清晰层级展示;名称、策略类型、可用状态、最近延迟与已选项可直接扫读。长名称截断时可查看完整内容;大订阅支持搜索、筛选与排序,但不把几十个节点和大量日志同时铺满主界面。状态颜色与图标有一致含义,不能单凭绿色表达“已保存、已连接、已验证”三个不同事实。
  • 空列表、加载、检测中、部分失败和全部失效都有可执行的下一步。窄窗口、较小高度、长账号名和长节点名下,标题、关闭/取消、主操作始终可见且内容可滚动;键盘焦点、禁用态和错误定位保持一致。动效只帮助识别状态变化,不以动画掩盖等待或造成频繁闪烁。

上游页面行为到本项目的映射(已核对上述源码;本项目设计目标尚未实现或逐屏验证):

参考 借鉴点 本项目的对应设计
Clash Verge Rev 的 profiles.tsx、profile-item.tsx、profile-box.tsx 链接导入、粘贴与新建并列;响应式来源卡片标记当前选中、展示用量/到期、单项和批量更新 订阅卡片显示来源默认节点/分组、绑定账号数、来源更新与账号快照是否同步;点击只定位来源,不直接替所有账号切换出口。
Clash Verge Rev 的 proxies.tsx、proxy-groups.tsx、proxy-item.tsx、use-filter-sort.ts、use-proxy-selection.ts 组内选成员、按名称/类型/延迟筛选排序、单项/整组测速、显示已选项;节点点击立即修改全局运行组 保留清楚的组和成员层级、延迟测试与选中反馈;节点点击只改账号草稿,提交前显示旧→新出口。自动组显示实际节点,手选组必须显式选成员。
Clash Verge Rev 的 home.tsx、connections.tsx、logs.tsx 首页卡片与连接/日志独立诊断页面;活动/已关闭连接、搜索排序、日志暂停和级别过滤 概览先呈现当前账号出口与异常状态;连接、流量和日志可按账号/通道过滤,状态不完整时说明统计覆盖范围。
Hiddify 的 home_page.dart、active_proxy_card.dart、add_profile_modal.dart、proxies_overview_page.dart 当前配置、实际代理/IP与连接操作集中;添加来源步骤短,节点列表可排序、测速 首次绑定从账号上下文进入并预填来源默认项;可直接查看该账号的实际出口。只借鉴流程,不复刻其连接页视觉或全局连接开关。
FlClash 的 navigation.dart、profiles.dart、proxies.dart、tab.dart、card.dart 按宽度调整页面布局;来源卡片与组页签/列表可切换;回到已选节点,节点选中和测速各有反馈 大订阅支持搜索、筛选、回到已选项;窄窗口依旧可完成账号绑定,测试结果与保存状态独立呈现。

代理区域建议以概览、账号、代理、订阅、连接、日志、测试、设置组织,优先完成已有能力的归位,不为凑齐导航项提前加入无实际内容的页面。顶部/「更多」入口继续使用宿主同一份页面注册和布局配置;代理内若采用截图式侧栏,仅用于这些内容的二级导航,不建立绕开宿主入口的另一套主导航,也不把功能主体放回弹框。账号卡片快捷入口直接定位到同一账号代理页面。

  • 概览:第一屏展示当前选定账号的实际出口、独立绑定/继承统一代理/默认出口、运行与健康状态、最近切换,以及一个明确的“更换代理”主操作;汇总异常账号、流量与连接,统计详情按需查看。
  • 账号:作为代理绑定视图,与现有账号管理共用账号数据,不复制一套账号库。逐账号显示来源、策略组、当前实际节点、固定本地端口、来源快照版本、受影响通道及最近检测;可筛选异常账号和批量绑定。账号代理优先于统一代理的规则在这里可见。
  • 代理:按照“来源 → 分组/自建策略 → 节点”选择,区分单节点、手选组与自动组。select 必须明确成员;自动组展示当前实际节点与切换原因。选择组后仍保留组身份,不能悄悄退化成绑定首个节点。
  • 订阅:沿用截图的紧凑卡片和明显的导入/刷新入口,显示流量、到期、更新、默认项和绑定关系;资源选择状态与账号实际出口分开显示。订阅更新、删除时说明旧快照和受影响账号,删除前提供影响预览。
  • 连接、日志、测试、设置:把实时连接与流量、可筛选且脱敏的日志、节点延迟/出口 IP/目标服务连通性测试分别呈现;设置承载健康检查、故障转移、统计保留等高级参数。状态来源与覆盖范围需说明,不能用探测延迟替代真实业务可用性。

页面结构和操作节奏以已核对的上游页面源码为主要参考,截图用于校准视觉目标;图标、品牌素材和代码不能未经许可证核对直接复制。上游全局订阅选中态不能原样映射到多账号场景;界面始终区分正在查看的来源、账号保存的绑定、当前运行的实际节点,并分别反馈“已保存、已接管新连接、最近检测通过/失败”。

优先级 当前交互断点 目标行为与验收
P0 账号快捷入口打开完整代理弹框,独立页面又能做相同的选择、检测和绑定 快捷入口直接导航到统一页面并预选该账号;账号卡片只展示简短出口状态。检查所有快捷入口都指向同一页面、保存后回到同一账号。
P0 资源页“选择账号”把草稿交给此前选中的账号;用户切换账号会丢失草稿 带着来源、分组/节点和选择版本进入真实账号选择步骤;选中目标后保留草稿直到确认或取消。批量入口要求用户明确勾选目标,不默认预选所有将变化的账号;确认前列出账号名称、数量与覆盖数。
P0 select 组暗中取首个受支持成员;选组后再点叶子节点会变为节点绑定,不能清楚地表达“绑定此组并固定其成员” 在选择器中标明 select、fallback、url-test、load-balance 及其差别。手动组绑定必须显式选成员并仍保存组身份及各层 selections;选择单节点是独立选项。自动组展示策略与可能变化的实际节点;提交摘要说明到底绑定了什么。
P0 账号概览以独立绑定是否存在显示绿色“已绑定/未绑定”,统一代理继承者看起来像无代理 对每个账号明确展示“独立绑定 / 继承统一代理 / 原有默认出口 / 失效”,再分别展示“配置已保存 / 新连接已接管 / 最近检测通过或失败 / 状态未知”。绑定成功不自动变成健康绿色;显示当前实际节点、检测时间和失败原因。
P0 统一代理状态读取失败被吞掉,view === null 一直显示加载中 读失败转为可见错误并提供重试;保留上一次可用状态,避免无限 loading 或误显示关闭。覆盖首次读取失败和切页后读取失败。
P1 来源“自动更新”与账号快照更新是两回事,用户只看到一行说明 已绑定账号显示“来源有更新/仍使用旧快照”,提供“更新此账号绑定”和明确的固定/跟随模式;来源默认项在账号选来源时预填草稿,不自动提交。更新失败保留旧可用绑定并显示原因。
P1 保存、运行和检测结果散在概览、运行态、请求记录和日志里,固定入口是否已用于当前客户端不可见 账号页顶部集中展示生效来源、策略、桌面/账号请求/API 服务网关各通道状态、实际节点和最近错误;状态详情区展示端口、日志及历史。只对旧版本启动、未安装固定入口的客户端提示一次性重启;已受管客户端说明新连接何时生效,旧连接是否仍走旧节点。
P1 删除来源仅给通用警告,失败时可能部分解绑 执行第 7 节的真实影响预览、复核与可恢复删除;确认区列出受影响账号、统一代理、策略和运行实例,失败列出已改/未改对象。
P1 OAuth 首次添加另填代理 URL,重新授权无账号代理选择,平台能力差异不清楚 首次添加允许选择代理资源作为临时授权出口;已有账号重新授权默认带入该账号生效代理,并允许查看/调整。授权网页、Token 交换、首次请求与客户端启动分别显示覆盖范围;macOS、外部浏览器和设备授权限制按真实能力解释。
P2 活动日志依赖 Mihomo,无鉴权直接代理的流量统计缺口与 API 服务网关状态容易被误读成“没有流量” 为固定入口和直连代理补宿主可采集的连接/流量指标;采集不到的通道显示覆盖范围与原因。分开展示健康探测延迟、出口 IP 检测和真实业务请求耗时,不用一次测速成功代表业务可用。

资源优先的路径也需闭环:导入或选择来源 → 检测候选 → 明确选择一个或多个账号 → 预览每个账号原出口与新出口 → 确认 → 查看逐账号结果。从账号或资源进入应复用同一选择器、绑定预览和错误文案;取消、切页及测试超时不应悄悄改变已保存绑定。空资源、来源更新、节点失效和全部节点不可用时,都给出下一步可执行动作,而非只给技术错误码或无解释的禁用按钮。

建议实施顺序与验收

  1. 先修交互断点并收敛页面样式:让账号快捷入口进入唯一管理页,修复资源到账号的草稿传递与批量目标预选,给统一代理读取失败提供重试;让概览区准确区分独立、继承、默认出口及“已保存/已生效/已检测”。按本节视觉要求形成简洁的主路径,再用状态、导航和选择器测试验证,随后进入更复杂的策略开发。
  2. 统一出口规则与数据模型:以一份纯函数覆盖账号绑定、统一代理、均无代理、资格排除等优先级矩阵;建立节点、来源默认项、自建策略、固定绑定、跟随绑定之间的引用关系。检查通用设置与对应弹框设置入口,以及桌面、OAuth 授权与重新授权、账号请求和 API 服务网关等消费者。让 select 的文档、前端草稿和后端选择一致。
  3. 完成稳定桌面入口:新版本所有受管账号客户端启动即绑定账号固定入口;验证未绑定时的原有系统/全局代理行为、首次绑定及后续所有改动无需重启。覆盖同账号多实例、端口冲突、宿主与内核重启、旧长连接排空和旧客户端一次性升级提示。不能保证代理生效的启动路径要明确失败或提示,不假装热切换已生效。
  4. 用 Mihomo 组策略完成自动选路:提供单节点、订阅原生组和自建多节点策略;验证 fallback 故障恢复与主节点回切、url-test 容差、load-balance 状态展示、嵌套组、订阅更新和网络变化。对无节点、全部健康检查失败、探测地址可达但目标服务不可达分别测试。
  5. 完成来源默认值、删除影响与跨通路同步:来源默认值只预填固定绑定;跟随绑定按用户选择更新。删除前预览真实依赖并复核,覆盖直接绑定、跟随、自建策略、统一代理与运行实例。验证 API 服务网关、sidecar 和桌面新连接分别生效;并发保存、资源删除和异步刷新不得回写旧状态或留下不可恢复的半删除。
  6. 补齐统计和交互:验证速度与累计字节口径、内核重启后的累计、通道去重、实际选中节点、健康检查/请求延迟区分、日志脱敏与内存上限。窄窗口、长账号名单及大量连接下仍可完成筛选、取消、确认和重试;不得只靠加载状态遮住旧数据。
  7. 交付前验证:执行相关 TypeScript 测试与 npm run typecheck、node scripts/check_locales.cjs、git diff --check;Rust 核心改动执行 cargo check、相关 cargo test --lib,并使用已核验的 Mihomo 二进制做本地回环集成测试。按项目规则,图形界面操作验证须由用户明确授权。跨平台真机及真实远端节点连通性若未测,须如实标记未验证。

最低验收场景:首次用户能从账号入口用少量明确步骤完成绑定;常用任务的主要操作与当前生效状态无需滚动寻找;窄窗口、600px 高窗口及长列表仍可操作,控件和状态视觉一致。还需覆盖账号快捷入口定位、资源选择后再选账号且草稿不丢、批量绑定仅修改明确勾选账号、手动组显式成员仍保留组身份、统一代理读取失败可重试、继承统一代理的账号显示真实来源、固定快照遇订阅更新给出更新入口;另覆盖无绑定→首次绑定、A 节点→B 节点、单节点→策略、策略内主节点失效→备用接管→主节点恢复、全部节点不可用、账号解绑后继承统一代理、统一代理关闭、来源默认值改变(固定/跟随账号各一)、来源删除时影响预览发生并发变化、删除失败后恢复、内核或宿主意外退出后重启、同账号多实例持续连接。还需覆盖已有 OAuth 账号绑定到默认/多开实例后启动、切号并启动、重新授权登录窗口与 Token 交换,以及首次添加账号时从资源中显式选择临时代理;验证目标账号代理始终优先且不会误用别的账号。每项须分别观察桌面新连接、API 服务网关和已存在连接;“配置保存成功”不能替代实际出口验证。

参考源码可直接阅读和对照实现,但不要复制整套客户端、引入第二个运行内核,或把上游仓库当作宿主运行时依赖。相关来源已在中英文 README 致谢区记录;后续修改须继续遵守各项目许可证与本项目分发审查要求。

实施状态(2026-09-24)

本节记录截至本轮的实际实现位置与验证结果,供后续调整对照。未列出的章节仍属于目标或待办,不代表已实现。

已落地的能力与代码入口

能力 实现位置 实际行为边界
出口优先级 codex_account_proxy.rs(has_effective_proxy)、codex_unified_proxy.rs 账号独立绑定 > 统一代理 > 原有默认出口;统一代理只保存资源引用与本地加密快照,关闭即恢复原出口
换代理不重启 codex_proxy_desktop_router.rs、端口记录 codex-proxy-desktop-ports.json 端口持久化并优先复用,被占用时按确定性顺序顺延;每条新连接按当前绑定解析出口,已建立的连接继续走旧出口
未绑定账号不注入本地入口 codex_proxy_desktop_router.rs 保持应用全局代理、自定义 --proxy-server/PAC 与系统代理不被改写;这类客户端首次绑定后需要重启一次
分组选择语义 src/utils/codexProxySelection.ts(defaultProxySelections)、codex_proxy_catalog_binding.rs select 必须显式选择成员,前端不再隐式取订阅首个成员;后端与文档一致要求明确 selections
自建多节点策略 codex_proxy_strategy.rs、codex_proxy_catalog.rs、CodexProxyStrategyPanel.tsx select / fallback / url-test / load-balance 四类,最多 64 个成员,成员顺序即主备顺序;参数按类型过滤(select 不做健康检查、load-balance 不带超时)
策略成员身份 strategy_members 记录 + strategyMemberViews() 编辑时按 (sourceId, itemId) 精确恢复,不再按名称猜测;同名成员在弹框内被拦截;原来源被删除后继续使用已保存副本,再次编辑保存不会丢掉这些成员
来源默认项 SourceDefault、sourceDefaultDraft() 只为草稿预填,点击确认前不写账号;来源刷新后默认项失效会清除并提示
删除影响预览 codex_proxy_catalog_dependencies、CodexProxyResources.tsx 列出将解除绑定的账号、统一代理是否关闭、引用该来源的策略及其副本保留说明;读取成功前不能确认删除
OAuth 授权出口 codex_oauth.rs 相关入口 重新授权默认沿用账号生效出口,并修复了带代理重新授权在 Token 交换阶段直接失败的问题;macOS 当前构建仍不提供内置授权窗口代理
统计、日志与运行态 codex_proxy_activity.rs、CodexProxyActivityPanel、CodexProxyRecentRequests 按账号与通道查看路由、最近请求与活动连接(含上传/下载量);日志由用户主动开启、仅内存限量保留;无鉴权的直连代理不提供同一套连接日志
入口统一 CodexEgressProxyPage.tsx、CodexProxyResources.tsx、顶部布局页面注册 代理管理与顶部布局都是独立页面;账号卡片快捷入口定位到同一页面,不再有第二套绑定弹框

本轮验证(可复现)

命令 结果
npm test 408 passed / 0 failed
npm run typecheck 通过
cd src-tauri && cargo check 通过(仅既有 warning)
cd src-tauri && cargo test --lib codex_proxy 136 passed / 0 failed / 11 ignored
cd src-tauri && cargo test --lib oauth 164 passed / 0 failed
node scripts/check_locales.cjs 通过(含值复用与平台通用 Key 检查)
node scripts/check_modal_sizing.cjs --strict 通过
node_modules/.bin/vite build 通过
git diff --check 无输出

仍未实现或未验证

  • 策略编辑之外的高级项:没有策略复制、停用、预期响应状态码、主节点恢复回切规则的界面;多跳 relay 未开放,仍按「上游能解析」不等于「本项目支持」处理。
  • 统计深度:只有实时连接与最近请求,没有历史流量/延迟曲线、跨重启累计流量与内核卸载入口。
  • 未接真实内核端到端验证:相关 Mihomo 集成用例仍是 #[ignore],未在真机与真实节点上验证回环、故障转移与回切;跨平台真机连通性同样未验证。
  • 未做界面操作验证:按项目规则 30,本轮所有结论来自代码、单测与构建检查,弹框真实渲染与窄窗口表现未手动确认。
  • 首次绑定仍需一次重启:未绑定账号在启动时不注入本地入口(有意保留,避免改写用户现有代理配置)。
  • 旧策略的兼容边界:没有 strategy_members 记录的历史策略,在原来源删除后仍无法在编辑时保留副本,需要重新选择成员。

代理工作台重写(2026-09-25 确认方向)

用户确认把代理功能从「顶部三页签 + 左列表右表单」整体重写为 Clash Verge 风格的独立工作台:左侧导航 + 主内容区 + 底部常驻流量条。本节是重写后的目标结构与已定的实现取舍,实施中以此为准。

text
侧栏:概览 / 账号管理 / 代理资源 / 连接 / 出口规则 / 日志 / 测试 / 设置
底部:↑ 实时上传  ↓ 实时下载  本次运行累计  版本号

页面职责

侧栏项 对应 Clash Verge 内容
概览 首页 来源卡片(用量/到期/更新/刷新)+ 当前出口卡片(来源→分组→节点,带延迟)+ 流量统计(10 分钟内存曲线)
账号管理 代理 Codex 可绑代理的 OAuth 账号列表 + 详情:出口状态、三级选择、出口检测、保存/解绑、批量绑定与批量解绑、运行记录与运行态
代理资源 订阅 订阅导入、手动节点、自建多节点策略、来源默认项、内核安装与版本
连接 连接 活动连接表格:通道、目标、网络、链路、规则、上传/下载、开始时间、时长;支持筛选、搜索、排序、暂停、清空
出口规则 规则 解析顺序说明(账号独立 > 统一代理 > 原有默认出口)、账号生效方式只读表、统一代理开关与影响预览
日志 日志 内核与隧道日志:级别筛选、搜索、暂停、清空、脱敏导出;必须由用户主动开启采集
测试 测试 节点测速(HTTP 延迟 / HTTPS 请求耗时)、出口 IP 检测;明确两者都不是下载速度
设置 设置 代理专属项:内核管理、采集与日志保留、隐私说明;与通用设置/平台设置重复的项必须共用同一份状态与组件(规则 32)

已定的实现取舍

  • 作用域:概览的出口卡片只提供「当前账号 / 统一代理」两个作用域;多账号批量操作留在账号管理页,避免第一屏误改其他账号。
  • 账号范围:账号管理只列可绑代理的 OAuth 账号;API Key 与模型供应商账号不在此列,也不参与统一代理。
  • 流量口径(第一版):实时上下行速率、本次运行累计、最近 10 分钟内存曲线,全部只保存在当前会话内存中,不做持久化;历史流量与跨重启累计留到后续版本。
  • 订阅用量与到期:需要解析订阅响应头 subscription-userinfo 并随来源保存;字段缺失时来源卡片只显示更新时间与节点数量,不显示假数据。
  • 不做系统代理 / TUN 开关:工作台不提供改系统代理或接管虚拟网卡的开关,只在页面上提示其他代理软件的 TUN/VPN 可能接管账号流量。
  • 连接页不提供手动关闭连接:后端没有关闭单条连接的命令,界面不提供该操作,也不假装已支持。
  • 入口不变:宿主顶部页签与「更多」仍指向同一个代理页面,账号卡片快捷入口仍定位到该账号(规则 37);侧栏只是工作台内部的二级导航。

落地结果(2026-09-25)

上表结构已经实现,工作台取代了原来的三页签页面;翻译键已并入 18 个语言文件(暂存目录已清理)。

部分 实现位置
工作台外壳(侧栏、分区切换、底部流量条、版本号) src/components/codex/CodexProxyWorkspace.tsx、codexProxySections.ts、src/styles/pages/codex-proxy-workspace.css
共享数据层(账号、资源、统一代理、流量采样、资源→账号草稿交接) src/components/codex/CodexProxyWorkspaceContext.tsx、useCodexProxyTraffic.ts、src/utils/codexProxyTraffic.ts
概览 / 连接 CodexProxyOverviewSection.tsx、CodexProxyConnectionsSection.tsx、src/utils/codexProxyFormat.ts
账号管理 / 出口规则 CodexProxyAccountsSection.tsx、CodexProxyExitRulesSection.tsx、useCodexProxyExitEditor.ts、src/utils/codexProxyDraft.ts
代理资源 / 测试 / 设置 CodexProxyResourcesSection.tsx(复用 CodexProxyResources.tsx 与 CodexProxyStrategyPanel.tsx)、CodexProxyTestsSection.tsx、CodexProxySettingsSection.tsx(复用 CodexProxyEngineCard.tsx)
日志 CodexProxyLogsSection.tsx(复用 useCodexProxyActivity.ts 的采集与脱敏导出口径)
全局流量聚合 后端命令 codex_proxy_activity_summary(只返回连接数与上传/下载字节,单账号失败不影响整体)
订阅用量与到期 后端解析 subscription-userinfo 响应头并存进来源,SourceView.usage 暴露给来源卡片与概览

当前验证(可复现):npm run typecheck、npm test(425 项)、node scripts/check_locales.cjs、node scripts/check_modal_sizing.cjs --strict、node_modules/.bin/vite build、git diff --check 全部通过;cd src-tauri && cargo check 通过,cargo test --lib 1570 passed / 0 failed / 13 ignored。

仍未验证:界面渲染与交互未做人工点击确认(项目规则 30 需要用户明确授权),窄窗口、深浅色与长列表表现只经过代码与样式检查;真实 Mihomo 二进制端到端回环仍未验证。


False Positive Template (`docs/false-positive-template.md`)

False Positive Report Template

中文模板(提交工单时可先内部保存)

基本信息

  • 产品名称:Cockpit Tools
  • 项目地址:
  • 下载地址:
  • 版本号:
  • 文件名:
  • SHA256:
  • VirusTotal 链接:
  • 命中引擎:

说明正文

你好,我们是开源项目 Cockpit Tools 的维护者。
我们发现最新发布文件被贵司引擎判定为恶意,但该文件为官方发布构建产物,未包含恶意行为。

请协助复核以下样本是否为误报:

  • 文件名:
  • SHA256:
  • 下载地址:
  • 项目仓库:
  • VirusTotal 报告:

如果需要更多信息(构建日志、源代码位置、复现步骤),我们可以立即补充。谢谢。


English Template (submit to AV vendors)

Subject: False Positive Report - Cockpit Tools

Hello Security Team,

We are the maintainers of an open-source project called Cockpit Tools.
One of our official release binaries appears to be flagged by your engine as malicious, and we believe this is a false positive.

Sample details:

  • Product: Cockpit Tools
  • Version:
  • File name:
  • SHA256:
  • Download URL:
  • Project URL:
  • VirusTotal URL:
  • Detecting engine:

This binary is generated from our public source repository and distributed through our official release channel.

Could you please review and reclassify this sample if appropriate?

If you need any additional information (build logs, source references, reproduction details), we can provide it promptly.

Thank you.


Release Process (`docs/release-process.md`)

Release Process

本文档描述仓库当前由 .github/workflows/release.yml 执行的发布流程。发布行为以 workflow 和 scripts/release/ 下的脚本为准;如果两者与本文不一致,应先修正文档或 workflow,再发版。

1. 发布前检查

在仓库根目录执行:

bash
npm run release:preflight

当前 preflight 依次执行:

  1. node scripts/check_locales.cjs
  2. npm run typecheck
  3. npm run build
  4. cargo check(src-tauri)
  5. cargo test --lib(src-tauri,RUST_TEST_THREADS=1)

排障时可以跳过单项:

bash
node scripts/release/preflight.cjs \
  --skip-locales \
  --skip-typecheck \
  --skip-build \
  --skip-cargo \
  --skip-cargo-test

正式发布不应为了绕过失败而随意使用 skip 参数。

2. 版本与标签

package.json.version 是发布 workflow 读取的版本。创建发布标签前先执行:

bash
npm run sync-version

然后确认版本同步后的文件与 changelog 已提交。发布标签必须严格匹配:

text
v<package.json.version>

例如 package.json.version 为 1.3.40 时,标签必须是 v1.3.40。workflow 会在版本或标签不一致时直接失败。

3. GitHub Actions 发布目标

当前 release workflow 构建并上传:

  • Windows
  • macOS Apple Silicon (aarch64)
  • macOS Intel (x86_64)
  • macOS Universal
  • Linux x86_64
  • Linux aarch64

Linux release 同时包含 AppImage、deb 和 rpm updater targets。macOS Universal DMG 还会用于后续 Homebrew Cask 更新。

三个 macOS 构建 job 在 tauri build 之后会执行 scripts/release/inject-dmg-readme.cjs,用 hdiutil 重建 DMG(保留 .app 原样)并写入 安装与常见问题.txt,同时固定窗口中三个图标的位置:Cockpit Tools 与 Applications 保持同一行(180,150 / 480,150),保证“把图标拖到右侧安装”的动线不变;说明文件单独放在下一行(330,330),窗口尺寸随之调整为 660×490、图标 112px、文字 14pt。Tauri bundler 没有“向 DMG 追加文件”的配置项,因此这里重建的是 bundler 产物本身,而不是在打包阶段插文件;重建后 DMG 文件名与 Tauri 约定一致(_<version>_<arch>.dmg),供 stage_release_assets.cjs 正常规范化。说明文案模板位于 scripts/release/assets/dmg-readme.txt,修改后需与 README.md / README.en.md 的 Gatekeeper 排查章节保持一致。

Tauri release build 使用仓库配置的 updater signing secrets:

  • TAURI_SIGNING_PRIVATE_KEY
  • TAURI_SIGNING_PRIVATE_KEY_PASSWORD

这里的 signing 指 Tauri updater artifact 签名;不要把它描述成已经完成 Apple notarization 或 Windows Authenticode,除非 workflow 另外明确实现了这些步骤。

4. Release assets 与 updater manifests

Windows、macOS Apple Silicon/Intel 和 Linux 构建 job 会先通过 scripts/release/stage_release_assets.cjs 规范化允许上传的 release assets,再用 scripts/release/build_target_latest_json.cjs 生成各 updater target 的 manifest。macOS Universal job 只规范化并上传 Universal DMG,不生成 updater manifest;该 DMG 供后续 Homebrew Cask 更新使用。

所有平台完成后,finalize-legacy-latest job 会下载 release assets,并用:

bash
node scripts/release/build_merged_latest_json.cjs

生成完整 legacy latest.json。workflow 会检查其中至少包含:

  • darwin-aarch64
  • darwin-x86_64
  • windows-x86_64
  • windows-x86_64-nsis
  • Linux x86_64 / aarch64 的 AppImage、deb、rpm targets

随后会通过 scripts/release/verify_published_updater_manifests.cjs 对公开 updater 状态做端到端验证。

5. SHA256SUMS

upload-checksums job 会重新下载该版本的 release assets,对文件逐个计算 SHA-256,并上传:

text
SHA256SUMS.txt

不要依赖文档中不存在的 npm run release:checksums 命令。当前 checksum 的权威实现位于 release workflow 本身;scripts/release/gen_checksums.cjs 是可单独调用的脚本,但不是 package.json 中的标准 npm script。

6. Homebrew Cask

release workflow 会下载已发布的 Universal DMG,计算 SHA-256,然后更新:

text
Casks/cockpit-tools.rb

该更新通过自动创建的 PR 提交,而不是本地 npm run release:github-and-cask。当前 package.json 没有这个 npm script,因此不要按旧文档中的本地一键脚本操作。

7. 推荐发版顺序

  1. 更新 package.json 版本。
  2. 更新 CHANGELOG.md 与 CHANGELOG.zh-CN.md,确保存在对应版本段落。
  3. 执行:
bash
npm run sync-version
npm run release:preflight
  1. 提交并合并发布所需改动。
  2. 从期望发布的 commit 创建 v<version> 标签并推送标签。
  3. 检查 GitHub Actions 的 release workflow 完整成功。
  4. 检查 GitHub Release 的平台 assets、target manifests、latest.json 和 SHA256SUMS.txt。
  5. 检查 Homebrew Cask 自动 PR 的版本和 SHA-256 是否与 Universal DMG 一致。

仅有远端 branch 和 tag 并不代表发布已经成功。正式完成应以 release workflow 成功、预期 assets/manifests 可用以及 checksum 生成完成为准。

8. 当前已知的发布状态问题

当前 workflow 会在所有平台构建完成前就把 staged release 公开并标记为 latest,再在后续 job 中补齐完整 updater state 和 checksums。这样如果某个平台中途失败,公开 release 可能短时间或持续处于不完整状态。

该问题应独立修复,不应通过文档把它描述成推荐设计。修复目标是:release 在所有平台 assets、完整 manifests 和 checksums 验证完成前保持 draft,最后一次性发布并再做公开 URL 验证。


Release Template (`docs/release-template.md`)

Release Notes Template

中文模板

标题

Cockpit Tools vX.Y.Z

更新摘要

  • 新增:
  • 变更:
  • 修复:

下载

  • Windows:
  • macOS:
  • Linux/Ubuntu: 不再提供官方安装包

文件校验(SHA256)

请下载并核对 SHA256SUMS.txt。
建议在安装前先校验哈希,确保文件完整且未被篡改。

安全扫描(可选)

  • VirusTotal:
  • 说明:如存在单引擎误报(例如 1/72),我们会提交误报复核。

已知问题

  • (没有可写 “暂无”)

English Template

Title

Cockpit Tools vX.Y.Z

Highlights

  • Added:
  • Changed:
  • Fixed:

Downloads

  • Windows:
  • macOS:
  • Linux/Ubuntu: no official installer is provided

File Integrity (SHA256)

Please verify downloaded files with SHA256SUMS.txt before installation.

Security Scan (Optional)

  • VirusTotal:
  • Note: If there is a single-engine detection (for example 1/72), we will submit a false-positive report.

Known Issues

  • (Use "None" if no known issues)

Adr 0001 Use Native Responses For Deepseek Codex (`docs/adr/0001-use-native-responses-for-deepseek-codex.md`)

Use native Responses for the official DeepSeek Codex preset

Decision

For the official DeepSeek preset (api.deepseek.com):

  1. Default protocol is Responses (wire_api = "responses"), aligned with DeepSeek’s Codex setup script.
  2. Chat Completions remains available when the user explicitly selects it (no hard lock).
  3. Responses stays native, but the instance provider gateway only rewrites the model name:
    • Picker display_name is DeepSeek-V4-Flash / Pro.
    • Catalog slug uses official Codex whitelist shells gpt-5.6-luna / gpt-5.6-sol.
    • The sidecar replaces that slug with deepseek-v4-flash / pro and forwards the Responses body unchanged.
    • Cockpit writes cockpit-provider-model-catalog.json into the target instance CODEX_HOME.
    • Official DeepSeek tool metadata is overlaid onto the Codex client-model shape.
    • Instance models_cache.json is invalidated after the catalog write.
  4. Default model prefers deepseek-v4-flash. Leftover shell names such as gpt-5.6-sol are replaced on switch.
  5. Codex API Service can still keep a visible per-account mapping for pool rotation. That mapping is not used by desktop instance startup.

Why

The user wants native Responses without a local remapping gateway. Official slugs plus official catalog metadata let Codex emit DeepSeek tool/shell/apply_patch shapes and send names the official API accepts.

Consequences

  • Desktop / multi-instance start uses a per-instance provider gateway sidecar only to rewrite gpt-5.6-luna / gpt-5.6-sol → deepseek-v4-flash / pro.
  • Enabling from 模型供应商 onto a non-default instance writes {instance_dir}/cockpit-provider-model-catalog.json.
  • Chat Completions still uses the instance provider gateway for protocol conversion.
  • Existing DeepSeek accounts with explicit Chat Completions are not auto-migrated away from Chat.
  • Accounts without a wire protocol still default to Responses for DeepSeek.

Update: direct / CDP catalogs use the official entries verbatim

The shell-template decision above only still applies to gateway mode, where the instance
provider gateway rewrites the model name. The direct and CDP catalogs no longer derive
their metadata from a Codex built-in model shell:

  • Entries written to {instance_dir}/cockpit-model-catalog.json are the complete official
    models.json entries, so multi_agent_version, minimal_client_version,
    effective_context_window_percent and friends match DeepSeek's declaration instead of the
    shell's, and shell-only fields (pricing tiers, plan gating, apps/plugins instruction switches)
    no longer leak onto a DeepSeek model.
  • Switching to DeepSeek also writes web_search = "disabled" and temporarily removes the
    top-level keys that contradict the official model declaration (the DEL_B list of DeepSeek's
    codex-deepseek-setup.sh), recording original values so switching away restores them.
    model_context_window / model_auto_compact_token_limit are intentionally not in that list:
    Cockpit's context-management feature owns them as an explicit user setting.

Third Party Mihomo V1.19.31 (`docs/third-party/mihomo-v1.19.31.md`)

Mihomo v1.19.31 — third-party review record

Status: not approved for bundling. The host downloads an official pinned archive only when the user requests installation, or accepts that exact archive from disk. Normal builds do not bundle the engine.

Upstream and pinned artifacts

Six target archives are pinned by their official GitHub asset digests. macOS and Linux use a gzip-compressed executable; Windows uses a ZIP containing one executable, normalized to mihomo.exe. No Cronet DLL is required. The x86_64 assets use the upstream amd64-v1 baseline. Upstream provides separate macOS architectures; universal bundling requires a separate build and verification decision.

Installation and execution

Installation verifies the archive SHA-256 before extraction, bounds compressed and decompressed sizes, supports cancellation and timeouts, checks the engine version, and atomically publishes an immutable release. Active processes hold a release lease. A failed installation preserves the previous active pointer. Old sing-box records fail the new version/digest requirements and are never selected as Mihomo.

Downloads occur only after a user installation request, directly from GitHub with restricted HTTPS redirects. Page reads and app startup do not download the engine. The configuration and account proxy lifecycle are managed by the host; the engine runs as a separate background process. Windows launches hide the console window. No system proxy or TUN is enabled by installing the engine.

Optional offline packaging

Verify an archive without executing or downloading it:

sh
node scripts/verify-proxy-engine-archive.cjs <rust-target> <archive-path>

Prepare the verified executable:

sh
COCKPIT_PROXY_ENGINE_TARGET=<rust-target> \
COCKPIT_PROXY_ENGINE_ARCHIVE=<verified-archive> \
npm run proxy-engine:prepare

prepared.json records the target, archive digest and executable digest. Bundling remains blocked by distributionApproved: false. Before changing this flag, review the corresponding source, license and dependency notices, build inputs, modifications and durable source availability for the intended distribution. Process separation alone is not a licensing conclusion. After that review, the existing explicit proxy-engine:bundle-config command can generate a per-target Tauri resources overlay. Default development and release builds do not include Mihomo.


Third Party Sing Box V1.14.1 (`docs/third-party/sing-box-v1.14.1.md`)

sing-box v1.14.1 — third-party review record

Historical record. The active proxy engine is now Mihomo v1.19.31; the commands and runtime details below describe the former sing-box integration.

Status: not approved for distribution. This file records engineering facts and is not legal advice.

Upstream

The upstream license is GPLv3-or-later and includes an additional name/association restriction. The host project license is different. Process separation is an engineering boundary, not a legal conclusion. Before shipping, preserve the corresponding source, license text, dependency notices, build inputs, modification record, and a durable source-access path as required by the chosen distribution model.

Pinned artifacts

The machine-readable list is sidecars/sing-box/upstream-assets.json. It pins six upstream archives and their SHA-256 values. Verify an archive without downloading or executing it:

sh
node scripts/verify-proxy-engine-archive.cjs <rust-target> <archive-path>

Prepare a verified archive explicitly:

sh
COCKPIT_PROXY_ENGINE_TARGET=<rust-target> \
COCKPIT_PROXY_ENGINE_ARCHIVE=<verified-archive> \
npm run proxy-engine:prepare

The preparation command does not download an archive. It extracts only an archive whose digest matches the manifest and refuses missing environment variables. It is not a distribution approval step.

The prepared directory also contains prepared.json, recording the target, pinned archive digest, and hashes of the files to bundle. After the corresponding-source and license review is complete, set distributionApproved to true in the pinned manifest through a reviewed project change. Then generate a Tauri configuration overlay for one target:

sh
npm run proxy-engine:bundle-config -- <rust-target>
npm run tauri build -- --target <rust-target> --config .tmp/proxy-engine/tauri.<rust-target>.conf.json

The configuration maps the executable to proxy-engine/ inside Tauri resources and includes libcronet.dll on Windows. The build command is an explicit packaging path; normal development and release builds do not include the engine. The generator rejects a missing or mismatched prepared target, changed binary, and the current unapproved manifest. It does not download or execute the engine. The macOS universal target is deliberately unsupported: upstream supplies separate architecture binaries, and a merged binary would need its own verification and signing review. The release workflows must be updated and their installer contents checked before claiming that official downloads include the engine.

Platform-specific review notes

  • Windows ZIP archives include sing-box.exe and libcronet.dll; shipping only the executable is not equivalent to shipping the upstream package.
  • The upstream release has separate macOS x64 and arm64 archives, not a macOS universal archive. Any universal build must be produced and signed separately, then verified.
  • The upstream build uses with_naive_outbound; the pinned build also needs review of with_quic, with_utls, and whether gRPC is present before presenting any URI combination as supported.
  • The pinned Cronet source version in the upstream build metadata is 0d28acc44093df24b2526dea3d6ffefd6b0a54f0.

User-triggered installation

The proxy page can download the pinned official archive directly from GitHub or import the same archive from disk. This is distinct from bundling: distributionApproved: false continues to disable inclusion in our installer. No app startup or page read triggers downloads. The installer checks the pinned archive SHA-256, preserves available LICENSE/NOTICE files, requires Windows companion DLLs, and switches an immutable user-data release only after extraction and version validation. Active processes retain a lease on their release. One previous release is retained, older unused releases and abandoned staging directories are cleaned during installation. Source and licensing references remain linked above.

Runtime boundary

The application passes configuration over stdin to sing-box run -c stdin; secrets are not command-line arguments or logs. The local mixed inbound is loopback-only, and Windows background launches use CREATE_NO_WINDOW. The desktop bridge intentionally has no local-user authentication because Chromium cannot reliably consume authenticated SOCKS launch flags; it is not a device or OS-user isolation feature.


Third Party Super Ai Tools (`docs/third-party/super-ai-tools.md`)

super-ai-tools source attribution / 来源声明

  • Source / 来源: https://github.com/lihah111222333-cloud/super-ai-tools (deleted upstream; retained local snapshot / 上游已删除,使用本地保留快照).
  • Revision / 提交: 8d48a91ad28744349e3a457e519dd0a0582036b1.
  • Reference areas / 参考范围: account-import validation, gateway credential loading and reliability fixes / 账号导入校验、网关凭据读取及稳定性修复。
  • These are host-source adaptations, not a runtime plugin, SDK integration or official partnership / 属于宿主源码参考与适配,不是运行时插件、SDK 集成或官方合作。
  • The original root license is preserved in super-ai-tools.LICENSE, CC BY-NC-SA 4.0; existing dependency notices remain applicable / 完整保留原始根目录许可 CC BY-NC-SA 4.0,依赖的原有许可声明继续适用。

--- METRICS ---