@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 +2 -51
- package/compatibility.json +1 -1
- package/lib/auth-paths.d.ts +3 -1
- package/lib/auth-paths.js +3 -1
- package/lib/client.js +689 -59
- package/lib/index.d.ts +2 -2
- package/lib/index.js +60 -3
- package/package.json +46 -41
package/README.md
CHANGED
|
@@ -1,54 +1,5 @@
|
|
|
1
1
|
# @tnnevol/dsh-codex-auth
|
|
2
2
|
|
|
3
|
-
|
|
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 仅保留插件识别信息,不再维护具体功能说明。
|
package/compatibility.json
CHANGED
package/lib/auth-paths.d.ts
CHANGED
|
@@ -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$
|
|
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$
|
|
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$
|
|
85
|
-
...buttonStyle$
|
|
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$
|
|
91
|
-
...bodyStyle$
|
|
92
|
+
const errorStyle$2 = {
|
|
93
|
+
...bodyStyle$2,
|
|
92
94
|
color: "var(--dsw-alias-state-error-primary, #d92d20)"
|
|
93
95
|
};
|
|
94
|
-
const successStyle = {
|
|
95
|
-
...bodyStyle$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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$
|
|
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: "
|
|
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.
|
|
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")
|
|
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: [
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
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
|
-
|
|
850
|
-
display: "inline-flex",
|
|
1419
|
+
display: "flex",
|
|
851
1420
|
alignItems: "center",
|
|
852
|
-
|
|
1421
|
+
flexWrap: "wrap",
|
|
1422
|
+
gap: 8
|
|
853
1423
|
},
|
|
854
|
-
children:
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
78
|
-
"@deepseek-ai/dsh-
|
|
79
|
-
"@deepseek-ai/dsh-
|
|
80
|
-
"@deepseek-ai/dsh-
|
|
81
|
-
"@deepseek-ai/dsh-
|
|
82
|
-
"@deepseek-ai/dsh-
|
|
83
|
-
"@deepseek-ai/dsh-llm
|
|
84
|
-
"@deepseek-ai/dsh-
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-
|
|
87
|
-
"@deepseek-ai/dsh-client-
|
|
88
|
-
"@deepseek-ai/dsh-client-
|
|
89
|
-
"@deepseek-ai/dsh-client-ui-
|
|
90
|
-
"@deepseek-ai/dsh-client-ui-
|
|
91
|
-
"@deepseek-ai/dsh-
|
|
92
|
-
"@deepseek-ai/dsh-
|
|
93
|
-
"@deepseek-ai/dsh-
|
|
94
|
-
"@deepseek-ai/dsh-
|
|
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.
|
|
102
|
-
"@deepseek-ai/dsh-
|
|
103
|
-
"@deepseek-ai/dsh-
|
|
104
|
-
"@deepseek-ai/dsh-
|
|
105
|
-
"@deepseek-ai/dsh-client-
|
|
106
|
-
"@deepseek-ai/dsh-client-
|
|
107
|
-
"@deepseek-ai/dsh-client-
|
|
108
|
-
"@deepseek-ai/dsh-client-ui-
|
|
109
|
-
"@deepseek-ai/dsh-client-ui-
|
|
110
|
-
"@deepseek-ai/dsh-client-ui-
|
|
111
|
-
"@deepseek-ai/dsh-client-ui-
|
|
112
|
-
"@deepseek-ai/dsh-
|
|
113
|
-
"@deepseek-ai/dsh-
|
|
114
|
-
"@deepseek-ai/dsh-
|
|
115
|
-
"@deepseek-ai/dsh-
|
|
116
|
-
"@deepseek-ai/dsh-
|
|
117
|
-
"@deepseek-ai/dsh-
|
|
118
|
-
"@deepseek-ai/dsh-
|
|
119
|
-
"@deepseek-ai/dsh-
|
|
120
|
-
"@deepseek-ai/dsh-
|
|
121
|
-
"@deepseek-ai/dsh-
|
|
122
|
-
"@deepseek-ai/dsh-
|
|
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",
|