@eddyskywalker/dsh-chatgpt-subscription 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.53.0 - 2026-11-01
6
+
7
+ - **[dispatch] Mandate v2 头部协议:样板自洽、可直接复制的骨架、会自纠的拒绝文案**
8
+ - **协议自带的样板是非法头部**:`dispatch_ledger {action:"self"}` 打印的派发样板带着 `"grant":null`,被 `kindViolation` 判成"抄错角色"(`a dispatch header must not carry grant`)——模型照协议抄一次被拒一次。样板已去掉该字段,并新增 **PER KIND** 一节写明 dispatch / report / steer 各自携带的字段集;`test/dispatch-ledger-header.test.ts` 新增用例把正文里**每一段围栏**都丢给真解析器,判不出 `ok` 即回归。
9
+ - **`null` 与字段缺失同义**:`parent_mandate` / `grant` 在 schema 里是 `nullable()`,解析器却把 `null` 当成"携带了该字段"。现在 `null` 等价于没写,真的带了值仍按原规则拒绝。
10
+ - **不再要求模型手写 JSON**:`self` 的结果在协议正文之前多打印一段可复制头部——协调者拿到 dispatch 骨架(policy / prompt_ref 已填、ids 每次渲染现造),子代理拿到自己那份 mandate 的 report 头(只差 `status`)。骨架生成后先过 `parseMandateHeader` 自检,非法就不打印;协议正文仍在结果最尾部,值形状与工具声明面不变。
11
+ - **拒绝文案自纠**:任一 kind 违规的 reason 尾部追加"该方向允许携带的字段集",守卫的两条 `MANDATE_KIND` 同样追加,子代理从"逐个字段试错"变成一次往返改对。
12
+ - 授权语义一处未动:命名空间永不重用、血缘、扩权上限、容量判定全部原样。
13
+
14
+ - **[kimi-code] 号池不再“自己切号”:切号不被旧轮询顶回、重登绑定账号、登录不再改写当前选择**
15
+ - **前端旧响应不再覆盖切换结果**:设置卡的 60 s 轮询、可见性回调与额度 follow-up 各发各的 `/status`,一条更早读出、更晚返回的答案会把刚切换的账号顶回旧账号(jsdom 里用真实组件复现:点「设为主账号」后显示新账号,旧答案到达后变回旧账号)。现在每次读取带一个单调代次,只有仍是最新的答案才应用;10 个账号 / 模型 / 额度动作统一走 `applyStatus`,应用自己的答案前先作废在飞读取。守卫只丢弃过期答案,不冻结卡片——新的一轮轮询仍然会生效。
16
+ - **重登绑定到具体那一行**:设备码登录授权的是浏览器里当前登录的账号,而 `/login` 会把拿到的账号直接加进池子——在 A 行点「重新登录」时若浏览器已是 B 账号,就会静默替换 B 并连带移动轮转位置。现在 `/login` 带 `accountId`,按身份键(`userId` 优先,其次邮箱)比对;不一致就终止登录流程并回「重新登录的是 X,本次登录的却是 Y,已取消,号池与凭据都没有改动」。拒绝发生在 `store.write` **之前**(`oauth.ts` 新增的 `accept` 钩子),镜像凭据与号池一个字节都不会被写。
17
+ - **登录不再顺手改写「当前账号」**:`addAccount` 原先在主账号重新登录时把 `activeAccountId` 拉回主账号,所谓“重登之后又切回那个号”就是这一行;现在只有池子从未有过选择时才补位。
18
+ - **`/status` 只读一次号池**:原先 `read()` 拿到 `activeAccountId` 后,`listAccounts()` 内部又读一次,两次之间落一次写就会让同一响应里的「当前账号」和账号列表来自两份快照。新增 `summariesOf(document)`,状态与列表派生自同一份文档。
19
+ - **验证**:新增 `test/kimi-code-switch-race.test.tsx` 钉住「旧答案不得翻盘、新答案仍生效」;新增 `test/kimi-code-relogin-binding.test.ts` 钉住身份不一致被拒(流程 error、账号数不变、`activeAccountId` 不变、镜像文件仍为空)、身份一致则正常替换、普通登录不改选择;`test/account-pool-core.test.ts` 补一条「池子已有选择时加号或重登都不改 `activeAccountId`」。
20
+
21
+ - **验证**
22
+ - `npm run typecheck`(host / client / test / scripts 三工程)0 错误。
23
+ - 全量 `npx vitest run`:**349 files passed / 2 skipped,6170 tests passed / 9 skipped**,exit 0(本次新增 5 条用例)。
24
+ - dispatch 定向复核:`npx vitest run test/dispatch-ledger-{header,tool,guard}.test.ts test/dispatch-model-surface-contract.test.ts` **101 passed**;用真解析器复核旧样板(带 `grant:null`)现判 `ok`,报告头带 `task` 的拒绝串已自带字段集。
25
+
5
26
  ## 0.52.0 - 2026-11-01
6
27
 
7
28
  - **[minimax-code] 请求形状、thinking 回放、缓存守卫与运行时增强对齐官方 agent**
package/lib/client.js CHANGED
@@ -5791,15 +5791,33 @@ window.__ModuleLoader__.load({
5791
5791
  const [compactionPreferences, setCompactionPreferences] = (0, react.useState)(null);
5792
5792
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
5793
5793
  const quotaFollowUp = (0, react.useRef)(null);
5794
+ /**
5795
+ * Which status answer may still be applied.
5796
+ *
5797
+ * A read goes out on a timer, on tab focus and after a quota refresh, and its
5798
+ * answer can land AFTER the answer to a switch the user made in between.
5799
+ * Applying that older document put the previous account back on screen, which
5800
+ * reads as the pool having switched on its own. So every explicit action
5801
+ * retires whatever read is still in flight, and a read applies its answer only
5802
+ * while it is still the newest one.
5803
+ */
5804
+ const statusGeneration = (0, react.useRef)(0);
5805
+ /** Show the answer to an explicit action, and retire any read it outdated. */
5806
+ const applyStatus = (0, react.useCallback)((next) => {
5807
+ statusGeneration.current += 1;
5808
+ setStatus(next);
5809
+ }, []);
5794
5810
  const t = useLineDict(NS_KIMI_CODE, zh$12);
5795
5811
  const notifyChange = (0, react.useCallback)(() => {
5796
5812
  onModelChange?.();
5797
5813
  loadModelDirectory?.();
5798
5814
  }, [onModelChange, loadModelDirectory]);
5799
5815
  const loadStatus = (0, react.useCallback)(async (quiet = false) => {
5816
+ const generation = ++statusGeneration.current;
5800
5817
  if (!quiet) setError(null);
5801
5818
  try {
5802
5819
  const data = await api$14.request("/status");
5820
+ if (generation !== statusGeneration.current) return;
5803
5821
  setStatus(data);
5804
5822
  setContextDrafts(contextDraftsFor(data));
5805
5823
  quotaFollowUp.current ??= createQuotaFollowUp();
@@ -5807,7 +5825,7 @@ window.__ModuleLoader__.load({
5807
5825
  loadStatus(true);
5808
5826
  });
5809
5827
  } catch (err) {
5810
- if (!quiet) setError(err instanceof Error ? err.message : String(err));
5828
+ if (!quiet && generation === statusGeneration.current) setError(err instanceof Error ? err.message : String(err));
5811
5829
  } finally {
5812
5830
  setLoading(false);
5813
5831
  }
@@ -5856,14 +5874,15 @@ window.__ModuleLoader__.load({
5856
5874
  notifyChange,
5857
5875
  t.loginFailed
5858
5876
  ]);
5859
- const handleLogin = async () => {
5877
+ /** Start a sign-in; a re-authorization names the row it must sign back in as. */
5878
+ const handleLogin = async (accountId) => {
5860
5879
  try {
5861
5880
  setBusy("login");
5862
5881
  setError(null);
5863
5882
  setCopied(false);
5864
5883
  const next = await api$14.request("/login", {
5865
5884
  method: "POST",
5866
- body: JSON.stringify({})
5885
+ body: JSON.stringify(accountId === void 0 ? {} : { accountId })
5867
5886
  });
5868
5887
  setFlow(next);
5869
5888
  } catch (err) {
@@ -5901,7 +5920,7 @@ window.__ModuleLoader__.load({
5901
5920
  accountId
5902
5921
  })
5903
5922
  });
5904
- setStatus(updated);
5923
+ applyStatus(updated);
5905
5924
  setFlow({ status: "idle" });
5906
5925
  notifyChange();
5907
5926
  } catch (err) {
@@ -5921,7 +5940,7 @@ window.__ModuleLoader__.load({
5921
5940
  strategy
5922
5941
  })
5923
5942
  });
5924
- setStatus(updated);
5943
+ applyStatus(updated);
5925
5944
  } catch (err) {
5926
5945
  setError(err instanceof Error ? err.message : String(err));
5927
5946
  } finally {
@@ -5944,12 +5963,12 @@ window.__ModuleLoader__.load({
5944
5963
  accountId
5945
5964
  })
5946
5965
  });
5947
- setStatus(updated);
5966
+ applyStatus(updated);
5948
5967
  } catch (err) {
5949
5968
  setError(err instanceof Error ? err.message : String(err));
5950
5969
  return;
5951
5970
  }
5952
- await handleLogin();
5971
+ await handleLogin(accountId);
5953
5972
  })();
5954
5973
  };
5955
5974
  const handleRefreshQuota = async () => {
@@ -5957,7 +5976,7 @@ window.__ModuleLoader__.load({
5957
5976
  setBusy("quota");
5958
5977
  setError(null);
5959
5978
  const updated = await api$14.request("/quota", { method: "POST" });
5960
- setStatus(updated);
5979
+ applyStatus(updated);
5961
5980
  } catch (err) {
5962
5981
  setError(err instanceof Error ? err.message : String(err));
5963
5982
  await loadStatus(true);
@@ -5970,7 +5989,7 @@ window.__ModuleLoader__.load({
5970
5989
  setBusy("catalog");
5971
5990
  setError(null);
5972
5991
  const updated = await api$14.request("/catalog/refresh", { method: "POST" });
5973
- setStatus(updated);
5992
+ applyStatus(updated);
5974
5993
  setContextDrafts(contextDraftsFor(updated));
5975
5994
  notifyChange();
5976
5995
  } catch (err) {
@@ -5999,7 +6018,7 @@ window.__ModuleLoader__.load({
5999
6018
  method: "POST",
6000
6019
  body: JSON.stringify({ enabledModelIds })
6001
6020
  });
6002
- setStatus(updated);
6021
+ applyStatus(updated);
6003
6022
  setContextDrafts(contextDraftsFor(updated));
6004
6023
  notifyChange();
6005
6024
  } catch (err) {
@@ -6022,7 +6041,7 @@ window.__ModuleLoader__.load({
6022
6041
  method: "POST",
6023
6042
  body: JSON.stringify({ defaultReasoningEffort: effort })
6024
6043
  });
6025
- setStatus(updated);
6044
+ applyStatus(updated);
6026
6045
  notifyChange();
6027
6046
  } catch (err) {
6028
6047
  setError(err instanceof Error ? err.message : String(err));
@@ -6042,7 +6061,7 @@ window.__ModuleLoader__.load({
6042
6061
  method: "POST",
6043
6062
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
6044
6063
  });
6045
- setStatus(updated);
6064
+ applyStatus(updated);
6046
6065
  setContextDrafts((prev) => ({
6047
6066
  ...prev,
6048
6067
  [modelId]: formatCapacity$1(parsed)
@@ -6063,7 +6082,7 @@ window.__ModuleLoader__.load({
6063
6082
  method: "POST",
6064
6083
  body: JSON.stringify({ contextWindowOverrides: { [modelId]: null } })
6065
6084
  });
6066
- setStatus(updated);
6085
+ applyStatus(updated);
6067
6086
  setContextDrafts((prev) => {
6068
6087
  const model = updated.models.find((candidate) => candidate.id === modelId);
6069
6088
  return model === void 0 ? prev : {
@@ -6090,7 +6109,7 @@ window.__ModuleLoader__.load({
6090
6109
  method: "POST",
6091
6110
  body: JSON.stringify({ contextWindowOverrides: Object.fromEntries(models.map((model) => [model, null])) })
6092
6111
  });
6093
- setStatus(updated);
6112
+ applyStatus(updated);
6094
6113
  setContextDrafts(contextDraftsFor(updated));
6095
6114
  notifyChange();
6096
6115
  } catch (err) {