@eddyskywalker/dsh-chatgpt-subscription 0.2.20 → 0.3.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/CHANGELOG.md +79 -0
- package/README.md +116 -1
- package/lib/client.js +2825 -512
- package/lib/client.js.map +1 -1
- package/lib/index.js +8758 -352
- package/lib/types/client/ProviderHubSection.d.ts +15 -0
- package/lib/types/client/ProviderHubSection.d.ts.map +1 -0
- package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts +24 -0
- package/lib/types/client/command-code/CommandCodeComposerQuota.d.ts.map +1 -0
- package/lib/types/client/command-code/CommandCodeSection.d.ts +11 -0
- package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -0
- package/lib/types/client/command-code/locales.d.ts +401 -0
- package/lib/types/client/command-code/locales.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +2 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts +25 -0
- package/lib/types/client/kimi-code/KimiCodeComposerQuota.d.ts.map +1 -0
- package/lib/types/client/kimi-code/KimiCodeSection.d.ts +11 -0
- package/lib/types/client/kimi-code/KimiCodeSection.d.ts.map +1 -0
- package/lib/types/client/kimi-code/KimiModelCapabilities.d.ts +16 -0
- package/lib/types/client/kimi-code/KimiModelCapabilities.d.ts.map +1 -0
- package/lib/types/client/kimi-code/locales.d.ts +665 -0
- package/lib/types/client/kimi-code/locales.d.ts.map +1 -0
- package/lib/types/client/kimi-code/styles.d.ts +4 -0
- package/lib/types/client/kimi-code/styles.d.ts.map +1 -0
- package/lib/types/client/locales.d.ts +3 -1
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/host/antigravity/adapter.d.ts +2 -0
- package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
- package/lib/types/host/antigravity/mapper.d.ts +51 -2
- package/lib/types/host/antigravity/mapper.d.ts.map +1 -1
- package/lib/types/host/command-code/adapter.d.ts +34 -0
- package/lib/types/host/command-code/adapter.d.ts.map +1 -0
- package/lib/types/host/command-code/client.d.ts +99 -0
- package/lib/types/host/command-code/client.d.ts.map +1 -0
- package/lib/types/host/command-code/mapper.d.ts +102 -0
- package/lib/types/host/command-code/mapper.d.ts.map +1 -0
- package/lib/types/host/command-code/model-catalog.d.ts +31 -0
- package/lib/types/host/command-code/model-catalog.d.ts.map +1 -0
- package/lib/types/host/command-code/oauth.d.ts +89 -0
- package/lib/types/host/command-code/oauth.d.ts.map +1 -0
- package/lib/types/host/command-code/plans.d.ts +40 -0
- package/lib/types/host/command-code/plans.d.ts.map +1 -0
- package/lib/types/host/command-code/routes.d.ts +27 -0
- package/lib/types/host/command-code/routes.d.ts.map +1 -0
- package/lib/types/host/command-code/token-store.d.ts +88 -0
- package/lib/types/host/command-code/token-store.d.ts.map +1 -0
- package/lib/types/host/command-code/types.d.ts +138 -0
- package/lib/types/host/command-code/types.d.ts.map +1 -0
- package/lib/types/host/kimi-code/adapter.d.ts +112 -0
- package/lib/types/host/kimi-code/adapter.d.ts.map +1 -0
- package/lib/types/host/kimi-code/client.d.ts +161 -0
- package/lib/types/host/kimi-code/client.d.ts.map +1 -0
- package/lib/types/host/kimi-code/mapper.d.ts +334 -0
- package/lib/types/host/kimi-code/mapper.d.ts.map +1 -0
- package/lib/types/host/kimi-code/modalities.d.ts +94 -0
- package/lib/types/host/kimi-code/modalities.d.ts.map +1 -0
- package/lib/types/host/kimi-code/model-catalog.d.ts +77 -0
- package/lib/types/host/kimi-code/model-catalog.d.ts.map +1 -0
- package/lib/types/host/kimi-code/oauth.d.ts +133 -0
- package/lib/types/host/kimi-code/oauth.d.ts.map +1 -0
- package/lib/types/host/kimi-code/routes.d.ts +26 -0
- package/lib/types/host/kimi-code/routes.d.ts.map +1 -0
- package/lib/types/host/kimi-code/token-store.d.ts +135 -0
- package/lib/types/host/kimi-code/token-store.d.ts.map +1 -0
- package/lib/types/host/kimi-code/types.d.ts +174 -0
- package/lib/types/host/kimi-code/types.d.ts.map +1 -0
- package/lib/types/host/relay-probe.d.ts +161 -0
- package/lib/types/host/relay-probe.d.ts.map +1 -0
- package/lib/types/host/responses-client.d.ts.map +1 -1
- package/lib/types/index.d.ts +13 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/command-code-contracts.d.ts +119 -0
- package/lib/types/shared/command-code-contracts.d.ts.map +1 -0
- package/lib/types/shared/kimi-code-contracts.d.ts +203 -0
- package/lib/types/shared/kimi-code-contracts.d.ts.map +1 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -56,7 +56,7 @@ window.__ModuleLoader__.load({
|
|
|
56
56
|
//#endregion
|
|
57
57
|
//#region src/client/CodexComposerQuota.tsx
|
|
58
58
|
function CodexComposerQuota({ api, directory, loadModelDirectory, t }) {
|
|
59
|
-
const modelState = useStore$
|
|
59
|
+
const modelState = useStore$3(directory);
|
|
60
60
|
const [status, setStatus] = (0, react.useState)(null);
|
|
61
61
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
62
62
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -103,7 +103,7 @@ window.__ModuleLoader__.load({
|
|
|
103
103
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("quickQuotaLabel") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: quota === null ? loading ? t("quickQuotaLoading") : "—" : formatPercent$1(quota.remainingPercent) })]
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
-
function useStore$
|
|
106
|
+
function useStore$3(store) {
|
|
107
107
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
108
108
|
}
|
|
109
109
|
function formatPercent$1(value) {
|
|
@@ -594,7 +594,7 @@ window.__ModuleLoader__.load({
|
|
|
594
594
|
}),
|
|
595
595
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
|
|
596
596
|
label: t("expires"),
|
|
597
|
-
value: formatDate$
|
|
597
|
+
value: formatDate$3(account?.tokenExpiresAt)
|
|
598
598
|
})
|
|
599
599
|
] }) : null,
|
|
600
600
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
|
|
@@ -657,7 +657,7 @@ window.__ModuleLoader__.load({
|
|
|
657
657
|
}),
|
|
658
658
|
connection !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoRow, {
|
|
659
659
|
label: t("latency"),
|
|
660
|
-
value: `${connection.latencyMs} ms · ${formatDate$
|
|
660
|
+
value: `${connection.latencyMs} ms · ${formatDate$3(connection.checkedAt)}`
|
|
661
661
|
}) : null,
|
|
662
662
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
663
663
|
className: "dsh-codex-muted dsh-codex-models-hint",
|
|
@@ -914,7 +914,7 @@ window.__ModuleLoader__.load({
|
|
|
914
914
|
id: inputId,
|
|
915
915
|
type: "text",
|
|
916
916
|
inputMode: "numeric",
|
|
917
|
-
value: draft ?? formatCapacity$
|
|
917
|
+
value: draft ?? formatCapacity$3(fallback),
|
|
918
918
|
disabled: busy !== null,
|
|
919
919
|
"aria-label": entry.name + " " + t("contextWindow"),
|
|
920
920
|
onChange: (event) => {
|
|
@@ -1028,7 +1028,7 @@ window.__ModuleLoader__.load({
|
|
|
1028
1028
|
children: [
|
|
1029
1029
|
t("updated"),
|
|
1030
1030
|
": ",
|
|
1031
|
-
formatDate$
|
|
1031
|
+
formatDate$3(quota.fetchedAt)
|
|
1032
1032
|
]
|
|
1033
1033
|
}) : null
|
|
1034
1034
|
]
|
|
@@ -1120,7 +1120,7 @@ window.__ModuleLoader__.load({
|
|
|
1120
1120
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
|
|
1121
1121
|
t("resetCreditExpires"),
|
|
1122
1122
|
": ",
|
|
1123
|
-
resetCredits.expiresAt == null ? t("unknown") : formatReset(resetCredits.expiresAt)
|
|
1123
|
+
resetCredits.expiresAt == null ? t("unknown") : formatReset$2(resetCredits.expiresAt)
|
|
1124
1124
|
] })
|
|
1125
1125
|
]
|
|
1126
1126
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
@@ -1153,7 +1153,7 @@ window.__ModuleLoader__.load({
|
|
|
1153
1153
|
}),
|
|
1154
1154
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1155
1155
|
className: "dsh-codex-meter-meta",
|
|
1156
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset(window.resetsAt)}` })]
|
|
1156
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: percent >= 100 ? `${t("exhausted")} · ${formatPercent(remaining)} ${t("remaining")}` : `${formatPercent(percent)} ${t("used")} · ${formatPercent(remaining)} ${t("remaining")}` }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window?.resetsAt == null ? "—" : `${t("resets")}: ${formatReset$2(window.resetsAt)}` })]
|
|
1157
1157
|
})
|
|
1158
1158
|
]
|
|
1159
1159
|
});
|
|
@@ -1179,7 +1179,7 @@ window.__ModuleLoader__.load({
|
|
|
1179
1179
|
return `${value} ${t("limitWindow")}`;
|
|
1180
1180
|
}
|
|
1181
1181
|
}
|
|
1182
|
-
function parsePositiveCapacity$
|
|
1182
|
+
function parsePositiveCapacity$3(value) {
|
|
1183
1183
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
1184
1184
|
if (matched === null) return null;
|
|
1185
1185
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
@@ -1187,10 +1187,10 @@ window.__ModuleLoader__.load({
|
|
|
1187
1187
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
1188
1188
|
}
|
|
1189
1189
|
function parseCapacity(value, maxContextWindow = GPT_56_MAX_CONTEXT_WINDOW) {
|
|
1190
|
-
const parsed = parsePositiveCapacity$
|
|
1190
|
+
const parsed = parsePositiveCapacity$3(value);
|
|
1191
1191
|
return parsed !== null && parsed <= maxContextWindow ? parsed : null;
|
|
1192
1192
|
}
|
|
1193
|
-
function formatCapacity$
|
|
1193
|
+
function formatCapacity$3(value) {
|
|
1194
1194
|
if (value % 1e3 === 0) return `${value / 1e3}K`;
|
|
1195
1195
|
return String(value);
|
|
1196
1196
|
}
|
|
@@ -1207,11 +1207,11 @@ window.__ModuleLoader__.load({
|
|
|
1207
1207
|
limit.remainingPercent !== null && limit.remainingPercent !== void 0 ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
|
|
1208
1208
|
limit.limit !== null && limit.limit !== void 0 ? `${t("limit")}: ${limit.limit}` : null,
|
|
1209
1209
|
limit.used !== null && limit.used !== void 0 ? `${t("used")}: ${limit.used}` : null,
|
|
1210
|
-
limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset(limit.resetsAt)}` : null
|
|
1210
|
+
limit.resetsAt !== null && limit.resetsAt !== void 0 ? `${t("resets")}: ${formatReset$2(limit.resetsAt)}` : null
|
|
1211
1211
|
].filter((part) => part !== null);
|
|
1212
1212
|
return parts.length > 0 ? parts.join(" · ") : t("unknown");
|
|
1213
1213
|
}
|
|
1214
|
-
function formatDate$
|
|
1214
|
+
function formatDate$3(seconds) {
|
|
1215
1215
|
if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
|
|
1216
1216
|
const ms = seconds > 1e10 ? seconds : seconds * 1e3;
|
|
1217
1217
|
try {
|
|
@@ -1223,10 +1223,10 @@ window.__ModuleLoader__.load({
|
|
|
1223
1223
|
return "—";
|
|
1224
1224
|
}
|
|
1225
1225
|
}
|
|
1226
|
-
function formatReset(seconds) {
|
|
1226
|
+
function formatReset$2(seconds) {
|
|
1227
1227
|
if (seconds === void 0 || seconds === null || typeof seconds !== "number" || !Number.isFinite(seconds) || seconds <= 0) return "—";
|
|
1228
1228
|
const ms = seconds > 1e10 ? seconds : seconds * 1e3;
|
|
1229
|
-
const absolute = formatDate$
|
|
1229
|
+
const absolute = formatDate$3(seconds);
|
|
1230
1230
|
const diff = ms - Date.now();
|
|
1231
1231
|
const abs = Math.abs(diff);
|
|
1232
1232
|
const [amount, unit] = abs >= 864e5 ? [Math.round(diff / 864e5), "day"] : abs >= 36e5 ? [Math.round(diff / 36e5), "hour"] : [Math.round(diff / 6e4), "minute"];
|
|
@@ -1240,380 +1240,9 @@ window.__ModuleLoader__.load({
|
|
|
1240
1240
|
return error instanceof Error ? error.message : String(error);
|
|
1241
1241
|
}
|
|
1242
1242
|
//#endregion
|
|
1243
|
-
//#region src/client/locales.ts
|
|
1244
|
-
const NS = "dsh-chatgpt-subscription";
|
|
1245
|
-
const dictionaries$1 = {
|
|
1246
|
-
zh: {
|
|
1247
|
-
title: "ChatGPT",
|
|
1248
|
-
intro: "使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的模型。",
|
|
1249
|
-
account: "账号",
|
|
1250
|
-
signedOut: "尚未登录",
|
|
1251
|
-
signedIn: "已登录",
|
|
1252
|
-
plan: "套餐",
|
|
1253
|
-
accountId: "账号 ID",
|
|
1254
|
-
expires: "令牌到期",
|
|
1255
|
-
storage: "凭据存储",
|
|
1256
|
-
storageWindows: "Windows DPAPI(当前用户加密)",
|
|
1257
|
-
storageMacKeychain: "macOS 钥匙串(Keychain 加密)",
|
|
1258
|
-
storageLinuxFile: "Linux 用户私有文件(权限 0600)",
|
|
1259
|
-
storageMemory: "仅 Host 内存(不持久化)",
|
|
1260
|
-
storageUnavailable: "凭据存储不可用",
|
|
1261
|
-
securityWindows: "令牌由 Host 使用 Windows CurrentUser DPAPI 加密,不会进入浏览器、settings.yaml 或日志。",
|
|
1262
|
-
securityMacKeychain: "令牌由 Host 存入 macOS 登录钥匙串(Keychain),在本机加密保存,不会进入浏览器、settings.yaml 或日志。",
|
|
1263
|
-
securityLinuxFile: "令牌仅写入 Host 上当前 Linux 用户可读的 0600 文件,但不会额外加密;同 UID 进程、root、备份和磁盘快照仍可能读取。",
|
|
1264
|
-
securityMemory: "令牌仅保留在 Host 内存中,Host 退出后丢失。",
|
|
1265
|
-
securityUnavailable: "Host 无法安全访问凭据存储;请修复文件所有者或权限后重试。",
|
|
1266
|
-
signIn: "使用 ChatGPT 登录",
|
|
1267
|
-
signInAgain: "重新登录",
|
|
1268
|
-
cancel: "取消登录",
|
|
1269
|
-
signOut: "注销",
|
|
1270
|
-
refreshToken: "刷新凭据",
|
|
1271
|
-
pending: "请在浏览器中完成登录。",
|
|
1272
|
-
popupBlocked: "浏览器拦截了登录窗口,请使用下面的链接继续。",
|
|
1273
|
-
continueLogin: "打开 ChatGPT 登录页",
|
|
1274
|
-
loading: "正在读取状态…",
|
|
1275
|
-
connection: "连接",
|
|
1276
|
-
provider: "Provider",
|
|
1277
|
-
connectionState: "连接状态",
|
|
1278
|
-
connected: "可用",
|
|
1279
|
-
untested: "尚未测试",
|
|
1280
|
-
testConnection: "测试连接",
|
|
1281
|
-
testing: "测试中…",
|
|
1282
|
-
latency: "最近延迟",
|
|
1283
|
-
models: "可用模型",
|
|
1284
|
-
modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;至少保留一个。",
|
|
1285
|
-
proxySettings: "网络代理",
|
|
1286
|
-
proxyMode: "代理模式",
|
|
1287
|
-
proxyModeHint: "GPT 与 Antigravity(Gemini)共用此代理设置;支持自动读取系统代理,修改后对后续请求生效。",
|
|
1288
|
-
proxyModeAuto: "系统代理(自动检测)",
|
|
1289
|
-
proxyModeCustom: "自定义代理",
|
|
1290
|
-
proxyModeDirect: "直连(禁用代理)",
|
|
1291
|
-
customProxyUrl: "自定义代理地址",
|
|
1292
|
-
customProxyUrlHint: "支持 HTTP/HTTPS/SOCKS5 代理地址,例如 http://127.0.0.1:7890",
|
|
1293
|
-
customProxyUrlPlaceholder: "例如: http://127.0.0.1:7890",
|
|
1294
|
-
saveProxyUrl: "保存代理地址",
|
|
1295
|
-
proxyDetected: "检测到系统代理",
|
|
1296
|
-
proxyDetectedEffective: "(已自动生效)",
|
|
1297
|
-
proxyNoneDetected: "未检测到系统代理,将使用直连",
|
|
1298
|
-
proxyDirectHint: "所有网络请求将直接连接,不经过任何代理服务器。",
|
|
1299
|
-
enhancements: "增强功能",
|
|
1300
|
-
fastMode: "快速模式(1.5x 速度)",
|
|
1301
|
-
fastModeHint: "提升 Token 生成速度至约 1.5 倍;将以约 2x–2.5x 速度消耗 Codex 订阅额度。",
|
|
1302
|
-
outputVerbosity: "输出详细程度",
|
|
1303
|
-
outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。",
|
|
1304
|
-
verbosityLow: "低(保持回答简洁)",
|
|
1305
|
-
verbosityMedium: "中(兼顾细节与简洁)",
|
|
1306
|
-
verbosityHigh: "高(在回答中包含更多细节)",
|
|
1307
|
-
reasoningSummary: "推理摘要",
|
|
1308
|
-
reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。",
|
|
1309
|
-
summaryAuto: "自动(让模型选择摘要详细程度)",
|
|
1310
|
-
summaryConcise: "简洁(显示简要推理摘要)",
|
|
1311
|
-
summaryDetailed: "详细(显示更详细的推理摘要)",
|
|
1312
|
-
summaryNone: "无(不显示推理摘要)",
|
|
1313
|
-
searchProvider: "搜索与抓取来源",
|
|
1314
|
-
searchProviderHint: "选择 DSH 联网工具使用默认来源,或改用当前 ChatGPT 订阅的 Codex 来源(自动走代理隧道)。",
|
|
1315
|
-
searchProviderDsh: "DSH 默认",
|
|
1316
|
-
searchProviderCodex: "ChatGPT(代理隧道)",
|
|
1317
|
-
providerDefault: "使用 Provider 默认值",
|
|
1318
|
-
contextWindows: "模型上下文窗口",
|
|
1319
|
-
contextWindowsHint: "默认 272K;6 Astra 最高 872K,GPT-5.6 最高 1M。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。",
|
|
1320
|
-
contextWindow: "上下文窗口",
|
|
1321
|
-
contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(6 Astra 为 872K,GPT-5.6 为 1M);可使用 K 或 M 后缀。",
|
|
1322
|
-
saveContextWindow: "保存上下文窗口",
|
|
1323
|
-
save: "保存",
|
|
1324
|
-
tokens: "tokens",
|
|
1325
|
-
quickQuota: "在输入框旁显示快捷用量",
|
|
1326
|
-
quickQuotaHint: "仅在当前会话选中 codex-chatgpt 模型时显示。",
|
|
1327
|
-
quota: "用量与限额",
|
|
1328
|
-
quotaIntro: "数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。",
|
|
1329
|
-
refreshQuota: "刷新用量",
|
|
1330
|
-
refreshing: "刷新中…",
|
|
1331
|
-
noQuota: "当前套餐未返回可显示的限额窗口。",
|
|
1332
|
-
quotaSignedOut: "登录后可查看订阅限额。",
|
|
1333
|
-
stale: "显示的是上次成功获取的数据。",
|
|
1334
|
-
updated: "更新时间",
|
|
1335
|
-
primary: "主要窗口",
|
|
1336
|
-
secondary: "次要窗口",
|
|
1337
|
-
limitWindow: "额度",
|
|
1338
|
-
used: "已使用",
|
|
1339
|
-
remaining: "剩余",
|
|
1340
|
-
available: "可用",
|
|
1341
|
-
unavailable: "不可用",
|
|
1342
|
-
unlimited: "无限",
|
|
1343
|
-
credits: "Credits",
|
|
1344
|
-
monthlySpend: "月度消费控制",
|
|
1345
|
-
resetCredits: "重置次数",
|
|
1346
|
-
resetCreditExpires: "到期时间",
|
|
1347
|
-
useResetCredit: "使用重置卡",
|
|
1348
|
-
usingResetCredit: "使用中…",
|
|
1349
|
-
useResetCreditConfirm: "使用后会立即消耗 1 次重置机会,并重置符合条件的 Codex 额度窗口。确定继续吗?",
|
|
1350
|
-
resetCreditUsed: "重置卡已使用,用量数据已刷新。",
|
|
1351
|
-
spendControlReached: "已触发月度消费控制,新的订阅调用可能被限制。",
|
|
1352
|
-
limit: "上限",
|
|
1353
|
-
exhausted: "额度已用尽",
|
|
1354
|
-
resets: "重置",
|
|
1355
|
-
quickQuotaLabel: "Codex 剩余",
|
|
1356
|
-
quickQuotaLoading: "用量…",
|
|
1357
|
-
imageToolRunning: "正在生成图片",
|
|
1358
|
-
imageToolDone: "已生成图片",
|
|
1359
|
-
imageToolFailed: "图片生成失败",
|
|
1360
|
-
image: "图片",
|
|
1361
|
-
openImage: "打开图片",
|
|
1362
|
-
openNamedImage: "打开 {name}",
|
|
1363
|
-
imageLoading: "加载图片…",
|
|
1364
|
-
imageLoadFailed: "图片加载失败,点击重试",
|
|
1365
|
-
imagePreviewClose: "关闭",
|
|
1366
|
-
imagePreviewOpenOriginal: "打开原图",
|
|
1367
|
-
retry: "重试",
|
|
1368
|
-
unknown: "未知"
|
|
1369
|
-
},
|
|
1370
|
-
en: {
|
|
1371
|
-
title: "ChatGPT",
|
|
1372
|
-
intro: "Sign in with ChatGPT to use models available to your subscription in DSH.",
|
|
1373
|
-
account: "Account",
|
|
1374
|
-
signedOut: "Not signed in",
|
|
1375
|
-
signedIn: "Signed in",
|
|
1376
|
-
plan: "Plan",
|
|
1377
|
-
accountId: "Account ID",
|
|
1378
|
-
expires: "Token expires",
|
|
1379
|
-
storage: "Credential storage",
|
|
1380
|
-
storageWindows: "Windows DPAPI (current-user encrypted)",
|
|
1381
|
-
storageMacKeychain: "macOS Keychain (encrypted)",
|
|
1382
|
-
storageLinuxFile: "Linux user-private file (mode 0600)",
|
|
1383
|
-
storageMemory: "Host memory only (not persistent)",
|
|
1384
|
-
storageUnavailable: "Credential storage unavailable",
|
|
1385
|
-
securityWindows: "The Host encrypts tokens with Windows CurrentUser DPAPI; they never enter the browser, settings.yaml, or logs.",
|
|
1386
|
-
securityMacKeychain: "The Host stores tokens in the macOS login Keychain, encrypted on this machine; they never enter the browser, settings.yaml, or logs.",
|
|
1387
|
-
securityLinuxFile: "Tokens are stored in a mode-0600 file readable only by the current Linux user, but are not additionally encrypted; same-UID processes, root, backups, and disk snapshots can still read them.",
|
|
1388
|
-
securityMemory: "Tokens remain only in Host memory and are lost when the Host exits.",
|
|
1389
|
-
securityUnavailable: "The Host cannot safely access credential storage. Fix the file owner or permissions and retry.",
|
|
1390
|
-
signIn: "Sign in with ChatGPT",
|
|
1391
|
-
signInAgain: "Sign in again",
|
|
1392
|
-
cancel: "Cancel sign-in",
|
|
1393
|
-
signOut: "Sign out",
|
|
1394
|
-
refreshToken: "Refresh credentials",
|
|
1395
|
-
pending: "Complete sign-in in your browser.",
|
|
1396
|
-
popupBlocked: "The sign-in window was blocked. Use the link below to continue.",
|
|
1397
|
-
continueLogin: "Open ChatGPT sign-in",
|
|
1398
|
-
loading: "Reading status…",
|
|
1399
|
-
connection: "Connection",
|
|
1400
|
-
provider: "Provider",
|
|
1401
|
-
connectionState: "Connection status",
|
|
1402
|
-
connected: "Available",
|
|
1403
|
-
untested: "Not tested",
|
|
1404
|
-
testConnection: "Test connection",
|
|
1405
|
-
testing: "Testing…",
|
|
1406
|
-
latency: "Last latency",
|
|
1407
|
-
models: "Available models",
|
|
1408
|
-
modelsHint: "Checked models appear in the conversation model picker; at least one must remain enabled.",
|
|
1409
|
-
proxySettings: "Network Proxy",
|
|
1410
|
-
proxyMode: "Proxy Mode",
|
|
1411
|
-
proxyModeHint: "GPT and Antigravity (Gemini) share these proxy settings. Supports system proxy detection; changes apply to subsequent requests.",
|
|
1412
|
-
proxyModeAuto: "System Proxy (Auto-detect)",
|
|
1413
|
-
proxyModeCustom: "Custom Proxy",
|
|
1414
|
-
proxyModeDirect: "Direct (No Proxy)",
|
|
1415
|
-
customProxyUrl: "Custom Proxy URL",
|
|
1416
|
-
customProxyUrlHint: "Supports HTTP/HTTPS/SOCKS5 proxy URLs, e.g. http://127.0.0.1:7890",
|
|
1417
|
-
customProxyUrlPlaceholder: "e.g. http://127.0.0.1:7890",
|
|
1418
|
-
saveProxyUrl: "Save Proxy URL",
|
|
1419
|
-
proxyDetected: "Detected system proxy",
|
|
1420
|
-
proxyDetectedEffective: " (active)",
|
|
1421
|
-
proxyNoneDetected: "No system proxy detected; connecting directly",
|
|
1422
|
-
proxyDirectHint: "All requests connect directly without using any proxy server.",
|
|
1423
|
-
enhancements: "Enhancements",
|
|
1424
|
-
fastMode: "Fast mode (1.5x speed)",
|
|
1425
|
-
fastModeHint: "Generates tokens ~1.5x faster; consumes Codex subscription quota at ~2x–2.5x the normal rate.",
|
|
1426
|
-
outputVerbosity: "Output verbosity",
|
|
1427
|
-
outputVerbosityHint: "Controls the detail level of final Codex answers without changing reasoning effort.",
|
|
1428
|
-
verbosityLow: "Low (keep answers concise)",
|
|
1429
|
-
verbosityMedium: "Medium (balance detail and brevity)",
|
|
1430
|
-
verbosityHigh: "High (include more detail)",
|
|
1431
|
-
reasoningSummary: "Reasoning summary",
|
|
1432
|
-
reasoningSummaryHint: "Controls how ChatGPT summarizes its chain of thought; does not change reasoning depth.",
|
|
1433
|
-
summaryAuto: "Auto (let model determine detail)",
|
|
1434
|
-
summaryConcise: "Concise (brief summary)",
|
|
1435
|
-
summaryDetailed: "Detailed (in-depth summary)",
|
|
1436
|
-
summaryNone: "None (hide reasoning summary)",
|
|
1437
|
-
searchProvider: "Search & Fetch provider",
|
|
1438
|
-
searchProviderHint: "Choose whether DSH web tools use the default provider or the Codex proxy-backed source from this ChatGPT subscription.",
|
|
1439
|
-
searchProviderDsh: "DSH default",
|
|
1440
|
-
searchProviderCodex: "ChatGPT (Proxy tunnel)",
|
|
1441
|
-
providerDefault: "Use provider default",
|
|
1442
|
-
contextWindows: "Model context windows",
|
|
1443
|
-
contextWindowsHint: "Defaults to 272K, with up to 872K for 6 Astra and 1M for GPT-5.6. DSH uses it for compaction and overflow detection; values such as 872K and 512K are accepted.",
|
|
1444
|
-
contextWindow: "Context window",
|
|
1445
|
-
contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for 6 Astra, 1M for GPT-5.6). K and M suffixes are accepted.",
|
|
1446
|
-
saveContextWindow: "Save context window",
|
|
1447
|
-
save: "Save",
|
|
1448
|
-
tokens: "tokens",
|
|
1449
|
-
quickQuota: "Show quick usage beside the composer",
|
|
1450
|
-
quickQuotaHint: "Shown only when the current session uses a codex-chatgpt model.",
|
|
1451
|
-
quota: "Usage and limits",
|
|
1452
|
-
quotaIntro: "Data comes from the ChatGPT Codex usage service and refreshes at most once per minute while visible.",
|
|
1453
|
-
refreshQuota: "Refresh usage",
|
|
1454
|
-
refreshing: "Refreshing…",
|
|
1455
|
-
noQuota: "Your plan did not return any displayable limit windows.",
|
|
1456
|
-
quotaSignedOut: "Sign in to view subscription limits.",
|
|
1457
|
-
stale: "Showing the last successfully fetched data.",
|
|
1458
|
-
updated: "Updated",
|
|
1459
|
-
primary: "Primary window",
|
|
1460
|
-
secondary: "Secondary window",
|
|
1461
|
-
limitWindow: "limit",
|
|
1462
|
-
used: "used",
|
|
1463
|
-
remaining: "remaining",
|
|
1464
|
-
available: "Available",
|
|
1465
|
-
unavailable: "Unavailable",
|
|
1466
|
-
unlimited: "Unlimited",
|
|
1467
|
-
credits: "Credits",
|
|
1468
|
-
monthlySpend: "Monthly spend control",
|
|
1469
|
-
resetCredits: "Reset credits",
|
|
1470
|
-
resetCreditExpires: "Expires",
|
|
1471
|
-
useResetCredit: "Use reset credit",
|
|
1472
|
-
usingResetCredit: "Using…",
|
|
1473
|
-
useResetCreditConfirm: "This immediately spends one reset credit and resets eligible Codex limit windows. Continue?",
|
|
1474
|
-
resetCreditUsed: "The reset credit was used and usage data was refreshed.",
|
|
1475
|
-
spendControlReached: "Monthly spend control has been reached; new subscription calls may be limited.",
|
|
1476
|
-
limit: "Limit",
|
|
1477
|
-
exhausted: "Quota exhausted",
|
|
1478
|
-
resets: "Resets",
|
|
1479
|
-
quickQuotaLabel: "Codex left",
|
|
1480
|
-
quickQuotaLoading: "Usage…",
|
|
1481
|
-
imageToolRunning: "Generating image",
|
|
1482
|
-
imageToolDone: "Generated image",
|
|
1483
|
-
imageToolFailed: "Image generation failed",
|
|
1484
|
-
image: "Image",
|
|
1485
|
-
openImage: "Open image",
|
|
1486
|
-
openNamedImage: "Open {name}",
|
|
1487
|
-
imageLoading: "Loading image…",
|
|
1488
|
-
imageLoadFailed: "Image failed to load. Click to retry",
|
|
1489
|
-
imagePreviewClose: "Close",
|
|
1490
|
-
imagePreviewOpenOriginal: "Open original",
|
|
1491
|
-
retry: "Retry",
|
|
1492
|
-
unknown: "Unknown"
|
|
1493
|
-
}
|
|
1494
|
-
};
|
|
1495
|
-
//#endregion
|
|
1496
|
-
//#region src/client/styles.ts
|
|
1497
|
-
const STYLE_ID$1 = "@eddyskywalker/dsh-chatgpt-subscription/main";
|
|
1498
|
-
const CSS = `
|
|
1499
|
-
.dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
1500
|
-
.dsh-codex-page *{box-sizing:border-box}
|
|
1501
|
-
.dsh-codex-title{font-size:15px;font-weight:650;line-height:1.4;margin:0 0 5px}
|
|
1502
|
-
.dsh-codex-intro,.dsh-codex-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}
|
|
1503
|
-
.dsh-codex-group{border-top:0.5px solid var(--dsw-alias-border-l2);min-width:0}
|
|
1504
|
-
.dsh-codex-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}
|
|
1505
|
-
.dsh-codex-grouphead h3{font-size:14px;font-weight:650;margin:0}
|
|
1506
|
-
.dsh-codex-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}
|
|
1507
|
-
.dsh-codex-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}
|
|
1508
|
-
.dsh-codex-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right}
|
|
1509
|
-
.dsh-codex-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}
|
|
1510
|
-
.dsh-codex-button{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}
|
|
1511
|
-
.dsh-codex-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
1512
|
-
.dsh-codex-button:focus-visible,.dsh-codex-link:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
1513
|
-
.dsh-codex-button:disabled{cursor:default;opacity:.5}
|
|
1514
|
-
.dsh-codex-button-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
1515
|
-
.dsh-codex-notice{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}
|
|
1516
|
-
.dsh-codex-error,.dsh-codex-warning,.dsh-codex-success{font-size:12px;line-height:1.5;margin:8px 0 0}
|
|
1517
|
-
.dsh-codex-error{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1518
|
-
.dsh-codex-warning{color:var(--dsw-alias-label-warning,#c77a18)}
|
|
1519
|
-
.dsh-codex-success{color:var(--dsw-alias-label-success,#2e9b62)}
|
|
1520
|
-
.dsh-codex-errorbar{align-items:center;background:color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 9%,transparent);border:0.5px solid color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 28%,transparent);border-radius:7px;color:var(--dsw-alias-label-danger,#d94b4b);display:flex;font-size:13px;gap:12px;justify-content:space-between;padding:10px 12px}
|
|
1521
|
-
.dsh-codex-link{color:var(--dsw-alias-label-link,#3278d4);display:inline-block;font-size:13px;margin-top:8px}
|
|
1522
|
-
.dsh-codex-models-hint{padding-top:10px}
|
|
1523
|
-
.dsh-codex-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
1524
|
-
.dsh-codex-models label{cursor:pointer;display:block;position:relative}
|
|
1525
|
-
.dsh-codex-models input{position:absolute;opacity:0;pointer-events:none}
|
|
1526
|
-
.dsh-codex-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px}
|
|
1527
|
-
.dsh-codex-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary)}
|
|
1528
|
-
.dsh-codex-models input:focus-visible+span{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
1529
|
-
.dsh-codex-models input:disabled+span{cursor:default;opacity:.5}
|
|
1530
|
-
.dsh-codex-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
1531
|
-
.dsh-codex-pref-row strong,.dsh-codex-check strong{display:block;font-size:13px;font-weight:600;line-height:1.35}
|
|
1532
|
-
.dsh-codex-segments{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:inline-flex;flex-wrap:nowrap;gap:3px;padding:3px}
|
|
1533
|
-
.dsh-codex-segments label{cursor:pointer;display:block;margin:0}
|
|
1534
|
-
.dsh-codex-segments input{position:absolute;opacity:0;pointer-events:none}
|
|
1535
|
-
.dsh-codex-segments span,.dsh-codex-segments button{border:0.5px solid transparent;border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font:inherit;font-size:12px;font-weight:500;line-height:1.2;padding:6px 12px;transition:all .15s ease;user-select:none;white-space:nowrap}
|
|
1536
|
-
.dsh-codex-segments button{background:transparent;cursor:pointer}
|
|
1537
|
-
.dsh-codex-segments label:hover span,.dsh-codex-segments button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
1538
|
-
.dsh-codex-segments input:checked+span,.dsh-codex-segments button.active,.dsh-codex-segments button[aria-pressed=true]{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 22%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 60%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600;box-shadow:0 1px 3px rgba(0,0,0,.15)}
|
|
1539
|
-
.dsh-codex-segments input:focus-visible+span,.dsh-codex-segments button:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
1540
|
-
.dsh-codex-segments input:disabled+span,.dsh-codex-segments button:disabled{cursor:default;opacity:.5}
|
|
1541
|
-
.dsh-codex-select,.dsh-codex-capacity-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px}
|
|
1542
|
-
.dsh-codex-select{max-width:210px;min-width:150px}
|
|
1543
|
-
.dsh-codex-context-settings{border-bottom:0.5px solid var(--dsw-alias-border-l2);display:grid;gap:10px;padding:12px 0}
|
|
1544
|
-
.dsh-codex-context-settings>div>strong{font-size:13px;font-weight:600}
|
|
1545
|
-
.dsh-codex-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
|
|
1546
|
-
.dsh-codex-proxy-control{align-items:center;display:flex;gap:8px;width:100%}
|
|
1547
|
-
.dsh-codex-proxy-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);flex:1;font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;min-width:220px;padding:7px 10px;text-align:left}
|
|
1548
|
-
.dsh-codex-proxy-status{align-items:center;color:var(--dsw-alias-label-secondary);display:flex;flex-wrap:wrap;font-size:12px;gap:6px;margin:6px 0 0}
|
|
1549
|
-
.dsh-codex-proxy-tag{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 18%,transparent);border:0.5px solid color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 45%,transparent);border-radius:4px;color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:2px 6px}
|
|
1550
|
-
.dsh-codex-capacity-control{align-items:center;display:flex;gap:7px}
|
|
1551
|
-
.dsh-codex-capacity-control input{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;text-align:right;width:90px}
|
|
1552
|
-
.dsh-codex-capacity-control input[type=number]{width:110px}
|
|
1553
|
-
.dsh-codex-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
|
|
1554
|
-
.dsh-codex-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
|
|
1555
|
-
.dsh-codex-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
1556
|
-
.dsh-codex-context-save:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
1557
|
-
.dsh-codex-context-save:disabled{cursor:default;opacity:.45}
|
|
1558
|
-
.dsh-codex-check{align-items:flex-start;border-bottom:0.5px solid var(--dsw-alias-border-l2);cursor:pointer;display:flex;gap:10px;padding:12px 0}
|
|
1559
|
-
.dsh-codex-check input{flex:none;margin-top:2px}
|
|
1560
|
-
.dsh-codex-check small{color:var(--dsw-alias-label-secondary);display:block;font-size:12px;line-height:1.45;margin-top:2px}
|
|
1561
|
-
.dsh-codex-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
1562
|
-
.dsh-codex-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between}
|
|
1563
|
-
.dsh-codex-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
1564
|
-
.dsh-codex-quota-fact{align-items:flex-start;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;font-size:12px;gap:12px;justify-content:space-between;line-height:1.45;padding:10px 0}
|
|
1565
|
-
.dsh-codex-quota-fact span{color:var(--dsw-alias-label-secondary);flex:none}
|
|
1566
|
-
.dsh-codex-quota-fact strong{font-weight:600;min-width:0;overflow-wrap:anywhere;text-align:right}
|
|
1567
|
-
.dsh-codex-reset-credits{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;padding:10px 0}
|
|
1568
|
-
.dsh-codex-reset-credits-info{display:grid;font-size:12px;gap:2px;grid-template-columns:auto auto}
|
|
1569
|
-
.dsh-codex-reset-credits-info>span{color:var(--dsw-alias-label-secondary)}
|
|
1570
|
-
.dsh-codex-reset-credits-info>strong{font-weight:650;text-align:right}
|
|
1571
|
-
.dsh-codex-reset-credits-info>small{color:var(--dsw-alias-label-tertiary);font-size:11px;grid-column:1/-1}
|
|
1572
|
-
.dsh-codex-meter-wrap{margin-top:13px}
|
|
1573
|
-
.dsh-codex-meter-label,.dsh-codex-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
1574
|
-
.dsh-codex-meter-label{font-size:12px;margin-bottom:6px}
|
|
1575
|
-
.dsh-codex-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}
|
|
1576
|
-
.dsh-codex-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;corner-shape:round;height:7px;overflow:hidden;width:100%}
|
|
1577
|
-
.dsh-codex-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}
|
|
1578
|
-
.dsh-codex-meter-warning>span{background:var(--dsw-alias-label-warning,#d58a24)}
|
|
1579
|
-
.dsh-codex-meter-danger>span{background:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1580
|
-
.dsh-codex-empty{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}
|
|
1581
|
-
.dsh-codex-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}
|
|
1582
|
-
.dsh-codex-skeleton{display:grid;gap:9px;padding-top:10px}
|
|
1583
|
-
.dsh-codex-skeleton span{animation:dsh-codex-pulse 1.4s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border-radius:5px;height:42px}
|
|
1584
|
-
.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}
|
|
1585
|
-
.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}
|
|
1586
|
-
.dsh-codex-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-secondary);display:inline-flex;font-size:11px;gap:6px;height:28px;line-height:1;max-width:160px;padding:0 9px;white-space:nowrap}
|
|
1587
|
-
.dsh-codex-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
1588
|
-
.dsh-codex-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
1589
|
-
.dsh-codex-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1590
|
-
.dsh-codex-image-tool{border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:flex;flex-direction:column;gap:8px;margin:4px 0 4px 4px;max-width:520px;padding:10px 12px}
|
|
1591
|
-
.dsh-codex-image-tool-head{align-items:center;display:flex;font-size:13px;gap:8px;min-width:0}
|
|
1592
|
-
.dsh-codex-image-dot{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:50%;corner-shape:round;display:inline-block;flex:none;height:8px;width:8px}
|
|
1593
|
-
.dsh-codex-image-tool[data-state=error] .dsh-codex-image-dot{background:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1594
|
-
.dsh-codex-image-title{font-weight:600}
|
|
1595
|
-
.dsh-codex-image-summary{color:var(--dsw-alias-label-tertiary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1596
|
-
.dsh-codex-image-grid{display:flex;flex-wrap:wrap;gap:8px}
|
|
1597
|
-
.dsh-codex-image-preview{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:block;max-height:260px;max-width:min(100%,360px);object-fit:contain}
|
|
1598
|
-
.dsh-codex-image-loading,.dsh-codex-image-failed{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-tertiary);display:inline-flex;font-size:12px;line-height:1.4;padding:18px 20px}
|
|
1599
|
-
.dsh-codex-image-failed{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1600
|
-
@keyframes dsh-codex-pulse{0%,100%{opacity:.45}50%{opacity:.85}}
|
|
1601
|
-
@media(max-width:560px){.dsh-codex-row,.dsh-codex-pref-row,.dsh-codex-quota-fact,.dsh-codex-reset-credits{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value,.dsh-codex-quota-fact strong{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}.dsh-codex-segments{width:100%}.dsh-codex-select{max-width:none;width:100%}.dsh-codex-context-row{align-items:flex-start;flex-direction:column;gap:5px}.dsh-codex-segments label{flex:1}.dsh-codex-segments span{text-align:center}.dsh-codex-image-tool{max-width:100%;margin-left:0}}
|
|
1602
|
-
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
1603
|
-
`;
|
|
1604
|
-
function installStyles() {
|
|
1605
|
-
if (document.querySelector(`style[data-plugin-css="${STYLE_ID$1}"]`) !== null) return () => void 0;
|
|
1606
|
-
const element = document.createElement("style");
|
|
1607
|
-
element.dataset.plugin = "@eddyskywalker/dsh-chatgpt-subscription";
|
|
1608
|
-
element.dataset.pluginCss = STYLE_ID$1;
|
|
1609
|
-
element.textContent = CSS;
|
|
1610
|
-
document.head.appendChild(element);
|
|
1611
|
-
return () => element.remove();
|
|
1612
|
-
}
|
|
1613
|
-
//#endregion
|
|
1614
1243
|
//#region src/client/antigravity/locales.ts
|
|
1615
1244
|
const NS_ANTIGRAVITY = "dsh-antigravity";
|
|
1616
|
-
const zh = {
|
|
1245
|
+
const zh$3 = {
|
|
1617
1246
|
title: "Antigravity",
|
|
1618
1247
|
pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
|
|
1619
1248
|
account: "已登录",
|
|
@@ -1664,7 +1293,7 @@ window.__ModuleLoader__.load({
|
|
|
1664
1293
|
loginFailed: "登录失败",
|
|
1665
1294
|
tokens: "tokens"
|
|
1666
1295
|
};
|
|
1667
|
-
const en = {
|
|
1296
|
+
const en$3 = {
|
|
1668
1297
|
title: "Antigravity",
|
|
1669
1298
|
pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
|
|
1670
1299
|
account: "Signed in",
|
|
@@ -1715,17 +1344,17 @@ window.__ModuleLoader__.load({
|
|
|
1715
1344
|
loginFailed: "Login failed",
|
|
1716
1345
|
tokens: "tokens"
|
|
1717
1346
|
};
|
|
1718
|
-
const dictionaries = {
|
|
1719
|
-
zh,
|
|
1720
|
-
"zh-CN": zh,
|
|
1721
|
-
en,
|
|
1722
|
-
"en-US": en
|
|
1347
|
+
const dictionaries$3 = {
|
|
1348
|
+
zh: zh$3,
|
|
1349
|
+
"zh-CN": zh$3,
|
|
1350
|
+
en: en$3,
|
|
1351
|
+
"en-US": en$3
|
|
1723
1352
|
};
|
|
1724
1353
|
//#endregion
|
|
1725
1354
|
//#region src/client/antigravity/AntigravitySection.tsx
|
|
1726
|
-
const API$
|
|
1727
|
-
async function fetchApi$
|
|
1728
|
-
const res = await fetch(`${API$
|
|
1355
|
+
const API$5 = "/antigravity/api";
|
|
1356
|
+
async function fetchApi$5(path, options) {
|
|
1357
|
+
const res = await fetch(`${API$5}${path}`, {
|
|
1729
1358
|
...options,
|
|
1730
1359
|
headers: {
|
|
1731
1360
|
"Content-Type": "application/json",
|
|
@@ -1736,14 +1365,14 @@ window.__ModuleLoader__.load({
|
|
|
1736
1365
|
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
1737
1366
|
return json.value;
|
|
1738
1367
|
}
|
|
1739
|
-
function parsePositiveCapacity(value) {
|
|
1368
|
+
function parsePositiveCapacity$2(value) {
|
|
1740
1369
|
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
1741
1370
|
if (matched === null) return null;
|
|
1742
1371
|
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
1743
1372
|
const parsed = Number(matched[1]) * multiplier;
|
|
1744
1373
|
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
1745
1374
|
}
|
|
1746
|
-
function formatCapacity(value) {
|
|
1375
|
+
function formatCapacity$2(value) {
|
|
1747
1376
|
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
1748
1377
|
if (value % 1e3 === 0) return `${value / 1e3}K`;
|
|
1749
1378
|
return String(value);
|
|
@@ -1759,7 +1388,7 @@ window.__ModuleLoader__.load({
|
|
|
1759
1388
|
if (hours > 0) return `${hours}h ${mins % 60}m`;
|
|
1760
1389
|
return `${mins}m`;
|
|
1761
1390
|
}
|
|
1762
|
-
function formatDate(ms) {
|
|
1391
|
+
function formatDate$2(ms) {
|
|
1763
1392
|
if (!ms || ms <= 0) return "—";
|
|
1764
1393
|
try {
|
|
1765
1394
|
return new Intl.DateTimeFormat(void 0, {
|
|
@@ -1779,7 +1408,7 @@ window.__ModuleLoader__.load({
|
|
|
1779
1408
|
const [loginProgress, setLoginProgress] = (0, react.useState)(null);
|
|
1780
1409
|
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
1781
1410
|
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
1782
|
-
const t = zh;
|
|
1411
|
+
const t = zh$3;
|
|
1783
1412
|
const notifyChange = (0, react.useCallback)(() => {
|
|
1784
1413
|
onModelChange?.();
|
|
1785
1414
|
loadModelDirectory?.();
|
|
@@ -1790,12 +1419,12 @@ window.__ModuleLoader__.load({
|
|
|
1790
1419
|
setValidationUrl(null);
|
|
1791
1420
|
}
|
|
1792
1421
|
try {
|
|
1793
|
-
const data = await fetchApi$
|
|
1422
|
+
const data = await fetchApi$5("/status");
|
|
1794
1423
|
setStatus(data);
|
|
1795
1424
|
const drafts = {};
|
|
1796
1425
|
for (const m of data.models) {
|
|
1797
1426
|
const val = data.contextWindowOverrides[m.id] || m.defaultContextWindow;
|
|
1798
|
-
drafts[m.id] = formatCapacity(val);
|
|
1427
|
+
drafts[m.id] = formatCapacity$2(val);
|
|
1799
1428
|
}
|
|
1800
1429
|
setContextDrafts(drafts);
|
|
1801
1430
|
} catch (err) {
|
|
@@ -1822,11 +1451,11 @@ window.__ModuleLoader__.load({
|
|
|
1822
1451
|
setError(null);
|
|
1823
1452
|
setValidationUrl(null);
|
|
1824
1453
|
setLoginProgress(null);
|
|
1825
|
-
const flow = await fetchApi$
|
|
1454
|
+
const flow = await fetchApi$5("/login", { method: "POST" });
|
|
1826
1455
|
if (flow.authUrl) window.open(flow.authUrl, "_blank");
|
|
1827
1456
|
const pollTimer = setInterval(async () => {
|
|
1828
1457
|
try {
|
|
1829
|
-
const pollStatus = await fetchApi$
|
|
1458
|
+
const pollStatus = await fetchApi$5("/login/status");
|
|
1830
1459
|
if (pollStatus.progress) setLoginProgress(pollStatus.progress);
|
|
1831
1460
|
if (pollStatus.status === "complete") {
|
|
1832
1461
|
clearInterval(pollTimer);
|
|
@@ -1858,7 +1487,7 @@ window.__ModuleLoader__.load({
|
|
|
1858
1487
|
try {
|
|
1859
1488
|
setBusy("quota");
|
|
1860
1489
|
setError(null);
|
|
1861
|
-
const updated = await fetchApi$
|
|
1490
|
+
const updated = await fetchApi$5("/quota", { method: "POST" });
|
|
1862
1491
|
setStatus(updated);
|
|
1863
1492
|
} catch (err) {
|
|
1864
1493
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -1870,7 +1499,7 @@ window.__ModuleLoader__.load({
|
|
|
1870
1499
|
try {
|
|
1871
1500
|
setBusy("logout");
|
|
1872
1501
|
setError(null);
|
|
1873
|
-
const updated = await fetchApi$
|
|
1502
|
+
const updated = await fetchApi$5("/logout", { method: "POST" });
|
|
1874
1503
|
setStatus(updated);
|
|
1875
1504
|
notifyChange();
|
|
1876
1505
|
} catch (err) {
|
|
@@ -1885,7 +1514,7 @@ window.__ModuleLoader__.load({
|
|
|
1885
1514
|
const nextEnabled = checked ? [.../* @__PURE__ */ new Set([...currentEnabled, modelId])] : currentEnabled.filter((id) => id !== modelId);
|
|
1886
1515
|
if (nextEnabled.length === 0) return;
|
|
1887
1516
|
try {
|
|
1888
|
-
const updated = await fetchApi$
|
|
1517
|
+
const updated = await fetchApi$5("/models", {
|
|
1889
1518
|
method: "POST",
|
|
1890
1519
|
body: JSON.stringify({ enabledModelIds: nextEnabled })
|
|
1891
1520
|
});
|
|
@@ -1899,7 +1528,7 @@ window.__ModuleLoader__.load({
|
|
|
1899
1528
|
if (!status) return;
|
|
1900
1529
|
const nextEnabled = selectAll ? status.models.map((m) => m.id) : [status.models[0].id];
|
|
1901
1530
|
try {
|
|
1902
|
-
const updated = await fetchApi$
|
|
1531
|
+
const updated = await fetchApi$5("/models", {
|
|
1903
1532
|
method: "POST",
|
|
1904
1533
|
body: JSON.stringify({ enabledModelIds: nextEnabled })
|
|
1905
1534
|
});
|
|
@@ -1911,7 +1540,7 @@ window.__ModuleLoader__.load({
|
|
|
1911
1540
|
};
|
|
1912
1541
|
const handleUpdateEffort = async (effort) => {
|
|
1913
1542
|
try {
|
|
1914
|
-
const updated = await fetchApi$
|
|
1543
|
+
const updated = await fetchApi$5("/settings", {
|
|
1915
1544
|
method: "POST",
|
|
1916
1545
|
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
1917
1546
|
});
|
|
@@ -1923,7 +1552,7 @@ window.__ModuleLoader__.load({
|
|
|
1923
1552
|
};
|
|
1924
1553
|
const handleSaveContextWindow = async (modelId) => {
|
|
1925
1554
|
const raw = contextDrafts[modelId] || "";
|
|
1926
|
-
const parsed = parsePositiveCapacity(raw);
|
|
1555
|
+
const parsed = parsePositiveCapacity$2(raw);
|
|
1927
1556
|
if (parsed === null) {
|
|
1928
1557
|
setError(`无效的上下文容量值: ${raw}`);
|
|
1929
1558
|
return;
|
|
@@ -1931,14 +1560,14 @@ window.__ModuleLoader__.load({
|
|
|
1931
1560
|
try {
|
|
1932
1561
|
setSavingModel(modelId);
|
|
1933
1562
|
setError(null);
|
|
1934
|
-
const updated = await fetchApi$
|
|
1563
|
+
const updated = await fetchApi$5("/settings", {
|
|
1935
1564
|
method: "POST",
|
|
1936
1565
|
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
1937
1566
|
});
|
|
1938
1567
|
setStatus(updated);
|
|
1939
1568
|
setContextDrafts((prev) => ({
|
|
1940
1569
|
...prev,
|
|
1941
|
-
[modelId]: formatCapacity(parsed)
|
|
1570
|
+
[modelId]: formatCapacity$2(parsed)
|
|
1942
1571
|
}));
|
|
1943
1572
|
notifyChange();
|
|
1944
1573
|
} catch (err) {
|
|
@@ -2005,7 +1634,7 @@ window.__ModuleLoader__.load({
|
|
|
2005
1634
|
children: t.expires
|
|
2006
1635
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2007
1636
|
className: "dsha-value",
|
|
2008
|
-
children: formatDate(Date.now() + 864e5 * 30)
|
|
1637
|
+
children: formatDate$2(Date.now() + 864e5 * 30)
|
|
2009
1638
|
})]
|
|
2010
1639
|
})
|
|
2011
1640
|
] }),
|
|
@@ -2279,78 +1908,174 @@ window.__ModuleLoader__.load({
|
|
|
2279
1908
|
});
|
|
2280
1909
|
}
|
|
2281
1910
|
//#endregion
|
|
2282
|
-
//#region src/
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
.dsha-group:first-of-type{border-top:0}
|
|
2293
|
-
.dsha-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}
|
|
2294
|
-
.dsha-grouphead h3{font-size:14px;font-weight:650;margin:0;color:var(--dsw-alias-label-primary)}
|
|
2295
|
-
.dsha-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}
|
|
2296
|
-
.dsha-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}
|
|
2297
|
-
.dsha-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--dsw-alias-label-primary)}
|
|
2298
|
-
.dsha-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}
|
|
2299
|
-
.dsha-btn{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}
|
|
2300
|
-
.dsha-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
2301
|
-
.dsha-btn:disabled{cursor:default;opacity:.5}
|
|
2302
|
-
.dsha-btn-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
2303
|
-
.dsha-btn-primary:hover:not(:disabled){opacity:.9}
|
|
2304
|
-
.dsha-notice{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}
|
|
2305
|
-
.dsha-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}
|
|
2306
|
-
.dsha-models-hint{padding-top:10px}
|
|
2307
|
-
.dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
2308
|
-
.dsha-models label{cursor:pointer;display:block;position:relative}
|
|
2309
|
-
.dsha-models input{position:absolute;opacity:0;pointer-events:none}
|
|
2310
|
-
.dsha-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
|
|
2311
|
-
.dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
|
|
2312
|
-
.dsha-models input:disabled+span{cursor:default;opacity:.5}
|
|
2313
|
-
.dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
2314
|
-
.dsha-pref-row strong{display:block;font-size:13px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary)}
|
|
2315
|
-
.dsha-select{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px;max-width:220px;min-width:160px}
|
|
2316
|
-
.dsha-context-settings{border-bottom:0.5px solid var(--dsw-alias-border-l2);display:grid;gap:10px;padding:12px 0}
|
|
2317
|
-
.dsha-context-settings>div>strong{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
2318
|
-
.dsha-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
|
|
2319
|
-
.dsha-capacity-control{align-items:center;display:flex;gap:7px}
|
|
2320
|
-
.dsha-capacity-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;padding:7px 9px;text-align:right;width:90px}
|
|
2321
|
-
.dsha-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
|
|
2322
|
-
.dsha-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
|
|
2323
|
-
.dsha-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
2324
|
-
.dsha-context-save:disabled{cursor:default;opacity:.45}
|
|
2325
|
-
.dsha-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
2326
|
-
.dsha-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between;color:var(--dsw-alias-label-primary);font-weight:650}
|
|
2327
|
-
.dsha-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
2328
|
-
.dsha-meter-wrap{margin-top:13px}
|
|
2329
|
-
.dsha-meter-label,.dsha-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
2330
|
-
.dsha-meter-label{font-size:12px;margin-bottom:6px;color:var(--dsw-alias-label-primary)}
|
|
2331
|
-
.dsha-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}
|
|
2332
|
-
.dsha-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;corner-shape:round;height:7px;overflow:hidden;width:100%}
|
|
2333
|
-
.dsha-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}
|
|
2334
|
-
.dsha-meter-green>span{background:var(--dsw-alias-label-success,#10b981)}
|
|
2335
|
-
.dsha-meter-cyan>span{background:#06b6d4}
|
|
2336
|
-
.dsha-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}
|
|
2337
|
-
.dsha-mini-btn{border:0;background:transparent;color:var(--dsw-alias-label-link,#397ee8);font-size:12px;line-height:18px;cursor:pointer;padding:0;margin-left:8px}
|
|
2338
|
-
.dsha-mini-btn:hover{text-decoration:underline}
|
|
2339
|
-
.dsha-empty{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}
|
|
2340
|
-
.dsha-error{color:var(--dsw-alias-label-danger,#d94b4b);font-size:12px;margin:8px 0 0}
|
|
2341
|
-
.dsha-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-secondary);cursor:pointer;display:inline-flex;font-size:11px;gap:6px;height:28px;line-height:1;max-width:160px;padding:0 9px;white-space:nowrap;user-select:none;transition:all .15s ease}
|
|
2342
|
-
.dsha-composer-quota:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l1,var(--dsw-alias-border-l2))}
|
|
2343
|
-
.dsha-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
2344
|
-
.dsha-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
2345
|
-
.dsha-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
2346
|
-
`;
|
|
2347
|
-
document.head.append(style);
|
|
2348
|
-
}
|
|
1911
|
+
//#region src/shared/command-code-contracts.ts
|
|
1912
|
+
/** Every level, in escalating order; the settings card renders exactly these. */
|
|
1913
|
+
const COMMAND_CODE_REASONING_EFFORTS = [
|
|
1914
|
+
"minimal",
|
|
1915
|
+
"low",
|
|
1916
|
+
"medium",
|
|
1917
|
+
"high",
|
|
1918
|
+
"xhigh",
|
|
1919
|
+
"max"
|
|
1920
|
+
];
|
|
2349
1921
|
//#endregion
|
|
2350
|
-
//#region src/client/
|
|
2351
|
-
const
|
|
2352
|
-
|
|
2353
|
-
|
|
1922
|
+
//#region src/client/command-code/locales.ts
|
|
1923
|
+
const NS_COMMAND_CODE = "dsh-command-code";
|
|
1924
|
+
const zh$2 = {
|
|
1925
|
+
title: "Command Code",
|
|
1926
|
+
pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
|
|
1927
|
+
account: "账号",
|
|
1928
|
+
signedIn: "已登录",
|
|
1929
|
+
signedOut: "未登录",
|
|
1930
|
+
keyName: "密钥名称",
|
|
1931
|
+
organization: "组织",
|
|
1932
|
+
plan: "套餐",
|
|
1933
|
+
planUnknown: "—",
|
|
1934
|
+
subscription: "订阅状态",
|
|
1935
|
+
renews: "续费于",
|
|
1936
|
+
authenticatedAt: "登录时间",
|
|
1937
|
+
storage: "凭据存储",
|
|
1938
|
+
storageNotice: "API Key 由 Host 保存于本地安全存储 ($DSH_HOME/storages/command-code-credentials.json),不会进入浏览器。",
|
|
1939
|
+
signIn: "浏览器登录",
|
|
1940
|
+
signInAgain: "重新登录",
|
|
1941
|
+
signingIn: "登录中...",
|
|
1942
|
+
signOut: "注销",
|
|
1943
|
+
cancelSignIn: "取消登录",
|
|
1944
|
+
openSignInPage: "打开登录页面",
|
|
1945
|
+
apiKeySection: "手动填写 API Key",
|
|
1946
|
+
apiKeyHint: "在 Command Code Studio 创建 API Key 后粘贴到此处;浏览器登录不可用时使用。",
|
|
1947
|
+
apiKeyPlaceholder: "粘贴 Command Code API Key",
|
|
1948
|
+
apiKeySave: "保存并验证",
|
|
1949
|
+
apiKeySaving: "验证中...",
|
|
1950
|
+
apiKeySaved: "已保存",
|
|
1951
|
+
connection: "连接",
|
|
1952
|
+
provider: "Provider",
|
|
1953
|
+
providerValue: "Command Code · command-code",
|
|
1954
|
+
connectionState: "连接状态",
|
|
1955
|
+
connected: "已连接",
|
|
1956
|
+
untested: "未测试",
|
|
1957
|
+
testConnection: "测试连接",
|
|
1958
|
+
testingConnection: "测试中...",
|
|
1959
|
+
routeOwned: "模型路由由本插件提供",
|
|
1960
|
+
routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
|
|
1961
|
+
modelsSection: "模型",
|
|
1962
|
+
modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;至少保留一个。",
|
|
1963
|
+
refreshCatalog: "刷新模型目录",
|
|
1964
|
+
refreshingCatalog: "刷新中...",
|
|
1965
|
+
selectAll: "全选",
|
|
1966
|
+
unselectAll: "全不选",
|
|
1967
|
+
wireAnthropic: "Anthropic",
|
|
1968
|
+
wireOpenai: "OpenAI",
|
|
1969
|
+
enhanced: "增强功能",
|
|
1970
|
+
defaultReasoningEffort: "默认思考深度",
|
|
1971
|
+
defaultReasoningEffortHint: "控制支持推理的模型在未单独指定时的思考强度。Anthropic 模型会映射为 thinking 预算。",
|
|
1972
|
+
defaultEffortAuto: "使用 Provider 默认值",
|
|
1973
|
+
contextWindowSection: "模型上下文窗口",
|
|
1974
|
+
contextWindowHint: "默认取 Command Code 模型目录的 context length;可覆盖为自定义容量,该值用于 DSH 的压缩与溢出判断,可输入 1M、512K、200K 等容量。",
|
|
1975
|
+
save: "保存",
|
|
1976
|
+
saved: "已保存",
|
|
1977
|
+
saving: "保存中...",
|
|
1978
|
+
quotaSection: "用量与配额",
|
|
1979
|
+
quotaDesc: "数据来自 Command Code 账户接口,页面可见时最多每 60 秒刷新一次。",
|
|
1980
|
+
refreshQuota: "刷新用量",
|
|
1981
|
+
refreshingQuota: "刷新中...",
|
|
1982
|
+
quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
|
|
1983
|
+
quotaCredits: "剩余额度",
|
|
1984
|
+
quotaUnlimited: "不限量",
|
|
1985
|
+
updatedAt: "更新时间:{time}",
|
|
1986
|
+
loading: "加载中...",
|
|
1987
|
+
loginFailed: "登录失败",
|
|
1988
|
+
tokens: "tokens"
|
|
1989
|
+
};
|
|
1990
|
+
const en$2 = {
|
|
1991
|
+
title: "Command Code",
|
|
1992
|
+
pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
|
|
1993
|
+
account: "Account",
|
|
1994
|
+
signedIn: "Signed in",
|
|
1995
|
+
signedOut: "Not signed in",
|
|
1996
|
+
keyName: "Key name",
|
|
1997
|
+
organization: "Organization",
|
|
1998
|
+
plan: "Plan",
|
|
1999
|
+
planUnknown: "—",
|
|
2000
|
+
subscription: "Subscription",
|
|
2001
|
+
renews: "renews",
|
|
2002
|
+
authenticatedAt: "Signed in at",
|
|
2003
|
+
storage: "Credential storage",
|
|
2004
|
+
storageNotice: "The API key is stored locally by the Host ($DSH_HOME/storages/command-code-credentials.json) and never reaches the browser.",
|
|
2005
|
+
signIn: "Sign in with browser",
|
|
2006
|
+
signInAgain: "Sign in again",
|
|
2007
|
+
signingIn: "Signing in...",
|
|
2008
|
+
signOut: "Sign out",
|
|
2009
|
+
cancelSignIn: "Cancel",
|
|
2010
|
+
openSignInPage: "Open the sign-in page",
|
|
2011
|
+
apiKeySection: "Paste an API key",
|
|
2012
|
+
apiKeyHint: "Create a key in Command Code Studio and paste it here; use this when the browser flow is unavailable.",
|
|
2013
|
+
apiKeyPlaceholder: "Command Code API key",
|
|
2014
|
+
apiKeySave: "Save and verify",
|
|
2015
|
+
apiKeySaving: "Verifying...",
|
|
2016
|
+
apiKeySaved: "Saved",
|
|
2017
|
+
connection: "Connection",
|
|
2018
|
+
provider: "Provider",
|
|
2019
|
+
providerValue: "Command Code · command-code",
|
|
2020
|
+
connectionState: "Connection state",
|
|
2021
|
+
connected: "Connected",
|
|
2022
|
+
untested: "Untested",
|
|
2023
|
+
testConnection: "Test connection",
|
|
2024
|
+
testingConnection: "Testing...",
|
|
2025
|
+
routeOwned: "This plugin serves the model route",
|
|
2026
|
+
routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
|
|
2027
|
+
modelsSection: "Models",
|
|
2028
|
+
modelsHint: "Checked models appear in the DSH conversation model list; keep at least one.",
|
|
2029
|
+
refreshCatalog: "Refresh catalog",
|
|
2030
|
+
refreshingCatalog: "Refreshing...",
|
|
2031
|
+
selectAll: "Select all",
|
|
2032
|
+
unselectAll: "Deselect all",
|
|
2033
|
+
wireAnthropic: "Anthropic",
|
|
2034
|
+
wireOpenai: "OpenAI",
|
|
2035
|
+
enhanced: "Enhanced features",
|
|
2036
|
+
defaultReasoningEffort: "Default reasoning effort",
|
|
2037
|
+
defaultReasoningEffortHint: "Reasoning effort for models that support it when the conversation does not specify one. Anthropic models map it to a thinking budget.",
|
|
2038
|
+
defaultEffortAuto: "Use provider default",
|
|
2039
|
+
contextWindowSection: "Model context window",
|
|
2040
|
+
contextWindowHint: "Defaults to the context length in the Command Code catalog; override it with the capacity DSH should use for compaction and overflow decisions (e.g., 1M, 512K, 200K).",
|
|
2041
|
+
save: "Save",
|
|
2042
|
+
saved: "Saved",
|
|
2043
|
+
saving: "Saving...",
|
|
2044
|
+
quotaSection: "Usage & quota",
|
|
2045
|
+
quotaDesc: "Read from the Command Code account endpoints; refreshes at most once every 60 seconds while visible.",
|
|
2046
|
+
refreshQuota: "Refresh quota",
|
|
2047
|
+
refreshingQuota: "Refreshing...",
|
|
2048
|
+
quotaEmpty: "No quota data yet — use “Refresh quota” to retry.",
|
|
2049
|
+
quotaCredits: "Remaining credits",
|
|
2050
|
+
quotaUnlimited: "Unlimited",
|
|
2051
|
+
updatedAt: "Updated at: {time}",
|
|
2052
|
+
loading: "Loading...",
|
|
2053
|
+
loginFailed: "Sign-in failed",
|
|
2054
|
+
tokens: "tokens"
|
|
2055
|
+
};
|
|
2056
|
+
const dictionaries$2 = {
|
|
2057
|
+
zh: zh$2,
|
|
2058
|
+
"zh-CN": zh$2,
|
|
2059
|
+
en: en$2,
|
|
2060
|
+
"en-US": en$2
|
|
2061
|
+
};
|
|
2062
|
+
//#endregion
|
|
2063
|
+
//#region src/client/command-code/CommandCodeSection.tsx
|
|
2064
|
+
/**
|
|
2065
|
+
* Display label per reasoning level. The locale dictionary only accepts flat
|
|
2066
|
+
* string values, so this nested table lives with the control that renders it.
|
|
2067
|
+
*/
|
|
2068
|
+
const EFFORT_LABELS = {
|
|
2069
|
+
minimal: "Minimal",
|
|
2070
|
+
low: "Low",
|
|
2071
|
+
medium: "Medium",
|
|
2072
|
+
high: "High",
|
|
2073
|
+
xhigh: "X-High",
|
|
2074
|
+
max: "Max"
|
|
2075
|
+
};
|
|
2076
|
+
const API$4 = "/command-code/api";
|
|
2077
|
+
async function fetchApi$4(path, options) {
|
|
2078
|
+
const res = await fetch(`${API$4}${path}`, {
|
|
2354
2079
|
...options,
|
|
2355
2080
|
headers: {
|
|
2356
2081
|
"Content-Type": "application/json",
|
|
@@ -2361,10 +2086,2246 @@ window.__ModuleLoader__.load({
|
|
|
2361
2086
|
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
2362
2087
|
return json.value;
|
|
2363
2088
|
}
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
const
|
|
2367
|
-
|
|
2089
|
+
/** Parse "1M", "512K", "200000" into a positive integer token count. */
|
|
2090
|
+
function parsePositiveCapacity$1(value) {
|
|
2091
|
+
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
2092
|
+
if (matched === null) return null;
|
|
2093
|
+
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
2094
|
+
const parsed = Number(matched[1]) * multiplier;
|
|
2095
|
+
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
2096
|
+
}
|
|
2097
|
+
function formatCapacity$1(value) {
|
|
2098
|
+
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
2099
|
+
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
2100
|
+
return String(value);
|
|
2101
|
+
}
|
|
2102
|
+
function formatDate$1(ms) {
|
|
2103
|
+
if (ms === void 0 || ms === null || ms <= 0) return "—";
|
|
2104
|
+
try {
|
|
2105
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
2106
|
+
dateStyle: "medium",
|
|
2107
|
+
timeStyle: "short"
|
|
2108
|
+
}).format(ms);
|
|
2109
|
+
} catch {
|
|
2110
|
+
return "—";
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
function formatReset$1(resetsAt) {
|
|
2114
|
+
if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
|
|
2115
|
+
const diff = resetsAt - Date.now();
|
|
2116
|
+
if (diff <= 0) return "now";
|
|
2117
|
+
const mins = Math.floor(diff / 6e4);
|
|
2118
|
+
const hours = Math.floor(mins / 60);
|
|
2119
|
+
const days = Math.floor(hours / 24);
|
|
2120
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
2121
|
+
if (hours > 0) return `${hours}h ${mins % 60}m`;
|
|
2122
|
+
return `${mins}m`;
|
|
2123
|
+
}
|
|
2124
|
+
function CommandCodeSection({ onModelChange, loadModelDirectory }) {
|
|
2125
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
2126
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
2127
|
+
const [busy, setBusy] = (0, react.useState)(null);
|
|
2128
|
+
const [error, setError] = (0, react.useState)(null);
|
|
2129
|
+
const [loginProgress, setLoginProgress] = (0, react.useState)(null);
|
|
2130
|
+
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
2131
|
+
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
2132
|
+
const [apiKey, setApiKey] = (0, react.useState)("");
|
|
2133
|
+
const t = zh$2;
|
|
2134
|
+
const notifyChange = (0, react.useCallback)(() => {
|
|
2135
|
+
onModelChange?.();
|
|
2136
|
+
loadModelDirectory?.();
|
|
2137
|
+
}, [onModelChange, loadModelDirectory]);
|
|
2138
|
+
const loadStatus = (0, react.useCallback)(async (quiet = false) => {
|
|
2139
|
+
if (!quiet) setError(null);
|
|
2140
|
+
try {
|
|
2141
|
+
const data = await fetchApi$4("/status");
|
|
2142
|
+
setStatus(data);
|
|
2143
|
+
const drafts = {};
|
|
2144
|
+
for (const model of data.models) drafts[model.id] = formatCapacity$1(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
2145
|
+
setContextDrafts(drafts);
|
|
2146
|
+
} catch (err) {
|
|
2147
|
+
if (!quiet) setError(err instanceof Error ? err.message : String(err));
|
|
2148
|
+
} finally {
|
|
2149
|
+
setLoading(false);
|
|
2150
|
+
}
|
|
2151
|
+
}, []);
|
|
2152
|
+
(0, react.useEffect)(() => {
|
|
2153
|
+
loadStatus();
|
|
2154
|
+
const refreshWhenVisible = () => {
|
|
2155
|
+
if (document.visibilityState === "visible") loadStatus(true);
|
|
2156
|
+
};
|
|
2157
|
+
document.addEventListener("visibilitychange", refreshWhenVisible);
|
|
2158
|
+
const timer = window.setInterval(refreshWhenVisible, 6e4);
|
|
2159
|
+
return () => {
|
|
2160
|
+
window.clearInterval(timer);
|
|
2161
|
+
document.removeEventListener("visibilitychange", refreshWhenVisible);
|
|
2162
|
+
};
|
|
2163
|
+
}, [loadStatus]);
|
|
2164
|
+
const handleLogin = async () => {
|
|
2165
|
+
try {
|
|
2166
|
+
setBusy("login");
|
|
2167
|
+
setError(null);
|
|
2168
|
+
setLoginProgress(null);
|
|
2169
|
+
const flow = await fetchApi$4("/login", { method: "POST" });
|
|
2170
|
+
if (flow.authUrl) window.open(flow.authUrl, "_blank");
|
|
2171
|
+
const pollTimer = window.setInterval(() => {
|
|
2172
|
+
(async () => {
|
|
2173
|
+
try {
|
|
2174
|
+
const poll = await fetchApi$4("/login/status");
|
|
2175
|
+
if (poll.progress) setLoginProgress(poll.progress);
|
|
2176
|
+
if (poll.status === "complete") {
|
|
2177
|
+
window.clearInterval(pollTimer);
|
|
2178
|
+
setBusy(null);
|
|
2179
|
+
setLoginProgress(null);
|
|
2180
|
+
await loadStatus();
|
|
2181
|
+
notifyChange();
|
|
2182
|
+
} else if (poll.status === "error") {
|
|
2183
|
+
window.clearInterval(pollTimer);
|
|
2184
|
+
setBusy(null);
|
|
2185
|
+
setLoginProgress(null);
|
|
2186
|
+
setError(poll.error || t.loginFailed);
|
|
2187
|
+
}
|
|
2188
|
+
} catch {}
|
|
2189
|
+
})();
|
|
2190
|
+
}, 1500);
|
|
2191
|
+
window.setTimeout(() => {
|
|
2192
|
+
window.clearInterval(pollTimer);
|
|
2193
|
+
setBusy(null);
|
|
2194
|
+
setLoginProgress(null);
|
|
2195
|
+
}, 300 * 1e3);
|
|
2196
|
+
} catch (err) {
|
|
2197
|
+
setBusy(null);
|
|
2198
|
+
setLoginProgress(null);
|
|
2199
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2200
|
+
}
|
|
2201
|
+
};
|
|
2202
|
+
const handleApiKey = async () => {
|
|
2203
|
+
try {
|
|
2204
|
+
setBusy("apikey");
|
|
2205
|
+
setError(null);
|
|
2206
|
+
const updated = await fetchApi$4("/login/apikey", {
|
|
2207
|
+
method: "POST",
|
|
2208
|
+
body: JSON.stringify({ apiKey })
|
|
2209
|
+
});
|
|
2210
|
+
setStatus(updated);
|
|
2211
|
+
setApiKey("");
|
|
2212
|
+
notifyChange();
|
|
2213
|
+
} catch (err) {
|
|
2214
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2215
|
+
} finally {
|
|
2216
|
+
setBusy(null);
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
const handleLogout = async () => {
|
|
2220
|
+
try {
|
|
2221
|
+
setBusy("logout");
|
|
2222
|
+
setError(null);
|
|
2223
|
+
const updated = await fetchApi$4("/logout", { method: "POST" });
|
|
2224
|
+
setStatus(updated);
|
|
2225
|
+
notifyChange();
|
|
2226
|
+
} catch (err) {
|
|
2227
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2228
|
+
} finally {
|
|
2229
|
+
setBusy(null);
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
const handleRefreshQuota = async () => {
|
|
2233
|
+
try {
|
|
2234
|
+
setBusy("quota");
|
|
2235
|
+
setError(null);
|
|
2236
|
+
const updated = await fetchApi$4("/quota", { method: "POST" });
|
|
2237
|
+
setStatus(updated);
|
|
2238
|
+
} catch (err) {
|
|
2239
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2240
|
+
} finally {
|
|
2241
|
+
setBusy(null);
|
|
2242
|
+
}
|
|
2243
|
+
};
|
|
2244
|
+
const handleRefreshCatalog = async () => {
|
|
2245
|
+
try {
|
|
2246
|
+
setBusy("catalog");
|
|
2247
|
+
setError(null);
|
|
2248
|
+
const updated = await fetchApi$4("/catalog/refresh", { method: "POST" });
|
|
2249
|
+
setStatus(updated);
|
|
2250
|
+
const drafts = {};
|
|
2251
|
+
for (const model of updated.models) drafts[model.id] = formatCapacity$1(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
2252
|
+
setContextDrafts(drafts);
|
|
2253
|
+
notifyChange();
|
|
2254
|
+
} catch (err) {
|
|
2255
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2256
|
+
} finally {
|
|
2257
|
+
setBusy(null);
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
const handleTestConnection = async () => {
|
|
2261
|
+
try {
|
|
2262
|
+
setBusy("connection");
|
|
2263
|
+
setError(null);
|
|
2264
|
+
await fetchApi$4("/connection/test", { method: "POST" });
|
|
2265
|
+
await loadStatus(true);
|
|
2266
|
+
} catch (err) {
|
|
2267
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2268
|
+
} finally {
|
|
2269
|
+
setBusy(null);
|
|
2270
|
+
}
|
|
2271
|
+
};
|
|
2272
|
+
const applyEnabled = async (enabledModelIds) => {
|
|
2273
|
+
try {
|
|
2274
|
+
const updated = await fetchApi$4("/models", {
|
|
2275
|
+
method: "POST",
|
|
2276
|
+
body: JSON.stringify({ enabledModelIds })
|
|
2277
|
+
});
|
|
2278
|
+
setStatus(updated);
|
|
2279
|
+
notifyChange();
|
|
2280
|
+
} catch (err) {
|
|
2281
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
const toggleModel = (modelId, checked) => {
|
|
2285
|
+
if (!status) return;
|
|
2286
|
+
const current = status.models.filter((model) => model.enabled).map((model) => model.id);
|
|
2287
|
+
const next = checked ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
|
|
2288
|
+
if (next.length === 0) return;
|
|
2289
|
+
applyEnabled(next);
|
|
2290
|
+
};
|
|
2291
|
+
const setAllModels = (selectAll) => {
|
|
2292
|
+
if (!status || status.models.length === 0) return;
|
|
2293
|
+
applyEnabled(selectAll ? status.models.map((model) => model.id) : [status.models[0].id]);
|
|
2294
|
+
};
|
|
2295
|
+
const handleUpdateEffort = async (effort) => {
|
|
2296
|
+
try {
|
|
2297
|
+
const updated = await fetchApi$4("/settings", {
|
|
2298
|
+
method: "POST",
|
|
2299
|
+
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
2300
|
+
});
|
|
2301
|
+
setStatus(updated);
|
|
2302
|
+
notifyChange();
|
|
2303
|
+
} catch (err) {
|
|
2304
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2307
|
+
const handleSaveContextWindow = async (modelId) => {
|
|
2308
|
+
const raw = contextDrafts[modelId] || "";
|
|
2309
|
+
const parsed = parsePositiveCapacity$1(raw);
|
|
2310
|
+
if (parsed === null) {
|
|
2311
|
+
setError(`Invalid context capacity: ${raw}`);
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2314
|
+
try {
|
|
2315
|
+
setSavingModel(modelId);
|
|
2316
|
+
setError(null);
|
|
2317
|
+
const updated = await fetchApi$4("/settings", {
|
|
2318
|
+
method: "POST",
|
|
2319
|
+
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
2320
|
+
});
|
|
2321
|
+
setStatus(updated);
|
|
2322
|
+
setContextDrafts((prev) => ({
|
|
2323
|
+
...prev,
|
|
2324
|
+
[modelId]: formatCapacity$1(parsed)
|
|
2325
|
+
}));
|
|
2326
|
+
notifyChange();
|
|
2327
|
+
} catch (err) {
|
|
2328
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
2329
|
+
} finally {
|
|
2330
|
+
setSavingModel(null);
|
|
2331
|
+
}
|
|
2332
|
+
};
|
|
2333
|
+
if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2334
|
+
className: "dsha-page",
|
|
2335
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2336
|
+
className: "dsha-empty",
|
|
2337
|
+
children: t.loading
|
|
2338
|
+
})
|
|
2339
|
+
});
|
|
2340
|
+
const quota = status?.quota;
|
|
2341
|
+
const account = status?.account;
|
|
2342
|
+
const visibleCount = status?.models.filter((model) => model.enabled).length || 0;
|
|
2343
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2344
|
+
className: "dsha-page",
|
|
2345
|
+
children: [
|
|
2346
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2347
|
+
className: "dsha-group",
|
|
2348
|
+
children: [
|
|
2349
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2350
|
+
className: "dsha-grouphead",
|
|
2351
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: status?.authenticated ? t.account : t.signedOut })
|
|
2352
|
+
}),
|
|
2353
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2354
|
+
className: "dsha-row",
|
|
2355
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2356
|
+
className: "dsha-label",
|
|
2357
|
+
children: status?.authenticated ? t.signedIn : t.signedOut
|
|
2358
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2359
|
+
className: "dsha-value",
|
|
2360
|
+
children: account?.email || account?.userName || "—"
|
|
2361
|
+
})]
|
|
2362
|
+
}),
|
|
2363
|
+
status?.authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2364
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2365
|
+
className: "dsha-row",
|
|
2366
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2367
|
+
className: "dsha-label",
|
|
2368
|
+
children: t.plan
|
|
2369
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2370
|
+
className: "dsha-value",
|
|
2371
|
+
children: quota?.planName || account?.planLabel || t.planUnknown
|
|
2372
|
+
})]
|
|
2373
|
+
}),
|
|
2374
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2375
|
+
className: "dsha-row",
|
|
2376
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2377
|
+
className: "dsha-label",
|
|
2378
|
+
children: t.keyName
|
|
2379
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2380
|
+
className: "dsha-value",
|
|
2381
|
+
children: account?.keyName || "—"
|
|
2382
|
+
})]
|
|
2383
|
+
}),
|
|
2384
|
+
quota?.subscriptionStatus && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2385
|
+
className: "dsha-row",
|
|
2386
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2387
|
+
className: "dsha-label",
|
|
2388
|
+
children: t.subscription
|
|
2389
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2390
|
+
className: "dsha-value",
|
|
2391
|
+
children: [quota.subscriptionStatus, quota.periodEndsAt !== null ? ` · ${t.renews} ${formatDate$1(quota.periodEndsAt)}` : ""]
|
|
2392
|
+
})]
|
|
2393
|
+
}),
|
|
2394
|
+
account?.organizationName && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2395
|
+
className: "dsha-row",
|
|
2396
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2397
|
+
className: "dsha-label",
|
|
2398
|
+
children: t.organization
|
|
2399
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2400
|
+
className: "dsha-value",
|
|
2401
|
+
children: account.organizationName
|
|
2402
|
+
})]
|
|
2403
|
+
}),
|
|
2404
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2405
|
+
className: "dsha-row",
|
|
2406
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2407
|
+
className: "dsha-label",
|
|
2408
|
+
children: t.authenticatedAt
|
|
2409
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2410
|
+
className: "dsha-value",
|
|
2411
|
+
children: formatDate$1(account?.authenticatedAt)
|
|
2412
|
+
})]
|
|
2413
|
+
})
|
|
2414
|
+
] }),
|
|
2415
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2416
|
+
className: "dsha-row",
|
|
2417
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2418
|
+
className: "dsha-label",
|
|
2419
|
+
children: t.storage
|
|
2420
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2421
|
+
className: "dsha-value",
|
|
2422
|
+
children: status?.storagePath || "—"
|
|
2423
|
+
})]
|
|
2424
|
+
}),
|
|
2425
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2426
|
+
className: "dsha-notice",
|
|
2427
|
+
children: t.storageNotice
|
|
2428
|
+
}),
|
|
2429
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2430
|
+
className: "dsha-actions",
|
|
2431
|
+
children: !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2432
|
+
className: "dsha-btn dsha-btn-primary",
|
|
2433
|
+
disabled: busy !== null,
|
|
2434
|
+
onClick: () => void handleLogin(),
|
|
2435
|
+
children: busy === "login" ? loginProgress || t.signingIn : t.signIn
|
|
2436
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2437
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2438
|
+
className: "dsha-btn dsha-btn-primary",
|
|
2439
|
+
disabled: busy !== null,
|
|
2440
|
+
onClick: () => void handleLogin(),
|
|
2441
|
+
children: busy === "login" ? loginProgress || t.signingIn : t.signInAgain
|
|
2442
|
+
}),
|
|
2443
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2444
|
+
className: "dsha-btn",
|
|
2445
|
+
disabled: busy !== null,
|
|
2446
|
+
onClick: () => void handleRefreshQuota(),
|
|
2447
|
+
children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
|
|
2448
|
+
}),
|
|
2449
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2450
|
+
className: "dsha-btn",
|
|
2451
|
+
disabled: busy !== null,
|
|
2452
|
+
onClick: () => void handleLogout(),
|
|
2453
|
+
children: t.signOut
|
|
2454
|
+
})
|
|
2455
|
+
] })
|
|
2456
|
+
})
|
|
2457
|
+
]
|
|
2458
|
+
}),
|
|
2459
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2460
|
+
className: "dsha-group",
|
|
2461
|
+
children: [
|
|
2462
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2463
|
+
className: "dsha-grouphead",
|
|
2464
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.apiKeySection })
|
|
2465
|
+
}),
|
|
2466
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2467
|
+
className: "dsha-muted",
|
|
2468
|
+
children: t.apiKeyHint
|
|
2469
|
+
}),
|
|
2470
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2471
|
+
className: "dsha-capacity-control",
|
|
2472
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2473
|
+
type: "password",
|
|
2474
|
+
"aria-label": t.apiKeySection,
|
|
2475
|
+
placeholder: t.apiKeyPlaceholder,
|
|
2476
|
+
value: apiKey,
|
|
2477
|
+
onChange: (event) => setApiKey(event.currentTarget.value),
|
|
2478
|
+
onKeyDown: (event) => {
|
|
2479
|
+
if (event.key === "Enter" && apiKey.trim() !== "") handleApiKey();
|
|
2480
|
+
}
|
|
2481
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2482
|
+
type: "button",
|
|
2483
|
+
className: "dsha-context-save",
|
|
2484
|
+
disabled: busy !== null || apiKey.trim() === "",
|
|
2485
|
+
onClick: () => void handleApiKey(),
|
|
2486
|
+
children: busy === "apikey" ? t.apiKeySaving : t.apiKeySave
|
|
2487
|
+
})]
|
|
2488
|
+
})
|
|
2489
|
+
]
|
|
2490
|
+
}),
|
|
2491
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2492
|
+
className: "dsha-group",
|
|
2493
|
+
children: [
|
|
2494
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2495
|
+
className: "dsha-grouphead",
|
|
2496
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
|
|
2497
|
+
}),
|
|
2498
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2499
|
+
className: "dsha-row",
|
|
2500
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2501
|
+
className: "dsha-label",
|
|
2502
|
+
children: t.provider
|
|
2503
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2504
|
+
className: "dsha-value",
|
|
2505
|
+
children: t.providerValue
|
|
2506
|
+
})]
|
|
2507
|
+
}),
|
|
2508
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2509
|
+
className: "dsha-row",
|
|
2510
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2511
|
+
className: "dsha-label",
|
|
2512
|
+
children: t.connectionState
|
|
2513
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2514
|
+
className: "dsha-value",
|
|
2515
|
+
children: status?.authenticated ? t.connected : t.untested
|
|
2516
|
+
})]
|
|
2517
|
+
}),
|
|
2518
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2519
|
+
className: "dsha-notice",
|
|
2520
|
+
children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
|
|
2521
|
+
}),
|
|
2522
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2523
|
+
className: "dsha-actions",
|
|
2524
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2525
|
+
className: "dsha-btn",
|
|
2526
|
+
disabled: busy !== null || !status?.authenticated,
|
|
2527
|
+
onClick: () => void handleTestConnection(),
|
|
2528
|
+
children: busy === "connection" ? t.testingConnection : t.testConnection
|
|
2529
|
+
})
|
|
2530
|
+
})
|
|
2531
|
+
]
|
|
2532
|
+
}),
|
|
2533
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2534
|
+
className: "dsha-group",
|
|
2535
|
+
children: [
|
|
2536
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2537
|
+
className: "dsha-grouphead",
|
|
2538
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2539
|
+
className: "dsha-btn",
|
|
2540
|
+
disabled: busy !== null,
|
|
2541
|
+
onClick: () => void handleRefreshCatalog(),
|
|
2542
|
+
children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
|
|
2543
|
+
})]
|
|
2544
|
+
}),
|
|
2545
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2546
|
+
className: "dsha-muted dsha-models-hint",
|
|
2547
|
+
children: t.modelsHint
|
|
2548
|
+
}),
|
|
2549
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2550
|
+
className: "dsha-models",
|
|
2551
|
+
"aria-label": "Command Code Models",
|
|
2552
|
+
children: status?.models.map((model) => {
|
|
2553
|
+
const lastVisible = model.enabled && visibleCount === 1;
|
|
2554
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
2555
|
+
title: `${model.id} · ${model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai}`,
|
|
2556
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2557
|
+
type: "checkbox",
|
|
2558
|
+
checked: model.enabled,
|
|
2559
|
+
disabled: busy !== null || lastVisible,
|
|
2560
|
+
onChange: (event) => toggleModel(model.id, event.currentTarget.checked)
|
|
2561
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
|
|
2562
|
+
}, model.id);
|
|
2563
|
+
})
|
|
2564
|
+
}),
|
|
2565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2566
|
+
className: "dsha-actions",
|
|
2567
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2568
|
+
className: "dsha-btn",
|
|
2569
|
+
disabled: busy !== null,
|
|
2570
|
+
onClick: () => setAllModels(true),
|
|
2571
|
+
children: t.selectAll
|
|
2572
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2573
|
+
className: "dsha-btn",
|
|
2574
|
+
disabled: busy !== null,
|
|
2575
|
+
onClick: () => setAllModels(false),
|
|
2576
|
+
children: t.unselectAll
|
|
2577
|
+
})]
|
|
2578
|
+
})
|
|
2579
|
+
]
|
|
2580
|
+
}),
|
|
2581
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2582
|
+
className: "dsha-group",
|
|
2583
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2584
|
+
className: "dsha-grouphead",
|
|
2585
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
|
|
2586
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2587
|
+
className: "dsha-pref-row",
|
|
2588
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2589
|
+
className: "dsha-muted",
|
|
2590
|
+
children: t.defaultReasoningEffortHint
|
|
2591
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
2592
|
+
className: "dsha-select",
|
|
2593
|
+
"aria-label": t.defaultReasoningEffort,
|
|
2594
|
+
value: status?.defaultReasoningEffort ?? "",
|
|
2595
|
+
disabled: busy !== null,
|
|
2596
|
+
onChange: (event) => {
|
|
2597
|
+
const value = event.currentTarget.value;
|
|
2598
|
+
handleUpdateEffort(value === "" ? null : value);
|
|
2599
|
+
},
|
|
2600
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2601
|
+
value: "",
|
|
2602
|
+
children: t.defaultEffortAuto
|
|
2603
|
+
}), COMMAND_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2604
|
+
value: effort,
|
|
2605
|
+
children: EFFORT_LABELS[effort]
|
|
2606
|
+
}, effort))]
|
|
2607
|
+
})]
|
|
2608
|
+
})]
|
|
2609
|
+
}),
|
|
2610
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2611
|
+
className: "dsha-group",
|
|
2612
|
+
children: [
|
|
2613
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2614
|
+
className: "dsha-grouphead",
|
|
2615
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
|
|
2616
|
+
}),
|
|
2617
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2618
|
+
className: "dsha-muted",
|
|
2619
|
+
children: t.contextWindowHint
|
|
2620
|
+
}),
|
|
2621
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2622
|
+
className: "dsha-context-settings",
|
|
2623
|
+
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2624
|
+
className: "dsha-context-row",
|
|
2625
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2626
|
+
title: model.id,
|
|
2627
|
+
children: model.name
|
|
2628
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2629
|
+
className: "dsha-capacity-control",
|
|
2630
|
+
children: [
|
|
2631
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2632
|
+
type: "text",
|
|
2633
|
+
"aria-label": `${model.name} context window`,
|
|
2634
|
+
value: contextDrafts[model.id] ?? "",
|
|
2635
|
+
onChange: (event) => setContextDrafts({
|
|
2636
|
+
...contextDrafts,
|
|
2637
|
+
[model.id]: event.currentTarget.value
|
|
2638
|
+
}),
|
|
2639
|
+
onKeyDown: (event) => {
|
|
2640
|
+
if (event.key === "Enter") handleSaveContextWindow(model.id);
|
|
2641
|
+
}
|
|
2642
|
+
}),
|
|
2643
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
|
|
2644
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2645
|
+
type: "button",
|
|
2646
|
+
className: "dsha-context-save",
|
|
2647
|
+
disabled: savingModel === model.id,
|
|
2648
|
+
onClick: () => void handleSaveContextWindow(model.id),
|
|
2649
|
+
children: savingModel === model.id ? t.saving : t.save
|
|
2650
|
+
})
|
|
2651
|
+
]
|
|
2652
|
+
})]
|
|
2653
|
+
}, model.id))
|
|
2654
|
+
})
|
|
2655
|
+
]
|
|
2656
|
+
}),
|
|
2657
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2658
|
+
className: "dsha-group",
|
|
2659
|
+
children: [
|
|
2660
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2661
|
+
className: "dsha-grouphead",
|
|
2662
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2663
|
+
className: "dsha-btn",
|
|
2664
|
+
disabled: busy !== null || !status?.authenticated,
|
|
2665
|
+
onClick: () => void handleRefreshQuota(),
|
|
2666
|
+
children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
|
|
2667
|
+
})]
|
|
2668
|
+
}),
|
|
2669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2670
|
+
className: "dsha-muted",
|
|
2671
|
+
children: t.quotaDesc
|
|
2672
|
+
}),
|
|
2673
|
+
!status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2674
|
+
className: "dsha-empty",
|
|
2675
|
+
children: t.signedOut
|
|
2676
|
+
}) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2677
|
+
className: "dsha-empty",
|
|
2678
|
+
children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
|
|
2679
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2680
|
+
className: "dsha-quota-card",
|
|
2681
|
+
children: [
|
|
2682
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2683
|
+
className: "dsha-quota-title",
|
|
2684
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.quotaCredits }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.unlimited ? t.quotaUnlimited : quota.creditBalance !== null ? quota.creditBalance : "—" })]
|
|
2685
|
+
}),
|
|
2686
|
+
quota.windows.map((window) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2687
|
+
className: "dsha-meter-wrap",
|
|
2688
|
+
children: [
|
|
2689
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2690
|
+
className: "dsha-meter-label",
|
|
2691
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [Math.max(0, 100 - window.usedPercent), "% left"] })]
|
|
2692
|
+
}),
|
|
2693
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2694
|
+
className: "dsha-meter dsha-meter-green",
|
|
2695
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${Math.max(0, 100 - window.usedPercent)}%` } })
|
|
2696
|
+
}),
|
|
2697
|
+
window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2698
|
+
className: "dsha-meter-meta",
|
|
2699
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$1(window.resetsAt)] })
|
|
2700
|
+
})
|
|
2701
|
+
]
|
|
2702
|
+
}, window.id)),
|
|
2703
|
+
quota.meters.map((meter) => {
|
|
2704
|
+
const remaining = meter.remainingFraction;
|
|
2705
|
+
const percent = remaining === null ? null : Math.round(remaining * 100);
|
|
2706
|
+
const isWindow = percent !== null;
|
|
2707
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2708
|
+
className: "dsha-meter-wrap",
|
|
2709
|
+
children: [
|
|
2710
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2711
|
+
className: "dsha-meter-label",
|
|
2712
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: isWindow ? `${percent}% left` : meter.limit ?? "—" })]
|
|
2713
|
+
}),
|
|
2714
|
+
isWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2715
|
+
className: "dsha-meter dsha-meter-cyan",
|
|
2716
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${percent}%` } })
|
|
2717
|
+
}),
|
|
2718
|
+
isWindow ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2719
|
+
className: "dsha-meter-meta",
|
|
2720
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
2721
|
+
meter.used ?? "—",
|
|
2722
|
+
" / ",
|
|
2723
|
+
meter.limit ?? "—"
|
|
2724
|
+
] }), meter.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: ["Reset: ", formatReset$1(meter.resetsAt)] })]
|
|
2725
|
+
}) : meter.description !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2726
|
+
className: "dsha-meter-meta",
|
|
2727
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: meter.description })
|
|
2728
|
+
}) : null
|
|
2729
|
+
]
|
|
2730
|
+
}, meter.id);
|
|
2731
|
+
}),
|
|
2732
|
+
quota.meters.length === 0 && quota.windows.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2733
|
+
className: "dsha-empty",
|
|
2734
|
+
children: t.quotaEmpty
|
|
2735
|
+
}),
|
|
2736
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2737
|
+
className: "dsha-timestamp",
|
|
2738
|
+
children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
|
|
2739
|
+
})
|
|
2740
|
+
]
|
|
2741
|
+
})
|
|
2742
|
+
]
|
|
2743
|
+
}),
|
|
2744
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2745
|
+
className: "dsha-error",
|
|
2746
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
|
|
2747
|
+
})
|
|
2748
|
+
]
|
|
2749
|
+
});
|
|
2750
|
+
}
|
|
2751
|
+
//#endregion
|
|
2752
|
+
//#region src/shared/kimi-code-contracts.ts
|
|
2753
|
+
/** Every level, in escalating order; the settings card renders exactly these. */
|
|
2754
|
+
const KIMI_CODE_REASONING_EFFORTS = [
|
|
2755
|
+
"low",
|
|
2756
|
+
"high",
|
|
2757
|
+
"max",
|
|
2758
|
+
"none"
|
|
2759
|
+
];
|
|
2760
|
+
//#endregion
|
|
2761
|
+
//#region src/client/kimi-code/locales.ts
|
|
2762
|
+
const NS_KIMI_CODE = "dsh-kimi-code";
|
|
2763
|
+
const zh$1 = {
|
|
2764
|
+
title: "Kimi Code",
|
|
2765
|
+
pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
|
|
2766
|
+
account: "账号",
|
|
2767
|
+
signedIn: "已登录",
|
|
2768
|
+
signedOut: "未登录",
|
|
2769
|
+
nickname: "昵称",
|
|
2770
|
+
email: "邮箱",
|
|
2771
|
+
plan: "套餐",
|
|
2772
|
+
planUnknown: "—",
|
|
2773
|
+
region: "区域",
|
|
2774
|
+
regionMainland: "中国大陆 (kimi.com)",
|
|
2775
|
+
regionGlobal: "国际 (kimi.ai)",
|
|
2776
|
+
authenticatedAt: "登录时间",
|
|
2777
|
+
storage: "凭据存储",
|
|
2778
|
+
storageNotice: "OAuth 凭据由 Host 保存在本地安全存储 ($DSH_HOME/storages/kimi-code-credentials.json),不会进入浏览器。访问令牌会自动刷新。",
|
|
2779
|
+
refreshRejected: "刷新令牌已被拒绝,请重新登录。",
|
|
2780
|
+
signIn: "设备码登录",
|
|
2781
|
+
signInAgain: "重新登录",
|
|
2782
|
+
signingIn: "登录中...",
|
|
2783
|
+
signOut: "注销",
|
|
2784
|
+
cancelSignIn: "取消登录",
|
|
2785
|
+
deviceCodeSection: "设备码授权",
|
|
2786
|
+
deviceCodeHint: "在浏览器中打开下方链接(已自动填充用户码),确认后用同一账号授权。",
|
|
2787
|
+
openSignInPage: "打开授权页面",
|
|
2788
|
+
copyCode: "复制用户码",
|
|
2789
|
+
copied: "已复制",
|
|
2790
|
+
userCode: "用户码",
|
|
2791
|
+
codeExpires: "有效期至",
|
|
2792
|
+
waitingAuthorization: "等待浏览器授权...",
|
|
2793
|
+
requestingCode: "正在申请设备码...",
|
|
2794
|
+
connection: "连接",
|
|
2795
|
+
provider: "Provider",
|
|
2796
|
+
providerValue: "Kimi Code · kimi-code",
|
|
2797
|
+
oauthHost: "OAuth 主机",
|
|
2798
|
+
codingEndpoint: "模型接口",
|
|
2799
|
+
connectionState: "连接状态",
|
|
2800
|
+
connected: "已连接",
|
|
2801
|
+
untested: "未测试",
|
|
2802
|
+
testConnection: "测试连接",
|
|
2803
|
+
testingConnection: "测试中...",
|
|
2804
|
+
testSuccess: "连接正常",
|
|
2805
|
+
testFailed: "连接失败:Kimi Code 未接受当前凭据",
|
|
2806
|
+
routeOwned: "模型路由由本插件提供",
|
|
2807
|
+
routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
|
|
2808
|
+
modelsSection: "模型",
|
|
2809
|
+
modelsHint: "勾选后模型才会出现在对话页的模型选择列表中;至少保留一个。",
|
|
2810
|
+
refreshCatalog: "刷新模型目录",
|
|
2811
|
+
refreshingCatalog: "刷新中...",
|
|
2812
|
+
selectAll: "全选",
|
|
2813
|
+
unselectAll: "全不选",
|
|
2814
|
+
wireAnthropic: "Anthropic",
|
|
2815
|
+
wireOpenai: "OpenAI",
|
|
2816
|
+
capVideo: "视频",
|
|
2817
|
+
capDynamicTools: "动态工具",
|
|
2818
|
+
capImageOnly: "仅图片",
|
|
2819
|
+
capNone: "—",
|
|
2820
|
+
capabilitiesTitle: "模型能力",
|
|
2821
|
+
capColMedia: "多模态",
|
|
2822
|
+
capColTools: "动态工具",
|
|
2823
|
+
capColNotes: "说明",
|
|
2824
|
+
capPlan: "需要套餐:{plan}",
|
|
2825
|
+
speedRegular: "标准",
|
|
2826
|
+
speedHighspeed: "高速 (约 6×)",
|
|
2827
|
+
quotaCost: "额度倍率",
|
|
2828
|
+
minimumPlan: "所需套餐",
|
|
2829
|
+
enhanced: "思考设置",
|
|
2830
|
+
defaultReasoningEffort: "默认思考档位",
|
|
2831
|
+
defaultReasoningEffortHint: "Kimi Code 只接受 low / high / max 三档;none 表示关闭思考。切换档位会使上下文缓存失效,建议在同一会话中保持一致。",
|
|
2832
|
+
defaultEffortAuto: "使用模型默认值",
|
|
2833
|
+
effortLow: "低 (low)",
|
|
2834
|
+
effortHigh: "高 (high)",
|
|
2835
|
+
effortMax: "最高 (max)",
|
|
2836
|
+
effortNone: "关闭思考",
|
|
2837
|
+
contextWindowSection: "模型上下文窗口",
|
|
2838
|
+
contextWindowHint: "默认取模型目录的上下文长度。k3 的 1M 上下文需要 Allegretto 及以上套餐,因此默认按 256K 计算;如已升级可在此覆盖为 1M。",
|
|
2839
|
+
contextWindowPlan: "完整上下文需要 {plan} 套餐",
|
|
2840
|
+
save: "保存",
|
|
2841
|
+
saved: "已保存",
|
|
2842
|
+
saving: "保存中...",
|
|
2843
|
+
cacheSection: "缓存与 K3 调优",
|
|
2844
|
+
cacheDesc: "Kimi 的前缀缓存按请求内容自动命中,无需也无法手动声明,因此这里用读缓存比例反映实际效果。",
|
|
2845
|
+
cacheEmpty: "本进程还没有带用量回报的请求。",
|
|
2846
|
+
cacheHitRatio: "缓存命中率",
|
|
2847
|
+
cacheCached: "命中 tokens",
|
|
2848
|
+
cacheFresh: "新处理 tokens",
|
|
2849
|
+
cacheOutput: "输出 tokens",
|
|
2850
|
+
cacheRequests: "请求数",
|
|
2851
|
+
cacheHint: "同一会话内:系统提示与工具列表一旦变化会使缓存整体失效,因此保持工具集合稳定、把新增内容追加在末尾,命中率最高。",
|
|
2852
|
+
preserveThinking: "保留思考 (Preserved Thinking)",
|
|
2853
|
+
preserveOn: "已开启(官方默认):跨轮保留 reasoning_content,多轮工具调用更连贯,但思考 token 也计入输出。",
|
|
2854
|
+
preserveOff: "已关闭:不要求服务回传推理内容。可设置 DSH_KIMI_CODE_PRESERVE_THINKING=0 关闭。",
|
|
2855
|
+
outputCap: "输出上限跟随上下文窗口,长思考不会被 32K 截断",
|
|
2856
|
+
quotaSection: "用量与额度",
|
|
2857
|
+
quotaDesc: "数据来自 Kimi Code 账户接口,页面可见时最多每 60 秒刷新一次。",
|
|
2858
|
+
refreshQuota: "刷新用量",
|
|
2859
|
+
refreshingQuota: "刷新中...",
|
|
2860
|
+
quotaEmpty: "暂无配额数据,点击「刷新用量」重试。",
|
|
2861
|
+
quotaPlan: "当前套餐",
|
|
2862
|
+
quotaWallet: "加油包余额",
|
|
2863
|
+
quotaWalletLimit: "月度上限",
|
|
2864
|
+
quotaWalletUsed: "本月已用",
|
|
2865
|
+
quotaUnlimited: "不限量",
|
|
2866
|
+
updatedAt: "更新时间:{time}",
|
|
2867
|
+
resetAt: "重置:{time}",
|
|
2868
|
+
loading: "加载中...",
|
|
2869
|
+
loginFailed: "登录失败",
|
|
2870
|
+
requests: "次请求",
|
|
2871
|
+
tokens: "tokens"
|
|
2872
|
+
};
|
|
2873
|
+
const en$1 = {
|
|
2874
|
+
title: "Kimi Code",
|
|
2875
|
+
pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
|
|
2876
|
+
account: "Account",
|
|
2877
|
+
signedIn: "Signed in",
|
|
2878
|
+
signedOut: "Not signed in",
|
|
2879
|
+
nickname: "Nickname",
|
|
2880
|
+
email: "Email",
|
|
2881
|
+
plan: "Plan",
|
|
2882
|
+
planUnknown: "—",
|
|
2883
|
+
region: "Region",
|
|
2884
|
+
regionMainland: "Mainland China (kimi.com)",
|
|
2885
|
+
regionGlobal: "Global (kimi.ai)",
|
|
2886
|
+
authenticatedAt: "Signed in at",
|
|
2887
|
+
storage: "Credential storage",
|
|
2888
|
+
storageNotice: "The OAuth credential is stored locally by the Host ($DSH_HOME/storages/kimi-code-credentials.json) and never reaches the browser. Access tokens refresh automatically.",
|
|
2889
|
+
refreshRejected: "The refresh token was rejected — sign in again.",
|
|
2890
|
+
signIn: "Sign in with device code",
|
|
2891
|
+
signInAgain: "Sign in again",
|
|
2892
|
+
signingIn: "Signing in...",
|
|
2893
|
+
signOut: "Sign out",
|
|
2894
|
+
cancelSignIn: "Cancel",
|
|
2895
|
+
deviceCodeSection: "Device authorization",
|
|
2896
|
+
deviceCodeHint: "Open the link below in a browser (the user code is pre-filled) and approve it with the same account.",
|
|
2897
|
+
openSignInPage: "Open the sign-in page",
|
|
2898
|
+
copyCode: "Copy user code",
|
|
2899
|
+
copied: "Copied",
|
|
2900
|
+
userCode: "User code",
|
|
2901
|
+
codeExpires: "Expires at",
|
|
2902
|
+
waitingAuthorization: "Waiting for browser authorization...",
|
|
2903
|
+
requestingCode: "Requesting a device code...",
|
|
2904
|
+
connection: "Connection",
|
|
2905
|
+
provider: "Provider",
|
|
2906
|
+
providerValue: "Kimi Code · kimi-code",
|
|
2907
|
+
oauthHost: "OAuth host",
|
|
2908
|
+
codingEndpoint: "Model endpoint",
|
|
2909
|
+
connectionState: "Connection state",
|
|
2910
|
+
connected: "Connected",
|
|
2911
|
+
untested: "Untested",
|
|
2912
|
+
testConnection: "Test connection",
|
|
2913
|
+
testingConnection: "Testing...",
|
|
2914
|
+
testSuccess: "Connection OK",
|
|
2915
|
+
testFailed: "Connection failed: Kimi Code did not accept the stored credential",
|
|
2916
|
+
routeOwned: "This plugin serves the model route",
|
|
2917
|
+
routeConflict: "Another provider already owns the model route: {detail}. Remove the duplicate provider configuration in DSH settings and reload.",
|
|
2918
|
+
modelsSection: "Models",
|
|
2919
|
+
modelsHint: "Checked models appear in the DSH conversation model list; keep at least one.",
|
|
2920
|
+
refreshCatalog: "Refresh catalog",
|
|
2921
|
+
refreshingCatalog: "Refreshing...",
|
|
2922
|
+
selectAll: "Select all",
|
|
2923
|
+
unselectAll: "Deselect all",
|
|
2924
|
+
wireAnthropic: "Anthropic",
|
|
2925
|
+
wireOpenai: "OpenAI",
|
|
2926
|
+
capVideo: "Video",
|
|
2927
|
+
capDynamicTools: "Dynamic tools",
|
|
2928
|
+
capImageOnly: "Images",
|
|
2929
|
+
capNone: "—",
|
|
2930
|
+
capabilitiesTitle: "Capabilities",
|
|
2931
|
+
capColMedia: "Multimodal",
|
|
2932
|
+
capColTools: "Dynamic tools",
|
|
2933
|
+
capColNotes: "Notes",
|
|
2934
|
+
capPlan: "Requires plan: {plan}",
|
|
2935
|
+
speedRegular: "Regular",
|
|
2936
|
+
speedHighspeed: "HighSpeed (~6x)",
|
|
2937
|
+
quotaCost: "Quota cost",
|
|
2938
|
+
minimumPlan: "Required plan",
|
|
2939
|
+
enhanced: "Thinking",
|
|
2940
|
+
defaultReasoningEffort: "Default thinking level",
|
|
2941
|
+
defaultReasoningEffortHint: "Kimi Code accepts only low / high / max; none disables thinking. Switching the level invalidates the context cache, so keep it steady within a session.",
|
|
2942
|
+
defaultEffortAuto: "Use the model default",
|
|
2943
|
+
effortLow: "Low",
|
|
2944
|
+
effortHigh: "High",
|
|
2945
|
+
effortMax: "Max",
|
|
2946
|
+
effortNone: "Thinking off",
|
|
2947
|
+
contextWindowSection: "Model context window",
|
|
2948
|
+
contextWindowHint: "Defaults to the catalog context length. k3 reaches 1M only on Allegretto and above, so it defaults to 256K; raise the override here after upgrading.",
|
|
2949
|
+
contextWindowPlan: "Full context requires the {plan} plan",
|
|
2950
|
+
save: "Save",
|
|
2951
|
+
saved: "Saved",
|
|
2952
|
+
saving: "Saving...",
|
|
2953
|
+
cacheSection: "Cache & K3 tuning",
|
|
2954
|
+
cacheDesc: "Kimi's prefix cache is automatic and content-hash based — there is no marker to set — so the cache-read ratio is the only evidence it is working.",
|
|
2955
|
+
cacheEmpty: "No request in this process has reported usage yet.",
|
|
2956
|
+
cacheHitRatio: "Cache hit ratio",
|
|
2957
|
+
cacheCached: "Cached tokens",
|
|
2958
|
+
cacheFresh: "Fresh tokens",
|
|
2959
|
+
cacheOutput: "Output tokens",
|
|
2960
|
+
cacheRequests: "Requests",
|
|
2961
|
+
cacheHint: "Within one session: any change to the system prompt or the tool list invalidates the whole prefix cache, so keep the tool set stable and append new material at the tail for the best hit rate.",
|
|
2962
|
+
preserveThinking: "Preserved Thinking",
|
|
2963
|
+
preserveOn: "On (the official default): reasoning_content is retained across turns, which keeps multi-step tool use coherent — its tokens are billed as output.",
|
|
2964
|
+
preserveOff: "Off: the service is not asked to return reasoning. Set DSH_KIMI_CODE_PRESERVE_THINKING=0 to disable.",
|
|
2965
|
+
outputCap: "Output cap follows the context window, so long reasoning is not cut off at 32K",
|
|
2966
|
+
quotaSection: "Usage & quota",
|
|
2967
|
+
quotaDesc: "Read from the Kimi Code account endpoints; refreshes at most once every 60 seconds while visible.",
|
|
2968
|
+
refreshQuota: "Refresh quota",
|
|
2969
|
+
refreshingQuota: "Refreshing...",
|
|
2970
|
+
quotaEmpty: "No quota data yet — use \"Refresh quota\" to retry.",
|
|
2971
|
+
quotaPlan: "Current plan",
|
|
2972
|
+
quotaWallet: "Booster wallet",
|
|
2973
|
+
quotaWalletLimit: "Monthly cap",
|
|
2974
|
+
quotaWalletUsed: "Used this month",
|
|
2975
|
+
quotaUnlimited: "Unlimited",
|
|
2976
|
+
updatedAt: "Updated at: {time}",
|
|
2977
|
+
resetAt: "Reset: {time}",
|
|
2978
|
+
loading: "Loading...",
|
|
2979
|
+
loginFailed: "Sign-in failed",
|
|
2980
|
+
requests: "requests",
|
|
2981
|
+
tokens: "tokens"
|
|
2982
|
+
};
|
|
2983
|
+
const dictionaries$1 = {
|
|
2984
|
+
zh: zh$1,
|
|
2985
|
+
"zh-CN": zh$1,
|
|
2986
|
+
en: en$1,
|
|
2987
|
+
"en-US": en$1
|
|
2988
|
+
};
|
|
2989
|
+
//#endregion
|
|
2990
|
+
//#region src/client/kimi-code/KimiModelCapabilities.tsx
|
|
2991
|
+
/**
|
|
2992
|
+
* Capability table for the Kimi model list.
|
|
2993
|
+
*
|
|
2994
|
+
* Extracted from the settings card so the layout is testable: an earlier
|
|
2995
|
+
* revision inlined each capability as prose beside the model name, which
|
|
2996
|
+
* stretched the name column and pushed the descriptions out of alignment.
|
|
2997
|
+
* Capabilities are now short tags in their own columns, with the per-model
|
|
2998
|
+
* detail kept in a hover title.
|
|
2999
|
+
*/
|
|
3000
|
+
const t = zh$1;
|
|
3001
|
+
function KimiModelCapabilities({ models }) {
|
|
3002
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3003
|
+
className: "dsha-cap-table",
|
|
3004
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
3005
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t.capabilitiesTitle }),
|
|
3006
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t.capColMedia }),
|
|
3007
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t.capColTools }),
|
|
3008
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("th", { children: t.capColNotes })
|
|
3009
|
+
] }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: models.map((model) => {
|
|
3010
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("tr", { children: [
|
|
3011
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
3012
|
+
title: [
|
|
3013
|
+
model.id,
|
|
3014
|
+
model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai,
|
|
3015
|
+
...model.defaultReasoningEffort ? [t.defaultReasoningEffort + ": " + model.defaultReasoningEffort] : [],
|
|
3016
|
+
...model.minimumPlan ? [t.capPlan.replace("{plan}", model.minimumPlan)] : []
|
|
3017
|
+
].join(" · "),
|
|
3018
|
+
children: model.name
|
|
3019
|
+
}),
|
|
3020
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3021
|
+
className: model.supportsVideo ? "dsha-cap-on" : "dsha-cap-off",
|
|
3022
|
+
children: model.supportsVideo ? t.capVideo : t.capImageOnly
|
|
3023
|
+
}) }),
|
|
3024
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", { children: model.supportsDynamicTools ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3025
|
+
className: "dsha-cap-on",
|
|
3026
|
+
children: t.capDynamicTools
|
|
3027
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3028
|
+
className: "dsha-cap-off",
|
|
3029
|
+
children: t.capNone
|
|
3030
|
+
}) }),
|
|
3031
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
|
|
3032
|
+
className: "dsha-cap-notes",
|
|
3033
|
+
children: model.description ?? ""
|
|
3034
|
+
})
|
|
3035
|
+
] }, model.id);
|
|
3036
|
+
}) })] })
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
//#endregion
|
|
3040
|
+
//#region src/client/kimi-code/KimiCodeSection.tsx
|
|
3041
|
+
const API$3 = "/kimi-code/api";
|
|
3042
|
+
async function fetchApi$3(path, options) {
|
|
3043
|
+
const res = await fetch(`${API$3}${path}`, {
|
|
3044
|
+
...options,
|
|
3045
|
+
headers: {
|
|
3046
|
+
"Content-Type": "application/json",
|
|
3047
|
+
...options?.headers
|
|
3048
|
+
}
|
|
3049
|
+
});
|
|
3050
|
+
const json = await res.json();
|
|
3051
|
+
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
3052
|
+
return json.value;
|
|
3053
|
+
}
|
|
3054
|
+
/** Parse "1M", "512K", "200000" into a positive integer token count. */
|
|
3055
|
+
function parsePositiveCapacity(value) {
|
|
3056
|
+
const matched = value.trim().toLowerCase().replace(/[,_\s]/g, "").match(/^(\d+(?:\.\d+)?)(k|m)?$/);
|
|
3057
|
+
if (matched === null) return null;
|
|
3058
|
+
const multiplier = matched[2] === "m" ? 1e6 : matched[2] === "k" ? 1e3 : 1;
|
|
3059
|
+
const parsed = Number(matched[1]) * multiplier;
|
|
3060
|
+
return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : null;
|
|
3061
|
+
}
|
|
3062
|
+
function formatCapacity(value) {
|
|
3063
|
+
if (value >= 1e6 && value % 1e5 === 0) return `${value / 1e6}M`;
|
|
3064
|
+
if (value >= 1e3 && value % 1e3 === 0) return `${value / 1e3}K`;
|
|
3065
|
+
return String(value);
|
|
3066
|
+
}
|
|
3067
|
+
function formatDate(ms) {
|
|
3068
|
+
if (ms === void 0 || ms === null || ms <= 0) return "—";
|
|
3069
|
+
try {
|
|
3070
|
+
return new Intl.DateTimeFormat(void 0, {
|
|
3071
|
+
dateStyle: "medium",
|
|
3072
|
+
timeStyle: "short"
|
|
3073
|
+
}).format(ms);
|
|
3074
|
+
} catch {
|
|
3075
|
+
return "—";
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
3078
|
+
function formatReset(resetsAt) {
|
|
3079
|
+
if (resetsAt === void 0 || resetsAt === null || resetsAt <= 0) return "";
|
|
3080
|
+
const diff = resetsAt - Date.now();
|
|
3081
|
+
if (diff <= 0) return "now";
|
|
3082
|
+
const mins = Math.floor(diff / 6e4);
|
|
3083
|
+
const hours = Math.floor(mins / 60);
|
|
3084
|
+
const days = Math.floor(hours / 24);
|
|
3085
|
+
if (days > 0) return `${days}d ${hours % 24}h`;
|
|
3086
|
+
if (hours > 0) return `${hours}h ${mins % 60}m`;
|
|
3087
|
+
return `${mins}m`;
|
|
3088
|
+
}
|
|
3089
|
+
/** Money the service reports in minor units, rendered in its own currency. */
|
|
3090
|
+
function formatMoney(cents, currency) {
|
|
3091
|
+
if (cents === null) return "—";
|
|
3092
|
+
const code = currency ?? "USD";
|
|
3093
|
+
try {
|
|
3094
|
+
return new Intl.NumberFormat(void 0, {
|
|
3095
|
+
style: "currency",
|
|
3096
|
+
currency: code
|
|
3097
|
+
}).format(cents / 100);
|
|
3098
|
+
} catch {
|
|
3099
|
+
return `${(cents / 100).toFixed(2)} ${code}`;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
const EFFORT_LABEL = {
|
|
3103
|
+
low: zh$1.effortLow,
|
|
3104
|
+
high: zh$1.effortHigh,
|
|
3105
|
+
max: zh$1.effortMax,
|
|
3106
|
+
none: zh$1.effortNone
|
|
3107
|
+
};
|
|
3108
|
+
function KimiCodeSection({ onModelChange, loadModelDirectory }) {
|
|
3109
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
3110
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
3111
|
+
const [busy, setBusy] = (0, react.useState)(null);
|
|
3112
|
+
const [error, setError] = (0, react.useState)(null);
|
|
3113
|
+
const [flow, setFlow] = (0, react.useState)(null);
|
|
3114
|
+
const [contextDrafts, setContextDrafts] = (0, react.useState)({});
|
|
3115
|
+
const [savingModel, setSavingModel] = (0, react.useState)(null);
|
|
3116
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
3117
|
+
const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
|
|
3118
|
+
const t = zh$1;
|
|
3119
|
+
const notifyChange = (0, react.useCallback)(() => {
|
|
3120
|
+
onModelChange?.();
|
|
3121
|
+
loadModelDirectory?.();
|
|
3122
|
+
}, [onModelChange, loadModelDirectory]);
|
|
3123
|
+
const loadStatus = (0, react.useCallback)(async (quiet = false) => {
|
|
3124
|
+
if (!quiet) setError(null);
|
|
3125
|
+
try {
|
|
3126
|
+
const data = await fetchApi$3("/status");
|
|
3127
|
+
setStatus(data);
|
|
3128
|
+
const drafts = {};
|
|
3129
|
+
for (const model of data.models) drafts[model.id] = formatCapacity(data.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3130
|
+
setContextDrafts(drafts);
|
|
3131
|
+
} catch (err) {
|
|
3132
|
+
if (!quiet) setError(err instanceof Error ? err.message : String(err));
|
|
3133
|
+
} finally {
|
|
3134
|
+
setLoading(false);
|
|
3135
|
+
}
|
|
3136
|
+
}, []);
|
|
3137
|
+
(0, react.useEffect)(() => {
|
|
3138
|
+
loadStatus();
|
|
3139
|
+
const refreshWhenVisible = () => {
|
|
3140
|
+
if (document.visibilityState === "visible") loadStatus(true);
|
|
3141
|
+
};
|
|
3142
|
+
document.addEventListener("visibilitychange", refreshWhenVisible);
|
|
3143
|
+
const timer = window.setInterval(refreshWhenVisible, 6e4);
|
|
3144
|
+
return () => {
|
|
3145
|
+
window.clearInterval(timer);
|
|
3146
|
+
document.removeEventListener("visibilitychange", refreshWhenVisible);
|
|
3147
|
+
};
|
|
3148
|
+
}, [loadStatus]);
|
|
3149
|
+
(0, react.useEffect)(() => {
|
|
3150
|
+
if (flow?.status !== "pending") return;
|
|
3151
|
+
const timer = window.setInterval(() => {
|
|
3152
|
+
(async () => {
|
|
3153
|
+
try {
|
|
3154
|
+
const poll = await fetchApi$3("/login/status");
|
|
3155
|
+
setFlow(poll);
|
|
3156
|
+
if (poll.status === "complete") {
|
|
3157
|
+
await loadStatus();
|
|
3158
|
+
notifyChange();
|
|
3159
|
+
} else if (poll.status === "error") setError(poll.error || t.loginFailed);
|
|
3160
|
+
} catch {}
|
|
3161
|
+
})();
|
|
3162
|
+
}, 2e3);
|
|
3163
|
+
return () => window.clearInterval(timer);
|
|
3164
|
+
}, [
|
|
3165
|
+
flow?.status,
|
|
3166
|
+
loadStatus,
|
|
3167
|
+
notifyChange,
|
|
3168
|
+
t.loginFailed
|
|
3169
|
+
]);
|
|
3170
|
+
const handleLogin = async () => {
|
|
3171
|
+
try {
|
|
3172
|
+
setBusy("login");
|
|
3173
|
+
setError(null);
|
|
3174
|
+
setCopied(false);
|
|
3175
|
+
const next = await fetchApi$3("/login", {
|
|
3176
|
+
method: "POST",
|
|
3177
|
+
body: JSON.stringify({})
|
|
3178
|
+
});
|
|
3179
|
+
setFlow(next);
|
|
3180
|
+
} catch (err) {
|
|
3181
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3182
|
+
} finally {
|
|
3183
|
+
setBusy(null);
|
|
3184
|
+
}
|
|
3185
|
+
};
|
|
3186
|
+
const handleCancelLogin = async () => {
|
|
3187
|
+
try {
|
|
3188
|
+
await fetchApi$3("/login/cancel", { method: "POST" });
|
|
3189
|
+
setFlow({ status: "idle" });
|
|
3190
|
+
} catch (err) {
|
|
3191
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3192
|
+
}
|
|
3193
|
+
};
|
|
3194
|
+
const handleCopyCode = async () => {
|
|
3195
|
+
const code = flow?.userCode;
|
|
3196
|
+
if (!code) return;
|
|
3197
|
+
try {
|
|
3198
|
+
await navigator.clipboard.writeText(code);
|
|
3199
|
+
setCopied(true);
|
|
3200
|
+
window.setTimeout(() => setCopied(false), 2e3);
|
|
3201
|
+
} catch {}
|
|
3202
|
+
};
|
|
3203
|
+
const handleLogout = async () => {
|
|
3204
|
+
try {
|
|
3205
|
+
setBusy("logout");
|
|
3206
|
+
setError(null);
|
|
3207
|
+
const updated = await fetchApi$3("/logout", { method: "POST" });
|
|
3208
|
+
setStatus(updated);
|
|
3209
|
+
setFlow({ status: "idle" });
|
|
3210
|
+
notifyChange();
|
|
3211
|
+
} catch (err) {
|
|
3212
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3213
|
+
} finally {
|
|
3214
|
+
setBusy(null);
|
|
3215
|
+
}
|
|
3216
|
+
};
|
|
3217
|
+
const handleRefreshQuota = async () => {
|
|
3218
|
+
try {
|
|
3219
|
+
setBusy("quota");
|
|
3220
|
+
setError(null);
|
|
3221
|
+
const updated = await fetchApi$3("/quota", { method: "POST" });
|
|
3222
|
+
setStatus(updated);
|
|
3223
|
+
} catch (err) {
|
|
3224
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3225
|
+
await loadStatus(true);
|
|
3226
|
+
} finally {
|
|
3227
|
+
setBusy(null);
|
|
3228
|
+
}
|
|
3229
|
+
};
|
|
3230
|
+
const handleRefreshCatalog = async () => {
|
|
3231
|
+
try {
|
|
3232
|
+
setBusy("catalog");
|
|
3233
|
+
setError(null);
|
|
3234
|
+
const updated = await fetchApi$3("/catalog/refresh", { method: "POST" });
|
|
3235
|
+
setStatus(updated);
|
|
3236
|
+
const drafts = {};
|
|
3237
|
+
for (const model of updated.models) drafts[model.id] = formatCapacity(updated.contextWindowOverrides[model.id] || model.defaultContextWindow);
|
|
3238
|
+
setContextDrafts(drafts);
|
|
3239
|
+
notifyChange();
|
|
3240
|
+
} catch (err) {
|
|
3241
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3242
|
+
} finally {
|
|
3243
|
+
setBusy(null);
|
|
3244
|
+
}
|
|
3245
|
+
};
|
|
3246
|
+
const handleTestConnection = async () => {
|
|
3247
|
+
try {
|
|
3248
|
+
setBusy("connection");
|
|
3249
|
+
setError(null);
|
|
3250
|
+
setConnectionNotice(null);
|
|
3251
|
+
const result = await fetchApi$3("/connection/test", { method: "POST" });
|
|
3252
|
+
setConnectionNotice(result.connected ? `${t.testSuccess} · ${result.latencyMs} ms` : t.testFailed);
|
|
3253
|
+
await loadStatus(true);
|
|
3254
|
+
} catch (err) {
|
|
3255
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3256
|
+
} finally {
|
|
3257
|
+
setBusy(null);
|
|
3258
|
+
}
|
|
3259
|
+
};
|
|
3260
|
+
const applyEnabled = async (enabledModelIds) => {
|
|
3261
|
+
try {
|
|
3262
|
+
const updated = await fetchApi$3("/models", {
|
|
3263
|
+
method: "POST",
|
|
3264
|
+
body: JSON.stringify({ enabledModelIds })
|
|
3265
|
+
});
|
|
3266
|
+
setStatus(updated);
|
|
3267
|
+
notifyChange();
|
|
3268
|
+
} catch (err) {
|
|
3269
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3270
|
+
}
|
|
3271
|
+
};
|
|
3272
|
+
const toggleModel = (modelId, checked) => {
|
|
3273
|
+
if (!status) return;
|
|
3274
|
+
const current = status.models.filter((model) => model.enabled).map((model) => model.id);
|
|
3275
|
+
const next = checked ? [.../* @__PURE__ */ new Set([...current, modelId])] : current.filter((id) => id !== modelId);
|
|
3276
|
+
if (next.length === 0) return;
|
|
3277
|
+
applyEnabled(next);
|
|
3278
|
+
};
|
|
3279
|
+
const setAllModels = (selectAll) => {
|
|
3280
|
+
if (!status || status.models.length === 0) return;
|
|
3281
|
+
applyEnabled(selectAll ? status.models.map((model) => model.id) : [status.models[0].id]);
|
|
3282
|
+
};
|
|
3283
|
+
const handleUpdateEffort = async (effort) => {
|
|
3284
|
+
try {
|
|
3285
|
+
const updated = await fetchApi$3("/settings", {
|
|
3286
|
+
method: "POST",
|
|
3287
|
+
body: JSON.stringify({ defaultReasoningEffort: effort })
|
|
3288
|
+
});
|
|
3289
|
+
setStatus(updated);
|
|
3290
|
+
notifyChange();
|
|
3291
|
+
} catch (err) {
|
|
3292
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3293
|
+
}
|
|
3294
|
+
};
|
|
3295
|
+
const handleSaveContextWindow = async (modelId) => {
|
|
3296
|
+
const raw = contextDrafts[modelId] || "";
|
|
3297
|
+
const parsed = parsePositiveCapacity(raw);
|
|
3298
|
+
if (parsed === null) {
|
|
3299
|
+
setError(`Invalid context capacity: ${raw}`);
|
|
3300
|
+
return;
|
|
3301
|
+
}
|
|
3302
|
+
try {
|
|
3303
|
+
setSavingModel(modelId);
|
|
3304
|
+
setError(null);
|
|
3305
|
+
const updated = await fetchApi$3("/settings", {
|
|
3306
|
+
method: "POST",
|
|
3307
|
+
body: JSON.stringify({ contextWindowOverrides: { [modelId]: parsed } })
|
|
3308
|
+
});
|
|
3309
|
+
setStatus(updated);
|
|
3310
|
+
setContextDrafts((prev) => ({
|
|
3311
|
+
...prev,
|
|
3312
|
+
[modelId]: formatCapacity(parsed)
|
|
3313
|
+
}));
|
|
3314
|
+
notifyChange();
|
|
3315
|
+
} catch (err) {
|
|
3316
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
3317
|
+
} finally {
|
|
3318
|
+
setSavingModel(null);
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3321
|
+
if (loading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3322
|
+
className: "dsha-page",
|
|
3323
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3324
|
+
className: "dsha-empty",
|
|
3325
|
+
children: t.loading
|
|
3326
|
+
})
|
|
3327
|
+
});
|
|
3328
|
+
const quota = status?.quota;
|
|
3329
|
+
const account = status?.account;
|
|
3330
|
+
const visibleCount = status?.models.filter((model) => model.enabled).length || 0;
|
|
3331
|
+
const loginPending = flow?.status === "pending";
|
|
3332
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3333
|
+
className: "dsha-page",
|
|
3334
|
+
children: [
|
|
3335
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3336
|
+
className: "dsha-group",
|
|
3337
|
+
children: [
|
|
3338
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3339
|
+
className: "dsha-grouphead",
|
|
3340
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: status?.authenticated ? t.account : t.signedOut })
|
|
3341
|
+
}),
|
|
3342
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3343
|
+
className: "dsha-row",
|
|
3344
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3345
|
+
className: "dsha-label",
|
|
3346
|
+
children: status?.authenticated ? t.signedIn : t.signedOut
|
|
3347
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3348
|
+
className: "dsha-value",
|
|
3349
|
+
children: account?.nickname || account?.email || account?.userId || "—"
|
|
3350
|
+
})]
|
|
3351
|
+
}),
|
|
3352
|
+
status?.authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3353
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3354
|
+
className: "dsha-row",
|
|
3355
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3356
|
+
className: "dsha-label",
|
|
3357
|
+
children: t.plan
|
|
3358
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3359
|
+
className: "dsha-value",
|
|
3360
|
+
children: quota?.planName || account?.planName || t.planUnknown
|
|
3361
|
+
})]
|
|
3362
|
+
}),
|
|
3363
|
+
account?.email && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3364
|
+
className: "dsha-row",
|
|
3365
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3366
|
+
className: "dsha-label",
|
|
3367
|
+
children: t.email
|
|
3368
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3369
|
+
className: "dsha-value",
|
|
3370
|
+
children: account.email
|
|
3371
|
+
})]
|
|
3372
|
+
}),
|
|
3373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3374
|
+
className: "dsha-row",
|
|
3375
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3376
|
+
className: "dsha-label",
|
|
3377
|
+
children: t.region
|
|
3378
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3379
|
+
className: "dsha-value",
|
|
3380
|
+
children: status.region === "global" ? t.regionGlobal : t.regionMainland
|
|
3381
|
+
})]
|
|
3382
|
+
}),
|
|
3383
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3384
|
+
className: "dsha-row",
|
|
3385
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3386
|
+
className: "dsha-label",
|
|
3387
|
+
children: t.authenticatedAt
|
|
3388
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3389
|
+
className: "dsha-value",
|
|
3390
|
+
children: formatDate(account?.authenticatedAt)
|
|
3391
|
+
})]
|
|
3392
|
+
})
|
|
3393
|
+
] }),
|
|
3394
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3395
|
+
className: "dsha-row",
|
|
3396
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3397
|
+
className: "dsha-label",
|
|
3398
|
+
children: t.storage
|
|
3399
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3400
|
+
className: "dsha-value",
|
|
3401
|
+
children: status?.storagePath || "—"
|
|
3402
|
+
})]
|
|
3403
|
+
}),
|
|
3404
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3405
|
+
className: "dsha-notice",
|
|
3406
|
+
children: t.storageNotice
|
|
3407
|
+
}),
|
|
3408
|
+
status?.credentialsRejected && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3409
|
+
className: "dsha-notice",
|
|
3410
|
+
children: t.refreshRejected
|
|
3411
|
+
}),
|
|
3412
|
+
loginPending && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3413
|
+
className: "dsha-device-box",
|
|
3414
|
+
children: [
|
|
3415
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.deviceCodeSection }),
|
|
3416
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3417
|
+
className: "dsha-muted",
|
|
3418
|
+
children: t.deviceCodeHint
|
|
3419
|
+
}),
|
|
3420
|
+
flow?.userCode && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3421
|
+
className: "dsha-code-row",
|
|
3422
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3423
|
+
className: "dsha-code",
|
|
3424
|
+
children: flow.userCode
|
|
3425
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3426
|
+
className: "dsha-btn",
|
|
3427
|
+
onClick: () => void handleCopyCode(),
|
|
3428
|
+
children: copied ? t.copied : t.copyCode
|
|
3429
|
+
})]
|
|
3430
|
+
}),
|
|
3431
|
+
flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
3432
|
+
className: "dsha-link",
|
|
3433
|
+
href: flow.verificationUriComplete,
|
|
3434
|
+
target: "_blank",
|
|
3435
|
+
rel: "noreferrer noopener",
|
|
3436
|
+
children: flow.verificationUriComplete
|
|
3437
|
+
}),
|
|
3438
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3439
|
+
className: "dsha-row",
|
|
3440
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3441
|
+
className: "dsha-label",
|
|
3442
|
+
children: t.codeExpires
|
|
3443
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3444
|
+
className: "dsha-value",
|
|
3445
|
+
children: formatDate(flow?.expiresAt)
|
|
3446
|
+
})]
|
|
3447
|
+
}),
|
|
3448
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3449
|
+
className: "dsha-actions",
|
|
3450
|
+
children: [flow?.verificationUriComplete && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
3451
|
+
className: "dsha-btn",
|
|
3452
|
+
href: flow.verificationUriComplete,
|
|
3453
|
+
target: "_blank",
|
|
3454
|
+
rel: "noreferrer noopener",
|
|
3455
|
+
children: t.openSignInPage
|
|
3456
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3457
|
+
className: "dsha-btn",
|
|
3458
|
+
disabled: busy !== null,
|
|
3459
|
+
onClick: () => void handleCancelLogin(),
|
|
3460
|
+
children: t.cancelSignIn
|
|
3461
|
+
})]
|
|
3462
|
+
})
|
|
3463
|
+
]
|
|
3464
|
+
}),
|
|
3465
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3466
|
+
className: "dsha-actions",
|
|
3467
|
+
children: !status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3468
|
+
className: "dsha-btn dsha-btn-primary",
|
|
3469
|
+
disabled: busy !== null || loginPending,
|
|
3470
|
+
onClick: () => void handleLogin(),
|
|
3471
|
+
children: loginPending ? t.waitingAuthorization : busy === "login" ? t.requestingCode : t.signIn
|
|
3472
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3473
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3474
|
+
className: "dsha-btn dsha-btn-primary",
|
|
3475
|
+
disabled: busy !== null || loginPending,
|
|
3476
|
+
onClick: () => void handleLogin(),
|
|
3477
|
+
children: loginPending ? t.waitingAuthorization : t.signInAgain
|
|
3478
|
+
}),
|
|
3479
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3480
|
+
className: "dsha-btn",
|
|
3481
|
+
disabled: busy !== null,
|
|
3482
|
+
onClick: () => void handleRefreshQuota(),
|
|
3483
|
+
children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
|
|
3484
|
+
}),
|
|
3485
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3486
|
+
className: "dsha-btn",
|
|
3487
|
+
disabled: busy !== null,
|
|
3488
|
+
onClick: () => void handleLogout(),
|
|
3489
|
+
children: t.signOut
|
|
3490
|
+
})
|
|
3491
|
+
] })
|
|
3492
|
+
})
|
|
3493
|
+
]
|
|
3494
|
+
}),
|
|
3495
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3496
|
+
className: "dsha-group",
|
|
3497
|
+
children: [
|
|
3498
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3499
|
+
className: "dsha-grouphead",
|
|
3500
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.connection })
|
|
3501
|
+
}),
|
|
3502
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3503
|
+
className: "dsha-row",
|
|
3504
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3505
|
+
className: "dsha-label",
|
|
3506
|
+
children: t.provider
|
|
3507
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3508
|
+
className: "dsha-value",
|
|
3509
|
+
children: t.providerValue
|
|
3510
|
+
})]
|
|
3511
|
+
}),
|
|
3512
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3513
|
+
className: "dsha-row",
|
|
3514
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3515
|
+
className: "dsha-label",
|
|
3516
|
+
children: t.oauthHost
|
|
3517
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3518
|
+
className: "dsha-value",
|
|
3519
|
+
children: status?.oauthHost || "—"
|
|
3520
|
+
})]
|
|
3521
|
+
}),
|
|
3522
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3523
|
+
className: "dsha-row",
|
|
3524
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3525
|
+
className: "dsha-label",
|
|
3526
|
+
children: t.codingEndpoint
|
|
3527
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3528
|
+
className: "dsha-value",
|
|
3529
|
+
children: status?.codingBaseUrl || "—"
|
|
3530
|
+
})]
|
|
3531
|
+
}),
|
|
3532
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3533
|
+
className: "dsha-row",
|
|
3534
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3535
|
+
className: "dsha-label",
|
|
3536
|
+
children: t.connectionState
|
|
3537
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3538
|
+
className: "dsha-value",
|
|
3539
|
+
children: status?.authenticated ? t.connected : t.untested
|
|
3540
|
+
})]
|
|
3541
|
+
}),
|
|
3542
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3543
|
+
className: "dsha-notice",
|
|
3544
|
+
children: status?.serving === false && status.conflict ? t.routeConflict.replace("{detail}", status.conflict) : t.routeOwned
|
|
3545
|
+
}),
|
|
3546
|
+
connectionNotice && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3547
|
+
className: "dsha-muted",
|
|
3548
|
+
children: connectionNotice
|
|
3549
|
+
}),
|
|
3550
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3551
|
+
className: "dsha-actions",
|
|
3552
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3553
|
+
className: "dsha-btn",
|
|
3554
|
+
disabled: busy !== null || !status?.authenticated,
|
|
3555
|
+
onClick: () => void handleTestConnection(),
|
|
3556
|
+
children: busy === "connection" ? t.testingConnection : t.testConnection
|
|
3557
|
+
})
|
|
3558
|
+
})
|
|
3559
|
+
]
|
|
3560
|
+
}),
|
|
3561
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3562
|
+
className: "dsha-group",
|
|
3563
|
+
children: [
|
|
3564
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3565
|
+
className: "dsha-grouphead",
|
|
3566
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3567
|
+
className: "dsha-btn",
|
|
3568
|
+
disabled: busy !== null,
|
|
3569
|
+
onClick: () => void handleRefreshCatalog(),
|
|
3570
|
+
children: busy === "catalog" ? t.refreshingCatalog : t.refreshCatalog
|
|
3571
|
+
})]
|
|
3572
|
+
}),
|
|
3573
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3574
|
+
className: "dsha-muted dsha-models-hint",
|
|
3575
|
+
children: t.modelsHint
|
|
3576
|
+
}),
|
|
3577
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3578
|
+
className: "dsha-models",
|
|
3579
|
+
"aria-label": "Kimi Code Models",
|
|
3580
|
+
children: status?.models.map((model) => {
|
|
3581
|
+
const lastVisible = model.enabled && visibleCount === 1;
|
|
3582
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3583
|
+
title: [
|
|
3584
|
+
model.id,
|
|
3585
|
+
model.wire === "anthropic" ? t.wireAnthropic : t.wireOpenai,
|
|
3586
|
+
...model.supportsVideo ? [t.capVideo] : [],
|
|
3587
|
+
...model.supportsDynamicTools ? [t.capDynamicTools] : [],
|
|
3588
|
+
...model.minimumPlan ? [t.capPlan.replace("{plan}", model.minimumPlan)] : []
|
|
3589
|
+
].join(" · "),
|
|
3590
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3591
|
+
type: "checkbox",
|
|
3592
|
+
checked: model.enabled,
|
|
3593
|
+
disabled: busy !== null || lastVisible,
|
|
3594
|
+
onChange: (event) => toggleModel(model.id, event.currentTarget.checked)
|
|
3595
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name })]
|
|
3596
|
+
}, model.id);
|
|
3597
|
+
})
|
|
3598
|
+
}),
|
|
3599
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3600
|
+
className: "dsha-actions",
|
|
3601
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3602
|
+
className: "dsha-btn",
|
|
3603
|
+
disabled: busy !== null,
|
|
3604
|
+
onClick: () => setAllModels(true),
|
|
3605
|
+
children: t.selectAll
|
|
3606
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3607
|
+
className: "dsha-btn",
|
|
3608
|
+
disabled: busy !== null,
|
|
3609
|
+
onClick: () => setAllModels(false),
|
|
3610
|
+
children: t.unselectAll
|
|
3611
|
+
})]
|
|
3612
|
+
}),
|
|
3613
|
+
status !== null && status.models.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiModelCapabilities, { models: status.models })
|
|
3614
|
+
]
|
|
3615
|
+
}),
|
|
3616
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3617
|
+
className: "dsha-group",
|
|
3618
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3619
|
+
className: "dsha-grouphead",
|
|
3620
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.enhanced })
|
|
3621
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3622
|
+
className: "dsha-pref-row",
|
|
3623
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.defaultReasoningEffort }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3624
|
+
className: "dsha-muted",
|
|
3625
|
+
children: t.defaultReasoningEffortHint
|
|
3626
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
3627
|
+
className: "dsha-select",
|
|
3628
|
+
"aria-label": t.defaultReasoningEffort,
|
|
3629
|
+
value: status?.defaultReasoningEffort ?? "",
|
|
3630
|
+
disabled: busy !== null,
|
|
3631
|
+
onChange: (event) => {
|
|
3632
|
+
const value = event.currentTarget.value;
|
|
3633
|
+
handleUpdateEffort(value === "" ? null : value);
|
|
3634
|
+
},
|
|
3635
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3636
|
+
value: "",
|
|
3637
|
+
children: t.defaultEffortAuto
|
|
3638
|
+
}), KIMI_CODE_REASONING_EFFORTS.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
3639
|
+
value: effort,
|
|
3640
|
+
children: EFFORT_LABEL[effort]
|
|
3641
|
+
}, effort))]
|
|
3642
|
+
})]
|
|
3643
|
+
})]
|
|
3644
|
+
}),
|
|
3645
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3646
|
+
className: "dsha-group",
|
|
3647
|
+
children: [
|
|
3648
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3649
|
+
className: "dsha-grouphead",
|
|
3650
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.contextWindowSection })
|
|
3651
|
+
}),
|
|
3652
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3653
|
+
className: "dsha-muted",
|
|
3654
|
+
children: t.contextWindowHint
|
|
3655
|
+
}),
|
|
3656
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3657
|
+
className: "dsha-context-settings",
|
|
3658
|
+
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3659
|
+
className: "dsha-context-row",
|
|
3660
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3661
|
+
title: model.id,
|
|
3662
|
+
children: [model.name, model.defaultContextWindow < model.contextWindow && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3663
|
+
className: "dsha-model-meta",
|
|
3664
|
+
children: formatCapacity(model.contextWindow)
|
|
3665
|
+
})]
|
|
3666
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3667
|
+
className: "dsha-capacity-control",
|
|
3668
|
+
children: [
|
|
3669
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3670
|
+
type: "text",
|
|
3671
|
+
"aria-label": `${model.name} context window`,
|
|
3672
|
+
value: contextDrafts[model.id] ?? "",
|
|
3673
|
+
onChange: (event) => setContextDrafts({
|
|
3674
|
+
...contextDrafts,
|
|
3675
|
+
[model.id]: event.currentTarget.value
|
|
3676
|
+
}),
|
|
3677
|
+
onKeyDown: (event) => {
|
|
3678
|
+
if (event.key === "Enter") handleSaveContextWindow(model.id);
|
|
3679
|
+
}
|
|
3680
|
+
}),
|
|
3681
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t.tokens }),
|
|
3682
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3683
|
+
type: "button",
|
|
3684
|
+
className: "dsha-context-save",
|
|
3685
|
+
disabled: savingModel === model.id,
|
|
3686
|
+
onClick: () => void handleSaveContextWindow(model.id),
|
|
3687
|
+
children: savingModel === model.id ? t.saving : t.save
|
|
3688
|
+
})
|
|
3689
|
+
]
|
|
3690
|
+
})]
|
|
3691
|
+
}, model.id))
|
|
3692
|
+
})
|
|
3693
|
+
]
|
|
3694
|
+
}),
|
|
3695
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3696
|
+
className: "dsha-group",
|
|
3697
|
+
children: [
|
|
3698
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3699
|
+
className: "dsha-grouphead",
|
|
3700
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.quotaSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3701
|
+
className: "dsha-btn",
|
|
3702
|
+
disabled: busy !== null || !status?.authenticated,
|
|
3703
|
+
onClick: () => void handleRefreshQuota(),
|
|
3704
|
+
children: busy === "quota" ? t.refreshingQuota : t.refreshQuota
|
|
3705
|
+
})]
|
|
3706
|
+
}),
|
|
3707
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3708
|
+
className: "dsha-muted",
|
|
3709
|
+
children: t.quotaDesc
|
|
3710
|
+
}),
|
|
3711
|
+
status?.quotaError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3712
|
+
className: "dsha-notice",
|
|
3713
|
+
children: status.quotaError
|
|
3714
|
+
}),
|
|
3715
|
+
!status?.authenticated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3716
|
+
className: "dsha-empty",
|
|
3717
|
+
children: t.signedOut
|
|
3718
|
+
}) : quota === null || quota === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3719
|
+
className: "dsha-empty",
|
|
3720
|
+
children: busy === "quota" ? t.refreshingQuota : t.quotaEmpty
|
|
3721
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3722
|
+
className: "dsha-quota-card",
|
|
3723
|
+
children: [
|
|
3724
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3725
|
+
className: "dsha-quota-title",
|
|
3726
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t.quotaPlan }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: quota.planName || t.planUnknown })]
|
|
3727
|
+
}),
|
|
3728
|
+
quota.windows.map((window) => {
|
|
3729
|
+
const remaining = Math.max(0, 100 - window.usedPercent);
|
|
3730
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3731
|
+
className: "dsha-meter-wrap",
|
|
3732
|
+
children: [
|
|
3733
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3734
|
+
className: "dsha-meter-label",
|
|
3735
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: window.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [remaining, "% left"] })]
|
|
3736
|
+
}),
|
|
3737
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3738
|
+
className: `dsha-meter ${remaining <= 10 ? "dsha-meter-cyan" : "dsha-meter-green"}`,
|
|
3739
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { width: `${remaining}%` } })
|
|
3740
|
+
}),
|
|
3741
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3742
|
+
className: "dsha-meter-meta",
|
|
3743
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
3744
|
+
window.used ?? "—",
|
|
3745
|
+
" / ",
|
|
3746
|
+
window.limit ?? "—",
|
|
3747
|
+
" ",
|
|
3748
|
+
t.requests
|
|
3749
|
+
] }), window.resetsAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.resetAt.replace("{time}", formatReset(window.resetsAt)) })]
|
|
3750
|
+
})
|
|
3751
|
+
]
|
|
3752
|
+
}, window.id);
|
|
3753
|
+
}),
|
|
3754
|
+
quota.extraUsage !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3755
|
+
className: "dsha-meter-wrap",
|
|
3756
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3757
|
+
className: "dsha-meter-label",
|
|
3758
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.quotaWallet }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: formatMoney(quota.extraUsage.balanceCents, quota.extraUsage.currency) })]
|
|
3759
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3760
|
+
className: "dsha-meter-meta",
|
|
3761
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: formatMoney(quota.extraUsage.totalCents, quota.extraUsage.currency) }), quota.extraUsage.monthlyChargeLimitEnabled && quota.extraUsage.monthlyChargeLimitCents !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
3762
|
+
t.quotaWalletLimit,
|
|
3763
|
+
": ",
|
|
3764
|
+
formatMoney(quota.extraUsage.monthlyChargeLimitCents, quota.extraUsage.currency)
|
|
3765
|
+
] })]
|
|
3766
|
+
})]
|
|
3767
|
+
}),
|
|
3768
|
+
quota.windows.length === 0 && quota.extraUsage === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3769
|
+
className: "dsha-empty",
|
|
3770
|
+
children: t.quotaEmpty
|
|
3771
|
+
}),
|
|
3772
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3773
|
+
className: "dsha-timestamp",
|
|
3774
|
+
children: t.updatedAt.replace("{time}", new Date(quota.fetchedAt).toLocaleString())
|
|
3775
|
+
})
|
|
3776
|
+
]
|
|
3777
|
+
})
|
|
3778
|
+
]
|
|
3779
|
+
}),
|
|
3780
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3781
|
+
className: "dsha-error",
|
|
3782
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error })
|
|
3783
|
+
})
|
|
3784
|
+
]
|
|
3785
|
+
});
|
|
3786
|
+
}
|
|
3787
|
+
//#endregion
|
|
3788
|
+
//#region src/client/ProviderHubSection.tsx
|
|
3789
|
+
const HUB_TABS = [
|
|
3790
|
+
{
|
|
3791
|
+
id: "chatgpt",
|
|
3792
|
+
label: "ChatGPT"
|
|
3793
|
+
},
|
|
3794
|
+
{
|
|
3795
|
+
id: "antigravity",
|
|
3796
|
+
label: "Antigravity"
|
|
3797
|
+
},
|
|
3798
|
+
{
|
|
3799
|
+
id: "command-code",
|
|
3800
|
+
label: "Command Code"
|
|
3801
|
+
},
|
|
3802
|
+
{
|
|
3803
|
+
id: "kimi-code",
|
|
3804
|
+
label: "Kimi Code"
|
|
3805
|
+
}
|
|
3806
|
+
];
|
|
3807
|
+
/**
|
|
3808
|
+
* Single settings page that hosts every subscription provider behind tabs,
|
|
3809
|
+
* so the settings sidebar shows one entry instead of one per provider. Only
|
|
3810
|
+
* the active tab is mounted, mirroring the shell's previous behavior of
|
|
3811
|
+
* mounting just the selected settings page (each provider section refetches
|
|
3812
|
+
* its status on mount).
|
|
3813
|
+
*/
|
|
3814
|
+
function ProviderHubSection({ t, onModelChange, ...runtime }) {
|
|
3815
|
+
const [active, setActive] = (0, react.useState)("chatgpt");
|
|
3816
|
+
const onTabKeyDown = (0, react.useCallback)((event) => {
|
|
3817
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
3818
|
+
event.preventDefault();
|
|
3819
|
+
const index = HUB_TABS.findIndex((tab) => tab.id === active);
|
|
3820
|
+
const delta = event.key === "ArrowRight" ? 1 : -1;
|
|
3821
|
+
const next = HUB_TABS[(index + delta + HUB_TABS.length) % HUB_TABS.length];
|
|
3822
|
+
setActive(next.id);
|
|
3823
|
+
document.getElementById(`dsh-hub-tab-${next.id}`)?.focus();
|
|
3824
|
+
}, [active]);
|
|
3825
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3826
|
+
className: "dsh-codex-page",
|
|
3827
|
+
"aria-labelledby": "dsh-hub-title",
|
|
3828
|
+
children: [
|
|
3829
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
3830
|
+
id: "dsh-hub-title",
|
|
3831
|
+
className: "dsh-codex-title",
|
|
3832
|
+
children: t("hubTitle")
|
|
3833
|
+
}) }),
|
|
3834
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3835
|
+
className: "dsh-codex-segments dsh-hub-tabs",
|
|
3836
|
+
role: "tablist",
|
|
3837
|
+
"aria-label": t("hubTitle"),
|
|
3838
|
+
children: HUB_TABS.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3839
|
+
type: "button",
|
|
3840
|
+
role: "tab",
|
|
3841
|
+
id: `dsh-hub-tab-${tab.id}`,
|
|
3842
|
+
"aria-selected": active === tab.id,
|
|
3843
|
+
"aria-controls": `dsh-hub-panel-${tab.id}`,
|
|
3844
|
+
className: active === tab.id ? "active" : void 0,
|
|
3845
|
+
tabIndex: active === tab.id ? 0 : -1,
|
|
3846
|
+
onClick: () => setActive(tab.id),
|
|
3847
|
+
onKeyDown: onTabKeyDown,
|
|
3848
|
+
children: tab.label
|
|
3849
|
+
}, tab.id))
|
|
3850
|
+
}),
|
|
3851
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3852
|
+
role: "tabpanel",
|
|
3853
|
+
id: `dsh-hub-panel-${active}`,
|
|
3854
|
+
"aria-labelledby": `dsh-hub-tab-${active}`,
|
|
3855
|
+
children: [
|
|
3856
|
+
active === "chatgpt" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodexSubscriptionSection, {
|
|
3857
|
+
t,
|
|
3858
|
+
...runtime
|
|
3859
|
+
}) : null,
|
|
3860
|
+
active === "antigravity" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AntigravitySection, { onModelChange }) : null,
|
|
3861
|
+
active === "command-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CommandCodeSection, { onModelChange }) : null,
|
|
3862
|
+
active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null
|
|
3863
|
+
]
|
|
3864
|
+
})
|
|
3865
|
+
]
|
|
3866
|
+
});
|
|
3867
|
+
}
|
|
3868
|
+
//#endregion
|
|
3869
|
+
//#region src/client/locales.ts
|
|
3870
|
+
const NS = "dsh-chatgpt-subscription";
|
|
3871
|
+
const dictionaries = {
|
|
3872
|
+
zh: {
|
|
3873
|
+
title: "ChatGPT",
|
|
3874
|
+
hubTitle: "订阅服务",
|
|
3875
|
+
intro: "使用 ChatGPT 账号登录,在 DSH 中使用订阅可用的模型。",
|
|
3876
|
+
account: "账号",
|
|
3877
|
+
signedOut: "尚未登录",
|
|
3878
|
+
signedIn: "已登录",
|
|
3879
|
+
plan: "套餐",
|
|
3880
|
+
accountId: "账号 ID",
|
|
3881
|
+
expires: "令牌到期",
|
|
3882
|
+
storage: "凭据存储",
|
|
3883
|
+
storageWindows: "Windows DPAPI(当前用户加密)",
|
|
3884
|
+
storageMacKeychain: "macOS 钥匙串(Keychain 加密)",
|
|
3885
|
+
storageLinuxFile: "Linux 用户私有文件(权限 0600)",
|
|
3886
|
+
storageMemory: "仅 Host 内存(不持久化)",
|
|
3887
|
+
storageUnavailable: "凭据存储不可用",
|
|
3888
|
+
securityWindows: "令牌由 Host 使用 Windows CurrentUser DPAPI 加密,不会进入浏览器、settings.yaml 或日志。",
|
|
3889
|
+
securityMacKeychain: "令牌由 Host 存入 macOS 登录钥匙串(Keychain),在本机加密保存,不会进入浏览器、settings.yaml 或日志。",
|
|
3890
|
+
securityLinuxFile: "令牌仅写入 Host 上当前 Linux 用户可读的 0600 文件,但不会额外加密;同 UID 进程、root、备份和磁盘快照仍可能读取。",
|
|
3891
|
+
securityMemory: "令牌仅保留在 Host 内存中,Host 退出后丢失。",
|
|
3892
|
+
securityUnavailable: "Host 无法安全访问凭据存储;请修复文件所有者或权限后重试。",
|
|
3893
|
+
signIn: "使用 ChatGPT 登录",
|
|
3894
|
+
signInAgain: "重新登录",
|
|
3895
|
+
cancel: "取消登录",
|
|
3896
|
+
signOut: "注销",
|
|
3897
|
+
refreshToken: "刷新凭据",
|
|
3898
|
+
pending: "请在浏览器中完成登录。",
|
|
3899
|
+
popupBlocked: "浏览器拦截了登录窗口,请使用下面的链接继续。",
|
|
3900
|
+
continueLogin: "打开 ChatGPT 登录页",
|
|
3901
|
+
loading: "正在读取状态…",
|
|
3902
|
+
connection: "连接",
|
|
3903
|
+
provider: "Provider",
|
|
3904
|
+
connectionState: "连接状态",
|
|
3905
|
+
connected: "可用",
|
|
3906
|
+
untested: "尚未测试",
|
|
3907
|
+
testConnection: "测试连接",
|
|
3908
|
+
testing: "测试中…",
|
|
3909
|
+
latency: "最近延迟",
|
|
3910
|
+
models: "可用模型",
|
|
3911
|
+
modelsHint: "勾选后模型才会显示在对话页的模型选择列表中;至少保留一个。",
|
|
3912
|
+
proxySettings: "网络代理",
|
|
3913
|
+
proxyMode: "代理模式",
|
|
3914
|
+
proxyModeHint: "GPT 与 Antigravity(Gemini)共用此代理设置;支持自动读取系统代理,修改后对后续请求生效。",
|
|
3915
|
+
proxyModeAuto: "系统代理(自动检测)",
|
|
3916
|
+
proxyModeCustom: "自定义代理",
|
|
3917
|
+
proxyModeDirect: "直连(禁用代理)",
|
|
3918
|
+
customProxyUrl: "自定义代理地址",
|
|
3919
|
+
customProxyUrlHint: "支持 HTTP/HTTPS/SOCKS5 代理地址,例如 http://127.0.0.1:7890",
|
|
3920
|
+
customProxyUrlPlaceholder: "例如: http://127.0.0.1:7890",
|
|
3921
|
+
saveProxyUrl: "保存代理地址",
|
|
3922
|
+
proxyDetected: "检测到系统代理",
|
|
3923
|
+
proxyDetectedEffective: "(已自动生效)",
|
|
3924
|
+
proxyNoneDetected: "未检测到系统代理,将使用直连",
|
|
3925
|
+
proxyDirectHint: "所有网络请求将直接连接,不经过任何代理服务器。",
|
|
3926
|
+
enhancements: "增强功能",
|
|
3927
|
+
fastMode: "快速模式(1.5x 速度)",
|
|
3928
|
+
fastModeHint: "提升 Token 生成速度至约 1.5 倍;将以约 2x–2.5x 速度消耗 Codex 订阅额度。",
|
|
3929
|
+
outputVerbosity: "输出详细程度",
|
|
3930
|
+
outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。",
|
|
3931
|
+
verbosityLow: "低(保持回答简洁)",
|
|
3932
|
+
verbosityMedium: "中(兼顾细节与简洁)",
|
|
3933
|
+
verbosityHigh: "高(在回答中包含更多细节)",
|
|
3934
|
+
reasoningSummary: "推理摘要",
|
|
3935
|
+
reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。",
|
|
3936
|
+
summaryAuto: "自动(让模型选择摘要详细程度)",
|
|
3937
|
+
summaryConcise: "简洁(显示简要推理摘要)",
|
|
3938
|
+
summaryDetailed: "详细(显示更详细的推理摘要)",
|
|
3939
|
+
summaryNone: "无(不显示推理摘要)",
|
|
3940
|
+
searchProvider: "搜索与抓取来源",
|
|
3941
|
+
searchProviderHint: "选择 DSH 联网工具使用默认来源,或改用当前 ChatGPT 订阅的 Codex 来源(自动走代理隧道)。",
|
|
3942
|
+
searchProviderDsh: "DSH 默认",
|
|
3943
|
+
searchProviderCodex: "ChatGPT(代理隧道)",
|
|
3944
|
+
providerDefault: "使用 Provider 默认值",
|
|
3945
|
+
contextWindows: "模型上下文窗口",
|
|
3946
|
+
contextWindowsHint: "默认 272K;6 Astra 最高 872K,GPT-5.6 最高 1M。该值用于 DSH 的压缩与溢出判断,可输入 872K、512K 等容量。",
|
|
3947
|
+
contextWindow: "上下文窗口",
|
|
3948
|
+
contextWindowInvalid: "上下文窗口必须是正整数,且不能超过模型上限(6 Astra 为 872K,GPT-5.6 为 1M);可使用 K 或 M 后缀。",
|
|
3949
|
+
saveContextWindow: "保存上下文窗口",
|
|
3950
|
+
save: "保存",
|
|
3951
|
+
tokens: "tokens",
|
|
3952
|
+
quickQuota: "在输入框旁显示快捷用量",
|
|
3953
|
+
quickQuotaHint: "仅在当前会话选中 codex-chatgpt 模型时显示。",
|
|
3954
|
+
quota: "用量与限额",
|
|
3955
|
+
quotaIntro: "数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。",
|
|
3956
|
+
refreshQuota: "刷新用量",
|
|
3957
|
+
refreshing: "刷新中…",
|
|
3958
|
+
noQuota: "当前套餐未返回可显示的限额窗口。",
|
|
3959
|
+
quotaSignedOut: "登录后可查看订阅限额。",
|
|
3960
|
+
stale: "显示的是上次成功获取的数据。",
|
|
3961
|
+
updated: "更新时间",
|
|
3962
|
+
primary: "主要窗口",
|
|
3963
|
+
secondary: "次要窗口",
|
|
3964
|
+
limitWindow: "额度",
|
|
3965
|
+
used: "已使用",
|
|
3966
|
+
remaining: "剩余",
|
|
3967
|
+
available: "可用",
|
|
3968
|
+
unavailable: "不可用",
|
|
3969
|
+
unlimited: "无限",
|
|
3970
|
+
credits: "Credits",
|
|
3971
|
+
monthlySpend: "月度消费控制",
|
|
3972
|
+
resetCredits: "重置次数",
|
|
3973
|
+
resetCreditExpires: "到期时间",
|
|
3974
|
+
useResetCredit: "使用重置卡",
|
|
3975
|
+
usingResetCredit: "使用中…",
|
|
3976
|
+
useResetCreditConfirm: "使用后会立即消耗 1 次重置机会,并重置符合条件的 Codex 额度窗口。确定继续吗?",
|
|
3977
|
+
resetCreditUsed: "重置卡已使用,用量数据已刷新。",
|
|
3978
|
+
spendControlReached: "已触发月度消费控制,新的订阅调用可能被限制。",
|
|
3979
|
+
limit: "上限",
|
|
3980
|
+
exhausted: "额度已用尽",
|
|
3981
|
+
resets: "重置",
|
|
3982
|
+
quickQuotaLabel: "Codex 剩余",
|
|
3983
|
+
quickQuotaLoading: "用量…",
|
|
3984
|
+
imageToolRunning: "正在生成图片",
|
|
3985
|
+
imageToolDone: "已生成图片",
|
|
3986
|
+
imageToolFailed: "图片生成失败",
|
|
3987
|
+
image: "图片",
|
|
3988
|
+
openImage: "打开图片",
|
|
3989
|
+
openNamedImage: "打开 {name}",
|
|
3990
|
+
imageLoading: "加载图片…",
|
|
3991
|
+
imageLoadFailed: "图片加载失败,点击重试",
|
|
3992
|
+
imagePreviewClose: "关闭",
|
|
3993
|
+
imagePreviewOpenOriginal: "打开原图",
|
|
3994
|
+
retry: "重试",
|
|
3995
|
+
unknown: "未知"
|
|
3996
|
+
},
|
|
3997
|
+
en: {
|
|
3998
|
+
title: "ChatGPT",
|
|
3999
|
+
hubTitle: "Subscriptions",
|
|
4000
|
+
intro: "Sign in with ChatGPT to use models available to your subscription in DSH.",
|
|
4001
|
+
account: "Account",
|
|
4002
|
+
signedOut: "Not signed in",
|
|
4003
|
+
signedIn: "Signed in",
|
|
4004
|
+
plan: "Plan",
|
|
4005
|
+
accountId: "Account ID",
|
|
4006
|
+
expires: "Token expires",
|
|
4007
|
+
storage: "Credential storage",
|
|
4008
|
+
storageWindows: "Windows DPAPI (current-user encrypted)",
|
|
4009
|
+
storageMacKeychain: "macOS Keychain (encrypted)",
|
|
4010
|
+
storageLinuxFile: "Linux user-private file (mode 0600)",
|
|
4011
|
+
storageMemory: "Host memory only (not persistent)",
|
|
4012
|
+
storageUnavailable: "Credential storage unavailable",
|
|
4013
|
+
securityWindows: "The Host encrypts tokens with Windows CurrentUser DPAPI; they never enter the browser, settings.yaml, or logs.",
|
|
4014
|
+
securityMacKeychain: "The Host stores tokens in the macOS login Keychain, encrypted on this machine; they never enter the browser, settings.yaml, or logs.",
|
|
4015
|
+
securityLinuxFile: "Tokens are stored in a mode-0600 file readable only by the current Linux user, but are not additionally encrypted; same-UID processes, root, backups, and disk snapshots can still read them.",
|
|
4016
|
+
securityMemory: "Tokens remain only in Host memory and are lost when the Host exits.",
|
|
4017
|
+
securityUnavailable: "The Host cannot safely access credential storage. Fix the file owner or permissions and retry.",
|
|
4018
|
+
signIn: "Sign in with ChatGPT",
|
|
4019
|
+
signInAgain: "Sign in again",
|
|
4020
|
+
cancel: "Cancel sign-in",
|
|
4021
|
+
signOut: "Sign out",
|
|
4022
|
+
refreshToken: "Refresh credentials",
|
|
4023
|
+
pending: "Complete sign-in in your browser.",
|
|
4024
|
+
popupBlocked: "The sign-in window was blocked. Use the link below to continue.",
|
|
4025
|
+
continueLogin: "Open ChatGPT sign-in",
|
|
4026
|
+
loading: "Reading status…",
|
|
4027
|
+
connection: "Connection",
|
|
4028
|
+
provider: "Provider",
|
|
4029
|
+
connectionState: "Connection status",
|
|
4030
|
+
connected: "Available",
|
|
4031
|
+
untested: "Not tested",
|
|
4032
|
+
testConnection: "Test connection",
|
|
4033
|
+
testing: "Testing…",
|
|
4034
|
+
latency: "Last latency",
|
|
4035
|
+
models: "Available models",
|
|
4036
|
+
modelsHint: "Checked models appear in the conversation model picker; at least one must remain enabled.",
|
|
4037
|
+
proxySettings: "Network Proxy",
|
|
4038
|
+
proxyMode: "Proxy Mode",
|
|
4039
|
+
proxyModeHint: "GPT and Antigravity (Gemini) share these proxy settings. Supports system proxy detection; changes apply to subsequent requests.",
|
|
4040
|
+
proxyModeAuto: "System Proxy (Auto-detect)",
|
|
4041
|
+
proxyModeCustom: "Custom Proxy",
|
|
4042
|
+
proxyModeDirect: "Direct (No Proxy)",
|
|
4043
|
+
customProxyUrl: "Custom Proxy URL",
|
|
4044
|
+
customProxyUrlHint: "Supports HTTP/HTTPS/SOCKS5 proxy URLs, e.g. http://127.0.0.1:7890",
|
|
4045
|
+
customProxyUrlPlaceholder: "e.g. http://127.0.0.1:7890",
|
|
4046
|
+
saveProxyUrl: "Save Proxy URL",
|
|
4047
|
+
proxyDetected: "Detected system proxy",
|
|
4048
|
+
proxyDetectedEffective: " (active)",
|
|
4049
|
+
proxyNoneDetected: "No system proxy detected; connecting directly",
|
|
4050
|
+
proxyDirectHint: "All requests connect directly without using any proxy server.",
|
|
4051
|
+
enhancements: "Enhancements",
|
|
4052
|
+
fastMode: "Fast mode (1.5x speed)",
|
|
4053
|
+
fastModeHint: "Generates tokens ~1.5x faster; consumes Codex subscription quota at ~2x–2.5x the normal rate.",
|
|
4054
|
+
outputVerbosity: "Output verbosity",
|
|
4055
|
+
outputVerbosityHint: "Controls the detail level of final Codex answers without changing reasoning effort.",
|
|
4056
|
+
verbosityLow: "Low (keep answers concise)",
|
|
4057
|
+
verbosityMedium: "Medium (balance detail and brevity)",
|
|
4058
|
+
verbosityHigh: "High (include more detail)",
|
|
4059
|
+
reasoningSummary: "Reasoning summary",
|
|
4060
|
+
reasoningSummaryHint: "Controls how ChatGPT summarizes its chain of thought; does not change reasoning depth.",
|
|
4061
|
+
summaryAuto: "Auto (let model determine detail)",
|
|
4062
|
+
summaryConcise: "Concise (brief summary)",
|
|
4063
|
+
summaryDetailed: "Detailed (in-depth summary)",
|
|
4064
|
+
summaryNone: "None (hide reasoning summary)",
|
|
4065
|
+
searchProvider: "Search & Fetch provider",
|
|
4066
|
+
searchProviderHint: "Choose whether DSH web tools use the default provider or the Codex proxy-backed source from this ChatGPT subscription.",
|
|
4067
|
+
searchProviderDsh: "DSH default",
|
|
4068
|
+
searchProviderCodex: "ChatGPT (Proxy tunnel)",
|
|
4069
|
+
providerDefault: "Use provider default",
|
|
4070
|
+
contextWindows: "Model context windows",
|
|
4071
|
+
contextWindowsHint: "Defaults to 272K, with up to 872K for 6 Astra and 1M for GPT-5.6. DSH uses it for compaction and overflow detection; values such as 872K and 512K are accepted.",
|
|
4072
|
+
contextWindow: "Context window",
|
|
4073
|
+
contextWindowInvalid: "The context window must be a positive integer within the model limit (872K for 6 Astra, 1M for GPT-5.6). K and M suffixes are accepted.",
|
|
4074
|
+
saveContextWindow: "Save context window",
|
|
4075
|
+
save: "Save",
|
|
4076
|
+
tokens: "tokens",
|
|
4077
|
+
quickQuota: "Show quick usage beside the composer",
|
|
4078
|
+
quickQuotaHint: "Shown only when the current session uses a codex-chatgpt model.",
|
|
4079
|
+
quota: "Usage and limits",
|
|
4080
|
+
quotaIntro: "Data comes from the ChatGPT Codex usage service and refreshes at most once per minute while visible.",
|
|
4081
|
+
refreshQuota: "Refresh usage",
|
|
4082
|
+
refreshing: "Refreshing…",
|
|
4083
|
+
noQuota: "Your plan did not return any displayable limit windows.",
|
|
4084
|
+
quotaSignedOut: "Sign in to view subscription limits.",
|
|
4085
|
+
stale: "Showing the last successfully fetched data.",
|
|
4086
|
+
updated: "Updated",
|
|
4087
|
+
primary: "Primary window",
|
|
4088
|
+
secondary: "Secondary window",
|
|
4089
|
+
limitWindow: "limit",
|
|
4090
|
+
used: "used",
|
|
4091
|
+
remaining: "remaining",
|
|
4092
|
+
available: "Available",
|
|
4093
|
+
unavailable: "Unavailable",
|
|
4094
|
+
unlimited: "Unlimited",
|
|
4095
|
+
credits: "Credits",
|
|
4096
|
+
monthlySpend: "Monthly spend control",
|
|
4097
|
+
resetCredits: "Reset credits",
|
|
4098
|
+
resetCreditExpires: "Expires",
|
|
4099
|
+
useResetCredit: "Use reset credit",
|
|
4100
|
+
usingResetCredit: "Using…",
|
|
4101
|
+
useResetCreditConfirm: "This immediately spends one reset credit and resets eligible Codex limit windows. Continue?",
|
|
4102
|
+
resetCreditUsed: "The reset credit was used and usage data was refreshed.",
|
|
4103
|
+
spendControlReached: "Monthly spend control has been reached; new subscription calls may be limited.",
|
|
4104
|
+
limit: "Limit",
|
|
4105
|
+
exhausted: "Quota exhausted",
|
|
4106
|
+
resets: "Resets",
|
|
4107
|
+
quickQuotaLabel: "Codex left",
|
|
4108
|
+
quickQuotaLoading: "Usage…",
|
|
4109
|
+
imageToolRunning: "Generating image",
|
|
4110
|
+
imageToolDone: "Generated image",
|
|
4111
|
+
imageToolFailed: "Image generation failed",
|
|
4112
|
+
image: "Image",
|
|
4113
|
+
openImage: "Open image",
|
|
4114
|
+
openNamedImage: "Open {name}",
|
|
4115
|
+
imageLoading: "Loading image…",
|
|
4116
|
+
imageLoadFailed: "Image failed to load. Click to retry",
|
|
4117
|
+
imagePreviewClose: "Close",
|
|
4118
|
+
imagePreviewOpenOriginal: "Open original",
|
|
4119
|
+
retry: "Retry",
|
|
4120
|
+
unknown: "Unknown"
|
|
4121
|
+
}
|
|
4122
|
+
};
|
|
4123
|
+
//#endregion
|
|
4124
|
+
//#region src/client/styles.ts
|
|
4125
|
+
const STYLE_ID$2 = "@eddyskywalker/dsh-chatgpt-subscription/main";
|
|
4126
|
+
const CSS = `
|
|
4127
|
+
.dsh-codex-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
4128
|
+
.dsh-codex-page *{box-sizing:border-box}
|
|
4129
|
+
.dsh-codex-title{font-size:15px;font-weight:650;line-height:1.4;margin:0 0 5px}
|
|
4130
|
+
.dsh-codex-intro,.dsh-codex-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}
|
|
4131
|
+
.dsh-codex-group{border-top:0.5px solid var(--dsw-alias-border-l2);min-width:0}
|
|
4132
|
+
.dsh-codex-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}
|
|
4133
|
+
.dsh-codex-grouphead h3{font-size:14px;font-weight:650;margin:0}
|
|
4134
|
+
.dsh-codex-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}
|
|
4135
|
+
.dsh-codex-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}
|
|
4136
|
+
.dsh-codex-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right}
|
|
4137
|
+
.dsh-codex-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}
|
|
4138
|
+
.dsh-codex-button{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}
|
|
4139
|
+
.dsh-codex-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4140
|
+
.dsh-codex-button:focus-visible,.dsh-codex-link:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
4141
|
+
.dsh-codex-button:disabled{cursor:default;opacity:.5}
|
|
4142
|
+
.dsh-codex-button-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
4143
|
+
.dsh-codex-notice{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}
|
|
4144
|
+
.dsh-codex-error,.dsh-codex-warning,.dsh-codex-success{font-size:12px;line-height:1.5;margin:8px 0 0}
|
|
4145
|
+
.dsh-codex-error{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4146
|
+
.dsh-codex-warning{color:var(--dsw-alias-label-warning,#c77a18)}
|
|
4147
|
+
.dsh-codex-success{color:var(--dsw-alias-label-success,#2e9b62)}
|
|
4148
|
+
.dsh-codex-errorbar{align-items:center;background:color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 9%,transparent);border:0.5px solid color-mix(in srgb,var(--dsw-alias-label-danger,#d94b4b) 28%,transparent);border-radius:7px;color:var(--dsw-alias-label-danger,#d94b4b);display:flex;font-size:13px;gap:12px;justify-content:space-between;padding:10px 12px}
|
|
4149
|
+
.dsh-codex-link{color:var(--dsw-alias-label-link,#3278d4);display:inline-block;font-size:13px;margin-top:8px}
|
|
4150
|
+
.dsh-codex-models-hint{padding-top:10px}
|
|
4151
|
+
.dsh-codex-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
4152
|
+
.dsh-codex-models label{cursor:pointer;display:block;position:relative}
|
|
4153
|
+
.dsh-codex-models input{position:absolute;opacity:0;pointer-events:none}
|
|
4154
|
+
.dsh-codex-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px}
|
|
4155
|
+
.dsh-codex-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary)}
|
|
4156
|
+
.dsh-codex-models input:focus-visible+span{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
4157
|
+
.dsh-codex-models input:disabled+span{cursor:default;opacity:.5}
|
|
4158
|
+
.dsh-codex-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
4159
|
+
.dsh-codex-pref-row strong,.dsh-codex-check strong{display:block;font-size:13px;font-weight:600;line-height:1.35}
|
|
4160
|
+
.dsh-codex-segments{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:inline-flex;flex-wrap:nowrap;gap:3px;padding:3px}
|
|
4161
|
+
.dsh-codex-segments label{cursor:pointer;display:block;margin:0}
|
|
4162
|
+
.dsh-codex-segments input{position:absolute;opacity:0;pointer-events:none}
|
|
4163
|
+
.dsh-codex-segments span,.dsh-codex-segments button{border:0.5px solid transparent;border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font:inherit;font-size:12px;font-weight:500;line-height:1.2;padding:6px 12px;transition:all .15s ease;user-select:none;white-space:nowrap}
|
|
4164
|
+
.dsh-codex-segments button{background:transparent;cursor:pointer}
|
|
4165
|
+
.dsh-codex-segments label:hover span,.dsh-codex-segments button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
4166
|
+
.dsh-codex-segments input:checked+span,.dsh-codex-segments button.active,.dsh-codex-segments button[aria-pressed=true]{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 22%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 60%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600;box-shadow:0 1px 3px rgba(0,0,0,.15)}
|
|
4167
|
+
.dsh-codex-segments input:focus-visible+span,.dsh-codex-segments button:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
4168
|
+
.dsh-codex-segments input:disabled+span,.dsh-codex-segments button:disabled{cursor:default;opacity:.5}
|
|
4169
|
+
.dsh-codex-select,.dsh-codex-capacity-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px}
|
|
4170
|
+
.dsh-codex-select{max-width:210px;min-width:150px}
|
|
4171
|
+
.dsh-codex-context-settings{border-bottom:0.5px solid var(--dsw-alias-border-l2);display:grid;gap:10px;padding:12px 0}
|
|
4172
|
+
.dsh-codex-context-settings>div>strong{font-size:13px;font-weight:600}
|
|
4173
|
+
.dsh-codex-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
|
|
4174
|
+
.dsh-codex-proxy-control{align-items:center;display:flex;gap:8px;width:100%}
|
|
4175
|
+
.dsh-codex-proxy-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);flex:1;font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;min-width:220px;padding:7px 10px;text-align:left}
|
|
4176
|
+
.dsh-codex-proxy-status{align-items:center;color:var(--dsw-alias-label-secondary);display:flex;flex-wrap:wrap;font-size:12px;gap:6px;margin:6px 0 0}
|
|
4177
|
+
.dsh-codex-proxy-tag{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 18%,transparent);border:0.5px solid color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 45%,transparent);border-radius:4px;color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:2px 6px}
|
|
4178
|
+
.dsh-codex-capacity-control{align-items:center;display:flex;gap:7px}
|
|
4179
|
+
.dsh-codex-capacity-control input{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;text-align:right;width:90px}
|
|
4180
|
+
.dsh-codex-capacity-control input[type=number]{width:110px}
|
|
4181
|
+
.dsh-codex-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
|
|
4182
|
+
.dsh-codex-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
|
|
4183
|
+
.dsh-codex-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4184
|
+
.dsh-codex-context-save:focus-visible{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
4185
|
+
.dsh-codex-context-save:disabled{cursor:default;opacity:.45}
|
|
4186
|
+
.dsh-codex-check{align-items:flex-start;border-bottom:0.5px solid var(--dsw-alias-border-l2);cursor:pointer;display:flex;gap:10px;padding:12px 0}
|
|
4187
|
+
.dsh-codex-check input{flex:none;margin-top:2px}
|
|
4188
|
+
.dsh-codex-check small{color:var(--dsw-alias-label-secondary);display:block;font-size:12px;line-height:1.45;margin-top:2px}
|
|
4189
|
+
.dsh-codex-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
4190
|
+
.dsh-codex-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between}
|
|
4191
|
+
.dsh-codex-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
4192
|
+
.dsh-codex-quota-fact{align-items:flex-start;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;font-size:12px;gap:12px;justify-content:space-between;line-height:1.45;padding:10px 0}
|
|
4193
|
+
.dsh-codex-quota-fact span{color:var(--dsw-alias-label-secondary);flex:none}
|
|
4194
|
+
.dsh-codex-quota-fact strong{font-weight:600;min-width:0;overflow-wrap:anywhere;text-align:right}
|
|
4195
|
+
.dsh-codex-reset-credits{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;padding:10px 0}
|
|
4196
|
+
.dsh-codex-reset-credits-info{display:grid;font-size:12px;gap:2px;grid-template-columns:auto auto}
|
|
4197
|
+
.dsh-codex-reset-credits-info>span{color:var(--dsw-alias-label-secondary)}
|
|
4198
|
+
.dsh-codex-reset-credits-info>strong{font-weight:650;text-align:right}
|
|
4199
|
+
.dsh-codex-reset-credits-info>small{color:var(--dsw-alias-label-tertiary);font-size:11px;grid-column:1/-1}
|
|
4200
|
+
.dsh-codex-meter-wrap{margin-top:13px}
|
|
4201
|
+
.dsh-codex-meter-label,.dsh-codex-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
4202
|
+
.dsh-codex-meter-label{font-size:12px;margin-bottom:6px}
|
|
4203
|
+
.dsh-codex-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}
|
|
4204
|
+
.dsh-codex-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;corner-shape:round;height:7px;overflow:hidden;width:100%}
|
|
4205
|
+
.dsh-codex-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}
|
|
4206
|
+
.dsh-codex-meter-warning>span{background:var(--dsw-alias-label-warning,#d58a24)}
|
|
4207
|
+
.dsh-codex-meter-danger>span{background:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4208
|
+
.dsh-codex-empty{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}
|
|
4209
|
+
.dsh-codex-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}
|
|
4210
|
+
.dsh-codex-skeleton{display:grid;gap:9px;padding-top:10px}
|
|
4211
|
+
.dsh-codex-skeleton span{animation:dsh-codex-pulse 1.4s ease-in-out infinite;background:var(--dsw-alias-bg-layer-2);border-radius:5px;height:42px}
|
|
4212
|
+
.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}
|
|
4213
|
+
.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}
|
|
4214
|
+
.dsh-codex-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-secondary);display:inline-flex;font-size:11px;gap:6px;height:28px;line-height:1;max-width:160px;padding:0 9px;white-space:nowrap}
|
|
4215
|
+
.dsh-codex-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
4216
|
+
.dsh-codex-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
4217
|
+
.dsh-codex-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4218
|
+
.dsh-codex-image-tool{border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:flex;flex-direction:column;gap:8px;margin:4px 0 4px 4px;max-width:520px;padding:10px 12px}
|
|
4219
|
+
.dsh-codex-image-tool-head{align-items:center;display:flex;font-size:13px;gap:8px;min-width:0}
|
|
4220
|
+
.dsh-codex-image-dot{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:50%;corner-shape:round;display:inline-block;flex:none;height:8px;width:8px}
|
|
4221
|
+
.dsh-codex-image-tool[data-state=error] .dsh-codex-image-dot{background:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4222
|
+
.dsh-codex-image-title{font-weight:600}
|
|
4223
|
+
.dsh-codex-image-summary{color:var(--dsw-alias-label-tertiary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
4224
|
+
.dsh-codex-image-grid{display:flex;flex-wrap:wrap;gap:8px}
|
|
4225
|
+
.dsh-codex-image-preview{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:block;max-height:260px;max-width:min(100%,360px);object-fit:contain}
|
|
4226
|
+
.dsh-codex-image-loading,.dsh-codex-image-failed{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-tertiary);display:inline-flex;font-size:12px;line-height:1.4;padding:18px 20px}
|
|
4227
|
+
.dsh-codex-image-failed{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4228
|
+
.dsh-hub-tabs{align-self:flex-start;max-width:100%}
|
|
4229
|
+
@keyframes dsh-codex-pulse{0%,100%{opacity:.45}50%{opacity:.85}}
|
|
4230
|
+
@media(max-width:560px){.dsh-codex-row,.dsh-codex-pref-row,.dsh-codex-quota-fact,.dsh-codex-reset-credits{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value,.dsh-codex-quota-fact strong{text-align:left}.dsh-codex-actions{justify-content:flex-start}.dsh-codex-grouphead{align-items:flex-start;flex-direction:column;gap:0;padding:12px 0}.dsh-codex-meter-meta{align-items:flex-start;flex-direction:column;gap:2px}.dsh-codex-errorbar{align-items:flex-start;flex-direction:column}.dsh-codex-segments{width:100%}.dsh-codex-select{max-width:none;width:100%}.dsh-codex-context-row{align-items:flex-start;flex-direction:column;gap:5px}.dsh-codex-segments label{flex:1}.dsh-codex-segments span{text-align:center}.dsh-codex-image-tool{max-width:100%;margin-left:0}}
|
|
4231
|
+
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
4232
|
+
`;
|
|
4233
|
+
function installStyles() {
|
|
4234
|
+
if (document.querySelector(`style[data-plugin-css="${STYLE_ID$2}"]`) !== null) return () => void 0;
|
|
4235
|
+
const element = document.createElement("style");
|
|
4236
|
+
element.dataset.plugin = "@eddyskywalker/dsh-chatgpt-subscription";
|
|
4237
|
+
element.dataset.pluginCss = STYLE_ID$2;
|
|
4238
|
+
element.textContent = CSS;
|
|
4239
|
+
document.head.appendChild(element);
|
|
4240
|
+
return () => element.remove();
|
|
4241
|
+
}
|
|
4242
|
+
//#endregion
|
|
4243
|
+
//#region src/client/antigravity/styles.ts
|
|
4244
|
+
const STYLE_ID$1 = "dsh-antigravity-settings-style";
|
|
4245
|
+
function installAntigravityStyles() {
|
|
4246
|
+
if (typeof document === "undefined" || document.getElementById("dsh-antigravity-settings-style")) return;
|
|
4247
|
+
const style = document.createElement("style");
|
|
4248
|
+
style.id = STYLE_ID$1;
|
|
4249
|
+
style.textContent = `
|
|
4250
|
+
.dsha-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
4251
|
+
.dsha-page *{box-sizing:border-box}
|
|
4252
|
+
.dsha-group{border-top:0.5px solid var(--dsw-alias-border-l2);min-width:0}
|
|
4253
|
+
.dsha-group:first-of-type{border-top:0}
|
|
4254
|
+
.dsha-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}
|
|
4255
|
+
.dsha-grouphead h3{font-size:14px;font-weight:650;margin:0;color:var(--dsw-alias-label-primary)}
|
|
4256
|
+
.dsha-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}
|
|
4257
|
+
.dsha-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}
|
|
4258
|
+
.dsha-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--dsw-alias-label-primary)}
|
|
4259
|
+
.dsha-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}
|
|
4260
|
+
.dsha-btn{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}
|
|
4261
|
+
.dsha-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4262
|
+
.dsha-btn:disabled{cursor:default;opacity:.5}
|
|
4263
|
+
.dsha-btn-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
4264
|
+
.dsha-btn-primary:hover:not(:disabled){opacity:.9}
|
|
4265
|
+
.dsha-notice{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}
|
|
4266
|
+
.dsha-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}
|
|
4267
|
+
.dsha-models-hint{padding-top:10px}
|
|
4268
|
+
.dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
4269
|
+
.dsha-models label{cursor:pointer;display:block;position:relative}
|
|
4270
|
+
.dsha-models input{position:absolute;opacity:0;pointer-events:none}
|
|
4271
|
+
.dsha-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
|
|
4272
|
+
.dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
|
|
4273
|
+
.dsha-models input:disabled+span{cursor:default;opacity:.5}
|
|
4274
|
+
.dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
4275
|
+
.dsha-pref-row strong{display:block;font-size:13px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary)}
|
|
4276
|
+
.dsha-select{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px;max-width:220px;min-width:160px}
|
|
4277
|
+
.dsha-context-settings{border-bottom:0.5px solid var(--dsw-alias-border-l2);display:grid;gap:10px;padding:12px 0}
|
|
4278
|
+
.dsha-context-settings>div>strong{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
4279
|
+
.dsha-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
|
|
4280
|
+
.dsha-capacity-control{align-items:center;display:flex;gap:7px}
|
|
4281
|
+
.dsha-capacity-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;padding:7px 9px;text-align:right;width:90px}
|
|
4282
|
+
.dsha-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
|
|
4283
|
+
.dsha-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
|
|
4284
|
+
.dsha-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4285
|
+
.dsha-context-save:disabled{cursor:default;opacity:.45}
|
|
4286
|
+
.dsha-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
4287
|
+
.dsha-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between;color:var(--dsw-alias-label-primary);font-weight:650}
|
|
4288
|
+
.dsha-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
4289
|
+
.dsha-meter-wrap{margin-top:13px}
|
|
4290
|
+
.dsha-meter-label,.dsha-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
4291
|
+
.dsha-meter-label{font-size:12px;margin-bottom:6px;color:var(--dsw-alias-label-primary)}
|
|
4292
|
+
.dsha-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}
|
|
4293
|
+
.dsha-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;corner-shape:round;height:7px;overflow:hidden;width:100%}
|
|
4294
|
+
.dsha-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}
|
|
4295
|
+
.dsha-meter-green>span{background:var(--dsw-alias-label-success,#10b981)}
|
|
4296
|
+
.dsha-meter-cyan>span{background:#06b6d4}
|
|
4297
|
+
.dsha-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}
|
|
4298
|
+
.dsha-mini-btn{border:0;background:transparent;color:var(--dsw-alias-label-link,#397ee8);font-size:12px;line-height:18px;cursor:pointer;padding:0;margin-left:8px}
|
|
4299
|
+
.dsha-mini-btn:hover{text-decoration:underline}
|
|
4300
|
+
.dsha-empty{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}
|
|
4301
|
+
.dsha-error{color:var(--dsw-alias-label-danger,#d94b4b);font-size:12px;margin:8px 0 0}
|
|
4302
|
+
.dsha-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-secondary);cursor:pointer;display:inline-flex;font-size:11px;gap:6px;height:28px;line-height:1;max-width:160px;padding:0 9px;white-space:nowrap;user-select:none;transition:all .15s ease}
|
|
4303
|
+
.dsha-composer-quota:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l1,var(--dsw-alias-border-l2))}
|
|
4304
|
+
.dsha-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
4305
|
+
.dsha-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
4306
|
+
.dsha-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4307
|
+
`;
|
|
4308
|
+
document.head.append(style);
|
|
4309
|
+
}
|
|
4310
|
+
//#endregion
|
|
4311
|
+
//#region src/client/antigravity/AntigravityComposerQuota.tsx
|
|
4312
|
+
const API$2 = "/antigravity/api";
|
|
4313
|
+
async function fetchApi$2(path, options) {
|
|
4314
|
+
const res = await fetch(`${API$2}${path}`, {
|
|
4315
|
+
...options,
|
|
4316
|
+
headers: {
|
|
4317
|
+
"Content-Type": "application/json",
|
|
4318
|
+
...options?.headers
|
|
4319
|
+
}
|
|
4320
|
+
});
|
|
4321
|
+
const json = await res.json();
|
|
4322
|
+
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
4323
|
+
return json.value;
|
|
4324
|
+
}
|
|
4325
|
+
function selectQuotaBucketForModel(groups, modelId) {
|
|
4326
|
+
if (!groups || groups.length === 0) return null;
|
|
4327
|
+
const isClaudeOrGpt = modelId ? /claude|gpt/i.test(modelId) : false;
|
|
4328
|
+
const targetGroup = groups.find((g) => {
|
|
2368
4329
|
const match = /claude|gpt|3p/i.test(g.displayName);
|
|
2369
4330
|
return isClaudeOrGpt ? match : !match;
|
|
2370
4331
|
}) || groups[0];
|
|
@@ -2391,7 +4352,7 @@ window.__ModuleLoader__.load({
|
|
|
2391
4352
|
}
|
|
2392
4353
|
}
|
|
2393
4354
|
function AntigravityComposerQuota({ directory, loadModelDirectory }) {
|
|
2394
|
-
const modelState = useStore(directory);
|
|
4355
|
+
const modelState = useStore$2(directory);
|
|
2395
4356
|
const [status, setStatus] = (0, react.useState)(null);
|
|
2396
4357
|
const [loading, setLoading] = (0, react.useState)(false);
|
|
2397
4358
|
const mountedRef = (0, react.useRef)(false);
|
|
@@ -2410,7 +4371,7 @@ window.__ModuleLoader__.load({
|
|
|
2410
4371
|
if (!mountedRef.current) return;
|
|
2411
4372
|
setLoading(true);
|
|
2412
4373
|
try {
|
|
2413
|
-
const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
|
|
4374
|
+
const data = refresh ? await fetchApi$2("/quota", { method: "POST" }) : await fetchApi$2("/status");
|
|
2414
4375
|
if (mountedRef.current) setStatus(data);
|
|
2415
4376
|
} catch {} finally {
|
|
2416
4377
|
if (mountedRef.current) setLoading(false);
|
|
@@ -2448,10 +4409,330 @@ window.__ModuleLoader__.load({
|
|
|
2448
4409
|
})]
|
|
2449
4410
|
});
|
|
2450
4411
|
}
|
|
4412
|
+
function useStore$2(store) {
|
|
4413
|
+
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
4414
|
+
}
|
|
4415
|
+
//#endregion
|
|
4416
|
+
//#region src/client/command-code/CommandCodeComposerQuota.tsx
|
|
4417
|
+
const API$1 = "/command-code/api";
|
|
4418
|
+
async function fetchApi$1(path, options) {
|
|
4419
|
+
const res = await fetch(`${API$1}${path}`, {
|
|
4420
|
+
...options,
|
|
4421
|
+
headers: {
|
|
4422
|
+
"Content-Type": "application/json",
|
|
4423
|
+
...options?.headers
|
|
4424
|
+
}
|
|
4425
|
+
});
|
|
4426
|
+
const json = await res.json();
|
|
4427
|
+
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
4428
|
+
return json.value;
|
|
4429
|
+
}
|
|
4430
|
+
/**
|
|
4431
|
+
* Pick the most meaningful number for the badge.
|
|
4432
|
+
*
|
|
4433
|
+
* A bounded usage window is the number a user actually spends down, so it wins
|
|
4434
|
+
* over a credit balance; the balance shows only when no window is reported.
|
|
4435
|
+
*/
|
|
4436
|
+
function selectBadgeFacts$1(status) {
|
|
4437
|
+
const quota = status?.quota;
|
|
4438
|
+
if (quota === null || quota === void 0) return {
|
|
4439
|
+
text: "—",
|
|
4440
|
+
tooltip: "Command Code quota unavailable — click to refresh",
|
|
4441
|
+
level: "normal"
|
|
4442
|
+
};
|
|
4443
|
+
const window = [...quota.windows ?? []].sort((a, b) => (a.windowDurationMins ?? Infinity) - (b.windowDurationMins ?? Infinity))[0];
|
|
4444
|
+
if (window !== void 0) {
|
|
4445
|
+
const remaining = Math.max(0, 100 - window.usedPercent);
|
|
4446
|
+
return {
|
|
4447
|
+
text: `${remaining}%`,
|
|
4448
|
+
tooltip: `[Command Code] ${window.label}: ${remaining}% left`,
|
|
4449
|
+
level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
|
|
4450
|
+
};
|
|
4451
|
+
}
|
|
4452
|
+
const meter = (quota.meters ?? []).find((candidate) => candidate.remainingFraction !== null);
|
|
4453
|
+
if (meter !== void 0 && meter.remainingFraction !== null) {
|
|
4454
|
+
const remaining = Math.round(meter.remainingFraction * 100);
|
|
4455
|
+
return {
|
|
4456
|
+
text: `${remaining}%`,
|
|
4457
|
+
tooltip: `[Command Code] ${meter.label}: ${remaining}% left`,
|
|
4458
|
+
level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
|
|
4459
|
+
};
|
|
4460
|
+
}
|
|
4461
|
+
if (quota.unlimited) return {
|
|
4462
|
+
text: "∞",
|
|
4463
|
+
tooltip: "[Command Code] Unlimited plan allowance",
|
|
4464
|
+
level: "normal"
|
|
4465
|
+
};
|
|
4466
|
+
if (quota.creditBalance !== null) return {
|
|
4467
|
+
text: quota.creditBalance,
|
|
4468
|
+
tooltip: `[Command Code] Remaining credits: ${quota.creditBalance}`,
|
|
4469
|
+
level: "normal"
|
|
4470
|
+
};
|
|
4471
|
+
return {
|
|
4472
|
+
text: "—",
|
|
4473
|
+
tooltip: "Command Code quota unavailable — click to refresh",
|
|
4474
|
+
level: "normal"
|
|
4475
|
+
};
|
|
4476
|
+
}
|
|
4477
|
+
function CommandCodeComposerQuota({ directory, loadModelDirectory }) {
|
|
4478
|
+
const modelState = useStore$1(directory);
|
|
4479
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
4480
|
+
const [loading, setLoading] = (0, react.useState)(false);
|
|
4481
|
+
const mountedRef = (0, react.useRef)(false);
|
|
4482
|
+
const isCommandCode = modelState.current?.provider === "command-code";
|
|
4483
|
+
(0, react.useEffect)(() => {
|
|
4484
|
+
loadModelDirectory();
|
|
4485
|
+
}, [loadModelDirectory]);
|
|
4486
|
+
(0, react.useEffect)(() => {
|
|
4487
|
+
mountedRef.current = true;
|
|
4488
|
+
return () => {
|
|
4489
|
+
mountedRef.current = false;
|
|
4490
|
+
};
|
|
4491
|
+
}, []);
|
|
4492
|
+
const fetchStatus = (0, react.useCallback)(async (refresh = false) => {
|
|
4493
|
+
if (!mountedRef.current) return;
|
|
4494
|
+
setLoading(true);
|
|
4495
|
+
try {
|
|
4496
|
+
const data = refresh ? await fetchApi$1("/quota", { method: "POST" }) : await fetchApi$1("/status");
|
|
4497
|
+
if (mountedRef.current) setStatus(data);
|
|
4498
|
+
} catch {} finally {
|
|
4499
|
+
if (mountedRef.current) setLoading(false);
|
|
4500
|
+
}
|
|
4501
|
+
}, []);
|
|
4502
|
+
(0, react.useEffect)(() => {
|
|
4503
|
+
if (!isCommandCode) return;
|
|
4504
|
+
fetchStatus(false);
|
|
4505
|
+
const timer = window.setInterval(() => {
|
|
4506
|
+
if (document.visibilityState === "visible") fetchStatus(false);
|
|
4507
|
+
}, 6e4);
|
|
4508
|
+
return () => {
|
|
4509
|
+
window.clearInterval(timer);
|
|
4510
|
+
};
|
|
4511
|
+
}, [fetchStatus, isCommandCode]);
|
|
4512
|
+
const facts = (0, react.useMemo)(() => selectBadgeFacts$1(status), [status]);
|
|
4513
|
+
if (!isCommandCode || !status?.authenticated || facts === null) return null;
|
|
4514
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4515
|
+
className: "dsha-composer-quota",
|
|
4516
|
+
"data-level": facts.level,
|
|
4517
|
+
title: facts.tooltip,
|
|
4518
|
+
"aria-label": facts.tooltip,
|
|
4519
|
+
onClick: () => void fetchStatus(true),
|
|
4520
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4521
|
+
className: "dsha-composer-quota-label",
|
|
4522
|
+
children: "额度"
|
|
4523
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
4524
|
+
className: "dsha-composer-quota-val",
|
|
4525
|
+
children: loading ? "…" : facts.text
|
|
4526
|
+
})]
|
|
4527
|
+
});
|
|
4528
|
+
}
|
|
4529
|
+
function useStore$1(store) {
|
|
4530
|
+
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
4531
|
+
}
|
|
4532
|
+
//#endregion
|
|
4533
|
+
//#region src/client/kimi-code/KimiCodeComposerQuota.tsx
|
|
4534
|
+
const API = "/kimi-code/api";
|
|
4535
|
+
async function fetchApi(path, options) {
|
|
4536
|
+
const res = await fetch(`${API}${path}`, {
|
|
4537
|
+
...options,
|
|
4538
|
+
headers: {
|
|
4539
|
+
"Content-Type": "application/json",
|
|
4540
|
+
...options?.headers
|
|
4541
|
+
}
|
|
4542
|
+
});
|
|
4543
|
+
const json = await res.json();
|
|
4544
|
+
if (!res.ok || !json.ok) throw new Error(json.error || `HTTP ${res.status}`);
|
|
4545
|
+
return json.value;
|
|
4546
|
+
}
|
|
4547
|
+
/**
|
|
4548
|
+
* Pick the most meaningful number for the badge.
|
|
4549
|
+
*
|
|
4550
|
+
* The shortest window is the one a user spends down first and the one that
|
|
4551
|
+
* blocks work soonest, so it wins over the longer pools; the 7-day allowance
|
|
4552
|
+
* shows only when no 5-hour window is reported.
|
|
4553
|
+
*/
|
|
4554
|
+
function selectBadgeFacts(status) {
|
|
4555
|
+
const quota = status?.quota;
|
|
4556
|
+
if (quota === null || quota === void 0) return {
|
|
4557
|
+
text: "—",
|
|
4558
|
+
tooltip: "[Kimi Code] quota unavailable — click to refresh",
|
|
4559
|
+
level: "normal"
|
|
4560
|
+
};
|
|
4561
|
+
const window = [...quota.windows ?? []].filter((candidate) => candidate.windowDurationMins !== null).sort((a, b) => (a.windowDurationMins ?? Infinity) - (b.windowDurationMins ?? Infinity))[0] ?? quota.windows[0];
|
|
4562
|
+
if (window !== void 0) {
|
|
4563
|
+
const remaining = Math.max(0, 100 - window.usedPercent);
|
|
4564
|
+
return {
|
|
4565
|
+
text: `${remaining}%`,
|
|
4566
|
+
tooltip: `[Kimi Code] ${window.label}: ${remaining}% left`,
|
|
4567
|
+
level: remaining <= 5 ? "danger" : remaining <= 20 ? "warning" : "normal"
|
|
4568
|
+
};
|
|
4569
|
+
}
|
|
4570
|
+
const wallet = quota.extraUsage;
|
|
4571
|
+
if (wallet !== null && wallet !== void 0 && wallet.balanceCents !== null) {
|
|
4572
|
+
const amount = (wallet.balanceCents / 100).toFixed(2);
|
|
4573
|
+
return {
|
|
4574
|
+
text: amount,
|
|
4575
|
+
tooltip: `[Kimi Code] booster wallet: ${amount} ${wallet.currency ?? ""}`.trim(),
|
|
4576
|
+
level: "normal"
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
return {
|
|
4580
|
+
text: "—",
|
|
4581
|
+
tooltip: "[Kimi Code] quota unavailable — click to refresh",
|
|
4582
|
+
level: "normal"
|
|
4583
|
+
};
|
|
4584
|
+
}
|
|
4585
|
+
function KimiCodeComposerQuota({ directory, loadModelDirectory }) {
|
|
4586
|
+
const modelState = useStore(directory);
|
|
4587
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
4588
|
+
const [loading, setLoading] = (0, react.useState)(false);
|
|
4589
|
+
const mountedRef = (0, react.useRef)(false);
|
|
4590
|
+
const isKimiCode = modelState.current?.provider === "kimi-code";
|
|
4591
|
+
(0, react.useEffect)(() => {
|
|
4592
|
+
loadModelDirectory();
|
|
4593
|
+
}, [loadModelDirectory]);
|
|
4594
|
+
(0, react.useEffect)(() => {
|
|
4595
|
+
mountedRef.current = true;
|
|
4596
|
+
return () => {
|
|
4597
|
+
mountedRef.current = false;
|
|
4598
|
+
};
|
|
4599
|
+
}, []);
|
|
4600
|
+
const fetchStatus = (0, react.useCallback)(async (refresh = false) => {
|
|
4601
|
+
if (!mountedRef.current) return;
|
|
4602
|
+
setLoading(true);
|
|
4603
|
+
try {
|
|
4604
|
+
const data = refresh ? await fetchApi("/quota", { method: "POST" }) : await fetchApi("/status");
|
|
4605
|
+
if (mountedRef.current) setStatus(data);
|
|
4606
|
+
} catch {} finally {
|
|
4607
|
+
if (mountedRef.current) setLoading(false);
|
|
4608
|
+
}
|
|
4609
|
+
}, []);
|
|
4610
|
+
(0, react.useEffect)(() => {
|
|
4611
|
+
if (!isKimiCode) return;
|
|
4612
|
+
fetchStatus(false);
|
|
4613
|
+
const timer = window.setInterval(() => {
|
|
4614
|
+
if (document.visibilityState === "visible") fetchStatus(false);
|
|
4615
|
+
}, 6e4);
|
|
4616
|
+
return () => {
|
|
4617
|
+
window.clearInterval(timer);
|
|
4618
|
+
};
|
|
4619
|
+
}, [fetchStatus, isKimiCode]);
|
|
4620
|
+
const facts = (0, react.useMemo)(() => selectBadgeFacts(status), [status]);
|
|
4621
|
+
if (!isKimiCode || !status?.authenticated || facts === null) return null;
|
|
4622
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4623
|
+
className: "dsha-composer-quota",
|
|
4624
|
+
"data-level": facts.level,
|
|
4625
|
+
title: facts.tooltip,
|
|
4626
|
+
"aria-label": facts.tooltip,
|
|
4627
|
+
onClick: () => void fetchStatus(true),
|
|
4628
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4629
|
+
className: "dsha-composer-quota-label",
|
|
4630
|
+
children: "额度"
|
|
4631
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", {
|
|
4632
|
+
className: "dsha-composer-quota-val",
|
|
4633
|
+
children: loading ? "…" : facts.text
|
|
4634
|
+
})]
|
|
4635
|
+
});
|
|
4636
|
+
}
|
|
2451
4637
|
function useStore(store) {
|
|
2452
4638
|
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
2453
4639
|
}
|
|
2454
4640
|
//#endregion
|
|
4641
|
+
//#region src/client/kimi-code/styles.ts
|
|
4642
|
+
const STYLE_ID = "dsh-kimi-code-settings-style";
|
|
4643
|
+
/**
|
|
4644
|
+
* Node the base control styles come from.
|
|
4645
|
+
*
|
|
4646
|
+
* The Kimi Code card renders the same controls as the sibling routes, so it
|
|
4647
|
+
* reuses one extracted stylesheet verbatim rather than re-declaring a parallel
|
|
4648
|
+
* design system that would drift from it.
|
|
4649
|
+
*/
|
|
4650
|
+
const BASE = `
|
|
4651
|
+
.dsha-page{box-sizing:border-box;color:var(--dsw-alias-label-primary);display:flex;flex-direction:column;gap:20px;max-width:780px;min-width:0;padding:2px 0 30px}
|
|
4652
|
+
.dsha-page *{box-sizing:border-box}
|
|
4653
|
+
.dsha-group{border-top:0.5px solid var(--dsw-alias-border-l2);min-width:0}
|
|
4654
|
+
.dsha-group:first-of-type{border-top:0}
|
|
4655
|
+
.dsha-grouphead{align-items:center;display:flex;gap:12px;justify-content:space-between;min-height:48px}
|
|
4656
|
+
.dsha-grouphead h3{font-size:14px;font-weight:650;margin:0;color:var(--dsw-alias-label-primary)}
|
|
4657
|
+
.dsha-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:20px;justify-content:space-between;min-height:44px;padding:8px 0}
|
|
4658
|
+
.dsha-label{color:var(--dsw-alias-label-secondary);font-size:13px;flex:0 0 auto}
|
|
4659
|
+
.dsha-value{font-size:13px;min-width:0;overflow-wrap:anywhere;text-align:right;color:var(--dsw-alias-label-primary)}
|
|
4660
|
+
.dsha-actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;padding-top:12px}
|
|
4661
|
+
.dsha-btn{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:13px;line-height:1;padding:8px 13px;white-space:nowrap}
|
|
4662
|
+
.dsha-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4663
|
+
.dsha-btn:disabled{cursor:default;opacity:.5}
|
|
4664
|
+
.dsha-btn-primary{background:var(--dsw-alias-button-info-fill,#397ee8);border-color:transparent;color:var(--dsw-alias-button-info-label,#fff)}
|
|
4665
|
+
.dsha-btn-primary:hover:not(:disabled){opacity:.9}
|
|
4666
|
+
.dsha-notice{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.55;margin:12px 0 0;padding:10px 12px}
|
|
4667
|
+
.dsha-muted{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55;margin:0}
|
|
4668
|
+
.dsha-models-hint{padding-top:10px}
|
|
4669
|
+
.dsha-models{display:flex;flex-wrap:wrap;gap:7px;padding-top:8px}
|
|
4670
|
+
.dsha-models label{cursor:pointer;display:block;position:relative}
|
|
4671
|
+
.dsha-models input{position:absolute;opacity:0;pointer-events:none}
|
|
4672
|
+
.dsha-models span{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:5px 8px;transition:all .15s ease}
|
|
4673
|
+
.dsha-models input:checked+span{background:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 14%,var(--dsw-alias-bg-layer-2));border-color:color-mix(in srgb,var(--dsw-alias-button-info-fill,#397ee8) 55%,var(--dsw-alias-border-l2));color:var(--dsw-alias-label-primary);font-weight:600}
|
|
4674
|
+
.dsha-models input:disabled+span{cursor:default;opacity:.5}
|
|
4675
|
+
.dsha-pref-row{align-items:center;border-bottom:0.5px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
4676
|
+
.dsha-pref-row strong{display:block;font-size:13px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary)}
|
|
4677
|
+
.dsha-select{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:7px 9px;max-width:220px;min-width:160px}
|
|
4678
|
+
.dsha-context-settings{border-bottom:0.5px solid var(--dsw-alias-border-l2);display:grid;gap:10px;padding:12px 0}
|
|
4679
|
+
.dsha-context-settings>div>strong{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}
|
|
4680
|
+
.dsha-context-row{align-items:center;display:flex;font-size:12px;gap:14px;justify-content:space-between}
|
|
4681
|
+
.dsha-capacity-control{align-items:center;display:flex;gap:7px}
|
|
4682
|
+
.dsha-capacity-control input{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font:inherit;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;padding:7px 9px;text-align:right;width:90px}
|
|
4683
|
+
.dsha-capacity-control small{color:var(--dsw-alias-label-tertiary);font-size:11px;width:42px}
|
|
4684
|
+
.dsha-context-save{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);cursor:pointer;font:inherit;font-size:12px;line-height:1;padding:8px 10px;white-space:nowrap}
|
|
4685
|
+
.dsha-context-save:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
4686
|
+
.dsha-context-save:disabled{cursor:default;opacity:.45}
|
|
4687
|
+
.dsha-quota-card{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
4688
|
+
.dsha-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between;color:var(--dsw-alias-label-primary);font-weight:650}
|
|
4689
|
+
.dsha-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
4690
|
+
.dsha-meter-wrap{margin-top:13px}
|
|
4691
|
+
.dsha-meter-label,.dsha-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
4692
|
+
.dsha-meter-label{font-size:12px;margin-bottom:6px;color:var(--dsw-alias-label-primary)}
|
|
4693
|
+
.dsha-meter-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45;margin-top:6px}
|
|
4694
|
+
.dsha-meter{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.15));border-radius:999px;corner-shape:round;height:7px;overflow:hidden;width:100%}
|
|
4695
|
+
.dsha-meter>span{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:inherit;display:block;height:100%;max-width:100%;min-width:0;transition:width .25s ease}
|
|
4696
|
+
.dsha-meter-green>span{background:var(--dsw-alias-label-success,#10b981)}
|
|
4697
|
+
.dsha-meter-cyan>span{background:#06b6d4}
|
|
4698
|
+
.dsha-timestamp{color:var(--dsw-alias-label-tertiary);font-size:11px;margin:10px 0 0;text-align:right}
|
|
4699
|
+
.dsha-mini-btn{border:0;background:transparent;color:var(--dsw-alias-label-link,#397ee8);font-size:12px;line-height:18px;cursor:pointer;padding:0;margin-left:8px}
|
|
4700
|
+
.dsha-mini-btn:hover{text-decoration:underline}
|
|
4701
|
+
.dsha-empty{border:0.5px dashed var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;margin:12px 0 0;padding:16px;text-align:center}
|
|
4702
|
+
.dsha-error{color:var(--dsw-alias-label-danger,#d94b4b);font-size:12px;margin:8px 0 0}
|
|
4703
|
+
.dsha-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;corner-shape:round;color:var(--dsw-alias-label-secondary);cursor:pointer;display:inline-flex;font-size:11px;gap:6px;height:28px;line-height:1;max-width:160px;padding:0 9px;white-space:nowrap;user-select:none;transition:all .15s ease}
|
|
4704
|
+
.dsha-composer-quota:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l1,var(--dsw-alias-border-l2))}
|
|
4705
|
+
.dsha-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
4706
|
+
.dsha-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
4707
|
+
.dsha-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
4708
|
+
|
|
4709
|
+
.dsha-device-box{background:var(--dsw-alias-bg-layer-2);border:0.5px solid var(--dsw-alias-border-l2);border-radius:8px;display:flex;flex-direction:column;gap:10px;margin-top:12px;padding:12px}
|
|
4710
|
+
.dsha-code-row{align-items:center;display:flex;flex-wrap:wrap;gap:10px;justify-content:space-between}
|
|
4711
|
+
.dsha-code{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.14));border:0.5px solid var(--dsw-alias-border-l2);border-radius:7px;color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:16px;font-weight:650;letter-spacing:.14em;padding:8px 12px}
|
|
4712
|
+
.dsha-link{color:var(--dsw-alias-label-link,#397ee8);font-size:12px;overflow-wrap:anywhere;text-decoration:none}
|
|
4713
|
+
.dsha-link:hover{text-decoration:underline}
|
|
4714
|
+
.dsha-model-meta{color:var(--dsw-alias-label-tertiary);font-size:11px;margin-left:5px}
|
|
4715
|
+
.dsha-badge{background:var(--dsw-alias-bg-layer-1,rgba(127,127,127,.14));border:0.5px solid var(--dsw-alias-border-l2);border-radius:999px;color:var(--dsw-alias-label-tertiary);font-size:10px;padding:2px 6px}
|
|
4716
|
+
.dsha-cap-table{border-bottom:0.5px solid var(--dsw-alias-border-l2);padding:12px 0}
|
|
4717
|
+
.dsha-cap-table table{border-collapse:collapse;font-size:11px;width:100%}
|
|
4718
|
+
.dsha-cap-table th{color:var(--dsw-alias-label-tertiary);font-size:11px;font-weight:500;padding:0 10px 6px 0;text-align:left;white-space:nowrap}
|
|
4719
|
+
.dsha-cap-table th:last-child,.dsha-cap-table td:last-child{padding-right:0}
|
|
4720
|
+
.dsha-cap-table td{border-top:0.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);padding:8px 10px 8px 0;vertical-align:top}
|
|
4721
|
+
.dsha-cap-table td:first-child{color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;white-space:nowrap}
|
|
4722
|
+
.dsha-cap-table td:nth-child(2),.dsha-cap-table td:nth-child(3){white-space:nowrap}
|
|
4723
|
+
.dsha-cap-on{color:var(--dsw-alias-label-primary);font-weight:500}
|
|
4724
|
+
.dsha-cap-off{color:var(--dsw-alias-label-tertiary)}
|
|
4725
|
+
.dsha-cap-notes{line-height:1.5;min-width:200px}
|
|
4726
|
+
`;
|
|
4727
|
+
/** Kimi-specific rules layered on top of the shared control styles. */
|
|
4728
|
+
function installKimiCodeStyles() {
|
|
4729
|
+
if (typeof document === "undefined" || document.getElementById("dsh-kimi-code-settings-style")) return;
|
|
4730
|
+
const style = document.createElement("style");
|
|
4731
|
+
style.id = STYLE_ID;
|
|
4732
|
+
style.textContent = BASE;
|
|
4733
|
+
document.head.appendChild(style);
|
|
4734
|
+
}
|
|
4735
|
+
//#endregion
|
|
2455
4736
|
//#region src/client/mermaid/sanitize.ts
|
|
2456
4737
|
const STRIP_ELEMENTS = /* @__PURE__ */ new Set([
|
|
2457
4738
|
"foreignobject",
|
|
@@ -2789,39 +5070,41 @@ window.__ModuleLoader__.load({
|
|
|
2789
5070
|
"conversation"
|
|
2790
5071
|
];
|
|
2791
5072
|
function apply(ctx) {
|
|
2792
|
-
ctx.effect(() => ctx.locale.register(NS, dictionaries
|
|
5073
|
+
ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
|
|
2793
5074
|
ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
|
|
2794
|
-
ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries), "dsh-antigravity: dictionaries");
|
|
5075
|
+
ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$3), "dsh-antigravity: dictionaries");
|
|
2795
5076
|
ctx.effect(() => {
|
|
2796
5077
|
installAntigravityStyles();
|
|
2797
5078
|
return () => {};
|
|
2798
5079
|
}, "dsh-antigravity: styles");
|
|
5080
|
+
ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$2), "dsh-command-code: dictionaries");
|
|
5081
|
+
ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$1), "dsh-kimi-code: dictionaries");
|
|
5082
|
+
ctx.effect(() => {
|
|
5083
|
+
installKimiCodeStyles();
|
|
5084
|
+
return () => {};
|
|
5085
|
+
}, "dsh-kimi-code: styles");
|
|
2799
5086
|
ctx.effect(() => setupMermaidObserver(), "dsh-mermaid: observer");
|
|
2800
5087
|
const t = ctx.locale.bind(NS);
|
|
5088
|
+
const handleModelDirectoryReload = () => {
|
|
5089
|
+
try {
|
|
5090
|
+
const conv = ctx.conversation;
|
|
5091
|
+
const activeSessionId = conv?.activeSessionId || conv?.currentSessionId || conv?.activeId;
|
|
5092
|
+
if (activeSessionId && ctx.modelDirectories) ctx.modelDirectories.directoryFor(activeSessionId)?.load?.().catch?.(() => void 0);
|
|
5093
|
+
} catch {}
|
|
5094
|
+
};
|
|
5095
|
+
const ProviderHubSectionWrapper = (props) => {
|
|
5096
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderHubSection, {
|
|
5097
|
+
...props,
|
|
5098
|
+
onModelChange: handleModelDirectoryReload
|
|
5099
|
+
});
|
|
5100
|
+
};
|
|
2801
5101
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2802
5102
|
name: "settings.section",
|
|
2803
|
-
id: "
|
|
5103
|
+
id: "subscription-hub",
|
|
2804
5104
|
order: 45,
|
|
2805
|
-
label: () => t("
|
|
5105
|
+
label: () => t("hubTitle"),
|
|
2806
5106
|
locale: NS
|
|
2807
|
-
},
|
|
2808
|
-
const AntigravitySectionWrapper = () => {
|
|
2809
|
-
const handleModelChange = () => {
|
|
2810
|
-
try {
|
|
2811
|
-
const conv = ctx.conversation;
|
|
2812
|
-
const activeSessionId = conv?.activeSessionId || conv?.currentSessionId || conv?.activeId;
|
|
2813
|
-
if (activeSessionId && ctx.modelDirectories) ctx.modelDirectories.directoryFor(activeSessionId)?.load?.().catch?.(() => void 0);
|
|
2814
|
-
} catch {}
|
|
2815
|
-
};
|
|
2816
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AntigravitySection, { onModelChange: handleModelChange });
|
|
2817
|
-
};
|
|
2818
|
-
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2819
|
-
name: "settings.section",
|
|
2820
|
-
id: "antigravity",
|
|
2821
|
-
order: 46,
|
|
2822
|
-
label: () => "Antigravity",
|
|
2823
|
-
locale: NS_ANTIGRAVITY
|
|
2824
|
-
}, AntigravitySectionWrapper));
|
|
5107
|
+
}, ProviderHubSectionWrapper));
|
|
2825
5108
|
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
2826
5109
|
name: "conversation.input.right",
|
|
2827
5110
|
id: "codex-subscription-quota",
|
|
@@ -2853,6 +5136,36 @@ window.__ModuleLoader__.load({
|
|
|
2853
5136
|
};
|
|
2854
5137
|
}
|
|
2855
5138
|
}, AntigravityComposerQuota));
|
|
5139
|
+
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
5140
|
+
name: "conversation.input.right",
|
|
5141
|
+
id: "command-code-quota",
|
|
5142
|
+
order: 37,
|
|
5143
|
+
locale: NS_COMMAND_CODE,
|
|
5144
|
+
inject: (sessionId) => {
|
|
5145
|
+
const directory = ctx.modelDirectories.directoryFor(sessionId);
|
|
5146
|
+
return {
|
|
5147
|
+
directory: directory.store,
|
|
5148
|
+
loadModelDirectory: () => {
|
|
5149
|
+
directory.load().catch(() => void 0);
|
|
5150
|
+
}
|
|
5151
|
+
};
|
|
5152
|
+
}
|
|
5153
|
+
}, CommandCodeComposerQuota));
|
|
5154
|
+
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
5155
|
+
name: "conversation.input.right",
|
|
5156
|
+
id: "kimi-code-quota",
|
|
5157
|
+
order: 38,
|
|
5158
|
+
locale: NS_KIMI_CODE,
|
|
5159
|
+
inject: (sessionId) => {
|
|
5160
|
+
const directory = ctx.modelDirectories.directoryFor(sessionId);
|
|
5161
|
+
return {
|
|
5162
|
+
directory: directory.store,
|
|
5163
|
+
loadModelDirectory: () => {
|
|
5164
|
+
directory.load().catch(() => void 0);
|
|
5165
|
+
}
|
|
5166
|
+
};
|
|
5167
|
+
}
|
|
5168
|
+
}, KimiCodeComposerQuota));
|
|
2856
5169
|
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
2857
5170
|
name: "tool.call.toolview",
|
|
2858
5171
|
key: CODEX_IMAGE_TOOL_NAME,
|