dsh-coding-subscription-oauth 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/CHANGELOG.md +291 -255
  2. package/CONTRIBUTING.md +138 -129
  3. package/INSTALL.md +261 -256
  4. package/LICENSE +19 -19
  5. package/NOTICE +11 -11
  6. package/README.de.md +303 -303
  7. package/README.es.md +304 -304
  8. package/README.fr.md +304 -304
  9. package/README.ja.md +304 -304
  10. package/README.ko.md +304 -304
  11. package/README.md +321 -320
  12. package/README.pt-BR.md +304 -304
  13. package/README.ru.md +304 -304
  14. package/README.zh-CN.md +319 -318
  15. package/compatibility/dsh-bom.json +36 -30
  16. package/cordis.patch.yml +13 -13
  17. package/docs/00-project-rules.md +213 -212
  18. package/docs/02-architecture.md +142 -138
  19. package/docs/02-architecture.zh-CN.md +142 -138
  20. package/lib/auth-routes.d.ts +10 -1
  21. package/lib/auth-routes.d.ts.map +1 -1
  22. package/lib/bin.js +483 -50
  23. package/lib/bin.js.map +4 -4
  24. package/lib/client.js +5 -5
  25. package/lib/client.js.map +4 -4
  26. package/lib/compatibility.d.ts +0 -1
  27. package/lib/compatibility.d.ts.map +1 -1
  28. package/lib/gateway-protocol.d.ts +3 -46
  29. package/lib/gateway-protocol.d.ts.map +1 -1
  30. package/lib/gateway-routes.d.ts.map +1 -1
  31. package/lib/grok-errors.d.ts +2 -12
  32. package/lib/grok-errors.d.ts.map +1 -1
  33. package/lib/grok-imagine/client.d.ts +73 -0
  34. package/lib/grok-imagine/client.d.ts.map +1 -0
  35. package/lib/grok-imagine/index.d.ts +8 -0
  36. package/lib/grok-imagine/index.d.ts.map +1 -0
  37. package/lib/grok-imagine/net.d.ts +10 -0
  38. package/lib/grok-imagine/net.d.ts.map +1 -0
  39. package/lib/grok-imagine/parse.d.ts +20 -0
  40. package/lib/grok-imagine/parse.d.ts.map +1 -0
  41. package/lib/grok-imagine/types.d.ts +191 -0
  42. package/lib/grok-imagine/types.d.ts.map +1 -0
  43. package/lib/grok-imagine.d.ts +3 -263
  44. package/lib/grok-imagine.d.ts.map +1 -1
  45. package/lib/http-json.d.ts +2 -9
  46. package/lib/http-json.d.ts.map +1 -1
  47. package/lib/ids.d.ts +4 -0
  48. package/lib/ids.d.ts.map +1 -1
  49. package/lib/index.d.ts +2 -1
  50. package/lib/index.d.ts.map +1 -1
  51. package/lib/index.js +730 -196
  52. package/lib/index.js.map +4 -4
  53. package/lib/invariant.js.map +1 -1
  54. package/lib/kimi-errors.d.ts +2 -12
  55. package/lib/kimi-errors.d.ts.map +1 -1
  56. package/lib/oauth-session.d.ts +2 -0
  57. package/lib/oauth-session.d.ts.map +1 -1
  58. package/lib/session.d.ts +2 -0
  59. package/lib/session.d.ts.map +1 -1
  60. package/lib/store.d.ts +73 -1
  61. package/lib/store.d.ts.map +1 -1
  62. package/media/en/settings_accounts.png +0 -0
  63. package/media/en/settings_capabilities.png +0 -0
  64. package/media/en/settings_gateway.png +0 -0
  65. package/media/settings_accounts.png +0 -0
  66. package/media/settings_capabilities.png +0 -0
  67. package/media/settings_gateway.png +0 -0
  68. package/media/settings_overview.png +0 -0
  69. package/media/zh-CN/settings_accounts.png +0 -0
  70. package/media/zh-CN/settings_capabilities.png +0 -0
  71. package/media/zh-CN/settings_gateway.png +0 -0
  72. package/package.json +224 -221
  73. package/patches/dsh-agy@0.1.2.patch +25 -25
  74. package/scripts/release.mjs +187 -186
  75. package/scripts/smoke-deployed-routes.mjs +146 -146
  76. package/scripts/verify-deployed-catalog.mjs +87 -87
  77. package/src/adapter.ts +0 -348
  78. package/src/alias-adapter.ts +0 -147
  79. package/src/auth-routes.ts +0 -921
  80. package/src/auth.ts +0 -67
  81. package/src/bin.ts +0 -350
  82. package/src/capability-routes.ts +0 -279
  83. package/src/capability-runtime.ts +0 -314
  84. package/src/capability-settings.ts +0 -671
  85. package/src/capability-tools.ts +0 -685
  86. package/src/catalog.ts +0 -271
  87. package/src/client/GrokBuildSettings.tsx +0 -771
  88. package/src/client/api.ts +0 -88
  89. package/src/client/components/AboutTab.tsx +0 -30
  90. package/src/client/components/AccountsTab.tsx +0 -241
  91. package/src/client/components/Badge.tsx +0 -33
  92. package/src/client/components/CapabilitiesTab.tsx +0 -265
  93. package/src/client/components/CliPullPreview.tsx +0 -116
  94. package/src/client/components/CopyButton.tsx +0 -57
  95. package/src/client/components/GatewayTab.tsx +0 -469
  96. package/src/client/components/NoticeBanner.tsx +0 -46
  97. package/src/client/components/ProgressBar.tsx +0 -53
  98. package/src/client/components/ProviderCard.tsx +0 -606
  99. package/src/client/components/SettingsTabs.tsx +0 -75
  100. package/src/client/components/ToggleSwitch.tsx +0 -71
  101. package/src/client/constants.ts +0 -230
  102. package/src/client/display.ts +0 -61
  103. package/src/client/dshClientAdapter.ts +0 -127
  104. package/src/client/gatewaySnippets.ts +0 -37
  105. package/src/client/index.tsx +0 -156
  106. package/src/client/locales.ts +0 -540
  107. package/src/client/microStyles.ts +0 -52
  108. package/src/client/parsers.ts +0 -398
  109. package/src/client/styles.ts +0 -325
  110. package/src/client/types.ts +0 -199
  111. package/src/codex-http.ts +0 -447
  112. package/src/codex-images.ts +0 -503
  113. package/src/codex-model-capabilities.ts +0 -320
  114. package/src/codex-search.ts +0 -245
  115. package/src/codex-usage.ts +0 -263
  116. package/src/compatibility.ts +0 -55
  117. package/src/dsh-host-adapter.ts +0 -173
  118. package/src/gateway-anthropic-messages.ts +0 -84
  119. package/src/gateway-auth.ts +0 -102
  120. package/src/gateway-backend.ts +0 -274
  121. package/src/gateway-body.ts +0 -49
  122. package/src/gateway-config.ts +0 -76
  123. package/src/gateway-http.ts +0 -104
  124. package/src/gateway-openai-chat.ts +0 -124
  125. package/src/gateway-openai-responses.ts +0 -53
  126. package/src/gateway-parse.ts +0 -224
  127. package/src/gateway-protocol.ts +0 -52
  128. package/src/gateway-routes.ts +0 -158
  129. package/src/gateway.ts +0 -258
  130. package/src/grok-errors.ts +0 -24
  131. package/src/grok-imagine.ts +0 -1627
  132. package/src/grok-import.ts +0 -151
  133. package/src/http-json.ts +0 -82
  134. package/src/ids.ts +0 -59
  135. package/src/imagine-routes.ts +0 -463
  136. package/src/index.ts +0 -735
  137. package/src/invariant.ts +0 -17
  138. package/src/kimi-errors.ts +0 -26
  139. package/src/media-store.ts +0 -927
  140. package/src/oauth-import-routes.ts +0 -324
  141. package/src/oauth-providers.ts +0 -152
  142. package/src/oauth-session.ts +0 -183
  143. package/src/oauth-sources.ts +0 -1104
  144. package/src/oauth.ts +0 -620
  145. package/src/provider.ts +0 -128
  146. package/src/proxy.ts +0 -11
  147. package/src/redact.ts +0 -72
  148. package/src/session.ts +0 -218
  149. package/src/store.ts +0 -217
  150. package/src/web-origin.ts +0 -296
  151. package/src/web-routes.ts +0 -38
@@ -1,53 +0,0 @@
1
- /** Usage quota progress bar with threshold-based color. */
2
-
3
- import { hintStyle } from "../styles.ts";
4
-
5
- export interface ProgressBarProps {
6
- /** 0–100 used percentage. */
7
- value: number;
8
- label?: string;
9
- meta?: string;
10
- }
11
-
12
- function barColor(percent: number): string {
13
- if (percent >= 90) return "var(--dsw-alias-state-error-primary, #d92d20)";
14
- if (percent >= 75) return "var(--dsw-alias-state-warn-primary, #e06c00)";
15
- // Prefer info fill over brand-primary: dark theme inverts brand-primary to near-white.
16
- return "var(--dsw-alias-button-info-fill, var(--dsw-static-deepseek-500, #4f6ef7))";
17
- }
18
-
19
- export function ProgressBar({ value, label, meta }: ProgressBarProps) {
20
- const clamped = Math.max(0, Math.min(100, value));
21
- return (
22
- <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
23
- {label === undefined ? null : (
24
- <div style={{ display: "flex", justifyContent: "space-between", gap: 8, flexWrap: "wrap" }}>
25
- <span style={{ ...hintStyle, color: "var(--dsw-alias-label-primary)" }}>{label}</span>
26
- {meta === undefined ? null : <span style={hintStyle}>{meta}</span>}
27
- </div>
28
- )}
29
- <div
30
- role="progressbar"
31
- aria-valuenow={clamped}
32
- aria-valuemin={0}
33
- aria-valuemax={100}
34
- style={{
35
- height: 8,
36
- borderRadius: 4,
37
- background: "var(--dsw-alias-border-l2)",
38
- overflow: "hidden",
39
- }}
40
- >
41
- <div
42
- style={{
43
- width: `${String(clamped)}%`,
44
- height: "100%",
45
- borderRadius: 4,
46
- background: barColor(clamped),
47
- transition: "width 0.3s ease, background 0.3s ease",
48
- }}
49
- />
50
- </div>
51
- </div>
52
- );
53
- }
@@ -1,606 +0,0 @@
1
- /** Single provider account card for the Accounts tab. */
2
-
3
- import { useEffect, useMemo, useRef, useState } from "react";
4
- import { SOURCE_REASON_KEY } from "../constants.ts";
5
- import { methodLabel, orderedLoginMethods, shouldShowPerCardSourceReason } from "../display.ts";
6
- import { formatEpoch, modelFields, usageHasVisibleFields } from "../parsers.ts";
7
- import {
8
- bodyStyle,
9
- buttonStyle,
10
- cardStyle,
11
- checkRowStyle,
12
- codeStyle,
13
- compactButtonStyle,
14
- hintStyle,
15
- inputStyle,
16
- listStyle,
17
- monoStyle,
18
- nestedStyle,
19
- primaryButtonStyle,
20
- rowStyle,
21
- stepActiveStyle,
22
- stepNumberActiveStyle,
23
- stepNumberStyle,
24
- stepRowStyle,
25
- titleStyle,
26
- visuallyHiddenStyle,
27
- } from "../styles.ts";
28
- import type {
29
- GrokBuildSettingsInjected,
30
- GrokStatus,
31
- LoginMethod,
32
- ProviderCardDefinition,
33
- ProviderStatus,
34
- SourceStatus,
35
- UsageView,
36
- } from "../types.ts";
37
- import { Badge } from "./Badge.tsx";
38
- import { CopyButton } from "./CopyButton.tsx";
39
- import { ProgressBar } from "./ProgressBar.tsx";
40
-
41
- export interface ProviderCardProps {
42
- t: GrokBuildSettingsInjected["t"];
43
- definition: ProviderCardDefinition;
44
- providerStatus: ProviderStatus;
45
- busy: boolean;
46
- sourcesBusy: boolean;
47
- remote: boolean;
48
- codeInput: string;
49
- popupBlocked: boolean;
50
- expanded: boolean;
51
- source: SourceStatus | undefined;
52
- showUsage: boolean;
53
- usage: UsageView | undefined;
54
- usageError: string | undefined;
55
- usageLoading: boolean;
56
- onSignIn: (method: LoginMethod) => void;
57
- onSignOut: () => void;
58
- onCancelLogin: () => void;
59
- onSubmitCode: () => void;
60
- onCodeChange: (value: string) => void;
61
- onToggleExpanded: () => void;
62
- onPreviewSource: () => void;
63
- onSaveModels: (selected: string[]) => void;
64
- }
65
-
66
- function SignInSteps({
67
- t,
68
- activeMethod,
69
- userCode,
70
- url,
71
- popupBlocked,
72
- }: {
73
- t: GrokBuildSettingsInjected["t"];
74
- activeMethod: LoginMethod;
75
- userCode: string | undefined;
76
- url: string | undefined;
77
- popupBlocked: boolean;
78
- }) {
79
- const hasCode = userCode !== undefined && userCode.length > 0;
80
- const hasUrl = url !== undefined && url.length > 0;
81
- const needsPaste = activeMethod !== "device";
82
-
83
- return (
84
- <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
85
- <div style={hasUrl ? stepActiveStyle : stepRowStyle}>
86
- <span style={hasUrl ? stepNumberActiveStyle : stepNumberStyle} aria-hidden="true">
87
- 1
88
- </span>
89
- <span>{t("signInStepOpen")}</span>
90
- </div>
91
- {hasUrl ? (
92
- <div style={{ display: "flex", flexWrap: "wrap", gap: 8, paddingLeft: 32 }}>
93
- <a href={url} target="_blank" rel="noreferrer" style={primaryButtonStyle}>
94
- {t("openAuthUrl")}
95
- </a>
96
- <CopyButton text={url} idleLabel={t("copy")} copiedLabel={t("copied")} failedLabel={t("copyFailed")} />
97
- </div>
98
- ) : null}
99
- {popupBlocked && hasUrl ? <p style={hintStyle}>{t("popupBlocked")}</p> : null}
100
- {hasCode ? (
101
- <>
102
- <div style={stepActiveStyle}>
103
- <span style={stepNumberActiveStyle} aria-hidden="true">
104
- 2
105
- </span>
106
- <span>{t("signInStepCode")}</span>
107
- </div>
108
- <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 8, paddingLeft: 32 }}>
109
- <span style={codeStyle}>{userCode}</span>
110
- <CopyButton
111
- text={userCode}
112
- idleLabel={t("copyUserCode")}
113
- copiedLabel={t("copied")}
114
- failedLabel={t("copyFailed")}
115
- primary
116
- />
117
- </div>
118
- </>
119
- ) : null}
120
- <div style={stepActiveStyle}>
121
- <span style={stepNumberActiveStyle} aria-hidden="true">
122
- {hasCode ? 3 : 2}
123
- </span>
124
- <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
125
- <span
126
- aria-hidden="true"
127
- style={{
128
- width: 14,
129
- height: 14,
130
- border: "2px solid var(--dsw-alias-brand-primary, #1677ff)",
131
- borderTopColor: "transparent",
132
- borderRadius: "50%",
133
- animation: "dsh-coding-oauth-spin 0.8s linear infinite",
134
- }}
135
- />
136
- {t("signInStepWait")}
137
- </span>
138
- </div>
139
- {needsPaste ? (
140
- <div style={{ display: "flex", flexDirection: "column", gap: 8, paddingLeft: 32 }}>
141
- <p style={bodyStyle}>{t(activeMethod === "browser" ? "pasteBrowserCodeHint" : "pasteCodeHint")}</p>
142
- </div>
143
- ) : null}
144
- </div>
145
- );
146
- }
147
-
148
- export function ProviderCard({
149
- t,
150
- definition,
151
- providerStatus,
152
- busy,
153
- sourcesBusy,
154
- remote,
155
- codeInput,
156
- popupBlocked,
157
- expanded,
158
- source,
159
- showUsage,
160
- usage,
161
- usageError,
162
- usageLoading,
163
- onSignIn,
164
- onSignOut,
165
- onCancelLogin,
166
- onSubmitCode,
167
- onCodeChange,
168
- onToggleExpanded,
169
- onPreviewSource,
170
- onSaveModels,
171
- }: ProviderCardProps) {
172
- const [showAltMethods, setShowAltMethods] = useState(false);
173
- const [modelFilter, setModelFilter] = useState("");
174
- const [logoutConfirm, setLogoutConfirm] = useState(false);
175
- const logoutTrigger = useRef<HTMLButtonElement>(null);
176
- const logoutConfirmAction = useRef<HTMLButtonElement>(null);
177
- const restoreLogoutFocus = useRef(false);
178
-
179
- const ordered = orderedLoginMethods(definition, remote);
180
- const primaryMethod: LoginMethod = ordered[0] ?? definition.recommended;
181
- const altMethods = ordered.filter((method) => method !== primaryMethod);
182
-
183
- const statusLabel =
184
- providerStatus.status === "signed-in"
185
- ? t("signedIn")
186
- : providerStatus.status === "signing-in"
187
- ? t("signingIn")
188
- : providerStatus.status === "error"
189
- ? t("requestFailed")
190
- : t("signedOut");
191
- const activeMethod = providerStatus.status === "signing-in" ? providerStatus.method : primaryMethod;
192
- const { available, selected } = useMemo(() => modelFields(providerStatus), [providerStatus]);
193
- const [modelDraft, setModelDraft] = useState<string[]>(selected);
194
- useEffect(() => {
195
- setModelDraft(selected);
196
- }, [selected]);
197
- useEffect(() => {
198
- if (providerStatus.status !== "signed-in") setLogoutConfirm(false);
199
- }, [providerStatus.status]);
200
- useEffect(() => {
201
- if (logoutConfirm) {
202
- logoutConfirmAction.current?.focus();
203
- return;
204
- }
205
- if (!restoreLogoutFocus.current) return;
206
- restoreLogoutFocus.current = false;
207
- if (providerStatus.status === "signed-in") {
208
- logoutTrigger.current?.focus();
209
- return;
210
- }
211
- document.getElementById(`coding-oauth-login-${definition.slug}`)?.focus();
212
- }, [definition.slug, logoutConfirm, providerStatus.status]);
213
- const modelDraftDirty =
214
- modelDraft.length !== selected.length || modelDraft.some((model, index) => model !== selected[index]);
215
- const grokProviderStatus = definition.slug === "grok" ? (providerStatus as GrokStatus) : undefined;
216
- const showSourceReason = shouldShowPerCardSourceReason(source);
217
-
218
- const filteredModels = useMemo(() => {
219
- const query = modelFilter.trim().toLowerCase();
220
- if (query.length === 0) return available;
221
- return available.filter((id) => id.toLowerCase().includes(query));
222
- }, [available, modelFilter]);
223
-
224
- const usagePercent =
225
- definition.slug === "codex" && showUsage
226
- ? usage?.individualRemainingPercent === undefined
227
- ? usage?.rateLimits[0]?.windows[0]?.usedPercent
228
- : 100 - usage.individualRemainingPercent
229
- : undefined;
230
- const fetchedAt = formatEpoch(usage?.fetchedAt);
231
-
232
- return (
233
- <div style={cardStyle}>
234
- <div style={rowStyle}>
235
- <div>
236
- <h3 style={{ ...titleStyle, fontSize: 16 }}>{t(definition.titleKey)}</h3>
237
- {providerStatus.status === "signed-in" && !expanded ? (
238
- <p style={{ ...hintStyle, marginTop: 4 }}>
239
- {t("modelsSummary", { selected: selected.length, total: available.length })}
240
- {usagePercent === undefined ? "" : ` · ${t("usageUsedShort", { value: `${String(usagePercent)}%` })}`}
241
- </p>
242
- ) : (
243
- <>
244
- <p style={{ ...bodyStyle, marginTop: 4 }}>{t(definition.descriptionKey)}</p>
245
- <p style={{ ...bodyStyle, marginTop: 4 }}>
246
- <span style={monoStyle}>{definition.route}</span>
247
- </p>
248
- </>
249
- )}
250
- </div>
251
- <Badge label={statusLabel} providerStatus={providerStatus.status} />
252
- </div>
253
- <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
254
- {providerStatus.status === "signed-in" ? (
255
- <>
256
- {logoutConfirm ? (
257
- <fieldset style={{ ...nestedStyle, margin: 0, minWidth: 0 }}>
258
- <legend style={visuallyHiddenStyle}>{t("logoutConfirmTitle")}</legend>
259
- <p style={bodyStyle}>{t("logoutConfirmHint")}</p>
260
- <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
261
- <button
262
- ref={logoutConfirmAction}
263
- type="button"
264
- style={primaryButtonStyle}
265
- disabled={busy}
266
- onClick={() => {
267
- restoreLogoutFocus.current = true;
268
- onSignOut();
269
- }}
270
- >
271
- {busy ? t("working") : t("logoutConfirmAction")}
272
- </button>
273
- <button
274
- type="button"
275
- style={buttonStyle}
276
- disabled={busy}
277
- onClick={() => {
278
- restoreLogoutFocus.current = true;
279
- setLogoutConfirm(false);
280
- }}
281
- >
282
- {t("cancel")}
283
- </button>
284
- </div>
285
- </fieldset>
286
- ) : (
287
- <button
288
- ref={logoutTrigger}
289
- type="button"
290
- style={buttonStyle}
291
- disabled={busy}
292
- onClick={() => setLogoutConfirm(true)}
293
- >
294
- {t("logout")}
295
- </button>
296
- )}
297
- <button
298
- id={`coding-oauth-models-toggle-${definition.slug}`}
299
- type="button"
300
- style={buttonStyle}
301
- aria-expanded={expanded}
302
- aria-controls={expanded ? `coding-oauth-models-${definition.slug}` : undefined}
303
- onClick={onToggleExpanded}
304
- >
305
- {expanded ? t("collapseModels") : t("expandModels")}
306
- </button>
307
- {source?.available === true ? (
308
- <button
309
- id={`coding-oauth-source-pull-${definition.slug}`}
310
- type="button"
311
- style={buttonStyle}
312
- disabled={sourcesBusy}
313
- onClick={onPreviewSource}
314
- >
315
- {t("sourcesPullCopy")}
316
- </button>
317
- ) : null}
318
- </>
319
- ) : providerStatus.status === "signing-in" ? (
320
- <>
321
- <button type="button" style={buttonStyle} disabled={busy} onClick={onCancelLogin}>
322
- {t("cancelLogin")}
323
- </button>
324
- {altMethods.length > 0 ? (
325
- <button
326
- type="button"
327
- style={compactButtonStyle}
328
- disabled={busy}
329
- onClick={() => {
330
- setShowAltMethods((current) => !current);
331
- }}
332
- >
333
- {showAltMethods ? t("hideOtherLoginMethods") : t("otherLoginMethods")}
334
- </button>
335
- ) : null}
336
- {showAltMethods
337
- ? altMethods.map((method) => (
338
- <button
339
- key={method}
340
- type="button"
341
- style={compactButtonStyle}
342
- disabled={busy}
343
- onClick={() => {
344
- onSignIn(method);
345
- }}
346
- >
347
- {methodLabel(method, t, { remote, primary: false })}
348
- </button>
349
- ))
350
- : null}
351
- </>
352
- ) : (
353
- <>
354
- <button
355
- id={`coding-oauth-login-${definition.slug}`}
356
- type="button"
357
- style={primaryButtonStyle}
358
- disabled={busy}
359
- onClick={() => {
360
- onSignIn(primaryMethod);
361
- }}
362
- >
363
- {busy ? t("working") : methodLabel(primaryMethod, t, { remote, primary: true })}
364
- </button>
365
- {altMethods.length > 0 ? (
366
- <button
367
- type="button"
368
- style={compactButtonStyle}
369
- disabled={busy}
370
- onClick={() => {
371
- setShowAltMethods((current) => !current);
372
- }}
373
- >
374
- {showAltMethods ? t("hideOtherLoginMethods") : t("otherLoginMethods")}
375
- </button>
376
- ) : null}
377
- {showAltMethods
378
- ? altMethods.map((method) => (
379
- <button
380
- key={method}
381
- type="button"
382
- style={compactButtonStyle}
383
- disabled={busy}
384
- onClick={() => {
385
- onSignIn(method);
386
- }}
387
- >
388
- {methodLabel(method, t, { remote, primary: false })}
389
- </button>
390
- ))
391
- : null}
392
- {source?.available === true ? (
393
- <button
394
- id={`coding-oauth-source-pull-${definition.slug}`}
395
- type="button"
396
- style={buttonStyle}
397
- disabled={sourcesBusy}
398
- onClick={onPreviewSource}
399
- >
400
- {t("sourcesPullCopy")}
401
- </button>
402
- ) : showSourceReason && source?.reason !== undefined ? (
403
- <span style={hintStyle}>{t(SOURCE_REASON_KEY[source.reason])}</span>
404
- ) : null}
405
- </>
406
- )}
407
- </div>
408
- {providerStatus.status === "error" ? (
409
- <p style={{ ...bodyStyle, color: "var(--dsw-alias-state-error-primary)" }}>{providerStatus.message}</p>
410
- ) : null}
411
- {providerStatus.status === "signing-in" ? (
412
- <SignInSteps
413
- t={t}
414
- activeMethod={activeMethod}
415
- userCode={providerStatus.userCode}
416
- url={providerStatus.url}
417
- popupBlocked={popupBlocked}
418
- />
419
- ) : null}
420
- {providerStatus.status === "signing-in" && activeMethod !== "device" ? (
421
- <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
422
- <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
423
- <label htmlFor={`coding-oauth-code-${definition.slug}`} style={visuallyHiddenStyle}>
424
- {t("pasteCodeLabel")}
425
- </label>
426
- <input
427
- id={`coding-oauth-code-${definition.slug}`}
428
- style={{ ...inputStyle, flex: "1 1 360px" }}
429
- value={codeInput}
430
- placeholder={t("pasteCodePlaceholder")}
431
- disabled={busy}
432
- onChange={(event) => {
433
- onCodeChange(event.target.value);
434
- }}
435
- onKeyDown={(event) => {
436
- if (event.key === "Enter") {
437
- event.preventDefault();
438
- onSubmitCode();
439
- }
440
- }}
441
- />
442
- <button
443
- type="button"
444
- style={primaryButtonStyle}
445
- disabled={busy || codeInput.trim().length === 0}
446
- onClick={onSubmitCode}
447
- >
448
- {t("submitCode")}
449
- </button>
450
- </div>
451
- </div>
452
- ) : null}
453
- {providerStatus.status === "signed-in" && expanded ? (
454
- <div id={`coding-oauth-models-${definition.slug}`} style={{ display: "flex", flexDirection: "column", gap: 8 }}>
455
- <div style={rowStyle}>
456
- <h4 style={{ ...titleStyle, fontSize: 14 }}>{t("models")}</h4>
457
- <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
458
- <button
459
- type="button"
460
- style={compactButtonStyle}
461
- disabled={busy}
462
- onClick={() => {
463
- setModelDraft([]);
464
- }}
465
- >
466
- {t("deselectAll")}
467
- </button>
468
- <button
469
- type="button"
470
- style={compactButtonStyle}
471
- disabled={busy}
472
- onClick={() => {
473
- setModelDraft([...available]);
474
- }}
475
- >
476
- {t("selectAll")}
477
- </button>
478
- <button
479
- type="button"
480
- style={compactButtonStyle}
481
- disabled={busy}
482
- onClick={() => {
483
- setModelDraft(available.length > 0 ? [available[0]!] : []);
484
- }}
485
- >
486
- {t("resetModelsDefault")}
487
- </button>
488
- </div>
489
- </div>
490
- <label htmlFor={`coding-oauth-model-filter-${definition.slug}`} style={visuallyHiddenStyle}>
491
- {t("modelFilterLabel", { provider: t(definition.titleKey) })}
492
- </label>
493
- <input
494
- id={`coding-oauth-model-filter-${definition.slug}`}
495
- type="search"
496
- style={inputStyle}
497
- value={modelFilter}
498
- placeholder={t("modelFilterPlaceholder")}
499
- disabled={busy}
500
- onChange={(event) => {
501
- setModelFilter(event.target.value);
502
- }}
503
- />
504
- {grokProviderStatus?.status === "signed-in" ? (
505
- <p style={bodyStyle}>
506
- {grokProviderStatus.catalogSource === "live"
507
- ? t("catalogLive")
508
- : grokProviderStatus.catalogSource === "cache"
509
- ? t("catalogCache")
510
- : t("catalogFallback")}
511
- </p>
512
- ) : null}
513
- <p style={bodyStyle}>
514
- {t("modelHint")} <span style={monoStyle}>{definition.route}/&lt;id&gt;</span>
515
- </p>
516
- <ul style={listStyle}>
517
- {filteredModels.map((id) => {
518
- const checked = modelDraft.includes(id);
519
- return (
520
- <li key={id}>
521
- <label style={checkRowStyle}>
522
- <input
523
- type="checkbox"
524
- checked={checked}
525
- disabled={busy}
526
- onChange={() => {
527
- const current = new Set(modelDraft);
528
- if (checked) current.delete(id);
529
- else current.add(id);
530
- setModelDraft([...available].filter((model) => current.has(model)));
531
- }}
532
- />
533
- <span style={monoStyle}>{id}</span>
534
- </label>
535
- </li>
536
- );
537
- })}
538
- </ul>
539
- <div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: 8 }}>
540
- <button
541
- type="button"
542
- style={primaryButtonStyle}
543
- disabled={busy || !modelDraftDirty}
544
- onClick={() => onSaveModels(modelDraft)}
545
- >
546
- {busy ? t("working") : t("applyModelDraft")}
547
- </button>
548
- {modelDraftDirty ? <span style={hintStyle}>{t("modelDraftPending")}</span> : null}
549
- </div>
550
- {filteredModels.length === 0 ? <p style={hintStyle}>{t("modelFilterPlaceholder")}</p> : null}
551
- {grokProviderStatus?.status === "signed-in" && grokProviderStatus.catalogError !== undefined ? (
552
- <p style={{ ...bodyStyle, color: "var(--dsw-alias-state-error-primary)" }}>{t("catalogError")}</p>
553
- ) : null}
554
- {definition.slug === "codex" && showUsage ? (
555
- <div style={nestedStyle}>
556
- <p style={{ ...bodyStyle, color: "var(--dsw-alias-label-primary)" }}>{t("usageTitle")}</p>
557
- {usageError === undefined ? null : (
558
- <p style={{ ...bodyStyle, color: "var(--dsw-alias-state-error-primary)" }} role="alert">
559
- {usageError}
560
- </p>
561
- )}
562
- {usageLoading && usage === undefined ? (
563
- <p style={hintStyle}>{t("usageLoading")}</p>
564
- ) : usage === undefined || !usageHasVisibleFields(usage) ? (
565
- <p style={hintStyle}>{t("usageEmpty")}</p>
566
- ) : (
567
- <>
568
- {fetchedAt === undefined ? null : <p style={hintStyle}>{t("usageFetchedAt", { time: fetchedAt })}</p>}
569
- {usagePercent !== undefined ? (
570
- <ProgressBar
571
- value={usagePercent}
572
- label={t("usageRateLimit")}
573
- meta={t("usageUsed", { value: `${String(usagePercent)}%` })}
574
- />
575
- ) : null}
576
- {usage.rateLimits.map((limit) => {
577
- const window = limit.windows[0];
578
- const used = window?.usedPercent;
579
- const resetsAt = formatEpoch(window?.resetsAt);
580
- return (
581
- <div key={limit.id} style={{ display: "flex", flexDirection: "column", gap: 4 }}>
582
- {used === undefined ? (
583
- <p style={hintStyle}>{limit.name ?? t("usageRateLimit")}</p>
584
- ) : (
585
- <ProgressBar
586
- value={used}
587
- label={limit.name ?? t("usageRateLimit")}
588
- meta={
589
- resetsAt === undefined
590
- ? t("usageUsed", { value: `${String(used)}%` })
591
- : `${t("usageUsed", { value: `${String(used)}%` })} · ${t("usageResets", { time: resetsAt })}`
592
- }
593
- />
594
- )}
595
- </div>
596
- );
597
- })}
598
- </>
599
- )}
600
- </div>
601
- ) : null}
602
- </div>
603
- ) : null}
604
- </div>
605
- );
606
- }