dsh-codex-subscription 2.5.9 → 2.6.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
@@ -106,7 +106,7 @@ This plugin supports the latest DeepSeek Harness release recorded in its package
106
106
  2. Paste this package name, with its version, into the **Package name or address** field:
107
107
 
108
108
  ```text
109
- dsh-codex-subscription@2.5.9
109
+ dsh-codex-subscription@2.6.0
110
110
  ```
111
111
 
112
112
  3. Click **Install** and wait for completion. Follow the page instructions; save your work before restarting if requested.
@@ -118,7 +118,7 @@ Why the version is included: DSH's plugin page only installs versions that are a
118
118
  <summary>Terminal installation (with an existing dsh command)</summary>
119
119
 
120
120
  ```sh
121
- dsh plugin --profile web add dsh-codex-subscription
121
+ dsh plugin --profile web add dsh-codex-subscription@2.6.0
122
122
  ```
123
123
 
124
124
  Follow the restart instructions, then sign in under **Settings → Codex**. Both the Plugins page and the terminal use DSH's installation management.
@@ -131,7 +131,7 @@ Follow the restart instructions, then sign in under **Settings → Codex**. Both
131
131
  After signing in and selecting a Codex model in Web, install the same plugin in the Headless profile:
132
132
 
133
133
  ```sh
134
- dsh plugin --profile headless add dsh-codex-subscription
134
+ dsh plugin --profile headless add dsh-codex-subscription@2.6.0
135
135
  dsh --profile headless "Reply with only the word: ok"
136
136
  ```
137
137
 
@@ -266,7 +266,7 @@ Find this plugin on the DSH **Plugins** page and use its update or uninstall act
266
266
  <summary>Terminal commands</summary>
267
267
 
268
268
  ```sh
269
- dsh plugin --profile web update dsh-codex-subscription
269
+ dsh plugin --profile web update dsh-codex-subscription@2.6.0
270
270
  ```
271
271
 
272
272
  Run only when you want to uninstall:
@@ -282,7 +282,14 @@ dsh plugin --profile web remove dsh-codex-subscription
282
282
  <details>
283
283
  <summary>DSH 0.2.0-rc.2 reports the plugin as incompatible?</summary>
284
284
 
285
- DSH 0.2.0-rc.2 did not exist when any release before 2.2.10 was published, and a published package's compatibility declaration cannot be changed. Install 2.2.10 or later (a bare package name can resolve to an older release during the first 24 hours, so enter `dsh-codex-subscription@2.2.10`) from the **Plugins** page, or run `dsh plugin --profile web update dsh-codex-subscription`, then restart DSH.
285
+ DSH 0.2.0-rc.2 did not exist when any release before 2.2.10 was published, and a published package's compatibility declaration cannot be changed. Install 2.2.10 or later (a bare package name can resolve to an older release during the first 24 hours, so enter `dsh-codex-subscription@2.2.10`) from the **Plugins** page, or run `dsh plugin --profile web update dsh-codex-subscription@2.6.0`, then restart DSH.
286
+
287
+ </details>
288
+
289
+ <details>
290
+ <summary>How does this relate to the official Codex bundle (dsh-hooks-codex) in the plugin list?</summary>
291
+
292
+ They are unrelated and can be installed together. The official Codex / Claude Code bundles let DSH run Codex or Claude Code style hooks configs (scripts that run before and after tool calls). This plugin signs in with your ChatGPT subscription and provides Codex models, quota, search, images and phone remote control.
286
293
 
287
294
  </details>
288
295
 
package/README.md CHANGED
@@ -106,7 +106,7 @@
106
106
  2. 在 **包名或地址** 输入框中粘贴下面的包名(已带版本号):
107
107
 
108
108
  ```text
109
- dsh-codex-subscription@2.5.9
109
+ dsh-codex-subscription@2.6.0
110
110
  ```
111
111
 
112
112
  3. 点击 **安装**,等待安装完成;按页面提示操作,需要重启时先保存工作。
@@ -118,7 +118,7 @@
118
118
  <summary>终端安装(已能运行 dsh 命令)</summary>
119
119
 
120
120
  ```sh
121
- dsh plugin --profile web add dsh-codex-subscription
121
+ dsh plugin --profile web add dsh-codex-subscription@2.6.0
122
122
  ```
123
123
 
124
124
  安装完成后按提示重启 DSH,再到 **设置 → Codex 订阅** 登录。插件页面和终端均由 DSH 管理安装。
@@ -131,7 +131,7 @@ dsh plugin --profile web add dsh-codex-subscription
131
131
  先在 Web 中完成登录并选择一次 Codex 模型,再把同一个插件安装到 Headless profile:
132
132
 
133
133
  ```sh
134
- dsh plugin --profile headless add dsh-codex-subscription
134
+ dsh plugin --profile headless add dsh-codex-subscription@2.6.0
135
135
  dsh --profile headless "只回复:ok"
136
136
  ```
137
137
 
@@ -295,7 +295,7 @@ DSH 实机设置截图。
295
295
  <summary>终端方式</summary>
296
296
 
297
297
  ```sh
298
- dsh plugin --profile web update dsh-codex-subscription
298
+ dsh plugin --profile web update dsh-codex-subscription@2.6.0
299
299
  ```
300
300
 
301
301
  仅在需要卸载时运行:
@@ -311,7 +311,14 @@ dsh plugin --profile web remove dsh-codex-subscription
311
311
  <details>
312
312
  <summary>DSH 0.2.0-rc.2 提示插件不兼容?</summary>
313
313
 
314
- 2.2.10 之前的所有版本发布时 DSH 0.2.0-rc.2 还不存在,其兼容声明无法事后修改。请安装 2.2.10 或更高版本(只填包名时,发布满 24 小时前可能装到旧版,请直接填 `dsh-codex-subscription@2.2.10`):在 **插件** 页面更新,或运行 `dsh plugin --profile web update dsh-codex-subscription`,然后重启 DSH。
314
+ 2.2.10 之前的所有版本发布时 DSH 0.2.0-rc.2 还不存在,其兼容声明无法事后修改。请安装 2.2.10 或更高版本(只填包名时,发布满 24 小时前可能装到旧版,请直接填 `dsh-codex-subscription@2.2.10`):在 **插件** 页面更新,或运行 `dsh plugin --profile web update dsh-codex-subscription@2.6.0`,然后重启 DSH。
315
+
316
+ </details>
317
+
318
+ <details>
319
+ <summary>和官方插件列表里的 Codex 组合包(dsh-hooks-codex)是什么关系?</summary>
320
+
321
+ 没有关系,可以同时安装。官方的 Codex / Claude Code 组合包让 DSH 运行 Codex 或 Claude Code 格式的 hooks 配置(工具调用前后自动执行的脚本);本插件负责用 ChatGPT 订阅登录、使用 Codex 模型、查看额度、搜索、生图和手机远程控制。
315
322
 
316
323
  </details>
317
324
 
@@ -17,6 +17,7 @@
17
17
  "0.1.6-alpha.2",
18
18
  "0.1.7-alpha.1",
19
19
  "0.1.7-alpha.2",
20
- "0.2.1-alpha.1"
20
+ "0.2.1-alpha.1",
21
+ "0.2.1-alpha.2"
21
22
  ]
22
23
  }
package/lib/client.js CHANGED
@@ -5676,6 +5676,12 @@ window.__ModuleLoader__.load({
5676
5676
  inputImageDetail_low: "低",
5677
5677
  inputImageDetail_high: "高",
5678
5678
  inputImageDetail_original: "原图",
5679
+ reasoningSummary: "推理摘要",
5680
+ reasoningSummaryHint: "让模型在会话的“思考”部分给出推理摘要。自动由模型决定;简洁更短;详细更完整;关闭则不要摘要。",
5681
+ reasoningSummary_auto: "自动",
5682
+ reasoningSummary_concise: "简洁",
5683
+ reasoningSummary_detailed: "详细",
5684
+ reasoningSummary_none: "关闭",
5679
5685
  subagentBackendTitle: "独立子任务",
5680
5686
  subagentBackend_dsh: "DSH",
5681
5687
  subagentBackend_codex: "Codex",
@@ -6263,6 +6269,12 @@ window.__ModuleLoader__.load({
6263
6269
  inputImageDetail_low: "Low",
6264
6270
  inputImageDetail_high: "High",
6265
6271
  inputImageDetail_original: "Original",
6272
+ reasoningSummary: "Reasoning summary",
6273
+ reasoningSummaryHint: "Shows a summary of the reasoning in the Thinking section of the conversation. Auto lets the model decide; concise is shorter; detailed is fuller; off asks for none.",
6274
+ reasoningSummary_auto: "Auto",
6275
+ reasoningSummary_concise: "Concise",
6276
+ reasoningSummary_detailed: "Detailed",
6277
+ reasoningSummary_none: "Off",
6266
6278
  subagentBackendTitle: "Independent subtasks",
6267
6279
  subagentBackend_dsh: "DSH",
6268
6280
  subagentBackend_codex: "Codex",
@@ -8368,6 +8380,14 @@ window.__ModuleLoader__.load({
8368
8380
  const OUTPUT_VERBOSITY_MEDIUM = "medium";
8369
8381
  const OUTPUT_VERBOSITY_HIGH = "high";
8370
8382
  const DEFAULT_OUTPUT_VERBOSITY = OUTPUT_VERBOSITY_DEFAULT;
8383
+ const REASONING_SUMMARY_FIELD = "reasoningSummary";
8384
+ const REASONING_SUMMARIES = Object.freeze([
8385
+ "auto",
8386
+ "concise",
8387
+ "detailed",
8388
+ "none"
8389
+ ]);
8390
+ const DEFAULT_REASONING_SUMMARY = "auto";
8371
8391
  const INPUT_IMAGE_DETAIL_FIELD = "inputImageDetail";
8372
8392
  const INPUT_IMAGE_DETAILS = Object.freeze([
8373
8393
  "low",
@@ -8427,6 +8447,7 @@ window.__ModuleLoader__.load({
8427
8447
  "medium",
8428
8448
  "high"
8429
8449
  ].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
8450
+ const normalizeReasoningSummary = (value) => REASONING_SUMMARIES.includes(value) ? value : DEFAULT_REASONING_SUMMARY;
8430
8451
  const normalizeInputImageDetail = (value) => INPUT_IMAGE_DETAILS.includes(value) ? value : DEFAULT_INPUT_IMAGE_DETAIL;
8431
8452
  const normalizeStreamIdleTimeoutMinutes = (value) => STREAM_IDLE_TIMEOUT_MINUTES.includes(value) ? value : 10;
8432
8453
  const normalizeSpeedMode = (value) => [
@@ -8507,6 +8528,7 @@ window.__ModuleLoader__.load({
8507
8528
  speedMode: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
8508
8529
  outputVerbosity: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
8509
8530
  inputImageDetail: normalizeInputImageDetail(value?.[INPUT_IMAGE_DETAIL_FIELD]),
8531
+ reasoningSummary: normalizeReasoningSummary(value?.[REASONING_SUMMARY_FIELD]),
8510
8532
  streamIdleTimeoutMinutes: normalizeStreamIdleTimeoutMinutes(value?.[STREAM_IDLE_TIMEOUT_MINUTES_FIELD]),
8511
8533
  contextMode: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
8512
8534
  customContextWindow: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
@@ -8566,6 +8588,7 @@ window.__ModuleLoader__.load({
8566
8588
  [SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
8567
8589
  [OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
8568
8590
  [INPUT_IMAGE_DETAIL_FIELD]: normalizeInputImageDetail(value?.[INPUT_IMAGE_DETAIL_FIELD]),
8591
+ [REASONING_SUMMARY_FIELD]: normalizeReasoningSummary(value?.[REASONING_SUMMARY_FIELD]),
8569
8592
  [STREAM_IDLE_TIMEOUT_MINUTES_FIELD]: normalizeStreamIdleTimeoutMinutes(value?.[STREAM_IDLE_TIMEOUT_MINUTES_FIELD]),
8570
8593
  [CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
8571
8594
  [CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
@@ -8995,7 +9018,6 @@ window.__ModuleLoader__.load({
8995
9018
  const NS = "settings.codexSubscription";
8996
9019
  const SUPPORT_ISSUE_URL = "https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml";
8997
9020
  const QUICK_QUOTA_REFRESH_EVENT = "dsh-codex-subscription:refresh-quick-quota";
8998
- const QUICK_QUOTA_REFRESH_MS = 6e4;
8999
9021
  const accountStatusErrorText = (error, t) => {
9000
9022
  const key = {
9001
9023
  "credential-unavailable": "accountCredentialUnavailable",
@@ -9091,7 +9113,7 @@ window.__ModuleLoader__.load({
9091
9113
  }
9092
9114
  //#endregion
9093
9115
  //#region src/version.js
9094
- const PACKAGE_VERSION = "2.5.9";
9116
+ const PACKAGE_VERSION = "2.6.0";
9095
9117
  //#endregion
9096
9118
  //#region src/client-recovery.js
9097
9119
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -9119,6 +9141,21 @@ window.__ModuleLoader__.load({
9119
9141
  };
9120
9142
  }
9121
9143
  //#endregion
9144
+ //#region src/quota-cadence.js
9145
+ /** Milliseconds until the next quota read, from the highest used percentage of the windows that matter. */
9146
+ function quotaRefreshMs(percent) {
9147
+ if (!Number.isFinite(percent)) return 6e4;
9148
+ if (percent >= 99) return 5e3;
9149
+ if (percent >= 90) return 15e3;
9150
+ if (percent >= 75) return 3e4;
9151
+ return 6e4;
9152
+ }
9153
+ /** Highest used percentage among windows (objects with usedPercent), or undefined when there are none. */
9154
+ function highestUsed(windows) {
9155
+ const values = (Array.isArray(windows) ? windows : []).map((window) => window?.usedPercent).filter(Number.isFinite);
9156
+ return values.length === 0 ? void 0 : Math.max(...values);
9157
+ }
9158
+ //#endregion
9122
9159
  //#region src/client-quota.jsx
9123
9160
  function useQuickQuota(rpc, enabled, model) {
9124
9161
  const [quota, setQuota] = (0, react.useState)();
@@ -9130,6 +9167,8 @@ window.__ModuleLoader__.load({
9130
9167
  setQuota(void 0);
9131
9168
  let live = true;
9132
9169
  let loading = false;
9170
+ let timer;
9171
+ let latest;
9133
9172
  const load = async () => {
9134
9173
  if (loading) return;
9135
9174
  loading = true;
@@ -9141,25 +9180,31 @@ window.__ModuleLoader__.load({
9141
9180
  return;
9142
9181
  }
9143
9182
  const usage = await recoveryCall(rpc, "usage", { force: false });
9144
- if (live) setQuota(selectModelQuotaWindows(usage, model)?.map((window) => ({
9183
+ const windows = selectModelQuotaWindows(usage, model)?.map((window) => ({
9145
9184
  ...window,
9146
9185
  fetchedAt: usage.fetchedAt
9147
- })));
9186
+ }));
9187
+ latest = windows;
9188
+ if (live) setQuota(windows);
9148
9189
  } catch {
9190
+ latest = void 0;
9149
9191
  if (live) setQuota(void 0);
9150
9192
  } finally {
9151
9193
  loading = false;
9194
+ if (live) {
9195
+ window.clearTimeout(timer);
9196
+ timer = window.setTimeout(refresh, quotaRefreshMs(highestUsed(latest)));
9197
+ }
9152
9198
  }
9153
9199
  };
9154
9200
  const refresh = () => {
9155
9201
  load();
9156
9202
  };
9157
9203
  load();
9158
- const timer = window.setInterval(refresh, QUICK_QUOTA_REFRESH_MS);
9159
9204
  window.addEventListener(QUICK_QUOTA_REFRESH_EVENT, refresh);
9160
9205
  return () => {
9161
9206
  live = false;
9162
- window.clearInterval(timer);
9207
+ window.clearTimeout(timer);
9163
9208
  window.removeEventListener(QUICK_QUOTA_REFRESH_EVENT, refresh);
9164
9209
  };
9165
9210
  }, [
@@ -10404,6 +10449,41 @@ window.__ModuleLoader__.load({
10404
10449
  })]
10405
10450
  });
10406
10451
  }
10452
+ function ReasoningSummaryPreference({ preference, t }) {
10453
+ const snapshot = usePreferenceSnapshot(preference);
10454
+ const writable = snapshot.status === "ready" && snapshot.writable === true;
10455
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10456
+ className: "codexSubscriptionPreference",
10457
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10458
+ className: "codexSubscriptionPreferenceCopy",
10459
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10460
+ className: "codexSubscriptionPreferenceLabel",
10461
+ children: t("reasoningSummary")
10462
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10463
+ className: "codexSubscriptionPreferenceHint",
10464
+ children: t("reasoningSummaryHint")
10465
+ })]
10466
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10467
+ className: "codexSubscriptionQuotaModes",
10468
+ "data-saving": snapshot.saving || void 0,
10469
+ "aria-busy": snapshot.saving || void 0,
10470
+ role: "radiogroup",
10471
+ "aria-label": t("reasoningSummary"),
10472
+ children: REASONING_SUMMARIES.map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
10473
+ className: "codexSubscriptionQuotaMode",
10474
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
10475
+ type: "radio",
10476
+ name: "codex-reasoning-summary",
10477
+ checked: snapshot.reasoningSummary === value,
10478
+ disabled: !writable,
10479
+ onChange: () => {
10480
+ preference.set({ [REASONING_SUMMARY_FIELD]: value });
10481
+ }
10482
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(`reasoningSummary_${value}`) })]
10483
+ }, value))
10484
+ })]
10485
+ });
10486
+ }
10407
10487
  function StreamIdleTimeoutPreference({ preference, t }) {
10408
10488
  const snapshot = usePreferenceSnapshot(preference);
10409
10489
  const writable = snapshot.status === "ready" && snapshot.writable === true;
@@ -10707,6 +10787,11 @@ window.__ModuleLoader__.load({
10707
10787
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InputImageDetailPreference, {
10708
10788
  preference,
10709
10789
  t
10790
+ }),
10791
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "codexSubscriptionDivider" }),
10792
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningSummaryPreference, {
10793
+ preference,
10794
+ t
10710
10795
  })
10711
10796
  ]
10712
10797
  }),
package/lib/index.js CHANGED
@@ -296,6 +296,14 @@ const OUTPUT_VERBOSITY_DEFAULT = "default";
296
296
  const OUTPUT_VERBOSITY_MEDIUM = "medium";
297
297
  const OUTPUT_VERBOSITY_HIGH = "high";
298
298
  const DEFAULT_OUTPUT_VERBOSITY = OUTPUT_VERBOSITY_DEFAULT;
299
+ const REASONING_SUMMARY_FIELD = "reasoningSummary";
300
+ const REASONING_SUMMARIES = Object.freeze([
301
+ "auto",
302
+ "concise",
303
+ "detailed",
304
+ "none"
305
+ ]);
306
+ const DEFAULT_REASONING_SUMMARY = "auto";
299
307
  const INPUT_IMAGE_DETAIL_FIELD = "inputImageDetail";
300
308
  const INPUT_IMAGE_DETAILS = Object.freeze([
301
309
  "low",
@@ -350,6 +358,7 @@ const normalizeOutputVerbosity = (value) => [
350
358
  "medium",
351
359
  "high"
352
360
  ].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
361
+ const normalizeReasoningSummary = (value) => REASONING_SUMMARIES.includes(value) ? value : DEFAULT_REASONING_SUMMARY;
353
362
  const normalizeInputImageDetail = (value) => INPUT_IMAGE_DETAILS.includes(value) ? value : DEFAULT_INPUT_IMAGE_DETAIL;
354
363
  const normalizeStreamIdleTimeoutMinutes = (value) => STREAM_IDLE_TIMEOUT_MINUTES.includes(value) ? value : 10;
355
364
  const normalizeContextMode = (value) => [
@@ -471,6 +480,11 @@ const PREFERENCE_FIELDS = Object.freeze({
471
480
  default: DEFAULT_OUTPUT_VERBOSITY,
472
481
  error: "Invalid output verbosity preference"
473
482
  },
483
+ [REASONING_SUMMARY_FIELD]: {
484
+ choices: REASONING_SUMMARIES,
485
+ default: DEFAULT_REASONING_SUMMARY,
486
+ error: "Invalid reasoning summary preference"
487
+ },
474
488
  [INPUT_IMAGE_DETAIL_FIELD]: {
475
489
  choices: INPUT_IMAGE_DETAILS,
476
490
  default: DEFAULT_INPUT_IMAGE_DETAIL,
@@ -1292,7 +1306,8 @@ const SUPPORTED_RUNTIME_VERSIONS = Object.freeze([
1292
1306
  "0.1.7-rc.2",
1293
1307
  "0.2.0-rc.1",
1294
1308
  "0.2.0-rc.2",
1295
- "0.2.1-alpha.1"
1309
+ "0.2.1-alpha.1",
1310
+ "0.2.1-alpha.2"
1296
1311
  ]);
1297
1312
  const require = createRequire(import.meta.url);
1298
1313
  const execute = promisify(execFile);
@@ -2049,7 +2064,7 @@ function inheritedOriginalImageRef(session, assetId) {
2049
2064
  }
2050
2065
  //#endregion
2051
2066
  //#region src/version.js
2052
- const PACKAGE_VERSION = "2.5.9";
2067
+ const PACKAGE_VERSION = "2.6.0";
2053
2068
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
2054
2069
  //#endregion
2055
2070
  //#region src/codex-images.js
@@ -2222,7 +2237,7 @@ async function readSessionImage(attachmentId, attachments, signal, messages) {
2222
2237
  };
2223
2238
  }
2224
2239
  async function editImages(values, attachments, signal, messages) {
2225
- if (!Array.isArray(values) || values.length === 0 || values.length > MAX_REFERENCE_IMAGES) throw new Error(`referenceImages must contain between 1 and ${MAX_REFERENCE_IMAGES} images`);
2240
+ if (!Array.isArray(values) || values.length === 0 || values.length > MAX_REFERENCE_IMAGES) throw new Error(`referenceImages must contain between 1 and ${MAX_REFERENCE_IMAGES} images; omit it to generate a new image`);
2226
2241
  const available = messages === void 0 ? void 0 : sessionImageReferences(messages);
2227
2242
  const references = values.map((value) => {
2228
2243
  const id = normalizeAttachmentId(value?.attachmentId);
@@ -2247,7 +2262,7 @@ function imageContent(value) {
2247
2262
  const label = typeof value.size === "string" && value.size.length > 0 ? `Generated a ${value.size} image.` : "Generated an image.";
2248
2263
  return [{
2249
2264
  type: "text",
2250
- text: value.localPath === void 0 ? label : `${label}\nOriginal PNG saved on the DSH host at: ${JSON.stringify(value.localPath)}. Read this file or copy it to the workspace with a .png extension; this host path is not a browser URL.`
2265
+ text: value.localPath === void 0 ? label : `${label}\nOriginal PNG saved on the DSH host at: ${JSON.stringify(value.localPath)}. Read this file or copy it to the workspace with a .png extension; this host path is not a browser URL. The image is already shown to the user, so do not embed it again; copy it rather than move it, and leave the original in place unless the user asks you to delete it.`
2251
2266
  }, {
2252
2267
  type: "image",
2253
2268
  attachment: imageReference(value.image)
@@ -2351,6 +2366,41 @@ function imageOutputSchema() {
2351
2366
  }
2352
2367
  };
2353
2368
  }
2369
+ const SUPPORT_ID = /^[A-Za-z0-9._-]{1,80}$/u;
2370
+ /** The request id Codex returns for an image call, kept on failures so a report can be traced. */
2371
+ function supportId(response) {
2372
+ const id = response.headers?.get?.("x-codex-imagegen-request-id");
2373
+ return typeof id === "string" && SUPPORT_ID.test(id) ? ` (request ${id})` : "";
2374
+ }
2375
+ /** What a 429 from the image endpoint says: when the limit resets, when the response tells us. */
2376
+ async function limitMessage(response, now = Date.now()) {
2377
+ const fallback = "Codex image generation quota is unavailable";
2378
+ let error;
2379
+ try {
2380
+ error = JSON.parse(await readTextWithin(response, 16 * 1024))?.error;
2381
+ } catch {
2382
+ return fallback;
2383
+ }
2384
+ if (!record$4(error)) return fallback;
2385
+ const at = Number.isSafeInteger(error.resets_at) && error.resets_at > 0 ? error.resets_at * 1e3 : Number.isSafeInteger(error.resets_in_seconds) && error.resets_in_seconds > 0 ? now + error.resets_in_seconds * 1e3 : void 0;
2386
+ if (at === void 0) return fallback;
2387
+ const minutes = Math.max(1, Math.ceil((at - now) / 6e4));
2388
+ return `Codex image generation limit reached; it resets in about ${minutes >= 120 ? `${Math.round(minutes / 60)} hours` : `${minutes} minutes`}`;
2389
+ }
2390
+ async function readTextWithin(response, maximumBytes) {
2391
+ if (response.body === null || response.body === void 0) return "";
2392
+ const reader = response.body.getReader();
2393
+ const chunks = [];
2394
+ let bytes = 0;
2395
+ while (bytes < maximumBytes) {
2396
+ const { done, value } = await reader.read();
2397
+ if (done) break;
2398
+ bytes += value.byteLength;
2399
+ chunks.push(value);
2400
+ }
2401
+ await reader.cancel().catch(() => {});
2402
+ return Buffer.concat(chunks.map((chunk) => Buffer.from(chunk))).toString("utf8").slice(0, maximumBytes);
2403
+ }
2354
2404
  function responseMetadata(value) {
2355
2405
  const data = Array.isArray(value?.data) ? value.data[0] : void 0;
2356
2406
  const encoded = record$4(data) ? data.b64_json : void 0;
@@ -2468,6 +2518,10 @@ function createCodexImageTool(options) {
2468
2518
  timeoutMs: 300 * 1e3,
2469
2519
  isConcurrencySafe: () => false,
2470
2520
  async execute(args, exec) {
2521
+ if (Array.isArray(args.referenceImages) && args.referenceImages.length === 0) {
2522
+ const { referenceImages: _empty, ...rest } = args;
2523
+ args = rest;
2524
+ }
2471
2525
  assertImageOperation(options.getFeatures?.(), args.referenceImages !== void 0);
2472
2526
  const defaults = readImageDefaults(options.getFeatures?.());
2473
2527
  args = {
@@ -2516,8 +2570,9 @@ function createCodexImageTool(options) {
2516
2570
  }
2517
2571
  if (!response.ok) {
2518
2572
  if (response.status === 401 || response.status === 403) throw new Error("ChatGPT sign-in needs to be renewed");
2519
- if (response.status === 429) throw new Error("Codex image generation quota is unavailable");
2520
- throw new Error(`Codex image ${editing ? "edit" : "generation"} failed (HTTP ${response.status})`);
2573
+ const requestId = supportId(response);
2574
+ if (response.status === 429) throw new Error(`${await limitMessage(response)}${requestId}`);
2575
+ throw new Error(`Codex image ${editing ? "edit" : "generation"} failed (HTTP ${response.status})${requestId}`);
2521
2576
  }
2522
2577
  const metadata = responseMetadata(await readJsonWithin(response, encodedLimit(maximumBytes) + RESPONSE_ENVELOPE_BYTES));
2523
2578
  const data = decodeCodexPng(metadata.encoded, maximumBytes);
@@ -3561,6 +3616,18 @@ function normalizeTransportEvent(event, signal) {
3561
3616
  const FAST_SERVICE_TIER = "priority";
3562
3617
  const ULTRAFAST_SERVICE_TIER = "ultrafast";
3563
3618
  /** Apply the chosen detail to user and tool-result images after the provider assembles the request. */
3619
+ const withoutUserAgent = (headers) => headers && typeof headers === "object" ? Object.fromEntries(Object.entries(headers).filter(([name]) => name.toLowerCase() !== "user-agent")) : headers;
3620
+ function withReasoningSummary(payload, summary) {
3621
+ if (summary === "auto" || payload?.reasoning === void 0 || payload.reasoning === null) return payload;
3622
+ const { summary: _previous, ...rest } = payload.reasoning;
3623
+ return {
3624
+ ...payload,
3625
+ reasoning: summary === "none" ? rest : {
3626
+ ...rest,
3627
+ summary
3628
+ }
3629
+ };
3630
+ }
3564
3631
  function withInputImageDetail(payload, detail) {
3565
3632
  if (!Array.isArray(payload.input)) return payload;
3566
3633
  let changed = false;
@@ -3614,7 +3681,7 @@ function isDshAutoReview(context) {
3614
3681
  * persistence, headers, transport, and model behavior remain owned by the
3615
3682
  * original provider.
3616
3683
  */
3617
- function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveInputImageDetail = () => void 0, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, resolveReviewModel = () => REVIEW_MODEL_SESSION, catalog, connection, compaction, runNetwork = (_area, operation) => operation() } = {}) {
3684
+ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveInputImageDetail = () => void 0, resolveReasoningSummary = () => void 0, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, resolveReviewModel = () => REVIEW_MODEL_SESSION, catalog, connection, compaction, runNetwork = (_area, operation) => operation() } = {}) {
3618
3685
  const provider = createOpenAICodexProvider();
3619
3686
  const requestToken = Object.freeze({
3620
3687
  name: "DSH-managed Codex OAuth request token",
@@ -3636,9 +3703,11 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
3636
3703
  const speedMode = resolveSpeedMode();
3637
3704
  const serviceTier = speedMode === "ultrafast" && metadata?.supportsUltrafast === true ? ULTRAFAST_SERVICE_TIER : speedMode === "fast" && (metadata?.supportsFast ?? supportsCodexFastMode(model?.id)) ? FAST_SERVICE_TIER : void 0;
3638
3705
  const inputImageDetail = normalizeInputImageDetail(resolveInputImageDetail());
3706
+ const reasoningSummary = normalizeReasoningSummary(resolveReasoningSummary());
3639
3707
  const { temperature: _temperature, onPayload, ...rest } = options;
3640
3708
  return {
3641
3709
  ...rest,
3710
+ ...rest.headers === void 0 ? {} : { headers: withoutUserAgent(rest.headers) },
3642
3711
  ...textVerbosity === void 0 ? {} : { textVerbosity },
3643
3712
  ...serviceTier === void 0 ? {} : { serviceTier },
3644
3713
  async onPayload(payload, requestModel) {
@@ -3653,7 +3722,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
3653
3722
  const managed = compaction?.preparePayload(preferred, model?.contextWindow) ?? preferred;
3654
3723
  const next = await onPayload?.(managed, requestModel);
3655
3724
  const detailed = inputImageDetail === "auto" ? next ?? managed : withInputImageDetail(next ?? managed, inputImageDetail);
3656
- const { temperature: _dropped, ...accepted } = detailed;
3725
+ const { temperature: _dropped, ...accepted } = withReasoningSummary(detailed, reasoningSummary);
3657
3726
  return {
3658
3727
  ...accepted,
3659
3728
  ...textVerbosity === void 0 ? {} : { text: {
@@ -3700,6 +3769,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
3700
3769
  const { temperature: _temperature, onPayload, ...rest } = options;
3701
3770
  return {
3702
3771
  ...rest,
3772
+ ...rest.headers === void 0 ? {} : { headers: withoutUserAgent(rest.headers) },
3703
3773
  async onPayload(payload, requestModel) {
3704
3774
  const { temperature: _dropped, service_tier: _tier, text: _text, ...accepted } = await onPayload?.(payload, requestModel) ?? payload;
3705
3775
  return {
@@ -3790,7 +3860,8 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
3790
3860
  Object.freeze([
3791
3861
  "0.82.1",
3792
3862
  "0.85.1",
3793
- "0.87.1"
3863
+ "0.87.1",
3864
+ "1.1.0"
3794
3865
  ]);
3795
3866
  //#endregion
3796
3867
  //#region src/model-catalog.js
@@ -4941,21 +5012,35 @@ function creditExpiry({ planType, balance, apiExpiresAt }, now = Date.now()) {
4941
5012
  };
4942
5013
  }
4943
5014
  //#endregion
5015
+ //#region src/quota-cadence.js
5016
+ /** Milliseconds until the next quota read, from the highest used percentage of the windows that matter. */
5017
+ function quotaRefreshMs(percent) {
5018
+ if (!Number.isFinite(percent)) return 6e4;
5019
+ if (percent >= 99) return 5e3;
5020
+ if (percent >= 90) return 15e3;
5021
+ if (percent >= 75) return 3e4;
5022
+ return 6e4;
5023
+ }
5024
+ /** Highest used percentage among windows (objects with usedPercent), or undefined when there are none. */
5025
+ function highestUsed(windows) {
5026
+ const values = (Array.isArray(windows) ? windows : []).map((window) => window?.usedPercent).filter(Number.isFinite);
5027
+ return values.length === 0 ? void 0 : Math.max(...values);
5028
+ }
5029
+ //#endregion
4944
5030
  //#region src/usage.js
4945
5031
  const CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
4946
- const DEFAULT_TTL_MS = 6e4;
4947
5032
  const DEFAULT_TIMEOUT_MS$1 = 15e3;
4948
5033
  const DEFAULT_FAILURE_TTL_MS = 5e3;
4949
5034
  const DEFAULT_MAX_RETRY_AFTER_MS = 5 * 6e4;
4950
5035
  const record$1 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
4951
- function windowOf(value) {
5036
+ function windowOf(value, nowSeconds) {
4952
5037
  if (value === void 0 || value === null) return void 0;
4953
5038
  if (!record$1(value)) throw new Error("Codex returned a malformed rate-limit window");
4954
5039
  const used = value.used_percent;
4955
5040
  const seconds = value.limit_window_seconds;
4956
5041
  if (!Number.isFinite(used) || used < 0 || used > 100) throw new Error("Codex returned an invalid used percentage");
4957
5042
  if (!Number.isInteger(seconds) || seconds <= 0) throw new Error("Codex returned an invalid window duration");
4958
- const resetsAt = epochSeconds(value.reset_at, "rate-limit reset time");
5043
+ const resetsAt = epochSeconds(value.reset_at, "rate-limit reset time") ?? (Number.isInteger(value.reset_after_seconds) && value.reset_after_seconds > 0 && Number.isFinite(nowSeconds) ? nowSeconds + value.reset_after_seconds : void 0);
4959
5044
  return {
4960
5045
  usedPercent: used,
4961
5046
  remainingPercent: 100 - used,
@@ -4963,10 +5048,10 @@ function windowOf(value) {
4963
5048
  ...resetsAt === void 0 ? {} : { resetsAt }
4964
5049
  };
4965
5050
  }
4966
- function limitOf(id, name, value) {
5051
+ function limitOf(id, name, value, nowSeconds) {
4967
5052
  if (value === void 0 || value === null) return void 0;
4968
5053
  if (!record$1(value)) throw new Error("Codex returned malformed rate-limit details");
4969
- const windows = [windowOf(value.primary_window), windowOf(value.secondary_window)].filter(Boolean);
5054
+ const windows = [windowOf(value.primary_window, nowSeconds), windowOf(value.secondary_window, nowSeconds)].filter(Boolean);
4970
5055
  return windows.length === 0 ? void 0 : {
4971
5056
  id,
4972
5057
  ...name ? { name } : {},
@@ -5066,7 +5151,8 @@ function resetCreditsOf(value) {
5066
5151
  };
5067
5152
  }
5068
5153
  /** Reduce the provider payload to a browser-safe quota projection. */
5069
- function parseCodexUsage(value) {
5154
+ function parseCodexUsage(value, nowMs = Date.now()) {
5155
+ const nowSeconds = Math.floor(nowMs / 1e3);
5070
5156
  if (!record$1(value)) throw new Error("Codex returned a malformed usage response");
5071
5157
  const rateLimits = [];
5072
5158
  const seenLimitIds = /* @__PURE__ */ new Set();
@@ -5075,21 +5161,27 @@ function parseCodexUsage(value) {
5075
5161
  seenLimitIds.add(limit.id);
5076
5162
  rateLimits.push(limit);
5077
5163
  };
5078
- addLimit(limitOf("codex", "Codex", value.rate_limit));
5164
+ addLimit(limitOf("codex", "Codex", value.rate_limit, nowSeconds));
5079
5165
  if (value.additional_rate_limits !== void 0 && value.additional_rate_limits !== null && !Array.isArray(value.additional_rate_limits)) throw new Error("Codex returned malformed additional rate limits");
5080
5166
  for (const entry of value.additional_rate_limits ?? []) {
5081
5167
  if (!record$1(entry) || typeof entry.metered_feature !== "string" || entry.metered_feature.length === 0) throw new Error("Codex returned a malformed additional rate limit");
5082
5168
  if (entry.limit_name !== void 0 && entry.limit_name !== null && typeof entry.limit_name !== "string") throw new Error("Codex returned an invalid additional rate-limit name");
5083
- addLimit(limitOf(entry.metered_feature, entry.limit_name || void 0, entry.rate_limit));
5169
+ addLimit(limitOf(entry.metered_feature, entry.limit_name || void 0, entry.rate_limit, nowSeconds));
5084
5170
  }
5085
- addLimit(limitOf("code_review", "Code review", value.code_review_rate_limit));
5171
+ addLimit(limitOf("code_review", "Code review", value.code_review_rate_limit, nowSeconds));
5086
5172
  const chatPass = chatPassOf(value.chatpass);
5087
5173
  const credits = creditsOf(value.credits, typeof value.plan_type === "string" ? value.plan_type : void 0);
5088
5174
  const individualLimit = individualOf(value.spend_control);
5089
5175
  const spendControlReached = spendControlReachedOf(value.spend_control);
5090
5176
  const resetCredits = resetCreditsOf(value.rate_limit_reset_credits);
5177
+ const planType = typeof value.plan_type === "string" && /^[a-z][a-z_]{0,31}$/u.test(value.plan_type) ? value.plan_type : void 0;
5178
+ const reached = value.rate_limit_reached_type;
5179
+ const reachedRaw = typeof reached === "string" ? reached : record$1(reached) ? reached.type : void 0;
5180
+ const rateLimitReachedType = typeof reachedRaw === "string" && /^[a-z][a-z_]{0,63}$/u.test(reachedRaw) ? reachedRaw : void 0;
5091
5181
  return {
5092
5182
  rateLimits,
5183
+ ...rateLimitReachedType === void 0 ? {} : { rateLimitReachedType },
5184
+ ...planType === void 0 ? {} : { planType },
5093
5185
  ...chatPass === void 0 ? {} : { chatPass },
5094
5186
  ...credits === void 0 ? {} : { credits },
5095
5187
  ...individualLimit === void 0 ? {} : { individualLimit },
@@ -5120,7 +5212,7 @@ function createCodexUsageReader(options) {
5120
5212
  const readCredential = options.readCredential;
5121
5213
  const fetchUsage = options.fetch ?? fetch;
5122
5214
  const now = options.now ?? Date.now;
5123
- const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
5215
+ const ttlFor = (value) => options.ttlMs ?? quotaRefreshMs(highestUsed(value?.rateLimits?.find((limit) => limit.id === "codex")?.windows));
5124
5216
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS$1;
5125
5217
  const failureTtlMs = options.failureTtlMs ?? DEFAULT_FAILURE_TTL_MS;
5126
5218
  const maxRetryAfterMs = options.maxRetryAfterMs ?? DEFAULT_MAX_RETRY_AFTER_MS;
@@ -5155,14 +5247,14 @@ function createCodexUsageReader(options) {
5155
5247
  throw new Error("ChatGPT returned an unreadable usage response");
5156
5248
  }
5157
5249
  return {
5158
- ...parseCodexUsage(value),
5250
+ ...parseCodexUsage(value, now()),
5159
5251
  fetchedAt: now()
5160
5252
  };
5161
5253
  };
5162
5254
  return Object.freeze({
5163
5255
  read({ force = false, signal } = {}) {
5164
5256
  if (failed !== void 0 && now() < failed.retryAt) return Promise.reject(new Error(failed.message));
5165
- if (!force && cached !== void 0 && now() - cached.fetchedAt < ttlMs) return Promise.resolve(structuredClone(cached));
5257
+ if (!force && cached !== void 0 && now() - cached.fetchedAt < ttlFor(cached)) return Promise.resolve(structuredClone(cached));
5166
5258
  if (inFlight !== void 0) return inFlight.then(structuredClone);
5167
5259
  const currentGeneration = generation;
5168
5260
  const current = load(signal).then((value) => {
@@ -5246,6 +5338,7 @@ function createWakeSignal() {
5246
5338
  };
5247
5339
  }
5248
5340
  function shortResetDelay(usage, nowMs, maxWaitMs, resetMarginMs) {
5341
+ if (typeof usage?.rateLimitReachedType === "string" && /^(?:workspace_|.*credits_depleted)/u.test(usage.rateLimitReachedType)) return void 0;
5249
5342
  let latestDelayMs;
5250
5343
  for (const limit of usage?.rateLimits ?? []) {
5251
5344
  if (limit?.id !== "codex") continue;
@@ -6383,6 +6476,7 @@ function apply(ctx, config = {}) {
6383
6476
  resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD],
6384
6477
  resolveOutputVerbosity: () => normalizeOutputVerbosity(settings.get()[OUTPUT_VERBOSITY_FIELD]),
6385
6478
  resolveInputImageDetail: () => settings.get()[INPUT_IMAGE_DETAIL_FIELD],
6479
+ resolveReasoningSummary: () => settings.get()[REASONING_SUMMARY_FIELD],
6386
6480
  resolveContextMode: () => normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
6387
6481
  resolveCustomContextWindow: (modelKey) => {
6388
6482
  const overrides = readCapabilitySettings(settings.get())[CUSTOM_CONTEXT_OVERRIDES_FIELD];
@@ -6413,6 +6507,7 @@ function apply(ctx, config = {}) {
6413
6507
  [SPEED_MODE_FIELD]: settings.get()[SPEED_MODE_FIELD],
6414
6508
  [OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(settings.get()[OUTPUT_VERBOSITY_FIELD]),
6415
6509
  [INPUT_IMAGE_DETAIL_FIELD]: normalizeInputImageDetail(settings.get()[INPUT_IMAGE_DETAIL_FIELD]),
6510
+ [REASONING_SUMMARY_FIELD]: normalizeReasoningSummary(settings.get()[REASONING_SUMMARY_FIELD]),
6416
6511
  [STREAM_IDLE_TIMEOUT_MINUTES_FIELD]: normalizeStreamIdleTimeoutMinutes(settings.get()[STREAM_IDLE_TIMEOUT_MINUTES_FIELD]),
6417
6512
  [CONTEXT_MODE_FIELD]: normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
6418
6513
  [CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(settings.get()[CUSTOM_CONTEXT_WINDOW_FIELD]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.5.9",
3
+ "version": "2.6.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",
@@ -77,26 +77,26 @@
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@deepseek-ai/cordis": "4.0.1 || 4.0.2 || 4.0.3 || 4.0.4 || 4.0.5-alpha.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 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.2",
95
95
  "@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
96
- "@earendil-works/pi-ai": "0.82.1 || 0.85.1 || 0.87.1",
96
+ "@earendil-works/pi-ai": "0.82.1 || 0.85.1 || 0.87.1 || 1.1.0",
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 || 0.2.0-rc.2 || 0.2.1-alpha.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 || 0.2.1-alpha.1 || 0.2.1-alpha.2"
100
100
  },
101
101
  "devDependencies": {
102
102
  "@deepseek-ai/cordis": "4.0.4",