Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 53 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ jobs:
CPA_BINARY=/tmp/cpa-test/cli-proxy-api python3 tests/cpa_round2.py
CPA_BINARY=/tmp/cpa-test/cli-proxy-api python3 tests/cpa_count_tokens.py
CPA_BINARY=/tmp/cpa-test/cli-proxy-api python3 tests/cpa_thinking_suffix.py
gh release download v0.2.11 --repo Gaoshou101/CommandCodeBridge --pattern commandcodebridge_0.2.11_linux_amd64.zip --pattern checksums.txt --dir /tmp/bridge-previous
gh release download v0.2.12 --repo Gaoshou101/CommandCodeBridge --pattern commandcodebridge_0.2.12_linux_amd64.zip --pattern checksums.txt --dir /tmp/bridge-previous
cd /tmp/bridge-previous
sha256sum --check --ignore-missing checksums.txt
cd "$GITHUB_WORKSPACE"
CPA_BINARY=/tmp/cpa-test/cli-proxy-api python3 tests/cpa_hot_reload.py --previous-archive /tmp/bridge-previous/commandcodebridge_0.2.11_linux_amd64.zip
CPA_BINARY=/tmp/cpa-test/cli-proxy-api python3 tests/cpa_hot_reload.py --previous-archive /tmp/bridge-previous/commandcodebridge_0.2.12_linux_amd64.zip
- uses: actions/download-artifact@v4
with:
name: cpamp-manager-test
Expand Down Expand Up @@ -92,12 +92,18 @@ jobs:
fail-fast: false
matrix:
include:
# Linux libraries are built in manylinux_2_28 so they load on glibc 2.28+ hosts, not only
# on the runner's glibc. Pinned by digest; bump deliberately.
- runner: ubuntu-24.04
target: linux-amd64
extension: so
manylinux: quay.io/pypa/manylinux_2_28_x86_64:2026.11.06-1@sha256:ae830e2ecbf4568743f8b760920cd7483538375b6b242a9fb02b5b2ad0245f68
cpa-archive: CLIProxyAPI_8.0.23_linux_amd64.tar.gz
- runner: ubuntu-24.04-arm
target: linux-arm64
extension: so
manylinux: quay.io/pypa/manylinux_2_28_aarch64:2026.11.06-1@sha256:6c4f9b6d9453bb47b21b4c1e4f04f3c662584f60f4ed8455f4561a336ff19414
cpa-archive: CLIProxyAPI_8.0.23_linux_aarch64.tar.gz
- runner: windows-2022
target: windows-amd64
extension: dll
Expand Down Expand Up @@ -128,9 +134,28 @@ jobs:
REPOSITORY: https://github.com/${{ github.repository }}
# Only read by the darwin toolchain; v0.2.11 and earlier shipped with minos 14.0.
MACOSX_DEPLOYMENT_TARGET: '14.0'
MANYLINUX_IMAGE: ${{ matrix.manylinux }}
# Supported Linux glibc minimum: the build fails above it and package.py records it in BUILD.json.
GLIBC_FLOOR: ${{ matrix.manylinux != '' && '2.28' || '' }}
run: |
mkdir -p dist
go build -trimpath -buildvcs=false -buildmode=c-shared -ldflags="-s -w -X commandcodebridge/internal/bridge.Repository=$REPOSITORY" -o dist/commandcodebridge.${{ matrix.extension }} ./cmd/commandcodebridge
ldflags="-s -w -X commandcodebridge/internal/bridge.Repository=$REPOSITORY"
if [ -n "$MANYLINUX_IMAGE" ]; then
# Reuse the runner's official (statically linked) Go toolchain and caches inside the container.
goroot="$(go env GOROOT)"; gomodcache="$(go env GOMODCACHE)"; gocache="$(go env GOCACHE)"
mkdir -p "$gomodcache" "$gocache"
docker run --rm -u "$(id -u):$(id -g)" -v "$GITHUB_WORKSPACE:/src" -w /src -v "$goroot:/goroot:ro" \
-v "$gomodcache:/gomodcache" -v "$gocache:/gocache" \
-e HOME=/tmp -e GOMODCACHE=/gomodcache -e GOCACHE=/gocache -e GOTOOLCHAIN=local -e CGO_ENABLED=1 \
"$MANYLINUX_IMAGE" /goroot/bin/go build -trimpath -buildvcs=false -buildmode=c-shared -ldflags="$ldflags" -o dist/commandcodebridge.so ./cmd/commandcodebridge
required="$(objdump -T dist/commandcodebridge.so | grep -o 'GLIBC_[0-9.]*' | sed 's/^GLIBC_//' | sort -V | tail -1)"
echo "linux library requires glibc $required"
if [ "$(printf '%s\n%s\n' "$required" "$GLIBC_FLOOR" | sort -V | tail -1)" != "$GLIBC_FLOOR" ]; then
echo "::error::linux library requires glibc $required > $GLIBC_FLOOR"; exit 1
fi
else
go build -trimpath -buildvcs=false -buildmode=c-shared -ldflags="$ldflags" -o dist/commandcodebridge.${{ matrix.extension }} ./cmd/commandcodebridge
fi
if [ "${{ matrix.target }}" = darwin-arm64 ]; then
minos="$(otool -l dist/commandcodebridge.dylib | awk '/LC_BUILD_VERSION/ {found=1} found && $1 == "minos" {print $2; exit}')"
echo "darwin dylib minos: $minos"
Expand All @@ -140,6 +165,29 @@ jobs:
if [ "${{ matrix.target }}" = windows-amd64 ]; then helper="$helper.exe"; fi
CGO_ENABLED=0 go build -trimpath -buildvcs=false -ldflags="-s -w" -o "$helper" ./cmd/commandcodebridge-login
python scripts/package.py dist/commandcodebridge.${{ matrix.extension }} --target ${{ matrix.target }}
- name: Load and run on glibc 2.28
if: matrix.manylinux != ''
shell: bash
env:
GH_TOKEN: ${{ github.token }}
MANYLINUX_IMAGE: ${{ matrix.manylinux }}
CPA_ARCHIVE: ${{ matrix.cpa-archive }}
run: |
task_dir="$RUNNER_TEMP/cpa-glibc228"
mkdir -p "$task_dir"
gh release download v8.0.23 --repo router-for-me/CLIProxyAPI --pattern "$CPA_ARCHIVE" --pattern checksums.txt --dir "$task_dir"
(cd "$task_dir" && sha256sum --check --ignore-missing checksums.txt && tar -xzf "$CPA_ARCHIVE")
# The pinned CPA release only needs glibc 2.3.2, so the whole host runs inside the old userland.
docker run --rm -u "$(id -u):$(id -g)" -v "$GITHUB_WORKSPACE:/src" -w /src -v "$task_dir:/cpa:ro" \
-e HOME=/tmp -e CPA_BINARY=/cpa/cli-proxy-api -e BRIDGE_LIBRARY=/src/dist/commandcodebridge.so \
"$MANYLINUX_IMAGE" bash -euc '
ldd --version | head -1
py=/opt/python/cp312-cp312/bin/python3
$py -c "import ctypes, os; ctypes.CDLL(os.environ[\"BRIDGE_LIBRARY\"]); print(\"dlopen OK\")"
$py tests/cpa_e2e.py
$py tests/cpa_count_tokens.py
$py tests/cpa_thinking_suffix.py
'
- name: Windows native host integration
if: matrix.target == 'windows-amd64'
shell: pwsh
Expand Down Expand Up @@ -358,7 +406,7 @@ jobs:
pattern: commandcodebridge-*
path: dist
merge-multiple: true
- run: python scripts/checksums.py dist --include-cpamp
- run: python scripts/checksums.py dist --include-cpamp --max-glibc 2.28
- uses: actions/upload-artifact@v4
with:
name: commandcodebridge-checksums
Expand Down Expand Up @@ -387,7 +435,7 @@ jobs:
env:
RELEASE_TAG: ${{ github.ref_name }}
run: |
python scripts/checksums.py dist --include-cpamp
python scripts/checksums.py dist --include-cpamp --max-glibc 2.28
python - <<'PY'
import json, os, pathlib, re, zipfile
version = re.search(r'const Version = "([^"]+)"', pathlib.Path('internal/bridge/types.go').read_text()).group(1)
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## [0.2.13] - 2026-11-07

### Added

- 可选的上游停滞保护:`first_byte_timeout_seconds` 限制从请求开始到首段上游响应数据的时间(含等待响应头),`stream_idle_timeout_seconds` 限制此后两段数据之间的间隔。两者都在 `timeout_seconds` 之内生效,0 为关闭(默认),启用时取 5–1800 秒;可在控制台设置页或 YAML 配置,保存即时生效。触发时返回 504,日志错误类型为 `upstream_first_byte_timeout` 或 `upstream_stream_idle_timeout`,并关闭上游连接。真实上游下长推理模型的首字节与段间间隔尚未实测,因此默认不启用。

### Changed

- 运行数据文件(`requests.json`、`statistics.json`、`usage.json` 及检查点)改为紧凑 JSON,结构不变;同一文件持续变更时,两次重写的间隔按上次写入大小折算为约 1 MiB/s(最长 10 秒)。小文件仍为 250ms,正常卸载立即写入全部待写文件。合成测量中,90 天 × 2 模型的统计文件从 9.8 MB 缩小到 7.5 MB,持续流量下写入从约 39 MB/s 降至约 1 MB/s;1,000 条请求记录从约 3.9 MB/s 降至约 1 MB/s。代价是强制结束进程时大文件可能丢失最多约 10 秒的变更。
- Linux 动态库改在固定摘要的 manylinux_2_28 容器中构建,最低 glibc 从 2.34 降至 **2.28**(RHEL/AlmaLinux 8、Debian 10、Ubuntu 20.04 及更新版本)。CI 在 glibc 2.28 用户态中加载动态库,并运行 CPA v8.0.23 宿主联测;构建与发布校验会拒绝要求更高 glibc 的 Linux 包。`BUILD.json` 的 `glibc_minimum` 记录受支持的最低版本,`glibc_symbol_version_max` 记录符号版本的实际上限。
- Antigravity 额度行为回归(请求层 Vitest、生产页面 Playwright 场景、Manager 快照与 SQLite 恢复、源码降版变异、真实 CPA 转发)纳入 `cpamp-web → test → build → release` 发布门槛(#14)。热升级联测的前一版本改为 v0.2.12。

## [0.2.12] - 2026-11-07

### Fixed
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
- **原生额度窗口**:在 CPAMP 列表、卡片和详情查看 5h、周、月额度,查询窗口请求统计、预测和周期快照。
- **请求记录**:查看凭证健康度、tokens、缓存用量、预估花费、首字耗时、输出速率及模型统计;支持明暗主题和手机布局。

当前版本 **v0.2.12**。插件调用官方 Provider API;Go 订阅的 `/alpha/generate` 路径和固定上游 provider 模式不在支持范围内。账户用量通过官方 `/alpha/...` 查询接口读取,模型权限以实际套餐为准。
当前版本 **v0.2.13**。插件调用官方 Provider API;Go 订阅的 `/alpha/generate` 路径和固定上游 provider 模式不在支持范围内。账户用量通过官方 `/alpha/...` 查询接口读取,模型权限以实际套餐为准。

### v0.2.13 更新

Linux 包的 glibc 要求从 2.34 降至 **2.28**(RHEL/AlmaLinux 8、Debian 10、Ubuntu 20.04 起);运行数据改为紧凑 JSON,并限制大文件的持续重写频率,持续流量下统计文件写盘约降为原来的 1/37;新增可选的首字节超时与流空闲超时(默认关闭,在「设置 → 请求策略」启用)。

### v0.2.12 更新

Expand Down Expand Up @@ -43,7 +47,7 @@ plugins:
- https://raw.githubusercontent.com/Gaoshou101/CommandCodeBridge/main/registry.json
```

保存并重载配置,在 CPAMP「插件商店」找到 **CommandCodeBridge**,选择 Latest 或 **v0.2.12** 安装。支持热升级的宿主会下载匹配平台的 ZIP、验证校验值并切换版本;安装后检查插件控制台显示的运行版本。
保存并重载配置,在 CPAMP「插件商店」找到 **CommandCodeBridge**,选择 Latest 或 **v0.2.13** 安装。支持热升级的宿主会下载匹配平台的 ZIP、验证校验值并切换版本;安装后检查插件控制台显示的运行版本。

也可从 [Releases](https://github.com/Gaoshou101/CommandCodeBridge/releases/latest) 手动下载 ZIP 和 `checksums.txt`。按 **CPA 所在服务器**选择动态库:

Expand All @@ -54,7 +58,7 @@ plugins:
| Windows x64 | `_windows_amd64.zip` | `commandcodebridge.dll` |
| macOS Apple Silicon | `_darwin_arm64.zip` | `commandcodebridge.dylib` |

Linux 发布包要求 glibc ≥2.34;Alpine/musl 需自行构建。手动安装时核验校验值,将动态库放入实际 `plugins.dir`,合并 [config.example.yaml](./config.example.yaml),按宿主的加载方式启用插件。完整步骤见[部署说明](./docs/DEPLOYMENT.md)。
Linux 发布包要求 glibc ≥2.28(v0.2.12 及更早为 ≥2.34);Alpine/musl 需自行构建。手动安装时核验校验值,将动态库放入实际 `plugins.dir`,合并 [config.example.yaml](./config.example.yaml),按宿主的加载方式启用插件。完整步骤见[部署说明](./docs/DEPLOYMENT.md)。

## 快速开始

Expand All @@ -69,7 +73,7 @@ Linux 发布包要求 glibc ≥2.34;Alpine/musl 需自行构建。手动安装

## 安装或更新原生面板

**升级插件后还要更新 CPAMP 页面**,才能使用新版凭证布局。v0.2.12 动态库已内嵌匹配页面。
**升级插件后还要更新 CPAMP 页面**,才能使用新版凭证布局。v0.2.13 动态库已内嵌匹配页面。

CPA 与 Manager Server 在同一主机直接运行时:

Expand All @@ -84,7 +88,7 @@ CPA 与 Manager Server 在同一主机直接运行时:
| 首次启用外部页面,或更改 Manager Server 的页面路径 | 重启 Manager Server 一次 |
| 迁移插件数据目录,或旧宿主不支持动态库热升级 | 安排相应服务重启 |

Manager Server 在另一台主机或独立容器中时,在其运行环境安装 `commandcodebridge_0.2.12_cpamp-web.zip` 内的 `management.html`,通过 `PANEL_PATH` 或 `panelPath` 托管。面板源码基线见 [compatibility.json](./internal/bridge/compatibility.json) 的 `cpamp_source_commit`;不同版本应在匹配源码上应用适配。
Manager Server 在另一台主机或独立容器中时,在其运行环境安装 `commandcodebridge_0.2.13_cpamp-web.zip` 内的 `management.html`,通过 `PANEL_PATH` 或 `panelPath` 托管。面板源码基线见 [compatibility.json](./internal/bridge/compatibility.json) 的 `cpamp_source_commit`;不同版本应在匹配源码上应用适配。

**完整周期快照另需 Manager Server 接受 `commandcode` 平台。** 前端包附带适配脚本、服务器名单补丁和测试;按现有 Manager Server 的同一源码版本重建并部署。仅更新插件和页面不能替代这个服务器改动。[原生集成说明](./integrations/cpamp/README.md)包含构建、HTTP 生效核验和回滚步骤。

Expand Down
4 changes: 4 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ plugins:
cpamp_panel_path: ""
# Browser OAuth uses a local POST receiver and CPAMP result submission.
timeout_seconds: 600
# Optional stall guards inside timeout_seconds (0 = off, otherwise 5-1800):
# time to the first upstream response data, and the longest gap between chunks.
first_byte_timeout_seconds: 0
stream_idle_timeout_seconds: 0
usage_refresh_seconds: 60
log_retention: 1000
max_response_bytes: 16777216
Expand Down
20 changes: 14 additions & 6 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# CPAMP 部署、升级与回滚

本文说明 CommandCodeBridge v0.2.12 的安装、页面更新与回滚。路径应以实际运行环境为准;历史排查中的路径仅用于说明当时的问题。
本文说明 CommandCodeBridge v0.2.13 的安装、页面更新与回滚。路径应以实际运行环境为准;历史排查中的路径仅用于说明当时的问题。

## v0.2.13:glibc 2.28、写盘与超时保护

1. 更新插件至 v0.2.13,确认实际运行版本;配置无需修改。Linux 主机只需 glibc ≥2.28,此前因 glibc 过低无法加载的主机(如 RHEL/AlmaLinux 8、Debian 10)可以直接安装。
2. 运行数据文件改为紧凑 JSON,结构不变,旧版本可直接读取;降级不需要迁移。
3. 首字节超时与流空闲超时默认关闭。需要时在「设置 → 请求策略」启用,取值宜宽松,详见下方常见问题。
4. 页面功能未变,但页面带插件版本标识,仍按下节步骤更新 CPAMP 页面并强刷浏览器。

## v0.2.12:count_tokens 与思考后缀兼容

Expand Down Expand Up @@ -35,7 +42,7 @@ v0.2.8 的四平台插件内嵌新版 CPAMP 页面,支持官方套餐月限额

| 操作 | 生效方式 |
| --- | --- |
| 控制台修改超时、日志保留、用量刷新、响应大小、ZDR、模型或面板探测路径 | 保存后即时生效,不重启 CPA |
| 控制台修改超时(含首字节与流空闲超时)、日志保留、用量刷新、响应大小、ZDR、模型或面板探测路径 | 保存后即时生效,不重启 CPA |
| CPA 配置页修改插件的 CPAMP 路径 | 宿主重载调用 `plugin.reconfigure`;显式非空路径覆盖旧保存值 |
| 更新已启用的外部原生面板 | 点击「更新原生面板」,原路径原子替换;强刷浏览器,不重启 Manager Server |
| 通过支持热升级的 CPA 插件商店升级动态库 | 宿主选择新的版本化文件并切换插件;确认运行版本,无需重启 CPA |
Expand Down Expand Up @@ -138,12 +145,12 @@ GitHub 仓库首页用于浏览源码;在“插件源”输入框应填写上

| 宿主 | 安装包后缀 | 动态库 | 要求 |
| --- | --- | --- | --- |
| Linux x64 | `_linux_amd64.zip` | `commandcodebridge.so` | glibc ≥2.34 |
| Linux ARM64 | `_linux_arm64.zip` | `commandcodebridge.so` | glibc ≥2.34 |
| Linux x64 | `_linux_amd64.zip` | `commandcodebridge.so` | glibc ≥2.28 |
| Linux ARM64 | `_linux_arm64.zip` | `commandcodebridge.so` | glibc ≥2.28 |
| Windows x64 | `_windows_amd64.zip` | `commandcodebridge.dll` | 64 位 CPA |
| macOS Apple Silicon | `_darwin_arm64.zip` | `commandcodebridge.dylib` | ARM64 CPA |

以上均已在对应平台使用 CPA v8.0.23 运行模拟集成与异常恢复测试。Linux Alpine/musl 需另外构建。
以上均已在对应平台使用 CPA v8.0.23 运行模拟集成与异常恢复测试;Linux x64/ARM64 另在 glibc 2.28 用户态中加载并运行宿主联测。Linux Alpine/musl 需另外构建。

Linux 下载后,在文件所在目录核验:

Expand Down Expand Up @@ -191,6 +198,7 @@ Windows 使用 `Get-FileHash -Algorithm SHA256`,macOS 使用 `shasum -a 256`
| 无法加载库 | CPA 是否含插件支持;CPU/系统/运行库是否匹配;文件是否可读 |
| 模型可见但返回 403 | 目录不保证套餐权限,检查 `MODEL_NOT_IN_PLAN` |
| 接口直连失败或超时 | 确认 CPA 全局代理;插件不继承 Windows 系统代理 |
| 上游长时间无响应才报 504 | 可在设置页启用「首字节超时」和「流空闲超时」(`first_byte_timeout_seconds`、`stream_idle_timeout_seconds`,0 为关闭,启用时 5–1800 秒)。日志的错误类型分别为 `upstream_first_byte_timeout`、`upstream_stream_idle_timeout`;默认关闭,长推理模型在真实上游中的首字节与段间间隔尚未实测,取值宜宽松 |
| 用量缺失 | 查看 `unavailable` / `status`;查询失败保留旧值 |
| 日志写入失败 | 检查 data_dir 的磁盘空间、权限及 `storage_error` |
| 重启后设置未按 YAML 改变 | 已存 settings.json 优先;采用明确的迁移方案 |
Expand All @@ -216,7 +224,7 @@ Windows 使用 `Get-FileHash -Algorithm SHA256`,macOS 使用 `shasum -a 256`

### 文件与写入

`settings.json`、凭证仍走原配置/宿主流程。`requests.json`、`statistics.json`、`usage.json` 保留原数组/字典结构,分别标脏、250ms 批量刷盘;只有变更的文件写入。`runtime-format.json` 记录格式版本及最近 20 条恢复警告。未知格式、设置损坏或不可读均明确报错,保留原文件。
`settings.json`、凭证仍走原配置/宿主流程。`requests.json`、`statistics.json`、`usage.json` 保留原数组/字典结构(紧凑 JSON),分别标脏、250ms 批量刷盘;只有变更的文件写入。持续变更时,同一文件两次重写的间隔按上次写入大小折算为约 1 MiB/s,最长 10 秒:小文件仍为 250ms,数 MB 的统计文件约数秒写一次;正常卸载会立即写入全部待写文件。强制结束进程或断电时,大文件可能丢失这一间隔内的变更。`runtime-format.json` 记录格式版本及最近 20 条恢复警告。未知格式、设置损坏或不可读均明确报错,保留原文件。

每个运行文件的 `.last-good` 检查点最多每分钟随变更刷新一次。恢复可能丢失检查点之后的数据,独立文件不构成跨文件事务,也不承诺断电 fsync 耐久性。状态/设置页显示最近成功刷盘、待写文件与起始时间,恢复警告重启后仍保留。无有效检查点时,仅重建损坏的观察文件,并提示该历史范围未知;配置与其他有效历史保留。

Expand Down
Loading
Loading