@deepseek-ai/dsh-client-ui-settings-models 0.1.6-alpha.2 → 0.1.7-alpha.2

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
@@ -55,7 +55,7 @@ window.__ModuleLoader__.load({
55
55
  }
56
56
  //#endregion
57
57
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/ModelsSection.module.css.mjs
58
- 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:.5px solid var(--dsw-alias-border-l4);border-radius:16px;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:.5px 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;corner-shape:round;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:.5px solid var(--dsw-alias-border-l3);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:16px;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:.5px 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:.5px 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:.5px solid var(--dsw-alias-border-l4);border-radius:10px;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(2,minmax(0,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;min-width:0;display:flex}.zGbnIq_modelInputTypes{border:none;grid-column:1/-1;min-width:0;margin:0;padding:0}.zGbnIq_modelInputTypes legend{margin-bottom:4px;padding:0}.zGbnIq_modelInputChoices{flex-wrap:wrap;align-items:center;gap:16px;min-height:32px;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:.5px solid var(--dsw-alias-border-l3);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:.5px solid var(--dsw-alias-border-l4);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_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.zGbnIq_candidateSearch{flex:240px;min-width:0}.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}.zGbnIq_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}";
58
+ 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:.5px solid var(--dsw-alias-border-l4);border-radius:16px;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:.5px 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;corner-shape:round;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:.5px solid var(--dsw-alias-border-l3);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{display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addModes{flex-direction:column;align-items:flex-start;gap:8px;display:flex}.zGbnIq_addPanel{flex-direction:column;gap:14px;display:flex}.zGbnIq_addPanel[hidden]{display:none}.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:.5px 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:.5px 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:.5px solid var(--dsw-alias-border-l4);border-radius:10px;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(2,minmax(0,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;min-width:0;display:flex}.zGbnIq_modelInputTypes{border:none;grid-column:1/-1;min-width:0;margin:0;padding:0}.zGbnIq_modelInputTypes legend{margin-bottom:4px;padding:0}.zGbnIq_modelInputChoices{flex-wrap:wrap;align-items:center;gap:16px;min-height:32px;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:.5px solid var(--dsw-alias-border-l3);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:.5px solid var(--dsw-alias-border-l4);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_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.zGbnIq_candidateSearch{flex:240px;min-width:0}.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_candidateName{text-overflow:ellipsis;white-space:nowrap;flex:auto;min-width:0;font-size:13px;overflow:hidden}.zGbnIq_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}";
59
59
  const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-models/ModelsSection.module.css";
60
60
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
61
61
  const tag = document.createElement("style");
@@ -70,12 +70,14 @@ window.__ModuleLoader__.load({
70
70
  "addButton": "zGbnIq_addButton",
71
71
  "addCard": "zGbnIq_addCard",
72
72
  "addModelButton": "zGbnIq_addModelButton",
73
+ "addModes": "zGbnIq_addModes",
74
+ "addPanel": "zGbnIq_addPanel",
73
75
  "advancedHint": "zGbnIq_advancedHint",
74
76
  "candidate": "zGbnIq_candidate",
75
77
  "candidateEmpty": "zGbnIq_candidateEmpty",
76
- "candidateId": "zGbnIq_candidateId",
77
78
  "candidateLabel": "zGbnIq_candidateLabel",
78
79
  "candidateList": "zGbnIq_candidateList",
80
+ "candidateName": "zGbnIq_candidateName",
79
81
  "candidateSearch": "zGbnIq_candidateSearch",
80
82
  "candidateToolbar": "zGbnIq_candidateToolbar",
81
83
  "credentialDot": "zGbnIq_credentialDot",
@@ -231,7 +233,7 @@ window.__ModuleLoader__.load({
231
233
  "aria-expanded": props.expanded,
232
234
  title: t("modelAdvanced"),
233
235
  onClick: props.onToggle,
234
- children: props.expanded ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutline14, {})
236
+ children: props.expanded ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, {}) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineRegular, {})
235
237
  }),
236
238
  (0, react_jsx_runtime.jsx)("button", {
237
239
  type: "button",
@@ -240,7 +242,7 @@ window.__ModuleLoader__.load({
240
242
  title: t("removeModel"),
241
243
  disabled,
242
244
  onClick: props.onRemove,
243
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 14 })
245
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: 14 })
244
246
  })
245
247
  ]
246
248
  }), props.expanded ? (0, react_jsx_runtime.jsxs)("div", {
@@ -511,7 +513,7 @@ window.__ModuleLoader__.load({
511
513
  onClick: () => {
512
514
  props.onChange([...props.models.map((model) => ({ ...model })), { id: "" }]);
513
515
  },
514
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), props.t("addModel")]
516
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), props.t("addModel")]
515
517
  })
516
518
  ]
517
519
  });
@@ -584,9 +586,12 @@ window.__ModuleLoader__.load({
584
586
  * @returns the model-list editor.
585
587
  */
586
588
  function ModelListEditor(props) {
587
- const { models, onChange, probe, operations, t, disabled } = props;
589
+ const { models, onChange, probe, operations, t, disabled, onBusyChange } = props;
588
590
  const { catalogProvider } = props;
589
591
  const [busy, setBusy] = (0, react.useState)(false);
592
+ (0, react.useEffect)(() => {
593
+ onBusyChange(busy);
594
+ }, [busy, onBusyChange]);
590
595
  const [failure, setFailure] = (0, react.useState)(void 0);
591
596
  const [inheritedCatalog, setInheritedCatalog] = (0, react.useState)(void 0);
592
597
  (0, react.useEffect)(() => {
@@ -810,7 +815,7 @@ window.__ModuleLoader__.load({
810
815
  onClick: () => {
811
816
  onChange([...models, { id: "" }]);
812
817
  },
813
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), t("addModel")]
818
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), t("addModel")]
814
819
  }),
815
820
  failure !== void 0 ? (0, react_jsx_runtime.jsx)("p", {
816
821
  className: ModelsSection_module_css_default["error"],
@@ -867,8 +872,9 @@ window.__ModuleLoader__.load({
867
872
  toggle(candidate.id);
868
873
  }
869
874
  }), (0, react_jsx_runtime.jsx)("span", {
870
- className: ModelsSection_module_css_default["candidateId"],
871
- children: candidate.id
875
+ className: ModelsSection_module_css_default["candidateName"],
876
+ title: candidate.name ?? candidate.id,
877
+ children: candidate.name ?? candidate.id
872
878
  })]
873
879
  })
874
880
  }, candidate.id))
@@ -1120,18 +1126,46 @@ window.__ModuleLoader__.load({
1120
1126
  return { kind: "credential-missing" };
1121
1127
  }
1122
1128
  //#endregion
1129
+ //#region lib/types/client/protocol-label.js
1130
+ /**
1131
+ * Product names for the wire protocols a pi-ai route may speak. The pickers
1132
+ * show these instead of the schema identifiers (`openai-completions`), which
1133
+ * are what `settings.yaml` carries and what the option values stay.
1134
+ */
1135
+ /** The protocols this page names, keyed by their schema identifier. */
1136
+ const PROTOCOL_LABEL_KEYS = {
1137
+ "openai-completions": "protocolOpenAiCompletions",
1138
+ "openai-responses": "protocolOpenAiResponses",
1139
+ "anthropic-messages": "protocolAnthropicMessages"
1140
+ };
1141
+ /**
1142
+ * The picker text for one protocol identifier.
1143
+ * @param t - section copy.
1144
+ * @param protocol - the schema identifier of the protocol.
1145
+ * @returns the product name this page knows the protocol by; a protocol the
1146
+ * adapter adds before this page names it shows its identifier, the spelling
1147
+ * `settings.yaml` needs anyway.
1148
+ */
1149
+ function protocolLabel(t, protocol) {
1150
+ const key = PROTOCOL_LABEL_KEYS[protocol];
1151
+ return key === void 0 ? protocol : t(key);
1152
+ }
1153
+ //#endregion
1123
1154
  //#region lib/types/client/CustomProviderCard.js
1124
1155
  /**
1125
1156
  * The card that declares a provider pi-ai does not ship — an OpenAI-compatible
1126
1157
  * gateway, a self-hosted server, or a provider newer than the installed
1127
1158
  * catalog.
1128
1159
  *
1129
- * This is a create, not an edit, which is why it is its own card rather than
1160
+ * This is a create, not an edit, which is why it is its own form rather than
1130
1161
  * the provider editor with extra fields: the route id is being *chosen* here,
1131
- * and the settings address does not exist until it is. One `settings.mutate`
1132
- * sets the whole profile at `providers.<route>`; the key travels separately
1133
- * through `credentials/set` under the reference the profile records, exactly as
1134
- * an existing provider's key does.
1162
+ * and the settings address does not exist until it is. It renders as the
1163
+ * custom-API panel of the section's add card; the card's mode switch names it
1164
+ * when both modes are offered, and with the custom mode alone the card shows
1165
+ * this form directly. One `settings.mutate` sets the whole profile at
1166
+ * `providers.<route>`; the key travels separately through `credentials/set`
1167
+ * under the reference the profile records, exactly as an existing provider's
1168
+ * key does.
1135
1169
  *
1136
1170
  * The three fields a hand-declared route cannot default — endpoint, protocol,
1137
1171
  * and at least one model — are required here rather than at load, so the
@@ -1168,7 +1202,7 @@ window.__ModuleLoader__.load({
1168
1202
  * @returns the creation card.
1169
1203
  */
1170
1204
  function CustomProviderCard(props) {
1171
- const { taken, protocols, operations, t } = props;
1205
+ const { taken, protocols, operations, t, onBusyChange } = props;
1172
1206
  const [openedAt] = (0, react.useState)(() => props.revision);
1173
1207
  const [route, setRoute] = (0, react.useState)("");
1174
1208
  const [displayName, setDisplayName] = (0, react.useState)("");
@@ -1177,6 +1211,14 @@ window.__ModuleLoader__.load({
1177
1211
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1178
1212
  const [models, setModels] = (0, react.useState)([]);
1179
1213
  const [busy, setBusy] = (0, react.useState)(false);
1214
+ const [listBusy, setListBusy] = (0, react.useState)(false);
1215
+ (0, react.useEffect)(() => {
1216
+ onBusyChange?.(busy || listBusy);
1217
+ }, [
1218
+ busy,
1219
+ listBusy,
1220
+ onBusyChange
1221
+ ]);
1180
1222
  const [failure, setFailure] = (0, react.useState)(void 0);
1181
1223
  /**
1182
1224
  * The profile write landed. Only the key write can still be outstanding, so
@@ -1238,13 +1280,6 @@ window.__ModuleLoader__.load({
1238
1280
  return (0, react_jsx_runtime.jsxs)("div", {
1239
1281
  className: ModelsSection_module_css_default["editor"],
1240
1282
  children: [
1241
- (0, react_jsx_runtime.jsx)("div", {
1242
- className: ModelsSection_module_css_default["editorHeader"],
1243
- children: (0, react_jsx_runtime.jsx)("span", {
1244
- className: ModelsSection_module_css_default["editorTitle"],
1245
- children: t("customTitle")
1246
- })
1247
- }),
1248
1283
  (0, react_jsx_runtime.jsxs)("div", {
1249
1284
  className: ModelsSection_module_css_default["field"],
1250
1285
  children: [(0, react_jsx_runtime.jsx)("span", {
@@ -1295,7 +1330,7 @@ window.__ModuleLoader__.load({
1295
1330
  className: ModelsSection_module_css_default["input"],
1296
1331
  type: "text",
1297
1332
  value: baseURL,
1298
- placeholder: t("customBaseUrlPlaceholder"),
1333
+ placeholder: t(protocol === "anthropic-messages" ? "customAnthropicBaseUrlPlaceholder" : "customBaseUrlPlaceholder"),
1299
1334
  "aria-label": t("baseUrl"),
1300
1335
  "aria-invalid": baseUrlInvalid,
1301
1336
  disabled: profileDisabled,
@@ -1323,7 +1358,7 @@ window.__ModuleLoader__.load({
1323
1358
  },
1324
1359
  children: protocols.map((choice) => (0, react_jsx_runtime.jsx)("option", {
1325
1360
  value: choice,
1326
- children: choice
1361
+ children: protocolLabel(t, choice)
1327
1362
  }, choice))
1328
1363
  })]
1329
1364
  }),
@@ -1364,7 +1399,8 @@ window.__ModuleLoader__.load({
1364
1399
  probeBlocked: baseUrlInvalid ? "customBaseUrlInvalid" : keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
1365
1400
  operations,
1366
1401
  t,
1367
- disabled: profileDisabled
1402
+ disabled: profileDisabled,
1403
+ onBusyChange: setListBusy
1368
1404
  }),
1369
1405
  failure !== void 0 ? (0, react_jsx_runtime.jsx)("p", {
1370
1406
  className: ModelsSection_module_css_default["error"],
@@ -1408,9 +1444,9 @@ window.__ModuleLoader__.load({
1408
1444
  * Reasoning effort is deliberately absent: it is a per-MODEL capability, and
1409
1445
  * the models under one provider disagree about it, so a provider-scoped
1410
1446
  * control can only be set to a value some of them reject. The composer's
1411
- * model picker offers each model its own levels; `settings.yaml` keeps the
1447
+ * model picker offers each model its own levels; `cordis.patch.yml` keeps the
1412
1448
  * profile field for a deployment that knows its route. Everything else stays
1413
- * owned by `settings.yaml`. Profile edits land as minimal `settings.mutate`
1449
+ * owned by `cordis.patch.yml`. Profile edits land as minimal `settings.mutate`
1414
1450
  * path ops against the stored section — the card names only the fields it can
1415
1451
  * see instead of rebuilding the whole subtree from a partial descriptor.
1416
1452
  */
@@ -1470,6 +1506,15 @@ window.__ModuleLoader__.load({
1470
1506
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1471
1507
  const [keyState, setKeyState] = (0, react.useState)(void 0);
1472
1508
  const [busy, setBusy] = (0, react.useState)(false);
1509
+ const [listBusy, setListBusy] = (0, react.useState)(false);
1510
+ const { onBusyChange } = props;
1511
+ (0, react.useEffect)(() => {
1512
+ onBusyChange?.(busy || listBusy);
1513
+ }, [
1514
+ busy,
1515
+ listBusy,
1516
+ onBusyChange
1517
+ ]);
1473
1518
  const [failure, setFailure] = (0, react.useState)(void 0);
1474
1519
  const [committedOriginal, setCommittedOriginal] = (0, react.useState)(() => schema.getPath(namespace.user, settingsPath));
1475
1520
  const [expectedRevision, setExpectedRevision] = (0, react.useState)(() => namespace.revision);
@@ -1681,7 +1726,7 @@ window.__ModuleLoader__.load({
1681
1726
  className: ModelsSection_module_css_default["input"],
1682
1727
  type: "text",
1683
1728
  value: stringAt(draft, "baseURL") ?? "",
1684
- placeholder: family === "deepseek" ? t(stringAt(fallback, "protocol") === "messages" ? "deepSeekMessagesBaseUrl" : "deepSeekChatBaseUrl") : stringAt(fallback, "baseURL") ?? t("baseUrlDefault"),
1729
+ placeholder: family === "deepseek" ? t("deepSeekBaseUrl") : stringAt(fallback, "baseURL") ?? t("baseUrlDefault"),
1685
1730
  "aria-describedby": family === "deepseek" ? `${props.provider}-endpoint-hint` : void 0,
1686
1731
  "aria-label": t("baseUrl"),
1687
1732
  disabled,
@@ -1714,7 +1759,7 @@ window.__ModuleLoader__.load({
1714
1759
  children: t("customApiUnset")
1715
1760
  }) : null, protocols.map((choice) => (0, react_jsx_runtime.jsx)("option", {
1716
1761
  value: choice,
1717
- children: choice
1762
+ children: protocolLabel(t, choice)
1718
1763
  }, choice))]
1719
1764
  })]
1720
1765
  }) : null,
@@ -1728,7 +1773,8 @@ window.__ModuleLoader__.load({
1728
1773
  defaultInput: Array.isArray(defaultInput) ? defaultInput : void 0,
1729
1774
  probe,
1730
1775
  probeBlocked: keyFailure,
1731
- operations
1776
+ operations,
1777
+ onBusyChange: setListBusy
1732
1778
  })
1733
1779
  ]
1734
1780
  })]
@@ -1785,11 +1831,19 @@ window.__ModuleLoader__.load({
1785
1831
  * solid configured or missing dots. A whole-section provider without a
1786
1832
  * configured key renders as its open setup card instead of a row, but only in
1787
1833
  * the first-run posture — no provider on the page can serve requests yet — and
1788
- * only until the user closes that card; the add flow is a card carrying the
1789
- * dormant-provider select. Each card kind owns its own open state, so closing
1790
- * one never discards a draft in another. Every mutation writes through the
1791
- * wire, while a provider removal first requires confirmation; the page
1792
- * re-renders from pushed invalidations or the post-apply reload.
1834
+ * only until the user closes that card. The add flow is one card behind one
1835
+ * button: a mode switch chooses between adopting a dormant directory provider
1836
+ * (the catalog select over the provider editor) and declaring a custom model
1837
+ * API (the create form). A panel mounts the first time its mode is shown and
1838
+ * stays mounted, hidden, while the card is open and its mode stays offered,
1839
+ * so switching modes discards neither draft and an unvisited mode costs
1840
+ * nothing; the switch holds still while either panel has a write or an
1841
+ * endpoint interrogation in flight, since a switch underneath one would
1842
+ * orphan the answer. Each card kind owns its own open state, so closing one
1843
+ * never discards a draft in another. Every
1844
+ * mutation writes through the wire, while a provider removal first requires
1845
+ * confirmation; the page re-renders from pushed invalidations or the
1846
+ * post-apply reload.
1793
1847
  */
1794
1848
  /** Render an editor for either the setup posture or an expanded provider row. */
1795
1849
  function renderProviderEditor({ target, ...props }) {
@@ -1891,30 +1945,48 @@ window.__ModuleLoader__.load({
1891
1945
  const { controller, operations, schema, t } = injected;
1892
1946
  const state = injected.useSnapshot((snapshot) => snapshot);
1893
1947
  const [editing, setEditing] = (0, react.useState)(void 0);
1894
- const [adding, setAdding] = (0, react.useState)(false);
1948
+ const [addOpen, setAddOpen] = (0, react.useState)(false);
1949
+ const [addMode, setAddMode] = (0, react.useState)("catalog");
1950
+ /** The modes shown since the add card opened; each keeps its panel mounted. */
1951
+ const [visited, setVisited] = (0, react.useState)(() => /* @__PURE__ */ new Set());
1952
+ /** Whether each add panel has a write or an interrogation in flight. */
1953
+ const [catalogBusy, setCatalogBusy] = (0, react.useState)(false);
1954
+ const [customBusy, setCustomBusy] = (0, react.useState)(false);
1955
+ /** Base of the add card's tab and panel ids. */
1956
+ const addId = (0, react.useId)();
1895
1957
  const [deleteTarget, setDeleteTarget] = (0, react.useState)(void 0);
1896
1958
  const [deleting, setDeleting] = (0, react.useState)(false);
1897
1959
  const [deleteFailure, setDeleteFailure] = (0, react.useState)(void 0);
1898
1960
  const [savedTarget, setSavedTarget] = (0, react.useState)(void 0);
1899
- const [declaring, setDeclaring] = (0, react.useState)(false);
1900
1961
  const [dismissedSetup, setDismissedSetup] = (0, react.useState)(() => /* @__PURE__ */ new Set());
1901
1962
  const announceSaved = (target) => {
1902
1963
  controller.load().then(() => {
1903
1964
  setSavedTarget(target);
1904
1965
  });
1905
1966
  };
1906
- const closeEditor = (changed, target) => {
1967
+ /**
1968
+ * Close the add card whole. The catalog target is forgotten with it, since
1969
+ * `editing` doubles as the row editor's target once the card is closed and a
1970
+ * refresh could otherwise open the row of a provider the draft never saved.
1971
+ * The busy flags reset here because a panel that closes itself on success
1972
+ * unmounts before it can report idle.
1973
+ */
1974
+ const closeAdd = () => {
1907
1975
  setEditing(void 0);
1908
- setAdding(false);
1909
- setDeclaring(false);
1976
+ setAddOpen(false);
1977
+ setCatalogBusy(false);
1978
+ setCustomBusy(false);
1979
+ };
1980
+ const closeEditor = (changed, target) => {
1981
+ closeAdd();
1910
1982
  if (changed) announceSaved(target);
1911
1983
  };
1912
1984
  /**
1913
- * Close a setup card, which owns none of the state above: the row-editor,
1914
- * add, and declare cards each own one of those, so clearing them here would
1915
- * discard a draft the user opened beside this card. Dismissal is this card's
1916
- * own — the provider falls back to an ordinary row for the rest of the
1917
- * session, and reopens through Edit.
1985
+ * Close a setup card, which owns none of the state above: the row-editor
1986
+ * and add cards each own one of those, so clearing them here would discard
1987
+ * a draft the user opened beside this card. Dismissal is this card's own —
1988
+ * the provider falls back to an ordinary row for the rest of the session,
1989
+ * and reopens through Edit.
1918
1990
  */
1919
1991
  const closeSetup = (changed, target) => {
1920
1992
  setDismissedSetup((previous) => new Set([...previous, target.provider]));
@@ -1967,11 +2039,37 @@ window.__ModuleLoader__.load({
1967
2039
  const anyUsable = state.rows.some(providerUsable);
1968
2040
  const configured = state.rows.filter((row) => row.configured);
1969
2041
  const configurable = state.rows.filter((row) => state.namespaces.has(row.entry.settingsNs));
1970
- const addable = configurable.filter((row) => !row.configured);
1971
- const addTarget = adding ? editing : void 0;
1972
- const addNamespace = addTarget === void 0 ? void 0 : state.namespaces.get(addTarget.settingsNs);
1973
- const addRow = addTarget === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === addTarget.provider);
1974
- const protocols = protocolChoices(state.namespaces.get("llm-pi-ai"), schema);
2042
+ const addable = state.rows.flatMap((row) => {
2043
+ const namespace = state.namespaces.get(row.entry.settingsNs);
2044
+ return namespace === void 0 || row.configured ? [] : [{
2045
+ row,
2046
+ namespace
2047
+ }];
2048
+ });
2049
+ const piAi = state.namespaces.get("llm-pi-ai");
2050
+ const protocols = protocolChoices(piAi, schema);
2051
+ const catalogOffered = configurable.length > 0;
2052
+ const catalogEnabled = addable.length > 0;
2053
+ const customOffered = piAi !== void 0;
2054
+ const customEnabled = protocols.length > 0;
2055
+ const bothOffered = catalogOffered && customOffered;
2056
+ const mode = bothOffered ? addMode : customOffered ? "custom" : "catalog";
2057
+ const mounted = (candidate) => mode === candidate || visited.has(candidate);
2058
+ const switchLocked = catalogBusy || customBusy;
2059
+ const draft = (() => {
2060
+ if (!addOpen || !catalogOffered) return void 0;
2061
+ const kept = editing === void 0 ? void 0 : state.namespaces.get(editing.settingsNs);
2062
+ if (editing !== void 0 && kept !== void 0) return {
2063
+ target: editing,
2064
+ namespace: kept
2065
+ };
2066
+ const first = addable[0];
2067
+ return first === void 0 ? void 0 : {
2068
+ target: targetOf(first.row),
2069
+ namespace: first.namespace
2070
+ };
2071
+ })();
2072
+ const addRow = draft === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === draft.target.provider);
1975
2073
  return (0, react_jsx_runtime.jsxs)("div", {
1976
2074
  className: ModelsSection_module_css_default["section"],
1977
2075
  children: [
@@ -2027,7 +2125,7 @@ window.__ModuleLoader__.load({
2027
2125
  }, { entryKey: row.entry.settingsNs })
2028
2126
  ]
2029
2127
  }, row.entry.provider);
2030
- const open = !adding && editing?.provider === row.entry.provider;
2128
+ const open = !addOpen && editing?.provider === row.entry.provider;
2031
2129
  const credentialConfigured = row.credential?.configured === true;
2032
2130
  const credentialMissing = !credentialConfigured && row.apiKeyEnv !== void 0 && row.credential?.configured === false;
2033
2131
  return (0, react_jsx_runtime.jsxs)("li", {
@@ -2066,8 +2164,7 @@ window.__ModuleLoader__.load({
2066
2164
  "aria-label": providerCopy(t("editProvider"), target),
2067
2165
  onClick: () => {
2068
2166
  setSavedTarget(void 0);
2069
- setDeclaring(false);
2070
- setAdding(false);
2167
+ setAddOpen(false);
2071
2168
  setEditing(open ? void 0 : target);
2072
2169
  },
2073
2170
  children: t("edit")
@@ -2108,94 +2205,136 @@ window.__ModuleLoader__.load({
2108
2205
  }),
2109
2206
  (0, react_jsx_runtime.jsx)("div", {
2110
2207
  className: ModelsSection_module_css_default["addBlock"],
2111
- children: addTarget !== void 0 && addNamespace !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2208
+ children: addOpen ? (0, react_jsx_runtime.jsxs)("div", {
2112
2209
  className: ModelsSection_module_css_default["addCard"],
2113
2210
  children: [
2114
2211
  (0, react_jsx_runtime.jsxs)("div", {
2115
- className: ModelsSection_module_css_default["field"],
2116
- children: [(0, react_jsx_runtime.jsx)("span", {
2117
- className: ModelsSection_module_css_default["fieldLabel"],
2118
- children: t("provider")
2119
- }), (0, react_jsx_runtime.jsx)("select", {
2120
- className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2121
- value: addTarget.provider,
2122
- "aria-label": t("provider"),
2123
- onChange: (event) => {
2124
- const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2125
- /* v8 ignore next -- the select only lists addable rows */
2126
- if (row === void 0) return;
2127
- setEditing(targetOf(row));
2128
- },
2129
- children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2130
- value: row.entry.provider,
2131
- children: row.entry.displayName
2132
- }, row.entry.provider))
2212
+ className: ModelsSection_module_css_default["addModes"],
2213
+ children: [bothOffered ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
2214
+ id: addId,
2215
+ label: t("addMode"),
2216
+ value: mode,
2217
+ disabled: switchLocked,
2218
+ options: [{
2219
+ value: "catalog",
2220
+ label: t("addCatalog"),
2221
+ disabled: !catalogEnabled,
2222
+ ...catalogEnabled ? {} : { title: t("addCatalogExhausted") }
2223
+ }, {
2224
+ value: "custom",
2225
+ label: t("addCustom"),
2226
+ disabled: !customEnabled,
2227
+ ...customEnabled ? {} : { title: t("addCustomUnavailable") }
2228
+ }],
2229
+ onChange: (next) => {
2230
+ setAddMode(next);
2231
+ setVisited((previous) => new Set([...previous, next]));
2232
+ }
2233
+ }) : (0, react_jsx_runtime.jsx)("div", {
2234
+ className: ModelsSection_module_css_default["editorHeader"],
2235
+ children: (0, react_jsx_runtime.jsx)("span", {
2236
+ className: ModelsSection_module_css_default["editorTitle"],
2237
+ children: t(mode === "catalog" ? "addCatalog" : "addCustom")
2238
+ })
2239
+ }), (0, react_jsx_runtime.jsx)("p", {
2240
+ className: ModelsSection_module_css_default["advancedHint"],
2241
+ children: t(mode === "catalog" ? "addCatalogHint" : "addCustomHint")
2133
2242
  })]
2134
2243
  }),
2135
- (0, react_jsx_runtime.jsx)(ProviderEditor, {
2136
- provider: addTarget.provider,
2137
- displayName: addTarget.displayName,
2138
- hideTitle: true,
2139
- namespace: addNamespace,
2140
- schema,
2141
- settingsPath: addTarget.settingsPath,
2142
- operations,
2143
- t,
2144
- readOnly: !state.writable,
2145
- onClose: (changed) => {
2146
- closeEditor(changed, addTarget);
2147
- }
2148
- }, addTarget.provider),
2149
- addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2150
- provider: addRow.entry,
2151
- configured: addRow.configured,
2152
- keyConfigured: keyConfiguredOf(addRow)
2153
- }, { entryKey: addRow.entry.settingsNs })
2244
+ mounted("catalog") && draft !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2245
+ id: `${addId}-catalog-panel`,
2246
+ ...bothOffered ? {
2247
+ role: "tabpanel",
2248
+ "aria-labelledby": `${addId}-catalog`
2249
+ } : {},
2250
+ hidden: mode !== "catalog",
2251
+ className: ModelsSection_module_css_default["addPanel"],
2252
+ children: [
2253
+ (0, react_jsx_runtime.jsxs)("div", {
2254
+ className: ModelsSection_module_css_default["field"],
2255
+ children: [(0, react_jsx_runtime.jsx)("span", {
2256
+ className: ModelsSection_module_css_default["fieldLabel"],
2257
+ children: t("provider")
2258
+ }), (0, react_jsx_runtime.jsx)("select", {
2259
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2260
+ value: draft.target.provider,
2261
+ "aria-label": t("provider"),
2262
+ disabled: catalogBusy,
2263
+ onChange: (event) => {
2264
+ const picked = addable.find((candidate) => candidate.row.entry.provider === event.target.value);
2265
+ /* v8 ignore next -- the select only lists addable rows */
2266
+ if (picked === void 0) return;
2267
+ setEditing(targetOf(picked.row));
2268
+ },
2269
+ children: addable.map(({ row }) => (0, react_jsx_runtime.jsx)("option", {
2270
+ value: row.entry.provider,
2271
+ children: row.entry.displayName
2272
+ }, row.entry.provider))
2273
+ })]
2274
+ }),
2275
+ (0, react_jsx_runtime.jsx)(ProviderEditor, {
2276
+ provider: draft.target.provider,
2277
+ displayName: draft.target.displayName,
2278
+ hideTitle: true,
2279
+ namespace: draft.namespace,
2280
+ schema,
2281
+ settingsPath: draft.target.settingsPath,
2282
+ operations,
2283
+ t,
2284
+ readOnly: !state.writable,
2285
+ onClose: (changed) => {
2286
+ closeEditor(changed, draft.target);
2287
+ },
2288
+ onBusyChange: setCatalogBusy
2289
+ }, draft.target.provider),
2290
+ addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2291
+ provider: addRow.entry,
2292
+ configured: addRow.configured,
2293
+ keyConfigured: keyConfiguredOf(addRow)
2294
+ }, { entryKey: addRow.entry.settingsNs })
2295
+ ]
2296
+ }) : null,
2297
+ mounted("custom") && piAi !== void 0 ? (0, react_jsx_runtime.jsx)("div", {
2298
+ id: `${addId}-custom-panel`,
2299
+ ...bothOffered ? {
2300
+ role: "tabpanel",
2301
+ "aria-labelledby": `${addId}-custom`
2302
+ } : {},
2303
+ hidden: mode !== "custom",
2304
+ className: ModelsSection_module_css_default["addPanel"],
2305
+ children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
2306
+ taken: state.rows.map((row) => row.entry.provider),
2307
+ protocols,
2308
+ revision: piAi.revision,
2309
+ operations,
2310
+ t,
2311
+ readOnly: !state.writable,
2312
+ onClose: (changed) => {
2313
+ closeAdd();
2314
+ if (changed) controller.load();
2315
+ },
2316
+ onBusyChange: setCustomBusy
2317
+ })
2318
+ }) : null
2154
2319
  ]
2155
- }) : declaring ? (0, react_jsx_runtime.jsx)("div", {
2156
- className: ModelsSection_module_css_default["addCard"],
2157
- children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
2158
- taken: state.rows.map((row) => row.entry.provider),
2159
- protocols,
2160
- /* v8 ignore next -- the card only opens from a button disabled without this namespace */
2161
- revision: state.namespaces.get("llm-pi-ai")?.revision ?? 0,
2162
- operations,
2163
- t,
2164
- readOnly: !state.writable,
2165
- onClose: (changed) => {
2166
- setDeclaring(false);
2167
- if (changed) controller.load();
2168
- }
2169
- })
2170
- }) : (0, react_jsx_runtime.jsxs)("div", {
2320
+ }) : catalogOffered || customOffered ? (0, react_jsx_runtime.jsx)("div", {
2171
2321
  className: ModelsSection_module_css_default["addActions"],
2172
- children: [configurable.length > 0 && (0, react_jsx_runtime.jsxs)("button", {
2322
+ children: (0, react_jsx_runtime.jsxs)("button", {
2173
2323
  type: "button",
2174
2324
  className: ModelsSection_module_css_default["addButton"],
2175
- disabled: addable.length === 0 || !state.writable,
2325
+ disabled: !state.writable || !catalogEnabled && !customEnabled,
2176
2326
  onClick: () => {
2177
2327
  const first = addable[0];
2178
- /* v8 ignore next -- the button is disabled while nothing is addable */
2179
- if (first === void 0) return;
2328
+ const initial = catalogEnabled ? "catalog" : "custom";
2180
2329
  setSavedTarget(void 0);
2181
- setDeclaring(false);
2182
- setAdding(true);
2183
- setEditing(targetOf(first));
2330
+ setEditing(first === void 0 ? void 0 : targetOf(first.row));
2331
+ setAddMode(initial);
2332
+ setVisited(new Set([initial]));
2333
+ setAddOpen(true);
2184
2334
  },
2185
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), t("add")]
2186
- }), state.namespaces.has("llm-pi-ai") && (0, react_jsx_runtime.jsxs)("button", {
2187
- type: "button",
2188
- className: ModelsSection_module_css_default["addButton"],
2189
- disabled: protocols.length === 0 || !state.writable,
2190
- onClick: () => {
2191
- setSavedTarget(void 0);
2192
- setAdding(false);
2193
- setEditing(void 0);
2194
- setDeclaring(true);
2195
- },
2196
- children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 14 }), t("customAdd")]
2197
- })]
2198
- })
2335
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 14 }), t("add")]
2336
+ })
2337
+ }) : null
2199
2338
  }),
2200
2339
  renderSlot("settings.models.footer", {}),
2201
2340
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
@@ -2228,7 +2367,7 @@ window.__ModuleLoader__.load({
2228
2367
  }
2229
2368
  //#endregion
2230
2369
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/OnboardingModal.module.css.mjs
2231
- const css$2 = ".jLrgrW_dialog{width:min(600px,100%);padding:0}.jLrgrW_content{box-sizing:border-box;flex-direction:column;max-height:calc(100vh - 48px);padding:28px;display:flex;overflow-y:auto}.jLrgrW_title{color:var(--dsw-alias-label-primary);outline:none;margin:0;font-size:20px;font-weight:500;line-height:28px}.jLrgrW_body{margin-top:20px}@media (width<=560px){.jLrgrW_content{padding:24px}}";
2370
+ const css$2 = ".jLrgrW_dialog{width:min(600px,100%);max-height:100%;padding:0}.jLrgrW_content{box-sizing:border-box;flex-direction:column;min-height:0;padding:28px;display:flex;overflow-y:auto}.jLrgrW_title{color:var(--dsw-alias-label-primary);outline:none;margin:0;font-size:20px;font-weight:500;line-height:28px}.jLrgrW_body{margin-top:20px}@media (width<=560px){.jLrgrW_content{padding:24px}}";
2232
2371
  const tagId$2 = "@deepseek-ai/dsh-client-ui-settings-models/OnboardingModal.module.css";
2233
2372
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
2234
2373
  const tag = document.createElement("style");
@@ -2323,20 +2462,34 @@ window.__ModuleLoader__.load({
2323
2462
  * @returns the onboarding modal or null when onboarding needs no intervention.
2324
2463
  */
2325
2464
  function DeepSeekOnboardingDialog(props) {
2326
- const { complete, controller, useModels, operations, schema, t } = props;
2465
+ const { complete, controller, useModels, operations, schema, t, renderSlot, automatic, explicit = false } = props;
2466
+ const [apiKey, setApiKey] = (0, react.useState)(explicit);
2327
2467
  const state = useModels((snapshot) => snapshot);
2328
2468
  const readiness = onboardingReadiness(state);
2329
2469
  (0, react.useEffect)(() => {
2330
- if (state.status === "idle") controller.load();
2331
- }, [controller, state.status]);
2470
+ if ((automatic || explicit) && state.status === "idle") controller.load();
2471
+ }, [
2472
+ controller,
2473
+ state.status,
2474
+ automatic,
2475
+ explicit
2476
+ ]);
2332
2477
  (0, react.useEffect)(() => {
2333
- if (readiness.kind === "adapter-absent" || readiness.kind === "provider-ready" || readiness.kind === "unavailable") complete();
2334
- }, [complete, readiness.kind]);
2478
+ if (!automatic && !explicit || readiness.kind === "adapter-absent" || !explicit && readiness.kind === "provider-ready" || readiness.kind === "unavailable") complete();
2479
+ }, [
2480
+ complete,
2481
+ readiness.kind,
2482
+ explicit,
2483
+ automatic
2484
+ ]);
2485
+ if (!automatic && !explicit) return null;
2335
2486
  switch (readiness.kind) {
2336
2487
  case "loading":
2337
2488
  case "adapter-absent":
2338
- case "provider-ready":
2339
2489
  case "unavailable": return null;
2490
+ case "provider-ready":
2491
+ if (!explicit) return null;
2492
+ break;
2340
2493
  case "credential-missing": break;
2341
2494
  /* v8 ignore next -- every current readiness variant is handled above */
2342
2495
  default: return assertNever$1(readiness);
@@ -2352,7 +2505,7 @@ window.__ModuleLoader__.load({
2352
2505
  }
2353
2506
  controller.load();
2354
2507
  };
2355
- return (0, react_jsx_runtime.jsxs)(OnboardingModal, {
2508
+ const editor = (0, react_jsx_runtime.jsxs)(OnboardingModal, {
2356
2509
  title: t("onboardingTitle"),
2357
2510
  children: [(0, react_jsx_runtime.jsx)("p", {
2358
2511
  className: DeepSeekOnboardingDialog_module_css_default.description,
@@ -2379,6 +2532,12 @@ window.__ModuleLoader__.load({
2379
2532
  })
2380
2533
  })]
2381
2534
  });
2535
+ return apiKey ? editor : renderSlot("settings.models.sign-in", {
2536
+ complete,
2537
+ useApiKey: () => {
2538
+ setApiKey(true);
2539
+ }
2540
+ }, { fallback: editor });
2382
2541
  }
2383
2542
  //#endregion
2384
2543
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/WelcomeNotice.module.css.mjs
@@ -2456,7 +2615,7 @@ window.__ModuleLoader__.load({
2456
2615
  //#endregion
2457
2616
  //#region lib/types/onboarding-copy.js
2458
2617
  /** Durable settings namespace for product-wide GUI onboarding facts. */
2459
- const WELCOME_NOTICE_SETTINGS_NAMESPACE = "ui-onboarding";
2618
+ const WELCOME_NOTICE_SETTINGS_NAMESPACE = "ui-settings-general";
2460
2619
  /** Field storing the last welcome notice version the user acknowledged. */
2461
2620
  const WELCOME_NOTICE_ACK_FIELD = "welcomeNoticeVersion";
2462
2621
  /**
@@ -2472,16 +2631,6 @@ window.__ModuleLoader__.load({
2472
2631
  * remote browser's memory-mode scope never answers and the acknowledgement
2473
2632
  * stays process-local here.
2474
2633
  */
2475
- /**
2476
- * Accept any object section verbatim; a malformed durable value reads as an
2477
- * empty section, so the notice treats it as unacknowledged instead of leaving
2478
- * the scope stuck on its previous value.
2479
- * @param section - the wire section value.
2480
- * @returns the section object, or an empty one for non-object values.
2481
- */
2482
- function decodeWelcomeSection(section) {
2483
- return typeof section === "object" && section !== null && !Array.isArray(section) ? section : {};
2484
- }
2485
2634
  /* v8 ignore next 3 -- closed-union default only defends future source widening */
2486
2635
  function assertNever(_value) {
2487
2636
  throw new Error("unexpected welcome settings status");
@@ -2680,7 +2829,14 @@ window.__ModuleLoader__.load({
2680
2829
  deleteDescriptionWithCredential: "Deleting {provider} removes its configuration and stored API key.",
2681
2830
  deleteConfirm: "Delete {provider}",
2682
2831
  deleting: "Deleting {provider}…",
2683
- add: "Add provider",
2832
+ add: "Add model provider",
2833
+ addMode: "How to add",
2834
+ addCatalog: "Third-party model provider",
2835
+ addCustom: "Custom model API",
2836
+ addCatalogHint: "Pick OpenAI, Anthropic, Kimi, or another provider from the built-in catalog and enter its API key.",
2837
+ addCustomHint: "Connect a relay, a self-hosted server, or any other OpenAI- or Anthropic-compatible endpoint by its base URL, protocol, and models.",
2838
+ addCatalogExhausted: "Every catalog provider is already configured.",
2839
+ addCustomUnavailable: "No API protocol is available to declare.",
2684
2840
  provider: "Provider",
2685
2841
  close: "Close",
2686
2842
  cancel: "Cancel",
@@ -2701,9 +2857,8 @@ window.__ModuleLoader__.load({
2701
2857
  customized: "Customized settings",
2702
2858
  baseUrl: "Base URL",
2703
2859
  baseUrlDefault: "Provider default",
2704
- deepSeekChatBaseUrl: "https://api.deepseek.com",
2705
- deepSeekMessagesBaseUrl: "https://api.deepseek.com/anthropic",
2706
- deepSeekEndpointHint: "Use an endpoint compatible with the configured connection.",
2860
+ deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
2861
+ deepSeekEndpointHint: "Use an API endpoint compatible with Anthropic Messages.",
2707
2862
  models: "Models",
2708
2863
  modelsInherited: "Using the adapter defaults",
2709
2864
  modelsCustomized: "Customized model catalog",
@@ -2731,7 +2886,7 @@ window.__ModuleLoader__.load({
2731
2886
  modelNameInvalid: "Display name cannot be empty.",
2732
2887
  modelContextInvalid: "Context window must be a positive count, like 131072, 256K, or 1M.",
2733
2888
  modelMaxTokensInvalid: "Max output tokens must be a positive count, like 8192, 64K, or 1M.",
2734
- advancedHint: "Other fields live in settings.yaml; edit that section directly.",
2889
+ advancedHint: "Other fields live in cordis.patch.yml; edit that section directly.",
2735
2890
  modelCapacityInvalid: "A capacity must be a number, optionally suffixed K or M.",
2736
2891
  modelDuplicate: "Each model ID may appear once.",
2737
2892
  fetchModels: "Fetch available models",
@@ -2745,8 +2900,6 @@ window.__ModuleLoader__.load({
2745
2900
  fetchSelectAll: "Select all",
2746
2901
  fetchDeselectAll: "Deselect all",
2747
2902
  fetchAdopt: "Add selected",
2748
- customAdd: "Add a custom provider",
2749
- customTitle: "Custom provider",
2750
2903
  customTag: "Custom",
2751
2904
  customRoute: "Provider ID",
2752
2905
  customRouteHint: "Lowercase identifier, starting with a letter, that uniquely names this provider in requests and as its credential name.",
@@ -2755,10 +2908,14 @@ window.__ModuleLoader__.load({
2755
2908
  customDisplayName: "Display name",
2756
2909
  customApi: "API protocol",
2757
2910
  customApiUnset: "Not selected",
2911
+ protocolOpenAiCompletions: "OpenAI Chat Completions",
2912
+ protocolOpenAiResponses: "OpenAI Responses",
2913
+ protocolAnthropicMessages: "Anthropic Messages",
2758
2914
  customNeedsBaseUrl: "A custom provider needs a base URL.",
2759
2915
  customBaseUrlInvalid: "Enter a valid HTTP or HTTPS URL.",
2760
2916
  customNeedsModels: "A custom provider needs at least one model.",
2761
2917
  customBaseUrlPlaceholder: "https://gateway.example/v1",
2918
+ customAnthropicBaseUrlPlaceholder: "https://gateway.example",
2762
2919
  settingsPathUnresolvable: "unresolvable settings path",
2763
2920
  create: "Create provider",
2764
2921
  creating: "Creating…",
@@ -2777,7 +2934,7 @@ window.__ModuleLoader__.load({
2777
2934
  const zh = {
2778
2935
  nav: "模型",
2779
2936
  title: "模型",
2780
- intro: "填入各提供方的 API 密钥即可使用其模型。",
2937
+ intro: "填入各提供商的 API 密钥即可使用其模型。",
2781
2938
  edit: "编辑",
2782
2939
  editProvider: "编辑 {provider}",
2783
2940
  remove: "删除",
@@ -2787,8 +2944,15 @@ window.__ModuleLoader__.load({
2787
2944
  deleteDescriptionWithCredential: "删除 {provider} 会移除其配置和存储的 API 密钥。",
2788
2945
  deleteConfirm: "删除 {provider}",
2789
2946
  deleting: "正在删除 {provider}…",
2790
- add: "添加提供方",
2791
- provider: "提供方",
2947
+ add: "添加模型提供商",
2948
+ addMode: "添加方式",
2949
+ addCatalog: "第三方模型提供商",
2950
+ addCustom: "自定义模型 API",
2951
+ addCatalogHint: "从内置目录中选择 OpenAI、Anthropic、Kimi 等提供商,填入其 API 密钥即可使用。",
2952
+ addCustomHint: "连接中转站、自部署服务或其他兼容 OpenAI / Anthropic 协议的接口,需填写 API 地址、协议和模型。",
2953
+ addCatalogExhausted: "目录中的提供商都已添加。",
2954
+ addCustomUnavailable: "没有可用的 API 协议。",
2955
+ provider: "提供商",
2792
2956
  close: "关闭",
2793
2957
  cancel: "取消",
2794
2958
  apply: "保存",
@@ -2797,7 +2961,7 @@ window.__ModuleLoader__.load({
2797
2961
  credentialConfigured: "API 密钥已配置",
2798
2962
  credentialMissing: "API 密钥缺失",
2799
2963
  readOnly: "当前部署的设置文档为只读。",
2800
- loadFailed: "加载提供方目录失败",
2964
+ loadFailed: "加载提供商目录失败",
2801
2965
  conflict: "这张卡片打开期间,这些设置已被其他地方改动。请关闭后重新打开,在当前值上编辑。",
2802
2966
  retry: "重试",
2803
2967
  keyInput: "API 密钥",
@@ -2807,10 +2971,9 @@ window.__ModuleLoader__.load({
2807
2971
  keyEnvLocked: "由启动环境提供(只读)",
2808
2972
  customized: "自定义设置",
2809
2973
  baseUrl: "API 地址",
2810
- baseUrlDefault: "提供方默认",
2811
- deepSeekChatBaseUrl: "https://api.deepseek.com",
2812
- deepSeekMessagesBaseUrl: "https://api.deepseek.com/anthropic",
2813
- deepSeekEndpointHint: "请填写与当前连接配置兼容的 API 地址。",
2974
+ baseUrlDefault: "提供商默认",
2975
+ deepSeekBaseUrl: "https://api.deepseek.com/anthropic",
2976
+ deepSeekEndpointHint: "请填写兼容 Anthropic Messages 协议的 API 地址。",
2814
2977
  models: "模型目录",
2815
2978
  modelsInherited: "正在使用适配器默认模型",
2816
2979
  modelsCustomized: "已自定义模型目录",
@@ -2820,9 +2983,9 @@ window.__ModuleLoader__.load({
2820
2983
  modelName: "显示名称",
2821
2984
  modelNamePlaceholder: "留空时使用模型 ID",
2822
2985
  contextWindow: "上下文窗口",
2823
- contextWindowPlaceholder: "使用提供方默认值",
2986
+ contextWindowPlaceholder: "使用提供商默认值",
2824
2987
  maxTokens: "最大输出 token 数",
2825
- maxTokensPlaceholder: "使用提供方默认值",
2988
+ maxTokensPlaceholder: "使用提供商默认值",
2826
2989
  modelAdvanced: "模型选项",
2827
2990
  modelInputTypes: "输入类型",
2828
2991
  modelInputText: "文本",
@@ -2831,43 +2994,45 @@ window.__ModuleLoader__.load({
2831
2994
  removeModel: "删除模型",
2832
2995
  modelsEmpty: "模型选择器中将不显示任何模型;目录外 ID 仍可直接发送。",
2833
2996
  keyBlank: "请输入 API 密钥;留空则保持已存储的密钥。",
2834
- keyBlankNew: "请输入 API 密钥;若该提供方以其他方式鉴权,可以留空。",
2997
+ keyBlankNew: "请输入 API 密钥;若该提供商以其他方式鉴权,可以留空。",
2835
2998
  keyIllegalCharacters: "该 API 密钥格式错误,请检查。",
2836
2999
  modelIdRequired: "模型 ID 不能为空。",
2837
3000
  modelIdDuplicate: "模型 ID 不能重复。",
2838
3001
  modelNameInvalid: "显示名称不能为空。",
2839
3002
  modelContextInvalid: "上下文窗口必须是正数,例如 131072、256K 或 1M。",
2840
3003
  modelMaxTokensInvalid: "最大输出 token 数必须是正数,例如 8192、64K 或 1M。",
2841
- advancedHint: "其余字段在 settings.yaml 中,请直接编辑对应段。",
3004
+ advancedHint: "其余字段在 cordis.patch.yml 中,请直接编辑对应段。",
2842
3005
  modelCapacityInvalid: "容量需为数字,可加 K 或 M 后缀。",
2843
3006
  modelDuplicate: "每个模型 ID 只能出现一次。",
2844
3007
  fetchModels: "获取可用模型",
2845
- fetching: "正在询问提供方…",
3008
+ fetching: "正在询问提供商…",
2846
3009
  fetchNeedsBaseUrl: "请先填写 API 地址,再获取。",
2847
- fetchEmpty: "该提供方没有列出任何模型,请手动添加。",
3010
+ fetchEmpty: "该提供商没有列出任何模型,请手动添加。",
2848
3011
  fetchTitle: "选择要添加的模型",
2849
- fetchDescription: "以下是模型提供方的可用模型,勾选要添加的模型。",
3012
+ fetchDescription: "以下是模型提供商的可用模型,勾选要添加的模型。",
2850
3013
  fetchSearch: "搜索模型",
2851
3014
  fetchNoMatches: "没有匹配的模型。",
2852
3015
  fetchSelectAll: "全选",
2853
3016
  fetchDeselectAll: "取消全选",
2854
3017
  fetchAdopt: "添加所选",
2855
- customAdd: "添加自定义提供方",
2856
- customTitle: "自定义提供方",
2857
3018
  customTag: "自定义",
2858
3019
  customRoute: "Provider ID",
2859
- customRouteHint: "以小写字母开头的标识,在请求中唯一标识该提供方,并用于派生凭据名。",
3020
+ customRouteHint: "以小写字母开头的标识,在请求中唯一标识该提供商,并用于派生凭据名。",
2860
3021
  customRouteInvalid: "需以小写字母开头,之后可用小写字母、数字和短横线。",
2861
- customRouteTaken: "已有提供方使用了这个 ID。",
3022
+ customRouteTaken: "已有提供商使用了这个 ID。",
2862
3023
  customDisplayName: "显示名称",
2863
3024
  customApi: "API 协议",
2864
3025
  customApiUnset: "未选择",
2865
- customNeedsBaseUrl: "自定义提供方需要填写 API 地址。",
3026
+ protocolOpenAiCompletions: "OpenAI Chat Completions",
3027
+ protocolOpenAiResponses: "OpenAI Responses",
3028
+ protocolAnthropicMessages: "Anthropic Messages",
3029
+ customNeedsBaseUrl: "自定义模型 API 需要填写 API 地址。",
2866
3030
  customBaseUrlInvalid: "请输入有效的 HTTP 或 HTTPS 地址。",
2867
- customNeedsModels: "自定义提供方至少需要一个模型。",
3031
+ customNeedsModels: "自定义模型 API 至少需要一个模型。",
2868
3032
  customBaseUrlPlaceholder: "https://gateway.example/v1",
3033
+ customAnthropicBaseUrlPlaceholder: "https://gateway.example",
2869
3034
  settingsPathUnresolvable: "无法解析设置路径",
2870
- create: "创建提供方",
3035
+ create: "创建提供商",
2871
3036
  creating: "创建中…",
2872
3037
  welcomeTitle: "内测声明",
2873
3038
  welcomeBody: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
@@ -2881,6 +3046,904 @@ window.__ModuleLoader__.load({
2881
3046
  keyRequired: "请输入 API 密钥后继续。"
2882
3047
  };
2883
3048
  //#endregion
3049
+ //#region ../../../vendor/cosmokit/src/misc.ts
3050
+ /** Return true when a value is `null` or `undefined`. */
3051
+ function isNullable(value) {
3052
+ return value === null || value === void 0;
3053
+ }
3054
+ /** Return true for non-array object values. */
3055
+ function isPlainObject(data) {
3056
+ return data && typeof data === "object" && !Array.isArray(data);
3057
+ }
3058
+ /** Filter object entries and return a new object. */
3059
+ function filterKeys(object, filter) {
3060
+ return Object.fromEntries(Object.entries(object).filter(([key, value]) => filter(key, value)));
3061
+ }
3062
+ /** Map object values while preserving the original key set. */
3063
+ function mapValues(object, transform) {
3064
+ return Object.fromEntries(Object.entries(object).map(([key, value]) => [key, transform(value, key)]));
3065
+ }
3066
+ /** Pick selected keys from an object, optionally including `undefined` values. */
3067
+ function pick(source, keys, forced) {
3068
+ if (!keys) return { ...source };
3069
+ const result = {};
3070
+ for (const key of keys) if (forced || source[key] !== void 0) result[key] = source[key];
3071
+ return result;
3072
+ }
3073
+ //#endregion
3074
+ //#region ../../../vendor/cosmokit/src/volatile.ts
3075
+ /** Shared config references used by schema validators and plugin runtimes. */
3076
+ const write = Symbol.for("cosmokit.volatile.write");
3077
+ function snapshot(value, ancestors = /* @__PURE__ */ new Set()) {
3078
+ if (typeof value === "function") throw new TypeError("volatile config cannot contain functions");
3079
+ if (value === null || typeof value !== "object") return value;
3080
+ if (ancestors.has(value)) throw new TypeError("volatile config cannot contain cycles");
3081
+ ancestors.add(value);
3082
+ try {
3083
+ if (Array.isArray(value)) return Object.freeze(value.map((item) => snapshot(item, ancestors)));
3084
+ if (Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) throw new TypeError("volatile config objects must be plain objects or arrays");
3085
+ return Object.freeze(Object.fromEntries(Object.entries(value).map(([key, item]) => [key, snapshot(item, ancestors)])));
3086
+ } finally {
3087
+ ancestors.delete(value);
3088
+ }
3089
+ }
3090
+ /**
3091
+ * Create a detached reference containing an immutable copy of the supplied data.
3092
+ * @param value - validated config data; class instances and functions are unsupported.
3093
+ * @returns a reference whose value is updated only by its owning runtime.
3094
+ */
3095
+ function createVolatile(value) {
3096
+ let current = snapshot(value);
3097
+ return Object.freeze({
3098
+ get: () => current,
3099
+ [write]: (value) => {
3100
+ current = value;
3101
+ }
3102
+ });
3103
+ }
3104
+ /**
3105
+ * Identify references across ESM/CJS copies of the shared library.
3106
+ * @param value - a parsed config value.
3107
+ * @returns whether the value implements the shared reference protocol.
3108
+ */
3109
+ function isVolatile(value) {
3110
+ return typeof value === "object" && value !== null && write in value;
3111
+ }
3112
+ //#endregion
3113
+ //#region ../../../vendor/cosmokit/src/types.ts
3114
+ /** Test values using `instanceof` with a `toStringTag` fallback. */
3115
+ function is(type, value) {
3116
+ if (arguments.length === 1) return (value) => is(type, value);
3117
+ return type in globalThis && value instanceof globalThis[type] || Object.prototype.toString.call(value).slice(8, -1) === type;
3118
+ }
3119
+ function isArrayBufferLike(value) {
3120
+ return is("ArrayBuffer", value) || is("SharedArrayBuffer", value);
3121
+ }
3122
+ function isArrayBufferSource(value) {
3123
+ return isArrayBufferLike(value) || ArrayBuffer.isView(value);
3124
+ }
3125
+ let Binary;
3126
+ (function(_Binary) {
3127
+ _Binary.is = isArrayBufferLike;
3128
+ _Binary.isSource = isArrayBufferSource;
3129
+ function fromSource(source) {
3130
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
3131
+ else return source;
3132
+ }
3133
+ _Binary.fromSource = fromSource;
3134
+ function toBase64(source) {
3135
+ source = fromSource(source);
3136
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("base64");
3137
+ let binary = "";
3138
+ const bytes = new Uint8Array(source);
3139
+ for (let i = 0; i < bytes.byteLength; i++) binary += String.fromCharCode(bytes[i]);
3140
+ return btoa(binary);
3141
+ }
3142
+ _Binary.toBase64 = toBase64;
3143
+ function fromBase64(source) {
3144
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "base64"));
3145
+ return Uint8Array.from(atob(source), (c) => c.charCodeAt(0));
3146
+ }
3147
+ _Binary.fromBase64 = fromBase64;
3148
+ function toHex(source) {
3149
+ source = fromSource(source);
3150
+ if (typeof Buffer !== "undefined") return Buffer.from(source).toString("hex");
3151
+ return Array.from(new Uint8Array(source), (byte) => byte.toString(16).padStart(2, "0")).join("");
3152
+ }
3153
+ _Binary.toHex = toHex;
3154
+ function fromHex(source) {
3155
+ if (typeof Buffer !== "undefined") return fromSource(Buffer.from(source, "hex"));
3156
+ const hex = source.length % 2 === 0 ? source : source.slice(0, source.length - 1);
3157
+ const buffer = [];
3158
+ for (let i = 0; i < hex.length; i += 2) buffer.push(parseInt(`${hex[i]}${hex[i + 1]}`, 16));
3159
+ return Uint8Array.from(buffer).buffer;
3160
+ }
3161
+ _Binary.fromHex = fromHex;
3162
+ })(Binary || (Binary = {}));
3163
+ Binary.fromBase64;
3164
+ Binary.toBase64;
3165
+ Binary.fromHex;
3166
+ Binary.toHex;
3167
+ /** Deep-clone common JavaScript values while preserving prototypes and cycles. */
3168
+ function clone(source, refs = /* @__PURE__ */ new Map()) {
3169
+ if (!source || typeof source !== "object") return source;
3170
+ if (is("Date", source)) return new Date(source.valueOf());
3171
+ if (is("RegExp", source)) return new RegExp(source.source, source.flags);
3172
+ if (isArrayBufferLike(source)) return source.slice(0);
3173
+ if (ArrayBuffer.isView(source)) return source.buffer.slice(source.byteOffset, source.byteOffset + source.byteLength);
3174
+ const cached = refs.get(source);
3175
+ if (cached) return cached;
3176
+ if (Array.isArray(source)) {
3177
+ const result = [];
3178
+ refs.set(source, result);
3179
+ source.forEach((value, index) => {
3180
+ result[index] = Reflect.apply(clone, null, [value, refs]);
3181
+ });
3182
+ return result;
3183
+ }
3184
+ const result = Object.create(Object.getPrototypeOf(source));
3185
+ refs.set(source, result);
3186
+ for (const key of Reflect.ownKeys(source)) {
3187
+ const descriptor = { ...Reflect.getOwnPropertyDescriptor(source, key) };
3188
+ if ("value" in descriptor) descriptor.value = Reflect.apply(clone, null, [descriptor.value, refs]);
3189
+ Reflect.defineProperty(result, key, descriptor);
3190
+ }
3191
+ return result;
3192
+ }
3193
+ /**
3194
+ * Compare values recursively, treating two volatile references as equal regardless of value.
3195
+ * Strict comparison distinguishes null/undefined, treats opaque objects by identity,
3196
+ * compares URLs by normalized href, treats array holes as undefined, and considers distinct cyclic structures unequal.
3197
+ * @param a - first value.
3198
+ * @param b - second value.
3199
+ * @param strict - whether to require strict data equality outside volatile references.
3200
+ * @returns whether the values compare equal.
3201
+ */
3202
+ function deepEqual(a, b, strict) {
3203
+ const ancestors = /* @__PURE__ */ new Set();
3204
+ function compare(a, b) {
3205
+ if (a === b) return true;
3206
+ if (isVolatile(a) || isVolatile(b)) return isVolatile(a) && isVolatile(b);
3207
+ if (!strict && isNullable(a) && isNullable(b)) return true;
3208
+ if (typeof a !== typeof b || typeof a !== "object" || !a || !b) return false;
3209
+ if (ancestors.has(a)) return false;
3210
+ function check(test, then) {
3211
+ return test(a) ? test(b) ? then(a, b) : false : test(b) ? false : void 0;
3212
+ }
3213
+ ancestors.add(a);
3214
+ try {
3215
+ return check(Array.isArray, (a, b) => {
3216
+ if (a.length !== b.length) return false;
3217
+ for (let index = 0; index < a.length; index++) if (!compare(a[index], b[index])) return false;
3218
+ return true;
3219
+ }) ?? check(is("Date"), (a, b) => a.valueOf() === b.valueOf()) ?? check(is("URL"), (a, b) => a.href === b.href) ?? check(is("RegExp"), (a, b) => a.source === b.source && a.flags === b.flags) ?? check(isArrayBufferLike, (a, b) => {
3220
+ if (a.byteLength !== b.byteLength) return false;
3221
+ const viewA = new Uint8Array(a);
3222
+ const viewB = new Uint8Array(b);
3223
+ for (let i = 0; i < viewA.length; i++) if (viewA[i] !== viewB[i]) return false;
3224
+ return true;
3225
+ }) ?? ((!strict || [a, b].every((value) => Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null)) && Object.keys({
3226
+ ...a,
3227
+ ...b
3228
+ }).every((key) => compare(a[key], b[key])));
3229
+ } finally {
3230
+ ancestors.delete(a);
3231
+ }
3232
+ }
3233
+ return compare(a, b);
3234
+ }
3235
+ //#endregion
3236
+ //#region ../../../vendor/cosmokit/src/time.ts
3237
+ let Time;
3238
+ (function(_Time) {
3239
+ _Time.millisecond = 1;
3240
+ const second = _Time.second = 1e3;
3241
+ const minute = _Time.minute = second * 60;
3242
+ const hour = _Time.hour = minute * 60;
3243
+ const day = _Time.day = hour * 24;
3244
+ const week = _Time.week = day * 7;
3245
+ let timezoneOffset = (/* @__PURE__ */ new Date()).getTimezoneOffset();
3246
+ function setTimezoneOffset(offset) {
3247
+ timezoneOffset = offset;
3248
+ }
3249
+ _Time.setTimezoneOffset = setTimezoneOffset;
3250
+ function getTimezoneOffset() {
3251
+ return timezoneOffset;
3252
+ }
3253
+ _Time.getTimezoneOffset = getTimezoneOffset;
3254
+ function getDateNumber(date = /* @__PURE__ */ new Date(), offset) {
3255
+ if (typeof date === "number") date = new Date(date);
3256
+ if (offset === void 0) offset = timezoneOffset;
3257
+ return Math.floor((date.valueOf() / minute - offset) / 1440);
3258
+ }
3259
+ _Time.getDateNumber = getDateNumber;
3260
+ function fromDateNumber(value, offset) {
3261
+ const date = new Date(value * day);
3262
+ if (offset === void 0) offset = timezoneOffset;
3263
+ return new Date(+date + offset * minute);
3264
+ }
3265
+ _Time.fromDateNumber = fromDateNumber;
3266
+ const numeric = /\d+(?:\.\d+)?/.source;
3267
+ const timeRegExp = new RegExp(`^${[
3268
+ "w(?:eek(?:s)?)?",
3269
+ "d(?:ay(?:s)?)?",
3270
+ "h(?:our(?:s)?)?",
3271
+ "m(?:in(?:ute)?(?:s)?)?",
3272
+ "s(?:ec(?:ond)?(?:s)?)?"
3273
+ ].map((unit) => `(${numeric}${unit})?`).join("")}$`);
3274
+ function parseTime(source) {
3275
+ const capture = timeRegExp.exec(source);
3276
+ if (!capture) return 0;
3277
+ return (parseFloat(capture[1]) * week || 0) + (parseFloat(capture[2]) * day || 0) + (parseFloat(capture[3]) * hour || 0) + (parseFloat(capture[4]) * minute || 0) + (parseFloat(capture[5]) * second || 0);
3278
+ }
3279
+ _Time.parseTime = parseTime;
3280
+ function parseDate(date) {
3281
+ const parsed = parseTime(date);
3282
+ if (parsed) date = Date.now() + parsed;
3283
+ else if (/^\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).toLocaleDateString()}-${date}`;
3284
+ else if (/^\d{1,2}-\d{1,2}-\d{1,2}(:\d{1,2}){1,2}$/.test(date)) date = `${(/* @__PURE__ */ new Date()).getFullYear()}-${date}`;
3285
+ return date ? new Date(date) : /* @__PURE__ */ new Date();
3286
+ }
3287
+ _Time.parseDate = parseDate;
3288
+ function format(ms) {
3289
+ const abs = Math.abs(ms);
3290
+ if (abs >= day - hour / 2) return Math.round(ms / day) + "d";
3291
+ else if (abs >= hour - minute / 2) return Math.round(ms / hour) + "h";
3292
+ else if (abs >= minute - second / 2) return Math.round(ms / minute) + "m";
3293
+ else if (abs >= second) return Math.round(ms / second) + "s";
3294
+ return ms + "ms";
3295
+ }
3296
+ _Time.format = format;
3297
+ function toDigits(source, length = 2) {
3298
+ return source.toString().padStart(length, "0");
3299
+ }
3300
+ _Time.toDigits = toDigits;
3301
+ function template(template, time = /* @__PURE__ */ new Date()) {
3302
+ return template.replace("yyyy", time.getFullYear().toString()).replace("yy", time.getFullYear().toString().slice(2)).replace("MM", toDigits(time.getMonth() + 1)).replace("dd", toDigits(time.getDate())).replace("hh", toDigits(time.getHours())).replace("mm", toDigits(time.getMinutes())).replace("ss", toDigits(time.getSeconds())).replace("SSS", toDigits(time.getMilliseconds(), 3));
3303
+ }
3304
+ _Time.template = template;
3305
+ })(Time || (Time = {}));
3306
+ //#endregion
3307
+ //#region ../../../vendor/schemastery/src/index.ts
3308
+ const kSchema = Symbol.for("schemastery");
3309
+ const kValidationError = Symbol.for("ValidationError");
3310
+ globalThis.__schemastery_index__ ??= 0;
3311
+ globalThis.__schemastery_refs__ = void 0;
3312
+ var ValidationError = class extends TypeError {
3313
+ options;
3314
+ name = "ValidationError";
3315
+ constructor(message, options) {
3316
+ let prefix = "$";
3317
+ for (const segment of options.path || []) if (typeof segment === "string") prefix += "." + segment;
3318
+ else if (typeof segment === "number") prefix += "[" + segment + "]";
3319
+ else if (typeof segment === "symbol") prefix += `[Symbol(${segment.toString()})]`;
3320
+ if (prefix.startsWith(".")) prefix = prefix.slice(1);
3321
+ super((prefix === "$" ? "" : `${prefix} `) + message);
3322
+ this.options = options;
3323
+ }
3324
+ static is(error) {
3325
+ return !!error?.[kValidationError];
3326
+ }
3327
+ };
3328
+ Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
3329
+ const Schema = function(options) {
3330
+ const schema = function(data, options = {}) {
3331
+ return Schema.resolve(data, schema, options)[0];
3332
+ };
3333
+ if (options.refs) {
3334
+ const refs = mapValues(options.refs, (options) => new Schema(options));
3335
+ const getRef = (uid) => refs[uid];
3336
+ for (const key in refs) {
3337
+ const options = refs[key];
3338
+ options.sKey = getRef(options.sKey);
3339
+ options.inner = getRef(options.inner);
3340
+ options.list = options.list && options.list.map(getRef);
3341
+ options.dict = options.dict && mapValues(options.dict, getRef);
3342
+ }
3343
+ return refs[options.uid];
3344
+ }
3345
+ Object.assign(schema, options);
3346
+ if (typeof schema.callback === "string") try {
3347
+ schema.callback = new Function("return " + schema.callback)();
3348
+ } catch {}
3349
+ Object.defineProperty(schema, "uid", { value: globalThis.__schemastery_index__++ });
3350
+ Object.setPrototypeOf(schema, Schema.prototype);
3351
+ schema.meta ||= {};
3352
+ schema.toString = schema.toString.bind(schema);
3353
+ return schema;
3354
+ };
3355
+ Schema.prototype = Object.create(Function.prototype);
3356
+ Schema.prototype[kSchema] = true;
3357
+ Object.defineProperty(Schema.prototype, "~standard", { get() {
3358
+ return {
3359
+ version: 1,
3360
+ vendor: "schemastery",
3361
+ validate: (value) => {
3362
+ try {
3363
+ return { value: Schema.resolve(value, this, {})[0] };
3364
+ } catch (error) {
3365
+ if (ValidationError.is(error)) return { issues: [{
3366
+ message: error.message,
3367
+ path: error.options.path
3368
+ }] };
3369
+ throw error;
3370
+ }
3371
+ }
3372
+ };
3373
+ } });
3374
+ Schema.ValidationError = ValidationError;
3375
+ Schema.prototype.toJSON = function toJSON() {
3376
+ if (globalThis.__schemastery_refs__) {
3377
+ globalThis.__schemastery_refs__[this.uid] ??= JSON.parse(JSON.stringify({ ...this }));
3378
+ return this.uid;
3379
+ }
3380
+ globalThis.__schemastery_refs__ = { [this.uid]: { ...this } };
3381
+ globalThis.__schemastery_refs__[this.uid] = JSON.parse(JSON.stringify({ ...this }));
3382
+ const result = {
3383
+ uid: this.uid,
3384
+ refs: globalThis.__schemastery_refs__
3385
+ };
3386
+ globalThis.__schemastery_refs__ = void 0;
3387
+ return result;
3388
+ };
3389
+ Schema.prototype.set = function set(key, value) {
3390
+ this.dict[key] = value;
3391
+ return this;
3392
+ };
3393
+ Schema.prototype.push = function push(value) {
3394
+ this.list.push(value);
3395
+ return this;
3396
+ };
3397
+ function mergeDesc(original, messages) {
3398
+ const result = typeof original === "string" ? { "": original } : { ...original };
3399
+ for (const locale in messages) {
3400
+ const value = messages[locale];
3401
+ if (value?.$description || value?.$desc) result[locale] = value.$description || value.$desc;
3402
+ else if (typeof value === "string") result[locale] = value;
3403
+ }
3404
+ return result;
3405
+ }
3406
+ function getInner(value) {
3407
+ return value?.$value ?? value?.$inner;
3408
+ }
3409
+ function extractKeys(data) {
3410
+ return filterKeys(data ?? {}, (key) => !key.startsWith("$"));
3411
+ }
3412
+ Schema.prototype.i18n = function i18n(messages) {
3413
+ const schema = Schema(this);
3414
+ const desc = mergeDesc(schema.meta.description, messages);
3415
+ if (Object.keys(desc).length) schema.meta.description = desc;
3416
+ if (schema.dict) schema.dict = mapValues(schema.dict, (inner, key) => {
3417
+ return inner.i18n(mapValues(messages, (data) => getInner(data)?.[key] ?? data?.[key]));
3418
+ });
3419
+ if (schema.list) schema.list = schema.list.map((inner, index) => {
3420
+ return inner.i18n(mapValues(messages, (data = {}) => {
3421
+ if (Array.isArray(getInner(data))) return getInner(data)[index];
3422
+ if (Array.isArray(data)) return data[index];
3423
+ return extractKeys(data);
3424
+ }));
3425
+ });
3426
+ if (schema.inner) schema.inner = schema.inner.i18n(mapValues(messages, (data) => {
3427
+ if (getInner(data)) return getInner(data);
3428
+ return extractKeys(data);
3429
+ }));
3430
+ if (schema.sKey) schema.sKey = schema.sKey.i18n(mapValues(messages, (data) => data?.$key));
3431
+ return schema;
3432
+ };
3433
+ Schema.prototype.extra = function extra(key, value) {
3434
+ const schema = Schema(this);
3435
+ schema.meta = {
3436
+ ...schema.meta,
3437
+ [key]: value
3438
+ };
3439
+ return schema;
3440
+ };
3441
+ for (const key of [
3442
+ "required",
3443
+ "disabled",
3444
+ "collapse",
3445
+ "hidden",
3446
+ "loose"
3447
+ ]) Object.assign(Schema.prototype, { [key](value = true) {
3448
+ const schema = Schema(this);
3449
+ schema.meta = {
3450
+ ...schema.meta,
3451
+ [key]: value
3452
+ };
3453
+ return schema;
3454
+ } });
3455
+ Schema.prototype.deprecated = function deprecated() {
3456
+ const schema = Schema(this);
3457
+ schema.meta.badges ||= [];
3458
+ schema.meta.badges.push({
3459
+ text: "deprecated",
3460
+ type: "danger"
3461
+ });
3462
+ return schema;
3463
+ };
3464
+ Schema.prototype.experimental = function experimental() {
3465
+ const schema = Schema(this);
3466
+ schema.meta.badges ||= [];
3467
+ schema.meta.badges.push({
3468
+ text: "experimental",
3469
+ type: "warning"
3470
+ });
3471
+ return schema;
3472
+ };
3473
+ Schema.prototype.pattern = function pattern(regexp) {
3474
+ const schema = Schema(this);
3475
+ const pattern = pick(regexp, ["source", "flags"]);
3476
+ schema.meta = {
3477
+ ...schema.meta,
3478
+ pattern
3479
+ };
3480
+ return schema;
3481
+ };
3482
+ Schema.prototype.simplify = function simplify(value) {
3483
+ if (isVolatile(value)) value = value.get();
3484
+ if (deepEqual(value, this.meta.default, this.type === "dict")) return null;
3485
+ if (isNullable(value)) return value;
3486
+ if (this.type === "object" || this.type === "dict") {
3487
+ const result = {};
3488
+ for (const key in value) {
3489
+ const item = (this.type === "object" ? this.dict[key] : this.inner)?.simplify(value[key]);
3490
+ if (this.type === "dict" || !isNullable(item)) result[key] = item;
3491
+ }
3492
+ if (deepEqual(result, this.meta.default, this.type === "dict")) return null;
3493
+ return result;
3494
+ } else if (this.type === "array" || this.type === "tuple") {
3495
+ const result = [];
3496
+ value.forEach((value, index) => {
3497
+ const schema = this.type === "array" ? this.inner : this.list[index];
3498
+ const item = schema ? schema.simplify(value) : value;
3499
+ result.push(item);
3500
+ });
3501
+ return result;
3502
+ } else if (this.type === "intersect") {
3503
+ const result = {};
3504
+ for (const item of this.list) Object.assign(result, item.simplify(value));
3505
+ return result;
3506
+ } else if (this.type === "union") for (const schema of this.list) try {
3507
+ Schema.resolve(value, schema, {});
3508
+ return schema.simplify(value);
3509
+ } catch {}
3510
+ return value;
3511
+ };
3512
+ Schema.prototype.toString = function toString(inline) {
3513
+ return formatters[this.type]?.(this, inline) ?? `Schema<${this.type}>`;
3514
+ };
3515
+ Schema.prototype.role = function role(role, extra) {
3516
+ const schema = Schema(this);
3517
+ schema.meta = {
3518
+ ...schema.meta,
3519
+ role,
3520
+ extra
3521
+ };
3522
+ return schema;
3523
+ };
3524
+ for (const key of [
3525
+ "default",
3526
+ "link",
3527
+ "comment",
3528
+ "description",
3529
+ "max",
3530
+ "min",
3531
+ "step"
3532
+ ]) Object.assign(Schema.prototype, { [key](value) {
3533
+ const schema = Schema(this);
3534
+ schema.meta = {
3535
+ ...schema.meta,
3536
+ [key]: value
3537
+ };
3538
+ return schema;
3539
+ } });
3540
+ Schema.prototype.volatile = function volatile() {
3541
+ if (this.meta.volatile) throw new TypeError("volatile schema is already wrapped");
3542
+ return this.extra("volatile", true);
3543
+ };
3544
+ const resolvers = {};
3545
+ const checkedVolatile = Symbol("checked-volatile-schema");
3546
+ function validateVolatileSchema(schema, path = [], blocked = false, seen = /* @__PURE__ */ new Map()) {
3547
+ const states = seen.get(schema) ?? /* @__PURE__ */ new Set();
3548
+ if (states.has(blocked)) return;
3549
+ states.add(blocked);
3550
+ seen.set(schema, states);
3551
+ if (schema.meta?.volatile && blocked) throw new ValidationError("volatile fields require a fixed object path without an enclosing volatile field", { path });
3552
+ const nested = blocked || !!schema.meta?.volatile;
3553
+ if (schema.dict) for (const [key, child] of Object.entries(schema.dict)) validateVolatileSchema(child, [...path, key], nested, seen);
3554
+ if (schema.sKey) validateVolatileSchema(schema.sKey, [...path, "<key>"], true, seen);
3555
+ if (schema.inner && (schema.type !== "lazy" || schema.inner[kSchema])) validateVolatileSchema(schema.inner, [...path, "*"], true, seen);
3556
+ if (schema.list) for (let index = 0; index < schema.list.length; index++) validateVolatileSchema(schema.list[index], [...path, String(index)], true, seen);
3557
+ }
3558
+ Schema.extend = function extend(type, resolve) {
3559
+ resolvers[type] = resolve;
3560
+ };
3561
+ Schema.resolve = function resolve(data, schema, options = {}, strict = false) {
3562
+ if (!schema) return [data];
3563
+ if (!options[checkedVolatile]) {
3564
+ validateVolatileSchema(schema, options.path);
3565
+ options = {
3566
+ ...options,
3567
+ [checkedVolatile]: true
3568
+ };
3569
+ }
3570
+ if (schema.meta?.volatile) {
3571
+ const inner = Schema(schema);
3572
+ inner.meta = {
3573
+ ...schema.meta,
3574
+ volatile: false
3575
+ };
3576
+ const [value, adapted] = Schema.resolve(data, inner, options, strict);
3577
+ try {
3578
+ return [createVolatile(value), adapted];
3579
+ } catch (error) {
3580
+ throw new ValidationError(error instanceof Error ? error.message : String(error), options);
3581
+ }
3582
+ }
3583
+ if (options.ignore?.(data, schema)) return [data];
3584
+ if (isNullable(data) && schema.type !== "lazy") {
3585
+ if (schema.meta.required) throw new ValidationError(`missing required value`, options);
3586
+ let current = schema;
3587
+ let fallback = schema.meta.default;
3588
+ while (current?.type === "intersect" && isNullable(fallback)) {
3589
+ current = current.list[0];
3590
+ fallback = current?.meta.default;
3591
+ }
3592
+ if (isNullable(fallback)) return [data];
3593
+ data = clone(fallback);
3594
+ }
3595
+ const callback = resolvers[schema.type];
3596
+ if (!callback) throw new ValidationError(`unsupported type "${schema.type}"`, options);
3597
+ try {
3598
+ return callback(data, schema, options, strict);
3599
+ } catch (error) {
3600
+ if (!schema.meta.loose) throw error;
3601
+ return [schema.meta.default];
3602
+ }
3603
+ };
3604
+ Schema.from = function from(source) {
3605
+ if (isNullable(source)) return Schema.any();
3606
+ else if ([
3607
+ "string",
3608
+ "number",
3609
+ "boolean"
3610
+ ].includes(typeof source)) return Schema.const(source).required();
3611
+ else if (source[kSchema]) return source;
3612
+ else if (typeof source === "function") switch (source) {
3613
+ case String: return Schema.string().required();
3614
+ case Number: return Schema.number().required();
3615
+ case Boolean: return Schema.boolean().required();
3616
+ case Function: return Schema.function().required();
3617
+ default: return Schema.is(source).required();
3618
+ }
3619
+ else throw new TypeError(`cannot infer schema from ${source}`);
3620
+ };
3621
+ Schema.lazy = function lazy(builder) {
3622
+ const toJSON = () => {
3623
+ if (!schema.inner[kSchema]) {
3624
+ schema.inner = schema.builder();
3625
+ schema.inner.meta = {
3626
+ ...schema.meta,
3627
+ ...schema.inner.meta
3628
+ };
3629
+ }
3630
+ return schema.inner.toJSON();
3631
+ };
3632
+ const schema = new Schema({
3633
+ type: "lazy",
3634
+ builder,
3635
+ inner: { toJSON }
3636
+ });
3637
+ return schema;
3638
+ };
3639
+ Schema.natural = function natural() {
3640
+ return Schema.number().step(1).min(0);
3641
+ };
3642
+ Schema.percent = function percent() {
3643
+ return Schema.number().step(.01).min(0).max(1).role("slider");
3644
+ };
3645
+ Schema.date = function date() {
3646
+ return Schema.union([Schema.is(Date), Schema.transform(Schema.string().role("datetime"), (value, options) => {
3647
+ const date = new Date(value);
3648
+ if (isNaN(+date)) throw new ValidationError(`invalid date "${value}"`, options);
3649
+ return date;
3650
+ }, true)]);
3651
+ };
3652
+ Schema.regExp = function regExp(flag = "") {
3653
+ return Schema.union([Schema.is(RegExp), Schema.transform(Schema.string().role("regexp", { flag }), (value, options) => {
3654
+ try {
3655
+ return new RegExp(value, flag);
3656
+ } catch (e) {
3657
+ throw new ValidationError(e.message, options);
3658
+ }
3659
+ }, true)]);
3660
+ };
3661
+ Schema.arrayBuffer = function arrayBuffer(encoding) {
3662
+ return Schema.union([
3663
+ Schema.is(ArrayBuffer),
3664
+ Schema.is(SharedArrayBuffer),
3665
+ Schema.transform(Schema.any(), (value, options) => {
3666
+ if (Binary.isSource(value)) return Binary.fromSource(value);
3667
+ throw new ValidationError(`expected ArrayBufferSource but got ${value}`, options);
3668
+ }, true),
3669
+ ...encoding ? [Schema.transform(Schema.string(), (value, options) => {
3670
+ try {
3671
+ return encoding === "base64" ? Binary.fromBase64(value) : Binary.fromHex(value);
3672
+ } catch (e) {
3673
+ throw new ValidationError(e.message, options);
3674
+ }
3675
+ }, true)] : []
3676
+ ]);
3677
+ };
3678
+ Schema.extend("lazy", (data, schema, options, strict) => {
3679
+ if (!schema.inner[kSchema]) {
3680
+ schema.inner = schema.builder();
3681
+ schema.inner.meta = {
3682
+ ...schema.meta,
3683
+ ...schema.inner.meta
3684
+ };
3685
+ validateVolatileSchema(schema.inner, options.path, true);
3686
+ }
3687
+ return Schema.resolve(data, schema.inner, options, strict);
3688
+ });
3689
+ Schema.extend("any", (data) => {
3690
+ return [data];
3691
+ });
3692
+ Schema.extend("never", (data, _, options) => {
3693
+ throw new ValidationError(`expected nullable but got ${data}`, options);
3694
+ });
3695
+ Schema.extend("const", (data, { value }, options) => {
3696
+ if (deepEqual(data, value)) return [value];
3697
+ throw new ValidationError(`expected ${value} but got ${data}`, options);
3698
+ });
3699
+ function checkWithinRange(data, meta, description, options, skipMin = false) {
3700
+ const { max = Infinity, min = -Infinity } = meta;
3701
+ if (data > max) throw new ValidationError(`expected ${description} <= ${max} but got ${data}`, options);
3702
+ if (data < min && !skipMin) throw new ValidationError(`expected ${description} >= ${min} but got ${data}`, options);
3703
+ }
3704
+ Schema.extend("string", (data, { meta }, options) => {
3705
+ if (typeof data !== "string") throw new ValidationError(`expected string but got ${data}`, options);
3706
+ if (meta.pattern) {
3707
+ const regexp = new RegExp(meta.pattern.source, meta.pattern.flags);
3708
+ if (!regexp.test(data)) throw new ValidationError(`expect string to match regexp ${regexp}`, options);
3709
+ }
3710
+ checkWithinRange(data.length, meta, "string length", options);
3711
+ return [data];
3712
+ });
3713
+ function decimalShift(data, digits) {
3714
+ const str = data.toString();
3715
+ if (str.includes("e")) return data * Math.pow(10, digits);
3716
+ const index = str.indexOf(".");
3717
+ if (index === -1) return data * Math.pow(10, digits);
3718
+ const frac = str.slice(index + 1);
3719
+ const integer = str.slice(0, index);
3720
+ if (frac.length <= digits) return +(integer + frac.padEnd(digits, "0"));
3721
+ return +(integer + frac.slice(0, digits) + "." + frac.slice(digits));
3722
+ }
3723
+ function isMultipleOf(data, min, step) {
3724
+ step = Math.abs(step);
3725
+ if (!/^\d+\.\d+$/.test(step.toString())) return (data - min) % step === 0;
3726
+ const index = step.toString().indexOf(".");
3727
+ const digits = step.toString().slice(index + 1).length;
3728
+ return Math.abs(decimalShift(data, digits) - decimalShift(min, digits)) % decimalShift(step, digits) === 0;
3729
+ }
3730
+ Schema.extend("number", (data, { meta }, options) => {
3731
+ if (typeof data !== "number") throw new ValidationError(`expected number but got ${data}`, options);
3732
+ checkWithinRange(data, meta, "number", options);
3733
+ const { step } = meta;
3734
+ if (step && !isMultipleOf(data, meta.min ?? 0, step)) throw new ValidationError(`expected number multiple of ${step} but got ${data}`, options);
3735
+ return [data];
3736
+ });
3737
+ Schema.extend("boolean", (data, _, options) => {
3738
+ if (typeof data === "boolean") return [data];
3739
+ throw new ValidationError(`expected boolean but got ${data}`, options);
3740
+ });
3741
+ Schema.extend("bitset", (data, { bits, meta }, options) => {
3742
+ let value = 0, keys = [];
3743
+ if (typeof data === "number") {
3744
+ value = data;
3745
+ for (const key in bits) if (data & bits[key]) keys.push(key);
3746
+ } else if (Array.isArray(data)) {
3747
+ keys = data;
3748
+ for (const key of keys) {
3749
+ if (typeof key !== "string") throw new ValidationError(`expected string but got ${key}`, options);
3750
+ if (key in bits) value |= bits[key];
3751
+ }
3752
+ } else throw new ValidationError(`expected number or array but got ${data}`, options);
3753
+ if (value === meta.default) return [value];
3754
+ return [value, keys];
3755
+ });
3756
+ Schema.extend("function", (data, _, options) => {
3757
+ if (typeof data === "function") return [data];
3758
+ throw new ValidationError(`expected function but got ${data}`, options);
3759
+ });
3760
+ Schema.extend("is", (data, { constructor }, options) => {
3761
+ if (typeof constructor === "function") {
3762
+ if (data instanceof constructor) return [data];
3763
+ throw new ValidationError(`expected ${constructor.name} but got ${data}`, options);
3764
+ } else {
3765
+ if (isNullable(data)) throw new ValidationError(`expected ${constructor} but got ${data}`, options);
3766
+ let prototype = Object.getPrototypeOf(data);
3767
+ while (prototype) {
3768
+ if (prototype.constructor?.name === constructor) return [data];
3769
+ prototype = Object.getPrototypeOf(prototype);
3770
+ }
3771
+ throw new ValidationError(`expected ${constructor} but got ${data}`, options);
3772
+ }
3773
+ });
3774
+ function property(data, key, schema, options) {
3775
+ try {
3776
+ const [value, adapted] = Schema.resolve(data[key], schema, {
3777
+ ...options,
3778
+ path: [...options.path || [], key]
3779
+ });
3780
+ if (adapted !== void 0) data[key] = adapted;
3781
+ return value;
3782
+ } catch (e) {
3783
+ if (!options?.autofix) throw e;
3784
+ delete data[key];
3785
+ return schema.meta.volatile ? createVolatile(schema.meta.default) : schema.meta.default;
3786
+ }
3787
+ }
3788
+ Schema.extend("array", (data, { inner, meta }, options) => {
3789
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
3790
+ checkWithinRange(data.length, meta, "array length", options, !isNullable(inner.meta.default));
3791
+ return [data.map((_, index) => property(data, index, inner, options))];
3792
+ });
3793
+ Schema.extend("dict", (data, { inner, sKey }, options, strict) => {
3794
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
3795
+ const result = {};
3796
+ for (const key in data) {
3797
+ let rKey;
3798
+ try {
3799
+ rKey = Schema.resolve(key, sKey, options)[0];
3800
+ } catch (error) {
3801
+ if (strict) continue;
3802
+ throw error;
3803
+ }
3804
+ result[rKey] = property(data, key, inner, options);
3805
+ data[rKey] = data[key];
3806
+ if (key !== rKey) delete data[key];
3807
+ }
3808
+ return [result];
3809
+ });
3810
+ Schema.extend("tuple", (data, { list }, options, strict) => {
3811
+ if (!Array.isArray(data)) throw new ValidationError(`expected array but got ${data}`, options);
3812
+ const result = list.map((inner, index) => property(data, index, inner, options));
3813
+ if (strict) return [result];
3814
+ result.push(...data.slice(list.length));
3815
+ return [result];
3816
+ });
3817
+ function merge(result, data) {
3818
+ for (const key in data) {
3819
+ if (key in result) continue;
3820
+ result[key] = data[key];
3821
+ }
3822
+ }
3823
+ Schema.extend("object", (data, { dict }, options, strict) => {
3824
+ if (!isPlainObject(data)) throw new ValidationError(`expected object but got ${data}`, options);
3825
+ const result = {};
3826
+ for (const key in dict) {
3827
+ const value = property(data, key, dict[key], options);
3828
+ if (!isNullable(value) || key in data) result[key] = value;
3829
+ }
3830
+ if (!strict) merge(result, data);
3831
+ return [result];
3832
+ });
3833
+ Schema.extend("union", (data, { list, toString }, options, strict) => {
3834
+ const messages = [];
3835
+ for (const inner of list) try {
3836
+ return Schema.resolve(data, inner, options, strict);
3837
+ } catch (error) {
3838
+ messages.push(error);
3839
+ }
3840
+ throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3841
+ });
3842
+ Schema.extend("intersect", (data, { list, toString }, options, strict) => {
3843
+ if (!list.length) return [data];
3844
+ let result;
3845
+ for (const inner of list) {
3846
+ const value = Schema.resolve(data, inner, options, true)[0];
3847
+ if (isNullable(value)) continue;
3848
+ if (isNullable(result)) result = value;
3849
+ else if (typeof result !== typeof value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3850
+ else if (typeof value === "object") merge(result ??= {}, value);
3851
+ else if (result !== value) throw new ValidationError(`expected ${toString()} but got ${JSON.stringify(data)}`, options);
3852
+ }
3853
+ if (!strict && isPlainObject(data)) merge(result, data);
3854
+ return [result];
3855
+ });
3856
+ Schema.extend("transform", (data, { inner, callback, preserve }, options) => {
3857
+ const [result, adapted = data] = Schema.resolve(data, inner, options, true);
3858
+ if (preserve) return [callback(result)];
3859
+ else return [callback(result), callback(adapted)];
3860
+ });
3861
+ const formatters = {};
3862
+ function defineMethod(name, keys, format) {
3863
+ formatters[name] = format;
3864
+ Object.assign(Schema, { [name](...args) {
3865
+ const schema = new Schema({ type: name });
3866
+ keys.forEach((key, index) => {
3867
+ switch (key) {
3868
+ case "sKey":
3869
+ schema.sKey = args[index] ?? Schema.string();
3870
+ break;
3871
+ case "inner":
3872
+ schema.inner = Schema.from(args[index]);
3873
+ break;
3874
+ case "list":
3875
+ schema.list = args[index].map(Schema.from);
3876
+ break;
3877
+ case "dict":
3878
+ schema.dict = mapValues(args[index], Schema.from);
3879
+ break;
3880
+ case "bits":
3881
+ schema.bits = {};
3882
+ for (const key in args[index]) {
3883
+ if (typeof args[index][key] !== "number") continue;
3884
+ schema.bits[key] = args[index][key];
3885
+ }
3886
+ break;
3887
+ case "callback": {
3888
+ const callback = schema.callback = args[index];
3889
+ callback["toJSON"] ||= () => callback.toString();
3890
+ break;
3891
+ }
3892
+ case "constructor": {
3893
+ const constructor = schema.constructor = args[index];
3894
+ if (typeof constructor === "function") constructor["toJSON"] ||= () => constructor["name"];
3895
+ break;
3896
+ }
3897
+ default: schema[key] = args[index];
3898
+ }
3899
+ });
3900
+ if (name === "object" || name === "dict") schema.meta.default = {};
3901
+ else if (name === "array" || name === "tuple") schema.meta.default = [];
3902
+ else if (name === "bitset") schema.meta.default = 0;
3903
+ return schema;
3904
+ } });
3905
+ }
3906
+ defineMethod("is", ["constructor"], ({ constructor }) => {
3907
+ if (typeof constructor === "function") return constructor.name;
3908
+ else return constructor;
3909
+ });
3910
+ defineMethod("any", [], () => "any");
3911
+ defineMethod("never", [], () => "never");
3912
+ defineMethod("const", ["value"], ({ value }) => typeof value === "string" ? JSON.stringify(value) : value);
3913
+ defineMethod("string", [], () => "string");
3914
+ defineMethod("number", [], () => "number");
3915
+ defineMethod("boolean", [], () => "boolean");
3916
+ defineMethod("bitset", ["bits"], () => "bitset");
3917
+ defineMethod("function", [], () => "function");
3918
+ defineMethod("array", ["inner"], ({ inner }) => `${inner.toString(true)}[]`);
3919
+ defineMethod("dict", ["inner", "sKey"], ({ inner, sKey }) => `{ [key: ${sKey.toString()}]: ${inner.toString()} }`);
3920
+ defineMethod("tuple", ["list"], ({ list }) => `[${list.map((inner) => inner.toString()).join(", ")}]`);
3921
+ defineMethod("object", ["dict"], ({ dict }) => {
3922
+ if (Object.keys(dict).length === 0) return "{}";
3923
+ return `{ ${Object.entries(dict).map(([key, inner]) => {
3924
+ return `${key}${inner.meta.required ? "" : "?"}: ${inner.toString()}`;
3925
+ }).join(", ")} }`;
3926
+ });
3927
+ defineMethod("union", ["list"], ({ list }, inline) => {
3928
+ const result = list.map(({ toString: format }) => format()).join(" | ");
3929
+ return inline ? `(${result})` : result;
3930
+ });
3931
+ defineMethod("intersect", ["list"], ({ list }) => {
3932
+ return `${list.map((inner) => inner.toString(true)).join(" & ")}`;
3933
+ });
3934
+ defineMethod("transform", [
3935
+ "inner",
3936
+ "callback",
3937
+ "preserve"
3938
+ ], ({ inner }, isInner) => inner.toString(isInner));
3939
+ //#endregion
3940
+ //#region lib/types/onboarding-config.js
3941
+ /** Public page-bootstrap options shared by the Host and Client halves. */
3942
+ /** Validate Host configuration and its public page-bootstrap payload. */
3943
+ const Config = Schema.object({ credentialOnboarding: Schema.boolean().default(true) });
3944
+ /** Page-global key carrying only the public onboarding options. */
3945
+ const ONBOARDING_CONFIG_GLOBAL = "__DSH_MODELS_ONBOARDING__";
3946
+ //#endregion
2884
3947
  //#region lib/types/client/index.js
2885
3948
  /** Dictionary namespace owned by this plugin. */
2886
3949
  const NS = "settings.models";
@@ -2905,7 +3968,7 @@ window.__ModuleLoader__.load({
2905
3968
  "remote.credentials",
2906
3969
  "remote.llm",
2907
3970
  "remote.settings",
2908
- "settingsScope",
3971
+ "configForms",
2909
3972
  "settingsSchema"
2910
3973
  ];
2911
3974
  /**
@@ -2915,13 +3978,15 @@ window.__ModuleLoader__.load({
2915
3978
  * @param ctx - client root context.
2916
3979
  */
2917
3980
  function apply(ctx) {
3981
+ const payload = globalThis[ONBOARDING_CONFIG_GLOBAL];
3982
+ const credentialOnboarding = Config(payload === void 0 ? {} : payload).credentialOnboarding && !("dshDesktop" in globalThis);
2918
3983
  ctx.effect(() => ctx.locale.register(NS, {
2919
3984
  zh,
2920
3985
  en
2921
3986
  }), "ui-settings-models: copy dictionaries");
2922
3987
  const schema = createSettingsSchemaOperations(ctx.settingsSchema);
2923
3988
  const operations = createModelsOperations(ctx);
2924
- const controller = new ModelsSettingsStore(ctx, schema, ctx.settingsScope.describe());
3989
+ const controller = new ModelsSettingsStore(ctx, schema, ctx.configForms.describe());
2925
3990
  const t = ctx.locale.bind(NS);
2926
3991
  const injected = () => ({
2927
3992
  controller,
@@ -2931,16 +3996,14 @@ window.__ModuleLoader__.load({
2931
3996
  t
2932
3997
  });
2933
3998
  const deepSeekOnboardingInjected = () => ({
3999
+ automatic: credentialOnboarding,
2934
4000
  controller,
2935
4001
  hooks: { models: controller.store },
2936
4002
  operations,
2937
4003
  schema,
2938
4004
  t
2939
4005
  });
2940
- const welcomeController = new WelcomeNoticeStore(ctx.settingsScope.bind({
2941
- namespace: WELCOME_NOTICE_SETTINGS_NAMESPACE,
2942
- decode: decodeWelcomeSection
2943
- }));
4006
+ const welcomeController = new WelcomeNoticeStore(ctx.configForms.get(WELCOME_NOTICE_SETTINGS_NAMESPACE));
2944
4007
  const welcomeInjected = () => ({
2945
4008
  controller: welcomeController,
2946
4009
  hooks: { welcome: welcomeController.store },
@@ -2989,6 +4052,10 @@ window.__ModuleLoader__.load({
2989
4052
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
2990
4053
  name: "settings.onboarding",
2991
4054
  id: "deepseek-official",
4055
+ children: { "settings.models.sign-in": {
4056
+ kind: "single",
4057
+ scope: "root"
4058
+ } },
2992
4059
  order: 0,
2993
4060
  inject: deepSeekOnboardingInjected
2994
4061
  }, DeepSeekOnboardingDialog));