@eddyskywalker/dsh-chatgpt-subscription 0.10.15 → 0.10.20

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 (62) hide show
  1. package/CHANGELOG.md +36 -1
  2. package/README.md +8 -4
  3. package/lib/client.js +641 -121
  4. package/lib/client.js.map +1 -1
  5. package/lib/index.js +2029 -299
  6. package/lib/types/client/ProviderHubSection.d.ts.map +1 -1
  7. package/lib/types/client/command-code/CommandCodeSection.d.ts.map +1 -1
  8. package/lib/types/client/index.d.ts +1 -0
  9. package/lib/types/client/index.d.ts.map +1 -1
  10. package/lib/types/client/locales.d.ts +4 -4
  11. package/lib/types/client/ollama/OllamaSection.d.ts +25 -0
  12. package/lib/types/client/ollama/OllamaSection.d.ts.map +1 -0
  13. package/lib/types/client/ollama/api.d.ts +36 -0
  14. package/lib/types/client/ollama/api.d.ts.map +1 -0
  15. package/lib/types/client/ollama/locales.d.ts +413 -0
  16. package/lib/types/client/ollama/locales.d.ts.map +1 -0
  17. package/lib/types/host/antigravity/adapter.d.ts.map +1 -1
  18. package/lib/types/host/claude/adapter.d.ts +3 -5
  19. package/lib/types/host/claude/adapter.d.ts.map +1 -1
  20. package/lib/types/host/claude/model-catalog.d.ts +30 -16
  21. package/lib/types/host/claude/model-catalog.d.ts.map +1 -1
  22. package/lib/types/host/command-code/adapter.d.ts.map +1 -1
  23. package/lib/types/host/command-code/mapper.d.ts.map +1 -1
  24. package/lib/types/host/command-code/model-catalog.d.ts +19 -2
  25. package/lib/types/host/command-code/model-catalog.d.ts.map +1 -1
  26. package/lib/types/host/command-code/types.d.ts +29 -1
  27. package/lib/types/host/command-code/types.d.ts.map +1 -1
  28. package/lib/types/host/common/output-reservation.d.ts +11 -0
  29. package/lib/types/host/common/output-reservation.d.ts.map +1 -0
  30. package/lib/types/host/kimi-code/adapter.d.ts.map +1 -1
  31. package/lib/types/host/kimi-code/model-catalog.d.ts +1 -1
  32. package/lib/types/host/kimi-code/model-catalog.d.ts.map +1 -1
  33. package/lib/types/host/minimax-code/adapter.d.ts +2 -3
  34. package/lib/types/host/minimax-code/adapter.d.ts.map +1 -1
  35. package/lib/types/host/model-catalog.d.ts.map +1 -1
  36. package/lib/types/host/ollama/account-pool.d.ts +65 -0
  37. package/lib/types/host/ollama/account-pool.d.ts.map +1 -0
  38. package/lib/types/host/ollama/adapter.d.ts +47 -0
  39. package/lib/types/host/ollama/adapter.d.ts.map +1 -0
  40. package/lib/types/host/ollama/client.d.ts +101 -0
  41. package/lib/types/host/ollama/client.d.ts.map +1 -0
  42. package/lib/types/host/ollama/mapper.d.ts +44 -0
  43. package/lib/types/host/ollama/mapper.d.ts.map +1 -0
  44. package/lib/types/host/ollama/routes.d.ts +22 -0
  45. package/lib/types/host/ollama/routes.d.ts.map +1 -0
  46. package/lib/types/host/ollama/token-store.d.ts +73 -0
  47. package/lib/types/host/ollama/token-store.d.ts.map +1 -0
  48. package/lib/types/host/ollama/types.d.ts +115 -0
  49. package/lib/types/host/ollama/types.d.ts.map +1 -0
  50. package/lib/types/host/responses-mapper.d.ts +0 -2
  51. package/lib/types/host/responses-mapper.d.ts.map +1 -1
  52. package/lib/types/host/search-provider-switcher.d.ts +12 -0
  53. package/lib/types/host/search-provider-switcher.d.ts.map +1 -1
  54. package/lib/types/host/workbuddy/adapter.d.ts.map +1 -1
  55. package/lib/types/index.d.ts.map +1 -1
  56. package/lib/types/shared/command-code-contracts.d.ts +10 -4
  57. package/lib/types/shared/command-code-contracts.d.ts.map +1 -1
  58. package/lib/types/shared/model-catalog.d.ts +58 -1
  59. package/lib/types/shared/model-catalog.d.ts.map +1 -1
  60. package/lib/types/shared/ollama-contracts.d.ts +36 -0
  61. package/lib/types/shared/ollama-contracts.d.ts.map +1 -0
  62. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -255,7 +255,9 @@ window.__ModuleLoader__.load({
255
255
  defaultReasoningEffort: "medium",
256
256
  reasoningProfile: "gpt-5.6",
257
257
  supportsReasoningSummary: true,
258
- fallbackModelId: "gpt-5.6-terra"
258
+ fallbackModelId: "gpt-5.6-terra",
259
+ supportsOutputVerbosity: true,
260
+ defaultOutputVerbosity: "low"
259
261
  },
260
262
  {
261
263
  id: "gpt-6-astra",
@@ -265,7 +267,9 @@ window.__ModuleLoader__.load({
265
267
  defaultReasoningEffort: "medium",
266
268
  reasoningProfile: "gpt-6",
267
269
  supportsReasoningSummary: true,
268
- maxTokens: GPT_6_MAX_TOKENS
270
+ maxTokens: GPT_6_MAX_TOKENS,
271
+ supportsOutputVerbosity: true,
272
+ defaultOutputVerbosity: "low"
269
273
  },
270
274
  {
271
275
  id: "gpt-6.1-sol",
@@ -275,7 +279,9 @@ window.__ModuleLoader__.load({
275
279
  defaultReasoningEffort: "medium",
276
280
  reasoningProfile: "gpt-6",
277
281
  supportsReasoningSummary: true,
278
- maxTokens: GPT_6_MAX_TOKENS
282
+ maxTokens: GPT_6_MAX_TOKENS,
283
+ supportsOutputVerbosity: true,
284
+ defaultOutputVerbosity: "low"
279
285
  },
280
286
  {
281
287
  id: "gpt-6-sol",
@@ -285,7 +291,9 @@ window.__ModuleLoader__.load({
285
291
  defaultReasoningEffort: "medium",
286
292
  reasoningProfile: "gpt-6",
287
293
  supportsReasoningSummary: true,
288
- maxTokens: GPT_6_MAX_TOKENS
294
+ maxTokens: GPT_6_MAX_TOKENS,
295
+ supportsOutputVerbosity: true,
296
+ defaultOutputVerbosity: "low"
289
297
  },
290
298
  {
291
299
  id: "gpt-6-luna",
@@ -295,7 +303,9 @@ window.__ModuleLoader__.load({
295
303
  defaultReasoningEffort: "medium",
296
304
  reasoningProfile: "gpt-6",
297
305
  supportsReasoningSummary: true,
298
- maxTokens: GPT_6_MAX_TOKENS
306
+ maxTokens: GPT_6_MAX_TOKENS,
307
+ supportsOutputVerbosity: true,
308
+ defaultOutputVerbosity: "low"
299
309
  },
300
310
  {
301
311
  id: "gpt-5.6-terra",
@@ -305,7 +315,9 @@ window.__ModuleLoader__.load({
305
315
  defaultReasoningEffort: "medium",
306
316
  reasoningProfile: "gpt-5.6",
307
317
  supportsReasoningSummary: true,
308
- fallbackModelId: "gpt-5.5"
318
+ fallbackModelId: "gpt-5.5",
319
+ supportsOutputVerbosity: true,
320
+ defaultOutputVerbosity: "low"
309
321
  },
310
322
  {
311
323
  id: "gpt-5.6-luna",
@@ -315,7 +327,9 @@ window.__ModuleLoader__.load({
315
327
  defaultReasoningEffort: "medium",
316
328
  reasoningProfile: "gpt-5.6",
317
329
  supportsReasoningSummary: true,
318
- fallbackModelId: "gpt-5.5"
330
+ fallbackModelId: "gpt-5.5",
331
+ supportsOutputVerbosity: true,
332
+ defaultOutputVerbosity: "low"
319
333
  },
320
334
  {
321
335
  id: "gpt-5.5",
@@ -324,7 +338,9 @@ window.__ModuleLoader__.load({
324
338
  inputModalities: ["text", "image"],
325
339
  defaultReasoningEffort: "medium",
326
340
  reasoningProfile: "standard",
327
- supportsReasoningSummary: true
341
+ supportsReasoningSummary: true,
342
+ supportsOutputVerbosity: true,
343
+ defaultOutputVerbosity: "low"
328
344
  },
329
345
  {
330
346
  id: "gpt-5.4",
@@ -380,17 +396,17 @@ window.__ModuleLoader__.load({
380
396
  //#region src/client/api.ts
381
397
  var SubscriptionApi = class {
382
398
  status() {
383
- return request$1(`${ROUTE_PREFIX}/status`);
399
+ return request$2(`${ROUTE_PREFIX}/status`);
384
400
  }
385
401
  startLogin() {
386
- return post$1(`${ROUTE_PREFIX}/login/start`, {});
402
+ return post$2(`${ROUTE_PREFIX}/login/start`, {});
387
403
  }
388
404
  cancelLogin(loginId) {
389
- return post$1(`${ROUTE_PREFIX}/login/cancel`, { loginId });
405
+ return post$2(`${ROUTE_PREFIX}/login/cancel`, { loginId });
390
406
  }
391
407
  /** Sign out one pooled account; without an id, the active one. */
392
408
  logout(accountId) {
393
- return post$1(`${ROUTE_PREFIX}/logout`, accountId === void 0 ? {} : { accountId });
409
+ return post$2(`${ROUTE_PREFIX}/logout`, accountId === void 0 ? {} : { accountId });
394
410
  }
395
411
  /**
396
412
  * One account-pool action, returning the refreshed status.
@@ -399,38 +415,38 @@ window.__ModuleLoader__.load({
399
415
  * never has to guess what the pool looks like after a change.
400
416
  */
401
417
  accountAction(action, body = {}) {
402
- return post$1(`${ROUTE_PREFIX}/accounts`, {
418
+ return post$2(`${ROUTE_PREFIX}/accounts`, {
403
419
  action,
404
420
  ...body
405
421
  });
406
422
  }
407
423
  refresh() {
408
- return post$1(`${ROUTE_PREFIX}/token/refresh`, {});
424
+ return post$2(`${ROUTE_PREFIX}/token/refresh`, {});
409
425
  }
410
426
  refreshQuota() {
411
- return post$1(`${ROUTE_PREFIX}/quota/refresh`, {});
427
+ return post$2(`${ROUTE_PREFIX}/quota/refresh`, {});
412
428
  }
413
429
  useResetCredit() {
414
- return post$1(`${ROUTE_PREFIX}/quota/reset-credit/use`, {});
430
+ return post$2(`${ROUTE_PREFIX}/quota/reset-credit/use`, {});
415
431
  }
416
432
  testConnection() {
417
- return post$1(`${ROUTE_PREFIX}/connection/test`, {});
433
+ return post$2(`${ROUTE_PREFIX}/connection/test`, {});
418
434
  }
419
435
  updatePreferences(patch) {
420
- return post$1(`${ROUTE_PREFIX}/preferences/update`, patch);
436
+ return post$2(`${ROUTE_PREFIX}/preferences/update`, patch);
421
437
  }
422
438
  events(loginId) {
423
439
  return new EventSource(`${ROUTE_PREFIX}/login/events?loginId=${encodeURIComponent(loginId)}`);
424
440
  }
425
441
  };
426
- async function post$1(url, body) {
427
- return request$1(url, {
442
+ async function post$2(url, body) {
443
+ return request$2(url, {
428
444
  method: "POST",
429
445
  headers: { "content-type": "application/json" },
430
446
  body: JSON.stringify(body)
431
447
  });
432
448
  }
433
- async function request$1(url, init) {
449
+ async function request$2(url, init) {
434
450
  const response = await fetch(url, {
435
451
  ...init,
436
452
  credentials: "same-origin"
@@ -1778,7 +1794,7 @@ window.__ModuleLoader__.load({
1778
1794
  //#endregion
1779
1795
  //#region src/client/antigravity/locales.ts
1780
1796
  const NS_ANTIGRAVITY = "dsh-antigravity";
1781
- const zh$6 = {
1797
+ const zh$7 = {
1782
1798
  ...accountPoolZh,
1783
1799
  title: "Antigravity",
1784
1800
  pageDesc: "登录 Google Antigravity / Cloud Code Assist,并查看当前账号的共享额度。",
@@ -1848,7 +1864,7 @@ window.__ModuleLoader__.load({
1848
1864
  loginFailed: "登录失败",
1849
1865
  tokens: "tokens"
1850
1866
  };
1851
- const en$6 = {
1867
+ const en$7 = {
1852
1868
  ...accountPoolEn,
1853
1869
  title: "Antigravity",
1854
1870
  pageDesc: "Sign in to Google Antigravity / Cloud Code Assist and view shared quotas.",
@@ -1918,17 +1934,17 @@ window.__ModuleLoader__.load({
1918
1934
  loginFailed: "Login failed",
1919
1935
  tokens: "tokens"
1920
1936
  };
1921
- const dictionaries$6 = {
1922
- zh: zh$6,
1923
- "zh-CN": zh$6,
1924
- en: en$6,
1925
- "en-US": en$6
1937
+ const dictionaries$7 = {
1938
+ zh: zh$7,
1939
+ "zh-CN": zh$7,
1940
+ en: en$7,
1941
+ "en-US": en$7
1926
1942
  };
1927
1943
  //#endregion
1928
1944
  //#region src/client/antigravity/AntigravitySection.tsx
1929
- const API$9 = "/antigravity/api";
1945
+ const API$11 = "/antigravity/api";
1930
1946
  async function fetchApi$9(path, options) {
1931
- const res = await fetch(`${API$9}${path}`, {
1947
+ const res = await fetch(`${API$11}${path}`, {
1932
1948
  ...options,
1933
1949
  headers: {
1934
1950
  "Content-Type": "application/json",
@@ -1994,7 +2010,7 @@ window.__ModuleLoader__.load({
1994
2010
  const [savingModel, setSavingModel] = (0, react.useState)(null);
1995
2011
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
1996
2012
  const quotaFollowUp = (0, react.useRef)(null);
1997
- const t = zh$6;
2013
+ const t = zh$7;
1998
2014
  const notifyChange = (0, react.useCallback)(() => {
1999
2015
  onModelChange?.();
2000
2016
  loadModelDirectory?.();
@@ -2601,6 +2617,7 @@ window.__ModuleLoader__.load({
2601
2617
  //#region src/shared/command-code-contracts.ts
2602
2618
  /** Every level, in escalating order; the settings card renders exactly these. */
2603
2619
  const COMMAND_CODE_REASONING_EFFORTS = [
2620
+ "none",
2604
2621
  "minimal",
2605
2622
  "low",
2606
2623
  "medium",
@@ -2611,7 +2628,7 @@ window.__ModuleLoader__.load({
2611
2628
  //#endregion
2612
2629
  //#region src/client/command-code/locales.ts
2613
2630
  const NS_COMMAND_CODE = "dsh-command-code";
2614
- const zh$5 = {
2631
+ const zh$6 = {
2615
2632
  ...accountPoolZh,
2616
2633
  title: "Command Code",
2617
2634
  pageDesc: "登录 Command Code,管理可用模型、上下文窗口与额度。",
@@ -2683,7 +2700,7 @@ window.__ModuleLoader__.load({
2683
2700
  loginFailed: "登录失败",
2684
2701
  tokens: "tokens"
2685
2702
  };
2686
- const en$5 = {
2703
+ const en$6 = {
2687
2704
  ...accountPoolEn,
2688
2705
  title: "Command Code",
2689
2706
  pageDesc: "Sign in to Command Code and manage models, context windows, and quota.",
@@ -2755,11 +2772,11 @@ window.__ModuleLoader__.load({
2755
2772
  loginFailed: "Sign-in failed",
2756
2773
  tokens: "tokens"
2757
2774
  };
2758
- const dictionaries$5 = {
2759
- zh: zh$5,
2760
- "zh-CN": zh$5,
2761
- en: en$5,
2762
- "en-US": en$5
2775
+ const dictionaries$6 = {
2776
+ zh: zh$6,
2777
+ "zh-CN": zh$6,
2778
+ en: en$6,
2779
+ "en-US": en$6
2763
2780
  };
2764
2781
  //#endregion
2765
2782
  //#region src/client/command-code/CommandCodeSection.tsx
@@ -2768,6 +2785,7 @@ window.__ModuleLoader__.load({
2768
2785
  * string values, so this nested table lives with the control that renders it.
2769
2786
  */
2770
2787
  const EFFORT_LABELS$2 = {
2788
+ none: "Off",
2771
2789
  minimal: "Minimal",
2772
2790
  low: "Low",
2773
2791
  medium: "Medium",
@@ -2775,9 +2793,9 @@ window.__ModuleLoader__.load({
2775
2793
  xhigh: "X-High",
2776
2794
  max: "Max"
2777
2795
  };
2778
- const API$8 = "/command-code/api";
2796
+ const API$10 = "/command-code/api";
2779
2797
  async function fetchApi$8(path, options) {
2780
- const res = await fetch(`${API$8}${path}`, {
2798
+ const res = await fetch(`${API$10}${path}`, {
2781
2799
  ...options,
2782
2800
  headers: {
2783
2801
  "Content-Type": "application/json",
@@ -2833,7 +2851,7 @@ window.__ModuleLoader__.load({
2833
2851
  const [apiKey, setApiKey] = (0, react.useState)("");
2834
2852
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
2835
2853
  const quotaFollowUp = (0, react.useRef)(null);
2836
- const t = zh$5;
2854
+ const t = zh$6;
2837
2855
  const notifyChange = (0, react.useCallback)(() => {
2838
2856
  onModelChange?.();
2839
2857
  loadModelDirectory?.();
@@ -3541,7 +3559,7 @@ window.__ModuleLoader__.load({
3541
3559
  * provider — the same reason every sibling line has one.
3542
3560
  */
3543
3561
  const NS_CLAUDE = "dsh-claude";
3544
- const zh$4 = {
3562
+ const zh$5 = {
3545
3563
  ...accountPoolZh,
3546
3564
  title: "Claude(订阅)",
3547
3565
  pageDesc: "登录 Claude Pro/Max 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -3670,7 +3688,7 @@ window.__ModuleLoader__.load({
3670
3688
  copy: "复制",
3671
3689
  copied: "已复制"
3672
3690
  };
3673
- const en$4 = {
3691
+ const en$5 = {
3674
3692
  ...accountPoolEn,
3675
3693
  title: "Claude (subscription)",
3676
3694
  pageDesc: "Sign in to a Claude Pro/Max subscription and manage models, thinking levels, context windows and quota.",
@@ -3799,15 +3817,15 @@ window.__ModuleLoader__.load({
3799
3817
  copy: "Copy",
3800
3818
  copied: "Copied"
3801
3819
  };
3802
- const dictionaries$4 = {
3803
- zh: zh$4,
3804
- "zh-CN": zh$4,
3805
- en: en$4,
3806
- "en-US": en$4
3820
+ const dictionaries$5 = {
3821
+ zh: zh$5,
3822
+ "zh-CN": zh$5,
3823
+ en: en$5,
3824
+ "en-US": en$5
3807
3825
  };
3808
3826
  //#endregion
3809
3827
  //#region src/client/claude/ClaudeSection.tsx
3810
- const API$7 = "/claude/api";
3828
+ const API$9 = "/claude/api";
3811
3829
  /**
3812
3830
  * The poll cadence of a pending sign-in.
3813
3831
  *
@@ -3817,7 +3835,7 @@ window.__ModuleLoader__.load({
3817
3835
  */
3818
3836
  const LOGIN_POLL_MS = 2e3;
3819
3837
  async function fetchApi$7(path, options) {
3820
- const res = await fetch(`${API$7}${path}`, {
3838
+ const res = await fetch(`${API$9}${path}`, {
3821
3839
  ...options,
3822
3840
  headers: {
3823
3841
  "Content-Type": "application/json",
@@ -3893,11 +3911,11 @@ window.__ModuleLoader__.load({
3893
3911
  * out here would hide a choice the host would accept and a catalog may expose.
3894
3912
  */
3895
3913
  const EFFORT_LABELS$1 = {
3896
- low: zh$4.effortLow,
3897
- medium: zh$4.effortMedium,
3898
- high: zh$4.effortHigh,
3899
- xhigh: zh$4.effortXHigh,
3900
- max: zh$4.effortMax
3914
+ low: zh$5.effortLow,
3915
+ medium: zh$5.effortMedium,
3916
+ high: zh$5.effortHigh,
3917
+ xhigh: zh$5.effortXHigh,
3918
+ max: zh$5.effortMax
3901
3919
  };
3902
3920
  /** One-line capability summary shown as a model pill's hover title. */
3903
3921
  function modelFacts(model, t) {
@@ -3922,7 +3940,7 @@ window.__ModuleLoader__.load({
3922
3940
  const [connection, setConnection] = (0, react.useState)(null);
3923
3941
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
3924
3942
  const quotaFollowUp = (0, react.useRef)(null);
3925
- const t = zh$4;
3943
+ const t = zh$5;
3926
3944
  const notifyChange = (0, react.useCallback)(() => {
3927
3945
  onModelChange?.();
3928
3946
  loadModelDirectory?.();
@@ -4936,7 +4954,7 @@ window.__ModuleLoader__.load({
4936
4954
  //#endregion
4937
4955
  //#region src/client/kimi-code/locales.ts
4938
4956
  const NS_KIMI_CODE = "dsh-kimi-code";
4939
- const zh$3 = {
4957
+ const zh$4 = {
4940
4958
  ...accountPoolZh,
4941
4959
  title: "Kimi Code",
4942
4960
  pageDesc: "登录 Kimi Code 订阅,管理模型、思考档位、上下文窗口与额度。",
@@ -5065,7 +5083,7 @@ window.__ModuleLoader__.load({
5065
5083
  requests: "次请求",
5066
5084
  tokens: "tokens"
5067
5085
  };
5068
- const en$3 = {
5086
+ const en$4 = {
5069
5087
  ...accountPoolEn,
5070
5088
  title: "Kimi Code",
5071
5089
  pageDesc: "Sign in to the Kimi Code subscription and manage models, thinking level, context windows, and quota.",
@@ -5194,11 +5212,11 @@ window.__ModuleLoader__.load({
5194
5212
  requests: "requests",
5195
5213
  tokens: "tokens"
5196
5214
  };
5197
- const dictionaries$3 = {
5198
- zh: zh$3,
5199
- "zh-CN": zh$3,
5200
- en: en$3,
5201
- "en-US": en$3
5215
+ const dictionaries$4 = {
5216
+ zh: zh$4,
5217
+ "zh-CN": zh$4,
5218
+ en: en$4,
5219
+ "en-US": en$4
5202
5220
  };
5203
5221
  //#endregion
5204
5222
  //#region src/client/kimi-code/KimiModelCapabilities.tsx
@@ -5211,7 +5229,7 @@ window.__ModuleLoader__.load({
5211
5229
  * Capabilities are now short tags in their own columns, with the per-model
5212
5230
  * detail kept in a hover title.
5213
5231
  */
5214
- const t = zh$3;
5232
+ const t = zh$4;
5215
5233
  function KimiModelCapabilities({ models }) {
5216
5234
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5217
5235
  className: "dsha-cap-table",
@@ -5255,9 +5273,9 @@ window.__ModuleLoader__.load({
5255
5273
  }
5256
5274
  //#endregion
5257
5275
  //#region src/client/kimi-code/KimiCodeSection.tsx
5258
- const API$6 = "/kimi-code/api";
5276
+ const API$8 = "/kimi-code/api";
5259
5277
  async function fetchApi$6(path, options) {
5260
- const res = await fetch(`${API$6}${path}`, {
5278
+ const res = await fetch(`${API$8}${path}`, {
5261
5279
  ...options,
5262
5280
  headers: {
5263
5281
  "Content-Type": "application/json",
@@ -5327,10 +5345,10 @@ window.__ModuleLoader__.load({
5327
5345
  }
5328
5346
  }
5329
5347
  const EFFORT_LABEL = {
5330
- low: zh$3.effortLow,
5331
- high: zh$3.effortHigh,
5332
- max: zh$3.effortMax,
5333
- none: zh$3.effortNone
5348
+ low: zh$4.effortLow,
5349
+ high: zh$4.effortHigh,
5350
+ max: zh$4.effortMax,
5351
+ none: zh$4.effortNone
5334
5352
  };
5335
5353
  /** Human label for the last request's prefix-drift cause. */
5336
5354
  function driftLabel(cause, t) {
@@ -5356,7 +5374,7 @@ window.__ModuleLoader__.load({
5356
5374
  const [connectionNotice, setConnectionNotice] = (0, react.useState)(null);
5357
5375
  /** Follow-up poll owed while the host refreshes the quota behind an answer. */
5358
5376
  const quotaFollowUp = (0, react.useRef)(null);
5359
- const t = zh$3;
5377
+ const t = zh$4;
5360
5378
  const notifyChange = (0, react.useCallback)(() => {
5361
5379
  onModelChange?.();
5362
5380
  loadModelDirectory?.();
@@ -6237,7 +6255,7 @@ window.__ModuleLoader__.load({
6237
6255
  }
6238
6256
  return fallback;
6239
6257
  }
6240
- async function request(path, init) {
6258
+ async function request$1(path, init) {
6241
6259
  const res = await fetch(`${MINIMAX_CODE_ROUTE_PREFIX}${path}`, {
6242
6260
  ...init,
6243
6261
  credentials: "same-origin",
@@ -6262,10 +6280,10 @@ window.__ModuleLoader__.load({
6262
6280
  return body;
6263
6281
  }
6264
6282
  function get(path) {
6265
- return request(path);
6283
+ return request$1(path);
6266
6284
  }
6267
- function post(path, body = {}) {
6268
- return request(path, {
6285
+ function post$1(path, body = {}) {
6286
+ return request$1(path, {
6269
6287
  method: "POST",
6270
6288
  body: JSON.stringify(body)
6271
6289
  });
@@ -6276,7 +6294,7 @@ window.__ModuleLoader__.load({
6276
6294
  //#endregion
6277
6295
  //#region src/client/minimax-code/locales.ts
6278
6296
  const NS_MINIMAX_CODE = "dsh-minimax-code";
6279
- const zh$2 = {
6297
+ const zh$3 = {
6280
6298
  ...accountPoolZh,
6281
6299
  title: "MiniMax Code",
6282
6300
  pageDesc: "登录 MiniMax Code 编程订阅(设备码 OAuth),复用本机 MiniMax Code 的登录态,管理账号、连接与模型。",
@@ -6382,7 +6400,7 @@ window.__ModuleLoader__.load({
6382
6400
  loading: "加载中...",
6383
6401
  unknown: "—"
6384
6402
  };
6385
- const en$2 = {
6403
+ const en$3 = {
6386
6404
  ...accountPoolEn,
6387
6405
  title: "MiniMax Code",
6388
6406
  pageDesc: "Sign in to the MiniMax Code coding subscription (device-code OAuth) and reuse the local MiniMax Code sign-in to manage the account, connection, and models.",
@@ -6488,11 +6506,11 @@ window.__ModuleLoader__.load({
6488
6506
  loading: "Loading...",
6489
6507
  unknown: "—"
6490
6508
  };
6491
- const dictionaries$2 = {
6492
- zh: zh$2,
6493
- "zh-CN": zh$2,
6494
- en: en$2,
6495
- "en-US": en$2
6509
+ const dictionaries$3 = {
6510
+ zh: zh$3,
6511
+ "zh-CN": zh$3,
6512
+ en: en$3,
6513
+ "en-US": en$3
6496
6514
  };
6497
6515
  //#endregion
6498
6516
  //#region src/client/minimax-code/MinimaxCodeSection.tsx
@@ -6574,7 +6592,7 @@ window.__ModuleLoader__.load({
6574
6592
  return t("thinkingToggle");
6575
6593
  }
6576
6594
  /** The card's own dictionary; stable identity keeps effect dependencies intact. */
6577
- const fallbackTranslate = (key) => zh$2[key];
6595
+ const fallbackTranslate = (key) => zh$3[key];
6578
6596
  /**
6579
6597
  * Hours still left on the access token, or null once it has run out.
6580
6598
  *
@@ -6660,7 +6678,7 @@ window.__ModuleLoader__.load({
6660
6678
  const timer = window.setInterval(() => {
6661
6679
  (async () => {
6662
6680
  try {
6663
- const poll = await post("/login/poll", { loginId });
6681
+ const poll = await post$1("/login/poll", { loginId });
6664
6682
  if (stopped || poll.status === "pending") return;
6665
6683
  stopped = true;
6666
6684
  window.clearInterval(timer);
@@ -6701,7 +6719,7 @@ window.__ModuleLoader__.load({
6701
6719
  quotaRequested.current = true;
6702
6720
  (async () => {
6703
6721
  try {
6704
- setStatus(await post("/quota"));
6722
+ setStatus(await post$1("/quota"));
6705
6723
  } catch {}
6706
6724
  })();
6707
6725
  }, [authenticated, status?.quota]);
@@ -6711,7 +6729,7 @@ window.__ModuleLoader__.load({
6711
6729
  setError(null);
6712
6730
  setConnectionNotice(null);
6713
6731
  setCopied(false);
6714
- const started = await post("/login/start");
6732
+ const started = await post$1("/login/start");
6715
6733
  const login = started.login ?? (typeof started.loginId === "string" ? started : void 0);
6716
6734
  if (login === void 0) {
6717
6735
  setError(t("loginFailed"));
@@ -6729,7 +6747,7 @@ window.__ModuleLoader__.load({
6729
6747
  setFlow(null);
6730
6748
  if (pending === null) return;
6731
6749
  try {
6732
- await post("/login/cancel", { loginId: pending.loginId });
6750
+ await post$1("/login/cancel", { loginId: pending.loginId });
6733
6751
  } catch (cause) {
6734
6752
  setError(messageOf(cause));
6735
6753
  }
@@ -6749,7 +6767,7 @@ window.__ModuleLoader__.load({
6749
6767
  setError(null);
6750
6768
  setConnectionNotice(null);
6751
6769
  setFlow(null);
6752
- const result = await post("/logout");
6770
+ const result = await post$1("/logout");
6753
6771
  if (result.native === true) setConnectionNotice(result.error ?? t("logoutOwnedByApp"));
6754
6772
  await loadStatus(true);
6755
6773
  onModelChange?.();
@@ -6780,7 +6798,7 @@ window.__ModuleLoader__.load({
6780
6798
  try {
6781
6799
  setBusy(action);
6782
6800
  setError(null);
6783
- await post("/accounts", {
6801
+ await post$1("/accounts", {
6784
6802
  action,
6785
6803
  accountId
6786
6804
  });
@@ -6797,7 +6815,7 @@ window.__ModuleLoader__.load({
6797
6815
  try {
6798
6816
  setBusy("strategy");
6799
6817
  setError(null);
6800
- await post("/accounts", {
6818
+ await post$1("/accounts", {
6801
6819
  action: "strategy",
6802
6820
  strategy
6803
6821
  });
@@ -6811,7 +6829,7 @@ window.__ModuleLoader__.load({
6811
6829
  const applyEnabled = async (enabledModelIds) => {
6812
6830
  try {
6813
6831
  setError(null);
6814
- const updated = await post("/models", { enabledModelIds });
6832
+ const updated = await post$1("/models", { enabledModelIds });
6815
6833
  setStatus(updated);
6816
6834
  setContextDrafts(contextDraftsFor$1(updated));
6817
6835
  onModelChange?.();
@@ -6833,7 +6851,7 @@ window.__ModuleLoader__.load({
6833
6851
  });
6834
6852
  try {
6835
6853
  setError(null);
6836
- const updated = await post("/settings", { enabled });
6854
+ const updated = await post$1("/settings", { enabled });
6837
6855
  setStatus(updated);
6838
6856
  onModelChange?.();
6839
6857
  } catch (cause) {
@@ -6846,7 +6864,7 @@ window.__ModuleLoader__.load({
6846
6864
  try {
6847
6865
  setBusy("checkin");
6848
6866
  setError(null);
6849
- const updated = await post("/settings", { checkin: { enabled } });
6867
+ const updated = await post$1("/settings", { checkin: { enabled } });
6850
6868
  setStatus(updated);
6851
6869
  } catch (cause) {
6852
6870
  setError(messageOf(cause));
@@ -6859,7 +6877,7 @@ window.__ModuleLoader__.load({
6859
6877
  try {
6860
6878
  setBusy("checkin");
6861
6879
  setError(null);
6862
- const updated = await post("/checkin/now");
6880
+ const updated = await post$1("/checkin/now");
6863
6881
  setStatus(updated);
6864
6882
  } catch (cause) {
6865
6883
  setError(messageOf(cause));
@@ -6880,7 +6898,7 @@ window.__ModuleLoader__.load({
6880
6898
  const handleUpdateEffort = async (effort) => {
6881
6899
  try {
6882
6900
  setError(null);
6883
- const updated = await post("/settings", { defaultReasoningEffort: effort });
6901
+ const updated = await post$1("/settings", { defaultReasoningEffort: effort });
6884
6902
  setStatus(updated);
6885
6903
  onModelChange?.();
6886
6904
  } catch (cause) {
@@ -6897,7 +6915,7 @@ window.__ModuleLoader__.load({
6897
6915
  try {
6898
6916
  setSavingModel(modelId);
6899
6917
  setError(null);
6900
- const updated = await post("/settings", { contextWindowOverrides: { [modelId]: parsed } });
6918
+ const updated = await post$1("/settings", { contextWindowOverrides: { [modelId]: parsed } });
6901
6919
  setStatus(updated);
6902
6920
  setContextDrafts((prev) => ({
6903
6921
  ...prev,
@@ -6914,7 +6932,7 @@ window.__ModuleLoader__.load({
6914
6932
  try {
6915
6933
  setSavingModel(modelId);
6916
6934
  setError(null);
6917
- const updated = await post("/settings", { contextWindowOverrides: { [modelId]: null } });
6935
+ const updated = await post$1("/settings", { contextWindowOverrides: { [modelId]: null } });
6918
6936
  setStatus(updated);
6919
6937
  const model = updated.models.find((entry) => entry.id === modelId);
6920
6938
  if (model !== void 0) setContextDrafts((prev) => ({
@@ -6933,7 +6951,7 @@ window.__ModuleLoader__.load({
6933
6951
  if (ids.length === 0) return;
6934
6952
  try {
6935
6953
  setError(null);
6936
- const updated = await post("/settings", { contextWindowOverrides: Object.fromEntries(ids.map((id) => [id, null])) });
6954
+ const updated = await post$1("/settings", { contextWindowOverrides: Object.fromEntries(ids.map((id) => [id, null])) });
6937
6955
  setStatus(updated);
6938
6956
  setContextDrafts(contextDraftsFor$1(updated));
6939
6957
  onModelChange?.();
@@ -6946,7 +6964,7 @@ window.__ModuleLoader__.load({
6946
6964
  try {
6947
6965
  setBusy("quota");
6948
6966
  setError(null);
6949
- setStatus(await post("/quota"));
6967
+ setStatus(await post$1("/quota"));
6950
6968
  } catch (cause) {
6951
6969
  setError(messageOf(cause));
6952
6970
  } finally {
@@ -6958,7 +6976,7 @@ window.__ModuleLoader__.load({
6958
6976
  setBusy("test");
6959
6977
  setError(null);
6960
6978
  setConnectionNotice(null);
6961
- const result = await post("/test");
6979
+ const result = await post$1("/test");
6962
6980
  if (result.ok === true) {
6963
6981
  setConnectionNotice(result.model === void 0 || result.model === "" ? t("testSuccess") : t("testSuccessModel").replace("{model}", result.model));
6964
6982
  return;
@@ -7509,7 +7527,7 @@ window.__ModuleLoader__.load({
7509
7527
  //#endregion
7510
7528
  //#region src/client/workbuddy/locales.ts
7511
7529
  const NS_WORKBUDDY = "dsh-workbuddy";
7512
- const zh$1 = {
7530
+ const zh$2 = {
7513
7531
  title: "WorkBuddy",
7514
7532
  pageDesc: "复用本机 CodeBuddy 桌面端登录态,管理 WorkBuddy(CodeBuddy 订阅)模型、上下文窗口与额度。",
7515
7533
  account: "账号",
@@ -7603,7 +7621,7 @@ window.__ModuleLoader__.load({
7603
7621
  checkinNow: "立即签到",
7604
7622
  checkinRunning: "签到中…"
7605
7623
  };
7606
- const en$1 = {
7624
+ const en$2 = {
7607
7625
  title: "WorkBuddy",
7608
7626
  pageDesc: "Reuse the local CodeBuddy desktop sign-in to manage WorkBuddy (CodeBuddy subscription) models, context windows, and quota.",
7609
7627
  account: "Account",
@@ -7697,11 +7715,11 @@ window.__ModuleLoader__.load({
7697
7715
  checkinNow: "Check in now",
7698
7716
  checkinRunning: "Checking in…"
7699
7717
  };
7700
- const dictionaries$1 = {
7701
- zh: zh$1,
7702
- "zh-CN": zh$1,
7703
- en: en$1,
7704
- "en-US": en$1
7718
+ const dictionaries$2 = {
7719
+ zh: zh$2,
7720
+ "zh-CN": zh$2,
7721
+ en: en$2,
7722
+ "en-US": en$2
7705
7723
  };
7706
7724
  //#endregion
7707
7725
  //#region src/client/workbuddy/WorkBuddySection.tsx
@@ -7717,7 +7735,7 @@ window.__ModuleLoader__.load({
7717
7735
  xhigh: "X-High",
7718
7736
  max: "Max"
7719
7737
  };
7720
- const API$5 = "/workbuddy/api";
7738
+ const API$7 = "/workbuddy/api";
7721
7739
  /**
7722
7740
  * The shared card's label set.
7723
7741
  *
@@ -7744,7 +7762,7 @@ window.__ModuleLoader__.load({
7744
7762
  * such instead of as a credential problem.
7745
7763
  */
7746
7764
  async function fetchApi$5(path, options) {
7747
- const res = await fetch(`${API$5}${path}`, {
7765
+ const res = await fetch(`${API$7}${path}`, {
7748
7766
  ...options,
7749
7767
  headers: {
7750
7768
  "Content-Type": "application/json",
@@ -7875,7 +7893,7 @@ window.__ModuleLoader__.load({
7875
7893
  const quotaFollowUp = (0, react.useRef)(null);
7876
7894
  const [contextDrafts, setContextDrafts] = (0, react.useState)({});
7877
7895
  const [savingModel, setSavingModel] = (0, react.useState)(null);
7878
- const t = zh$1;
7896
+ const t = zh$2;
7879
7897
  const notifyChange = (0, react.useCallback)(() => {
7880
7898
  onModelChange?.();
7881
7899
  loadModelDirectory?.();
@@ -8728,6 +8746,502 @@ window.__ModuleLoader__.load({
8728
8746
  });
8729
8747
  }
8730
8748
  //#endregion
8749
+ //#region src/client/ollama/api.ts
8750
+ const API$6 = "/ollama/api";
8751
+ /**
8752
+ * The Ollama settings API, as the card uses it.
8753
+ *
8754
+ * Deliberately the same envelope and the same fetch shape every other provider
8755
+ * section uses, so the shared account-pool card and this helper read alike.
8756
+ */
8757
+ var OllamaApi = class {
8758
+ status() {
8759
+ return request(`${API$6}/status`);
8760
+ }
8761
+ /**
8762
+ * One pool action, returning the refreshed status.
8763
+ *
8764
+ * The host answers with the same envelope the status route uses, so the card
8765
+ * never has to guess what the pool looks like after a change.
8766
+ */
8767
+ accountAction(action, body = {}) {
8768
+ return post(`${API$6}/accounts`, {
8769
+ action,
8770
+ ...body
8771
+ });
8772
+ }
8773
+ refreshCatalog() {
8774
+ return post(`${API$6}/catalog/refresh`, {});
8775
+ }
8776
+ /**
8777
+ * Replace the enabled-model selection.
8778
+ *
8779
+ * The whole list is sent rather than a single id's new state, because the card
8780
+ * offers bulk select and unselect and would otherwise have to read the current
8781
+ * selection before it could answer 'turn this one off'.
8782
+ */
8783
+ setEnabledModels(enabledModelIds) {
8784
+ return post(`${API$6}/models`, { enabledModelIds });
8785
+ }
8786
+ };
8787
+ async function post(url, body) {
8788
+ return request(url, {
8789
+ method: "POST",
8790
+ headers: { "Content-Type": "application/json" },
8791
+ body: JSON.stringify(body)
8792
+ });
8793
+ }
8794
+ async function request(url, init) {
8795
+ const response = await fetch(url, {
8796
+ ...init,
8797
+ credentials: "same-origin"
8798
+ });
8799
+ const envelope = await response.json();
8800
+ if (!response.ok || !envelope.ok) throw new Error(envelope.error || `HTTP ${response.status}`);
8801
+ return envelope.value;
8802
+ }
8803
+ //#endregion
8804
+ //#region src/client/ollama/locales.ts
8805
+ const NS_OLLAMA = "dsh-ollama";
8806
+ const zh$1 = {
8807
+ ...accountPoolZh,
8808
+ relogin: "更换 Key",
8809
+ needsRelogin: "Key 已失效",
8810
+ addAccount: "添加 API Key",
8811
+ noAccounts: "暂无 API Key。点击「添加 API Key」粘贴 ollama.com 创建的 Key。",
8812
+ storageNotice: "API Key 由 Host 保存于本地安全存储,不会进入浏览器。",
8813
+ title: "Ollama",
8814
+ pageDesc: "接入 Ollama Cloud,用多个 API Key 组成号池,自动轮换与故障转移。",
8815
+ provider: "Provider",
8816
+ providerValue: "Ollama · ollama",
8817
+ routeOwned: "模型路由由本插件提供",
8818
+ routeConflict: "模型路由已被其他 Provider 占用:{detail}。请在 DSH 设置中移除重复的 Provider 配置后重试。",
8819
+ keySection: "添加 API Key",
8820
+ keyHint: "在 https://ollama.com/settings/keys 创建 API Key 后粘贴到此处。Key 不会过期,可随时在设置页吊销。",
8821
+ keyPlaceholder: "粘贴 Ollama API Key",
8822
+ keyAliasLabel: "备注名(可选)",
8823
+ keyAliasPlaceholder: "例如:主号、备用号",
8824
+ keyAliasHint: "Ollama 不返回账号信息,多个 Key 靠备注名区分。",
8825
+ keySave: "添加",
8826
+ keySaving: "添加中...",
8827
+ modelsSection: "模型",
8828
+ modelsHint: "模型列表来自 Ollama 的 /api/tags,随服务更新,无需手动维护。",
8829
+ catalogSync: "同步模型列表",
8830
+ catalogSyncing: "同步中...",
8831
+ catalogNeverSynced: "尚未同步模型列表。点右上角「同步模型列表」获取你账号可用的模型 —— 在此之前这里不会有任何条目,本线路也不会出现在模型选择器中。",
8832
+ catalogEmpty: "Ollama 未返回任何模型。",
8833
+ catalogNeedKey: "请先添加一个 API Key,再同步模型列表。",
8834
+ catalogFailed: "无法从 Ollama 读取模型列表。",
8835
+ modelCount: "{count} 个模型",
8836
+ noModels: "暂无可用模型。",
8837
+ selectAll: "全选",
8838
+ unselectAll: "全不选",
8839
+ noneSelected: "未选择任何模型,该线路不会出现在模型选择器中。",
8840
+ limitsSection: "能力边界",
8841
+ limitsHint: "以下为 Ollama Cloud 官方文档列出的限制,本线路不会绕过:",
8842
+ limitNoStateful: "不支持 Responses 的有状态会话(仅无状态形式)。",
8843
+ limitNoWebSearch: "不支持通过 /v1/responses 使用内置联网搜索。",
8844
+ limitNoToolReplay: "不支持自定义工具调用的重放(replay)。",
8845
+ limitUsage: "Ollama 没有配额/剩余额度 API(上游 issue #15132、#15663 均已关闭),所以只能显示「已消耗」,无法显示「剩余多少」。",
8846
+ wireNote: "请求默认走 OpenAI 兼容面(/v1),必要时回落到原生面(/api/chat)。",
8847
+ lastModel: "最近模型",
8848
+ keyCreated: "添加于",
8849
+ error: "操作失败:{detail}",
8850
+ usageTitle: "累计消耗",
8851
+ usageInput: "输入 {tokens}",
8852
+ usageOutput: "输出 {tokens}",
8853
+ usageRequests: "{count} 次请求",
8854
+ usageNone: "尚无请求",
8855
+ usageHint: "按 Ollama 每次响应自带的 token 计数本地累加。"
8856
+ };
8857
+ const en$1 = {
8858
+ ...accountPoolEn,
8859
+ relogin: "Replace Key",
8860
+ needsRelogin: "Key rejected",
8861
+ addAccount: "Add API Key",
8862
+ noAccounts: "No API keys yet. Click \"Add API Key\" to paste one from ollama.com.",
8863
+ storageNotice: "API keys are stored locally by the Host and never sent to the browser.",
8864
+ title: "Ollama",
8865
+ pageDesc: "Connect Ollama Cloud with several API keys pooled for rotation and failover.",
8866
+ provider: "Provider",
8867
+ providerValue: "Ollama · ollama",
8868
+ routeOwned: "Model route served by this plugin",
8869
+ routeConflict: "The model route is already owned by another provider: {detail}",
8870
+ keySection: "Add an API key",
8871
+ keyHint: "Create a key at https://ollama.com/settings/keys and paste it here. Keys do not expire and can be revoked from that page.",
8872
+ keyPlaceholder: "Paste an Ollama API key",
8873
+ keyAliasLabel: "Label (optional)",
8874
+ keyAliasPlaceholder: "e.g. primary, backup",
8875
+ keyAliasHint: "Ollama reports no account identity, so labels are what tell several keys apart.",
8876
+ keySave: "Add",
8877
+ keySaving: "Adding...",
8878
+ modelsSection: "Models",
8879
+ modelsHint: "The list comes from Ollama '/api/tags' and tracks the service, so there is nothing to maintain by hand.",
8880
+ catalogSync: "Sync model list",
8881
+ catalogSyncing: "Syncing...",
8882
+ catalogNeverSynced: "The model list has not been synced yet. Use \"Sync model list\" above to fetch the models your account can use - until then this list is empty and the line will not appear in the model picker.",
8883
+ catalogEmpty: "Ollama returned no models.",
8884
+ catalogNeedKey: "Add an API key before syncing the model list.",
8885
+ catalogFailed: "Could not read the model list from Ollama.",
8886
+ modelCount: "{count} model(s)",
8887
+ noModels: "No models available.",
8888
+ selectAll: "Select all",
8889
+ unselectAll: "Clear all",
8890
+ noneSelected: "No models are selected, so this line will not appear in the model picker.",
8891
+ limitsSection: "Documented limits",
8892
+ limitsHint: "Ollama Cloud documents these limits; this line does not work around them:",
8893
+ limitNoStateful: "No stateful Responses (stateless only).",
8894
+ limitNoWebSearch: "No built-in web search through /v1/responses.",
8895
+ limitNoToolReplay: "No replay of custom tool calls.",
8896
+ limitUsage: "Ollama has no quota or remaining-balance API (upstream issues #15132 and #15663 were both closed), so this card can show what has been consumed but not what is left.",
8897
+ wireNote: "Requests use the OpenAI-compatible surface (/v1) and fall back to the native surface (/api/chat) when needed.",
8898
+ lastModel: "Last model",
8899
+ keyCreated: "Added",
8900
+ error: "Action failed: {detail}",
8901
+ usageTitle: "Consumed so far",
8902
+ usageInput: "in {tokens}",
8903
+ usageOutput: "out {tokens}",
8904
+ usageRequests: "{count} request(s)",
8905
+ usageNone: "No requests yet",
8906
+ usageHint: "Summed locally from the token counts Ollama returns on each response."
8907
+ };
8908
+ const dictionaries$1 = {
8909
+ zh: zh$1,
8910
+ "zh-CN": zh$1,
8911
+ en: en$1,
8912
+ "en-US": en$1
8913
+ };
8914
+ //#endregion
8915
+ //#region src/client/ollama/OllamaSection.tsx
8916
+ const API$5 = new OllamaApi();
8917
+ /**
8918
+ * A token count short enough to sit in an account card.
8919
+ *
8920
+ * Exact below a thousand, then thousands, then millions. A six-figure number with
8921
+ * no grouping is unreadable at card width, and these are running totals that only
8922
+ * ever grow, so rounding is fine but commas are not optional.
8923
+ */
8924
+ function formatTokens(value) {
8925
+ if (!Number.isFinite(value) || value < 0) return "—";
8926
+ if (value < 1e3) return String(Math.floor(value));
8927
+ if (value < 1e6) return `${(value / 1e3).toFixed(value < 1e4 ? 1 : 0)}K`;
8928
+ return `${(value / 1e6).toFixed(1)}M`;
8929
+ }
8930
+ /**
8931
+ * The Ollama tab.
8932
+ *
8933
+ * Deliberately thin. The account card, its badges, the rotation picker and the
8934
+ * storage notice are the shared {@link AccountPoolSection}, so this line looks
8935
+ * like every other provider tab by construction rather than by imitation; only
8936
+ * what is genuinely Ollama's - pasting a key, syncing the catalog, and the
8937
+ * documented service limits - is written here.
8938
+ */
8939
+ function OllamaSection(props) {
8940
+ const [status, setStatus] = (0, react.useState)(null);
8941
+ const [busy, setBusy] = (0, react.useState)(null);
8942
+ const [error, setError] = (0, react.useState)(null);
8943
+ const [key, setKey] = (0, react.useState)("");
8944
+ const [alias, setAlias] = (0, react.useState)("");
8945
+ const [showKeyForm, setShowKeyForm] = (0, react.useState)(false);
8946
+ /** Ids the user has switched on. Empty means 'no filter', i.e. all of them. */
8947
+ const [enabled, setEnabled] = (0, react.useState)(/* @__PURE__ */ new Set());
8948
+ const reload = (0, react.useCallback)(async () => {
8949
+ try {
8950
+ const next = await API$5.status();
8951
+ setStatus(next);
8952
+ setEnabled(new Set(next.enabledModelIds));
8953
+ } catch (cause) {
8954
+ setError(cause instanceof Error ? cause.message : String(cause));
8955
+ }
8956
+ }, []);
8957
+ (0, react.useEffect)(() => {
8958
+ reload();
8959
+ }, [reload]);
8960
+ const run = (0, react.useCallback)(async (label, action) => {
8961
+ setBusy(label);
8962
+ setError(null);
8963
+ try {
8964
+ setStatus(await action());
8965
+ props.onModelChange?.();
8966
+ props.loadModelDirectory?.();
8967
+ } catch (cause) {
8968
+ setError(cause instanceof Error ? cause.message : String(cause));
8969
+ } finally {
8970
+ setBusy(null);
8971
+ }
8972
+ }, [props]);
8973
+ const addKey = (0, react.useCallback)(() => {
8974
+ const trimmed = key.trim();
8975
+ if (trimmed === "") return;
8976
+ run("add", async () => {
8977
+ const next = await API$5.accountAction("add", {
8978
+ apiKey: trimmed,
8979
+ ...alias.trim() === "" ? {} : { alias: alias.trim() }
8980
+ });
8981
+ setKey("");
8982
+ setAlias("");
8983
+ setShowKeyForm(false);
8984
+ return next;
8985
+ });
8986
+ }, [
8987
+ key,
8988
+ alias,
8989
+ run
8990
+ ]);
8991
+ const syncCatalog = (0, react.useCallback)(() => {
8992
+ run("catalog", async () => {
8993
+ await API$5.refreshCatalog();
8994
+ return API$5.status();
8995
+ });
8996
+ }, [run]);
8997
+ const isModelEnabled = (0, react.useCallback)((id) => {
8998
+ return enabled.size === 0 || enabled.has(id);
8999
+ }, [enabled]);
9000
+ const applyEnabled = (0, react.useCallback)((next) => {
9001
+ run("models", async () => {
9002
+ const result = await API$5.setEnabledModels(next);
9003
+ setEnabled(new Set(result.enabledModelIds));
9004
+ return API$5.status();
9005
+ });
9006
+ }, [run]);
9007
+ const toggleModel = (0, react.useCallback)((id, checked) => {
9008
+ if (status === null) return;
9009
+ const current = status.models.filter((model) => isModelEnabled(model.id)).map((model) => model.id);
9010
+ const next = checked ? [.../* @__PURE__ */ new Set([...current, id])] : current.filter((entry) => entry !== id);
9011
+ applyEnabled(next);
9012
+ }, [
9013
+ status,
9014
+ isModelEnabled,
9015
+ applyEnabled
9016
+ ]);
9017
+ const setAllModels = (0, react.useCallback)((selectAll) => {
9018
+ if (status === null || status.models.length === 0) return;
9019
+ applyEnabled(selectAll ? status.models.map((model) => model.id) : []);
9020
+ }, [status, applyEnabled]);
9021
+ const t = zh$1;
9022
+ const pool = status?.pool;
9023
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
9024
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9025
+ className: "dsha-group",
9026
+ children: [
9027
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9028
+ className: "dsha-grouphead",
9029
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.title })
9030
+ }),
9031
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9032
+ className: "dsha-notice",
9033
+ children: t.pageDesc
9034
+ }),
9035
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9036
+ className: "dsha-row",
9037
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9038
+ className: "dsha-label",
9039
+ children: t.provider
9040
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9041
+ className: "dsha-value",
9042
+ children: t.providerValue
9043
+ })]
9044
+ }),
9045
+ error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9046
+ className: "dsha-notice",
9047
+ style: { color: "var(--dsha-danger, #c0392b)" },
9048
+ children: t.error.replace("{detail}", error)
9049
+ })
9050
+ ]
9051
+ }),
9052
+ pool !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountPoolSection, {
9053
+ accounts: pool.accounts,
9054
+ activeAccountId: pool.activeAccountId,
9055
+ rotationStrategy: pool.rotationStrategy,
9056
+ labels: t,
9057
+ busy,
9058
+ onLogin: () => setShowKeyForm((value) => !value),
9059
+ onSetPrimary: (id) => void run("set-primary", () => API$5.accountAction("set-primary", { accountId: id })),
9060
+ onDelete: (id) => void run("delete", () => API$5.accountAction("delete", { accountId: id })),
9061
+ onClearCooldown: (id) => void run("clear-cooldown", () => API$5.accountAction("clear-cooldown", { accountId: id })),
9062
+ onSetStrategy: (strategy) => void run("strategy", () => API$5.accountAction("strategy", { strategy })),
9063
+ renderDetails: (account) => {
9064
+ const usage = account.usage;
9065
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [account.lastModelId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
9066
+ t.lastModel,
9067
+ ": ",
9068
+ account.lastModelId
9069
+ ] }), usage === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t.usageNone }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
9070
+ t.usageInput.replace("{tokens}", formatTokens(usage.inputTokens)),
9071
+ t.usageOutput.replace("{tokens}", formatTokens(usage.outputTokens)),
9072
+ t.usageRequests.replace("{count}", String(usage.requestCount))
9073
+ ] })] });
9074
+ },
9075
+ renderLoginActions: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9076
+ style: {
9077
+ display: "flex",
9078
+ gap: 8
9079
+ },
9080
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9081
+ className: "dsha-btn dsha-btn-primary",
9082
+ disabled: busy !== null,
9083
+ onClick: () => setShowKeyForm((value) => !value),
9084
+ children: t.addAccount
9085
+ })
9086
+ }),
9087
+ children: showKeyForm && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9088
+ className: "dsha-pref-row",
9089
+ style: {
9090
+ flexDirection: "column",
9091
+ alignItems: "stretch",
9092
+ gap: 8
9093
+ },
9094
+ children: [
9095
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
9096
+ className: "dsha-label",
9097
+ htmlFor: "ollama-key",
9098
+ children: t.keySection
9099
+ }),
9100
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
9101
+ id: "ollama-key",
9102
+ className: "dsha-input",
9103
+ type: "password",
9104
+ value: key,
9105
+ placeholder: t.keyPlaceholder,
9106
+ autoComplete: "off",
9107
+ onChange: (event) => setKey(event.target.value)
9108
+ }),
9109
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
9110
+ className: "dsha-label",
9111
+ htmlFor: "ollama-alias",
9112
+ children: t.keyAliasLabel
9113
+ }),
9114
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
9115
+ id: "ollama-alias",
9116
+ className: "dsha-input",
9117
+ value: alias,
9118
+ placeholder: t.keyAliasPlaceholder,
9119
+ onChange: (event) => setAlias(event.target.value)
9120
+ }),
9121
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9122
+ className: "dsha-muted",
9123
+ style: { fontSize: 12 },
9124
+ children: t.keyHint
9125
+ }),
9126
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9127
+ className: "dsha-muted",
9128
+ style: { fontSize: 12 },
9129
+ children: t.keyAliasHint
9130
+ }),
9131
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9132
+ style: {
9133
+ display: "flex",
9134
+ gap: 8
9135
+ },
9136
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9137
+ className: "dsha-btn dsha-btn-primary",
9138
+ disabled: busy !== null || key.trim() === "",
9139
+ onClick: addKey,
9140
+ children: busy === "add" ? t.keySaving : t.keySave
9141
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9142
+ className: "dsha-btn",
9143
+ disabled: busy !== null,
9144
+ onClick: () => setShowKeyForm(false),
9145
+ children: zh$1.deleteAccount
9146
+ })]
9147
+ })
9148
+ ]
9149
+ })
9150
+ }),
9151
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9152
+ className: "dsha-group",
9153
+ children: [
9154
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9155
+ className: "dsha-grouphead",
9156
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.modelsSection }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9157
+ className: "dsha-btn",
9158
+ disabled: busy !== null,
9159
+ onClick: syncCatalog,
9160
+ children: busy === "catalog" ? t.catalogSyncing : t.catalogSync
9161
+ })]
9162
+ }),
9163
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9164
+ className: "dsha-muted",
9165
+ style: { fontSize: 12 },
9166
+ children: t.modelsHint
9167
+ }),
9168
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9169
+ className: "dsha-muted",
9170
+ style: { fontSize: 12 },
9171
+ children: t.wireNote
9172
+ }),
9173
+ status !== null && status.models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9174
+ className: "dsha-empty",
9175
+ children: status.catalogSynced ? t.catalogEmpty : t.catalogNeverSynced
9176
+ }),
9177
+ status !== null && status.models.length === 0 && !status.usable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9178
+ className: "dsha-muted",
9179
+ style: { fontSize: 12 },
9180
+ children: t.catalogNeedKey
9181
+ }),
9182
+ status !== null && status.models.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9183
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9184
+ className: "dsha-muted",
9185
+ style: { fontSize: 12 },
9186
+ children: t.modelCount.replace("{count}", String(status.models.length))
9187
+ }),
9188
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9189
+ className: "dsha-models",
9190
+ "aria-label": "Ollama Models",
9191
+ children: status.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
9192
+ title: model.id,
9193
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
9194
+ type: "checkbox",
9195
+ checked: isModelEnabled(model.id),
9196
+ disabled: busy !== null,
9197
+ onChange: (event) => void toggleModel(model.id, event.currentTarget.checked)
9198
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name ?? model.id })]
9199
+ }, model.id))
9200
+ }),
9201
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9202
+ className: "dsha-actions",
9203
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9204
+ className: "dsha-btn",
9205
+ disabled: busy !== null,
9206
+ onClick: () => void setAllModels(true),
9207
+ children: t.selectAll
9208
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9209
+ className: "dsha-btn",
9210
+ disabled: busy !== null,
9211
+ onClick: () => void setAllModels(false),
9212
+ children: t.unselectAll
9213
+ })]
9214
+ })
9215
+ ] })
9216
+ ]
9217
+ }),
9218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9219
+ className: "dsha-group",
9220
+ children: [
9221
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9222
+ className: "dsha-grouphead",
9223
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t.limitsSection })
9224
+ }),
9225
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9226
+ className: "dsha-muted",
9227
+ style: { fontSize: 12 },
9228
+ children: t.limitsHint
9229
+ }),
9230
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
9231
+ className: "dsha-notice",
9232
+ style: { paddingLeft: 18 },
9233
+ children: [
9234
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t.limitNoStateful }),
9235
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t.limitNoWebSearch }),
9236
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t.limitNoToolReplay }),
9237
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t.limitUsage })
9238
+ ]
9239
+ })
9240
+ ]
9241
+ })
9242
+ ] });
9243
+ }
9244
+ //#endregion
8731
9245
  //#region src/client/ProviderHubSection.tsx
8732
9246
  const HUB_TABS = [
8733
9247
  {
@@ -8757,6 +9271,10 @@ window.__ModuleLoader__.load({
8757
9271
  {
8758
9272
  id: "claude",
8759
9273
  label: "Claude"
9274
+ },
9275
+ {
9276
+ id: "ollama",
9277
+ label: "Ollama"
8760
9278
  }
8761
9279
  ];
8762
9280
  /**
@@ -8843,7 +9361,8 @@ window.__ModuleLoader__.load({
8843
9361
  active === "kimi-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KimiCodeSection, { onModelChange }) : null,
8844
9362
  active === "workbuddy" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkBuddySection, { onModelChange }) : null,
8845
9363
  active === "minimax-code" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MinimaxCodeSection, { onModelChange }) : null,
8846
- active === "claude" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClaudeSection, { onModelChange }) : null
9364
+ active === "claude" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ClaudeSection, { onModelChange }) : null,
9365
+ active === "ollama" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OllamaSection, { onModelChange }) : null
8847
9366
  ]
8848
9367
  })
8849
9368
  ]
@@ -8915,12 +9434,12 @@ window.__ModuleLoader__.load({
8915
9434
  fastMode: "快速模式(1.5x 速度)",
8916
9435
  fastModeHint: "提升 Token 生成速度至约 1.5 倍;将以约 2x–2.5x 速度消耗 Codex 订阅额度。",
8917
9436
  outputVerbosity: "输出详细程度",
8918
- outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。",
9437
+ outputVerbosityHint: "控制 Codex 最终回答的详细程度;不影响思考深度。默认值与官方 Codex 客户端一致(低)。",
8919
9438
  verbosityLow: "低(保持回答简洁)",
8920
9439
  verbosityMedium: "中(兼顾细节与简洁)",
8921
9440
  verbosityHigh: "高(在回答中包含更多细节)",
8922
9441
  reasoningSummary: "推理摘要",
8923
- reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。",
9442
+ reasoningSummaryHint: "选择 ChatGPT 总结其推理的方式;不影响思考深度。默认值与官方 Codex 客户端一致(不生成摘要,可省额度)。",
8924
9443
  summaryAuto: "自动(让模型选择摘要详细程度)",
8925
9444
  summaryConcise: "简洁(显示简要推理摘要)",
8926
9445
  summaryDetailed: "详细(显示更详细的推理摘要)",
@@ -9048,12 +9567,12 @@ window.__ModuleLoader__.load({
9048
9567
  fastMode: "Fast mode (1.5x speed)",
9049
9568
  fastModeHint: "Generates tokens ~1.5x faster; consumes Codex subscription quota at ~2x–2.5x the normal rate.",
9050
9569
  outputVerbosity: "Output verbosity",
9051
- outputVerbosityHint: "Controls the detail level of final Codex answers without changing reasoning effort.",
9570
+ outputVerbosityHint: "Controls the detail level of final Codex answers without changing reasoning effort. The default matches the official Codex client (low).",
9052
9571
  verbosityLow: "Low (keep answers concise)",
9053
9572
  verbosityMedium: "Medium (balance detail and brevity)",
9054
9573
  verbosityHigh: "High (include more detail)",
9055
9574
  reasoningSummary: "Reasoning summary",
9056
- reasoningSummaryHint: "Controls how ChatGPT summarizes its chain of thought; does not change reasoning depth.",
9575
+ reasoningSummaryHint: "Controls how ChatGPT summarizes its chain of thought; does not change reasoning depth. The default matches the official Codex client (no summary, which saves quota).",
9057
9576
  summaryAuto: "Auto (let model determine detail)",
9058
9577
  summaryConcise: "Concise (brief summary)",
9059
9578
  summaryDetailed: "Detailed (in-depth summary)",
@@ -10546,28 +11065,29 @@ window.__ModuleLoader__.load({
10546
11065
  function apply(ctx) {
10547
11066
  ctx.effect(() => ctx.locale.register(NS, dictionaries), "dsh-chatgpt-subscription: dictionaries");
10548
11067
  ctx.effect(() => installStyles(), "dsh-chatgpt-subscription: styles");
10549
- ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$6), "dsh-antigravity: dictionaries");
11068
+ ctx.effect(() => ctx.locale.register(NS_ANTIGRAVITY, dictionaries$7), "dsh-antigravity: dictionaries");
10550
11069
  ctx.effect(() => {
10551
11070
  installAntigravityStyles();
10552
11071
  return () => {};
10553
11072
  }, "dsh-antigravity: styles");
10554
- ctx.effect(() => ctx.locale.register(NS_CLAUDE, dictionaries$4), "dsh-claude: dictionaries");
11073
+ ctx.effect(() => ctx.locale.register(NS_CLAUDE, dictionaries$5), "dsh-claude: dictionaries");
10555
11074
  ctx.effect(() => {
10556
11075
  installClaudeStyles();
10557
11076
  return () => {};
10558
11077
  }, "dsh-claude: styles");
10559
- ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$5), "dsh-command-code: dictionaries");
10560
- ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$3), "dsh-kimi-code: dictionaries");
11078
+ ctx.effect(() => ctx.locale.register(NS_COMMAND_CODE, dictionaries$6), "dsh-command-code: dictionaries");
11079
+ ctx.effect(() => ctx.locale.register(NS_KIMI_CODE, dictionaries$4), "dsh-kimi-code: dictionaries");
10561
11080
  ctx.effect(() => {
10562
11081
  installKimiCodeStyles();
10563
11082
  return () => {};
10564
11083
  }, "dsh-kimi-code: styles");
10565
- ctx.effect(() => ctx.locale.register(NS_MINIMAX_CODE, dictionaries$2), "dsh-minimax-code: dictionaries");
11084
+ ctx.effect(() => ctx.locale.register(NS_MINIMAX_CODE, dictionaries$3), "dsh-minimax-code: dictionaries");
10566
11085
  ctx.effect(() => {
10567
11086
  installMinimaxCodeStyles();
10568
11087
  return () => {};
10569
11088
  }, "dsh-minimax-code: styles");
10570
- ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$1), "dsh-workbuddy: dictionaries");
11089
+ ctx.effect(() => ctx.locale.register(NS_WORKBUDDY, dictionaries$2), "dsh-workbuddy: dictionaries");
11090
+ ctx.effect(() => ctx.locale.register(NS_OLLAMA, dictionaries$1), "dsh-ollama: dictionaries");
10571
11091
  ctx.effect(() => {
10572
11092
  installWorkBuddyStyles();
10573
11093
  return () => {};