dsh-opencode-go 0.1.19 → 0.1.21

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.
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");
@@ -145,10 +145,10 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id) + "]")
145
145
  const style = document.createElement("style");
146
146
  style.dataset.plugin = "dsh-opencode-go";
147
147
  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}}";
148
+ style.textContent = ".N807zW_accounts{gap:10px;margin:12px 0;display:grid}.N807zW_accountRow{border:.5px solid var(--dsw-alias-border-l2);border-radius:10px}.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_accountDropLine{background:var(--dsw-alias-brand-primary);border-radius:2px;height:2px}.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_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
149
  document.head.appendChild(style);
150
150
  }
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" };
151
+ var Section_default = { "accountActions": "N807zW_accountActions", "accountBar": "N807zW_accountBar", "accountBarFill": "N807zW_accountBarFill", "accountBarTick": "N807zW_accountBarTick", "accountDetail": "N807zW_accountDetail", "accountDot": "N807zW_accountDot", "accountDropLine": "N807zW_accountDropLine", "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", "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
152
 
153
153
  // src/client/ModelEditor.tsx
154
154
  var import_jsx_runtime = require("react/jsx-runtime");
@@ -375,21 +375,447 @@ function Capacity({ model, field, limit, disabled, t, locale, onChange }) {
375
375
  ] });
376
376
  }
377
377
 
378
+ // src/client/AccountsCard.tsx
379
+ var import_react2 = require("react");
380
+ var primitives = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
381
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
382
+
383
+ // src/accounts.ts
384
+ var MAX_ACCOUNTS = 20;
385
+ var ACCOUNT_REF_PREFIX = "DSH_OPENCODE_GO_ACCOUNT_";
386
+ var DEFAULT_ACCOUNT_REF = "OPENCODE_API_KEY";
387
+ function accountRefOf(settings) {
388
+ return settings.apiKeyEnv || DEFAULT_ACCOUNT_REF;
389
+ }
390
+ function accountsOf(settings) {
391
+ const ref = accountRefOf(settings);
392
+ if (settings.accounts?.length === 0) return [];
393
+ const accounts = settings.accounts ?? [];
394
+ return accounts.some((account) => account.apiKeyEnv === ref) ? accounts : [
395
+ { id: `legacy:${ref}`, name: "", apiKeyEnv: ref },
396
+ ...accounts
397
+ ];
398
+ }
399
+
400
+ // src/client/AccountsCard.tsx
401
+ var import_jsx_runtime2 = require("react/jsx-runtime");
402
+ var WINDOWS = ["rolling", "weekly", "monthly"];
403
+ var TICKS = [25, 50, 75];
404
+ var ChevronDown = primitives.IconChevronDownOutlineRegular ?? primitives.IconChevronDownOutline14;
405
+ function resetText(resetsAt, t) {
406
+ const remaining = Date.parse(resetsAt) - Date.now();
407
+ if (!Number.isFinite(remaining)) return t("usageResetUnknown");
408
+ if (remaining <= 0) return t("usageResetDue");
409
+ const minutes = Math.max(1, Math.round(remaining / 6e4));
410
+ if (minutes < 60) return t("usageResetMinutes", { minutes });
411
+ const hours = Math.round(minutes / 60);
412
+ if (hours < 24) return t("usageResetHours", { hours });
413
+ return t("usageResetDays", { days: Math.round(hours / 24) });
414
+ }
415
+ function barLevel(window) {
416
+ if (window.status === "rate-limited" || window.percent >= 100) return "limited";
417
+ return window.percent >= 80 ? "high" : "ok";
418
+ }
419
+ function stampText(at, locale) {
420
+ const date = new Date(at);
421
+ const time = date.toLocaleTimeString(locale, { hour: "2-digit", minute: "2-digit" });
422
+ return date.toDateString() === (/* @__PURE__ */ new Date()).toDateString() ? time : `${date.toLocaleDateString(locale)} ${time}`;
423
+ }
424
+ function GripIcon() {
425
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "10", height: "14", viewBox: "0 0 10 14", fill: "currentColor", "aria-hidden": "true", children: [
426
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "2.5", r: "1.3" }),
427
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "2.5", r: "1.3" }),
428
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "7", r: "1.3" }),
429
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "7", r: "1.3" }),
430
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "2.5", cy: "11.5", r: "1.3" }),
431
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("circle", { cx: "7.5", cy: "11.5", r: "1.3" })
432
+ ] });
433
+ }
434
+ function AccountsCard({ state, actions, writable, t, locale }) {
435
+ const [open, setOpen] = (0, import_react2.useState)(false);
436
+ const [details, setDetails] = (0, import_react2.useState)(null);
437
+ const [dragging, setDragging] = (0, import_react2.useState)(null);
438
+ const [dropAt, setDropAt] = (0, import_react2.useState)(null);
439
+ const [editor, setEditor] = (0, import_react2.useState)(null);
440
+ const [name, setName] = (0, import_react2.useState)("");
441
+ const [key, setKey] = (0, import_react2.useState)("");
442
+ const disabled = state.busy || state.blocked || !writable;
443
+ const total = state.entries.length;
444
+ const ready = state.entries.filter((entry) => entry.configured === true).length;
445
+ const unreadable = state.entries.filter((entry) => entry.failed === true).length;
446
+ const preferred = state.entries.find((entry) => entry.apiKeyEnv === state.activeRef);
447
+ const reorderable = !disabled && total > 1;
448
+ const updatedAt = state.entries.reduce((latest, entry) => Math.max(latest, entry.updatedAt ?? 0), 0);
449
+ (0, import_react2.useEffect)(() => {
450
+ actions.loadAccounts();
451
+ const timer = setInterval(() => {
452
+ if (document.visibilityState !== "hidden") actions.loadAccounts();
453
+ }, 6e4);
454
+ return () => {
455
+ clearInterval(timer);
456
+ };
457
+ }, [actions.loadAccounts]);
458
+ const start = (next, label = "") => {
459
+ setEditor(next);
460
+ setName(label);
461
+ setKey("");
462
+ };
463
+ const cancel = () => {
464
+ setEditor(null);
465
+ setName("");
466
+ setKey("");
467
+ };
468
+ (0, import_react2.useEffect)(() => {
469
+ if (editor?.ref != null && !state.entries.some((entry) => entry.apiKeyEnv === editor.ref)) cancel();
470
+ }, [state.entries, editor]);
471
+ const submit = async () => {
472
+ if (!editor) return;
473
+ 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);
474
+ if (accepted) cancel();
475
+ };
476
+ const move = (ref, toIndex) => {
477
+ void actions.moveAccount(ref, toIndex);
478
+ };
479
+ const summary = total ? t("accountsSummary", { count: total, name: preferred ? preferred.name || t("accountDefault") : "" }) : t("accountsSummaryEmpty");
480
+ const editorTitle = (kind) => t(kind === "add" ? "accountAdd" : kind === "rename" ? "accountRename" : kind === "key" ? "accountReplaceKey" : "accountRemove");
481
+ const editorForm = (label = "") => editor ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
482
+ "form",
483
+ {
484
+ className: Section_default.accountEditor,
485
+ onSubmit: (event) => {
486
+ event.preventDefault();
487
+ void submit();
488
+ },
489
+ onKeyDown: (event) => {
490
+ if (event.key === "Escape") {
491
+ event.preventDefault();
492
+ cancel();
493
+ }
494
+ },
495
+ children: [
496
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountEditorHead, children: [
497
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountEditorTitle, children: editorTitle(editor.kind) }),
498
+ label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountEditorFor, children: label }) : null
499
+ ] }),
500
+ editor.kind === "remove" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountRemoveHint", { name }) }) : null,
501
+ editor.kind === "add" || editor.kind === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: Section_default.accountField, children: [
502
+ t("accountName"),
503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
504
+ "input",
505
+ {
506
+ className: Section_default.input,
507
+ value: name,
508
+ maxLength: 80,
509
+ required: true,
510
+ disabled: state.busy,
511
+ autoFocus: true,
512
+ onChange: (event) => {
513
+ setName(event.target.value);
514
+ }
515
+ }
516
+ )
517
+ ] }) : null,
518
+ editor.kind === "add" || editor.kind === "key" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
519
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: Section_default.accountField, children: [
520
+ t("keyLabel"),
521
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
522
+ "input",
523
+ {
524
+ className: Section_default.input,
525
+ type: "password",
526
+ autoComplete: "off",
527
+ value: key,
528
+ required: true,
529
+ disabled: state.busy,
530
+ autoFocus: true,
531
+ onChange: (event) => {
532
+ setKey(event.target.value);
533
+ }
534
+ }
535
+ )
536
+ ] }),
537
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountKeyHint") })
538
+ ] }) : null,
539
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountEditorActions, children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
541
+ import_dsh_client_ui_primitives2.Button,
542
+ {
543
+ variant: "primary",
544
+ size: "sm",
545
+ type: "submit",
546
+ disabled: editor.kind === "key" ? state.busy || state.blocked : disabled,
547
+ children: t(state.busy ? "saving" : "accountConfirm")
548
+ }
549
+ ),
550
+ /* @__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") })
551
+ ] })
552
+ ]
553
+ }
554
+ ) : null;
555
+ const detail = (account, label) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountDetail, children: [
556
+ 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: [
557
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { children: [
558
+ t(`usage_${window}`),
559
+ " \xB7 ",
560
+ account.usage[window].percent,
561
+ "%"
562
+ ] }),
563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
564
+ "progress",
565
+ {
566
+ "data-level": barLevel(account.usage[window]),
567
+ max: 100,
568
+ value: Math.min(100, account.usage[window].percent),
569
+ "aria-label": `${label} ${t(`usage_${window}`)}`
570
+ }
571
+ ),
572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.hint, children: [
573
+ t("usageResets"),
574
+ " ",
575
+ new Date(account.usage[window].resetsAt).toLocaleString(locale)
576
+ ] })
577
+ ] }, window)) }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t(account.loading ? "usageLoading" : "usageUnavailable") }),
578
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountActions, children: [
579
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", disabled, onClick: () => {
580
+ start({ kind: "rename", ref: account.apiKeyEnv }, label);
581
+ }, children: t("accountRename") }),
582
+ /* @__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: () => {
583
+ start({ kind: "key", ref: account.apiKeyEnv }, label);
584
+ }, children: t("accountReplaceKey") }),
585
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", size: "sm", disabled, onClick: () => {
586
+ start({ kind: "remove", ref: account.apiKeyEnv }, label);
587
+ }, children: t("accountRemove") })
588
+ ] })
589
+ ] });
590
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: open ? Section_default.card : Section_default.card + " " + Section_default.cardFolded, children: [
591
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.cardHead, children: [
592
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
593
+ "button",
594
+ {
595
+ type: "button",
596
+ className: Section_default.cardTrigger,
597
+ "aria-expanded": open,
598
+ "aria-controls": "opencode-go-accounts",
599
+ onClick: () => {
600
+ setOpen(!open);
601
+ },
602
+ children: [
603
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardTitle, children: t("accountsTitle") }),
604
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.cardSub, children: summary }),
605
+ 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,
606
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: open ? Section_default.chevronOpen : Section_default.chevron })
607
+ ]
608
+ }
609
+ ),
610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.trailing, children: [
611
+ updatedAt > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.cardStamp, title: new Date(updatedAt).toLocaleString(locale), children: [
612
+ t("usageLastUpdated"),
613
+ " ",
614
+ stampText(updatedAt, locale)
615
+ ] }) : null,
616
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
617
+ import_dsh_client_ui_primitives2.Button,
618
+ {
619
+ variant: "outline",
620
+ size: "sm",
621
+ disabled: state.refreshing,
622
+ onClick: actions.loadAccounts,
623
+ children: t(state.refreshing ? "usageRefreshing" : "accountsRefresh")
624
+ }
625
+ )
626
+ ] })
627
+ ] }),
628
+ open ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-accounts", className: Section_default.cardBody, children: [
629
+ state.blocked ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountsBlocked") }) : null,
630
+ 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,
631
+ !total ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountsEmpty") }) : null,
632
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accounts, children: [
633
+ state.entries.map((account, index) => {
634
+ const label = account.name || t("accountDefault");
635
+ const rolling = account.usage?.rolling;
636
+ const expanded = details === account.apiKeyEnv;
637
+ const panelId = `opencode-go-account-${index}`;
638
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Fragment, { children: [
639
+ reorderable && dropAt === index ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.accountDropLine }) : null,
640
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
641
+ "div",
642
+ {
643
+ className: Section_default.accountRow,
644
+ "data-account-row": account.apiKeyEnv,
645
+ "data-dragging": dragging === account.apiKeyEnv ? "true" : void 0,
646
+ onDragStart: (event) => {
647
+ if (!reorderable || event.target?.closest?.("[data-account-handle]") == null) {
648
+ event.preventDefault();
649
+ return;
650
+ }
651
+ if (event.dataTransfer) {
652
+ event.dataTransfer.effectAllowed = "move";
653
+ event.dataTransfer.setData("text/plain", account.apiKeyEnv);
654
+ if (typeof event.dataTransfer.setDragImage === "function") {
655
+ event.dataTransfer.setDragImage(event.currentTarget, 16, 16);
656
+ }
657
+ }
658
+ setDragging(account.apiKeyEnv);
659
+ },
660
+ onDragOver: (event) => {
661
+ if (!reorderable || dragging === null || dragging === account.apiKeyEnv) return;
662
+ event.preventDefault();
663
+ if (event.dataTransfer) event.dataTransfer.dropEffect = "move";
664
+ const box = event.currentTarget.getBoundingClientRect();
665
+ setDropAt(event.clientY < box.top + box.height / 2 ? index : index + 1);
666
+ },
667
+ onDrop: (event) => {
668
+ const source = dragging;
669
+ const slot = dropAt;
670
+ setDragging(null);
671
+ setDropAt(null);
672
+ if (source === null || slot === null) return;
673
+ event.preventDefault();
674
+ const from = state.entries.findIndex((entry) => entry.apiKeyEnv === source);
675
+ if (from >= 0) move(source, slot > from ? slot - 1 : slot);
676
+ },
677
+ onDragEnd: () => {
678
+ setDragging(null);
679
+ setDropAt(null);
680
+ },
681
+ children: [
682
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountMain, "data-account-main": "", children: [
683
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
684
+ "button",
685
+ {
686
+ type: "button",
687
+ className: Section_default.accountHandle,
688
+ "data-account-handle": "",
689
+ draggable: reorderable,
690
+ disabled: !reorderable,
691
+ title: t("accountDragHandle", { name: label }),
692
+ "aria-label": t("accountDragHandle", { name: label }),
693
+ onKeyDown: (event) => {
694
+ if (event.key === "ArrowUp" && index > 0) {
695
+ event.preventDefault();
696
+ move(account.apiKeyEnv, index - 1);
697
+ }
698
+ if (event.key === "ArrowDown" && index < total - 1) {
699
+ event.preventDefault();
700
+ move(account.apiKeyEnv, index + 1);
701
+ }
702
+ },
703
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GripIcon, {})
704
+ }
705
+ ),
706
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { className: Section_default.accountName, title: label, children: label }),
707
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.accountState, children: [
708
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountDot, "data-off": account.configured === false ? "true" : void 0 }),
709
+ account.configured === void 0 ? t(account.failed ? "accountsStatusUnknown" : "usageLoading") : account.configured ? t("keyConfigured") : t("keyMissing")
710
+ ] }),
711
+ rolling ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
713
+ "span",
714
+ {
715
+ className: Section_default.accountBar,
716
+ role: "progressbar",
717
+ "data-level": barLevel(rolling),
718
+ "aria-valuemin": 0,
719
+ "aria-valuemax": 100,
720
+ "aria-valuenow": Math.min(100, rolling.percent),
721
+ "aria-label": `${label} ${t("usage_rolling")}`,
722
+ children: [
723
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountBarFill, style: { width: `${Math.min(100, rolling.percent)}%` } }),
724
+ TICKS.map((at) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountBarTick, style: { left: `${at}%` } }, at))
725
+ ]
726
+ }
727
+ ),
728
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: Section_default.accountPercent, children: [
729
+ rolling.percent,
730
+ "%"
731
+ ] }),
732
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountReset, children: resetText(rolling.resetsAt, t) })
733
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.accountIdle, children: account.configured === false ? t("accountConfigureHint") : t(account.loading ? "usageLoading" : "usageUnavailable") }),
734
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
735
+ "button",
736
+ {
737
+ type: "button",
738
+ className: Section_default.accountToggle,
739
+ "aria-expanded": expanded,
740
+ "aria-controls": panelId,
741
+ "aria-label": t(expanded ? "accountsDetailsHide" : "accountsDetails", { name: label }),
742
+ onClick: () => {
743
+ setDetails(expanded ? null : account.apiKeyEnv);
744
+ },
745
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, { className: expanded ? Section_default.chevronOpen : Section_default.chevron })
746
+ }
747
+ )
748
+ ] }),
749
+ account.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.accountProblems, role: "alert", children: [
750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: account.problem ?? t(account.stale ? "usageStaleHint" : "usageRefreshFailed") }),
751
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
752
+ "button",
753
+ {
754
+ type: "button",
755
+ className: Section_default.accountRetry,
756
+ disabled: state.refreshing,
757
+ onClick: actions.loadAccounts,
758
+ children: t("usageRetry")
759
+ }
760
+ )
761
+ ] }) : null,
762
+ expanded ? detail(account, label) : null,
763
+ editor?.ref === account.apiKeyEnv ? editorForm(label) : null
764
+ ]
765
+ }
766
+ )
767
+ ] }, account.id);
768
+ }),
769
+ reorderable && dropAt === total ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.accountDropLine }) : null
770
+ ] }),
771
+ editor ? editor.kind === "add" ? editorForm() : null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
772
+ import_dsh_client_ui_primitives2.Button,
773
+ {
774
+ variant: "outline",
775
+ size: "sm",
776
+ disabled: disabled || total >= MAX_ACCOUNTS,
777
+ onClick: () => {
778
+ start({ kind: "add" });
779
+ },
780
+ children: t("accountAdd")
781
+ }
782
+ ),
783
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.field, children: [
784
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: Section_default.head, children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: Section_default.label, children: t("accountAutoSwitch") }),
786
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
787
+ import_dsh_client_ui_primitives2.Switch,
788
+ {
789
+ checked: state.autoSwitch,
790
+ disabled,
791
+ label: t("accountAutoSwitch"),
792
+ onChange: (next) => {
793
+ void actions.setAutoSwitch(next);
794
+ }
795
+ }
796
+ )
797
+ ] }),
798
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("accountAutoSwitchHint") })
799
+ ] })
800
+ ] }) : null
801
+ ] });
802
+ }
803
+
378
804
  // src/usage-display.ts
379
805
  var USAGE_DISPLAY_MODES = ["auto", "always", "off"];
380
806
  var DEFAULT_USAGE_DISPLAY = "auto";
381
807
 
382
808
  // src/client/Section.tsx
383
- var import_jsx_runtime2 = require("react/jsx-runtime");
384
- var ChevronDown = primitives.IconChevronDownOutlineRegular ?? primitives.IconChevronDownOutline14;
809
+ var import_jsx_runtime3 = require("react/jsx-runtime");
810
+ var ChevronDown2 = primitives2.IconChevronDownOutlineRegular ?? primitives2.IconChevronDownOutline14;
385
811
  function ValueField(props) {
386
812
  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)(
813
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.field, children: [
814
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.head, children: [
815
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: Section_default.label, htmlFor: props.id, children: props.label }),
816
+ props.field.overridden ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: Section_default.badges, children: [
817
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: "neutral", children: props.overriddenLabel }),
818
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
393
819
  "button",
394
820
  {
395
821
  type: "button",
@@ -401,7 +827,7 @@ function ValueField(props) {
401
827
  )
402
828
  ] }) : null
403
829
  ] }),
404
- props.options ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
830
+ props.options ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
405
831
  "select",
406
832
  {
407
833
  id: props.id,
@@ -414,14 +840,15 @@ function ValueField(props) {
414
840
  onChange: (event) => {
415
841
  props.onEdit(event.target.value);
416
842
  },
417
- children: props.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: option.value, children: option.label }, option.value))
843
+ children: props.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: option.value, children: option.label }, option.value))
418
844
  }
419
- ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
845
+ ) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
420
846
  "input",
421
847
  {
422
848
  id: props.id,
423
849
  name: props.id,
424
850
  autoComplete: "off",
851
+ placeholder: props.placeholder,
425
852
  "aria-describedby": hintId,
426
853
  className: props.field.invalid ? Section_default.inputInvalid : Section_default.input,
427
854
  type: props.numeric === true ? "number" : "text",
@@ -434,7 +861,7 @@ function ValueField(props) {
434
861
  }
435
862
  }
436
863
  ),
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 })
864
+ /* @__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
865
  ] });
439
866
  }
440
867
  function ModelsBody({ models, t, locale }) {
@@ -442,7 +869,7 @@ function ModelsBody({ models, t, locale }) {
442
869
  const metadataOnlyFailure = sources?.metadata.error !== void 0 && sources.listing.error === void 0;
443
870
  const sourceStatus = sources ? ["listing", "metadata"].map((source) => {
444
871
  const status = sources[source];
445
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: Section_default.hint, children: [
872
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: Section_default.hint, children: [
446
873
  t(source === "listing" ? "modelsListingSource" : "modelsMetadataSource"),
447
874
  ": ",
448
875
  " ",
@@ -453,28 +880,28 @@ function ModelsBody({ models, t, locale }) {
453
880
  ] }, source);
454
881
  }) : null;
455
882
  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,
883
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
884
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsFailed") }),
885
+ models.message ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
459
886
  sourceStatus
460
887
  ] });
461
888
  }
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: [
889
+ if (models.status !== "ready") return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, role: "status", "aria-live": "polite", children: t("modelsLoading") });
890
+ const progress = models.refreshing ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, role: "status", children: t("modelsRefreshing") }) : null;
891
+ if (models.stale) return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
465
892
  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,
893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t(metadataOnlyFailure ? "modelsMetadataFailed" : "modelsStale") }),
894
+ models.message ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: models.message }) : null,
468
895
  sourceStatus
469
896
  ] });
470
897
  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") });
898
+ if (models.count === 0) return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("modelsEmpty") });
472
899
  return null;
473
900
  }
474
901
  function OpencodeGoSection(props) {
475
902
  const { useOpencodeGo, edit, resetField, save, discard, loadModels, setEnabled, setModelEnabled, t } = props;
476
903
  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)(
904
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
478
905
  Loaded,
479
906
  {
480
907
  state: useOpencodeGo((snapshot) => snapshot),
@@ -486,43 +913,63 @@ function OpencodeGoSection(props) {
486
913
  discard,
487
914
  loadModels,
488
915
  setEnabled,
489
- setModelEnabled
916
+ setModelEnabled,
917
+ accountActions: props.loadAccounts && props.addAccount && props.renameAccount && props.removeAccount && props.selectAccount && props.setAutoSwitch && props.replaceAccountKey && props.moveAccount ? {
918
+ loadAccounts: props.loadAccounts,
919
+ addAccount: props.addAccount,
920
+ renameAccount: props.renameAccount,
921
+ removeAccount: props.removeAccount,
922
+ selectAccount: props.selectAccount,
923
+ setAutoSwitch: props.setAutoSwitch,
924
+ replaceAccountKey: props.replaceAccountKey,
925
+ moveAccount: props.moveAccount
926
+ } : void 0
490
927
  }
491
928
  );
492
929
  }
493
930
  function Loaded(props) {
494
931
  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
932
+ const [advanced, setAdvanced] = (0, import_react3.useState)(false);
933
+ const [modelsOpen, setModelsOpen] = (0, import_react3.useState)(false);
934
+ const modelNotices = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ModelsBody, { models: state.models, t, locale: props.locale }),
936
+ state.pickerFailed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, role: "alert", children: t("pickerFailed") }) : null
500
937
  ] });
501
- (0, import_react2.useEffect)(() => {
938
+ (0, import_react3.useEffect)(() => {
502
939
  if (state.available && state.models.status === "idle") loadModels();
503
940
  }, [state.available, state.models.status, loadModels]);
504
941
  if (!state.available) {
505
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.intro, children: t("unavailable") });
942
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.intro, children: t("unavailable") });
506
943
  }
507
944
  const disabled = !state.writable;
945
+ const accountCard = state.accounts && props.accountActions ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
946
+ AccountsCard,
947
+ {
948
+ state: state.accounts,
949
+ actions: props.accountActions,
950
+ writable: state.writable,
951
+ t,
952
+ locale: props.locale
953
+ }
954
+ ) : null;
508
955
  const fieldProps = {
509
956
  invalidLabel: t("invalidValue"),
510
957
  overriddenLabel: t("overridden"),
511
958
  resetLabel: t("reset"),
512
959
  disabled
513
960
  };
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") })
961
+ const advancedOverridden = state.usageDisplay.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;
962
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.page, children: [
963
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.pageBody, children: [
964
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.pageTop, children: [
965
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { className: Section_default.title, children: t("titleLabel") }),
966
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.intro, children: t("intro") })
520
967
  ] }),
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,
968
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: Section_default.card, children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardHead, children: [
970
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: Section_default.cardTitle, children: t("enabledLabel") }),
971
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
972
+ import_dsh_client_ui_primitives3.Switch,
526
973
  {
527
974
  checked: state.enabled,
528
975
  label: t("enabledLabel"),
@@ -531,38 +978,41 @@ function Loaded(props) {
531
978
  }
532
979
  )
533
980
  ] }),
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);
981
+ /* @__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") }) }),
982
+ accountCard ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
983
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: Section_default.cardDivider }),
984
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardHead, children: [
985
+ /* @__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: [
986
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "5.4", cy: "8", r: "3.1" }),
987
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M8.5 8h5.3M11.9 8v2.2M10.2 8v1.6" })
988
+ ] }) }),
989
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: Section_default.label, htmlFor: "opencode-go-key", children: t("keyLabel") }),
990
+ /* @__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") }) })
991
+ ] }),
992
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.cardBody, children: [
993
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
994
+ "input",
995
+ {
996
+ id: "opencode-go-key",
997
+ name: "api-key",
998
+ className: Section_default.input,
999
+ type: "password",
1000
+ autoComplete: "off",
1001
+ "aria-describedby": "opencode-go-key-hint",
1002
+ value: state.apiKey.text,
1003
+ disabled: !state.apiKeyWritable,
1004
+ onChange: (event) => {
1005
+ props.edit("apiKey", event.target.value);
1006
+ }
558
1007
  }
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") })
1008
+ ),
1009
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { id: "opencode-go-key-hint", className: Section_default.hint, children: state.apiKeyWritable ? t("keyHint") : t("keyNotWritable") })
1010
+ ] })
562
1011
  ] })
563
1012
  ] }),
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)(
1013
+ accountCard,
1014
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: modelsOpen ? Section_default.cardModels : Section_default.cardModels + " " + Section_default.cardFolded, children: [
1015
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
566
1016
  "button",
567
1017
  {
568
1018
  type: "button",
@@ -573,14 +1023,14 @@ function Loaded(props) {
573
1023
  setModelsOpen(!modelsOpen);
574
1024
  },
575
1025
  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 })
1026
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardTitle, children: t("modelsLabel") }),
1027
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDown2, { className: modelsOpen ? Section_default.chevronOpen : Section_default.chevron })
578
1028
  ]
579
1029
  }
580
1030
  ),
581
- modelsOpen ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { id: "opencode-go-models", className: Section_default.cardBody, children: [
1031
+ modelsOpen ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { id: "opencode-go-models", className: Section_default.cardBody, children: [
582
1032
  modelNotices,
583
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1033
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
584
1034
  ModelEditor,
585
1035
  {
586
1036
  models: state.models,
@@ -590,8 +1040,8 @@ function Loaded(props) {
590
1040
  disabled: disabled || state.saving,
591
1041
  modelVisibility: state.modelVisibility,
592
1042
  visibilitySaving: state.pickerSaving,
593
- filterAction: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
594
- import_dsh_client_ui_primitives2.Button,
1043
+ filterAction: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1044
+ import_dsh_client_ui_primitives3.Button,
595
1045
  {
596
1046
  variant: "outline",
597
1047
  size: "sm",
@@ -606,10 +1056,10 @@ function Loaded(props) {
606
1056
  }
607
1057
  }
608
1058
  )
609
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: Section_default.cardNotes, children: modelNotices })
1059
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: Section_default.cardNotes, children: modelNotices })
610
1060
  ] }),
611
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: Section_default.card, children: [
612
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1061
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: Section_default.card, children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
613
1063
  "button",
614
1064
  {
615
1065
  type: "button",
@@ -620,17 +1070,17 @@ function Loaded(props) {
620
1070
  setAdvanced(!advanced);
621
1071
  },
622
1072
  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 })
1073
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardTitle, children: t("advancedLabel") }),
1074
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: Section_default.cardSub, children: t("advancedSummary") }),
1075
+ advancedOverridden ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: "neutral", children: t("overridden") }) : null,
1076
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDown2, { className: advanced ? Section_default.chevronOpen : Section_default.chevron })
627
1077
  ]
628
1078
  }
629
1079
  ),
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)(
1080
+ advanced ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { id: "opencode-go-advanced", className: Section_default.cardBody, children: [
1081
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("advancedHint") }),
1082
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.advancedGrid, children: [
1083
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
634
1084
  ValueField,
635
1085
  {
636
1086
  id: "opencode-go-usage-display",
@@ -647,7 +1097,7 @@ function Loaded(props) {
647
1097
  }
648
1098
  }
649
1099
  ),
650
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1100
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
651
1101
  ValueField,
652
1102
  {
653
1103
  id: "opencode-go-api-key-env",
@@ -663,7 +1113,7 @@ function Loaded(props) {
663
1113
  }
664
1114
  }
665
1115
  ),
666
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1116
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
667
1117
  ValueField,
668
1118
  {
669
1119
  id: "opencode-go-base-url",
@@ -679,7 +1129,25 @@ function Loaded(props) {
679
1129
  }
680
1130
  }
681
1131
  ),
682
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1132
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1133
+ ValueField,
1134
+ {
1135
+ id: "opencode-go-proxy-url",
1136
+ label: t("proxyURLLabel"),
1137
+ hint: t("proxyURLHint"),
1138
+ placeholder: "http://127.0.0.1:7890",
1139
+ field: state.proxyURL,
1140
+ ...fieldProps,
1141
+ invalidLabel: t("proxyURLInvalid"),
1142
+ onEdit: (text) => {
1143
+ props.edit("proxyURL", text);
1144
+ },
1145
+ onReset: () => {
1146
+ props.resetField("proxyURL");
1147
+ }
1148
+ }
1149
+ ),
1150
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
683
1151
  ValueField,
684
1152
  {
685
1153
  id: "opencode-go-refresh-minutes",
@@ -696,7 +1164,7 @@ function Loaded(props) {
696
1164
  }
697
1165
  }
698
1166
  ),
699
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1167
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
700
1168
  ValueField,
701
1169
  {
702
1170
  id: "opencode-go-stream-idle",
@@ -713,7 +1181,7 @@ function Loaded(props) {
713
1181
  }
714
1182
  }
715
1183
  ),
716
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1184
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
717
1185
  ValueField,
718
1186
  {
719
1187
  id: "opencode-go-max-images",
@@ -730,7 +1198,7 @@ function Loaded(props) {
730
1198
  }
731
1199
  }
732
1200
  ),
733
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1201
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
734
1202
  ValueField,
735
1203
  {
736
1204
  id: "opencode-go-max-request-image-bytes",
@@ -747,7 +1215,7 @@ function Loaded(props) {
747
1215
  }
748
1216
  }
749
1217
  ),
750
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1218
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
751
1219
  ValueField,
752
1220
  {
753
1221
  id: "opencode-go-image-pixel-budget",
@@ -764,7 +1232,7 @@ function Loaded(props) {
764
1232
  }
765
1233
  }
766
1234
  ),
767
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1235
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
768
1236
  ValueField,
769
1237
  {
770
1238
  id: "opencode-go-image-max-bytes",
@@ -784,12 +1252,12 @@ function Loaded(props) {
784
1252
  ] })
785
1253
  ] }) : null
786
1254
  ] }),
787
- disabled ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
1255
+ disabled ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.hint, children: t("readOnly") }) : null
788
1256
  ] }),
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)(
1257
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: Section_default.actions, children: [
1258
+ /* @__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") }),
1259
+ /* @__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") }),
1260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
793
1261
  "a",
794
1262
  {
795
1263
  className: Section_default.starLink,
@@ -798,12 +1266,12 @@ function Loaded(props) {
798
1266
  rel: "noopener noreferrer",
799
1267
  title: t("starProjectTitle"),
800
1268
  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") })
1269
+ /* @__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" }) }),
1270
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("starProject") })
803
1271
  ]
804
1272
  }
805
1273
  ),
806
- state.failed ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
1274
+ state.failed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: Section_default.failedNote, children: t("savedFailed") }) : null
807
1275
  ] })
808
1276
  ] });
809
1277
  }
@@ -811,6 +1279,329 @@ function Loaded(props) {
811
1279
  // src/provider-identity.ts
812
1280
  var PROVIDER_ID = "dsh-opencode-go";
813
1281
 
1282
+ // src/proxy-url.ts
1283
+ function assertProxyURL(raw) {
1284
+ const value = raw?.trim() ?? "";
1285
+ if (!value) return "";
1286
+ let url;
1287
+ try {
1288
+ url = new URL(value);
1289
+ } catch {
1290
+ throw new Error("OpenCode Go: proxy address must be a valid URL");
1291
+ }
1292
+ if (!["http:", "https:", "socks5:"].includes(url.protocol)) {
1293
+ throw new Error("OpenCode Go: proxy address must use http://, https:// or socks5://");
1294
+ }
1295
+ if (!url.hostname || url.port === "0" || url.pathname !== "" && url.pathname !== "/" || url.search || url.hash) {
1296
+ throw new Error("OpenCode Go: proxy address must contain a host and optional port, without a path, query or fragment");
1297
+ }
1298
+ try {
1299
+ decodeURIComponent(url.username);
1300
+ decodeURIComponent(url.password);
1301
+ } catch {
1302
+ throw new Error("OpenCode Go: proxy credentials contain invalid URL encoding");
1303
+ }
1304
+ return url.href;
1305
+ }
1306
+
1307
+ // src/client/accounts-controller.ts
1308
+ function isSettingsConflict(error) {
1309
+ if (!error || typeof error !== "object") return false;
1310
+ const { name, code, message } = error;
1311
+ return /conflict/i.test(`${String(name ?? "")} ${String(code ?? "")} ${String(message ?? "")}`);
1312
+ }
1313
+ var GoAccountsController = class {
1314
+ constructor(scope, ctx, readUsage, publish, blocked) {
1315
+ this.scope = scope;
1316
+ this.ctx = ctx;
1317
+ this.readUsage = readUsage;
1318
+ this.publish = publish;
1319
+ this.blocked = blocked;
1320
+ this.sync();
1321
+ }
1322
+ rows = /* @__PURE__ */ new Map();
1323
+ busy = false;
1324
+ refreshing = false;
1325
+ failure;
1326
+ epoch = 0;
1327
+ identity = "";
1328
+ loaded = false;
1329
+ disposed = false;
1330
+ snapshot() {
1331
+ const config = this.scope.getSnapshot().value ?? {};
1332
+ return {
1333
+ entries: accountsOf(config).map((account) => ({ ...this.rows.get(account.apiKeyEnv), ...account })),
1334
+ activeRef: accountRefOf(config),
1335
+ autoSwitch: config.autoSwitch === true,
1336
+ busy: this.busy,
1337
+ blocked: this.blocked(),
1338
+ refreshing: this.refreshing,
1339
+ failure: this.failure
1340
+ };
1341
+ }
1342
+ sync() {
1343
+ const config = this.scope.getSnapshot().value ?? {};
1344
+ const identity = JSON.stringify([
1345
+ accountsOf(config).map((account) => [account.id, account.apiKeyEnv]).sort((left, right) => left[1] < right[1] ? -1 : left[1] > right[1] ? 1 : 0),
1346
+ config.baseURL,
1347
+ config.proxyURL
1348
+ ]);
1349
+ if (identity === this.identity) return;
1350
+ this.identity = identity;
1351
+ this.epoch++;
1352
+ this.rows.clear();
1353
+ this.refreshing = false;
1354
+ if (this.loaded) void this.refresh();
1355
+ }
1356
+ dispose() {
1357
+ this.disposed = true;
1358
+ this.epoch++;
1359
+ }
1360
+ invalidate(ref) {
1361
+ if (!accountsOf(this.scope.getSnapshot().value ?? {}).some((account) => account.apiKeyEnv === ref)) return;
1362
+ this.epoch++;
1363
+ this.rows.delete(ref);
1364
+ if (this.loaded) void this.refresh();
1365
+ }
1366
+ async refresh() {
1367
+ this.loaded = true;
1368
+ const epoch = ++this.epoch;
1369
+ const accounts = [...accountsOf(this.scope.getSnapshot().value ?? {})];
1370
+ this.refreshing = true;
1371
+ this.publish();
1372
+ try {
1373
+ const described = await this.ctx.remote.credentials.describe(accounts.map((account) => account.apiKeyEnv));
1374
+ if (this.disposed || epoch !== this.epoch) return;
1375
+ if (!described.ok) {
1376
+ this.failure = "read";
1377
+ this.markUnreadable(accounts, described.error instanceof Error ? described.error.message : String(described.error));
1378
+ return;
1379
+ }
1380
+ this.failure = void 0;
1381
+ await Promise.all(accounts.map(async (account) => {
1382
+ const ref = account.apiKeyEnv;
1383
+ const info = described.value[ref];
1384
+ const previous = this.rows.get(ref);
1385
+ this.rows.set(ref, {
1386
+ ...previous,
1387
+ ...account,
1388
+ configured: info?.configured ?? false,
1389
+ writable: info?.writable ?? true,
1390
+ loading: info?.configured === true,
1391
+ failed: false
1392
+ });
1393
+ this.publish();
1394
+ if (!info?.configured) {
1395
+ this.rows.set(ref, { ...account, configured: false, writable: info?.writable ?? true });
1396
+ return;
1397
+ }
1398
+ try {
1399
+ const usage = await this.readUsage(ref);
1400
+ if (this.disposed || epoch !== this.epoch) return;
1401
+ this.rows.set(ref, { ...account, configured: true, writable: info.writable, usage, updatedAt: Date.now() });
1402
+ } catch (error) {
1403
+ if (this.disposed || epoch !== this.epoch) return;
1404
+ 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;
1405
+ const retain = details?.retryable === true && details.retainPrevious === true && previous?.usage?.source && previous.usage.source === details.source;
1406
+ const message = error instanceof Error ? error.message : String(error);
1407
+ this.rows.set(ref, {
1408
+ ...account,
1409
+ configured: true,
1410
+ writable: info.writable,
1411
+ failed: true,
1412
+ problem: message.length > 200 ? message.slice(0, 200) + "\u2026" : message,
1413
+ ...retain ? { usage: previous.usage, updatedAt: previous.updatedAt, stale: true } : {}
1414
+ });
1415
+ }
1416
+ this.publish();
1417
+ }));
1418
+ } catch (error) {
1419
+ if (epoch === this.epoch) {
1420
+ this.failure = "read";
1421
+ this.markUnreadable(accounts, error instanceof Error ? error.message : String(error));
1422
+ }
1423
+ } finally {
1424
+ if (!this.disposed && epoch === this.epoch) {
1425
+ this.refreshing = false;
1426
+ this.publish();
1427
+ }
1428
+ }
1429
+ }
1430
+ /** Mark every account row as unreadable with the Host's own diagnostic. */
1431
+ markUnreadable(accounts, message) {
1432
+ const problem = message.length > 200 ? message.slice(0, 200) + "\u2026" : message;
1433
+ for (const account of accounts) this.rows.set(account.apiKeyEnv, { ...account, failed: true, problem });
1434
+ this.publish();
1435
+ }
1436
+ actions() {
1437
+ return {
1438
+ loadAccounts: () => {
1439
+ void this.refresh();
1440
+ },
1441
+ addAccount: (name, key) => this.add(name, key),
1442
+ renameAccount: (ref, name) => this.rename(ref, name),
1443
+ removeAccount: (ref) => this.remove(ref),
1444
+ selectAccount: (ref) => this.select(ref),
1445
+ setAutoSwitch: (next) => this.run(async () => {
1446
+ await this.scope.set("autoSwitch", next);
1447
+ return this.scope.getSnapshot().value?.autoSwitch === next;
1448
+ }),
1449
+ replaceAccountKey: (ref, key) => this.run(async () => {
1450
+ if (!key.trim() || !this.account(ref) || this.rows.get(ref)?.writable === false) return false;
1451
+ const response = await this.ctx.remote.credentials.set(ref, key.trim());
1452
+ if (!response.ok) return false;
1453
+ this.invalidate(ref);
1454
+ return true;
1455
+ }, false),
1456
+ moveAccount: (ref, toIndex) => this.move(ref, toIndex)
1457
+ };
1458
+ }
1459
+ /**
1460
+ * Reorder the visible accounts and keep the preferred reference on the first row.
1461
+ * The adapter tries the preferred reference first and the rest in array order, so
1462
+ * one write is what makes top-to-bottom the real call order. A placeholder row the
1463
+ * settings never stored is materialized here, which its `legacy:` id admits.
1464
+ */
1465
+ move(ref, toIndex) {
1466
+ return this.run(async () => {
1467
+ const snapshot = this.scope.getSnapshot();
1468
+ const entries = [...accountsOf(snapshot.value ?? {})];
1469
+ const from = entries.findIndex((account) => account.apiKeyEnv === ref);
1470
+ if (from < 0 || !Number.isInteger(toIndex) || toIndex < 0 || toIndex >= entries.length || toIndex === from) return false;
1471
+ const [moved] = entries.splice(from, 1);
1472
+ entries.splice(toIndex, 0, moved);
1473
+ await this.mutate([
1474
+ { op: "set", path: ["accounts"], value: entries },
1475
+ { op: "set", path: ["apiKeyEnv"], value: entries[0].apiKeyEnv }
1476
+ ], snapshot.revision);
1477
+ const after = this.scope.getSnapshot().value;
1478
+ return after?.apiKeyEnv === entries[0].apiKeyEnv && after.accounts?.[toIndex]?.apiKeyEnv === ref;
1479
+ });
1480
+ }
1481
+ account(ref) {
1482
+ return accountsOf(this.scope.getSnapshot().value ?? {}).find((account) => account.apiKeyEnv === ref);
1483
+ }
1484
+ async mutate(ops, revision = this.scope.getSnapshot().revision) {
1485
+ await this.scope.mutate(ops, revision);
1486
+ }
1487
+ add(name, key) {
1488
+ return this.run(async () => {
1489
+ if (!name.trim() || name.trim().length > 80 || !key.trim()) return false;
1490
+ const id3 = Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
1491
+ const ref = ACCOUNT_REF_PREFIX + id3.replaceAll("-", "").toUpperCase();
1492
+ const account = { id: id3, name: name.trim(), apiKeyEnv: ref };
1493
+ const response = await this.ctx.remote.credentials.set(ref, key.trim());
1494
+ if (!response.ok) return false;
1495
+ for (let attempt = 0; attempt < 3; attempt++) {
1496
+ const snapshot = this.scope.getSnapshot();
1497
+ const existing = accountsOf(snapshot.value ?? {});
1498
+ if (existing.some((entry) => entry.id === id3)) return true;
1499
+ const configured = await this.configuredOf(existing.map((entry) => entry.apiKeyEnv));
1500
+ const accounts = existing.filter((entry) => !(snapshot.value?.accounts == null && !entry.name && configured.get(entry.apiKeyEnv) === false));
1501
+ if (accounts.length >= MAX_ACCOUNTS) break;
1502
+ const first = existing.length === 0 || existing.every((entry) => configured.get(entry.apiKeyEnv) === false);
1503
+ try {
1504
+ await this.mutate([
1505
+ { op: "set", path: ["accounts"], value: [...accounts, account] },
1506
+ ...first ? [{ op: "set", path: ["apiKeyEnv"], value: ref }] : []
1507
+ ], snapshot.revision);
1508
+ } catch (error) {
1509
+ if (attempt < 2 && isSettingsConflict(error)) continue;
1510
+ return false;
1511
+ }
1512
+ if (this.scope.getSnapshot().value?.accounts?.some((entry) => entry.id === id3)) return true;
1513
+ break;
1514
+ }
1515
+ try {
1516
+ if (!(await this.ctx.remote.credentials.unset(ref)).ok) this.failure = "cleanup";
1517
+ } catch {
1518
+ this.failure = "cleanup";
1519
+ }
1520
+ return false;
1521
+ });
1522
+ }
1523
+ /** Loaded rows answer from cache; anything they do not know is described on
1524
+ * the spot, so a placeholder decision never races the page's first describe. */
1525
+ async configuredOf(refs) {
1526
+ const configured = /* @__PURE__ */ new Map();
1527
+ const unknown = refs.filter((ref) => {
1528
+ const known = this.rows.get(ref)?.configured;
1529
+ if (known === void 0) return true;
1530
+ configured.set(ref, known);
1531
+ return false;
1532
+ });
1533
+ if (unknown.length === 0) return configured;
1534
+ try {
1535
+ const described = await this.ctx.remote.credentials.describe(unknown);
1536
+ if (described.ok) for (const ref of unknown) configured.set(ref, described.value[ref]?.configured ?? false);
1537
+ } catch {
1538
+ }
1539
+ return configured;
1540
+ }
1541
+ rename(ref, name) {
1542
+ return this.run(async () => {
1543
+ if (!this.account(ref) || !name.trim() || name.trim().length > 80) return false;
1544
+ const accounts = accountsOf(this.scope.getSnapshot().value ?? {}).map((account) => account.apiKeyEnv === ref ? { ...account, name: name.trim() } : account);
1545
+ await this.mutate([{ op: "set", path: ["accounts"], value: accounts }]);
1546
+ return this.scope.getSnapshot().value?.accounts?.find((account) => account.apiKeyEnv === ref)?.name === name.trim();
1547
+ });
1548
+ }
1549
+ select(ref) {
1550
+ return this.run(async () => {
1551
+ if (!this.account(ref)) return false;
1552
+ await this.mutate([{ op: "set", path: ["apiKeyEnv"], value: ref }]);
1553
+ return accountRefOf(this.scope.getSnapshot().value ?? {}) === ref;
1554
+ });
1555
+ }
1556
+ remove(ref) {
1557
+ return this.run(async () => {
1558
+ if (!this.account(ref)) return false;
1559
+ if (ref.startsWith(ACCOUNT_REF_PREFIX)) {
1560
+ const described = await this.ctx.remote.credentials.describe([ref]).catch(() => void 0);
1561
+ if (!described?.ok || described.value[ref] === void 0) {
1562
+ this.failure = "remove";
1563
+ return false;
1564
+ }
1565
+ if (described.value[ref].configured === true) {
1566
+ let removed = false;
1567
+ try {
1568
+ removed = (await this.ctx.remote.credentials.unset(ref)).ok;
1569
+ } catch {
1570
+ }
1571
+ if (!removed) {
1572
+ this.failure = "remove";
1573
+ return false;
1574
+ }
1575
+ }
1576
+ }
1577
+ const config = this.scope.getSnapshot().value ?? {};
1578
+ const remaining = accountsOf(config).filter((account) => account.apiKeyEnv !== ref);
1579
+ await this.mutate([
1580
+ { op: "set", path: ["accounts"], value: remaining },
1581
+ ...accountRefOf(config) === ref && remaining.length ? [{ op: "set", path: ["apiKeyEnv"], value: remaining[0].apiKeyEnv }] : []
1582
+ ]);
1583
+ return !this.account(ref);
1584
+ });
1585
+ }
1586
+ async run(action, requiresSettings = true) {
1587
+ if (this.busy || this.blocked() || requiresSettings && !this.scope.getSnapshot().writable) return false;
1588
+ this.busy = true;
1589
+ this.failure = void 0;
1590
+ this.publish();
1591
+ try {
1592
+ const accepted = await action();
1593
+ if (!accepted && !this.failure) this.failure = "write";
1594
+ return accepted;
1595
+ } catch {
1596
+ this.failure ??= "write";
1597
+ return false;
1598
+ } finally {
1599
+ this.busy = false;
1600
+ this.publish();
1601
+ }
1602
+ }
1603
+ };
1604
+
814
1605
  // src/client/staged-form.ts
815
1606
  var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
816
1607
  function numberField(field, validate = () => true) {
@@ -932,7 +1723,9 @@ var StagedForm = class {
932
1723
  const write = staged.clear ? { kind: "clear" } : spec.parse(staged.text);
933
1724
  return {
934
1725
  text: staged.text,
935
- overridden: write?.kind === "set",
1726
+ // A draft a save would skip leaves the user layer exactly as it stands, so
1727
+ // the badge answers for that standing override instead of the edit.
1728
+ overridden: this.unchangedDraft(field, staged) ? this.stored(field) : write?.kind === "set",
936
1729
  invalid: write === void 0
937
1730
  };
938
1731
  }
@@ -976,7 +1769,11 @@ var StagedForm = class {
976
1769
  this.publish();
977
1770
  let landed = true;
978
1771
  for (const write of writes) {
979
- landed = await write() && landed;
1772
+ try {
1773
+ landed = await write() && landed;
1774
+ } catch {
1775
+ landed = false;
1776
+ }
980
1777
  }
981
1778
  if (landed) this.staged.clear();
982
1779
  this.saving = false;
@@ -1003,7 +1800,7 @@ var StagedForm = class {
1003
1800
  if (this.stored(field)) plan.push({ field, run: () => this.clear(field) });
1004
1801
  continue;
1005
1802
  }
1006
- if (staged.text === spec.format(this.sectionValue(field))) continue;
1803
+ if (this.unchangedDraft(field, staged)) continue;
1007
1804
  const write = spec.parse(staged.text);
1008
1805
  if (write === void 0) plan.push({ field, run: void 0 });
1009
1806
  else if (write.kind === "clear") plan.push({ field, run: () => this.clear(field) });
@@ -1045,6 +1842,16 @@ var StagedForm = class {
1045
1842
  const user = this.userLayer();
1046
1843
  return user !== void 0 && Object.hasOwn(user, field);
1047
1844
  }
1845
+ /**
1846
+ * Whether a draft already equals the field's effective value, so a save would
1847
+ * write nothing. The save plan and the override badge both answer for it.
1848
+ * @param field - field name inside the namespace section.
1849
+ * @param staged - the staged edit to test.
1850
+ * @returns true when the draft is a no-op; a clear is never one.
1851
+ */
1852
+ unchangedDraft(field, staged) {
1853
+ return !staged.clear && staged.text === this.spec(field).format(this.sectionValue(field));
1854
+ }
1048
1855
  publish() {
1049
1856
  for (const listener of this.listeners) listener();
1050
1857
  }
@@ -1076,6 +1883,10 @@ var OpencodeGoSectionController = class {
1076
1883
  constructor(scope, ctx, readModels = async () => {
1077
1884
  const result = await ctx.remote.llm.discoverModels(OPENCODE_GO_NS, { provider: PROVIDER_ID });
1078
1885
  return result.ok ? { ok: true, value: { models: result.value, stale: false } } : result;
1886
+ }, readUsage = async (ref) => {
1887
+ const result = await ctx.remote.opencodeGoUsage.readAccount(ref);
1888
+ if (!result.ok) throw result.error;
1889
+ return result.value;
1079
1890
  }) {
1080
1891
  this.scope = scope;
1081
1892
  this.ctx = ctx;
@@ -1093,6 +1904,18 @@ var OpencodeGoSectionController = class {
1093
1904
  },
1094
1905
  textField("apiKeyEnv"),
1095
1906
  textField("baseURL"),
1907
+ {
1908
+ ...textField("proxyURL"),
1909
+ // Blank explicitly disables an inherited proxy; Reset removes the override.
1910
+ parse: (text) => {
1911
+ try {
1912
+ assertProxyURL(text);
1913
+ return { kind: "set", value: text.trim() };
1914
+ } catch {
1915
+ return void 0;
1916
+ }
1917
+ }
1918
+ },
1096
1919
  numberField("refreshMinutes"),
1097
1920
  numberField("streamIdleTimeoutMs"),
1098
1921
  numberField("maxImages", (value) => Number.isSafeInteger(value) && value > 0),
@@ -1104,9 +1927,25 @@ var OpencodeGoSectionController = class {
1104
1927
  [{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]
1105
1928
  );
1106
1929
  this.store = this.form.bind(() => this.projection());
1107
- let modelsEndpoint = scope.getSnapshot().value?.baseURL;
1930
+ this.accounts = new GoAccountsController(
1931
+ scope,
1932
+ ctx,
1933
+ readUsage,
1934
+ () => {
1935
+ this.store.set(this.projection());
1936
+ },
1937
+ () => this.form.shell().saving || this.pickerSaving || Boolean(this.form.field(API_KEY_FIELD).text.trim())
1938
+ );
1939
+ this.store.set(this.projection());
1940
+ const networkIdentity = () => JSON.stringify([
1941
+ scope.getSnapshot().value?.baseURL,
1942
+ scope.getSnapshot().value?.proxyURL
1943
+ ]);
1944
+ let modelsEndpoint = networkIdentity();
1108
1945
  this.unsubscribe = scope.subscribe(() => {
1109
- const endpoint = scope.getSnapshot().value?.baseURL;
1946
+ this.accounts?.sync();
1947
+ this.store.set(this.projection());
1948
+ const endpoint = networkIdentity();
1110
1949
  if (endpoint !== modelsEndpoint) {
1111
1950
  modelsEndpoint = endpoint;
1112
1951
  this.modelsRequest++;
@@ -1126,8 +1965,13 @@ var OpencodeGoSectionController = class {
1126
1965
  pickerFailed = false;
1127
1966
  face;
1128
1967
  unsubscribe;
1968
+ accounts;
1969
+ credentialRequest = 0;
1970
+ keyDraftRef;
1129
1971
  /** Release subscriptions without disposing the host's shared form. */
1130
1972
  dispose() {
1973
+ this.credentialRequest++;
1974
+ this.accounts?.dispose();
1131
1975
  this.modelsRequest++;
1132
1976
  this.unsubscribe();
1133
1977
  this.form.dispose();
@@ -1135,6 +1979,8 @@ var OpencodeGoSectionController = class {
1135
1979
  projection() {
1136
1980
  return {
1137
1981
  ...this.form.shell(),
1982
+ saving: this.form.shell().saving || this.accounts?.snapshot().busy === true,
1983
+ accounts: this.accounts?.snapshot(),
1138
1984
  enabled: this.enabled(),
1139
1985
  usageDisplay: this.form.field("usageDisplay"),
1140
1986
  modelVisibility: this.scope.getSnapshot().value?.modelVisibility ?? {},
@@ -1142,6 +1988,7 @@ var OpencodeGoSectionController = class {
1142
1988
  pickerFailed: this.pickerFailed,
1143
1989
  apiKeyEnv: this.form.field("apiKeyEnv"),
1144
1990
  baseURL: this.form.field("baseURL"),
1991
+ proxyURL: this.form.field("proxyURL"),
1145
1992
  refreshMinutes: this.form.field("refreshMinutes"),
1146
1993
  streamIdleTimeoutMs: this.form.field("streamIdleTimeoutMs"),
1147
1994
  maxImages: this.form.field("maxImages"),
@@ -1149,7 +1996,7 @@ var OpencodeGoSectionController = class {
1149
1996
  requestImagePixelBudget: this.form.field("requestImagePixelBudget"),
1150
1997
  requestImageMaxBytes: this.form.field("requestImageMaxBytes"),
1151
1998
  apiKey: this.form.field(API_KEY_FIELD),
1152
- apiKeyConfigured: this.credential.configured,
1999
+ apiKeyConfigured: this.credential.ref === refOf(this.scope.getSnapshot()) && this.credential.configured && accountsOf(this.scope.getSnapshot().value ?? {}).length > 0,
1153
2000
  apiKeyWritable: this.credential.writable,
1154
2001
  models: this.models,
1155
2002
  modelLimits: this.form.field("modelLimits"),
@@ -1206,7 +2053,7 @@ var OpencodeGoSectionController = class {
1206
2053
  }
1207
2054
  /** Serialize immediate switches with form saves; refused writes retain committed values. */
1208
2055
  async writePickerSetting(field, value, accepted) {
1209
- if (this.pickerSaving || this.form.shell().saving || !this.scope.getSnapshot().writable) return;
2056
+ if (this.pickerSaving || this.form.shell().saving || this.accounts?.snapshot().busy || !this.scope.getSnapshot().writable) return;
1210
2057
  this.pickerSaving = true;
1211
2058
  this.pickerFailed = false;
1212
2059
  this.store.set(this.projection());
@@ -1271,13 +2118,19 @@ var OpencodeGoSectionController = class {
1271
2118
  * reference in force.
1272
2119
  */
1273
2120
  async readCredential() {
2121
+ const request = ++this.credentialRequest;
1274
2122
  const ref = refOf(this.scope.getSnapshot());
2123
+ if (accountsOf(this.scope.getSnapshot().value ?? {}).length === 0) {
2124
+ this.credential = { ref, configured: false, writable: false };
2125
+ this.store.set(this.projection());
2126
+ return;
2127
+ }
1275
2128
  if (ref !== this.credential.ref) {
1276
2129
  this.credential = { ref, configured: false, writable: true };
1277
2130
  this.store.set(this.projection());
1278
2131
  }
1279
- const response = await this.ctx.remote.credentials.describe([ref]);
1280
- if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return;
2132
+ const response = await this.ctx.remote.credentials.describe([ref]).catch(() => void 0);
2133
+ if (!response?.ok || request !== this.credentialRequest || ref !== refOf(this.scope.getSnapshot())) return;
1281
2134
  const view = response.value[ref];
1282
2135
  const next = {
1283
2136
  ref,
@@ -1299,6 +2152,7 @@ var OpencodeGoSectionController = class {
1299
2152
  * @param ref - the reference the Host reports as changed.
1300
2153
  */
1301
2154
  refreshCredential(ref) {
2155
+ this.accounts?.invalidate(ref);
1302
2156
  if (ref !== this.credential.ref) return;
1303
2157
  void this.readCredential();
1304
2158
  }
@@ -1319,7 +2173,24 @@ var OpencodeGoSectionController = class {
1319
2173
  setModelEnabled: (id3, next) => {
1320
2174
  void this.setModelEnabled(id3, next);
1321
2175
  },
1322
- ...this.form.actions()
2176
+ ...this.form.actions(),
2177
+ ...this.accounts.actions(),
2178
+ edit: (field, text) => {
2179
+ if (field === API_KEY_FIELD) {
2180
+ if (text.trim()) this.keyDraftRef ??= refOf(this.scope.getSnapshot());
2181
+ else this.keyDraftRef = void 0;
2182
+ }
2183
+ this.form.actions().edit(field, text);
2184
+ },
2185
+ discard: () => {
2186
+ this.keyDraftRef = void 0;
2187
+ this.form.actions().discard();
2188
+ },
2189
+ save: () => {
2190
+ if (!this.accounts?.snapshot().busy) void this.form.save().then(() => {
2191
+ if (!this.form.field(API_KEY_FIELD).text.trim()) this.keyDraftRef = void 0;
2192
+ });
2193
+ }
1323
2194
  };
1324
2195
  return this.face;
1325
2196
  }
@@ -1329,9 +2200,12 @@ var OpencodeGoSectionController = class {
1329
2200
  * @returns whether the Host reports a configured credential afterwards.
1330
2201
  */
1331
2202
  async writeKey(value) {
1332
- await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value);
2203
+ const ref = this.keyDraftRef ?? refOf(this.scope.getSnapshot());
2204
+ const response = await this.ctx.remote.credentials.set(ref, value);
2205
+ if (!response.ok) return false;
2206
+ this.accounts?.invalidate(ref);
1333
2207
  await this.readCredential();
1334
- return this.credential.configured;
2208
+ return ref === this.credential.ref ? this.credential.configured : true;
1335
2209
  }
1336
2210
  };
1337
2211
  function modelLimitsOf(value) {
@@ -1364,9 +2238,50 @@ function refOf(snapshot) {
1364
2238
 
1365
2239
  // src/client/locales.ts
1366
2240
  var en = {
2241
+ accountsTitle: "Accounts",
2242
+ accountsRefresh: "Refresh accounts",
2243
+ accountsBlocked: "Save or discard the API key draft before changing accounts.",
2244
+ accountsEmpty: "Add an account to use OpenCode Go.",
2245
+ accountsWriteFailed: "Could not apply the account change. Your input is kept; please retry.",
2246
+ accountsReadFailed: "Could not read account status. Please refresh.",
2247
+ accountsCleanupFailed: "The account entry was removed, but its stored key could not be deleted. Remove the unused reference through the host credential service.",
2248
+ accountsRemoveKeyFailed: "The stored key could not be deleted, so the account was kept. Please retry.",
2249
+ accountsStatusUnknown: "Status unknown",
2250
+ accountDefault: "Default account",
2251
+ accountAdd: "Add account",
2252
+ accountRename: "Rename",
2253
+ accountReplaceKey: "Replace key",
2254
+ accountRemove: "Remove account",
2255
+ accountRemoveHint: "Remove \u201C{name}\u201D? If it is selected, the next account becomes preferred. Keys added here are deleted from the credential service; existing external references are kept.",
2256
+ accountName: "Account name",
2257
+ accountKeyHint: "The key is saved through the host credential service and is never returned to this page.",
2258
+ accountConfirm: "Confirm",
2259
+ accountCancel: "Cancel",
2260
+ accountAutoSwitch: "Automatic fallback",
2261
+ accountAutoSwitchHint: "Off by default. On quota exhaustion or a rejected key, try the other accounts in order before any content or tool call is emitted. Each account is tried at most once. Your preferred account stays selected; ordinary rate limits and network failures use host recovery.",
2262
+ accountPreferredTag: "Preferred",
2263
+ accountSwitchAction: "Switch",
2264
+ accountSwitchTitle: "Switch account",
2265
+ accountSwitchBack: "Back to usage",
2266
+ accountSwitchHint: "Later requests in this profile use this account. The consumption order stays on the Settings page.",
2267
+ accountSwitchFailed: "Could not switch account. Please retry.",
2268
+ accountFallbackQuota: "The preferred account reached its quota; automatically used",
2269
+ accountFallbackCredential: "The preferred key was unavailable or rejected; automatically used",
2270
+ accountsSummary: "{count} accounts \xB7 Preferred {name}",
2271
+ accountsSummaryEmpty: "No accounts yet",
2272
+ accountsAvailability: "{ready}/{total} configured",
2273
+ accountsAvailabilityFailed: "{ready}/{total} configured \xB7 {failed} unreadable",
2274
+ accountsDetails: "Details for {name}",
2275
+ accountsDetailsHide: "Hide details for {name}",
2276
+ accountDragHandle: "Reorder {name}",
2277
+ accountConfigureHint: "Add a key to read usage",
2278
+ usageResetMinutes: "resets in {minutes} min",
2279
+ usageResetHours: "resets in {hours} h",
2280
+ usageResetDays: "resets in {days} d",
2281
+ usageResetDue: "resets now",
2282
+ usageResetUnknown: "reset time unknown",
1367
2283
  usageTitle: "OpenCode Go usage",
1368
2284
  usageRollingShort: "5h",
1369
- usageHint: "Account usage \xB7 used percentage \xB7 refreshes every minute",
1370
2285
  usageWeekShort: "week",
1371
2286
  usage_rolling: "5 hours",
1372
2287
  usage_weekly: "Weekly",
@@ -1376,6 +2291,7 @@ var en = {
1376
2291
  usageLoading: "Loading usage\u2026",
1377
2292
  usageUnavailable: "Unavailable",
1378
2293
  usageStaleShort: "Last data",
2294
+ usageFallbackShort: "fallback",
1379
2295
  usageStaleHint: "Showing the last successful usage reading. Current usage may have changed.",
1380
2296
  usageRefreshFailed: "Refresh failed",
1381
2297
  usageLastUpdated: "Last updated",
@@ -1465,6 +2381,9 @@ var en = {
1465
2381
  apiKeyEnvHint: "The name the key is resolved from, addressed through the credentials service.",
1466
2382
  baseURLLabel: "Gateway URL",
1467
2383
  baseURLHint: "The endpoint that serves requests and the live model list.",
2384
+ proxyURLLabel: "Proxy address",
2385
+ 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.",
2386
+ proxyURLInvalid: "Enter an http://, https:// or socks5:// proxy address without a path, query or fragment.",
1468
2387
  refreshMinutesLabel: "Catalog refresh (minutes)",
1469
2388
  refreshMinutesHint: "Catalog cache lifetime for conversations and model pickers. Opening this settings page or clicking Refresh checks the gateway and online model metadata immediately.",
1470
2389
  streamIdleTimeoutMsLabel: "Stream idle timeout (ms)",
@@ -1488,9 +2407,50 @@ var en = {
1488
2407
  unavailable: "The OpenCode Go settings are not served in this deployment."
1489
2408
  };
1490
2409
  var zh = {
2410
+ accountsTitle: "\u8D26\u53F7",
2411
+ accountsRefresh: "\u5237\u65B0\u989D\u5EA6",
2412
+ accountsBlocked: "\u8BF7\u5148\u4FDD\u5B58\u6216\u653E\u5F03 API Key \u8349\u7A3F\uFF0C\u518D\u5207\u6362\u6216\u4FEE\u6539\u8D26\u53F7\u3002",
2413
+ accountsEmpty: "\u6DFB\u52A0\u8D26\u53F7\u540E\u5373\u53EF\u4F7F\u7528 OpenCode Go\u3002",
2414
+ accountsWriteFailed: "\u8D26\u53F7\u4FEE\u6539\u672A\u751F\u6548\uFF0C\u8F93\u5165\u5DF2\u4FDD\u7559\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2415
+ accountsReadFailed: "\u672A\u80FD\u8BFB\u53D6\u8D26\u53F7\u72B6\u6001\uFF0C\u8BF7\u5237\u65B0\u91CD\u8BD5\u3002",
2416
+ 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",
2417
+ accountsRemoveKeyFailed: "\u672A\u80FD\u5220\u9664\u5DF2\u4FDD\u5B58\u7684 Key\uFF0C\u8D26\u53F7\u6682\u65F6\u4FDD\u7559\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2418
+ accountsStatusUnknown: "\u72B6\u6001\u672A\u77E5",
2419
+ accountDefault: "\u9ED8\u8BA4\u8D26\u53F7",
2420
+ accountAdd: "\u6DFB\u52A0\u8D26\u53F7",
2421
+ accountRename: "\u91CD\u547D\u540D",
2422
+ accountReplaceKey: "\u66FF\u6362 Key",
2423
+ accountRemove: "\u5220\u9664\u8D26\u53F7",
2424
+ accountRemoveHint: "\u5220\u9664\u201C{name}\u201D\uFF1F\u82E5\u5B83\u662F\u5F53\u524D\u9996\u9009\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",
2425
+ accountName: "\u8D26\u53F7\u540D\u79F0",
2426
+ 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",
2427
+ accountConfirm: "\u786E\u8BA4",
2428
+ accountCancel: "\u53D6\u6D88",
2429
+ accountAutoSwitch: "\u81EA\u52A8\u4F7F\u7528\u5907\u7528\u8D26\u53F7",
2430
+ accountAutoSwitchHint: "\u9ED8\u8BA4\u5173\u95ED\u3002\u989D\u5EA6\u8017\u5C3D\u6216 Key \u4E0D\u53EF\u7528\u65F6\uFF0C\u5728\u5C1A\u672A\u8F93\u51FA\u5185\u5BB9\u6216\u5DE5\u5177\u8C03\u7528\u524D\u6309\u987A\u5E8F\u5C1D\u8BD5\u5176\u4ED6\u8D26\u53F7\uFF0C\u6BCF\u4E2A\u8D26\u53F7\u6700\u591A\u4E00\u6B21\u3002\u624B\u52A8\u9009\u5B9A\u7684\u9996\u9009\u8D26\u53F7\u4FDD\u6301\u4E0D\u53D8\uFF1B\u666E\u901A\u9650\u6D41\u548C\u7F51\u7EDC\u9519\u8BEF\u4EA4\u7531\u5BBF\u4E3B\u6062\u590D\u3002",
2431
+ accountPreferredTag: "\u9996\u9009",
2432
+ accountSwitchAction: "\u5207\u6362",
2433
+ accountSwitchTitle: "\u5207\u6362\u8D26\u53F7",
2434
+ accountSwitchBack: "\u8FD4\u56DE\u989D\u5EA6",
2435
+ 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",
2436
+ accountSwitchFailed: "\u8D26\u53F7\u5207\u6362\u672A\u751F\u6548\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2437
+ accountFallbackQuota: "\u9996\u9009\u8D26\u53F7\u989D\u5EA6\u8017\u5C3D\uFF0C\u5DF2\u81EA\u52A8\u4F7F\u7528\u5907\u7528\u8D26\u53F7\uFF1A",
2438
+ accountFallbackCredential: "\u9996\u9009 Key \u4E0D\u53EF\u7528\u6216\u88AB\u62D2\u7EDD\uFF0C\u5DF2\u81EA\u52A8\u4F7F\u7528\u5907\u7528\u8D26\u53F7\uFF1A",
2439
+ accountsSummary: "{count} \u4E2A \xB7 \u9996\u9009 {name}",
2440
+ accountsSummaryEmpty: "\u5C1A\u672A\u6DFB\u52A0\u8D26\u53F7",
2441
+ accountsAvailability: "{ready}/{total} \u5DF2\u914D\u7F6E",
2442
+ accountsAvailabilityFailed: "{ready}/{total} \u5DF2\u914D\u7F6E \xB7 {failed} \u4E2A\u8BFB\u53D6\u5931\u8D25",
2443
+ accountsDetails: "{name} \u7684\u8BE6\u60C5",
2444
+ accountsDetailsHide: "\u6536\u8D77 {name} \u7684\u8BE6\u60C5",
2445
+ accountDragHandle: "\u62D6\u52A8 {name} \u8C03\u6574\u987A\u5E8F",
2446
+ accountConfigureHint: "\u914D\u7F6E Key \u540E\u663E\u793A\u989D\u5EA6",
2447
+ usageResetMinutes: "{minutes} \u5206\u949F\u540E\u91CD\u7F6E",
2448
+ usageResetHours: "{hours} \u5C0F\u65F6\u540E\u91CD\u7F6E",
2449
+ usageResetDays: "{days} \u5929\u540E\u91CD\u7F6E",
2450
+ usageResetDue: "\u5373\u5C06\u91CD\u7F6E",
2451
+ usageResetUnknown: "\u91CD\u7F6E\u65F6\u95F4\u672A\u77E5",
1491
2452
  usageTitle: "OpenCode Go \u7528\u91CF",
1492
2453
  usageRollingShort: "5\u5C0F\u65F6",
1493
- usageHint: "\u8D26\u53F7\u989D\u5EA6 \xB7 \u5DF2\u7528\u767E\u5206\u6BD4 \xB7 \u6BCF\u5206\u949F\u5237\u65B0",
1494
2454
  usageWeekShort: "\u5468",
1495
2455
  usage_rolling: "5 \u5C0F\u65F6",
1496
2456
  usage_weekly: "\u6BCF\u5468",
@@ -1500,6 +2460,7 @@ var zh = {
1500
2460
  usageLoading: "\u6B63\u5728\u8BFB\u53D6\u7528\u91CF\u2026",
1501
2461
  usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
1502
2462
  usageStaleShort: "\u4E0A\u6B21\u6570\u636E",
2463
+ usageFallbackShort: "\u5DF2\u56DE\u9000",
1503
2464
  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",
1504
2465
  usageRefreshFailed: "\u5237\u65B0\u5931\u8D25",
1505
2466
  usageLastUpdated: "\u66F4\u65B0\u4E8E",
@@ -1589,6 +2550,9 @@ var zh = {
1589
2550
  apiKeyEnvHint: "key \u89E3\u6790\u6240\u4F9D\u636E\u7684\u5F15\u7528\u540D\uFF0C\u7ECF\u51ED\u8BC1\u670D\u52A1\u5BFB\u5740\u3002",
1590
2551
  baseURLLabel: "\u7F51\u5173\u5730\u5740",
1591
2552
  baseURLHint: "\u540C\u65F6\u63D0\u4F9B\u6A21\u578B\u8BF7\u6C42\u4E0E\u5B9E\u65F6\u6A21\u578B\u5217\u8868\u7684\u7AEF\u70B9\u3002",
2553
+ proxyURLLabel: "\u4EE3\u7406\u5730\u5740",
2554
+ 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",
2555
+ 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",
1592
2556
  refreshMinutesLabel: "\u76EE\u5F55\u5237\u65B0\uFF08\u5206\u949F\uFF09",
1593
2557
  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",
1594
2558
  streamIdleTimeoutMsLabel: "\u6D41\u7A7A\u95F2\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
@@ -1613,6 +2577,11 @@ var zh = {
1613
2577
  };
1614
2578
 
1615
2579
  // src/usage-contract.ts
2580
+ function parseAccountSwitch(value) {
2581
+ const notice = value;
2582
+ 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");
2583
+ return { fromRef: notice.fromRef, toRef: notice.toRef, reason: notice.reason, at: notice.at };
2584
+ }
1616
2585
  function parseGoUsage(value) {
1617
2586
  if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
1618
2587
  const source = value;
@@ -1623,6 +2592,9 @@ function parseGoUsage(value) {
1623
2592
  }
1624
2593
  result.source = source.source;
1625
2594
  }
2595
+ if (source.lastSwitch !== void 0) {
2596
+ result.lastSwitch = parseAccountSwitch(source.lastSwitch);
2597
+ }
1626
2598
  for (const key of ["rolling", "weekly", "monthly"]) {
1627
2599
  const row = source[key];
1628
2600
  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))) {
@@ -1638,6 +2610,16 @@ var usageCodec = {
1638
2610
  schema: { parse: parseGoUsage },
1639
2611
  create: () => ({ parse: parseGoUsage })
1640
2612
  };
2613
+ var parseRef = (value) => {
2614
+ if (typeof value !== "string" || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) throw new Error("Invalid account reference");
2615
+ return value;
2616
+ };
2617
+ var refCodec = {
2618
+ mode: "strict",
2619
+ typeSymbol: "dsh-opencode-go#AccountRef",
2620
+ schema: { parse: parseRef },
2621
+ create: () => ({ parse: parseRef })
2622
+ };
1641
2623
  var usageRemote = {
1642
2624
  package: "dsh-opencode-go",
1643
2625
  descriptors: [{
@@ -1648,6 +2630,14 @@ var usageRemote = {
1648
2630
  invocation: { kind: "direct" },
1649
2631
  parameters: [],
1650
2632
  result: usageCodec
2633
+ }, {
2634
+ id: "dsh-opencode-go#opencodeGoUsage/readAccount",
2635
+ service: "opencodeGoUsage",
2636
+ namespace: "opencodeGoUsage",
2637
+ method: "readAccount",
2638
+ invocation: { kind: "direct" },
2639
+ parameters: [{ name: "ref", wire: "ref", source: "json", codec: refCodec }],
2640
+ result: usageCodec
1651
2641
  }]
1652
2642
  };
1653
2643
 
@@ -1658,7 +2648,7 @@ var goRemote = {
1658
2648
  };
1659
2649
 
1660
2650
  // src/client/UsagePill.tsx
1661
- var import_react3 = require("react");
2651
+ var import_react4 = require("react");
1662
2652
 
1663
2653
  // plugin-css:src/client/UsagePill.module.css
1664
2654
  var id2 = "dsh-opencode-go/UsagePill.module.css";
@@ -1666,20 +2656,29 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
1666
2656
  const style = document.createElement("style");
1667
2657
  style.dataset.plugin = "dsh-opencode-go";
1668
2658
  style.dataset.pluginCss = id2;
1669
- 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}";
2659
+ 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}';
1670
2660
  document.head.appendChild(style);
1671
2661
  }
1672
- 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" };
2662
+ 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" };
1673
2663
 
1674
2664
  // src/client/UsagePill.tsx
1675
- var import_jsx_runtime3 = require("react/jsx-runtime");
2665
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2666
+ var unchanged = () => 0;
2667
+ var noSubscription = () => () => {
2668
+ };
1676
2669
  function usageFailure(error) {
1677
2670
  if (error && typeof error === "object" && "code" in error && error.code === "opencode-go/usage-unavailable" && "details" in error && error.details && typeof error.details === "object") {
1678
2671
  const details = error.details;
2672
+ let lastSwitch;
2673
+ try {
2674
+ if (details.lastSwitch) lastSwitch = parseAccountSwitch(details.lastSwitch);
2675
+ } catch {
2676
+ }
1679
2677
  return {
1680
2678
  ..."message" in error && typeof error.message === "string" ? { message: error.message } : {},
1681
2679
  retainPrevious: details.retryable === true && details.retainPrevious === true,
1682
- ...typeof details.source === "string" ? { source: details.source } : {}
2680
+ ...typeof details.source === "string" ? { source: details.source } : {},
2681
+ ...lastSwitch ? { lastSwitch } : {}
1683
2682
  };
1684
2683
  }
1685
2684
  return { retainPrevious: false };
@@ -1688,22 +2687,50 @@ function usageLevel(window) {
1688
2687
  if (window.status === "rate-limited" || window.percent >= 100) return UsagePill_default.limited;
1689
2688
  return window.percent >= 80 ? UsagePill_default.high : void 0;
1690
2689
  }
1691
- function UsagePill({ directory, settings, ...props }) {
1692
- const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
1693
- const config = (0, import_react3.useSyncExternalStore)(settings.subscribe, settings.getSnapshot, settings.getSnapshot);
2690
+ function ChevronRight() {
2691
+ 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" }) });
2692
+ }
2693
+ function ChevronLeft() {
2694
+ 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" }) });
2695
+ }
2696
+ function Tick() {
2697
+ 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" }) });
2698
+ }
2699
+ function UsagePill({ directory, settings, credentialChanges, ...props }) {
2700
+ const state = (0, import_react4.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
2701
+ const readSettings = (0, import_react4.useCallback)(() => settings.getSnapshot(), [settings]);
2702
+ const subscribeSettings = (0, import_react4.useCallback)((listener) => settings.subscribe(listener), [settings]);
2703
+ const config = (0, import_react4.useSyncExternalStore)(subscribeSettings, readSettings, readSettings);
2704
+ const readChanges = (0, import_react4.useCallback)(() => credentialChanges?.getSnapshot() ?? unchanged(), [credentialChanges]);
2705
+ const subscribeChanges = (0, import_react4.useCallback)((listener) => credentialChanges?.subscribe(listener) ?? noSubscription(), [credentialChanges]);
2706
+ const credentialRevision = (0, import_react4.useSyncExternalStore)(subscribeChanges, readChanges, readChanges);
1694
2707
  const mode = config.value?.usageDisplay ?? DEFAULT_USAGE_DISPLAY;
1695
2708
  const visible = config.status === "ready" && config.value?.enabled !== false && (mode === "always" || mode === "auto" && state.current?.provider === PROVIDER_ID);
1696
- return visible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
2709
+ const accounts = accountsOf(config.value ?? {});
2710
+ const activeRef = accountRefOf(config.value ?? {});
2711
+ return visible ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2712
+ ActiveUsage,
2713
+ {
2714
+ ...props,
2715
+ accounts,
2716
+ activeRef,
2717
+ writable: config.writable
2718
+ },
2719
+ JSON.stringify([activeRef, config.value?.baseURL, config.value?.proxyURL, credentialRevision, accounts])
2720
+ ) : null;
1697
2721
  }
1698
- function ActiveUsage({ readUsage, t, getLocale }) {
1699
- const [snapshot, setSnapshot] = (0, import_react3.useState)(null);
1700
- const [failed, setFailed] = (0, import_react3.useState)(null);
1701
- const [refreshing, setRefreshing] = (0, import_react3.useState)(false);
1702
- const [open, setOpen] = (0, import_react3.useState)(false);
1703
- const root = (0, import_react3.useRef)(null);
1704
- const retry = (0, import_react3.useRef)(() => {
2722
+ function ActiveUsage({ readUsage, t, getLocale, accounts, activeRef, writable, selectAccount }) {
2723
+ const [snapshot, setSnapshot] = (0, import_react4.useState)(null);
2724
+ const [failed, setFailed] = (0, import_react4.useState)(null);
2725
+ const [refreshing, setRefreshing] = (0, import_react4.useState)(false);
2726
+ const [open, setOpen] = (0, import_react4.useState)(false);
2727
+ const [switching, setSwitching] = (0, import_react4.useState)(false);
2728
+ const [switchFailed, setSwitchFailed] = (0, import_react4.useState)(false);
2729
+ const [view, setView] = (0, import_react4.useState)("usage");
2730
+ const root = (0, import_react4.useRef)(null);
2731
+ const retry = (0, import_react4.useRef)(() => {
1705
2732
  });
1706
- (0, import_react3.useEffect)(() => {
2733
+ (0, import_react4.useEffect)(() => {
1707
2734
  let alive = true;
1708
2735
  let busy = false;
1709
2736
  setSnapshot(null);
@@ -1749,7 +2776,7 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1749
2776
  document.removeEventListener("visibilitychange", visible);
1750
2777
  };
1751
2778
  }, [readUsage]);
1752
- (0, import_react3.useEffect)(() => {
2779
+ (0, import_react4.useEffect)(() => {
1753
2780
  if (!open) return;
1754
2781
  const click = (event) => {
1755
2782
  if (!root.current?.contains(event.target)) setOpen(false);
@@ -1767,71 +2794,227 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1767
2794
  const current = snapshot?.reader === readUsage ? snapshot : null;
1768
2795
  const usage = current?.usage;
1769
2796
  const failure = failed?.reader === readUsage ? failed.failure : null;
1770
- 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"}`;
1771
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
1772
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2797
+ const notice = usage?.lastSwitch ?? failure?.lastSwitch;
2798
+ const accountName = accounts.find((account) => account.apiKeyEnv === activeRef)?.name || t("accountDefault");
2799
+ const accountsView = view === "accounts" && accounts.length > 1;
2800
+ const switchable = accounts.length > 1 && writable && selectAccount !== void 0;
2801
+ const switchTo = (ref) => {
2802
+ if (ref === activeRef) {
2803
+ setView("usage");
2804
+ return;
2805
+ }
2806
+ setSwitching(true);
2807
+ setSwitchFailed(false);
2808
+ void selectAccount?.(ref).then((accepted) => {
2809
+ setSwitchFailed(!accepted);
2810
+ if (accepted) setView("usage");
2811
+ }).catch(() => {
2812
+ setSwitchFailed(true);
2813
+ }).finally(() => {
2814
+ setSwitching(false);
2815
+ });
2816
+ };
2817
+ 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}` : ""}`;
2818
+ const segments = usage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2819
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.brand, children: "Go \xB7 " }),
2820
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.reading, "data-stale": failure ? "" : void 0, children: [
2821
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.unit, children: [
2822
+ t("usageRollingShort"),
2823
+ " "
2824
+ ] }),
2825
+ usage.rolling.percent,
2826
+ "%",
2827
+ " \xB7 ",
2828
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.unit, children: [
2829
+ t("usageWeekShort"),
2830
+ " "
2831
+ ] }),
2832
+ usage.weekly.percent,
2833
+ "%"
2834
+ ] }),
2835
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.stale, children: [
2836
+ " \xB7 ",
2837
+ t("usageStaleShort")
2838
+ ] }) : null,
2839
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.fallback, children: [
2840
+ " \xB7 ",
2841
+ t("usageFallbackShort")
2842
+ ] }) : null,
2843
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.account, children: [
2844
+ " \xB7 ",
2845
+ accountName
2846
+ ] }) : null
2847
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2848
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.brand, children: "Go \xB7 " }),
2849
+ failure ? t("usageUnavailable") : "\u2026",
2850
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.fallback, children: [
2851
+ " \xB7 ",
2852
+ t("usageFallbackShort")
2853
+ ] }) : null,
2854
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.account, children: [
2855
+ " \xB7 ",
2856
+ accountName
2857
+ ] }) : null
2858
+ ] });
2859
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
2860
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1773
2861
  "button",
1774
2862
  {
1775
2863
  type: "button",
1776
2864
  className: UsagePill_default.trigger,
1777
2865
  "aria-expanded": open,
1778
2866
  "aria-haspopup": "dialog",
2867
+ "data-fallback": notice ? "" : void 0,
1779
2868
  "aria-label": `${t("usageTitle")}: ${label}`,
2869
+ title: label,
1780
2870
  onClick: () => {
1781
2871
  setOpen(!open);
2872
+ setView("usage");
1782
2873
  },
1783
- children: label
2874
+ children: segments
1784
2875
  }
1785
2876
  ),
1786
- open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
1787
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageTitle") }),
1788
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
1789
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
1790
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageRefreshFailed") }),
1791
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
1792
- usage ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageStaleHint") }) : null
1793
- ] }) : null,
1794
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1795
- "button",
1796
- {
1797
- type: "button",
1798
- className: UsagePill_default.retry,
1799
- disabled: refreshing,
1800
- onClick: () => {
1801
- retry.current();
1802
- },
1803
- children: t(refreshing ? "usageRefreshing" : "usageRetry")
1804
- }
1805
- ) : null,
1806
- current ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: UsagePill_default.hint, children: [
1807
- t("usageLastUpdated"),
1808
- " ",
1809
- new Date(current.updatedAt).toLocaleString(getLocale?.())
1810
- ] }) : null,
1811
- usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.window, children: [
1812
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.row, children: [
1813
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(`usage_${key}`) }),
1814
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
1815
- usage[key].percent,
1816
- "%"
1817
- ] })
2877
+ open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
2878
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.material, "aria-hidden": "true" }),
2879
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.body, children: accountsView ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2880
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.panelHead, children: [
2881
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: UsagePill_default.back, "aria-label": t("accountSwitchBack"), onClick: () => {
2882
+ setView("usage");
2883
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronLeft, {}) }),
2884
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("accountSwitchTitle") })
1818
2885
  ] }),
1819
- /* @__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) }),
1820
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.hint, children: [
1821
- t("usageResets"),
2886
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2887
+ "div",
2888
+ {
2889
+ className: UsagePill_default.tile,
2890
+ role: "listbox",
2891
+ "aria-label": t("accountSwitchTitle"),
2892
+ onKeyDown: (event) => {
2893
+ if (event.key === "Escape") {
2894
+ event.stopPropagation();
2895
+ setView("usage");
2896
+ return;
2897
+ }
2898
+ const step = event.key === "ArrowDown" ? 1 : event.key === "ArrowUp" ? -1 : 0;
2899
+ if (step === 0) return;
2900
+ event.preventDefault();
2901
+ const options = Array.from(event.currentTarget.querySelectorAll('[role="option"]'));
2902
+ const at = options.indexOf(document.activeElement);
2903
+ options[(at + step + options.length) % options.length]?.focus();
2904
+ },
2905
+ children: accounts.map((account, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react4.Fragment, { children: [
2906
+ index ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.divider }) : null,
2907
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2908
+ "button",
2909
+ {
2910
+ type: "button",
2911
+ role: "option",
2912
+ "aria-selected": account.apiKeyEnv === activeRef,
2913
+ "data-selected": account.apiKeyEnv === activeRef ? "" : void 0,
2914
+ className: UsagePill_default.option,
2915
+ disabled: switching,
2916
+ onClick: () => {
2917
+ switchTo(account.apiKeyEnv);
2918
+ },
2919
+ children: [
2920
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.optionName, children: account.name || t("accountDefault") }),
2921
+ account.apiKeyEnv === activeRef ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Tick, {}) : null
2922
+ ]
2923
+ }
2924
+ )
2925
+ ] }, account.id))
2926
+ }
2927
+ ),
2928
+ switchFailed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.warning, role: "alert", children: t("accountSwitchFailed") }) : null,
2929
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.hint, children: t("accountSwitchHint") })
2930
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2931
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.panelTitle, children: t("usageTitle") }),
2932
+ 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: [
2933
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.dot }),
2934
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.accName, children: accountName }),
2935
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.tag, children: t("accountPreferredTag") }) : null,
2936
+ accounts.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2937
+ "button",
2938
+ {
2939
+ type: "button",
2940
+ className: UsagePill_default.switch,
2941
+ disabled: !switchable || switching,
2942
+ "aria-haspopup": "listbox",
2943
+ onClick: () => {
2944
+ setView("accounts");
2945
+ },
2946
+ children: [
2947
+ t("accountSwitchAction"),
2948
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronRight, {})
2949
+ ]
2950
+ }
2951
+ ) : null
2952
+ ] }) }) : null,
2953
+ switchFailed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.warning, role: "alert", children: t("accountSwitchFailed") }) : null,
2954
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { className: UsagePill_default.warning, role: "status", children: [
2955
+ t(notice.reason === "quota" ? "accountFallbackQuota" : "accountFallbackCredential"),
1822
2956
  " ",
1823
- new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
1824
- ] }),
1825
- usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: UsagePill_default.limitedText, children: t("usageLimited") })
1826
- ] }, key)) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageLoading") })
2957
+ accounts.find((account) => account.apiKeyEnv === notice.toRef)?.name || t("accountDefault"),
2958
+ " \xB7 ",
2959
+ new Date(notice.at).toLocaleString(getLocale?.())
2960
+ ] }) : null,
2961
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
2962
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t("usageRefreshFailed") }),
2963
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
2964
+ usage ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("usageStaleHint") }) : null
2965
+ ] }) : null,
2966
+ failure ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2967
+ "button",
2968
+ {
2969
+ type: "button",
2970
+ className: UsagePill_default.retry,
2971
+ disabled: refreshing,
2972
+ onClick: () => {
2973
+ retry.current();
2974
+ },
2975
+ children: t(refreshing ? "usageRefreshing" : "usageRetry")
2976
+ }
2977
+ ) : null,
2978
+ 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: [
2979
+ index ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.divider }) : null,
2980
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.window, children: [
2981
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.windowRow, children: [
2982
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: UsagePill_default.windowLabel, children: t(`usage_${key}`) }),
2983
+ /* @__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) }),
2984
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("strong", { className: UsagePill_default.windowPercent, children: [
2985
+ usage[key].percent,
2986
+ "%"
2987
+ ] })
2988
+ ] }),
2989
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: UsagePill_default.windowReset, children: [
2990
+ t("usageResets"),
2991
+ " ",
2992
+ new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
2993
+ ] }),
2994
+ usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.limitedText, children: t("usageLimited") })
2995
+ ] })
2996
+ ] }, key)) }) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: UsagePill_default.hint, children: t("usageLoading") }),
2997
+ current ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: UsagePill_default.foot, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
2998
+ t("usageLastUpdated"),
2999
+ " ",
3000
+ new Date(current.updatedAt).toLocaleString(getLocale?.())
3001
+ ] }) }) : null
3002
+ ] }) })
1827
3003
  ] })
1828
3004
  ] });
1829
3005
  }
1830
3006
 
1831
3007
  // src/client/usage.ts
3008
+ var import_dsh_client_store2 = require("@deepseek-ai/dsh-client-store");
1832
3009
  function registerUsagePill(ctx, settings) {
1833
3010
  ctx.inject(["modelDirectories", "sessions", "remote.session"], (scope) => {
1834
3011
  scope.inject(["remote.opencodeGoUsage"], (ready) => {
3012
+ const credentialChanges = (0, import_dsh_client_store2.createSnapshotStore)(0);
3013
+ ready.effect(() => ready.remote.$on("credentials/reference-updated", (ref) => {
3014
+ if (accountsOf(settings.getSnapshot().value ?? {}).some((account) => account.apiKeyEnv === ref)) {
3015
+ credentialChanges.set(credentialChanges.getSnapshot() + 1);
3016
+ }
3017
+ }));
1835
3018
  const readUsage = async () => {
1836
3019
  const result = await ready.remote.opencodeGoUsage.read();
1837
3020
  if (!result.ok) throw result.error;
@@ -1845,6 +3028,17 @@ function registerUsagePill(ctx, settings) {
1845
3028
  inject: (sessionId) => ({
1846
3029
  directory: ready.modelDirectories.directoryFor(sessionId).store,
1847
3030
  settings,
3031
+ credentialChanges,
3032
+ selectAccount: async (ref) => {
3033
+ const snapshot = settings.getSnapshot();
3034
+ if (!snapshot.writable || !accountsOf(snapshot.value ?? {}).some((account) => account.apiKeyEnv === ref)) return false;
3035
+ try {
3036
+ await settings.mutate([{ op: "set", path: ["apiKeyEnv"], value: ref }], snapshot.revision);
3037
+ return accountRefOf(settings.getSnapshot().value ?? {}) === ref;
3038
+ } catch {
3039
+ return false;
3040
+ }
3041
+ },
1848
3042
  readUsage,
1849
3043
  getLocale: () => ready.locale.getLocale().active,
1850
3044
  t: (key) => translate(key)
@@ -1874,9 +3068,21 @@ function apply(ctx) {
1874
3068
  }
1875
3069
  function mountSettings(ctx, scope, modelsReady) {
1876
3070
  registerUsagePill(ctx, scope);
3071
+ let readAccount;
3072
+ ctx.inject(["remote.opencodeGoUsage"], (ready) => {
3073
+ readAccount = async (ref) => {
3074
+ const result = await ready.remote.opencodeGoUsage.readAccount(ref);
3075
+ if (!result.ok) throw result.error;
3076
+ return result.value;
3077
+ };
3078
+ });
1877
3079
  const controller = new OpencodeGoSectionController(scope, ctx, async () => {
1878
3080
  await modelsReady;
1879
3081
  return ctx.remote.opencodeGoModels.read();
3082
+ }, async (ref) => {
3083
+ await modelsReady;
3084
+ if (readAccount === void 0) throw new Error("OpenCode Go account usage is unavailable in this session");
3085
+ return readAccount(ref);
1880
3086
  });
1881
3087
  ctx.effect(() => () => controller.dispose());
1882
3088
  const t = ctx.locale.bind(NS);