@mofeng2223/dsh-claude-provider 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  let react = require("react");
9
9
  let react_dom = require("react-dom");
10
10
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
12
12
  //#region lib/types/client/apiKey.js
13
13
  /**
14
14
  * Browser-side judgement of a typed API key.
@@ -56,7 +56,7 @@ window.__ModuleLoader__.load({
56
56
  }
57
57
  //#endregion
58
58
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/ModelsSection.module.css.mjs
59
- const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.zGbnIq_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{flex-wrap:wrap;gap:10px;display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:12px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addCard,.zGbnIq_setupCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:14px;line-height:22px}select.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_selectInput{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateActions{justify-content:flex-end;margin-bottom:6px;display:flex}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:6px}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{font-family:var(--ds-font-family-code);overflow-wrap:anywhere;flex:auto;font-size:13px}";
59
+ const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.zGbnIq_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{flex-wrap:wrap;gap:10px;display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:12px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addCard,.zGbnIq_setupCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:14px;line-height:22px}select.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_selectInput{appearance:none;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before,.zGbnIq_switchThumb{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateActions{justify-content:flex-end;margin-bottom:6px;display:flex}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:6px}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{font-family:var(--ds-font-family-code);overflow-wrap:anywhere;flex:auto;font-size:13px}";
60
60
  const tagId$3 = "@mofeng2223/dsh-claude-provider/ModelsSection.module.css";
61
61
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
62
62
  const tag = document.createElement("style");
@@ -127,6 +127,7 @@ window.__ModuleLoader__.load({
127
127
  "section": "zGbnIq_section",
128
128
  "selectInput": "zGbnIq_selectInput",
129
129
  "setupCard": "zGbnIq_setupCard",
130
+ "switchThumb": "zGbnIq_switchThumb",
130
131
  "title": "zGbnIq_title"
131
132
  };
132
133
  //#endregion
@@ -145,13 +146,13 @@ window.__ModuleLoader__.load({
145
146
  className: ModelsSection_module_css_default["secondaryButton"],
146
147
  disabled: props.busy,
147
148
  onClick: props.onCancel,
148
- children: t(props.cancelLabel ?? "cancel")
149
+ children: t(props.cancelLabelKey ?? "cancel")
149
150
  }), (0, react_jsx_runtime.jsx)("button", {
150
151
  type: "button",
151
152
  className: ModelsSection_module_css_default["primaryButton"],
152
153
  disabled: props.submitDisabled,
153
154
  onClick: props.onSubmit,
154
- children: props.busy ? t(props.submitBusyLabel) : t(props.submitLabel)
155
+ children: props.busy ? t(props.submitBusyLabelKey) : t(props.submitLabelKey)
155
156
  })]
156
157
  });
157
158
  }
@@ -443,212 +444,6 @@ window.__ModuleLoader__.load({
443
444
  });
444
445
  }
445
446
  //#endregion
446
- //#region lib/types/client/store.js
447
- /**
448
- * Models settings page store: one snapshot joining the configurable-provider
449
- * directory (`llm.providers`), the settings namespaces (shared settings mirror),
450
- * and the referenced credentials (`credentials.describe`). The host stays the
451
- * single fact source — every mutation writes through the wire and the page
452
- * re-renders from the next describe, pushed or refetched.
453
- */
454
- /**
455
- * Any route key walks a dict schema to the same profile node, so the lookup
456
- * names one that cannot collide with a configured route.
457
- */
458
- const PROBE_ROUTE = "\0probe";
459
- /**
460
- * Human text for a rejected wire call. A transport failure rejects with an
461
- * Error; a host or a runtime can reject with anything, and the page still has
462
- * to say something.
463
- * @param error - the rejection value.
464
- * @returns the message to show.
465
- */
466
- function messageOf(error) {
467
- return error instanceof Error ? error.message : String(error);
468
- }
469
- /**
470
- * Derive the conventional credential reference for a provider route: the v1
471
- * page never asks for an environment-variable name, so a typed key stores
472
- * under this derived reference and the profile records it as `apiKeyEnv`.
473
- * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
474
- * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
475
- */
476
- function deriveKeyRef(provider) {
477
- return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
478
- }
479
- /**
480
- * The wire protocols a hand-declared route may name, read out of the owning
481
- * namespace's own schema. This stays a schema read rather than a wire field so
482
- * the choices the page offers cannot drift from the ones the adapter accepts:
483
- * both come from the same `Config`.
484
- * @param namespace - the namespace view whose schema declares the profile shape.
485
- * @param schema - settings schema operations.
486
- * @returns the protocol identifiers, or an empty list when the schema has none.
487
- */
488
- function protocolChoices(namespace, schema) {
489
- if (namespace === void 0) return [];
490
- const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
491
- "providers",
492
- PROBE_ROUTE,
493
- "api"
494
- ]);
495
- if (list?.type !== "union" || list.list === void 0) return [];
496
- return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
497
- }
498
- /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
499
- function apiKeyEnvOf(namespace, path, schema) {
500
- if (namespace === void 0) return void 0;
501
- const profile = schema.getPath(namespace.value, path);
502
- if (typeof profile !== "object" || profile === null) return void 0;
503
- const ref = profile.apiKeyEnv;
504
- return typeof ref === "string" && ref.length > 0 ? ref : void 0;
505
- }
506
- /** The models settings page controller (one per settings surface). */
507
- var ModelsSettingsStore = class {
508
- api;
509
- schema;
510
- describeFace;
511
- /** The snapshot the section renders from (uSES-safe store). */
512
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
513
- status: "idle",
514
- error: null,
515
- credentialError: null,
516
- writable: false,
517
- rows: [],
518
- namespaces: /* @__PURE__ */ new Map()
519
- });
520
- /** Latest load wins; an older response never overwrites a newer one. */
521
- generation = 0;
522
- /**
523
- * @param api - the wire face (credentials/llm domains, and settings writes).
524
- * @param describeFace - the shared mirror's describe face (namespace views and writability).
525
- */
526
- constructor(api, schema, describeFace) {
527
- this.api = api;
528
- this.schema = schema;
529
- this.describeFace = describeFace;
530
- }
531
- /**
532
- * Refresh the whole page snapshot: the provider directory and the mirror's
533
- * settings answer in parallel, then one batched credential describe over
534
- * every referenced ref. Provider failure or absence of an initial settings
535
- * answer keeps the last good rows and surfaces an error; a failed settings
536
- * refresh reuses the mirror's held view.
537
- * @returns nothing; the snapshot carries the outcome.
538
- */
539
- async load() {
540
- const generation = ++this.generation;
541
- this.store.update((s) => {
542
- s.status = "loading";
543
- s.error = null;
544
- });
545
- let providers;
546
- let writable;
547
- let views;
548
- try {
549
- const [providersResponse] = await Promise.all([this.api.llm.providers({}), this.describeFace.ensure()]);
550
- if (!providersResponse.result.ok) throw new Error(providersResponse.result.error.message);
551
- const mirrored = this.describeFace.getSnapshot();
552
- if (mirrored.view === void 0) throw new Error(mirrored.error ?? "settings are unavailable in this browser");
553
- providers = providersResponse.result.value.providers.filter((entry) => entry.provider !== CLAUDE_PROVIDER_DIRECTORY_SENTINEL);
554
- writable = mirrored.view.writable;
555
- views = mirrored.view.namespaces;
556
- } catch (error) {
557
- if (generation !== this.generation) return;
558
- this.store.update((s) => {
559
- s.status = "error";
560
- s.error = error instanceof Error ? error.message : String(error);
561
- });
562
- return;
563
- }
564
- const namespaces = new Map(views.map((view) => [view.ns, view]));
565
- const rows = providers.map((entry) => {
566
- const namespace = namespaces.get(entry.settingsNs);
567
- return {
568
- entry,
569
- configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
570
- removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
571
- apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
572
- credential: void 0
573
- };
574
- });
575
- const refs = [...new Set(rows.flatMap((row) => row.apiKeyEnv === void 0 ? [] : [row.apiKeyEnv]))];
576
- let credentials = {};
577
- let credentialError = null;
578
- if (refs.length > 0) try {
579
- const response = await this.api.credentials.describe({ refs });
580
- if (response.result.ok) credentials = response.result.value.credentials;
581
- else credentialError = response.result.error.message;
582
- } catch (error) {
583
- credentialError = messageOf(error);
584
- }
585
- if (generation !== this.generation) return;
586
- this.store.update((s) => {
587
- s.status = "ready";
588
- s.error = null;
589
- s.credentialError = credentialError;
590
- s.writable = writable;
591
- s.rows = rows.map((row) => ({
592
- ...row,
593
- ...row.apiKeyEnv !== void 0 && credentials[row.apiKeyEnv] !== void 0 ? { credential: credentials[row.apiKeyEnv] } : {}
594
- }));
595
- s.namespaces = namespaces;
596
- });
597
- }
598
- };
599
- /**
600
- * Whether a joined row can serve model requests as it stands: the route is
601
- * registered with the adapter registry, and whatever credential its resolved
602
- * profile names is stored. A profile naming no reference authenticates through
603
- * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
604
- * nothing), as does a live route with no settings address at all, so neither
605
- * owes this page a key.
606
- * @param row - one joined provider row.
607
- * @returns whether the user already has this provider to talk to.
608
- */
609
- function providerUsable(row) {
610
- if (!row.entry.active) return false;
611
- if (row.apiKeyEnv === void 0) return true;
612
- return row.credential?.configured === true;
613
- }
614
- /**
615
- * Project first-run readiness from the provider/settings/credential join used
616
- * by the Models page. The step exists to leave the user with a model to talk
617
- * to, so ANY usable provider ends it; only when none exists does the official
618
- * DeepSeek route — the one route the prompt can offer a key field for — decide
619
- * whether prompting can help. A missing official configurable-provider
620
- * declaration means the adapter is not repairable by navigating to Models.
621
- * @param state - current shared Models join snapshot.
622
- * @returns the onboarding state without reading a parallel fact source.
623
- */
624
- function onboardingReadiness(state) {
625
- if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
626
- if (state.status === "error") return {
627
- kind: "unavailable",
628
- reason: "load-failed"
629
- };
630
- if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
631
- const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
632
- if (row === void 0) return { kind: "adapter-absent" };
633
- if (!row.entry.active) return {
634
- kind: "unavailable",
635
- reason: "provider-inactive"
636
- };
637
- if (state.credentialError !== null || row.credential === void 0) return {
638
- kind: "unavailable",
639
- reason: "credentials-unavailable"
640
- };
641
- if (!state.writable) return {
642
- kind: "unavailable",
643
- reason: "settings-read-only"
644
- };
645
- if (!row.credential.writable) return {
646
- kind: "unavailable",
647
- reason: "credential-read-only"
648
- };
649
- return { kind: "credential-missing" };
650
- }
651
- //#endregion
652
447
  //#region lib/types/client/ModelListEditor.js
653
448
  /**
654
449
  * The model list of one pi-ai provider profile, plus the action that asks the
@@ -753,7 +548,7 @@ window.__ModuleLoader__.load({
753
548
  * @returns the model-list editor.
754
549
  */
755
550
  function ModelListEditor(props) {
756
- const { models, onChange, probe, api, t, disabled } = props;
551
+ const { models, onChange, probe, operations, t, disabled } = props;
757
552
  const [busy, setBusy] = (0, react.useState)(false);
758
553
  const [failure, setFailure] = (0, react.useState)(void 0);
759
554
  const [candidates, setCandidates] = (0, react.useState)(void 0);
@@ -799,18 +594,17 @@ window.__ModuleLoader__.load({
799
594
  setBusy(true);
800
595
  setFailure(void 0);
801
596
  try {
802
- const response = await api.llm.discoverModels({
803
- settingsNs: probe.settingsNs,
597
+ const answer = await operations.discoverModels(probe.settingsNs, {
804
598
  ...probe.provider === void 0 ? {} : { provider: probe.provider },
805
599
  ...probe.baseURL === void 0 || probe.baseURL.length === 0 ? {} : { baseURL: probe.baseURL },
806
600
  ...probe.api === void 0 ? {} : { api: props.thinkingPresets ? CLAUDE_DISCOVERY_API : probe.api },
807
601
  ...probe.apiKey === void 0 ? {} : { apiKey: probe.apiKey }
808
602
  });
809
- if (!response.result.ok) {
810
- setFailure(response.result.error.message);
603
+ if (answer.kind === "refused") {
604
+ setFailure(answer.message);
811
605
  return;
812
606
  }
813
- const found = response.result.value.models;
607
+ const found = answer.models;
814
608
  if (found.length === 0) {
815
609
  setFailure(t("fetchEmpty"));
816
610
  return;
@@ -818,8 +612,6 @@ window.__ModuleLoader__.load({
818
612
  const known = new Set(models.map((model) => textOf(model, "id")));
819
613
  setCandidates(found);
820
614
  setPicked(new Set(found.filter((model) => !known.has(model.id)).map((model) => model.id)));
821
- } catch (error) {
822
- setFailure(messageOf(error));
823
615
  } finally {
824
616
  setBusy(false);
825
617
  }
@@ -1066,6 +858,247 @@ window.__ModuleLoader__.load({
1066
858
  });
1067
859
  }
1068
860
  //#endregion
861
+ //#region lib/types/client/store.js
862
+ /**
863
+ * Models settings page store: one snapshot joining the configurable-provider
864
+ * directory (`llm/listProviders` joined with `llm/listConfigurableProviders`),
865
+ * the settings namespaces (shared settings mirror),
866
+ * and the referenced credentials (`credentials/describe`). The host stays the
867
+ * single fact source — every mutation writes through the wire and the page
868
+ * re-renders from the next describe, pushed or refetched.
869
+ */
870
+ /**
871
+ * Any route key walks a dict schema to the same profile node, so the lookup
872
+ * names one that cannot collide with a configured route.
873
+ */
874
+ const PROBE_ROUTE = "\0probe";
875
+ /**
876
+ * Join declared configurable providers with the currently registered routes.
877
+ * @param registered - live provider routes in registration order.
878
+ * @param directory - declared configurable providers in declaration order.
879
+ * @returns declared rows followed by live routes with no declaration.
880
+ */
881
+ function joinProviderDirectory(registered, directory) {
882
+ const active = new Set(registered.map((provider) => provider.id));
883
+ const declared = new Set(directory.map((entry) => entry.provider));
884
+ const rows = directory.map((entry) => ({
885
+ provider: entry.provider,
886
+ displayName: entry.displayName,
887
+ settingsNs: entry.settingsNs,
888
+ settingsPath: [...entry.settingsPath],
889
+ active: active.has(entry.provider),
890
+ ...entry.declared === void 0 ? {} : { declared: entry.declared }
891
+ }));
892
+ for (const provider of registered) {
893
+ if (declared.has(provider.id)) continue;
894
+ rows.push({
895
+ provider: provider.id,
896
+ displayName: provider.name,
897
+ settingsNs: "",
898
+ settingsPath: [],
899
+ active: true
900
+ });
901
+ }
902
+ return rows;
903
+ }
904
+ /**
905
+ * Derive the conventional credential reference for a provider route: the v1
906
+ * page never asks for an environment-variable name, so a typed key stores
907
+ * under this derived reference and the profile records it as `apiKeyEnv`.
908
+ * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
909
+ * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
910
+ */
911
+ function deriveKeyRef(provider) {
912
+ return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
913
+ }
914
+ /**
915
+ * The wire protocols a hand-declared route may name, read out of the owning
916
+ * namespace's own schema. This stays a schema read rather than a wire field so
917
+ * the choices the page offers cannot drift from the ones the adapter accepts:
918
+ * both come from the same `Config`.
919
+ * @param namespace - the namespace view whose schema declares the profile shape.
920
+ * @param schema - settings schema operations.
921
+ * @returns the protocol identifiers, or an empty list when the schema has none.
922
+ */
923
+ function protocolChoices(namespace, schema) {
924
+ if (namespace === void 0) return [];
925
+ const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
926
+ "providers",
927
+ PROBE_ROUTE,
928
+ "api"
929
+ ]);
930
+ if (list?.type !== "union" || list.list === void 0) return [];
931
+ return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
932
+ }
933
+ /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
934
+ function apiKeyEnvOf(namespace, path, schema) {
935
+ if (namespace === void 0) return void 0;
936
+ const profile = schema.getPath(namespace.value, path);
937
+ if (typeof profile !== "object" || profile === null) return void 0;
938
+ const ref = profile.apiKeyEnv;
939
+ return typeof ref === "string" && ref.length > 0 ? ref : void 0;
940
+ }
941
+ /** The models settings page controller (one per settings surface). */
942
+ var ModelsSettingsStore = class {
943
+ ctx;
944
+ schema;
945
+ describeFace;
946
+ /** The snapshot the section renders from (uSES-safe store). */
947
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
948
+ status: "idle",
949
+ error: null,
950
+ credentialError: null,
951
+ writable: false,
952
+ rows: [],
953
+ namespaces: /* @__PURE__ */ new Map()
954
+ });
955
+ /** Latest load wins; an older response never overwrites a newer one. */
956
+ generation = 0;
957
+ /**
958
+ * @param ctx - the page plugin's context, whose `remote.llm` and
959
+ * `remote.credentials` namespaces carry the directory and credential reads.
960
+ * @param schema - settings-owned schema and immutable path operations.
961
+ * @param describeFace - the shared mirror's describe face (namespace views and writability).
962
+ */
963
+ constructor(ctx, schema, describeFace) {
964
+ this.ctx = ctx;
965
+ this.schema = schema;
966
+ this.describeFace = describeFace;
967
+ }
968
+ /**
969
+ * Refresh the whole page snapshot: the provider directory and the mirror's
970
+ * settings answer in parallel, then one batched credential describe over
971
+ * every referenced ref. Provider failure or absence of an initial settings
972
+ * answer keeps the last good rows and surfaces an error; a failed settings
973
+ * refresh reuses the mirror's held view.
974
+ * @returns nothing; the snapshot carries the outcome.
975
+ */
976
+ async load() {
977
+ const generation = ++this.generation;
978
+ this.store.update((s) => {
979
+ s.status = "loading";
980
+ s.error = null;
981
+ });
982
+ const [registered, declared] = await Promise.all([
983
+ this.ctx.remote.llm.listProviders(),
984
+ this.ctx.remote.llm.listConfigurableProviders(),
985
+ this.describeFace.ensure()
986
+ ]);
987
+ if (!registered.ok) {
988
+ this.failLoad(generation, registered.error.message);
989
+ return;
990
+ }
991
+ if (!declared.ok) {
992
+ this.failLoad(generation, declared.error.message);
993
+ return;
994
+ }
995
+ const mirrored = this.describeFace.getSnapshot();
996
+ if (mirrored.view === void 0) {
997
+ this.failLoad(generation, mirrored.error ?? "settings are unavailable in this browser");
998
+ return;
999
+ }
1000
+ const providers = joinProviderDirectory(registered.value, declared.value);
1001
+ const writable = mirrored.view.writable;
1002
+ const views = mirrored.view.namespaces;
1003
+ const namespaces = new Map(views.map((view) => [view.ns, view]));
1004
+ const rows = providers.map((entry) => {
1005
+ const namespace = namespaces.get(entry.settingsNs);
1006
+ return {
1007
+ entry,
1008
+ configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
1009
+ removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
1010
+ apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
1011
+ credential: void 0
1012
+ };
1013
+ });
1014
+ const refs = [...new Set(rows.map((row) => row.apiKeyEnv ?? deriveKeyRef(row.entry.provider)))];
1015
+ let credentials = {};
1016
+ let credentialError = null;
1017
+ if (refs.length > 0) {
1018
+ const response = await this.ctx.remote.credentials.describe(refs);
1019
+ if (response.ok) credentials = response.value;
1020
+ else credentialError = response.error.message;
1021
+ }
1022
+ if (generation !== this.generation) return;
1023
+ this.store.update((s) => {
1024
+ s.status = "ready";
1025
+ s.error = null;
1026
+ s.credentialError = credentialError;
1027
+ s.writable = writable;
1028
+ s.rows = rows.map((row) => {
1029
+ const named = row.apiKeyEnv === void 0 ? void 0 : credentials[row.apiKeyEnv];
1030
+ const derived = row.apiKeyEnv !== void 0 ? void 0 : credentials[deriveKeyRef(row.entry.provider)];
1031
+ return {
1032
+ ...row,
1033
+ ...named === void 0 ? {} : { credential: named },
1034
+ ...derived === void 0 ? {} : { derivedCredential: derived }
1035
+ };
1036
+ });
1037
+ s.namespaces = namespaces;
1038
+ });
1039
+ }
1040
+ /** Publish one load's failure text, unless a newer load already took over. */
1041
+ failLoad(generation, message) {
1042
+ if (generation !== this.generation) return;
1043
+ this.store.update((s) => {
1044
+ s.status = "error";
1045
+ s.error = message;
1046
+ });
1047
+ }
1048
+ };
1049
+ /**
1050
+ * Whether a joined row can serve model requests as it stands: the route is
1051
+ * registered with the adapter registry, and whatever credential its resolved
1052
+ * profile names is stored. A profile naming no reference authenticates through
1053
+ * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
1054
+ * nothing), as does a live route with no settings address at all, so neither
1055
+ * owes this page a key.
1056
+ * @param row - one joined provider row.
1057
+ * @returns whether the user already has this provider to talk to.
1058
+ */
1059
+ function providerUsable(row) {
1060
+ if (!row.entry.active) return false;
1061
+ if (row.apiKeyEnv === void 0) return true;
1062
+ return row.credential?.configured === true;
1063
+ }
1064
+ /**
1065
+ * Project first-run readiness from the provider/settings/credential join used
1066
+ * by the Models page. The step exists to leave the user with a model to talk
1067
+ * to, so ANY usable provider ends it; only when none exists does the official
1068
+ * DeepSeek route — the one route the prompt can offer a key field for — decide
1069
+ * whether prompting can help. A missing official configurable-provider
1070
+ * declaration means the adapter is not repairable by navigating to Models.
1071
+ * @param state - current shared Models join snapshot.
1072
+ * @returns the onboarding state without reading a parallel fact source.
1073
+ */
1074
+ function onboardingReadiness(state) {
1075
+ if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
1076
+ if (state.status === "error") return {
1077
+ kind: "unavailable",
1078
+ reason: "load-failed"
1079
+ };
1080
+ if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
1081
+ const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
1082
+ if (row === void 0) return { kind: "adapter-absent" };
1083
+ if (!row.entry.active) return {
1084
+ kind: "unavailable",
1085
+ reason: "provider-inactive"
1086
+ };
1087
+ if (state.credentialError !== null || row.credential === void 0) return {
1088
+ kind: "unavailable",
1089
+ reason: "credentials-unavailable"
1090
+ };
1091
+ if (!state.writable) return {
1092
+ kind: "unavailable",
1093
+ reason: "settings-read-only"
1094
+ };
1095
+ if (!row.credential.writable) return {
1096
+ kind: "unavailable",
1097
+ reason: "credential-read-only"
1098
+ };
1099
+ return { kind: "credential-missing" };
1100
+ }
1101
+ //#endregion
1069
1102
  //#region lib/types/client/CustomProviderCard.js
1070
1103
  /**
1071
1104
  * The card that declares a provider pi-ai does not ship — an OpenAI-compatible
@@ -1076,7 +1109,7 @@ window.__ModuleLoader__.load({
1076
1109
  * the provider editor with extra fields: the route id is being *chosen* here,
1077
1110
  * and the settings address does not exist until it is. One `settings.mutate`
1078
1111
  * sets the whole profile at `providers.<route>`; the key travels separately
1079
- * through `credentials.set` under the reference the profile records, exactly as
1112
+ * through `credentials/set` under the reference the profile records, exactly as
1080
1113
  * an existing provider's key does.
1081
1114
  *
1082
1115
  * The three fields a hand-declared route cannot default — endpoint, protocol,
@@ -1106,7 +1139,7 @@ window.__ModuleLoader__.load({
1106
1139
  * @returns the creation card.
1107
1140
  */
1108
1141
  function CustomProviderCard(props) {
1109
- const { taken, protocols, api, t } = props;
1142
+ const { taken, protocols, operations, t } = props;
1110
1143
  const [openedAt] = (0, react.useState)(() => props.revision);
1111
1144
  const [route, setRoute] = (0, react.useState)("");
1112
1145
  const [displayName, setDisplayName] = (0, react.useState)("");
@@ -1147,31 +1180,25 @@ window.__ModuleLoader__.load({
1147
1180
  models: models.map((model) => isAdaptiveClaude ? withNativeClaudeModel(model) : { ...model }),
1148
1181
  ...isAdaptiveClaude ? { reasoning: "high" } : {}
1149
1182
  };
1150
- const response = await api.settings.mutate({
1151
- ns: NS$1,
1152
- ops: [{
1153
- op: "set",
1154
- path: ["providers", route],
1155
- value: profile
1156
- }],
1157
- expectedRevision: openedAt
1158
- });
1159
- if (!response.result.ok) return response.result.error.message;
1183
+ const written = await operations.writeSettings(NS$1, [{
1184
+ op: "set",
1185
+ path: ["providers", route],
1186
+ value: profile
1187
+ }], openedAt);
1188
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1160
1189
  setCommitted(true);
1161
1190
  }
1162
1191
  if (isAdaptiveClaude) {
1163
- const typed = await api.settings.mutate({
1164
- ns: CLAUDE_PROVIDER_SETTINGS_NS,
1165
- ops: [{ op: "set", path: ["providerTypes", route], value: CLAUDE_PROVIDER_TYPE }]
1166
- });
1167
- if (!typed.result.ok) return typed.result.error.message;
1192
+ const typed = await operations.writeSettings(CLAUDE_PROVIDER_SETTINGS_NS, [{
1193
+ op: "set",
1194
+ path: ["providerTypes", route],
1195
+ value: CLAUDE_PROVIDER_TYPE
1196
+ }], void 0);
1197
+ if (typed.kind !== "written") return typed.kind === "conflict" ? t("conflict") : typed.message;
1168
1198
  }
1169
1199
  if (storesKey) {
1170
- const stored = await api.credentials.set({
1171
- ref: keyRef,
1172
- value: keyValue
1173
- });
1174
- if (!stored.result.ok) return stored.result.error.message;
1200
+ const stored = await operations.storeCredential(keyRef, keyValue);
1201
+ if (stored !== void 0) return stored;
1175
1202
  }
1176
1203
  };
1177
1204
  const create = async () => {
@@ -1184,8 +1211,6 @@ window.__ModuleLoader__.load({
1184
1211
  return;
1185
1212
  }
1186
1213
  props.onClose(true);
1187
- } catch (error) {
1188
- setFailure(messageOf(error));
1189
1214
  } finally {
1190
1215
  setBusy(false);
1191
1216
  }
@@ -1255,7 +1280,7 @@ window.__ModuleLoader__.load({
1255
1280
  className: ModelsSection_module_css_default["input"],
1256
1281
  type: "text",
1257
1282
  value: baseURL,
1258
- placeholder: "https://gateway.example/v1",
1283
+ placeholder: t("customBaseUrlPlaceholder"),
1259
1284
  "aria-label": t("baseUrl"),
1260
1285
  disabled: profileDisabled,
1261
1286
  onChange: (event) => {
@@ -1318,7 +1343,7 @@ window.__ModuleLoader__.load({
1318
1343
  },
1319
1344
  probeBlocked: keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
1320
1345
  thinkingPresets: isAdaptiveClaude,
1321
- api,
1346
+ operations,
1322
1347
  t,
1323
1348
  disabled: profileDisabled
1324
1349
  }),
@@ -1334,8 +1359,8 @@ window.__ModuleLoader__.load({
1334
1359
  t,
1335
1360
  busy,
1336
1361
  submitDisabled: disabled || !ready,
1337
- submitLabel: "create",
1338
- submitBusyLabel: "creating",
1362
+ submitLabelKey: "create",
1363
+ submitBusyLabelKey: "creating",
1339
1364
  onCancel: () => {
1340
1365
  props.onClose(committed);
1341
1366
  },
@@ -1351,7 +1376,7 @@ window.__ModuleLoader__.load({
1351
1376
  /**
1352
1377
  * One provider's editor card, hand-written per adapter family: the primary
1353
1378
  * field is a single write-only **API key** input (the page never asks for an
1354
- * environment-variable name — a typed key stores through `credentials.set`
1379
+ * environment-variable name — a typed key stores through `credentials/set`
1355
1380
  * under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile
1356
1381
  * has none. The pi-ai profile records that derivation as `apiKeyEnv` only when
1357
1382
  * a key is entered; a blank key materializes a reference-free profile for
@@ -1423,7 +1448,7 @@ window.__ModuleLoader__.load({
1423
1448
  * @returns the editor card.
1424
1449
  */
1425
1450
  function ProviderEditor(props) {
1426
- const { namespace, schema, settingsPath, api, t } = props;
1451
+ const { namespace, schema, settingsPath, operations, t } = props;
1427
1452
  const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
1428
1453
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1429
1454
  const [keyState, setKeyState] = (0, react.useState)(void 0);
@@ -1449,14 +1474,14 @@ window.__ModuleLoader__.load({
1449
1474
  (0, react.useEffect)(() => {
1450
1475
  let stale = false;
1451
1476
  setKeyState(void 0);
1452
- api.credentials.describe({ refs: [keyRef] }).then((response) => {
1453
- if (stale || !response.result.ok) return;
1454
- setKeyState(response.result.value.credentials[keyRef]);
1455
- }, () => void 0);
1477
+ operations.describeCredential(keyRef).then((described) => {
1478
+ if (stale) return;
1479
+ setKeyState(described);
1480
+ });
1456
1481
  return () => {
1457
1482
  stale = true;
1458
1483
  };
1459
- }, [api.credentials, keyRef]);
1484
+ }, [operations, keyRef]);
1460
1485
  const stringAt = (source, key) => {
1461
1486
  const value = schema.getPath(source, [key]);
1462
1487
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -1505,22 +1530,15 @@ window.__ModuleLoader__.load({
1505
1530
  value: {}
1506
1531
  }] : pathOps(settingsPath, committedOriginal, next);
1507
1532
  if (ops.length > 0) {
1508
- const response = await api.settings.mutate({
1509
- ns,
1510
- ops,
1511
- expectedRevision
1512
- });
1513
- if (!response.result.ok) return response.result.error.code === "settings-conflict" ? t("conflict") : response.result.error.message;
1514
- setCommittedOriginal(schema.getPath(response.result.value.user, settingsPath));
1515
- setExpectedRevision(response.result.value.revision);
1533
+ const written = await operations.writeSettings(ns, ops, expectedRevision);
1534
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1535
+ setCommittedOriginal(schema.getPath(written.view.user, settingsPath));
1536
+ setExpectedRevision(written.view.revision);
1516
1537
  setDraft(next);
1517
1538
  }
1518
1539
  if (keyValue.length > 0) {
1519
- const stored = await api.credentials.set({
1520
- ref: keyRef,
1521
- value: keyValue
1522
- });
1523
- if (!stored.result.ok) return stored.result.error.message;
1540
+ const stored = await operations.storeCredential(keyRef, keyValue);
1541
+ if (stored !== void 0) return stored;
1524
1542
  }
1525
1543
  setKeyDraft("");
1526
1544
  };
@@ -1534,15 +1552,17 @@ window.__ModuleLoader__.load({
1534
1552
  return;
1535
1553
  }
1536
1554
  props.onClose(true);
1537
- } catch (error) {
1538
- setFailure(messageOf(error));
1539
1555
  } finally {
1540
1556
  setBusy(false);
1541
1557
  }
1542
1558
  };
1543
- if (node === void 0) return (0, react_jsx_runtime.jsx)("p", {
1559
+ if (node === void 0) return (0, react_jsx_runtime.jsxs)("p", {
1544
1560
  className: ModelsSection_module_css_default["error"],
1545
- children: `${props.provider}: unresolvable settings path`
1561
+ children: [
1562
+ props.provider,
1563
+ ": ",
1564
+ props.t("settingsPathUnresolvable")
1565
+ ]
1546
1566
  });
1547
1567
  const keyLocked = keyState?.writable === false;
1548
1568
  /**
@@ -1681,7 +1701,7 @@ window.__ModuleLoader__.load({
1681
1701
  probe,
1682
1702
  probeBlocked: keyFailure,
1683
1703
  thinkingPresets: props.thinkingPresets === true,
1684
- api
1704
+ operations
1685
1705
  })
1686
1706
  ]
1687
1707
  })]
@@ -1716,9 +1736,9 @@ window.__ModuleLoader__.load({
1716
1736
  t,
1717
1737
  busy,
1718
1738
  submitDisabled: disabled || layout === "unknown" || props.credentialOnly !== true && modelFailure !== void 0 || shownKeyFailure !== void 0 || props.credentialRequired === true && keyValue.length === 0,
1719
- submitLabel: props.submitLabel ?? "apply",
1720
- submitBusyLabel: props.submitBusyLabel ?? "applying",
1721
- ...props.cancelLabel === void 0 ? {} : { cancelLabel: props.cancelLabel },
1739
+ submitLabelKey: props.submitLabelKey ?? "apply",
1740
+ submitBusyLabelKey: props.submitBusyLabelKey ?? "applying",
1741
+ ...props.cancelLabelKey === void 0 ? {} : { cancelLabelKey: props.cancelLabelKey },
1722
1742
  onCancel: () => {
1723
1743
  props.onClose(false);
1724
1744
  },
@@ -1760,33 +1780,26 @@ window.__ModuleLoader__.load({
1760
1780
  * and the whole operation safely retryable; both unsets are idempotent.
1761
1781
  * The settings removal names the profile rather than rebuilding its whole
1762
1782
  * namespace from a partial view.
1763
- * @param api - settings and credential wire faces.
1783
+ * @param operations - the page's Host operations.
1764
1784
  * @param controller - the page store to refresh.
1765
1785
  * @param target - the provider's settings address and optional managed credential.
1766
1786
  * @returns the failure message, or undefined once the write and reload landed.
1767
1787
  */
1768
- async function removeProviderProfile(api, controller, target) {
1769
- try {
1770
- if (target.credentialRef !== void 0) {
1771
- const credential = await api.credentials.unset({ ref: target.credentialRef });
1772
- if (!credential.result.ok) return credential.result.error.message;
1773
- }
1774
- const response = await api.settings.mutate({
1775
- ns: target.settingsNs,
1776
- ops: [{
1777
- op: "unset",
1778
- path: [...target.settingsPath]
1779
- }]
1780
- });
1781
- if (!response.result.ok) return response.result.error.message;
1782
- const typeResponse = await api.settings.mutate({
1783
- ns: CLAUDE_PROVIDER_SETTINGS_NS,
1784
- ops: [{ op: "unset", path: ["providerTypes", target.provider] }]
1785
- });
1786
- if (!typeResponse.result.ok) return typeResponse.result.error.message;
1787
- } catch (error) {
1788
- return messageOf(error);
1788
+ async function removeProviderProfile(operations, controller, target) {
1789
+ if (target.credentialRef !== void 0) {
1790
+ const credential = await operations.removeCredential(target.credentialRef);
1791
+ if (credential !== void 0) return credential;
1789
1792
  }
1793
+ const written = await operations.writeSettings(target.settingsNs, [{
1794
+ op: "unset",
1795
+ path: [...target.settingsPath]
1796
+ }], void 0);
1797
+ if (written.kind !== "written") return written.message;
1798
+ const typedRemoval = await operations.writeSettings(CLAUDE_PROVIDER_SETTINGS_NS, [{
1799
+ op: "unset",
1800
+ path: ["providerTypes", target.provider]
1801
+ }], void 0);
1802
+ if (typedRemoval.kind !== "written") return typedRemoval.message;
1790
1803
  await controller.load();
1791
1804
  }
1792
1805
  /**
@@ -1803,6 +1816,16 @@ window.__ModuleLoader__.load({
1803
1816
  if (row.entry.settingsPath.length > 0) return false;
1804
1817
  return row.credential?.configured !== true;
1805
1818
  }
1819
+ /**
1820
+ * The provider-card seat's credential fact: the reference this page would use
1821
+ * for the row — the profile's `apiKeyEnv`, or the page's derived
1822
+ * `<ROUTE>_API_KEY` while the profile names none — confirmed configured. The
1823
+ * derived half is what keeps the seat consistent with the editor on the
1824
+ * add-provider draft, whose dormant row names no reference yet.
1825
+ */
1826
+ function keyConfiguredOf(row) {
1827
+ return row.apiKeyEnv !== void 0 ? row.credential?.configured === true : row.derivedCredential?.configured === true;
1828
+ }
1806
1829
  function targetOf(row) {
1807
1830
  const managedRef = deriveKeyRef(row.entry.provider);
1808
1831
  const credentialRef = row.apiKeyEnv === managedRef && row.credential?.configured === true && row.credential.writable ? managedRef : void 0;
@@ -1818,7 +1841,6 @@ window.__ModuleLoader__.load({
1818
1841
  const CLAUDE_DISCOVERY_API = "mofeng-anthropic-models";
1819
1842
  const CLAUDE_PROVIDER_SETTINGS_NS = "dsh-claude-provider";
1820
1843
  const CLAUDE_PROVIDER_TYPE = "claude-adaptive";
1821
- const CLAUDE_PROVIDER_DIRECTORY_SENTINEL = "dsh-claude-provider-type";
1822
1844
  const CLAUDE_FIVE_EFFORTS = Object.freeze({ low: "low", medium: "medium", high: "high", xhigh: "xhigh", max: "max" });
1823
1845
  const CLAUDE_FOUR_EFFORTS = Object.freeze({ low: "low", medium: "medium", high: "high", max: "max" });
1824
1846
  const CLAUDE_TOGGLE_EFFORTS = Object.freeze({ off: null, high: "high" });
@@ -1948,18 +1970,21 @@ window.__ModuleLoader__.load({
1948
1970
  * @returns the section, or null while the shell has not injected yet.
1949
1971
  */
1950
1972
  function ModelsSection(props) {
1951
- const { controller, useSnapshot, api, schema, t } = props;
1952
- if (controller === void 0 || useSnapshot === void 0 || api === void 0 || schema === void 0 || t === void 0) return null;
1953
- return (0, react_jsx_runtime.jsx)(Loaded, { injected: {
1954
- controller,
1955
- useSnapshot,
1956
- api,
1957
- schema,
1958
- t
1959
- } });
1973
+ const { controller, useSnapshot, operations, schema, t, renderSlot } = props;
1974
+ if (controller === void 0 || useSnapshot === void 0 || operations === void 0 || schema === void 0 || t === void 0) return null;
1975
+ return (0, react_jsx_runtime.jsx)(Loaded, {
1976
+ injected: {
1977
+ controller,
1978
+ useSnapshot,
1979
+ operations,
1980
+ schema,
1981
+ t
1982
+ },
1983
+ renderSlot
1984
+ });
1960
1985
  }
1961
- function Loaded({ injected }) {
1962
- const { controller, api, schema, t } = injected;
1986
+ function Loaded({ injected, renderSlot }) {
1987
+ const { controller, operations, schema, t } = injected;
1963
1988
  const state = injected.useSnapshot((snapshot) => snapshot);
1964
1989
  const [editing, setEditing] = (0, react.useState)(void 0);
1965
1990
  const [adding, setAdding] = (0, react.useState)(false);
@@ -2001,7 +2026,7 @@ window.__ModuleLoader__.load({
2001
2026
  if (deleteTarget === void 0 || deleting) return;
2002
2027
  setDeleting(true);
2003
2028
  setDeleteFailure(void 0);
2004
- removeProviderProfile(api, controller, deleteTarget).then((failure) => {
2029
+ removeProviderProfile(operations, controller, deleteTarget).then((failure) => {
2005
2030
  if (failure !== void 0) {
2006
2031
  setDeleteFailure(failure);
2007
2032
  return;
@@ -2040,6 +2065,7 @@ window.__ModuleLoader__.load({
2040
2065
  const addable = state.rows.filter((row) => !row.configured && row.entry.settingsNs !== "");
2041
2066
  const addTarget = adding ? editing : void 0;
2042
2067
  const addNamespace = addTarget === void 0 ? void 0 : state.namespaces.get(addTarget.settingsNs);
2068
+ const addRow = addTarget === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === addTarget.provider);
2043
2069
  const protocols = protocolChoices(state.namespaces.get("llm-pi-ai"), schema);
2044
2070
  return (0, react_jsx_runtime.jsxs)("div", {
2045
2071
  className: ModelsSection_module_css_default["section"],
@@ -2069,20 +2095,24 @@ window.__ModuleLoader__.load({
2069
2095
  const namespace = state.namespaces.get(target.settingsNs);
2070
2096
  /* v8 ignore next -- the join marks a row configured only when its namespace resolved */
2071
2097
  if (namespace === void 0) return null;
2072
- if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsx)("li", {
2098
+ if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsxs)("li", {
2073
2099
  className: ModelsSection_module_css_default["setupCard"],
2074
- children: renderProviderEditor({
2100
+ children: [renderProviderEditor({
2075
2101
  target,
2076
2102
  namespace,
2077
2103
  schema,
2078
2104
  thinkingPresets: isClaudeProvider(row, state),
2079
- api,
2105
+ operations,
2080
2106
  t,
2081
2107
  readOnly: !state.writable,
2082
2108
  onClose: (changed) => {
2083
2109
  closeSetup(changed, target);
2084
2110
  }
2085
- })
2111
+ }), renderSlot("settings.models.provider-card", {
2112
+ provider: row.entry,
2113
+ configured: row.configured,
2114
+ keyConfigured: keyConfiguredOf(row)
2115
+ }, { entryKey: row.entry.settingsNs })]
2086
2116
  }, row.entry.provider);
2087
2117
  const open = !adding && editing?.provider === row.entry.provider;
2088
2118
  const adaptiveClaude = isClaudeProvider(row, state);
@@ -2090,73 +2120,81 @@ window.__ModuleLoader__.load({
2090
2120
  const credentialMissing = !credentialConfigured && row.apiKeyEnv !== void 0 && row.credential?.configured === false;
2091
2121
  return (0, react_jsx_runtime.jsxs)("li", {
2092
2122
  className: ModelsSection_module_css_default["rowCard"],
2093
- children: [(0, react_jsx_runtime.jsxs)("div", {
2094
- className: ModelsSection_module_css_default["rowHead"],
2095
- children: [(0, react_jsx_runtime.jsxs)("span", {
2096
- className: ModelsSection_module_css_default["rowIdentity"],
2097
- children: [
2098
- (0, react_jsx_runtime.jsx)("span", {
2099
- className: ModelsSection_module_css_default["rowName"],
2100
- children: row.entry.displayName
2101
- }),
2102
- row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
2103
- className: ModelsSection_module_css_default["rowTag"],
2104
- children: t("customTag")
2105
- }) : null,
2106
- adaptiveClaude ? (0, react_jsx_runtime.jsx)("span", {
2107
- className: ModelsSection_module_css_default["rowTag"],
2108
- children: t("claudeTypeTag")
2109
- }) : null,
2110
- credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2111
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2112
- role: "img",
2113
- "aria-label": t("credentialConfigured"),
2114
- title: t("credentialConfigured")
2115
- }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
2116
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
2117
- role: "img",
2118
- "aria-label": t("credentialMissing"),
2119
- title: t("credentialMissing")
2120
- }) : null
2121
- ]
2122
- }), (0, react_jsx_runtime.jsxs)("span", {
2123
- className: ModelsSection_module_css_default["rowActions"],
2124
- children: [(0, react_jsx_runtime.jsx)("button", {
2125
- type: "button",
2126
- className: ModelsSection_module_css_default["secondaryButton"],
2127
- "aria-label": providerCopy(t("editProvider"), target),
2128
- onClick: () => {
2129
- setSavedTarget(void 0);
2130
- setDeclaringType(void 0);
2131
- setAdding(false);
2132
- setEditing(open ? void 0 : target);
2133
- },
2134
- children: t("edit")
2135
- }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2136
- type: "button",
2137
- className: ModelsSection_module_css_default["dangerButton"],
2138
- "aria-label": providerCopy(t("removeProvider"), target),
2139
- disabled: !state.writable,
2140
- onClick: () => {
2141
- setSavedTarget(void 0);
2142
- setDeleteFailure(void 0);
2143
- setDeleteTarget(target);
2144
- },
2145
- children: t("remove")
2146
- }) : null]
2147
- })]
2148
- }), open ? renderProviderEditor({
2149
- target,
2150
- namespace,
2151
- schema,
2152
- thinkingPresets: isClaudeProvider(row, state),
2153
- api,
2154
- t,
2155
- readOnly: !state.writable,
2156
- onClose: (changed) => {
2157
- closeEditor(changed, target);
2158
- }
2159
- }) : null]
2123
+ children: [
2124
+ (0, react_jsx_runtime.jsxs)("div", {
2125
+ className: ModelsSection_module_css_default["rowHead"],
2126
+ children: [(0, react_jsx_runtime.jsxs)("span", {
2127
+ className: ModelsSection_module_css_default["rowIdentity"],
2128
+ children: [
2129
+ (0, react_jsx_runtime.jsx)("span", {
2130
+ className: ModelsSection_module_css_default["rowName"],
2131
+ children: row.entry.displayName
2132
+ }),
2133
+ row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
2134
+ className: ModelsSection_module_css_default["rowTag"],
2135
+ children: t("customTag")
2136
+ }) : null,
2137
+ adaptiveClaude ? (0, react_jsx_runtime.jsx)("span", {
2138
+ className: ModelsSection_module_css_default["rowTag"],
2139
+ children: t("claudeTypeTag")
2140
+ }) : null,
2141
+ credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2142
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2143
+ role: "img",
2144
+ "aria-label": t("credentialConfigured"),
2145
+ title: t("credentialConfigured")
2146
+ }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
2147
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
2148
+ role: "img",
2149
+ "aria-label": t("credentialMissing"),
2150
+ title: t("credentialMissing")
2151
+ }) : null
2152
+ ]
2153
+ }), (0, react_jsx_runtime.jsxs)("span", {
2154
+ className: ModelsSection_module_css_default["rowActions"],
2155
+ children: [(0, react_jsx_runtime.jsx)("button", {
2156
+ type: "button",
2157
+ className: ModelsSection_module_css_default["secondaryButton"],
2158
+ "aria-label": providerCopy(t("editProvider"), target),
2159
+ onClick: () => {
2160
+ setSavedTarget(void 0);
2161
+ setDeclaringType(void 0);
2162
+ setAdding(false);
2163
+ setEditing(open ? void 0 : target);
2164
+ },
2165
+ children: t("edit")
2166
+ }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2167
+ type: "button",
2168
+ className: ModelsSection_module_css_default["dangerButton"],
2169
+ "aria-label": providerCopy(t("removeProvider"), target),
2170
+ disabled: !state.writable,
2171
+ onClick: () => {
2172
+ setSavedTarget(void 0);
2173
+ setDeleteFailure(void 0);
2174
+ setDeleteTarget(target);
2175
+ },
2176
+ children: t("remove")
2177
+ }) : null]
2178
+ })]
2179
+ }),
2180
+ renderSlot("settings.models.provider-card", {
2181
+ provider: row.entry,
2182
+ configured: row.configured,
2183
+ keyConfigured: keyConfiguredOf(row)
2184
+ }, { entryKey: row.entry.settingsNs }),
2185
+ open ? renderProviderEditor({
2186
+ target,
2187
+ namespace,
2188
+ schema,
2189
+ thinkingPresets: isClaudeProvider(row, state),
2190
+ operations,
2191
+ t,
2192
+ readOnly: !state.writable,
2193
+ onClose: (changed) => {
2194
+ closeEditor(changed, target);
2195
+ }
2196
+ }) : null
2197
+ ]
2160
2198
  }, row.entry.provider);
2161
2199
  })
2162
2200
  }),
@@ -2164,40 +2202,48 @@ window.__ModuleLoader__.load({
2164
2202
  className: ModelsSection_module_css_default["addBlock"],
2165
2203
  children: addTarget !== void 0 && addNamespace !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2166
2204
  className: ModelsSection_module_css_default["addCard"],
2167
- children: [(0, react_jsx_runtime.jsxs)("div", {
2168
- className: ModelsSection_module_css_default["field"],
2169
- children: [(0, react_jsx_runtime.jsx)("span", {
2170
- className: ModelsSection_module_css_default["fieldLabel"],
2171
- children: t("provider")
2172
- }), (0, react_jsx_runtime.jsx)("select", {
2173
- className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2174
- value: addTarget.provider,
2175
- "aria-label": t("provider"),
2176
- onChange: (event) => {
2177
- const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2178
- /* v8 ignore next -- the select only lists addable rows */
2179
- if (row === void 0) return;
2180
- setEditing(targetOf(row));
2181
- },
2182
- children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2183
- value: row.entry.provider,
2184
- children: row.entry.displayName
2185
- }, row.entry.provider))
2186
- })]
2187
- }), (0, react_jsx_runtime.jsx)(ProviderEditor, {
2188
- provider: addTarget.provider,
2189
- displayName: addTarget.displayName,
2190
- hideTitle: true,
2191
- namespace: addNamespace,
2192
- schema,
2193
- settingsPath: addTarget.settingsPath,
2194
- api,
2195
- t,
2196
- readOnly: !state.writable,
2197
- onClose: (changed) => {
2198
- closeEditor(changed, addTarget);
2199
- }
2200
- }, addTarget.provider)]
2205
+ children: [
2206
+ (0, react_jsx_runtime.jsxs)("div", {
2207
+ className: ModelsSection_module_css_default["field"],
2208
+ children: [(0, react_jsx_runtime.jsx)("span", {
2209
+ className: ModelsSection_module_css_default["fieldLabel"],
2210
+ children: t("provider")
2211
+ }), (0, react_jsx_runtime.jsx)("select", {
2212
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2213
+ value: addTarget.provider,
2214
+ "aria-label": t("provider"),
2215
+ onChange: (event) => {
2216
+ const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2217
+ /* v8 ignore next -- the select only lists addable rows */
2218
+ if (row === void 0) return;
2219
+ setEditing(targetOf(row));
2220
+ },
2221
+ children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2222
+ value: row.entry.provider,
2223
+ children: row.entry.displayName
2224
+ }, row.entry.provider))
2225
+ })]
2226
+ }),
2227
+ (0, react_jsx_runtime.jsx)(ProviderEditor, {
2228
+ provider: addTarget.provider,
2229
+ displayName: addTarget.displayName,
2230
+ hideTitle: true,
2231
+ namespace: addNamespace,
2232
+ schema,
2233
+ settingsPath: addTarget.settingsPath,
2234
+ operations,
2235
+ t,
2236
+ readOnly: !state.writable,
2237
+ onClose: (changed) => {
2238
+ closeEditor(changed, addTarget);
2239
+ }
2240
+ }, addTarget.provider),
2241
+ addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2242
+ provider: addRow.entry,
2243
+ configured: addRow.configured,
2244
+ keyConfigured: keyConfiguredOf(addRow)
2245
+ }, { entryKey: addRow.entry.settingsNs })
2246
+ ]
2201
2247
  }) : declaringType !== void 0 ? (0, react_jsx_runtime.jsx)("div", {
2202
2248
  className: ModelsSection_module_css_default["addCard"],
2203
2249
  children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
@@ -2206,7 +2252,7 @@ window.__ModuleLoader__.load({
2206
2252
  providerType: declaringType,
2207
2253
  /* v8 ignore next -- the card only opens from a button disabled without this namespace */
2208
2254
  revision: state.namespaces.get("llm-pi-ai")?.revision ?? 0,
2209
- api,
2255
+ operations,
2210
2256
  t,
2211
2257
  readOnly: !state.writable,
2212
2258
  onClose: (changed) => {
@@ -2255,6 +2301,7 @@ window.__ModuleLoader__.load({
2255
2301
  })]
2256
2302
  })
2257
2303
  }),
2304
+ renderSlot("settings.models.footer", {}),
2258
2305
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
2259
2306
  open: deleteTarget !== void 0,
2260
2307
  onClose: closeDelete,
@@ -2380,7 +2427,7 @@ window.__ModuleLoader__.load({
2380
2427
  * @returns the onboarding modal or null when onboarding needs no intervention.
2381
2428
  */
2382
2429
  function DeepSeekOnboardingDialog(props) {
2383
- const { complete, controller, useModels, api, schema, t } = props;
2430
+ const { complete, controller, useModels, operations, schema, t } = props;
2384
2431
  const state = useModels((snapshot) => snapshot);
2385
2432
  const readiness = onboardingReadiness(state);
2386
2433
  (0, react.useEffect)(() => {
@@ -2422,16 +2469,16 @@ window.__ModuleLoader__.load({
2422
2469
  namespace,
2423
2470
  schema,
2424
2471
  settingsPath: row.entry.settingsPath,
2425
- api,
2472
+ operations,
2426
2473
  t,
2427
2474
  readOnly: false,
2428
2475
  hideTitle: true,
2429
2476
  credentialOnly: true,
2430
2477
  credentialRequired: true,
2431
2478
  autoFocusCredential: true,
2432
- cancelLabel: "onboardingLater",
2433
- submitLabel: "onboardingSave",
2434
- submitBusyLabel: "onboardingSaving",
2479
+ cancelLabelKey: "onboardingLater",
2480
+ submitLabelKey: "onboardingSave",
2481
+ submitBusyLabelKey: "onboardingSaving",
2435
2482
  onClose: finishCredential
2436
2483
  })
2437
2484
  })]
@@ -2521,19 +2568,6 @@ window.__ModuleLoader__.load({
2521
2568
  * again. The acknowledgement is compared for exact equality.
2522
2569
  */
2523
2570
  const WELCOME_NOTICE_VERSION = "2026-08-13.1";
2524
- /** The complete editable internal-testing notice in both supported GUI locales. */
2525
- const WELCOME_NOTICE_COPY = {
2526
- zh: {
2527
- title: "内测声明",
2528
- body: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2529
- continueLabel: "继续"
2530
- },
2531
- en: {
2532
- title: "Internal Testing Notice",
2533
- body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
2534
- continueLabel: "Continue"
2535
- }
2536
- };
2537
2571
  //#endregion
2538
2572
  //#region lib/types/client/welcome-store.js
2539
2573
  /**
@@ -2560,7 +2594,7 @@ window.__ModuleLoader__.load({
2560
2594
  var WelcomeNoticeStore = class {
2561
2595
  scope;
2562
2596
  /** uSES-safe state source shared by the registered welcome step. */
2563
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
2597
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
2564
2598
  status: "idle",
2565
2599
  acknowledged: false,
2566
2600
  error: null
@@ -2661,6 +2695,61 @@ window.__ModuleLoader__.load({
2661
2695
  }
2662
2696
  };
2663
2697
  //#endregion
2698
+ //#region lib/types/client/operations.js
2699
+ /**
2700
+ * The Host reads and writes the Models cards perform, as callbacks built in the
2701
+ * plugin body. Cards receive these instead of a context: the outcomes name what
2702
+ * a card renders — a stored view, a stale revision, a refusal message — so the
2703
+ * failure codes and Remote namespaces stay in the apply world.
2704
+ */
2705
+ /**
2706
+ * Bind the page's Host operations to the plugin's own Remote namespaces.
2707
+ * @param ctx - the page plugin's context, which declares `remote.credentials`,
2708
+ * `remote.llm`, and `remote.settings` in its own `inject`.
2709
+ * @returns the callbacks the section and its cards are injected with.
2710
+ */
2711
+ function createModelsOperations(ctx) {
2712
+ return {
2713
+ describeCredential: async (ref) => {
2714
+ const response = await ctx.remote.credentials.describe([ref]);
2715
+ return response.ok ? response.value[ref] : void 0;
2716
+ },
2717
+ storeCredential: async (ref, value) => {
2718
+ const response = await ctx.remote.credentials.set(ref, value);
2719
+ return response.ok ? void 0 : response.error.message;
2720
+ },
2721
+ removeCredential: async (ref) => {
2722
+ const response = await ctx.remote.credentials.unset(ref);
2723
+ return response.ok ? void 0 : response.error.message;
2724
+ },
2725
+ writeSettings: async (ns, ops, expectedRevision) => {
2726
+ const response = await ctx.remote.settings.mutate(ns, ops, expectedRevision);
2727
+ if (response.ok) return {
2728
+ kind: "written",
2729
+ view: response.value
2730
+ };
2731
+ const { code, message } = response.error;
2732
+ return code === "settings/conflict" ? {
2733
+ kind: "conflict",
2734
+ message
2735
+ } : {
2736
+ kind: "refused",
2737
+ message
2738
+ };
2739
+ },
2740
+ discoverModels: async (settingsNs, request) => {
2741
+ const response = await ctx.remote.llm.discoverModels(settingsNs, request);
2742
+ return response.ok ? {
2743
+ kind: "found",
2744
+ models: response.value
2745
+ } : {
2746
+ kind: "refused",
2747
+ message: response.error.message
2748
+ };
2749
+ }
2750
+ };
2751
+ }
2752
+ //#endregion
2664
2753
  //#region lib/types/client/schema-operations.js
2665
2754
  /**
2666
2755
  * Hide the Cordis service identity behind bound schema callbacks.
@@ -2779,11 +2868,13 @@ window.__ModuleLoader__.load({
2779
2868
  customApiUnset: "Not selected",
2780
2869
  customNeedsBaseUrl: "A custom provider needs a base URL.",
2781
2870
  customNeedsModels: "A custom provider needs at least one model.",
2871
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2872
+ settingsPathUnresolvable: "unresolvable settings path",
2782
2873
  create: "Create provider",
2783
2874
  creating: "Creating…",
2784
- welcomeTitle: WELCOME_NOTICE_COPY.en.title,
2785
- welcomeBody: WELCOME_NOTICE_COPY.en.body,
2786
- welcomeContinue: WELCOME_NOTICE_COPY.en.continueLabel,
2875
+ welcomeTitle: "Internal Testing Notice",
2876
+ welcomeBody: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
2877
+ welcomeContinue: "Continue",
2787
2878
  welcomeError: "The acknowledgement could not be saved. Please try again.",
2788
2879
  onboardingTitle: "Add an API key to get started",
2789
2880
  onboardingDescription: "Configure the official DeepSeek provider to start building.",
@@ -2890,11 +2981,13 @@ window.__ModuleLoader__.load({
2890
2981
  customApiUnset: "未选择",
2891
2982
  customNeedsBaseUrl: "自定义提供方需要填写 API 地址。",
2892
2983
  customNeedsModels: "自定义提供方至少需要一个模型。",
2984
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2985
+ settingsPathUnresolvable: "无法解析设置路径",
2893
2986
  create: "创建提供方",
2894
2987
  creating: "创建中…",
2895
- welcomeTitle: WELCOME_NOTICE_COPY.zh.title,
2896
- welcomeBody: WELCOME_NOTICE_COPY.zh.body,
2897
- welcomeContinue: WELCOME_NOTICE_COPY.zh.continueLabel,
2988
+ welcomeTitle: "内测声明",
2989
+ welcomeBody: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2990
+ welcomeContinue: "继续",
2898
2991
  welcomeError: "暂时无法保存确认状态,请重试。",
2899
2992
  onboardingTitle: "添加一个 API Key 开始使用",
2900
2993
  onboardingDescription: "配置 DeepSeek 官方模型,即可开始使用。",
@@ -2924,8 +3017,10 @@ window.__ModuleLoader__.load({
2924
3017
  const inject = [
2925
3018
  "slots",
2926
3019
  "locale",
2927
- "connection",
2928
3020
  "remote",
3021
+ "remote.credentials",
3022
+ "remote.llm",
3023
+ "remote.settings",
2929
3024
  "settingsScope",
2930
3025
  "settingsSchema"
2931
3026
  ];
@@ -2940,21 +3035,21 @@ window.__ModuleLoader__.load({
2940
3035
  zh,
2941
3036
  en
2942
3037
  }), "ui-settings-models: copy dictionaries");
2943
- const connection = ctx.get("connection");
2944
3038
  const schema = createSettingsSchemaOperations(ctx.settingsSchema);
2945
- const controller = new ModelsSettingsStore(connection.api, schema, ctx.settingsScope.describe());
3039
+ const operations = createModelsOperations(ctx);
3040
+ const controller = new ModelsSettingsStore(ctx, schema, ctx.settingsScope.describe());
2946
3041
  const t = ctx.locale.bind(NS);
2947
3042
  const injected = () => ({
2948
3043
  controller,
2949
3044
  hooks: { snapshot: controller.store },
2950
- api: connection.api,
3045
+ operations,
2951
3046
  schema,
2952
3047
  t
2953
3048
  });
2954
3049
  const deepSeekOnboardingInjected = () => ({
2955
3050
  controller,
2956
3051
  hooks: { models: controller.store },
2957
- api: connection.api,
3052
+ operations,
2958
3053
  schema,
2959
3054
  t
2960
3055
  });
@@ -2975,6 +3070,7 @@ window.__ModuleLoader__.load({
2975
3070
  ctx.remote.$on("settings/document-updated", () => {
2976
3071
  refreshModels();
2977
3072
  }),
3073
+ ctx.remote.$on("credentials/reference-updated", refreshModels),
2978
3074
  ctx.remote.$on("credentials/updated", refreshModels),
2979
3075
  ctx.remote.$on("llm/adapters-updated", refreshModels),
2980
3076
  ctx.on("connection/reset", refreshModels)
@@ -2989,7 +3085,17 @@ window.__ModuleLoader__.load({
2989
3085
  id: "models",
2990
3086
  order: 10,
2991
3087
  label: () => t("nav"),
2992
- inject: injected
3088
+ inject: injected,
3089
+ children: {
3090
+ "settings.models.provider-card": {
3091
+ kind: "keyed",
3092
+ scope: "root"
3093
+ },
3094
+ "settings.models.footer": {
3095
+ kind: "list",
3096
+ scope: "root"
3097
+ }
3098
+ }
2993
3099
  }, ModelsSection));
2994
3100
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
2995
3101
  name: "settings.onboarding",