dsh-subscriptions 0.2.2 → 0.3.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 (43) hide show
  1. package/README.md +28 -32
  2. package/lib/auth/rpc.d.ts +10 -24
  3. package/lib/auth/rpc.js +18 -51
  4. package/lib/client/ProviderAccountManager.d.ts +1 -1
  5. package/lib/client/ProviderAccountManager.js +86 -110
  6. package/lib/client/ProviderModelEditor.d.ts +1 -1
  7. package/lib/client/ProviderModelEditor.js +61 -43
  8. package/lib/client/SpeedSelect.js +13 -12
  9. package/lib/client/SubscriptionUsageBadge.d.ts +1 -1
  10. package/lib/client/SubscriptionUsageBadge.js +1 -13
  11. package/lib/client/SubscriptionsSection.d.ts +2 -0
  12. package/lib/client/SubscriptionsSection.js +10 -4
  13. package/lib/client/locales.d.ts +12 -32
  14. package/lib/client/locales.js +14 -34
  15. package/lib/client/model-filter.d.ts +37 -0
  16. package/lib/client/model-filter.js +45 -0
  17. package/lib/client/subscription-card-styles.d.ts +1 -1
  18. package/lib/client/subscription-card-styles.js +1 -1
  19. package/lib/client/usage-window-filter.d.ts +7 -0
  20. package/lib/client/usage-window-filter.js +12 -0
  21. package/lib/client.js +374 -584
  22. package/lib/client.js.map +1 -1
  23. package/lib/index.js +249 -3322
  24. package/lib/provider-settings.d.ts +5 -0
  25. package/lib/provider-settings.js +21 -0
  26. package/lib/providers/ollama-settings.d.ts +1 -1
  27. package/lib/providers/ollama-settings.js +1 -1
  28. package/lib/translate/antigravity.js +10 -2
  29. package/package.json +2 -7
  30. package/lib/client/CursorCard.d.ts +0 -9
  31. package/lib/client/CursorCard.js +0 -151
  32. package/lib/providers/cursor-adapter.d.ts +0 -50
  33. package/lib/providers/cursor-adapter.js +0 -304
  34. package/lib/providers/cursor-auth.d.ts +0 -43
  35. package/lib/providers/cursor-auth.js +0 -221
  36. package/lib/providers/cursor-model-settings.d.ts +0 -15
  37. package/lib/providers/cursor-model-settings.js +0 -60
  38. package/lib/providers/cursor-usage.d.ts +0 -9
  39. package/lib/providers/cursor-usage.js +0 -131
  40. package/vendor/cursor/LICENSE +0 -21
  41. package/vendor/cursor/index.d.ts +0 -18
  42. package/vendor/cursor/index.js +0 -3574
  43. package/vendor/cursor/proto.js +0 -254
package/lib/client.js CHANGED
@@ -56,7 +56,7 @@ const en = {
56
56
  accountsCatalogUnavailable: "Model discovery is currently unavailable. Saved model selections are preserved.",
57
57
  modelsPartialSave: "Some reasoning defaults were saved. Remaining changes are still in the draft; retry to finish.",
58
58
  modelsEdit: "Edit model list",
59
- modelsHint: "Configure model visibility, default reasoning effort, context and tools here; Save changes below submits them together with the account settings. Hidden models remain usable by existing sessions; tool changes apply to new sessions.",
59
+ modelsHint: "Configure model visibility, default reasoning effort, subagent speed, context and tools here; Save changes below submits them together with the account settings. Hidden models remain usable by existing sessions; tool changes apply to new sessions.",
60
60
  modelsAutomatic: "Automatically show all models, including new models",
61
61
  modelsSelectAll: "Select all",
62
62
  modelsSelectNone: "Clear selection",
@@ -64,6 +64,8 @@ const en = {
64
64
  modelsContextBounds: "Default {default} · Maximum {max}",
65
65
  modelsContextHint: "Leave blank to follow the provider. The requested window is capped by the account’s advertised maximum; account pools use the smallest member window. This controls local history and compaction, not the API’s capacity.",
66
66
  modelsContextInvalid: "Enter a positive whole number of tokens for {model}.",
67
+ modelsSubagentSpeed: "Subagent default speed",
68
+ modelsSubagentSpeedHint: "Applies to subsequent subagent requests using this model, regardless of the parent model. Main conversations keep their own Speed setting. Fast requires model support.",
67
69
  modelsTools: "Provider tools",
68
70
  modelsToolsHint: "Changes apply only to sessions created after saving. Existing sessions keep their tools. Shared tools remain available if any supporting provider is enabled.",
69
71
  modelsImage: "Image generation",
@@ -113,6 +115,7 @@ const en = {
113
115
  usageRefresh: "Refresh",
114
116
  usageLoading: "Loading usage…",
115
117
  usageEmpty: "No usage windows reported.",
118
+ usageNoVisibleModels: "No usage windows for the models visible in the picker.",
116
119
  usageUnsupported: "This endpoint has no usage surface.",
117
120
  usageError: "Usage lookup failed: {message}",
118
121
  usageSession: "5-hour window",
@@ -180,22 +183,6 @@ const en = {
180
183
  externalUsageApiKey: "API key",
181
184
  externalUsageConfigure: "No API key found at {ref}. Add one in Settings → Models.",
182
185
  externalUsageUnavailable: "Usage status unavailable: {message}",
183
- cursorTitle: "Cursor",
184
- cursorOpenLogin: "Open Cursor sign-in",
185
- cursorWaiting: "Waiting for Cursor sign-in…",
186
- cursorConnected: "Connected",
187
- cursorManageTitle: "Manage Cursor",
188
- cursorManageSignIn: "Sign in to see the models available to this Cursor account.",
189
- cursorAccountsHint: "Cursor uses one connected account. Choose which of its models appear in the model picker.",
190
- cursorManageHint: "Choose model visibility here. Refresh fetches the current models from Cursor; Save changes updates the model picker.",
191
- cursorFilterModels: "Filter models",
192
- cursorModelsLoading: "Loading Cursor models…",
193
- cursorModelsError: "Could not load Cursor models: {message}",
194
- cursorModelsCount: "{count} models available",
195
- cursorIncluded: "Included usage",
196
- cursorModels: "Cursor Models",
197
- cursorOtherModels: "Other Models",
198
- cursorIncludedRequests: "Included requests",
199
186
  modelDefaultsTitle: "Default reasoning effort",
200
187
  modelDefaultsHint: "The model picker preselects this level when you switch to the model; models without levels always follow the provider.",
201
188
  modelDefaultsFollowProvider: "Follow provider",
@@ -211,6 +198,9 @@ const en = {
211
198
  modelDefaultsSummaryEmpty: "No model advertises reasoning levels",
212
199
  modelDefaultsFilterPlaceholder: "Filter models",
213
200
  modelDefaultsFilterEmpty: "No model matches “{query}”.",
201
+ modelDefaultsNoModels: "This provider reports no models.",
202
+ modelDefaultsNoAccount: "No connected accounts. Connect one on the provider card first.",
203
+ modelDefaultsDiscoveryFailed: "Model discovery failed or timed out. Use Refresh to try again.",
214
204
  generating: "Generating image…",
215
205
  image: "image",
216
206
  viewImage: "View image",
@@ -296,7 +286,7 @@ const zh = {
296
286
  accountsCatalogUnavailable: "暂时无法获取模型目录,已保存的模型选择会被保留。",
297
287
  modelsPartialSave: "部分推理档已保存,其余更改仍保留在草稿中,请重试完成保存。",
298
288
  modelsEdit: "编辑模型列表",
299
- modelsHint: "在此配置模型显示、默认推理档、上下文与工具,底部的「保存更改」会连同账号设置一起提交。隐藏模型不影响已有会话;工具开关对新建会话生效。",
289
+ modelsHint: "在此配置模型显示、默认推理档、子代理速度、上下文与工具,底部的「保存更改」会连同账号设置一起提交。隐藏模型不影响已有会话;工具开关对新建会话生效。",
300
290
  modelsAutomatic: "自动显示全部模型(包含以后新增的模型)",
301
291
  modelsSelectAll: "全选",
302
292
  modelsSelectNone: "清空选择",
@@ -304,6 +294,8 @@ const zh = {
304
294
  modelsContextBounds: "默认 {default} · 最大 {max}",
305
295
  modelsContextHint: "留空跟随服务商。配置值按账号返回的最大窗口限制;账号池取各成员的最小窗口。此设置控制本地历史保留和压缩时机,不会扩大 API 本身的容量。",
306
296
  modelsContextInvalid: "请为 {model} 输入正整数 token 数。",
297
+ modelsSubagentSpeed: "子代理默认速度",
298
+ modelsSubagentSpeedHint: "对使用此模型的子代理后续请求生效,与父会话模型无关。主会话仍使用自己的速度设置;快速档仅在模型支持时生效。",
307
299
  modelsTools: "Provider 工具",
308
300
  modelsToolsHint: "仅对保存后新建的会话生效,已有会话保留原工具。任一支持的服务商启用共享工具时,该工具仍会显示。",
309
301
  modelsImage: "图片生成",
@@ -353,6 +345,7 @@ const zh = {
353
345
  usageRefresh: "刷新",
354
346
  usageLoading: "用量加载中…",
355
347
  usageEmpty: "服务商未返回任何用量窗口。",
348
+ usageNoVisibleModels: "选择器中的可见模型没有任何用量窗口。",
356
349
  usageUnsupported: "该端点不提供用量查询。",
357
350
  usageError: "用量查询失败:{message}",
358
351
  usageSession: "5 小时窗口",
@@ -420,22 +413,6 @@ const zh = {
420
413
  externalUsageApiKey: "API 密钥",
421
414
  externalUsageConfigure: "未在 {ref} 找到 API 密钥。请在「设置 → 模型」中添加。",
422
415
  externalUsageUnavailable: "无法获取用量状态:{message}",
423
- cursorTitle: "Cursor",
424
- cursorOpenLogin: "打开 Cursor 登录页面",
425
- cursorWaiting: "等待 Cursor 登录…",
426
- cursorConnected: "已连接",
427
- cursorManageTitle: "管理 Cursor",
428
- cursorManageSignIn: "登录后可查看此 Cursor 账号可用的模型。",
429
- cursorAccountsHint: "Cursor 使用一个已连接账号。可在此选择模型选择器中显示的模型。",
430
- cursorManageHint: "在此选择模型是否显示。刷新可从 Cursor 获取当前模型;保存更改后更新模型选择器。",
431
- cursorFilterModels: "筛选模型",
432
- cursorModelsLoading: "正在加载 Cursor 模型…",
433
- cursorModelsError: "无法加载 Cursor 模型:{message}",
434
- cursorModelsCount: "可用模型:{count} 个",
435
- cursorIncluded: "套餐内用量",
436
- cursorModels: "Cursor 模型",
437
- cursorOtherModels: "其他模型",
438
- cursorIncludedRequests: "套餐内请求",
439
416
  modelDefaultsTitle: "默认推理档",
440
417
  modelDefaultsHint: "切换到该模型时,模型选择器会预选此档位;没有推理档的模型始终跟随服务商默认。",
441
418
  modelDefaultsFollowProvider: "跟随服务商",
@@ -451,6 +428,9 @@ const zh = {
451
428
  modelDefaultsSummaryEmpty: "没有模型声明推理档",
452
429
  modelDefaultsFilterPlaceholder: "筛选模型",
453
430
  modelDefaultsFilterEmpty: "没有匹配「{query}」的模型。",
431
+ modelDefaultsNoModels: "这个服务商没有报告任何模型。",
432
+ modelDefaultsNoAccount: "还没有连接账号。请先在卡片上连接一个账号。",
433
+ modelDefaultsDiscoveryFailed: "模型列表发现失败或超时。可以点「刷新」重试。",
454
434
  generating: "正在生成图片…",
455
435
  image: "图片",
456
436
  viewImage: "查看图片",
@@ -527,6 +507,19 @@ function resetActionBlock(usage, now = Date.now()) {
527
507
  if (!usage.resetCredits.some((c) => c.id && (c.expiresAt === void 0 || c.expiresAt > now))) return "resetUseRefresh";
528
508
  }
529
509
 
510
+ //#endregion
511
+ //#region src/client/usage-window-filter.ts
512
+ /**
513
+ * Keep model-scoped Google quotas aligned with the saved model-picker selection.
514
+ * Account-wide windows and other providers are unaffected; an absent selection
515
+ * follows discovery, while an empty selection hides every model-scoped window.
516
+ */
517
+ function visibleUsageWindows(provider, windows, visibleModels) {
518
+ if (windows === void 0) return [];
519
+ if (provider !== "antigravity" || visibleModels === void 0) return windows;
520
+ return windows.filter((window$1) => !window$1.scope || visibleModels.includes(window$1.scope));
521
+ }
522
+
530
523
  //#endregion
531
524
  //#region src/client/subscriptions-rpc.ts
532
525
  /**
@@ -610,6 +603,43 @@ function mergeAccountChanges(latest, changes) {
610
603
  };
611
604
  }
612
605
 
606
+ //#endregion
607
+ //#region src/client/model-filter.ts
608
+ /** Distinguish an empty provider from a query that filtered out every row. */
609
+ function modelListState(total, matched) {
610
+ if (total === 0) return "provider-empty";
611
+ return matched === 0 ? "filter-empty" : "rows";
612
+ }
613
+ /**
614
+ * Retain saved model ids when discovery returns no rows. A temporary catalog
615
+ * failure must not hide the visibility or subagent-speed settings they edit.
616
+ */
617
+ function savedModelIds(visibleModels, subagentSpeeds) {
618
+ return [...new Set([...visibleModels ?? [], ...Object.keys(subagentSpeeds ?? {})])];
619
+ }
620
+ /**
621
+ * Use account discovery evidence to explain an empty provider. Connected
622
+ * accounts with failed discovery need a retry, not another login prompt.
623
+ */
624
+ function modelEditorNotice(accounts) {
625
+ if (accounts === void 0) return "noModels";
626
+ if (accounts.length === 0) return "noAccount";
627
+ return accounts.every((account) => account.unavailable === true) ? "discoveryFailed" : "noModels";
628
+ }
629
+ /** Locale keys for the three empty states. */
630
+ const NOTICE_KEYS = {
631
+ noAccount: "modelDefaultsNoAccount",
632
+ discoveryFailed: "modelDefaultsDiscoveryFailed",
633
+ noModels: "modelDefaultsNoModels"
634
+ };
635
+ /** Combine discovered and saved rows, filter results, and discovery evidence. */
636
+ function modelEditorState(input) {
637
+ return {
638
+ listState: modelListState(input.discovered + input.saved, input.matched),
639
+ noticeKey: NOTICE_KEYS[modelEditorNotice(input.accounts)]
640
+ };
641
+ }
642
+
613
643
  //#endregion
614
644
  //#region src/client/ProviderModelEditor.tsx
615
645
  /** Providers whose runtime honours a local context-window override. */
@@ -655,7 +685,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
655
685
  setBusy(true);
656
686
  setError("");
657
687
  try {
658
- const data = await callSubscriptionsAuth(rpc, provider === "cursor-subscription" ? "cursorSettings" : "providerSettings", {
688
+ const data = await callSubscriptionsAuth(rpc, "providerSettings", {
659
689
  provider,
660
690
  force
661
691
  });
@@ -711,12 +741,18 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
711
741
  ]);
712
742
  const allModels = catalog?.models ?? [];
713
743
  const known = new Set(allModels.map((model) => model.id));
714
- const missing = (draft.visibleModels ?? []).filter((id) => !known.has(id)).map((id) => ({
744
+ const missing = savedModelIds(draft.visibleModels, draft.subagentSpeeds).filter((id) => !known.has(id)).map((id) => ({
715
745
  id,
716
746
  name: id
717
747
  }));
718
748
  const models = [...allModels, ...missing].filter((model) => `${model.name} ${model.id}`.toLowerCase().includes(query.trim().toLowerCase()));
719
- const selected = new Set(draft.visibleModels ?? allModels.map((model) => model.id));
749
+ const editorState = modelEditorState({
750
+ discovered: allModels.length,
751
+ saved: missing.length,
752
+ matched: models.length,
753
+ accounts: catalog?.accounts
754
+ });
755
+ const selected = new Set(draft.visibleModels ?? [...allModels, ...missing].map((model) => model.id));
720
756
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
721
757
  style: {
722
758
  borderTop: border$2,
@@ -735,7 +771,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
735
771
  children: [
736
772
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
737
773
  className: "dsh-subscription-hint",
738
- children: t(provider === "cursor-subscription" ? "cursorManageHint" : "modelsHint")
774
+ children: t("modelsHint")
739
775
  }),
740
776
  error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
741
777
  role: "alert",
@@ -756,7 +792,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
756
792
  children: t("modelDefaultsLoading")
757
793
  })]
758
794
  }),
759
- catalog && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
795
+ !busy && catalog && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
760
796
  disabled: busy || disabled,
761
797
  style: {
762
798
  border: 0,
@@ -781,7 +817,10 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
781
817
  " ",
782
818
  t("modelsAutomatic")
783
819
  ] }),
784
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
820
+ editorState.listState === "provider-empty" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
821
+ className: "dsh-subscription-hint",
822
+ children: t(editorState.noticeKey)
823
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
785
824
  style: actions$2,
786
825
  children: [
787
826
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -808,8 +847,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
808
847
  children: t("modelsSelectNone")
809
848
  })
810
849
  ]
811
- }),
812
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
850
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
813
851
  style: {
814
852
  maxHeight: 360,
815
853
  overflowY: "auto",
@@ -823,87 +861,118 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
823
861
  display: "grid",
824
862
  gap: 8
825
863
  },
826
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
827
- style: { overflowWrap: "anywhere" },
828
- children: [
829
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
830
- type: "checkbox",
831
- checked: selected.has(model.id),
832
- onChange: (event) => {
833
- const next = new Set(selected);
834
- if (event.target.checked) next.add(model.id);
835
- else next.delete(model.id);
836
- edit({
837
- ...draft,
838
- visibleModels: [...next]
839
- });
840
- }
841
- }),
842
- " ",
843
- model.name,
844
- !known.has(model.id) && ` (${t("modelsUnavailable")})`
845
- ]
846
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
847
- style: actions$2,
848
- children: [(model.efforts?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
849
- style: actions$2,
850
- children: [t("modelDefaultsTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
851
- "aria-label": `${model.name} ${t("modelDefaultsTitle")}`,
852
- value: efforts[model.id] ?? "",
853
- onChange: (event) => {
854
- setEfforts({
855
- ...efforts,
856
- [model.id]: event.target.value
857
- });
858
- setDirty(true);
859
- },
860
- children: [
861
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
862
- value: "",
863
- children: t("modelDefaultsFollowProvider")
864
- }),
865
- model.configured && !model.efforts?.some((effort) => effort.id === model.configured) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
866
- value: model.configured,
867
- disabled: true,
868
- children: [
869
- model.configured,
870
- " (",
871
- t("modelsUnavailable"),
872
- ")"
873
- ]
874
- }),
875
- model.efforts?.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
876
- value: effort.id,
877
- children: effort.name
878
- }, effort.id))
879
- ]
880
- })]
881
- }), supportsContext(provider) && model.maxContextWindow !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
864
+ children: [
865
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
866
+ style: { overflowWrap: "anywhere" },
867
+ children: [
868
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
869
+ type: "checkbox",
870
+ checked: selected.has(model.id),
871
+ onChange: (event) => {
872
+ const next = new Set(selected);
873
+ if (event.target.checked) next.add(model.id);
874
+ else next.delete(model.id);
875
+ edit({
876
+ ...draft,
877
+ visibleModels: [...next]
878
+ });
879
+ }
880
+ }),
881
+ " ",
882
+ model.name,
883
+ !known.has(model.id) && ` (${t("modelsUnavailable")})`
884
+ ]
885
+ }),
886
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
882
887
  style: actions$2,
883
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
888
+ children: [(model.efforts?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
884
889
  style: actions$2,
885
- children: [t("modelsContext"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
886
- style: { width: 140 },
887
- inputMode: "numeric",
888
- value: contexts[model.id] ?? "",
889
- "aria-label": `${model.name} ${t("modelsContext")}`,
890
- placeholder: String(model.defaultContextWindow),
890
+ children: [t("modelDefaultsTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
891
+ "aria-label": `${model.name} ${t("modelDefaultsTitle")}`,
892
+ value: efforts[model.id] ?? "",
891
893
  onChange: (event) => {
892
- setContexts({
893
- ...contexts,
894
+ setEfforts({
895
+ ...efforts,
894
896
  [model.id]: event.target.value
895
897
  });
896
898
  setDirty(true);
897
- }
899
+ },
900
+ children: [
901
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
902
+ value: "",
903
+ children: t("modelDefaultsFollowProvider")
904
+ }),
905
+ model.configured && !model.efforts?.some((effort) => effort.id === model.configured) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
906
+ value: model.configured,
907
+ disabled: true,
908
+ children: [
909
+ model.configured,
910
+ " (",
911
+ t("modelsUnavailable"),
912
+ ")"
913
+ ]
914
+ }),
915
+ model.efforts?.map((effort) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
916
+ value: effort.id,
917
+ children: effort.name
918
+ }, effort.id))
919
+ ]
898
920
  })]
899
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("modelsContextBounds", {
900
- default: model.defaultContextWindow,
901
- max: model.maxContextWindow
902
- }) })]
903
- })]
904
- })]
921
+ }), supportsContext(provider) && model.maxContextWindow !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
922
+ style: actions$2,
923
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
924
+ style: actions$2,
925
+ children: [t("modelsContext"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
926
+ style: { width: 140 },
927
+ inputMode: "numeric",
928
+ value: contexts[model.id] ?? "",
929
+ "aria-label": `${model.name} ${t("modelsContext")}`,
930
+ placeholder: String(model.defaultContextWindow),
931
+ onChange: (event) => {
932
+ setContexts({
933
+ ...contexts,
934
+ [model.id]: event.target.value
935
+ });
936
+ setDirty(true);
937
+ }
938
+ })]
939
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("modelsContextBounds", {
940
+ default: model.defaultContextWindow,
941
+ max: model.maxContextWindow
942
+ }) })]
943
+ })]
944
+ }),
945
+ provider === "codex" && (model.fastTier === true || Object.hasOwn(draft.subagentSpeeds ?? {}, model.id)) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
946
+ style: {
947
+ display: "grid",
948
+ gap: 6
949
+ },
950
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
951
+ style: actions$2,
952
+ children: [t("modelsSubagentSpeed"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
953
+ "aria-label": `${model.name} ${t("modelsSubagentSpeed")}`,
954
+ value: Object.hasOwn(draft.subagentSpeeds ?? {}, model.id) ? draft.subagentSpeeds[model.id] : "standard",
955
+ onChange: (event) => edit({
956
+ ...draft,
957
+ subagentSpeeds: {
958
+ ...draft.subagentSpeeds,
959
+ [model.id]: event.target.value
960
+ }
961
+ }),
962
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
963
+ value: "standard",
964
+ children: t("speedStandard")
965
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
966
+ value: "fast",
967
+ disabled: !model.fastTier,
968
+ children: [t("speedFast"), !model.fastTier && ` (${t("modelsUnavailable")})`]
969
+ })]
970
+ })]
971
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("modelsSubagentSpeedHint") })]
972
+ })
973
+ ]
905
974
  }, model.id)), models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("modelDefaultsFilterEmpty", { query }) })]
906
- }),
975
+ })] }),
907
976
  supportsContext(provider) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: t("modelsContextHint") }),
908
977
  catalog.tools.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
909
978
  style: {
@@ -1193,7 +1262,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1193
1262
  let current = true;
1194
1263
  setLoading(true);
1195
1264
  setError("");
1196
- callSubscriptionsAuth(rpc, provider === "cursor-subscription" ? "cursorSettings" : "providerSettings", { provider }).then((data) => {
1265
+ callSubscriptionsAuth(rpc, "providerSettings", { provider }).then((data) => {
1197
1266
  if (current) {
1198
1267
  setCatalog(data);
1199
1268
  setTtlDraft(data.settings.promptCacheTtl);
@@ -1232,7 +1301,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1232
1301
  setSaveError("");
1233
1302
  let savedEfforts = 0;
1234
1303
  try {
1235
- if (provider !== "cursor-subscription") for (const { model, effort } of models.efforts) {
1304
+ for (const { model, effort } of models.efforts) {
1236
1305
  await callSubscriptionsAuth(rpc, "setModelDefault", {
1237
1306
  provider,
1238
1307
  model,
@@ -1241,18 +1310,17 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1241
1310
  savedEfforts++;
1242
1311
  if (!alive.current) return;
1243
1312
  }
1244
- const latest = await callSubscriptionsAuth(rpc, provider === "cursor-subscription" ? "cursorSettings" : "providerSettings", { provider });
1313
+ const latest = await callSubscriptionsAuth(rpc, "providerSettings", { provider });
1245
1314
  if (!alive.current) return;
1246
- if (provider === "cursor-subscription") await callSubscriptionsAuth(rpc, "cursorSetSettings", { settings: models.settings ?? latest.settings });
1247
- else await callSubscriptionsAuth(rpc, "setProviderSettings", {
1315
+ await callSubscriptionsAuth(rpc, "setProviderSettings", {
1248
1316
  provider,
1249
1317
  settings: mergeAccountChanges(mergePromptCacheTtl(models.settings === void 0 ? latest.settings : mergeLatestAccounts(models.settings, latest.settings), ttlDirty ? ttlDraft : latest.settings.promptCacheTtl), changes)
1250
1318
  });
1251
1319
  if (alive.current) onClose();
1252
1320
  } catch (error$1) {
1253
1321
  if (alive.current) {
1254
- const message$3 = error$1 instanceof Error ? error$1.message : String(error$1);
1255
- setSaveError((savedEfforts ? t("modelsPartialSave") + " " : "") + t("accountsSaveFailed", { message: message$3 }));
1322
+ const message$2 = error$1 instanceof Error ? error$1.message : String(error$1);
1323
+ setSaveError((savedEfforts ? t("modelsPartialSave") + " " : "") + t("accountsSaveFailed", { message: message$2 }));
1256
1324
  }
1257
1325
  } finally {
1258
1326
  saveLock.current = false;
@@ -1300,7 +1368,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1300
1368
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1301
1369
  id: description,
1302
1370
  className: "dsh-subscription-hint",
1303
- children: t(provider === "cursor-subscription" ? "cursorAccountsHint" : "accountsHint")
1371
+ children: t("accountsHint")
1304
1372
  }),
1305
1373
  error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1306
1374
  role: "alert",
@@ -1324,190 +1392,173 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1324
1392
  margin: 0,
1325
1393
  padding: 0
1326
1394
  },
1327
- children: [
1328
- catalog.accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1329
- className: "dsh-subscription-hint",
1330
- children: t(provider === "cursor-subscription" ? "cursorManageSignIn" : "accountsEmpty")
1331
- }),
1332
- provider === "cursor-subscription" && catalog.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
1395
+ children: [catalog.accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1396
+ className: "dsh-subscription-hint",
1397
+ children: t("accountsEmpty")
1398
+ }), catalog.accounts.map((account) => {
1399
+ const preferences = changes[account.key] ?? catalog.settings.accounts?.[account.key] ?? {};
1400
+ const selected = accountPoolSelection(preferences, account.models);
1401
+ const models = accountModelRows(account, preferences);
1402
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
1333
1403
  style: {
1404
+ ...stack$1,
1334
1405
  border: border$1,
1335
1406
  borderRadius: "var(--dsw-radius-lg, 12px)",
1336
- padding: 14
1407
+ padding: 14,
1408
+ margin: 0
1337
1409
  },
1338
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
1339
- style: { padding: "0 6px" },
1340
- children: name
1341
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1342
- className: "dsh-subscription-hint",
1343
- children: t("cursorConnected")
1344
- })]
1345
- }),
1346
- provider !== "cursor-subscription" && catalog.accounts.map((account) => {
1347
- const preferences = changes[account.key] ?? catalog.settings.accounts?.[account.key] ?? {};
1348
- const selected = accountPoolSelection(preferences, account.models);
1349
- const models = accountModelRows(account, preferences);
1350
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
1351
- style: {
1352
- ...stack$1,
1353
- border: border$1,
1354
- borderRadius: "var(--dsw-radius-lg, 12px)",
1355
- padding: 14,
1356
- margin: 0
1357
- },
1358
- children: [
1359
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
1360
- style: {
1361
- padding: "0 6px",
1362
- overflowWrap: "anywhere",
1363
- maxWidth: "100%"
1364
- },
1365
- children: account.label
1366
- }),
1367
- account.unavailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1368
- className: "dsh-subscription-hint",
1369
- children: t("accountsCatalogUnavailable")
1410
+ children: [
1411
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
1412
+ style: {
1413
+ padding: "0 6px",
1414
+ overflowWrap: "anywhere",
1415
+ maxWidth: "100%"
1416
+ },
1417
+ children: account.label
1418
+ }),
1419
+ account.unavailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1420
+ className: "dsh-subscription-hint",
1421
+ children: t("accountsCatalogUnavailable")
1422
+ }),
1423
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1424
+ style: {
1425
+ ...stack$1,
1426
+ gap: 6
1427
+ },
1428
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1429
+ className: "dsh-subscription-label",
1430
+ children: t("accountsAlias")
1431
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1432
+ value: preferences.alias ?? "",
1433
+ placeholder: account.label,
1434
+ onChange: (event) => {
1435
+ const next = { ...preferences };
1436
+ if (event.target.value.trim()) next.alias = event.target.value;
1437
+ else delete next.alias;
1438
+ edit(account.key, next);
1439
+ }
1440
+ })]
1441
+ }),
1442
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1444
+ type: "checkbox",
1445
+ checked: preferences.poolEnabled !== false,
1446
+ onChange: (event) => edit(account.key, {
1447
+ ...preferences,
1448
+ poolEnabled: event.target.checked
1449
+ })
1370
1450
  }),
1371
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1372
- style: {
1373
- ...stack$1,
1374
- gap: 6
1375
- },
1376
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1377
- className: "dsh-subscription-label",
1378
- children: t("accountsAlias")
1379
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1380
- value: preferences.alias ?? "",
1381
- placeholder: account.label,
1382
- onChange: (event) => {
1383
- const next = { ...preferences };
1384
- if (event.target.value.trim()) next.alias = event.target.value;
1385
- else delete next.alias;
1386
- edit(account.key, next);
1387
- }
1388
- })]
1451
+ " ",
1452
+ t("accountsPoolEnabled")
1453
+ ] }),
1454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1455
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1456
+ type: "checkbox",
1457
+ checked: preferences.independentEntry === true,
1458
+ onChange: (event) => edit(account.key, {
1459
+ ...preferences,
1460
+ independentEntry: event.target.checked
1461
+ })
1389
1462
  }),
1390
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1391
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1392
- type: "checkbox",
1393
- checked: preferences.poolEnabled !== false,
1394
- onChange: (event) => edit(account.key, {
1395
- ...preferences,
1396
- poolEnabled: event.target.checked
1397
- })
1398
- }),
1463
+ " ",
1464
+ t("accountsIndependent")
1465
+ ] }),
1466
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1467
+ className: "dsh-subscription-hint",
1468
+ children: t("accountsIndependentHint")
1469
+ }),
1470
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
1471
+ style: {
1472
+ cursor: "pointer",
1473
+ fontSize: 13
1474
+ },
1475
+ children: [
1476
+ t("accountsModels"),
1477
+ " ·",
1399
1478
  " ",
1400
- t("accountsPoolEnabled")
1401
- ] }),
1402
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1403
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1404
- type: "checkbox",
1405
- checked: preferences.independentEntry === true,
1406
- onChange: (event) => edit(account.key, {
1407
- ...preferences,
1408
- independentEntry: event.target.checked
1409
- })
1479
+ preferences.poolModels === void 0 ? t("accountsModelsAll") : t("accountsModelsCount", { count: preferences.poolModels.length })
1480
+ ]
1481
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1482
+ style: {
1483
+ ...stack$1,
1484
+ marginTop: 12
1485
+ },
1486
+ children: [
1487
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1488
+ className: "dsh-subscription-hint",
1489
+ children: t("accountsModelsHint")
1410
1490
  }),
1411
- " ",
1412
- t("accountsIndependent")
1413
- ] }),
1414
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1415
- className: "dsh-subscription-hint",
1416
- children: t("accountsIndependentHint")
1417
- }),
1418
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
1419
- style: {
1420
- cursor: "pointer",
1421
- fontSize: 13
1422
- },
1423
- children: [
1424
- t("accountsModels"),
1425
- " ·",
1426
- " ",
1427
- preferences.poolModels === void 0 ? t("accountsModelsAll") : t("accountsModelsCount", { count: preferences.poolModels.length })
1428
- ]
1429
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1430
- style: {
1431
- ...stack$1,
1432
- marginTop: 12
1433
- },
1434
- children: [
1435
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1436
- className: "dsh-subscription-hint",
1437
- children: t("accountsModelsHint")
1491
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1492
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1493
+ type: "checkbox",
1494
+ checked: preferences.poolModels === void 0,
1495
+ onChange: (event) => {
1496
+ const next = { ...preferences };
1497
+ if (event.target.checked) delete next.poolModels;
1498
+ else next.poolModels = account.models.map((model) => model.id);
1499
+ edit(account.key, next);
1500
+ }
1438
1501
  }),
1439
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
1440
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1441
- type: "checkbox",
1442
- checked: preferences.poolModels === void 0,
1443
- onChange: (event) => {
1444
- const next = { ...preferences };
1445
- if (event.target.checked) delete next.poolModels;
1446
- else next.poolModels = account.models.map((model) => model.id);
1447
- edit(account.key, next);
1448
- }
1502
+ " ",
1503
+ t("accountsModelsAutomatic")
1504
+ ] }),
1505
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1506
+ style: actions$1,
1507
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1508
+ type: "button",
1509
+ onClick: () => edit(account.key, {
1510
+ ...preferences,
1511
+ poolModels: models.map((model) => model.id)
1449
1512
  }),
1450
- " ",
1451
- t("accountsModelsAutomatic")
1452
- ] }),
1453
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1454
- style: actions$1,
1455
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1456
- type: "button",
1457
- onClick: () => edit(account.key, {
1458
- ...preferences,
1459
- poolModels: models.map((model) => model.id)
1460
- }),
1461
- children: t("modelsSelectAll")
1462
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1463
- type: "button",
1464
- onClick: () => edit(account.key, {
1465
- ...preferences,
1466
- poolModels: []
1513
+ children: t("modelsSelectAll")
1514
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1515
+ type: "button",
1516
+ onClick: () => edit(account.key, {
1517
+ ...preferences,
1518
+ poolModels: []
1519
+ }),
1520
+ children: t("modelsSelectNone")
1521
+ })]
1522
+ }),
1523
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1524
+ style: {
1525
+ ...stack$1,
1526
+ gap: 8,
1527
+ maxHeight: 240,
1528
+ overflowY: "auto"
1529
+ },
1530
+ children: [models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1531
+ style: { overflowWrap: "anywhere" },
1532
+ children: [
1533
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1534
+ type: "checkbox",
1535
+ checked: selected.has(model.id),
1536
+ onChange: (event) => {
1537
+ const next = new Set(selected);
1538
+ if (event.target.checked) next.add(model.id);
1539
+ else next.delete(model.id);
1540
+ edit(account.key, {
1541
+ ...preferences,
1542
+ poolModels: [...next]
1543
+ });
1544
+ }
1467
1545
  }),
1468
- children: t("modelsSelectNone")
1469
- })]
1470
- }),
1471
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1472
- style: {
1473
- ...stack$1,
1474
- gap: 8,
1475
- maxHeight: 240,
1476
- overflowY: "auto"
1477
- },
1478
- children: [models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1479
- style: { overflowWrap: "anywhere" },
1480
- children: [
1481
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1482
- type: "checkbox",
1483
- checked: selected.has(model.id),
1484
- onChange: (event) => {
1485
- const next = new Set(selected);
1486
- if (event.target.checked) next.add(model.id);
1487
- else next.delete(model.id);
1488
- edit(account.key, {
1489
- ...preferences,
1490
- poolModels: [...next]
1491
- });
1492
- }
1493
- }),
1494
- " ",
1495
- model.name,
1496
- model.unavailable && ` (${t("modelsUnavailable")})`
1497
- ]
1498
- }, model.id)), models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1499
- className: "dsh-subscription-hint",
1500
- children: t("accountsNoModels")
1501
- })]
1502
- })
1503
- ]
1504
- })] })
1505
- ]
1506
- }, account.key);
1507
- })
1508
- ]
1546
+ " ",
1547
+ model.name,
1548
+ model.unavailable && ` (${t("modelsUnavailable")})`
1549
+ ]
1550
+ }, model.id)), models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1551
+ className: "dsh-subscription-hint",
1552
+ children: t("accountsNoModels")
1553
+ })]
1554
+ })
1555
+ ]
1556
+ })] })
1557
+ ]
1558
+ }, account.key);
1559
+ })]
1509
1560
  }),
1510
- (provider !== "cursor-subscription" || (catalog?.accounts.length ?? 0) > 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderModelEditor, {
1561
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderModelEditor, {
1511
1562
  ref: editor,
1512
1563
  provider,
1513
1564
  rpc,
@@ -1602,7 +1653,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
1602
1653
 
1603
1654
  //#endregion
1604
1655
  //#region src/client/subscription-card-styles.ts
1605
- /** Shared visual language for OAuth, Cursor, and built-in provider cards. */
1656
+ /** Shared visual language for OAuth and built-in provider cards. */
1606
1657
  const subscriptionCardStyles = {
1607
1658
  card: {
1608
1659
  border: "1px solid var(--dsw-alias-border-l2)",
@@ -2185,250 +2236,6 @@ function ExternalUsageCards({ rpc, t }) {
2185
2236
  }) });
2186
2237
  }
2187
2238
 
2188
- //#endregion
2189
- //#region src/client/CursorCard.tsx
2190
- function message$2(error) {
2191
- return error instanceof Error ? error.message : String(error);
2192
- }
2193
- /** Cursor's single connected account, rendered with the same card and Manage dialog as the other providers. */
2194
- function CursorCard({ rpc, t }) {
2195
- const [status, setStatus] = (0, react.useState)();
2196
- const [usage, setUsage] = (0, react.useState)();
2197
- const [observedAt, setObservedAt] = (0, react.useState)();
2198
- const [usageStale, setUsageStale] = (0, react.useState)(false);
2199
- const [authorizeUrl, setAuthorizeUrl] = (0, react.useState)();
2200
- const [error, setError] = (0, react.useState)();
2201
- const [loading, setLoading] = (0, react.useState)(false);
2202
- const [manage, setManage] = (0, react.useState)(false);
2203
- const authenticated = (0, react.useRef)();
2204
- const refreshStatus = (0, react.useCallback)(async () => {
2205
- try {
2206
- const value = await callSubscriptionsAuth(rpc, "cursorStatus", {});
2207
- setStatus(value);
2208
- if (authenticated.current !== value.authenticated) {
2209
- authenticated.current = value.authenticated;
2210
- window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
2211
- }
2212
- if (value.authenticated) setAuthorizeUrl(void 0);
2213
- if (value.error) setError(value.error);
2214
- } catch (failure) {
2215
- setError(message$2(failure));
2216
- }
2217
- }, [rpc]);
2218
- const refreshUsage = (0, react.useCallback)(async () => {
2219
- setLoading(true);
2220
- try {
2221
- const value = await callSubscriptionsAuth(rpc, "cursorUsage", {});
2222
- setUsage(value);
2223
- setObservedAt(value.observedAt ?? Date.now());
2224
- setUsageStale(value.stale === true);
2225
- setError(void 0);
2226
- window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
2227
- } catch (failure) {
2228
- setError(message$2(failure));
2229
- setUsageStale(true);
2230
- } finally {
2231
- setLoading(false);
2232
- }
2233
- }, [rpc]);
2234
- (0, react.useEffect)(() => {
2235
- refreshStatus();
2236
- }, [refreshStatus]);
2237
- (0, react.useEffect)(() => {
2238
- if (status?.busy !== true) return;
2239
- const timer = setInterval(() => {
2240
- refreshStatus();
2241
- }, 2e3);
2242
- return () => clearInterval(timer);
2243
- }, [status?.busy, refreshStatus]);
2244
- (0, react.useEffect)(() => {
2245
- if (status?.authenticated === true) refreshUsage();
2246
- }, [status?.authenticated, refreshUsage]);
2247
- const login = async () => {
2248
- setError(void 0);
2249
- try {
2250
- const value = await callSubscriptionsAuth(rpc, "cursorLogin", {});
2251
- setAuthorizeUrl(value.authorizeUrl);
2252
- window.open(value.authorizeUrl, "_blank", "noopener");
2253
- await refreshStatus();
2254
- } catch (failure) {
2255
- setError(message$2(failure));
2256
- }
2257
- };
2258
- const cancel = async () => {
2259
- try {
2260
- await callSubscriptionsAuth(rpc, "cursorCancel", {});
2261
- setAuthorizeUrl(void 0);
2262
- await refreshStatus();
2263
- } catch (failure) {
2264
- setError(message$2(failure));
2265
- }
2266
- };
2267
- const logout = async () => {
2268
- if (!window.confirm(t("logoutAccountConfirm", {
2269
- account: "Cursor",
2270
- provider: "Cursor"
2271
- }))) return;
2272
- try {
2273
- await callSubscriptionsAuth(rpc, "cursorLogout", {});
2274
- setUsage(void 0);
2275
- setObservedAt(void 0);
2276
- setUsageStale(false);
2277
- await refreshStatus();
2278
- } catch (failure) {
2279
- setError(message$2(failure));
2280
- }
2281
- };
2282
- const connected = status?.authenticated === true;
2283
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2284
- style: subscriptionCardStyles.card,
2285
- children: [
2286
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2287
- style: subscriptionCardStyles.header,
2288
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
2289
- ...subscriptionCardStyles.dot,
2290
- background: status?.busy ? "var(--dsw-alias-state-warn-label)" : connected ? "var(--dsw-alias-state-success-primary)" : "var(--dsw-alias-label-dimmed)"
2291
- } }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2292
- style: subscriptionCardStyles.name,
2293
- children: t("cursorTitle")
2294
- })]
2295
- }),
2296
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2297
- style: subscriptionCardStyles.status,
2298
- children: status === void 0 ? t("checking") : status.busy ? t("loginInProgress") : connected ? t("loggedInCount", { count: 1 }) : t("notLoggedIn")
2299
- }),
2300
- error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2301
- style: subscriptionCardStyles.error,
2302
- children: error
2303
- }),
2304
- connected && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2305
- style: subscriptionCardStyles.account,
2306
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2307
- style: subscriptionCardStyles.accountHeader,
2308
- children: [
2309
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2310
- style: subscriptionCardStyles.defaultStar,
2311
- title: t("defaultBadge"),
2312
- children: "★"
2313
- }),
2314
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2315
- style: subscriptionCardStyles.accountName,
2316
- children: "Cursor"
2317
- }),
2318
- status.expiresAt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2319
- style: subscriptionCardStyles.status,
2320
- children: t("accountExpires", { date: new Date(status.expiresAt).toLocaleString() })
2321
- }),
2322
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2323
- type: "button",
2324
- style: {
2325
- ...subscriptionCardStyles.button,
2326
- marginLeft: "auto",
2327
- flexShrink: 0
2328
- },
2329
- onClick: () => {
2330
- logout();
2331
- },
2332
- children: t("logout")
2333
- })
2334
- ]
2335
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2336
- style: subscriptionCardStyles.usage,
2337
- children: [
2338
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2339
- style: subscriptionCardStyles.usageHeader,
2340
- children: [
2341
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2342
- style: subscriptionCardStyles.usageTitle,
2343
- children: t("usageTitle")
2344
- }),
2345
- usage?.plan !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2346
- style: subscriptionCardStyles.status,
2347
- children: t("usagePlan", { plan: usage.plan })
2348
- }),
2349
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2350
- type: "button",
2351
- style: subscriptionCardStyles.usageRefresh,
2352
- disabled: loading,
2353
- onClick: () => {
2354
- refreshUsage();
2355
- },
2356
- children: t("usageRefresh")
2357
- })
2358
- ]
2359
- }),
2360
- loading && usage === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2361
- style: subscriptionCardStyles.status,
2362
- children: t("usageLoading")
2363
- }),
2364
- usage?.windows?.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2365
- style: subscriptionCardStyles.status,
2366
- children: t("usageEmpty")
2367
- }),
2368
- usage?.windows?.map((window$1, index) => {
2369
- const percent = displayUsedPercent(window$1.usedPercent);
2370
- const label = window$1.scope === "Included" ? t("cursorIncluded") : window$1.scope === "Cursor Models" ? t("cursorModels") : window$1.scope === "Other Models" ? t("cursorOtherModels") : window$1.scope === "Included requests" ? t("cursorIncludedRequests") : window$1.scope ?? t("usageWindow");
2371
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2372
- style: subscriptionCardStyles.usageRow,
2373
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2374
- style: subscriptionCardStyles.usageMeta,
2375
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [percent === void 0 ? t("usageMeterInvalid") : `${percent}%`, window$1.resetsAt === void 0 ? "" : ` · ${t("usageResets", { date: new Date(window$1.resetsAt).toLocaleString() })}`] })]
2376
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageMeter, {
2377
- window: window$1,
2378
- t,
2379
- observedAt,
2380
- stale: usageStale
2381
- })]
2382
- }, index);
2383
- })
2384
- ]
2385
- })]
2386
- }),
2387
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2388
- style: subscriptionCardStyles.actions,
2389
- children: [
2390
- status?.authenticated === false && !status.busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2391
- type: "button",
2392
- style: subscriptionCardStyles.button,
2393
- onClick: () => {
2394
- login();
2395
- },
2396
- children: t("login")
2397
- }),
2398
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2399
- type: "button",
2400
- style: subscriptionCardStyles.button,
2401
- "aria-haspopup": "dialog",
2402
- onClick: () => setManage(true),
2403
- children: t("accountsManage")
2404
- }),
2405
- status?.busy === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2406
- type: "button",
2407
- style: subscriptionCardStyles.button,
2408
- onClick: () => {
2409
- cancel();
2410
- },
2411
- children: t("cancel")
2412
- })
2413
- ]
2414
- }),
2415
- status?.busy === true && authorizeUrl !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2416
- href: authorizeUrl,
2417
- target: "_blank",
2418
- rel: "noopener noreferrer",
2419
- children: t("cursorOpenLogin")
2420
- }),
2421
- manage && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProviderAccountManager, {
2422
- provider: "cursor-subscription",
2423
- name: "Cursor",
2424
- rpc,
2425
- t,
2426
- onClose: () => setManage(false)
2427
- })
2428
- ]
2429
- });
2430
- }
2431
-
2432
2239
  //#endregion
2433
2240
  //#region src/client/ollama-draft.ts
2434
2241
  /**
@@ -3545,15 +3352,15 @@ function showsResetCredits(provider, credits) {
3545
3352
  return (credits?.length ?? 0) > 0;
3546
3353
  }
3547
3354
  /** The error line the settings card mounts. Claude never interpolates provider text. */
3548
- function ResetCreditsErrorLine({ provider, message: message$3, t }) {
3355
+ function ResetCreditsErrorLine({ provider, message: message$2, t }) {
3549
3356
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3550
3357
  style: subscriptionCardStyles.error,
3551
- children: resetCreditsErrorText(provider, message$3, t)
3358
+ children: resetCreditsErrorText(provider, message$2, t)
3552
3359
  });
3553
3360
  }
3554
3361
  /** Fixed sentence for Claude. Codex may include the lookup message; Claude must not. */
3555
- function resetCreditsErrorText(provider, message$3, t) {
3556
- return provider === "claude" ? t("resetCreditsErrorFixed") : t("resetCreditsError", { message: message$3 });
3362
+ function resetCreditsErrorText(provider, message$2, t) {
3363
+ return provider === "claude" ? t("resetCreditsErrorFixed") : t("resetCreditsError", { message: message$2 });
3557
3364
  }
3558
3365
  const summaryStyle = {
3559
3366
  ...subscriptionCardStyles.usageMeta,
@@ -4089,12 +3896,12 @@ function SubscriptionsSection(props) {
4089
3896
  const usageInflightRef = (0, react.useRef)(/* @__PURE__ */ new Map());
4090
3897
  const usageRosterSignatureRef = (0, react.useRef)();
4091
3898
  const [managedProvider, setManagedProvider] = (0, react.useState)();
4092
- const setProviderError = (0, react.useCallback)((provider, message$3) => {
3899
+ const setProviderError = (0, react.useCallback)((provider, message$2) => {
4093
3900
  if (!mountedRef.current) return;
4094
3901
  setErrors((prev) => {
4095
3902
  const next = { ...prev };
4096
- if (message$3 === void 0) delete next[provider];
4097
- else next[provider] = message$3;
3903
+ if (message$2 === void 0) delete next[provider];
3904
+ else next[provider] = message$2;
4098
3905
  return next;
4099
3906
  });
4100
3907
  }, []);
@@ -4112,8 +3919,8 @@ function SubscriptionsSection(props) {
4112
3919
  try {
4113
3920
  response = await callSubscriptionsAuth(rpc, "status", {});
4114
3921
  } catch (error) {
4115
- const message$3 = error instanceof Error ? error.message : String(error);
4116
- for (const { id } of PROVIDERS) setProviderError(id, message$3);
3922
+ const message$2 = error instanceof Error ? error.message : String(error);
3923
+ for (const { id } of PROVIDERS) setProviderError(id, message$2);
4117
3924
  return;
4118
3925
  }
4119
3926
  if (!mountedRef.current) return;
@@ -4452,6 +4259,7 @@ function SubscriptionsSection(props) {
4452
4259
  accounts.map((account) => {
4453
4260
  const usageKey = `${id}:${account.key}`;
4454
4261
  const usage = usages[usageKey];
4262
+ const shownWindows = visibleUsageWindows(id, usage?.windows, status?.visibleModels);
4455
4263
  const usageError = usageErrors[usageKey];
4456
4264
  const display = account.account ?? account.key;
4457
4265
  const sortedCredits = [...usage?.resetCredits ?? []].sort((a, b) => (a.expiresAt ?? Infinity) - (b.expiresAt ?? Infinity));
@@ -4534,7 +4342,11 @@ function SubscriptionsSection(props) {
4534
4342
  style: styles$5.statusLine,
4535
4343
  children: t("usageEmpty")
4536
4344
  }),
4537
- (usage?.windows ?? []).map((window$1, index) => {
4345
+ usage?.windows !== void 0 && usage.windows.length > 0 && shownWindows.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4346
+ style: styles$5.statusLine,
4347
+ children: t("usageNoVisibleModels")
4348
+ }),
4349
+ shownWindows.map((window$1, index) => {
4538
4350
  const percent = displayUsedPercent(window$1.usedPercent);
4539
4351
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4540
4352
  style: styles$5.usageRow,
@@ -4605,7 +4417,7 @@ function SubscriptionsSection(props) {
4605
4417
  },
4606
4418
  children: t("addAccount")
4607
4419
  }),
4608
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4420
+ !busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4609
4421
  type: "button",
4610
4422
  "aria-haspopup": "dialog",
4611
4423
  onClick: () => setManagedProvider({
@@ -4680,10 +4492,6 @@ function SubscriptionsSection(props) {
4680
4492
  ]
4681
4493
  }, id);
4682
4494
  }),
4683
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CursorCard, {
4684
- rpc,
4685
- t
4686
- }),
4687
4495
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OllamaCard, {
4688
4496
  rpc,
4689
4497
  t
@@ -4697,7 +4505,10 @@ function SubscriptionsSection(props) {
4697
4505
  name: managedProvider.name,
4698
4506
  rpc,
4699
4507
  t,
4700
- onClose: () => setManagedProvider(void 0)
4508
+ onClose: () => {
4509
+ setManagedProvider(void 0);
4510
+ refresh();
4511
+ }
4701
4512
  }),
4702
4513
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ".subscriptions-reset-dialog::backdrop { background: var(--dsw-alias-bg-mask-1, #0006); backdrop-filter: var(--dsw-mask-blur, none); }" }),
4703
4514
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
@@ -5537,22 +5348,17 @@ function VideoGenerateToolview(props) {
5537
5348
  */
5538
5349
  function createSpeedLoader(connection, models, sessionId) {
5539
5350
  return async () => {
5540
- const state = await callSubscriptionsAuth(connection.rpc, "speed", { sessionId });
5541
5351
  const directories = models();
5542
- if (directories === void 0) return {
5543
- visible: false,
5544
- tier: state.tier
5545
- };
5546
- let current;
5547
- try {
5352
+ let current = null;
5353
+ if (directories !== void 0) try {
5548
5354
  current = (await directories.directoryFor(sessionId).load()).current;
5549
5355
  } catch (error) {
5550
5356
  if (!modelSelectionUnavailable(error)) throw error;
5551
- return {
5552
- visible: false,
5553
- tier: state.tier
5554
- };
5555
5357
  }
5358
+ const state = await callSubscriptionsAuth(connection.rpc, "speed", {
5359
+ sessionId,
5360
+ ...current?.provider === "codex" ? { model: current.model } : {}
5361
+ });
5556
5362
  return {
5557
5363
  visible: current !== null && current.provider === "codex" && state.fastModels.includes(current.model),
5558
5364
  tier: state.tier
@@ -5938,7 +5744,6 @@ const PROVIDER_NAMES = {
5938
5744
  grok: "Grok",
5939
5745
  copilot: "Copilot",
5940
5746
  antigravity: "Antigravity",
5941
- "cursor-subscription": "Cursor",
5942
5747
  "opencode-go": "OpenCode Go",
5943
5748
  "kimi-coding": "Kimi Code",
5944
5749
  minimax: "MiniMax",
@@ -5985,11 +5790,7 @@ function groupUsageDisplays(roster, windowsOf, plans) {
5985
5790
  }
5986
5791
  /** Read each account source independently so a failing endpoint cannot hide the others. */
5987
5792
  async function loadBadgeRoster(rpc) {
5988
- const [subscriptions, cursor, external] = await Promise.allSettled([
5989
- callSubscriptionsAuth(rpc, "status", {}),
5990
- callSubscriptionsAuth(rpc, "cursorStatus", {}),
5991
- callSubscriptionsAuth(rpc, "externalStatus", {})
5992
- ]);
5793
+ const [subscriptions, external] = await Promise.allSettled([callSubscriptionsAuth(rpc, "status", {}), callSubscriptionsAuth(rpc, "externalStatus", {})]);
5993
5794
  const roster = [];
5994
5795
  const refreshed = /* @__PURE__ */ new Set();
5995
5796
  if (subscriptions.status === "fulfilled") for (const provider of [
@@ -6005,16 +5806,6 @@ async function loadBadgeRoster(rpc) {
6005
5806
  account
6006
5807
  });
6007
5808
  }
6008
- if (cursor.status === "fulfilled") {
6009
- refreshed.add("cursor-subscription");
6010
- if (cursor.value.authenticated) roster.push({
6011
- provider: "cursor-subscription",
6012
- account: {
6013
- key: "cursor",
6014
- isDefault: true
6015
- }
6016
- });
6017
- }
6018
5809
  if (external.status === "fulfilled") for (const [source, provider] of [
6019
5810
  ["opencode-go", "opencode-go"],
6020
5811
  ["kimi-code", "kimi-coding"],
@@ -6037,7 +5828,6 @@ async function loadBadgeRoster(rpc) {
6037
5828
  };
6038
5829
  }
6039
5830
  async function usageOf(rpc, { provider, account }) {
6040
- if (provider === "cursor-subscription") return callSubscriptionsAuth(rpc, "cursorUsage", {});
6041
5831
  if (provider === "opencode-go" || provider === "kimi-coding" || provider === "minimax" || provider === "minimax-cn" || provider === "ollama-cloud") return callSubscriptionsAuth(rpc, "externalUsage", { source: provider === "kimi-coding" ? "kimi-code" : provider });
6042
5832
  return callSubscriptionsAuth(rpc, "usage", {
6043
5833
  provider,