本文定义将上游社区仓库合并进本二次开发 monorepo 时的目标、目录挂载模型、映射表、流程与裁决规则。
上游来源:相关入口:根目录
AGENTS.md、backend/CLIPROXYAPI_UPSTREAM_CN.md、双引擎架构。
社区合并只追求三件事:
/v0、/v1、SSE、WebSocket、OAuth、插件 ABI 不回退。不以“与社区文件逐行一致”为成功标准。
本仓不是单上游 fork,而是 双上游合成 monorepo:
1) 上游挂载层
- 前端社区工程根
- 后端社区工程根
2) 二开层
- 前端 external
- 后端 internal/core
- 后端 cmd/cpamc
3) 合成控制面
- 根 AGENTS.md
- doc/
- .devcontainer/
- build.sh
- 本地 CI / upstream-ref
判断新文件放哪时,先问它属于哪一层。
本仓已完成 monorepo 目录迁移。执行规则一律使用 frontend/ 与 backend/。
.
├── frontend/ # 挂载前端社区整仓
│ ├── package.json
│ ├── bun.lock
│ ├── index.html
│ ├── vite.config.ts
│ ├── tsconfig*.json
│ ├── eslint.config.js
│ ├── .prettierrc
│ ├── logo.jpg
│ ├── .frontend-upstream-ref # 本地前端上游 pin
│ ├── tests/ # 上游 tests(若存在)
│ └── src/
│ ├── external/ # 本地二开(上游无)
│ └── ... # 上游 src
│
├── backend/ # 挂载后端社区整仓
│ ├── go.mod / go.sum # module: .../backend
│ ├── config.example.yaml
│ ├── cmd/
│ │ ├── server/ # 上游兼容入口
│ │ └── cpamc/ # 本地统一入口
│ ├── internal/
│ │ ├── core/ # 本地二开
│ │ └── ... # 上游 internal
│ ├── sdk/
│ ├── examples/
│ ├── test/
│ ├── assets/ # 按需保留上游资产
│ ├── CLIPROXYAPI_UPSTREAM_CN.md
│ └── .cliproxyapi-upstream-ref
│
├── doc/ # 本地正式文档(不是上游 docs 的替代拷贝)
├── .devcontainer/ # 统一 Dockerfile + start.sh(默认 dev)+ compose 画像
├── build.sh # 根总控
├── AGENTS.md # 本地二开/合并总则
├── README.md
└── .github/workflows/ # 本地 CI
历史路径对照(迁移前 → 迁移后):
| 迁移前 | 迁移后 |
|---|---|
src/** |
frontend/src/** |
根前端工程文件(package.json、vite.config.ts、index.html、tsconfig* 等) |
frontend/ |
services/** |
backend/** |
src/external/** |
frontend/src/external/** |
services/internal/core/** |
backend/internal/core/** |
services/cmd/cpamc/** |
backend/cmd/cpamc/** |
Go module path 保持社区原值:github.com/router-for-me/CLIProxyAPI/v7。同步时不做 module path 批量改写。
前端上游根(示例)包含:AGENTS.md、README*、LICENSE、package.json、bun.lock、index.html、vite.config.ts、tsconfig*、eslint.config.js、.prettierrc、.github/、logo.jpg、src/、tests/ 等。
| 上游路径 | 本地挂载 | 策略 |
|---|---|---|
src/** |
frontend/src/** |
覆盖式同步;排除 external/ |
tests/** |
frontend/tests/** |
同步(若上游有) |
package.json / bun.lock |
frontend/ |
同步后检查本地脚本 |
index.html / vite.config.ts / tsconfig* / eslint / prettier / logo.jpg |
frontend/ |
同步 |
上游 AGENTS.md / README* / LICENSE |
— | 不覆盖 monorepo 根控制面;仅参考 |
上游 .github/ |
— | 不直接覆盖本地 CI;按需移植 job |
(本地)frontend/src/external/** |
保护 | 永不覆盖 |
(本地)frontend/.frontend-upstream-ref |
保护 | 永不覆盖;仅成功同步后由本仓更新 |
前端二开入口已经整体迁入 frontend/src/external/。frontend/index.html 指向 src/external/main.tsx,社区 main.tsx、App.tsx、MainRoutes.tsx 和 MainLayout.tsx 由 manifest 保持不存在。
商业入口排除(不移植):
/quick-start 页面、路由、导航、Dashboard 入口SponsorQuickStartPanel 以及 fixedBrand='apikeyFun' 的 quick-start 展示普通 AI Providers 工作台所需 sponsor adapter 等 plumbing 可保留,但不得再出现独立 quick-start / quick-fill 入口。
后端上游根(示例)包含:AGENTS.md、CLAUDE.md、README*、LICENSE、go.mod、go.sum、config.example.yaml、Docker/compose、.env*.example、.github/、cmd/、internal/、sdk/、examples/、test/、docs/、assets/、auths/ 等。
| 上游路径 | 本地挂载 | 策略 |
|---|---|---|
cmd/** |
backend/cmd/** |
三方/镜像;保留本地 cmd/cpamc |
internal/** |
backend/internal/** |
三方/镜像;保留本地 internal/core |
sdk/** |
backend/sdk/** |
镜像 |
test/** / examples/** |
backend/test/**、backend/examples/** |
镜像 |
go.mod / go.sum / config.example.yaml |
backend/ |
镜像 + 追加本地依赖;module 保持 .../backend |
assets/** |
backend/assets/** |
按需同步 |
上游 docs/ |
— | 不替代本仓 ../;仅参考 |
| 上游 Docker/compose/Dockerfile | — | 不替代 .devcontainer/(统一 Dockerfile + compose 画像) |
上游 AGENTS.md / README* / .github/ |
— | 不占领 monorepo 根;仅参考/按需移植 job |
上游 auths/、运行时敏感目录 |
— | 通常不进主跟踪;本地夹具只用 doc.local/ |
(本地)backend/internal/core/** |
保护 | 永不覆盖 |
(本地)backend/cmd/cpamc/** |
保护 | 永不覆盖 |
(本地)backend/.cliproxyapi-upstream-ref |
保护 | 永不覆盖;仅成功同步后由本仓更新 |
模块路径不改写:本地与社区均为 github.com/router-for-me/CLIProxyAPI/v7。
这些路径不是上游整树的简单镜像:
AGENTS.md../(VitePress 正式文档).devcontainer/(统一 Dockerfile + start.sh 默认 dev + 多 compose 画像)build.sh.github/workflows/frontend/.frontend-upstream-ref / backend/.cliproxyapi-upstream-ref(成功同步后更新)backend/CLIPROXYAPI_UPSTREAM_CN.md(非平凡后端同步叙事)原则:镜像上游实现树与工程文件到对应挂载点;不让上游 README/AGENTS/Docker/CI/docs 抢 monorepo 根。
路径:
frontend/.frontend-upstream-refbackend/.cliproxyapi-upstream-ref角色:只表达“当前已成功对齐的上游基线”,供下一次合并计算 old..new。
不存全部历史、也不存最近 N 次;历史看该文件的 git log,叙事看同步文档。
推荐字段(key=value,单记录,覆盖写):
canonical_repository=https://github.com/router-for-me/<repo>
source_repository=git@github.com:<mirror-or-fork>.git # 可选
branch=main
commit=<full-sha>
tag=<vX.Y.Z> # 有则写
synced_at=<YYYY-MM-DD> # 可选
字段约定:
| 字段 | 必填 | 含义 |
|---|---|---|
commit |
是 | 唯一权威冻结点;下次 diff 的 old |
tag |
有则写 | 发布版本友好名;与 commit 对应 |
branch |
是(默认 main) | 跟踪策略/发布线,不是冻结点 |
canonical_repository |
是 | 社区权威远程 |
source_repository |
否 | 本地 mirror/fork,仅便携 |
synced_at |
否 | 本次成功写入 pin 的日期 |
版本选择与记录:
commit 必写,tag 有则写。branch=main 表示默认在 main 发布线上找 tag/commit,禁止只写 branch 当基线。commit(+ branch),并在同步叙述中说明原因。与仓库内现有 pin 文件的过渡:
tag=;若文件仍写 ref=vX.Y.Z,读作 tag,下次成功同步覆盖写时改为 tag=。commit= / 首行 SHA、tag= / ref= / 次行 v*。更新时机(硬规则):
commit/tag。策略:镜像覆盖 + external 入口保护 + 商业入口排除
frontend/.frontend-upstream-ref(成功后才更新)frontend/src/**(排除 frontend/src/external/)frontend/ 工程根文件按社区更新,但不要覆盖合成控制面,也不覆盖 pin 本身external/ 和 manifest 中的入口/商业排除文件策略:候选树镜像覆盖 + 极小 manifest
backend/.cliproxyapi-upstream-ref(成功后才更新)backend/CLIPROXYAPI_UPSTREAM_CN.md(非平凡同步 prepend 一节)bin/compare-cliproxyapi.shbackend/internal/core/、backend/cmd/cpamc/、pin 文件门禁(同步后必须全绿,CI 亦执行):
bin/check-upstream-drift.sh --verbose # 镜像 == 上游@pin + upstream-allowlist.conf,零容忍
bin/check-import-boundary.sh # 二开手写代码对上游 internal 的依赖只能减少
bin/gen-cli-mirror.sh --check # run.gen.go 与上游 cmd/server/main.go 一致
cd backend && go test ./internal/core/upstreamcontract/ # 上游路由表与配置键契约
契约测试覆盖编译器抓不到的部分:core 发往 CPA 的 12 条管理端点(含 method)和
localengine 改写的 5 个 config.yaml 键路径。上游改名或移除端点时,这里失败并直接
点出调用方文件与同前缀的可用路由。
两类脚本与 compare-cliproxyapi.sh 的分工:后者面向人、预期有差异、用于阅读;门禁面向 CI、预期零意外、用于卡门。已批准差异分别声明在 bin/upstream-allowlist.conf 与 bin/import-boundary-allowlist.conf。
后端已不再依赖「跳过覆盖」保留本地改动,bin/sync-manifest.conf 的 [backend] 段为空,后端同步无需 --confirm-manifest:
backend/patches/*.patch,同步时 git apply --check 先验后应用,冲突即整体失败cmd/server/main.go 的镜像由 bin/gen-cli-mirror.sh 生成为 internal/core/cli/run.gen.go,禁止手改internal/core/httpapi/plugin_store_patch_test.go 兜底,补丁静默丢失会被测试点名后端架构层面的优化路线(双 module 拆分、契约测试、纯依赖模式)见后端二次开发架构优化方案。
准备上游树时按以下优先级,不要无条件每次全量 clone:
FRONTEND_UPSTREAM_SOURCECLIPROXYAPI_SOURCE(与 bin/compare-cliproxyapi.sh 一致)/home/gwd/projects/github/Cli-Proxy-API-Management-Center/home/gwd/projects/github/CLIProxyAPIgit fetch origin --tags(或等价),只读解析 tag/commit,不在上游仓做合成仓的合并提交。/tmp(或 mktemp -d)做只读临时准备(次选)
git fetch + checkout 目标 tag,或 git archive 出树/tmp 里对合成仓执行 git merge 式整树合并main HEAD 或“最新 tag”自动整仓覆盖口令:
有准备好的上游 clone → 直接用(快)
没有 → /tmp 只读准备目标 tag 的树
无论哪种 → 以 pin.commit 为 old,以选定 tag 解析的 commit 为 new
严格顺序(pin 在验证成功之后才改):
commit(必有)、tag(若有)、branch(默认 main)/tmp 只读准备fetch --tags,确认候选 tag 落在跟踪线(默认 main)历史中git rev-parse <tag>^{commit}old..newbin/compare-cliproxyapi.sh --source <upstream> --ref <tag-or-commit>bin/compare-frontend.sh)bin/sync-community.sh(交互模式或非交互模式)bin/sync-manifest.conf 中列出的文件bin/sync-community.sh --dry-run --side backend --source <upstream> --ref <tag>bin/sync-community.sh --side backend --source <upstream> --ref <tag> --confirm-manifest--force;脚本在候选验证通过后才替换挂载点并更新 pinbin/sync-manifest.conf)internal/pluginstore/auth.go:社区未导出的运行期 URL 校验需要允许 GitHub CDN 短期签名参数git -C <upstream> show <commit>:<path> > /tmp/upstream.go; diff -u /tmp/upstream.go <local>/v0/cpamc/* 二开路由和 external 入口cd frontend && bun install --frozen-lockfile && bun run build
cd backend && GOMAXPROCS=1 go test -p 1 ./...
cd backend && go build ./cmd/cpamc/ ./cmd/server/
./build.sh docs # 若文档/路径受影响
按改动面可收缩测试范围,但不能用“先改 pin”代替验证。
*-upstream-ref:新 commit、新 tag(若有)、branch=main、可选 synced_atbackend/CLIPROXYAPI_UPSTREAM_CN.md prepend 一节chore(sync): bump *-upstream-refchore(sync): frontend <tag>chore(sync): backend <tag>fix(compat): reapply local divergencesfeat(core|external): ...每次后端同步后必须勾核:
| 差异项 | 路径 | 原因 |
|---|---|---|
| 签名下载 URL 兼容 | backend/internal/pluginstore/auth.go |
仅允许 artifact 类型的 GitHub CDN 临时签名查询参数;registry/metadata 与非 GitHub URL 仍严格校验 |
| Plugin Store 独立代理 | backend/internal/core/httpapi/plugin_{proxy,store}.go |
SQLite 存储、新路径,与社区 config/handler 解耦 |
| SQLite 运营库依赖 | backend/go.mod |
core 需要 modernc.org/sqlite |
| 统一运行入口 | backend/cmd/cpamc/、backend/internal/core/localengine/ |
管理面 + 内置引擎 |
| 前端扩展子系统 | frontend/src/external/ |
全部 CPA 二开 UI/业务 |
手动合并清单(机读):bin/sync-manifest.conf,由 bin/sync-community.sh 自动消费。
go.mod:社区基线 + 本地必要依赖,再 tidyexternal / core / cpamcdoc.local/、凭证、sqlite、.qwen/、.codegraph/ 混进同步提交迁移已完成。历史 runbook、阶段拆分、验证矩阵与回滚预案见 Monorepo 目录迁移实施计划。
AGENTS.md 已定案目标结构.../backend(建议是)git mv 前端工程文件与 src/、tests/ 到 frontend/git mv services/ 到 backend/build.sh、Vite/TS 路径、devcontainer、CIchore(repo): split monorepo into frontend/ and backend/同步前端社区
输入:community frontend root
输出:./frontend
保护:./frontend/src/external , ./frontend/.frontend-upstream-ref
同步后端社区
输入:community backend root
输出:./backend
保护:./backend/internal/core , ./backend/cmd/cpamc
bin/sync-frontend.shbin/sync-backend.shbin/verify-monorepo.shindex.html 仍指向 src/external/main.tsxfrontend/ + backend/)build.sh 能从根调前端与后端frontend/ + backend/ 口径| 文档 | 用途 |
|---|---|
AGENTS.md |
权限级别与权威布局总则 |
backend/CLIPROXYAPI_UPSTREAM_CN.md |
后端上游基线与非平凡同步叙事 |
| 双引擎架构 | cpamc 管理面与内置引擎 |
| 迁移/融合方案 | 早期加法式迁移背景 |