# opencode-provider-manager **Repository Path**: opencode-plugin/opencode-provider-manager ## Basic Information - **Project Name**: opencode-provider-manager - **Description**: No description available - **Primary Language**: TypeScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-02 - **Last Updated**: 2026-10-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # opencode-provider-manager OpenCode 提供商插件管理工具——本地运行的 Web 面板,管理 30 个提供商插件 (21 个 key 类 + 9 个 auth 类)的配置三件套(`provider.jsonc` / `models.jsonc` / `auth.json`),提供模型测试与同步、智能体配置分组化能力,不必再手改 JSONC。 - **与 opencode-flow-engine 零耦合**:`opencode-flow-engine.json` 只是本工具读写的普通配置文件之一,不存在运行时依赖。 - **两类插件**:key 类(apikey 直连、多 key 轮询)与 auth 类(OAuth 鉴权、多账号轮询)。 - **收录契约**:扫描层仅收录 `provider.jsonc` + `models.jsonc` 两件套齐全可解析的插件目录(收录即健康);auth.json 缺失视为未授权正常态。 - **工具自有存储**:`%USERPROFILE%\.provider-manager\`(分组、探测沉淀、路径注册等),与插件三件套物理隔离。 ## 功能列表 ### 提供商列表(入口枢纽,卡片化) - 扫描收录两件套齐全的插件,卡片网格展示:健康圆点、mono 名称、类型/授权徽标、key/模型数字组 - 模糊搜索:按显示名与内部键双通道实时过滤,空结果有引导空态 - 统计卡可点击筛选(插件总数 / key 类 / auth 类),与搜索叠加生效 - 卡片操作(弹框直开,零页面切换): - **查看 keys** → KeysDialog - **模型列表** → ModelsDialog - **授权信息**(仅 auth 类)→ AuthInfoDialog - doctor 明细折叠(三级校验汇总并入本页) ### 模型管理弹框(ModelsDialog) - `models.jsonc` 表格化编辑:行内编辑(点击单元格变输入框,Enter/失焦提交、Esc 取消)、key 行内改名、id 写入后锁定 - 新增模型:表单弹窗(key/id/name/context/output/desc + reasoning/vision 复选) - 从上游拉取:探测 → 测试所选 → 应用所选;候选来自上游 `/v1/models` 与本地 `models.jsonc` 并集,**上游不可用自动降级为本地候选**;支持模糊搜索、多选勾选、全选半选、行内单测;路径未配置时引导注册(RegisterPathsDialog) - 删除行走危险确认弹窗,未保存改动单元格高亮标记 ### key 管理(KeysDialog + KeyManagerPanel) - 新增 / 删除(危险确认)/ 复制明文(clipboard API 降级 prompt)/ 显示-隐藏切换 - key 列表 mono 脱敏(前 6 后 4);未授权插件渲染空态,新增行恒显示(添加首个 key 即授权) - 批量灌入:一个 key 可多选 N 个插件一次性写入(`POST /api/providers/batch-keys`) - **key 健康状态**(blacklist 展示):`blacklist.jsonc` 快照存在时,key 列表区顶部展示每个 key 的错误计数徽标(0=正常 / 1-2=警告 / ≥3=「已跳过」)与快照更新时间。**需插件侧落盘 `blacklist.jsonc` 快照(jsonc 格式:允许注释与尾随逗号;旧 `blacklist.json` 不兼容、不再读取),文件不存在时界面不显示**;本工具对快照只读,不写该文件 ### 授权信息弹框(AuthInfoDialog,auth 类) - 账号标识、accessToken 脱敏展示(服务端输出前统一脱敏,无明文入口)、过期时间 / 剩余天数徽标 - 三态渲染:加载骨架 → 降级空态(文件损坏不回显服务端原文)→ 无账号空态 → 账号列表 - **删除账号**:账号行内删除钮(危险确认,展示账号 username)→ `DELETE /api/providers/:name/auth/accounts/:userId`;成功后刷新列表并提示重启;auth.json 缺失/解析失败 400、账号不存在 404;账号删空后 auth.json 保留空对象 ### 智能体配置(/agents) `opencode-flow-engine.json` 的分组化界面管理: - 分组 CRUD(左栏分组列表 + 右栏快照编辑,主从双栏);**默认分组保护**:不可删除、名称不可改(服务端 400 权威裁决,前端前置拦截) - `agents` / `modelProfiles` 结构化编辑 + 高级 JSON 模式;新增条目候选来自 `/api/agent-config/candidates`,端点不可用降级回退已有键名 + 手动输入 - **OpenCode Agents 卡片**:管理 `opencode.json`(`~/.config/opencode/`)的原生 `agent` 节——内置 7 agent(plan/build/general/explore/title/summary/compaction)默认行全部列出(未配置行不写入,由 OpenCode 使用内置默认),支持自定义 agent(名限 `[a-zA-Z0-9_-]+`);字段含 mode/model/temperature/top_p/steps/disable/hidden/prompt/description/color/variant(值域校验 fail fast:mode 枚举、temperature 0-2、top_p 0-1、steps 正整数、color `#RRGGBB` 或语义名);JSON 高级模式下 `opencodeAgents` 节同步可编辑 - 模型选择器(ModelPickerDialog):写入格式 `providerId/modelKey`,providerId 为 `provider.jsonc` 真实 id(用派生名写入不生效) - **应用分组(双文件写入)**:分组配置快照写入 `opencode-flow-engine.json` + `opencodeAgents` 深合并写入 `opencode.json` 的 `agent` 节(分组有该 agent → 整体替换其配置对象;分组没有的 agent 保留现状;permission/mcp/plugin 等其他节与注释原样保留;无有效变化跳过写)。危险确认(提示变更两个文件,建议先「保存当前配置为分组」备份),双文件写前 .bak + 原子写,重启 opencode cli 生效;分组集存工具自有存储(`groups.jsonc`),增删改不提示重启 - `opencode.json` 路径复用自动发现(优先 `opencode.json`,其次 `opencode.jsonc`);文件语法损坏时应用拒绝(fail fast,双文件一字不动) ### 备份恢复(/backup) - 按插件分组列出可恢复项;有 `.bak` 的项可恢复(危险确认后覆盖还原),无 `.bak` 灰置不可点 - 恢复成功后提示重启 ### doctor 校验(并入提供商列表) - 三件套齐全性、jsonc 可解析、key 池非空等三级校验;汇总卡 + 卡片内明细折叠 ### 路径注册(RegisterPathsDialog) - **自动发现**:读 `opencode.json(.jsonc)` plugin 列表,即时探测候选插件路径(不持久化) - **手动注册**:逐项校验(目录存在且含 `src/`),非法项拒绝落盘;路径统一用 `/` 处理,规避 Windows `\.` 转义问题 ## 架构概览 ``` server/ 本地后端(Bun 运行,无第三方 Web 框架) index.ts 进程入口:listen → open(url) → 常驻;静态资源 + REST API api/ 路由层:只做参数校验与 HTTP 语义(routes.ts 主分发 + probe/project-paths/agent-config 子路由) domain/ 领域层:scan/aggregate/models/apikey/doctor/backup/agent-config/probe/project-paths/discover file-io/ 基础层:原子写(atomic)、jsonc 解析(保注释)、路径归一、schema web/ 前端(Vue 3 + Vite + Vue Router,History 模式) src/views/ 仅 3 个页面:Panorama(提供商列表)/ AgentConfig / Backup src/components/ 弹框与基础组件(KeysDialog / ModelsDialog / AuthInfoDialog / ModelPickerDialog / RegisterPathsDialog 等) src/api.ts 统一请求封装 src/store/ 全局状态(重启提示条) ``` 两类职责严格分开:`server/` 直接读写用户家目录里的真实文件,`web/` 只通过 REST 与它对话。 **布局形态(v8 弹框化整合)**:提供商列表为入口枢纽,apikey 管理 / 模型编辑 / auth 只读 / 模型测试等操作全部以弹框承载,导航收敛为三项(提供商列表 / 智能体配置 / 备份恢复);`/apikey`、`/models`、`/auth`、`/probe` 旧路径统一回落提供商列表,对应后端端点全部保留。 **硬约束**(写代码时别破坏): 1. **原子写**:任何落盘都先写临时文件再 rename(temp+rename),绝不 half-write 出一个坏文件;auth.json 写前按 schema 校验。 2. **fail fast**:文件不存在、插件未注册、字段类型不对,直接报错,不做静默兜底(文件缺失时插件亦 fail fast,因此靠 doctor 校验 + 编辑防损坏保障)。 3. **jsonc 保注释**:用 `jsonc-parser`(`allowTrailingComma: true`)做编辑式更新,用户手写的注释与尾随逗号必须原样保留。 4. **每次写生成 .bak**:覆盖三件套前先留一份 `.bak`,恢复是安全的二次撤销手段(工具自有存储不生成 .bak、不提示重启)。 5. **两件套收录**:扫描层仅收录 `provider.jsonc` + `models.jsonc` 齐全可解析的目录;auth.json 缺失 = 未授权(正常态),仅解析失败才降级。 6. **写操作重启提示**:所有写三件套/活配置的操作返回 `restartRequired: true`,前端弹出常驻重启条——「刷新页面不够,要重启 opencode cli」。 7. **不代理模型请求**:不重写任何插件的模型请求逻辑(模型测试的探测请求除外,仅 `max_tokens: 1` 最小请求 + `/v1/models` 列表探测)。 8. **Windows 路径统一 `/`**:规避 `\.{插件名}` 前缀的 `\.` 转义问题。 ## 快速开始 需要本机已安装 [Bun](https://bun.sh) 与 `opencode` cli(面板用于提示重启,不做自动安装)。 ```bash bun install bun run dev # 开发模式:Vite HMR(仅前端,调 API 需另开 dev:server) bun run dev:server # 开发模式后端(server/index.ts) bun run start # 生产模式:跑 server,默认端口 5174,PORT 环境变量可覆盖(如 PORT=5199) # 启动后自动打开浏览器,常驻运行 bun run build # 构建前端到 server/public bun run test # 前端单元测试(vitest) ``` ## 页面与端点 页面(3 项导航): | 路由 | 页面 | 说明 | |------|------|------| | `/panorama` | 提供商列表 | 卡片化入口枢纽:搜索/筛选/统计/弹框操作/doctor 明细 | | `/agents` | 智能体配置 | 分组化的 opencode-flow-engine.json 管理 | | `/backup` | 备份恢复 | 列出可恢复文件,从 .bak 覆盖还原 | | `/apikey` `/models` `/auth` `/probe` | (旧路径) | v8 弹框化整合后统一回落 `/panorama` | 后端端点(均为 `/api` 前缀): - **providers** - `GET /api/providers` — 全景聚合(id/name/type/key 数/模型数/授权状态) - `GET|PUT /api/providers/:name/models` — 模型读取 / 编辑(PUT 按 action:addModel / updateField / removeModel) - `GET|PUT /api/providers/:name/auth` — key 类 keys 读写 / auth 类账号只读(PUT 对 auth 类返回 403;输出统一脱敏) - `DELETE /api/providers/:name/auth/accounts/:userId` — auth 类删除账号(restartRequired;auth.json 缺失/损坏 400,账号不存在 404) - `GET /api/providers/:name/blacklist` — key 健康快照只读展示(插件侧 `blacklist.jsonc`,jsonc 格式;文件缺失/解析失败返回 `available:false`,key 值脱敏) - `POST /api/providers/batch-keys` — key 批量灌入 - **probe**(v1.5 探针) - `GET /api/probe/:name/candidates` — 候选列表(上游 + 本地并集) - `POST /api/probe/:name/test` — 单模型探测(互斥,进行中返回 409) - `POST /api/probe/:name/test-all` — 全部测试(限速 + 互斥,完成沉淀) - `POST /api/probe/:name/sync` — 勾选模型同步回写 models.jsonc(restartRequired) - **agent-config**(v2 智能体配置) - `GET /api/agent-config/groups` / `groups/:id` — 分组列表 / 详情(响应携带各分组 opencodeAgents) - `GET /api/agent-config/current` — 宽松读当前 flow-engine 配置 - `GET /api/agent-config/candidates` — agents / modelProfiles 候选名单(只读) - `POST /api/agent-config/create` / `rename` / `update` / `delete` — 分组 CRUD(默认分组 delete 400 拒绝;create/update 接受可选 opencodeAgents,非法 400) - `POST /api/agent-config/apply` — 应用分组(双文件写入:opencode-flow-engine.json + opencode.json agent 节深合并,restartRequired,响应含 files) - `POST /api/agent-config/save-current` — 保存当前配置为分组 - **project-paths**(v3 路径注册) - `GET /api/project-paths` — 合并视图(user + builtin) - `PUT /api/project-paths` — 全量覆盖写(逐项校验,非法项 400 不落盘) - `POST /api/project-paths/validate` — 即时验证(不持久化) - `GET /api/project-paths/discover` — 自动发现候选(读 opencode.json plugin 列表) - **doctor** - `GET /api/doctor` — 校验汇总 - **backup** - `GET /api/backup/list` — 列出各插件可恢复的 .bak 项 - `POST /api/backup/restore` — 恢复(restartRequired) 路由键说明:`/api/providers/:name/*` 与 `/api/probe/:name/*` 按目录派生名(storageKey)解析插件,传显示名会 404(响应附可用键清单)。 ## 目录结构 ``` server/ index.ts 进程入口:静态托管 + REST API + SPA 回退 + 路径穿越拦截 api/ routes.ts 主路由分发(providers/models/auth/batch-keys/doctor/backup) probe-routes.ts 探针端点(candidates/test/test-all/sync) project-paths-routes.ts 路径注册端点(list/validate/discover) agent-config-routes.ts 智能体配置端点(groups CRUD/apply/candidates 等) __tests__/ domain/ scan.ts 插件目录扫描(两件套收录契约) aggregate.ts 全景聚合 models.ts models.jsonc 编辑(保注释 + .bak + 原子写) apikey.ts auth.json keys 读写 + 批量灌入 blacklist.ts blacklist.jsonc 快照只读读取(key 健康状态) auth-accounts.ts auth 类插件账号删除(原子写回) doctor.ts doctor 三级校验 backup.ts .bak 列表与恢复 agent-config.ts 分组存储 + flow-engine 配置应用 + opencode.json agent 节双文件写入 opencode-agents.ts OpenCode 原生 agent 节校验/深合并/opencode.json 原子写 probe/ 探针子域(candidates/probeService/rateLimiter/baseUrlExtractor 等) project-paths.ts 路径注册存储与校验 discover.ts opencode.json plugin 自动发现 __tests__/ file-io/ atomic.ts 原子写(temp + rename) jsonc.ts jsonc-parser 编辑式读写(保注释/尾随逗号) paths.ts 路径归一(统一 /) schema.ts 写前 schema 校验 __tests__/ public/ 前端构建产物(bun run build 输出) web/ src/ views/ 3 个页面:Panorama / AgentConfig / Backup (AgentConfig 含 agents / modelProfiles / OpenCode Agents 卡片, 共享常量与校验纯函数在 views/agent-config-oc.ts) components/ 弹框与基础组件: KeysDialog / KeyManagerPanel / ModelsDialog / AuthInfoDialog / ModelPickerDialog / RegisterPathsDialog / ConfirmDialog / ProviderCard / RestartBanner / AppButton / AppInput / AppIcon / Badge / CollapsiblePanel / EmptyState / PageHeader / PageLoading / PageWrap / Skeleton / Spinner router/ Vue Router(History 模式,旧路径回落) store/ 全局状态(重启提示条) composables/ 组合式函数 api.ts 统一请求封装 styles/ 设计 token 与全局样式 utils.ts __tests__/ docs/ 插件管理支持总结.md 设计共识(插件分类 / 模板契约 / 方案 / 硬约束) ``` ## 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码(`bun run test` 需全绿) 4. 新建 Pull Request