dsh-codex-community 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/README.en.md +14 -10
- package/README.md +14 -10
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/dist/client/index.js +746 -64
- package/dist/host/index.mjs +3 -0
- package/dist/internal/authorization-bridge.mjs +12 -0
- package/dist/internal/codex-account-usage.mjs +509 -0
- package/dist/internal/codex-model-capabilities.mjs +90 -0
- package/dist/internal/codex-pi-provider.mjs +30 -3
- package/dist/internal/codex-provider-runtime.mjs +27 -1
- package/dist/internal/codex-route-adapter.mjs +36 -3
- package/dist/internal/session-preference-bridge.mjs +150 -0
- package/docs/README.en.md +2 -0
- package/docs/README.md +2 -0
- package/docs/architecture.en.md +20 -11
- package/docs/architecture.md +20 -11
- package/docs/compatibility.en.md +14 -12
- package/docs/compatibility.md +14 -12
- package/docs/configuration.en.md +23 -1
- package/docs/configuration.md +23 -1
- package/docs/releases/v0.0.1.md +0 -2
- package/docs/releases/v0.0.2.acceptance.json +160 -0
- package/docs/releases/v0.0.2.md +56 -0
- package/docs/releases/v0.0.3.acceptance.json +160 -0
- package/docs/releases/v0.0.3.md +62 -0
- package/docs/releasing.en.md +1 -1
- package/docs/releasing.md +1 -1
- package/docs/troubleshooting.en.md +19 -3
- package/docs/troubleshooting.md +19 -3
- package/package.json +11 -1
- package/types/client.d.ts +59 -0
package/dist/client/index.js
CHANGED
|
@@ -7,6 +7,7 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
const h = React.createElement
|
|
8
8
|
|
|
9
9
|
const CHANNEL = "/dsh-codex"
|
|
10
|
+
const SESSION_CHANNEL = "/dsh-codex-session"
|
|
10
11
|
const NS = "settings.codex"
|
|
11
12
|
const CODEX_PROVIDER = "dsh-codex"
|
|
12
13
|
const CODEX_SETTINGS_NS = "dsh-codex"
|
|
@@ -27,6 +28,7 @@ window.__ModuleLoader__.load({
|
|
|
27
28
|
unavailable: "当前环境没有可用的 Codex 登录流程。",
|
|
28
29
|
writableNo: "当前凭据存储不可写。",
|
|
29
30
|
refresh: "刷新",
|
|
31
|
+
refreshing: "刷新中…",
|
|
30
32
|
signIn: "登录",
|
|
31
33
|
signInWithChatGPT: "使用 ChatGPT 登录",
|
|
32
34
|
signInAgain: "重新登录",
|
|
@@ -47,20 +49,36 @@ window.__ModuleLoader__.load({
|
|
|
47
49
|
logoutFailed: "退出登录失败,请重试。",
|
|
48
50
|
responseFailed: "提交登录信息失败,请重试。",
|
|
49
51
|
requestFailed: "暂时无法连接本机授权服务。",
|
|
52
|
+
locale: "zh-CN",
|
|
50
53
|
quotaTitle: "使用额度",
|
|
51
54
|
quotaProduct: "Codex",
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
quotaLoading: "正在读取账户额度…",
|
|
56
|
+
quotaLoadFailed: "暂时无法刷新账户额度。",
|
|
57
|
+
quotaStaleHelp: "继续显示上一次验证成功的数据。",
|
|
58
|
+
quotaUnknown: "尚无可验证的额度数据。",
|
|
59
|
+
quotaUnknownHelp: "登录后会在每次进入此页面和手动刷新时读取;读取失败时保留最近的安全观测。",
|
|
60
|
+
quotaFiveHour: "5 小时额度",
|
|
61
|
+
quotaWeekly: "每周额度",
|
|
62
|
+
quotaMinuteWindow: "分钟额度",
|
|
63
|
+
quotaRemaining: "剩余",
|
|
64
|
+
quotaResetsAt: "重置时间",
|
|
65
|
+
quotaUpdatedAt: "数据更新时间",
|
|
66
|
+
quotaResetSoon: "即将重置",
|
|
67
|
+
quotaResetPrefix: "",
|
|
68
|
+
quotaResetSuffix: "后重置",
|
|
69
|
+
quotaResetMinute: "分钟",
|
|
70
|
+
quotaResetHour: "小时",
|
|
71
|
+
quotaResetDay: "天",
|
|
54
72
|
quotaRecentSuccess: "最近一次 Codex 请求成功",
|
|
55
73
|
quotaSuccessCaution: "这只表示最近一次请求成功,不代表账户剩余额度。",
|
|
56
74
|
quotaExhausted: "最近观测到 Codex 账户额度已用尽。",
|
|
57
75
|
quotaObservedAt: "观测时间",
|
|
58
76
|
quotaResetAt: "观测到的重置时间",
|
|
59
|
-
quotaResetIn: "预计还有约",
|
|
60
|
-
quotaMinutes: "分钟",
|
|
61
77
|
quotaNoReset: "未获得通过校验的重置时间;状态会在有限时间后自动回到未知。",
|
|
62
|
-
modelsTitle: "
|
|
63
|
-
modelsDescription: "
|
|
78
|
+
modelsTitle: "当前安装的 Codex 模型",
|
|
79
|
+
modelsDescription: "选择在模型选择器中显示的 Codex 模型。名称、上下文和最大输出来自当前安装的 provider catalog;隐藏模型不影响已有会话。",
|
|
80
|
+
modelsContextWindow: "上下文",
|
|
81
|
+
modelsMaxOutput: "最大输出",
|
|
64
82
|
modelsLoading: "正在读取 Codex 模型目录…",
|
|
65
83
|
modelsUnavailable: "当前环境没有可用的 Codex 模型管理接口。",
|
|
66
84
|
modelsReadOnly: "当前设置存储为只读,无法修改启用模型。",
|
|
@@ -69,11 +87,24 @@ window.__ModuleLoader__.load({
|
|
|
69
87
|
modelsSaving: "正在保存…",
|
|
70
88
|
modelsSaved: "模型启用设置已保存。",
|
|
71
89
|
modelsAtLeastOne: "至少需要启用一个 Codex 模型。",
|
|
72
|
-
modelsAllEnabledFollow: "
|
|
73
|
-
modelsAllEnabledPreserve: "
|
|
90
|
+
modelsAllEnabledFollow: "已启用全部当前目录模型;保存后将清除列表覆盖,未来新增模型会自动显示。",
|
|
91
|
+
modelsAllEnabledPreserve: "已启用全部当前目录模型;为保留其他模型参数,保存后会固定当前列表,未来新增模型不会自动显示。",
|
|
92
|
+
modelsShowMore: "显示未选择的 {count} 个模型",
|
|
93
|
+
modelsCollapse: "收起未选择的模型",
|
|
94
|
+
modelsSummary: "已选择 {selected}/{total} · 当前显示 {visible}/{total}",
|
|
74
95
|
modelsRetry: "重新读取",
|
|
75
96
|
modelsLoadFailed: "读取 Codex 模型目录失败。",
|
|
76
97
|
modelsSaveFailed: "保存模型启用设置失败。",
|
|
98
|
+
fastEnable: "启用 Fast(1.5×)",
|
|
99
|
+
fastDisable: "关闭 Fast,恢复默认速度",
|
|
100
|
+
fastUnsupported: "当前模型不支持 Fast(1.5×)",
|
|
101
|
+
fastLoading: "正在读取 Fast 状态",
|
|
102
|
+
fastUnavailable: "暂时无法读取 Fast 状态,点击重试",
|
|
103
|
+
legacyReasoningRepair: "修复并设为新会话默认模型",
|
|
104
|
+
legacyReasoningRepairing: "正在修复…",
|
|
105
|
+
legacyReasoningRepaired: "已修复并设为新会话默认模型",
|
|
106
|
+
legacyReasoningRepairRetry: "重试修复并设为新会话默认模型",
|
|
107
|
+
legacyReasoningRepairHelp: "旧会话保存了当前不支持的 Off/Minimal。点击后会切换到此模型当前默认档位;与模型选择器相同,此操作也会把该模型保存为未来新会话的默认模型。",
|
|
77
108
|
}
|
|
78
109
|
const en = {
|
|
79
110
|
nav: "OpenAI Codex",
|
|
@@ -88,6 +119,7 @@ window.__ModuleLoader__.load({
|
|
|
88
119
|
unavailable: "No Codex sign-in flow is available in this environment.",
|
|
89
120
|
writableNo: "The credential store is currently read-only.",
|
|
90
121
|
refresh: "Refresh",
|
|
122
|
+
refreshing: "Refreshing…",
|
|
91
123
|
signIn: "Sign in",
|
|
92
124
|
signInWithChatGPT: "Sign in with ChatGPT",
|
|
93
125
|
signInAgain: "Sign in again",
|
|
@@ -108,20 +140,36 @@ window.__ModuleLoader__.load({
|
|
|
108
140
|
logoutFailed: "Could not sign out. Please try again.",
|
|
109
141
|
responseFailed: "Could not submit the sign-in response. Please try again.",
|
|
110
142
|
requestFailed: "The local authorization service is temporarily unavailable.",
|
|
143
|
+
locale: "en-US",
|
|
111
144
|
quotaTitle: "Usage",
|
|
112
145
|
quotaProduct: "Codex",
|
|
113
|
-
|
|
114
|
-
|
|
146
|
+
quotaLoading: "Reading account usage…",
|
|
147
|
+
quotaLoadFailed: "Account usage could not be refreshed.",
|
|
148
|
+
quotaStaleHelp: "The last successfully verified data remains visible.",
|
|
149
|
+
quotaUnknown: "No verifiable usage data is available yet.",
|
|
150
|
+
quotaUnknownHelp: "After sign-in, usage is read whenever this page opens and when you refresh it; the latest safe observation remains available if the read fails.",
|
|
151
|
+
quotaFiveHour: "5-hour limit",
|
|
152
|
+
quotaWeekly: "Weekly limit",
|
|
153
|
+
quotaMinuteWindow: "minute limit",
|
|
154
|
+
quotaRemaining: "Remaining",
|
|
155
|
+
quotaResetsAt: "Resets",
|
|
156
|
+
quotaUpdatedAt: "Data updated",
|
|
157
|
+
quotaResetSoon: "Resets soon",
|
|
158
|
+
quotaResetPrefix: "Resets in",
|
|
159
|
+
quotaResetSuffix: "",
|
|
160
|
+
quotaResetMinute: "minute",
|
|
161
|
+
quotaResetHour: "hour",
|
|
162
|
+
quotaResetDay: "day",
|
|
115
163
|
quotaRecentSuccess: "The latest Codex request succeeded",
|
|
116
164
|
quotaSuccessCaution: "This only describes the latest request; it does not represent remaining account quota.",
|
|
117
165
|
quotaExhausted: "Codex account quota was exhausted in the latest observation.",
|
|
118
166
|
quotaObservedAt: "Observed at",
|
|
119
167
|
quotaResetAt: "Observed reset time",
|
|
120
|
-
quotaResetIn: "Approximately",
|
|
121
|
-
quotaMinutes: "minutes remaining",
|
|
122
168
|
quotaNoReset: "No reset time passed validation; this state automatically returns to unknown after a bounded interval.",
|
|
123
|
-
modelsTitle: "
|
|
124
|
-
modelsDescription: "Choose which Codex models appear in the model selector.
|
|
169
|
+
modelsTitle: "Codex models in this installation",
|
|
170
|
+
modelsDescription: "Choose which Codex models appear in the model selector. Names, context windows, and maximum output values come from the installed provider catalog; hidden models do not affect existing conversations.",
|
|
171
|
+
modelsContextWindow: "Context",
|
|
172
|
+
modelsMaxOutput: "Max output",
|
|
125
173
|
modelsLoading: "Reading the Codex model catalog…",
|
|
126
174
|
modelsUnavailable: "Codex model management is unavailable in this environment.",
|
|
127
175
|
modelsReadOnly: "The settings store is read-only, so enabled models cannot be changed.",
|
|
@@ -130,13 +178,43 @@ window.__ModuleLoader__.load({
|
|
|
130
178
|
modelsSaving: "Saving…",
|
|
131
179
|
modelsSaved: "Enabled models saved.",
|
|
132
180
|
modelsAtLeastOne: "At least one Codex model must remain enabled.",
|
|
133
|
-
modelsAllEnabledFollow: "All current catalog models are enabled.
|
|
134
|
-
modelsAllEnabledPreserve: "All current catalog models are enabled. To preserve
|
|
181
|
+
modelsAllEnabledFollow: "All current catalog models are enabled. Saving clears the list override, so future models appear automatically.",
|
|
182
|
+
modelsAllEnabledPreserve: "All current catalog models are enabled. To preserve other model settings, saving fixes the current list and future models will not appear automatically.",
|
|
183
|
+
modelsShowMore: "Show {count} unselected models",
|
|
184
|
+
modelsCollapse: "Hide unselected models",
|
|
185
|
+
modelsSummary: "Selected {selected}/{total} · Showing {visible}/{total}",
|
|
135
186
|
modelsRetry: "Reload",
|
|
136
187
|
modelsLoadFailed: "Could not read the Codex model catalog.",
|
|
137
188
|
modelsSaveFailed: "Could not save the enabled models.",
|
|
189
|
+
fastEnable: "Enable Fast (1.5×)",
|
|
190
|
+
fastDisable: "Turn off Fast and restore standard speed",
|
|
191
|
+
fastUnsupported: "The current model does not support Fast (1.5×)",
|
|
192
|
+
fastLoading: "Reading Fast status",
|
|
193
|
+
fastUnavailable: "Fast status is temporarily unavailable; click to retry",
|
|
194
|
+
legacyReasoningRepair: "Repair and set as future default",
|
|
195
|
+
legacyReasoningRepairing: "Repairing…",
|
|
196
|
+
legacyReasoningRepaired: "Repaired and set as future default",
|
|
197
|
+
legacyReasoningRepairRetry: "Retry repair and set as future default",
|
|
198
|
+
legacyReasoningRepairHelp: "This conversation saved an unsupported Off/Minimal level. Click to switch to this model's current default. Like using the model selector, this also saves it as the default model for future conversations.",
|
|
138
199
|
}
|
|
139
200
|
|
|
201
|
+
const NAV_ICON_MARKER = "data-dsh-codex-community-nav-icon"
|
|
202
|
+
const NAV_ICON_STYLE_SELECTOR = 'style[data-plugin-nav-icon="dsh-codex-community"]'
|
|
203
|
+
const NAV_ICON_STATE_KEY = Symbol.for("dsh-codex-community.settings-nav-icon.v1")
|
|
204
|
+
const NAV_ICON_LABELS = new Set([zh.nav.trim(), en.nav.trim()])
|
|
205
|
+
const SETTINGS_DIALOG_SELECTOR = '[role="dialog"][aria-modal="true"]'
|
|
206
|
+
const SETTINGS_NAV_SELECTOR = `${SETTINGS_DIALOG_SELECTOR} > nav`
|
|
207
|
+
const SETTINGS_NAV_BUTTON_SELECTOR = `${SETTINGS_NAV_SELECTOR} button`
|
|
208
|
+
// settings.section has no icon slot in Harness 0.1.1-rc.2. This original code-brackets glyph is applied only to the unique Codex nav entry.
|
|
209
|
+
const CODE_ICON_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
|
|
210
|
+
<path d="M5.25 3.25 1.5 8l3.75 4.75M10.75 3.25 14.5 8l-3.75 4.75M9.25 2.5l-2.5 11" fill="none" stroke="black" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
211
|
+
</svg>`
|
|
212
|
+
const CODE_ICON_MASK = `data:image/svg+xml,${encodeURIComponent(CODE_ICON_SVG).replace(/[!'()*]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`)}`
|
|
213
|
+
const NAV_ICON_CSS = [
|
|
214
|
+
`[${NAV_ICON_MARKER}]>svg:first-child{display:none!important}`,
|
|
215
|
+
`[${NAV_ICON_MARKER}]::before{content:"";width:16px;height:16px;flex:none;background:currentColor;-webkit-mask:url("${CODE_ICON_MASK}") center/contain no-repeat;mask:url("${CODE_ICON_MASK}") center/contain no-repeat}`,
|
|
216
|
+
].join("")
|
|
217
|
+
|
|
140
218
|
function createAuthorizationClient(connection) {
|
|
141
219
|
const call = async (endpoint, payload, signal) => {
|
|
142
220
|
const result = await connection.rpc.call(CHANNEL, endpoint, payload, signal)
|
|
@@ -164,9 +242,199 @@ window.__ModuleLoader__.load({
|
|
|
164
242
|
}),
|
|
165
243
|
cancel: (attemptId) => call("cancel", attemptId === undefined ? {} : { attemptId }),
|
|
166
244
|
logout: () => call("logout", {}),
|
|
245
|
+
usage: (signal) => call("usage", {}, signal),
|
|
167
246
|
})
|
|
168
247
|
}
|
|
169
248
|
|
|
249
|
+
function createSessionPreferenceClient(connection) {
|
|
250
|
+
const call = async (endpoint, payload, signal) => {
|
|
251
|
+
const result = await connection.rpc.call(SESSION_CHANNEL, endpoint, payload, signal)
|
|
252
|
+
if (!result.ok) {
|
|
253
|
+
const error = new Error(result.error.message)
|
|
254
|
+
error.code = result.error.code
|
|
255
|
+
throw error
|
|
256
|
+
}
|
|
257
|
+
return result.value
|
|
258
|
+
}
|
|
259
|
+
return Object.freeze({
|
|
260
|
+
forSession(sessionId) {
|
|
261
|
+
return Object.freeze({
|
|
262
|
+
get: (signal) => call("get", { sessionId }, signal),
|
|
263
|
+
setFast: (fast, signal) => call("set-fast", { sessionId, fast }, signal),
|
|
264
|
+
})
|
|
265
|
+
},
|
|
266
|
+
})
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function supportsFastModel(modelId) {
|
|
270
|
+
return modelId === "gpt-5.4"
|
|
271
|
+
|| modelId === "gpt-5.5"
|
|
272
|
+
|| modelId === "gpt-5.6-luna"
|
|
273
|
+
|| modelId === "gpt-5.6-sol"
|
|
274
|
+
|| modelId === "gpt-5.6-terra"
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function CodexFastToggle({
|
|
278
|
+
session,
|
|
279
|
+
useModelDirectory,
|
|
280
|
+
preferenceClient,
|
|
281
|
+
selectModel,
|
|
282
|
+
t,
|
|
283
|
+
}) {
|
|
284
|
+
const current = useModelDirectory((state) => state.current ?? null)
|
|
285
|
+
const [preference, setPreference] = React.useState({ status: "loading", fast: false })
|
|
286
|
+
const [repair, setRepair] = React.useState({ key: null, status: "idle" })
|
|
287
|
+
const mountedRef = React.useRef(false)
|
|
288
|
+
const generationRef = React.useRef(0)
|
|
289
|
+
const controllerRef = React.useRef(null)
|
|
290
|
+
const repairAttemptRef = React.useRef(null)
|
|
291
|
+
const isCodex = current?.provider === CODEX_PROVIDER
|
|
292
|
+
const supported = isCodex && supportsFastModel(current?.model)
|
|
293
|
+
|
|
294
|
+
const refreshPreference = React.useCallback(async () => {
|
|
295
|
+
if (!mountedRef.current || !isCodex) return
|
|
296
|
+
const generation = ++generationRef.current
|
|
297
|
+
controllerRef.current?.abort()
|
|
298
|
+
const controller = new AbortController()
|
|
299
|
+
controllerRef.current = controller
|
|
300
|
+
setPreference((value) => ({ status: "loading", fast: value.fast }))
|
|
301
|
+
try {
|
|
302
|
+
const value = await preferenceClient.get(controller.signal)
|
|
303
|
+
if (!mountedRef.current || generation !== generationRef.current || controller.signal.aborted) return
|
|
304
|
+
setPreference({ status: "ready", fast: value?.fast === true })
|
|
305
|
+
} catch {
|
|
306
|
+
if (!mountedRef.current || generation !== generationRef.current || controller.signal.aborted) return
|
|
307
|
+
setPreference((value) => ({ status: "error", fast: value.fast }))
|
|
308
|
+
} finally {
|
|
309
|
+
if (controllerRef.current === controller) controllerRef.current = null
|
|
310
|
+
}
|
|
311
|
+
}, [isCodex, preferenceClient])
|
|
312
|
+
|
|
313
|
+
React.useEffect(() => {
|
|
314
|
+
mountedRef.current = true
|
|
315
|
+
if (isCodex) void refreshPreference()
|
|
316
|
+
return () => {
|
|
317
|
+
mountedRef.current = false
|
|
318
|
+
generationRef.current += 1
|
|
319
|
+
controllerRef.current?.abort()
|
|
320
|
+
controllerRef.current = null
|
|
321
|
+
}
|
|
322
|
+
}, [isCodex, preferenceClient, refreshPreference])
|
|
323
|
+
|
|
324
|
+
const legacySelection = isCodex
|
|
325
|
+
&& (current?.reasoningEffort === "off" || current?.reasoningEffort === "minimal")
|
|
326
|
+
const legacyKey = legacySelection ? `${current.model}:${current.reasoningEffort}` : null
|
|
327
|
+
const repairStatus = repair.key === legacyKey ? repair.status : "idle"
|
|
328
|
+
|
|
329
|
+
const repairLegacySelection = async () => {
|
|
330
|
+
if (
|
|
331
|
+
!mountedRef.current
|
|
332
|
+
|| !legacySelection
|
|
333
|
+
|| typeof selectModel !== "function"
|
|
334
|
+
|| session?.removed === true
|
|
335
|
+
|| repairStatus === "saving"
|
|
336
|
+
|| repairStatus === "done"
|
|
337
|
+
|| repairAttemptRef.current === legacyKey
|
|
338
|
+
) return
|
|
339
|
+
const key = legacyKey
|
|
340
|
+
repairAttemptRef.current = key
|
|
341
|
+
setRepair({ key, status: "saving" })
|
|
342
|
+
try {
|
|
343
|
+
await selectModel({
|
|
344
|
+
provider: CODEX_PROVIDER,
|
|
345
|
+
model: current.model,
|
|
346
|
+
})
|
|
347
|
+
if (mountedRef.current) setRepair({ key, status: "done" })
|
|
348
|
+
} catch {
|
|
349
|
+
if (repairAttemptRef.current === key) repairAttemptRef.current = null
|
|
350
|
+
if (mountedRef.current) setRepair({ key, status: "error" })
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const toggleFast = async () => {
|
|
355
|
+
if (!mountedRef.current || !supported || session?.removed === true) return
|
|
356
|
+
if (preference.status === "error") {
|
|
357
|
+
void refreshPreference()
|
|
358
|
+
return
|
|
359
|
+
}
|
|
360
|
+
if (preference.status !== "ready") return
|
|
361
|
+
const generation = ++generationRef.current
|
|
362
|
+
controllerRef.current?.abort()
|
|
363
|
+
const controller = new AbortController()
|
|
364
|
+
controllerRef.current = controller
|
|
365
|
+
const nextFast = !preference.fast
|
|
366
|
+
setPreference({ status: "saving", fast: preference.fast })
|
|
367
|
+
try {
|
|
368
|
+
const value = await preferenceClient.setFast(nextFast, controller.signal)
|
|
369
|
+
if (!mountedRef.current || generation !== generationRef.current || controller.signal.aborted) return
|
|
370
|
+
setPreference({ status: "ready", fast: value?.fast === true })
|
|
371
|
+
} catch {
|
|
372
|
+
if (!mountedRef.current || generation !== generationRef.current || controller.signal.aborted) return
|
|
373
|
+
setPreference({ status: "error", fast: preference.fast })
|
|
374
|
+
} finally {
|
|
375
|
+
if (controllerRef.current === controller) controllerRef.current = null
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!isCodex) return null
|
|
380
|
+
const label = !supported
|
|
381
|
+
? t("fastUnsupported")
|
|
382
|
+
: preference.status === "loading" || preference.status === "saving"
|
|
383
|
+
? t("fastLoading")
|
|
384
|
+
: preference.status === "error"
|
|
385
|
+
? t("fastUnavailable")
|
|
386
|
+
: preference.fast
|
|
387
|
+
? t("fastDisable")
|
|
388
|
+
: t("fastEnable")
|
|
389
|
+
const disabled = !supported
|
|
390
|
+
|| session?.removed === true
|
|
391
|
+
|| preference.status === "loading"
|
|
392
|
+
|| preference.status === "saving"
|
|
393
|
+
|
|
394
|
+
const fastButton = h("button", {
|
|
395
|
+
type: "button",
|
|
396
|
+
className: "dshCodexFastToggle",
|
|
397
|
+
"data-fast": preference.fast ? "true" : undefined,
|
|
398
|
+
"aria-label": label,
|
|
399
|
+
"aria-pressed": preference.fast,
|
|
400
|
+
"aria-busy": preference.status === "loading" || preference.status === "saving" ? "true" : undefined,
|
|
401
|
+
title: label,
|
|
402
|
+
disabled,
|
|
403
|
+
onClick: () => void toggleFast(),
|
|
404
|
+
}, h("svg", {
|
|
405
|
+
viewBox: "0 0 24 24",
|
|
406
|
+
width: 16,
|
|
407
|
+
height: 16,
|
|
408
|
+
fill: "none",
|
|
409
|
+
stroke: "currentColor",
|
|
410
|
+
strokeWidth: 2,
|
|
411
|
+
strokeLinecap: "round",
|
|
412
|
+
strokeLinejoin: "round",
|
|
413
|
+
"aria-hidden": "true",
|
|
414
|
+
}, h("path", { d: "M13 2 4.5 13h7L11 22l8.5-11h-7L13 2Z" })))
|
|
415
|
+
|
|
416
|
+
if (!legacySelection || typeof selectModel !== "function") return fastButton
|
|
417
|
+
const repairLabel = repairStatus === "saving"
|
|
418
|
+
? t("legacyReasoningRepairing")
|
|
419
|
+
: repairStatus === "done"
|
|
420
|
+
? t("legacyReasoningRepaired")
|
|
421
|
+
: repairStatus === "error"
|
|
422
|
+
? t("legacyReasoningRepairRetry")
|
|
423
|
+
: t("legacyReasoningRepair")
|
|
424
|
+
return h(React.Fragment, null,
|
|
425
|
+
h("button", {
|
|
426
|
+
type: "button",
|
|
427
|
+
className: "dshCodexLegacyRepair",
|
|
428
|
+
"data-status": repairStatus,
|
|
429
|
+
"aria-label": repairLabel,
|
|
430
|
+
"aria-busy": repairStatus === "saving" ? "true" : undefined,
|
|
431
|
+
title: t("legacyReasoningRepairHelp"),
|
|
432
|
+
disabled: session?.removed === true || repairStatus === "saving" || repairStatus === "done",
|
|
433
|
+
onClick: () => void repairLegacySelection(),
|
|
434
|
+
}, repairLabel),
|
|
435
|
+
fastButton)
|
|
436
|
+
}
|
|
437
|
+
|
|
170
438
|
function resultValue(response) {
|
|
171
439
|
if (response?.result?.ok === true) return response.result.value
|
|
172
440
|
const message = response?.result?.error?.message
|
|
@@ -184,7 +452,9 @@ window.__ModuleLoader__.load({
|
|
|
184
452
|
return { status: "unknown" }
|
|
185
453
|
}
|
|
186
454
|
if (value.resetAt === undefined) return { status: value.status, observedAt: value.observedAt }
|
|
187
|
-
if (!Number.isSafeInteger(value.resetAt) || value.resetAt <= now
|
|
455
|
+
if (!Number.isSafeInteger(value.resetAt) || value.resetAt <= now || !Number.isFinite(new Date(value.resetAt).getTime())) {
|
|
456
|
+
return { status: "unknown" }
|
|
457
|
+
}
|
|
188
458
|
return {
|
|
189
459
|
status: value.status,
|
|
190
460
|
observedAt: value.observedAt,
|
|
@@ -193,6 +463,168 @@ window.__ModuleLoader__.load({
|
|
|
193
463
|
}
|
|
194
464
|
}
|
|
195
465
|
|
|
466
|
+
function safeAccountUsage(value) {
|
|
467
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
|
|
468
|
+
if (!Number.isSafeInteger(value.observedAt) || value.observedAt < 0) return undefined
|
|
469
|
+
if (!Array.isArray(value.rateLimits) || value.rateLimits.length > 16) return undefined
|
|
470
|
+
const rateLimits = []
|
|
471
|
+
for (const candidate of value.rateLimits) {
|
|
472
|
+
if (typeof candidate !== "object" || candidate === null || Array.isArray(candidate)) continue
|
|
473
|
+
if (typeof candidate.limitId !== "string" || candidate.limitId.length < 1 || candidate.limitId.length > 128) continue
|
|
474
|
+
const primary = safeUsageWindow(candidate.primary)
|
|
475
|
+
const secondary = safeUsageWindow(candidate.secondary)
|
|
476
|
+
if (primary === undefined && secondary === undefined) continue
|
|
477
|
+
rateLimits.push({
|
|
478
|
+
limitId: candidate.limitId,
|
|
479
|
+
...(typeof candidate.limitName === "string" && candidate.limitName.length > 0 && candidate.limitName.length <= 256
|
|
480
|
+
? { limitName: candidate.limitName }
|
|
481
|
+
: {}),
|
|
482
|
+
...(primary === undefined ? {} : { primary }),
|
|
483
|
+
...(secondary === undefined ? {} : { secondary }),
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
if (rateLimits.length === 0) return undefined
|
|
487
|
+
return { observedAt: value.observedAt, rateLimits }
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function safeUsageWindow(value) {
|
|
491
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return undefined
|
|
492
|
+
if (typeof value.usedPercent !== "number" || !Number.isFinite(value.usedPercent) || value.usedPercent < 0 || value.usedPercent > 100) return undefined
|
|
493
|
+
if (!Number.isSafeInteger(value.windowDurationMins) || value.windowDurationMins < 1 || value.windowDurationMins > 525_600) return undefined
|
|
494
|
+
if (!Number.isSafeInteger(value.resetsAt) || value.resetsAt < 0 || !Number.isFinite(new Date(value.resetsAt).getTime())) return undefined
|
|
495
|
+
return {
|
|
496
|
+
usedPercent: value.usedPercent,
|
|
497
|
+
windowDurationMins: value.windowDurationMins,
|
|
498
|
+
resetsAt: value.resetsAt,
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function percentText(value) {
|
|
503
|
+
return String(Math.round(value * 10) / 10)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function usageWindowLabel(window, t) {
|
|
507
|
+
if (window.windowDurationMins === 300) return t("quotaFiveHour")
|
|
508
|
+
if (window.windowDurationMins === 10_080) return t("quotaWeekly")
|
|
509
|
+
return `${window.windowDurationMins} ${t("quotaMinuteWindow")}`
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function formatResetDistance(resetsAt, t, now = Date.now()) {
|
|
513
|
+
if (!Number.isSafeInteger(resetsAt) || !Number.isSafeInteger(now) || resetsAt < 0 || now < 0) {
|
|
514
|
+
return t("quotaResetSoon")
|
|
515
|
+
}
|
|
516
|
+
const remaining = resetsAt - now
|
|
517
|
+
if (remaining <= 60_000) return t("quotaResetSoon")
|
|
518
|
+
let count
|
|
519
|
+
let unit
|
|
520
|
+
if (remaining < 60 * 60_000) {
|
|
521
|
+
count = Math.ceil(remaining / 60_000)
|
|
522
|
+
unit = t("quotaResetMinute")
|
|
523
|
+
} else if (remaining < 24 * 60 * 60_000) {
|
|
524
|
+
count = Math.ceil(remaining / (60 * 60_000))
|
|
525
|
+
unit = t("quotaResetHour")
|
|
526
|
+
} else {
|
|
527
|
+
count = Math.ceil(remaining / (24 * 60 * 60_000))
|
|
528
|
+
unit = t("quotaResetDay")
|
|
529
|
+
}
|
|
530
|
+
if (t("locale").toLowerCase().startsWith("zh")) {
|
|
531
|
+
return `${count} ${unit}${t("quotaResetSuffix")}`
|
|
532
|
+
}
|
|
533
|
+
return `${t("quotaResetPrefix")} ${count} ${unit}${count === 1 ? "" : "s"}`
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function renderResetTime(resetsAt, t, { showExact = false, now = Date.now() } = {}) {
|
|
537
|
+
const exact = new Date(resetsAt).toLocaleString(t("locale"))
|
|
538
|
+
const relative = formatResetDistance(resetsAt, t, now)
|
|
539
|
+
const separator = t("locale").toLowerCase().startsWith("zh") ? ":" : ": "
|
|
540
|
+
const exactLabel = `${t("quotaResetsAt")}${separator}${exact}`
|
|
541
|
+
return h("time", {
|
|
542
|
+
dateTime: new Date(resetsAt).toISOString(),
|
|
543
|
+
title: exactLabel,
|
|
544
|
+
"aria-label": showExact ? exactLabel : `${relative} · ${exactLabel}`,
|
|
545
|
+
}, showExact ? exactLabel : relative)
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
function refreshIcon() {
|
|
549
|
+
return h("svg", {
|
|
550
|
+
className: "dshCodexRefreshIcon",
|
|
551
|
+
viewBox: "0 0 16 16",
|
|
552
|
+
fill: "none",
|
|
553
|
+
"aria-hidden": "true",
|
|
554
|
+
focusable: "false",
|
|
555
|
+
},
|
|
556
|
+
h("path", {
|
|
557
|
+
d: "M13.25 5.75A5.5 5.5 0 1 0 13.1 10.6",
|
|
558
|
+
stroke: "currentColor",
|
|
559
|
+
strokeWidth: "1.4",
|
|
560
|
+
strokeLinecap: "round",
|
|
561
|
+
}),
|
|
562
|
+
h("path", {
|
|
563
|
+
d: "M10.25 5.75h3v-3",
|
|
564
|
+
stroke: "currentColor",
|
|
565
|
+
strokeWidth: "1.4",
|
|
566
|
+
strokeLinecap: "round",
|
|
567
|
+
strokeLinejoin: "round",
|
|
568
|
+
}))
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function renderObservedQuota(quota, t) {
|
|
572
|
+
if (quota.status === "recent-success") {
|
|
573
|
+
return h(React.Fragment, null,
|
|
574
|
+
h("p", { className: "dshCodexQuotaState" }, `${t("quotaRecentSuccess")} · ${new Date(quota.observedAt).toLocaleString(t("locale"))}`),
|
|
575
|
+
h("p", { className: "dshCodexMuted" }, t("quotaSuccessCaution")))
|
|
576
|
+
}
|
|
577
|
+
if (quota.status === "exhausted") {
|
|
578
|
+
return h(React.Fragment, null,
|
|
579
|
+
h("p", { className: "dshCodexQuotaState dshCodexQuotaExhausted" }, t("quotaExhausted")),
|
|
580
|
+
h("p", { className: "dshCodexMuted" }, `${t("quotaObservedAt")} · ${new Date(quota.observedAt).toLocaleString(t("locale"))}`),
|
|
581
|
+
quota.resetAt === undefined
|
|
582
|
+
? h("p", { className: "dshCodexMuted" }, t("quotaNoReset"))
|
|
583
|
+
: h("p", { className: "dshCodexMuted" },
|
|
584
|
+
`${t("quotaResetAt")} · `,
|
|
585
|
+
renderResetTime(quota.resetAt, t)))
|
|
586
|
+
}
|
|
587
|
+
return h(React.Fragment, null,
|
|
588
|
+
h("p", { className: "dshCodexQuotaState dshCodexQuotaUnknown" }, t("quotaUnknown")),
|
|
589
|
+
h("p", { className: "dshCodexMuted" }, t("quotaUnknownHelp")))
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
function renderAccountUsage(usage, t) {
|
|
593
|
+
const now = Date.now()
|
|
594
|
+
return h(React.Fragment, null,
|
|
595
|
+
...usage.rateLimits.map((limit) => {
|
|
596
|
+
const windows = [limit.primary, limit.secondary].filter((window) => window !== undefined)
|
|
597
|
+
const limitLabel = limit.limitId === "codex"
|
|
598
|
+
? t("quotaProduct")
|
|
599
|
+
: limit.limitName ?? limit.limitId
|
|
600
|
+
return h("section", { key: limit.limitId, className: "dshCodexQuotaGroup" },
|
|
601
|
+
h("p", { className: "dshCodexQuotaProduct" }, limitLabel),
|
|
602
|
+
h("div", { className: "dshCodexQuotaWindows" },
|
|
603
|
+
...windows.map((window) => {
|
|
604
|
+
const remaining = Math.max(0, Math.min(100, 100 - window.usedPercent))
|
|
605
|
+
const remainingText = percentText(remaining)
|
|
606
|
+
const label = usageWindowLabel(window, t)
|
|
607
|
+
const resetDistance = window.resetsAt - now
|
|
608
|
+
const showExactReset = window.windowDurationMins === 300
|
|
609
|
+
|| (window.windowDurationMins === 10_080
|
|
610
|
+
&& resetDistance > 0
|
|
611
|
+
&& resetDistance < 24 * 60 * 60_000)
|
|
612
|
+
return h("div", { key: `${limit.limitId}-${window.windowDurationMins}`, className: "dshCodexQuotaWindow" },
|
|
613
|
+
h("div", { className: "dshCodexQuotaWindowHeader" },
|
|
614
|
+
h("span", null, label),
|
|
615
|
+
h("strong", null, `${t("quotaRemaining")} ${remainingText}%`)),
|
|
616
|
+
h("progress", {
|
|
617
|
+
max: 100,
|
|
618
|
+
value: remaining,
|
|
619
|
+
"aria-label": `${limitLabel} · ${label} · ${t("quotaRemaining")} ${remainingText}%`,
|
|
620
|
+
}),
|
|
621
|
+
h("div", { className: "dshCodexQuotaMeta" },
|
|
622
|
+
renderResetTime(window.resetsAt, t, { showExact: showExactReset, now })))
|
|
623
|
+
})))
|
|
624
|
+
}),
|
|
625
|
+
h("p", { className: "dshCodexMuted dshCodexQuotaUpdated" }, `${t("quotaUpdatedAt")}${t("locale").toLowerCase().startsWith("zh") ? ":" : ": "}${new Date(usage.observedAt).toLocaleString(t("locale"))}`))
|
|
626
|
+
}
|
|
627
|
+
|
|
196
628
|
function objectAtPath(root, path) {
|
|
197
629
|
let current = root
|
|
198
630
|
for (const key of path) {
|
|
@@ -217,11 +649,28 @@ window.__ModuleLoader__.load({
|
|
|
217
649
|
rows.push({
|
|
218
650
|
id: candidate.id,
|
|
219
651
|
...(typeof candidate.name === "string" && candidate.name.length > 0 ? { name: candidate.name } : {}),
|
|
652
|
+
...(Number.isSafeInteger(candidate.contextWindow) && candidate.contextWindow > 0
|
|
653
|
+
? { contextWindow: candidate.contextWindow }
|
|
654
|
+
: {}),
|
|
655
|
+
...(Number.isSafeInteger(candidate.maxTokens) && candidate.maxTokens > 0
|
|
656
|
+
? { maxTokens: candidate.maxTokens }
|
|
657
|
+
: {}),
|
|
220
658
|
})
|
|
221
659
|
}
|
|
222
660
|
return rows
|
|
223
661
|
}
|
|
224
662
|
|
|
663
|
+
function formatModelTokenCount(value, locale) {
|
|
664
|
+
const divisor = value >= 1_000_000 ? 1_000_000 : value >= 1_000 ? 1_000 : 1
|
|
665
|
+
const suffix = divisor === 1_000_000 ? "M" : divisor === 1_000 ? "K" : ""
|
|
666
|
+
const compact = value / divisor
|
|
667
|
+
try {
|
|
668
|
+
return `${compact.toLocaleString(locale, { maximumFractionDigits: 1 })}${suffix}`
|
|
669
|
+
} catch {
|
|
670
|
+
return `${Math.round(compact * 10) / 10}${suffix}`
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
225
674
|
function modelSavePlan(snapshot, selectedIds) {
|
|
226
675
|
const selected = new Set(selectedIds)
|
|
227
676
|
const modelIds = snapshot.models.map((model) => model.id)
|
|
@@ -340,6 +789,7 @@ window.__ModuleLoader__.load({
|
|
|
340
789
|
|
|
341
790
|
function AuthorizationSettings({ client, t }) {
|
|
342
791
|
const [snapshot, setSnapshot] = React.useState({ status: "loading" })
|
|
792
|
+
const [usageSnapshot, setUsageSnapshot] = React.useState({ status: "idle" })
|
|
343
793
|
const [attempt, setAttempt] = React.useState(null)
|
|
344
794
|
const [notices, setNotices] = React.useState([])
|
|
345
795
|
const [prompt, setPrompt] = React.useState(null)
|
|
@@ -368,6 +818,29 @@ window.__ModuleLoader__.load({
|
|
|
368
818
|
const value = await client.describe(controller.signal)
|
|
369
819
|
if (!mountedRef.current || generation !== refreshGenerationRef.current || controller.signal.aborted) return
|
|
370
820
|
setSnapshot({ status: "ready", value })
|
|
821
|
+
const credentialState = value?.credential?.state
|
|
822
|
+
const signedIn = credentialState === "signed-in"
|
|
823
|
+
|| (credentialState === undefined && value?.credential?.configured === true)
|
|
824
|
+
if (!signedIn || typeof client.usage !== "function") {
|
|
825
|
+
setUsageSnapshot({ status: "idle" })
|
|
826
|
+
return
|
|
827
|
+
}
|
|
828
|
+
setUsageSnapshot((current) => ({
|
|
829
|
+
status: "loading",
|
|
830
|
+
...(current.value === undefined ? {} : { value: current.value }),
|
|
831
|
+
}))
|
|
832
|
+
try {
|
|
833
|
+
const usage = safeAccountUsage(await client.usage(controller.signal))
|
|
834
|
+
if (usage === undefined) throw new Error("invalid account usage")
|
|
835
|
+
if (!mountedRef.current || generation !== refreshGenerationRef.current || controller.signal.aborted) return
|
|
836
|
+
setUsageSnapshot({ status: "ready", value: usage })
|
|
837
|
+
} catch {
|
|
838
|
+
if (!mountedRef.current || generation !== refreshGenerationRef.current || controller.signal.aborted) return
|
|
839
|
+
setUsageSnapshot((current) => ({
|
|
840
|
+
status: "error",
|
|
841
|
+
...(current.value === undefined ? {} : { value: current.value }),
|
|
842
|
+
}))
|
|
843
|
+
}
|
|
371
844
|
} catch {
|
|
372
845
|
if (!mountedRef.current || generation !== refreshGenerationRef.current || controller.signal.aborted) return
|
|
373
846
|
setSnapshot({ status: "error" })
|
|
@@ -381,9 +854,6 @@ window.__ModuleLoader__.load({
|
|
|
381
854
|
React.useEffect(() => {
|
|
382
855
|
mountedRef.current = true
|
|
383
856
|
void refresh()
|
|
384
|
-
const timer = typeof window.setInterval === "function"
|
|
385
|
-
? window.setInterval(() => void refresh(), 60_000)
|
|
386
|
-
: undefined
|
|
387
857
|
return () => {
|
|
388
858
|
mountedRef.current = false
|
|
389
859
|
refreshGenerationRef.current += 1
|
|
@@ -396,7 +866,6 @@ window.__ModuleLoader__.load({
|
|
|
396
866
|
attemptRef.current = null
|
|
397
867
|
current?.controller.abort()
|
|
398
868
|
if (current !== null && !current.done) void client.cancel(current.id).catch(() => undefined)
|
|
399
|
-
if (timer !== undefined) window.clearInterval(timer)
|
|
400
869
|
}
|
|
401
870
|
}, [client])
|
|
402
871
|
|
|
@@ -646,22 +1115,22 @@ window.__ModuleLoader__.load({
|
|
|
646
1115
|
onClick: () => void logout(),
|
|
647
1116
|
}, loggingOut ? t("signingOut") : t("signOut")) : null)
|
|
648
1117
|
|
|
1118
|
+
const liveUsage = usageSnapshot.value
|
|
649
1119
|
let quotaBody
|
|
650
|
-
if (
|
|
1120
|
+
if (liveUsage !== undefined) {
|
|
651
1121
|
quotaBody = h(React.Fragment, null,
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
1122
|
+
renderAccountUsage(liveUsage, t),
|
|
1123
|
+
usageSnapshot.status === "error"
|
|
1124
|
+
? h("p", { role: "status", className: "dshCodexError" }, `${t("quotaLoadFailed")} ${t("quotaStaleHelp")}`)
|
|
1125
|
+
: null)
|
|
1126
|
+
} else if (usageSnapshot.status === "loading") {
|
|
1127
|
+
quotaBody = h("p", { className: "dshCodexMuted", "aria-busy": "true" }, t("quotaLoading"))
|
|
1128
|
+
} else if (usageSnapshot.status === "error") {
|
|
655
1129
|
quotaBody = h(React.Fragment, null,
|
|
656
|
-
h("p", {
|
|
657
|
-
|
|
658
|
-
quota.resetAt === undefined
|
|
659
|
-
? h("p", { className: "dshCodexMuted" }, t("quotaNoReset"))
|
|
660
|
-
: h("p", { className: "dshCodexMuted" }, `${t("quotaResetAt")} · ${new Date(quota.resetAt).toLocaleString()} · ${t("quotaResetIn")} ${quota.remainingMinutes} ${t("quotaMinutes")}`))
|
|
1130
|
+
h("p", { role: "status", className: "dshCodexError" }, t("quotaLoadFailed")),
|
|
1131
|
+
renderObservedQuota(quota, t))
|
|
661
1132
|
} else {
|
|
662
|
-
quotaBody =
|
|
663
|
-
h("p", { className: "dshCodexQuotaState dshCodexQuotaUnknown" }, t("quotaUnknown")),
|
|
664
|
-
h("p", { className: "dshCodexMuted" }, t("quotaUnknownHelp")))
|
|
1133
|
+
quotaBody = renderObservedQuota(quota, t)
|
|
665
1134
|
}
|
|
666
1135
|
|
|
667
1136
|
return h("section", {
|
|
@@ -733,6 +1202,7 @@ window.__ModuleLoader__.load({
|
|
|
733
1202
|
h("section", {
|
|
734
1203
|
className: "dshCodexQuota",
|
|
735
1204
|
"data-quota-status": quota.status,
|
|
1205
|
+
"aria-busy": usageSnapshot.status === "loading" ? "true" : undefined,
|
|
736
1206
|
"aria-live": "polite",
|
|
737
1207
|
"aria-labelledby": "dsh-codex-quota-title",
|
|
738
1208
|
},
|
|
@@ -741,10 +1211,16 @@ window.__ModuleLoader__.load({
|
|
|
741
1211
|
h("button", {
|
|
742
1212
|
type: "button",
|
|
743
1213
|
className: "dshCodexButton dshCodexRefreshButton",
|
|
744
|
-
|
|
1214
|
+
"data-loading": usageSnapshot.status === "loading" ? "true" : undefined,
|
|
1215
|
+
"aria-busy": usageSnapshot.status === "loading" ? "true" : undefined,
|
|
1216
|
+
disabled: actionBusy || usageSnapshot.status === "loading",
|
|
745
1217
|
onClick: refresh,
|
|
746
|
-
},
|
|
747
|
-
|
|
1218
|
+
},
|
|
1219
|
+
refreshIcon(),
|
|
1220
|
+
h("span", null, usageSnapshot.status === "loading" ? t("refreshing") : t("refresh")))),
|
|
1221
|
+
liveUsage === undefined
|
|
1222
|
+
? h("p", { className: "dshCodexQuotaProduct" }, t("quotaProduct"))
|
|
1223
|
+
: null,
|
|
748
1224
|
quotaBody))
|
|
749
1225
|
}
|
|
750
1226
|
|
|
@@ -761,13 +1237,17 @@ window.__ModuleLoader__.load({
|
|
|
761
1237
|
const [saving, setSaving] = React.useState(false)
|
|
762
1238
|
const [saved, setSaved] = React.useState(false)
|
|
763
1239
|
const [failure, setFailure] = React.useState(null)
|
|
1240
|
+
const [expanded, setExpanded] = React.useState(false)
|
|
764
1241
|
const generationRef = React.useRef(0)
|
|
765
1242
|
const mountedRef = React.useRef(false)
|
|
1243
|
+
const modelToggleRef = React.useRef(null)
|
|
1244
|
+
const focusModelToggleRef = React.useRef(false)
|
|
766
1245
|
|
|
767
1246
|
const refresh = React.useCallback(async () => {
|
|
768
1247
|
const generation = ++generationRef.current
|
|
769
1248
|
setSaved(false)
|
|
770
1249
|
setFailure(null)
|
|
1250
|
+
setExpanded(false)
|
|
771
1251
|
setSnapshot({ kind: "loading" })
|
|
772
1252
|
try {
|
|
773
1253
|
const next = await client.load()
|
|
@@ -792,6 +1272,12 @@ window.__ModuleLoader__.load({
|
|
|
792
1272
|
}
|
|
793
1273
|
}, [client, refresh])
|
|
794
1274
|
|
|
1275
|
+
React.useEffect(() => {
|
|
1276
|
+
if (!focusModelToggleRef.current) return
|
|
1277
|
+
focusModelToggleRef.current = false
|
|
1278
|
+
if (typeof modelToggleRef.current?.focus === "function") modelToggleRef.current.focus()
|
|
1279
|
+
}, [expanded, selectedIds])
|
|
1280
|
+
|
|
795
1281
|
const toggle = (id) => {
|
|
796
1282
|
const selected = selectedIds.includes(id)
|
|
797
1283
|
if (selected && selectedIds.length === 1) {
|
|
@@ -800,6 +1286,7 @@ window.__ModuleLoader__.load({
|
|
|
800
1286
|
}
|
|
801
1287
|
setSaved(false)
|
|
802
1288
|
setFailure(null)
|
|
1289
|
+
if (selected && !expanded) focusModelToggleRef.current = true
|
|
803
1290
|
setSelectedIds(selected
|
|
804
1291
|
? selectedIds.filter((candidate) => candidate !== id)
|
|
805
1292
|
: [...selectedIds, id])
|
|
@@ -832,6 +1319,7 @@ window.__ModuleLoader__.load({
|
|
|
832
1319
|
}
|
|
833
1320
|
|
|
834
1321
|
let content
|
|
1322
|
+
let modelSummary = null
|
|
835
1323
|
if (snapshot.kind === "loading") {
|
|
836
1324
|
content = h("p", { className: "dshCodexMuted", "aria-busy": "true" }, t("modelsLoading"))
|
|
837
1325
|
} else if (snapshot.kind === "unavailable") {
|
|
@@ -851,26 +1339,68 @@ window.__ModuleLoader__.load({
|
|
|
851
1339
|
const original = new Set(snapshot.selectedIds)
|
|
852
1340
|
const dirty = selected.size !== original.size || [...selected].some((id) => !original.has(id))
|
|
853
1341
|
const plan = modelSavePlan(snapshot, selectedIds)
|
|
854
|
-
const
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
1342
|
+
const selectedModels = snapshot.models.filter((model) => selected.has(model.id))
|
|
1343
|
+
const unselectedModels = snapshot.models.filter((model) => !selected.has(model.id))
|
|
1344
|
+
const hiddenModelCount = unselectedModels.length
|
|
1345
|
+
const visibleModels = expanded
|
|
1346
|
+
? [...selectedModels, ...unselectedModels]
|
|
1347
|
+
: selectedModels
|
|
1348
|
+
modelSummary = t("modelsSummary")
|
|
1349
|
+
.replace("{selected}", String(selected.size))
|
|
1350
|
+
.replaceAll("{total}", String(snapshot.models.length))
|
|
1351
|
+
.replace("{visible}", String(visibleModels.length))
|
|
1352
|
+
const modelItems = visibleModels.map((model) => {
|
|
1353
|
+
const metadata = [
|
|
1354
|
+
...(model.contextWindow === undefined
|
|
1355
|
+
? []
|
|
1356
|
+
: [`${t("modelsContextWindow")} ${formatModelTokenCount(model.contextWindow, t("locale"))}`]),
|
|
1357
|
+
...(model.maxTokens === undefined
|
|
1358
|
+
? []
|
|
1359
|
+
: [`${t("modelsMaxOutput")} ${formatModelTokenCount(model.maxTokens, t("locale"))}`]),
|
|
1360
|
+
]
|
|
1361
|
+
return h("li", { key: model.id },
|
|
1362
|
+
h("label", {
|
|
1363
|
+
className: "dshCodexModelOption",
|
|
1364
|
+
"data-selected": selected.has(model.id) ? "true" : undefined,
|
|
1365
|
+
},
|
|
1366
|
+
h("input", {
|
|
1367
|
+
type: "checkbox",
|
|
1368
|
+
checked: selected.has(model.id),
|
|
1369
|
+
disabled: saving || !snapshot.writable,
|
|
1370
|
+
onChange: () => toggle(model.id),
|
|
1371
|
+
}),
|
|
1372
|
+
h("span", { className: "dshCodexModelCopy" },
|
|
1373
|
+
h("span", { className: "dshCodexModelHeading" },
|
|
1374
|
+
h("strong", null, model.name ?? model.id),
|
|
1375
|
+
model.name === undefined || model.name === model.id
|
|
1376
|
+
? null
|
|
1377
|
+
: h("code", { className: "dshCodexModelId" }, model.id)),
|
|
1378
|
+
metadata.length === 0
|
|
1379
|
+
? null
|
|
1380
|
+
: h("span", { className: "dshCodexModelCapabilities" },
|
|
1381
|
+
...metadata.map((label) => h("span", {
|
|
1382
|
+
key: label,
|
|
1383
|
+
className: "dshCodexModelBadge",
|
|
1384
|
+
}, label))))))
|
|
1385
|
+
})
|
|
868
1386
|
content = h(React.Fragment, null,
|
|
869
1387
|
snapshot.writable ? null : h("p", { className: "dshCodexMuted" }, t("modelsReadOnly")),
|
|
870
1388
|
h("ul", {
|
|
1389
|
+
id: "dsh-codex-model-list",
|
|
871
1390
|
className: "dshCodexModelList",
|
|
872
1391
|
"aria-labelledby": "dsh-codex-models-title",
|
|
873
1392
|
}, ...modelItems),
|
|
1393
|
+
hiddenModelCount === 0 ? null : h("button", {
|
|
1394
|
+
type: "button",
|
|
1395
|
+
className: "dshCodexButton dshCodexModelToggle",
|
|
1396
|
+
"aria-controls": "dsh-codex-model-list",
|
|
1397
|
+
"aria-expanded": expanded ? "true" : "false",
|
|
1398
|
+
ref: modelToggleRef,
|
|
1399
|
+
disabled: saving,
|
|
1400
|
+
onClick: () => setExpanded((current) => !current),
|
|
1401
|
+
}, expanded
|
|
1402
|
+
? t("modelsCollapse")
|
|
1403
|
+
: t("modelsShowMore").replace("{count}", String(hiddenModelCount))),
|
|
874
1404
|
plan.allCatalogSelected ? h("p", { className: "dshCodexMuted" }, t(plan.unsetOverride
|
|
875
1405
|
? "modelsAllEnabledFollow"
|
|
876
1406
|
: "modelsAllEnabledPreserve")) : null,
|
|
@@ -894,7 +1424,11 @@ window.__ModuleLoader__.load({
|
|
|
894
1424
|
return h("section", { className: "dshCodexPanel dshCodexCard dshCodexModelPanel" },
|
|
895
1425
|
h("header", { className: "dshCodexHeader" },
|
|
896
1426
|
h("div", null,
|
|
897
|
-
h("
|
|
1427
|
+
h("div", { className: "dshCodexModelTitleRow" },
|
|
1428
|
+
h("h3", { id: "dsh-codex-models-title" }, t("modelsTitle")),
|
|
1429
|
+
modelSummary === null
|
|
1430
|
+
? null
|
|
1431
|
+
: h("span", { className: "dshCodexModelSummary" }, modelSummary)),
|
|
898
1432
|
h("p", { className: "dshCodexWarning" }, t("modelsDescription")))),
|
|
899
1433
|
content)
|
|
900
1434
|
}
|
|
@@ -912,9 +1446,11 @@ window.__ModuleLoader__.load({
|
|
|
912
1446
|
|
|
913
1447
|
function apply(ctx) {
|
|
914
1448
|
ctx.effect(installStyle, "dsh-codex: client styles")
|
|
1449
|
+
ctx.effect(installSettingsNavIcon, "dsh-codex: settings nav icon")
|
|
915
1450
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-codex: client dictionaries")
|
|
916
1451
|
const t = ctx.locale.bind(NS)
|
|
917
1452
|
const client = createAuthorizationClient(ctx.connection)
|
|
1453
|
+
const sessionPreferenceClient = createSessionPreferenceClient(ctx.connection)
|
|
918
1454
|
const modelClient = createModelEnablementClient(ctx.connection, ctx.settingsScope?.describe?.())
|
|
919
1455
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
920
1456
|
name: "settings.section",
|
|
@@ -924,6 +1460,115 @@ window.__ModuleLoader__.load({
|
|
|
924
1460
|
locale: NS,
|
|
925
1461
|
inject: () => ({ client, modelClient, t }),
|
|
926
1462
|
}, CodexSettings))
|
|
1463
|
+
ctx.inject?.(["slots", "modelDirectories"], (scope) => {
|
|
1464
|
+
scope.slots.inject("conversation.input.right", () => scope.slots.register({
|
|
1465
|
+
name: "conversation.input.right",
|
|
1466
|
+
id: "dsh-codex-fast",
|
|
1467
|
+
order: 100,
|
|
1468
|
+
locale: NS,
|
|
1469
|
+
inject: (sessionId) => {
|
|
1470
|
+
const directory = scope.modelDirectories.directoryFor(sessionId)
|
|
1471
|
+
return {
|
|
1472
|
+
preferenceClient: sessionPreferenceClient.forSession(sessionId),
|
|
1473
|
+
selectModel: (selection) => directory.select(selection),
|
|
1474
|
+
t,
|
|
1475
|
+
hooks: {
|
|
1476
|
+
modelDirectory: directory.store,
|
|
1477
|
+
},
|
|
1478
|
+
}
|
|
1479
|
+
},
|
|
1480
|
+
}, CodexFastToggle))
|
|
1481
|
+
})
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
function installSettingsNavIcon() {
|
|
1485
|
+
if (typeof document === "undefined" || typeof window === "undefined") return undefined
|
|
1486
|
+
const Observer = typeof window.MutationObserver === "function"
|
|
1487
|
+
? window.MutationObserver
|
|
1488
|
+
: typeof MutationObserver === "function" ? MutationObserver : undefined
|
|
1489
|
+
if (!document.body || typeof document.querySelectorAll !== "function" || Observer === undefined) return undefined
|
|
1490
|
+
|
|
1491
|
+
const isInsideSettingsNav = (target) => {
|
|
1492
|
+
const element = target?.nodeType === 1 ? target : target?.parentElement
|
|
1493
|
+
return typeof element?.closest === "function" && element.closest(SETTINGS_NAV_SELECTOR) !== null
|
|
1494
|
+
}
|
|
1495
|
+
const matchesOrContains = (node, selector) => (
|
|
1496
|
+
(typeof node?.matches === "function" && node.matches(selector))
|
|
1497
|
+
|| (typeof node?.querySelector === "function" && node.querySelector(selector) !== null)
|
|
1498
|
+
)
|
|
1499
|
+
const mutationTouchesSettingsNav = (records) => Array.from(records ?? []).some((record) => {
|
|
1500
|
+
if (isInsideSettingsNav(record.target)) return true
|
|
1501
|
+
return [...Array.from(record.addedNodes ?? []), ...Array.from(record.removedNodes ?? [])]
|
|
1502
|
+
.some((node) => matchesOrContains(node, SETTINGS_DIALOG_SELECTOR) || matchesOrContains(node, SETTINGS_NAV_SELECTOR))
|
|
1503
|
+
})
|
|
1504
|
+
const enqueueMicrotask = typeof window.queueMicrotask === "function"
|
|
1505
|
+
? (callback) => window.queueMicrotask(callback)
|
|
1506
|
+
: (callback) => Promise.resolve().then(callback)
|
|
1507
|
+
|
|
1508
|
+
let state = window[NAV_ICON_STATE_KEY]
|
|
1509
|
+
if (state === undefined) {
|
|
1510
|
+
let style = document.querySelector(NAV_ICON_STYLE_SELECTOR)
|
|
1511
|
+
if (style === null) {
|
|
1512
|
+
style = document.createElement("style")
|
|
1513
|
+
style.dataset.pluginNavIcon = "dsh-codex-community"
|
|
1514
|
+
document.head.appendChild(style)
|
|
1515
|
+
}
|
|
1516
|
+
style.dataset.plugin = "dsh-codex-community"
|
|
1517
|
+
const clearMarkers = () => {
|
|
1518
|
+
for (const button of document.querySelectorAll(`[${NAV_ICON_MARKER}]`)) button.removeAttribute(NAV_ICON_MARKER)
|
|
1519
|
+
}
|
|
1520
|
+
state = {
|
|
1521
|
+
active: true,
|
|
1522
|
+
refs: 0,
|
|
1523
|
+
scheduled: false,
|
|
1524
|
+
style,
|
|
1525
|
+
clearMarkers,
|
|
1526
|
+
scheduleSync() {
|
|
1527
|
+
if (!state.active || state.scheduled) return
|
|
1528
|
+
state.scheduled = true
|
|
1529
|
+
enqueueMicrotask(() => {
|
|
1530
|
+
state.scheduled = false
|
|
1531
|
+
state.sync()
|
|
1532
|
+
})
|
|
1533
|
+
},
|
|
1534
|
+
sync() {
|
|
1535
|
+
if (!state.active) return
|
|
1536
|
+
clearMarkers()
|
|
1537
|
+
const candidates = []
|
|
1538
|
+
for (const button of document.querySelectorAll(SETTINGS_NAV_BUTTON_SELECTOR)) {
|
|
1539
|
+
const icon = button.firstElementChild
|
|
1540
|
+
const labelElement = icon?.nextElementSibling
|
|
1541
|
+
if (icon?.localName !== "svg" || labelElement?.localName !== "span") continue
|
|
1542
|
+
const label = String(labelElement.textContent ?? "").replace(/\s+/gu, " ").trim()
|
|
1543
|
+
if (NAV_ICON_LABELS.has(label)) candidates.push(button)
|
|
1544
|
+
}
|
|
1545
|
+
if (candidates.length === 1) candidates[0].setAttribute(NAV_ICON_MARKER, "")
|
|
1546
|
+
},
|
|
1547
|
+
}
|
|
1548
|
+
state.observer = new Observer((records) => {
|
|
1549
|
+
if (mutationTouchesSettingsNav(records)) state.scheduleSync()
|
|
1550
|
+
})
|
|
1551
|
+
state.observer.observe(document.body, { childList: true, subtree: true, characterData: true })
|
|
1552
|
+
window[NAV_ICON_STATE_KEY] = state
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
state.refs += 1
|
|
1556
|
+
state.style.textContent = NAV_ICON_CSS
|
|
1557
|
+
state.sync()
|
|
1558
|
+
let active = true
|
|
1559
|
+
return () => {
|
|
1560
|
+
if (!active) return
|
|
1561
|
+
active = false
|
|
1562
|
+
if (window[NAV_ICON_STATE_KEY] !== state) return
|
|
1563
|
+
state.refs -= 1
|
|
1564
|
+
if (state.refs > 0) return
|
|
1565
|
+
state.active = false
|
|
1566
|
+
state.observer.disconnect()
|
|
1567
|
+
state.clearMarkers()
|
|
1568
|
+
if (typeof state.style.remove === "function") state.style.remove()
|
|
1569
|
+
else state.style.parentNode?.removeChild(state.style)
|
|
1570
|
+
delete window[NAV_ICON_STATE_KEY]
|
|
1571
|
+
}
|
|
927
1572
|
}
|
|
928
1573
|
|
|
929
1574
|
function installStyle() {
|
|
@@ -936,16 +1581,15 @@ window.__ModuleLoader__.load({
|
|
|
936
1581
|
document.head.appendChild(style)
|
|
937
1582
|
}
|
|
938
1583
|
style.textContent = [
|
|
939
|
-
"
|
|
940
|
-
".dshCodexPage{box-sizing:border-box;display:flex;width:100%;max-width:1120px;min-width:0;flex-direction:column;gap:28px;padding:6px 0 40px;color:var(--dsw-alias-label-primary)}",
|
|
1584
|
+
".dshCodexPage{box-sizing:border-box;display:flex;width:100%;min-width:0;flex-direction:column;gap:12px;padding:4px 0 20px;color:var(--dsw-alias-label-primary);font:inherit}",
|
|
941
1585
|
".dshCodexPage *{box-sizing:border-box}",
|
|
942
1586
|
".dshCodexHero{display:flex;min-width:0;flex-direction:column;gap:8px}",
|
|
943
1587
|
".dshCodexHero h2,.dshCodexHero p{margin:0}",
|
|
944
1588
|
".dshCodexHero h2{font-size:16px;font-weight:500;line-height:24px}",
|
|
945
1589
|
".dshCodexHero p{max-width:760px;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}",
|
|
946
|
-
".dshCodexPanel{display:flex;width:100%;min-width:0;
|
|
1590
|
+
".dshCodexPanel{display:flex;width:100%;min-width:0;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px}",
|
|
947
1591
|
".dshCodexPanel p,.dshCodexPanel label{overflow-wrap:anywhere;word-break:break-word}",
|
|
948
|
-
".dshCodexCard{border:1px solid var(--dsw-alias-border-l2);border-radius:18px;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-3));padding:
|
|
1592
|
+
".dshCodexCard{border:1px solid var(--dsw-alias-border-l2);border-radius:18px;background:var(--dsw-alias-bg-module-platform,var(--dsw-alias-bg-layer-3));padding:18px}",
|
|
949
1593
|
".dshCodexHeader{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}",
|
|
950
1594
|
".dshCodexHeader>div{min-width:0}",
|
|
951
1595
|
".dshCodexHeader h3,.dshCodexHeader p,.dshCodexNotices p,.dshCodexQuota p{margin:0}",
|
|
@@ -957,7 +1601,7 @@ window.__ModuleLoader__.load({
|
|
|
957
1601
|
".dshCodexStatus[data-state=active] .dshCodexStatusDot{background:var(--dsw-alias-state-success-primary)}",
|
|
958
1602
|
".dshCodexStatus[data-state=invalid] .dshCodexStatusDot{background:var(--dsw-alias-state-error-primary)}",
|
|
959
1603
|
".dshCodexStatus[data-state=busy] .dshCodexStatusDot{background:var(--dsw-alias-state-business-primary)}",
|
|
960
|
-
".dshCodexQuota{display:flex;min-width:0;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:
|
|
1604
|
+
".dshCodexQuota{display:flex;min-width:0;flex-direction:column;gap:10px;border-top:1px solid var(--dsw-alias-border-l2);padding-top:16px}",
|
|
961
1605
|
".dshCodexQuotaHeader{display:flex;min-width:0;align-items:center;justify-content:space-between;gap:12px}",
|
|
962
1606
|
".dshCodexQuota h3{margin:0;font-size:16px;font-weight:500;line-height:24px}",
|
|
963
1607
|
".dshCodexQuotaProduct{font-size:14px;font-weight:500;line-height:22px}",
|
|
@@ -966,28 +1610,61 @@ window.__ModuleLoader__.load({
|
|
|
966
1610
|
".dshCodexQuotaUnknown::before{background:var(--dsw-alias-label-tertiary)}",
|
|
967
1611
|
".dshCodexQuotaExhausted::before{background:var(--dsw-alias-state-error-primary)}",
|
|
968
1612
|
".dshCodexQuotaExhausted{color:var(--dsw-alias-state-error-primary)}",
|
|
1613
|
+
".dshCodexQuotaGroup{display:flex;min-width:0;flex-direction:column;gap:8px}",
|
|
1614
|
+
".dshCodexQuotaGroup+.dshCodexQuotaGroup{border-top:1px solid var(--dsw-alias-border-l2);padding-top:14px}",
|
|
1615
|
+
".dshCodexQuotaWindows{display:grid;min-width:0;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}",
|
|
1616
|
+
".dshCodexQuotaWindow{display:flex;min-width:0;flex-direction:column;gap:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);padding:11px 12px}",
|
|
1617
|
+
".dshCodexQuotaWindowHeader,.dshCodexQuotaMeta{display:flex;min-width:0;align-items:center;justify-content:space-between;gap:12px}",
|
|
1618
|
+
".dshCodexQuotaWindowHeader{font-size:14px;line-height:22px}",
|
|
1619
|
+
".dshCodexQuotaWindowHeader strong{font-weight:500;color:var(--dsw-alias-label-secondary)}",
|
|
1620
|
+
".dshCodexQuotaMeta{justify-content:flex-end;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}",
|
|
1621
|
+
".dshCodexQuotaMeta time{cursor:help}",
|
|
1622
|
+
".dshCodexQuotaWindow progress{display:block;width:100%;height:8px;overflow:hidden;border:0;border-radius:999px;appearance:none;-webkit-appearance:none;background:var(--dsw-alias-bg-layer-1)}",
|
|
1623
|
+
".dshCodexQuotaWindow progress::-webkit-progress-bar{border-radius:999px;background:var(--dsw-alias-bg-layer-1)}",
|
|
1624
|
+
".dshCodexQuotaWindow progress::-webkit-progress-value{border-radius:999px;background:var(--dsw-alias-state-business-primary)}",
|
|
1625
|
+
".dshCodexQuotaWindow progress::-moz-progress-bar{border-radius:999px;background:var(--dsw-alias-state-business-primary)}",
|
|
969
1626
|
".dshCodexMuted{color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}",
|
|
1627
|
+
".dshCodexQuota .dshCodexQuotaUpdated{margin-top:2px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}",
|
|
970
1628
|
".dshCodexWarning{max-width:820px;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:22px}",
|
|
971
1629
|
".dshCodexActions{display:flex;min-width:0;flex-wrap:wrap;gap:8px}",
|
|
972
1630
|
".dshCodexAuthActions{margin-left:auto;justify-content:flex-end}",
|
|
973
1631
|
".dshCodexAuthActions .dshCodexButton{height:36px;min-height:36px;border-radius:18px;padding:0 14px;font-size:14px;line-height:22px}",
|
|
974
|
-
".dshCodexQuotaHeader .dshCodexRefreshButton{min-height:
|
|
1632
|
+
".dshCodexQuotaHeader .dshCodexRefreshButton{display:inline-flex;min-height:30px;align-items:center;gap:6px;border:1px solid var(--dsw-alias-border-l2);border-radius:15px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);padding:0 10px;font-size:12px;line-height:18px;white-space:nowrap}",
|
|
1633
|
+
".dshCodexRefreshIcon{width:14px;height:14px;flex:none}",
|
|
1634
|
+
".dshCodexRefreshButton[data-loading=true] .dshCodexRefreshIcon{animation:dshCodexRefreshSpin .8s linear infinite}",
|
|
1635
|
+
"@keyframes dshCodexRefreshSpin{to{transform:rotate(360deg)}}",
|
|
975
1636
|
".dshCodexButton{box-sizing:border-box;max-width:100%;white-space:normal;overflow-wrap:anywhere;word-break:break-word;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;padding:8px 14px;transition:background-color .15s ease,border-color .15s ease}",
|
|
976
1637
|
".dshCodexButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}",
|
|
977
1638
|
".dshCodexButton:focus-visible,.dshCodexModelOption:has(input:focus-visible){outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-border-l3));outline-offset:2px}",
|
|
978
1639
|
".dshCodexButton:disabled{cursor:not-allowed;opacity:.5}",
|
|
1640
|
+
".dshCodexFastToggle{box-sizing:border-box;display:inline-flex;width:28px;height:28px;flex:none;align-items:center;justify-content:center;border:0;border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;padding:0;transition:background-color .15s ease,color .15s ease}",
|
|
1641
|
+
".dshCodexFastToggle:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-label-primary)}",
|
|
1642
|
+
".dshCodexFastToggle[data-fast=true]{background:var(--dsw-alias-state-business-secondary,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-state-business-primary)}",
|
|
1643
|
+
".dshCodexFastToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-border-l3));outline-offset:2px}",
|
|
1644
|
+
".dshCodexFastToggle:disabled{cursor:not-allowed;opacity:.45}",
|
|
1645
|
+
".dshCodexLegacyRepair{box-sizing:border-box;display:inline-flex;min-width:0;height:28px;flex:none;align-items:center;border:1px solid var(--dsw-alias-border-l2);border-radius:14px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));font:inherit;font-size:12px;line-height:18px;cursor:pointer;padding:0 10px;white-space:nowrap}",
|
|
1646
|
+
".dshCodexLegacyRepair:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}",
|
|
1647
|
+
".dshCodexLegacyRepair:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,var(--dsw-alias-border-l3));outline-offset:2px}",
|
|
1648
|
+
".dshCodexLegacyRepair:disabled{cursor:not-allowed;opacity:.55}",
|
|
979
1649
|
".dshCodexPrimary{border-color:var(--dsw-alias-button-primary-fill,var(--dsw-alias-state-business-primary));background:var(--dsw-alias-button-primary-fill,var(--dsw-alias-state-business-primary));color:var(--dsw-alias-label-primary-foreground,#fff)}",
|
|
980
1650
|
".dshCodexPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover,var(--dsw-alias-state-business-primary))}",
|
|
981
|
-
".dshCodexModelList{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
|
|
982
|
-
".
|
|
1651
|
+
".dshCodexModelList{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none}",
|
|
1652
|
+
".dshCodexModelTitleRow{display:flex;min-width:0;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:4px 12px}",
|
|
1653
|
+
".dshCodexModelSummary{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;white-space:nowrap}",
|
|
1654
|
+
".dshCodexModelOption{display:flex;min-width:0;height:100%;align-items:flex-start;gap:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:11px;background:var(--dsw-alias-bg-layer-1);padding:9px 10px;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}",
|
|
983
1655
|
".dshCodexModelOption:hover{background:var(--dsw-alias-interactive-bg-hover,var(--dsw-alias-bg-layer-2))}",
|
|
1656
|
+
".dshCodexModelOption[data-selected=true]{border-color:var(--dsw-alias-state-business-primary)}",
|
|
984
1657
|
".dshCodexModelOption:has(input:disabled){cursor:not-allowed;opacity:.65}",
|
|
985
1658
|
".dshCodexModelOption:has(input:disabled):hover{background:transparent}",
|
|
986
1659
|
".dshCodexModelOption input{width:18px;height:18px;flex:none;margin:2px 0 0;accent-color:var(--dsw-alias-state-business-primary)}",
|
|
987
|
-
".
|
|
1660
|
+
".dshCodexModelCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:5px}",
|
|
1661
|
+
".dshCodexModelHeading{display:flex;min-width:0;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:1px 8px}",
|
|
988
1662
|
".dshCodexModelOption strong{overflow-wrap:anywhere;font-size:14px;font-weight:500;line-height:22px}",
|
|
989
|
-
".
|
|
990
|
-
".
|
|
1663
|
+
".dshCodexModelId{overflow-wrap:anywhere;color:var(--dsw-alias-label-tertiary);font-family:inherit;font-size:12px;line-height:18px}",
|
|
1664
|
+
".dshCodexModelCapabilities{display:flex;min-width:0;flex-wrap:wrap;gap:6px}",
|
|
1665
|
+
".dshCodexModelBadge{display:inline-flex;align-items:center;border-radius:999px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:18px;padding:1px 7px}",
|
|
1666
|
+
".dshCodexModelToggle{align-self:center;border-radius:999px;padding:6px 12px;font-size:12px;line-height:18px}",
|
|
1667
|
+
".dshCodexModelActions{justify-content:flex-end;border-top:1px solid var(--dsw-alias-border-l2);padding-top:16px}",
|
|
991
1668
|
".dshCodexNotices{display:flex;min-width:0;flex-direction:column;gap:10px;margin:0;padding:0;list-style:none}",
|
|
992
1669
|
".dshCodexNotices li,.dshCodexPrompt{box-sizing:border-box;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);padding:14px 16px}",
|
|
993
1670
|
".dshCodexNotices a{display:inline-block;max-width:100%;margin-top:8px;color:var(--dsw-alias-state-business-primary)}",
|
|
@@ -998,9 +1675,10 @@ window.__ModuleLoader__.load({
|
|
|
998
1675
|
".dshCodexPrompt input,.dshCodexPrompt select{box-sizing:border-box;width:100%;min-width:0;height:38px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;padding:0 10px}",
|
|
999
1676
|
".dshCodexError{margin:0;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}",
|
|
1000
1677
|
".dshCodexSuccess{margin:0;color:var(--dsw-alias-state-success-primary);font-size:12px;line-height:18px}",
|
|
1001
|
-
"@media(
|
|
1678
|
+
"@media(prefers-reduced-motion:reduce){.dshCodexRefreshButton[data-loading=true] .dshCodexRefreshIcon{animation:none}}",
|
|
1679
|
+
"@media(max-width:760px){.dshCodexQuotaWindows,.dshCodexModelList{grid-template-columns:1fr}.dshCodexModelActions{justify-content:flex-start}}",
|
|
1002
1680
|
"@media(max-width:640px){.dshCodexAuthToolbar,.dshCodexHeader{align-items:stretch;flex-direction:column}.dshCodexAuthActions{margin-left:0;justify-content:flex-start}}",
|
|
1003
|
-
"@media(max-width:480px){
|
|
1681
|
+
"@media(max-width:480px){.dshCodexPage{gap:10px;padding:0 0 16px}.dshCodexCard{border-radius:14px;padding:16px}.dshCodexActions{align-items:stretch;flex-direction:column}.dshCodexButton{width:100%}.dshCodexQuotaHeader .dshCodexRefreshButton{width:auto}.dshCodexQuotaWindowHeader{gap:8px}}",
|
|
1004
1682
|
].join("")
|
|
1005
1683
|
const references = style[STYLE_REF_KEY]
|
|
1006
1684
|
style[STYLE_REF_KEY] = Number.isSafeInteger(references) && references > 0
|
|
@@ -1024,13 +1702,17 @@ window.__ModuleLoader__.load({
|
|
|
1024
1702
|
exports.AuthorizationSettings = AuthorizationSettings
|
|
1025
1703
|
exports.CHANNEL = CHANNEL
|
|
1026
1704
|
exports.CODEX_PROVIDER = CODEX_PROVIDER
|
|
1705
|
+
exports.CodexFastToggle = CodexFastToggle
|
|
1027
1706
|
exports.CodexSettings = CodexSettings
|
|
1028
1707
|
exports.ModelEnablementSettings = ModelEnablementSettings
|
|
1029
1708
|
exports.NS = NS
|
|
1030
1709
|
exports.apply = apply
|
|
1031
1710
|
exports.createAuthorizationClient = createAuthorizationClient
|
|
1032
1711
|
exports.createModelEnablementClient = createModelEnablementClient
|
|
1712
|
+
exports.createSessionPreferenceClient = createSessionPreferenceClient
|
|
1713
|
+
exports.formatResetDistance = formatResetDistance
|
|
1033
1714
|
exports.inject = inject
|
|
1715
|
+
exports.installSettingsNavIcon = installSettingsNavIcon
|
|
1034
1716
|
exports.safeQuotaSnapshot = safeQuotaSnapshot
|
|
1035
1717
|
return module.exports
|
|
1036
1718
|
},
|