dsh-codex-subscription 2.1.8 → 2.2.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/README.en.md CHANGED
@@ -22,7 +22,7 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
22
22
  <img src="docs/assets/codex-subscription-overview-en.webp" width="900" alt="Use ChatGPT and Codex subscriptions in DeepSeek Harness: sign in without an API key, choose models and view remaining quota">
23
23
  </p>
24
24
 
25
- Compatible with DSH `0.1.7-rc.1` plugin compatibility checks and settings APIs, while retaining support for previously supported versions.
25
+ Compatible with DSH `0.1.7-rc.2` plugin compatibility checks and settings APIs, while retaining support for previously supported versions.
26
26
 
27
27
  ## Three-step start
28
28
 
@@ -39,6 +39,7 @@ See below for detailed installation steps, terminal commands, updates, and remov
39
39
  | **Subscription models** | Sign in to ChatGPT and use Codex without an OpenAI API key or Codex CLI |
40
40
  | **Recoverable and diagnosable** | Sign-in state reconciles automatically; failed reads can be retried in place, while timeouts and stale account responses cannot overwrite current state; Settings can create a support report without credentials or account identifiers |
41
41
  | **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate, with reset times |
42
+ | **Optional quota recovery** | Opt in to keep a turn open until a confirmed short Codex quota resets; the turn shows the wait and remains cancellable, while switching accounts retries immediately |
42
43
  | **Composer quota** | Choose a compact percentage, progress bar, Beta runway forecast, or no inline display |
43
44
  | **Safe quota reset** | See each reset credit separately and deliberately try one with a cooldown and acknowledgement |
44
45
  | **Subscription search** | Explicitly route search globally through DSH default search or the signed-in Codex subscription |
@@ -78,7 +79,7 @@ This plugin supports the latest DeepSeek Harness release recorded in its package
78
79
  3. Click **Install** and wait for completion. Follow the page instructions; save your work before restarting if requested.
79
80
  4. Open **Settings → Codex**, sign in to ChatGPT, then select a Codex model in your conversation.
80
81
 
81
- The unversioned package name installs the latest stable release. To select a version, enter `dsh-codex-subscription@2.1.8`; for a beta, use the complete version from its release notes. Enter only the package name here, not a terminal command. This plugin can be installed using its npm package name; no GitHub URL or local directory is needed.
82
+ The unversioned package name installs the latest stable release. To select a version, enter `dsh-codex-subscription@2.1.9`; for a beta, use the complete version from its release notes. Enter only the package name here, not a terminal command. This plugin can be installed using its npm package name; no GitHub URL or local directory is needed.
82
83
 
83
84
  <details>
84
85
  <summary>Terminal installation (with an existing dsh command)</summary>
@@ -244,15 +245,15 @@ In **Settings → Codex → Advanced → Independent subtasks**, click **Install
244
245
 
245
246
  ![Optional component management](docs/assets/settings-runtime-current-en.png)
246
247
 
247
- Prefer **Install component** above. Stable release **2.1.8** selects a component matching the current DSH version: DSH `0.1.7-rc.1` installs component `0.1.7-rc.1`, while DSH `0.1.5-rc.2` installs component `0.1.5-rc.2`. An existing `0.1.5-rc.3` component is recognized only on a matching host. Do not omit the component version or substitute `@next`.
248
+ Prefer **Install component** above. Stable release **2.1.9** selects a component matching the current DSH version: DSH `0.1.7-rc.2` installs component `0.1.7-rc.2`, while DSH `0.1.5-rc.2` installs component `0.1.5-rc.2`. An existing `0.1.5-rc.3` component is recognized only on a matching host. Do not omit the component version or substitute `@next`.
248
249
 
249
250
  <details>
250
251
  <summary>Manual installation on older hosts and offline preparation</summary>
251
252
 
252
- Enter a component version matching the current DSH version in the plugin installer. For DSH `0.1.7-rc.1`, enter `@deepseek-ai/dsh-subagent-codex@0.1.7-rc.1`, or run:
253
+ Enter a component version matching the current DSH version in the plugin installer. For DSH `0.1.7-rc.2`, enter `@deepseek-ai/dsh-subagent-codex@0.1.7-rc.2`, or run:
253
254
 
254
255
  ```sh
255
- dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.7-rc.1
256
+ dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.7-rc.2
256
257
  ```
257
258
 
258
259
  Use the same profile as the subscription plugin and restart afterwards. Offline preparation requires a complete runtime installed and verified on the target OS and architecture; copying only the subscription plugin or Codex launcher is insufficient. Model requests still need connectivity.
package/README.md CHANGED
@@ -23,7 +23,7 @@
23
23
  <img src="docs/assets/codex-subscription-overview.webp" width="900" alt="在 DeepSeek Harness 登录 ChatGPT 并使用 Codex 订阅:无需 API Key,支持模型选择和剩余额度显示">
24
24
  </p>
25
25
 
26
- 已适配 DSH `0.1.7-rc.1` 的插件兼容性检查与设置接口,同时保留已支持版本的兼容。
26
+ 已适配 DSH `0.1.7-rc.2` 的插件兼容性检查与设置接口,同时保留已支持版本的兼容。
27
27
 
28
28
  ## 三步开始
29
29
 
@@ -40,6 +40,7 @@
40
40
  | **订阅模型直连** | 登录 ChatGPT 后直接使用 Codex,不需要 OpenAI API Key 或 Codex CLI |
41
41
  | **可恢复、可诊断** | 登录状态会自动对账;读取失败时可在原处重试,超时和旧账号响应不会覆盖当前状态;设置页可生成不含凭据和账号标识的支持报告 |
42
42
  | **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示,并显示重置时间 |
43
+ | **可选额度恢复** | 可选择让对话等待已确认的短时 Codex 额度重置;对话会显示等待原因、仍可停止,等待期间切换账号会立即重试 |
43
44
  | **输入框额度** | 可选择紧凑百分比、进度条、Beta 续航预测或关闭显示 |
44
45
  | **安全额度重置** | 每张重置卡单独显示,并通过冷静期和知情确认主动尝试重置 |
45
46
  | **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
@@ -79,7 +80,7 @@
79
80
  3. 点击 **安装**,等待安装完成;按页面提示操作,需要重启时先保存工作。
80
81
  4. 打开 **设置 → Codex 订阅**,登录 ChatGPT,然后在会话中选择 Codex 模型。
81
82
 
82
- 包名不带版本号时安装最新正式版。指定版本时填写 `dsh-codex-subscription@2.1.8`;测试版则使用对应发布说明中的完整版本号。此处只填包名,不要粘贴整条终端命令。安装本插件使用上面的 npm 包名即可,无需填写 GitHub 地址或本地目录。
83
+ 包名不带版本号时安装最新正式版。指定版本时填写 `dsh-codex-subscription@2.1.9`;测试版则使用对应发布说明中的完整版本号。此处只填包名,不要粘贴整条终端命令。安装本插件使用上面的 npm 包名即可,无需填写 GitHub 地址或本地目录。
83
84
 
84
85
  <details>
85
86
  <summary>终端安装(已能运行 dsh 命令)</summary>
@@ -243,15 +244,15 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
243
244
 
244
245
  ![可选组件管理实机界面](docs/assets/settings-runtime-current.png)
245
246
 
246
- 优先使用上面的 **安装组件** 按钮。正式版 **2.1.8** 会按当前 DSH 版本选择对应组件:DSH `0.1.7-rc.1` 安装组件 `0.1.7-rc.1`,DSH `0.1.5-rc.2` 安装组件 `0.1.5-rc.2`;已安装的 `0.1.5-rc.3` 组件仅在同版本宿主上识别。请不要省略组件版本号或自行改用 `@next`。
247
+ 优先使用上面的 **安装组件** 按钮。正式版 **2.1.9** 会按当前 DSH 版本选择对应组件:DSH `0.1.7-rc.2` 安装组件 `0.1.7-rc.2`,DSH `0.1.5-rc.2` 安装组件 `0.1.5-rc.2`;已安装的 `0.1.5-rc.3` 组件仅在同版本宿主上识别。请不要省略组件版本号或自行改用 `@next`。
247
248
 
248
249
  <details>
249
250
  <summary>旧版宿主手动安装与离线准备</summary>
250
251
 
251
- 插件安装页面填写与当前 DSH 相同版本的组件,例如 DSH `0.1.7-rc.1` 填写 `@deepseek-ai/dsh-subagent-codex@0.1.7-rc.1`。终端方式:
252
+ 插件安装页面填写与当前 DSH 相同版本的组件,例如 DSH `0.1.7-rc.2` 填写 `@deepseek-ai/dsh-subagent-codex@0.1.7-rc.2`。终端方式:
252
253
 
253
254
  ```sh
254
- dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.7-rc.1
255
+ dsh plugin --profile web add @deepseek-ai/dsh-subagent-codex@0.1.7-rc.2
255
256
  ```
256
257
 
257
258
  安装到订阅插件所在的同一个 profile,完成后重启。离线使用须提前在目标系统与架构上安装并验证完整运行时;只复制订阅插件或 Codex 启动脚本不够。模型请求仍需联网。
@@ -1,11 +1,12 @@
1
1
  {
2
- "latestTested": "0.1.7-rc.1",
2
+ "latestTested": "0.1.7-rc.2",
3
3
  "supported": [
4
4
  "0.1.2-rc.1",
5
5
  "0.1.5-rc.1",
6
6
  "0.1.5-rc.2",
7
7
  "0.1.5-rc.3",
8
- "0.1.7-rc.1"
8
+ "0.1.7-rc.1",
9
+ "0.1.7-rc.2"
9
10
  ],
10
11
  "previews": [
11
12
  "0.1.5-alpha.1",
package/lib/client.js CHANGED
@@ -4878,6 +4878,8 @@ window.__ModuleLoader__.load({
4878
4878
  quickQuotaBar: "进度条",
4879
4879
  quickQuotaForecast: "续航预测",
4880
4880
  quickQuotaBeta: "Beta",
4881
+ autoQuotaRetry: "额度重置后自动重试",
4882
+ autoQuotaRetryHint: "选择开启后,将等待已确认的短时额度重置;对话会显示等待原因且可停止,等待期间切换账号会立即重试。",
4881
4883
  quickQuotaForecastHint: "按最近两小时的消耗估算;消耗不足或速度突变时重新校准,详情显示估计范围。仅供参考,历史保存在本机。",
4882
4884
  contextTitle: "上下文窗口",
4883
4885
  contextStandard: "标准",
@@ -5332,6 +5334,8 @@ window.__ModuleLoader__.load({
5332
5334
  quickQuotaBar: "Progress bar",
5333
5335
  quickQuotaForecast: "Runway",
5334
5336
  quickQuotaBeta: "Beta",
5337
+ autoQuotaRetry: "Retry after quota reset",
5338
+ autoQuotaRetryHint: "Opt in to wait for confirmed short quota resets. The turn shows why it is waiting and can be stopped; switching accounts retries immediately.",
5335
5339
  quickQuotaForecastHint: "Estimates recent two-hour consumption; recalibrates with insufficient data or changing pace. Details show a range. Indicative only; history stays local.",
5336
5340
  contextTitle: "Context window",
5337
5341
  contextStandard: "Standard",
@@ -5470,6 +5474,12 @@ window.__ModuleLoader__.load({
5470
5474
  .codexSubscriptionPreferenceCopy{display:flex;min-width:0;flex-direction:column;gap:2px}
5471
5475
  .codexSubscriptionPreferenceLabel{display:flex;align-items:center;gap:6px}
5472
5476
  .codexSubscriptionPreferenceHint{max-width:300px;font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
5477
+ .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)}
5478
+ .codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-primary)}
5479
+ .codexSubscriptionSwitch:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}
5480
+ .codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}
5481
+ .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)}
5482
+ .codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(16px)}
5473
5483
  .codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}
5474
5484
  .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}
5475
5485
  .codexSubscriptionQuotaMode small{margin-left:3px;font-size:9px;line-height:1;color:var(--dsw-alias-label-tertiary)}
@@ -6687,6 +6697,7 @@ window.__ModuleLoader__.load({
6687
6697
  limitId: limit.id
6688
6698
  }))).filter((window) => Number.isFinite(window.remainingPercent) && window.remainingPercent >= 0 && window.remainingPercent <= (mode === "custom" ? readCapabilitySettings(thresholds)[window.windowSeconds > 0 && window.windowSeconds <= 6 * 3600 ? "quotaShortThreshold" : "quotaLongThreshold"] : mode === "early" && window.windowSeconds > 0 && window.windowSeconds <= 6 * 3600 ? 50 : 20) && (!Number.isFinite(window.resetsAt) || window.resetsAt * 1e3 > now)).sort((a, b) => a.remainingPercent - b.remainingPercent)[0];
6689
6699
  }
6700
+ const AUTO_QUOTA_RETRY_FIELD = "autoQuotaRetry";
6690
6701
  const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
6691
6702
  const LEGACY_QUICK_QUOTA_FIELD = "quickQuotaVisible";
6692
6703
  const QUICK_QUOTA_MODE_PERCENT = "percent";
@@ -6734,6 +6745,7 @@ window.__ModuleLoader__.load({
6734
6745
  "gpt-5.6": 272e3,
6735
6746
  "gpt-6-astra": 272e3
6736
6747
  });
6748
+ const normalizeAutoQuotaRetry = (value) => typeof value === "boolean" ? value : false;
6737
6749
  const normalizeSearchProvider = (value) => [
6738
6750
  "auto",
6739
6751
  "dsh",
@@ -6805,6 +6817,7 @@ window.__ModuleLoader__.load({
6805
6817
  return Object.freeze({
6806
6818
  status: current.status,
6807
6819
  ...capabilities,
6820
+ autoQuotaRetry: normalizeAutoQuotaRetry(value?.[AUTO_QUOTA_RETRY_FIELD]),
6808
6821
  connectionMode: value?.connectionMode === "websocket" ? "websocket" : "sse",
6809
6822
  compactionMode: value?.compactionMode === "cloud" ? "cloud" : "dsh",
6810
6823
  subagentBackend: value?.subagentBackend === "codex" ? "codex" : "dsh",
@@ -6855,6 +6868,7 @@ window.__ModuleLoader__.load({
6855
6868
  fallback = {
6856
6869
  status: "ready",
6857
6870
  value: {
6871
+ [AUTO_QUOTA_RETRY_FIELD]: normalizeAutoQuotaRetry(value?.[AUTO_QUOTA_RETRY_FIELD]),
6858
6872
  connectionMode: value?.connectionMode === "websocket" ? "websocket" : "sse",
6859
6873
  compactionMode: value?.compactionMode === "cloud" ? "cloud" : "dsh",
6860
6874
  subagentBackend: value?.subagentBackend === "codex" ? "codex" : "dsh",
@@ -7276,7 +7290,7 @@ window.__ModuleLoader__.load({
7276
7290
  }
7277
7291
  //#endregion
7278
7292
  //#region src/version.js
7279
- const PACKAGE_VERSION = "2.1.8";
7293
+ const PACKAGE_VERSION = "2.2.0";
7280
7294
  //#endregion
7281
7295
  //#region src/client-recovery.js
7282
7296
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -8353,6 +8367,34 @@ window.__ModuleLoader__.load({
8353
8367
  })]
8354
8368
  });
8355
8369
  }
8370
+ function AutoQuotaRetryPreference({ preference, t }) {
8371
+ const snapshot = usePreferenceSnapshot(preference);
8372
+ const writable = snapshot.status === "ready" && snapshot.writable === true;
8373
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8374
+ className: "codexSubscriptionPreference",
8375
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8376
+ className: "codexSubscriptionPreferenceCopy",
8377
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8378
+ className: "codexSubscriptionPreferenceLabel",
8379
+ children: t("autoQuotaRetry")
8380
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8381
+ className: "codexSubscriptionPreferenceHint",
8382
+ children: t("autoQuotaRetryHint")
8383
+ })]
8384
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8385
+ className: "codexSubscriptionSwitch",
8386
+ type: "button",
8387
+ role: "switch",
8388
+ "aria-label": t("autoQuotaRetry"),
8389
+ "aria-checked": snapshot.autoQuotaRetry,
8390
+ disabled: !writable,
8391
+ onClick: () => {
8392
+ preference.set({ [AUTO_QUOTA_RETRY_FIELD]: !snapshot.autoQuotaRetry });
8393
+ },
8394
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "codexSubscriptionSwitchKnob" })
8395
+ })]
8396
+ });
8397
+ }
8356
8398
  function SearchProviderPreference({ preference, t }) {
8357
8399
  const snapshot = usePreferenceSnapshot(preference);
8358
8400
  const writable = snapshot.status === "ready" && snapshot.writable === true;
@@ -8700,14 +8742,22 @@ window.__ModuleLoader__.load({
8700
8742
  t
8701
8743
  })]
8702
8744
  })
8703
- ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickQuotaPreference, {
8704
- preference,
8705
- t
8706
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CapabilityPreferences, {
8707
- preference,
8708
- t,
8709
- section: "quota"
8710
- })] }), snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8745
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
8746
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickQuotaPreference, {
8747
+ preference,
8748
+ t
8749
+ }),
8750
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CapabilityPreferences, {
8751
+ preference,
8752
+ t,
8753
+ section: "quota"
8754
+ }),
8755
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "codexSubscriptionDivider" }),
8756
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AutoQuotaRetryPreference, {
8757
+ preference,
8758
+ t
8759
+ })
8760
+ ] }), snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8711
8761
  className: "codexSubscriptionRecover",
8712
8762
  role: "alert",
8713
8763
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
package/lib/index.js CHANGED
@@ -193,6 +193,7 @@ function capabilityPatch(payload) {
193
193
  //#endregion
194
194
  //#region src/settings-contract.js
195
195
  const SETTINGS_NAMESPACE = "codex-subscription";
196
+ const AUTO_QUOTA_RETRY_FIELD = "autoQuotaRetry";
196
197
  const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
197
198
  const LEGACY_QUICK_QUOTA_FIELD = "quickQuotaVisible";
198
199
  const QUICK_QUOTA_MODE_PERCENT = "percent";
@@ -240,6 +241,7 @@ const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
240
241
  "gpt-5.6": 272e3,
241
242
  "gpt-6-astra": 272e3
242
243
  });
244
+ const normalizeAutoQuotaRetry = (value) => typeof value === "boolean" ? value : false;
243
245
  const normalizeOutputVerbosity = (value) => [
244
246
  "default",
245
247
  "low",
@@ -1074,17 +1076,18 @@ function authenticatedSubagentChild(child, { Transport, getTokens, thread, signa
1074
1076
  //#endregion
1075
1077
  //#region src/subagent-runtime.js
1076
1078
  const SUBAGENT_RUNTIME_PACKAGE = "@deepseek-ai/dsh-subagent-codex";
1077
- const SUPPORTED_RUNTIME_VERSIONS = /* @__PURE__ */ new Set([
1079
+ const SUPPORTED_RUNTIME_VERSIONS = Object.freeze([
1078
1080
  "0.1.5-rc.2",
1079
1081
  "0.1.5-rc.3",
1080
- "0.1.7-rc.1"
1082
+ "0.1.7-rc.1",
1083
+ "0.1.7-rc.2"
1081
1084
  ]);
1082
1085
  const require = createRequire(import.meta.url);
1083
1086
  const execute = promisify(execFile);
1084
1087
  function matchingSubagentRuntimeVersion(resolve = require.resolve) {
1085
1088
  try {
1086
1089
  const host = JSON.parse(readFileSync(resolve("@deepseek-ai/dsh-llm/package.json"), "utf8"));
1087
- return SUPPORTED_RUNTIME_VERSIONS.has(host.version) ? host.version : void 0;
1090
+ return SUPPORTED_RUNTIME_VERSIONS.includes(host.version) ? host.version : void 0;
1088
1091
  } catch {
1089
1092
  return;
1090
1093
  }
@@ -1093,7 +1096,7 @@ function inspectSubagentRuntime(resolve = require.resolve) {
1093
1096
  try {
1094
1097
  const manifestPath = resolve(`${SUBAGENT_RUNTIME_PACKAGE}/package.json`);
1095
1098
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
1096
- if (!SUPPORTED_RUNTIME_VERSIONS.has(manifest.version) || manifest.version !== matchingSubagentRuntimeVersion(resolve)) return {
1099
+ if (!SUPPORTED_RUNTIME_VERSIONS.includes(manifest.version) || manifest.version !== matchingSubagentRuntimeVersion(resolve)) return {
1097
1100
  installed: false,
1098
1101
  present: true
1099
1102
  };
@@ -2828,7 +2831,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2828
2831
  Object.freeze(["0.82.1", "0.85.1"]);
2829
2832
  //#endregion
2830
2833
  //#region src/version.js
2831
- const PACKAGE_VERSION = "2.1.8";
2834
+ const PACKAGE_VERSION = "2.2.0";
2832
2835
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
2833
2836
  //#endregion
2834
2837
  //#region src/model-catalog.js
@@ -3971,6 +3974,7 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
3971
3974
  ...gaps.length ? { unsupported: gaps } : {}
3972
3975
  } } : {},
3973
3976
  configuration: {
3977
+ ...typeof preference.autoQuotaRetry === "boolean" ? { autoQuotaRetry: preference.autoQuotaRetry } : {},
3974
3978
  contextMode: preference.contextMode,
3975
3979
  quickQuotaMode: preference.quickQuotaMode,
3976
3980
  ...typeof preference.outputVerbosity === "string" ? { outputVerbosity: preference.outputVerbosity } : {},
@@ -4208,6 +4212,187 @@ function createCodexUsageReader(options) {
4208
4212
  });
4209
4213
  }
4210
4214
  //#endregion
4215
+ //#region src/quota-retry.js
4216
+ const DEFAULT_MAX_WAIT_MS = 360 * 60 * 1e3;
4217
+ const DEFAULT_RESET_MARGIN_MS = 1e4;
4218
+ const EXHAUSTED_PERCENT = 99.9;
4219
+ const CODEX_USAGE_LIMIT_MESSAGE = /^You have hit your ChatGPT usage limit(?: \([a-z0-9][a-z0-9 ._-]{0,39} plan\))?\.(?: Try again in ~\d{1,6} min\.)?$/u;
4220
+ const isCodexRateLimit = (failure) => failure?.code === "RATE_LIMIT" || failure?.code === "PI_AI_ERROR" && typeof failure.message === "string" && CODEX_USAGE_LIMIT_MESSAGE.test(failure.message);
4221
+ function cancellableDelay(delayMs, signal) {
4222
+ if (signal?.aborted) return Promise.resolve(false);
4223
+ return new Promise((resolve) => {
4224
+ const timer = setTimeout(() => {
4225
+ signal?.removeEventListener("abort", onAbort);
4226
+ resolve(true);
4227
+ }, delayMs);
4228
+ function onAbort() {
4229
+ clearTimeout(timer);
4230
+ resolve(false);
4231
+ }
4232
+ signal?.addEventListener("abort", onAbort, { once: true });
4233
+ });
4234
+ }
4235
+ function createWakeSignal() {
4236
+ let revision = 0;
4237
+ let reason;
4238
+ const waiters = /* @__PURE__ */ new Set();
4239
+ const notify = (nextReason) => {
4240
+ revision += 1;
4241
+ reason = nextReason;
4242
+ for (const waiter of [...waiters]) waiter(nextReason);
4243
+ };
4244
+ const wait = (since, signal) => {
4245
+ if (revision !== since) return Promise.resolve(reason);
4246
+ if (signal?.aborted) return Promise.resolve("cancelled");
4247
+ return new Promise((resolve) => {
4248
+ const settle = (value) => {
4249
+ waiters.delete(settle);
4250
+ signal?.removeEventListener("abort", onAbort);
4251
+ resolve(value);
4252
+ };
4253
+ const onAbort = () => settle("cancelled");
4254
+ waiters.add(settle);
4255
+ signal?.addEventListener("abort", onAbort, { once: true });
4256
+ if (revision !== since) settle(reason);
4257
+ });
4258
+ };
4259
+ return {
4260
+ revision: () => revision,
4261
+ notify,
4262
+ wait
4263
+ };
4264
+ }
4265
+ function shortResetDelay(usage, nowMs, maxWaitMs, resetMarginMs) {
4266
+ let latestDelayMs;
4267
+ for (const limit of usage?.rateLimits ?? []) {
4268
+ if (limit?.id !== "codex") continue;
4269
+ for (const window of limit?.windows ?? []) {
4270
+ if (!Number.isFinite(window?.usedPercent) || window.usedPercent < EXHAUSTED_PERCENT) continue;
4271
+ if (!Number.isFinite(window?.windowSeconds) || window.windowSeconds * 1e3 > maxWaitMs) return void 0;
4272
+ if (!Number.isFinite(window?.resetsAt)) return void 0;
4273
+ const delayMs = window.resetsAt * 1e3 - nowMs;
4274
+ if (delayMs <= 0 || delayMs + resetMarginMs > maxWaitMs) return void 0;
4275
+ latestDelayMs = Math.max(latestDelayMs ?? 0, delayMs);
4276
+ }
4277
+ }
4278
+ return latestDelayMs;
4279
+ }
4280
+ function publishScheduledRetry({ agent, turn, step, provider, failure }, delayMs, resetAtMs) {
4281
+ if (typeof agent?.session?.append !== "function" || !Number.isSafeInteger(turn) || !Number.isSafeInteger(step)) return void 0;
4282
+ const retryId = `codex-quota-${randomUUID()}`;
4283
+ const message = `Codex usage limit exhausted. Waiting for quota reset at ${new Date(resetAtMs).toISOString()}; retrying shortly afterward.`;
4284
+ const visibleFailure = {
4285
+ code: failure.code,
4286
+ message,
4287
+ ...Number.isInteger(failure.status) && failure.status >= 100 && failure.status <= 599 ? { status: failure.status } : {},
4288
+ ...typeof failure.requestId === "string" && failure.requestId.length > 0 ? { requestId: failure.requestId } : {}
4289
+ };
4290
+ try {
4291
+ agent.session.append("llm/retry", {
4292
+ retryId,
4293
+ turn,
4294
+ step,
4295
+ provider,
4296
+ mode: "normal",
4297
+ policyKey: retryId,
4298
+ retry: 1,
4299
+ maxRetries: 1,
4300
+ delayMs,
4301
+ failure: visibleFailure
4302
+ });
4303
+ return {
4304
+ retryId,
4305
+ turn,
4306
+ step,
4307
+ retry: 1
4308
+ };
4309
+ } catch {
4310
+ return;
4311
+ }
4312
+ }
4313
+ function publishRetryStarted(agent, scheduled) {
4314
+ try {
4315
+ agent.session.append("llm/retry-started", scheduled);
4316
+ return true;
4317
+ } catch {
4318
+ return false;
4319
+ }
4320
+ }
4321
+ async function waitForResetOrWake(delayMs, signal, wait, wakeSignal, revision) {
4322
+ const controller = new AbortController();
4323
+ const fusedSignal = signal === void 0 ? controller.signal : AbortSignal.any([signal, controller.signal]);
4324
+ const delayed = Promise.resolve(wait(delayMs, fusedSignal)).then((completed) => completed ? "reset" : "cancelled");
4325
+ const result = await Promise.race([delayed, wakeSignal.wait(revision, fusedSignal)]);
4326
+ controller.abort();
4327
+ return result;
4328
+ }
4329
+ /**
4330
+ * Recover a Codex subscription RATE_LIMIT only when the backend confirms an
4331
+ * exhausted short quota window whose reset is close enough to wait out.
4332
+ *
4333
+ * The listener owns the authoritative wait from `/wham/usage` and publishes
4334
+ * the host's standard model-retry surface event so the turn shows the reason,
4335
+ * countdown, and normal turn cancellation affordance while it is parked.
4336
+ */
4337
+ function createCodexQuotaRetryHandler({ usageReader, provider = "openai-codex", enabled = () => true, now = Date.now, wait = cancellableDelay, maxWaitMs = DEFAULT_MAX_WAIT_MS, resetMarginMs = DEFAULT_RESET_MARGIN_MS } = {}) {
4338
+ if (usageReader === void 0 || typeof usageReader.read !== "function") throw new TypeError("quota retry requires a usage reader");
4339
+ if (typeof enabled !== "function" || typeof now !== "function" || typeof wait !== "function") throw new TypeError("quota retry requires enablement, clock, and wait functions");
4340
+ if (!Number.isFinite(maxWaitMs) || maxWaitMs <= 0 || !Number.isFinite(resetMarginMs) || resetMarginMs < 0) throw new TypeError("quota retry requires a positive wait cap and non-negative reset margin");
4341
+ const wakeSignal = createWakeSignal();
4342
+ const clearCache = async () => {
4343
+ try {
4344
+ if (typeof usageReader.clearCache === "function") await usageReader.clearCache();
4345
+ else await usageReader.clear?.();
4346
+ } catch {}
4347
+ };
4348
+ const handler = async ({ agent, turn, step, provider: requestProvider, failure, signal }, next) => {
4349
+ if (requestProvider !== provider || !isCodexRateLimit(failure) || !enabled()) return next();
4350
+ if (signal?.aborted) return void 0;
4351
+ let wakeRevision = wakeSignal.revision();
4352
+ let usage;
4353
+ try {
4354
+ usage = await usageReader.read({
4355
+ force: true,
4356
+ signal
4357
+ });
4358
+ } catch {
4359
+ if (signal?.aborted) return void 0;
4360
+ return next();
4361
+ }
4362
+ if (signal?.aborted) return void 0;
4363
+ if (!enabled()) return next();
4364
+ const observedAtMs = now();
4365
+ let resetDelayMs = shortResetDelay(usage, observedAtMs, maxWaitMs, resetMarginMs);
4366
+ if (resetDelayMs === void 0) return next();
4367
+ const scheduled = publishScheduledRetry({
4368
+ agent,
4369
+ turn,
4370
+ step,
4371
+ provider: requestProvider,
4372
+ failure
4373
+ }, resetDelayMs + resetMarginMs, observedAtMs + resetDelayMs);
4374
+ if (scheduled === void 0) return next();
4375
+ while (true) {
4376
+ const reason = await waitForResetOrWake(resetDelayMs + resetMarginMs, signal, wait, wakeSignal, wakeRevision);
4377
+ if (reason === "cancelled" || signal?.aborted) return void 0;
4378
+ if (!enabled()) return next();
4379
+ if (reason !== "configuration") break;
4380
+ wakeRevision = wakeSignal.revision();
4381
+ resetDelayMs = shortResetDelay(usage, now(), maxWaitMs, resetMarginMs);
4382
+ if (resetDelayMs === void 0) return next();
4383
+ }
4384
+ await clearCache();
4385
+ if (signal?.aborted) return void 0;
4386
+ if (!publishRetryStarted(agent, scheduled)) return next();
4387
+ return { kind: "retry" };
4388
+ };
4389
+ Object.defineProperties(handler, {
4390
+ notifyAccountChanged: { value: () => wakeSignal.notify("account") },
4391
+ notifyConfigurationChanged: { value: () => wakeSignal.notify("configuration") }
4392
+ });
4393
+ return handler;
4394
+ }
4395
+ //#endregion
4211
4396
  //#region src/quota-rate-interval.js
4212
4397
  function quotaRateInterval(samples, { quantum = 1, rounding = "unknown" } = {}) {
4213
4398
  if (!(quantum > 0) || !Number.isFinite(quantum)) throw new RangeError("Invalid quantum");
@@ -4878,7 +5063,7 @@ const publicError = (code, message) => ({
4878
5063
  details: { issues: [] }
4879
5064
  }
4880
5065
  });
4881
- function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, runtimeManagement, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections }) {
5066
+ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, runtimeManagement, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections, onAccountChanged }) {
4882
5067
  return async (endpoint, payload, signal) => {
4883
5068
  if ([
4884
5069
  "runtime/status",
@@ -4949,6 +5134,10 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
4949
5134
  signal.throwIfAborted();
4950
5135
  if (endpoint === "preferences/update") {
4951
5136
  const patch = capabilityPatch(payload);
5137
+ if (Object.hasOwn(payload ?? {}, "autoQuotaRetry")) {
5138
+ if (typeof payload["autoQuotaRetry"] !== "boolean") return publicError("internal", "Invalid automatic quota retry preference");
5139
+ patch[AUTO_QUOTA_RETRY_FIELD] = payload[AUTO_QUOTA_RETRY_FIELD];
5140
+ }
4952
5141
  for (const [field, rule] of Object.entries(PREFERENCE_FIELDS)) {
4953
5142
  if (!Object.hasOwn(payload ?? {}, field)) continue;
4954
5143
  if (!rule.choices.includes(payload[field])) return publicError("internal", rule.error);
@@ -5031,10 +5220,12 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
5031
5220
  await usageReader.clear();
5032
5221
  resetCreditService.clear();
5033
5222
  modelCatalog?.clear();
5223
+ onAccountChanged?.();
5034
5224
  } else if (result.ok === true && (endpoint === "account/select" || endpoint === "account/remove" || endpoint === "login/status" && result.value?.authenticated === true)) {
5035
5225
  usageReader.clearCache();
5036
5226
  resetCreditService.clear();
5037
5227
  modelCatalog?.clear();
5228
+ onAccountChanged?.();
5038
5229
  modelCatalog?.refresh({ signal: void 0 }).catch(() => {});
5039
5230
  } else if (result.ok === true && (endpoint === "status" || result.value?.authenticated === true)) modelCatalog?.refresh({ signal: void 0 }).catch(() => {});
5040
5231
  return result;
@@ -5087,6 +5278,7 @@ function createSearchProviderSwitcher(loader) {
5087
5278
  });
5088
5279
  }
5089
5280
  const settingsFields = {
5281
+ [AUTO_QUOTA_RETRY_FIELD]: z.boolean().default(false),
5090
5282
  ...Object.fromEntries(Object.entries(PREFERENCE_FIELDS).map(([field, rule]) => [field, rule.default === void 0 ? z.union(rule.choices) : z.union(rule.choices).default(rule.default)])),
5091
5283
  imageModel: z.union(Object.keys(IMAGE_MODELS)).default(DEFAULT_IMAGE_MODEL),
5092
5284
  imageQuality: z.union([
@@ -5169,6 +5361,7 @@ function apply(ctx, config = {}) {
5169
5361
  });
5170
5362
  const preferences = {
5171
5363
  status: () => ({
5364
+ [AUTO_QUOTA_RETRY_FIELD]: normalizeAutoQuotaRetry(settings.get()[AUTO_QUOTA_RETRY_FIELD]),
5172
5365
  compactionMode: settings.get().compactionMode ?? "dsh",
5173
5366
  connectionMode: settings.get().connectionMode ?? "sse",
5174
5367
  subagentBackend: settings.get().subagentBackend ?? "dsh",
@@ -5379,6 +5572,30 @@ function apply(ctx, config = {}) {
5379
5572
  usageReader.clearCache();
5380
5573
  };
5381
5574
  }, "codex-subscription: quota forecast warm-up");
5575
+ const quotaRetryLifetime = new AbortController();
5576
+ const activeQuotaRetries = /* @__PURE__ */ new Set();
5577
+ const quotaRetryHandler = createCodexQuotaRetryHandler({
5578
+ usageReader,
5579
+ enabled: () => normalizeAutoQuotaRetry(settings.get()[AUTO_QUOTA_RETRY_FIELD])
5580
+ });
5581
+ const disposeQuotaRetry = ctx.on("agent/request-error", (payload, next) => {
5582
+ if (quotaRetryLifetime.signal.aborted) return Promise.resolve(void 0);
5583
+ const signal = payload.signal === void 0 ? quotaRetryLifetime.signal : AbortSignal.any([payload.signal, quotaRetryLifetime.signal]);
5584
+ const tracked = quotaRetryHandler({
5585
+ ...payload,
5586
+ signal
5587
+ }, next).finally(() => activeQuotaRetries.delete(tracked));
5588
+ activeQuotaRetries.add(tracked);
5589
+ return tracked;
5590
+ });
5591
+ ctx.effect(() => async () => {
5592
+ disposeQuotaRetry();
5593
+ quotaRetryLifetime.abort(/* @__PURE__ */ new Error("codex-subscription quota retry disposed"));
5594
+ await Promise.allSettled([...activeQuotaRetries]);
5595
+ }, "codex-subscription: abort and drain quota recovery");
5596
+ ctx.effect(() => settings.watch((value, previous) => {
5597
+ if (normalizeAutoQuotaRetry(value["autoQuotaRetry"]) !== normalizeAutoQuotaRetry(previous?.["autoQuotaRetry"])) quotaRetryHandler.notifyConfigurationChanged();
5598
+ }), "codex-subscription: update quota recovery preference");
5382
5599
  const resetCreditService = createCodexResetCreditService({
5383
5600
  getAuth: resolveAuth,
5384
5601
  readCredential: (options) => store.read(PROVIDER, options),
@@ -5411,6 +5628,7 @@ function apply(ctx, config = {}) {
5411
5628
  resetCreditService,
5412
5629
  preferences,
5413
5630
  runtimeManagement,
5631
+ onAccountChanged: quotaRetryHandler.notifyAccountChanged,
5414
5632
  diagnosticsReader: () => createSubscriptionDiagnostics({
5415
5633
  auth,
5416
5634
  preferences,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.1.8",
3
+ "version": "2.2.0",
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",
@@ -75,46 +75,46 @@
75
75
  },
76
76
  "peerDependencies": {
77
77
  "@deepseek-ai/cordis": "4.0.1 || 4.0.2 || 4.0.3 || 4.0.4",
78
- "@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",
79
- "@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",
80
- "@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",
81
- "@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",
82
- "@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",
83
- "@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",
84
- "@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",
85
- "@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",
86
- "@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",
87
- "@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",
88
- "@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",
89
- "@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",
90
- "@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",
91
- "@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",
92
- "@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",
78
+ "@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",
79
+ "@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",
80
+ "@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",
81
+ "@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",
82
+ "@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",
83
+ "@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",
84
+ "@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",
85
+ "@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",
86
+ "@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",
87
+ "@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",
88
+ "@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",
89
+ "@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",
90
+ "@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",
91
+ "@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",
92
+ "@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",
93
93
  "@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
94
94
  "@earendil-works/pi-ai": "0.82.1 || 0.85.1",
95
95
  "react": "^18.2.0",
96
96
  "react-dom": "^18.2.0",
97
- "@deepseek-ai/dsh-subagent-codex": "0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1"
97
+ "@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"
98
98
  },
99
99
  "devDependencies": {
100
100
  "@deepseek-ai/cordis": "4.0.4",
101
- "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.1",
102
- "@deepseek-ai/dsh-client-connection": "0.1.7-rc.1",
103
- "@deepseek-ai/dsh-client-locale": "0.1.7-rc.1",
104
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.1",
105
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.7-rc.1",
106
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.1",
107
- "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.1",
108
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.1",
109
- "@deepseek-ai/dsh-client-ui-tool": "0.1.7-rc.1",
110
- "@deepseek-ai/dsh-credentials": "0.1.7-rc.1",
111
- "@deepseek-ai/dsh-invariants": "0.1.7-rc.1",
112
- "@deepseek-ai/dsh-llm": "0.1.7-rc.1",
113
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.1",
114
- "@deepseek-ai/dsh-session": "0.1.7-rc.1",
115
- "@deepseek-ai/dsh-settings": "0.1.7-rc.1",
116
- "@deepseek-ai/dsh-tools": "0.1.7-rc.1",
117
- "@deepseek-ai/dsh-web": "0.1.7-rc.1",
101
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
102
+ "@deepseek-ai/dsh-client-connection": "0.1.7-rc.2",
103
+ "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
104
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2",
105
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.7-rc.2",
106
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
107
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.7-rc.2",
108
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
109
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.7-rc.2",
110
+ "@deepseek-ai/dsh-credentials": "0.1.7-rc.2",
111
+ "@deepseek-ai/dsh-invariants": "0.1.7-rc.2",
112
+ "@deepseek-ai/dsh-llm": "0.1.7-rc.2",
113
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.7-rc.2",
114
+ "@deepseek-ai/dsh-session": "0.1.7-rc.2",
115
+ "@deepseek-ai/dsh-settings": "0.1.7-rc.2",
116
+ "@deepseek-ai/dsh-tools": "0.1.7-rc.2",
117
+ "@deepseek-ai/dsh-web": "0.1.7-rc.2",
118
118
  "@deepseek-ai/schemastery": "3.18.4",
119
119
  "@earendil-works/pi-ai": "0.85.1",
120
120
  "@heroicons/react": "2.2.0",
@@ -123,10 +123,10 @@
123
123
  "react": "18.3.1",
124
124
  "react-dom": "18.3.1",
125
125
  "tsdown": "0.22.2",
126
- "@deepseek-ai/dsh-subagent-codex": "0.1.7-rc.1"
126
+ "@deepseek-ai/dsh-subagent-codex": "0.1.7-rc.2"
127
127
  },
128
128
  "dependencies": {
129
- "@deepseek-ai/dsh-home-paths": "0.1.7-rc.1",
129
+ "@deepseek-ai/dsh-home-paths": "0.1.7-rc.2",
130
130
  "https-proxy-agent": "7.0.6",
131
131
  "ws": "8.21.3"
132
132
  },