@eddyskywalker/dsh-chatgpt-subscription 0.1.9 → 0.1.11
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 +11 -1
- package/README.md +17 -7
- package/lib/client.js +442 -28
- package/lib/client.js.map +1 -1
- package/lib/index.js +720 -248
- package/lib/types/client/CodexComposerQuota.d.ts +13 -0
- package/lib/types/client/CodexComposerQuota.d.ts.map +1 -0
- package/lib/types/client/CodexImageToolView.d.ts +10 -0
- package/lib/types/client/CodexImageToolView.d.ts.map +1 -0
- package/lib/types/client/CodexSubscriptionSection.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +2 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +57 -3
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/quota.d.ts +9 -0
- package/lib/types/client/quota.d.ts.map +1 -0
- package/lib/types/client/styles.d.ts.map +1 -1
- package/lib/types/compat.d.ts +7 -0
- package/lib/types/compat.d.ts.map +1 -1
- package/lib/types/host/codex-images.d.ts +9 -0
- package/lib/types/host/codex-images.d.ts.map +1 -0
- package/lib/types/host/codex-search.d.ts +11 -0
- package/lib/types/host/codex-search.d.ts.map +1 -0
- package/lib/types/host/model-catalog.d.ts.map +1 -1
- package/lib/types/host/preferences.d.ts +12 -0
- package/lib/types/host/preferences.d.ts.map +1 -0
- package/lib/types/host/responses-mapper.d.ts +1 -2
- package/lib/types/host/responses-mapper.d.ts.map +1 -1
- package/lib/types/host/routes.d.ts +2 -1
- package/lib/types/host/routes.d.ts.map +1 -1
- package/lib/types/host/search-provider-switcher.d.ts +15 -0
- package/lib/types/host/search-provider-switcher.d.ts.map +1 -0
- package/lib/types/host/usage-service.d.ts +2 -1
- package/lib/types/host/usage-service.d.ts.map +1 -1
- package/lib/types/index.d.ts +3 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/shared/contracts.d.ts +40 -3
- package/lib/types/shared/contracts.d.ts.map +1 -1
- package/lib/types/shared/model-catalog.d.ts +81 -0
- package/lib/types/shared/model-catalog.d.ts.map +1 -0
- package/lib/types/shared/preferences.d.ts +7 -0
- package/lib/types/shared/preferences.d.ts.map +1 -0
- package/package.json +21 -2
- package/lib/types/host/subagent-report-scheduling-compat.d.ts +0 -21
- package/lib/types/host/subagent-report-scheduling-compat.d.ts.map +0 -1
package/lib/client.js
CHANGED
|
@@ -7,6 +7,242 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react = require("react");
|
|
8
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
9
9
|
const ROUTE_PREFIX = "/api/dsh-chatgpt-subscription";
|
|
10
|
+
const CODEX_CHATGPT_PROVIDER_ID = "codex-chatgpt";
|
|
11
|
+
const CODEX_IMAGE_TOOL_NAME = "codex_image_generate";
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/client/quota.ts
|
|
14
|
+
function selectQuotaForModel(quota, modelId) {
|
|
15
|
+
if (quota === void 0 || quota.buckets.length === 0) return null;
|
|
16
|
+
const bucket = (modelId?.toLowerCase() ?? "").includes("spark") ? quota.buckets.find((candidate) => `${candidate.id} ${candidate.name}`.toLowerCase().includes("spark")) : quota.buckets.find((candidate) => candidate.id === "codex") ?? quota.buckets.find((candidate) => candidate.name.toLowerCase() === "codex");
|
|
17
|
+
if (bucket === void 0) return null;
|
|
18
|
+
const windows = quotaWindows(bucket);
|
|
19
|
+
if (windows.length === 0) return null;
|
|
20
|
+
const window = windows.reduce((tightest, candidate) => candidate.usedPercent > tightest.usedPercent ? candidate : tightest, windows[0]);
|
|
21
|
+
return {
|
|
22
|
+
bucket,
|
|
23
|
+
window,
|
|
24
|
+
remainingPercent: Math.max(0, 100 - window.usedPercent)
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function quotaWindows(bucket) {
|
|
28
|
+
if (bucket.windows.length > 0) return bucket.windows;
|
|
29
|
+
return [bucket.primary, bucket.secondary].filter((window) => window !== null);
|
|
30
|
+
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/client/CodexComposerQuota.tsx
|
|
33
|
+
function CodexComposerQuota({ api, directory, loadModelDirectory, t }) {
|
|
34
|
+
const modelState = useStore(directory);
|
|
35
|
+
const [status, setStatus] = (0, react.useState)(null);
|
|
36
|
+
const [loading, setLoading] = (0, react.useState)(false);
|
|
37
|
+
const mountedRef = (0, react.useRef)(false);
|
|
38
|
+
const selected = modelState.current;
|
|
39
|
+
const isCodex = selected?.provider === CODEX_CHATGPT_PROVIDER_ID;
|
|
40
|
+
(0, react.useEffect)(() => {
|
|
41
|
+
loadModelDirectory();
|
|
42
|
+
}, [loadModelDirectory]);
|
|
43
|
+
(0, react.useEffect)(() => {
|
|
44
|
+
mountedRef.current = true;
|
|
45
|
+
return () => {
|
|
46
|
+
mountedRef.current = false;
|
|
47
|
+
};
|
|
48
|
+
}, []);
|
|
49
|
+
(0, react.useEffect)(() => {
|
|
50
|
+
if (!isCodex) return;
|
|
51
|
+
let disposed = false;
|
|
52
|
+
const refresh = async () => {
|
|
53
|
+
setLoading(true);
|
|
54
|
+
try {
|
|
55
|
+
const next = await api.status();
|
|
56
|
+
if (!disposed && mountedRef.current) setStatus(next);
|
|
57
|
+
} catch {
|
|
58
|
+
if (!disposed && mountedRef.current) setStatus(null);
|
|
59
|
+
} finally {
|
|
60
|
+
if (!disposed && mountedRef.current) setLoading(false);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
refresh();
|
|
64
|
+
const timer = window.setInterval(() => {
|
|
65
|
+
if (document.visibilityState === "visible") refresh();
|
|
66
|
+
}, 6e4);
|
|
67
|
+
return () => {
|
|
68
|
+
disposed = true;
|
|
69
|
+
window.clearInterval(timer);
|
|
70
|
+
};
|
|
71
|
+
}, [api, isCodex]);
|
|
72
|
+
const quota = (0, react.useMemo)(() => selectQuotaForModel(status?.quota, selected?.model), [selected?.model, status?.quota]);
|
|
73
|
+
if (!isCodex || status?.preferences.quickQuotaVisible !== true) return null;
|
|
74
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
75
|
+
className: "dsh-codex-composer-quota",
|
|
76
|
+
"data-level": quota === null ? "normal" : quota.remainingPercent <= 5 ? "danger" : quota.remainingPercent <= 20 ? "warning" : "normal",
|
|
77
|
+
"aria-label": quota === null ? t("quickQuotaLoading") : `${t("quickQuotaLabel")}: ${formatPercent$1(quota.remainingPercent)}`,
|
|
78
|
+
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) })]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function useStore(store) {
|
|
82
|
+
return (0, react.useSyncExternalStore)((listener) => store.subscribe(listener), () => store.getSnapshot(), () => store.getSnapshot());
|
|
83
|
+
}
|
|
84
|
+
function formatPercent$1(value) {
|
|
85
|
+
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 0 }).format(value)}%`;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/client/CodexImageToolView.tsx
|
|
89
|
+
function CodexImageToolView({ block, loadImage, t }) {
|
|
90
|
+
const settled = "kind" in block;
|
|
91
|
+
const isError = settled ? block.isError : false;
|
|
92
|
+
const prompt = promptFromBlock(block);
|
|
93
|
+
const images = settled && !isError ? imageBlocks(block.content) : [];
|
|
94
|
+
const label = isError ? t("imageToolFailed") : settled ? t("imageToolDone") : t("imageToolRunning");
|
|
95
|
+
const summary = prompt ?? textSummary(settled ? block.content : []);
|
|
96
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
97
|
+
className: "dsh-codex-image-tool",
|
|
98
|
+
"data-state": isError ? "error" : settled ? "done" : "running",
|
|
99
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
100
|
+
className: "dsh-codex-image-tool-head",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
103
|
+
className: "dsh-codex-image-dot",
|
|
104
|
+
"aria-hidden": "true"
|
|
105
|
+
}),
|
|
106
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
107
|
+
className: "dsh-codex-image-title",
|
|
108
|
+
children: label
|
|
109
|
+
}),
|
|
110
|
+
summary !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
111
|
+
className: "dsh-codex-image-summary",
|
|
112
|
+
children: summary
|
|
113
|
+
}) : null
|
|
114
|
+
]
|
|
115
|
+
}), images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
116
|
+
className: "dsh-codex-image-grid",
|
|
117
|
+
children: images.map((attachment) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GeneratedImage, {
|
|
118
|
+
attachment,
|
|
119
|
+
load: loadImage,
|
|
120
|
+
label: attachment.name ?? t("image"),
|
|
121
|
+
t
|
|
122
|
+
}, String(attachment.attachmentId)))
|
|
123
|
+
}) : null]
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function GeneratedImage({ attachment, load, label, t }) {
|
|
127
|
+
const [src, setSrc] = (0, react.useState)(null);
|
|
128
|
+
const [failed, setFailed] = (0, react.useState)(false);
|
|
129
|
+
(0, react.useEffect)(() => {
|
|
130
|
+
let disposed = false;
|
|
131
|
+
setSrc(null);
|
|
132
|
+
setFailed(false);
|
|
133
|
+
load(attachment).then((url) => {
|
|
134
|
+
if (!disposed) setSrc(url);
|
|
135
|
+
}, () => {
|
|
136
|
+
if (!disposed) setFailed(true);
|
|
137
|
+
});
|
|
138
|
+
return () => {
|
|
139
|
+
disposed = true;
|
|
140
|
+
};
|
|
141
|
+
}, [attachment, load]);
|
|
142
|
+
if (failed) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
143
|
+
className: "dsh-codex-image-failed",
|
|
144
|
+
children: t("imageLoadFailed")
|
|
145
|
+
});
|
|
146
|
+
if (src === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
147
|
+
className: "dsh-codex-image-loading",
|
|
148
|
+
children: t("imageLoading")
|
|
149
|
+
});
|
|
150
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
151
|
+
className: "dsh-codex-image-preview",
|
|
152
|
+
src,
|
|
153
|
+
alt: label
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
function promptFromBlock(block) {
|
|
157
|
+
const raw = "kind" in block ? block.call?.argsRaw : block.argsRaw;
|
|
158
|
+
if (typeof raw !== "string" || raw.trim() === "") return null;
|
|
159
|
+
try {
|
|
160
|
+
const value = JSON.parse(raw);
|
|
161
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.prompt === "string" ? value.prompt : null;
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function imageBlocks(blocks) {
|
|
167
|
+
const result = [];
|
|
168
|
+
for (const block of blocks) {
|
|
169
|
+
if (block.type === "image") result.push(block.attachment);
|
|
170
|
+
if (block.type === "tool-result") result.push(...imageBlocks(block.content));
|
|
171
|
+
}
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
function textSummary(blocks) {
|
|
175
|
+
const text = blocks.map((block) => block.type === "text" || block.type === "reasoning" ? block.text : "").filter(Boolean).join(" ").trim();
|
|
176
|
+
return text === "" ? null : text;
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/shared/model-catalog.ts
|
|
180
|
+
const CODEX_MODEL_CATALOG = [
|
|
181
|
+
{
|
|
182
|
+
id: "gpt-5.6-sol",
|
|
183
|
+
name: "5.6 Sol",
|
|
184
|
+
contextWindow: 272e3,
|
|
185
|
+
inputModalities: ["text", "image"],
|
|
186
|
+
defaultReasoningEffort: "medium",
|
|
187
|
+
reasoningProfile: "gpt-5.6",
|
|
188
|
+
supportsReasoningSummary: true
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "gpt-5.6-terra",
|
|
192
|
+
name: "5.6 Terra",
|
|
193
|
+
contextWindow: 272e3,
|
|
194
|
+
inputModalities: ["text", "image"],
|
|
195
|
+
defaultReasoningEffort: "medium",
|
|
196
|
+
reasoningProfile: "gpt-5.6",
|
|
197
|
+
supportsReasoningSummary: true
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: "gpt-5.6-luna",
|
|
201
|
+
name: "5.6 Luna",
|
|
202
|
+
contextWindow: 272e3,
|
|
203
|
+
inputModalities: ["text", "image"],
|
|
204
|
+
defaultReasoningEffort: "medium",
|
|
205
|
+
reasoningProfile: "gpt-5.6",
|
|
206
|
+
supportsReasoningSummary: true
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "gpt-5.5",
|
|
210
|
+
name: "5.5",
|
|
211
|
+
contextWindow: 272e3,
|
|
212
|
+
inputModalities: ["text", "image"],
|
|
213
|
+
defaultReasoningEffort: "medium",
|
|
214
|
+
reasoningProfile: "standard",
|
|
215
|
+
supportsReasoningSummary: true
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
id: "gpt-5.4",
|
|
219
|
+
name: "5.4",
|
|
220
|
+
contextWindow: 272e3,
|
|
221
|
+
inputModalities: ["text", "image"],
|
|
222
|
+
defaultReasoningEffort: "none",
|
|
223
|
+
reasoningProfile: "standard",
|
|
224
|
+
supportsReasoningSummary: true
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: "gpt-5.4-mini",
|
|
228
|
+
name: "5.4 Mini",
|
|
229
|
+
contextWindow: 272e3,
|
|
230
|
+
inputModalities: ["text", "image"],
|
|
231
|
+
defaultReasoningEffort: "none",
|
|
232
|
+
reasoningProfile: "standard",
|
|
233
|
+
supportsReasoningSummary: true
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
id: "gpt-5.3-codex-spark",
|
|
237
|
+
name: "5.3 Codex Spark",
|
|
238
|
+
contextWindow: 258e3,
|
|
239
|
+
inputModalities: ["text"],
|
|
240
|
+
defaultReasoningEffort: "high",
|
|
241
|
+
reasoningProfile: "standard",
|
|
242
|
+
supportsReasoningSummary: false
|
|
243
|
+
}
|
|
244
|
+
];
|
|
245
|
+
CODEX_MODEL_CATALOG[0];
|
|
10
246
|
//#endregion
|
|
11
247
|
//#region src/client/api.ts
|
|
12
248
|
var SubscriptionApi = class {
|
|
@@ -31,6 +267,9 @@ window.__ModuleLoader__.load({
|
|
|
31
267
|
testConnection() {
|
|
32
268
|
return post(`${ROUTE_PREFIX}/connection/test`, {});
|
|
33
269
|
}
|
|
270
|
+
updatePreferences(patch) {
|
|
271
|
+
return post(`${ROUTE_PREFIX}/preferences/update`, patch);
|
|
272
|
+
}
|
|
34
273
|
events(loginId) {
|
|
35
274
|
return new EventSource(`${ROUTE_PREFIX}/login/events?loginId=${encodeURIComponent(loginId)}`);
|
|
36
275
|
}
|
|
@@ -61,15 +300,6 @@ window.__ModuleLoader__.load({
|
|
|
61
300
|
}
|
|
62
301
|
//#endregion
|
|
63
302
|
//#region src/client/CodexSubscriptionSection.tsx
|
|
64
|
-
const MODELS = [
|
|
65
|
-
"gpt-5.6-sol",
|
|
66
|
-
"gpt-5.6-terra",
|
|
67
|
-
"gpt-5.6-luna",
|
|
68
|
-
"gpt-5.5",
|
|
69
|
-
"gpt-5.4",
|
|
70
|
-
"gpt-5.4-mini",
|
|
71
|
-
"gpt-5.2"
|
|
72
|
-
];
|
|
73
303
|
function CodexSubscriptionSection({ t }) {
|
|
74
304
|
const apiRef = (0, react.useRef)(new SubscriptionApi());
|
|
75
305
|
const eventSourceRef = (0, react.useRef)(null);
|
|
@@ -182,6 +412,13 @@ window.__ModuleLoader__.load({
|
|
|
182
412
|
checkedAt: result.checkedAt
|
|
183
413
|
});
|
|
184
414
|
});
|
|
415
|
+
const updatePreferences = async (patch) => run("preferences", async () => {
|
|
416
|
+
const preferences = await apiRef.current.updatePreferences(patch);
|
|
417
|
+
setStatus((current) => current === null ? current : {
|
|
418
|
+
...current,
|
|
419
|
+
preferences
|
|
420
|
+
});
|
|
421
|
+
});
|
|
185
422
|
const logout = async () => run("logout", async () => {
|
|
186
423
|
await apiRef.current.logout();
|
|
187
424
|
eventSourceRef.current?.close();
|
|
@@ -310,7 +547,10 @@ window.__ModuleLoader__.load({
|
|
|
310
547
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
311
548
|
className: "dsh-codex-models",
|
|
312
549
|
"aria-label": t("models"),
|
|
313
|
-
children:
|
|
550
|
+
children: CODEX_MODEL_CATALOG.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
551
|
+
title: model.id,
|
|
552
|
+
children: model.name
|
|
553
|
+
}, model.id))
|
|
314
554
|
}),
|
|
315
555
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
316
556
|
className: "dsh-codex-actions",
|
|
@@ -322,6 +562,41 @@ window.__ModuleLoader__.load({
|
|
|
322
562
|
})
|
|
323
563
|
]
|
|
324
564
|
}),
|
|
565
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
|
|
566
|
+
title: t("enhancements"),
|
|
567
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
568
|
+
className: "dsh-codex-pref-row",
|
|
569
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("searchProvider") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
570
|
+
className: "dsh-codex-muted",
|
|
571
|
+
children: t("searchProviderHint")
|
|
572
|
+
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
573
|
+
className: "dsh-codex-segments",
|
|
574
|
+
role: "radiogroup",
|
|
575
|
+
"aria-label": t("searchProvider"),
|
|
576
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
577
|
+
type: "radio",
|
|
578
|
+
name: "dsh-codex-search-provider",
|
|
579
|
+
checked: status?.preferences.searchProvider === "dsh",
|
|
580
|
+
disabled: busy !== null,
|
|
581
|
+
onChange: () => updatePreferences({ searchProvider: "dsh" })
|
|
582
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("searchProviderDsh") })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
583
|
+
type: "radio",
|
|
584
|
+
name: "dsh-codex-search-provider",
|
|
585
|
+
checked: status?.preferences.searchProvider === "codex",
|
|
586
|
+
disabled: busy !== null,
|
|
587
|
+
onChange: () => updatePreferences({ searchProvider: "codex" })
|
|
588
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("searchProviderCodex") })] })]
|
|
589
|
+
})]
|
|
590
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
591
|
+
className: "dsh-codex-check",
|
|
592
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
593
|
+
type: "checkbox",
|
|
594
|
+
checked: status?.preferences.quickQuotaVisible === true,
|
|
595
|
+
disabled: busy !== null,
|
|
596
|
+
onChange: (event) => updatePreferences({ quickQuotaVisible: event.currentTarget.checked })
|
|
597
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: t("quickQuota") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("quickQuotaHint") })] })]
|
|
598
|
+
})]
|
|
599
|
+
}),
|
|
325
600
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
|
|
326
601
|
title: t("quota"),
|
|
327
602
|
aside: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
@@ -342,6 +617,23 @@ window.__ModuleLoader__.load({
|
|
|
342
617
|
bucket,
|
|
343
618
|
t
|
|
344
619
|
}, bucket.id)),
|
|
620
|
+
status?.quota.credits !== null && status?.quota.credits !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuotaFact, {
|
|
621
|
+
label: t("credits"),
|
|
622
|
+
value: status.quota.credits.unlimited ? t("unlimited") : status.quota.credits.balance ?? (status.quota.credits.hasCredits ? t("available") : t("unavailable"))
|
|
623
|
+
}) : null,
|
|
624
|
+
status?.quota.individualLimit !== null && status?.quota.individualLimit !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuotaFact, {
|
|
625
|
+
label: t("monthlySpend"),
|
|
626
|
+
value: individualLimitLabel(status.quota.individualLimit, t)
|
|
627
|
+
}) : null,
|
|
628
|
+
status?.quota.resetCredits !== null && status?.quota.resetCredits !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuotaFact, {
|
|
629
|
+
label: t("resetCredits"),
|
|
630
|
+
value: String(status.quota.resetCredits.availableCount)
|
|
631
|
+
}) : null,
|
|
632
|
+
status?.quota.spendControlReached === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
633
|
+
className: "dsh-codex-warning",
|
|
634
|
+
role: "status",
|
|
635
|
+
children: t("spendControlReached")
|
|
636
|
+
}) : null,
|
|
345
637
|
status?.quota.state === "empty" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
346
638
|
className: "dsh-codex-empty",
|
|
347
639
|
children: t("noQuota")
|
|
@@ -420,24 +712,23 @@ window.__ModuleLoader__.load({
|
|
|
420
712
|
return t("securityUnavailable");
|
|
421
713
|
}
|
|
422
714
|
function QuotaBucket({ bucket, t }) {
|
|
715
|
+
const windows = quotaWindows(bucket);
|
|
423
716
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
424
717
|
className: "dsh-codex-quota-card",
|
|
425
|
-
children: [
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}) : null
|
|
440
|
-
]
|
|
718
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
719
|
+
className: "dsh-codex-quota-title",
|
|
720
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: bucket.name }), bucket.planType ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: bucket.planType }) : null]
|
|
721
|
+
}), windows.map((window, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuotaBar, {
|
|
722
|
+
label: windowLabel(window.windowDurationMins, t),
|
|
723
|
+
window,
|
|
724
|
+
t
|
|
725
|
+
}, `${window.windowDurationMins ?? "x"}:${window.resetsAt ?? "x"}:${index}`))]
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
function QuotaFact({ label, value }) {
|
|
729
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
730
|
+
className: "dsh-codex-quota-fact",
|
|
731
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: value })]
|
|
441
732
|
});
|
|
442
733
|
}
|
|
443
734
|
function QuotaBar({ label, window, t }) {
|
|
@@ -487,6 +778,15 @@ window.__ModuleLoader__.load({
|
|
|
487
778
|
function formatPercent(value) {
|
|
488
779
|
return `${new Intl.NumberFormat(void 0, { maximumFractionDigits: 1 }).format(value)}%`;
|
|
489
780
|
}
|
|
781
|
+
function individualLimitLabel(limit, t) {
|
|
782
|
+
const parts = [
|
|
783
|
+
limit.remainingPercent !== null ? `${formatPercent(limit.remainingPercent)} ${t("remaining")}` : null,
|
|
784
|
+
limit.limit !== null ? `${t("limit")}: ${limit.limit}` : null,
|
|
785
|
+
limit.used !== null ? `${t("used")}: ${limit.used}` : null,
|
|
786
|
+
limit.resetsAt !== null ? `${t("resets")}: ${formatReset(limit.resetsAt)}` : null
|
|
787
|
+
].filter((part) => part !== null);
|
|
788
|
+
return parts.length > 0 ? parts.join(" · ") : t("unknown");
|
|
789
|
+
}
|
|
490
790
|
function formatDate(seconds) {
|
|
491
791
|
if (seconds === void 0) return "—";
|
|
492
792
|
return new Intl.DateTimeFormat(void 0, {
|
|
@@ -544,6 +844,13 @@ window.__ModuleLoader__.load({
|
|
|
544
844
|
testing: "测试中…",
|
|
545
845
|
latency: "最近延迟",
|
|
546
846
|
models: "可用模型",
|
|
847
|
+
enhancements: "增强功能",
|
|
848
|
+
searchProvider: "搜索来源",
|
|
849
|
+
searchProviderHint: "选择 DSH Web 搜索工具使用默认来源,或改用当前 ChatGPT 订阅的 Codex 搜索来源。",
|
|
850
|
+
searchProviderDsh: "DSH 默认",
|
|
851
|
+
searchProviderCodex: "Codex 订阅",
|
|
852
|
+
quickQuota: "在输入框旁显示快捷用量",
|
|
853
|
+
quickQuotaHint: "仅在当前会话选中 codex-chatgpt 模型时显示。",
|
|
547
854
|
quota: "用量与限额",
|
|
548
855
|
quotaIntro: "数据来自 ChatGPT Codex 用量服务。页面可见时最多每 60 秒刷新一次。",
|
|
549
856
|
refreshQuota: "刷新用量",
|
|
@@ -557,8 +864,28 @@ window.__ModuleLoader__.load({
|
|
|
557
864
|
limitWindow: "额度",
|
|
558
865
|
used: "已使用",
|
|
559
866
|
remaining: "剩余",
|
|
867
|
+
available: "可用",
|
|
868
|
+
unavailable: "不可用",
|
|
869
|
+
unlimited: "无限",
|
|
870
|
+
credits: "Credits",
|
|
871
|
+
monthlySpend: "月度消费控制",
|
|
872
|
+
resetCredits: "重置次数",
|
|
873
|
+
spendControlReached: "已触发月度消费控制,新的订阅调用可能被限制。",
|
|
874
|
+
limit: "上限",
|
|
560
875
|
exhausted: "额度已用尽",
|
|
561
876
|
resets: "重置",
|
|
877
|
+
quickQuotaLabel: "Codex 剩余",
|
|
878
|
+
quickQuotaLoading: "用量…",
|
|
879
|
+
imageToolRunning: "正在生成图片",
|
|
880
|
+
imageToolDone: "已生成图片",
|
|
881
|
+
imageToolFailed: "图片生成失败",
|
|
882
|
+
image: "图片",
|
|
883
|
+
openImage: "打开图片",
|
|
884
|
+
openNamedImage: "打开 {name}",
|
|
885
|
+
imageLoading: "加载图片…",
|
|
886
|
+
imageLoadFailed: "图片加载失败,点击重试",
|
|
887
|
+
imagePreviewClose: "关闭",
|
|
888
|
+
imagePreviewOpenOriginal: "打开原图",
|
|
562
889
|
retry: "重试",
|
|
563
890
|
unknown: "未知"
|
|
564
891
|
},
|
|
@@ -598,6 +925,13 @@ window.__ModuleLoader__.load({
|
|
|
598
925
|
testing: "Testing…",
|
|
599
926
|
latency: "Last latency",
|
|
600
927
|
models: "Available models",
|
|
928
|
+
enhancements: "Enhancements",
|
|
929
|
+
searchProvider: "Search provider",
|
|
930
|
+
searchProviderHint: "Choose whether DSH web search uses its default provider or the Codex search source from this ChatGPT subscription.",
|
|
931
|
+
searchProviderDsh: "DSH default",
|
|
932
|
+
searchProviderCodex: "Codex subscription",
|
|
933
|
+
quickQuota: "Show quick usage beside the composer",
|
|
934
|
+
quickQuotaHint: "Shown only when the current session uses a codex-chatgpt model.",
|
|
601
935
|
quota: "Usage and limits",
|
|
602
936
|
quotaIntro: "Data comes from the ChatGPT Codex usage service and refreshes at most once per minute while visible.",
|
|
603
937
|
refreshQuota: "Refresh usage",
|
|
@@ -611,8 +945,28 @@ window.__ModuleLoader__.load({
|
|
|
611
945
|
limitWindow: "limit",
|
|
612
946
|
used: "used",
|
|
613
947
|
remaining: "remaining",
|
|
948
|
+
available: "Available",
|
|
949
|
+
unavailable: "Unavailable",
|
|
950
|
+
unlimited: "Unlimited",
|
|
951
|
+
credits: "Credits",
|
|
952
|
+
monthlySpend: "Monthly spend control",
|
|
953
|
+
resetCredits: "Reset credits",
|
|
954
|
+
spendControlReached: "Monthly spend control has been reached; new subscription calls may be limited.",
|
|
955
|
+
limit: "Limit",
|
|
614
956
|
exhausted: "Quota exhausted",
|
|
615
957
|
resets: "Resets",
|
|
958
|
+
quickQuotaLabel: "Codex left",
|
|
959
|
+
quickQuotaLoading: "Usage…",
|
|
960
|
+
imageToolRunning: "Generating image",
|
|
961
|
+
imageToolDone: "Generated image",
|
|
962
|
+
imageToolFailed: "Image generation failed",
|
|
963
|
+
image: "Image",
|
|
964
|
+
openImage: "Open image",
|
|
965
|
+
openNamedImage: "Open {name}",
|
|
966
|
+
imageLoading: "Loading image…",
|
|
967
|
+
imageLoadFailed: "Image failed to load. Click to retry",
|
|
968
|
+
imagePreviewClose: "Close",
|
|
969
|
+
imagePreviewOpenOriginal: "Open original",
|
|
616
970
|
retry: "Retry",
|
|
617
971
|
unknown: "Unknown"
|
|
618
972
|
}
|
|
@@ -645,9 +999,24 @@ window.__ModuleLoader__.load({
|
|
|
645
999
|
.dsh-codex-link{color:var(--dsw-alias-label-link,#3278d4);display:inline-block;font-size:13px;margin-top:8px}
|
|
646
1000
|
.dsh-codex-models{display:flex;flex-wrap:wrap;gap:6px;padding-top:12px}
|
|
647
1001
|
.dsh-codex-models code{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:5px;font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;padding:4px 6px}
|
|
1002
|
+
.dsh-codex-pref-row{align-items:center;border-bottom:1px solid var(--dsw-alias-border-l2);display:flex;gap:16px;justify-content:space-between;min-height:58px;padding:10px 0}
|
|
1003
|
+
.dsh-codex-pref-row strong,.dsh-codex-check strong{display:block;font-size:13px;font-weight:600;line-height:1.35}
|
|
1004
|
+
.dsh-codex-segments{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;display:flex;flex:none;gap:2px;padding:2px}
|
|
1005
|
+
.dsh-codex-segments label{cursor:pointer;display:block}
|
|
1006
|
+
.dsh-codex-segments input{position:absolute;opacity:0;pointer-events:none}
|
|
1007
|
+
.dsh-codex-segments span{border-radius:6px;color:var(--dsw-alias-label-secondary);display:block;font-size:12px;line-height:1;padding:7px 10px;white-space:nowrap}
|
|
1008
|
+
.dsh-codex-segments input:checked+span{background:var(--dsw-alias-bg-base);box-shadow:0 1px 2px rgba(0,0,0,.08);color:var(--dsw-alias-label-primary)}
|
|
1009
|
+
.dsh-codex-segments input:focus-visible+span{outline:2px solid var(--dsw-alias-button-info-fill,#397ee8);outline-offset:2px}
|
|
1010
|
+
.dsh-codex-segments input:disabled+span{cursor:default;opacity:.5}
|
|
1011
|
+
.dsh-codex-check{align-items:flex-start;border-bottom:1px solid var(--dsw-alias-border-l2);cursor:pointer;display:flex;gap:10px;padding:12px 0}
|
|
1012
|
+
.dsh-codex-check input{flex:none;margin-top:2px}
|
|
1013
|
+
.dsh-codex-check small{color:var(--dsw-alias-label-secondary);display:block;font-size:12px;line-height:1.45;margin-top:2px}
|
|
648
1014
|
.dsh-codex-quota-card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;margin-top:12px;padding:12px}
|
|
649
1015
|
.dsh-codex-quota-title{align-items:center;display:flex;font-size:13px;gap:8px;justify-content:space-between}
|
|
650
1016
|
.dsh-codex-quota-title span{color:var(--dsw-alias-label-tertiary);font-size:11px;text-transform:uppercase}
|
|
1017
|
+
.dsh-codex-quota-fact{align-items:flex-start;border-bottom:1px solid var(--dsw-alias-border-l2);display:flex;font-size:12px;gap:12px;justify-content:space-between;line-height:1.45;padding:10px 0}
|
|
1018
|
+
.dsh-codex-quota-fact span{color:var(--dsw-alias-label-secondary);flex:none}
|
|
1019
|
+
.dsh-codex-quota-fact strong{font-weight:600;min-width:0;overflow-wrap:anywhere;text-align:right}
|
|
651
1020
|
.dsh-codex-meter-wrap{margin-top:13px}
|
|
652
1021
|
.dsh-codex-meter-label,.dsh-codex-meter-meta{display:flex;gap:10px;justify-content:space-between}
|
|
653
1022
|
.dsh-codex-meter-label{font-size:12px;margin-bottom:6px}
|
|
@@ -662,8 +1031,22 @@ window.__ModuleLoader__.load({
|
|
|
662
1031
|
.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}
|
|
663
1032
|
.dsh-codex-skeleton span:nth-child(2){animation-delay:.12s}.dsh-codex-skeleton span:nth-child(3){animation-delay:.24s}
|
|
664
1033
|
.dsh-codex-sr{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0 0 0 0);white-space:nowrap}
|
|
1034
|
+
.dsh-codex-composer-quota{align-items:center;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;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}
|
|
1035
|
+
.dsh-codex-composer-quota strong{color:var(--dsw-alias-label-primary);font-size:11px;font-weight:650}
|
|
1036
|
+
.dsh-codex-composer-quota[data-level=warning] strong{color:var(--dsw-alias-label-warning,#d58a24)}
|
|
1037
|
+
.dsh-codex-composer-quota[data-level=danger] strong{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1038
|
+
.dsh-codex-image-tool{border:1px 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}
|
|
1039
|
+
.dsh-codex-image-tool-head{align-items:center;display:flex;font-size:13px;gap:8px;min-width:0}
|
|
1040
|
+
.dsh-codex-image-dot{background:var(--dsw-alias-button-info-fill,#397ee8);border-radius:50%;display:inline-block;flex:none;height:8px;width:8px}
|
|
1041
|
+
.dsh-codex-image-tool[data-state=error] .dsh-codex-image-dot{background:var(--dsw-alias-label-danger,#d94b4b)}
|
|
1042
|
+
.dsh-codex-image-title{font-weight:600}
|
|
1043
|
+
.dsh-codex-image-summary{color:var(--dsw-alias-label-tertiary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1044
|
+
.dsh-codex-image-grid{display:flex;flex-wrap:wrap;gap:8px}
|
|
1045
|
+
.dsh-codex-image-preview{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;display:block;max-height:260px;max-width:min(100%,360px);object-fit:contain}
|
|
1046
|
+
.dsh-codex-image-loading,.dsh-codex-image-failed{border:1px 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}
|
|
1047
|
+
.dsh-codex-image-failed{color:var(--dsw-alias-label-danger,#d94b4b)}
|
|
665
1048
|
@keyframes dsh-codex-pulse{0%,100%{opacity:.55}50%{opacity:1}}
|
|
666
|
-
@media(max-width:560px){.dsh-codex-row{align-items:flex-start;flex-direction:column;gap:3px}.dsh-codex-value{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}}
|
|
1049
|
+
@media(max-width:560px){.dsh-codex-row,.dsh-codex-pref-row,.dsh-codex-quota-fact{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-segments label{flex:1}.dsh-codex-segments span{text-align:center}.dsh-codex-image-tool{max-width:100%;margin-left:0}}
|
|
667
1050
|
@media(prefers-reduced-motion:reduce){.dsh-codex-meter>span{transition:none}.dsh-codex-skeleton span{animation:none}}
|
|
668
1051
|
`;
|
|
669
1052
|
function installStyles() {
|
|
@@ -677,7 +1060,12 @@ window.__ModuleLoader__.load({
|
|
|
677
1060
|
}
|
|
678
1061
|
//#endregion
|
|
679
1062
|
//#region src/client/index.tsx
|
|
680
|
-
const inject = [
|
|
1063
|
+
const inject = [
|
|
1064
|
+
"slots",
|
|
1065
|
+
"locale",
|
|
1066
|
+
"modelDirectories",
|
|
1067
|
+
"conversation"
|
|
1068
|
+
];
|
|
681
1069
|
function apply(ctx) {
|
|
682
1070
|
ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
|
|
683
1071
|
ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
|
|
@@ -688,6 +1076,32 @@ window.__ModuleLoader__.load({
|
|
|
688
1076
|
label: "Codex 订阅",
|
|
689
1077
|
locale: NS
|
|
690
1078
|
}, CodexSubscriptionSection));
|
|
1079
|
+
ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
|
|
1080
|
+
name: "conversation.input.right",
|
|
1081
|
+
id: "codex-subscription-quota",
|
|
1082
|
+
order: 35,
|
|
1083
|
+
locale: NS,
|
|
1084
|
+
inject: (sessionId) => {
|
|
1085
|
+
const directory = ctx.modelDirectories.directoryFor(sessionId);
|
|
1086
|
+
return {
|
|
1087
|
+
api: new SubscriptionApi(),
|
|
1088
|
+
directory: directory.store,
|
|
1089
|
+
loadModelDirectory: () => {
|
|
1090
|
+
directory.load().catch(() => void 0);
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
}, CodexComposerQuota));
|
|
1095
|
+
ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
|
|
1096
|
+
name: "tool.call.toolview",
|
|
1097
|
+
key: CODEX_IMAGE_TOOL_NAME,
|
|
1098
|
+
locale: NS,
|
|
1099
|
+
inject: (sessionId) => ({ loadImage: imageLoader(ctx, sessionId) })
|
|
1100
|
+
}, CodexImageToolView));
|
|
1101
|
+
}
|
|
1102
|
+
function imageLoader(ctx, sessionId) {
|
|
1103
|
+
const conversation = ctx.conversation;
|
|
1104
|
+
return (attachment) => conversation.resolveImage(sessionId, attachment);
|
|
691
1105
|
}
|
|
692
1106
|
//#endregion
|
|
693
1107
|
exports.apply = apply;
|