dsh-codex-subscription 2.2.8 → 2.2.10

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/README.en.md CHANGED
@@ -31,7 +31,7 @@ Subscription access, model controls, quota management, and image creation in one
31
31
  | Feature | What you can do | Availability / setup |
32
32
  | --- | --- | --- |
33
33
  | **Subscription sign-in** | Sign in to ChatGPT and use Codex subscription models without an API key | Normal chat needs no Codex CLI |
34
- | **Model catalog sync** | Read available models and reasoning levels from your account, with manual refresh; models marked for retirement show their retirement date next to the model name, without automatically switching your selection | New models appear when your account offers them |
34
+ | **Model catalog sync** | Read available models and reasoning levels from your account, with manual refresh; models marked for retirement show their retirement date next to the model name, without automatically switching your selection | New models appear when your account offers them; the account catalog is the only source, so signed out or when it cannot be read no models are shown and no bundled list stands in |
35
35
  | **Model list** | Show or hide individual models in the composer picker under Models & runtime | Display only; selected models and requests still work |
36
36
  | **Reasoning levels** | Choose supported reasoning effort in the composer | Levels vary by model |
37
37
  | **Fast mode** | Switch supported models between Standard and Fast, with a lightning indicator | Standard by default; Fast increases usage |
@@ -88,11 +88,12 @@ Subscription access, model controls, quota management, and image creation in one
88
88
 
89
89
  ## Prepare DSH
90
90
 
91
- Verified against DSH `0.2.0-rc.1` (`next` channel) and `0.1.7-rc.2` (`latest` channel), with earlier accepted versions still supported.
91
+ Verified against DSH `0.2.0-rc.2` (`next` channel) and `0.1.7-rc.2` (`latest` channel), with earlier accepted versions still supported.
92
92
 
93
93
  This plugin supports the latest DeepSeek Harness release recorded in its package metadata and requires a ChatGPT account that currently has Codex access.
94
94
 
95
- - Do not want to configure Node.js? Use [DSH-Portable](https://github.com/WSL043/DSH-Portable), a community portable desktop distribution for Windows, macOS, and Linux.
95
+ - **Recommended: the official desktop app.** DeepSeek now ships a [DeepSeek Harness desktop app](https://www.deepseek.com/harness/) (macOS on Apple Silicon and 64-bit Windows; preview, open source). It needs no Node.js setup: install it, then add this plugin from the Plugins page as described below. The desktop app, the web app and the CLI share one DSH plugin system; this plugin's end-to-end acceptance is mainly run on the web app, so please [open an issue](https://github.com/WSL043/dsh-codex-subscription/issues) if the desktop app misbehaves.
96
+ - Need Linux, or prefer a community portable build? Use [DSH-Portable](https://github.com/WSL043/DSH-Portable), a community portable desktop distribution for Windows, macOS, and Linux.
96
97
  - Prefer the official route? Follow the [DeepSeek Harness run guide](https://github.com/deepseek-ai/deepseek-harness#run).
97
98
 
98
99
  ## Install
@@ -272,9 +273,9 @@ dsh plugin --profile web remove dsh-codex-subscription
272
273
  ## Troubleshooting
273
274
 
274
275
  <details>
275
- <summary>DSH 0.2.0-rc.1 reports plugin 2.2.4 as incompatible?</summary>
276
+ <summary>DSH 0.2.0-rc.2 reports plugin 2.2.4 as incompatible?</summary>
276
277
 
277
- DSH 0.2.0-rc.1 did not exist when 2.2.4 and earlier were published, and a published package's compatibility declaration cannot be changed. Update to 2.2.5 or later from the **Plugins** page, or run `dsh plugin --profile web update dsh-codex-subscription`, then restart DSH.
278
+ DSH 0.2.0-rc.2 did not exist when 2.2.4 and earlier were published, and a published package's compatibility declaration cannot be changed. Update to 2.2.5 or later from the **Plugins** page, or run `dsh plugin --profile web update dsh-codex-subscription`, then restart DSH.
278
279
 
279
280
  </details>
280
281
 
package/README.md CHANGED
@@ -31,7 +31,7 @@
31
31
  | 功能 | 你可以做什么 | 使用方式 / 条件 |
32
32
  | --- | --- | --- |
33
33
  | **订阅登录** | 直接登录 ChatGPT,使用 Codex 订阅模型,无需 API Key | 普通聊天无需 Codex CLI |
34
- | **模型目录同步** | 自动读取账号可用模型与推理档位,支持手动刷新;目录标注退役的模型会在模型名称旁显示退役日期,不会自动切换你的选择 | 新型号以账号目录开放情况为准 |
34
+ | **模型目录同步** | 自动读取账号可用模型与推理档位,支持手动刷新;目录标注退役的模型会在模型名称旁显示退役日期,不会自动切换你的选择 | 新型号以账号目录开放情况为准;模型只来自账号目录,未登录或读取失败时不显示任何模型,也不使用内置列表 |
35
35
  | **模型列表** | 在“模型与运行”中逐个显示或隐藏输入框中的模型 | 仅影响列表显示;已选模型和请求不受影响 |
36
36
  | **推理等级** | 在输入框选择模型支持的推理档位 | 档位随模型变化 |
37
37
  | **高速模式** | 在支持的模型上切换标准 / Fast,输入框显示闪电标识 | 默认标准;Fast 会增加用量消耗 |
@@ -88,11 +88,12 @@
88
88
 
89
89
  ## 准备 DSH
90
90
 
91
- 已验证兼容 DSH `0.2.0-rc.1`(`next` 通道)和 `0.1.7-rc.2`(`latest` 通道),并继续支持更早的已验收版本。
91
+ 已验证兼容 DSH `0.2.0-rc.2`(`next` 通道)和 `0.1.7-rc.2`(`latest` 通道),并继续支持更早的已验收版本。
92
92
 
93
93
  本插件支持软件包元数据中记录的最新版 DeepSeek Harness,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
94
94
 
95
- - 不想配置 Node.js:使用 [DSH-Portable](https://github.com/WSL043/DSH-Portable)。这是面向 Windows、macOS 和 Linux 的社区便携桌面分发;
95
+ - **推荐:官方桌面端**。DeepSeek 已发布 [DeepSeek Harness 桌面版](https://www.deepseek.com/harness/)(macOS Apple Silicon、Windows 64 位,预览版、开源),无需配置 Node.js,安装后按下文在插件页面添加本插件即可。桌面端与网页版、命令行使用同一套 DSH 插件系统;本插件的端到端验收主要在网页版上完成,桌面端遇到问题请[提交 issue](https://github.com/WSL043/dsh-codex-subscription/issues);
96
+ - 需要 Linux,或想要社区便携分发:使用 [DSH-Portable](https://github.com/WSL043/DSH-Portable)。这是面向 Windows、macOS 和 Linux 的社区便携桌面分发;
96
97
  - 想按官方方式运行:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
97
98
 
98
99
  ## 安装
@@ -272,9 +273,9 @@ dsh plugin --profile web remove dsh-codex-subscription
272
273
  ## 常见问题
273
274
 
274
275
  <details>
275
- <summary>DSH 0.2.0-rc.1 提示插件 2.2.4 不兼容?</summary>
276
+ <summary>DSH 0.2.0-rc.2 提示插件 2.2.4 不兼容?</summary>
276
277
 
277
- 2.2.4 及更早版本发布时 DSH 0.2.0-rc.1 还不存在,其兼容声明无法事后修改。请更新到 2.2.5 或更高版本:在 **插件** 页面更新,或运行 `dsh plugin --profile web update dsh-codex-subscription`,然后重启 DSH。
278
+ 2.2.4 及更早版本发布时 DSH 0.2.0-rc.2 还不存在,其兼容声明无法事后修改。请更新到 2.2.5 或更高版本:在 **插件** 页面更新,或运行 `dsh plugin --profile web update dsh-codex-subscription`,然后重启 DSH。
278
279
 
279
280
  </details>
280
281
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "latestTested": "0.2.0-rc.1",
2
+ "latestTested": "0.2.0-rc.2",
3
3
  "supported": [
4
4
  "0.1.2-rc.1",
5
5
  "0.1.5-rc.1",
@@ -7,7 +7,8 @@
7
7
  "0.1.5-rc.3",
8
8
  "0.1.7-rc.1",
9
9
  "0.1.7-rc.2",
10
- "0.2.0-rc.1"
10
+ "0.2.0-rc.1",
11
+ "0.2.0-rc.2"
11
12
  ],
12
13
  "previews": [
13
14
  "0.1.5-alpha.1",
package/lib/client.js CHANGED
@@ -4537,6 +4537,7 @@ window.__ModuleLoader__.load({
4537
4537
  //#region src/client-primitives.js
4538
4538
  const Input = _deepseek_ai_dsh_client_ui_primitives.Input;
4539
4539
  const Button = _deepseek_ai_dsh_client_ui_primitives.Button;
4540
+ const Switch = _deepseek_ai_dsh_client_ui_primitives.Switch;
4540
4541
  const useAnchoredPosition = _deepseek_ai_dsh_client_ui_primitives.useAnchoredPosition;
4541
4542
  const useDismissOnOutsidePointer = _deepseek_ai_dsh_client_ui_primitives.useDismissOnOutsidePointer;
4542
4543
  const IconCheckOutline16 = _deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16 ?? _deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular;
@@ -4659,7 +4660,7 @@ window.__ModuleLoader__.load({
4659
4660
  "diagnosticReason_inspection-timeout": "检查超时",
4660
4661
  "diagnosticSource_network": "网络请求(非完整回复)",
4661
4662
  "diagnosticReason_catalog-online": "在线目录已载入",
4662
- "diagnosticReason_catalog-fallback": "使用备用目录",
4663
+ "diagnosticReason_catalog-unavailable": "尚未读取账户目录",
4663
4664
  "diagnosticReason_storage-readable": "预测缓存可读",
4664
4665
  "diagnosticReason_tool-registered": "全局工具已注册",
4665
4666
  "diagnosticReason_tool-missing": "未找到全局工具",
@@ -4737,6 +4738,8 @@ window.__ModuleLoader__.load({
4737
4738
  compaction_cloud: "开启",
4738
4739
  compactionHint: "实验功能,默认关闭。长上下文由 Codex 压缩后继续请求,保留 DSH 历史与原生压缩。开启时该请求使用 SSE;历史改变后重新建立压缩状态。",
4739
4740
  advancedModelSearch: "模型与搜索",
4741
+ modelsSectionTitle: "模型",
4742
+ searchSectionTitle: "搜索",
4740
4743
  inputImageDetail: "输入图片精度",
4741
4744
  inputImageDetailHint: "控制发送给模型的图片精度,精度越高输入 token 用量越大。",
4742
4745
  inputImageDetail_auto: "自动",
@@ -4929,7 +4932,9 @@ window.__ModuleLoader__.load({
4929
4932
  searchDomainCount: "个域名",
4930
4933
  catalogRefresh: "刷新模型",
4931
4934
  catalogOnline: "已加载账户在线模型目录",
4932
- catalogFallback: "当前使用内置模型目录;登录后可刷新账户可用模型",
4935
+ catalogSignedOut: "登录后显示账户可用的模型。",
4936
+ catalogLoading: "正在读取账户模型目录…",
4937
+ catalogFailed: "无法读取账户模型目录,请检查网络后重试。",
4933
4938
  pickerModelsTitle: "输入框模型列表",
4934
4939
  pickerModelsHint: "只控制输入框中的模型列表;不会影响已选模型或模型请求。新模型默认显示。",
4935
4940
  searchMode: "订阅搜索模式",
@@ -5148,7 +5153,7 @@ window.__ModuleLoader__.load({
5148
5153
  providerDefault: "Default",
5149
5154
  selectModel: "选择模型",
5150
5155
  modelsLoading: "正在读取模型…",
5151
- modelsEmpty: "没有可用模型。",
5156
+ modelsEmpty: "没有可用模型;请先登录,并确认网络可用。",
5152
5157
  modelsHidden: "所有模型都已从列表中隐藏;可在设置中重新显示。",
5153
5158
  effortsEmpty: "当前模型未提供推理等级。",
5154
5159
  modelRetry: "重试",
@@ -5210,7 +5215,7 @@ window.__ModuleLoader__.load({
5210
5215
  "diagnosticReason_inspection-timeout": "Check timed out",
5211
5216
  "diagnosticSource_network": "Network request (not full reply)",
5212
5217
  "diagnosticReason_catalog-online": "Online catalog loaded",
5213
- "diagnosticReason_catalog-fallback": "Fallback catalog",
5218
+ "diagnosticReason_catalog-unavailable": "Account catalog not loaded",
5214
5219
  "diagnosticReason_storage-readable": "Forecast cache readable",
5215
5220
  "diagnosticReason_tool-registered": "Global tool registered",
5216
5221
  "diagnosticReason_tool-missing": "Global tool not found",
@@ -5288,6 +5293,8 @@ window.__ModuleLoader__.load({
5288
5293
  compaction_cloud: "On",
5289
5294
  compactionHint: "Experimental, off by default. Codex compacts long requests while DSH history and native compaction remain available. These requests use SSE; changed history invalidates previous checkpoints.",
5290
5295
  advancedModelSearch: "Models and search",
5296
+ modelsSectionTitle: "Models",
5297
+ searchSectionTitle: "Search",
5291
5298
  inputImageDetail: "Input image detail",
5292
5299
  inputImageDetailHint: "Controls the detail level of images sent to the model. Higher detail uses more input tokens.",
5293
5300
  inputImageDetail_auto: "Auto",
@@ -5480,7 +5487,9 @@ window.__ModuleLoader__.load({
5480
5487
  searchDomainCount: "domains",
5481
5488
  catalogRefresh: "Refresh models",
5482
5489
  catalogOnline: "Account model catalog loaded",
5483
- catalogFallback: "Using the built-in catalog. Sign in to refresh account models.",
5490
+ catalogSignedOut: "Sign in to show the models your account can use.",
5491
+ catalogLoading: "Reading the account model catalog…",
5492
+ catalogFailed: "Could not read the account model catalog. Check the network and try again.",
5484
5493
  pickerModelsTitle: "Models in picker",
5485
5494
  pickerModelsHint: "Only controls the composer model list. Selected models and requests still work. New models appear by default.",
5486
5495
  searchMode: "Subscription search mode",
@@ -5699,7 +5708,7 @@ window.__ModuleLoader__.load({
5699
5708
  providerDefault: "Default",
5700
5709
  selectModel: "Select model",
5701
5710
  modelsLoading: "Loading models…",
5702
- modelsEmpty: "No models available.",
5711
+ modelsEmpty: "No models available. Sign in and make sure the network is reachable.",
5703
5712
  modelsHidden: "All models are hidden from this list. Show one in settings.",
5704
5713
  effortsEmpty: "This model provides no reasoning effort levels.",
5705
5714
  modelRetry: "Retry",
@@ -5780,12 +5789,6 @@ window.__ModuleLoader__.load({
5780
5789
  .codexSubscriptionPreferenceCopy{display:flex;min-width:0;flex-direction:column;gap:2px}
5781
5790
  .codexSubscriptionPreferenceLabel{display:flex;align-items:center;gap:6px}
5782
5791
  .codexSubscriptionPreferenceHint{max-width:300px;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
5783
- .codexSubscriptionSwitch{position:relative;flex:none;width:36px;height:20px;padding:2px;border:0;border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer;transition:background 120ms var(--ds-ease-in-out)}
5784
- .codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-primary)}
5785
- .codexSubscriptionSwitch:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
5786
- .codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}
5787
- .codexSubscriptionSwitchKnob{display:block;width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);box-shadow:0 1px 2px var(--dsw-alias-border-l3);transition:transform 120ms var(--ds-ease-in-out)}
5788
- .codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(16px)}
5789
5792
  .codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}
5790
5793
  .codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer;white-space:nowrap}
5791
5794
  .codexSubscriptionQuotaMode small{margin-left:3px;font-size:9px;line-height:1;color:var(--dsw-alias-label-tertiary)}
@@ -5794,7 +5797,8 @@ window.__ModuleLoader__.load({
5794
5797
  .codexSubscriptionQuotaMode:has(input:disabled){cursor:not-allowed;opacity:.5}
5795
5798
  .codexSubscriptionQuotaMode input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
5796
5799
  .codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}
5797
- .codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
5800
+ .codexSubscriptionPickerSetting{display:flex;flex-direction:column;gap:8px}
5801
+ .codexSubscriptionContextHead{font-size:13px;line-height:20px;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}
5798
5802
  .codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}
5799
5803
  .codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
5800
5804
  .codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}
@@ -5858,6 +5862,10 @@ window.__ModuleLoader__.load({
5858
5862
  .codexSubscriptionLimitMeta{display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
5859
5863
  .codexSubscriptionLimitPeriod{display:flex;gap:8px;flex-wrap:wrap}
5860
5864
  .codexSubscriptionSearchOptions{margin-top:10px;font-size:12px}
5865
+ .codexSubscriptionDivider+.codexSubscriptionDivider{display:none}
5866
+ .codexSubscriptionPickerModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}
5867
+ .codexSubscriptionPickerModel{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:36px;border-bottom:1px solid var(--dsw-alias-border-l2);font-size:13px}
5868
+ .codexSubscriptionPickerModel:last-child{border-bottom:0}
5861
5869
  .codexSubscriptionSearchOptions>summary{cursor:pointer;color:var(--dsw-alias-label-primary);padding:6px 0}
5862
5870
  .codexSubscriptionSearchOptions>summary>span{float:right;color:var(--dsw-alias-label-tertiary)}
5863
5871
  .codexSubscriptionSearchOptions[open]>summary{margin-bottom:8px}
@@ -7652,7 +7660,7 @@ window.__ModuleLoader__.load({
7652
7660
  }
7653
7661
  //#endregion
7654
7662
  //#region src/version.js
7655
- const PACKAGE_VERSION = "2.2.8";
7663
+ const PACKAGE_VERSION = "2.2.10";
7656
7664
  //#endregion
7657
7665
  //#region src/client-recovery.js
7658
7666
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -7921,8 +7929,9 @@ window.__ModuleLoader__.load({
7921
7929
  const hidden = new Set(preferenceSnapshot.disabledModels);
7922
7930
  return state.groups.map((group) => group.id === "openai-codex" ? {
7923
7931
  ...group,
7924
- models: group.models.filter((model) => !hidden.has(model.id))
7925
- } : group).filter((group) => group.models.length > 0);
7932
+ models: group.models.filter((model) => !hidden.has(model.id)),
7933
+ allHidden: group.models.length > 0 && group.models.every((model) => hidden.has(model.id))
7934
+ } : group).filter((group) => group.models.length > 0 || group.allHidden === true);
7926
7935
  }, [state.groups, preferenceSnapshot.disabledModels]);
7927
7936
  const currentChoice = choices.find((choice) => choice.selection.provider === state.current?.provider && choice.selection.model === state.current?.model);
7928
7937
  const reasoning = currentChoice?.model.reasoning;
@@ -8099,21 +8108,28 @@ window.__ModuleLoader__.load({
8099
8108
  className: "codexModelSelectGroup",
8100
8109
  role: "group",
8101
8110
  "aria-labelledby": `${id}-${group.id}`,
8102
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8103
- className: "codexModelSelectGroupTitle",
8104
- id: `${id}-${group.id}`,
8105
- children: group.name
8106
- }), group.models.map((model) => option({
8107
- key: model.id,
8108
- label: model.name,
8109
- description: model.description,
8110
- selected: state.current?.provider === group.id && state.current.model === model.id,
8111
- disabled: busy,
8112
- onClick: () => chooseModel({
8113
- provider: group.id,
8114
- model: model.id
8115
- })
8116
- }))]
8111
+ children: [
8112
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8113
+ className: "codexModelSelectGroupTitle",
8114
+ id: `${id}-${group.id}`,
8115
+ children: group.name
8116
+ }),
8117
+ group.allHidden === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8118
+ className: "codexModelSelectEmpty",
8119
+ children: t("modelsHidden")
8120
+ }) : null,
8121
+ group.models.map((model) => option({
8122
+ key: model.id,
8123
+ label: model.name,
8124
+ description: model.description,
8125
+ selected: state.current?.provider === group.id && state.current.model === model.id,
8126
+ disabled: busy,
8127
+ onClick: () => chooseModel({
8128
+ provider: group.id,
8129
+ model: model.id
8130
+ })
8131
+ }))
8132
+ ]
8117
8133
  }, group.id))
8118
8134
  }),
8119
8135
  state.status === "ready" && visibleGroups.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -8706,6 +8722,21 @@ window.__ModuleLoader__.load({
8706
8722
  return next;
8707
8723
  }
8708
8724
  //#endregion
8725
+ //#region src/picker-draft.js
8726
+ const toggleModelId = (draft, modelId) => draft.includes(modelId) ? draft.filter((id) => id !== modelId) : [...draft, modelId];
8727
+ /**
8728
+ * What to do with the draft after a render.
8729
+ * - adopt: nothing pending, follow the saved value
8730
+ * - wait: a change is pending but a write is still in flight
8731
+ * - save: send the draft
8732
+ * - settled: the pending change already equals the saved value
8733
+ */
8734
+ function draftStep({ dirty, writable, draft, saved }) {
8735
+ if (!dirty) return "adopt";
8736
+ if (!writable) return "wait";
8737
+ return JSON.stringify(draft) === JSON.stringify(saved) ? "settled" : "save";
8738
+ }
8739
+ //#endregion
8709
8740
  //#region src/client-preferences.jsx
8710
8741
  function QuickQuotaPreference({ preference, t }) {
8711
8742
  const snapshot = usePreferenceSnapshot(preference);
@@ -8766,17 +8797,13 @@ window.__ModuleLoader__.load({
8766
8797
  className: "codexSubscriptionPreferenceHint",
8767
8798
  children: t("autoQuotaRetryHint")
8768
8799
  })]
8769
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8770
- className: "codexSubscriptionSwitch",
8771
- type: "button",
8772
- role: "switch",
8773
- "aria-label": t("autoQuotaRetry"),
8774
- "aria-checked": snapshot.autoQuotaRetry,
8800
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Switch, {
8801
+ checked: snapshot.autoQuotaRetry,
8802
+ label: t("autoQuotaRetry"),
8775
8803
  disabled: !writable,
8776
- onClick: () => {
8777
- preference.set({ [AUTO_QUOTA_RETRY_FIELD]: !snapshot.autoQuotaRetry });
8778
- },
8779
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "codexSubscriptionSwitchKnob" })
8804
+ onChange: (next) => {
8805
+ preference.set({ [AUTO_QUOTA_RETRY_FIELD]: next });
8806
+ }
8780
8807
  })]
8781
8808
  });
8782
8809
  }
@@ -8898,47 +8925,77 @@ window.__ModuleLoader__.load({
8898
8925
  })]
8899
8926
  });
8900
8927
  }
8901
- /** Show every account model while saving which entries the composer picker hides. */
8928
+ /**
8929
+ * Show every account model while saving which entries the composer picker hides.
8930
+ * The controller ignores a write while another is saving, so quick toggles are kept
8931
+ * in a local draft and sent as one write once the previous one has settled.
8932
+ */
8902
8933
  function PickerModelsPreference({ preference, t }) {
8903
8934
  const snapshot = usePreferenceSnapshot(preference);
8904
- const writable = snapshot.status === "ready" && snapshot.writable === true;
8905
- const hidden = snapshot.disabledModels;
8935
+ const ready = snapshot.status === "ready" && (snapshot.writable === true || snapshot.saving === true);
8936
+ const saved = snapshot.disabledModels;
8937
+ const [draft, setDraft] = (0, react.useState)(saved);
8938
+ const [open, setOpen] = (0, react.useState)(false);
8939
+ const dirty = (0, react.useRef)(false);
8940
+ (0, react.useEffect)(() => {
8941
+ const step = draftStep({
8942
+ dirty: dirty.current,
8943
+ writable: snapshot.writable === true,
8944
+ draft,
8945
+ saved
8946
+ });
8947
+ if (step === "adopt") setDraft(saved);
8948
+ else if (step === "save" || step === "settled") dirty.current = false;
8949
+ if (step === "save") preference.set({ [DISABLED_MODELS_FIELD]: draft });
8950
+ }, [
8951
+ draft,
8952
+ saved.join(" "),
8953
+ snapshot.writable
8954
+ ]);
8906
8955
  const toggle = (modelId) => {
8907
- const next = hidden.includes(modelId) ? hidden.filter((id) => id !== modelId) : [...hidden, modelId];
8908
- preference.set({ [DISABLED_MODELS_FIELD]: next });
8956
+ dirty.current = true;
8957
+ setDraft((current) => toggleModelId(current, modelId));
8909
8958
  };
8959
+ const shown = snapshot.availableModels.filter((model) => !draft.includes(model.id)).length;
8960
+ if (snapshot.availableModels.length === 0) return null;
8910
8961
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8911
- className: "codexSubscriptionContext",
8962
+ className: "codexSubscriptionPickerSetting",
8912
8963
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8913
- className: "codexSubscriptionContextCopy",
8914
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8915
- className: "codexSubscriptionPreferenceLabel",
8916
- children: t("pickerModelsTitle")
8917
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8918
- className: "codexSubscriptionContextHint",
8919
- children: t("pickerModelsHint")
8964
+ className: "codexSubscriptionPreference",
8965
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8966
+ className: "codexSubscriptionPreferenceCopy",
8967
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8968
+ className: "codexSubscriptionPreferenceLabel",
8969
+ children: t("pickerModelsTitle")
8970
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8971
+ className: "codexSubscriptionPreferenceHint",
8972
+ children: t("pickerModelsHint")
8973
+ })]
8974
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8975
+ className: "codexSubscriptionContextTrigger",
8976
+ type: "button",
8977
+ "aria-expanded": open,
8978
+ onClick: () => setOpen((value) => !value),
8979
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
8980
+ shown,
8981
+ " / ",
8982
+ snapshot.availableModels.length
8983
+ ] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {})]
8920
8984
  })]
8921
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8922
- className: "codexSubscriptionContextModels",
8985
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8986
+ className: "codexSubscriptionPickerModels",
8923
8987
  role: "group",
8924
8988
  "aria-label": t("pickerModelsTitle"),
8925
8989
  children: snapshot.availableModels.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8926
- className: "codexSubscriptionContextModel",
8927
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8928
- className: "codexSubscriptionContextModelCopy",
8929
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.name })
8930
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8931
- className: "codexSubscriptionSwitch",
8932
- type: "button",
8933
- role: "switch",
8934
- "aria-label": model.name,
8935
- "aria-checked": !hidden.includes(model.id),
8936
- disabled: !writable,
8937
- onClick: () => toggle(model.id),
8938
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "codexSubscriptionSwitchKnob" })
8990
+ className: "codexSubscriptionPickerModel",
8991
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Switch, {
8992
+ checked: !draft.includes(model.id),
8993
+ label: model.name,
8994
+ disabled: !ready,
8995
+ onChange: () => toggle(model.id)
8939
8996
  })]
8940
8997
  }, model.id))
8941
- })]
8998
+ }) : null]
8942
8999
  });
8943
9000
  }
8944
9001
  function ContextWindowPreference({ preference, t }) {
@@ -8995,110 +9052,112 @@ window.__ModuleLoader__.load({
8995
9052
  }
8996
9053
  ];
8997
9054
  const selectedMode = contextModeItems.find((item) => item.id === snapshot.contextMode)?.label ?? t("contextStandard");
9055
+ if (snapshot.contextModels.length === 0) return null;
8998
9056
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8999
9057
  className: "codexSubscriptionContext",
9000
- children: [
9001
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9002
- className: "codexSubscriptionContextHead",
9003
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9004
- className: "codexSubscriptionContextCopy",
9005
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9006
- className: "codexSubscriptionPreferenceLabel",
9007
- children: t("contextTitle")
9008
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9009
- className: "codexSubscriptionContextHint",
9010
- children: hint
9011
- })]
9012
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
9013
- open: menuOpen,
9014
- items: contextModeItems,
9015
- selectedId: snapshot.contextMode,
9016
- onSelect: (value) => {
9017
- setMenuOpen(false);
9018
- preference.set({ [CONTEXT_MODE_FIELD]: value });
9019
- },
9020
- onClose: () => setMenuOpen(false),
9021
- align: "end",
9022
- side: "bottom",
9023
- portal: true,
9024
- compact: true,
9025
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9026
- className: "codexSubscriptionContextTrigger",
9027
- type: "button",
9028
- "aria-label": t("contextTitle"),
9029
- "aria-haspopup": "menu",
9030
- "aria-expanded": menuOpen,
9031
- disabled: !writable,
9032
- onClick: () => setMenuOpen((value) => !value),
9033
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selectedMode }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {})]
9034
- })
9035
- })]
9036
- }),
9037
- snapshot.contextMode === "custom" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9038
- className: "codexSubscriptionContextModels",
9039
- children: [modelRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9040
- className: "codexSubscriptionContextModel",
9041
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9042
- className: "codexSubscriptionContextModelCopy",
9043
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextMaximum"), {
9044
- minimum: String(Math.min(MIN_CUSTOM_CONTEXT_WINDOW, model.maximum)),
9045
- value: String(model.maximum)
9046
- }) })]
9047
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
9048
- "aria-label": `${model.label} ${t("contextTokens")}`,
9049
- className: "codexSubscriptionContextInput",
9050
- type: "number",
9051
- inputMode: "numeric",
9052
- min: Math.min(MIN_CUSTOM_CONTEXT_WINDOW, model.maximum),
9053
- max: model.maximum,
9054
- step: 1,
9055
- value: drafts[model.key] ?? "",
9056
- disabled: !writable,
9057
- onChange: (event) => {
9058
- const nextValue = event.currentTarget.value;
9059
- setDrafts((current) => ({
9060
- ...current,
9061
- [model.key]: nextValue
9062
- }));
9063
- },
9064
- onBlur: () => commit(model.key),
9065
- onKeyDown: (event) => {
9066
- if (event.key === "Enter") event.currentTarget.blur();
9067
- }
9068
- })]
9069
- }, model.key)), fixedRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9070
- className: "codexSubscriptionContextModel",
9071
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9072
- className: "codexSubscriptionContextModelCopy",
9073
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextFixed"), { value: formatContextWindow(model.maximum) }) })]
9074
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9075
- className: "codexSubscriptionContextHint",
9076
- children: formatContextWindow(model.maximum)
9077
- })]
9078
- }, model.key))]
9079
- }) : null,
9080
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9081
- className: "codexSubscriptionPreference",
9058
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9059
+ className: "codexSubscriptionContextHead",
9060
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9061
+ className: "codexSubscriptionContextCopy",
9082
9062
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9083
- className: "codexSubscriptionPreferenceHint",
9084
- children: t(snapshot.catalogStatus?.source === "online" ? "catalogOnline" : "catalogFallback")
9085
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
9063
+ className: "codexSubscriptionPreferenceLabel",
9064
+ children: t("contextTitle")
9065
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9066
+ className: "codexSubscriptionContextHint",
9067
+ children: hint
9068
+ })]
9069
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
9070
+ open: menuOpen,
9071
+ items: contextModeItems,
9072
+ selectedId: snapshot.contextMode,
9073
+ onSelect: (value) => {
9074
+ setMenuOpen(false);
9075
+ preference.set({ [CONTEXT_MODE_FIELD]: value });
9076
+ },
9077
+ onClose: () => setMenuOpen(false),
9078
+ align: "end",
9079
+ side: "bottom",
9080
+ portal: true,
9081
+ compact: true,
9082
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9083
+ className: "codexSubscriptionContextTrigger",
9086
9084
  type: "button",
9087
- variant: "outline",
9088
- disabled: snapshot.modelsLoading,
9089
- "aria-busy": snapshot.modelsLoading,
9090
- onClick: () => {
9091
- preference.refreshModels();
9085
+ "aria-label": t("contextTitle"),
9086
+ "aria-haspopup": "menu",
9087
+ "aria-expanded": menuOpen,
9088
+ disabled: !writable,
9089
+ onClick: () => setMenuOpen((value) => !value),
9090
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selectedMode }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {})]
9091
+ })
9092
+ })]
9093
+ }), snapshot.contextMode === "custom" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9094
+ className: "codexSubscriptionContextModels",
9095
+ children: [modelRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9096
+ className: "codexSubscriptionContextModel",
9097
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9098
+ className: "codexSubscriptionContextModelCopy",
9099
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextMaximum"), {
9100
+ minimum: String(Math.min(MIN_CUSTOM_CONTEXT_WINDOW, model.maximum)),
9101
+ value: String(model.maximum)
9102
+ }) })]
9103
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Input, {
9104
+ "aria-label": `${model.label} ${t("contextTokens")}`,
9105
+ className: "codexSubscriptionContextInput",
9106
+ type: "number",
9107
+ inputMode: "numeric",
9108
+ min: Math.min(MIN_CUSTOM_CONTEXT_WINDOW, model.maximum),
9109
+ max: model.maximum,
9110
+ step: 1,
9111
+ value: drafts[model.key] ?? "",
9112
+ disabled: !writable,
9113
+ onChange: (event) => {
9114
+ const nextValue = event.currentTarget.value;
9115
+ setDrafts((current) => ({
9116
+ ...current,
9117
+ [model.key]: nextValue
9118
+ }));
9092
9119
  },
9093
- children: t(snapshot.modelsLoading ? "refreshing" : "catalogRefresh")
9120
+ onBlur: () => commit(model.key),
9121
+ onKeyDown: (event) => {
9122
+ if (event.key === "Enter") event.currentTarget.blur();
9123
+ }
9094
9124
  })]
9095
- }),
9096
- snapshot.modelError ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9097
- className: "codexSubscriptionError",
9098
- role: "alert",
9099
- children: t("modelDirectoryFailed")
9100
- }) : null
9101
- ]
9125
+ }, model.key)), fixedRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9126
+ className: "codexSubscriptionContextModel",
9127
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9128
+ className: "codexSubscriptionContextModelCopy",
9129
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextFixed"), { value: formatContextWindow(model.maximum) }) })]
9130
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9131
+ className: "codexSubscriptionContextHint",
9132
+ children: formatContextWindow(model.maximum)
9133
+ })]
9134
+ }, model.key))]
9135
+ }) : null]
9136
+ });
9137
+ }
9138
+ /** The account catalog is the only model list: say why it is empty, and offer one refresh. */
9139
+ function ModelCatalogStatus({ preference, t }) {
9140
+ const snapshot = usePreferenceSnapshot(preference);
9141
+ const online = snapshot.catalogStatus?.source === "online";
9142
+ const { refresh: catalogRefresh } = snapshot.catalogStatus ?? {};
9143
+ const failed = snapshot.modelError || catalogRefresh === "failed";
9144
+ const message = snapshot.modelsLoading || catalogRefresh === "refreshing" ? "catalogLoading" : failed && !online ? "catalogFailed" : online ? "catalogOnline" : "catalogSignedOut";
9145
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9146
+ className: "codexSubscriptionPreference",
9147
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9148
+ className: failed && !online ? "codexSubscriptionError" : "codexSubscriptionPreferenceHint",
9149
+ role: failed && !online ? "alert" : void 0,
9150
+ children: t(message)
9151
+ }), online || catalogRefresh !== "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
9152
+ type: "button",
9153
+ variant: "outline",
9154
+ disabled: snapshot.modelsLoading,
9155
+ "aria-busy": snapshot.modelsLoading,
9156
+ onClick: () => {
9157
+ preference.refreshModels();
9158
+ },
9159
+ children: t(snapshot.modelsLoading ? "refreshing" : "catalogRefresh")
9160
+ }) : null]
9102
9161
  });
9103
9162
  }
9104
9163
  function PreferencesCard({ preference, rpc, t, section = "display" }) {
@@ -9108,10 +9167,10 @@ window.__ModuleLoader__.load({
9108
9167
  children: [section === "advanced" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9109
9168
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9110
9169
  className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
9111
- "aria-label": t("advancedModelSearch"),
9170
+ "aria-label": t("modelsSectionTitle"),
9112
9171
  children: [
9113
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("advancedModelSearch") }),
9114
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchProviderPreference, {
9172
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("modelsSectionTitle") }),
9173
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
9115
9174
  preference,
9116
9175
  t
9117
9176
  }),
@@ -9132,6 +9191,14 @@ window.__ModuleLoader__.load({
9132
9191
  })
9133
9192
  ]
9134
9193
  }),
9194
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9195
+ className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
9196
+ "aria-label": t("searchSectionTitle"),
9197
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("searchSectionTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SearchProviderPreference, {
9198
+ preference,
9199
+ t
9200
+ })]
9201
+ }),
9135
9202
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9136
9203
  className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
9137
9204
  "aria-label": t("connectionTitle"),
package/lib/index.js CHANGED
@@ -1195,7 +1195,8 @@ const SUPPORTED_RUNTIME_VERSIONS = Object.freeze([
1195
1195
  "0.1.5-rc.3",
1196
1196
  "0.1.7-rc.1",
1197
1197
  "0.1.7-rc.2",
1198
- "0.2.0-rc.1"
1198
+ "0.2.0-rc.1",
1199
+ "0.2.0-rc.2"
1199
1200
  ]);
1200
1201
  const require = createRequire(import.meta.url);
1201
1202
  const execute = promisify(execFile);
@@ -2966,7 +2967,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2966
2967
  }
2967
2968
  };
2968
2969
  };
2969
- const getModels = () => (catalog?.getModels(provider.getModels()) ?? provider.getModels()).map((model) => {
2970
+ const getModels = () => (catalog?.getModels() ?? provider.getModels()).map((model) => {
2970
2971
  const maximum = modelContextMaximum(model);
2971
2972
  const mode = resolveContextMode();
2972
2973
  if (model.id === "gpt-5.3-codex-spark" || !["extended", "custom"].includes(mode)) return model;
@@ -3023,7 +3024,11 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
3023
3024
  streamSimple: (model, context, options) => networkIterable((prepared) => provider.streamSimple(model, context, prepared), withPreferences(model, options))
3024
3025
  });
3025
3026
  }
3026
- Object.freeze(["0.82.1", "0.85.1"]);
3027
+ Object.freeze([
3028
+ "0.82.1",
3029
+ "0.85.1",
3030
+ "0.87.1"
3031
+ ]);
3027
3032
  //#endregion
3028
3033
  //#region src/subscription-credentials.js
3029
3034
  async function readSubscriptionCredentials(getAuth, readCredential, signal) {
@@ -3046,7 +3051,7 @@ async function readSubscriptionCredentials(getAuth, readCredential, signal) {
3046
3051
  }
3047
3052
  //#endregion
3048
3053
  //#region src/version.js
3049
- const PACKAGE_VERSION = "2.2.8";
3054
+ const PACKAGE_VERSION = "2.2.10";
3050
3055
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
3051
3056
  //#endregion
3052
3057
  //#region src/model-catalog.js
@@ -3303,7 +3308,7 @@ function createOfficialModelCatalog(options = {}) {
3303
3308
  };
3304
3309
  return Object.freeze({
3305
3310
  refresh,
3306
- getModels: (fallback) => models ?? fallback.filter((model) => model.id !== "gpt-5.3-codex-spark"),
3311
+ getModels: () => models ?? [],
3307
3312
  metadata: (modelId) => metadata.get(modelId),
3308
3313
  revision: () => revision,
3309
3314
  capabilityGaps: () => [...metadata.values()].filter((model) => model.unsupported && /^[a-z][a-z0-9._-]{0,79}$/u.test(model.id)).slice(0, 20).map((model) => ({
@@ -3311,7 +3316,7 @@ function createOfficialModelCatalog(options = {}) {
3311
3316
  ...structuredClone(model.unsupported)
3312
3317
  })),
3313
3318
  status: () => ({
3314
- source: models === void 0 ? "fallback" : "online",
3319
+ source: models === void 0 ? "unavailable" : "online",
3315
3320
  refresh: refreshStatus
3316
3321
  }),
3317
3322
  clear() {
@@ -4293,7 +4298,7 @@ function capabilityCoverage({ account, preference, runtime, catalog, tools, stor
4293
4298
  reason = runtime.restartRequired ? "restart-required" : runtime.installed ? "runtime-present" : "runtime-missing";
4294
4299
  } else if (id === "models" && catalog) {
4295
4300
  readiness = catalog.source === "online" ? "pass" : "warn";
4296
- reason = catalog.source === "online" ? "catalog-online" : "catalog-fallback";
4301
+ reason = catalog.source === "online" ? "catalog-online" : "catalog-unavailable";
4297
4302
  } else if (id === "storage" && storage?.readable) {
4298
4303
  readiness = "pass";
4299
4304
  reason = "storage-readable";
@@ -4639,7 +4644,7 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
4639
4644
  ...collected.operations ? { operations: collected.operations } : {},
4640
4645
  ...collected.websocket ? { websocket: collected.websocket } : {},
4641
4646
  ...collected.compaction ? { compaction: collected.compaction } : {},
4642
- ...catalog && ["fallback", "online"].includes(catalog.source) && [
4647
+ ...catalog && ["unavailable", "online"].includes(catalog.source) && [
4643
4648
  "idle",
4644
4649
  "refreshing",
4645
4650
  "ok",
@@ -6072,7 +6077,7 @@ function apply(ctx, config = {}) {
6072
6077
  });
6073
6078
  const preferences = {
6074
6079
  status: () => {
6075
- const models = modelCatalog.getModels(baseProvider.getModels());
6080
+ const models = modelCatalog.getModels();
6076
6081
  return {
6077
6082
  [DISABLED_MODELS_FIELD]: normalizeDisabledModels(settings.get()[DISABLED_MODELS_FIELD]),
6078
6083
  [AUTO_QUOTA_RETRY_FIELD]: normalizeAutoQuotaRetry(settings.get()[AUTO_QUOTA_RETRY_FIELD]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.2.8",
3
+ "version": "2.2.10",
4
4
  "description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -77,46 +77,46 @@
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@deepseek-ai/cordis": "4.0.1 || 4.0.2 || 4.0.3 || 4.0.4",
80
- "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
81
- "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
82
- "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
83
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
84
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
85
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
86
- "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
87
- "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
88
- "@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
89
- "@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
90
- "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
91
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
92
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
93
- "@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
94
- "@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1",
80
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
81
+ "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
82
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
83
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
84
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
85
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
86
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
87
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
88
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
89
+ "@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
90
+ "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
91
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
92
+ "@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
93
+ "@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
94
+ "@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.6-alpha.1 || 0.1.6-alpha.2 || 0.1.7-alpha.1 || 0.1.7-alpha.2 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2",
95
95
  "@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
96
- "@earendil-works/pi-ai": "0.82.1 || 0.85.1",
96
+ "@earendil-works/pi-ai": "0.82.1 || 0.85.1 || 0.87.1",
97
97
  "react": "^18.2.0",
98
98
  "react-dom": "^18.2.0",
99
- "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1"
99
+ "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2"
100
100
  },
101
101
  "devDependencies": {
102
102
  "@deepseek-ai/cordis": "4.0.4",
103
- "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
104
- "@deepseek-ai/dsh-client-connection": "0.2.0-rc.1",
105
- "@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
106
- "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1",
107
- "@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.1",
108
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
109
- "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.1",
110
- "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
111
- "@deepseek-ai/dsh-client-ui-tool": "0.2.0-rc.1",
112
- "@deepseek-ai/dsh-credentials": "0.2.0-rc.1",
113
- "@deepseek-ai/dsh-invariants": "0.2.0-rc.1",
114
- "@deepseek-ai/dsh-llm": "0.2.0-rc.1",
115
- "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.1",
116
- "@deepseek-ai/dsh-session": "0.2.0-rc.1",
117
- "@deepseek-ai/dsh-settings": "0.2.0-rc.1",
118
- "@deepseek-ai/dsh-tools": "0.2.0-rc.1",
119
- "@deepseek-ai/dsh-web": "0.2.0-rc.1",
103
+ "@deepseek-ai/dsh-api-remotes": "0.2.0-rc.2",
104
+ "@deepseek-ai/dsh-client-connection": "0.2.0-rc.2",
105
+ "@deepseek-ai/dsh-client-locale": "0.2.0-rc.2",
106
+ "@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.2",
107
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.2.0-rc.2",
108
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.2",
109
+ "@deepseek-ai/dsh-client-ui-settings": "0.2.0-rc.2",
110
+ "@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.2",
111
+ "@deepseek-ai/dsh-client-ui-tool": "0.2.0-rc.2",
112
+ "@deepseek-ai/dsh-credentials": "0.2.0-rc.2",
113
+ "@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
114
+ "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
115
+ "@deepseek-ai/dsh-llm-pi-ai": "0.2.0-rc.2",
116
+ "@deepseek-ai/dsh-session": "0.2.0-rc.2",
117
+ "@deepseek-ai/dsh-settings": "0.2.0-rc.2",
118
+ "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
119
+ "@deepseek-ai/dsh-web": "0.2.0-rc.2",
120
120
  "@deepseek-ai/schemastery": "3.18.4",
121
121
  "@earendil-works/pi-ai": "0.85.1",
122
122
  "@heroicons/react": "2.2.0",
@@ -125,10 +125,10 @@
125
125
  "react": "18.3.1",
126
126
  "react-dom": "18.3.1",
127
127
  "tsdown": "0.22.2",
128
- "@deepseek-ai/dsh-subagent-codex": "0.2.0-rc.1"
128
+ "@deepseek-ai/dsh-subagent-codex": "0.2.0-rc.2"
129
129
  },
130
130
  "dependencies": {
131
- "@deepseek-ai/dsh-home-paths": "0.2.0-rc.1",
131
+ "@deepseek-ai/dsh-home-paths": "0.2.0-rc.2",
132
132
  "https-proxy-agent": "7.0.6",
133
133
  "ws": "8.21.3"
134
134
  },