@tnnevol/dsh-codex-auth 0.1.0-rc.7.2 → 0.1.0-rc.8.1

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.md CHANGED
@@ -1,54 +1,5 @@
1
1
  # @tnnevol/dsh-codex-auth
2
2
 
3
- 一个独立的 DeepSeek Harness Codex OAuth 插件,适配 DSH `0.1.0-rc.7`。
3
+ Codex Auth 插件的功能、交互、安装和调试文档已统一迁移到文档站的 [Harness 插件](https://fnapps-doc.tnnevol.cn/plugins/) 章节。
4
4
 
5
- ## 功能
6
-
7
- - 在 DSH Web 的“插件”设置中提供 ChatGPT 登录和退出登录入口。
8
- - 通过 `@earendil-works/pi-ai` 发起 Codex device-code 授权,由插件展示一次性授权码并轮询登录结果。
9
- - 授权页面不要求选择工作空间;用户只需在 Codex 授权页面提交插件生成的一次性代码。
10
- - 复用 `dsh-codex-connect` 的凭据文件格式:`$DSH_HOME/.openai-codex-auth.json`。
11
- - 复用 `dsh-llm-pi-ai` 的官方模型设置入口,使 OpenAI Codex 在模型列表中显示登录状态,并直接展示可编辑的模型目录。
12
- - OAuth 登录成功后,将当前 access token 同步到 `OPENAI_CODEX_AUTH_TOKEN` 凭据引用;OAuth 文件仍是唯一登录源,凭据引用只是给通用 pi-ai adapter 和官方模型页使用的镜像。
13
- - Codex 编辑页隐藏通用的 API 密钥和 API 地址字段,避免用户误改 OAuth 管理的认证与端点;模型目录仍使用 DSH 官方编辑器。
14
- - 模型列表弹框增加“全选”,确认按钮文案为“确定”,并使用官方保存按钮的主色。
15
- - 在“设置 → 插件 → Codex Auth”中提供图片识别开关;开启后按 DSH 附件规范注册 `view_image`,仅允许当前图片模型读取经过文件系统权限控制的本地图片。
16
- - 图像生成开关会明确显示为当前不可用:DSH `rc.7` 的 Codex provider 只声明图片输入,不提供图像输出能力。
17
- - 通过 DSH `rc.7` 的 keyed slot `settings.plugin.item` 注册 UI,并显式提供 `key`。
18
-
19
- ## 本地构建
20
-
21
- 在仓库根目录执行:
22
-
23
- ```sh
24
- pnpm --filter @tnnevol/dsh-codex-auth install
25
- pnpm --filter @tnnevol/dsh-codex-auth run check
26
- ```
27
-
28
- ## 使用本地 DSH CLI 调试
29
-
30
- 先确保本地 DSH 源码已经安装依赖并可运行,然后在 DSH 仓库目录执行:
31
-
32
- ```sh
33
- pnpm --filter @tnnevol/dsh-codex-auth run build
34
- pnpm dsh web --patch /absolute/path/to/fn-os-apps/plugins/dsh-codex-auth-plugin/cordis.patch.yml
35
- ```
36
-
37
- `cordis.patch.yml` 使用包名加载 Host bundle;如果要调试尚未构建的源码,可将 patch 中的 `name` 改成源码入口的绝对路径,并使用 DSH skill 中的 `--patch` 调试流程。
38
-
39
- ## 发布 rc 版本
40
-
41
- 当前版本为 npm prerelease,发布时必须使用 `rc` dist-tag:
42
-
43
- ```sh
44
- npm run publish:rc
45
- ```
46
-
47
- ## 安装到 profile
48
-
49
- ```sh
50
- dsh plugin --profile web add @tnnevol/dsh-codex-auth
51
- dsh --profile web --dump-config
52
- ```
53
-
54
- 安装后重新启动 Web profile。该插件不应与旧的 `dsh-codex-connect` 同时注册同一套 Codex 模型能力;迁移时请先停用旧插件,再启用本插件。
5
+ 本 README 仅保留插件识别信息,不再维护具体功能说明。
@@ -4,7 +4,7 @@
4
4
  "node": "^22.19.0 || >=24.0.0"
5
5
  },
6
6
  "dshPluginApi": {
7
- "version": "0.1.0-rc.7",
7
+ "version": "0.1.0-rc.8",
8
8
  "packages": [
9
9
  "@deepseek-ai/dsh-atomic-write",
10
10
  "@deepseek-ai/dsh-attachment",
@@ -8,5 +8,7 @@ declare const CODEX_AUTH_LOGOUT_PATH = "/plugins/dsh-codex-auth-plugin/auth/logo
8
8
  declare const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
9
9
  /** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
10
10
  declare const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
11
+ /** Same-origin endpoint for the DSH-wide Codex default model selection. */
12
+ declare const CODEX_GLOBAL_MODEL_PATH = "/plugins/dsh-codex-auth-plugin/auth/global-model";
11
13
  //#endregion
12
- export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
14
+ export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_USAGE_PATH };
package/lib/auth-paths.js CHANGED
@@ -8,5 +8,7 @@ const CODEX_AUTH_LOGOUT_PATH = "/plugins/dsh-codex-auth-plugin/auth/logout";
8
8
  const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
9
9
  /** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
10
10
  const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
11
+ /** Same-origin endpoint for the DSH-wide Codex default model selection. */
12
+ const CODEX_GLOBAL_MODEL_PATH = "/plugins/dsh-codex-auth-plugin/auth/global-model";
11
13
  //#endregion
12
- export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH };
14
+ export { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_USAGE_PATH };
package/lib/client.js CHANGED
@@ -6,23 +6,24 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
9
10
  //#region src/client/CodexCapabilities.tsx
10
11
  /** Live optional-capability settings for the Codex Auth plugin. */
11
- const sectionStyle = {
12
+ const sectionStyle$1 = {
12
13
  display: "flex",
13
14
  flexDirection: "column",
14
15
  gap: 12,
15
16
  borderTop: "1px solid var(--dsw-alias-border-l2)",
16
17
  paddingTop: 14
17
18
  };
18
- const headingStyle = {
19
+ const headingStyle$1 = {
19
20
  margin: 0,
20
21
  fontSize: 14,
21
22
  lineHeight: "20px",
22
23
  fontWeight: 600,
23
24
  color: "var(--dsw-alias-label-primary)"
24
25
  };
25
- const bodyStyle$1 = {
26
+ const bodyStyle$2 = {
26
27
  margin: 0,
27
28
  fontSize: 12,
28
29
  lineHeight: "18px",
@@ -47,6 +48,7 @@ window.__ModuleLoader__.load({
47
48
  cursor: "not-allowed",
48
49
  opacity: .62
49
50
  };
51
+ const checkboxStyle = { accentColor: "var(--dsw-alias-button-primary-fill)" };
50
52
  const copyStyle = {
51
53
  display: "flex",
52
54
  flexDirection: "column",
@@ -58,7 +60,7 @@ window.__ModuleLoader__.load({
58
60
  fontWeight: 500,
59
61
  color: "var(--dsw-alias-label-primary)"
60
62
  };
61
- const actionsStyle = {
63
+ const actionsStyle$1 = {
62
64
  display: "flex",
63
65
  alignItems: "center",
64
66
  justifyContent: "space-between",
@@ -69,7 +71,7 @@ window.__ModuleLoader__.load({
69
71
  display: "flex",
70
72
  gap: 8
71
73
  };
72
- const buttonStyle$1 = {
74
+ const buttonStyle$2 = {
73
75
  boxSizing: "border-box",
74
76
  minHeight: 30,
75
77
  padding: "4px 12px",
@@ -81,18 +83,18 @@ window.__ModuleLoader__.load({
81
83
  fontSize: 12,
82
84
  cursor: "pointer"
83
85
  };
84
- const primaryButtonStyle$1 = {
85
- ...buttonStyle$1,
86
+ const primaryButtonStyle$2 = {
87
+ ...buttonStyle$2,
86
88
  border: 0,
87
89
  background: "var(--dsw-alias-button-primary-fill)",
88
90
  color: "var(--dsw-alias-label-primary-foreground)"
89
91
  };
90
- const errorStyle$1 = {
91
- ...bodyStyle$1,
92
+ const errorStyle$2 = {
93
+ ...bodyStyle$2,
92
94
  color: "var(--dsw-alias-state-error-primary, #d92d20)"
93
95
  };
94
- const successStyle = {
95
- ...bodyStyle$1,
96
+ const successStyle$1 = {
97
+ ...bodyStyle$2,
96
98
  color: "var(--dsw-alias-state-success-primary, #16825d)"
97
99
  };
98
100
  const UNAVAILABLE_SNAPSHOT = {
@@ -165,32 +167,32 @@ window.__ModuleLoader__.load({
165
167
  const loading = snapshot.status === "loading";
166
168
  const editable = snapshot.status === "ready" && snapshot.writable && !busy;
167
169
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
168
- style: sectionStyle,
170
+ style: sectionStyle$1,
169
171
  "aria-labelledby": "dsh-codex-capabilities-title",
170
172
  children: [
171
173
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
172
174
  id: "dsh-codex-capabilities-title",
173
- style: headingStyle,
175
+ style: headingStyle$1,
174
176
  children: t("capabilitiesTitle")
175
177
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
176
178
  style: {
177
- ...bodyStyle$1,
179
+ ...bodyStyle$2,
178
180
  marginTop: 3
179
181
  },
180
182
  children: t("capabilitiesIntro")
181
183
  })] }),
182
184
  loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
183
- style: bodyStyle$1,
185
+ style: bodyStyle$2,
184
186
  role: "status",
185
187
  children: t("settingsLoading")
186
188
  }) : null,
187
189
  snapshot.status === "unavailable" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
188
- style: errorStyle$1,
190
+ style: errorStyle$2,
189
191
  role: "alert",
190
192
  children: t("settingsUnavailable")
191
193
  }) : null,
192
194
  snapshot.status === "ready" && !snapshot.writable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
193
- style: errorStyle$1,
195
+ style: errorStyle$2,
194
196
  role: "alert",
195
197
  children: t("settingsReadOnly")
196
198
  }) : null,
@@ -201,6 +203,7 @@ window.__ModuleLoader__.load({
201
203
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
202
204
  style: rowStyle$1,
203
205
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
206
+ style: checkboxStyle,
204
207
  type: "checkbox",
205
208
  checked: draft.enableImageTool,
206
209
  onChange: (event) => {
@@ -212,7 +215,7 @@ window.__ModuleLoader__.load({
212
215
  style: labelStyle,
213
216
  children: t("enableImageRecognition")
214
217
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
215
- style: bodyStyle$1,
218
+ style: bodyStyle$2,
216
219
  children: t("enableImageRecognitionHelp")
217
220
  })]
218
221
  })]
@@ -220,6 +223,7 @@ window.__ModuleLoader__.load({
220
223
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
221
224
  style: rowStyle$1,
222
225
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
226
+ style: checkboxStyle,
223
227
  type: "checkbox",
224
228
  checked: draft.enableImageUpload,
225
229
  onChange: (event) => {
@@ -231,7 +235,7 @@ window.__ModuleLoader__.load({
231
235
  style: labelStyle,
232
236
  children: t("enableImageUpload")
233
237
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234
- style: bodyStyle$1,
238
+ style: bodyStyle$2,
235
239
  children: t("enableImageUploadHelp")
236
240
  })]
237
241
  })]
@@ -240,6 +244,7 @@ window.__ModuleLoader__.load({
240
244
  style: disabledRowStyle,
241
245
  title: t("imageGenerationUnavailableHelp"),
242
246
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
247
+ style: checkboxStyle,
243
248
  type: "checkbox",
244
249
  checked: false,
245
250
  disabled: true,
@@ -251,7 +256,7 @@ window.__ModuleLoader__.load({
251
256
  style: labelStyle,
252
257
  children: t("enableImageGeneration")
253
258
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
254
- style: bodyStyle$1,
259
+ style: bodyStyle$2,
255
260
  children: t("imageGenerationUnavailableHelp")
256
261
  })]
257
262
  })]
@@ -259,27 +264,27 @@ window.__ModuleLoader__.load({
259
264
  ]
260
265
  }),
261
266
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
262
- style: actionsStyle,
267
+ style: actionsStyle$1,
263
268
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
264
269
  "aria-live": "polite",
265
270
  children: [feedback === "saved" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
266
- style: successStyle,
271
+ style: successStyle$1,
267
272
  children: t("settingsSaved")
268
273
  }) : null, feedback === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
269
- style: errorStyle$1,
274
+ style: errorStyle$2,
270
275
  children: t("settingsSaveFailed")
271
276
  }) : null]
272
277
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
273
278
  style: buttonsStyle,
274
279
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
275
280
  type: "button",
276
- style: buttonStyle$1,
281
+ style: buttonStyle$2,
277
282
  disabled: !dirty || busy,
278
283
  onClick: discard,
279
284
  children: t("discard")
280
285
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
281
286
  type: "button",
282
- style: primaryButtonStyle$1,
287
+ style: primaryButtonStyle$2,
283
288
  disabled: !dirty || !snapshot.writable || busy,
284
289
  onClick: () => {
285
290
  save();
@@ -302,6 +307,566 @@ window.__ModuleLoader__.load({
302
307
  const CODEX_USAGE_PATH = "/plugins/dsh-codex-auth-plugin/auth/usage";
303
308
  /** Same-origin settings endpoint used when DSH marks a NAS browser as remote. */
304
309
  const CODEX_AUTH_SETTINGS_PATH = "/plugins/dsh-codex-auth-plugin/auth/settings";
310
+ /** Same-origin endpoint for the DSH-wide Codex default model selection. */
311
+ const CODEX_GLOBAL_MODEL_PATH = "/plugins/dsh-codex-auth-plugin/auth/global-model";
312
+ //#endregion
313
+ //#region src/client/CodexGlobalModel.tsx
314
+ /** DSH-wide Codex default model controls. */
315
+ const sectionStyle = {
316
+ display: "flex",
317
+ flexDirection: "column",
318
+ gap: 12,
319
+ borderTop: "1px solid var(--dsw-alias-border-l2)",
320
+ paddingTop: 14
321
+ };
322
+ const headingStyle = {
323
+ margin: 0,
324
+ fontSize: 14,
325
+ lineHeight: "20px",
326
+ fontWeight: 600,
327
+ color: "var(--dsw-alias-label-primary)"
328
+ };
329
+ const bodyStyle$1 = {
330
+ margin: 0,
331
+ fontSize: 12,
332
+ lineHeight: "18px",
333
+ color: "var(--dsw-alias-label-secondary)"
334
+ };
335
+ const fieldsStyle = {
336
+ display: "flex",
337
+ alignItems: "center",
338
+ minWidth: 0
339
+ };
340
+ const actionsStyle = {
341
+ display: "flex",
342
+ alignItems: "center",
343
+ justifyContent: "space-between",
344
+ gap: 10,
345
+ flexWrap: "wrap"
346
+ };
347
+ const buttonStyle$1 = {
348
+ boxSizing: "border-box",
349
+ minHeight: 30,
350
+ padding: "4px 12px",
351
+ border: "1px solid var(--dsw-alias-border-l2)",
352
+ borderRadius: 16,
353
+ background: "var(--dsw-alias-bg-layer-1)",
354
+ color: "var(--dsw-alias-label-primary)",
355
+ font: "inherit",
356
+ fontSize: 12,
357
+ cursor: "pointer"
358
+ };
359
+ const primaryButtonStyle$1 = {
360
+ ...buttonStyle$1,
361
+ border: 0,
362
+ background: "var(--dsw-alias-button-primary-fill)",
363
+ color: "var(--dsw-alias-label-primary-foreground)"
364
+ };
365
+ const errorStyle$1 = {
366
+ ...bodyStyle$1,
367
+ color: "var(--dsw-alias-state-error-primary, #d92d20)"
368
+ };
369
+ const successStyle = {
370
+ ...bodyStyle$1,
371
+ color: "var(--dsw-alias-state-success-primary, #16825d)"
372
+ };
373
+ async function request(method, body) {
374
+ const response = await fetch(CODEX_GLOBAL_MODEL_PATH, {
375
+ method,
376
+ headers: {
377
+ accept: "application/json",
378
+ ...body === void 0 ? {} : { "content-type": "application/json" }
379
+ },
380
+ ...body === void 0 ? {} : { body: JSON.stringify(body) },
381
+ credentials: "same-origin"
382
+ });
383
+ const payload = await response.json().catch(() => void 0);
384
+ if (!response.ok) throw new Error(typeof payload === "object" && payload !== null && "error" in payload && typeof payload.error === "string" ? payload.error : `HTTP ${response.status}`);
385
+ return payload;
386
+ }
387
+ function codexModels(groups) {
388
+ return groups.find((group) => group.id === "openai-codex")?.models ?? [];
389
+ }
390
+ const choiceButtonStyle = {
391
+ boxSizing: "border-box",
392
+ display: "flex",
393
+ alignItems: "center",
394
+ justifyContent: "space-between",
395
+ gap: 8,
396
+ width: "100%",
397
+ minHeight: 34,
398
+ padding: "5px 9px",
399
+ border: "1px solid var(--dsw-alias-border-l2)",
400
+ borderRadius: 8,
401
+ background: "var(--dsw-alias-bg-layer-1)",
402
+ color: "var(--dsw-alias-label-primary)",
403
+ font: "inherit",
404
+ fontSize: 13,
405
+ textAlign: "left",
406
+ cursor: "pointer"
407
+ };
408
+ const choicePanelStyle = {
409
+ position: "absolute",
410
+ zIndex: 20,
411
+ top: "calc(100% + 6px)",
412
+ left: 0,
413
+ width: "max(100%, 220px)",
414
+ maxHeight: 260,
415
+ overflowY: "auto",
416
+ boxSizing: "border-box",
417
+ padding: 6,
418
+ border: "1px solid var(--dsw-alias-border-l1, var(--dsw-alias-border-l2))",
419
+ borderRadius: 10,
420
+ background: "var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2))",
421
+ boxShadow: "var(--dsw-alias-shadow-popover, 0 12px 30px rgb(0 0 0 / 24%))"
422
+ };
423
+ const choiceItemStyle = {
424
+ display: "flex",
425
+ alignItems: "center",
426
+ justifyContent: "space-between",
427
+ gap: 10,
428
+ width: "100%",
429
+ minHeight: 34,
430
+ padding: "6px 9px",
431
+ border: 0,
432
+ borderRadius: 7,
433
+ background: "transparent",
434
+ color: "var(--dsw-alias-label-primary)",
435
+ font: "inherit",
436
+ fontSize: 13,
437
+ textAlign: "left",
438
+ cursor: "pointer"
439
+ };
440
+ function ChevronDown() {
441
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
442
+ "aria-hidden": "true",
443
+ style: {
444
+ display: "inline-flex",
445
+ alignItems: "center",
446
+ color: "var(--dsw-alias-label-tertiary)",
447
+ lineHeight: 1
448
+ },
449
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
450
+ });
451
+ }
452
+ const pickerButtonStyle = {
453
+ ...choiceButtonStyle,
454
+ width: "fit-content",
455
+ maxWidth: "100%",
456
+ minHeight: 30,
457
+ padding: "3px 4px",
458
+ border: 0,
459
+ borderRadius: 7,
460
+ background: "transparent",
461
+ fontSize: 14
462
+ };
463
+ const pickerPanelStyle = {
464
+ ...choicePanelStyle,
465
+ display: "flex",
466
+ position: "absolute",
467
+ gap: 0,
468
+ width: "min(210px, calc(100vw - 32px))",
469
+ maxHeight: 260,
470
+ padding: 5,
471
+ overflow: "visible"
472
+ };
473
+ const pickerColumnStyle = {
474
+ display: "flex",
475
+ width: "100%",
476
+ flexDirection: "column",
477
+ gap: 2
478
+ };
479
+ const pickerSubmenuStyle = {
480
+ position: "absolute",
481
+ zIndex: 1,
482
+ top: 5,
483
+ left: "calc(100% + 4px)",
484
+ width: "210px",
485
+ maxHeight: 250,
486
+ overflowY: "auto",
487
+ boxSizing: "border-box",
488
+ display: "flex",
489
+ flexDirection: "column",
490
+ gap: 2,
491
+ padding: 5,
492
+ border: "1px solid var(--dsw-alias-border-l1, var(--dsw-alias-border-l2))",
493
+ borderRadius: 10,
494
+ background: "var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-2))",
495
+ boxShadow: "var(--dsw-alias-shadow-popover, 0 12px 30px rgb(0 0 0 / 24%))"
496
+ };
497
+ function PickerRow({ label, value, disabled, active, onClick }) {
498
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
499
+ type: "button",
500
+ disabled,
501
+ style: {
502
+ ...choiceItemStyle,
503
+ minHeight: 34,
504
+ padding: "4px 8px",
505
+ background: active ? "var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover))" : "transparent",
506
+ opacity: disabled ? .5 : 1,
507
+ cursor: disabled ? "not-allowed" : "pointer"
508
+ },
509
+ onMouseEnter: (event) => {
510
+ if (!disabled) event.currentTarget.style.background = "var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-1))";
511
+ },
512
+ onMouseLeave: (event) => {
513
+ event.currentTarget.style.background = active ? "var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover))" : "transparent";
514
+ },
515
+ onClick,
516
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
517
+ style: {
518
+ minWidth: 0,
519
+ overflow: "hidden",
520
+ textOverflow: "ellipsis",
521
+ whiteSpace: "nowrap",
522
+ fontSize: 13
523
+ },
524
+ children: label
525
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
526
+ style: {
527
+ display: "inline-flex",
528
+ alignItems: "center",
529
+ gap: 6,
530
+ minWidth: 0,
531
+ color: "var(--dsw-alias-label-secondary)",
532
+ fontSize: 13
533
+ },
534
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
535
+ style: {
536
+ maxWidth: 140,
537
+ overflow: "hidden",
538
+ textOverflow: "ellipsis",
539
+ whiteSpace: "nowrap"
540
+ },
541
+ children: value
542
+ }), !disabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
543
+ "aria-hidden": "true",
544
+ style: {
545
+ fontSize: 18,
546
+ lineHeight: 1
547
+ },
548
+ children: "›"
549
+ }) : null]
550
+ })]
551
+ });
552
+ }
553
+ function GlobalModelPicker({ modelMenuLabel, effortMenuLabel, modelLabel, modelPlaceholder, effortLabel, selectedModelId, selectedEffortId, modelOptions, effortOptions, activeMenu, onToggle, onOpenSubmenu, onChooseModel, onChooseEffort }) {
554
+ const open = activeMenu !== null;
555
+ const modelValue = modelLabel === "" ? modelPlaceholder : modelLabel;
556
+ const buttonValue = effortLabel === "" ? modelValue : `${modelValue} · ${effortLabel}`;
557
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
558
+ style: {
559
+ position: "relative",
560
+ width: "fit-content",
561
+ maxWidth: "100%"
562
+ },
563
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
564
+ type: "button",
565
+ "aria-haspopup": "menu",
566
+ "aria-expanded": open,
567
+ style: pickerButtonStyle,
568
+ onClick: onToggle,
569
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
570
+ style: {
571
+ minWidth: 0,
572
+ overflow: "hidden",
573
+ textOverflow: "ellipsis",
574
+ whiteSpace: "nowrap",
575
+ color: modelLabel === "" ? "var(--dsw-alias-label-dimmed)" : "var(--dsw-alias-label-primary)"
576
+ },
577
+ children: buttonValue
578
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDown, {})]
579
+ }), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
580
+ role: "menu",
581
+ style: pickerPanelStyle,
582
+ children: [
583
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
584
+ style: pickerColumnStyle,
585
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerRow, {
586
+ label: modelMenuLabel,
587
+ value: modelValue,
588
+ active: activeMenu === "model",
589
+ onClick: () => {
590
+ onOpenSubmenu("model");
591
+ }
592
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PickerRow, {
593
+ label: effortMenuLabel,
594
+ value: effortLabel,
595
+ active: activeMenu === "effort",
596
+ onClick: () => {
597
+ onOpenSubmenu("effort");
598
+ }
599
+ })]
600
+ }),
601
+ activeMenu === "model" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
602
+ role: "menu",
603
+ "aria-label": modelMenuLabel,
604
+ style: pickerSubmenuStyle,
605
+ children: modelOptions.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
606
+ type: "button",
607
+ role: "menuitemradio",
608
+ "aria-checked": option.id === selectedModelId,
609
+ style: option.id === selectedModelId ? {
610
+ ...choiceItemStyle,
611
+ background: "var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover))"
612
+ } : choiceItemStyle,
613
+ onClick: () => {
614
+ onChooseModel(option.id);
615
+ },
616
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
617
+ style: {
618
+ minWidth: 0,
619
+ overflow: "hidden",
620
+ textOverflow: "ellipsis",
621
+ whiteSpace: "nowrap"
622
+ },
623
+ children: option.label
624
+ }), option.id === selectedModelId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
625
+ "aria-hidden": "true",
626
+ children: "✓"
627
+ }) : null]
628
+ }, option.id))
629
+ }) : null,
630
+ activeMenu === "effort" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
631
+ role: "menu",
632
+ "aria-label": effortMenuLabel,
633
+ style: pickerSubmenuStyle,
634
+ children: effortOptions.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
635
+ type: "button",
636
+ role: "menuitemradio",
637
+ "aria-checked": option.id === selectedEffortId,
638
+ style: option.id === selectedEffortId ? {
639
+ ...choiceItemStyle,
640
+ background: "var(--dsw-alias-interactive-bg-active, var(--dsw-alias-interactive-bg-hover))"
641
+ } : choiceItemStyle,
642
+ onClick: () => {
643
+ onChooseEffort(option.id);
644
+ },
645
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: option.label }), option.id === selectedEffortId ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
646
+ "aria-hidden": "true",
647
+ children: "✓"
648
+ }) : null]
649
+ }, option.id))
650
+ }) : null
651
+ ]
652
+ }) : null]
653
+ });
654
+ }
655
+ /** Set the model used by new DSH sessions and the host-backed agent entry point. */
656
+ function CodexGlobalModel({ connection, t }) {
657
+ const [models, setModels] = (0, react.useState)([]);
658
+ const [current, setCurrent] = (0, react.useState)();
659
+ const [draftModel, setDraftModel] = (0, react.useState)("");
660
+ const [draftEffort, setDraftEffort] = (0, react.useState)("");
661
+ const [status, setStatus] = (0, react.useState)("loading");
662
+ const [busy, setBusy] = (0, react.useState)(false);
663
+ const [feedback, setFeedback] = (0, react.useState)("idle");
664
+ const [openMenu, setOpenMenu] = (0, react.useState)(null);
665
+ const fieldsRef = (0, react.useRef)(null);
666
+ const load = (0, react.useCallback)(async () => {
667
+ setStatus("loading");
668
+ try {
669
+ const [global, catalog] = await Promise.all([request("GET"), connection.api.llm.models({})]);
670
+ if (!catalog.result.ok) throw new Error(catalog.result.error.message);
671
+ const available = codexModels(catalog.result.value.groups);
672
+ setModels(available);
673
+ setCurrent(global.globalModel);
674
+ setDraftModel(global.globalModel?.model ?? "");
675
+ setDraftEffort(global.globalModel?.reasoningEffort ?? "");
676
+ setStatus("ready");
677
+ } catch {
678
+ setStatus("error");
679
+ }
680
+ }, [connection]);
681
+ (0, react.useEffect)(() => {
682
+ load();
683
+ }, [load]);
684
+ (0, react.useEffect)(() => {
685
+ if (openMenu === null) return;
686
+ const onPointerDown = (event) => {
687
+ if (event.target instanceof Node && fieldsRef.current?.contains(event.target)) return;
688
+ setOpenMenu(null);
689
+ };
690
+ const onKeyDown = (event) => {
691
+ if (event.key === "Escape") setOpenMenu(null);
692
+ };
693
+ document.addEventListener("pointerdown", onPointerDown);
694
+ document.addEventListener("keydown", onKeyDown);
695
+ return () => {
696
+ document.removeEventListener("pointerdown", onPointerDown);
697
+ document.removeEventListener("keydown", onKeyDown);
698
+ };
699
+ }, [openMenu]);
700
+ const selected = (0, react.useMemo)(() => models.find((model) => model.id === draftModel), [draftModel, models]);
701
+ const efforts = selected?.reasoning?.efforts ?? [];
702
+ const modelLabel = selected?.name ?? draftModel;
703
+ const modelOptions = [
704
+ {
705
+ id: "",
706
+ label: t("globalModelUnset")
707
+ },
708
+ ...draftModel !== "" && !models.some((model) => model.id === draftModel) ? [{
709
+ id: draftModel,
710
+ label: draftModel
711
+ }] : [],
712
+ ...models.map((model) => ({
713
+ id: model.id,
714
+ label: model.name
715
+ }))
716
+ ];
717
+ const effortOptions = [{
718
+ id: "",
719
+ label: t("globalModelProviderDefault")
720
+ }, ...efforts.map((effort) => ({
721
+ id: effort.id,
722
+ label: effort.name
723
+ }))];
724
+ const dirty = draftModel.length > 0 && (current?.model !== draftModel || (current?.reasoningEffort ?? "") !== draftEffort);
725
+ const save = async () => {
726
+ if (!dirty || busy) return;
727
+ setBusy(true);
728
+ setFeedback("idle");
729
+ try {
730
+ const result = await request("PUT", {
731
+ model: draftModel,
732
+ ...draftEffort.length === 0 ? {} : { reasoningEffort: draftEffort }
733
+ });
734
+ setCurrent(result.globalModel);
735
+ setDraftModel(result.globalModel?.model ?? draftModel);
736
+ setDraftEffort(result.globalModel?.reasoningEffort ?? "");
737
+ setFeedback("saved");
738
+ } catch {
739
+ setFeedback("error");
740
+ } finally {
741
+ setBusy(false);
742
+ }
743
+ };
744
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
745
+ style: sectionStyle,
746
+ "aria-labelledby": "dsh-codex-global-model-title",
747
+ children: [
748
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
749
+ id: "dsh-codex-global-model-title",
750
+ style: headingStyle,
751
+ children: t("globalModelTitle")
752
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
753
+ style: {
754
+ ...bodyStyle$1,
755
+ marginTop: 3
756
+ },
757
+ children: t("globalModelIntro")
758
+ })] }),
759
+ status === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
760
+ style: bodyStyle$1,
761
+ children: t("settingsLoading")
762
+ }) : null,
763
+ status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
764
+ style: errorStyle$1,
765
+ role: "alert",
766
+ children: t("globalModelLoadFailed")
767
+ }) : null,
768
+ status === "ready" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
769
+ ref: fieldsRef,
770
+ style: fieldsStyle,
771
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(GlobalModelPicker, {
772
+ modelMenuLabel: t("globalModelModel"),
773
+ effortMenuLabel: t("globalModelThinking"),
774
+ modelLabel,
775
+ modelPlaceholder: t("globalModelUnset"),
776
+ effortLabel: effortOptions.find((option) => option.id === draftEffort)?.label ?? t("globalModelProviderDefault"),
777
+ selectedModelId: draftModel,
778
+ selectedEffortId: draftEffort,
779
+ modelOptions,
780
+ effortOptions,
781
+ activeMenu: openMenu,
782
+ onToggle: () => {
783
+ setOpenMenu((current) => current === null ? "root" : null);
784
+ },
785
+ onOpenSubmenu: (menu) => {
786
+ setOpenMenu(menu);
787
+ },
788
+ onChooseModel: (id) => {
789
+ setDraftModel(id);
790
+ setDraftEffort("");
791
+ setFeedback("idle");
792
+ setOpenMenu(null);
793
+ },
794
+ onChooseEffort: (id) => {
795
+ setDraftEffort(id);
796
+ setFeedback("idle");
797
+ setOpenMenu(null);
798
+ }
799
+ }), selected === void 0 && modelLabel !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
800
+ style: bodyStyle$1,
801
+ children: t("globalModelUnavailable")
802
+ }) : null]
803
+ }) : null,
804
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
805
+ style: actionsStyle,
806
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
807
+ "aria-live": "polite",
808
+ children: [feedback === "saved" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
809
+ style: successStyle,
810
+ children: t("settingsSaved")
811
+ }) : null, feedback === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
812
+ style: errorStyle$1,
813
+ children: t("settingsSaveFailed")
814
+ }) : null]
815
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
816
+ style: {
817
+ display: "flex",
818
+ gap: 8
819
+ },
820
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
821
+ type: "button",
822
+ style: buttonStyle$1,
823
+ disabled: status === "loading" || busy,
824
+ onClick: () => {
825
+ load();
826
+ },
827
+ children: t("refreshUsage")
828
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
829
+ type: "button",
830
+ style: primaryButtonStyle$1,
831
+ disabled: !dirty || busy,
832
+ onClick: () => {
833
+ save();
834
+ },
835
+ children: busy ? t("saving") : t("setGlobalModel")
836
+ })]
837
+ })]
838
+ })
839
+ ]
840
+ });
841
+ }
842
+ //#endregion
843
+ //#region src/client/copy-to-clipboard.ts
844
+ async function copyTextToClipboard(text, environment = {}) {
845
+ const navigatorRef = environment.navigator ?? globalThis.navigator;
846
+ const documentRef = environment.document ?? globalThis.document;
847
+ try {
848
+ if (typeof navigatorRef?.clipboard?.writeText === "function") {
849
+ await navigatorRef.clipboard.writeText(text);
850
+ return;
851
+ }
852
+ } catch {}
853
+ if (documentRef === void 0) throw new Error("Clipboard is unavailable");
854
+ const textarea = documentRef.createElement("textarea");
855
+ textarea.value = text;
856
+ textarea.setAttribute("readonly", "");
857
+ textarea.style.position = "fixed";
858
+ textarea.style.top = "0";
859
+ textarea.style.left = "-9999px";
860
+ textarea.style.opacity = "0";
861
+ documentRef.body.appendChild(textarea);
862
+ textarea.focus();
863
+ textarea.select();
864
+ try {
865
+ if (!documentRef.execCommand("copy")) throw new Error("Copy command was rejected");
866
+ } finally {
867
+ documentRef.body.removeChild(textarea);
868
+ }
869
+ }
305
870
  //#endregion
306
871
  //#region src/client/CodexAuthCard.tsx
307
872
  /** Expandable account card for the DSH Plugins settings section. */
@@ -485,7 +1050,7 @@ window.__ModuleLoader__.load({
485
1050
  maxWidth: 192,
486
1051
  height: 8,
487
1052
  borderRadius: 999,
488
- background: "var(--dsw-alias-bg-layer-3, rgba(127, 127, 127, 0.28))"
1053
+ background: "rgba(127, 127, 127, 0.28)"
489
1054
  };
490
1055
  const usageFillStyle = {
491
1056
  height: "100%",
@@ -617,13 +1182,15 @@ window.__ModuleLoader__.load({
617
1182
  })
618
1183
  });
619
1184
  }
620
- /** Render a standalone login/logout card in the rc.7 keyed Plugin slot. */
621
- function CodexAuthCard({ t, configScope }) {
1185
+ /** Render a standalone login/logout card in the rc.8 keyed Plugin slot. */
1186
+ function CodexAuthCard({ t, configScope, connection }) {
622
1187
  if (t === void 0) throw new Error("Codex auth card requires its translation function");
1188
+ if (connection === void 0) throw new Error("Codex auth card requires the DSH connection");
623
1189
  const [open, setOpen] = (0, react.useState)(false);
624
1190
  const [status, setStatus] = (0, react.useState)({ status: "loading" });
625
1191
  const [busy, setBusy] = (0, react.useState)(false);
626
1192
  const [challenge, setChallenge] = (0, react.useState)();
1193
+ const [copyStatus, setCopyStatus] = (0, react.useState)("idle");
627
1194
  const [usage, setUsage] = (0, react.useState)({ status: "hidden" });
628
1195
  const refreshUsage = (0, react.useCallback)(async () => {
629
1196
  if (status.status !== "signed-in") return;
@@ -641,7 +1208,10 @@ window.__ModuleLoader__.load({
641
1208
  try {
642
1209
  const next = await jsonRequest(CODEX_AUTH_STATUS_PATH);
643
1210
  setStatus(next);
644
- if (next.status !== "signing-in") setChallenge(void 0);
1211
+ if (next.status !== "signing-in") {
1212
+ setChallenge(void 0);
1213
+ setCopyStatus("idle");
1214
+ }
645
1215
  } catch (error) {
646
1216
  setStatus(error instanceof AccountRequestError && error.code === "remote-web-origin-not-trusted" ? { status: "remote-web-origin-not-trusted" } : {
647
1217
  status: "error",
@@ -687,6 +1257,7 @@ window.__ModuleLoader__.load({
687
1257
  setBusy(true);
688
1258
  setStatus({ status: "signing-in" });
689
1259
  setChallenge(void 0);
1260
+ setCopyStatus("idle");
690
1261
  try {
691
1262
  const next = await jsonRequest(CODEX_AUTH_LOGIN_PATH, "POST");
692
1263
  setChallenge(next);
@@ -694,6 +1265,7 @@ window.__ModuleLoader__.load({
694
1265
  } catch (error) {
695
1266
  popup.close();
696
1267
  setChallenge(void 0);
1268
+ setCopyStatus("idle");
697
1269
  setStatus(error instanceof AccountRequestError && error.code === "remote-web-origin-not-trusted" ? { status: "remote-web-origin-not-trusted" } : {
698
1270
  status: "error",
699
1271
  message: error instanceof Error ? error.message : t("requestFailed")
@@ -709,6 +1281,7 @@ window.__ModuleLoader__.load({
709
1281
  setStatus({ status: "signed-out" });
710
1282
  setUsage({ status: "hidden" });
711
1283
  setChallenge(void 0);
1284
+ setCopyStatus("idle");
712
1285
  } catch (error) {
713
1286
  setStatus({
714
1287
  status: "error",
@@ -718,6 +1291,15 @@ window.__ModuleLoader__.load({
718
1291
  setBusy(false);
719
1292
  }
720
1293
  };
1294
+ const copyAuthorizationCode = async () => {
1295
+ if (challenge === void 0) return;
1296
+ try {
1297
+ await copyTextToClipboard(challenge.userCode);
1298
+ setCopyStatus("copied");
1299
+ } catch {
1300
+ setCopyStatus("failed");
1301
+ }
1302
+ };
721
1303
  const label = status.status === "signed-in" ? t("signedIn") : status.status === "loading" ? t("loading") : status.status === "signing-in" ? t("signingIn") : status.status === "remote-web-origin-not-trusted" ? t("remoteOrigin") : status.status === "error" ? t("requestFailed") : t("signedOut");
722
1304
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
723
1305
  style: {
@@ -827,34 +1409,56 @@ window.__ModuleLoader__.load({
827
1409
  flexDirection: "column",
828
1410
  gap: 8
829
1411
  },
830
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
831
- style: bodyStyle,
832
- children: t("authorizationCodeHelp")
833
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
834
- style: {
835
- display: "flex",
836
- alignItems: "center",
837
- flexWrap: "wrap",
838
- gap: 8
839
- },
840
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
841
- "aria-label": t("authorizationCodeLabel"),
842
- style: codeStyle,
843
- children: challenge.userCode
844
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
845
- href: challenge.verificationUri,
846
- target: "_blank",
847
- rel: "noreferrer",
1412
+ children: [
1413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1414
+ style: bodyStyle,
1415
+ children: t("authorizationCodeHelp")
1416
+ }),
1417
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
848
1418
  style: {
849
- ...buttonStyle,
850
- display: "inline-flex",
1419
+ display: "flex",
851
1420
  alignItems: "center",
852
- textDecoration: "none"
1421
+ flexWrap: "wrap",
1422
+ gap: 8
853
1423
  },
854
- children: t("openAuthorization")
855
- })]
856
- })]
1424
+ children: [
1425
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
1426
+ "aria-label": t("authorizationCodeLabel"),
1427
+ style: codeStyle,
1428
+ children: challenge.userCode
1429
+ }),
1430
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1431
+ type: "button",
1432
+ style: buttonStyle,
1433
+ onClick: () => {
1434
+ copyAuthorizationCode();
1435
+ },
1436
+ children: copyStatus === "copied" ? t("authorizationCodeCopied") : t("copyAuthorizationCode")
1437
+ }),
1438
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1439
+ href: challenge.verificationUri,
1440
+ target: "_blank",
1441
+ rel: "noreferrer",
1442
+ style: {
1443
+ ...buttonStyle,
1444
+ display: "inline-flex",
1445
+ alignItems: "center",
1446
+ textDecoration: "none"
1447
+ },
1448
+ children: t("openAuthorization")
1449
+ })
1450
+ ]
1451
+ }),
1452
+ copyStatus === "failed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1453
+ style: errorStyle,
1454
+ children: t("authorizationCodeCopyFailed")
1455
+ }) : null
1456
+ ]
857
1457
  }) : null,
1458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexGlobalModel, {
1459
+ connection,
1460
+ t
1461
+ }),
858
1462
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexCapabilities, {
859
1463
  scope: configScope,
860
1464
  t
@@ -1646,6 +2250,9 @@ window.__ModuleLoader__.load({
1646
2250
  remoteOrigin: "This browser origin is not trusted by the DSH Web server.",
1647
2251
  authorizationCodeHelp: "The plugin generated a one-time authorization code. Enter it on the opened Codex authorization page; no workspace selection is required.",
1648
2252
  authorizationCodeLabel: "Codex authorization code",
2253
+ copyAuthorizationCode: "Copy",
2254
+ authorizationCodeCopied: "Copied",
2255
+ authorizationCodeCopyFailed: "Unable to copy the authorization code. Please select and copy it manually.",
1649
2256
  openAuthorization: "Open authorization page",
1650
2257
  usageTitle: "General usage limits",
1651
2258
  refreshUsage: "Refresh",
@@ -1671,7 +2278,7 @@ window.__ModuleLoader__.load({
1671
2278
  enableImageUpload: "Enable image upload",
1672
2279
  enableImageUploadHelp: "Allow image-capable Codex models to receive images pasted or dropped into the conversation.",
1673
2280
  enableImageGeneration: "Enable image generation",
1674
- imageGenerationUnavailableHelp: "Not supported by the Codex provider and DSH rc.7 model adapter.",
2281
+ imageGenerationUnavailableHelp: "Not supported by the Codex provider and DSH rc.8 model adapter.",
1675
2282
  settingsLoading: "Loading plugin settings…",
1676
2283
  settingsUnavailable: "Plugin settings are unavailable in this dsh profile.",
1677
2284
  settingsReadOnly: "This profile exposes plugin settings as read-only.",
@@ -1679,7 +2286,16 @@ window.__ModuleLoader__.load({
1679
2286
  settingsSaveFailed: "Unable to save settings.",
1680
2287
  discard: "Discard",
1681
2288
  save: "Save",
1682
- saving: "Saving…"
2289
+ saving: "Saving…",
2290
+ globalModelTitle: "Global model",
2291
+ globalModelIntro: "Choose the default Codex model for new DSH sessions.",
2292
+ globalModelModel: "Model",
2293
+ globalModelThinking: "Reasoning effort",
2294
+ globalModelProviderDefault: "Provider default",
2295
+ globalModelUnset: "Select a model",
2296
+ globalModelLoadFailed: "Unable to load the Codex model catalog.",
2297
+ globalModelUnavailable: "This model is no longer in the current catalog.",
2298
+ setGlobalModel: "Set as global model"
1683
2299
  };
1684
2300
  const zh = {
1685
2301
  title: "Codex Auth",
@@ -1698,6 +2314,9 @@ window.__ModuleLoader__.load({
1698
2314
  remoteOrigin: "当前浏览器来源未被 DSH Web 服务信任。",
1699
2315
  authorizationCodeHelp: "插件已生成一次性授权码。请在打开的 Codex 授权页面中输入此代码,无需选择工作空间。",
1700
2316
  authorizationCodeLabel: "Codex 授权码",
2317
+ copyAuthorizationCode: "复制",
2318
+ authorizationCodeCopied: "已复制",
2319
+ authorizationCodeCopyFailed: "授权码复制失败,请手动选中并复制。",
1701
2320
  openAuthorization: "打开授权页面",
1702
2321
  usageTitle: "通用使用限额",
1703
2322
  refreshUsage: "刷新",
@@ -1723,7 +2342,7 @@ window.__ModuleLoader__.load({
1723
2342
  enableImageUpload: "启用图片上传",
1724
2343
  enableImageUploadHelp: "允许具备图片输入能力的 Codex 模型接收粘贴或拖入对话的图片。",
1725
2344
  enableImageGeneration: "启用图像生成",
1726
- imageGenerationUnavailableHelp: "当前 Codex 提供方和 DSH rc.7 模型适配器暂不支持图像输出。",
2345
+ imageGenerationUnavailableHelp: "当前 Codex 提供方和 DSH rc.8 模型适配器暂不支持图像输出。",
1727
2346
  settingsLoading: "正在加载插件设置…",
1728
2347
  settingsUnavailable: "此 dsh profile 无法使用插件设置。",
1729
2348
  settingsReadOnly: "此 profile 的插件设置为只读。",
@@ -1731,7 +2350,16 @@ window.__ModuleLoader__.load({
1731
2350
  settingsSaveFailed: "设置保存失败。",
1732
2351
  discard: "放弃",
1733
2352
  save: "保存",
1734
- saving: "保存中…"
2353
+ saving: "保存中…",
2354
+ globalModelTitle: "全局模型",
2355
+ globalModelIntro: "设置新 DSH 会话使用的 Codex 默认模型。",
2356
+ globalModelModel: "模型",
2357
+ globalModelThinking: "思考强度",
2358
+ globalModelProviderDefault: "提供方默认",
2359
+ globalModelUnset: "请选择模型",
2360
+ globalModelLoadFailed: "加载 Codex 模型目录失败。",
2361
+ globalModelUnavailable: "当前模型已不在可用目录中。",
2362
+ setGlobalModel: "设置为全局模型"
1735
2363
  };
1736
2364
  //#endregion
1737
2365
  //#region src/client/index.tsx
@@ -1751,7 +2379,8 @@ window.__ModuleLoader__.load({
1751
2379
  en
1752
2380
  }), "dsh-codex-auth-plugin: locale");
1753
2381
  const t = ctx.locale.bind(namespace);
1754
- const remoteScope = ctx.get("connection").isLoopback ? void 0 : new CodexAuthRemoteSettingsScope();
2382
+ const connection = ctx.get("connection");
2383
+ const remoteScope = connection.isLoopback ? void 0 : new CodexAuthRemoteSettingsScope();
1755
2384
  const configScope = remoteScope ?? ctx.settingsScope.bind({
1756
2385
  namespace: "dsh-codex-auth",
1757
2386
  decode: decodeCodexAuthSettings
@@ -1767,7 +2396,8 @@ window.__ModuleLoader__.load({
1767
2396
  key: CODEX_AUTH_SETTINGS_NAMESPACE,
1768
2397
  inject: () => ({
1769
2398
  t,
1770
- configScope
2399
+ configScope,
2400
+ connection
1771
2401
  })
1772
2402
  }, CodexAuthCard));
1773
2403
  }
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH } from "./auth-paths.js";
1
+ import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH } from "./auth-paths.js";
2
2
  import { a as CODEX_AUTH_FILENAME, c as codexAuthPath, i as logoutCodex, n as codexAuthStatus, o as CODEX_PROVIDER, r as loginCodex, s as CodexCredentialStore, t as CodexAuthStatus } from "./auth-BBBeI24-.js";
3
3
  import { CredentialProvider } from "@deepseek-ai/dsh-credentials";
4
4
  import "@deepseek-ai/dsh-settings";
@@ -124,4 +124,4 @@ declare const name = "dsh-codex-auth-plugin";
124
124
  declare const inject: string[];
125
125
  declare function apply(ctx: Context): void;
126
126
  //#endregion
127
- export { CODEX_API_KEY_ENV, CODEX_API_KEY_REF, CODEX_AUTH_FILENAME, CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_PROVIDER, CODEX_STREAM_IDLE_TIMEOUT_MS, type CodexAuthStatus, CodexCredentialMirror, CodexCredentialStore, type CodexLoginChallenge, CodexUsageService, CodexWebAuth, type CodexWebAuthStatus, apply, codexAuthPath, codexAuthStatus, createCodexAdapter, inject, loginCodex, logoutCodex, name, normalizeCodexUsagePayload, registerCodexAuthRoutes, trustedRequest };
127
+ export { CODEX_API_KEY_ENV, CODEX_API_KEY_REF, CODEX_AUTH_FILENAME, CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_PROVIDER, CODEX_STREAM_IDLE_TIMEOUT_MS, type CodexAuthStatus, CodexCredentialMirror, CodexCredentialStore, type CodexLoginChallenge, CodexUsageService, CodexWebAuth, type CodexWebAuthStatus, apply, codexAuthPath, codexAuthStatus, createCodexAdapter, inject, loginCodex, logoutCodex, name, normalizeCodexUsagePayload, registerCodexAuthRoutes, trustedRequest };
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as CODEX_PROVIDER, i as CODEX_AUTH_FILENAME, n as loginCodex, o as CodexCredentialStore, r as logoutCodex, s as codexAuthPath, t as codexAuthStatus } from "./auth-DQ2F4vc6.js";
2
- import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
2
+ import { CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_SETTINGS_PATH, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_USAGE_PATH } from "./auth-paths.js";
3
3
  import { createModels } from "@earendil-works/pi-ai";
4
4
  import { openaiCodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
5
5
  import { basename } from "node:path";
@@ -158,6 +158,7 @@ const CODEX_AUTH_URL_TIMEOUT_MS = 3e4;
158
158
  const REMOTE_WEB_ORIGIN_NOT_TRUSTED = "remote-web-origin-not-trusted";
159
159
  const CODEX_USAGE_UNAVAILABLE = "codex-usage-unavailable";
160
160
  const CODEX_SETTINGS_INVALID = "codex-settings-invalid";
161
+ const CODEX_GLOBAL_MODEL_INVALID = "codex-global-model-invalid";
161
162
  const CODEX_SETTINGS_BODY_LIMIT = 8192;
162
163
  function signedInStatus(expiresAt) {
163
164
  return expiresAt === void 0 ? { status: "signed-in" } : {
@@ -393,6 +394,56 @@ function decodeSettingsWrite(value) {
393
394
  if (typeof record["enableImageTool"] !== "boolean" || typeof record["enableImageUpload"] !== "boolean") return;
394
395
  return decodeCodexAuthSettings(record);
395
396
  }
397
+ function codexGlobalModelOf(selection) {
398
+ if (selection.provider !== "openai-codex") return void 0;
399
+ return {
400
+ model: selection.model,
401
+ ...selection.reasoningEffort === void 0 ? {} : { reasoningEffort: selection.reasoningEffort }
402
+ };
403
+ }
404
+ function decodeGlobalModelWrite(value) {
405
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
406
+ const record = value;
407
+ if (typeof record.model !== "string" || record.model.trim().length === 0) return void 0;
408
+ if (record.reasoningEffort !== void 0 && (typeof record.reasoningEffort !== "string" || record.reasoningEffort.trim().length === 0)) return void 0;
409
+ return {
410
+ model: record.model.trim(),
411
+ ...typeof record.reasoningEffort === "string" ? { reasoningEffort: record.reasoningEffort } : {}
412
+ };
413
+ }
414
+ /** Register the plugin-owned bridge to DSH rc.8's shared Agent default model. */
415
+ function registerCodexGlobalModelRoute(ctx, defaultModel, llm) {
416
+ ctx.effect(() => {
417
+ const authorize = (req, res) => {
418
+ if (trustedRequest(req)) return true;
419
+ json(res, 403, { error: REMOTE_WEB_ORIGIN_NOT_TRUSTED });
420
+ return false;
421
+ };
422
+ return ctx.webServer.register({
423
+ kind: "exact",
424
+ path: CODEX_GLOBAL_MODEL_PATH,
425
+ handler: async (req, res) => {
426
+ if (req.method !== "GET" && req.method !== "PUT") return json(res, 405, { error: "method not allowed" });
427
+ if (!authorize(req, res)) return;
428
+ if (req.method === "GET") return json(res, 200, { globalModel: codexGlobalModelOf(defaultModel.currentSelection()) });
429
+ try {
430
+ const next = decodeGlobalModelWrite(await readJsonBody(req));
431
+ if (next === void 0) return json(res, 400, { error: CODEX_GLOBAL_MODEL_INVALID });
432
+ const resolved = await llm.resolveCallConfig({
433
+ provider: CODEX_PROVIDER,
434
+ model: next.model,
435
+ ...next.reasoningEffort === void 0 ? {} : { reasoningEffort: next.reasoningEffort }
436
+ });
437
+ if (resolved.provider !== "openai-codex") return json(res, 400, { error: CODEX_GLOBAL_MODEL_INVALID });
438
+ await defaultModel.saveSelection(resolved);
439
+ return json(res, 200, { globalModel: codexGlobalModelOf(defaultModel.currentSelection()) });
440
+ } catch (error) {
441
+ return json(res, 400, { error: safeMessage(error) });
442
+ }
443
+ }
444
+ });
445
+ }, "dsh-codex-auth-plugin: global Codex model route");
446
+ }
396
447
  /** Register the plugin-owned settings endpoint for browsers opened through a NAS authority. */
397
448
  function registerCodexSettingsRoute(ctx, settings) {
398
449
  ctx.effect(() => {
@@ -715,6 +766,8 @@ function viewImageTool(ctx) {
715
766
  /** OpenAI Codex adapter assembled from dsh's public pi-ai extension seam. */
716
767
  /** Keep the Codex stream open while the provider is still producing output. */
717
768
  const CODEX_STREAM_IDLE_TIMEOUT_MS = 3e5;
769
+ /** Match dsh rc.8's default request-level image payload bound. */
770
+ const CODEX_MAX_REQUEST_IMAGE_BYTES = 20971520;
718
771
  /**
719
772
  * Give dsh's generic adapter the bearer token resolved by the plugin-owned
720
773
  * OAuth store. This keeps the provider-native login flow separate from model
@@ -745,6 +798,7 @@ function createCodexAdapter(credentials, resolveAttachments) {
745
798
  provider: CODEX_PROVIDER,
746
799
  displayName: "OpenAI Codex",
747
800
  streamIdleTimeoutMs: CODEX_STREAM_IDLE_TIMEOUT_MS,
801
+ maxRequestImageBytes: CODEX_MAX_REQUEST_IMAGE_BYTES,
748
802
  retryPolicy: resolveRetryPolicy(void 0, "dsh-codex-auth-plugin retryPolicy"),
749
803
  configuredMaxTokens: /* @__PURE__ */ new Map(),
750
804
  piProvider: requestProvider(provider)
@@ -765,7 +819,9 @@ const name = "dsh-codex-auth-plugin";
765
819
  const inject = [
766
820
  "webServer",
767
821
  "settings",
768
- "credentials"
822
+ "credentials",
823
+ "agentDefaultModel",
824
+ "llm"
769
825
  ];
770
826
  function apply(ctx) {
771
827
  const settings = ctx.settings.register(CODEX_AUTH_SETTINGS_NS, CodexAuthSettingsSchema);
@@ -785,6 +841,7 @@ function apply(ctx) {
785
841
  }, "dsh-codex-auth: credential mirror");
786
842
  registerCodexAuthRoutes(ctx, store, mirror);
787
843
  registerCodexSettingsRoute(ctx, settings);
844
+ registerCodexGlobalModelRoute(ctx, ctx.agentDefaultModel, ctx.llm);
788
845
  let stopped = false;
789
846
  let imageFiber;
790
847
  let imageTail = Promise.resolve();
@@ -827,4 +884,4 @@ function apply(ctx) {
827
884
  scheduleImageTool();
828
885
  }
829
886
  //#endregion
830
- export { CODEX_API_KEY_ENV, CODEX_API_KEY_REF, CODEX_AUTH_FILENAME, CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_PROVIDER, CODEX_STREAM_IDLE_TIMEOUT_MS, CodexCredentialMirror, CodexCredentialStore, CodexUsageService, CodexWebAuth, apply, codexAuthPath, codexAuthStatus, createCodexAdapter, inject, loginCodex, logoutCodex, name, normalizeCodexUsagePayload, registerCodexAuthRoutes, trustedRequest };
887
+ export { CODEX_API_KEY_ENV, CODEX_API_KEY_REF, CODEX_AUTH_FILENAME, CODEX_AUTH_LOGIN_PATH, CODEX_AUTH_LOGOUT_PATH, CODEX_AUTH_SETTINGS_NAMESPACE, CODEX_AUTH_STATUS_PATH, CODEX_GLOBAL_MODEL_PATH, CODEX_PROVIDER, CODEX_STREAM_IDLE_TIMEOUT_MS, CodexCredentialMirror, CodexCredentialStore, CodexUsageService, CodexWebAuth, apply, codexAuthPath, codexAuthStatus, createCodexAdapter, inject, loginCodex, logoutCodex, name, normalizeCodexUsagePayload, registerCodexAuthRoutes, trustedRequest };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tnnevol/dsh-codex-auth",
3
3
  "displayName": "Codex Auth",
4
4
  "description": "Standalone ChatGPT OAuth account management for DeepSeek Harness.",
5
- "version": "0.1.0-rc.7.2",
5
+ "version": "0.1.0-rc.8.1",
6
6
  "author": "tnnevol",
7
7
  "repository": {
8
8
  "type": "git",
@@ -64,6 +64,7 @@
64
64
  "@deepseek-ai/dsh-client-runtime",
65
65
  "@deepseek-ai/dsh-client-ui-conversation",
66
66
  "@deepseek-ai/dsh-client-ui-model-selection",
67
+ "@deepseek-ai/dsh-client-ui-primitives",
67
68
  "@deepseek-ai/dsh-client-ui-settings",
68
69
  "@deepseek-ai/dsh-client-ui-settings-plugins",
69
70
  "@deepseek-ai/dsh-client-locale"
@@ -74,52 +75,56 @@
74
75
  "peerDependencies": {
75
76
  "@earendil-works/pi-ai": "0.82.1",
76
77
  "@deepseek-ai/cordis": "^4.0.1-rc.1",
77
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.7",
78
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.7",
79
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.7",
80
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.7",
81
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.7",
82
- "@deepseek-ai/dsh-llm": "0.1.0-rc.7",
83
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.7",
84
- "@deepseek-ai/dsh-settings": "0.1.0-rc.7",
85
- "@deepseek-ai/dsh-tools": "0.1.0-rc.7",
86
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.7",
87
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.7",
88
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.7",
89
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.0-rc.7",
90
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.7",
91
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.7",
92
- "@deepseek-ai/dsh-fs": "0.1.0-rc.7",
93
- "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.7",
94
- "@deepseek-ai/dsh-timeout": "0.1.0-rc.7",
78
+ "@deepseek-ai/dsh-attachment": "0.1.0-rc.8",
79
+ "@deepseek-ai/dsh-agent-default-model": "0.1.0-rc.8",
80
+ "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.8",
81
+ "@deepseek-ai/dsh-home-paths": "0.1.0-rc.8",
82
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8",
83
+ "@deepseek-ai/dsh-invariants": "0.1.0-rc.8",
84
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
85
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.8",
86
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.8",
87
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
88
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.8",
89
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8",
90
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8",
91
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.8",
92
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.0-rc.8",
93
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.8",
94
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.8",
95
+ "@deepseek-ai/dsh-fs": "0.1.0-rc.8",
96
+ "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8",
97
+ "@deepseek-ai/dsh-timeout": "0.1.0-rc.8",
95
98
  "@deepseek-ai/schemastery": "3.18.1",
96
99
  "react": "^18.2.0"
97
100
  },
98
101
  "devDependencies": {
99
102
  "@earendil-works/pi-ai": "0.82.1",
100
103
  "@deepseek-ai/cordis": "^4.0.1",
101
- "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.7",
102
- "@deepseek-ai/dsh-attachment": "0.1.0-rc.7",
103
- "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.7",
104
- "@deepseek-ai/dsh-client-connection": "0.1.0-rc.7",
105
- "@deepseek-ai/dsh-client-locale": "0.1.0-rc.7",
106
- "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.7",
107
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.7",
108
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.7",
109
- "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.7",
110
- "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.0-rc.7",
111
- "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.7",
112
- "@deepseek-ai/dsh-credentials": "0.1.0-rc.7",
113
- "@deepseek-ai/dsh-home-paths": "0.1.0-rc.7",
114
- "@deepseek-ai/dsh-fs": "0.1.0-rc.7",
115
- "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.7",
116
- "@deepseek-ai/dsh-invariants": "0.1.0-rc.7",
117
- "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.7",
118
- "@deepseek-ai/dsh-llm": "0.1.0-rc.7",
119
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.7",
120
- "@deepseek-ai/dsh-settings": "0.1.0-rc.7",
121
- "@deepseek-ai/dsh-tools": "0.1.0-rc.7",
122
- "@deepseek-ai/dsh-timeout": "0.1.0-rc.7",
104
+ "@deepseek-ai/dsh-api-remotes": "0.1.0-rc.8",
105
+ "@deepseek-ai/dsh-agent-default-model": "0.1.0-rc.8",
106
+ "@deepseek-ai/dsh-attachment": "0.1.0-rc.8",
107
+ "@deepseek-ai/dsh-atomic-write": "0.1.0-rc.8",
108
+ "@deepseek-ai/dsh-client-connection": "0.1.0-rc.8",
109
+ "@deepseek-ai/dsh-client-locale": "0.1.0-rc.8",
110
+ "@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8",
111
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8",
112
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.0-rc.8",
113
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8",
114
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.0-rc.8",
115
+ "@deepseek-ai/dsh-client-ui-settings-plugins": "0.1.0-rc.8",
116
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.8",
117
+ "@deepseek-ai/dsh-credentials": "0.1.0-rc.8",
118
+ "@deepseek-ai/dsh-home-paths": "0.1.0-rc.8",
119
+ "@deepseek-ai/dsh-fs": "0.1.0-rc.8",
120
+ "@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8",
121
+ "@deepseek-ai/dsh-invariants": "0.1.0-rc.8",
122
+ "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8",
123
+ "@deepseek-ai/dsh-llm": "0.1.0-rc.8",
124
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.0-rc.8",
125
+ "@deepseek-ai/dsh-settings": "0.1.0-rc.8",
126
+ "@deepseek-ai/dsh-tools": "0.1.0-rc.8",
127
+ "@deepseek-ai/dsh-timeout": "0.1.0-rc.8",
123
128
  "@deepseek-ai/schemastery": "3.18.1",
124
129
  "@types/node": "^22.20.0",
125
130
  "@types/react": "~18.3.1",