Skip to content

Releases: dingminhua/dsh-connect-qoder

v1.14.0 — 卡片新增只读「活动」区,上游下发的活动整份读出来

Choose a tag to compare

@dingminhua dingminhua released this 25 Oct 10:13

📣 v1.14.0 — 卡片新增只读「活动」区,上游下发的活动整份读出来

Qoder 的 sash/api/v1/me/campaigns 此前在本插件里只被当作签到接口用:签到路径
只挑 actionType === 'CLAIM_BENEFIT' 的那一条,而 VIEW_DETAILS 这类纯展示活动
(「1024 创造力集结」「首月订阅 Credits 翻倍」这些 banner)在解析层就被整行丢掉了。
用户实拍截图里这些活动一个都不出现——本版把活动面整份读出来,并在卡片上加了
一条只读的「活动」列表。


一、签到路径与展示路径共用一份解析

新增 fetchCampaignFeed()(src/upstream.ts)返回整份活动面(活动列表 + 顶层
campaignUrl / showCampaign / claimable),纯函数 projectCampaignEntry() 把
placements[*].content.{zh,en} 收拢成标题 / 描述 / detailUrl / buttonText;
原有的 fetchCampaigns() 退化成它的窄投影。

这样做的理由是避免两条路径各写一份解析、日后漂移:签到找可领那条、卡片渲染整份,
读的是同一个 projectCampaignEntry。签到行为本身没有变化(旧实现同样返回全部行,
过滤只发生在 claimDailyCredits 内部)。

二、文案原样来自上游,不发明标题也不伪造链接

活动标题与描述逐字来自上游(按界面语言取 zh / en,缺哪边用另一边);
「查看详情」是真链接,指向上游给的 detailUrl,缺失时退回活动落地页。解析对字段
缺席宽容:活动形状按节日变,缺字段就少渲染一点,绝不拿 campaignId 编一句
「限时活动」。

读不到 ≠ 没有:上游没下发时显示「当前没有活动。」,读取失败时显示原因,而不是
把失败伪装成空列表。

三、新增只读路由

GET /plugins/dsh-connect-qoder/campaigns(src/status-paths.ts +
src/web-status.ts),与 /account-credits 同款形状:非 GET 405、未接线 503、
读失败 502。只读:不签到、不写账号。

四、验证

  • 新增测试:tests/upstream.spec.ts(feed 解析 / 窄投影 / 幂等)、
    tests/campaigns.spec.tsx(客户端渲染 10 例)、tests/web-status.spec.ts
    (路由 200/503/502/405)。
  • 维护者审查后并入两处修正:探测脚本 probe-campaigns.mjs 原写死了 tsdown 带
    hash 的分块名(必然 ERR_MODULE_NOT_FOUND),改为直接导入源码;同时补回插入
    活动样式时被误删的 .dsm-qoder-composer-panel-error 规则。
  • 全量 982 条测试通过,typecheck 零错;CI 的 ubuntu 与 windows 两个 job 转绿后才发布。

五、已知边界

活动列表只在卡片挂载与切换区域时拉取,不参与 60s 轮询——活动是只读内容,够用
即可。活动区当前放在卡片正文、区域作用域内(额度读数之下的同层);组件本身不绑定
容器位置,位置若需调整只需改挂载那一行。

v1.13.0 — 上下文档位的 400K 一律按 500K 呈现与保存

Choose a tag to compare

@dingminhua dingminhua released this 24 Oct 10:08

🎚️ v1.13.0 — 上下文档位的 400K 一律按 500K 呈现与保存

Qoder 设置卡片里的上下文预算下拉,中间那一档此前显示 400K(上游 context_config
至今声明 [200000, 400000, 1000000],两个区域、实时刷新均核实)。本版起这一档在
插件内一律按 500K 呈现与保存:下拉显示 200K / 500K / 1M,升级前勾选过 400K
的存档读回即 500K,不会留下一个命中不了任何选项的选中值。


一、改写在解析边界,而不是渲染层

档位表在本插件里只有一个写点(parseUpstreamModel)与一个存档读点
(modelFromStored)。新增的改写表 QODER_CONTEXT_TIER_OVERRIDES 就落在这两处
之间:卡片下拉、usage 投影、落盘往返、运行期预算四个读点拿到的是同一份改写后
的表。在渲染层改只会让它们重新变成两张表——「下拉里的选项」与「保存后生效的窗口」
对不上,正是这个文件历史上踩过的坑。上游哪天真的改口发 500K,这张表自动变成恒等
映射,不需要再动任何读点。

默认档(上游把 is_default 标在 400K 上时)同步改写:只改表不改默认档,会出现
「选中值不在选项里」的下拉。

二、不替上游说话

档位是插件本地的上下文预算:聊天请求体里没有任何上下文字段(实测
createChatBodyTemplate),网关按模型自己的配置服务请求。所以这次改写只影响 DSH
侧的预算选择与显示,不构成对上游窗口的任何承诺——这一点写进了 CHANGELOG 与代码
注释,避免后来人把它读成「上游支持 500K」。

三、验证

  • 新增测试 6 条:改写表单值/整表去重升序/保存预算迁移/默认档改写/表外值不受影响
    (tests/catalog.spec.ts),以及一条端到端(tests/index.spec.ts)——存档里留
    改写前的预算 400K 与旧快照,读一次 /usage,文档里的档位表、生效窗口、回显预算
    三处必须都是 500K。
  • 全量 958 条测试通过,typecheck 零错;CI 的 ubuntu 与 windows 两个 job 转绿后才发布。

v1.11.0 — 上游报额度耗尽必显示:池关着时那次失败也有出口

Choose a tag to compare

@dingminhua dingminhua released this 24 Oct 06:31

🚨 v1.11.0 — 上游报额度耗尽必显示:池关着时那次失败也有出口

账号池的逐账号明细只在池视图里,而池的记账有两道门——池关着不记盘、非成员不记。于是池关着时,对话路径上一次上游报「当日额度用尽」(业务码 110)的失败,在任何 UI 上都无处可看:用户只看到请求失败,卡片上的余额还是旧数。

0.7.x 时代有个「今日额度疑似已用尽(本地统计,仅供参考)」胶囊专门补这个缺口,它在后来随本地请求计数器一起被拆掉了,缺口就一直留着。本版补上它——但用的是上游明说的事实,而不是本地推断。

上一版 1.10.0 发的是跨连接器余额对比(issue #14),与本版互不掺杂:1.10.0 的产物里不含本版的任何代码。


一、上游报额度耗尽必显示

  • 对话路径上一旦上游业务码命中配额族(QUOTA_CODES:110 当日用量 / 113 配额 / 115 免费 / 116-118 团队与个人 Credits / 119 免费额度 / 122 Billing Group / 402 / 6004),该区域的卡片出现一条通知:最近一次时刻 + 业务码,悬停是脱敏后的上游原文。
  • 与账号池开关无关:池开着且命中号是成员时,逐账号明细(红点 + 原因)在池表格里;这条区域级通知补的是「最近一次」的时序上下文。池关着时,它就是那次失败唯一可见的出口。
  • 措辞是「上游报」,不是旧版的「疑似(本地统计)」:这份记录只由上游明说的业务码产生,不是本地推断——上游明说过,就别再说疑似。
  • 限流不会被标成耗尽:rate-limited(HTTP 429 短窗)映射的是池的短冷却,把它标成耗尽会把一个还有额度的号误判成「今天没救了」;这条界线有测试钉住。
  • 进程内状态、不落盘:它说的是「上游最近一次说过」,不是「现在仍然耗尽」——上游恢复不会主动通知,时效由时间戳表达,重启清零可接受。
  • 上游原文走既有脱敏路径:与账号池探针同一条 redactUpstreamText,PAT(pt- 形态)绝不进通知原文,有测试钉住。

二、验证

  • 本机 pnpm run check 全绿:typecheck + 测试 970 passed / 8 skipped + build。
  • GitHub CI 的 ubuntu-latest 与 windows-latest 两个 job 均 success。
  • 新增用例覆盖判据三条(只有 quota-exhausted 才记、限流不算耗尽、PAT 不进原文)与卡片渲染一条(带字段即渲染、悬停挂脱敏原文、不带字段一条都不画)。

本版只新增一个 usage 文档的可选字段(lastQuotaExhaustion,缺席 = 上游从没说过);请求形状、落盘格式、配置键、CLI 与宿主 peer 范围一律未动。宿主 0.2.1-rc.3 上无需任何适配。升级后请重启对应 profile 的 DSH 进程。

v1.10.0 — 跨连接器余额对比:别的连接器当家时也显示积分

Choose a tag to compare

@dingminhua dingminhua released this 24 Oct 06:31

💳 v1.10.0 — 跨连接器余额对比:别的连接器当家时,也看得见本家的余额

同时装多个连接器(比如 Qoder 与 WorkBuddy)时,积分胶囊本来只跟着会话当前选中的 provider 走:两家的 provider 映射表互不相交,选了谁家的模型,另一家的读数立刻从输入区消失——而卡片里的「显示位置」设置救不了它(provider 的判断在前,位置判断在后)。于是想比较两边余额再决定切哪家,只能来回切模型看余额。

本版给每个区域加一个 opt-in 开关:勾上之后,别家模型当家时,本区域的读数仍然显示在原位,与对方的读数并排常驻,两边余额一眼可比。

开关默认关闭,默认行为逐字不变——多渲染一个胶囊是所有用户都会注意到的变化,必须是你自己要。


一、跨连接器余额对比(issue #14)

  • 卡片积分区新增第三行「其他连接器的模型选中时也显示」(regions.*.showCreditsForForeignModels,默认 false),与「在对话框显示积分」「显示位置」并列,同样整行可点、立即生效,不需要点保存。
  • 勾选后的行为:会话模型属于别的连接器(或模型投影尚未落地)时,第一个开了开关、且本区域的显示/启用开关都放行的区域照常渲染;两个区域都开时取国内版(区域顺序,可预测)。
  • 位置选择照旧把关:读数仍可放在「输入框工具栏」或「输入框下方」,对比态不影响这个选择。
  • 区域开关照旧把关:显示与启用开关、席位选择在对比态下一律照常生效。
  • 悬停文案分流:对比态下写的是「Qoder 侧计费账号 {name} 的余额」——此时本会话并不经 Qoder 计费,沿用「当前计费」会让人误以为这个号在给本会话付钱。

二、顺带修掉的一处守卫错误

胶囊的挂载取数 effect 原本挂在「provider 是否属于本插件」上,而请求真正用的是区域。对比模式下 provider 是外来的,effect 整个不跑——胶囊画出来了,余额却永远显示「—」。守卫改为按区域判定(activeRegion),并由新增测试钉住。

三、验证

  • 本机 pnpm run check 全绿:typecheck + 测试 962 passed / 12 skipped + build。
  • GitHub CI 的 ubuntu-latest 与 windows-latest 两个 job 均 success。
  • 新增 tests/composer-foreign-credits.spec.tsx 共 18 条用例,覆盖:默认关时的兼容面、区域选择与顺序、显示/启用/席位三道原有关卡照旧生效、模型投影未落地、对比态与原生态的悬停文案分流、写入不伤到隔壁区域。

本版不含「上游报额度耗尽」那条通知(那是下一版 1.11.0 的内容),请求形状、落盘格式、CLI 与宿主 peer 范围也都没有变动。

v1.9.2 — 宿主基线推进至 0.2.1-rc.3,本插件无需运行时代码改动

Choose a tag to compare

@dingminhua dingminhua released this 24 Oct 06:11

🛠️ v1.9.2 — 宿主基线推进至 DSH 0.2.1-rc.3,本插件无需运行时代码改动

本版是一次宿主适配版:DSH 桌面端升到 0.2.1-rc.3,我们逐包比对了 rc.2 → rc.3 的全部变更,确认本插件用到的宿主包与槽位契约一字未改,因此运行时代码保持原样,版本号按 patch 递增。

与以往不同,这次宿主换代还带来一个环境层面的变化:宿主 app 目录名从 DSH NEXT.app 变为 DeepSeek Harness.app,指向旧路径的 dsh 命令行 shim 会直接失效——README 里那条 dsh plugin --profile desktop add @dmh2002/dsh-connect-qoder 因此也跑不通。本版把修法写进了中英双语 README。


一、rc.3 到底变了什么(逐包比对结论)

  • 插件依赖的宿主包(dsh-llm / dsh-llm-pi-ai / dsh-settings / dsh-atomic-write / dsh-attachment / dsh-host-webserver / dsh-home-paths / dsh-client-ui-slots / dsh-client-ui-settings / dsh-client-ui-settings-plugins / dsh-client-ui-renderer / dsh-client-locale)与 rc.2 逐字节相同,只有 package.json 的版本号不同。
  • rc.3 的客户端改动全部是增量的,且都落在本插件用不到的地方:会话头的 View 标签页置顶(新增 conversation.session.header.views.actions 槽位)、草稿接管新增 whenDraftExists(replace / append / keep)、primitives 的 Tooltip 支持 left 侧并按视口自动翻转、Menu 新增 current 与 minWidthFromAnchor。
  • 宿主内置 pi-ai 仍是 1.1.0,上下文归一化契约不变——所以 1.1.0 修掉的那个「静默丢工具」缺陷不会复现。
  • peer 范围 >=0.2.1-rc.1 <0.3.0-0 在 npm 标准语义与宿主兼容门禁语义下都放行 0.2.1-rc.3,声明一个字没改。

二、本次实际做了什么

  • 回归覆盖:tests/dsh-line.spec.ts 的 ADMITTED_PRERELEASES 补进 0.2.1-rc.2 / 0.2.1-rc.3,host gate 用例补进 0.2.1-rc.3,把「当前宿主版本确实落在声明范围内」钉住,防止宿主再推进 rc 时静默失配。
  • 文档登记:README 中英双语新增「当前宿主基线 0.2.1-rc.3」小节,逐项列出上面的比对结论与实测结果(宿主内加载状态、槽位占据情况、兼容告警情况、回归结果)。
  • 宿主换代的环境修复:dsh 命令行 shim 改指新宿主自带的 CLI 入口 DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh(内部以 ELECTRON_RUN_AS_NODE 运行 app.asar 里的 dsh/lib/bin.js),修法同样写进 README 的安装一节。

三、验证

  • 本机 pnpm run check(typecheck + test + build)全绿;测试 948 passed / 8 skipped。
  • GitHub CI 的 ubuntu-latest 与 windows-latest 两个 job 均 success。
  • 宿主 0.2.1-rc.3 实机加载:配置目录里 include:dsh-connect-qoder 状态 schema;模型选择器槽位 conversation.input.model.label 由 dsh-connect-qoder-client(priority -1)占据;composer 槽位 conversation.input.left 有 dsh-connect-qoder-composer-credits;dsh plugin list 对本插件无兼容性告警。

升级后请重启该 profile 的 DSH 进程,让新版本生效。

v1.9.1 — 积分胶囊在池接管时显示计费号的余额

Choose a tag to compare

@dingminhua dingminhua released this 23 Oct 20:13

🔍 v1.9.1 — 积分胶囊在池接管时显示计费号的余额

修一处「显示的是错的号的余额」。用户实拍:面板高亮「当前选用 丁晓潇 100」,胶囊却读「QD AI · 773」——773 是已用量上限、根本没在计费的 ddd。


根因:两个数来自两条判据

  • 胶囊读 usage 文档的文档级 credits。那份文档是 refreshUsage 用第一发目标(区域选中号)读上来的,所以它天然是选中号的余额。
  • **面板「当前选用」**按请求路径真判据(src/shim.ts:第一发被硬拒才由 rankPool 第一名接管)落在接管者身上。

池开且选中号被排除时,两者必然分叉。这不是显示层的小错——胶囊给了一个误导性的「我还有 773」,而真实在烧的是 100 的那个号。

修法

胶囊改读此刻在计费那个号的余额,三级回落:

  1. 表格逐号读数(面板打开 / 切号 / 一键测试后取,最新);
  2. 同一份 usage 文档里池视图的每行余额(composer 拉的是 full 文档,恒带,零额外请求);
  3. 仅当计费号就是文档自己的号时才退回文档级总额。

拿不到计费号的余额就显示「—」:说不知道,比说一个错的号强。

另两处连带修正:

  • 悬停写明这个数字是谁的(composer.billingAccount,双语)。接管发生时「QD AI · 100」本身不说归属,正是截图困惑的来源。
  • 面板选中行缺读数时的回填改用文档总额(它本来就是选中号自己的余额),不再用胶囊显示值——否则接管时 ddd 行会被写成接管号的 100。

兼容性

旧宿主 / 池关(无 current 行)时退回选中号 = 文档总额,行为与 1.9.0 逐字相同;无接管时两路同值。版本号取 patch:只改「显示谁的余额」,不改判据、请求形状、落盘格式、配置键、CLI 与 peer 范围。

测试

新增 tests/composer-billing.spec.tsx 7 条:截图现场(表格路径与池视图路径各一条)、无读数退「—」、旧宿主兼容、无接管同值、面板打开后的表格路径、行回填不串号。变异 4/4 被拒:胶囊退回文档总额 ✗、current 判据改 selected ✗、行回填用显示值 ✗、悬停不说归属 ✗。

安装

npm install @dmh2002/dsh-connect-qoder@1.9.1

v1.9.0 — 活动徽标走进模型选择器

Choose a tag to compare

@dingminhua dingminhua released this 23 Oct 19:23

🔍 v1.9.0 — 活动徽标走进模型选择器

这一版让「错峰 4 折」「免费」两枚徽标出现在做选择的地方——宿主的模型选择器。issue #12 的观察一针见血:徽标原先只画在设置卡片里,而卡片是设置面,等你翻到那里读到「今晚打折」时,模型早选完了。同一个上游事实,现在画在还能改变决定的位置。


一、选择器里画什么

  • 活动徽标三态与卡片完全一致:窗口内实心、窗口外灰显虚线(悬停写明几点生效)、没有生效时间可说就整枚不画。判定复用 promoDisplayAt()(1.8.1 引入),文案复用 promoBadgeLabel/Tooltip——上游原文,插件不翻译不改写。
  • 免费标签:is_free(倍率 0)的模型挂「免费」胶囊,悬停「倍率为 0,不消耗积分」。
  • 样式零新增:.dsm-qoder-model-promo* / .dsm-qoder-model-meta-tag 一族直接复用,只加一个菜单行限宽修饰类(trigger 行宽、菜单行窄,不限宽时长文案会把模型名挤成省略号——主次颠倒)。两个表面不各写一套,观感永不漂移。

二、数据从哪来

  • 读卡片自己的路由(/plugins/dsh-connect-qoder/usage)但带 detail=fast:只答本地已有状态,不触发上游重读——选择器每开一次都去烧一次上游请求是不成比例的。
  • 快照按区域共享缓存(60s TTL)+ 单飞:菜单里几十行同区只发一次请求。
  • 窗口边界的翻面靠共享分钟时器重读时钟,不依赖新数据到达:22:00 开启、08:00 结束,挂着的选择器最迟各差一分钟翻面。所有挂载实例共用一个 timer,最后一个退订时关掉。

三、single 槽的抢位与交还(跨插件共存)

conversation.input.model.label 是 single 槽:只渲染第一条注册,同优先级重复注册直接抛。workbuddy 占着默认优先级 0,且它给所有模型画东西(倍率后缀、忙闲图标、「新」标记)。

  • 本插件以 priority: -1 抢占——抢位后外来 provider 必须交还:用原始 entries() 找到账本里下一个组件原样委托(entriesOfSlot() 对 single 槽去重后只剩自己,拿不到别人)。不交还的后果是「qoder 一到场,workbuddy 的标签集体消失」。
  • 委托渲染成子元素而非函数调用:被委托组件自带 hooks,直接调用会把它的 hooks 混进本组件的 hook 序列——同一槽位实例在外来↔本插件 provider 之间切换时,hook 数量一变 React 直接崩(有测试钉住)。
  • 组件由工厂按注册闭包捕获 slots:bundle 是单例,模块级变量会在多 fiber 各跑一次 apply 时被后者覆盖——委托会读到错误宿主的账本(issue #12 报告的本地补丁正是这个写法,已修)。
  • 两个都委托的插件理论上存在互委托环;宿主的错误边界会把抛错的 entry 一次性弃权(下一帧换幸存者),不会死循环。当前生态(workbuddy、1017 参考实现)都是「渲染裸名」的终点型组件,不成环。
  • 旧宿主线(0.2.1-rc.2 之前)没有这个槽:inject 永不兑现或注册抛错被 catch 成一行日志,卡片与 provider 不受影响,选择器退回宿主裸名。

四、这一版的测试

新增 tests/model-label.spec.tsx 18 条:三态渲染、免费标签、菜单/trigger 限宽、key/显示名两列匹配、fetch 失败退裸名、委托转发 ownerProps(且绝不把本插件的 t 递出去——那是绑在 settings.qoder 上的,递出去等于让别人拿我们的字典读它自己的 key)、同实例切换 provider 不崩、两 fiber 同时存活互不覆盖、单飞、纯时钟翻面。

变异验证 8 个变异体全部被拒:priority 改默认 ✗、委托改函数调用 ✗、不过滤自己 ✗(worker 崩溃)、转发 t ✗、绕过 promoDisplayAt ✗、工厂改模块级变量 ✗、时器不重渲染 ✗、单飞失效 ✗。settings-rebind 的槽位计数 4→5,并新增「注册必须带 priority: -1 + locale」断言。

五、安装

npm install @dmh2002/dsh-connect-qoder@1.9.0

peer 范围不变(宿主 ≥0.2.1-rc.1 各线均装得上;选择器徽标只在声明了该槽位的 0.2.1-rc.2+ 线上出现,更早的线静默退回裸名)。


issue #12 由 jinlei81 报告并附本地验证补丁,五个坑(priority 冲突、委托必要性、entries() vs entriesOfSlot()、无模块级 t、组件拿不到 ctx)全部核实成立;其中「无模块级 t」由注册时的 locale: namespace 解决(渲染器按 entry 注入命名空间绑定的 t,与宿主 1017 参考实现同机制),「ctx 捕获」改成了工厂闭包(见上)。

v1.8.1 — 免费徽标补悬停、错峰窗口外灰显

Choose a tag to compare

@dingminhua dingminhua released this 23 Oct 08:19

🔍 v1.8.1 — 免费徽标补悬停、错峰窗口外灰显

这一版补齐两枚模型徽标「看不出来」的那一半:「免费」有了悬停说明(为什么免费),「错峰折扣」在窗口外不再整枚消失(白天也看得出晚上有折扣)。都是从实机截图反馈来的:14:5x 打开卡片,Qwen3.8-Max 行上既没有「错峰 4 折」、悬停也问不出什么——而它的规则、文案、窗口在目录里全都是齐的。


一、「错峰 4 折」在窗口外改成灰显

旧实现只在「此刻成立」时画,于是白天打开 DSH 的人永远发现不了晚上有折扣。新增 promoDisplayAt() 三态:live 实心、pending 灰显、none 不画。

  • 灰显挂的仍是上游那句原文案(「错峰 4 折」),但换成虚线描边 + 中性底色 + tertiary 灰字——虚线是形状差异,不依赖颜色,色觉障碍与高对比度主题下仍成立。只调深浅会被读成「现在就在打折」。
  • 悬停里前置一句状态:「当前未生效,22:00 起生效」,再接上游的时段与时区。信息一条不少,只多一句「还没到点」。
  • 两种情形仍整枚不画:窗口读不懂(给不出「几点生效」——猜一个时间比不说更糟)、没有窗口而 active 为 false(常驻活动此刻没开,同样没有生效时间可说,画出来只能是一句空话)。

判定函数 promoLiveAt() 签名与语义不变(现在实现为「promoDisplayAt 等于 live」),两个函数共用同一套前提。

二、「免费」补上悬停

它不是活动徽标,是上游的 is_free(倍率 0)——上游对它没有 description / 时段 / 链接可引用,所以这句解释由插件自己写:「倍率为 0,不消耗积分」。

加它的理由:卡片上「免费」与「错峰 4 折」并排,后者才是限时的那个。两个字的徽标不说清判据,就会被读成「这模型在搞活动」。

三、这一版的测试

新增 9 条(promo.spec.ts 6 条三态判定、card-promo.spec.tsx 2 条挂载断言、locales.spec.ts 2 条对着真表钉文案)。其中文案测试断言的是 key(row.modelFreeHint / row.promoPending)而不是某句中文——key-preserving 的假翻译器只能钉住「用了哪个 key」,说不出这句话会不会误导人;措辞另由真表断言(「免费」的悬停必须写出判据且不能出现「限时」,灰显前缀必须真的把 {start} 插进去且点明「未生效」)。

三个变异逐个验证过测试真抓得住:窗口外返回 live(退回旧行为)⇒ 5 条红;去掉 windowUnreadable 守卫 ⇒ 1 条红;免费徽标去掉 title ⇒ 1 条红。


完整逐条记录见 CHANGELOG.md。升级方式照旧:更新插件后重启一次 DSH,新卡片即生效。

v1.8.0 — 设置卡片重排:总开关回到它控制的一切之前

Choose a tag to compare

@dingminhua dingminhua released this 23 Oct 06:56

🧭 v1.8.0 — 设置卡片重排:总开关回到它控制的一切之前

这一版是账号池卡片的信息架构重排:把「决定整页怎么读」的开关放回标题下方,把每一句说明贴在它所解释的控件旁边,把重复的话删掉。不改任何行为语义——开关仍然是「点保存才生效」,请求参数、落盘格式、配置键、CLI 与宿主范围全部不动。判据移植自同族 dsh-connect-workbuddy(MIT,同作者)的 94c339f:移植的是判据,不是它的 DOM——qoder 独有的三级账号来源(设置 → 环境变量 → 保险库)按本地现实保留。


一、总开关回到它所控制的一切之前

「启用账号池」原来排在设置卡片里,而设置卡片在成员表之后——于是这个决定整页怎么读的开关,排在它所控制的一切下方约 400px,还排在每一列含义都随它变化的成员表之后(「未入池」只在池负责挑号时才成立)。

现在它是标题正下方的一条模式条:开关 + 运行中的模式(「自动挑号」/「手动选号」)+ 未保存标记。

  • 模式芯片读的是运行态(已保存的偏好),不是草稿。开关显示「你正要改成什么」、脏标记说「还没保存」,那这枚芯片必须回答另一个问题——「池子此刻在做什么」。读草稿会在你拨了开关还没保存时写着「自动挑号」,而保存着的池其实还关着:显示 A、实际记 B。
  • 「谁在服务」只留一个槽位:池关着是选号下拉(搬进标题行右侧),池开着是「当前使用」芯片。同一个账号名此前在一屏上出现三次。qoder 的「自动」是真实第三态(三级回退),不是占位项,这一处没有照抄。
  • 池开着、正在计费的号却不在成员名单里时,模式条下多一句旁注——「在用」与「在池里」是正交的两件事,同框会被读成 bug,解释只在这个状态出现。

二、就近:说明、禁用原因、保存动作都搬回它们作用的地方

  • 批量动作条搬进成员区(标题之后、账号表之前)。条上每个按钮都只对「已选 N / M」声明的集合做事,而那个数字在上一行、被计数的复选框在下一行。禁用原因(「勾选至少一个账号,才能签到与测试」)紧贴两颗被禁用的按钮。
  • 保存条钉在视口底部(position: sticky)。面板比一屏高,而让任何编辑真正生效的两颗按钮原本在它最底部——你改完的那一刻正好在视口之外。
  • 「PAT 从哪来」合成一块,放在添加 PAT 对话框的输入框下方:路径说明与文档外链此前分居两处,各读一半才是完整答案。
  • 「更多设置」分节线:过这条线,页面从「池是什么」转到「改它的旋钮」。

三、删掉的重复与顺带修掉的缺陷

  • 成员行不再复述「已在池中」:勾选框已勾、行底色已标出的行再写一遍是同一件事说第三遍。缺席的那一半才需要文字——空复选框配空的积分列,否则与「勾了但还没数据」分不开。
  • 表下那条琥珀横幅删掉:同一个事实已经写在按钮旁边,300px 之下再来一份更响的副本,只会让页面看起来在两处坏掉。
  • 工具条不再自己念一遍标题(「添加账号」压着同名按钮、「导出 / 导入账号」压着「导出」「导入」)。标题保留在 aria-label 上,屏幕阅读器照样听得到。
  • 桌面宽度下按钮被压成竖排(操作列只有 .88rem 宽,中文可在任意两字之间断行)——加了不换行并收窄内边距。
  • 一条空转的测试:旧断言取的是 indexOf('dsm-qoder-bar-label'),而那个标签已被删掉,indexOf 恒为 -1、断言恒真——它自那时起就一直假绿。已改为按对话框内真实节点顺序断言。

新增 tests/pool-architecture.spec.tsx(11 条)守住这些位置:它直接挂载真实组件,因为「位置搬错」不会让界面渲染失败、也不会让类型检查失败,只有挂载能抓住。


完整逐条记录见 CHANGELOG.md。升级方式照旧:更新插件后重启一次 DSH,新卡片即生效。

v1.7.3 — 设置卡片不再空白,批量 405 不再把你引向错误的修复

Choose a tag to compare

@dingminhua dingminhua released this 23 Oct 06:03

🩹 v1.7.3 — 设置卡片不再空白,批量 405 不再把你引向错误的修复

这一版全是客户端健壮性修复,移植自同族 dsh-connect-workbuddy(MIT,同作者)——qoder 的卡片本就复刻自 workbuddy,上游修过的坑不该在下游重踩。三处都表现为「界面安静地坏了」:没有红横幅、控制台也干净,只是卡片存不了设置、或提示你做一件根本无效的事。宿主侧一行没改。


一、设置卡片整页空白,且没有任何报错

症状:插件列出来是 running,描述和组件行都在,但配置卡片正文一片空白;控制台干净,没有任何错误。

成因:宿主的 settings 镜像由异步 remote.settings.describe() 填充,插件 apply 那一刻它通常还是空的。旧代码把这份「空」当成「我声明的命名空间名一定对」,绑了一个 forms.get(声明名) 之后再也不回看;而宿主按命名空间精确匹配,于是这个猜错的 form 永远停在 unavailable——用户看得见卡片,却存不了任何设置。

修法:改成订阅宿主的 whileServed,等命名空间真正到货才绑定,并重建全部槽位注册(先 dispose 再注册——渲染器按 entry 身份缓存 inject 结果,旧注册留着就一直发旧 props)。即使边缘永不触发(宿主没挂可配置项、settings 面答得晚),也无条件先注册一次:卡片没有 form 也能按只读渲染,那总比不注册强。宿主那条线没有 whileServed 时回退成单次绑定。

顺带修掉两个移植时走样的地方:两个 composer 读数槽漏了 return,disposer 从不被追踪(fiber 拆除时泄漏、重绑时撞「already has an entry」被静默吞掉,读数永远停在第一代闭包);命名空间候选表只监视一种拼写,宿主以 include: 前缀挂载时边缘永不触发、兜底成了死代码。

二、批量接口 405 的误导文案

症状:账号池的签到 / 测试 / 移除返回 405 时,卡片说「请确认插件是最新版本后重试」——可插件已经是最新的。

成因:那种 405 根本不是本插件拒绝该方法,而是宿主进程还在跑更旧的构建、那条路由从未注册,宿主的 HTTP 层在为一个不存在的路由作答。旧文案把用户引向「升级插件」这条走不通的路,真正该做的是重启 DSH。

修法:每条池路由的 handler 都以 JSON 作答(含自身的 405),所以「405 且响应体不可解析」就是宿主路由缺失的指纹。命中时改提示重启应用,并明确否定「重装或升级插件」。以 JSON 作答的 405 仍是「方法不对」,别的状态没有 body 也照旧措辞。

三、这一版的测试

两条改动此前零覆盖,这次补了 17 条。其中 9 条直接 import 真实的 apply()——上游那边导入真实入口会拉进浏览器专属的宿主包,只能测手抄的镜像副本(会随产品漂移而静默失效);qoder 侧实测可以直接 import,所以断言的是产品代码本身。

六个变异逐个跑过验证测试真抓得住:加回早期猜测绑定、去掉两个 return、候选表缩回单一拼写、重绑顺序倒置、去掉 405 限定、去掉 bodyUnreadable 判据——每个都至少一条用例变红。


完整逐条记录见 CHANGELOG.md。升级后请重启一次 DSH(宿主进程需要重新注册路由)。