🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

免费模型同步 rumilhz/dsh-pylon-opencode-free

DeepSeek Harness
rumilhz15 天前有提交已提供中文文档扫描:无法判定

启动时拉取网关免费模型并自动更新配置清单

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/17 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add rumilhz/dsh-pylon-opencode-free
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:待复验
是什么
dsh 原生插件 · model
装得上吗
曾在 dsh 0.2.0-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.1-rc.5,本站尚未在新版下复验
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 15 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
⚪ 扫描:无法判定尚无人工评估
展开查看扫描说明与证据 ↓

已尝试扫描但取不到可分析的源码:仓库或包不存在、已删除,或为非 JS/TS 实现、未随包发布源码。无法判定,不代表安全。

  • · 取源不可用(Error: github tarball HTTP 404 @ https:
  • · api.github.com
  • · repos
  • · rumilhz
  • · dsh-pylon-opencode-free
  • · tarball)
扫描于 2026/11/1(0 天前)

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

让 OpenCode Go 免费档服务商与网关保持同步:读取 /v1/models,筛出官方文档标为 Free 的模型,把列表写进 DSH 配置档,新增模型、移除下架模型。

README

由 DeepSeek 最新模型翻译生成
dsh-pylon-opencode-free 自动生成并维护 OpenCode Go 的免费档 provider(opencode-go-free):启动时问一次网关,把免费模型清单如实写进 profile —— 新增的补上,下架的删掉。 为什么需要它:DSH 没有「运行时拉取模型」这回事 一个 provider 的模型清单只有两个来源(dsh-llm-pi-ai/lib/index.js:642): const configured = request.models ?? [] const entries = configured.length > 0 ? configured : [...catalogDefaults] if (entries.length === 0) invalid(provider, "resolves no models; the installed catalog does not describe this route, so its models must be listed in configuration") 1. 内置 catalog —— 按 provider 名字索引(@earendil-works/pi-ai/dist/providers/data/<name>.json);或 2. 配置里的 models: 列表。
展开完整文档(README 剩余 1 节)
dsh-pylon-opencode-free

自动生成并维护 OpenCode Go 的免费档 provider(opencode-go-free):启动时问一次网关,把免费模型清单如实写进 profile —— 新增的补上,下架的删掉。

为什么需要它:DSH 没有「运行时拉取模型」这回事

一个 provider 的模型清单只有两个来源(dsh-llm-pi-ai/lib/index.js:642):

const configured = request.models ?? []
const entries = configured.length > 0 ? configured : [...catalogDefaults]
if (entries.length === 0) invalid(provider,
"resolves no models; the installed catalog does not describe this route,
so its models must be listed in configuration")

1. 内置 catalog —— 按 provider 名字索引(@earendil-works/pi-ai/dist/providers/data/<name>.json);或
2. 配置里的 models: 列表。

没有第三条路。网关的 /v1/models 只是我们自己拿来看的,DSH 运行时不会去拉。

这解释了两件事:

| 官方 opencode-go 为什么「填个 key 就能用」 | 它的名字在内置 catalog 里(data/opencode-go.json) |
| opencode-go-free 为什么必须手写清单 | 这个名字不在 catalog 里 ⇒ 只能写进配置 |

而网关会变,所以那份清单需要有人维护。这个插件就是那个人。

工作方式

启动时(syncOnStart: true):

1. GET <baseURL>/models(带 OPENCODE_GO_API_KEY,只读接口);
2. 按免费判据筛出免费模型;
3. 与 profile 里现有的清单比对;
4. 有变化才写:新增的补上,下架的删掉;
5. 写完读回核对,不对就整份盖回。

不碰路由。 路由指向哪个模型是路由自己的事。provider 的职责是如实反映网关 ——一个已下架的模型留在 provider 里等于假装它还能用,代价是派发在更晚、更贵的地方失败。

免费判据:白名单,不是名字

/v1/models 不发布免费标志(只返回 id、零元数据),所以判据只能自己维护。
这个判据在本插件里换过三次,每一次都被真实账单推翻:

| 判据 | 怎么被推翻的 |
| KNOWN_FREE = ['space-bunny'](「实测例外」) | 实测是真的,但保质期 8 天。网关 10-07 前后开始对它计费,它留在免费 provider 里,10-15 一天 $0.59、累计 $1.64 |
| 「命名带 -free 就算免费」 | 官方定价表打脸:Step 5 Preview 定价 $1.00 / $2.70,而它的 API id 正是 step-5-preview-free |
| 现在:只认官方文档标 Free 的 | — |

名单是每次同步现场去文档取的,不是抄死的

插件启动时会去 <https://opencode.ai/v2/docs/console/go> 现场读一遍:取模型清单里名字含独立 Free 词的,归一成 id 形状,再和网关的实时 /v1/models 对号——两边都对得上才算数。取不到就退回静态白名单(src/free-provider.ts 的 VERIFIED_FREE),不会因为网络问题就不同步。

为什么必须现场取:名单变得比想象中快。2026-10-16 实测,一小时之内 Cat Jam Free 从名单消失、Beam Free 出现,网关清单同步跟着变。
静态白名单只能保证「不误收计费的」,保证不了「不漏收新免费的」。

两条日志要留意:

* 文档里有免费显示名、但网关清单里找不到对应 id 的 → 不猜,点名报出来(显示名与 API id 不保证一一对应)
* 网关上名字含 free、但文档没有列为免费的 → 点名警告(step-5-preview-free 就是这一类,官方定价 $1.00 / $2.70)

故意往「漏」的方向错

白名单会过期,而过期的后果有两种,代价严重不对称:

* 免费模型没被收进来 → 少用一个免费模型(看得见,代价为零)
* 计费模型被收进来 → 安静地花钱(这次就是这样)

所以策略是「不确定就不收」,并且大声报出被排除的那些:名字像 -free、却不在白名单里的模型(step-5-preview-free 那一类)会在日志里点名。

想加模型:先去上面那个表确认它写着 Free,再用配置里的 freeAllowlist 加进来。
不要凭「它看起来免费」往里加。

另一条独立证据:网关请求日志

免费与否过硬的证据是:这个模型成功调用过、且 cost 恰好为 0。
网关导出的请求日志每条都带 cost,那就是账本本身。本插件带了一个工具读它:

node --experimental-strip-types tools/classify-from-log.ts <导出的日志.json>

它会按 计费 / 免费(观测) / 样本不足 / 未知 分类。注意两个刻意的取舍: 成功调用收过钱就是铁证(哪怕大部分调用是 0);而成功次数少于 3 次不下结论 (step-5-preview-free 就是只有 1 次成功、cost 为 0 —— 一次零花费什么都证明不了)。

⚠️ 「观测免费」仍然只是观测:space-bunny 就经历过「观测免费 → 后来开始计费」。
它用来交叉验证文档,不能当长期判据。

安全性

写路径:原子写 + 四条铁律(src/patch-guard.ts)

1. 写前备份,落在 profile 之外,并读回校验 —— 备份进同一个 profile 会跟正本一起被同一次故障毁掉;不读回校验的备份等于没有备份;
2. 写入是原子的:临时文件 → fsync → rename。writeFileSync 是「先 O_TRUNC 再写」, ENOSPC / EIO / 文件被锁时它会抛,而那时文件已经被截断了;
3. 写后读回,必须逐字节等于刚写出的那一份 —— next 本来就在手里,这个断言零成本,且一次盖住「内容被换掉但条目数不变」这类所有形状;
4. 任何一步失败都先回滚,并且回滚结果由读回比对算出,不是「调用过了」。

这不是假想的风险:2026-10-08 一次写配置返回成功,而 cordis.patch.yml 从 34 条目 / 63,570 B 变成 3 条目 / 661 B,没有任何环节发现。

这套安全网是被一次对抗性审查打穿后重写的

第一版只做了「备份 → 写 → 比条目数 → 少了就盖回」。审查用故障注入证明它有四个洞,每一条现在都有对应的回归断言:

| 洞 | 第一版的行为 | 现在 |
| 写入抛错(文件已被截断) | 异常穿出去,回滚调用数 = 0,日志说「不影响宿主启动」 | 整段包在 try 语义里,失败必回滚;原子写让「失败」根本不碰正本 |
| 回滚自己失败 | recovered 是字面量 true,无条件打印「已整份盖回」 | 由读回比对算出;没恢复成功就明说「配置可能停在损坏态」 |
| 校验不与刚写出的内容比对 | 只查「条目数变少 / 邻居模型数 / 非空」 ⇒ 内容被换掉但计数不变轻松过关 | 第一位判据是 after === next |
| bytes 采了不用 | 63,570 → 661 这条最刺眼的信号被浪费 | 纳入判定(低于写前 50% 即报警) |

另外补上:网关 id 的形状校验(审查实测出 YAML 注入:id 带换行能把顶层条目从 2 变 4 而守卫放行)、空 models: 块的缩进兜底(原来 repeat(-1) 抛 RangeError、每次启动都抛且没有拒绝出口)、以及「models 块里有不认识的行就拒绝重写」(原来注释会被静默丢弃,而顶层条目数与模型数全不变,守卫一个字都看不见)。

两个「不写」的情形

* 拉取失败(超时 / 5xx)→ 不写。一次没有答案的提问不构成「全部下架」的证据。
* 选出 0 个免费模型 → 不写。这条不是保守策略,是硬约束:DSH 对模型数为 0 的 provider 直接判非法(上面那段代码)。写进去不是「少了几个模型」,是整份配置加载失败。

不在 settings 路径上新增消费点

本插件直接写 profile patch 文件,不经过 settings.mutate。DSH 的 HMR 用 chokidar 精确盯着 profile patch(dsh-hmr/lib/index.js:"Exact-path watching for live profile patch files outside Cordis module roots"),所以写完即热加载。

并且 Config 里没有 volatile 字段 ⇒ dsh-settings 不会给这个条目建表单。
2026-10-08 正是「给 Config schema 加了 volatile 字段」让 DSH 冷启动直接起不来。

配置

- id: dsh-pylon-opencode-free
name: 'dsh-pylon-opencode-free'
config:
enabled: true
providerId: opencode-go-free
siblingId: opencode-go
api: openai-completions
baseURL: https://opencode.ai/zen/go/v1
sessionHeaderName: x-opencode-session
sessionHeaderValue: dsh-in-process-subagent
syncOnStart: true
每次同步去官方文档现场取免费名单(推荐开)。取不到自动退回下面的白名单。
freeListFromDocs: true
docsUrl: https://opencode.ai/v2/docs/console/go
兜底白名单。只在 freeListFromDocs 关掉、或文档取不到时生效。
freeAllowlist:
- longcat-2.5-preview-free
- beam-free

apiKeyEnv 与缩进从 siblingId 指的兄弟 provider 抄,不写死 ——写死缩进是这类生成器最典型的退化方式(手下一次调整文件结构就会拼错位置,而且 YAML 照样能解析,没人会发现)。

附带工具

| 工具 | 作用 |
| tools/free-list-from-docs.ts | 读官方文档解析出当前免费名单,再和网关实时清单对号。名单会变(实测一小时内 Cat Jam Free 消失、Beam Free 出现),所以要定期重跑。 |
| tools/classify-from-log.ts | 读网关请求日志判定谁真的收过钱:成功调用 cost > 0 就是铁证;成功不足 3 次不下结论。 |
| tools/dryrun-check.ts | 只读试算:下一次同步会新增/删掉什么,一个字节都不写。 |

测试

node tools\_run-suites.mjs → 3/3 suites exited 0

| 套件 | 覆盖 |
| tools/free-provider.test.ts | 解析 / 比对 / 渲染;幂等;对真 profile 的只读往返 |
| tools/sync.test.ts | 同步路径 + 安全网,内存 IO 做故障注入(含「写入把文件截断」) |
| tools/e2e-temp-profile.ts | 真 patch-guard + 真文件系统 + 临时 profile:备份位置、no-op、回滚 |

三条都只碰 <tmp>/…,绝不碰操作者的真 ~/.dsh。

验证过的行为

* 原子 rename 仍会触发热加载(审查要求实测、不能假定)。依据是监听器自己的代码: dsh-hmr/lib/index.js 把 add / change / unlink 三个事件绑到同一个 handler,且配置监听默认开 awaitWriteFinish: true。所以 rename 无论被 chokidar 报成哪一种,都会触发一次刷新。
* 真 DSH 冷启动已验证:插件被加载、apply 跑通、只收免费档(从网关 37 个 id 筛出 4 个)、备份落在 profile 之外、二次运行逐字节 no-op 且不新增备份。

已知限制

* provider 块字段漂移只报不修:api / baseURL / headers.x-opencode-session 被改坏时,本插件只写 models 块,不会重写整块 —— 它会打一条明确的警告,但不修复。
* 模型条目里的元数据刻意不动:contextWindow / maxTokens 是逐字保留的,本插件不认识、也不该改操作员填好的值。所以日志说的是"模型清单已与网关一致",不是"整份配置与网关一致"。
* 跨进程没有锁:同进程内(含热重载导致的重复 apply())不会交错、是安全的;但两个宿主共享一个 DSH home 时,read-modify-write 之间没有 mtime/hash 检查。
* 备份轮转窗口是全目录共享的:多个 profile 共用一个 backupDir 时,一个 profile 的健康备份可能被另一个挤掉(备份名已含毫秒 + pid,但仍是按 patch 文件名分组)。
* 免费判据靠命名(见上),会漏不带 -free 的免费模型。
* 新增模型只写 id + name 骨架 —— contextWindow / maxTokens / input 没有现成来源(实测那 4 个免费模型一个都不在内置 catalog 里),需要时人工补。
填错比不填更危险:填大了会被派发超出真实上限的请求。
* 本插件只维护 provider 条目,不修路由、不碰额度闸门。
预览分享卡片长什么样 ↓rumilhz/dsh-pylon-opencode-free
分享 · DeepSeek Harness Hub
rumilhz/dsh-pylon-opencode-free

启动时拉取网关免费模型并自动更新配置清单

回到顶部