dsh-opencode-go 0.1.20 → 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) {
@@ -978,7 +1769,11 @@ var StagedForm = class {
978
1769
  this.publish();
979
1770
  let landed = true;
980
1771
  for (const write of writes) {
981
- landed = await write() && landed;
1772
+ try {
1773
+ landed = await write() && landed;
1774
+ } catch {
1775
+ landed = false;
1776
+ }
982
1777
  }
983
1778
  if (landed) this.staged.clear();
984
1779
  this.saving = false;
@@ -1088,6 +1883,10 @@ var OpencodeGoSectionController = class {
1088
1883
  constructor(scope, ctx, readModels = async () => {
1089
1884
  const result = await ctx.remote.llm.discoverModels(OPENCODE_GO_NS, { provider: PROVIDER_ID });
1090
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;
1091
1890
  }) {
1092
1891
  this.scope = scope;
1093
1892
  this.ctx = ctx;
@@ -1105,6 +1904,18 @@ var OpencodeGoSectionController = class {
1105
1904
  },
1106
1905
  textField("apiKeyEnv"),
1107
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
+ },
1108
1919
  numberField("refreshMinutes"),
1109
1920
  numberField("streamIdleTimeoutMs"),
1110
1921
  numberField("maxImages", (value) => Number.isSafeInteger(value) && value > 0),
@@ -1116,9 +1927,25 @@ var OpencodeGoSectionController = class {
1116
1927
  [{ field: API_KEY_FIELD, write: (text) => this.writeKey(text) }]
1117
1928
  );
1118
1929
  this.store = this.form.bind(() => this.projection());
1119
- 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();
1120
1945
  this.unsubscribe = scope.subscribe(() => {
1121
- const endpoint = scope.getSnapshot().value?.baseURL;
1946
+ this.accounts?.sync();
1947
+ this.store.set(this.projection());
1948
+ const endpoint = networkIdentity();
1122
1949
  if (endpoint !== modelsEndpoint) {
1123
1950
  modelsEndpoint = endpoint;
1124
1951
  this.modelsRequest++;
@@ -1138,8 +1965,13 @@ var OpencodeGoSectionController = class {
1138
1965
  pickerFailed = false;
1139
1966
  face;
1140
1967
  unsubscribe;
1968
+ accounts;
1969
+ credentialRequest = 0;
1970
+ keyDraftRef;
1141
1971
  /** Release subscriptions without disposing the host's shared form. */
1142
1972
  dispose() {
1973
+ this.credentialRequest++;
1974
+ this.accounts?.dispose();
1143
1975
  this.modelsRequest++;
1144
1976
  this.unsubscribe();
1145
1977
  this.form.dispose();
@@ -1147,6 +1979,8 @@ var OpencodeGoSectionController = class {
1147
1979
  projection() {
1148
1980
  return {
1149
1981
  ...this.form.shell(),
1982
+ saving: this.form.shell().saving || this.accounts?.snapshot().busy === true,
1983
+ accounts: this.accounts?.snapshot(),
1150
1984
  enabled: this.enabled(),
1151
1985
  usageDisplay: this.form.field("usageDisplay"),
1152
1986
  modelVisibility: this.scope.getSnapshot().value?.modelVisibility ?? {},
@@ -1154,6 +1988,7 @@ var OpencodeGoSectionController = class {
1154
1988
  pickerFailed: this.pickerFailed,
1155
1989
  apiKeyEnv: this.form.field("apiKeyEnv"),
1156
1990
  baseURL: this.form.field("baseURL"),
1991
+ proxyURL: this.form.field("proxyURL"),
1157
1992
  refreshMinutes: this.form.field("refreshMinutes"),
1158
1993
  streamIdleTimeoutMs: this.form.field("streamIdleTimeoutMs"),
1159
1994
  maxImages: this.form.field("maxImages"),
@@ -1161,7 +1996,7 @@ var OpencodeGoSectionController = class {
1161
1996
  requestImagePixelBudget: this.form.field("requestImagePixelBudget"),
1162
1997
  requestImageMaxBytes: this.form.field("requestImageMaxBytes"),
1163
1998
  apiKey: this.form.field(API_KEY_FIELD),
1164
- apiKeyConfigured: this.credential.configured,
1999
+ apiKeyConfigured: this.credential.ref === refOf(this.scope.getSnapshot()) && this.credential.configured && accountsOf(this.scope.getSnapshot().value ?? {}).length > 0,
1165
2000
  apiKeyWritable: this.credential.writable,
1166
2001
  models: this.models,
1167
2002
  modelLimits: this.form.field("modelLimits"),
@@ -1218,7 +2053,7 @@ var OpencodeGoSectionController = class {
1218
2053
  }
1219
2054
  /** Serialize immediate switches with form saves; refused writes retain committed values. */
1220
2055
  async writePickerSetting(field, value, accepted) {
1221
- 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;
1222
2057
  this.pickerSaving = true;
1223
2058
  this.pickerFailed = false;
1224
2059
  this.store.set(this.projection());
@@ -1283,13 +2118,19 @@ var OpencodeGoSectionController = class {
1283
2118
  * reference in force.
1284
2119
  */
1285
2120
  async readCredential() {
2121
+ const request = ++this.credentialRequest;
1286
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
+ }
1287
2128
  if (ref !== this.credential.ref) {
1288
2129
  this.credential = { ref, configured: false, writable: true };
1289
2130
  this.store.set(this.projection());
1290
2131
  }
1291
- const response = await this.ctx.remote.credentials.describe([ref]);
1292
- 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;
1293
2134
  const view = response.value[ref];
1294
2135
  const next = {
1295
2136
  ref,
@@ -1311,6 +2152,7 @@ var OpencodeGoSectionController = class {
1311
2152
  * @param ref - the reference the Host reports as changed.
1312
2153
  */
1313
2154
  refreshCredential(ref) {
2155
+ this.accounts?.invalidate(ref);
1314
2156
  if (ref !== this.credential.ref) return;
1315
2157
  void this.readCredential();
1316
2158
  }
@@ -1331,7 +2173,24 @@ var OpencodeGoSectionController = class {
1331
2173
  setModelEnabled: (id3, next) => {
1332
2174
  void this.setModelEnabled(id3, next);
1333
2175
  },
1334
- ...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
+ }
1335
2194
  };
1336
2195
  return this.face;
1337
2196
  }
@@ -1341,9 +2200,12 @@ var OpencodeGoSectionController = class {
1341
2200
  * @returns whether the Host reports a configured credential afterwards.
1342
2201
  */
1343
2202
  async writeKey(value) {
1344
- 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);
1345
2207
  await this.readCredential();
1346
- return this.credential.configured;
2208
+ return ref === this.credential.ref ? this.credential.configured : true;
1347
2209
  }
1348
2210
  };
1349
2211
  function modelLimitsOf(value) {
@@ -1376,9 +2238,50 @@ function refOf(snapshot) {
1376
2238
 
1377
2239
  // src/client/locales.ts
1378
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",
1379
2283
  usageTitle: "OpenCode Go usage",
1380
2284
  usageRollingShort: "5h",
1381
- usageHint: "Account usage \xB7 used percentage \xB7 refreshes every minute",
1382
2285
  usageWeekShort: "week",
1383
2286
  usage_rolling: "5 hours",
1384
2287
  usage_weekly: "Weekly",
@@ -1388,6 +2291,7 @@ var en = {
1388
2291
  usageLoading: "Loading usage\u2026",
1389
2292
  usageUnavailable: "Unavailable",
1390
2293
  usageStaleShort: "Last data",
2294
+ usageFallbackShort: "fallback",
1391
2295
  usageStaleHint: "Showing the last successful usage reading. Current usage may have changed.",
1392
2296
  usageRefreshFailed: "Refresh failed",
1393
2297
  usageLastUpdated: "Last updated",
@@ -1477,6 +2381,9 @@ var en = {
1477
2381
  apiKeyEnvHint: "The name the key is resolved from, addressed through the credentials service.",
1478
2382
  baseURLLabel: "Gateway URL",
1479
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.",
1480
2387
  refreshMinutesLabel: "Catalog refresh (minutes)",
1481
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.",
1482
2389
  streamIdleTimeoutMsLabel: "Stream idle timeout (ms)",
@@ -1500,9 +2407,50 @@ var en = {
1500
2407
  unavailable: "The OpenCode Go settings are not served in this deployment."
1501
2408
  };
1502
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",
1503
2452
  usageTitle: "OpenCode Go \u7528\u91CF",
1504
2453
  usageRollingShort: "5\u5C0F\u65F6",
1505
- usageHint: "\u8D26\u53F7\u989D\u5EA6 \xB7 \u5DF2\u7528\u767E\u5206\u6BD4 \xB7 \u6BCF\u5206\u949F\u5237\u65B0",
1506
2454
  usageWeekShort: "\u5468",
1507
2455
  usage_rolling: "5 \u5C0F\u65F6",
1508
2456
  usage_weekly: "\u6BCF\u5468",
@@ -1512,6 +2460,7 @@ var zh = {
1512
2460
  usageLoading: "\u6B63\u5728\u8BFB\u53D6\u7528\u91CF\u2026",
1513
2461
  usageUnavailable: "\u6682\u4E0D\u53EF\u7528",
1514
2462
  usageStaleShort: "\u4E0A\u6B21\u6570\u636E",
2463
+ usageFallbackShort: "\u5DF2\u56DE\u9000",
1515
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",
1516
2465
  usageRefreshFailed: "\u5237\u65B0\u5931\u8D25",
1517
2466
  usageLastUpdated: "\u66F4\u65B0\u4E8E",
@@ -1601,6 +2550,9 @@ var zh = {
1601
2550
  apiKeyEnvHint: "key \u89E3\u6790\u6240\u4F9D\u636E\u7684\u5F15\u7528\u540D\uFF0C\u7ECF\u51ED\u8BC1\u670D\u52A1\u5BFB\u5740\u3002",
1602
2551
  baseURLLabel: "\u7F51\u5173\u5730\u5740",
1603
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",
1604
2556
  refreshMinutesLabel: "\u76EE\u5F55\u5237\u65B0\uFF08\u5206\u949F\uFF09",
1605
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",
1606
2558
  streamIdleTimeoutMsLabel: "\u6D41\u7A7A\u95F2\u8D85\u65F6\uFF08\u6BEB\u79D2\uFF09",
@@ -1625,6 +2577,11 @@ var zh = {
1625
2577
  };
1626
2578
 
1627
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
+ }
1628
2585
  function parseGoUsage(value) {
1629
2586
  if (!value || typeof value !== "object") throw new Error("Invalid OpenCode Go usage response");
1630
2587
  const source = value;
@@ -1635,6 +2592,9 @@ function parseGoUsage(value) {
1635
2592
  }
1636
2593
  result.source = source.source;
1637
2594
  }
2595
+ if (source.lastSwitch !== void 0) {
2596
+ result.lastSwitch = parseAccountSwitch(source.lastSwitch);
2597
+ }
1638
2598
  for (const key of ["rolling", "weekly", "monthly"]) {
1639
2599
  const row = source[key];
1640
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))) {
@@ -1650,6 +2610,16 @@ var usageCodec = {
1650
2610
  schema: { parse: parseGoUsage },
1651
2611
  create: () => ({ parse: parseGoUsage })
1652
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
+ };
1653
2623
  var usageRemote = {
1654
2624
  package: "dsh-opencode-go",
1655
2625
  descriptors: [{
@@ -1660,6 +2630,14 @@ var usageRemote = {
1660
2630
  invocation: { kind: "direct" },
1661
2631
  parameters: [],
1662
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
1663
2641
  }]
1664
2642
  };
1665
2643
 
@@ -1670,7 +2648,7 @@ var goRemote = {
1670
2648
  };
1671
2649
 
1672
2650
  // src/client/UsagePill.tsx
1673
- var import_react3 = require("react");
2651
+ var import_react4 = require("react");
1674
2652
 
1675
2653
  // plugin-css:src/client/UsagePill.module.css
1676
2654
  var id2 = "dsh-opencode-go/UsagePill.module.css";
@@ -1678,20 +2656,29 @@ if (!document.querySelector("style[data-plugin-css=" + JSON.stringify(id2) + "]"
1678
2656
  const style = document.createElement("style");
1679
2657
  style.dataset.plugin = "dsh-opencode-go";
1680
2658
  style.dataset.pluginCss = id2;
1681
- style.textContent = ".mAjYhq_root{min-width:0;display:inline-flex;position:relative}.mAjYhq_trigger{color:inherit;opacity:.75;font:inherit;cursor:pointer;white-space:nowrap;background:0 0;border:0;border-radius:6px;padding:4px 6px;font-size:12px}.mAjYhq_trigger:hover,.mAjYhq_trigger:focus-visible{opacity:1;background:color-mix(in srgb, currentColor 8%, transparent)}.mAjYhq_panel{z-index:100;box-sizing:border-box;border:1px solid color-mix(in srgb, currentColor 18%, transparent);width:280px;max-width:calc(100vw - 32px);max-height:70vh;color:var(--dsw-alias-label-primary,CanvasText);isolation:isolate;background-color:canvas;background-image:linear-gradient(var(--dsw-specific-menu,transparent), var(--dsw-specific-menu,transparent)), linear-gradient(var(--dsw-alias-bg-layer-2,Canvas), var(--dsw-alias-bg-layer-2,Canvas));border-radius:12px;padding:16px;font-size:12px;position:absolute;bottom:calc(100% + 12px);right:0;overflow-y:auto;box-shadow:0 8px 30px #0003}.mAjYhq_hint{opacity:.65;font-size:11px;line-height:1.6}.mAjYhq_warning{background:color-mix(in srgb, currentColor 6%, transparent);overflow-wrap:anywhere;border-radius:6px;margin:10px 0;padding:10px;line-height:1.5}.mAjYhq_warning p{margin:5px 0 0}.mAjYhq_retry{border:1px solid color-mix(in srgb, currentColor 25%, transparent);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:5px 9px}.mAjYhq_retry:disabled{opacity:.6;cursor:default}.mAjYhq_retry:focus-visible{outline-offset:2px;outline:2px solid}.mAjYhq_window{margin-top:14px}.mAjYhq_row{justify-content:space-between;margin-bottom:5px;display:flex}.mAjYhq_window progress{appearance:none;background:color-mix(in srgb, currentColor 15%, transparent);border:0;border-radius:4px;width:100%;height:5px;margin-bottom:5px;display:block}.mAjYhq_window progress::-webkit-progress-bar{background:0 0;border-radius:4px}.mAjYhq_window progress::-webkit-progress-value{background:#39a878;border-radius:4px}.mAjYhq_window progress::-moz-progress-bar{background:#39a878;border-radius:4px}.mAjYhq_window progress.mAjYhq_high::-webkit-progress-value{background:#e0a100}.mAjYhq_window progress.mAjYhq_high::-moz-progress-bar{background:#e0a100}.mAjYhq_window progress.mAjYhq_limited::-webkit-progress-value{background:#e5484d}.mAjYhq_window progress.mAjYhq_limited::-moz-progress-bar{background:#e5484d}.mAjYhq_limitedText{color:#e5484d;margin-top:2px;font-weight:600}";
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}';
1682
2660
  document.head.appendChild(style);
1683
2661
  }
1684
- var UsagePill_default = { "high": "mAjYhq_high", "hint": "mAjYhq_hint", "limited": "mAjYhq_limited", "limitedText": "mAjYhq_limitedText", "panel": "mAjYhq_panel", "retry": "mAjYhq_retry", "root": "mAjYhq_root", "row": "mAjYhq_row", "trigger": "mAjYhq_trigger", "warning": "mAjYhq_warning", "window": "mAjYhq_window" };
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" };
1685
2663
 
1686
2664
  // src/client/UsagePill.tsx
1687
- 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
+ };
1688
2669
  function usageFailure(error) {
1689
2670
  if (error && typeof error === "object" && "code" in error && error.code === "opencode-go/usage-unavailable" && "details" in error && error.details && typeof error.details === "object") {
1690
2671
  const details = error.details;
2672
+ let lastSwitch;
2673
+ try {
2674
+ if (details.lastSwitch) lastSwitch = parseAccountSwitch(details.lastSwitch);
2675
+ } catch {
2676
+ }
1691
2677
  return {
1692
2678
  ..."message" in error && typeof error.message === "string" ? { message: error.message } : {},
1693
2679
  retainPrevious: details.retryable === true && details.retainPrevious === true,
1694
- ...typeof details.source === "string" ? { source: details.source } : {}
2680
+ ...typeof details.source === "string" ? { source: details.source } : {},
2681
+ ...lastSwitch ? { lastSwitch } : {}
1695
2682
  };
1696
2683
  }
1697
2684
  return { retainPrevious: false };
@@ -1700,24 +2687,50 @@ function usageLevel(window) {
1700
2687
  if (window.status === "rate-limited" || window.percent >= 100) return UsagePill_default.limited;
1701
2688
  return window.percent >= 80 ? UsagePill_default.high : void 0;
1702
2689
  }
1703
- function UsagePill({ directory, settings, ...props }) {
1704
- const state = (0, import_react3.useSyncExternalStore)(directory.subscribe, directory.getSnapshot, directory.getSnapshot);
1705
- const readSettings = (0, import_react3.useCallback)(() => settings.getSnapshot(), [settings]);
1706
- const subscribeSettings = (0, import_react3.useCallback)((listener) => settings.subscribe(listener), [settings]);
1707
- const config = (0, import_react3.useSyncExternalStore)(subscribeSettings, readSettings, readSettings);
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);
1708
2707
  const mode = config.value?.usageDisplay ?? DEFAULT_USAGE_DISPLAY;
1709
2708
  const visible = config.status === "ready" && config.value?.enabled !== false && (mode === "always" || mode === "auto" && state.current?.provider === PROVIDER_ID);
1710
- return visible ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ActiveUsage, { ...props }) : null;
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;
1711
2721
  }
1712
- function ActiveUsage({ readUsage, t, getLocale }) {
1713
- const [snapshot, setSnapshot] = (0, import_react3.useState)(null);
1714
- const [failed, setFailed] = (0, import_react3.useState)(null);
1715
- const [refreshing, setRefreshing] = (0, import_react3.useState)(false);
1716
- const [open, setOpen] = (0, import_react3.useState)(false);
1717
- const root = (0, import_react3.useRef)(null);
1718
- const retry = (0, import_react3.useRef)(() => {
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)(() => {
1719
2732
  });
1720
- (0, import_react3.useEffect)(() => {
2733
+ (0, import_react4.useEffect)(() => {
1721
2734
  let alive = true;
1722
2735
  let busy = false;
1723
2736
  setSnapshot(null);
@@ -1763,7 +2776,7 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1763
2776
  document.removeEventListener("visibilitychange", visible);
1764
2777
  };
1765
2778
  }, [readUsage]);
1766
- (0, import_react3.useEffect)(() => {
2779
+ (0, import_react4.useEffect)(() => {
1767
2780
  if (!open) return;
1768
2781
  const click = (event) => {
1769
2782
  if (!root.current?.contains(event.target)) setOpen(false);
@@ -1781,71 +2794,227 @@ function ActiveUsage({ readUsage, t, getLocale }) {
1781
2794
  const current = snapshot?.reader === readUsage ? snapshot : null;
1782
2795
  const usage = current?.usage;
1783
2796
  const failure = failed?.reader === readUsage ? failed.failure : null;
1784
- const label = usage ? `Go \xB7 ${t("usageRollingShort")} ${usage.rolling.percent}% \xB7 ${t("usageWeekShort")} ${usage.weekly.percent}%${failure ? ` \xB7 ${t("usageStaleShort")}` : ""}` : `Go \xB7 ${failure ? t("usageUnavailable") : "\u2026"}`;
1785
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: UsagePill_default.root, ref: root, children: [
1786
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
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)(
1787
2861
  "button",
1788
2862
  {
1789
2863
  type: "button",
1790
2864
  className: UsagePill_default.trigger,
1791
2865
  "aria-expanded": open,
1792
2866
  "aria-haspopup": "dialog",
2867
+ "data-fallback": notice ? "" : void 0,
1793
2868
  "aria-label": `${t("usageTitle")}: ${label}`,
2869
+ title: label,
1794
2870
  onClick: () => {
1795
2871
  setOpen(!open);
2872
+ setView("usage");
1796
2873
  },
1797
- children: label
2874
+ children: segments
1798
2875
  }
1799
2876
  ),
1800
- open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.panel, role: "dialog", "aria-label": t("usageTitle"), "aria-busy": refreshing, children: [
1801
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageTitle") }),
1802
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: UsagePill_default.hint, children: t("usageHint") }),
1803
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.warning, role: "alert", children: [
1804
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("usageRefreshFailed") }),
1805
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: failure.message ?? t("usageUnavailable") }),
1806
- usage ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageStaleHint") }) : null
1807
- ] }) : null,
1808
- failure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1809
- "button",
1810
- {
1811
- type: "button",
1812
- className: UsagePill_default.retry,
1813
- disabled: refreshing,
1814
- onClick: () => {
1815
- retry.current();
1816
- },
1817
- children: t(refreshing ? "usageRefreshing" : "usageRetry")
1818
- }
1819
- ) : null,
1820
- current ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: UsagePill_default.hint, children: [
1821
- t("usageLastUpdated"),
1822
- " ",
1823
- new Date(current.updatedAt).toLocaleString(getLocale?.())
1824
- ] }) : null,
1825
- usage ? ["rolling", "weekly", "monthly"].map((key) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.window, children: [
1826
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.row, children: [
1827
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t(`usage_${key}`) }),
1828
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("strong", { children: [
1829
- usage[key].percent,
1830
- "%"
1831
- ] })
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") })
1832
2885
  ] }),
1833
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("progress", { className: usageLevel(usage[key]), "aria-label": t(`usage_${key}`), max: 100, value: Math.min(100, usage[key].percent) }),
1834
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: UsagePill_default.hint, children: [
1835
- t("usageResets"),
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"),
1836
2956
  " ",
1837
- new Date(usage[key].resetsAt).toLocaleString(getLocale?.())
1838
- ] }),
1839
- usage[key].status === "rate-limited" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: UsagePill_default.limitedText, children: t("usageLimited") })
1840
- ] }, key)) : failure ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("usageLoading") })
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
+ ] }) })
1841
3003
  ] })
1842
3004
  ] });
1843
3005
  }
1844
3006
 
1845
3007
  // src/client/usage.ts
3008
+ var import_dsh_client_store2 = require("@deepseek-ai/dsh-client-store");
1846
3009
  function registerUsagePill(ctx, settings) {
1847
3010
  ctx.inject(["modelDirectories", "sessions", "remote.session"], (scope) => {
1848
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
+ }));
1849
3018
  const readUsage = async () => {
1850
3019
  const result = await ready.remote.opencodeGoUsage.read();
1851
3020
  if (!result.ok) throw result.error;
@@ -1859,6 +3028,17 @@ function registerUsagePill(ctx, settings) {
1859
3028
  inject: (sessionId) => ({
1860
3029
  directory: ready.modelDirectories.directoryFor(sessionId).store,
1861
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
+ },
1862
3042
  readUsage,
1863
3043
  getLocale: () => ready.locale.getLocale().active,
1864
3044
  t: (key) => translate(key)
@@ -1888,9 +3068,21 @@ function apply(ctx) {
1888
3068
  }
1889
3069
  function mountSettings(ctx, scope, modelsReady) {
1890
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
+ });
1891
3079
  const controller = new OpencodeGoSectionController(scope, ctx, async () => {
1892
3080
  await modelsReady;
1893
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);
1894
3086
  });
1895
3087
  ctx.effect(() => () => controller.dispose());
1896
3088
  const t = ctx.locale.bind(NS);