dsh-opencode-go 0.1.20 → 0.1.22

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 (56) hide show
  1. package/README.en.md +133 -127
  2. package/README.md +131 -127
  3. package/THIRD_PARTY_NOTICES.md +3 -1
  4. package/docs/development.md +60 -8
  5. package/docs/fork-review-2026-09-25.md +191 -0
  6. package/docs/independent-package.md +2 -2
  7. package/docs/verification.md +241 -0
  8. package/lib/build-info.json +8 -1
  9. package/lib/client.js +1576 -234
  10. package/lib/index.js +7001 -338
  11. package/lib/types/account-manager.d.ts +23 -0
  12. package/lib/types/account-operations.d.ts +31 -0
  13. package/lib/types/account-policy.d.ts +16 -0
  14. package/lib/types/account-recovery.d.ts +2 -0
  15. package/lib/types/account-selection.d.ts +30 -0
  16. package/lib/types/account-service.d.ts +12 -0
  17. package/lib/types/accounts-contract.d.ts +38 -0
  18. package/lib/types/accounts.d.ts +31 -0
  19. package/lib/types/adapter.d.ts +43 -9
  20. package/lib/types/call-trace.d.ts +54 -0
  21. package/lib/types/catalog-manager.d.ts +20 -0
  22. package/lib/types/catalog.d.ts +6 -3
  23. package/lib/types/client/AccountsCard.d.ts +19 -0
  24. package/lib/types/client/Section.d.ts +3 -6
  25. package/lib/types/client/UsagePill.d.ts +4 -2
  26. package/lib/types/client/accounts-controller.d.ts +69 -0
  27. package/lib/types/client/host-compat.d.ts +7 -0
  28. package/lib/types/client/locales.d.ts +55 -1
  29. package/lib/types/client/section-controller.d.ts +17 -41
  30. package/lib/types/client/staged-form.d.ts +1 -3
  31. package/lib/types/client/usage.d.ts +1 -1
  32. package/lib/types/config-contract.d.ts +69 -0
  33. package/lib/types/config.d.ts +12 -47
  34. package/lib/types/conversion/context.d.ts +5 -1
  35. package/lib/types/conversion/image-pool.d.ts +24 -0
  36. package/lib/types/conversion/replay.d.ts +1 -1
  37. package/lib/types/conversion/stream.d.ts +1 -1
  38. package/lib/types/gateway-diagnostics.d.ts +22 -0
  39. package/lib/types/gateway-error.d.ts +2 -0
  40. package/lib/types/host-settings.d.ts +11 -0
  41. package/lib/types/index.d.ts +2 -1
  42. package/lib/types/json-response.d.ts +1 -1
  43. package/lib/types/model-metadata.d.ts +3 -1
  44. package/lib/types/models-contract.d.ts +7 -0
  45. package/lib/types/protocol-contract.d.ts +5 -0
  46. package/lib/types/protocol-policy.d.ts +4 -0
  47. package/lib/types/proxy-url.d.ts +2 -0
  48. package/lib/types/proxy.d.ts +11 -0
  49. package/lib/types/reasoning.d.ts +36 -6
  50. package/lib/types/request-control.d.ts +2 -0
  51. package/lib/types/sdk-types.d.ts +1568 -0
  52. package/lib/types/settings-bridge.d.ts +22 -0
  53. package/lib/types/usage-contract.d.ts +5 -0
  54. package/lib/types/usage.d.ts +14 -2
  55. package/lib/vendor-licenses.txt +103 -0
  56. package/package.json +8 -2
package/lib/client.js CHANGED
@@ -38,9 +38,9 @@ __export(index_exports, {
38
38
  module.exports = __toCommonJS(index_exports);
39
39
 
40
40
  // src/client/Section.tsx
41
- var import_react2 = require("react");
42
- var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
43
- var primitives = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
41
+ var import_react3 = require("react");
42
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
43
+ var primitives2 = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
44
44
 
45
45
  // src/client/ModelEditor.tsx
46
46
  var import_react = require("react");
@@ -82,6 +82,10 @@ function parseGoModels(value) {
82
82
  for (const key of ["contextWindow", "maxTokens"]) {
83
83
  if (typeof row[key] === "number" && Number.isSafeInteger(row[key]) && row[key] > 0) model[key] = row[key];
84
84
  }
85
+ if (row.reasoningBudget !== null && typeof row.reasoningBudget === "object") {
86
+ const { min, max } = row.reasoningBudget;
87
+ if (typeof min === "number" && Number.isSafeInteger(min) && min > 0 && typeof max === "number" && Number.isSafeInteger(max) && max >= min) model.reasoningBudget = { min, max };
88
+ }
85
89
  if (typeof row.deprecated === "boolean") model.deprecated = row.deprecated;
86
90
  if (typeof row.configurationMissing === "boolean") model.configurationMissing = row.configurationMissing;
87
91
  if (validReleaseDate(row.releaseDate)) model.releaseDate = row.releaseDate;
@@ -113,9 +117,11 @@ function parseSources(value) {
113
117
  throw new Error("Invalid OpenCode Go catalog source timestamp");
114
118
  }
115
119
  if (source.error !== void 0 && typeof source.error !== "string") throw new Error("Invalid OpenCode Go catalog source error");
120
+ if (source.warning !== void 0 && typeof source.warning !== "string") throw new Error("Invalid OpenCode Go catalog source warning");
116
121
  return {
117
122
  ...source.updatedAt === void 0 ? {} : { updatedAt: source.updatedAt },
118
- ...source.error === void 0 ? {} : { error: source.error }
123
+ ...source.error === void 0 ? {} : { error: source.error },
124
+ ...source.warning === void 0 ? {} : { warning: source.warning }
119
125
  };
120
126
  };
121
127
  return { listing: parse(sources.listing), metadata: parse(sources.metadata) };
@@ -145,10 +151,10 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
145
151
  const style = document.createElement("style");
146
152
  style.dataset.plugin = "dsh-opencode-go";
147
153
  style.dataset.pluginCss = id;
148
- style.textContent = ".N807zW_page{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;container-type:size}.N807zW_pageBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;padding:0 4px 16px 0;display:flex;overflow-y:auto}.N807zW_pageBody,.N807zW_modelList,.N807zW_modelDetails{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l3) transparent}.N807zW_pageBody::-webkit-scrollbar,.N807zW_modelList::-webkit-scrollbar,.N807zW_modelDetails::-webkit-scrollbar{width:8px;height:8px}.N807zW_pageBody::-webkit-scrollbar-track,.N807zW_modelList::-webkit-scrollbar-track,.N807zW_modelDetails::-webkit-scrollbar-track{background:0 0}.N807zW_pageBody::-webkit-scrollbar-thumb,.N807zW_modelList::-webkit-scrollbar-thumb,.N807zW_modelDetails::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}.N807zW_pageBody:hover::-webkit-scrollbar-thumb,.N807zW_modelList:hover::-webkit-scrollbar-thumb,.N807zW_modelDetails:hover::-webkit-scrollbar-thumb{background:var(--dsw-alias-label-tertiary);background-clip:content-box}.N807zW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.N807zW_field+.N807zW_field{border-top:.5px solid var(--dsw-alias-border-l2)}.N807zW_head{align-items:center;gap:8px;display:flex}.N807zW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.N807zW_badges{align-items:center;gap:8px;display:inline-flex}.N807zW_trailing{flex:none;align-items:center;gap:8px;display:inline-flex}.N807zW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.N807zW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.N807zW_reset:disabled{cursor:default}.N807zW_reset:focus-visible,.N807zW_cardTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.N807zW_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.N807zW_input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-color:var(--dsw-alias-brand-primary)}.N807zW_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.N807zW_inputInvalid{border-color:var(--dsw-alias-label-error);}.N807zW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.N807zW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.N807zW_pageTop{flex-direction:column;gap:3px;padding:2px 0 12px;display:flex}.N807zW_title{color:var(--dsw-alias-label-primary);margin:0;font-size:15px;font-weight:600;line-height:1.4}.N807zW_intro{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:1.5}.N807zW_card,.N807zW_cardModels{border:.5px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-3) 40%, transparent);border-radius:12px;padding:8px 0 10px}.N807zW_card{flex:none}.N807zW_card+.N807zW_card,.N807zW_card+.N807zW_cardModels,.N807zW_cardModels+.N807zW_card{margin-top:8px}.N807zW_cardModels{flex-direction:column;flex:1 0 auto;display:flex}.N807zW_cardFolded{flex:none}.N807zW_cardHead{align-items:center;gap:8px;min-height:24px;padding:0 14px;display:flex}.N807zW_cardTitle{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13.5px;font-weight:600;line-height:1.5}.N807zW_cardSub{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11.5px;line-height:1.5}.N807zW_cardBody{flex-direction:column;gap:8px;padding:4px 14px 0;display:flex}.N807zW_cardBody>.N807zW_input{box-sizing:border-box;width:100%}.N807zW_cardModels>.N807zW_cardBody{flex:1 0 auto}.N807zW_cardNotes{flex-direction:column;gap:8px;padding:6px 14px 2px;display:flex}.N807zW_cardNotes:empty{display:none}.N807zW_cardDivider{border-top:.5px solid var(--dsw-alias-border-l2);margin:10px 14px}.N807zW_cardTrigger{width:100%;min-height:24px;font:inherit;text-align:left;color:inherit;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0 14px;display:flex}.N807zW_cardTrigger:hover .N807zW_cardTitle{color:var(--dsw-alias-brand-primary)}.N807zW_advancedGrid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px 18px;display:grid}.N807zW_advancedGrid .N807zW_field{padding:0}.N807zW_advancedGrid .N807zW_field+.N807zW_field{border-top:none}.N807zW_limitsEditor{flex-direction:column;flex:1 0 auto;gap:10px;padding-top:4px;display:flex}.N807zW_limitsFoot{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;margin:2px -14px 0;padding:10px 14px 0;display:flex}.N807zW_limitsSummary{min-width:0;color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:1;font-size:12px;line-height:1.5}.N807zW_modelMeta{align-items:baseline;gap:10px;display:flex}.N807zW_modelMeta .N807zW_limitsModelId{flex:1;min-width:0}.N807zW_releaseDate{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px;line-height:1.4}.N807zW_limitsModelId{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.4;display:block;overflow:hidden}.N807zW_visuallyHidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.N807zW_actions{border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:12px 0;display:flex}.N807zW_starLink{max-width:100%;color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;gap:7px;margin-left:auto;padding:6px 0;font-size:12px;line-height:1.5;text-decoration:none;display:inline-flex}.N807zW_starLink svg{flex:none}.N807zW_starLink:hover{color:var(--dsw-alias-brand-primary)}.N807zW_starLink:hover span{text-underline-offset:3px;text-decoration:underline}.N807zW_starLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.N807zW_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.N807zW_slot{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.N807zW_slot svg{width:15px;height:15px}.N807zW_chevron,.N807zW_chevronOpen{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .15s}.N807zW_chevron{transform:rotate(-90deg)}.N807zW_filters{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.N807zW_filterAction{align-items:center;margin-left:auto;display:inline-flex}.N807zW_filter{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:6px 9px;font-size:12px}.N807zW_filter[aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.N807zW_filter span{color:var(--dsw-alias-label-tertiary);margin-left:4px}.N807zW_modelLayout{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;flex:auto;grid-template-columns:minmax(0,45fr) minmax(0,55fr);min-height:260px;max-height:560px;display:grid;overflow:hidden}.N807zW_modelList{border-right:.5px solid var(--dsw-alias-border-l2);min-height:0;padding:4px 6px;overflow-y:auto}.N807zW_modelRow{align-items:center;gap:8px;padding-right:6px;display:flex}.N807zW_modelRow+.N807zW_modelRow{border-top:.5px solid var(--dsw-alias-border-l2)}.N807zW_modelRowSelected{background:var(--dsw-alias-bg-layer-3);border-top-color:#0000;border-radius:6px}.N807zW_modelRow>[role=switch]{flex-shrink:0}.N807zW_modelChoice{text-align:left;min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:1;align-items:baseline;padding:9px 3px 9px 6px;display:flex}.N807zW_modelRow:hover:not(.N807zW_modelRowSelected){background:color-mix(in srgb, var(--dsw-alias-bg-layer-3) 92%, var(--dsw-alias-label-primary));border-top-color:#0000;border-radius:6px}.N807zW_modelName{overflow-wrap:anywhere;flex-wrap:wrap;flex:0 auto;align-items:center;gap:5px;min-width:0;font-size:13px;display:flex}.N807zW_overrideDot{background:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;width:6px;height:6px}.N807zW_modelDetails{flex-direction:column;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.N807zW_modelDetails h3{overflow-wrap:anywhere;margin:0;font-size:14px}.N807zW_modelHeading{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.N807zW_stats{flex-direction:column;gap:10px;display:flex}.N807zW_stat{flex-direction:column;gap:4px;display:flex}.N807zW_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}.N807zW_modelDetails .N807zW_input{box-sizing:border-box;width:100%;min-width:0;height:30px;padding:0 9px;font-size:12px}.N807zW_modalities{flex-wrap:wrap;gap:4px;display:flex}.N807zW_modality,.N807zW_modalityOff{border-radius:6px;padding:2px 7px;font-size:11px;line-height:1.5}.N807zW_modality{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary)}.N807zW_modalityOff{border:.5px dashed var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}.N807zW_modelDetails .N807zW_reset{align-self:flex-start}.N807zW_paneFoot{color:var(--dsw-alias-label-tertiary);margin:auto 0 0;font-size:11px;line-height:1.5}.N807zW_newBadge{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:4px;padding:2px 4px;font-size:9px}.N807zW_modelChoice:focus-visible,.N807zW_filter:focus-visible,.N807zW_cardTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}@container (width<=440px){.N807zW_advancedGrid{grid-template-columns:minmax(0,1fr)}.N807zW_modelLayout{flex:none;grid-template-columns:minmax(0,1fr);max-height:none}.N807zW_modelList{border-right:0;border-bottom:.5px solid var(--dsw-alias-border-l2);max-height:240px}.N807zW_modelDetails{max-height:460px}}@media (prefers-reduced-motion:reduce){.N807zW_chevron,.N807zW_chevronOpen{transition:none}}";
154
+ style.textContent = '.N807zW_accounts{gap:10px;margin:6px 0;padding:6px 0;display:grid}.N807zW_accountRow{border:.5px solid var(--dsw-alias-border-l2);border-radius:10px;position:relative}.N807zW_accountRow[data-dragging=true]{opacity:.55}.N807zW_accountMain{grid-template-columns:16px 112px 92px minmax(0,1fr) 38px 106px 14px;align-items:center;gap:9px;padding:9px 11px;display:grid}.N807zW_accountHandle{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:grab;-webkit-user-drag:element;background:0 0;border:0;place-items:center;padding:0;display:grid}.N807zW_accountHandle:disabled{cursor:default;opacity:.5}.N807zW_accountHandle:focus-visible,.N807zW_accountToggle:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px;border-radius:4px}.N807zW_accountName{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:600;overflow:hidden}.N807zW_accountState{min-width:0;color:var(--dsw-alias-label-tertiary);align-items:center;gap:5px;font-size:11.5px;display:inline-flex;overflow:hidden}.N807zW_accountDot{background:#39a878;border-radius:50%;flex:none;width:6px;height:6px}.N807zW_accountDot[data-off=true]{background:#d9a441}.N807zW_accountPercent{text-align:right;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-primary);font-size:12.5px;font-weight:650}.N807zW_accountBar{background:#ffffff1a;border-radius:99px;height:12px;position:relative;overflow:hidden}.N807zW_accountBarFill{background:#39a878;border-radius:99px;position:absolute;inset:0 auto 0 0}.N807zW_accountBar[data-level=high] .N807zW_accountBarFill{background:#e0a100}.N807zW_accountBar[data-level=limited] .N807zW_accountBarFill{background:#e5484d}.N807zW_accountBarTick{background:#fff3;width:1px;position:absolute;top:0;bottom:0}.N807zW_accountReset{text-align:right;color:var(--dsw-alias-label-tertiary);font-size:11.5px}.N807zW_accountIdle{text-align:right;color:var(--dsw-alias-label-tertiary);grid-column:4/7;font-size:11.5px;line-height:1.5}.N807zW_accountToggle{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;place-items:center;padding:0;display:grid}.N807zW_accountProblems{align-items:baseline;gap:8px;padding:0 11px 9px 36px;display:flex}.N807zW_accountRetry{font:inherit;color:var(--dsw-alias-brand-primary);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-size:11.5px;line-height:1.5}.N807zW_accountRetry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.N807zW_accountHandle:active{cursor:grabbing}.N807zW_accountDetail{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding:9px 11px 10px 36px;display:flex}.N807zW_accountRow:after{content:"";background:var(--dsw-alias-brand-primary);opacity:0;pointer-events:none;border-radius:2px;height:2px;position:absolute;left:0;right:0}.N807zW_accountRow[data-drop=before]:after{opacity:1;top:-6px}.N807zW_accountRow[data-drop=after]:after{opacity:1;bottom:-6px}.N807zW_accountUsage{grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;font-size:12px;display:grid}.N807zW_accountUsage progress{accent-color:#39a878;width:100%;height:8px;margin:6px 0;display:block}.N807zW_accountUsage progress[data-level=high]{accent-color:#e0a100}.N807zW_accountUsage progress[data-level=limited]{accent-color:#e5484d}.N807zW_accountUsage .N807zW_hint{overflow-wrap:anywhere;display:block}.N807zW_accountActions{flex-wrap:wrap;gap:8px;margin-top:10px;display:flex}.N807zW_accountEditor{border:.5px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-3) 25%, transparent);border-radius:10px;flex-direction:column;gap:8px;margin:0 11px 10px 36px;padding:10px 12px;display:flex}.N807zW_accountEditorHead{align-items:baseline;gap:6px;min-width:0;display:flex}.N807zW_accountEditorTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:12.5px;font-weight:600;line-height:1.5}.N807zW_accountEditorFor{min-width:0;color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11.5px;line-height:1.5}.N807zW_accountField{color:var(--dsw-alias-label-tertiary);flex-direction:column;gap:5px;font-size:11.5px;line-height:1.5;display:flex}.N807zW_accountEditorActions{align-items:center;gap:8px;margin-top:2px;display:flex}@media (width<=480px){.N807zW_accountUsage{grid-template-columns:1fr}}.N807zW_page{flex-direction:column;min-width:0;height:100%;min-height:0;display:flex;container-type:size}.N807zW_pageBody{scrollbar-gutter:stable;flex-direction:column;flex:1;min-height:0;padding:0 4px 16px 0;display:flex;overflow-y:auto}.N807zW_pageBody,.N807zW_modelList,.N807zW_modelDetails{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l3) transparent}.N807zW_pageBody::-webkit-scrollbar,.N807zW_modelList::-webkit-scrollbar,.N807zW_modelDetails::-webkit-scrollbar{width:8px;height:8px}.N807zW_pageBody::-webkit-scrollbar-track,.N807zW_modelList::-webkit-scrollbar-track,.N807zW_modelDetails::-webkit-scrollbar-track{background:0 0}.N807zW_pageBody::-webkit-scrollbar-thumb,.N807zW_modelList::-webkit-scrollbar-thumb,.N807zW_modelDetails::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l3);background-clip:content-box;border:2px solid #0000;border-radius:999px}.N807zW_pageBody:hover::-webkit-scrollbar-thumb,.N807zW_modelList:hover::-webkit-scrollbar-thumb,.N807zW_modelDetails:hover::-webkit-scrollbar-thumb{background:var(--dsw-alias-label-tertiary);background-clip:content-box}.N807zW_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.N807zW_field+.N807zW_field{border-top:.5px solid var(--dsw-alias-border-l2)}.N807zW_head{align-items:center;gap:8px;display:flex}.N807zW_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.N807zW_badges{align-items:center;gap:8px;display:inline-flex}.N807zW_trailing{flex:none;align-items:center;gap:8px;display:inline-flex}.N807zW_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.N807zW_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.N807zW_reset:disabled{cursor:default}.N807zW_reset:focus-visible,.N807zW_cardTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.N807zW_input{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}.N807zW_input:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-color:var(--dsw-alias-brand-primary)}.N807zW_input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.N807zW_inputInvalid{border-color:var(--dsw-alias-label-error);}.N807zW_invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.N807zW_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.N807zW_pageTop{flex-direction:column;gap:3px;padding:2px 0 12px;display:flex}.N807zW_title{color:var(--dsw-alias-label-primary);margin:0;font-size:15px;font-weight:600;line-height:1.4}.N807zW_intro{color:var(--dsw-alias-label-secondary);margin:0;font-size:13px;line-height:1.5}.N807zW_card,.N807zW_cardModels{border:.5px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-3) 40%, transparent);border-radius:12px;padding:8px 0 10px}.N807zW_card{flex:none}.N807zW_card+.N807zW_card,.N807zW_card+.N807zW_cardModels,.N807zW_cardModels+.N807zW_card{margin-top:8px}.N807zW_cardModels{flex-direction:column;flex:1 0 auto;display:flex}.N807zW_cardFolded{flex:none}.N807zW_cardHead{align-items:center;gap:8px;min-height:24px;padding:0 14px;display:flex}.N807zW_cardTitle{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13.5px;font-weight:600;line-height:1.5}.N807zW_cardSub{color:var(--dsw-alias-label-tertiary);flex:none;font-size:11.5px;line-height:1.5}.N807zW_cardStamp{white-space:nowrap;color:var(--dsw-alias-label-tertiary);flex:none;font-size:11.5px;line-height:1.5}.N807zW_cardBody{flex-direction:column;gap:8px;padding:4px 14px 0;display:flex}.N807zW_cardBody>.N807zW_input{box-sizing:border-box;width:100%}.N807zW_cardModels>.N807zW_cardBody{flex:1 0 auto}.N807zW_cardNotes{flex-direction:column;gap:8px;padding:6px 14px 2px;display:flex}.N807zW_cardNotes:empty{display:none}.N807zW_cardDivider{border-top:.5px solid var(--dsw-alias-border-l2);margin:10px 14px}.N807zW_cardTrigger{width:100%;min-height:24px;font:inherit;text-align:left;color:inherit;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;margin:0;padding:0 14px;display:flex}.N807zW_cardTrigger:hover .N807zW_cardTitle{color:var(--dsw-alias-brand-primary)}.N807zW_cardHead>.N807zW_cardTrigger{padding:0}.N807zW_advancedGrid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:12px 18px;display:grid}.N807zW_advancedGrid .N807zW_field{padding:0}.N807zW_advancedGrid .N807zW_field+.N807zW_field{border-top:none}.N807zW_limitsEditor{flex-direction:column;flex:1 0 auto;gap:10px;padding-top:4px;display:flex}.N807zW_limitsFoot{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;margin:2px -14px 0;padding:10px 14px 0;display:flex}.N807zW_limitsSummary{min-width:0;color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex:1;font-size:12px;line-height:1.5}.N807zW_modelMeta{align-items:baseline;gap:10px;display:flex}.N807zW_modelMeta .N807zW_limitsModelId{flex:1;min-width:0}.N807zW_releaseDate{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px;line-height:1.4}.N807zW_limitsModelId{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.4;display:block;overflow:hidden}.N807zW_visuallyHidden{clip:rect(0, 0, 0, 0);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.N807zW_actions{border-top:.5px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:12px 0;display:flex}.N807zW_starLink{max-width:100%;color:var(--dsw-alias-label-secondary);border-radius:4px;align-items:center;gap:7px;margin-left:auto;padding:6px 0;font-size:12px;line-height:1.5;text-decoration:none;display:inline-flex}.N807zW_starLink svg{flex:none}.N807zW_starLink:hover{color:var(--dsw-alias-brand-primary)}.N807zW_starLink:hover span{text-underline-offset:3px;text-decoration:underline}.N807zW_starLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:3px}.N807zW_failedNote{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.N807zW_slot{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.N807zW_slot svg{width:15px;height:15px}.N807zW_chevron,.N807zW_chevronOpen{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .15s}.N807zW_chevron{transform:rotate(-90deg)}.N807zW_filters{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.N807zW_filterAction{align-items:center;margin-left:auto;display:inline-flex}.N807zW_filter{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;border-radius:6px;padding:6px 9px;font-size:12px}.N807zW_filter[aria-pressed=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3)}.N807zW_filter span{color:var(--dsw-alias-label-tertiary);margin-left:4px}.N807zW_modelLayout{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;flex:auto;grid-template-columns:minmax(0,45fr) minmax(0,55fr);min-height:260px;max-height:560px;display:grid;overflow:hidden}.N807zW_modelList{border-right:.5px solid var(--dsw-alias-border-l2);min-height:0;padding:4px 6px;overflow-y:auto}.N807zW_modelRow{align-items:center;gap:8px;padding-right:6px;display:flex}.N807zW_modelRow+.N807zW_modelRow{border-top:.5px solid var(--dsw-alias-border-l2)}.N807zW_modelRowSelected{background:var(--dsw-alias-bg-layer-3);border-top-color:#0000;border-radius:6px}.N807zW_modelRow>[role=switch]{flex-shrink:0}.N807zW_modelChoice{text-align:left;min-width:0;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:1;align-items:baseline;padding:9px 3px 9px 6px;display:flex}.N807zW_modelRow:hover:not(.N807zW_modelRowSelected){background:color-mix(in srgb, var(--dsw-alias-bg-layer-3) 92%, var(--dsw-alias-label-primary));border-top-color:#0000;border-radius:6px}.N807zW_modelName{overflow-wrap:anywhere;flex-wrap:wrap;flex:0 auto;align-items:center;gap:5px;min-width:0;font-size:13px;display:flex}.N807zW_overrideDot{background:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;width:6px;height:6px}.N807zW_modelDetails{flex-direction:column;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.N807zW_modelDetails h3{overflow-wrap:anywhere;margin:0;font-size:14px}.N807zW_modelHeading{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.N807zW_stats{flex-direction:column;gap:10px;display:flex}.N807zW_stat{flex-direction:column;gap:4px;display:flex}.N807zW_statLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}.N807zW_budgetEditor{margin-top:12px;font-size:12px}.N807zW_budgetEditor summary{cursor:pointer}.N807zW_budgetInput{align-items:center;gap:8px;margin-top:4px;display:flex}.N807zW_budgetPresets{flex-wrap:wrap;gap:6px;margin-top:8px;display:flex}.N807zW_modelDetails .N807zW_input{box-sizing:border-box;width:100%;min-width:0;height:30px;padding:0 9px;font-size:12px}.N807zW_modalities{flex-wrap:wrap;gap:4px;display:flex}.N807zW_modality,.N807zW_modalityOff{border-radius:6px;padding:2px 7px;font-size:11px;line-height:1.5}.N807zW_modality{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary)}.N807zW_modalityOff{border:.5px dashed var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}.N807zW_modelDetails .N807zW_reset{align-self:flex-start}.N807zW_paneFoot{color:var(--dsw-alias-label-tertiary);margin:auto 0 0;font-size:11px;line-height:1.5}.N807zW_newBadge{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l4);border-radius:4px;padding:2px 4px;font-size:9px}.N807zW_modelChoice:focus-visible,.N807zW_filter:focus-visible,.N807zW_cardTrigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}@container (width<=440px){.N807zW_advancedGrid{grid-template-columns:minmax(0,1fr)}.N807zW_modelLayout{flex:none;grid-template-columns:minmax(0,1fr);max-height:none}.N807zW_modelList{border-right:0;border-bottom:.5px solid var(--dsw-alias-border-l2);max-height:240px}.N807zW_modelDetails{max-height:460px}}@media (prefers-reduced-motion:reduce){.N807zW_chevron,.N807zW_chevronOpen{transition:none}}';
149
155
  document.head.appendChild(style);
150
156
  }
151
- var Section_default = { "actions": "N807zW_actions", "advancedGrid": "N807zW_advancedGrid", "badges": "N807zW_badges", "card": "N807zW_card", "cardBody": "N807zW_cardBody", "cardDivider": "N807zW_cardDivider", "cardFolded": "N807zW_cardFolded", "cardHead": "N807zW_cardHead", "cardModels": "N807zW_cardModels", "cardNotes": "N807zW_cardNotes", "cardSub": "N807zW_cardSub", "cardTitle": "N807zW_cardTitle", "cardTrigger": "N807zW_cardTrigger", "chevron": "N807zW_chevron", "chevronOpen": "N807zW_chevronOpen", "failedNote": "N807zW_failedNote", "field": "N807zW_field", "filter": "N807zW_filter", "filterAction": "N807zW_filterAction", "filters": "N807zW_filters", "head": "N807zW_head", "hint": "N807zW_hint", "input": "N807zW_input", "inputInvalid": "N807zW_inputInvalid N807zW_input", "intro": "N807zW_intro", "invalid": "N807zW_invalid", "label": "N807zW_label", "limitsEditor": "N807zW_limitsEditor", "limitsFoot": "N807zW_limitsFoot", "limitsModelId": "N807zW_limitsModelId", "limitsSummary": "N807zW_limitsSummary", "modalities": "N807zW_modalities", "modality": "N807zW_modality", "modalityOff": "N807zW_modalityOff", "modelChoice": "N807zW_modelChoice", "modelDetails": "N807zW_modelDetails", "modelHeading": "N807zW_modelHeading", "modelLayout": "N807zW_modelLayout", "modelList": "N807zW_modelList", "modelMeta": "N807zW_modelMeta", "modelName": "N807zW_modelName", "modelRow": "N807zW_modelRow", "modelRowSelected": "N807zW_modelRowSelected", "newBadge": "N807zW_newBadge", "overrideDot": "N807zW_overrideDot", "page": "N807zW_page", "pageBody": "N807zW_pageBody", "pageTop": "N807zW_pageTop", "paneFoot": "N807zW_paneFoot", "releaseDate": "N807zW_releaseDate", "reset": "N807zW_reset", "slot": "N807zW_slot", "starLink": "N807zW_starLink", "stat": "N807zW_stat", "statLabel": "N807zW_statLabel", "stats": "N807zW_stats", "title": "N807zW_title", "trailing": "N807zW_trailing", "visuallyHidden": "N807zW_visuallyHidden" };
157
+ var Section_default = { "accountActions": "N807zW_accountActions", "accountBar": "N807zW_accountBar", "accountBarFill": "N807zW_accountBarFill", "accountBarTick": "N807zW_accountBarTick", "accountDetail": "N807zW_accountDetail", "accountDot": "N807zW_accountDot", "accountEditor": "N807zW_accountEditor", "accountEditorActions": "N807zW_accountEditorActions", "accountEditorFor": "N807zW_accountEditorFor", "accountEditorHead": "N807zW_accountEditorHead", "accountEditorTitle": "N807zW_accountEditorTitle", "accountField": "N807zW_accountField", "accountHandle": "N807zW_accountHandle", "accountIdle": "N807zW_accountIdle", "accountMain": "N807zW_accountMain", "accountName": "N807zW_accountName", "accountPercent": "N807zW_accountPercent", "accountProblems": "N807zW_accountProblems", "accountReset": "N807zW_accountReset", "accountRetry": "N807zW_accountRetry", "accountRow": "N807zW_accountRow", "accountState": "N807zW_accountState", "accountToggle": "N807zW_accountToggle", "accountUsage": "N807zW_accountUsage", "accounts": "N807zW_accounts", "actions": "N807zW_actions", "advancedGrid": "N807zW_advancedGrid", "badges": "N807zW_badges", "budgetEditor": "N807zW_budgetEditor", "budgetInput": "N807zW_budgetInput", "budgetPresets": "N807zW_budgetPresets", "card": "N807zW_card", "cardBody": "N807zW_cardBody", "cardDivider": "N807zW_cardDivider", "cardFolded": "N807zW_cardFolded", "cardHead": "N807zW_cardHead", "cardModels": "N807zW_cardModels", "cardNotes": "N807zW_cardNotes", "cardStamp": "N807zW_cardStamp", "cardSub": "N807zW_cardSub", "cardTitle": "N807zW_cardTitle", "cardTrigger": "N807zW_cardTrigger", "chevron": "N807zW_chevron", "chevronOpen": "N807zW_chevronOpen", "failedNote": "N807zW_failedNote", "field": "N807zW_field", "filter": "N807zW_filter", "filterAction": "N807zW_filterAction", "filters": "N807zW_filters", "head": "N807zW_head", "hint": "N807zW_hint", "input": "N807zW_input", "inputInvalid": "N807zW_inputInvalid N807zW_input", "intro": "N807zW_intro", "invalid": "N807zW_invalid", "label": "N807zW_label", "limitsEditor": "N807zW_limitsEditor", "limitsFoot": "N807zW_limitsFoot", "limitsModelId": "N807zW_limitsModelId", "limitsSummary": "N807zW_limitsSummary", "modalities": "N807zW_modalities", "modality": "N807zW_modality", "modalityOff": "N807zW_modalityOff", "modelChoice": "N807zW_modelChoice", "modelDetails": "N807zW_modelDetails", "modelHeading": "N807zW_modelHeading", "modelLayout": "N807zW_modelLayout", "modelList": "N807zW_modelList", "modelMeta": "N807zW_modelMeta", "modelName": "N807zW_modelName", "modelRow": "N807zW_modelRow", "modelRowSelected": "N807zW_modelRowSelected", "newBadge": "N807zW_newBadge", "overrideDot": "N807zW_overrideDot", "page": "N807zW_page", "pageBody": "N807zW_pageBody", "pageTop": "N807zW_pageTop", "paneFoot": "N807zW_paneFoot", "releaseDate": "N807zW_releaseDate", "reset": "N807zW_reset", "slot": "N807zW_slot", "starLink": "N807zW_starLink", "stat": "N807zW_stat", "statLabel": "N807zW_statLabel", "stats": "N807zW_stats", "title": "N807zW_title", "trailing": "N807zW_trailing", "visuallyHidden": "N807zW_visuallyHidden" };
152
158
 
153
159
  // src/client/ModelEditor.tsx
154
160
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -160,7 +166,7 @@ var MODALITY_COPY = {
160
166
  pdf: "modalityPdf"
161
167
  };
162
168
  function hasCapacityOverride(limit) {
163
- return limit?.contextWindow != null || limit?.maxTokens != null;
169
+ return limit?.contextWindow != null || limit?.maxTokens != null || (limit?.thinkingBudgets?.length ?? 0) > 0;
164
170
  }
165
171
  function ModelEditor({ models, draft, modelVisibility, t, locale, disabled, visibilitySaving, filterAction, onEdit, onModelEnabled }) {
166
172
  const [query, setQuery] = (0, import_react.useState)("");
@@ -189,7 +195,7 @@ function ModelEditor({ models, draft, modelVisibility, t, locale, disabled, visi
189
195
  ["deprecated", "filterDeprecated", all.filter((entry) => entry.deprecated).length]
190
196
  ];
191
197
  const write = (id3, field, value) => {
192
- const current = draft[id3] === null ? { contextWindow: null, maxTokens: null } : draft[id3] ?? {};
198
+ const current = draft[id3] === null ? { contextWindow: null, maxTokens: null, thinkingBudgets: null } : draft[id3] ?? {};
193
199
  onEdit({ ...draft, [id3]: { ...current, [field]: value ?? null } });
194
200
  };
195
201
  const badges = (entry) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
@@ -291,6 +297,20 @@ function ModelEditor({ models, draft, modelVisibility, t, locale, disabled, visi
291
297
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Modalities, { model, t })
292
298
  ] })
293
299
  ] }),
300
+ model.reasoningBudget ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
301
+ BudgetPresets,
302
+ {
303
+ model,
304
+ limit: draft[model.id],
305
+ t,
306
+ locale,
307
+ disabled,
308
+ onChange: (values) => {
309
+ write(model.id, "thinkingBudgets", values);
310
+ }
311
+ },
312
+ model.id
313
+ ) : null,
294
314
  hasCapacityOverride(draft[model.id]) ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
295
315
  "button",
296
316
  {
@@ -374,22 +394,541 @@ function Capacity({ model, field, limit, disabled, t, locale, onChange }) {
374
394
  ] })
375
395
  ] });
376
396
  }
397
+ function BudgetPresets({ model, limit, disabled, t, locale, onChange }) {
398
+ const [text, setText] = (0, import_react.useState)("");
399
+ const range = model.reasoningBudget;
400
+ const max = Math.min(range.max, (limit?.maxTokens ?? model.maxTokens ?? range.max + 1024) - 1024);
401
+ const values = limit?.thinkingBudgets ?? [];
402
+ const tokens = Number(text);
403
+ const valid = text.trim() !== "" && Number.isSafeInteger(tokens) && tokens >= range.min && tokens <= max;
404
+ const id3 = `opencode-go-thinking-budget-${encodeURIComponent(model.id)}`;
405
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("details", { className: Section_default.budgetEditor, children: [
406
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("summary", { children: t("thinkingBudgets") }),
407
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: Section_default.hint, children: t("thinkingBudgetsHint", { min: range.min.toLocaleString(locale), max: max.toLocaleString(locale) }) }),
408
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { className: Section_default.statLabel, htmlFor: id3, children: t("thinkingBudgetAddLabel", { name: model.name ?? model.id }) }),
409
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: Section_default.budgetInput, children: [
410
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
411
+ "input",
412
+ {
413
+ id: id3,
414
+ className: Section_default.input,
415
+ type: "number",
416
+ step: 1,
417
+ min: range.min,
418
+ max,
419
+ inputMode: "numeric",
420
+ value: text,
421
+ placeholder: "4096",
422
+ disabled,
423
+ "aria-invalid": text !== "" && !valid,
424
+ onChange: (event) => {
425
+ setText(event.target.value);
426
+ }
427
+ }
428
+ ),
429
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
430
+ import_dsh_client_ui_primitives.Button,
431
+ {
432
+ variant: "outline",
433
+ size: "sm",
434
+ disabled: disabled || !valid || values.includes(tokens) || values.length >= 16,
435
+ onClick: () => {
436
+ onChange([...values, tokens].sort((a, b) => a - b));
437
+ setText("");
438
+ },
439
+ children: t("thinkingBudgetAdd")
440
+ }
441
+ )
442
+ ] }),
443
+ values.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: Section_default.budgetPresets, children: values.map((value) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
444
+ "button",
445
+ {
446
+ type: "button",
447
+ className: Section_default.filter,
448
+ disabled,
449
+ "aria-label": t("thinkingBudgetRemove", { value }),
450
+ onClick: () => {
451
+ const next = values.filter((tokens2) => tokens2 !== value);
452
+ onChange(next.length > 0 ? next : void 0);
453
+ },
454
+ children: [
455
+ value.toLocaleString(locale),
456
+ " tokens \xD7"
457
+ ]
458
+ },
459
+ value
460
+ )) }) : null
461
+ ] });
462
+ }
463
+
464
+ // src/client/AccountsCard.tsx
465
+ var import_react2 = require("react");
466
+ var primitives = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
467
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
468
+
469
+ // src/accounts.ts
470
+ var MAX_ACCOUNTS = 20;
471
+ var DEFAULT_ACCOUNT_REF = "OPENCODE_API_KEY";
472
+ var ACCOUNT_REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
473
+ function accountRefOf(settings) {
474
+ return settings.apiKeyEnv || DEFAULT_ACCOUNT_REF;
475
+ }
476
+ function accountsOf(settings) {
477
+ const ref = accountRefOf(settings);
478
+ if (settings.accounts?.length === 0) return [];
479
+ const accounts = settings.accounts ?? [];
480
+ return accounts.some((account) => account.apiKeyEnv === ref) ? accounts : [
481
+ { id: `legacy:${ref}`, name: "", apiKeyEnv: ref },
482
+ ...accounts
483
+ ];
484
+ }
485
+
486
+ // src/client/AccountsCard.tsx
487
+ var import_jsx_runtime2 = require("react/jsx-runtime");
488
+ var WINDOWS = ["rolling", "weekly", "monthly"];
489
+ var TICKS = [25, 50, 75];
490
+ var ChevronDown = primitives.IconChevronDownOutlineRegular ?? primitives.IconChevronDownOutline14;
491
+ function resetText(resetsAt, t) {
492
+ const remaining = Date.parse(resetsAt) - Date.now();
493
+ if (!Number.isFinite(remaining)) return t("usageResetUnknown");
494
+ if (remaining <= 0) return t("usageResetDue");
495
+ const minutes = Math.max(1, Math.round(remaining / 6e4));
496
+ if (minutes < 60) return t("usageResetMinutes", { minutes });
497
+ const hours = Math.round(minutes / 60);
498
+ if (hours < 24) return t("usageResetHours", { hours });
499
+ return t("usageResetDays", { days: Math.round(hours / 24) });
500
+ }
501
+ function barLevel(window) {
502
+ if (window.status === "rate-limited" || window.percent >= 100) return "limited";
503
+ return window.percent >= 80 ? "high" : "ok";
504
+ }
505
+ function stampText(at, locale) {
506
+ const date = new Date(at);
507
+ const time = date.toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
508
+ return date.toDateString() === (/* @__PURE__ */ new Date()).toDateString() ? time : `${date.toLocaleDateString(locale)} ${time}`;
509
+ }
510
+ function GripIcon() {
511
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", "aria-hidden": "true", children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "2.5", r: "1.3" }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "2.5", r: "1.3" }),
514
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "7", r: "1.3" }),
515
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "7", r: "1.3" }),
516
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "11.5", r: "1.3" }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "11.5", r: "1.3" })
518
+ ] });
519
+ }
520
+ function slotAt(container, clientY) {
521
+ const rows = container.querySelectorAll("[data-account-row]");
522
+ for (let index = 0; index < rows.length; index++) {
523
+ const box = rows[index].getBoundingClientRect();
524
+ if (clientY < box.top + box.height / 2) return index;
525
+ }
526
+ return rows.length;
527
+ }
528
+ function AccountsCard({ state, actions, writable, t, locale }) {
529
+ const [open, setOpen] = (0, import_react2.useState)(false);
530
+ const [details, setDetails] = (0, import_react2.useState)(null);
531
+ const [dragging, setDragging] = (0, import_react2.useState)(null);
532
+ const [dropAt, setDropAt] = (0, import_react2.useState)(null);
533
+ const [editor, setEditor] = (0, import_react2.useState)(null);
534
+ const [name, setName] = (0, import_react2.useState)("");
535
+ const [key, setKey] = (0, import_react2.useState)("");
536
+ const disabled = state.busy || state.blocked || !writable;
537
+ const total = state.entries.length;
538
+ const ready = state.entries.filter((entry) => entry.configured === true).length;
539
+ const unreadable = state.entries.filter((entry) => entry.failed === true).length;
540
+ const preferred = state.entries.find((entry) => entry.apiKeyEnv === state.activeRef);
541
+ const reorderable = !disabled && total > 1;
542
+ const draggingFrom = dragging === null ? -1 : state.entries.findIndex((entry) => entry.apiKeyEnv === dragging);
543
+ const noopSlot = draggingFrom >= 0 && (dropAt === draggingFrom || dropAt === draggingFrom + 1);
544
+ const markAt = (index) => {
545
+ if (!reorderable || dropAt === null || noopSlot) return void 0;
546
+ if (dropAt === index) return "before";
547
+ return dropAt === total && index === total - 1 ? "after" : void 0;
548
+ };
549
+ const updatedAt = state.entries.reduce((latest, entry) => Math.max(latest, entry.updatedAt ?? 0), 0);
550
+ (0, import_react2.useEffect)(() => {
551
+ actions.loadAccounts();
552
+ const timer = setInterval(() => {
553
+ if (document.visibilityState !== "hidden") actions.loadAccounts();
554
+ }, 6e4);
555
+ return () => {
556
+ clearInterval(timer);
557
+ };
558
+ }, [actions.loadAccounts]);
559
+ const start = (next, label = "") => {
560
+ setEditor(next);
561
+ setName(label);
562
+ setKey("");
563
+ };
564
+ const cancel = () => {
565
+ setEditor(null);
566
+ setName("");
567
+ setKey("");
568
+ };
569
+ (0, import_react2.useEffect)(() => {
570
+ if (editor?.ref != null && !state.entries.some((entry) => entry.apiKeyEnv === editor.ref)) cancel();
571
+ }, [state.entries, editor]);
572
+ (0, import_react2.useEffect)(() => {
573
+ if (dragging !== null && !state.entries.some((entry) => entry.apiKeyEnv === dragging)) {
574
+ setDragging(null);
575
+ setDropAt(null);
576
+ }
577
+ }, [state.entries, dragging]);
578
+ const submit = async () => {
579
+ if (!editor) return;
580
+ const accepted = editor.kind === "add" ? await actions.addAccount(name, key) : editor.kind === "rename" ? await actions.renameAccount(editor.ref, name) : editor.kind === "key" ? await actions.replaceAccountKey(editor.ref, key) : await actions.removeAccount(editor.ref);
581
+ if (accepted) cancel();
582
+ };
583
+ const move = (ref, toIndex) => {
584
+ void actions.moveAccount(ref, toIndex);
585
+ };
586
+ const summary = total ? t("accountsSummary", { count: total, name: preferred ? preferred.name || t("accountDefault") : "" }) : t("accountsSummaryEmpty");
587
+ const editorTitle = (kind) => t(kind === "add" ? "accountAdd" : kind === "rename" ? "accountRename" : kind === "key" ? "accountReplaceKey" : "accountRemove");
588
+ const editorForm = (label = "") => editor ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
589
+ "form",
590
+ {
591
+ className: Section_default.accountEditor,
592
+ onSubmit: (event) => {
593
+ event.preventDefault();
594
+ void submit();
595
+ },
596
+ onKeyDown: (event) => {
597
+ if (event.key === "Escape") {
598
+ event.preventDefault();
599
+ cancel();
600
+ }
601
+ },
602
+ children: [
603
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountEditorHead, children: [
604
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountEditorTitle, children: editorTitle(editor.kind) }),
605
+ label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountEditorFor, children: label }) : null
606
+ ] }),
607
+ editor.kind === "remove" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountRemoveHint", { name }) }) : null,
608
+ editor.kind === "add" || editor.kind === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: Section_default.accountField, children: [
609
+ t("accountName"),
610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
611
+ "input",
612
+ {
613
+ className: Section_default.input,
614
+ value: name,
615
+ maxLength: 80,
616
+ required: true,
617
+ disabled: state.busy,
618
+ autoFocus: true,
619
+ onChange: (event) => {
620
+ setName(event.target.value);
621
+ }
622
+ }
623
+ )
624
+ ] }) : null,
625
+ editor.kind === "add" || editor.kind === "key" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
626
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: Section_default.accountField, children: [
627
+ t("keyLabel"),
628
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
629
+ "input",
630
+ {
631
+ className: Section_default.input,
632
+ type: "password",
633
+ autoComplete: "off",
634
+ value: key,
635
+ required: true,
636
+ disabled: state.busy,
637
+ autoFocus: true,
638
+ onChange: (event) => {
639
+ setKey(event.target.value);
640
+ }
641
+ }
642
+ )
643
+ ] }),
644
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountKeyHint") })
645
+ ] }) : null,
646
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountEditorActions, children: [
647
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
648
+ import_dsh_client_ui_primitives2.Button,
649
+ {
650
+ variant: "primary",
651
+ size: "sm",
652
+ type: "submit",
653
+ disabled: editor.kind === "key" ? state.busy || state.blocked : disabled,
654
+ children: t(state.busy ? "saving" : "accountConfirm")
655
+ }
656
+ ),
657
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", type: "button", disabled: state.busy, onClick: cancel, children: t("accountCancel") })
658
+ ] })
659
+ ]
660
+ }
661
+ ) : null;
662
+ const detail = (account, label) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountDetail, children: [
663
+ account.usage ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.accountUsage, children: WINDOWS.map((window) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
664
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
665
+ t(`usage_${window}`),
666
+ " \xB7 ",
667
+ account.usage[window].percent,
668
+ "%"
669
+ ] }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
671
+ "progress",
672
+ {
673
+ "data-level": barLevel(account.usage[window]),
674
+ max: 100,
675
+ value: Math.min(100, account.usage[window].percent),
676
+ "aria-label": `${label} ${t(`usage_${window}`)}`
677
+ }
678
+ ),
679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.hint, children: [
680
+ t("usageResets"),
681
+ " ",
682
+ new Date(account.usage[window].resetsAt).toLocaleString(locale)
683
+ ] })
684
+ ] }, window)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t(account.loading ? "usageLoading" : "usageUnavailable") }),
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountActions, children: [
686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", disabled, onClick: () => {
687
+ start({ kind: "rename", ref: account.apiKeyEnv }, label);
688
+ }, children: t("accountRename") }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", disabled: state.busy || state.blocked || account.writable === false, onClick: () => {
690
+ start({ kind: "key", ref: account.apiKeyEnv }, label);
691
+ }, children: t("accountReplaceKey") }),
692
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", disabled, onClick: () => {
693
+ start({ kind: "remove", ref: account.apiKeyEnv }, label);
694
+ }, children: t("accountRemove") })
695
+ ] })
696
+ ] });
697
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: open ? Section_default.card : Section_default.card + " " + Section_default.cardFolded, children: [
698
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.cardHead, children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
700
+ "button",
701
+ {
702
+ type: "button",
703
+ className: Section_default.cardTrigger,
704
+ "aria-expanded": open,
705
+ "aria-controls": "opencode-go-accounts",
706
+ onClick: () => {
707
+ setOpen(!open);
708
+ },
709
+ children: [
710
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardTitle, children: t("accountsTitle") }),
711
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardSub, children: summary }),
712
+ total > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: unreadable > 0 || ready < total ? "warning" : "success", children: t(unreadable > 0 ? "accountsAvailabilityFailed" : "accountsAvailability", { ready, total, failed: unreadable }) }) : null,
713
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: open ? Section_default.chevronOpen : Section_default.chevron })
714
+ ]
715
+ }
716
+ ),
717
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.trailing, children: [
718
+ updatedAt > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.cardStamp, title: new Date(updatedAt).toLocaleString(locale), children: [
719
+ t("usageLastUpdated"),
720
+ " ",
721
+ stampText(updatedAt, locale)
722
+ ] }) : null,
723
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
724
+ import_dsh_client_ui_primitives2.Button,
725
+ {
726
+ variant: "outline",
727
+ size: "sm",
728
+ disabled: state.refreshing,
729
+ onClick: actions.loadAccounts,
730
+ children: t(state.refreshing ? "usageRefreshing" : "accountsRefresh")
731
+ }
732
+ )
733
+ ] })
734
+ ] }),
735
+ open ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-accounts", className: Section_default.cardBody, children: [
736
+ state.blocked ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountsBlocked") }) : null,
737
+ state.failure ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(state.failure === "cleanup" ? "accountsCleanupFailed" : state.failure === "remove" ? "accountsRemoveKeyFailed" : state.failure === "read" ? "accountsReadFailed" : "accountsWriteFailed") }) : null,
738
+ !total ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountsEmpty") }) : null,
739
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
740
+ "div",
741
+ {
742
+ className: Section_default.accounts,
743
+ onDragEnter: (event) => {
744
+ if (reorderable && dragging !== null) event.preventDefault();
745
+ },
746
+ onDragOver: (event) => {
747
+ if (!reorderable || dragging === null) return;
748
+ event.preventDefault();
749
+ if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
750
+ setDropAt(slotAt(event.currentTarget, event.clientY));
751
+ },
752
+ onDrop: (event) => {
753
+ const source = dragging;
754
+ setDragging(null);
755
+ setDropAt(null);
756
+ if (source === null) return;
757
+ event.preventDefault();
758
+ const from = state.entries.findIndex((entry) => entry.apiKeyEnv === source);
759
+ if (from < 0) return;
760
+ const slot = Number.isFinite(event.clientY) ? slotAt(event.currentTarget, event.clientY) : dropAt;
761
+ if (slot === null) return;
762
+ const to = slot > from ? slot - 1 : slot;
763
+ if (to !== from) move(source, to);
764
+ },
765
+ onDragEnd: () => {
766
+ setDragging(null);
767
+ setDropAt(null);
768
+ },
769
+ children: state.entries.map((account, index) => {
770
+ const label = account.name || t("accountDefault");
771
+ const rolling = account.usage?.rolling;
772
+ const expanded = details === account.apiKeyEnv;
773
+ const panelId = `opencode-go-account-${index}`;
774
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
775
+ "div",
776
+ {
777
+ className: Section_default.accountRow,
778
+ "data-account-row": account.apiKeyEnv,
779
+ "data-dragging": dragging === account.apiKeyEnv ? "true" : void 0,
780
+ "data-drop": markAt(index),
781
+ onDragStart: (event) => {
782
+ if (!reorderable || event.target?.closest?.("[data-account-handle]") == null) {
783
+ event.preventDefault();
784
+ return;
785
+ }
786
+ if (event.dataTransfer) {
787
+ event.dataTransfer.effectAllowed = "move";
788
+ event.dataTransfer.setData("text/plain", account.apiKeyEnv);
789
+ if (typeof event.dataTransfer.setDragImage === "function") {
790
+ event.dataTransfer.setDragImage(event.currentTarget, 16, 16);
791
+ }
792
+ }
793
+ setDragging(account.apiKeyEnv);
794
+ },
795
+ children: [
796
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountMain, "data-account-main": "", children: [
797
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
798
+ "button",
799
+ {
800
+ type: "button",
801
+ className: Section_default.accountHandle,
802
+ "data-account-handle": "",
803
+ draggable: reorderable,
804
+ disabled: !reorderable,
805
+ title: t("accountDragHandle", { name: label }),
806
+ "aria-label": t("accountDragHandle", { name: label }),
807
+ onKeyDown: (event) => {
808
+ if (event.key === "ArrowUp" && index > 0) {
809
+ event.preventDefault();
810
+ move(account.apiKeyEnv, index - 1);
811
+ }
812
+ if (event.key === "ArrowDown" && index < total - 1) {
813
+ event.preventDefault();
814
+ move(account.apiKeyEnv, index + 1);
815
+ }
816
+ },
817
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GripIcon, {})
818
+ }
819
+ ),
820
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: Section_default.accountName, title: label, children: label }),
821
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.accountState, children: [
822
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountDot, "data-off": account.configured === false ? "true" : void 0 }),
823
+ account.configured === void 0 ? t(account.failed ? "accountsStatusUnknown" : "usageLoading") : account.configured ? t("keyConfigured") : t("keyMissing")
824
+ ] }),
825
+ rolling ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
827
+ "span",
828
+ {
829
+ className: Section_default.accountBar,
830
+ role: "progressbar",
831
+ "data-level": barLevel(rolling),
832
+ "aria-valuemin": 0,
833
+ "aria-valuemax": 100,
834
+ "aria-valuenow": Math.min(100, rolling.percent),
835
+ "aria-label": `${label} ${t("usage_rolling")}`,
836
+ children: [
837
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountBarFill, style: { width: `${Math.min(100, rolling.percent)}%` } }),
838
+ TICKS.map((at) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountBarTick, style: { left: `${at}%` } }, at))
839
+ ]
840
+ }
841
+ ),
842
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.accountPercent, children: [
843
+ rolling.percent,
844
+ "%"
845
+ ] }),
846
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountReset, children: resetText(rolling.resetsAt, t) })
847
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountIdle, children: account.configured === false ? t("accountConfigureHint") : t(account.loading ? "usageLoading" : "usageUnavailable") }),
848
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
849
+ "button",
850
+ {
851
+ type: "button",
852
+ className: Section_default.accountToggle,
853
+ "aria-expanded": expanded,
854
+ "aria-controls": panelId,
855
+ "aria-label": t(expanded ? "accountsDetailsHide" : "accountsDetails", { name: label }),
856
+ onClick: () => {
857
+ setDetails(expanded ? null : account.apiKeyEnv);
858
+ },
859
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: expanded ? Section_default.chevronOpen : Section_default.chevron })
860
+ }
861
+ )
862
+ ] }),
863
+ account.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountProblems, role: "alert", children: [
864
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: account.problem ?? t(account.stale ? "usageStaleHint" : "usageRefreshFailed") }),
865
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
866
+ "button",
867
+ {
868
+ type: "button",
869
+ className: Section_default.accountRetry,
870
+ disabled: state.refreshing,
871
+ onClick: actions.loadAccounts,
872
+ children: t("usageRetry")
873
+ }
874
+ )
875
+ ] }) : null,
876
+ expanded ? detail(account, label) : null,
877
+ editor?.ref === account.apiKeyEnv ? editorForm(label) : null
878
+ ]
879
+ }
880
+ ) }, account.id);
881
+ })
882
+ }
883
+ ),
884
+ editor ? editor.kind === "add" ? editorForm() : null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
885
+ import_dsh_client_ui_primitives2.Button,
886
+ {
887
+ variant: "outline",
888
+ size: "sm",
889
+ disabled: disabled || total >= MAX_ACCOUNTS,
890
+ onClick: () => {
891
+ start({ kind: "add" });
892
+ },
893
+ children: t("accountAdd")
894
+ }
895
+ ),
896
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
897
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
898
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("accountAutoSwitch") }),
899
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
900
+ import_dsh_client_ui_primitives2.Switch,
901
+ {
902
+ checked: state.autoSwitch,
903
+ disabled,
904
+ label: t("accountAutoSwitch"),
905
+ onChange: (next) => {
906
+ void actions.setAutoSwitch(next);
907
+ }
908
+ }
909
+ )
910
+ ] }),
911
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountAutoSwitchHint") })
912
+ ] })
913
+ ] }) : null
914
+ ] });
915
+ }
377
916
 
378
917
  // src/usage-display.ts
379
918
  var USAGE_DISPLAY_MODES = ["auto", "always", "off"];
380
919
  var DEFAULT_USAGE_DISPLAY = "auto";
381
920
 
382
921
  // src/client/Section.tsx
383
- var import_jsx_runtime2 = require("react/jsx-runtime");
384
- var ChevronDown = primitives.IconChevronDownOutlineRegular ?? primitives.IconChevronDownOutline14;
922
+ var import_jsx_runtime3 = require("react/jsx-runtime");
923
+ var ChevronDown2 = primitives2.IconChevronDownOutlineRegular ?? primitives2.IconChevronDownOutline14;
385
924
  function ValueField(props) {
386
925
  const hintId = props.id + "-hint";
387
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
388
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
389
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: Section_default.label, htmlFor: props.id, children: props.label }),
390
- props.field.overridden ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.badges, children: [
391
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: "neutral", children: props.overriddenLabel }),
392
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
926
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.field, children: [
927
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.head, children: [
928
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: Section_default.label, htmlFor: props.id, children: props.label }),
929
+ props.field.overridden ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: Section_default.badges, children: [
930
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: "neutral", children: props.overriddenLabel }),
931
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
393
932
  "button",
394
933
  {
395
934
  type: "button",
@@ -401,7 +940,7 @@ function ValueField(props) {
401
940
  )
402
941
  ] }) : null
403
942
  ] }),
404
- props.options ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
943
+ props.options ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
405
944
  "select",
406
945
  {
407
946
  id: props.id,
@@ -414,14 +953,15 @@ function ValueField(props) {
414
953
  onChange: (event) => {
415
954
  props.onEdit(event.target.value);
416
955
  },
417
- children: props.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: option.value, children: option.label }, option.value))
956
+ children: props.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: option.value, children: option.label }, option.value))
418
957
  }
419
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
958
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
420
959
  "input",
421
960
  {
422
961
  id: props.id,
423
962
  name: props.id,
424
963
  autoComplete: "off",
964
+ placeholder: props.placeholder,
425
965
  "aria-describedby": hintId,
426
966
  className: props.field.invalid ? Section_default.inputInvalid : Section_default.input,
427
967
  type: props.numeric === true ? "number" : "text",
@@ -434,7 +974,7 @@ function ValueField(props) {
434
974
  }
435
975
  }
436
976
  ),
437
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { id: hintId, className: props.field.invalid ? Section_default.invalid : Section_default.hint, children: props.field.invalid ? props.invalidLabel : props.hint })
977
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { id: hintId, className: props.field.invalid ? Section_default.invalid : Section_default.hint, children: props.field.invalid ? props.invalidLabel : props.hint })
438
978
  ] });
439
979
  }
440
980
  function ModelsBody({ models, t, locale }) {
@@ -442,39 +982,46 @@ function ModelsBody({ models, t, locale }) {
442
982
  const metadataOnlyFailure = sources?.metadata.error !== void 0 && sources.listing.error === void 0;
443
983
  const sourceStatus = sources ? ["listing", "metadata"].map((source) => {
444
984
  const status = sources[source];
445
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: Section_default.hint, children: [
985
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: Section_default.hint, children: [
446
986
  t(source === "listing" ? "modelsListingSource" : "modelsMetadataSource"),
447
987
  ": ",
448
988
  " ",
449
989
  status.error ? t("modelsSourceFailed") : t("modelsSourceCurrent"),
450
990
  ". ",
451
991
  " ",
452
- status.updatedAt === void 0 ? t("modelsSourceNeverFetched") : t("modelsSourceUpdated", { time: new Date(status.updatedAt).toLocaleString(locale) })
992
+ status.updatedAt === void 0 ? t("modelsSourceNeverFetched") : t("modelsSourceUpdated", { time: new Date(status.updatedAt).toLocaleString(locale) }),
993
+ status.warning ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
994
+ " ",
995
+ status.warning
996
+ ] }) : null
453
997
  ] }, source);
454
998
  }) : null;
455
999
  if (models.status === "failed") {
456
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
457
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsFailed") }),
458
- models.message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
1000
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1001
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsFailed") }),
1002
+ models.message ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
459
1003
  sourceStatus
460
1004
  ] });
461
1005
  }
462
- if (models.status !== "ready") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, role: "status", "aria-live": "polite", children: t("modelsLoading") });
463
- const progress = models.refreshing ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, role: "status", children: t("modelsRefreshing") }) : null;
464
- if (models.stale) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1006
+ if (models.status !== "ready") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, role: "status", "aria-live": "polite", children: t("modelsLoading") });
1007
+ const progress = models.refreshing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, role: "status", children: t("modelsRefreshing") }) : null;
1008
+ if (models.stale) return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
465
1009
  progress,
466
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsStale") }),
467
- models.message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
1010
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsStale") }),
1011
+ models.message ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
468
1012
  sourceStatus
469
1013
  ] });
470
- if (models.refreshing) return progress;
471
- if (models.count === 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("modelsEmpty") });
472
- return null;
1014
+ const warning = sources?.listing.warning ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: sources.listing.warning }) : null;
1015
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1016
+ progress,
1017
+ warning,
1018
+ models.count === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("modelsEmpty") }) : null
1019
+ ] });
473
1020
  }
474
1021
  function OpencodeGoSection(props) {
475
1022
  const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled, setModelEnabled, t } = props;
476
1023
  if (useOpencodeGo === void 0 || edit === void 0 || resetField === void 0 || save === void 0 || discard === void 0 || loadModels === void 0 || setEnabled === void 0 || setModelEnabled === void 0 || t === void 0) return null;
477
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1024
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
478
1025
  Loaded,
479
1026
  {
480
1027
  state: useOpencodeGo((snapshot) => snapshot),
@@ -486,43 +1033,63 @@ function OpencodeGoSection(props) {
486
1033
  discard,
487
1034
  loadModels,
488
1035
  setEnabled,
489
- setModelEnabled
1036
+ setModelEnabled,
1037
+ accountActions: props.loadAccounts && props.addAccount && props.renameAccount && props.removeAccount && props.selectAccount && props.setAutoSwitch && props.replaceAccountKey && props.moveAccount ? {
1038
+ loadAccounts: props.loadAccounts,
1039
+ addAccount: props.addAccount,
1040
+ renameAccount: props.renameAccount,
1041
+ removeAccount: props.removeAccount,
1042
+ selectAccount: props.selectAccount,
1043
+ setAutoSwitch: props.setAutoSwitch,
1044
+ replaceAccountKey: props.replaceAccountKey,
1045
+ moveAccount: props.moveAccount
1046
+ } : void 0
490
1047
  }
491
1048
  );
492
1049
  }
493
1050
  function Loaded(props) {
494
1051
  const { t, state, loadModels } = props;
495
- const [advanced, setAdvanced] = (0, import_react2.useState)(false);
496
- const [modelsOpen, setModelsOpen] = (0, import_react2.useState)(false);
497
- const modelNotices = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
498
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ModelsBody, { models: state.models, t, locale: props.locale }),
499
- state.pickerFailed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("pickerFailed") }) : null
1052
+ const [advanced, setAdvanced] = (0, import_react3.useState)(false);
1053
+ const [modelsOpen, setModelsOpen] = (0, import_react3.useState)(false);
1054
+ const modelNotices = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1055
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModelsBody, { models: state.models, t, locale: props.locale }),
1056
+ state.pickerFailed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("pickerFailed") }) : null
500
1057
  ] });
501
- (0, import_react2.useEffect)(() => {
1058
+ (0, import_react3.useEffect)(() => {
502
1059
  if (state.available && state.models.status === "idle") loadModels();
503
1060
  }, [state.available, state.models.status, loadModels]);
504
1061
  if (!state.available) {
505
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.intro, children: t("unavailable") });
1062
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.intro, children: t("unavailable") });
506
1063
  }
507
1064
  const disabled = !state.writable;
1065
+ const accountCard = state.accounts && props.accountActions ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1066
+ AccountsCard,
1067
+ {
1068
+ state: state.accounts,
1069
+ actions: props.accountActions,
1070
+ writable: state.writable,
1071
+ t,
1072
+ locale: props.locale
1073
+ }
1074
+ ) : null;
508
1075
  const fieldProps = {
509
1076
  invalidLabel: t("invalidValue"),
510
1077
  overriddenLabel: t("overridden"),
511
1078
  resetLabel: t("reset"),
512
1079
  disabled
513
1080
  };
514
- const advancedOverridden = state.usageDisplay.overridden || state.apiKeyEnv.overridden || state.baseURL.overridden || state.refreshMinutes.overridden || state.streamIdleTimeoutMs.overridden || state.maxImages.overridden || state.maxRequestImageBytes.overridden || state.requestImagePixelBudget.overridden || state.requestImageMaxBytes.overridden;
515
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.page, children: [
516
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.pageBody, children: [
517
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.pageTop, children: [
518
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: Section_default.title, children: t("titleLabel") }),
519
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.intro, children: t("intro") })
1081
+ const advancedOverridden = state.usageDisplay.overridden || state.protocolOverrides.overridden || state.apiKeyEnv.overridden || state.baseURL.overridden || state.proxyURL.overridden || state.refreshMinutes.overridden || state.streamIdleTimeoutMs.overridden || state.maxImages.overridden || state.maxRequestImageBytes.overridden || state.requestImagePixelBudget.overridden || state.requestImageMaxBytes.overridden;
1082
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.page, children: [
1083
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.pageBody, children: [
1084
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.pageTop, children: [
1085
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: Section_default.title, children: t("titleLabel") }),
1086
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.intro, children: t("intro") })
520
1087
  ] }),
521
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: Section_default.card, children: [
522
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.cardHead, children: [
523
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { className: Section_default.cardTitle, children: t("enabledLabel") }),
524
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
525
- import_dsh_client_ui_primitives2.Switch,
1088
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: Section_default.card, children: [
1089
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardHead, children: [
1090
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: Section_default.cardTitle, children: t("enabledLabel") }),
1091
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1092
+ import_dsh_client_ui_primitives3.Switch,
526
1093
  {
527
1094
  checked: state.enabled,
528
1095
  label: t("enabledLabel"),
@@ -531,38 +1098,41 @@ function Loaded(props) {
531
1098
  }
532
1099
  )
533
1100
  ] }),
534
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.cardBody, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: state.enabled ? t("enabledHint") : t("enabledOff") }) }),
535
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.cardDivider }),
536
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.cardHead, children: [
537
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.slot, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", focusable: "false", children: [
538
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "5.4", cy: "8", r: "3.1" }),
539
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8.5 8h5.3M11.9 8v2.2M10.2 8v1.6" })
540
- ] }) }),
541
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { className: Section_default.label, htmlFor: "opencode-go-key", children: t("keyLabel") }),
542
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.trailing, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: state.apiKeyConfigured ? "success" : "warning", children: state.apiKeyConfigured ? t("keyConfigured") : t("keyMissing") }) })
543
- ] }),
544
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.cardBody, children: [
545
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
546
- "input",
547
- {
548
- id: "opencode-go-key",
549
- name: "api-key",
550
- className: Section_default.input,
551
- type: "password",
552
- autoComplete: "off",
553
- "aria-describedby": "opencode-go-key-hint",
554
- value: state.apiKey.text,
555
- disabled: !state.apiKeyWritable,
556
- onChange: (event) => {
557
- props.edit("apiKey", event.target.value);
1101
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: Section_default.cardBody, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: state.enabled ? t("enabledHint") : t("enabledOff") }) }),
1102
+ accountCard ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1103
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: Section_default.cardDivider }),
1104
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardHead, children: [
1105
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.slot, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", focusable: "false", children: [
1106
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "5.4", cy: "8", r: "3.1" }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8.5 8h5.3M11.9 8v2.2M10.2 8v1.6" })
1108
+ ] }) }),
1109
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: Section_default.label, htmlFor: "opencode-go-key", children: t("keyLabel") }),
1110
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.trailing, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: state.apiKeyConfigured ? "success" : "warning", children: state.apiKeyConfigured ? t("keyConfigured") : t("keyMissing") }) })
1111
+ ] }),
1112
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardBody, children: [
1113
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1114
+ "input",
1115
+ {
1116
+ id: "opencode-go-key",
1117
+ name: "api-key",
1118
+ className: Section_default.input,
1119
+ type: "password",
1120
+ autoComplete: "off",
1121
+ "aria-describedby": "opencode-go-key-hint",
1122
+ value: state.apiKey.text,
1123
+ disabled: !state.apiKeyWritable,
1124
+ onChange: (event) => {
1125
+ props.edit("apiKey", event.target.value);
1126
+ }
558
1127
  }
559
- }
560
- ),
561
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { id: "opencode-go-key-hint", className: Section_default.hint, children: state.apiKeyWritable ? t("keyHint") : t("keyNotWritable") })
1128
+ ),
1129
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { id: "opencode-go-key-hint", className: Section_default.hint, children: state.apiKeyWritable ? t("keyHint") : t("keyNotWritable") })
1130
+ ] })
562
1131
  ] })
563
1132
  ] }),
564
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: modelsOpen ? Section_default.cardModels : Section_default.cardModels + " " + Section_default.cardFolded, children: [
565
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1133
+ accountCard,
1134
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: modelsOpen ? Section_default.cardModels : Section_default.cardModels + " " + Section_default.cardFolded, children: [
1135
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
566
1136
  "button",
567
1137
  {
568
1138
  type: "button",
@@ -573,14 +1143,14 @@ function Loaded(props) {
573
1143
  setModelsOpen(!modelsOpen);
574
1144
  },
575
1145
  children: [
576
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardTitle, children: t("modelsLabel") }),
577
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: modelsOpen ? Section_default.chevronOpen : Section_default.chevron })
1146
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardTitle, children: t("modelsLabel") }),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDown2, { className: modelsOpen ? Section_default.chevronOpen : Section_default.chevron })
578
1148
  ]
579
1149
  }
580
1150
  ),
581
- modelsOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-models", className: Section_default.cardBody, children: [
1151
+ modelsOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { id: "opencode-go-models", className: Section_default.cardBody, children: [
582
1152
  modelNotices,
583
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1153
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
584
1154
  ModelEditor,
585
1155
  {
586
1156
  models: state.models,
@@ -590,8 +1160,8 @@ function Loaded(props) {
590
1160
  disabled: disabled || state.saving,
591
1161
  modelVisibility: state.modelVisibility,
592
1162
  visibilitySaving: state.pickerSaving,
593
- filterAction: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
594
- import_dsh_client_ui_primitives2.Button,
1163
+ filterAction: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1164
+ import_dsh_client_ui_primitives3.Button,
595
1165
  {
596
1166
  variant: "outline",
597
1167
  size: "sm",
@@ -606,10 +1176,10 @@ function Loaded(props) {
606
1176
  }
607
1177
  }
608
1178
  )
609
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.cardNotes, children: modelNotices })
1179
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: Section_default.cardNotes, children: modelNotices })
610
1180
  ] }),
611
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: Section_default.card, children: [
612
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1181
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: Section_default.card, children: [
1182
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
613
1183
  "button",
614
1184
  {
615
1185
  type: "button",
@@ -620,17 +1190,17 @@ function Loaded(props) {
620
1190
  setAdvanced(!advanced);
621
1191
  },
622
1192
  children: [
623
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardTitle, children: t("advancedLabel") }),
624
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardSub, children: t("advancedSummary") }),
625
- advancedOverridden ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Tag, { tone: "neutral", children: t("overridden") }) : null,
626
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: advanced ? Section_default.chevronOpen : Section_default.chevron })
1193
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardTitle, children: t("advancedLabel") }),
1194
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardSub, children: t("advancedSummary") }),
1195
+ advancedOverridden ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: "neutral", children: t("overridden") }) : null,
1196
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDown2, { className: advanced ? Section_default.chevronOpen : Section_default.chevron })
627
1197
  ]
628
1198
  }
629
1199
  ),
630
- advanced ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-advanced", className: Section_default.cardBody, children: [
631
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("advancedHint") }),
632
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.advancedGrid, children: [
633
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1200
+ advanced ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { id: "opencode-go-advanced", className: Section_default.cardBody, children: [
1201
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("advancedHint") }),
1202
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.advancedGrid, children: [
1203
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
634
1204
  ValueField,
635
1205
  {
636
1206
  id: "opencode-go-usage-display",
@@ -647,7 +1217,27 @@ function Loaded(props) {
647
1217
  }
648
1218
  }
649
1219
  ),
650
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1220
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1221
+ ValueField,
1222
+ {
1223
+ id: "opencode-go-protocol-overrides",
1224
+ label: t("protocolOverridesLabel"),
1225
+ hint: t("protocolOverridesHint"),
1226
+ field: state.protocolOverrides,
1227
+ options: [
1228
+ { value: "auto", label: t("protocolOverridesAuto") },
1229
+ { value: "openai-responses", label: t("protocolOverridesResponses") }
1230
+ ],
1231
+ ...fieldProps,
1232
+ onEdit: (text) => {
1233
+ props.edit("protocolOverrides", text);
1234
+ },
1235
+ onReset: () => {
1236
+ props.resetField("protocolOverrides");
1237
+ }
1238
+ }
1239
+ ),
1240
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
651
1241
  ValueField,
652
1242
  {
653
1243
  id: "opencode-go-api-key-env",
@@ -663,7 +1253,7 @@ function Loaded(props) {
663
1253
  }
664
1254
  }
665
1255
  ),
666
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1256
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
667
1257
  ValueField,
668
1258
  {
669
1259
  id: "opencode-go-base-url",
@@ -679,7 +1269,25 @@ function Loaded(props) {
679
1269
  }
680
1270
  }
681
1271
  ),
682
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1272
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1273
+ ValueField,
1274
+ {
1275
+ id: "opencode-go-proxy-url",
1276
+ label: t("proxyURLLabel"),
1277
+ hint: t("proxyURLHint"),
1278
+ placeholder: "http://127.0.0.1:7890",
1279
+ field: state.proxyURL,
1280
+ ...fieldProps,
1281
+ invalidLabel: t("proxyURLInvalid"),
1282
+ onEdit: (text) => {
1283
+ props.edit("proxyURL", text);
1284
+ },
1285
+ onReset: () => {
1286
+ props.resetField("proxyURL");
1287
+ }
1288
+ }
1289
+ ),
1290
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
683
1291
  ValueField,
684
1292
  {
685
1293
  id: "opencode-go-refresh-minutes",
@@ -696,7 +1304,7 @@ function Loaded(props) {
696
1304
  }
697
1305
  }
698
1306
  ),
699
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1307
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
700
1308
  ValueField,
701
1309
  {
702
1310
  id: "opencode-go-stream-idle",
@@ -713,7 +1321,7 @@ function Loaded(props) {
713
1321
  }
714
1322
  }
715
1323
  ),
716
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1324
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
717
1325
  ValueField,
718
1326
  {
719
1327
  id: "opencode-go-max-images",
@@ -730,7 +1338,7 @@ function Loaded(props) {
730
1338
  }
731
1339
  }
732
1340
  ),
733
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1341
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
734
1342
  ValueField,
735
1343
  {
736
1344
  id: "opencode-go-max-request-image-bytes",
@@ -747,7 +1355,7 @@ function Loaded(props) {
747
1355
  }
748
1356
  }
749
1357
  ),
750
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1358
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
751
1359
  ValueField,
752
1360
  {
753
1361
  id: "opencode-go-image-pixel-budget",
@@ -764,7 +1372,7 @@ function Loaded(props) {
764
1372
  }
765
1373
  }
766
1374
  ),
767
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
768
1376
  ValueField,
769
1377
  {
770
1378
  id: "opencode-go-image-max-bytes",
@@ -784,12 +1392,12 @@ function Loaded(props) {
784
1392
  ] })
785
1393
  ] }) : null
786
1394
  ] }),
787
- disabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
1395
+ disabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
788
1396
  ] }),
789
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.actions, children: [
790
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", size: "md", disabled: disabled || !state.dirty || state.invalid || state.saving || state.pickerSaving, onClick: props.save, children: state.saving ? t("saving") : t("save") }),
791
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "md", disabled: disabled || !state.dirty || state.saving, onClick: props.discard, children: t("discard") }),
792
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1397
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.actions, children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "primary", size: "md", disabled: disabled || !state.dirty || state.invalid || state.saving || state.pickerSaving, onClick: props.save, children: state.saving ? t("saving") : t("save") }),
1399
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "outline", size: "md", disabled: disabled || !state.dirty || state.saving, onClick: props.discard, children: t("discard") }),
1400
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
793
1401
  "a",
794
1402
  {
795
1403
  className: Section_default.starLink,
@@ -798,12 +1406,12 @@ function Loaded(props) {
798
1406
  rel: "noopener noreferrer",
799
1407
  title: t("starProjectTitle"),
800
1408
  children: [
801
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "currentColor", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" }) }),
802
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: t("starProject") })
1409
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "currentColor", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" }) }),
1410
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("starProject") })
803
1411
  ]
804
1412
  }
805
1413
  ),
806
- state.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
1414
+ state.failed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
807
1415
  ] })
808
1416
  ] });
809
1417
  }
@@ -811,6 +1419,236 @@ function Loaded(props) {
811
1419
  // src/provider-identity.ts
812
1420
  var PROVIDER_ID = "dsh-opencode-go";
813
1421
 
1422
+ // src/config-contract.ts
1423
+ var SETTINGS_NAMESPACE = "llm-opencode-go";
1424
+ var PROFILE_ENTRY_ID = "opencode-go";
1425
+
1426
+ // src/settings-bridge.ts
1427
+ function settingsWriteResult(verdict, committed) {
1428
+ if (verdict === true) return "applied";
1429
+ if (verdict === false) return "rejected";
1430
+ return committed() ? "applied" : "unknown";
1431
+ }
1432
+
1433
+ // src/proxy-url.ts
1434
+ function assertProxyURL(raw) {
1435
+ const value = raw?.trim() ?? "";
1436
+ if (!value) return "";
1437
+ let url;
1438
+ try {
1439
+ url = new URL(value);
1440
+ } catch {
1441
+ throw new Error("OpenCode Go: proxy address must be a valid URL");
1442
+ }
1443
+ if (!["http:", "https:", "socks5:"].includes(url.protocol)) {
1444
+ throw new Error("OpenCode Go: proxy address must use http://, https:// or socks5://");
1445
+ }
1446
+ if (!url.hostname || url.port === "0" || url.pathname !== "" && url.pathname !== "/" || url.search || url.hash) {
1447
+ throw new Error("OpenCode Go: proxy address must contain a host and optional port, without a path, query or fragment");
1448
+ }
1449
+ try {
1450
+ decodeURIComponent(url.username);
1451
+ decodeURIComponent(url.password);
1452
+ } catch {
1453
+ throw new Error("OpenCode Go: proxy credentials contain invalid URL encoding");
1454
+ }
1455
+ return url.href;
1456
+ }
1457
+
1458
+ // src/protocol-contract.ts
1459
+ var RESPONSES_OVERRIDE_MODEL = "deepseek-v4.1-flash";
1460
+
1461
+ // src/account-operations.ts
1462
+ function visibleAccountsOf(settings) {
1463
+ const entries = [...accountsOf(settings)];
1464
+ for (const operation of settings.accountOperations ?? []) {
1465
+ if (!entries.some((account) => account.apiKeyEnv === operation.account.apiKeyEnv)) entries.push(operation.account);
1466
+ }
1467
+ return entries;
1468
+ }
1469
+
1470
+ // src/client/accounts-controller.ts
1471
+ function operationId() {
1472
+ return Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
1473
+ }
1474
+ var GoAccountsController = class {
1475
+ constructor(scope, ctx, readUsage, publish, blocked, execute = async (command) => {
1476
+ const response = await ctx.remote.opencodeGoAccounts.execute(command);
1477
+ return response.ok ? response.value : "unknown";
1478
+ }) {
1479
+ this.scope = scope;
1480
+ this.ctx = ctx;
1481
+ this.readUsage = readUsage;
1482
+ this.publish = publish;
1483
+ this.blocked = blocked;
1484
+ this.execute = execute;
1485
+ this.sync();
1486
+ }
1487
+ rows = /* @__PURE__ */ new Map();
1488
+ busy = false;
1489
+ refreshing = false;
1490
+ failure;
1491
+ epoch = 0;
1492
+ identity = "";
1493
+ loaded = false;
1494
+ disposed = false;
1495
+ addition;
1496
+ snapshot() {
1497
+ const config = this.scope.getSnapshot().value ?? {};
1498
+ return {
1499
+ entries: visibleAccountsOf(config).map((account) => ({ ...this.rows.get(account.apiKeyEnv), ...account })),
1500
+ activeRef: accountRefOf(config),
1501
+ autoSwitch: config.autoSwitch === true,
1502
+ busy: this.busy,
1503
+ blocked: this.blocked(),
1504
+ refreshing: this.refreshing,
1505
+ failure: this.failure
1506
+ };
1507
+ }
1508
+ sync() {
1509
+ const config = this.scope.getSnapshot().value ?? {};
1510
+ const identity = JSON.stringify([
1511
+ visibleAccountsOf(config).map((account) => [account.id, account.apiKeyEnv]).sort((left, right) => left[1] < right[1] ? -1 : left[1] > right[1] ? 1 : 0),
1512
+ config.baseURL,
1513
+ config.proxyURL
1514
+ ]);
1515
+ if (identity === this.identity) return;
1516
+ this.identity = identity;
1517
+ this.epoch++;
1518
+ this.rows.clear();
1519
+ this.refreshing = false;
1520
+ if (this.loaded) void this.refresh();
1521
+ }
1522
+ dispose() {
1523
+ this.disposed = true;
1524
+ this.epoch++;
1525
+ }
1526
+ invalidate(ref) {
1527
+ if (!visibleAccountsOf(this.scope.getSnapshot().value ?? {}).some((account) => account.apiKeyEnv === ref)) return;
1528
+ this.epoch++;
1529
+ this.rows.delete(ref);
1530
+ if (this.loaded) void this.refresh();
1531
+ }
1532
+ async refresh() {
1533
+ this.loaded = true;
1534
+ const epoch = ++this.epoch;
1535
+ const accounts = [...visibleAccountsOf(this.scope.getSnapshot().value ?? {})];
1536
+ this.refreshing = true;
1537
+ this.publish();
1538
+ try {
1539
+ const described = await this.ctx.remote.credentials.describe(accounts.map((account) => account.apiKeyEnv));
1540
+ if (this.disposed || epoch !== this.epoch) return;
1541
+ if (!described.ok) {
1542
+ this.failure = "read";
1543
+ this.markUnreadable(accounts, described.error instanceof Error ? described.error.message : String(described.error));
1544
+ return;
1545
+ }
1546
+ this.failure = void 0;
1547
+ await Promise.all(accounts.map(async (account) => {
1548
+ const ref = account.apiKeyEnv;
1549
+ const info = described.value[ref];
1550
+ const previous = this.rows.get(ref);
1551
+ this.rows.set(ref, {
1552
+ ...previous,
1553
+ ...account,
1554
+ configured: info?.configured ?? false,
1555
+ writable: info?.writable ?? true,
1556
+ loading: info?.configured === true,
1557
+ failed: false
1558
+ });
1559
+ this.publish();
1560
+ if (!info?.configured) {
1561
+ this.rows.set(ref, { ...account, configured: false, writable: info?.writable ?? true });
1562
+ return;
1563
+ }
1564
+ try {
1565
+ const usage = await this.readUsage(ref);
1566
+ if (this.disposed || epoch !== this.epoch) return;
1567
+ this.rows.set(ref, { ...account, configured: true, writable: info.writable, usage, updatedAt: Date.now() });
1568
+ } catch (error) {
1569
+ if (this.disposed || epoch !== this.epoch) return;
1570
+ const details = error && typeof error === "object" && "code" in error && error.code === "opencode-go/usage-unavailable" && "details" in error && error.details && typeof error.details === "object" ? error.details : void 0;
1571
+ const retain = details?.retryable === true && details.retainPrevious === true && previous?.usage?.source && previous.usage.source === details.source;
1572
+ const message = error instanceof Error ? error.message : String(error);
1573
+ this.rows.set(ref, {
1574
+ ...account,
1575
+ configured: true,
1576
+ writable: info.writable,
1577
+ failed: true,
1578
+ problem: message.length > 200 ? message.slice(0, 200) + "\u2026" : message,
1579
+ ...retain ? { usage: previous.usage, updatedAt: previous.updatedAt, stale: true } : {}
1580
+ });
1581
+ }
1582
+ this.publish();
1583
+ }));
1584
+ } catch (error) {
1585
+ if (epoch === this.epoch) {
1586
+ this.failure = "read";
1587
+ this.markUnreadable(accounts, error instanceof Error ? error.message : String(error));
1588
+ }
1589
+ } finally {
1590
+ if (!this.disposed && epoch === this.epoch) {
1591
+ this.refreshing = false;
1592
+ this.publish();
1593
+ }
1594
+ }
1595
+ }
1596
+ /** Mark every account row as unreadable with the Host's own diagnostic. */
1597
+ markUnreadable(accounts, message) {
1598
+ const problem = message.length > 200 ? message.slice(0, 200) + "\u2026" : message;
1599
+ for (const account of accounts) this.rows.set(account.apiKeyEnv, { ...account, failed: true, problem });
1600
+ this.publish();
1601
+ }
1602
+ actions() {
1603
+ const command = (request) => this.execute(request).then((status) => status === "applied");
1604
+ return {
1605
+ loadAccounts: () => {
1606
+ void this.refresh();
1607
+ },
1608
+ addAccount: (name, key) => this.run(async () => {
1609
+ if (!name.trim() || name.trim().length > 80 || !key.trim()) return false;
1610
+ const resumed = this.scope.getSnapshot().value?.accountOperations?.find((entry) => entry.kind === "add" && entry.account.name === name.trim());
1611
+ if (this.addition?.name !== name.trim()) this.addition = { name: name.trim(), id: resumed?.account.id ?? operationId() };
1612
+ const accepted = await command({ kind: "add", id: this.addition.id, name, key });
1613
+ if (accepted) this.addition = void 0;
1614
+ return accepted;
1615
+ }),
1616
+ renameAccount: (ref, name) => this.run(() => command({ kind: "rename", ref, name })),
1617
+ removeAccount: (ref) => this.run(async () => {
1618
+ const accepted = await command({ kind: "remove", ref });
1619
+ if (!accepted) this.failure = "remove";
1620
+ return accepted;
1621
+ }),
1622
+ selectAccount: (ref) => this.run(() => command({ kind: "select", ref })),
1623
+ setAutoSwitch: (value) => this.run(() => command({ kind: "auto-switch", value })),
1624
+ replaceAccountKey: (ref, key) => this.run(async () => {
1625
+ if (!key.trim() || this.rows.get(ref)?.writable === false) return false;
1626
+ const accepted = await command({ kind: "replace-key", ref, key });
1627
+ if (accepted) this.invalidate(ref);
1628
+ return accepted;
1629
+ }, false),
1630
+ moveAccount: (ref, toIndex) => this.run(() => command({ kind: "move", ref, toIndex }))
1631
+ };
1632
+ }
1633
+ async run(action, requiresSettings = true) {
1634
+ if (this.busy || this.blocked() || requiresSettings && !this.scope.getSnapshot().writable) return false;
1635
+ this.busy = true;
1636
+ this.failure = void 0;
1637
+ this.publish();
1638
+ try {
1639
+ const accepted = await action();
1640
+ if (!accepted && !this.failure) this.failure = "write";
1641
+ return accepted;
1642
+ } catch {
1643
+ this.failure ??= "write";
1644
+ return false;
1645
+ } finally {
1646
+ this.busy = false;
1647
+ this.publish();
1648
+ }
1649
+ }
1650
+ };
1651
+
814
1652
  // src/client/staged-form.ts
815
1653
  var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
816
1654
  function numberField(field, validate = () => true) {
@@ -910,7 +1748,7 @@ var StagedForm = class {
910
1748
  available: snapshot.status === "ready",
911
1749
  writable: snapshot.writable,
912
1750
  dirty: plan.length > 0,
913
- invalid: plan.some((item) => item.run === void 0),
1751
+ invalid: plan.some((item) => item.run === void 0 && item.write === void 0),
914
1752
  saving: this.saving,
915
1753
  failed: this.failed
916
1754
  };
@@ -971,16 +1809,34 @@ var StagedForm = class {
971
1809
  */
972
1810
  async save() {
973
1811
  const plan = this.plan();
974
- const writes = plan.flatMap((item) => item.run === void 0 ? [] : [item.run]);
975
- if (plan.length === 0 || this.saving || writes.length !== plan.length) return;
1812
+ if (plan.length === 0 || this.saving || plan.some((item) => !item.write && !item.run)) return;
1813
+ const revision = this.snapshotOf().revision;
976
1814
  this.saving = true;
977
1815
  this.failed = false;
978
1816
  this.publish();
979
1817
  let landed = true;
980
- for (const write of writes) {
981
- landed = await write() && landed;
1818
+ const settings = plan.filter((item) => item.write !== void 0);
1819
+ const accept = (item) => {
1820
+ if (this.staged.get(item.field) === item.edit) this.staged.delete(item.field);
1821
+ };
1822
+ if (settings.length > 0) {
1823
+ const ops = settings.map(({ field, write }) => write.kind === "clear" ? { op: "unset", path: [field] } : { op: "set", path: [field], value: write.value });
1824
+ try {
1825
+ const accepted = await this.scope.mutate(ops, revision);
1826
+ landed = settingsWriteResult(accepted, () => settings.every((item) => item.write.kind === "clear" ? !this.stored(item.field) : sameJsonValue(this.userLayer()?.[item.field], item.write.value))) === "applied";
1827
+ if (landed) settings.forEach(accept);
1828
+ } catch {
1829
+ landed = false;
1830
+ }
1831
+ }
1832
+ if (landed) for (const item of plan.filter((item2) => item2.run !== void 0)) {
1833
+ try {
1834
+ if (await item.run()) accept(item);
1835
+ else landed = false;
1836
+ } catch {
1837
+ landed = false;
1838
+ }
982
1839
  }
983
- if (landed) this.staged.clear();
984
1840
  this.saving = false;
985
1841
  this.failed = !landed;
986
1842
  this.publish();
@@ -997,30 +1853,20 @@ var StagedForm = class {
997
1853
  const secret = this.secretSpecs.get(field);
998
1854
  if (secret !== void 0) {
999
1855
  const value = staged.text.trim();
1000
- if (value !== "") plan.push({ field, run: () => secret.write(value) });
1856
+ if (value !== "") plan.push({ field, edit: staged, run: () => secret.write(value) });
1001
1857
  continue;
1002
1858
  }
1003
1859
  const spec = this.spec(field);
1004
1860
  if (staged.clear) {
1005
- if (this.stored(field)) plan.push({ field, run: () => this.clear(field) });
1861
+ if (this.stored(field)) plan.push({ field, edit: staged, write: { kind: "clear" }, run: void 0 });
1006
1862
  continue;
1007
1863
  }
1008
1864
  if (this.unchangedDraft(field, staged)) continue;
1009
1865
  const write = spec.parse(staged.text);
1010
- if (write === void 0) plan.push({ field, run: void 0 });
1011
- else if (write.kind === "clear") plan.push({ field, run: () => this.clear(field) });
1012
- else plan.push({ field, run: () => this.store(field, write.value) });
1866
+ plan.push({ field, edit: staged, write, run: void 0 });
1013
1867
  }
1014
1868
  return plan;
1015
1869
  }
1016
- async clear(field) {
1017
- await this.scope.unset(field);
1018
- return !this.stored(field);
1019
- }
1020
- async store(field, value) {
1021
- await this.scope.set(field, value);
1022
- return sameJsonValue(this.userLayer()?.[field], value);
1023
- }
1024
1870
  stage(field, edit) {
1025
1871
  this.staged.set(field, edit);
1026
1872
  this.failed = false;
@@ -1076,8 +1922,7 @@ function sameJsonValue(left, right) {
1076
1922
  }
1077
1923
 
1078
1924
  // src/client/section-controller.ts
1079
- var OPENCODE_GO_NS = "llm-opencode-go";
1080
- var DEFAULT_API_KEY_REF = "OPENCODE_API_KEY";
1925
+ var OPENCODE_GO_NS = SETTINGS_NAMESPACE;
1081
1926
  var API_KEY_FIELD = "apiKey";
1082
1927
  var OpencodeGoSectionController = class {
1083
1928
  /**
@@ -1088,10 +1933,18 @@ var OpencodeGoSectionController = class {
1088
1933
  constructor(scope, ctx, readModels = async () => {
1089
1934
  const result = await ctx.remote.llm.discoverModels(OPENCODE_GO_NS, { provider: PROVIDER_ID });
1090
1935
  return result.ok ? { ok: true, value: { models: result.value, stale: false } } : result;
1936
+ }, readUsage = async (ref) => {
1937
+ const result = await ctx.remote.opencodeGoUsage.readAccount(ref);
1938
+ if (!result.ok) throw result.error;
1939
+ return result.value;
1940
+ }, executeAccountCommand = async (command) => {
1941
+ const result = await ctx.remote.opencodeGoAccounts.execute(command);
1942
+ return result.ok ? result.value : "unknown";
1091
1943
  }) {
1092
1944
  this.scope = scope;
1093
1945
  this.ctx = ctx;
1094
1946
  this.readModels = readModels;
1947
+ this.executeAccountCommand = executeAccountCommand;
1095
1948
  this.form = new StagedForm(
1096
1949
  scope,
1097
1950
  [
@@ -1103,8 +1956,25 @@ var OpencodeGoSectionController = class {
1103
1956
  format: (value) => typeof value === "string" ? value : DEFAULT_USAGE_DISPLAY,
1104
1957
  parse: (text) => USAGE_DISPLAY_MODES.some((mode) => mode === text) ? { kind: "set", value: text } : void 0
1105
1958
  },
1959
+ {
1960
+ field: "protocolOverrides",
1961
+ format: (value) => value?.[RESPONSES_OVERRIDE_MODEL] ?? "auto",
1962
+ parse: (text) => text === "auto" || text === "openai-responses" ? { kind: "set", value: { [RESPONSES_OVERRIDE_MODEL]: text === "auto" ? null : text } } : void 0
1963
+ },
1106
1964
  textField("apiKeyEnv"),
1107
1965
  textField("baseURL"),
1966
+ {
1967
+ ...textField("proxyURL"),
1968
+ // Blank explicitly disables an inherited proxy; Reset removes the override.
1969
+ parse: (text) => {
1970
+ try {
1971
+ assertProxyURL(text);
1972
+ return { kind: "set", value: text.trim() };
1973
+ } catch {
1974
+ return void 0;
1975
+ }
1976
+ }
1977
+ },
1108
1978
  numberField("refreshMinutes"),
1109
1979
  numberField("streamIdleTimeoutMs"),
1110
1980
  numberField("maxImages", (value) => Number.isSafeInteger(value) && value > 0),
@@ -1116,9 +1986,26 @@ var OpencodeGoSectionController = class {
1116
1986
  [{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]
1117
1987
  );
1118
1988
  this.store = this.form.bind(() => this.projection());
1119
- let modelsEndpoint = scope.getSnapshot().value?.baseURL;
1989
+ this.accounts = new GoAccountsController(
1990
+ scope,
1991
+ ctx,
1992
+ readUsage,
1993
+ () => {
1994
+ this.store.set(this.projection());
1995
+ },
1996
+ () => this.form.shell().saving || this.pickerSaving || Boolean(this.form.field(API_KEY_FIELD).text.trim()),
1997
+ this.executeAccountCommand
1998
+ );
1999
+ this.store.set(this.projection());
2000
+ const networkIdentity = () => JSON.stringify([
2001
+ scope.getSnapshot().value?.baseURL,
2002
+ scope.getSnapshot().value?.proxyURL
2003
+ ]);
2004
+ let modelsEndpoint = networkIdentity();
1120
2005
  this.unsubscribe = scope.subscribe(() => {
1121
- const endpoint = scope.getSnapshot().value?.baseURL;
2006
+ this.accounts?.sync();
2007
+ this.store.set(this.projection());
2008
+ const endpoint = networkIdentity();
1122
2009
  if (endpoint !== modelsEndpoint) {
1123
2010
  modelsEndpoint = endpoint;
1124
2011
  this.modelsRequest++;
@@ -1138,8 +2025,13 @@ var OpencodeGoSectionController = class {
1138
2025
  pickerFailed = false;
1139
2026
  face;
1140
2027
  unsubscribe;
2028
+ accounts;
2029
+ credentialRequest = 0;
2030
+ keyDraftRef;
1141
2031
  /** Release subscriptions without disposing the host's shared form. */
1142
2032
  dispose() {
2033
+ this.credentialRequest++;
2034
+ this.accounts?.dispose();
1143
2035
  this.modelsRequest++;
1144
2036
  this.unsubscribe();
1145
2037
  this.form.dispose();
@@ -1147,13 +2039,17 @@ var OpencodeGoSectionController = class {
1147
2039
  projection() {
1148
2040
  return {
1149
2041
  ...this.form.shell(),
2042
+ saving: this.form.shell().saving || this.accounts?.snapshot().busy === true,
2043
+ accounts: this.accounts?.snapshot(),
1150
2044
  enabled: this.enabled(),
1151
2045
  usageDisplay: this.form.field("usageDisplay"),
2046
+ protocolOverrides: this.form.field("protocolOverrides"),
1152
2047
  modelVisibility: this.scope.getSnapshot().value?.modelVisibility ?? {},
1153
2048
  pickerSaving: this.pickerSaving,
1154
2049
  pickerFailed: this.pickerFailed,
1155
2050
  apiKeyEnv: this.form.field("apiKeyEnv"),
1156
2051
  baseURL: this.form.field("baseURL"),
2052
+ proxyURL: this.form.field("proxyURL"),
1157
2053
  refreshMinutes: this.form.field("refreshMinutes"),
1158
2054
  streamIdleTimeoutMs: this.form.field("streamIdleTimeoutMs"),
1159
2055
  maxImages: this.form.field("maxImages"),
@@ -1161,7 +2057,7 @@ var OpencodeGoSectionController = class {
1161
2057
  requestImagePixelBudget: this.form.field("requestImagePixelBudget"),
1162
2058
  requestImageMaxBytes: this.form.field("requestImageMaxBytes"),
1163
2059
  apiKey: this.form.field(API_KEY_FIELD),
1164
- apiKeyConfigured: this.credential.configured,
2060
+ apiKeyConfigured: this.credential.ref === refOf(this.scope.getSnapshot()) && this.credential.configured && accountsOf(this.scope.getSnapshot().value ?? {}).length > 0,
1165
2061
  apiKeyWritable: this.credential.writable,
1166
2062
  models: this.models,
1167
2063
  modelLimits: this.form.field("modelLimits"),
@@ -1218,13 +2114,13 @@ var OpencodeGoSectionController = class {
1218
2114
  }
1219
2115
  /** Serialize immediate switches with form saves; refused writes retain committed values. */
1220
2116
  async writePickerSetting(field, value, accepted) {
1221
- if (this.pickerSaving || this.form.shell().saving || !this.scope.getSnapshot().writable) return;
2117
+ if (this.pickerSaving || this.form.shell().saving || this.accounts?.snapshot().busy || !this.scope.getSnapshot().writable) return;
1222
2118
  this.pickerSaving = true;
1223
2119
  this.pickerFailed = false;
1224
2120
  this.store.set(this.projection());
1225
2121
  try {
1226
- await this.scope.set(field, value);
1227
- this.pickerFailed = !accepted();
2122
+ const verdict = await this.scope.set(field, value);
2123
+ this.pickerFailed = settingsWriteResult(verdict, accepted) !== "applied";
1228
2124
  } catch {
1229
2125
  this.pickerFailed = true;
1230
2126
  } finally {
@@ -1283,13 +2179,19 @@ var OpencodeGoSectionController = class {
1283
2179
  * reference in force.
1284
2180
  */
1285
2181
  async readCredential() {
2182
+ const request = ++this.credentialRequest;
1286
2183
  const ref = refOf(this.scope.getSnapshot());
2184
+ if (accountsOf(this.scope.getSnapshot().value ?? {}).length === 0) {
2185
+ this.credential = { ref, configured: false, writable: false };
2186
+ this.store.set(this.projection());
2187
+ return;
2188
+ }
1287
2189
  if (ref !== this.credential.ref) {
1288
2190
  this.credential = { ref, configured: false, writable: true };
1289
2191
  this.store.set(this.projection());
1290
2192
  }
1291
- const response = await this.ctx.remote.credentials.describe([ref]);
1292
- if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return;
2193
+ const response = await this.ctx.remote.credentials.describe([ref]).catch(() => void 0);
2194
+ if (!response?.ok || request !== this.credentialRequest || ref !== refOf(this.scope.getSnapshot())) return;
1293
2195
  const view = response.value[ref];
1294
2196
  const next = {
1295
2197
  ref,
@@ -1311,6 +2213,7 @@ var OpencodeGoSectionController = class {
1311
2213
  * @param ref - the reference the Host reports as changed.
1312
2214
  */
1313
2215
  refreshCredential(ref) {
2216
+ this.accounts?.invalidate(ref);
1314
2217
  if (ref !== this.credential.ref) return;
1315
2218
  void this.readCredential();
1316
2219
  }
@@ -1331,19 +2234,38 @@ var OpencodeGoSectionController = class {
1331
2234
  setModelEnabled: (id3, next) => {
1332
2235
  void this.setModelEnabled(id3, next);
1333
2236
  },
1334
- ...this.form.actions()
2237
+ ...this.form.actions(),
2238
+ ...this.accounts.actions(),
2239
+ edit: (field, text) => {
2240
+ if (field === API_KEY_FIELD) {
2241
+ if (text.trim()) this.keyDraftRef ??= refOf(this.scope.getSnapshot());
2242
+ else this.keyDraftRef = void 0;
2243
+ }
2244
+ this.form.actions().edit(field, text);
2245
+ },
2246
+ discard: () => {
2247
+ this.keyDraftRef = void 0;
2248
+ this.form.actions().discard();
2249
+ },
2250
+ save: () => {
2251
+ if (!this.accounts?.snapshot().busy) void this.form.save().then(() => {
2252
+ if (!this.form.field(API_KEY_FIELD).text.trim()) this.keyDraftRef = void 0;
2253
+ });
2254
+ }
1335
2255
  };
1336
2256
  return this.face;
1337
2257
  }
1338
2258
  /**
1339
- * Write the staged key, then re-read whether the Host now holds one.
2259
+ * Ask the account service to write the staged key, then refresh its display.
1340
2260
  * @param value - the staged credential literal.
1341
- * @returns whether the Host reports a configured credential afterwards.
2261
+ * @returns whether the Host confirmed the write.
1342
2262
  */
1343
2263
  async writeKey(value) {
1344
- await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value);
2264
+ const ref = this.keyDraftRef ?? refOf(this.scope.getSnapshot());
2265
+ if (await this.executeAccountCommand({ kind: "replace-key", ref, key: value }) !== "applied") return false;
2266
+ this.accounts?.invalidate(ref);
1345
2267
  await this.readCredential();
1346
- return this.credential.configured;
2268
+ return true;
1347
2269
  }
1348
2270
  };
1349
2271
  function modelLimitsOf(value) {
@@ -1359,26 +2281,70 @@ function modelLimitsOf(value) {
1359
2281
  const limit = {};
1360
2282
  if (fields.contextWindow === null) limit.contextWindow = null;
1361
2283
  if (fields.maxTokens === null) limit.maxTokens = null;
2284
+ if (fields.thinkingBudgets === null) limit.thinkingBudgets = null;
2285
+ if (Array.isArray(fields.thinkingBudgets) && fields.thinkingBudgets.length <= 16 && fields.thinkingBudgets.every((value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 > 0)) {
2286
+ limit.thinkingBudgets = fields.thinkingBudgets;
2287
+ }
1362
2288
  if (typeof fields.contextWindow === "number" && Number.isSafeInteger(fields.contextWindow) && fields.contextWindow > 0) {
1363
2289
  limit.contextWindow = fields.contextWindow;
1364
2290
  }
1365
2291
  if (typeof fields.maxTokens === "number" && Number.isSafeInteger(fields.maxTokens) && fields.maxTokens > 0) {
1366
2292
  limit.maxTokens = fields.maxTokens;
1367
2293
  }
1368
- if (limit.contextWindow !== void 0 || limit.maxTokens !== void 0) limits[id3] = limit;
2294
+ if (limit.contextWindow !== void 0 || limit.maxTokens !== void 0 || limit.thinkingBudgets !== void 0) limits[id3] = limit;
1369
2295
  }
1370
2296
  return limits;
1371
2297
  }
1372
2298
  function refOf(snapshot) {
1373
- const declared = snapshot.value?.apiKeyEnv;
1374
- return declared !== void 0 && declared.length > 0 ? declared : DEFAULT_API_KEY_REF;
2299
+ return accountRefOf(snapshot.value ?? {});
1375
2300
  }
1376
2301
 
1377
2302
  // src/client/locales.ts
1378
2303
  var en = {
2304
+ accountsTitle: "Accounts",
2305
+ accountsRefresh: "Refresh accounts",
2306
+ accountsBlocked: "Save or discard the API key draft before changing accounts.",
2307
+ accountsEmpty: "Add an account to use OpenCode Go.",
2308
+ accountsWriteFailed: "Could not apply the account change. Your input is kept; please retry.",
2309
+ accountsReadFailed: "Could not read account status. Please refresh.",
2310
+ accountsCleanupFailed: "The account entry was removed, but its stored key could not be deleted. Remove the unused reference through the host credential service.",
2311
+ accountsRemoveKeyFailed: "The stored key could not be deleted, so the account was kept. Please retry.",
2312
+ accountsStatusUnknown: "Status unknown",
2313
+ accountDefault: "Default account",
2314
+ accountAdd: "Add account",
2315
+ accountRename: "Rename",
2316
+ accountReplaceKey: "Replace key",
2317
+ accountRemove: "Remove account",
2318
+ accountRemoveHint: "Remove \u201C{name}\u201D? If it is the current account, the next account takes over. Keys added here are deleted from the credential service; existing external references are kept.",
2319
+ accountName: "Account name",
2320
+ accountKeyHint: "The key is saved through the host credential service and is never returned to this page.",
2321
+ accountConfirm: "Confirm",
2322
+ accountCancel: "Cancel",
2323
+ accountAutoSwitch: "Automatic fallback",
2324
+ accountAutoSwitchHint: "When a quota runs out or a key is unusable, the other accounts are tried in the Settings page order before any content or tool call is emitted; once an account starts producing output, it becomes the current account.",
2325
+ accountPreferredTag: "Current",
2326
+ accountSwitchAction: "Switch",
2327
+ accountSwitchTitle: "Switch account",
2328
+ accountSwitchBack: "Back to usage",
2329
+ accountSwitchHint: "Later requests in this profile use this account. The consumption order stays on the Settings page.",
2330
+ accountSwitchFailed: "Could not switch account. Please retry.",
2331
+ accountFallbackQuota: "The current account reached its quota; switched to",
2332
+ accountFallbackCredential: "The current key was unavailable or rejected; switched to",
2333
+ accountsSummary: "{count} accounts \xB7 Current {name}",
2334
+ accountsSummaryEmpty: "No accounts yet",
2335
+ accountsAvailability: "{ready}/{total} configured",
2336
+ accountsAvailabilityFailed: "{ready}/{total} configured \xB7 {failed} unreadable",
2337
+ accountsDetails: "Details for {name}",
2338
+ accountsDetailsHide: "Hide details for {name}",
2339
+ accountDragHandle: "Reorder {name}",
2340
+ accountConfigureHint: "Add a key to read usage",
2341
+ usageResetMinutes: "resets in {minutes} min",
2342
+ usageResetHours: "resets in {hours} h",
2343
+ usageResetDays: "resets in {days} d",
2344
+ usageResetDue: "resets now",
2345
+ usageResetUnknown: "reset time unknown",
1379
2346
  usageTitle: "OpenCode Go usage",
1380
2347
  usageRollingShort: "5h",
1381
- usageHint: "Account usage \xB7 used percentage \xB7 refreshes every minute",
1382
2348
  usageWeekShort: "week",
1383
2349
  usage_rolling: "5 hours",
1384
2350
  usage_weekly: "Weekly",
@@ -1388,6 +2354,7 @@ var en = {
1388
2354
  usageLoading: "Loading usage\u2026",
1389
2355
  usageUnavailable: "Unavailable",
1390
2356
  usageStaleShort: "Last data",
2357
+ usageFallbackShort: "fallback",
1391
2358
  usageStaleHint: "Showing the last successful usage reading. Current usage may have changed.",
1392
2359
  usageRefreshFailed: "Refresh failed",
1393
2360
  usageLastUpdated: "Last updated",
@@ -1430,6 +2397,11 @@ var en = {
1430
2397
  limitsModel: "Model",
1431
2398
  limitsContext: "Context window",
1432
2399
  limitsOutput: "Max output",
2400
+ thinkingBudgets: "Thinking budgets",
2401
+ thinkingBudgetsHint: "Add token budgets to the conversation picker, then Save. Range: {min}\u2013{max} tokens. Existing reasoning choices stay available; Default uses the service settings. The SDK may reduce a budget to leave room for the answer.",
2402
+ thinkingBudgetAddLabel: "New thinking budget for {name}",
2403
+ thinkingBudgetAdd: "Add",
2404
+ thinkingBudgetRemove: "Remove {value} token budget",
1433
2405
  capacityDefault: "Default: {value} tokens",
1434
2406
  capacityMissing: "API did not provide a value",
1435
2407
  modalityLabel: "Input modalities",
@@ -1465,7 +2437,7 @@ var en = {
1465
2437
  limitsEmpty: "Read the model list first; capacities are edited per model the gateway serves.",
1466
2438
  limitsContextLabel: "Context window for {name}",
1467
2439
  limitsOutputLabel: "Max output for {name}",
1468
- advancedSummary: "Usage display \xB7 Credential name \xB7 Gateway URL \xB7 Refresh \xB7 Idle timeout \xB7 Image limits",
2440
+ advancedSummary: "Usage display \xB7 Protocol \xB7 Credential name \xB7 Gateway URL \xB7 Refresh \xB7 Idle timeout \xB7 Image limits",
1469
2441
  advancedLabel: "Advanced settings",
1470
2442
  advancedHint: "Usage display, credential name, gateway URL, and adapter tuning. The inherited values work as they are; change them only if you know you need to.",
1471
2443
  usageDisplayLabel: "Usage display",
@@ -1473,10 +2445,17 @@ var en = {
1473
2445
  usageDisplay_auto: "Auto (default)",
1474
2446
  usageDisplay_always: "Always",
1475
2447
  usageDisplay_off: "Off",
2448
+ protocolOverridesLabel: "DeepSeek V4.1 Flash protocol",
2449
+ protocolOverridesHint: "Auto follows the model catalog. Responses is experimental and applies only to DeepSeek V4.1 Flash; speed depends on the gateway. Save to apply to new requests. Choose Auto to restore catalog routing.",
2450
+ protocolOverridesAuto: "Auto (default)",
2451
+ protocolOverridesResponses: "Responses (experimental)",
1476
2452
  apiKeyEnvLabel: "Credential reference",
1477
2453
  apiKeyEnvHint: "The name the key is resolved from, addressed through the credentials service.",
1478
2454
  baseURLLabel: "Gateway URL",
1479
2455
  baseURLHint: "The endpoint that serves requests and the live model list.",
2456
+ proxyURLLabel: "Proxy address",
2457
+ proxyURLHint: "HTTP(S) or SOCKS5 proxy for conversations, model updates and usage. For example, socks5://127.0.0.1:1080. Leave blank to use the default network settings. The address is relative to the machine running DSH.",
2458
+ proxyURLInvalid: "Enter an http://, https:// or socks5:// proxy address without a path, query or fragment.",
1480
2459
  refreshMinutesLabel: "Catalog refresh (minutes)",
1481
2460
  refreshMinutesHint: "Catalog cache lifetime for conversations and model pickers. Opening this settings page or clicking Refresh checks the gateway and online model metadata immediately.",
1482
2461
  streamIdleTimeoutMsLabel: "Stream idle timeout (ms)",
@@ -1500,9 +2479,50 @@ var en = {
1500
2479
  unavailable: "The OpenCode Go settings are not served in this deployment."
1501
2480
  };
1502
2481
  var zh = {
2482
+ accountsTitle: "\u8D26\u53F7",
2483
+ accountsRefresh: "\u5237\u65B0\u989D\u5EA6",
2484
+ accountsBlocked: "\u8BF7\u5148\u4FDD\u5B58\u6216\u653E\u5F03 API Key \u8349\u7A3F\uFF0C\u518D\u5207\u6362\u6216\u4FEE\u6539\u8D26\u53F7\u3002",
2485
+ accountsEmpty: "\u6DFB\u52A0\u8D26\u53F7\u540E\u5373\u53EF\u4F7F\u7528 OpenCode Go\u3002",
2486
+ accountsWriteFailed: "\u8D26\u53F7\u4FEE\u6539\u672A\u751F\u6548\uFF0C\u8F93\u5165\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2487
+ accountsReadFailed: "\u672A\u80FD\u8BFB\u53D6\u8D26\u53F7\u72B6\u6001\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5\u3002",
2488
+ accountsCleanupFailed: "\u8D26\u53F7\u6761\u76EE\u5DF2\u79FB\u9664\uFF0C\u4F46\u4FDD\u5B58\u7684 Key \u672A\u80FD\u5220\u9664\u3002\u8BF7\u901A\u8FC7\u5BBF\u4E3B\u51ED\u636E\u670D\u52A1\u5220\u9664\u672A\u4F7F\u7528\u7684\u5F15\u7528\u3002",
2489
+ accountsRemoveKeyFailed: "\u672A\u80FD\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key\uFF0C\u8D26\u53F7\u6682\u65F6\u4FDD\u7559\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2490
+ accountsStatusUnknown: "\u72B6\u6001\u672A\u77E5",
2491
+ accountDefault: "\u9ED8\u8BA4\u8D26\u53F7",
2492
+ accountAdd: "\u6DFB\u52A0\u8D26\u53F7",
2493
+ accountRename: "\u91CD\u547D\u540D",
2494
+ accountReplaceKey: "\u66FF\u6362 Key",
2495
+ accountRemove: "\u5220\u9664\u8D26\u53F7",
2496
+ accountRemoveHint: "\u5220\u9664\u201C{name}\u201D\uFF1F\u82E5\u5B83\u662F\u5F53\u524D\u8D26\u53F7\uFF0C\u5C06\u4F7F\u7528\u4E0B\u4E00\u4E2A\u8D26\u53F7\u3002\u5728\u8FD9\u91CC\u6DFB\u52A0\u7684 Key \u4F1A\u4ECE\u51ED\u636E\u670D\u52A1\u5220\u9664\uFF1B\u5DF2\u6709\u5916\u90E8\u5F15\u7528\u4F1A\u4FDD\u7559\u3002",
2497
+ accountName: "\u8D26\u53F7\u540D\u79F0",
2498
+ accountKeyHint: "Key \u901A\u8FC7\u5BBF\u4E3B\u51ED\u636E\u670D\u52A1\u4FDD\u5B58\uFF0C\u9875\u9762\u4E0D\u4F1A\u56DE\u663E\u5DF2\u4FDD\u5B58\u7684\u5BC6\u94A5\u3002",
2499
+ accountConfirm: "\u786E\u8BA4",
2500
+ accountCancel: "\u53D6\u6D88",
2501
+ accountAutoSwitch: "\u81EA\u52A8\u4F7F\u7528\u5907\u7528\u8D26\u53F7",
2502
+ accountAutoSwitchHint: "\u989D\u5EA6\u8017\u5C3D\u6216 Key \u4E0D\u53EF\u7528\u65F6\uFF0C\u5728\u5C1A\u672A\u8F93\u51FA\u5185\u5BB9\u6216\u5DE5\u5177\u8C03\u7528\u524D\uFF0C\u6309\u8BBE\u7F6E\u9875\u7684\u8D26\u53F7\u987A\u5E8F\u5C1D\u8BD5\u5176\u4ED6\u8D26\u53F7\uFF1B\u4E00\u65E6\u67D0\u4E2A\u8D26\u53F7\u5F00\u59CB\u6B63\u5E38\u8F93\u51FA\uFF0C\u5F53\u524D\u8D26\u53F7\u5373\u5207\u6362\u4E3A\u5B83\u3002",
2503
+ accountPreferredTag: "\u5F53\u524D\u8D26\u53F7",
2504
+ accountSwitchAction: "\u5207\u6362",
2505
+ accountSwitchTitle: "\u5207\u6362\u8D26\u53F7",
2506
+ accountSwitchBack: "\u8FD4\u56DE\u989D\u5EA6",
2507
+ accountSwitchHint: "\u5207\u6362\u540E\uFF0C\u672C profile \u7684\u540E\u7EED\u8BF7\u6C42\u4F7F\u7528\u8BE5\u8D26\u53F7\uFF1B\u989D\u5EA6\u6D88\u8017\u987A\u5E8F\u5728\u8BBE\u7F6E\u9875\u8C03\u6574\u3002",
2508
+ accountSwitchFailed: "\u8D26\u53F7\u5207\u6362\u672A\u751F\u6548\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2509
+ accountFallbackQuota: "\u5F53\u524D\u8D26\u53F7\u989D\u5EA6\u8017\u5C3D\uFF0C\u5DF2\u81EA\u52A8\u5207\u6362\u4E3A\uFF1A",
2510
+ accountFallbackCredential: "\u5F53\u524D Key \u4E0D\u53EF\u7528\u6216\u88AB\u62D2\u7EDD\uFF0C\u5DF2\u81EA\u52A8\u5207\u6362\u4E3A\uFF1A",
2511
+ accountsSummary: "{count} \u4E2A \xB7 \u5F53\u524D {name}",
2512
+ accountsSummaryEmpty: "\u5C1A\u672A\u6DFB\u52A0\u8D26\u53F7",
2513
+ accountsAvailability: "{ready}/{total} \u5DF2\u914D\u7F6E",
2514
+ accountsAvailabilityFailed: "{ready}/{total} \u5DF2\u914D\u7F6E \xB7 {failed} \u4E2A\u8BFB\u53D6\u5931\u8D25",
2515
+ accountsDetails: "{name} \u7684\u8BE6\u60C5",
2516
+ accountsDetailsHide: "\u6536\u8D77 {name} \u7684\u8BE6\u60C5",
2517
+ accountDragHandle: "\u62D6\u52A8 {name} \u8C03\u6574\u987A\u5E8F",
2518
+ accountConfigureHint: "\u914D\u7F6E Key \u540E\u663E\u793A\u989D\u5EA6",
2519
+ usageResetMinutes: "{minutes} \u5206\u949F\u540E\u91CD\u7F6E",
2520
+ usageResetHours: "{hours} \u5C0F\u65F6\u540E\u91CD\u7F6E",
2521
+ usageResetDays: "{days} \u5929\u540E\u91CD\u7F6E",
2522
+ usageResetDue: "\u5373\u5C06\u91CD\u7F6E",
2523
+ usageResetUnknown: "\u91CD\u7F6E\u65F6\u95F4\u672A\u77E5",
1503
2524
  usageTitle: "OpenCode Go \u7528\u91CF",
1504
2525
  usageRollingShort: "5\u5C0F\u65F6",
1505
- usageHint: "\u8D26\u53F7\u989D\u5EA6 \xB7 \u5DF2\u7528\u767E\u5206\u6BD4 \xB7 \u6BCF\u5206\u949F\u5237\u65B0",
1506
2526
  usageWeekShort: "\u5468",
1507
2527
  usage_rolling: "5 \u5C0F\u65F6",
1508
2528
  usage_weekly: "\u6BCF\u5468",
@@ -1512,6 +2532,7 @@ var zh = {
1512
2532
  usageLoading: "\u6B63\u5728\u8BFB\u53D6\u7528\u91CF\u2026",
1513
2533
  usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
1514
2534
  usageStaleShort: "\u4E0A\u6B21\u6570\u636E",
2535
+ usageFallbackShort: "\u5DF2\u56DE\u9000",
1515
2536
  usageStaleHint: "\u5F53\u524D\u663E\u793A\u4E0A\u6B21\u6210\u529F\u8BFB\u53D6\u7684\u7528\u91CF\uFF0C\u5B9E\u9645\u7528\u91CF\u53EF\u80FD\u5DF2\u53D8\u5316\u3002",
1516
2537
  usageRefreshFailed: "\u5237\u65B0\u5931\u8D25",
1517
2538
  usageLastUpdated: "\u66F4\u65B0\u4E8E",
@@ -1554,6 +2575,11 @@ var zh = {
1554
2575
  limitsModel: "\u6A21\u578B",
1555
2576
  limitsContext: "\u4E0A\u4E0B\u6587\u7A97\u53E3",
1556
2577
  limitsOutput: "\u6700\u5927\u8F93\u51FA",
2578
+ thinkingBudgets: "\u601D\u8003\u9884\u7B97",
2579
+ thinkingBudgetsHint: "\u6DFB\u52A0 token \u9884\u7B97\u5E76\u4FDD\u5B58\uFF0C\u5373\u53EF\u5728\u4F1A\u8BDD\u4E2D\u9009\u62E9\u3002\u8303\u56F4\uFF1A{min}\u2013{max} tokens\u3002\u4FDD\u7559\u539F\u6709\u601D\u8003\u9009\u9879\uFF1B\u201C\u9ED8\u8BA4\u201D\u4F7F\u7528\u670D\u52A1\u5546\u8BBE\u7F6E\u3002SDK \u4F1A\u6309\u5269\u4F59\u8F93\u51FA\u7A7A\u95F4\u7F29\u5C0F\u9884\u7B97\uFF0C\u4E3A\u56DE\u7B54\u7559\u51FA\u7A7A\u95F4\u3002",
2580
+ thinkingBudgetAddLabel: "\u4E3A {name} \u6DFB\u52A0\u601D\u8003\u9884\u7B97",
2581
+ thinkingBudgetAdd: "\u6DFB\u52A0",
2582
+ thinkingBudgetRemove: "\u79FB\u9664 {value} token \u9884\u7B97",
1557
2583
  capacityDefault: "\u9ED8\u8BA4\uFF1A{value} tokens",
1558
2584
  capacityMissing: "API \u672A\u63D0\u4F9B",
1559
2585
  modalityLabel: "\u8F93\u5165\u6A21\u6001",
@@ -1589,7 +2615,7 @@ var zh = {
1589
2615
  limitsEmpty: "\u8BF7\u5148\u8BFB\u53D6\u6A21\u578B\u5217\u8868\uFF1B\u5BB9\u91CF\u6309\u7F51\u5173\u63D0\u4F9B\u7684\u6A21\u578B\u9010\u4E2A\u7F16\u8F91\u3002",
1590
2616
  limitsContextLabel: "{name} \u7684\u4E0A\u4E0B\u6587\u7A97\u53E3",
1591
2617
  limitsOutputLabel: "{name} \u7684\u6700\u5927\u8F93\u51FA",
1592
- advancedSummary: "\u989D\u5EA6\u663E\u793A \xB7 \u51ED\u8BC1\u5F15\u7528\u540D \xB7 \u7F51\u5173\u5730\u5740 \xB7 \u76EE\u5F55\u5237\u65B0 \xB7 \u6D41\u7A7A\u95F2\u8D85\u65F6 \xB7 \u56FE\u7247 4 \u9879",
2618
+ advancedSummary: "\u989D\u5EA6\u663E\u793A \xB7 \u534F\u8BAE \xB7 \u51ED\u8BC1\u5F15\u7528\u540D \xB7 \u7F51\u5173\u5730\u5740 \xB7 \u76EE\u5F55\u5237\u65B0 \xB7 \u6D41\u7A7A\u95F2\u8D85\u65F6 \xB7 \u56FE\u7247 4 \u9879",
1593
2619
  advancedLabel: "\u9AD8\u7EA7\u8BBE\u7F6E",
1594
2620
  advancedHint: "\u989D\u5EA6\u663E\u793A\u3001\u51ED\u8BC1\u540D\u79F0\u3001\u7F51\u5173\u5730\u5740\u4E0E\u9002\u914D\u5668\u8C03\u4F18\u53C2\u6570\u3002\u7EE7\u627F\u6765\u7684\u53D6\u503C\u5373\u53EF\u6B63\u5E38\u4F7F\u7528\uFF0C\u6309\u9700\u4FEE\u6539\u3002",
1595
2621
  usageDisplayLabel: "\u989D\u5EA6\u663E\u793A",
@@ -1597,10 +2623,17 @@ var zh = {
1597
2623
  usageDisplay_auto: "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09",
1598
2624
  usageDisplay_always: "\u5E38\u9A7B",
1599
2625
  usageDisplay_off: "\u5173\u95ED",
2626
+ protocolOverridesLabel: "DeepSeek V4.1 Flash \u534F\u8BAE",
2627
+ protocolOverridesHint: "\u81EA\u52A8\u8DDF\u968F\u6A21\u578B\u76EE\u5F55\u3002Responses \u4E3A\u5B9E\u9A8C\u6027\u9009\u9879\uFF0C\u4EC5\u5F71\u54CD DeepSeek V4.1 Flash\uFF0C\u901F\u5EA6\u53D6\u51B3\u4E8E\u7F51\u5173\u3002\u4FDD\u5B58\u540E\u5BF9\u65B0\u8BF7\u6C42\u751F\u6548\uFF1B\u9009\u62E9\u81EA\u52A8\u53EF\u6062\u590D\u76EE\u5F55\u8DEF\u7531\u3002",
2628
+ protocolOverridesAuto: "\u81EA\u52A8\uFF08\u9ED8\u8BA4\uFF09",
2629
+ protocolOverridesResponses: "Responses\uFF08\u5B9E\u9A8C\u6027\uFF09",
1600
2630
  apiKeyEnvLabel: "\u51ED\u8BC1\u5F15\u7528\u540D",
1601
2631
  apiKeyEnvHint: "key \u89E3\u6790\u6240\u4F9D\u636E\u7684\u5F15\u7528\u540D\uFF0C\u7ECF\u51ED\u8BC1\u670D\u52A1\u5BFB\u5740\u3002",
1602
2632
  baseURLLabel: "\u7F51\u5173\u5730\u5740",
1603
2633
  baseURLHint: "\u540C\u65F6\u63D0\u4F9B\u6A21\u578B\u8BF7\u6C42\u4E0E\u5B9E\u65F6\u6A21\u578B\u5217\u8868\u7684\u7AEF\u70B9\u3002",
2634
+ proxyURLLabel: "\u4EE3\u7406\u5730\u5740",
2635
+ proxyURLHint: "\u5BF9\u8BDD\u3001\u6A21\u578B\u66F4\u65B0\u548C\u7528\u91CF\u67E5\u8BE2\u4F7F\u7528\u7684 HTTP(S) \u6216 SOCKS5 \u4EE3\u7406\uFF0C\u4F8B\u5982 socks5://127.0.0.1:1080\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u7F51\u7EDC\u8BBE\u7F6E\u3002\u5730\u5740\u4EE5\u8FD0\u884C DSH \u7684\u673A\u5668\u4E3A\u51C6\u3002",
2636
+ proxyURLInvalid: "\u8BF7\u8F93\u5165 http://\u3001https:// \u6216 socks5:// \u4EE3\u7406\u5730\u5740\uFF0C\u4E0D\u5305\u542B\u8DEF\u5F84\u3001\u67E5\u8BE2\u53C2\u6570\u6216\u7247\u6BB5\u3002",
1604
2637
  refreshMinutesLabel: "\u76EE\u5F55\u5237\u65B0\uFF08\u5206\u949F\uFF09",
1605
2638
  refreshMinutesHint: "\u4F1A\u8BDD\u8BF7\u6C42\u548C\u6A21\u578B\u9009\u62E9\u5668\u7684\u76EE\u5F55\u7F13\u5B58\u65F6\u957F\u3002\u6253\u5F00\u672C\u8BBE\u7F6E\u9875\u6216\u70B9\u51FB\u5237\u65B0\u65F6\uFF0C\u4F1A\u7ACB\u5373\u6838\u5BF9\u7F51\u5173\u4E0E\u5728\u7EBF\u6A21\u578B\u914D\u7F6E\u3002",
1606
2639
  streamIdleTimeoutMsLabel: "\u6D41\u7A7A\u95F2\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
@@ -1625,6 +2658,11 @@ var zh = {
1625
2658
  };
1626
2659
 
1627
2660
  // src/usage-contract.ts
2661
+ function parseAccountSwitch(value) {
2662
+ const notice = value;
2663
+ if (!notice || typeof notice.fromRef !== "string" || typeof notice.toRef !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(notice.fromRef) || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(notice.toRef) || notice.reason !== "quota" && notice.reason !== "credential" || typeof notice.at !== "number" || !Number.isSafeInteger(notice.at) || notice.at < 0 || notice.at > 864e13) throw new Error("Invalid account switch notice");
2664
+ return { fromRef: notice.fromRef, toRef: notice.toRef, reason: notice.reason, at: notice.at };
2665
+ }
1628
2666
  function parseGoUsage(value) {
1629
2667
  if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
1630
2668
  const source = value;
@@ -1635,9 +2673,12 @@ function parseGoUsage(value) {
1635
2673
  }
1636
2674
  result.source = source.source;
1637
2675
  }
2676
+ if (source.lastSwitch !== void 0) {
2677
+ result.lastSwitch = parseAccountSwitch(source.lastSwitch);
2678
+ }
1638
2679
  for (const key of ["rolling", "weekly", "monthly"]) {
1639
2680
  const row = source[key];
1640
- if (!row || row.status !== "ok" && row.status !== "rate-limited" || typeof row.percent !== "number" || !Number.isFinite(row.percent) || row.percent < 0 || typeof row.resetsAt !== "string" || !Number.isFinite(Date.parse(row.resetsAt))) {
2681
+ if (!row || row.status !== "ok" && row.status !== "rate-limited" || typeof row.percent !== "number" || !Number.isFinite(row.percent) || row.percent < 0 || row.percent > 100 || typeof row.resetsAt !== "string" || !Number.isFinite(Date.parse(row.resetsAt))) {
1641
2682
  throw new Error("Invalid OpenCode Go usage response");
1642
2683
  }
1643
2684
  result[key] = { status: row.status, percent: row.percent, resetsAt: row.resetsAt };
@@ -1650,6 +2691,16 @@ var usageCodec = {
1650
2691
  schema: { parse: parseGoUsage },
1651
2692
  create: () => ({ parse: parseGoUsage })
1652
2693
  };
2694
+ var parseRef = (value) => {
2695
+ if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) throw new Error("Invalid account reference");
2696
+ return value;
2697
+ };
2698
+ var refCodec = {
2699
+ mode: "strict",
2700
+ typeSymbol: "dsh-opencode-go#AccountRef",
2701
+ schema: { parse: parseRef },
2702
+ create: () => ({ parse: parseRef })
2703
+ };
1653
2704
  var usageRemote = {
1654
2705
  package: "dsh-opencode-go",
1655
2706
  descriptors: [{
@@ -1660,17 +2711,76 @@ var usageRemote = {
1660
2711
  invocation: { kind: "direct" },
1661
2712
  parameters: [],
1662
2713
  result: usageCodec
2714
+ }, {
2715
+ id: "dsh-opencode-go#opencodeGoUsage/readAccount",
2716
+ service: "opencodeGoUsage",
2717
+ namespace: "opencodeGoUsage",
2718
+ method: "readAccount",
2719
+ invocation: { kind: "direct" },
2720
+ parameters: [{ name: "ref", wire: "ref", source: "json", codec: refCodec }],
2721
+ result: usageCodec
2722
+ }]
2723
+ };
2724
+
2725
+ // src/accounts-contract.ts
2726
+ function parseAccountCommand(value) {
2727
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid account command");
2728
+ const row = value;
2729
+ const fields = {
2730
+ add: ["kind", "id", "name", "key"],
2731
+ remove: ["kind", "ref"],
2732
+ select: ["kind", "ref"],
2733
+ rename: ["kind", "ref", "name"],
2734
+ "replace-key": ["kind", "ref", "key"],
2735
+ move: ["kind", "ref", "toIndex"],
2736
+ "auto-switch": ["kind", "value"]
2737
+ };
2738
+ if (typeof row.kind !== "string" || !Object.hasOwn(fields, row.kind) || Object.keys(row).some((key) => !fields[row.kind].includes(key)) || fields[row.kind].some((key) => !Object.hasOwn(row, key))) throw new Error("Invalid account command");
2739
+ if ("ref" in row && (typeof row.ref !== "string" || !ACCOUNT_REF_PATTERN.test(row.ref))) throw new Error("Invalid account reference");
2740
+ if ("name" in row && (typeof row.name !== "string" || !row.name.trim() || row.name.trim().length > 80)) throw new Error("Invalid account name");
2741
+ if ("key" in row && (typeof row.key !== "string" || !row.key.trim())) throw new Error("Missing account credential");
2742
+ if (row.kind === "add" && (typeof row.id !== "string" || !/^[a-f0-9]{32}$/.test(row.id))) throw new Error("Invalid account operation ID");
2743
+ if (row.kind === "move" && (!Number.isInteger(row.toIndex) || row.toIndex < 0)) throw new Error("Invalid account position");
2744
+ if (row.kind === "auto-switch" && typeof row.value !== "boolean") throw new Error("Invalid account switch");
2745
+ return { ...row };
2746
+ }
2747
+ function parseResult(value) {
2748
+ if (value !== "applied" && value !== "rejected" && value !== "unknown") throw new Error("Invalid account command result");
2749
+ return value;
2750
+ }
2751
+ var commandCodec = {
2752
+ mode: "strict",
2753
+ typeSymbol: "dsh-opencode-go#AccountCommand",
2754
+ schema: { parse: parseAccountCommand },
2755
+ create: () => ({ parse: parseAccountCommand })
2756
+ };
2757
+ var resultCodec = {
2758
+ mode: "strict",
2759
+ typeSymbol: "dsh-opencode-go#AccountCommandResult",
2760
+ schema: { parse: parseResult },
2761
+ create: () => ({ parse: parseResult })
2762
+ };
2763
+ var accountsRemote = {
2764
+ package: "dsh-opencode-go",
2765
+ descriptors: [{
2766
+ id: "dsh-opencode-go#opencodeGoAccounts/execute",
2767
+ service: "opencodeGoAccounts",
2768
+ namespace: "opencodeGoAccounts",
2769
+ method: "execute",
2770
+ invocation: { kind: "direct" },
2771
+ parameters: [{ name: "command", wire: "command", source: "json", codec: commandCodec }],
2772
+ result: resultCodec
1663
2773
  }]
1664
2774
  };
1665
2775
 
1666
2776
  // src/remote-contract.ts
1667
2777
  var goRemote = {
1668
2778
  package: "dsh-opencode-go",
1669
- descriptors: [...usageRemote.descriptors, ...modelsRemote.descriptors]
2779
+ descriptors: [...usageRemote.descriptors, ...modelsRemote.descriptors, ...accountsRemote.descriptors]
1670
2780
  };
1671
2781
 
1672
2782
  // src/client/UsagePill.tsx
1673
- var import_react3 = require("react");
2783
+ var import_react4 = require("react");
1674
2784
 
1675
2785
  // plugin-css:src/client/UsagePill.module.css
1676
2786
  var id2 = "dsh-opencode-go/UsagePill.module.css";
@@ -1678,20 +2788,29 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
1678
2788
  const style = document.createElement("style");
1679
2789
  style.dataset.plugin = "dsh-opencode-go";
1680
2790
  style.dataset.pluginCss = id2;
1681
- style.textContent = ".mAjYhq_root{min-width:0;display:inline-flex;position:relative}.mAjYhq_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.mAjYhq_trigger:hover,.mAjYhq_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.mAjYhq_panel{z-index:100;box-sizing:border-box;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);max-height:70vh;color:var(--dsw-alias-label-primary,CanvasText);isolation:isolate;background-color:canvas;background-image:linear-gradient(var(--dsw-specific-menu,transparent), var(--dsw-specific-menu,transparent)), linear-gradient(var(--dsw-alias-bg-layer-2,Canvas), var(--dsw-alias-bg-layer-2,Canvas));border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;overflow-y:auto;box-shadow:0 8px 30px #0003}.mAjYhq_hint{opacity:.65;font-size:11px;line-height:1.6}.mAjYhq_warning{background:color-mix(in srgb, currentColor 6%, transparent);overflow-wrap:anywhere;border-radius:6px;margin:10px 0;padding:10px;line-height:1.5}.mAjYhq_warning p{margin:5px 0 0}.mAjYhq_retry{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:5px 9px}.mAjYhq_retry:disabled{opacity:.6;cursor:default}.mAjYhq_retry:focus-visible{outline-offset:2px;outline:2px solid}.mAjYhq_window{margin-top:14px}.mAjYhq_row{justify-content:space-between;margin-bottom:5px;display:flex}.mAjYhq_window progress{appearance:none;background:color-mix(in srgb, currentColor 15%, transparent);border:0;border-radius:4px;width:100%;height:5px;margin-bottom:5px;display:block}.mAjYhq_window progress::-webkit-progress-bar{background:0 0;border-radius:4px}.mAjYhq_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.mAjYhq_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}.mAjYhq_window progress.mAjYhq_high::-webkit-progress-value{background:#e0a100}.mAjYhq_window progress.mAjYhq_high::-moz-progress-bar{background:#e0a100}.mAjYhq_window progress.mAjYhq_limited::-webkit-progress-value{background:#e5484d}.mAjYhq_window progress.mAjYhq_limited::-moz-progress-bar{background:#e5484d}.mAjYhq_limitedText{color:#e5484d;margin-top:2px;font-weight:600}";
2791
+ style.textContent = '.mAjYhq_root{min-width:0;display:inline-flex;position:relative}.mAjYhq_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.mAjYhq_trigger:hover,.mAjYhq_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.mAjYhq_account{text-overflow:ellipsis;vertical-align:bottom;max-width:12ch;display:inline-block;overflow:hidden}@container (width<=460px){.mAjYhq_brand,.mAjYhq_stale,.mAjYhq_account,.mAjYhq_fallback{display:none}.mAjYhq_reading[data-stale]:after{content:"*"}.mAjYhq_trigger[data-fallback]:after{content:" \u21B3"}}@container (width<=360px){.mAjYhq_unit{display:none}}.mAjYhq_panel{z-index:100;box-sizing:border-box;border-radius:var(--dsw-radius-lg,16px);width:320px;max-width:calc(100vw - 32px);max-height:70vh;color:var(--dsw-alias-label-primary,CanvasText);isolation:isolate;--dsw-elevation-stroke-color:var(--dsw-alias-border-l1,color-mix(in srgb, currentColor 10%, transparent));box-shadow:var(--dsw-elevation-prominent,0 8px 30px #0003);border:0;flex-direction:column;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 12px);right:0}.mAjYhq_material{z-index:-1;border-radius:inherit;pointer-events:none;background:var(--dsw-menu-surface-fill,var(--dsw-specific-menu,#43454a73));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(40px) saturate(150%));position:absolute;inset:0}@supports not (backdrop-filter:blur(1px)){.mAjYhq_material{background:var(--dsw-alias-bg-layer-2,Canvas)}}.mAjYhq_body{overscroll-behavior:contain;box-sizing:border-box;flex-direction:column;flex:1;gap:6px;min-height:0;padding:10px;display:flex;overflow-y:auto}.mAjYhq_panelTitle,.mAjYhq_panelHead{color:var(--dsw-alias-label-tertiary,currentColor);flex:none;padding:2px 6px 0;font-size:11.5px;line-height:1.6}.mAjYhq_panelHead{align-items:center;gap:6px;display:flex}.mAjYhq_panelHead strong{color:var(--dsw-alias-label-primary,CanvasText);font-size:12px;font-weight:600}.mAjYhq_back{width:18px;height:18px;color:inherit;cursor:pointer;background:0 0;border:0;border-radius:5px;place-items:center;padding:0;display:grid}.mAjYhq_back:hover{background:color-mix(in srgb, currentColor 8%, transparent)}.mAjYhq_icon{flex:none;width:14px;height:14px}.mAjYhq_tick{color:#39a878;flex:none;width:14px;height:14px}.mAjYhq_tile{background:color-mix(in srgb, currentColor 6%, transparent);border-radius:10px;flex:none;overflow:hidden}.mAjYhq_divider{background:color-mix(in srgb, currentColor 10%, transparent);height:.5px;margin:0 12px}.mAjYhq_accHead{align-items:center;gap:8px;min-height:42px;padding:0 12px;display:flex}.mAjYhq_dot{background:#39a878;border-radius:50%;flex:none;width:7px;height:7px}.mAjYhq_accName{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:13.5px;font-weight:600;overflow:hidden}.mAjYhq_tag{color:#39a878;background:#39a8781f;border:.5px solid #39a87873;border-radius:999px;flex:none;padding:0 7px;font-size:10.5px;line-height:1.7}.mAjYhq_switch{font:inherit;color:var(--dsw-alias-label-tertiary,currentColor);cursor:pointer;background:0 0;border:0;border-radius:6px;flex:none;align-items:center;gap:3px;padding:3px 6px;font-size:11.5px;display:inline-flex}.mAjYhq_switch:hover:not(:disabled){background:color-mix(in srgb, currentColor 8%, transparent)}.mAjYhq_switch:disabled{opacity:.55;cursor:default}.mAjYhq_option{width:100%;min-height:38px;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:0 12px;display:flex}.mAjYhq_option:hover:not(:disabled){background:color-mix(in srgb, currentColor 6%, transparent)}.mAjYhq_option:disabled{opacity:.6;cursor:default}.mAjYhq_optionName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-secondary,currentColor);flex:1;font-size:13px;overflow:hidden}.mAjYhq_option[data-selected] .mAjYhq_optionName{color:var(--dsw-alias-label-primary,CanvasText);font-weight:600}.mAjYhq_hint{opacity:.65;font-size:11px;line-height:1.6}.mAjYhq_warning{background:color-mix(in srgb, currentColor 6%, transparent);overflow-wrap:anywhere;border-radius:6px;margin:10px 0;padding:10px;line-height:1.5}.mAjYhq_warning p{margin:5px 0 0}.mAjYhq_retry{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:5px 9px}.mAjYhq_retry:disabled{opacity:.6;cursor:default}.mAjYhq_back:focus-visible,.mAjYhq_switch:focus-visible,.mAjYhq_option:focus-visible,.mAjYhq_retry:focus-visible{outline-offset:2px;outline:2px solid}.mAjYhq_window{padding:10px 12px}.mAjYhq_windowRow{align-items:center;gap:10px;display:flex}.mAjYhq_windowLabel{width:48px;color:var(--dsw-alias-label-secondary,currentColor);flex:none;font-size:12.5px}.mAjYhq_windowPercent{text-align:right;font-variant-numeric:tabular-nums;flex:none;width:38px;font-size:13px;font-weight:650}.mAjYhq_window progress{appearance:none;background:color-mix(in srgb, currentColor 15%, transparent);border:0;border-radius:99px;flex:1;min-width:60px;height:10px;display:block}.mAjYhq_window progress::-webkit-progress-bar{background:0 0;border-radius:99px}.mAjYhq_window progress::-webkit-progress-value{background:#39a878;border-radius:99px}.mAjYhq_window progress::-moz-progress-bar{background:#39a878;border-radius:99px}.mAjYhq_windowReset{color:var(--dsw-alias-label-tertiary,currentColor);margin-top:6px;font-size:11px;line-height:1.6}.mAjYhq_foot{color:var(--dsw-alias-label-tertiary,currentColor);justify-content:space-between;align-items:center;gap:8px;padding:3px 6px 1px;font-size:11px;display:flex}.mAjYhq_window progress.mAjYhq_high::-webkit-progress-value{background:#e0a100}.mAjYhq_window progress.mAjYhq_high::-moz-progress-bar{background:#e0a100}.mAjYhq_window progress.mAjYhq_limited::-webkit-progress-value{background:#e5484d}.mAjYhq_window progress.mAjYhq_limited::-moz-progress-bar{background:#e5484d}.mAjYhq_limitedText{color:#e5484d;margin-top:2px;font-weight:600}';
1682
2792
  document.head.appendChild(style);
1683
2793
  }
1684
- var UsagePill_default = { "high": "mAjYhq_high", "hint": "mAjYhq_hint", "limited": "mAjYhq_limited", "limitedText": "mAjYhq_limitedText", "panel": "mAjYhq_panel", "retry": "mAjYhq_retry", "root": "mAjYhq_root", "row": "mAjYhq_row", "trigger": "mAjYhq_trigger", "warning": "mAjYhq_warning", "window": "mAjYhq_window" };
2794
+ var UsagePill_default = { "accHead": "mAjYhq_accHead", "accName": "mAjYhq_accName", "account": "mAjYhq_account", "back": "mAjYhq_back", "body": "mAjYhq_body", "brand": "mAjYhq_brand", "divider": "mAjYhq_divider", "dot": "mAjYhq_dot", "fallback": "mAjYhq_fallback", "foot": "mAjYhq_foot", "high": "mAjYhq_high", "hint": "mAjYhq_hint", "icon": "mAjYhq_icon", "limited": "mAjYhq_limited", "limitedText": "mAjYhq_limitedText", "material": "mAjYhq_material", "option": "mAjYhq_option", "optionName": "mAjYhq_optionName", "panel": "mAjYhq_panel", "panelHead": "mAjYhq_panelHead", "panelTitle": "mAjYhq_panelTitle", "reading": "mAjYhq_reading", "retry": "mAjYhq_retry", "root": "mAjYhq_root", "stale": "mAjYhq_stale", "switch": "mAjYhq_switch", "tag": "mAjYhq_tag", "tick": "mAjYhq_tick", "tile": "mAjYhq_tile", "trigger": "mAjYhq_trigger", "unit": "mAjYhq_unit", "warning": "mAjYhq_warning", "window": "mAjYhq_window", "windowLabel": "mAjYhq_windowLabel", "windowPercent": "mAjYhq_windowPercent", "windowReset": "mAjYhq_windowReset", "windowRow": "mAjYhq_windowRow" };
1685
2795
 
1686
2796
  // src/client/UsagePill.tsx
1687
- var import_jsx_runtime3 = require("react/jsx-runtime");
2797
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2798
+ var unchanged = () => 0;
2799
+ var noSubscription = () => () => {
2800
+ };
1688
2801
  function usageFailure(error) {
1689
2802
  if (error && typeof error === "object" && "code" in error && error.code === "opencode-go/usage-unavailable" && "details" in error && error.details && typeof error.details === "object") {
1690
2803
  const details = error.details;
2804
+ let lastSwitch;
2805
+ try {
2806
+ if (details.lastSwitch) lastSwitch = parseAccountSwitch(details.lastSwitch);
2807
+ } catch {
2808
+ }
1691
2809
  return {
1692
2810
  ..."message" in error && typeof error.message === "string" ? { message: error.message } : {},
1693
2811
  retainPrevious: details.retryable === true && details.retainPrevious === true,
1694
- ...typeof details.source === "string" ? { source: details.source } : {}
2812
+ ...typeof details.source === "string" ? { source: details.source } : {},
2813
+ ...lastSwitch ? { lastSwitch } : {}
1695
2814
  };
1696
2815
  }
1697
2816
  return { retainPrevious: false };
@@ -1700,24 +2819,50 @@ function usageLevel(window) {
1700
2819
  if (window.status === "rate-limited" || window.percent >= 100) return UsagePill_default.limited;
1701
2820
  return window.percent >= 80 ? UsagePill_default.high : void 0;
1702
2821
  }
1703
- function UsagePill({ directory, settings, ...props }) {
1704
- const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
1705
- const readSettings = (0, import_react3.useCallback)(() => settings.getSnapshot(), [settings]);
1706
- const subscribeSettings = (0, import_react3.useCallback)((listener) => settings.subscribe(listener), [settings]);
1707
- const config = (0, import_react3.useSyncExternalStore)(subscribeSettings, readSettings, readSettings);
2822
+ function ChevronRight() {
2823
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: UsagePill_default.icon, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M6 4l4 4-4 4" }) });
2824
+ }
2825
+ function ChevronLeft() {
2826
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: UsagePill_default.icon, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M10 4 6 8l4 4" }) });
2827
+ }
2828
+ function Tick() {
2829
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { className: UsagePill_default.tick, viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3.5 8.5 6.5 11.5 12.5 4.5" }) });
2830
+ }
2831
+ function UsagePill({ directory, settings, credentialChanges, ...props }) {
2832
+ const state = (0, import_react4.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
2833
+ const readSettings = (0, import_react4.useCallback)(() => settings.getSnapshot(), [settings]);
2834
+ const subscribeSettings = (0, import_react4.useCallback)((listener) => settings.subscribe(listener), [settings]);
2835
+ const config = (0, import_react4.useSyncExternalStore)(subscribeSettings, readSettings, readSettings);
2836
+ const readChanges = (0, import_react4.useCallback)(() => credentialChanges?.getSnapshot() ?? unchanged(), [credentialChanges]);
2837
+ const subscribeChanges = (0, import_react4.useCallback)((listener) => credentialChanges?.subscribe(listener) ?? noSubscription(), [credentialChanges]);
2838
+ const credentialRevision = (0, import_react4.useSyncExternalStore)(subscribeChanges, readChanges, readChanges);
1708
2839
  const mode = config.value?.usageDisplay ?? DEFAULT_USAGE_DISPLAY;
1709
2840
  const visible = config.status === "ready" && config.value?.enabled !== false && (mode === "always" || mode === "auto" && state.current?.provider === PROVIDER_ID);
1710
- return visible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
2841
+ const accounts = accountsOf(config.value ?? {});
2842
+ const activeRef = accountRefOf(config.value ?? {});
2843
+ return visible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2844
+ ActiveUsage,
2845
+ {
2846
+ ...props,
2847
+ accounts,
2848
+ activeRef,
2849
+ writable: config.writable
2850
+ },
2851
+ JSON.stringify([activeRef, config.value?.baseURL, config.value?.proxyURL, credentialRevision, accounts])
2852
+ ) : null;
1711
2853
  }
1712
- function ActiveUsage({ readUsage, t, getLocale }) {
1713
- const [snapshot, setSnapshot] = (0, import_react3.useState)(null);
1714
- const [failed, setFailed] = (0, import_react3.useState)(null);
1715
- const [refreshing, setRefreshing] = (0, import_react3.useState)(false);
1716
- const [open, setOpen] = (0, import_react3.useState)(false);
1717
- const root = (0, import_react3.useRef)(null);
1718
- const retry = (0, import_react3.useRef)(() => {
2854
+ function ActiveUsage({ readUsage, t, getLocale, accounts, activeRef, writable, selectAccount }) {
2855
+ const [snapshot, setSnapshot] = (0, import_react4.useState)(null);
2856
+ const [failed, setFailed] = (0, import_react4.useState)(null);
2857
+ const [refreshing, setRefreshing] = (0, import_react4.useState)(false);
2858
+ const [open, setOpen] = (0, import_react4.useState)(false);
2859
+ const [switching, setSwitching] = (0, import_react4.useState)(false);
2860
+ const [switchFailed, setSwitchFailed] = (0, import_react4.useState)(false);
2861
+ const [view, setView] = (0, import_react4.useState)("usage");
2862
+ const root = (0, import_react4.useRef)(null);
2863
+ const retry = (0, import_react4.useRef)(() => {
1719
2864
  });
1720
- (0, import_react3.useEffect)(() => {
2865
+ (0, import_react4.useEffect)(() => {
1721
2866
  let alive = true;
1722
2867
  let busy = false;
1723
2868
  setSnapshot(null);
@@ -1763,7 +2908,7 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1763
2908
  document.removeEventListener("visibilitychange", visible);
1764
2909
  };
1765
2910
  }, [readUsage]);
1766
- (0, import_react3.useEffect)(() => {
2911
+ (0, import_react4.useEffect)(() => {
1767
2912
  if (!open) return;
1768
2913
  const click = (event) => {
1769
2914
  if (!root.current?.contains(event.target)) setOpen(false);
@@ -1781,71 +2926,227 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1781
2926
  const current = snapshot?.reader === readUsage ? snapshot : null;
1782
2927
  const usage = current?.usage;
1783
2928
  const failure = failed?.reader === readUsage ? failed.failure : null;
1784
- const label = usage ? `Go \xB7 ${t("usageRollingShort")} ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%${failure ? ` \xB7 ${t("usageStaleShort")}` : ""}` : `Go \xB7 ${failure ? t("usageUnavailable") : "\u2026"}`;
1785
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
1786
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2929
+ const notice = usage?.lastSwitch ?? failure?.lastSwitch;
2930
+ const accountName = accounts.find((account) => account.apiKeyEnv === activeRef)?.name || t("accountDefault");
2931
+ const accountsView = view === "accounts" && accounts.length > 1;
2932
+ const switchable = accounts.length > 1 && writable && selectAccount !== void 0;
2933
+ const switchTo = (ref) => {
2934
+ if (ref === activeRef) {
2935
+ setView("usage");
2936
+ return;
2937
+ }
2938
+ setSwitching(true);
2939
+ setSwitchFailed(false);
2940
+ void selectAccount?.(ref).then((accepted) => {
2941
+ setSwitchFailed(!accepted);
2942
+ if (accepted) setView("usage");
2943
+ }).catch(() => {
2944
+ setSwitchFailed(true);
2945
+ }).finally(() => {
2946
+ setSwitching(false);
2947
+ });
2948
+ };
2949
+ const label = usage ? `Go \xB7 ${t("usageRollingShort")} ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%${failure ? ` \xB7 ${t("usageStaleShort")}` : ""}${notice ? ` \xB7 ${t("usageFallbackShort")}` : ""}${accounts.length > 1 ? ` \xB7 ${accountName}` : ""}` : `Go \xB7 ${failure ? t("usageUnavailable") : "\u2026"}${notice ? ` \xB7 ${t("usageFallbackShort")}` : ""}${accounts.length > 1 ? ` \xB7 ${accountName}` : ""}`;
2950
+ const segments = usage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.brand, children: "Go \xB7 " }),
2952
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.reading, "data-stale": failure ? "" : void 0, children: [
2953
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.unit, children: [
2954
+ t("usageRollingShort"),
2955
+ " "
2956
+ ] }),
2957
+ usage.rolling.percent,
2958
+ "%",
2959
+ " \xB7 ",
2960
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.unit, children: [
2961
+ t("usageWeekShort"),
2962
+ " "
2963
+ ] }),
2964
+ usage.weekly.percent,
2965
+ "%"
2966
+ ] }),
2967
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.stale, children: [
2968
+ " \xB7 ",
2969
+ t("usageStaleShort")
2970
+ ] }) : null,
2971
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.fallback, children: [
2972
+ " \xB7 ",
2973
+ t("usageFallbackShort")
2974
+ ] }) : null,
2975
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.account, children: [
2976
+ " \xB7 ",
2977
+ accountName
2978
+ ] }) : null
2979
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2980
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.brand, children: "Go \xB7 " }),
2981
+ failure ? t("usageUnavailable") : "\u2026",
2982
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.fallback, children: [
2983
+ " \xB7 ",
2984
+ t("usageFallbackShort")
2985
+ ] }) : null,
2986
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.account, children: [
2987
+ " \xB7 ",
2988
+ accountName
2989
+ ] }) : null
2990
+ ] });
2991
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
2992
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1787
2993
  "button",
1788
2994
  {
1789
2995
  type: "button",
1790
2996
  className: UsagePill_default.trigger,
1791
2997
  "aria-expanded": open,
1792
2998
  "aria-haspopup": "dialog",
2999
+ "data-fallback": notice ? "" : void 0,
1793
3000
  "aria-label": `${t("usageTitle")}: ${label}`,
3001
+ title: label,
1794
3002
  onClick: () => {
1795
3003
  setOpen(!open);
3004
+ setView("usage");
1796
3005
  },
1797
- children: label
3006
+ children: segments
1798
3007
  }
1799
3008
  ),
1800
- open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
1801
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageTitle") }),
1802
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
1803
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
1804
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageRefreshFailed") }),
1805
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
1806
- usage ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageStaleHint") }) : null
1807
- ] }) : null,
1808
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1809
- "button",
1810
- {
1811
- type: "button",
1812
- className: UsagePill_default.retry,
1813
- disabled: refreshing,
1814
- onClick: () => {
1815
- retry.current();
1816
- },
1817
- children: t(refreshing ? "usageRefreshing" : "usageRetry")
1818
- }
1819
- ) : null,
1820
- current ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: UsagePill_default.hint, children: [
1821
- t("usageLastUpdated"),
1822
- " ",
1823
- new Date(current.updatedAt).toLocaleString(getLocale?.())
1824
- ] }) : null,
1825
- usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.window, children: [
1826
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.row, children: [
1827
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(`usage_${key}`) }),
1828
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
1829
- usage[key].percent,
1830
- "%"
1831
- ] })
3009
+ open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
3010
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.material, "aria-hidden": "true" }),
3011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.body, children: accountsView ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3012
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.panelHead, children: [
3013
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: UsagePill_default.back, "aria-label": t("accountSwitchBack"), onClick: () => {
3014
+ setView("usage");
3015
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeft, {}) }),
3016
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("accountSwitchTitle") })
1832
3017
  ] }),
1833
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("progress", { className: usageLevel(usage[key]), "aria-label": t(`usage_${key}`), max: 100, value: Math.min(100, usage[key].percent) }),
1834
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.hint, children: [
1835
- t("usageResets"),
3018
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3019
+ "div",
3020
+ {
3021
+ className: UsagePill_default.tile,
3022
+ role: "listbox",
3023
+ "aria-label": t("accountSwitchTitle"),
3024
+ onKeyDown: (event) => {
3025
+ if (event.key === "Escape") {
3026
+ event.stopPropagation();
3027
+ setView("usage");
3028
+ return;
3029
+ }
3030
+ const step = event.key === "ArrowDown" ? 1 : event.key === "ArrowUp" ? -1 : 0;
3031
+ if (step === 0) return;
3032
+ event.preventDefault();
3033
+ const options = Array.from(event.currentTarget.querySelectorAll('[role="option"]'));
3034
+ const at = options.indexOf(document.activeElement);
3035
+ options[(at + step + options.length) % options.length]?.focus();
3036
+ },
3037
+ children: accounts.map((account, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react4.Fragment, { children: [
3038
+ index ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.divider }) : null,
3039
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3040
+ "button",
3041
+ {
3042
+ type: "button",
3043
+ role: "option",
3044
+ "aria-selected": account.apiKeyEnv === activeRef,
3045
+ "data-selected": account.apiKeyEnv === activeRef ? "" : void 0,
3046
+ className: UsagePill_default.option,
3047
+ disabled: switching,
3048
+ onClick: () => {
3049
+ switchTo(account.apiKeyEnv);
3050
+ },
3051
+ children: [
3052
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.optionName, children: account.name || t("accountDefault") }),
3053
+ account.apiKeyEnv === activeRef ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tick, {}) : null
3054
+ ]
3055
+ }
3056
+ )
3057
+ ] }, account.id))
3058
+ }
3059
+ ),
3060
+ switchFailed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.warning, role: "alert", children: t("accountSwitchFailed") }) : null,
3061
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.hint, children: t("accountSwitchHint") })
3062
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
3063
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.panelTitle, children: t("usageTitle") }),
3064
+ accounts.length ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.tile, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.accHead, children: [
3065
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.dot }),
3066
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.accName, children: accountName }),
3067
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.tag, children: t("accountPreferredTag") }) : null,
3068
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
3069
+ "button",
3070
+ {
3071
+ type: "button",
3072
+ className: UsagePill_default.switch,
3073
+ disabled: !switchable || switching,
3074
+ "aria-haspopup": "listbox",
3075
+ onClick: () => {
3076
+ setView("accounts");
3077
+ },
3078
+ children: [
3079
+ t("accountSwitchAction"),
3080
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronRight, {})
3081
+ ]
3082
+ }
3083
+ ) : null
3084
+ ] }) }) : null,
3085
+ switchFailed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.warning, role: "alert", children: t("accountSwitchFailed") }) : null,
3086
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: UsagePill_default.warning, role: "status", children: [
3087
+ t(notice.reason === "quota" ? "accountFallbackQuota" : "accountFallbackCredential"),
1836
3088
  " ",
1837
- new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
1838
- ] }),
1839
- usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: UsagePill_default.limitedText, children: t("usageLimited") })
1840
- ] }, key)) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageLoading") })
3089
+ accounts.find((account) => account.apiKeyEnv === notice.toRef)?.name || t("accountDefault"),
3090
+ " \xB7 ",
3091
+ new Date(notice.at).toLocaleString(getLocale?.())
3092
+ ] }) : null,
3093
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
3094
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("usageRefreshFailed") }),
3095
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
3096
+ usage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("usageStaleHint") }) : null
3097
+ ] }) : null,
3098
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
3099
+ "button",
3100
+ {
3101
+ type: "button",
3102
+ className: UsagePill_default.retry,
3103
+ disabled: refreshing,
3104
+ onClick: () => {
3105
+ retry.current();
3106
+ },
3107
+ children: t(refreshing ? "usageRefreshing" : "usageRetry")
3108
+ }
3109
+ ) : null,
3110
+ usage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.tile, children: ["rolling", "weekly", "monthly"].map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react4.Fragment, { children: [
3111
+ index ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.divider }) : null,
3112
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.window, children: [
3113
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.windowRow, children: [
3114
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.windowLabel, children: t(`usage_${key}`) }),
3115
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("progress", { className: usageLevel(usage[key]), "aria-label": t(`usage_${key}`), max: 100, value: Math.min(100, usage[key].percent) }),
3116
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { className: UsagePill_default.windowPercent, children: [
3117
+ usage[key].percent,
3118
+ "%"
3119
+ ] })
3120
+ ] }),
3121
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.windowReset, children: [
3122
+ t("usageResets"),
3123
+ " ",
3124
+ new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
3125
+ ] }),
3126
+ usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.limitedText, children: t("usageLimited") })
3127
+ ] })
3128
+ ] }, key)) }) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.hint, children: t("usageLoading") }),
3129
+ current ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.foot, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
3130
+ t("usageLastUpdated"),
3131
+ " ",
3132
+ new Date(current.updatedAt).toLocaleString(getLocale?.())
3133
+ ] }) }) : null
3134
+ ] }) })
1841
3135
  ] })
1842
3136
  ] });
1843
3137
  }
1844
3138
 
1845
3139
  // src/client/usage.ts
1846
- function registerUsagePill(ctx, settings) {
3140
+ var import_dsh_client_store2 = require("@deepseek-ai/dsh-client-store");
3141
+ function registerUsagePill(ctx, settings, selectAccount) {
1847
3142
  ctx.inject(["modelDirectories", "sessions", "remote.session"], (scope) => {
1848
3143
  scope.inject(["remote.opencodeGoUsage"], (ready) => {
3144
+ const credentialChanges = (0, import_dsh_client_store2.createSnapshotStore)(0);
3145
+ ready.effect(() => ready.remote.$on("credentials/reference-updated", (ref) => {
3146
+ if (accountsOf(settings.getSnapshot().value ?? {}).some((account) => account.apiKeyEnv === ref)) {
3147
+ credentialChanges.set(credentialChanges.getSnapshot() + 1);
3148
+ }
3149
+ }));
1849
3150
  const readUsage = async () => {
1850
3151
  const result = await ready.remote.opencodeGoUsage.read();
1851
3152
  if (!result.ok) throw result.error;
@@ -1859,6 +3160,12 @@ function registerUsagePill(ctx, settings) {
1859
3160
  inject: (sessionId) => ({
1860
3161
  directory: ready.modelDirectories.directoryFor(sessionId).store,
1861
3162
  settings,
3163
+ credentialChanges,
3164
+ selectAccount: async (ref) => {
3165
+ const snapshot = settings.getSnapshot();
3166
+ if (!snapshot.writable || !accountsOf(snapshot.value ?? {}).some((account) => account.apiKeyEnv === ref)) return false;
3167
+ return selectAccount ? selectAccount(ref).catch(() => false) : false;
3168
+ },
1862
3169
  readUsage,
1863
3170
  getLocale: () => ready.locale.getLocale().active,
1864
3171
  t: (key) => translate(key)
@@ -1868,6 +3175,37 @@ function registerUsagePill(ctx, settings) {
1868
3175
  });
1869
3176
  }
1870
3177
 
3178
+ // src/client/host-compat.ts
3179
+ function mountSettingsScopes(ctx, mount) {
3180
+ ctx.inject(["configForms", "remote.opencodeGoModels"], (child) => {
3181
+ const forms = child.get("configForms");
3182
+ mount(child, forms.get(PROFILE_ENTRY_ID));
3183
+ });
3184
+ ctx.inject(["settingsScope", "remote.opencodeGoModels"], (child) => {
3185
+ mount(child, child.settingsScope.bind({
3186
+ namespace: SETTINGS_NAMESPACE,
3187
+ decode: (section) => typeof section === "object" && section !== null ? section : void 0
3188
+ }));
3189
+ });
3190
+ }
3191
+ function accountCommands(ctx) {
3192
+ const unavailable = async () => "unknown";
3193
+ let execute = unavailable;
3194
+ ctx.inject(["remote.opencodeGoAccounts"], (ready) => {
3195
+ ready.effect(() => {
3196
+ const connected = async (command) => {
3197
+ const result = await ready.remote.opencodeGoAccounts.execute(command);
3198
+ return result.ok ? result.value : "unknown";
3199
+ };
3200
+ execute = connected;
3201
+ return () => {
3202
+ if (execute === connected) execute = unavailable;
3203
+ };
3204
+ });
3205
+ });
3206
+ return (command) => execute(command);
3207
+ }
3208
+
1871
3209
  // src/client/index.ts
1872
3210
  var NS = "settings.opencode-go";
1873
3211
  var inject = ["slots", "locale", "remote", "remote.credentials", "remote.llm"];
@@ -1875,23 +3213,27 @@ function apply(ctx) {
1875
3213
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), "llm-opencode-go: copy dictionaries");
1876
3214
  const modelsReady = ctx.remote.$mount(goRemote);
1877
3215
  ctx.effect(async () => await modelsReady);
1878
- ctx.inject(["configForms", "remote.opencodeGoModels"], (child) => {
1879
- const forms = child.get("configForms");
1880
- mountSettings(child, forms.get("opencode-go"), modelsReady);
1881
- });
1882
- ctx.inject(["settingsScope", "remote.opencodeGoModels"], (child) => {
1883
- mountSettings(child, child.settingsScope.bind({
1884
- namespace: "llm-opencode-go",
1885
- decode: (section) => typeof section === "object" && section !== null ? section : void 0
1886
- }), modelsReady);
1887
- });
3216
+ mountSettingsScopes(ctx, (child, scope) => mountSettings(child, scope, modelsReady));
1888
3217
  }
1889
3218
  function mountSettings(ctx, scope, modelsReady) {
1890
- registerUsagePill(ctx, scope);
3219
+ const executeAccountCommand = accountCommands(ctx);
3220
+ registerUsagePill(ctx, scope, async (ref) => await executeAccountCommand({ kind: "select", ref }) === "applied");
3221
+ let readAccount;
3222
+ ctx.inject(["remote.opencodeGoUsage"], (ready) => {
3223
+ readAccount = async (ref) => {
3224
+ const result = await ready.remote.opencodeGoUsage.readAccount(ref);
3225
+ if (!result.ok) throw result.error;
3226
+ return result.value;
3227
+ };
3228
+ });
1891
3229
  const controller = new OpencodeGoSectionController(scope, ctx, async () => {
1892
3230
  await modelsReady;
1893
3231
  return ctx.remote.opencodeGoModels.read();
1894
- });
3232
+ }, async (ref) => {
3233
+ await modelsReady;
3234
+ if (readAccount === void 0) throw new Error("OpenCode Go account usage is unavailable in this session");
3235
+ return readAccount(ref);
3236
+ }, executeAccountCommand);
1895
3237
  ctx.effect(() => () => controller.dispose());
1896
3238
  const t = ctx.locale.bind(NS);
1897
3239
  const injected = () => ({ ...controller.inject(), t, getLocale: () => ctx.locale.getLocale().active });