dsh-codex-subscription 1.14.1 → 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +7 -9
- package/README.md +7 -9
- package/lib/client.js +423 -116
- package/lib/index.js +118 -19
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -22,12 +22,6 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
|
|
|
22
22
|
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/readme-hero-en.webp" width="900" alt="Your Codex subscription inside DSH: models, web search, quota and safe reset, image generation, and Fast mode">
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
|
-
## What's included in 1.14.1
|
|
26
|
-
|
|
27
|
-
- The composer shows both 5-hour and weekly quota windows when returned by the service, so neither window is hidden.
|
|
28
|
-
- Image edits validate attachment references, normalize bare SHA-256 digests, and resolve the actual attachment metadata from the current session. Paths produce an actionable error asking the model to obtain the correct reference with `read_image` and retry.
|
|
29
|
-
- Location edits attach the clean source, a numbered annotation image, and coordinate instructions so the model can match each requested change to its location.
|
|
30
|
-
|
|
31
25
|
## Three-step start
|
|
32
26
|
|
|
33
27
|
1. **Install the plugin.** Run the standard DSH bundle command:
|
|
@@ -46,14 +40,14 @@ DSH-Portable exposes the same standard plugin command, so the command above also
|
|
|
46
40
|
| Capability | What you get |
|
|
47
41
|
| --- | --- |
|
|
48
42
|
| **Subscription models** | Sign in to ChatGPT and use Codex without an OpenAI API key or Codex CLI |
|
|
49
|
-
| **Recoverable and diagnosable** | Sign-in state reconciles automatically; Settings can create a support report without credentials or account identifiers |
|
|
43
|
+
| **Recoverable and diagnosable** | Sign-in state reconciles automatically; failed reads can be retried in place, while timeouts and stale account responses cannot overwrite current state; Settings can create a support report without credentials or account identifiers |
|
|
50
44
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
51
45
|
| **Composer quota** | Choose a compact percentage, progress bar, or no inline quota display |
|
|
52
46
|
| **Safe quota reset** | See each reset credit separately and deliberately try one with a cooldown and acknowledgement |
|
|
53
47
|
| **Subscription search** | Explicitly route search globally through DSH default search or the signed-in Codex subscription |
|
|
54
48
|
| **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit one selected image; preview, zoom, annotate regions, download the original, and get the original host path for new or edited images |
|
|
55
49
|
| **Fast mode** | Switch between Standard and Fast directly in the composer |
|
|
56
|
-
| **Model-aware context** | Keep catalog defaults, use each model's supported extended window, or enter a full numeric token limit for each model |
|
|
50
|
+
| **Model-aware context** | Keep catalog defaults, use each model's supported extended window, or enter a full numeric token limit for each model; Settings refreshes the model directory on open, account changes, and connection resets without overwriting an unsaved draft |
|
|
57
51
|
| **Headless runs** | Use the same signed-in Codex provider for one-shot DSH tasks that print their answer and exit |
|
|
58
52
|
|
|
59
53
|
These capabilities reuse the same local ChatGPT sign-in. Subscription routing failures stay visible and never silently switch to another paid route.
|
|
@@ -141,6 +135,10 @@ Restart DSH manually after installation, then:
|
|
|
141
135
|
|
|
142
136
|
The plugin can follow an existing HTTPS proxy from the process environment or operating-system proxy settings for official OpenAI and ChatGPT requests. It does not provide a proxy, relay, node list, or system-proxy configuration.
|
|
143
137
|
|
|
138
|
+
### GPT-6 Astra context
|
|
139
|
+
|
|
140
|
+
When the official model catalog exposes GPT-6 Astra, Standard preserves the catalog window, Extended uses 872000 tokens, and Custom accepts 128000–872000 tokens (initially 272000). This limit follows the [official Codex model catalog](https://github.com/openai/codex/blob/6af345407d9c2a568da9d01b6c4b81a9e61495c0/codex-rs/models-manager/models.json#L33-L34), not the API model's total context capacity. These settings only adjust DSH's local context budget; they do not grant model access or guarantee an account's server-side capacity. Actual availability remains subject to the service.
|
|
141
|
+
|
|
144
142
|
### Composer quota
|
|
145
143
|
|
|
146
144
|
<p align="center">
|
|
@@ -173,7 +171,7 @@ A new image request does not silently include earlier images. GPT Image 2 can ta
|
|
|
173
171
|
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations-en.png" width="800" alt="Generated image, region note, and continue editing inside the DSH Image Viewer">
|
|
174
172
|
</p>
|
|
175
173
|
|
|
176
|
-
The screenshot above illustrates image viewing and on-image notes
|
|
174
|
+
The screenshot above illustrates image viewing and on-image notes; available buttons can vary with the image and installed viewer version.
|
|
177
175
|
|
|
178
176
|
### Composer speed
|
|
179
177
|
|
package/README.md
CHANGED
|
@@ -23,12 +23,6 @@
|
|
|
23
23
|
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/readme-hero.webp" width="900" alt="Codex 订阅直接用在 DSH:订阅模型、联网搜索、额度与安全重置、图片生成和高速模式">
|
|
24
24
|
</p>
|
|
25
25
|
|
|
26
|
-
## 1.14.1 重点变化
|
|
27
|
-
|
|
28
|
-
- 输入框同时显示服务端返回的 5 小时与每周额度,避免其中一个额度窗口被隐藏。
|
|
29
|
-
- 图片编辑会检查附件引用,自动补全裸 SHA-256,并从当前会话取回真实附件元数据;误填路径时提示模型通过 `read_image` 获取正确引用并重试。
|
|
30
|
-
- 部位修改会同时附上干净原图、编号标注图和坐标说明,让模型能够对应每条修改要求。
|
|
31
|
-
|
|
32
26
|
## 三步开始
|
|
33
27
|
|
|
34
28
|
1. **安装插件**:直接运行 DSH 标准 bundle 命令:
|
|
@@ -47,14 +41,14 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
47
41
|
| 能力 | 用户得到什么 |
|
|
48
42
|
| --- | --- |
|
|
49
43
|
| **订阅模型直连** | 登录 ChatGPT 后直接使用 Codex,不需要 OpenAI API Key 或 Codex CLI |
|
|
50
|
-
| **可恢复、可诊断** |
|
|
44
|
+
| **可恢复、可诊断** | 登录状态会自动对账;读取失败时可在原处重试,超时和旧账号响应不会覆盖当前状态;设置页可生成不含凭据和账号标识的支持报告 |
|
|
51
45
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
52
46
|
| **输入框额度** | 可选择紧凑百分比、进度条或完全关闭输入框额度显示 |
|
|
53
47
|
| **安全额度重置** | 每张重置卡单独显示,并通过冷静期和知情确认主动尝试重置 |
|
|
54
48
|
| **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
|
|
55
49
|
| **Codex 图片生成与编辑(Beta)** | 可无参考图全新生成,也可明确选择会话图片继续编辑;支持预览、缩放、区域备注、下载原图,并为新生成或编辑的图片提供 DSH 主机上的原图路径 |
|
|
56
50
|
| **高速模式** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
57
|
-
| **模型感知上下文** | 可保留目录默认值、按模型启用扩展窗口,或为每个模型填写完整数字 Token
|
|
51
|
+
| **模型感知上下文** | 可保留目录默认值、按模型启用扩展窗口,或为每个模型填写完整数字 Token 上限;设置页打开、账号切换和连接重置后会刷新模型目录,失败时可重试且不会覆盖未保存的草稿 |
|
|
58
52
|
| **Headless 任务** | 使用同一份已登录的 Codex Provider 运行一次性 DSH 任务,输出答案后自动退出 |
|
|
59
53
|
|
|
60
54
|
这些能力共用同一份本机 ChatGPT 登录。订阅路由失败时会明确报错,不会静默切换到其他付费路由。
|
|
@@ -142,6 +136,10 @@ dsh --profile web --dump-config
|
|
|
142
136
|
|
|
143
137
|
对于 OpenAI 与 ChatGPT 官方请求,插件可以沿用进程环境或操作系统中已有的 HTTPS 代理。插件本身不提供代理、转发服务、节点列表,也不会修改系统代理设置。
|
|
144
138
|
|
|
139
|
+
### GPT-6 Astra 上下文
|
|
140
|
+
|
|
141
|
+
当官方模型目录提供 GPT-6 Astra 时,标准模式保留目录默认窗口;扩展模式使用 872000 Token,自定义模式可设置 128000–872000 Token(初始值为 272000)。该上限依据 [Codex 官方模型目录](https://github.com/openai/codex/blob/6af345407d9c2a568da9d01b6c4b81a9e61495c0/codex-rs/models-manager/models.json#L33-L34),不是 API 模型的总上下文容量。这些设置只调整 DSH 的本地上下文预算,不授予模型访问权限,也不保证账号的服务端容量;实际可用性以服务端为准。
|
|
142
|
+
|
|
145
143
|
### 输入框额度
|
|
146
144
|
|
|
147
145
|
<p align="center">
|
|
@@ -171,7 +169,7 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
|
|
|
171
169
|
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/image-preview-annotations.png" width="800" alt="DSH 图片查看器中的生成图、区域备注和继续编辑">
|
|
172
170
|
</p>
|
|
173
171
|
|
|
174
|
-
|
|
172
|
+
上图展示图片查看与图上备注的基本交互;具体按钮会随图片和所安装的查看器版本变化。
|
|
175
173
|
|
|
176
174
|
### 输入框速度
|
|
177
175
|
|
package/lib/client.js
CHANGED
|
@@ -987,19 +987,22 @@ window.__ModuleLoader__.load({
|
|
|
987
987
|
"gpt-5.4": "customContextGpt54",
|
|
988
988
|
"gpt-5.4-mini": "customContextGpt54Mini",
|
|
989
989
|
"gpt-5.5": "customContextGpt55",
|
|
990
|
-
"gpt-5.6": "customContextGpt56"
|
|
990
|
+
"gpt-5.6": "customContextGpt56",
|
|
991
|
+
"gpt-6-astra": "customContextGpt6Astra"
|
|
991
992
|
});
|
|
992
993
|
const CUSTOM_CONTEXT_MODEL_CAPS = Object.freeze({
|
|
993
994
|
"gpt-5.4": 1e6,
|
|
994
995
|
"gpt-5.4-mini": 4e5,
|
|
995
996
|
"gpt-5.5": 1e6,
|
|
996
|
-
"gpt-5.6": 1e6
|
|
997
|
+
"gpt-5.6": 1e6,
|
|
998
|
+
"gpt-6-astra": 872e3
|
|
997
999
|
});
|
|
998
1000
|
const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
|
|
999
1001
|
"gpt-5.4": 272e3,
|
|
1000
1002
|
"gpt-5.4-mini": 272e3,
|
|
1001
1003
|
"gpt-5.5": 272e3,
|
|
1002
|
-
"gpt-5.6": 272e3
|
|
1004
|
+
"gpt-5.6": 272e3,
|
|
1005
|
+
"gpt-6-astra": 272e3
|
|
1003
1006
|
});
|
|
1004
1007
|
const normalizeSearchProvider = (value) => [
|
|
1005
1008
|
"auto",
|
|
@@ -1094,7 +1097,7 @@ window.__ModuleLoader__.load({
|
|
|
1094
1097
|
}
|
|
1095
1098
|
//#endregion
|
|
1096
1099
|
//#region src/preference-controller.js
|
|
1097
|
-
const CHANNEL$
|
|
1100
|
+
const CHANNEL$2 = "/codex-subscription";
|
|
1098
1101
|
const unwrap$1 = (response) => {
|
|
1099
1102
|
if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
|
|
1100
1103
|
return response.value;
|
|
@@ -1109,6 +1112,11 @@ window.__ModuleLoader__.load({
|
|
|
1109
1112
|
let generation = 0;
|
|
1110
1113
|
let contextModels = [];
|
|
1111
1114
|
let verbosityModels = [];
|
|
1115
|
+
let modelError = false;
|
|
1116
|
+
let modelRefreshGeneration = 0;
|
|
1117
|
+
let modelRefreshStarted = false;
|
|
1118
|
+
let disposed = false;
|
|
1119
|
+
const sameModels = (left, right) => left.length === right.length && left.every((model, index) => JSON.stringify(model) === JSON.stringify(right[index]));
|
|
1112
1120
|
const nativeSnapshot = () => scope.getSnapshot();
|
|
1113
1121
|
const read = () => {
|
|
1114
1122
|
const native = nativeSnapshot();
|
|
@@ -1128,6 +1136,7 @@ window.__ModuleLoader__.load({
|
|
|
1128
1136
|
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
1129
1137
|
contextModels,
|
|
1130
1138
|
verbosityModels,
|
|
1139
|
+
modelError,
|
|
1131
1140
|
writable: !updating && current.status === "ready" && current.writable === true,
|
|
1132
1141
|
saving: updating,
|
|
1133
1142
|
error
|
|
@@ -1145,8 +1154,10 @@ window.__ModuleLoader__.load({
|
|
|
1145
1154
|
publish();
|
|
1146
1155
|
});
|
|
1147
1156
|
const acceptFallback = (value) => {
|
|
1148
|
-
|
|
1149
|
-
|
|
1157
|
+
if (!modelRefreshStarted) {
|
|
1158
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1159
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1160
|
+
}
|
|
1150
1161
|
fallbackStatus = "ready";
|
|
1151
1162
|
fallback = {
|
|
1152
1163
|
status: "ready",
|
|
@@ -1171,21 +1182,50 @@ window.__ModuleLoader__.load({
|
|
|
1171
1182
|
error = false;
|
|
1172
1183
|
publish();
|
|
1173
1184
|
try {
|
|
1174
|
-
const value = unwrap$1(await rpc.call(CHANNEL$
|
|
1175
|
-
if (current !== generation) return;
|
|
1185
|
+
const value = unwrap$1(await rpc.call(CHANNEL$2, "preferences/status", {}));
|
|
1186
|
+
if (current !== generation || disposed) return;
|
|
1176
1187
|
if (nativeSnapshot().status === "ready") {
|
|
1177
|
-
|
|
1178
|
-
|
|
1188
|
+
if (!modelRefreshStarted) {
|
|
1189
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1190
|
+
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1191
|
+
}
|
|
1179
1192
|
} else acceptFallback(value);
|
|
1180
1193
|
publish();
|
|
1181
1194
|
} catch {
|
|
1182
|
-
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
1195
|
+
if (current !== generation || disposed || nativeSnapshot().status === "ready") return;
|
|
1183
1196
|
fallbackStatus = "unavailable";
|
|
1184
1197
|
publish();
|
|
1185
1198
|
}
|
|
1186
1199
|
};
|
|
1200
|
+
const refreshModels = async () => {
|
|
1201
|
+
const current = ++modelRefreshGeneration;
|
|
1202
|
+
modelRefreshStarted = true;
|
|
1203
|
+
const hadError = modelError;
|
|
1204
|
+
modelError = false;
|
|
1205
|
+
if (hadError) publish();
|
|
1206
|
+
try {
|
|
1207
|
+
const value = unwrap$1(await rpc.call(CHANNEL$2, "preferences/models", {}));
|
|
1208
|
+
if (disposed || current !== modelRefreshGeneration) return false;
|
|
1209
|
+
const nextContextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
1210
|
+
const nextVerbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
1211
|
+
const changed = !sameModels(contextModels, nextContextModels) || !sameModels(verbosityModels, nextVerbosityModels);
|
|
1212
|
+
if (changed) {
|
|
1213
|
+
contextModels = nextContextModels;
|
|
1214
|
+
verbosityModels = nextVerbosityModels;
|
|
1215
|
+
publish();
|
|
1216
|
+
}
|
|
1217
|
+
return changed;
|
|
1218
|
+
} catch {
|
|
1219
|
+
if (disposed || current !== modelRefreshGeneration) return false;
|
|
1220
|
+
if (!modelError) {
|
|
1221
|
+
modelError = true;
|
|
1222
|
+
publish();
|
|
1223
|
+
}
|
|
1224
|
+
return false;
|
|
1225
|
+
}
|
|
1226
|
+
};
|
|
1187
1227
|
const set = async (patch) => {
|
|
1188
|
-
if (snapshot.status !== "ready" || snapshot.writable !== true) return;
|
|
1228
|
+
if (disposed || snapshot.status !== "ready" || snapshot.writable !== true) return;
|
|
1189
1229
|
const current = ++generation;
|
|
1190
1230
|
const entries = Object.entries(patch);
|
|
1191
1231
|
updating = true;
|
|
@@ -1204,7 +1244,7 @@ window.__ModuleLoader__.load({
|
|
|
1204
1244
|
error = entries.some(([field, value]) => accepted?.[field] !== value);
|
|
1205
1245
|
pendingPatch = void 0;
|
|
1206
1246
|
} else {
|
|
1207
|
-
const value = unwrap$1(await rpc.call(CHANNEL$
|
|
1247
|
+
const value = unwrap$1(await rpc.call(CHANNEL$2, "preferences/update", patch));
|
|
1208
1248
|
if (current !== generation) return;
|
|
1209
1249
|
acceptFallback(value);
|
|
1210
1250
|
pendingPatch = void 0;
|
|
@@ -1231,10 +1271,219 @@ window.__ModuleLoader__.load({
|
|
|
1231
1271
|
load,
|
|
1232
1272
|
set,
|
|
1233
1273
|
retry: () => failedPatch === void 0 ? load() : set(failedPatch),
|
|
1234
|
-
|
|
1274
|
+
refreshModels,
|
|
1275
|
+
dispose: () => {
|
|
1276
|
+
disposed = true;
|
|
1277
|
+
generation += 1;
|
|
1278
|
+
modelRefreshGeneration += 1;
|
|
1279
|
+
disposeScope();
|
|
1280
|
+
}
|
|
1235
1281
|
};
|
|
1236
1282
|
}
|
|
1237
1283
|
//#endregion
|
|
1284
|
+
//#region src/account-status-controller.js
|
|
1285
|
+
const CHANNEL$1 = "/codex-subscription";
|
|
1286
|
+
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
1287
|
+
const STATUS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
1288
|
+
"credential-unavailable",
|
|
1289
|
+
"credential-malformed",
|
|
1290
|
+
"transport",
|
|
1291
|
+
"timeout",
|
|
1292
|
+
"unknown"
|
|
1293
|
+
]);
|
|
1294
|
+
const STATUS_ERROR_MESSAGES = /* @__PURE__ */ new Map([
|
|
1295
|
+
["Codex account credentials are unavailable", "credential-unavailable"],
|
|
1296
|
+
["Codex account credentials are malformed", "credential-malformed"],
|
|
1297
|
+
["Codex account status service is unavailable", "transport"],
|
|
1298
|
+
["Could not read Codex account status", "unknown"]
|
|
1299
|
+
]);
|
|
1300
|
+
const TIMEOUT_CODES = /* @__PURE__ */ new Set([
|
|
1301
|
+
"TIMEOUT",
|
|
1302
|
+
"ETIMEDOUT",
|
|
1303
|
+
"ERR_TIMEOUT",
|
|
1304
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
1305
|
+
]);
|
|
1306
|
+
const TRANSPORT_CODES = /* @__PURE__ */ new Set([
|
|
1307
|
+
"ECONNRESET",
|
|
1308
|
+
"ECONNREFUSED",
|
|
1309
|
+
"ENOTFOUND",
|
|
1310
|
+
"EAI_AGAIN",
|
|
1311
|
+
"NETWORK",
|
|
1312
|
+
"NETWORK_ERROR",
|
|
1313
|
+
"TRANSPORT",
|
|
1314
|
+
"CONNECTION_CLOSED",
|
|
1315
|
+
"DISCONNECTED"
|
|
1316
|
+
]);
|
|
1317
|
+
const asCode = (value) => typeof value === "string" ? value.trim().toLowerCase() : void 0;
|
|
1318
|
+
function rpcError(response) {
|
|
1319
|
+
const code = asCode(response?.error?.code);
|
|
1320
|
+
const message = typeof response?.error?.message === "string" ? response.error.message : "";
|
|
1321
|
+
const error = /* @__PURE__ */ new Error("Codex account status request failed");
|
|
1322
|
+
error.code = code === "internal" && STATUS_ERROR_MESSAGES.has(message) ? STATUS_ERROR_MESSAGES.get(message) : "unknown";
|
|
1323
|
+
return error;
|
|
1324
|
+
}
|
|
1325
|
+
function timeoutError() {
|
|
1326
|
+
const error = /* @__PURE__ */ new Error("Codex account status request timed out");
|
|
1327
|
+
error.code = "timeout";
|
|
1328
|
+
error.name = "TimeoutError";
|
|
1329
|
+
return error;
|
|
1330
|
+
}
|
|
1331
|
+
function classifyAccountStatusError(error) {
|
|
1332
|
+
const code = typeof error?.code === "string" ? error.code.trim().toUpperCase() : "";
|
|
1333
|
+
if (code === "TIMEOUT" || TIMEOUT_CODES.has(code) || error?.name === "TimeoutError") return "timeout";
|
|
1334
|
+
if (STATUS_ERROR_CODES.has(asCode(error?.code))) return asCode(error.code);
|
|
1335
|
+
if (TRANSPORT_CODES.has(code) || error?.name === "NetworkError") return "transport";
|
|
1336
|
+
return "unknown";
|
|
1337
|
+
}
|
|
1338
|
+
function publicAccountStatusError(error) {
|
|
1339
|
+
return Object.freeze({ code: classifyAccountStatusError(error) });
|
|
1340
|
+
}
|
|
1341
|
+
/** Own the account-status request lifecycle independently from account actions. */
|
|
1342
|
+
function createAccountStatusController(rpc, options = {}) {
|
|
1343
|
+
const request = options.request ?? (() => rpc.call(CHANNEL$1, "status", {}));
|
|
1344
|
+
const scheduleTimeout = options.setTimeout ?? setTimeout;
|
|
1345
|
+
const cancelTimeout = options.clearTimeout ?? clearTimeout;
|
|
1346
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1347
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) throw new Error("Account status timeout must be positive");
|
|
1348
|
+
let snapshot = Object.freeze({
|
|
1349
|
+
status: "loading",
|
|
1350
|
+
account: void 0,
|
|
1351
|
+
error: void 0,
|
|
1352
|
+
retrying: false
|
|
1353
|
+
});
|
|
1354
|
+
let generation = 0;
|
|
1355
|
+
let active;
|
|
1356
|
+
let disposed = false;
|
|
1357
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1358
|
+
const publish = (next) => {
|
|
1359
|
+
snapshot = Object.freeze(next);
|
|
1360
|
+
for (const listener of [...listeners]) listener();
|
|
1361
|
+
};
|
|
1362
|
+
const load = () => {
|
|
1363
|
+
if (disposed) return Promise.resolve(void 0);
|
|
1364
|
+
if (active !== void 0) return active.promise;
|
|
1365
|
+
const id = ++generation;
|
|
1366
|
+
const retrying = snapshot.error !== void 0;
|
|
1367
|
+
publish({
|
|
1368
|
+
status: retrying ? "error" : "loading",
|
|
1369
|
+
account: retrying ? snapshot.account : void 0,
|
|
1370
|
+
error: retrying ? snapshot.error : void 0,
|
|
1371
|
+
retrying: true
|
|
1372
|
+
});
|
|
1373
|
+
const controller = new AbortController();
|
|
1374
|
+
let timer;
|
|
1375
|
+
let onAbort;
|
|
1376
|
+
const cancelled = new Promise((resolve, reject) => {
|
|
1377
|
+
onAbort = () => reject(controller.signal.reason);
|
|
1378
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
1379
|
+
if (controller.signal.aborted) onAbort();
|
|
1380
|
+
});
|
|
1381
|
+
const timeout = new Promise((resolve, reject) => {
|
|
1382
|
+
timer = scheduleTimeout(() => {
|
|
1383
|
+
const error = timeoutError();
|
|
1384
|
+
controller.abort(error);
|
|
1385
|
+
reject(error);
|
|
1386
|
+
}, timeoutMs);
|
|
1387
|
+
});
|
|
1388
|
+
const work = Promise.resolve().then(() => request(controller.signal)).then((response) => {
|
|
1389
|
+
if (!response?.ok) throw rpcError(response);
|
|
1390
|
+
return response.value;
|
|
1391
|
+
});
|
|
1392
|
+
const promise = Promise.race([
|
|
1393
|
+
work,
|
|
1394
|
+
timeout,
|
|
1395
|
+
cancelled
|
|
1396
|
+
]).then((account) => {
|
|
1397
|
+
if (disposed || id !== generation || controller.signal.aborted) return void 0;
|
|
1398
|
+
if (account === null || typeof account !== "object" || Array.isArray(account) || typeof account.authenticated !== "boolean") throw new Error("Invalid account status");
|
|
1399
|
+
publish({
|
|
1400
|
+
status: "ready",
|
|
1401
|
+
account,
|
|
1402
|
+
error: void 0,
|
|
1403
|
+
retrying: false
|
|
1404
|
+
});
|
|
1405
|
+
return account;
|
|
1406
|
+
}).catch((error) => {
|
|
1407
|
+
if (disposed || id !== generation || controller.signal.aborted && error?.code !== "timeout") return void 0;
|
|
1408
|
+
publish({
|
|
1409
|
+
status: "error",
|
|
1410
|
+
account: void 0,
|
|
1411
|
+
error: publicAccountStatusError(error),
|
|
1412
|
+
retrying: false
|
|
1413
|
+
});
|
|
1414
|
+
}).finally(() => {
|
|
1415
|
+
cancelTimeout(timer);
|
|
1416
|
+
controller.signal.removeEventListener("abort", onAbort);
|
|
1417
|
+
if (active?.id === id) active = void 0;
|
|
1418
|
+
});
|
|
1419
|
+
active = {
|
|
1420
|
+
id,
|
|
1421
|
+
controller,
|
|
1422
|
+
promise
|
|
1423
|
+
};
|
|
1424
|
+
return promise;
|
|
1425
|
+
};
|
|
1426
|
+
const acceptAccount = (account) => {
|
|
1427
|
+
if (disposed) return false;
|
|
1428
|
+
generation += 1;
|
|
1429
|
+
active?.controller.abort(/* @__PURE__ */ new Error("Account status superseded by an account action"));
|
|
1430
|
+
active = void 0;
|
|
1431
|
+
publish({
|
|
1432
|
+
status: "ready",
|
|
1433
|
+
account,
|
|
1434
|
+
error: void 0,
|
|
1435
|
+
retrying: false
|
|
1436
|
+
});
|
|
1437
|
+
return true;
|
|
1438
|
+
};
|
|
1439
|
+
const reload = () => {
|
|
1440
|
+
if (disposed) return Promise.resolve(void 0);
|
|
1441
|
+
if (active !== void 0) {
|
|
1442
|
+
generation += 1;
|
|
1443
|
+
active.controller.abort(/* @__PURE__ */ new Error("Account status reload superseded the previous request"));
|
|
1444
|
+
active = void 0;
|
|
1445
|
+
}
|
|
1446
|
+
return load();
|
|
1447
|
+
};
|
|
1448
|
+
const dispose = () => {
|
|
1449
|
+
if (disposed) return;
|
|
1450
|
+
disposed = true;
|
|
1451
|
+
generation += 1;
|
|
1452
|
+
active?.controller.abort(/* @__PURE__ */ new Error("Account status controller disposed"));
|
|
1453
|
+
active = void 0;
|
|
1454
|
+
listeners.clear();
|
|
1455
|
+
};
|
|
1456
|
+
return Object.freeze({
|
|
1457
|
+
getSnapshot: () => snapshot,
|
|
1458
|
+
subscribe(listener) {
|
|
1459
|
+
listeners.add(listener);
|
|
1460
|
+
return () => listeners.delete(listener);
|
|
1461
|
+
},
|
|
1462
|
+
load,
|
|
1463
|
+
retry: load,
|
|
1464
|
+
reload,
|
|
1465
|
+
acceptAccount,
|
|
1466
|
+
dispose
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
//#endregion
|
|
1470
|
+
//#region src/context-draft-state.js
|
|
1471
|
+
const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value ?? {}, key);
|
|
1472
|
+
/**
|
|
1473
|
+
* Reconcile saved context values with the inputs currently shown in Settings.
|
|
1474
|
+
* A draft survives a catalog refresh while its saved value is unchanged. New
|
|
1475
|
+
* rows and rows whose saved value changed start from the new saved value.
|
|
1476
|
+
*/
|
|
1477
|
+
function reconcileContextDrafts({ modelRows, drafts, previousSavedValues, savedValues }) {
|
|
1478
|
+
const next = {};
|
|
1479
|
+
for (const model of modelRows) {
|
|
1480
|
+
const key = model.key;
|
|
1481
|
+
const saved = String(savedValues?.[key] ?? "");
|
|
1482
|
+
next[key] = hasOwn(previousSavedValues, key) && previousSavedValues[key] === saved && hasOwn(drafts, key) ? drafts[key] : saved;
|
|
1483
|
+
}
|
|
1484
|
+
return next;
|
|
1485
|
+
}
|
|
1486
|
+
//#endregion
|
|
1238
1487
|
//#region src/client.jsx
|
|
1239
1488
|
const inject = [
|
|
1240
1489
|
"slots",
|
|
@@ -1278,6 +1527,12 @@ window.__ModuleLoader__.load({
|
|
|
1278
1527
|
failed: "登录失败,请重试。",
|
|
1279
1528
|
loadFailed: "无法读取账户状态。",
|
|
1280
1529
|
accountRetry: "重试",
|
|
1530
|
+
accountRetrying: "正在重试账户状态…",
|
|
1531
|
+
accountCredentialUnavailable: "登录凭据暂时不可用。请重试;不会删除已保存的登录信息。",
|
|
1532
|
+
accountCredentialMalformed: "登录凭据格式异常,无法读取账户状态。重试不会删除已保存的登录信息。",
|
|
1533
|
+
accountStatusTimeout: "读取账户状态超时,请重试。",
|
|
1534
|
+
accountStatusTransport: "无法连接账户服务,请检查连接后重试。",
|
|
1535
|
+
accountStatusUnknown: "无法读取账户状态,请重试。",
|
|
1281
1536
|
diagnostics: "支持诊断",
|
|
1282
1537
|
diagnosticsLoad: "生成诊断",
|
|
1283
1538
|
diagnosticsLoading: "生成中…",
|
|
@@ -1361,7 +1616,7 @@ window.__ModuleLoader__.load({
|
|
|
1361
1616
|
contextStandard: "标准",
|
|
1362
1617
|
contextStandardHint: "使用模型目录默认值;官方 Agent 预设会自动管理上下文。",
|
|
1363
1618
|
contextExtended: "扩展",
|
|
1364
|
-
contextExtendedHint: "
|
|
1619
|
+
contextExtendedHint: "按模型使用已审核的扩展预算(Astra:872K);实际可用性由服务端决定。",
|
|
1365
1620
|
contextCustom: "自定义",
|
|
1366
1621
|
contextCustomHint: "输入完整 Token 数值;较低数值会让官方 Agent 预设更早压缩上下文。",
|
|
1367
1622
|
contextTokens: "Token 上限",
|
|
@@ -1406,6 +1661,7 @@ window.__ModuleLoader__.load({
|
|
|
1406
1661
|
modelsEmpty: "没有可用模型。",
|
|
1407
1662
|
effortsEmpty: "当前模型未提供推理等级。",
|
|
1408
1663
|
modelRetry: "重试",
|
|
1664
|
+
modelDirectoryFailed: "模型目录加载失败,请重试。",
|
|
1409
1665
|
modelFailed: "模型目录加载失败:{value}",
|
|
1410
1666
|
groupFailed: "{name}:{value}",
|
|
1411
1667
|
imageGenerate: "生成图片",
|
|
@@ -1473,6 +1729,12 @@ window.__ModuleLoader__.load({
|
|
|
1473
1729
|
failed: "Sign-in failed. Try again.",
|
|
1474
1730
|
loadFailed: "Could not read account status.",
|
|
1475
1731
|
accountRetry: "Retry",
|
|
1732
|
+
accountRetrying: "Retrying account status…",
|
|
1733
|
+
accountCredentialUnavailable: "The saved sign-in credentials are temporarily unavailable. Retry; saved sign-in information will not be deleted.",
|
|
1734
|
+
accountCredentialMalformed: "The saved sign-in credentials are malformed, so account status cannot be read. Retrying will not delete saved sign-in information.",
|
|
1735
|
+
accountStatusTimeout: "Reading account status timed out. Retry.",
|
|
1736
|
+
accountStatusTransport: "The account service is unavailable. Check the connection and retry.",
|
|
1737
|
+
accountStatusUnknown: "Could not read account status. Retry.",
|
|
1476
1738
|
diagnostics: "Support diagnostics",
|
|
1477
1739
|
diagnosticsLoad: "Create report",
|
|
1478
1740
|
diagnosticsLoading: "Creating…",
|
|
@@ -1556,7 +1818,7 @@ window.__ModuleLoader__.load({
|
|
|
1556
1818
|
contextStandard: "Standard",
|
|
1557
1819
|
contextStandardHint: "Use the model catalog default; official agent presets manage context automatically.",
|
|
1558
1820
|
contextExtended: "Extended",
|
|
1559
|
-
contextExtendedHint: "Uses
|
|
1821
|
+
contextExtendedHint: "Uses each model's audited extended budget (Astra: 872K); availability depends on the service.",
|
|
1560
1822
|
contextCustom: "Custom",
|
|
1561
1823
|
contextCustomHint: "Enter the full token count; lower values make official agent presets compact sooner.",
|
|
1562
1824
|
contextTokens: "Token limit",
|
|
@@ -1601,6 +1863,7 @@ window.__ModuleLoader__.load({
|
|
|
1601
1863
|
modelsEmpty: "No models available.",
|
|
1602
1864
|
effortsEmpty: "This model provides no reasoning effort levels.",
|
|
1603
1865
|
modelRetry: "Retry",
|
|
1866
|
+
modelDirectoryFailed: "Could not load the model directory. Try again.",
|
|
1604
1867
|
modelFailed: "Could not load models: {value}",
|
|
1605
1868
|
groupFailed: "{name}: {value}",
|
|
1606
1869
|
imageGenerate: "Generate image",
|
|
@@ -1691,6 +1954,16 @@ window.__ModuleLoader__.load({
|
|
|
1691
1954
|
if (!response?.ok) throw new Error(response?.error?.message ?? "Codex RPC failed");
|
|
1692
1955
|
return response.value;
|
|
1693
1956
|
};
|
|
1957
|
+
const accountStatusErrorText = (error, t) => {
|
|
1958
|
+
const key = {
|
|
1959
|
+
"credential-unavailable": "accountCredentialUnavailable",
|
|
1960
|
+
"credential-malformed": "accountCredentialMalformed",
|
|
1961
|
+
timeout: "accountStatusTimeout",
|
|
1962
|
+
transport: "accountStatusTransport",
|
|
1963
|
+
unknown: "accountStatusUnknown"
|
|
1964
|
+
}[error?.code];
|
|
1965
|
+
return t(key ?? "accountStatusUnknown");
|
|
1966
|
+
};
|
|
1694
1967
|
const fill = (text, values) => Object.entries(values).reduce((next, [key, value]) => next.replace(`{${key}}`, String(value)), text);
|
|
1695
1968
|
const maskEmail = (value) => {
|
|
1696
1969
|
if (typeof value !== "string" || !value.includes("@")) return "••••";
|
|
@@ -1924,6 +2197,7 @@ window.__ModuleLoader__.load({
|
|
|
1924
2197
|
});
|
|
1925
2198
|
}
|
|
1926
2199
|
const usePreferenceSnapshot = (preference) => (0, react.useSyncExternalStore)(preference.subscribe, preference.getSnapshot);
|
|
2200
|
+
const useAccountStatusSnapshot = (accountStatus) => (0, react.useSyncExternalStore)(accountStatus.subscribe, accountStatus.getSnapshot);
|
|
1927
2201
|
const notifyQuickQuota = () => window.dispatchEvent(new Event(QUICK_QUOTA_REFRESH_EVENT));
|
|
1928
2202
|
const formatRunway = (seconds, t) => {
|
|
1929
2203
|
if (!Number.isFinite(seconds) || seconds <= 0) return void 0;
|
|
@@ -2086,7 +2360,18 @@ window.__ModuleLoader__.load({
|
|
|
2086
2360
|
const modelRows = snapshot.contextModels.filter((model) => model.fixed !== true);
|
|
2087
2361
|
const fixedRows = snapshot.contextModels.filter((model) => model.fixed === true);
|
|
2088
2362
|
const [drafts, setDrafts] = (0, react.useState)({});
|
|
2089
|
-
(0, react.
|
|
2363
|
+
const previousSavedValues = (0, react.useRef)();
|
|
2364
|
+
(0, react.useEffect)(() => {
|
|
2365
|
+
const savedValues = Object.fromEntries(modelRows.map((model) => [model.key, String(snapshot.customContextWindows[model.key])]));
|
|
2366
|
+
const previous = previousSavedValues.current;
|
|
2367
|
+
setDrafts((current) => reconcileContextDrafts({
|
|
2368
|
+
modelRows,
|
|
2369
|
+
drafts: current,
|
|
2370
|
+
previousSavedValues: previous,
|
|
2371
|
+
savedValues
|
|
2372
|
+
}));
|
|
2373
|
+
previousSavedValues.current = savedValues;
|
|
2374
|
+
}, [modelRows.map((model) => `${model.key}\u0000${snapshot.customContextWindows[model.key]}`).join("")]);
|
|
2090
2375
|
const hint = snapshot.contextMode === "extended" ? t("contextExtendedHint") : snapshot.contextMode === "custom" ? t("contextCustomHint") : t("contextStandardHint");
|
|
2091
2376
|
const commit = (modelKey) => {
|
|
2092
2377
|
const parsed = parseContextWindow(drafts[modelKey]);
|
|
@@ -2121,81 +2406,99 @@ window.__ModuleLoader__.load({
|
|
|
2121
2406
|
const selectedMode = contextModeItems.find((item) => item.id === snapshot.contextMode)?.label ?? t("contextStandard");
|
|
2122
2407
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2123
2408
|
className: "codexSubscriptionContext",
|
|
2124
|
-
children: [
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2409
|
+
children: [
|
|
2410
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2411
|
+
className: "codexSubscriptionContextHead",
|
|
2412
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2413
|
+
className: "codexSubscriptionContextCopy",
|
|
2414
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2415
|
+
className: "codexSubscriptionPreferenceLabel",
|
|
2416
|
+
children: t("contextTitle")
|
|
2417
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2418
|
+
className: "codexSubscriptionContextHint",
|
|
2419
|
+
children: hint
|
|
2420
|
+
})]
|
|
2421
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2422
|
+
open: menuOpen,
|
|
2423
|
+
items: contextModeItems,
|
|
2424
|
+
selectedId: snapshot.contextMode,
|
|
2425
|
+
onSelect: (value) => {
|
|
2426
|
+
setMenuOpen(false);
|
|
2427
|
+
preference.set({ [CONTEXT_MODE_FIELD]: value });
|
|
2428
|
+
},
|
|
2429
|
+
onClose: () => setMenuOpen(false),
|
|
2430
|
+
align: "end",
|
|
2431
|
+
side: "bottom",
|
|
2432
|
+
portal: true,
|
|
2433
|
+
compact: true,
|
|
2434
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
2435
|
+
className: "codexSubscriptionContextTrigger",
|
|
2436
|
+
type: "button",
|
|
2437
|
+
"aria-label": t("contextTitle"),
|
|
2438
|
+
"aria-haspopup": "menu",
|
|
2439
|
+
"aria-expanded": menuOpen,
|
|
2440
|
+
disabled: !writable,
|
|
2441
|
+
onClick: () => setMenuOpen((value) => !value),
|
|
2442
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selectedMode }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})]
|
|
2443
|
+
})
|
|
2134
2444
|
})]
|
|
2135
|
-
}),
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2445
|
+
}),
|
|
2446
|
+
snapshot.contextMode === "custom" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2447
|
+
className: "codexSubscriptionContextModels",
|
|
2448
|
+
children: [modelRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2449
|
+
className: "codexSubscriptionContextModel",
|
|
2450
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2451
|
+
className: "codexSubscriptionContextModelCopy",
|
|
2452
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextMaximum"), { value: String(model.maximum) }) })]
|
|
2453
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
2454
|
+
"aria-label": `${model.label} ${t("contextTokens")}`,
|
|
2455
|
+
className: "codexSubscriptionContextInput",
|
|
2456
|
+
type: "number",
|
|
2457
|
+
inputMode: "numeric",
|
|
2458
|
+
min: MIN_CUSTOM_CONTEXT_WINDOW,
|
|
2459
|
+
max: model.maximum,
|
|
2460
|
+
step: 1,
|
|
2461
|
+
value: drafts[model.key] ?? "",
|
|
2462
|
+
disabled: !writable,
|
|
2463
|
+
onChange: (event) => {
|
|
2464
|
+
const nextValue = event.currentTarget.value;
|
|
2465
|
+
setDrafts((current) => ({
|
|
2466
|
+
...current,
|
|
2467
|
+
[model.key]: nextValue
|
|
2468
|
+
}));
|
|
2469
|
+
},
|
|
2470
|
+
onBlur: () => commit(model.key),
|
|
2471
|
+
onKeyDown: (event) => {
|
|
2472
|
+
if (event.key === "Enter") event.currentTarget.blur();
|
|
2473
|
+
}
|
|
2474
|
+
})]
|
|
2475
|
+
}, model.key)), fixedRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2476
|
+
className: "codexSubscriptionContextModel",
|
|
2477
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2478
|
+
className: "codexSubscriptionContextModelCopy",
|
|
2479
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextFixed"), { value: formatContextWindow(model.maximum) }) })]
|
|
2480
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2481
|
+
className: "codexSubscriptionContextHint",
|
|
2482
|
+
children: formatContextWindow(model.maximum)
|
|
2483
|
+
})]
|
|
2484
|
+
}, model.key))]
|
|
2485
|
+
}) : null,
|
|
2486
|
+
snapshot.modelError ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2487
|
+
className: "codexSubscriptionRecover",
|
|
2488
|
+
role: "alert",
|
|
2489
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2490
|
+
className: "codexSubscriptionError",
|
|
2491
|
+
children: t("modelDirectoryFailed")
|
|
2492
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2150
2493
|
type: "button",
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
disabled: !writable,
|
|
2155
|
-
onClick: () => setMenuOpen((value) => !value),
|
|
2156
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selectedMode }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})]
|
|
2157
|
-
})
|
|
2158
|
-
})]
|
|
2159
|
-
}), snapshot.contextMode === "custom" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2160
|
-
className: "codexSubscriptionContextModels",
|
|
2161
|
-
children: [modelRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2162
|
-
className: "codexSubscriptionContextModel",
|
|
2163
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2164
|
-
className: "codexSubscriptionContextModelCopy",
|
|
2165
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextMaximum"), { value: String(model.maximum) }) })]
|
|
2166
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
2167
|
-
"aria-label": `${model.label} ${t("contextTokens")}`,
|
|
2168
|
-
className: "codexSubscriptionContextInput",
|
|
2169
|
-
type: "number",
|
|
2170
|
-
inputMode: "numeric",
|
|
2171
|
-
min: MIN_CUSTOM_CONTEXT_WINDOW,
|
|
2172
|
-
max: model.maximum,
|
|
2173
|
-
step: 1,
|
|
2174
|
-
value: drafts[model.key] ?? "",
|
|
2175
|
-
disabled: !writable,
|
|
2176
|
-
onChange: (event) => {
|
|
2177
|
-
const nextValue = event.currentTarget.value;
|
|
2178
|
-
setDrafts((current) => ({
|
|
2179
|
-
...current,
|
|
2180
|
-
[model.key]: nextValue
|
|
2181
|
-
}));
|
|
2494
|
+
variant: "outline",
|
|
2495
|
+
onClick: () => {
|
|
2496
|
+
preference.refreshModels();
|
|
2182
2497
|
},
|
|
2183
|
-
|
|
2184
|
-
onKeyDown: (event) => {
|
|
2185
|
-
if (event.key === "Enter") event.currentTarget.blur();
|
|
2186
|
-
}
|
|
2187
|
-
})]
|
|
2188
|
-
}, model.key)), fixedRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2189
|
-
className: "codexSubscriptionContextModel",
|
|
2190
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2191
|
-
className: "codexSubscriptionContextModelCopy",
|
|
2192
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextFixed"), { value: formatContextWindow(model.maximum) }) })]
|
|
2193
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2194
|
-
className: "codexSubscriptionContextHint",
|
|
2195
|
-
children: formatContextWindow(model.maximum)
|
|
2498
|
+
children: t("modelRetry")
|
|
2196
2499
|
})]
|
|
2197
|
-
}
|
|
2198
|
-
|
|
2500
|
+
}) : null
|
|
2501
|
+
]
|
|
2199
2502
|
});
|
|
2200
2503
|
}
|
|
2201
2504
|
function PreferencesCard({ preference, t }) {
|
|
@@ -2932,18 +3235,23 @@ window.__ModuleLoader__.load({
|
|
|
2932
3235
|
]
|
|
2933
3236
|
});
|
|
2934
3237
|
}
|
|
2935
|
-
function AccountFailureCard({
|
|
3238
|
+
function AccountFailureCard({ accountStatus, snapshot, t }) {
|
|
3239
|
+
const retrying = snapshot.retrying === true;
|
|
2936
3240
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2937
3241
|
className: "codexSubscriptionCard codexSubscriptionRecover",
|
|
2938
3242
|
role: "alert",
|
|
2939
3243
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2940
3244
|
className: "codexSubscriptionError",
|
|
2941
|
-
children: t("
|
|
3245
|
+
children: retrying ? t("accountRetrying") : accountStatusErrorText(snapshot.error, t)
|
|
2942
3246
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
2943
3247
|
type: "button",
|
|
2944
3248
|
variant: "outline",
|
|
2945
|
-
|
|
2946
|
-
|
|
3249
|
+
disabled: retrying,
|
|
3250
|
+
"aria-busy": retrying,
|
|
3251
|
+
onClick: () => {
|
|
3252
|
+
accountStatus.retry();
|
|
3253
|
+
},
|
|
3254
|
+
children: retrying ? t("accountRetrying") : t("accountRetry")
|
|
2947
3255
|
})]
|
|
2948
3256
|
});
|
|
2949
3257
|
}
|
|
@@ -3403,27 +3711,19 @@ window.__ModuleLoader__.load({
|
|
|
3403
3711
|
]
|
|
3404
3712
|
});
|
|
3405
3713
|
}
|
|
3406
|
-
function CodexSection({ preference, rpc, t }) {
|
|
3407
|
-
const
|
|
3408
|
-
const
|
|
3714
|
+
function CodexSection({ preference, rpc, accountStatus, t }) {
|
|
3715
|
+
const accountSnapshot = useAccountStatusSnapshot(accountStatus);
|
|
3716
|
+
const account = accountSnapshot.account;
|
|
3409
3717
|
const [resetKey, setResetKey] = (0, react.useState)(0);
|
|
3410
|
-
const
|
|
3411
|
-
const
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
setAccountError(void 0);
|
|
3415
|
-
rpc.call(CHANNEL, "status", {}).then(unwrap).then((next) => {
|
|
3416
|
-
if (accountRequest.current === id) setAccount(next);
|
|
3417
|
-
}).catch(() => {
|
|
3418
|
-
if (accountRequest.current === id) setAccountError(true);
|
|
3419
|
-
});
|
|
3718
|
+
const setAccount = accountStatus.acceptAccount;
|
|
3719
|
+
const accountChanged = () => {
|
|
3720
|
+
setResetKey((value) => value + 1);
|
|
3721
|
+
preference.refreshModels();
|
|
3420
3722
|
};
|
|
3421
3723
|
(0, react.useEffect)(() => {
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
};
|
|
3426
|
-
}, []);
|
|
3724
|
+
accountStatus.load();
|
|
3725
|
+
preference.refreshModels();
|
|
3726
|
+
}, [accountStatus, preference]);
|
|
3427
3727
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3428
3728
|
className: "codexSubscription",
|
|
3429
3729
|
children: [
|
|
@@ -3431,15 +3731,16 @@ window.__ModuleLoader__.load({
|
|
|
3431
3731
|
className: "codexSubscriptionHead",
|
|
3432
3732
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: t("title") })
|
|
3433
3733
|
}),
|
|
3434
|
-
|
|
3734
|
+
accountSnapshot.status === "error" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountFailureCard, {
|
|
3735
|
+
accountStatus,
|
|
3736
|
+
snapshot: accountSnapshot,
|
|
3737
|
+
t
|
|
3738
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountCard, {
|
|
3435
3739
|
rpc,
|
|
3436
3740
|
t,
|
|
3437
3741
|
account,
|
|
3438
3742
|
setAccount,
|
|
3439
|
-
onSignedOut:
|
|
3440
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountFailureCard, {
|
|
3441
|
-
retry: loadAccount,
|
|
3442
|
-
t
|
|
3743
|
+
onSignedOut: accountChanged
|
|
3443
3744
|
}),
|
|
3444
3745
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PreferencesCard, {
|
|
3445
3746
|
preference,
|
|
@@ -3473,16 +3774,21 @@ window.__ModuleLoader__.load({
|
|
|
3473
3774
|
}, "codex-subscription: style");
|
|
3474
3775
|
const connection = ctx.get("connection");
|
|
3475
3776
|
const preference = createPreferenceController(ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE }), connection.rpc);
|
|
3777
|
+
const accountStatus = createAccountStatusController(connection.rpc);
|
|
3476
3778
|
ctx.effect(() => {
|
|
3477
3779
|
preference.load();
|
|
3780
|
+
accountStatus.load();
|
|
3478
3781
|
const disposeReset = ctx.on("connection/reset", () => {
|
|
3479
3782
|
preference.load();
|
|
3783
|
+
preference.refreshModels();
|
|
3784
|
+
accountStatus.reload();
|
|
3480
3785
|
});
|
|
3481
3786
|
return () => {
|
|
3482
3787
|
disposeReset?.();
|
|
3483
3788
|
preference.dispose();
|
|
3789
|
+
accountStatus.dispose();
|
|
3484
3790
|
};
|
|
3485
|
-
}, "codex-subscription: preferences");
|
|
3791
|
+
}, "codex-subscription: preferences and account status");
|
|
3486
3792
|
const t = ctx.locale.bind(NS);
|
|
3487
3793
|
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
3488
3794
|
name: "shell.overlay",
|
|
@@ -3502,6 +3808,7 @@ window.__ModuleLoader__.load({
|
|
|
3502
3808
|
inject: () => ({
|
|
3503
3809
|
preference,
|
|
3504
3810
|
rpc: connection.rpc,
|
|
3811
|
+
accountStatus,
|
|
3505
3812
|
t
|
|
3506
3813
|
})
|
|
3507
3814
|
}, CodexSection));
|
package/lib/index.js
CHANGED
|
@@ -565,6 +565,35 @@ const badRequest = (message) => ({
|
|
|
565
565
|
details: { issues: [] }
|
|
566
566
|
}
|
|
567
567
|
});
|
|
568
|
+
const accountStatusError = (message) => ({
|
|
569
|
+
ok: false,
|
|
570
|
+
error: {
|
|
571
|
+
code: "internal",
|
|
572
|
+
message,
|
|
573
|
+
details: { issues: [] }
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
const classifyAccountStatusError = (error) => {
|
|
577
|
+
const message = error instanceof Error ? error.message : "";
|
|
578
|
+
if (/malformed (?:OAuth|grant|account vault)|received a malformed OAuth|contains malformed OAuth/iu.test(message)) return ["credential-malformed", "Codex account credentials are malformed"];
|
|
579
|
+
if (/credential|account vault|readRecord|credential store|credentials service/iu.test(message)) return ["credential-unavailable", "Codex account credentials are unavailable"];
|
|
580
|
+
const code = typeof error?.code === "string" ? error.code.toUpperCase() : "";
|
|
581
|
+
if (error?.name === "TimeoutError" || [
|
|
582
|
+
"TIMEOUT",
|
|
583
|
+
"ETIMEDOUT",
|
|
584
|
+
"UND_ERR_CONNECT_TIMEOUT"
|
|
585
|
+
].includes(code)) return ["transport", "Codex account status service is unavailable"];
|
|
586
|
+
if ([
|
|
587
|
+
"ECONNRESET",
|
|
588
|
+
"ECONNREFUSED",
|
|
589
|
+
"ENOTFOUND",
|
|
590
|
+
"EAI_AGAIN",
|
|
591
|
+
"NETWORK",
|
|
592
|
+
"NETWORK_ERROR",
|
|
593
|
+
"TRANSPORT"
|
|
594
|
+
].includes(code) || error?.name === "NetworkError") return ["transport", "Codex account status service is unavailable"];
|
|
595
|
+
return ["unknown", "Could not read Codex account status"];
|
|
596
|
+
};
|
|
568
597
|
const deferred = () => {
|
|
569
598
|
let resolve;
|
|
570
599
|
let reject;
|
|
@@ -804,7 +833,13 @@ function createCodexRpcHandler(coordinator, options = {}) {
|
|
|
804
833
|
try {
|
|
805
834
|
signal.throwIfAborted();
|
|
806
835
|
const input = asObject(payload);
|
|
807
|
-
if (endpoint === "status")
|
|
836
|
+
if (endpoint === "status") try {
|
|
837
|
+
return ok(await coordinator.accountStatus({ signal }));
|
|
838
|
+
} catch (error) {
|
|
839
|
+
if (signal.aborted) throw error;
|
|
840
|
+
const [, message] = classifyAccountStatusError(error);
|
|
841
|
+
return accountStatusError(message);
|
|
842
|
+
}
|
|
808
843
|
if (endpoint === "login/start") {
|
|
809
844
|
const started = await coordinator.start({
|
|
810
845
|
method: input.method,
|
|
@@ -1123,19 +1158,22 @@ const CUSTOM_CONTEXT_MODEL_FIELDS = Object.freeze({
|
|
|
1123
1158
|
"gpt-5.4": "customContextGpt54",
|
|
1124
1159
|
"gpt-5.4-mini": "customContextGpt54Mini",
|
|
1125
1160
|
"gpt-5.5": "customContextGpt55",
|
|
1126
|
-
"gpt-5.6": "customContextGpt56"
|
|
1161
|
+
"gpt-5.6": "customContextGpt56",
|
|
1162
|
+
"gpt-6-astra": "customContextGpt6Astra"
|
|
1127
1163
|
});
|
|
1128
1164
|
const CUSTOM_CONTEXT_MODEL_CAPS = Object.freeze({
|
|
1129
1165
|
"gpt-5.4": 1e6,
|
|
1130
1166
|
"gpt-5.4-mini": 4e5,
|
|
1131
1167
|
"gpt-5.5": 1e6,
|
|
1132
|
-
"gpt-5.6": 1e6
|
|
1168
|
+
"gpt-5.6": 1e6,
|
|
1169
|
+
"gpt-6-astra": 872e3
|
|
1133
1170
|
});
|
|
1134
1171
|
const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
|
|
1135
1172
|
"gpt-5.4": 272e3,
|
|
1136
1173
|
"gpt-5.4-mini": 272e3,
|
|
1137
1174
|
"gpt-5.5": 272e3,
|
|
1138
|
-
"gpt-5.6": 272e3
|
|
1175
|
+
"gpt-5.6": 272e3,
|
|
1176
|
+
"gpt-6-astra": 272e3
|
|
1139
1177
|
});
|
|
1140
1178
|
const normalizeOutputVerbosity = (value) => [
|
|
1141
1179
|
"default",
|
|
@@ -1213,7 +1251,8 @@ const EXTENDED_CONTEXT_WINDOWS = Object.freeze({
|
|
|
1213
1251
|
"gpt-5.5": 1e6,
|
|
1214
1252
|
"gpt-5.6-luna": 1e6,
|
|
1215
1253
|
"gpt-5.6-sol": 1e6,
|
|
1216
|
-
"gpt-5.6-terra": 1e6
|
|
1254
|
+
"gpt-5.6-terra": 1e6,
|
|
1255
|
+
"gpt-6-astra": CUSTOM_CONTEXT_MODEL_CAPS["gpt-6-astra"]
|
|
1217
1256
|
});
|
|
1218
1257
|
function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, catalog, runNetwork = (_area, operation) => operation() } = {}) {
|
|
1219
1258
|
const provider = createOpenAICodexProvider();
|
|
@@ -1265,10 +1304,13 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
1265
1304
|
const maximum = EXTENDED_CONTEXT_WINDOWS[model.id];
|
|
1266
1305
|
const mode = resolveContextMode();
|
|
1267
1306
|
if (maximum === void 0 || !["extended", "custom"].includes(mode)) return model;
|
|
1268
|
-
if (mode === "extended")
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1307
|
+
if (mode === "extended") {
|
|
1308
|
+
const contextWindow = model.id === "gpt-6-astra" ? maximum : Math.max(model.contextWindow, maximum);
|
|
1309
|
+
return {
|
|
1310
|
+
...model,
|
|
1311
|
+
contextWindow
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1272
1314
|
const requested = normalizeCustomContextWindow(resolveCustomContextWindow(customContextModelKey(model.id)), maximum);
|
|
1273
1315
|
return {
|
|
1274
1316
|
...model,
|
|
@@ -1303,7 +1345,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
1303
1345
|
}
|
|
1304
1346
|
//#endregion
|
|
1305
1347
|
//#region src/version.js
|
|
1306
|
-
const PACKAGE_VERSION = "1.14.
|
|
1348
|
+
const PACKAGE_VERSION = "1.14.3";
|
|
1307
1349
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
1308
1350
|
//#endregion
|
|
1309
1351
|
//#region src/model-catalog.js
|
|
@@ -1317,6 +1359,7 @@ const LEVELS = [
|
|
|
1317
1359
|
"xhigh",
|
|
1318
1360
|
"max"
|
|
1319
1361
|
];
|
|
1362
|
+
const DEFAULT_REFRESH_TIMEOUT_MS = 1e4;
|
|
1320
1363
|
const record$4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1321
1364
|
const nonEmpty$2 = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1322
1365
|
const positiveInteger$1 = (value) => Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
@@ -1377,16 +1420,32 @@ function mergeModel(baseModels, remote) {
|
|
|
1377
1420
|
}
|
|
1378
1421
|
function createOfficialModelCatalog(options = {}) {
|
|
1379
1422
|
const fetchCatalog = options.fetch ?? fetch;
|
|
1423
|
+
const scheduleTimeout = options.setTimeout ?? setTimeout;
|
|
1424
|
+
const cancelTimeout = options.clearTimeout ?? clearTimeout;
|
|
1425
|
+
const timeoutMs = Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : DEFAULT_REFRESH_TIMEOUT_MS;
|
|
1380
1426
|
let models;
|
|
1381
1427
|
let metadata = /* @__PURE__ */ new Map();
|
|
1382
1428
|
let etag;
|
|
1383
1429
|
let revision = 0;
|
|
1384
1430
|
let refreshing;
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1431
|
+
let generation = 0;
|
|
1432
|
+
const refresh = ({ signal } = {}) => {
|
|
1433
|
+
if (signal?.aborted) return Promise.reject(signal.reason ?? /* @__PURE__ */ new Error("Codex model catalog refresh aborted"));
|
|
1434
|
+
if (refreshing?.generation === generation) return refreshing.promise;
|
|
1435
|
+
const currentGeneration = generation;
|
|
1436
|
+
const controller = new AbortController();
|
|
1437
|
+
const abort = () => {
|
|
1438
|
+
if (!controller.signal.aborted) controller.abort(signal?.reason ?? /* @__PURE__ */ new Error("Codex model catalog refresh aborted"));
|
|
1439
|
+
};
|
|
1440
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
1441
|
+
const requestSignal = controller.signal;
|
|
1442
|
+
let timer;
|
|
1443
|
+
const timeoutError = /* @__PURE__ */ new Error("Codex model catalog refresh timed out");
|
|
1444
|
+
const work = (async () => {
|
|
1445
|
+
const auth = await options.getAuth({ signal: requestSignal });
|
|
1446
|
+
if (currentGeneration !== generation || requestSignal.aborted) return false;
|
|
1447
|
+
const credential = await options.readCredential({ signal: requestSignal });
|
|
1448
|
+
if (currentGeneration !== generation || requestSignal.aborted) return false;
|
|
1390
1449
|
const access = auth?.auth?.apiKey;
|
|
1391
1450
|
const accountId = credential?.type === "oauth" ? credential.accountId : void 0;
|
|
1392
1451
|
if (typeof access !== "string" || access.length === 0 || typeof accountId !== "string" || accountId.length === 0) return false;
|
|
@@ -1402,24 +1461,44 @@ function createOfficialModelCatalog(options = {}) {
|
|
|
1402
1461
|
method: "GET",
|
|
1403
1462
|
redirect: "error",
|
|
1404
1463
|
headers,
|
|
1405
|
-
signal
|
|
1464
|
+
signal: requestSignal
|
|
1406
1465
|
});
|
|
1466
|
+
if (currentGeneration !== generation || requestSignal.aborted) return false;
|
|
1407
1467
|
if (response.status === 304) return false;
|
|
1408
1468
|
if (!response.ok) throw new Error(`Codex model catalog failed (HTTP ${response.status})`);
|
|
1409
1469
|
const remote = parseOfficialModelCatalog(await response.json());
|
|
1470
|
+
if (currentGeneration !== generation || requestSignal.aborted) return false;
|
|
1410
1471
|
if (remote.length === 0) throw new Error("Codex returned an empty model catalog");
|
|
1411
1472
|
const baseModels = options.baseModels();
|
|
1412
1473
|
const next = remote.map((model) => mergeModel(baseModels, model)).filter(Boolean);
|
|
1413
1474
|
if (next.length === 0) throw new Error("Codex model catalog has no compatible models");
|
|
1475
|
+
if (currentGeneration !== generation || requestSignal.aborted) return false;
|
|
1414
1476
|
models = next;
|
|
1415
1477
|
metadata = new Map(remote.map((model) => [model.id, model]));
|
|
1416
1478
|
etag = nonEmpty$2(response.headers.get("etag")) ?? etag;
|
|
1417
1479
|
revision += 1;
|
|
1418
1480
|
return true;
|
|
1419
|
-
})()
|
|
1420
|
-
|
|
1481
|
+
})();
|
|
1482
|
+
let rejectAborted;
|
|
1483
|
+
const abortPromise = new Promise((_, reject) => {
|
|
1484
|
+
rejectAborted = () => reject(requestSignal.reason ?? /* @__PURE__ */ new Error("Codex model catalog refresh aborted"));
|
|
1485
|
+
if (requestSignal.aborted) rejectAborted();
|
|
1486
|
+
else requestSignal.addEventListener("abort", rejectAborted, { once: true });
|
|
1421
1487
|
});
|
|
1422
|
-
|
|
1488
|
+
timer = scheduleTimeout(() => controller.abort(timeoutError), timeoutMs);
|
|
1489
|
+
timer.unref?.();
|
|
1490
|
+
const promise = Promise.race([work, abortPromise]).finally(() => {
|
|
1491
|
+
cancelTimeout(timer);
|
|
1492
|
+
signal?.removeEventListener("abort", abort);
|
|
1493
|
+
requestSignal.removeEventListener("abort", rejectAborted);
|
|
1494
|
+
if (refreshing?.promise === promise) refreshing = void 0;
|
|
1495
|
+
});
|
|
1496
|
+
refreshing = {
|
|
1497
|
+
generation: currentGeneration,
|
|
1498
|
+
promise,
|
|
1499
|
+
cancel: () => controller.abort()
|
|
1500
|
+
};
|
|
1501
|
+
return promise;
|
|
1423
1502
|
};
|
|
1424
1503
|
return Object.freeze({
|
|
1425
1504
|
refresh,
|
|
@@ -1427,6 +1506,10 @@ function createOfficialModelCatalog(options = {}) {
|
|
|
1427
1506
|
metadata: (modelId) => metadata.get(modelId),
|
|
1428
1507
|
revision: () => revision,
|
|
1429
1508
|
clear() {
|
|
1509
|
+
generation += 1;
|
|
1510
|
+
const flight = refreshing;
|
|
1511
|
+
refreshing = void 0;
|
|
1512
|
+
flight?.cancel();
|
|
1430
1513
|
models = void 0;
|
|
1431
1514
|
metadata = /* @__PURE__ */ new Map();
|
|
1432
1515
|
etag = void 0;
|
|
@@ -3117,6 +3200,22 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
3117
3200
|
if (signal.aborted) throw error;
|
|
3118
3201
|
return publicError("internal", "Could not create support diagnostics");
|
|
3119
3202
|
}
|
|
3203
|
+
if (endpoint === "preferences/models") try {
|
|
3204
|
+
signal.throwIfAborted();
|
|
3205
|
+
if (typeof modelCatalog?.refresh !== "function" || typeof preferences?.status !== "function") return publicError("internal", "Could not refresh Codex model catalog");
|
|
3206
|
+
await modelCatalog.refresh({ signal });
|
|
3207
|
+
const value = preferences.status();
|
|
3208
|
+
return {
|
|
3209
|
+
ok: true,
|
|
3210
|
+
value: {
|
|
3211
|
+
contextModels: Array.isArray(value?.contextModels) ? value.contextModels : [],
|
|
3212
|
+
verbosityModels: Array.isArray(value?.verbosityModels) ? value.verbosityModels : []
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
} catch (error) {
|
|
3216
|
+
if (signal.aborted) throw error;
|
|
3217
|
+
return publicError("internal", "Could not refresh Codex model catalog");
|
|
3218
|
+
}
|
|
3120
3219
|
if (endpoint === "preferences/status" || endpoint === "preferences/update") try {
|
|
3121
3220
|
signal.throwIfAborted();
|
|
3122
3221
|
if (endpoint === "preferences/update") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.3",
|
|
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",
|