dsh-codex-subscription 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +5 -5
- package/README.md +3 -2
- package/README.zh-CN.md +3 -2
- package/lib/client.js +108 -10
- package/lib/index.js +323 -38
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
|
6
6
|
## Safety
|
|
7
7
|
|
|
8
8
|
- Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
|
|
9
|
-
- Use the exact `1.
|
|
9
|
+
- Use the exact `1.10.0` package below; do not install a moving branch.
|
|
10
10
|
- Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
|
|
11
11
|
- Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
|
|
12
12
|
- Do not start, stop, or restart DSH without explicit permission.
|
|
@@ -34,13 +34,13 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
|
|
|
34
34
|
run command does not create a global `dsh` command:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.
|
|
37
|
+
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.10.0
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
With an existing global `dsh` command:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-codex-subscription@1.
|
|
43
|
+
dsh plugin --profile web add dsh-codex-subscription@1.10.0
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
@@ -58,12 +58,12 @@ dsh --profile web --dump-config
|
|
|
58
58
|
|
|
59
59
|
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.2` in place of `dsh`.
|
|
60
60
|
|
|
61
|
-
1. `dsh-codex-subscription` version `1.
|
|
61
|
+
1. `dsh-codex-subscription` version `1.10.0` appears exactly once.
|
|
62
62
|
2. `codex-subscription` appears exactly once in the composed config.
|
|
63
63
|
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
64
64
|
|
|
65
65
|
With permission to restart DSH, open **Settings -> Codex** and verify the settings page loads. Confirm
|
|
66
|
-
that search offers
|
|
66
|
+
that search offers **Auto**, **DSH default**, and **Codex subscription**, the composer quota switch defaults
|
|
67
67
|
to off, and `codex_image_generate` is available. Do not consume quota merely to test installation unless
|
|
68
68
|
the user explicitly asks for a live model, search, or image-generation check.
|
|
69
69
|
|
package/README.md
CHANGED
|
@@ -65,7 +65,7 @@ Captured from the installed official DeepSeek Harness `0.1.1-rc.2` product with
|
|
|
65
65
|
|
|
66
66
|
## Prepare DSH
|
|
67
67
|
|
|
68
|
-
This plugin
|
|
68
|
+
This plugin supports the latest DeepSeek Harness release recorded in its package metadata and requires a ChatGPT account that currently has Codex access.
|
|
69
69
|
|
|
70
70
|
- Do not want to configure Node.js? Use [DSH-Portable](https://github.com/WSL043/DSH-Portable), a community portable desktop distribution for Windows, macOS, and Linux.
|
|
71
71
|
- Prefer the official route? Follow the [DeepSeek Harness run guide](https://github.com/deepseek-ai/deepseek-harness#run).
|
|
@@ -219,9 +219,10 @@ dsh plugin --profile web remove dsh-codex-subscription
|
|
|
219
219
|
The ChatGPT Codex backend and DSH can change independently. This community project is not affiliated with or endorsed by DeepSeek or OpenAI.
|
|
220
220
|
|
|
221
221
|
Use the [bug report form](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml) for project feedback.
|
|
222
|
+
Use the [feature request form](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=feature-request.yml) for focused product suggestions.
|
|
222
223
|
For DSH plugin discussion, visit [DeepSeek Harness Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions).
|
|
223
224
|
Read [SECURITY.md](SECURITY.md) before reporting sensitive issues.
|
|
224
225
|
|
|
225
226
|
If this project is useful, the [Star button](https://github.com/WSL043/dsh-codex-subscription/stargazers) helps more DSH users find it.
|
|
226
227
|
|
|
227
|
-
[简体中文](README.md) · [MIT](LICENSE)
|
|
228
|
+
[简体中文](README.zh-CN.md) · [MIT](LICENSE)
|
package/README.zh-CN.md
CHANGED
|
@@ -50,7 +50,7 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
50
50
|
| **输入框额度** | 可选择紧凑百分比、进度条或完全关闭输入框额度显示 |
|
|
51
51
|
| **安全额度重置** | 直接查看最早到期时间,并通过冷静期和知情确认主动尝试重置 |
|
|
52
52
|
| **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
|
|
53
|
-
| **Codex 图片生成与编辑(Beta)** |
|
|
53
|
+
| **Codex 图片生成与编辑(Beta)** | 可无参考图全新生成,也可明确选择会话图片继续编辑;支持预览、缩放、区域备注、下载原图并衔接回当前输入框 |
|
|
54
54
|
| **高速模式** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
55
55
|
| **模型感知上下文** | 可保留目录默认值、按模型启用扩展窗口,或为每个模型填写完整数字 Token 上限 |
|
|
56
56
|
|
|
@@ -66,7 +66,7 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
66
66
|
|
|
67
67
|
## 准备 DSH
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
本插件支持软件包元数据中记录的最新版 DeepSeek Harness,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
|
|
70
70
|
|
|
71
71
|
- 不想配置 Node.js:使用 [DSH-Portable](https://github.com/WSL043/DSH-Portable)。这是面向 Windows、macOS 和 Linux 的社区便携桌面分发;
|
|
72
72
|
- 想按官方方式运行:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
|
|
@@ -217,6 +217,7 @@ dsh plugin --profile web remove dsh-codex-subscription
|
|
|
217
217
|
ChatGPT Codex 后端和 DSH 可能独立变化;本项目为社区项目,与 DeepSeek、OpenAI 无隶属或背书关系。
|
|
218
218
|
|
|
219
219
|
本项目的问题反馈请使用[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml);
|
|
220
|
+
明确的产品建议请使用[功能建议表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=feature-request.yml);
|
|
220
221
|
DSH 插件交流可前往 [DeepSeek Harness Discussions](https://github.com/deepseek-ai/deepseek-harness/discussions)。
|
|
221
222
|
敏感问题请先阅读 [SECURITY.md](SECURITY.md)。
|
|
222
223
|
|
package/lib/client.js
CHANGED
|
@@ -66,11 +66,18 @@ window.__ModuleLoader__.load({
|
|
|
66
66
|
const LEGACY_QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
67
67
|
const QUICK_QUOTA_MODE_PERCENT = "percent";
|
|
68
68
|
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
69
|
+
const SEARCH_PROVIDER_AUTO = "auto";
|
|
69
70
|
const SEARCH_PROVIDER_CODEX = "codex";
|
|
71
|
+
const DEFAULT_SEARCH_PROVIDER = SEARCH_PROVIDER_AUTO;
|
|
70
72
|
const SPEED_MODE_FIELD = "speedMode";
|
|
71
73
|
const SPEED_MODE_STANDARD = "standard";
|
|
72
74
|
const SPEED_MODE_FAST = "fast";
|
|
73
75
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
76
|
+
const OUTPUT_VERBOSITY_FIELD = "outputVerbosity";
|
|
77
|
+
const OUTPUT_VERBOSITY_DEFAULT = "default";
|
|
78
|
+
const OUTPUT_VERBOSITY_MEDIUM = "medium";
|
|
79
|
+
const OUTPUT_VERBOSITY_HIGH = "high";
|
|
80
|
+
const DEFAULT_OUTPUT_VERBOSITY = OUTPUT_VERBOSITY_DEFAULT;
|
|
74
81
|
const CONTEXT_MODE_FIELD = "contextMode";
|
|
75
82
|
const CONTEXT_MODE_STANDARD = "standard";
|
|
76
83
|
const CONTEXT_MODE_EXTENDED = "extended";
|
|
@@ -98,7 +105,17 @@ window.__ModuleLoader__.load({
|
|
|
98
105
|
"gpt-5.5": 272e3,
|
|
99
106
|
"gpt-5.6": 272e3
|
|
100
107
|
});
|
|
101
|
-
const normalizeSearchProvider = (value) => [
|
|
108
|
+
const normalizeSearchProvider = (value) => [
|
|
109
|
+
"auto",
|
|
110
|
+
"dsh",
|
|
111
|
+
"codex"
|
|
112
|
+
].includes(value) ? value : DEFAULT_SEARCH_PROVIDER;
|
|
113
|
+
const normalizeOutputVerbosity = (value) => [
|
|
114
|
+
"default",
|
|
115
|
+
"low",
|
|
116
|
+
"medium",
|
|
117
|
+
"high"
|
|
118
|
+
].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
|
|
102
119
|
const normalizeSpeedMode = (value) => ["standard", "fast"].includes(value) ? value : DEFAULT_SPEED_MODE;
|
|
103
120
|
const normalizeContextMode = (value) => [
|
|
104
121
|
"standard",
|
|
@@ -223,7 +240,9 @@ window.__ModuleLoader__.load({
|
|
|
223
240
|
diagnosticsFailed: "无法生成诊断信息。",
|
|
224
241
|
feedbackOpen: "反馈问题",
|
|
225
242
|
searchTitle: "搜索来源",
|
|
226
|
-
searchScope: "
|
|
243
|
+
searchScope: "自动按当前会话模型分流;手动选择会覆盖所有模型和会话。",
|
|
244
|
+
searchAuto: "自动",
|
|
245
|
+
searchAutoHint: "Codex 模型用订阅搜索,其他模型用 DSH",
|
|
227
246
|
searchDsh: "DSH 默认",
|
|
228
247
|
searchDshHint: "所有模型使用 DSH 当前搜索服务",
|
|
229
248
|
searchCodex: "Codex 订阅",
|
|
@@ -301,7 +320,16 @@ window.__ModuleLoader__.load({
|
|
|
301
320
|
speedStandardHint: "标准速度",
|
|
302
321
|
speedFast: "高速",
|
|
303
322
|
speedFastHint: "1.5 倍,消耗更多 Credits",
|
|
304
|
-
|
|
323
|
+
verbosityTitle: "输出详略",
|
|
324
|
+
verbosityDefault: "模型默认",
|
|
325
|
+
verbosityDefaultHint: "使用官方模型目录推荐值",
|
|
326
|
+
verbosityLow: "简洁",
|
|
327
|
+
verbosityLowHint: "更短、更直接",
|
|
328
|
+
verbosityMedium: "均衡",
|
|
329
|
+
verbosityMediumHint: "兼顾完整性与长度",
|
|
330
|
+
verbosityHigh: "详细",
|
|
331
|
+
verbosityHighHint: "更充分的说明与结构",
|
|
332
|
+
modelMenuAria: "模型、推理等级、速度与输出详略",
|
|
305
333
|
modelLabel: "模型",
|
|
306
334
|
effortLabel: "推理等级",
|
|
307
335
|
providerDefault: "Default",
|
|
@@ -366,7 +394,9 @@ window.__ModuleLoader__.load({
|
|
|
366
394
|
diagnosticsFailed: "Could not create diagnostics.",
|
|
367
395
|
feedbackOpen: "Report a problem",
|
|
368
396
|
searchTitle: "Search source",
|
|
369
|
-
searchScope: "
|
|
397
|
+
searchScope: "Auto follows the current session model; an explicit choice overrides every model and session.",
|
|
398
|
+
searchAuto: "Auto",
|
|
399
|
+
searchAutoHint: "Codex models use subscription search; other models use DSH",
|
|
370
400
|
searchDsh: "DSH default",
|
|
371
401
|
searchDshHint: "Use DSH's current search service for every model",
|
|
372
402
|
searchCodex: "Codex subscription",
|
|
@@ -444,7 +474,16 @@ window.__ModuleLoader__.load({
|
|
|
444
474
|
speedStandardHint: "Standard speed",
|
|
445
475
|
speedFast: "Fast",
|
|
446
476
|
speedFastHint: "1.5x; higher Credits use",
|
|
447
|
-
|
|
477
|
+
verbosityTitle: "Output detail",
|
|
478
|
+
verbosityDefault: "Model default",
|
|
479
|
+
verbosityDefaultHint: "Use the official model catalog recommendation",
|
|
480
|
+
verbosityLow: "Concise",
|
|
481
|
+
verbosityLowHint: "Shorter and more direct",
|
|
482
|
+
verbosityMedium: "Balanced",
|
|
483
|
+
verbosityMediumHint: "Balance completeness and length",
|
|
484
|
+
verbosityHigh: "Detailed",
|
|
485
|
+
verbosityHighHint: "More explanation and structure",
|
|
486
|
+
modelMenuAria: "Model, effort, speed, and output detail",
|
|
448
487
|
modelLabel: "Model",
|
|
449
488
|
effortLabel: "Effort",
|
|
450
489
|
providerDefault: "Default",
|
|
@@ -495,7 +534,7 @@ window.__ModuleLoader__.load({
|
|
|
495
534
|
.codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer}.codexSubscriptionQuotaMode:has(input:checked){background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 0 0 1px var(--dsw-alias-border-l3)}.codexSubscriptionQuotaMode:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionQuotaMode:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionQuotaMode input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
|
|
496
535
|
.codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}.codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.codexSubscriptionContextTrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionContextTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexSubscriptionContextTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.codexSubscriptionContextTrigger svg{color:var(--dsw-alias-label-tertiary);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionContextTrigger[aria-expanded=true] svg{transform:rotate(180deg)}.codexSubscriptionContextModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel:last-child{border-bottom:0}.codexSubscriptionContextModelCopy{display:flex;min-width:0;flex-direction:column}.codexSubscriptionContextModelCopy strong{font-size:12px;line-height:18px;font-weight:500}.codexSubscriptionContextModelCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextInput{width:116px}
|
|
497
536
|
.codexSubscriptionSwitch{position:relative;flex:0 0 auto;width:32px;height:18px;padding:0;border:1px solid var(--dsw-alias-border-l3);border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer}.codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}.codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary)}.codexSubscriptionSwitchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(14px)}
|
|
498
|
-
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(
|
|
537
|
+
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:6px}.codexSubscriptionSearchChoice{display:grid;grid-template-columns:14px minmax(0,1fr);align-items:center;column-gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);padding:9px 10px;text-align:left;cursor:pointer}.codexSubscriptionSearchChoice:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionSearchChoice:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.codexSubscriptionSearchChoice:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.codexSubscriptionSearchInput{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-label-primary);cursor:inherit}.codexSubscriptionSearchCopy{display:block;min-width:0;pointer-events:none}.codexSubscriptionSearchCopy strong,.codexSubscriptionSearchCopy span{display:block}.codexSubscriptionSearchCopy strong{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}.codexSubscriptionSearchChoice:has(input:checked) strong{color:var(--dsw-alias-label-primary)}.codexSubscriptionSearchCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionDivider{height:1px;background:var(--dsw-alias-border-l2)}
|
|
499
538
|
.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionStatus{display:flex;align-items:center;gap:8px;font-size:14px;line-height:22px;font-weight:500}
|
|
500
539
|
.codexSubscriptionDot{width:8px;height:8px;border-radius:50%;background:var(--dsw-alias-label-dimmed)}.codexSubscriptionDot[data-state=connected]{background:var(--dsw-alias-state-success-primary)}.codexSubscriptionDot[data-state=disconnected]{background:var(--dsw-alias-state-error-primary)}
|
|
501
540
|
.codexSubscriptionActions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.codexSubscriptionFlow{display:flex;flex-direction:column;gap:10px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-module-platform)}
|
|
@@ -922,6 +961,7 @@ window.__ModuleLoader__.load({
|
|
|
922
961
|
let failedPatch;
|
|
923
962
|
let generation = 0;
|
|
924
963
|
let contextModels = [];
|
|
964
|
+
let verbosityModels = [];
|
|
925
965
|
const nativeSnapshot = () => scope.getSnapshot();
|
|
926
966
|
const read = () => {
|
|
927
967
|
const native = nativeSnapshot();
|
|
@@ -931,10 +971,12 @@ window.__ModuleLoader__.load({
|
|
|
931
971
|
quickQuotaMode: normalizeQuickQuotaMode(current.value?.[QUICK_QUOTA_MODE_FIELD], current.value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
932
972
|
searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
|
|
933
973
|
speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
|
|
974
|
+
outputVerbosity: normalizeOutputVerbosity(current.value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
934
975
|
contextMode: normalizeContextMode(current.value?.[CONTEXT_MODE_FIELD]),
|
|
935
976
|
customContextWindow: normalizeCustomContextWindow(current.value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
936
977
|
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(current.value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
937
978
|
contextModels,
|
|
979
|
+
verbosityModels,
|
|
938
980
|
writable: !updating && current.status === "ready" && current.writable === true,
|
|
939
981
|
error
|
|
940
982
|
});
|
|
@@ -952,6 +994,7 @@ window.__ModuleLoader__.load({
|
|
|
952
994
|
});
|
|
953
995
|
const acceptFallback = (value) => {
|
|
954
996
|
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
997
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
955
998
|
fallbackStatus = "ready";
|
|
956
999
|
fallback = {
|
|
957
1000
|
status: "ready",
|
|
@@ -959,6 +1002,7 @@ window.__ModuleLoader__.load({
|
|
|
959
1002
|
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
960
1003
|
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
961
1004
|
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
1005
|
+
[OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(value?.[OUTPUT_VERBOSITY_FIELD]),
|
|
962
1006
|
[CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
963
1007
|
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
964
1008
|
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
|
|
@@ -977,8 +1021,10 @@ window.__ModuleLoader__.load({
|
|
|
977
1021
|
try {
|
|
978
1022
|
const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
|
|
979
1023
|
if (current !== generation) return;
|
|
980
|
-
if (nativeSnapshot().status === "ready")
|
|
981
|
-
|
|
1024
|
+
if (nativeSnapshot().status === "ready") {
|
|
1025
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1026
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1027
|
+
} else acceptFallback(value);
|
|
982
1028
|
publish();
|
|
983
1029
|
} catch {
|
|
984
1030
|
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
@@ -1145,7 +1191,11 @@ window.__ModuleLoader__.load({
|
|
|
1145
1191
|
className: "codexSubscriptionSearchChoices",
|
|
1146
1192
|
role: "radiogroup",
|
|
1147
1193
|
"aria-label": t("searchTitle"),
|
|
1148
|
-
children: [
|
|
1194
|
+
children: [
|
|
1195
|
+
choice(SEARCH_PROVIDER_AUTO, t("searchAuto"), t("searchAutoHint")),
|
|
1196
|
+
choice("dsh", t("searchDsh"), t("searchDshHint")),
|
|
1197
|
+
choice(SEARCH_PROVIDER_CODEX, t("searchCodex"), t("searchCodexHint"))
|
|
1198
|
+
]
|
|
1149
1199
|
})]
|
|
1150
1200
|
});
|
|
1151
1201
|
}
|
|
@@ -1363,6 +1413,31 @@ window.__ModuleLoader__.load({
|
|
|
1363
1413
|
const speedSupported = state.current?.provider === "openai-codex" && supportsCodexFastMode(state.current?.model);
|
|
1364
1414
|
const speedWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
1365
1415
|
const fast = speedSupported && preferenceSnapshot.speedMode === "fast";
|
|
1416
|
+
const verbositySupported = state.current?.provider === "openai-codex" && preferenceSnapshot.verbosityModels.includes(state.current?.model);
|
|
1417
|
+
const verbosityWritable = preferenceSnapshot.status === "ready" && preferenceSnapshot.writable === true;
|
|
1418
|
+
const verbosityItems = [
|
|
1419
|
+
{
|
|
1420
|
+
id: OUTPUT_VERBOSITY_DEFAULT,
|
|
1421
|
+
label: t("verbosityDefault"),
|
|
1422
|
+
description: t("verbosityDefaultHint")
|
|
1423
|
+
},
|
|
1424
|
+
{
|
|
1425
|
+
id: "low",
|
|
1426
|
+
label: t("verbosityLow"),
|
|
1427
|
+
description: t("verbosityLowHint")
|
|
1428
|
+
},
|
|
1429
|
+
{
|
|
1430
|
+
id: OUTPUT_VERBOSITY_MEDIUM,
|
|
1431
|
+
label: t("verbosityMedium"),
|
|
1432
|
+
description: t("verbosityMediumHint")
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
id: OUTPUT_VERBOSITY_HIGH,
|
|
1436
|
+
label: t("verbosityHigh"),
|
|
1437
|
+
description: t("verbosityHighHint")
|
|
1438
|
+
}
|
|
1439
|
+
];
|
|
1440
|
+
const verbosityLabel = verbosityItems.find((item) => item.id === preferenceSnapshot.outputVerbosity)?.label ?? t("verbosityDefault");
|
|
1366
1441
|
const busy = state.status === "selecting";
|
|
1367
1442
|
(0, react.useEffect)(() => {
|
|
1368
1443
|
if (available) load();
|
|
@@ -1380,7 +1455,12 @@ window.__ModuleLoader__.load({
|
|
|
1380
1455
|
}, [open]);
|
|
1381
1456
|
(0, react.useEffect)(() => {
|
|
1382
1457
|
if (!speedSupported && pane === "speed") setPane("root");
|
|
1383
|
-
|
|
1458
|
+
if (!verbositySupported && pane === "verbosity") setPane("root");
|
|
1459
|
+
}, [
|
|
1460
|
+
pane,
|
|
1461
|
+
speedSupported,
|
|
1462
|
+
verbositySupported
|
|
1463
|
+
]);
|
|
1384
1464
|
if (!available) return null;
|
|
1385
1465
|
const close = (restoreFocus = false) => {
|
|
1386
1466
|
setOpen(false);
|
|
@@ -1413,6 +1493,10 @@ window.__ModuleLoader__.load({
|
|
|
1413
1493
|
close(true);
|
|
1414
1494
|
preference.set({ [SPEED_MODE_FIELD]: speedMode });
|
|
1415
1495
|
};
|
|
1496
|
+
const chooseVerbosity = (outputVerbosity) => {
|
|
1497
|
+
close(true);
|
|
1498
|
+
preference.set({ [OUTPUT_VERBOSITY_FIELD]: outputVerbosity });
|
|
1499
|
+
};
|
|
1416
1500
|
const option = ({ key, label, description, selected, disabled, onClick }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1417
1501
|
type: "button",
|
|
1418
1502
|
role: "menuitemradio",
|
|
@@ -1545,6 +1629,19 @@ window.__ModuleLoader__.load({
|
|
|
1545
1629
|
onClick: () => chooseSpeed(SPEED_MODE_FAST)
|
|
1546
1630
|
})]
|
|
1547
1631
|
});
|
|
1632
|
+
else if (pane === "verbosity") submenu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1633
|
+
className: "codexModelSelectSubmenu",
|
|
1634
|
+
role: "menu",
|
|
1635
|
+
"aria-label": t("verbosityTitle"),
|
|
1636
|
+
children: verbosityItems.map((item) => option({
|
|
1637
|
+
key: item.id,
|
|
1638
|
+
label: item.label,
|
|
1639
|
+
description: item.description,
|
|
1640
|
+
selected: preferenceSnapshot.outputVerbosity === item.id,
|
|
1641
|
+
disabled: !verbosityWritable,
|
|
1642
|
+
onClick: () => chooseVerbosity(item.id)
|
|
1643
|
+
}))
|
|
1644
|
+
});
|
|
1548
1645
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1549
1646
|
className: "codexModelSelect",
|
|
1550
1647
|
ref: rootRef,
|
|
@@ -1590,6 +1687,7 @@ window.__ModuleLoader__.load({
|
|
|
1590
1687
|
cell("model", t("modelLabel"), modelLabel),
|
|
1591
1688
|
reasoning === void 0 ? null : cell("effort", t("effortLabel"), effortLabel),
|
|
1592
1689
|
speedSupported && cell("speed", t("speedTitle"), t(fast ? "speedFast" : "speedStandard")),
|
|
1690
|
+
verbositySupported && cell("verbosity", t("verbosityTitle"), verbosityLabel),
|
|
1593
1691
|
submenu
|
|
1594
1692
|
]
|
|
1595
1693
|
}) : null]
|
package/lib/index.js
CHANGED
|
@@ -726,11 +726,18 @@ const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
|
|
|
726
726
|
const LEGACY_QUICK_QUOTA_FIELD = "quickQuotaVisible";
|
|
727
727
|
const QUICK_QUOTA_MODE_PERCENT = "percent";
|
|
728
728
|
const SEARCH_PROVIDER_FIELD = "searchProvider";
|
|
729
|
+
const SEARCH_PROVIDER_AUTO = "auto";
|
|
729
730
|
const SEARCH_PROVIDER_CODEX = "codex";
|
|
731
|
+
const DEFAULT_SEARCH_PROVIDER = SEARCH_PROVIDER_AUTO;
|
|
730
732
|
const SPEED_MODE_FIELD = "speedMode";
|
|
731
733
|
const SPEED_MODE_STANDARD = "standard";
|
|
732
734
|
const SPEED_MODE_FAST = "fast";
|
|
733
735
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
736
|
+
const OUTPUT_VERBOSITY_FIELD = "outputVerbosity";
|
|
737
|
+
const OUTPUT_VERBOSITY_DEFAULT = "default";
|
|
738
|
+
const OUTPUT_VERBOSITY_MEDIUM = "medium";
|
|
739
|
+
const OUTPUT_VERBOSITY_HIGH = "high";
|
|
740
|
+
const DEFAULT_OUTPUT_VERBOSITY = OUTPUT_VERBOSITY_DEFAULT;
|
|
734
741
|
const CONTEXT_MODE_FIELD = "contextMode";
|
|
735
742
|
const CONTEXT_MODE_STANDARD = "standard";
|
|
736
743
|
const CONTEXT_MODE_EXTENDED = "extended";
|
|
@@ -758,6 +765,12 @@ const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
|
|
|
758
765
|
"gpt-5.5": 272e3,
|
|
759
766
|
"gpt-5.6": 272e3
|
|
760
767
|
});
|
|
768
|
+
const normalizeOutputVerbosity = (value) => [
|
|
769
|
+
"default",
|
|
770
|
+
"low",
|
|
771
|
+
"medium",
|
|
772
|
+
"high"
|
|
773
|
+
].includes(value) ? value : DEFAULT_OUTPUT_VERBOSITY;
|
|
761
774
|
const normalizeContextMode = (value) => [
|
|
762
775
|
"standard",
|
|
763
776
|
"extended",
|
|
@@ -829,7 +842,7 @@ const EXTENDED_CONTEXT_WINDOWS = Object.freeze({
|
|
|
829
842
|
"gpt-5.6-sol": 1e6,
|
|
830
843
|
"gpt-5.6-terra": 1e6
|
|
831
844
|
});
|
|
832
|
-
function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, runNetwork = (_area, operation) => operation() } = {}) {
|
|
845
|
+
function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, catalog, runNetwork = (_area, operation) => operation() } = {}) {
|
|
833
846
|
const provider = createOpenAICodexProvider();
|
|
834
847
|
const requestToken = Object.freeze({
|
|
835
848
|
name: "DSH-managed Codex OAuth request token",
|
|
@@ -842,25 +855,40 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
842
855
|
};
|
|
843
856
|
}
|
|
844
857
|
});
|
|
845
|
-
const
|
|
846
|
-
|
|
858
|
+
const modelMetadata = (model) => catalog?.metadata(model?.id);
|
|
859
|
+
const supportsVerbosity = (model) => modelMetadata(model)?.supportVerbosity ?? model?.id !== "gpt-5.3-codex-spark";
|
|
860
|
+
const withPreferences = (model, options = {}) => {
|
|
861
|
+
const metadata = modelMetadata(model);
|
|
862
|
+
const requestedVerbosity = resolveOutputVerbosity();
|
|
863
|
+
const textVerbosity = supportsVerbosity(model) ? requestedVerbosity === "default" ? metadata?.defaultVerbosity ?? "medium" : requestedVerbosity : void 0;
|
|
864
|
+
const fast = resolveSpeedMode() === "fast" && (metadata?.supportsFast ?? supportsCodexFastMode(model?.id));
|
|
847
865
|
const onPayload = options.onPayload;
|
|
848
866
|
return {
|
|
849
867
|
...options,
|
|
850
|
-
|
|
868
|
+
...textVerbosity === void 0 ? {} : { textVerbosity },
|
|
869
|
+
...fast ? { serviceTier: FAST_SERVICE_TIER } : {},
|
|
851
870
|
async onPayload(payload, requestModel) {
|
|
852
|
-
const
|
|
871
|
+
const preferred = {
|
|
853
872
|
...payload,
|
|
854
|
-
|
|
873
|
+
...textVerbosity === void 0 ? {} : { text: {
|
|
874
|
+
...payload.text ?? {},
|
|
875
|
+
verbosity: textVerbosity
|
|
876
|
+
} },
|
|
877
|
+
...fast ? { service_tier: FAST_SERVICE_TIER } : {}
|
|
855
878
|
};
|
|
879
|
+
const next = await onPayload?.(preferred, requestModel);
|
|
856
880
|
return {
|
|
857
|
-
...
|
|
858
|
-
|
|
881
|
+
...next ?? preferred,
|
|
882
|
+
...textVerbosity === void 0 ? {} : { text: {
|
|
883
|
+
...(next ?? preferred).text ?? {},
|
|
884
|
+
verbosity: textVerbosity
|
|
885
|
+
} },
|
|
886
|
+
...fast ? { service_tier: FAST_SERVICE_TIER } : {}
|
|
859
887
|
};
|
|
860
888
|
}
|
|
861
889
|
};
|
|
862
890
|
};
|
|
863
|
-
const getModels = () => provider.getModels().map((model) => {
|
|
891
|
+
const getModels = () => (catalog?.getModels(provider.getModels()) ?? provider.getModels()).map((model) => {
|
|
864
892
|
const maximum = EXTENDED_CONTEXT_WINDOWS[model.id];
|
|
865
893
|
const mode = resolveContextMode();
|
|
866
894
|
if (maximum === void 0 || !["extended", "custom"].includes(mode)) return model;
|
|
@@ -896,17 +924,147 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
896
924
|
apiKey: requestToken
|
|
897
925
|
}),
|
|
898
926
|
getModels,
|
|
899
|
-
stream: (model, context, options) => networkIterable(() => provider.stream(model, context,
|
|
900
|
-
streamSimple: (model, context, options) => networkIterable(() => provider.streamSimple(model, context,
|
|
927
|
+
stream: (model, context, options) => networkIterable(() => provider.stream(model, context, withPreferences(model, options))),
|
|
928
|
+
streamSimple: (model, context, options) => networkIterable(() => provider.streamSimple(model, context, withPreferences(model, options)))
|
|
901
929
|
});
|
|
902
930
|
}
|
|
903
931
|
//#endregion
|
|
904
932
|
//#region src/version.js
|
|
905
|
-
const PACKAGE_VERSION = "1.
|
|
933
|
+
const PACKAGE_VERSION = "1.10.0";
|
|
906
934
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
907
935
|
//#endregion
|
|
936
|
+
//#region src/model-catalog.js
|
|
937
|
+
const CODEX_MODELS_URL = `https://chatgpt.com/backend-api/codex/models?client_version=${encodeURIComponent(PACKAGE_VERSION)}`;
|
|
938
|
+
const LEVELS = [
|
|
939
|
+
"off",
|
|
940
|
+
"minimal",
|
|
941
|
+
"low",
|
|
942
|
+
"medium",
|
|
943
|
+
"high",
|
|
944
|
+
"xhigh",
|
|
945
|
+
"max"
|
|
946
|
+
];
|
|
947
|
+
const record$4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
948
|
+
const nonEmpty$2 = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
949
|
+
const positiveInteger = (value) => Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
950
|
+
function reasoningMap(levels) {
|
|
951
|
+
const supported = new Set((Array.isArray(levels) ? levels : []).map((level) => nonEmpty$2(record$4(level) ? level.effort : void 0)).filter(Boolean));
|
|
952
|
+
const map = Object.fromEntries(LEVELS.map((level) => [level, null]));
|
|
953
|
+
if (supported.has("none")) map.off = "none";
|
|
954
|
+
for (const level of LEVELS.slice(1)) if (supported.has(level)) map[level] = level;
|
|
955
|
+
return map;
|
|
956
|
+
}
|
|
957
|
+
function visibleModel(value) {
|
|
958
|
+
if (!record$4(value)) return void 0;
|
|
959
|
+
const id = nonEmpty$2(value.slug);
|
|
960
|
+
if (id === void 0 || value.supported_in_api !== true || value.visibility !== "list") return void 0;
|
|
961
|
+
const supported = Array.isArray(value.supported_reasoning_levels) ? value.supported_reasoning_levels : [];
|
|
962
|
+
const input = Array.isArray(value.input_modalities) ? value.input_modalities.filter((item) => ["text", "image"].includes(item)) : ["text", "image"];
|
|
963
|
+
return {
|
|
964
|
+
id,
|
|
965
|
+
name: nonEmpty$2(value.display_name) ?? id,
|
|
966
|
+
description: nonEmpty$2(value.description),
|
|
967
|
+
priority: Number.isFinite(value.priority) ? value.priority : 0,
|
|
968
|
+
input: input.length > 0 ? input : ["text"],
|
|
969
|
+
contextWindow: positiveInteger(value.context_window) ?? positiveInteger(value.max_context_window),
|
|
970
|
+
reasoning: supported.length > 0,
|
|
971
|
+
thinkingLevelMap: reasoningMap(supported),
|
|
972
|
+
supportVerbosity: value.support_verbosity === true,
|
|
973
|
+
defaultVerbosity: [
|
|
974
|
+
"low",
|
|
975
|
+
"medium",
|
|
976
|
+
"high"
|
|
977
|
+
].includes(value.default_verbosity) ? value.default_verbosity : void 0,
|
|
978
|
+
supportsFast: [...Array.isArray(value.additional_speed_tiers) ? value.additional_speed_tiers : [], ...Array.isArray(value.service_tiers) ? value.service_tiers.map((tier) => tier?.id) : []].some((tier) => tier === "fast" || tier === "priority")
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function parseOfficialModelCatalog(value) {
|
|
982
|
+
if (!record$4(value) || !Array.isArray(value.models)) throw new Error("Codex returned a malformed model catalog");
|
|
983
|
+
const seen = /* @__PURE__ */ new Set();
|
|
984
|
+
return value.models.map(visibleModel).filter((model) => model !== void 0 && !seen.has(model.id) && seen.add(model.id)).sort((left, right) => right.priority - left.priority);
|
|
985
|
+
}
|
|
986
|
+
function mergeModel(baseModels, remote) {
|
|
987
|
+
const base = baseModels.find((model) => model.id === remote.id) ?? baseModels.find((model) => model.id !== "gpt-5.3-codex-spark") ?? baseModels[0];
|
|
988
|
+
if (base === void 0) return void 0;
|
|
989
|
+
return {
|
|
990
|
+
...base,
|
|
991
|
+
id: remote.id,
|
|
992
|
+
name: remote.name,
|
|
993
|
+
input: remote.input,
|
|
994
|
+
reasoning: remote.reasoning,
|
|
995
|
+
thinkingLevelMap: remote.thinkingLevelMap,
|
|
996
|
+
...remote.contextWindow === void 0 ? {} : { contextWindow: remote.contextWindow },
|
|
997
|
+
...base.id === remote.id ? {} : { cost: {
|
|
998
|
+
input: 0,
|
|
999
|
+
output: 0,
|
|
1000
|
+
cacheRead: 0,
|
|
1001
|
+
cacheWrite: 0
|
|
1002
|
+
} }
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function createOfficialModelCatalog(options = {}) {
|
|
1006
|
+
const fetchCatalog = options.fetch ?? fetch;
|
|
1007
|
+
let models;
|
|
1008
|
+
let metadata = /* @__PURE__ */ new Map();
|
|
1009
|
+
let etag;
|
|
1010
|
+
let revision = 0;
|
|
1011
|
+
let refreshing;
|
|
1012
|
+
const refresh = async ({ signal } = {}) => {
|
|
1013
|
+
if (refreshing !== void 0) return refreshing;
|
|
1014
|
+
refreshing = (async () => {
|
|
1015
|
+
const auth = await options.getAuth({ signal });
|
|
1016
|
+
const credential = await options.readCredential({ signal });
|
|
1017
|
+
const access = auth?.auth?.apiKey;
|
|
1018
|
+
const accountId = credential?.type === "oauth" ? credential.accountId : void 0;
|
|
1019
|
+
if (typeof access !== "string" || access.length === 0 || typeof accountId !== "string" || accountId.length === 0) return false;
|
|
1020
|
+
const headers = {
|
|
1021
|
+
authorization: `Bearer ${access}`,
|
|
1022
|
+
"chatgpt-account-id": accountId,
|
|
1023
|
+
accept: "application/json",
|
|
1024
|
+
originator: "pi",
|
|
1025
|
+
"user-agent": USER_AGENT,
|
|
1026
|
+
...etag === void 0 ? {} : { "if-none-match": etag }
|
|
1027
|
+
};
|
|
1028
|
+
const response = await fetchCatalog(CODEX_MODELS_URL, {
|
|
1029
|
+
method: "GET",
|
|
1030
|
+
redirect: "error",
|
|
1031
|
+
headers,
|
|
1032
|
+
signal
|
|
1033
|
+
});
|
|
1034
|
+
if (response.status === 304) return false;
|
|
1035
|
+
if (!response.ok) throw new Error(`Codex model catalog failed (HTTP ${response.status})`);
|
|
1036
|
+
const remote = parseOfficialModelCatalog(await response.json());
|
|
1037
|
+
if (remote.length === 0) throw new Error("Codex returned an empty model catalog");
|
|
1038
|
+
const baseModels = options.baseModels();
|
|
1039
|
+
const next = remote.map((model) => mergeModel(baseModels, model)).filter(Boolean);
|
|
1040
|
+
if (next.length === 0) throw new Error("Codex model catalog has no compatible models");
|
|
1041
|
+
models = next;
|
|
1042
|
+
metadata = new Map(remote.map((model) => [model.id, model]));
|
|
1043
|
+
etag = nonEmpty$2(response.headers.get("etag")) ?? etag;
|
|
1044
|
+
revision += 1;
|
|
1045
|
+
return true;
|
|
1046
|
+
})().finally(() => {
|
|
1047
|
+
refreshing = void 0;
|
|
1048
|
+
});
|
|
1049
|
+
return refreshing;
|
|
1050
|
+
};
|
|
1051
|
+
return Object.freeze({
|
|
1052
|
+
refresh,
|
|
1053
|
+
getModels: (fallback) => models ?? fallback,
|
|
1054
|
+
metadata: (modelId) => metadata.get(modelId),
|
|
1055
|
+
revision: () => revision,
|
|
1056
|
+
clear() {
|
|
1057
|
+
models = void 0;
|
|
1058
|
+
metadata = /* @__PURE__ */ new Map();
|
|
1059
|
+
etag = void 0;
|
|
1060
|
+
revision += 1;
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
//#endregion
|
|
908
1065
|
//#region src/codex-search.js
|
|
909
1066
|
const CODEX_SEARCH_PROVIDER_ID = "codex-subscription";
|
|
1067
|
+
const CODEX_AUTO_SEARCH_PROVIDER_ID = "codex-subscription-auto";
|
|
910
1068
|
const CODEX_SEARCH_URL = "https://chatgpt.com/backend-api/codex/alpha/search";
|
|
911
1069
|
const DEFAULT_MODEL = "gpt-5.6-luna";
|
|
912
1070
|
const MAX_OUTPUT_TOKENS = 4096;
|
|
@@ -1021,6 +1179,19 @@ function createCodexSearchProvider(options) {
|
|
|
1021
1179
|
}
|
|
1022
1180
|
});
|
|
1023
1181
|
}
|
|
1182
|
+
/** Route each request by its initiating model without changing the user's explicit overrides. */
|
|
1183
|
+
function createCodexAutoSearchProvider(options) {
|
|
1184
|
+
return Object.freeze({
|
|
1185
|
+
id: CODEX_AUTO_SEARCH_PROVIDER_ID,
|
|
1186
|
+
available: () => true,
|
|
1187
|
+
async search(request, signal) {
|
|
1188
|
+
if (options.resolveModelProvider?.() === "openai-codex") return options.codex.search(request, signal);
|
|
1189
|
+
const provider = options.resolveDshProvider?.();
|
|
1190
|
+
if (provider === void 0 || provider.id === "codex-subscription-auto" || provider.id === "codex-subscription" || provider.available() !== true) throw new WebError("DSH default search is unavailable", "WEB_PROVIDER_UNAVAILABLE");
|
|
1191
|
+
return provider.search(request, signal);
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1024
1195
|
//#endregion
|
|
1025
1196
|
//#region src/codex-images.js
|
|
1026
1197
|
const CODEX_IMAGE_TOOL_NAME = "codex_image_generate";
|
|
@@ -1029,6 +1200,17 @@ const CODEX_IMAGE_EDIT_URL = "https://chatgpt.com/backend-api/codex/images/edits
|
|
|
1029
1200
|
const IMAGE_MODEL = "gpt-image-2";
|
|
1030
1201
|
const MAX_REFERENCE_IMAGES = 5;
|
|
1031
1202
|
const RESPONSE_ENVELOPE_BYTES = 1024 * 1024;
|
|
1203
|
+
const IMAGE_QUALITIES = /* @__PURE__ */ new Set([
|
|
1204
|
+
"auto",
|
|
1205
|
+
"low",
|
|
1206
|
+
"medium",
|
|
1207
|
+
"high"
|
|
1208
|
+
]);
|
|
1209
|
+
const IMAGE_BACKGROUNDS = /* @__PURE__ */ new Set([
|
|
1210
|
+
"auto",
|
|
1211
|
+
"transparent",
|
|
1212
|
+
"opaque"
|
|
1213
|
+
]);
|
|
1032
1214
|
const PNG_SIGNATURE = Buffer.from([
|
|
1033
1215
|
137,
|
|
1034
1216
|
80,
|
|
@@ -1041,6 +1223,27 @@ const PNG_SIGNATURE = Buffer.from([
|
|
|
1041
1223
|
]);
|
|
1042
1224
|
const record$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1043
1225
|
const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1226
|
+
function normalizeImageOptions(args) {
|
|
1227
|
+
const quality = nonEmpty(args?.quality) ?? "auto";
|
|
1228
|
+
const background = nonEmpty(args?.background) ?? "auto";
|
|
1229
|
+
const size = nonEmpty(args?.size) ?? "auto";
|
|
1230
|
+
if (!IMAGE_QUALITIES.has(quality)) throw new Error("quality must be auto, low, medium, or high");
|
|
1231
|
+
if (!IMAGE_BACKGROUNDS.has(background)) throw new Error("background must be auto, transparent, or opaque");
|
|
1232
|
+
if (size !== "auto") {
|
|
1233
|
+
const match = /^(\d+)x(\d+)$/u.exec(size);
|
|
1234
|
+
const width = Number(match?.[1]);
|
|
1235
|
+
const height = Number(match?.[2]);
|
|
1236
|
+
const short = Math.min(width, height);
|
|
1237
|
+
const long = Math.max(width, height);
|
|
1238
|
+
const pixels = width * height;
|
|
1239
|
+
if (match === null || width % 16 !== 0 || height % 16 !== 0 || long > 3840 || long > short * 3 || pixels < 655360 || pixels > 8294400) throw new Error("size must be auto or a valid GPT Image 2 widthxheight resolution");
|
|
1240
|
+
}
|
|
1241
|
+
return {
|
|
1242
|
+
quality,
|
|
1243
|
+
background,
|
|
1244
|
+
size
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1044
1247
|
function encodedLimit(decodedBytes) {
|
|
1045
1248
|
return Math.ceil(decodedBytes / 3) * 4;
|
|
1046
1249
|
}
|
|
@@ -1187,6 +1390,29 @@ function createCodexImageTool(options) {
|
|
|
1187
1390
|
required: true,
|
|
1188
1391
|
description: "A complete, production-ready description of the image to generate."
|
|
1189
1392
|
},
|
|
1393
|
+
size: {
|
|
1394
|
+
type: "string",
|
|
1395
|
+
description: "Optional GPT Image 2 output size. Use auto unless the user requests an exact valid widthxheight resolution."
|
|
1396
|
+
},
|
|
1397
|
+
quality: {
|
|
1398
|
+
type: "string",
|
|
1399
|
+
enum: [
|
|
1400
|
+
"auto",
|
|
1401
|
+
"low",
|
|
1402
|
+
"medium",
|
|
1403
|
+
"high"
|
|
1404
|
+
],
|
|
1405
|
+
description: "Optional rendering quality. Use auto unless the user requests draft speed or final quality."
|
|
1406
|
+
},
|
|
1407
|
+
background: {
|
|
1408
|
+
type: "string",
|
|
1409
|
+
enum: [
|
|
1410
|
+
"auto",
|
|
1411
|
+
"transparent",
|
|
1412
|
+
"opaque"
|
|
1413
|
+
],
|
|
1414
|
+
description: "Optional background mode. Request transparent only when the user needs transparency."
|
|
1415
|
+
},
|
|
1190
1416
|
referenceImages: {
|
|
1191
1417
|
type: "array",
|
|
1192
1418
|
description: "Optional explicit references to 1-5 prior images to edit. Omit for a new image.",
|
|
@@ -1228,6 +1454,7 @@ function createCodexImageTool(options) {
|
|
|
1228
1454
|
async execute(args, exec) {
|
|
1229
1455
|
const prompt = nonEmpty(args.prompt);
|
|
1230
1456
|
if (prompt === void 0) throw new Error("prompt must be a non-empty string");
|
|
1457
|
+
const imageOptions = normalizeImageOptions(args);
|
|
1231
1458
|
const auth = await options.getAuth({ signal: exec.signal });
|
|
1232
1459
|
const credential = await options.readCredential({ signal: exec.signal });
|
|
1233
1460
|
const access = auth?.auth?.apiKey;
|
|
@@ -1254,10 +1481,10 @@ function createCodexImageTool(options) {
|
|
|
1254
1481
|
body: JSON.stringify({
|
|
1255
1482
|
...images === void 0 ? {} : { images },
|
|
1256
1483
|
prompt,
|
|
1257
|
-
background:
|
|
1484
|
+
background: imageOptions.background,
|
|
1258
1485
|
model: IMAGE_MODEL,
|
|
1259
|
-
quality:
|
|
1260
|
-
size:
|
|
1486
|
+
quality: imageOptions.quality,
|
|
1487
|
+
size: imageOptions.size
|
|
1261
1488
|
}),
|
|
1262
1489
|
signal: exec.signal
|
|
1263
1490
|
});
|
|
@@ -1367,6 +1594,7 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
|
|
|
1367
1594
|
configuration: {
|
|
1368
1595
|
contextMode: preference.contextMode,
|
|
1369
1596
|
quickQuotaMode: preference.quickQuotaMode,
|
|
1597
|
+
...typeof preference.outputVerbosity === "string" ? { outputVerbosity: preference.outputVerbosity } : {},
|
|
1370
1598
|
searchProvider: preference.searchProvider,
|
|
1371
1599
|
speedMode: preference.speedMode,
|
|
1372
1600
|
writable: preference.writable === true
|
|
@@ -1783,7 +2011,7 @@ const publicError = (code, message) => ({
|
|
|
1783
2011
|
details: { issues: [] }
|
|
1784
2012
|
}
|
|
1785
2013
|
});
|
|
1786
|
-
function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, diagnosticsReader }) {
|
|
2014
|
+
function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, diagnosticsReader, modelCatalog }) {
|
|
1787
2015
|
return async (endpoint, payload, signal) => {
|
|
1788
2016
|
if (endpoint === "diagnostics") try {
|
|
1789
2017
|
signal.throwIfAborted();
|
|
@@ -1808,13 +2036,26 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
1808
2036
|
patch[QUICK_QUOTA_MODE_FIELD] = payload[QUICK_QUOTA_MODE_FIELD];
|
|
1809
2037
|
}
|
|
1810
2038
|
if (Object.hasOwn(payload ?? {}, "searchProvider")) {
|
|
1811
|
-
if (![
|
|
2039
|
+
if (![
|
|
2040
|
+
"auto",
|
|
2041
|
+
"dsh",
|
|
2042
|
+
"codex"
|
|
2043
|
+
].includes(payload["searchProvider"])) return publicError("internal", "Invalid search provider preference");
|
|
1812
2044
|
patch[SEARCH_PROVIDER_FIELD] = payload[SEARCH_PROVIDER_FIELD];
|
|
1813
2045
|
}
|
|
1814
2046
|
if (Object.hasOwn(payload ?? {}, "speedMode")) {
|
|
1815
2047
|
if (!["standard", "fast"].includes(payload["speedMode"])) return publicError("internal", "Invalid speed mode preference");
|
|
1816
2048
|
patch[SPEED_MODE_FIELD] = payload[SPEED_MODE_FIELD];
|
|
1817
2049
|
}
|
|
2050
|
+
if (Object.hasOwn(payload ?? {}, "outputVerbosity")) {
|
|
2051
|
+
if (![
|
|
2052
|
+
"default",
|
|
2053
|
+
"low",
|
|
2054
|
+
"medium",
|
|
2055
|
+
"high"
|
|
2056
|
+
].includes(payload["outputVerbosity"])) return publicError("internal", "Invalid output verbosity preference");
|
|
2057
|
+
patch[OUTPUT_VERBOSITY_FIELD] = payload[OUTPUT_VERBOSITY_FIELD];
|
|
2058
|
+
}
|
|
1818
2059
|
if (Object.hasOwn(payload ?? {}, "contextMode")) {
|
|
1819
2060
|
if (![
|
|
1820
2061
|
"standard",
|
|
@@ -1890,26 +2131,34 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
1890
2131
|
if (endpoint === "logout" && result.ok === true) {
|
|
1891
2132
|
usageReader.clear();
|
|
1892
2133
|
resetCreditService.clear();
|
|
1893
|
-
|
|
2134
|
+
modelCatalog?.clear();
|
|
2135
|
+
} else if (result.ok === true && (endpoint === "status" || result.value?.authenticated === true)) modelCatalog?.refresh({ signal: void 0 }).catch(() => {});
|
|
1894
2136
|
return result;
|
|
1895
2137
|
};
|
|
1896
2138
|
}
|
|
1897
2139
|
function createSearchProviderSwitcher(loader) {
|
|
1898
2140
|
const webEntry = () => [...loader.entries()].find((entry) => entry.options?.id === WEB_ENTRY_ID);
|
|
1899
|
-
|
|
1900
|
-
const
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
2141
|
+
const dshProviderId = () => {
|
|
2142
|
+
const baseConfig = webEntry()?.options?.config ?? {};
|
|
2143
|
+
return typeof baseConfig.searchProvider === "string" && baseConfig.searchProvider.length > 0 ? baseConfig.searchProvider : DSH_SEARCH_PROVIDER_FALLBACK;
|
|
2144
|
+
};
|
|
2145
|
+
return Object.freeze({
|
|
2146
|
+
dshProviderId,
|
|
2147
|
+
async select(selection) {
|
|
2148
|
+
const entry = webEntry();
|
|
2149
|
+
const fiber = entry?.fiber;
|
|
2150
|
+
if (entry === void 0 || fiber === void 0 || typeof fiber.update !== "function") throw new Error("DSH web runtime is unavailable");
|
|
2151
|
+
const baseConfig = entry.options?.config ?? {};
|
|
2152
|
+
const currentConfig = fiber.config ?? baseConfig;
|
|
2153
|
+
const dshProvider = dshProviderId();
|
|
2154
|
+
const provider = selection === "codex" ? CODEX_SEARCH_PROVIDER_ID : selection === "auto" ? CODEX_AUTO_SEARCH_PROVIDER_ID : dshProvider;
|
|
2155
|
+
if (currentConfig.searchProvider === provider) return;
|
|
2156
|
+
await fiber.update({
|
|
2157
|
+
...currentConfig,
|
|
2158
|
+
searchProvider: provider
|
|
2159
|
+
}, true);
|
|
2160
|
+
}
|
|
2161
|
+
});
|
|
1913
2162
|
}
|
|
1914
2163
|
function apply(ctx) {
|
|
1915
2164
|
const settings = ctx.settings.register(settingsNamespace(SETTINGS_NAMESPACE), z.object({
|
|
@@ -1919,8 +2168,18 @@ function apply(ctx) {
|
|
|
1919
2168
|
"bar"
|
|
1920
2169
|
]),
|
|
1921
2170
|
[LEGACY_QUICK_QUOTA_FIELD]: z.boolean(),
|
|
1922
|
-
[SEARCH_PROVIDER_FIELD]: z.union([
|
|
2171
|
+
[SEARCH_PROVIDER_FIELD]: z.union([
|
|
2172
|
+
SEARCH_PROVIDER_AUTO,
|
|
2173
|
+
"dsh",
|
|
2174
|
+
SEARCH_PROVIDER_CODEX
|
|
2175
|
+
]).default(DEFAULT_SEARCH_PROVIDER),
|
|
1923
2176
|
[SPEED_MODE_FIELD]: z.union([SPEED_MODE_STANDARD, SPEED_MODE_FAST]).default(DEFAULT_SPEED_MODE),
|
|
2177
|
+
[OUTPUT_VERBOSITY_FIELD]: z.union([
|
|
2178
|
+
OUTPUT_VERBOSITY_DEFAULT,
|
|
2179
|
+
"low",
|
|
2180
|
+
OUTPUT_VERBOSITY_MEDIUM,
|
|
2181
|
+
OUTPUT_VERBOSITY_HIGH
|
|
2182
|
+
]).default(DEFAULT_OUTPUT_VERBOSITY),
|
|
1924
2183
|
[CONTEXT_MODE_FIELD]: z.union([
|
|
1925
2184
|
CONTEXT_MODE_STANDARD,
|
|
1926
2185
|
CONTEXT_MODE_EXTENDED,
|
|
@@ -1931,13 +2190,24 @@ function apply(ctx) {
|
|
|
1931
2190
|
}));
|
|
1932
2191
|
const searchProvider = createSearchProviderSwitcher(ctx.loader);
|
|
1933
2192
|
const network = createCodexNetworkTransport();
|
|
2193
|
+
const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF]);
|
|
2194
|
+
const baseProvider = createOpenAICodexProvider();
|
|
2195
|
+
let resolveAuth = async () => void 0;
|
|
2196
|
+
const modelCatalog = createOfficialModelCatalog({
|
|
2197
|
+
getAuth: (options) => resolveAuth(options),
|
|
2198
|
+
readCredential: (options) => store.read(PROVIDER, options),
|
|
2199
|
+
baseModels: () => baseProvider.getModels(),
|
|
2200
|
+
fetch: (input, init) => network.fetch("catalog", input, init)
|
|
2201
|
+
});
|
|
1934
2202
|
const provider = openaiCodexSubscriptionProvider({
|
|
1935
2203
|
resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD],
|
|
2204
|
+
resolveOutputVerbosity: () => normalizeOutputVerbosity(settings.get()[OUTPUT_VERBOSITY_FIELD]),
|
|
1936
2205
|
resolveContextMode: () => normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
|
|
1937
2206
|
resolveCustomContextWindow: (modelKey) => {
|
|
1938
2207
|
const field = CUSTOM_CONTEXT_MODEL_FIELDS[modelKey];
|
|
1939
2208
|
return normalizeCustomContextWindow(settings.get()[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey]);
|
|
1940
2209
|
},
|
|
2210
|
+
catalog: modelCatalog,
|
|
1941
2211
|
runNetwork: network.run
|
|
1942
2212
|
});
|
|
1943
2213
|
const preferences = {
|
|
@@ -1945,15 +2215,16 @@ function apply(ctx) {
|
|
|
1945
2215
|
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(settings.get()[QUICK_QUOTA_MODE_FIELD], settings.get()[LEGACY_QUICK_QUOTA_FIELD]),
|
|
1946
2216
|
[SEARCH_PROVIDER_FIELD]: settings.get()[SEARCH_PROVIDER_FIELD],
|
|
1947
2217
|
[SPEED_MODE_FIELD]: settings.get()[SPEED_MODE_FIELD],
|
|
2218
|
+
[OUTPUT_VERBOSITY_FIELD]: normalizeOutputVerbosity(settings.get()[OUTPUT_VERBOSITY_FIELD]),
|
|
1948
2219
|
[CONTEXT_MODE_FIELD]: normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
|
|
1949
2220
|
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(settings.get()[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
1950
2221
|
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(settings.get()[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
1951
2222
|
contextModels: contextModelGroups(provider.getModels()),
|
|
2223
|
+
verbosityModels: provider.getModels().filter((model) => modelCatalog.metadata(model.id)?.supportVerbosity ?? model.id !== "gpt-5.3-codex-spark").map((model) => model.id),
|
|
1952
2224
|
writable: ctx.settings.writable
|
|
1953
2225
|
}),
|
|
1954
2226
|
update: (patch) => settings.update(patch)
|
|
1955
2227
|
};
|
|
1956
|
-
const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF]);
|
|
1957
2228
|
const authModels = createModels({ credentials: store });
|
|
1958
2229
|
authModels.setProvider(provider);
|
|
1959
2230
|
const profile = Object.freeze({
|
|
@@ -1971,14 +2242,18 @@ function apply(ctx) {
|
|
|
1971
2242
|
let profileKey;
|
|
1972
2243
|
let profileSnapshot;
|
|
1973
2244
|
const profiles = () => {
|
|
1974
|
-
const key = [
|
|
2245
|
+
const key = [
|
|
2246
|
+
modelCatalog.revision(),
|
|
2247
|
+
normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
|
|
2248
|
+
...Object.values(CUSTOM_CONTEXT_MODEL_FIELDS).map((field) => settings.get()[field])
|
|
2249
|
+
].join(":");
|
|
1975
2250
|
if (key !== profileKey) {
|
|
1976
2251
|
profileKey = key;
|
|
1977
2252
|
profileSnapshot = /* @__PURE__ */ new Map([[PROVIDER, profile]]);
|
|
1978
2253
|
}
|
|
1979
2254
|
return profileSnapshot;
|
|
1980
2255
|
};
|
|
1981
|
-
|
|
2256
|
+
resolveAuth = () => authModels.getAuth(PROVIDER);
|
|
1982
2257
|
const adapterAuth = Object.freeze({
|
|
1983
2258
|
credentials: store,
|
|
1984
2259
|
authContext: Object.freeze({
|
|
@@ -2009,7 +2284,7 @@ function apply(ctx) {
|
|
|
2009
2284
|
});
|
|
2010
2285
|
ctx.llm.registerAdapter([PROVIDER], adapter);
|
|
2011
2286
|
const currentAgent = () => ctx.get?.("agents")?.currentInitiator?.();
|
|
2012
|
-
|
|
2287
|
+
const codexSearch = createCodexSearchProvider({
|
|
2013
2288
|
getAuth: resolveAuth,
|
|
2014
2289
|
readCredential: (options) => store.read(PROVIDER, options),
|
|
2015
2290
|
resolveModel: () => {
|
|
@@ -2018,6 +2293,12 @@ function apply(ctx) {
|
|
|
2018
2293
|
},
|
|
2019
2294
|
resolveSessionId: () => currentAgent()?.session.id,
|
|
2020
2295
|
fetch: (input, init) => network.fetch("search", input, init)
|
|
2296
|
+
});
|
|
2297
|
+
ctx.web.registerSearchProvider(codexSearch);
|
|
2298
|
+
ctx.web.registerSearchProvider(createCodexAutoSearchProvider({
|
|
2299
|
+
codex: codexSearch,
|
|
2300
|
+
resolveModelProvider: () => currentAgent()?.session.requestContext?.()?.provider,
|
|
2301
|
+
resolveDshProvider: () => ctx.web.searchProviders?.get(searchProvider.dshProviderId())
|
|
2021
2302
|
}));
|
|
2022
2303
|
ctx.effect(() => {
|
|
2023
2304
|
const select = async (value) => {
|
|
@@ -2053,8 +2334,12 @@ function apply(ctx) {
|
|
|
2053
2334
|
preferences,
|
|
2054
2335
|
login: coordinator.supportState(),
|
|
2055
2336
|
network
|
|
2056
|
-
})
|
|
2337
|
+
}),
|
|
2338
|
+
modelCatalog
|
|
2057
2339
|
});
|
|
2340
|
+
ctx.effect(() => {
|
|
2341
|
+
modelCatalog.refresh().catch((error) => ctx.logger?.debug?.("could not refresh Codex model catalog: %s", error.message));
|
|
2342
|
+
}, "codex-subscription: official model catalog");
|
|
2058
2343
|
ctx.effect(() => ctx.connection.rpc.handle(CHANNEL, handler, { authority: "loopback" }), "codex-subscription: loopback account RPC");
|
|
2059
2344
|
}
|
|
2060
2345
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|