dsh-workbuddy-meter
Identified★ 2Fix WorkBuddy/CodeBuddy 400 'Illegal API invocation from an unapproved channel' (code 11128) —— prompt-preserving bypass + credits usage metering panel | Fix WorkBuddy unapproved channel 400
WorkBuddy 400 错误修复 · unapproved channel (code 11128) · 积分用量计量
两件事,一个仓库:
① 修复一个让人抓狂的 400 错误 —— WorkBuddy / CodeBuddy 返回
Illegal API invocation from an unapproved channel(code11128)。 这个报错的文案是骗人的:它跟渠道、域名、身份、请求头全都无关, 真正原因是上游在按关键词拦 system prompt(命中的是DeepSeek Harness)。 本仓库给出提示词无损绕过方案 —— 插一个零宽空格,语义不变、请求通过。 → 直接看修复方法② 顺带把积分账算清楚 —— 逐请求记录本地 OFM 通道 (
buddy/= CodeBuddy 国内版、workbuddy/= WorkBuddy 国际版)的 token 明细与credit(积分)消耗,在 DSH Web UI 给出实测单价、缓存命中率、 冷热对比、账号余额。
关键词:unapproved channel · Illegal API invocation · code 11128 ·
11140 · WorkBuddy 400 · CodeBuddy 400 · 请求被拦截 · 提示词风控 ·
关键词过滤绕过 · 零宽空格 · DeepSeek Harness
⚠️ 搜索到这里? 如果你正在找下面这个报错的解决方法,直接跳到 🔧 修复 WorkBuddy「请求被拦截 / unapproved channel」400 错误 —— 那是本仓库最常被搜索到的部分。
常见报错速查
搜到这些错误?点进去看原因和修法:
| 你看到的报错 | 真实原因 | 章节 |
|---|---|---|
buddy: 请求被拦截,请重新发送 Illegal API invocation from an unapproved channel | 上游按关键词风控 system prompt | 修复 400 错误 |
workbuddy: 请求被安全策略拦截... first message is not system prompt | 首条消息不是 system 角色 | 同章节 |
code 11128 / code 11140 / HTTP 400 | 上游内容/结构校验失败(同一个错误族) | 同章节 |
code 11133 integer_below_min_value | max_tokens 给太小 | 同章节·附注 |
code 6004 usage exceeds frequency limit | 上游限流 | 切账号或等冷却 |
EMPTY_RESPONSE / 有思考无正文 | 推理模型把 max_tokens 吃光了 | max_tokens ≥ 4096 |
🔧 修复 WorkBuddy「请求被拦截 / unapproved channel」400 错误
这是本仓库存在的主要理由。 如果你因为下面这个报错搜到这里,你要的东西就在这一节。
你会看到的报错
buddy: 请求被拦截,请重新发送 Illegal API invocation from an unapproved channel
或者英文原文:
Illegal API invocation from an unapproved channel
HTTP 状态码 400,上游业务码 11128(有时 11140)。
真实原因(不是你想的那个)
报错文案说 "unapproved channel"(未获批准的渠道),这个措辞是误导的。 实测逐项排除后可以确定:它跟渠道、域名、客户端身份、请求头、账号、API Key 全都无关。
真因是:上游对 system prompt 做关键词内容风控。
只要 system prompt 里出现 DeepSeek Harness 这个词组,就会被拒。
说白了就是「逆天操作」—— 上游在按品牌词拦请求,然后用一个完全不相关的错误信息掩盖它。
怎么验证是这个原因(60 秒)
用同一个 token 打两次,只改 system prompt 里的一个词:
| system prompt 内容 | 结果 |
|---|---|
You are an AI agent powered by DeepSeek Harness. | ❌ 400 / 11128 |
You are an AI agent. | ✅ 200 |
如果符合这个规律,就是这个原因。其他已排除的可能见下表。
修复方法(本仓库的做法,无损绕过)
把散文语境里的 DeepSeek Harness 中间插入一个零宽空格 \u200B:
// 改前
"You are an AI agent powered by DeepSeek Harness."
// 改后(两个词之间多了一个不可见字符 U+200B)
"You are an AI agent powered by DeepSeek\u200B Harness."
- 模型看到的语义完全不变(零宽空格在渲染、分词上几乎无影响)
- 上游的字符串匹配不再命中
- 这是无损的:没有裁剪、没有改写、没有丢上下文
实测对比(真实 DSH 请求形状:316 tools + effort=max + max_tokens=128000):
原文 → ❌ 0/5 全部失败
中和后 → ✅ 5/5 全部成功
关键约束:文件路径不能被改写 ⚠️
运行时上下文里有真实路径:
D:\10_COD\DeepSeek Harness\resources\app.asar\dsh\
如果在路径里也插入零宽字符,模型会把坏路径传给工具调用,直接失败。
所以匹配器必须跳过路径语境(前后不能是 / 或 \):
/(?<![\\/])(DeepSeek)[ \u00A0]+(Harness)(?![\\/])/gi
实测:中和后路径里残留的那一处不会触发拦截(上游匹配的是身份陈述位置,不是全文子串)。
一键用(本仓库已实现)
装好插件后,面板底部有「关键词风控中和」卡片,4 个开关:
| 开关 | 默认 | 作用 |
|---|---|---|
| 总开关 | 开 | 关掉即完全恢复原始请求(一个字节都不改) |
| 中和身份关键词 | 开 | 上面说的零宽空格替换 |
| 补首条 system | 开 | 首条非 system 时注入保底 system |
| 隐藏品牌词 | 关 | 更激进:连 DeepSeek 也打散 |
改完即时生效,不需要重启。 上游以后不拦了,把总开关关掉就行。
不想装插件?手动改也行
最小实现就是一段字符串替换。如果你自己在写反代:
const ZW = '\u200B'
const PATTERN = /(?<![\\/])(DeepSeek)[ \u00A0]+(Harness)(?![\\/])/gi
function neutralize(messages) {
for (const msg of messages) {
const walk = (obj) => {
for (const key of Object.keys(obj)) {
const v = obj[key]
if (typeof v === 'string') obj[key] = v.replace(PATTERN, '$1' + ZW + ' $2')
else if (Array.isArray(v)) v.forEach((x) => typeof x === 'string'
? null : (x && typeof x === 'object' && walk(x)))
else if (v && typeof v === 'object') walk(v)
}
}
walk(msg)
}
}
把它挂在出站请求前(组装好 messages、JSON.stringify 之前)。
已排除的其他可能(省得你重复排查)
这些我都实测排除了,都不是原因:
| 假设 | 实测结果 |
|---|---|
| 账号被风控 / 坏了 | ❌ 换账号同样报;改昵称前后无差异 |
| 域名错(copilot vs workbuddy.cn) | ❌ copilot.tencent.com 是正确端点 |
| 客户端身份错(CodeBuddy vs WorkBuddy) | ❌ 两种身份 × 两种域名交叉测试全 200 |
请求头缺失(X-User-Id 等 13 个头) | ❌ 全部补齐后仍失败 |
reasoning_effort 值非法 | ❌ max 单独测也 200 |
max_tokens=128000 超限 | ❌ 上限是 131072 |
| 工具数量太多(316 个) | ❌ 单独带 316 tools 多次成功 |
| 网络代理改写请求 | ❌ 无代理时同样报 |
| 并发太高 | ❌ 12 并发全成功 |
唯一能稳定复现的条件:system prompt 含 DeepSeek Harness 且 请求体够大(约 >1KB)。
短 prompt 即使含关键词也会放过 —— 这是它表现得「时好时坏」的原因。
附注:其他错误码
11133 integer_below_min_value——max_tokens太小(< 某个下限),不是风控11128 first message is not system prompt—— 首条必须是system角色11140—— 安全策略拦截,同一错误族的另一种
为什么需要它
OFM(dsh-our-free-model)的 channel-pack 已经有一份 token 账本
(~/.dsh/channel-pack/token-ledger.json),但只记 token,不记积分 —— 而积分才是这两个渠道真正在消耗的额度。
上游其实报了积分。实测 WorkBuddy / CodeBuddy 的 SSE 最后一帧:
"usage": {
"prompt_tokens": 4018, "completion_tokens": 8, "total_tokens": 4026,
"prompt_cache_hit_tokens": 0, "prompt_cache_miss_tokens": 4018,
"credit": 0.17
}
OFM 解析 usage 时只取了 token 字段,credit 被丢弃。本插件用一行补丁把它接出来。
三个组件
| 组件 | 位置 | 作用 |
|---|---|---|
| 补丁引擎 | src/patch-engine.mjs | 打/还原/检查 OFM 补丁的唯一实现(脚本与 Host 自愈共用) |
| 词库模块 | src/lexicon.mjs | 关键词风控中和的实际逻辑 + 永不抛错的钩子 |
| 补丁脚本 | scripts/patch-ofm.mjs | 命令行包装:dry-run / --apply / --revert / --check |
| Host 半身 | index.js | 采集回调 → 写 JSONL → 聚合 → 5 个 HTTP 路由;启动时自愈两个补丁 |
| Client 半身 | client.js | 侧边栏「用量」图标 + 独立主面板 |
关键词风控中和(2026-10-21 新增,可运行时开关)
它解决什么
上游腾讯 WorkBuddy/CodeBuddy 网关会对 system prompt 做关键词风控:命中
「DeepSeek Harness」就返回 HTTP 400 / code 11128,报文写着
Illegal API invocation from an unapproved channel —— 这个措辞极具误导性,
实测与渠道、域名、客户端身份、请求头全都无关。
实测证据(真实 DSH 请求形状:316 tools + effort=max + max_tokens=128000):
| system prompt 内容 | 结果 |
|---|---|
含 DeepSeek Harness 原样 | ❌ 0/5 全部失败 |
含 DeepSeek\u200B Harness(零宽空格) | ✅ 5/5 通过 |
改写成 DSH / 去掉身份词 | ✅ 通过 |
小写 deepseek harness | ✅ 通过(大小写敏感) |
只写 DeepSeek 或只写 Harness | ✅ 通过(需完整词对) |
⚠️ 体积是关键变量:短 system prompt(<1KB)即使含关键词也会放行, 只有真实 DSH 那种大请求体才稳定触发。
面板上的开关
面板底部「关键词风控中和」卡片有 4 个开关,改完即时生效,不需要重启:
| 开关 | 默认 | 作用 |
|---|---|---|
| 总开关 | 开 | 关掉后完全恢复原始请求,一个字节都不改 |
| 中和身份关键词 | 开 | 把散文里的关键词换成零宽分隔 |
| 补首条 system | 开 | 首条非 system 时注入保底 system(11128 的另一个成因) |
| 隐藏品牌词 | 关 | 更激进:连 DeepSeek 也打散 |
卡片同时显示运行时统计(已中和多少处 / 注入多少次)和补丁健康状态。
关键约束:文件路径不能被改写
运行时上下文里有真实路径:
D:\10_COD\DeepSeek Harness\resources\app.asar\dsh\
若在路径里插入零宽字符,模型会把坏路径传给工具调用导致失败。所以匹配器用
前后负向断言 (?<![\\/])…(?![\\/]) 跳过路径语境。实测:中和后路径里残留的
那一处不会触发拦截(上游匹配的是身份陈述位置,不是全文子串)。
为什么是可开关的
上游策略随时可能变化。关掉 = 钩子直接返回,行为与未打补丁完全一致, 不需要重新打补丁或重启 —— 这就是「万一到时候要切回来」的用途。
实现方式:一行钩子 + Host 提供逻辑
pack.js 里只插一行:
;globalThis.__wbLexicon?.rewrite?.(messages);
真正的替换逻辑在 src/lexicon.mjs,由 Host 半身通过 globalThis.__wbLexicon
提供。这样除了能即时开关,还有个好处:OFM 升级后重打成本极低(就一行)。
补丁自愈(重要)
每次用 pluginManager 装卸任何插件都会跑 pnpm,而 pnpm 会把
dsh-our-free-model 从它钉住的 tarball 重新解包 —— 补丁必被冲掉。
所以 Host 半身启动 1.5 秒后会自检一次:发现 pack.js 里没有 __wbMeter
标记且锚点唯一,就自动重打并写 patch-state.json(selfHealed: true)。
关键词钩子同理(1.8 秒后自检 __wbLexicon)。自助修复不会改变你的开关选择
—— 开关状态存在 ~/.dsh/workbuddy-meter/lexicon.json。
实测验证:手动
--revert后重装插件 → 补丁自动恢复,--check退出码 0。
数据落在 ~/.dsh/workbuddy-meter/:
usage-<YYYY-MM-DD>.jsonl # 逐请求记录(UTC+8 分天,append-only)
balance.json # 账号积分余额快照
patch-state.json # 补丁状态(版本/时间/备份路径/前后 sha256)
前置条件
本插件是 DSH(DeepSeek Harness)的插件,不是独立程序。装之前请确认:
必需
| 项 | 要求 | 怎么确认 |
|---|---|---|
| DSH 桌面版 | 已在用,且能打开 Web UI | 应用里能看到侧边栏「用量」区域 |
| dsh-our-free-model(OFM) | 已安装并至少登录一个 WorkBuddy / CodeBuddy 账号 | DSH 设置 → 渠道包 / Channel Pack 里能看到账号 |
| Node.js | ^22.19.0 或 >=24.0.0 | node --version |
本插件的数据全部来自 OFM 的 channel-pack。没装 OFM 或没登录账号, 面板会是空的 —— 那不是 bug。
平台
- Windows / macOS / Linux 均可(纯 Node + 浏览器 CSS,无原生依赖)
- 已在 Windows 11 + DSH 0.2.1-rc.2 实测
可选(按需)
| 项 | 用途 |
|---|---|
| Git | 从仓库克隆安装 |
| 任意支持 OpenAI 协议的客户端 | 只是想测通道是否通,不需要装本插件 |
不需要
- ❌ 不需要 WorkBuddy 官方客户端在后台运行
- ❌ 不需要额外的 API Key(插件读的是 OFM 已存好的凭据)
- ❌ 不需要管理员权限
快速开始
方式 A:让 DSH 的 agent 帮你装(推荐)
在 DSH 里直接说:
把这个目录装成插件:
<本仓库的绝对路径>
agent 会调用 plugin_manager 的 install_bundle,几秒钟装好,不用重启。
方式 B:手动走 pluginManager RPC
先取到当前 Web 端口(每次启动 DSH 都会变):
# 从 DSH 窗口标题或运行时上下文里读到 http://127.0.0.1:<端口>
然后:
POST http://127.0.0.1:<端口>/api/pluginManager/installBundle
Content-Type: application/json
Cookie: dsh-auth-<...>=v1.<...>.<...>
{"type":"client-request","rpcId":"install-1","method":"pluginManager/installBundle",
"payload":{"args":{"spec":"<本仓库绝对路径>","options":{"saveExact":true,"enabled":true}}}}
⚠️ 认证 cookie 的签名算法见
CONTRACT.md。如果嫌麻烦,用方式 A。
装完要做的两件事
1. 打补丁
插件需要往 OFM 的 channel-pack/pack.js 里插两处极小的钩子。
默认 dry-run,先看会改什么:
cd <本仓库>
# 补丁 1:meter 采集(记录每次请求的 usage.credit)
node scripts/patch-ofm.mjs # 预览
node scripts/patch-ofm.mjs --apply # 落盘
node scripts/patch-ofm.mjs --check # 退出码 0 = 在位
# 补丁 2:关键词风控中和(可选,见下文)
node scripts/patch-keyword-bypass.mjs
node scripts/patch-keyword-bypass.mjs --apply
node scripts/patch-keyword-bypass.mjs --check
💡 其实不打也行 —— 插件启动后 1.5 秒会自动自检并补上。 手动跑是为了当场看到「改了什么」。
2. 重启 DSH 一次
补丁改的是 pack.js,而 Node 会缓存已加载的模块。
新装的补丁必须重启一次 DSH 才生效(之后不用再重启)。
验证装好了
打开侧边栏「用量」,应该看到:
- 顶部有「今日 / 7 天 / 30 天」切换
- 大数字区显示积分消耗
- 底部有「已打补丁 OFM x.y.z」绿字
- 最底部有「关键词风控中和」卡片
如果底部显示「未打补丁」:点「打补丁」按钮,或按上面手动跑一次。
特色功能
1. 逐请求记账,不是估算
别的工具多半是按余额差算消耗。本插件在 OFM 的 SSE 流里挂一个钩子,
把上游返回的 usage(含 credit 积分字段)逐请求抄下来:
provider / model / accountId / prompt / cache_read / cache_write
/ completion / reasoning / credit / ttft / duration
所以能算出实测单价,而不是「大概」。
2. 缓存命中率 → 直接换算成钱
上游对冷/热请求的计价差极大。本插件把命中率变成可操作的数字:
| 场景 | 实测单价 |
|---|---|
冷请求(cache_miss) | 17.92 积分/1M token |
热请求(cache_hit) | 0.68 积分/1M token |
差 26 倍。面板会直接告诉你「你的命中率是多少、离目标差多少」。
3. 模型性价比排行
同一个问题,不同模型的实付价可能差 3 倍。面板按你实际用出来的单价排序, 并标出「换这个模型能省多少」。
官方倍率只能做粗筛 —— 真实差价要看实测,因为缓存命中率会放大差距。
4. 还能用多久 / 还能用多少 token
两个视角同时给:
- 整个号池:所有账号余额加起来能撑多久
- 当前账号:这个账号自己还能撑多久
并且换算成还能用多少 token(结合你的实测单价和缓存命中率)。
5. 一键测速 + 限速倒计时
点一下就用一个真实请求测当前账号的 deepseek-v4.1-flash 通不通。
如果不通,直接显示距离解除限速还有多久(用上游返回的权威解封时间,不是猜的)。
6. 账号池可视化 + 昵称编辑
- 每个账号的余额、占比、消耗
- 点 ✎ 内联改名(只改本地显示,不动上游账号)
- 一键切换当前使用的账号
7. 关键词风控中和(应急开关)
上游可能会按关键词拦截请求。面板提供 4 个开关,改完即时生效、关掉即恢复原样。 详见下面「关键词风控中和」章节。
8. 省钱诊断
面板会读你的实际数据,给具体建议而不是泛泛而谈:
- 「你的缓存命中率 87%,低于 90% —— 每次多花 X 积分」
- 「47.6% 的请求上下文超过 500k,吃掉 63.2% 的积分」
- 「v4-flash 比 v4.1-flash 贵 2.9 倍,本区间多花 Y 积分」
9. 全部本地,零遥测
没有上报、没有外发。关键词中和是纯字符串处理。
数据结构见 CONTRACT.md。
补丁详解
打在哪
BuddyAdapter.consumeSse(同时服务 buddy 与 workbuddy 两个 provider)内,
if (data.usage) { ... } 块、yield { type: "usage", ... } 之前:
;globalThis.__wbMeter?.capture?.({
provider: this.product.id,
model: options.model,
accountId: policyBlockedAccountId ?? "",
usage: data.usage,
startedAt: Date.now()
})
为什么只打一处就够
markGatewayChannel() 只给 options 打标记(用于 OFM 自己的 ledger 归属),
不改变解析路径 —— 所以 DSH 内直接调用(direct)和经 8326/18326 网关(gateway)
都走同一个 consumeSse。一处补丁覆盖两条路。
安全性
- 打前自动备份
pack.js.backup-<ISO时间戳>(同目录) - 幂等:已含
__wbMeter即跳过 - 锚点校验:命中数 ≠ 1 就中止,不改文件
- 可还原:
--revert从备份还原,sha256 逐字节一致 - 补丁后
node --check语法校验通过(脚本内置)
⚠️ OFM 升级会覆盖补丁
OFM 的升级(应用内「立即升级」或 pnpm)会重写 pack.js → 补丁消失。
面板的「补丁状态」条会显示 未打补丁 / 版本漂移,点「打补丁」重打即可。
升级后请先跑一次 node scripts/patch-ofm.mjs --check。
数据语义(重要)
| 情况 | 记录 | 面板显示 |
|---|---|---|
上游报 credit: 0.17 | credit: 0.17, creditReported: true | 0.17 |
上游报 credit: 0 | credit: 0, creditReported: true | 0 |
| 上游没报 credit | credit: null, creditReported: false | —(未上报) |
0 与 null 语义不同,不要混:小请求低于计费门槛会返回 0(真实免费),
而上游没给这个字段时我们不知道消耗了多少,如实留空。
实测基线(2026-10-18,deepseek-v4.1-flash 国内站)
| 场景 | 积分 / 1M token |
|---|---|
| 冷(无缓存命中) | ≈ 14.4 |
| 热(大量缓存命中) | ≈ 0.40 |
| 日均混合 | ≈ 3.2 |
缓存命中与否差 36 倍。面板的「冷/热单价」就是给你看这个的。
本机 2026-10-18 实测(
deepseek-v4-flash,96 条真实请求): 冷 65.57 / 热 1.64 积分 per 1M token,差 41 倍,缓存命中率 99.8%。
面板设计
设计立意取自计价器 / 电表,不是通用数据看板 —— 因为这套数据唯一值得一眼看懂的事 就是「同样 1M token,冷请求比热请求贵几十倍」。
| 区块 | 设计决策 |
|---|---|
| Hero | 一个大号(44px)的「本区间消耗积分」,右侧一条紧凑指标轨(请求/token/单价/命中率/每积分 token)。刻意不做 6 个等大卡片 —— 那会埋没主数字。 |
| 冷热单价尺 | 本面板唯一"值得记住"的元素:对数刻度的横向尺,冷价与热价钉在上面,中间用渐变段连起来并标出差值倍数。线性刻度看不出 41 倍,对数刻度能。 |
| 趋势图 | 手写 SVG(零依赖),token 柱 + 积分折线双轴。高度随数据量自适应(≤2 天 168px / ≤5 天 209px / 更多 250px)—— 固定 250px 在只有一天数据时会留下半屏空白。 |
| 模型明细 | 紧凑表格,积分与单价分列。 |
| 账号余额 | 每个账号一张小卡,剩余积分用 *Precise 字段(8 位小数)。 |
| 补丁状态 | 底部一条,含版本/锚点/自愈标记与三个操作按钮。 |
工程约束(自检脚本强制):
- 只用
var(--dsw-alias-*)主题 token,零硬编码颜色(亮/暗自动适配) - 类名全部
wbm-前缀,不污染全局 - 数字全部
font-variant-numeric: tabular-nums backdrop-filter有@supports回退- 响应式:820 / 1024 / 1440 三档实测无横向溢出、无标注重叠
动画(全部 CSS/rAF,零依赖)
一次编排好的开场 + 交互反馈,没有滚动触发的重复播放: 设计原则是"把大胆花在一次开场,其余保持安静"。
| 动画 | 实现 | 实测证据(CDP 帧采样) |
|---|---|---|
| 阶梯入场 | hero → 尺 → 趋势 → 明细 → 余额,60ms 阶梯延迟 + 500ms 上升淡入 | t=124ms 时首区块 opacity 0.40、其余仍 0 |
| 数字滚动 | rAF 计数,1100ms ease-out(1−(1−p)³) | 28.4 → 56.8 → 83.0 → … → 134.8 |
| 冷热尺生长 | span 条 scaleX 0→1(900ms) | 宽度 231 → 616px |
| 柱子生长 | scaleY 0→1(800ms) | 高度 51 → 122px |
| 折线绘制 | pathLength=1 + dashoffset 动画(1.2s) | — |
| 标记浮现 | 冷 0.95s / 热 0.5s 依次上浮 | — |
| hover 反馈 | 卡片边框亮起 + 轻投影(180ms) | — |
prefers-reduced-motion: reduce 时全部禁用(CDP 模拟实测:
数字直接显示终值、区块全部立即可见、柱子无生长)。
已知边界
- 只统计本机 OFM 进程内的请求。你在服务器上反代给朋友用的流量不在这里 (那台机要单独装本插件才能记)。
- 不是余额扣减量。逐请求的
credit是上游对该请求的计价, 而账号余额是另一套(get-user-resource)——两者会有小差异(上游计价与结算口径)。 - 小请求
credit=0不代表免费模型。要判断模型是否免费,看 OFM 模型目录的creditsRate(x0= 免费)。 - 数据只增不删。本插件不做轮转,长期使用请自行归档旧
usage-*.jsonl。
文件清单
workbuddy-meter/
├── CONTRACT.md # 冻结的接口契约(数据/聚合/路由/面板)
├── package.json # 插件清单
├── cordis.patch.yml # bundle 插入行
├── icon.svg # 侧边栏图标
├── index.js # Host 半身(采集/聚合/余额/路由/两个补丁自愈)
├── client.js # Client 半身(面板 UI,含内嵌 zh/en 字典)
├── src/
│ ├── patch-engine.mjs # 补丁引擎(脚本与自愈共用;两个补丁)
│ └── lexicon.mjs # 关键词风控中和逻辑 + 永不抛错的钩子
├── locale/{zh,en}.json # 文案(与 client.js 内嵌字典保持同键集)
├── scripts/
│ ├── patch-ofm.mjs # meter 采集补丁命令行
│ └── patch-keyword-bypass.mjs # 关键词中和补丁独立命令行(备选路径)
└── _out/ # 自检与验证脚本(不发布)
├── host-selftest.mjs # Host 半身 162 项自检
├── selftest.mjs # Client 半身 116 项自检(含静态审计)
├── test-lexicon.mjs # 词库逻辑 18 项断言(含路径安全)
├── test-click.mjs # CDP 真浏览器点开关验证
├── lead-adversarial4.mjs# 独立复算聚合数学
├── cdp-verify-ui.mjs # CDP 真浏览器渲染验证(多视口)
└── verify-patch.mjs # 补丁静态+功能验证
回滚
# 1. 还原 OFM 补丁
node scripts/patch-ofm.mjs --revert
# 2. 卸载插件
POST .../pluginManager/removeBundle {"payload":{"args":{"name":"dsh-workbuddy-meter"}}}
# 3. 数据(可选,默认保留)
# ~/.dsh/workbuddy-meter/ 整目录删除即清空全部历史
隐私说明
这个插件不会把你的数据发到任何地方:
- 用量记录、余额快照、补丁状态、开关配置全部写在本地
~/.dsh/workbuddy-meter/ - 没有任何遥测、上报或外部请求(除了你本来就在用的 WorkBuddy 上游)
- 关键词中和是纯本地的字符串处理,不发任何东西出去
贡献
欢迎 issue 与 PR。提交前请确保:
node _out/host-selftest.mjs # Host 半身 164 项
node _out/selftest.mjs # Client 半身 116 项(含静态审计)
三条代码约定(自测会强制检查):
- 样式只能用
var(--dsw-alias-*)token —— 不允许十六进制色值或rgb()/hsl() - 所有 CSS 类名以
wbm-开头 —— 避免污染宿主样式 - 中英文案键集必须完全一致 ——
locale/zh.json与client.js内嵌字典同步
许可
MIT © 2026 balong
2026-10-18 建立,2026-10-21 开源。补丁点与数据契约见 CONTRACT.md。
Comments
Loading…