dsh-subscriptions 0.1.5 → 0.2.2

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 (110) hide show
  1. package/README.md +212 -154
  2. package/lib/auth/claude-code-creds.js +31 -9
  3. package/lib/auth/device-flow.js +16 -9
  4. package/lib/auth/oauth-flow.js +13 -10
  5. package/lib/auth/rpc.d.ts +73 -2
  6. package/lib/auth/rpc.js +124 -23
  7. package/lib/auth/store.js +80 -31
  8. package/lib/client/CursorCard.d.ts +1 -1
  9. package/lib/client/CursorCard.js +50 -16
  10. package/lib/client/ExternalUsageCards.d.ts +1 -1
  11. package/lib/client/ExternalUsageCards.js +37 -16
  12. package/lib/client/ImageGallery.d.ts +2 -2
  13. package/lib/client/ImageGallery.js +92 -33
  14. package/lib/client/ImageGenerateToolview.js +50 -14
  15. package/lib/client/OllamaCard.d.ts +13 -0
  16. package/lib/client/OllamaCard.js +94 -0
  17. package/lib/client/OllamaSettingsManager.d.ts +24 -0
  18. package/lib/client/OllamaSettingsManager.js +329 -0
  19. package/lib/client/ProviderAccountManager.d.ts +1 -1
  20. package/lib/client/ProviderAccountManager.js +164 -49
  21. package/lib/client/ProviderModelEditor.js +109 -26
  22. package/lib/client/SpeedSelect.d.ts +62 -14
  23. package/lib/client/SpeedSelect.js +257 -46
  24. package/lib/client/SubscriptionUsageBadge.d.ts +5 -11
  25. package/lib/client/SubscriptionUsageBadge.js +301 -112
  26. package/lib/client/SubscriptionsSection.d.ts +2 -0
  27. package/lib/client/SubscriptionsSection.js +259 -85
  28. package/lib/client/UsageBadgeDisplaySetting.js +35 -12
  29. package/lib/client/UsageMeter.d.ts +1 -1
  30. package/lib/client/UsageMeter.js +69 -27
  31. package/lib/client/VideoGenerateToolview.js +69 -17
  32. package/lib/client/account-preferences.d.ts +8 -0
  33. package/lib/client/account-preferences.js +20 -5
  34. package/lib/client/host-contract.d.ts +11 -2
  35. package/lib/client/host-contract.js +20 -3
  36. package/lib/client/index.d.ts +5 -5
  37. package/lib/client/index.js +34 -12
  38. package/lib/client/locales.d.ts +78 -0
  39. package/lib/client/locales.js +121 -34
  40. package/lib/client/ollama-draft.d.ts +229 -0
  41. package/lib/client/ollama-draft.js +255 -0
  42. package/lib/client/reset-action.js +6 -4
  43. package/lib/client/reset-credits-view.d.ts +1 -1
  44. package/lib/client/reset-credits-view.js +66 -17
  45. package/lib/client/subscription-card-styles.js +94 -24
  46. package/lib/client/usage-color-preferences.js +4 -2
  47. package/lib/client/usage-pace.d.ts +7 -0
  48. package/lib/client/usage-pace.js +43 -10
  49. package/lib/client.js +1647 -266
  50. package/lib/client.js.map +1 -1
  51. package/lib/http.js +1 -1
  52. package/lib/index.d.ts +28 -3
  53. package/lib/index.js +9329 -8217
  54. package/lib/model-defaults.js +4 -2
  55. package/lib/provider-settings.d.ts +14 -1
  56. package/lib/provider-settings.js +64 -20
  57. package/lib/providers/account-preferences.js +51 -22
  58. package/lib/providers/accounts.js +15 -9
  59. package/lib/providers/antigravity-oauth-client.js +2 -2
  60. package/lib/providers/antigravity.js +141 -68
  61. package/lib/providers/catalog-store.js +120 -41
  62. package/lib/providers/claude-cli-version.js +3 -3
  63. package/lib/providers/claude.d.ts +23 -3
  64. package/lib/providers/claude.js +167 -92
  65. package/lib/providers/codex-client-version.js +3 -3
  66. package/lib/providers/codex-search.js +40 -13
  67. package/lib/providers/codex.js +196 -112
  68. package/lib/providers/common.d.ts +14 -0
  69. package/lib/providers/common.js +118 -38
  70. package/lib/providers/copilot.js +143 -82
  71. package/lib/providers/cursor-adapter.js +42 -18
  72. package/lib/providers/cursor-auth.d.ts +1 -1
  73. package/lib/providers/cursor-auth.js +69 -24
  74. package/lib/providers/cursor-model-settings.js +14 -5
  75. package/lib/providers/cursor-usage.js +27 -13
  76. package/lib/providers/external-usage-controller.d.ts +9 -2
  77. package/lib/providers/external-usage-controller.js +30 -7
  78. package/lib/providers/external-usage.d.ts +8 -0
  79. package/lib/providers/external-usage.js +140 -20
  80. package/lib/providers/grok.js +152 -89
  81. package/lib/providers/image-pool.js +29 -11
  82. package/lib/providers/minimax-usage.js +31 -11
  83. package/lib/providers/npm-cli-version.js +10 -3
  84. package/lib/providers/ollama-settings.d.ts +90 -0
  85. package/lib/providers/ollama-settings.js +213 -0
  86. package/lib/providers/ollama-web.d.ts +46 -0
  87. package/lib/providers/ollama-web.js +231 -0
  88. package/lib/providers/ollama.d.ts +107 -0
  89. package/lib/providers/ollama.js +608 -0
  90. package/lib/providers/pool-family.js +11 -3
  91. package/lib/providers/pool-health.js +28 -8
  92. package/lib/providers/pool-usage.js +16 -9
  93. package/lib/providers/pool.d.ts +8 -0
  94. package/lib/providers/pool.js +81 -42
  95. package/lib/providers/rate-limit.js +8 -2
  96. package/lib/providers/replay.js +40 -17
  97. package/lib/providers/reset-redemption.js +18 -6
  98. package/lib/tools/image-generate.js +123 -65
  99. package/lib/tools/registration.js +5 -2
  100. package/lib/tools/video-generate.js +51 -31
  101. package/lib/tools/x-search.js +50 -22
  102. package/lib/translate/anthropic.js +85 -37
  103. package/lib/translate/antigravity-schema.js +71 -28
  104. package/lib/translate/antigravity-thinking.js +22 -9
  105. package/lib/translate/antigravity.js +141 -50
  106. package/lib/translate/chat-completions.js +67 -23
  107. package/lib/translate/resolved.js +55 -21
  108. package/lib/translate/responses.js +69 -29
  109. package/lib/translate/sse.js +4 -1
  110. package/package.json +26 -4
@@ -0,0 +1,24 @@
1
+ import type { ConnectionHandle } from '@deepseek-ai/dsh-api-remotes/client';
2
+ import type { SubscriptionsSectionInjected } from './SubscriptionsSection.js';
3
+ type Translate = SubscriptionsSectionInjected['t'];
4
+ interface Props {
5
+ rpc: ConnectionHandle['rpc'];
6
+ t: Translate;
7
+ onClose: () => void;
8
+ /** Called after a successful save or reset, so the card re-reads its status. */
9
+ onSaved: () => void;
10
+ }
11
+ /**
12
+ * Ollama Cloud settings dialog. It owns one draft (model list, web toggle,
13
+ * base URL and credential reference) that Save writes in a single
14
+ * `ollamaSetSettings` call, so a failure keeps every edit. Fetching the cloud
15
+ * catalog is a read-only side trip, and a key typed for the fetch never
16
+ * leaves this component. The model list follows the shared model editor: a
17
+ * filter, select all/none over the filtered rows, and one checkbox per
18
+ * model, where ticking edits the draft and enables Save. Ollama adds what the
19
+ * shared editor lacks: a display name, ordering, and a local context window.
20
+ * Unticking keeps the row's full settings in a dialog-local stash, so ticking
21
+ * it again restores them even when the cloud listing no longer returns it.
22
+ */
23
+ export declare function OllamaSettingsManager({ rpc, t, onClose, onSaved }: Props): import("react").JSX.Element;
24
+ export {};
@@ -0,0 +1,329 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useId, useRef, useState } from 'react';
3
+ import { callSubscriptionsAuth } from './subscriptions-rpc.js';
4
+ import { contextLabel, effortOptions, moveModel, parseContextInput, renameModel, setModelContext, setModelEffort, tickModel, tickModels, untickModel, untickModels, } from './ollama-draft.js';
5
+ import { subscriptionCardStyles as styles } from './subscription-card-styles.js';
6
+ import { providerSettingsCss } from './provider-settings-styles.js';
7
+ const border = '0.5px solid var(--dsw-alias-border-l2)';
8
+ const stack = { display: 'grid', gap: 12, minWidth: 0 };
9
+ const actions = {
10
+ display: 'flex',
11
+ flexWrap: 'wrap',
12
+ gap: 8,
13
+ alignItems: 'center',
14
+ };
15
+ function message(error) {
16
+ return error instanceof Error ? error.message : String(error);
17
+ }
18
+ /** `vision · thinking · context 262K`, dropping whatever the model does not advertise. */
19
+ function capabilities(t, model) {
20
+ const context = contextLabel(model.contextWindow);
21
+ return [
22
+ model.vision === true ? t('ollamaCapVision') : false,
23
+ model.thinking === true ? t('ollamaCapThinking') : false,
24
+ context === undefined ? false : t('ollamaContext', { tokens: context }),
25
+ ]
26
+ .filter(Boolean)
27
+ .join(' · ');
28
+ }
29
+ /**
30
+ * Ollama Cloud settings dialog. It owns one draft (model list, web toggle,
31
+ * base URL and credential reference) that Save writes in a single
32
+ * `ollamaSetSettings` call, so a failure keeps every edit. Fetching the cloud
33
+ * catalog is a read-only side trip, and a key typed for the fetch never
34
+ * leaves this component. The model list follows the shared model editor: a
35
+ * filter, select all/none over the filtered rows, and one checkbox per
36
+ * model, where ticking edits the draft and enables Save. Ollama adds what the
37
+ * shared editor lacks: a display name, ordering, and a local context window.
38
+ * Unticking keeps the row's full settings in a dialog-local stash, so ticking
39
+ * it again restores them even when the cloud listing no longer returns it.
40
+ */
41
+ export function OllamaSettingsManager({ rpc, t, onClose, onSaved }) {
42
+ const dialog = useRef(null);
43
+ const title = useId();
44
+ const description = useId();
45
+ const [view, setView] = useState();
46
+ const [draft, setDraft] = useState({});
47
+ const [dirty, setDirty] = useState(false);
48
+ const [loading, setLoading] = useState(true);
49
+ const [saving, setSaving] = useState(false);
50
+ const [error, setError] = useState('');
51
+ const [saveError, setSaveError] = useState('');
52
+ const [attempt, setAttempt] = useState(0);
53
+ const [apiKey, setApiKey] = useState('');
54
+ const [candidates, setCandidates] = useState();
55
+ const [fetching, setFetching] = useState(false);
56
+ const [fetchError, setFetchError] = useState('');
57
+ const [query, setQuery] = useState('');
58
+ const [expanded, setExpanded] = useState(new Set());
59
+ const [stash, setStash] = useState(new Map());
60
+ const [contextText, setContextText] = useState({});
61
+ const alive = useRef(true);
62
+ const saveLock = useRef(false);
63
+ const fetchLock = useRef(false);
64
+ useEffect(() => {
65
+ alive.current = true;
66
+ const element = dialog.current;
67
+ const previous = document.activeElement;
68
+ element.showModal();
69
+ return () => {
70
+ alive.current = false;
71
+ element.close();
72
+ if (previous instanceof HTMLElement && previous.isConnected)
73
+ previous.focus();
74
+ };
75
+ }, []);
76
+ useEffect(() => {
77
+ let current = true;
78
+ setLoading(true);
79
+ setError('');
80
+ void callSubscriptionsAuth(rpc, 'ollamaSettings', {})
81
+ .then((data) => {
82
+ if (!current)
83
+ return;
84
+ setView(data);
85
+ // An unset store value inherits the deployed config: the checkbox
86
+ // shows the effective state, and ticking it writes the override.
87
+ setDraft({ ...data.settings });
88
+ setStash(new Map());
89
+ setContextText({});
90
+ setDirty(false);
91
+ })
92
+ .catch((failure) => {
93
+ if (current)
94
+ setError(t('ollamaModelsLoadFailed', { message: message(failure) }));
95
+ })
96
+ .finally(() => {
97
+ if (current)
98
+ setLoading(false);
99
+ });
100
+ return () => {
101
+ current = false;
102
+ };
103
+ // `t` only formats the load error. A new translator must not refetch.
104
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- refetch on rpc and attempt only
105
+ }, [rpc, attempt]);
106
+ function edit(next) {
107
+ setDraft(next);
108
+ setDirty(true);
109
+ }
110
+ /** Fetch the cloud catalog; a failure keeps the previous list and the draft. */
111
+ async function fetchCandidates() {
112
+ if (fetchLock.current)
113
+ return;
114
+ fetchLock.current = true;
115
+ setFetching(true);
116
+ setFetchError('');
117
+ try {
118
+ const value = await callSubscriptionsAuth(rpc, 'ollamaModels', {
119
+ ...(apiKey ? { apiKey } : {}),
120
+ ...(draft.baseURL ? { baseURL: draft.baseURL } : {}),
121
+ });
122
+ if (!alive.current)
123
+ return;
124
+ setCandidates(value.models);
125
+ }
126
+ catch (failure) {
127
+ if (alive.current)
128
+ setFetchError(t('ollamaFetchFailed', { message: message(failure) }));
129
+ }
130
+ finally {
131
+ fetchLock.current = false;
132
+ if (alive.current)
133
+ setFetching(false);
134
+ }
135
+ }
136
+ /** Save the whole draft; a failure keeps the dialog open with every edit. */
137
+ async function save() {
138
+ if (saveLock.current)
139
+ return;
140
+ saveLock.current = true;
141
+ setSaving(true);
142
+ setSaveError('');
143
+ try {
144
+ await callSubscriptionsAuth(rpc, 'ollamaSetSettings', { settings: draft });
145
+ if (alive.current) {
146
+ onSaved();
147
+ onClose();
148
+ }
149
+ }
150
+ catch (failure) {
151
+ if (alive.current)
152
+ setSaveError(t('ollamaModelsSaveFailed', { message: message(failure) }));
153
+ }
154
+ finally {
155
+ saveLock.current = false;
156
+ if (alive.current)
157
+ setSaving(false);
158
+ }
159
+ }
160
+ /** Drop every stored override, then reload the draft from the deployment values. */
161
+ async function resetDefaults() {
162
+ if (saveLock.current)
163
+ return;
164
+ if (!window.confirm(t('ollamaResetConfirm')))
165
+ return;
166
+ saveLock.current = true;
167
+ setSaving(true);
168
+ setSaveError('');
169
+ try {
170
+ await callSubscriptionsAuth(rpc, 'ollamaSetSettings', { settings: {} });
171
+ if (alive.current) {
172
+ setAttempt((value) => value + 1);
173
+ onSaved();
174
+ }
175
+ }
176
+ catch (failure) {
177
+ if (alive.current)
178
+ setSaveError(t('ollamaModelsSaveFailed', { message: message(failure) }));
179
+ }
180
+ finally {
181
+ saveLock.current = false;
182
+ if (alive.current)
183
+ setSaving(false);
184
+ }
185
+ }
186
+ function editOverride(field, value) {
187
+ const next = { ...draft };
188
+ if (value.trim())
189
+ next[field] = value;
190
+ else
191
+ delete next[field];
192
+ edit(next);
193
+ }
194
+ /**
195
+ * One list for both sources, like the shared editor: the ticked models in
196
+ * draft order first (so Move up/down is visible), then the unticked ones
197
+ * (stashed in this dialog, or fetched and not yet adopted). A kept model
198
+ * the fetch did not return stays listed, ticked or not.
199
+ */
200
+ const fetchedById = new Map((candidates ?? []).map((candidate) => [candidate.id, candidate]));
201
+ const present = new Set((draft.models ?? []).map((model) => model.id));
202
+ const asRow = (model, ticked) => {
203
+ const fetched = fetchedById.get(model.id);
204
+ // The latest fetch outranks the stored snapshot, matching the runtime:
205
+ // discovery is the ceiling and the snapshot only stands in without it.
206
+ const contextWindow = fetched?.contextWindow ?? model.contextWindow;
207
+ return {
208
+ id: model.id,
209
+ name: model.name ?? fetched?.name ?? model.id,
210
+ ticked,
211
+ vision: model.vision === true || fetched?.vision === true,
212
+ thinking: model.thinking === true || fetched?.thinking === true,
213
+ ...(contextWindow === undefined ? {} : { contextWindow }),
214
+ efforts: model.efforts ?? fetched?.efforts ?? [],
215
+ };
216
+ };
217
+ const rows = [
218
+ ...(draft.models ?? []).map((model) => asRow(model, true)),
219
+ ...[...stash.values()]
220
+ .filter((model) => !present.has(model.id))
221
+ .map((model) => asRow(model, false)),
222
+ ...(candidates ?? [])
223
+ .filter((candidate) => !present.has(candidate.id) && !stash.has(candidate.id))
224
+ .map((candidate) => asRow({ id: candidate.id }, false)),
225
+ ];
226
+ const shown = rows.filter((row) => `${row.name} ${row.id}`.toLowerCase().includes(query.trim().toLowerCase()));
227
+ /** Rename and default-effort edits ride the tested draft helpers. */
228
+ function rename(id, name) {
229
+ edit({ ...draft, models: renameModel(draft.models ?? [], id, name) });
230
+ }
231
+ function setEffort(id, effort) {
232
+ edit({ ...draft, models: setModelEffort(draft.models ?? [], id, effort) });
233
+ }
234
+ /** Keep the typed text; only a valid number (or blank) reaches the draft. */
235
+ function setContext(id, text) {
236
+ setContextText((current) => ({ ...current, [id]: text }));
237
+ const tokens = parseContextInput(text);
238
+ if (tokens !== null)
239
+ edit({
240
+ ...draft,
241
+ models: setModelContext(draft.models ?? [], id, tokens),
242
+ });
243
+ }
244
+ function applyTicks(next) {
245
+ setStash(next.stash);
246
+ edit({ ...draft, models: next.models });
247
+ }
248
+ const invalidContext = Object.entries(contextText)
249
+ .filter(([id, text]) => present.has(id) && parseContextInput(text) === null)
250
+ .map(([id]) => id);
251
+ return (_jsxs("dialog", { className: "dsh-subscription-manager", ref: dialog, "aria-labelledby": title, "aria-describedby": description, onCancel: (event) => {
252
+ if (saveLock.current)
253
+ event.preventDefault();
254
+ }, onClose: onClose, style: {
255
+ width: 620,
256
+ maxWidth: 'calc(100vw - 32px)',
257
+ maxHeight: 'calc(100dvh - 32px)',
258
+ overflow: 'auto',
259
+ }, children: [_jsx("style", { children: providerSettingsCss }), _jsxs("div", { style: { ...stack, padding: 20 }, children: [_jsxs("header", { style: { ...actions, justifyContent: 'space-between' }, children: [_jsx("h2", { id: title, style: { margin: 0 }, children: t('ollamaManageTitle') }), _jsx("button", { type: "button", autoFocus: true, disabled: saving, onClick: onClose, children: t('imageClose') })] }), _jsx("p", { id: description, className: "dsh-subscription-hint", children: t('ollamaManageHint') }), view?.configOverridesModels === true && (_jsx("p", { className: "dsh-subscription-hint", children: t('ollamaCatalogOverride') })), error && _jsx("p", { role: "alert", children: error }), loading && (_jsx("p", { role: "status", className: "dsh-subscription-hint", children: t('modelDefaultsLoading') })), !loading && !view && (_jsx("button", { type: "button", onClick: () => setAttempt((value) => value + 1), children: t('modelDefaultsRetry') })), view && (_jsxs("fieldset", { disabled: saving, style: { ...stack, border: 0, margin: 0, padding: 0, minWidth: 0 }, children: [_jsxs("div", { style: {
260
+ borderTop: border,
261
+ paddingTop: 12,
262
+ display: 'grid',
263
+ gap: 12,
264
+ }, children: [_jsx("h3", { style: { margin: 0 }, children: t('modelsEdit') }), _jsxs("div", { style: actions, children: [_jsx("input", { type: "password", autoComplete: "off", style: { flex: '1 1 180px' }, "aria-label": t('ollamaKeyPlaceholder'), placeholder: t('ollamaKeyPlaceholder'), value: apiKey, onChange: (event) => setApiKey(event.target.value) }), _jsx("button", { type: "button", className: "dsh-subscription-quiet", disabled: fetching, onClick: () => {
265
+ void fetchCandidates();
266
+ }, children: fetching ? t('ollamaFetching') : t('ollamaFetch') }), candidates !== undefined && (_jsx("span", { className: "dsh-subscription-hint", children: t('ollamaCandidatesCount', { count: candidates.length }) }))] }), _jsx("p", { className: "dsh-subscription-hint", children: t('ollamaKeyHint') }), fetchError && _jsx("p", { role: "alert", children: fetchError }), candidates?.length === 0 && (_jsx("p", { className: "dsh-subscription-hint", children: t('ollamaCandidatesEmpty') })), _jsxs("div", { style: actions, children: [_jsx("input", { style: { flex: '1 1 180px' }, value: query, onChange: (event) => setQuery(event.target.value), placeholder: t('modelDefaultsFilterPlaceholder'), "aria-label": t('modelDefaultsFilterPlaceholder') }), _jsx("button", { type: "button", onClick: () => applyTicks(tickModels(draft.models ?? [], stash, candidates ?? [], shown.map((row) => row.id))), children: t('modelsSelectAll') }), _jsx("button", { type: "button", onClick: () => applyTicks(untickModels(draft.models ?? [], stash, shown.map((row) => row.id))), children: t('modelsSelectNone') })] }), _jsxs("div", { style: {
267
+ maxHeight: 360,
268
+ overflowY: 'auto',
269
+ display: 'grid',
270
+ gap: 8,
271
+ }, children: [shown.map((row) => {
272
+ const stored = (draft.models ?? []).find((entry) => entry.id === row.id);
273
+ const index = (draft.models ?? []).findIndex((entry) => entry.id === row.id);
274
+ const open = expanded.has(row.id);
275
+ const details = `${row.id}-details`;
276
+ const efforts = stored === undefined
277
+ ? []
278
+ : effortOptions(stored, fetchedById.get(row.id)?.efforts, view.models.find((entry) => entry.id === row.id)
279
+ ?.efforts);
280
+ const contextProblem = invalidContext.includes(row.id);
281
+ return (_jsxs("div", { style: {
282
+ borderBottom: border,
283
+ padding: '8px 2px',
284
+ display: 'grid',
285
+ gap: 8,
286
+ }, children: [_jsxs("label", { style: { overflowWrap: 'anywhere' }, children: [_jsx("input", { type: "checkbox", checked: row.ticked, onChange: (event) => {
287
+ applyTicks(event.target.checked
288
+ ? tickModel(draft.models ?? [], stash, candidates ?? [], row.id)
289
+ : untickModel(draft.models ?? [], stash, row.id));
290
+ } }), ' ', row.name, ' ', _jsx("span", { style: styles.status, children: capabilities(t, row) })] }), stored !== undefined && (_jsxs("div", { style: actions, children: [row.thinking && efforts.length > 0 && (_jsxs("label", { style: actions, children: [t('modelDefaultsTitle'), _jsxs("select", { "aria-label": `${row.name} ${t('modelDefaultsTitle')}`, value: stored.defaultEffort ?? '', onChange: (event) => setEffort(row.id, event.target.value), children: [_jsx("option", { value: "", children: t('modelDefaultsFollowProvider') }), efforts.map((effort) => (_jsx("option", { value: effort.id, disabled: effort.unavailable === true, children: effort.unavailable === true
291
+ ? `${effort.name} (${t('modelsUnavailable')})`
292
+ : effort.name }, effort.id)))] })] })), row.thinking && efforts.length === 0 && (_jsx("small", { children: t('ollamaEffortsUnknown') })), _jsxs("label", { style: actions, children: [t('modelsContext'), _jsx("input", { style: { width: 140 }, inputMode: "numeric", "aria-invalid": contextProblem, value: contextText[row.id] ??
293
+ (stored.contextOverride === undefined
294
+ ? ''
295
+ : String(stored.contextOverride)), "aria-label": `${row.name} ${t('modelsContext')}`, placeholder: row.contextWindow === undefined
296
+ ? ''
297
+ : String(row.contextWindow), onChange: (event) => setContext(row.id, event.target.value) })] }), row.contextWindow !== undefined && (_jsx("small", { children: t('modelsContextBounds', {
298
+ default: row.contextWindow,
299
+ max: row.contextWindow,
300
+ }) })), _jsxs("button", { type: "button", className: "dsh-subscription-quiet", "aria-expanded": open, "aria-controls": details, "aria-label": `${row.name} ${t('ollamaRowDetails')}`, onClick: () => {
301
+ const next = new Set(expanded);
302
+ if (open)
303
+ next.delete(row.id);
304
+ else
305
+ next.add(row.id);
306
+ setExpanded(next);
307
+ }, children: [t('ollamaRowDetails'), " ", open ? '\u25BE' : '\u25B8'] })] })), contextProblem && (_jsx("p", { role: "alert", children: t('modelsContextInvalid', { model: row.name }) })), stored !== undefined && open && (_jsxs("div", { id: details, style: actions, children: [_jsxs("label", { style: actions, children: [t('ollamaDisplayName'), _jsx("input", { value: stored.name ?? '', placeholder: row.id, "aria-label": `${row.name} ${t('ollamaDisplayName')}`, onChange: (event) => rename(row.id, event.target.value), onBlur: (event) => rename(row.id, event.target.value.trim()) })] }), _jsx("button", { type: "button", disabled: index === 0, "aria-label": `${row.name} ${t('ollamaMoveUp')}`, onClick: () => edit({
308
+ ...draft,
309
+ models: moveModel(draft.models ?? [], row.id, -1),
310
+ }), children: t('ollamaMoveUp') }), _jsx("button", { type: "button", disabled: index === (draft.models ?? []).length - 1, "aria-label": `${row.name} ${t('ollamaMoveDown')}`, onClick: () => edit({
311
+ ...draft,
312
+ models: moveModel(draft.models ?? [], row.id, 1),
313
+ }), children: t('ollamaMoveDown') })] }))] }, row.id));
314
+ }), shown.length === 0 && (_jsx("span", { className: "dsh-subscription-hint", children: query.trim()
315
+ ? t('modelDefaultsFilterEmpty', { query })
316
+ : t('ollamaModelsEmpty') }))] }), _jsx("small", { children: t('modelsContextHint') })] }), _jsxs("label", { style: { ...stack, gap: 6 }, children: [_jsx("span", { className: "dsh-subscription-label", children: t('ollamaBaseURL') }), _jsx("input", { value: draft.baseURL ?? '', placeholder: view.effective.baseURL, onChange: (event) => editOverride('baseURL', event.target.value) })] }), _jsxs("label", { style: { ...stack, gap: 6 }, children: [_jsx("span", { className: "dsh-subscription-label", children: t('ollamaApiKeyRef') }), _jsx("input", { value: draft.apiKeyRef ?? '', placeholder: view.effective.apiKeyRef, onChange: (event) => editOverride('apiKeyRef', event.target.value) })] }), _jsx("p", { className: "dsh-subscription-hint", children: t('ollamaConnectionHint') }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: (draft.web ?? view.effective.web) === true, onChange: (event) => edit({ ...draft, web: event.target.checked }) }), ' ', t('modelsWebSearch')] }), _jsx("p", { className: "dsh-subscription-hint", children: t('ollamaWebHint') })] })), _jsxs("footer", { style: {
317
+ ...stack,
318
+ gap: 8,
319
+ borderTop: border,
320
+ padding: '14px 0 8px',
321
+ position: 'sticky',
322
+ bottom: 0,
323
+ background: 'var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1))',
324
+ }, children: [saveError && _jsx("p", { role: "alert", children: saveError }), _jsxs("div", { style: { ...actions, justifyContent: 'flex-end' }, children: [_jsx("button", { type: "button", style: { marginRight: 'auto' }, disabled: loading || saving, onClick: () => {
325
+ void resetDefaults();
326
+ }, children: t('ollamaResetDefaults') }), _jsx("button", { type: "button", disabled: saving, onClick: onClose, children: t('cancel') }), _jsx("button", { type: "button", className: "dsh-subscription-primary", disabled: loading || saving || !dirty || invalidContext.length > 0, onClick: () => {
327
+ void save();
328
+ }, children: saving ? t('modelDefaultsSaving') : t('modelsSave') })] })] })] })] }));
329
+ }
@@ -9,5 +9,5 @@ interface Props {
9
9
  onClose: () => void;
10
10
  }
11
11
  /** Native top-layer dialog provides keyboard containment, Escape and focus restoration. */
12
- export declare function ProviderAccountManager({ provider, name, rpc, t, onClose }: Props): import("react").JSX.Element;
12
+ export declare function ProviderAccountManager({ provider, name, rpc, t, onClose, }: Props): import("react").JSX.Element;
13
13
  export {};