Repository navigation
Releases: Slacom/dsh-usage-dock
Release list
dsh-usage-dock v0.8.2
dsh-usage-dock v0.8.2 发布说明
发布日期:2026-10-15
主方向:DSHA(Android 移植)WorkBuddy 读取失败修复
背景
DSHA(Android APK / dsh web 0.2.0-rc.2)上 WorkBuddy 渠道一直显示「获取失败」,
报 WorkBuddy 状态读取失败(fetch failed)。经完整诊断(见 DHSA移植反馈/交接文档-0.8.2修复.md),
usage-dock 本身无缺陷,根因在宿主侧:
- DSHA 内置插件
dsh-web-mobile@3.0.5的compress.js改写ServerResponse.prototype
做响应压缩,会把「可延迟」的响应头攒起来晚一拍提交; @deepseek-ai/dsh-host-webserver的 gzip 中间件(阈值 1024 B)在res.end代理里
看到headersSent仍为 false,会自己再调一次res.writeHead(statusCode);- 该重入落回
compress.js的patchedWriteHead,它先flush()(headersSent变 true),
后面的 guard 又因这个 true 调原生writeHead→ 抛ERR_HTTP_HEADERS_SENT→
webServer 兜底 catch 直接res.destroy()→ 客户端只见fetch failed。 - 触发条件:响应体 < 1 KiB 且带显式
Content-Length+ 客户端声明 gzip。
WorkBuddy AI 版的 52 Bsigned-out桩响应正好中招,而国内版(3.5 KB)正常;
旧策略「任一版本失败即整体报错」于是把整条渠道拖垮。 - 该内置插件目录受 App 完整性保护(改了会被还原),只能从消费侧绕过。
修复 1:status 请求声明不压缩(plans/workbuddy.js)
fetchStatus() 的 fetch 请求头显式加 accept-encoding: identity——无编码可协商,
gzip 中间件不进入问题重入分支。已在 DSHA 真实宿主上实测:错误消失,
creditsTotal 恢复 1846、11 条明细。
修复 2:失败降级为「部分数据」(plans/workbuddy.js + client.js)
- Host:先看有没有任何版本真的拿到 credits——
- 有 → 照常展示该版本合计,并带
partial/partialNote标记; - 没有 → 保持原有
api/exec/signed-out分类与文案。
signed-out/ 404 依旧不算失败(不是「另一方坏了」,只是没登录/没装)。
- 有 → 照常展示该版本合计,并带
- Client:WorkBuddy 面板合计行下以灰色脚注(
sectionNoteStyle)渲染
partialNote(「以下版本未取到数据:…」),不把部分合计伪装成完整合计。 - 实测三场景(真实宿主 + 模拟):一方失败一方正常 → 正常展示 + 脚注;
两方都失败 → 仍报exec;两方都未登录 → 仍报signed-out。
注意:WorkBuddy 插件自身的设置卡片与「检查更新」(
/update、/probe端点)
仍受同一宿主 bug 影响,需宿主侧修复(方案已提交 dsh-web-mobile 维护者,
或用户级cordis.patch.yml关 gzip),不在本插件范围内。
新功能
详情卡片:点击卡片外自动关闭
详情卡片打开后,点击卡片外的任意位置自动关闭(pointerdown 捕获阶段判定,
按在胶囊/面板内不关;兼容 Shadow DOM composedPath);Esc 同样关闭。
不必再通过再次点击胶囊来收起。
详情卡片:从胶囊向上展开的渐变动画
参考 DSH 桌面端左侧工作区「点击项目展开会话记录」的动效语言:面板出现那一帧
播放一次「从胶囊向上展开 + 渐显」动画(translateY 6px → 0 + opacity 0 → 1,
170ms,WAAPI 合成器路径,与峰谷条动画同款方案);无 WAAPI 的环境(旧 WebView)
静态呈现,行为与上一版一致。打开期间的数据刷新不重播动画。
峰谷条游标:方案 K「上下对尖」
替换原 2px 白柱:上游 8×5 倒三角 + 轨道下 6×4 小正三角夹住「现在」,
色条内部没有任何覆盖物,也没有类似边界的竖线(方案出自
docs/demos/cursor-directions-v2.html 方向 K,用户定稿)。
上三角底缘与轨道上缘留 1px 空隙、下三角顶缘与轨道下缘留 2px 空隙,
全部挂在共享 50% 锚点上,不进轨道圆角裁切。
测试
- 回归总量 156 + 5 项全绿:
test-workbuddy.mjs13 → 22 项:W8 改为降级策略断言(部分成功 → partial 标记 +
不报错;两方都失败 → 仍 exec),新增 W11(两条 status 请求都带
accept-encoding: identity);- 新增
tools/test-panel-interactions.mjs(8 项):外点/Esc 监听生命周期、
点击卡片外自动关闭、卡片内按下不关、Shadow DOM 判定、Esc、展开动画
单次播放与关键帧、partial 脚注渲染与无标记零影响; tools/test-peak-marker.mjs(真实 Chromium 几何)改为方案 K 断言:
上下三角与轨道中点同轴、1px/2px 空隙、无轨道内游标元素,24 组宽度/zoom
组合共 144 项断言通过;tools/mock-react.mjs对齐真实 React 的两处语义(effect cleanup 保存与执行、
渲染后补全 mock DOM 父子链),供外点判定测试使用;可选waapi运行时记录
element.animate调用。
test-android-compat.mjs13 项、test-workbuddy-contract.mjs5 项(真实 0.7.4
移植包源码契约)通过,模拟无 shell / 无账号 / 无 configEditor 宿主依旧成立。
升级
dsh plugin --profile web add dsh-usage-dock@0.8.2桌面端按实际 profile 使用 --profile desktop。安装后重启 DSH / 安卓引擎并刷新页面。
dsh-usage-dock v0.8.1
dsh-usage-dock v0.8.1
2026-10-15。上一公开版本为 v0.7.2;此前本地规划的 0.8.0 没有单独发布,相关功能一并纳入本版。
新增与改进
- 小米 MiMo 余额:控制台 Cookie 鉴权,显示总余额及现金/赠送明细,可设低余额警告阈值。
- WorkBuddy 积分:复用 dsh-workbuddy-connect 的国内/国际版状态接口,显示剩余积分及套餐明细;无需本插件另行认证。
- 渠道排序:设置页 ▲ / ▼ 调整胶囊及面板中的渠道顺序。
- DeepSeek 峰谷条:以现在为固定中点,24h 峰谷图案平滑移动,分钟级漂移校准;小字显示高峰/空闲时段与下一切换时间。
- 倒三角定位修复:三角与柱共享唯一中心锚点,三角尖端接触轨道上沿;用户已确认修复成功。
保留 2px 柱,光柱/引线等候选仅保留为演示,未实装。 - 失败降级与刷新:短暂传输失败保留旧值,连续两轮失败显示错误;展开、focus、重新可见时立即刷新,余额向下取整到分。
- 配置读取:Host 可用时通过 configEditor 重读配置;保存 Cookie/Key 与关闭渠道不必总是依赖重启。无该服务的移植宿主回退启动快照。
- 充值入口回退:移除本地试验的内嵌/原生充值按钮,避免视图与返回栏互相遮挡;低余额提示引导相应平台操作。
安卓 / DSHA 检查与防护
- 继续使用 Host 原生 fetch,无 shell、无 Python/curl、无桌面账号服务时可以走 API Key 读取余额。
- 修复单渠道异常导致整条用量接口失败的问题;同步抛错、异步拒绝均返回本渠道结构化错误。
- 修复旧请求 JSON 解析迟到覆盖最新强刷结果;请求身份与 AbortController 解耦,缺少该 API 的裁剪 WebView 仍有锁与超时兜底。
- 修复 PeakBar 数据缺失/恢复时 hooks 数量变化;无 WAAPI 时静态定位,无 ResizeObserver 时定时校准宽度。
- 登录失效、缺凭据等语义错误立即透传,不拿旧余额掩盖。
- WorkBuddy 外层异常返回结构化错误;一版成功、另一版异常时不再把部分积分伪装成完整合计。
- 设置保存期间锁定字段和排序,避免慢网下继续编辑后草稿丢失;纠正 WorkBuddy 登录来源提示。
已核对 DSHA 移植使用的 dsh-workbuddy-connect 0.7.4 安装包:两条 status 路由、回环安全限制、
credits.total/accounts 字段与手机插件自有认证副本读取方式均匹配。以真实 status handler + 模拟认证/计费
完成接口对接;无需在安卓安装 WorkBuddy 桌面应用。两插件应装在同一 profile,登录副本和计费网络必须可用。
验证边界:这是源码、模拟宿主与真实浏览器几何检查,不是 Android 手机联网真机测试;不能保证所有移植版本及 WebView 版本都一致。
验证
| 检查 | 通过数 |
|---|---|
| 取数后端(含真实上游无效 Key 鉴权与 Python 兜底) | 8 |
| 侧栏折叠 | 4 |
| 底部独占行及额度布局 | 11 |
| 失败降级、刷新竞态、余额与各渠道渲染 | 39 |
| 峰谷相位与段窗口 | 32 |
| MiMo Cookie / 余额解析 | 21 |
| WorkBuddy 归一化及异常路径 | 13 |
| 安卓 Host、可选服务、hooks 与 API 降级 | 13 |
| 设置页、排序及保存锁 | 6 |
| 真实 Chrome 标记几何(宽度 / 缩放) | 120 |
| 真实 WorkBuddy 0.7.4 status handler 接口契约 | 5 |
合计 272 条断言/检查通过,其中 120 条是布局矩阵的几何断言,不应理解为 120 台设备。
安装
dsh plugin --profile web add dsh-usage-dock@0.8.1安卓使用 web profile;桌面按实际配置使用 desktop。安装后重启引擎,重新打开 WebView / 刷新页面。
v0.7.2 — 修回详情面板额度条 + 缩略态圆点居中
dsh-usage-dock v0.7.2 — 修回详情面板的额度条 + 缩略态圆点居中
上一版:v0.7.1。本版修两个 0.7.1 引入/遗留的显示问题,取数逻辑与配置项未动。
⚠️ v0.7.1 的详情面板不显示额度进度条,建议直接升到 0.7.2。
1. 详情面板里 OpenAI Codex 没有额度条了(0.7.1 引入的回归)
现象:展开详情面板后,5小时 / 周限 这几行只剩「标签 + 百分比 + 剩余时间」竖着堆在一起,
中间那条进度条整个不见了(真机截图:0%1 小时 / 68%7 天 挤成一列)。
根因:一个 JavaScript 变量遮蔽。
client.js 模块级本来就有一个给面板额度行用的样式:
var rowStyle = { display: 'flex', alignItems: 'center', gap: 8, margin: '6px 0' }0.7.1 为了让胶囊向外贴边 4px,在组件内部又写了一个同名变量:
var rowStyle = null // ← 0.7.1 引入的 bug
if (ownRow) { rowStyle = wide ? { …贴边样式… } : { … } }var 声明会被提升到整个函数作用域,于是组件里渲染面板额度行时用的 rowStyle
不再是模块级那个 flex 样式,而是这个局部变量 —— 面板还没被打开时它是 null,
被打开后它又变成根节点的贴边样式。两种情况都让额度行丢掉 display: flex,
label / 进度条 / 百分比 / 剩余时间于是从"一行四列"退化成"竖排文字",
进度条因为宽度塌成 0 而看不见。
修法:把局部变量改名(ownRowStyle),并在代码注释里写明"这个作用域里不要再有
叫 rowStyle 的变量",同时把面板渲染处的依赖关系记下来。
这个教训是通用的:
var没有块级作用域,同名的局部变量会静默接管外层模块级变量。
该不该用同名,编译器不会提醒,只有测试与真机能发现。
2. 缩略(rail)态状态点没有居中,而是贴左
现象:侧栏折叠成 rail 后,两个状态圆点贴在左侧,而不是像其他图标那样居中。
根因:胶囊是 column 方向的 flex 容器。0.6.3 起为了"折叠时不出面板",
给胶囊写的居中是 justifyContent: 'center' —— 但 column 容器里 justifyContent 管的是
纵轴,对横向居中完全无效;而子项在 align-items: stretch(默认值)下会被拉成满宽,
圆点自然就落在左端。
修法:缩略态补 alignItems: 'center' —— 子项不再被拉伸,而是按内容宽度水平居中。
展开态保持 undefined(默认 stretch),因此圆点、名称、数值的横向位置一行未动
(测试 T11 专门断言"展开态不得出现 alignItems")。
验证
浏览器半回归测试扩到 11 项,两条新用例都先在 v0.7.1 上跑失败、在修复版上跑通过,
证明它们真的守得住这两个 bug:
用 v0.7.1 的 client.js 跑:
[FAIL] T10 面板额度行 — 面板里应有 5小时/周限 两条额度行,实际 0
[FAIL] T11 缩略态圆点居中 — 缩略态圆点必须水平居中
11 项:9 通过, 2 失败
用修复后的 client.js 跑:
[PASS] T10 面板额度行:flex 布局 + 进度条完整(守住 var 遮蔽回归)
[PASS] T11 缩略态圆点居中,展开态位置不受影响
11 项:11 通过, 0 失败
- T10 打开详情面板,遍历组件树找出两条额度行,断言它们是
display:flex的四列结构、
且进度条轨道(height 6)与百分比填充(width: NN%)都在; - T11 断言缩略态
alignItems === 'center'、展开态没有该属性。
取数套件(8 项)与缩略交互套件(4 项)复跑无回归。
升级方式
dsh plugin --profile <你的 profile> add dsh-usage-dock@0.7.2安装后重启 DSH,浏览器硬刷新(Ctrl+Shift+R)。
相关链接
- npm:https://www.npmjs.com/package/dsh-usage-dock
- 上一版说明:v0.7.1
- 许可:MIT
v0.7.1 — 悬停灰底与侧栏其他按钮完全对齐
dsh-usage-dock v0.7.1 — 悬停灰底与侧栏其他按钮完全对齐
上一版:v0.7.0。本版只修一处细节:胶囊悬停底色的左右边界。取数逻辑、配置项、
详情面板一律未动。
问题
v0.7.0 把胶囊改成了「透明 + 悬停灰底」,但灰底比 Remote 等按钮两侧各短约 5px,
放在一起能看出不对齐。
实测(用真机截图量的像素,不是目测)
| 元素 | 灰底左右边界 | 宽度 | 左右内距 |
|---|---|---|---|
| Remote 按钮 | x 10..339 | 330px | 10px |
| 胶囊(v0.7.0) | x 15..334 | 320px | 15px |
顺带量了同一张截图里的其他基准(没有采用,但值得记下来):
元素 宽度 说明 DSH 自带列表行(工作区/「调试」悬停) 320px(x 15..334) 设计系统自己的数 「新会话」按钮的常驻边框 302px(x 23..324) 那是按钮表面,不是悬停底色 也就是说 v0.7.0 其实与 DSH 自带行同宽,是 Remote 比 DSH 原生宽 10px。
本版选择向同一容器里的直接邻居(Remote,330px)看齐 —— 这是用户看过三者数据后
明确选定的基准,不是随手取的数。
根因
sidebar.footer.action 这一行会给条目留内距:整行可用宽度是 x 10..339,
但条目的内容区只有 x 15..334。胶囊此前只声明了 width:100%,拿到的就是被缩进后的
320px。
ds-harness-remote 的侧栏条目对此有显式处理 —— 向外贴边:
.dshRemoteSidebarEntry.isWide{width:calc(100% + 8px);height:34px;margin:4px -4px}本次改动
照抄同款写法(ROW_BLEED = 4):
// 展开态、且确认独占一行时
{ flex: '0 0 auto', width: 'calc(100% + 8px)', marginLeft: -4, marginRight: -4 }- 左右各向外撑 4px,抵消整行内距,灰底边界与 Remote 对齐;
- 缩略(rail)态不贴边:rail 只有约 36px 宽,外扩会溢出侧栏(测试 T9 专门守住这条);
- 探测不到宿主 / 纵向容器时依旧完全不动(沿用 0.7.0 的降级路径)。
验证
浏览器半回归测试扩到 9 项,新增/更新的是:
[PASS] T1 横向 flex 行:容器开放换行 + 胶囊独占整行并向外贴边
[PASS] T9 缩略态不贴边(避免在 36px 宽的 rail 里溢出)
T1 现在断言 width === 'calc(100% + 8px)' 且左右 margin === -4,把这次的修复锁住;
T9 断言缩略态不得出现这两个外扩值。既有套件复跑无回归(取数 8 项、缩略交互 4 项)。
升级方式
dsh plugin --profile <你的 profile> add dsh-usage-dock@0.7.1安装后重启 DSH,浏览器硬刷新(Ctrl+Shift+R)。
相关链接
- npm:https://www.npmjs.com/package/dsh-usage-dock
- 上一版说明:v0.7.0
- 许可:MIT
v0.7.0 — 底部席位独占一行 + 外观与侧栏按钮对齐
dsh-usage-dock v0.7.0 — 底部席位独占一行 + 外观与侧栏按钮对齐
上一版:v0.6.3(侧栏缩略态交互修复)。本版只改浏览器半的布局与外观,取数逻辑与配置项未动;
点击展开的详情面板维持原样,本次不涉及。
一句话
三件事:胶囊独占一行、排到最上面一行、外观与侧栏其他按钮一致(不再是那个边缘分明的胶囊)。
装多个底部插件时不再互相挤压,详情面板向上展开也不会盖住其他按钮。
问题现象
- 只装本插件时一切正常(胶囊横跨侧栏宽度);
- 再装一个也用底部席位的插件(如
ds-harness-remote)后,两者挤在同一行:
Remote 的按钮和本插件胶囊并排,胶囊被压窄,渠道名与数值显示不全; - 侧栏缩略成 rail 后尤其明显;
- 胶囊自带深色底 + 边框 + 阴影,而侧栏其他条目(如「调试」「Remote」)都是无边框、悬停才出灰底,
放在一起风格割裂; - 胶囊排在底部最后一行时,点击展开的详情面板(向上展开)还会盖住其他插件的按钮。
根因
sidebar.footer.action 是 list 席位:DSH 把所有插件注册到底部的动作放进同一条横向 flex 行
(0.1.x 核心包里这条规则就是 .footerActions{display:flex},默认 nowrap)。
本插件此前用 flex: 1 1 auto 参与这一行 —— 于是它必然与同行的其他插件按比例瓜分宽度:
| 插件 | 注册方式 |
|---|---|
ds-harness-remote |
sidebar.footer.action,order: -20 |
dsh-usage-dock |
sidebar.footer.action,order: 10 |
顺序没问题(各插件本来就按 order 排),问题在于它们被排在同一行。
本次改动
只动 client.js(不含详情面板)。
1. 独占一行(useOwnRow())
- 挂载后从胶囊根节点向上探测最近的 flex 容器;
- 若该容器是
flex-direction: row(DSH 的实际布局):- 给它补一条
flex-wrap: wrap(只加这一条,不碰宿主的其他样式); - 把胶囊声明为
flex: 1 1 100%—— 在一行里 100% 宽度的元素无法与别人共处,于是必然独占一行;
- 给它补一条
- 若容器是纵向(旧版
footArea就是column):什么都不做,保持原来的flex: 1 1 auto。
纵向容器里flex-basis:100%会被解释成「高度」,会把同列的其他条目压扁 —— 这是必须避开的坑; - 探测不到宿主(没有 DOM / 老环境)时同样退回原行为,不报错。
2. 排到最上面一行(order: -1000)
详情面板是向上展开的(bottom: calc(100% + 10px))。排在底部最后一行时,面板会盖住其他插件的按钮;
把席位 order 取一个很小的负数(-1000,远早于 Remote 的 -20),本插件就排到最上面一行,
面板向上展开时没有可遮挡的对象。
3. 外观向侧栏按钮看齐
| 项 | 旧 | 新 |
|---|---|---|
| 背景 | --dsw-alias-bg-layer-2 深色底 |
透明(与「调试」「Remote」一致) |
| 边框 | 1px 描边 | 无 |
| 阴影 | 有 | 无 |
| 圆角 | 999(单行)/ 12(多行) | 12px,与侧栏其它条目完全一致(DSH 自带「新会话」按钮是 border-radius:12px;ds-harness-remote 的侧栏条目 .dshRemoteSidebarEntry.isWide .dshRemoteModeButton{height:34px;padding:6px 48px 6px 10px;border-radius:12px} 同样是 12px) |
| 内距 | 6px 6px |
6px 10px(对齐上面那条 Remote 规则的左内距,悬停底色左右留白对得上) |
| 悬停 | 无变化 | 浮出同款灰底 --dsw-alias-interactive-bg-hover(sidebar 的 .iconButton:hover 用的就是它) |
| 文字 | 统一主文字色 | 套餐名用次要色、数值用主文字色 |
状态点(7px 圆点)与套餐额度文字完全保留 —— 去掉的只是那层「胶囊外壳」。
悬停底色由 React 状态驱动,不靠 CSS :hover —— 这是踩坑后的选择:行内样式优先级高于
任何选择器,只要行内写了 background,注入的 :hover 规则就永远不生效(本版第一版就是这样:
鼠标移上去没有灰底,但 title 提示照常弹出,说明 :hover 其实在触发、只是被行内盖住)。
现在用 onMouseEnter / onMouseLeave(以及 onFocus / onBlur,键盘聚焦同样可见)切换
hot 状态,直接写行内底色,不经过优先级之争。行内只留不会被交互态覆盖的属性
(appearance:none 去掉 button 的原生外观,避免回落到系统灰底)。
注入的样式表因此只剩兜底与键盘可达性:
.dsh-plan-usage-pill{background:transparent}
.dsh-plan-usage-pill[data-interactive]:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:-2px}
data-interactive(以及悬停处理器)只在展开且可点击时才输出:缩略(rail)状态胶囊是纯展示、
点不动,因此既没有悬停底色、也不该有手型光标。
为什么用运行时探测而不是写死 CSS 类名:DSH 的 CSS Module 类名带哈希(如
hHd-Xa_footerActions),
跨版本会变;:has()选择器在旧版 Android WebView 上又不保证支持。探测getComputedStyle
的display/flex-direction(标准属性,不随构建变化)最稳。只给容器补
flex-wrap、并在确认是横向容器之后才声明basis:100%,是这次实现的两个安全边界:
万一将来 DSH 换了布局,最坏情况也只是退回旧行为,不会把侧栏布局弄坏。
验证
浏览器半回归测试 tools/test-footer-row.mjs 扩到 8 项(离线运行):
[PASS] T1 横向 flex 行:容器开放换行 + 胶囊独占整行
[PASS] T2 纵向容器:保持原样(不加 wrap、不声明整行)
[PASS] T3 跨过非 flex 包裹层找到行容器
[PASS] T4 容器本就允许换行:不改宿主样式,胶囊仍独占整行
[PASS] T5 无法探测宿主时退化为原行为且不报错
[PASS] T6 席位 order=-1000:排在 Remote(-20) 之前,详情面板不再遮挡其他按钮
[PASS] T7 外观:透明、无边框无阴影(仅状态点 + 文字),悬停态另配
[PASS] T8 注入样式表:悬停/聚焦规则正确,且不碰宿主选择器
它用假的 DOM 节点模拟出「横向 flex 行 / 纵向容器 / 中间夹着非 flex 包裹层 / 没有 DOM」四种宿主,
断言容器与胶囊各自被(或不被)改写成预期样式,并覆盖席位 order、胶囊样式与注入的 CSS 内容。
测试用的上游数据仍是真机截图里的那一组(DeepSeek ¥7.38 / Codex 33% 72%)。
同时复跑既有套件,确认无回归:
tools/test-collapsed-pill.mjs(4 项):缩略态不可交互 —— 仍全绿;tools/test-fetch-backends.mjs(8 项):取数后端与 DeepSeek 渠道 —— 仍全绿。
两个浏览器半测试的 mock 运行时(极简 React + client.js 加载器 + 假 DOM)本版抽成了
tools/mock-react.mjs,避免两份实现漂移。
兼容性
- 只改浏览器半(
client.js);Host 半、取数后端、配置项一律未动,无需迁移、无需重填 Key; - 桌面端、Web、移动端 Web UI 行为一致;侧栏缩略(rail)时仍然只有状态点且不可点击(0.6.3 的行为保持);
- 依旧零 DSH 核心补丁 —— 只往宿主的行内样式补一条
flex-wrap、只调自己的席位order,
注入的 CSS 也仅针对本插件自己的类名,不改任何核心包文件。
升级方式
# npm(推荐)
dsh plugin --profile <你的 profile> add dsh-usage-dock@0.7.0
# 或 GitHub 源
dsh plugin --profile <你的 profile> add github:Slacom/dsh-usage-dock安装后重启 DSH,浏览器硬刷新(Ctrl+Shift+R);移动端 Web UI 同理,更新插件后重开页面。
如果你还在更早的版本
- 0.6.3:修掉侧栏缩略时点击状态点弹出竖排乱码面板的问题(缩略态不再可点击);
- 0.6.2:修掉移动端(Android APK)取数全断的问题(改为 Host 进程内原生 fetch,
不再依赖设备上有python/curl),并让失败信息能指明后端与原因; - 0.6.1 及更早:
0.4.x/0.5.x/0.6.0未单独发布到 npm,累积变更见
v0.6.2 发布说明 文末的「累积变更」。
相关链接
- npm:https://www.npmjs.com/package/dsh-usage-dock
- 上游项目(本插件 fork 自):https://github.com/chendefine/dsh-plugins-plan-usage
- 许可:MIT
v0.6.3 — 侧栏缩略态交互修复
dsh-usage-dock v0.6.3 — 侧栏缩略态交互修复
上一版:v0.6.2(移动端取数修复)。本版只动浏览器半的交互,不涉及取数逻辑与配置。
一句话
侧栏收起成 rail 后,那两颗用量状态点不再可点:详情面板只在侧栏展开时点击打开。
此前在缩略状态点击会把面板挤成一条竖排乱码(移动端 Web UI 实测)。
问题现象
| 状态 | 表现 |
|---|---|
| 侧栏展开 | 胶囊正常,点击弹出详情面板 —— 桌面端一直良好 |
| 侧栏缩略(rail) | 只剩状态圆点,但仍可点击;点击后面板照常渲染,被约 56px 宽的 rail 压成一条竖排文字,显示不全 |
根因
两条都出在浏览器半(client.js)对折叠信号 wide 的使用上:
- 胶囊的
onClick与wide无关:缩略状态只是不再渲染文字列(wide && …),
但onClick={() => setOpen(!open)}一直挂着,于是照样能打开面板。 - 面板的渲染条件只有
open:面板是position:absolute; left:0; right:0; width:100%,
宽度跟随胶囊 —— 在 rail 里就等于被压到约 56px,中文逐字换行成竖排。
原有的useEffect只在wide发生变化时关闭面板;缩略状态下点击并不会改变wide,
所以那个兜底根本不会触发。
(wide 由 sidebar 经 ownerProps 传入:renderSlot('sidebar.footer.action', { wide }),
其值为 !collapsed || !settled。)
本次改动
| 位置 | 改动 |
|---|---|
| 胶囊元素 | 缩略状态根本不挂 onClick,标签由 button 换成 div(键盘回车也触发不了), |
不再输出 aria-expanded / aria-haspopup |
|
| 光标 | 缩略状态由 pointer 改为 default,不再暗示"可以点" |
| 详情面板 | 渲染条件由 open 改为 open && wide:即使"先展开点击、再折叠", |
| 折叠当帧也不会在 rail 里闪出面板 | |
| 展开状态 | 行为完全不变:仍是可点击的 button,点击切换面板,文字与数值照常显示 |
| 折叠兼容 | wide 缺失时(旧版 sidebar / 其他宿主)按展开处理,保持既有行为 |
保留悬停提示:缩略状态仍保留 title(鼠标悬停显示 DeepSeek ¥7.38 / OpenAI Codex 33% 72%)。
它是非点击交互,能在不展开侧栏时快速看到数值。若不需要,可以再关掉。
验证
新增浏览器半回归测试 tools/test-collapsed-pill.mjs(4 项,离线运行):
[PASS] T1 展开状态:可点击、点击后显示完整详情面板
[PASS] T2 缩略状态:无 onClick / 非 button / 无面板 / 无文字
[PASS] T3 展开→折叠:面板即时收起且无闪烁
[PASS] T4 缺失 wide 时保持展开语义(向后兼容)
仓库里没有 jsdom/React 依赖,因此这个测试用极简 hooks 运行时(createElement /
useState / useEffect / useMemo / useSyncExternalStore)加载真实的 client.js,
再按数据结构断言渲染结果;测试用的上游数据就取自真机截图里的同一组数值
(DeepSeek ¥7.38 / Codex 33% 72%)。
这个测试在编写当天就抓到一个真实错误:改动胶囊时漏掉了
var wide声明,
4 项用例全部以wide is not defined失败 —— 只有node --check是看不出这类问题的。
Host 半的既有回归测试 tools/test-fetch-backends.mjs(8 项)同时复跑通过,确认无回归。
兼容性
- 只改浏览器半(
client.js);Host 半、取数后端、配置项一律未动,无需迁移、无需重填 Key。 - 桌面端表现不变(侧栏足够宽,本来就没有这个问题)。
- 依旧零 DSH 核心补丁。
升级方式
# npm(推荐)
dsh plugin --profile <你的 profile> add dsh-usage-dock@0.6.3
# 或 GitHub 源
dsh plugin --profile <你的 profile> add github:Slacom/dsh-usage-dock安装后重启 DSH,浏览器硬刷新(Ctrl+Shift+R);移动端 Web UI 同理,更新插件后重开页面。
客户端 bundle 在插件激活时缓存,不重启不会生效 —— 这是 DSH 的既有行为。
如果你还在更早的版本
- 0.6.2:修掉移动端(Android APK)取数全断的问题 —— 取数改为 Host 进程内原生
fetch,
不再依赖设备上有python/curl,并让失败信息能指明后端与原因; - 0.6.1 及更早:
0.4.x/0.5.x/0.6.0未单独发布到 npm,
累积变更见 v0.6.2 发布说明 文末的「累积变更」。
相关链接
- npm:https://www.npmjs.com/package/dsh-usage-dock
- 上游项目(本插件 fork 自):https://github.com/chendefine/dsh-plugins-plan-usage
- 许可:MIT
v0.6.2 — 移动端(Android APK)取数修复
dsh-usage-dock v0.6.2 — 移动端取数修复
本仓库的首个 GitHub Release。npm 上此前的发布版本为
0.6.1
(0.3.0→0.6.1之间的0.4.x/0.5.x/0.6.0未单独发布到 npm,
其内容已包含在本次发布中,见文末「累积变更」)。
一句话
移动端(Android APK)上只用 DeepSeek API Key 时余额永远显示「获取失败」的问题已修复:
取数不再依赖设备上是否装有 python / curl,改为在 DSH 的 Host 进程内直接用 Node 原生
fetch 请求。
问题现象
在平板(移动端 DSH,com.dsharnessmobile)上安装本插件后:
- 侧栏胶囊:
DeepSeek 获取失败 - 详情面板:
upstream request failed(API Key 方式;账号侧:账号未登录) - 同一屏里的 OpenAI Codex 却完全正常(5 小时 / 周限都能读出百分比)
也就是说:API Key 已经正确解析到了,问题不在凭据。
根因
0.6.1 的取数实现是「DSH shell 服务 + 外部命令」,两个后端依次尝试:
| 后端 | 依赖 | 移动端现状 |
|---|---|---|
python plans/http-fetch.py(首选) |
设备上要有 python |
❌ 没有 |
curl(兜底) |
设备上要有 curl |
❌ 没有 |
两个后端全部失败后,错误被统一折叠成一句 upstream request failed,用户完全看不出原因。
反证(两条,都指向同一个结论):
- Codex 是唯一不经过 shell、直接在 Host 进程里
fetch()取数的渠道 —— 它在平板上正常; - 平板上「用 DeepSeek API Key 跑模型」本身就是同一个 Host 进程发往
api.deepseek.com
的请求 —— 这说明该进程出网没有问题。
所以正确做法是把插件的请求也放回 Host 进程内,而不是去 shell 里找出路。
本次改动(0.6.1 → 0.6.2)
| 文件 | 改动 |
|---|---|
plans/util.js |
取数后端顺序改为 原生 fetch(Host 进程内)→ Python shim → curl;只有在传输层失败(命令缺失 / DNS / TLS / 连接失败)时才换下一个后端,上游已给出 HTTP 或业务错误则立即返回,不再空耗一轮超时;首个成功的后端会被记住并复用 |
plans/util.js |
失败信息具体化:点名后端、退出码与原因,并挖出 Node fetch 默认隐藏的 err.cause |
index.js |
shell 服务不可用时不再让整个路由返回 503,交给后端按可用性降级 |
tools/test-fetch-backends.mjs |
新增 8 项回归测试(含平板场景复现) |
README.md / AGENTS.md |
前提条件去掉「必须装 Python」;把这两个坑写进对接文档第 5 节 |
适配与兼容性
- 不再需要 Python:Windows 桌面端此前的硬前提(沙箱内
curl的 TLS 不可用,
只能靠 Python/OpenSSL)已解除。Python shim 与curl保留为兜底后端。 - 兜底仍有意义:Node 原生 fetch 不读系统代理设置。在必须经系统代理出网的环境里,
首次请求会先失败一次(最多 10 秒),随后自动落到会读代理的 Python shim 并被记住,
功能不受影响,只是首次稍慢。也可给 Host 进程加NODE_USE_ENV_PROXY=1(Node 24+)让
fetch 直接支持代理。 - 平台覆盖:移动端(Android APK)、Termux、Windows 桌面端、普通 Web 部署共用同一套代码。
- 未受影响:桌面端「DSH 账号余额优先(含赠金)、API Key 回退」的优先级不变;
插件配置项与配置存储格式不变,升级无需迁移、无需重填 Key;依旧零 DSH 核心补丁。
可诊断性(本次一并改善)
失败不再是一句无信息量的话,而是会说明是哪个后端、什么原因:
upstream request failed(fetch: fetch failed (ENOTFOUND api.deepseek.com))
upstream request failed(fetch: fetch failed (timeout after 10000ms))
upstream request failed(fetch: exit 1: fetch failed (ECONNREFUSED 127.0.0.1:1);python: exit 127: ...;curl: exit 127: ...)
验证
新增的回归测试可离线运行,8 项全部通过:
node tools/test-fetch-backends.mjs[PASS] T1 透传(Authorization/Cookie/自定义头/POST body,零 shell 调用)
[PASS] T2 无 shell 服务时仍可取数
[PASS] T3 全后端失败时错误消息含逐后端原因
[PASS] T4 真实上游(无效 Key)返回确定性鉴权错误,零 shell 调用
[PASS] T5 fetch 失败时 Python shim 兜底(确定性错误)
[PASS] T6 平板场景:DeepSeek API Key 正确读出余额 ¥11.38(零 shell 调用)
[PASS] T7 桌面端账号余额优先(20.50 + 赠金 5.00 = 25.50)且不发请求
[PASS] T8 全渠道(6 个)在无 shell / 无凭据时降级正常
其中 T6 就是本次故障的现场复现:没有账号服务、python/curl 全部不可用,
只给配置里的 API Key,断言余额被正确解析且一次 shell 都没有调用。
真实环境另有实测:同一端点下 curl.exe 报 schannel: SEC_E_NO_CREDENTIALS(沙箱 TLS 限制),
而原生 fetch 正常拿到上游响应;移动端升级后余额恢复显示。
升级方式
# npm(推荐)
dsh plugin --profile <你的 profile> add dsh-usage-dock@0.6.2
# 或 GitHub 源
dsh plugin --profile <你的 profile> add github:Slacom/dsh-usage-dock安装后重启 DSH,浏览器硬刷新(Ctrl+Shift+R)。移动端同理:更新插件 → 重启 App。
插件配置改动在 Host 侧生效需要重启,这是 DSH 的既有行为,与本版无关。
附:累积变更(自 npm 上一公开版本 0.3.0 起)
0.4.x / 0.5.x / 0.6.0 未单独发布到 npm,内容一并包含在 0.6.2 里:
| 版本 | 内容 |
|---|---|
| 0.4.0 | 恢复 Config schema 交由 DSH 托管设置页;DeepSeek 改为「账号余额优先、API Key 回退」;移除自建 /config 路由与 JSON 配置文件 |
| 0.4.1 | 所有 Config 字段补 .volatile()(DSH 设置表单只显示 volatile 字段,否则没有设置页);胶囊展示账号余额失败原因 |
| 0.5.0 | 「设置 → 内置插件 → Usage Dock」独立设置页(settings.plugins.tab + configForms);按 Remote 投影契约修正账号余额解析 |
| 0.5.1 | 绑定 ConfigFormController 的方法(修设置页白屏);标签页更名 Usage Dock |
| 0.6.0 | 设置页「保存 / 放弃」草稿态;DeepSeek 余额警告阈值可配(deepseekWarnThreshold,默认 10 元,0 表示不警告) |
| 0.6.1 | 胶囊订阅 configForms:停用渠道即时消失(DSH 不会热重载插件配置) |
| 0.6.2 | 本版:移动端取数修复(原生 fetch)+ 失败原因可诊断 + 回归测试 |
以上同时覆盖了 DSH 0.2.0 的破坏性 API 变更适配(ctx.settings.register 移除、
volatile 字段、settings.plugins.tab 席位、sidebar.footer.action 公共席位等),
细节记录在仓库 AGENTS.md 第 5 节。
相关链接
- npm:https://www.npmjs.com/package/dsh-usage-dock
- 上游项目(本插件 fork 自):https://github.com/chendefine/dsh-plugins-plan-usage
- 许可:MIT