@noob-stupid/dsh-plugin-console 0.3.29 → 0.3.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/client.js +384 -59
  2. package/lib/index.js +507 -54
  3. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -6,7 +6,7 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
8
  //#region styles
9
- const css = ".pc_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}.pc_section h3{margin:0;font-size:13px;font-weight:600;line-height:20px}.pc_message{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0}.pc_messageRow{display:flex;align-items:center;gap:10px}.pc_spinner{width:14px;height:14px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}@keyframes pcspin{to{transform:rotate(360deg)}}.pc_message[data-error=true]{color:var(--dsw-alias-state-error-primary)}.pc_list{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none;display:grid}.pc_row{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_rowTop{align-items:center;gap:8px;display:flex}.pc_name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pc_tag{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:16px;flex:none}.pc_tag[data-enabled=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-user=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_tag[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_status[data-pending=true]{color:var(--dsw-alias-state-warning-primary)}.pc_toggle[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-skill=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-system=true]{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}.pc_tag[data-disabled=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tag[data-suite=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-error=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tabGroup{display:inline-flex;gap:4px;align-items:center}.pc_meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;gap:6px;display:flex;align-items:center}.pc_phase[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.pc_phase[data-phase=active]{color:var(--dsw-alias-state-success-primary)}.pc_toggle{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_toggle:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_toggle:disabled{opacity:.5;cursor:default}.pc_search{gap:8px;display:flex}.pc_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;flex:1;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 12px;font-size:13px}.pc_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.pc_search button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:0 14px;font-size:13px}.pc_search button:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_market{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pc_item{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_itemTop{align-items:center;gap:8px;display:flex}.pc_itemTop a{color:var(--dsw-alias-state-business-primary);font-size:13px;font-weight:600;text-decoration:none;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pc_stars{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none}.pc_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_item button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:3px 10px;align-self:flex-start;font-size:12px}.pc_item button:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_item button:disabled{opacity:.5;cursor:default}.pc_detail{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_status{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_note{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0}.pc_marketHead{display:flex;align-items:center;justify-content:space-between;gap:10px}.pc_descWrap{flex-direction:column;display:flex}.pc_installedHead{display:flex;align-items:center;gap:10px}.pc_backTopWrap{position:fixed;top:56px;right:20px;z-index:100;display:flex;flex-direction:column;gap:8px}.pc_backTop{width:34px;height:34px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:rgba(22,27,34,.72);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;backdrop-filter:blur(4px);opacity:.7}.pc_backTop:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_descTopbar{display:flex;justify-content:flex-end;margin:2px 0}.pc_ghpill{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 10px;font-size:11px;line-height:18px}.pc_ghpill[data-on=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_extraBtn{opacity:.75;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 10px;font-size:12px;line-height:16px;flex:none;transition:opacity .15s ease,border-color 1.5s ease,color 1.5s ease}.pc_extraBtn:hover{opacity:1}.pc_extraBtn[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_extraBtn[data-flash=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_view{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px;flex:none}.pc_floatPanel{position:fixed;left:20px;top:50%;transform:translateY(-50%);width:340px;max-height:75vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:50;flex-direction:column;gap:8px;display:flex}.pc_refresh{position:sticky;bottom:14px;align-self:flex-end;margin-top:8px;z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_refresh:hover{opacity:.9}.pc_date{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;flex:none}.pc_searchInner{position:relative;flex:1;display:flex;align-items:center;min-width:0}.pc_searchInner input{padding-right:32px;width:100%}.pc_starBtn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:13px;line-height:1;padding:4px 8px;border-radius:6px;opacity:.75;transition:opacity .15s ease;flex:none}.pc_starBtn:hover{opacity:1}.pc_starBtn[data-active=true]{opacity:1;color:var(--dsw-alias-state-business-primary)}.pc_restartBtn{position:fixed;right:20px;top:50%;transform:translateY(-50%);z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_restartBtn:hover{opacity:.9}.pc_relaunchFloat{position:fixed;left:20px;top:50%;transform:translateY(-50%);z-index:70;opacity:.85;border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_relaunchFloat:hover{opacity:1}.pc_aiToggle{position:fixed;right:20px;top:20px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiToggle:hover{opacity:1}.pc_aiToggle[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_sourcesFloat{position:fixed;right:20px;top:104px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_sourcesFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat{position:fixed;right:20px;top:204px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_modeFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_trashBtn{border:0;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:12px;line-height:16px;padding:2px 6px;flex:none;display:flex;align-items:center;border-radius:6px;transition:color .15s ease}.pc_trashBtn:hover{color:var(--dsw-alias-state-error-primary)}.pc_consentRemember{display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-secondary);cursor:pointer}.pc_modalBackdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center}.pc_modalCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:16px 18px;max-width:420px;width:calc(100% - 48px);flex-direction:column;gap:10px;display:flex;box-shadow:0 12px 32px rgba(0,0,0,.25)}.pc_ghpill{background:0 0;cursor:pointer}.pc_ghwrap{position:relative;display:inline-flex}.pc_sourceMenu{position:absolute;right:0;top:calc(100% + 6px);z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:4px;flex-direction:column;display:flex;min-width:120px;box-shadow:0 8px 24px rgba(0,0,0,.18)}.pc_sourceOpt{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 10px;text-align:left;font-size:12px;line-height:16px}.pc_sourceOpt[data-active=true]{color:var(--dsw-alias-state-business-primary);font-weight:600}.pc_sourceOpt:hover{background:var(--dsw-alias-bg-layer-3)}.pc_aiEmpower{position:fixed;right:20px;top:48px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiEmpower:hover{opacity:.9}.pc_aiEmpower[data-busy=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_aiEmpower[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_compCard{position:fixed;left:8px;top:20px;width:320px;max-height:70vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:45;flex-direction:column;gap:8px;display:flex}.pc_compCard .pc_rowTop{flex-wrap:wrap}.pc_compCard .pc_toggle{padding:3px 8px;font-size:11px}.pc_compCard[data-hidden=true]{display:none}.pc_compDrop{background:rgba(24,28,34,.92);backdrop-filter:blur(6px);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,.35);flex-direction:column;display:flex;gap:2px}.pc_compDropRow{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 8px;text-align:left;font-size:12px;line-height:16px;flex-direction:column;display:flex;gap:2px}.pc_compDropRow:hover{background:var(--dsw-alias-bg-layer-2)}.pc_compDropUrl{color:var(--dsw-alias-label-tertiary);font-size:11px;word-break:break-all}.pc_compToggle{position:fixed;left:336px;top:20px;z-index:46;opacity:.55;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:rgba(22,27,34,.72);font:inherit;cursor:pointer;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;backdrop-filter:blur(4px);transition:opacity .15s ease}.pc_compToggle:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain{position:fixed;right:70px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:border-color .15s ease}.pc_toolbarMain:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain[data-active=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolbarGroup{position:fixed;right:70px;top:56px;z-index:70;flex-direction:column;gap:8px;display:flex;transform-origin:top right;animation:pcDrawerIn .3s cubic-bezier(.34,1.56,.64,1)}@media (max-width:1160px){.pc_toolbarMain{top:104px}.pc_toolbarGroup{top:140px}.pc_aiToggle{top:104px}.pc_aiEmpower{top:132px}.pc_sourcesFloat{top:188px}.pc_modeFloat{top:288px}}@keyframes pcDrawerIn{from{opacity:0;transform:translateX(28px) scale(.94)}to{opacity:1;transform:translateX(0) scale(1)}}.pc_toolItem{opacity:.85;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_toolItem:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_switch{width:34px;height:18px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);position:relative;cursor:pointer;flex:none;transition:background .15s ease,border-color .15s ease}.pc_switch:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_switch[data-on=true]{background:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.pc_switchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;transition:left .15s ease}.pc_switch[data-on=true] .pc_switchKnob{left:18px}.pc_aiSpinner{width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}.pc_aiSpinBtn{position:fixed;right:152px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px}.pc_aiSpinBtn:hover{border-color:var(--dsw-alias-state-business-primary)}";
9
+ const css = ".pc_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}.pc_section h3{margin:0;font-size:13px;font-weight:600;line-height:20px}.pc_message{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0}.pc_messageRow{display:flex;align-items:center;gap:10px}.pc_spinner{width:14px;height:14px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}@keyframes pcspin{to{transform:rotate(360deg)}}.pc_message[data-error=true]{color:var(--dsw-alias-state-error-primary)}.pc_message[data-warn=true]{color:var(--dsw-alias-state-warning-primary)}.pc_list{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none;display:grid}.pc_row{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_rowTop{align-items:center;gap:8px;display:flex}.pc_name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pc_tag{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:16px;flex:none}.pc_tag[data-enabled=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-user=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_tag[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_status[data-pending=true]{color:var(--dsw-alias-state-warning-primary)}.pc_toggle[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-skill=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-system=true]{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}.pc_tag[data-disabled=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tag[data-suite=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-error=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tabGroup{display:inline-flex;gap:4px;align-items:center}.pc_meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;gap:6px;display:flex;align-items:center}.pc_phase[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.pc_phase[data-phase=active]{color:var(--dsw-alias-state-success-primary)}.pc_toggle{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_toggle:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_toggle:disabled{opacity:.5;cursor:default}.pc_search{gap:8px;display:flex}.pc_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;flex:1;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 12px;font-size:13px}.pc_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.pc_search button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:0 14px;font-size:13px}.pc_search button:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_market{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pc_item{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_itemTop{align-items:center;gap:8px;display:flex}.pc_itemTop a{color:var(--dsw-alias-state-business-primary);font-size:13px;font-weight:600;text-decoration:none;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pc_stars{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none}.pc_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_item button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:3px 10px;align-self:flex-start;font-size:12px}.pc_item button:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_item button:disabled{opacity:.5;cursor:default}.pc_detail{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_status{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_note{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0}.pc_marketHead{display:flex;align-items:center;justify-content:space-between;gap:10px}.pc_descWrap{flex-direction:column;display:flex}.pc_installedHead{display:flex;align-items:center;gap:10px}.pc_backTopWrap{position:fixed;top:56px;right:20px;z-index:100;display:flex;flex-direction:column;gap:8px}.pc_backTop{width:34px;height:34px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:rgba(22,27,34,.72);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;backdrop-filter:blur(4px);opacity:.7}.pc_backTop:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_descTopbar{display:flex;justify-content:flex-end;margin:2px 0}.pc_ghpill{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 10px;font-size:11px;line-height:18px}.pc_ghpill[data-on=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_extraBtn{opacity:.75;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 10px;font-size:12px;line-height:16px;flex:none;transition:opacity .15s ease,border-color 1.5s ease,color 1.5s ease}.pc_extraBtn:hover{opacity:1}.pc_extraBtn[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_extraBtn[data-flash=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_view{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px;flex:none}.pc_floatPanel{position:fixed;left:20px;top:50%;transform:translateY(-50%);width:340px;max-height:75vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:50;flex-direction:column;gap:8px;display:flex}.pc_refresh{position:sticky;bottom:14px;align-self:flex-end;margin-top:8px;z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_refresh:hover{opacity:.9}.pc_date{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;flex:none}.pc_searchInner{position:relative;flex:1;display:flex;align-items:center;min-width:0}.pc_searchInner input{padding-right:32px;width:100%}.pc_starBtn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:13px;line-height:1;padding:4px 8px;border-radius:6px;opacity:.75;transition:opacity .15s ease;flex:none}.pc_starBtn:hover{opacity:1}.pc_starBtn[data-active=true]{opacity:1;color:var(--dsw-alias-state-business-primary)}.pc_restartBtn{position:fixed;right:20px;top:50%;transform:translateY(-50%);z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_restartBtn:hover{opacity:.9}.pc_relaunchFloat{position:fixed;left:20px;top:50%;transform:translateY(-50%);z-index:70;opacity:.85;border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_relaunchFloat:hover{opacity:1}.pc_aiToggle{position:fixed;right:20px;top:20px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiToggle:hover{opacity:1}.pc_aiToggle[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_sourcesFloat{position:fixed;right:20px;top:104px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_sourcesFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat{position:fixed;right:20px;top:204px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_modeFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_trashBtn{border:0;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:12px;line-height:16px;padding:2px 6px;flex:none;display:flex;align-items:center;border-radius:6px;transition:color .15s ease}.pc_trashBtn:hover{color:var(--dsw-alias-state-error-primary)}.pc_consentRemember{display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-secondary);cursor:pointer}.pc_modalBackdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center}.pc_modalCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:16px 18px;width:min(760px,calc(100vw - 64px));max-height:calc(100vh - 96px);overflow-y:auto;overscroll-behavior:contain;flex-direction:column;gap:10px;display:flex;box-shadow:0 12px 32px rgba(0,0,0,.25)}.pc_modalCard::-webkit-scrollbar{width:8px}.pc_modalCard::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:4px}.pc_srcUrl{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}.pc_accWrap{display:flex;flex-direction:column;gap:8px}.pc_acc{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;overflow:hidden;background:var(--dsw-alias-bg-layer-2)}.pc_accHead{width:100%;text-align:left;background:transparent;border:0;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;font-weight:600;line-height:20px;padding:8px 12px;cursor:pointer;display:flex;align-items:center;gap:6px}.pc_accHead:hover{background:var(--dsw-alias-bg-layer-3)}.pc_accHead[data-open=true]{border-bottom:1px solid var(--dsw-alias-border-l2)}.pc_accBody{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.pc_ghpill{background:0 0;cursor:pointer}.pc_ghwrap{position:relative;display:inline-flex}.pc_sourceMenu{position:absolute;right:0;top:calc(100% + 6px);z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:4px;flex-direction:column;display:flex;min-width:120px;box-shadow:0 8px 24px rgba(0,0,0,.18)}.pc_sourceOpt{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 10px;text-align:left;font-size:12px;line-height:16px}.pc_sourceOpt[data-active=true]{color:var(--dsw-alias-state-business-primary);font-weight:600}.pc_sourceOpt:hover{background:var(--dsw-alias-bg-layer-3)}.pc_aiEmpower{position:fixed;right:20px;top:48px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiEmpower:hover{opacity:.9}.pc_aiEmpower[data-busy=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_aiEmpower[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_compCard{position:fixed;left:8px;top:20px;width:320px;max-height:70vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:45;flex-direction:column;gap:8px;display:flex}.pc_compCard .pc_rowTop{flex-wrap:wrap}.pc_compCard .pc_toggle{padding:3px 8px;font-size:11px}.pc_compCard[data-hidden=true]{display:none}.pc_compDrop{background:rgba(24,28,34,.92);backdrop-filter:blur(6px);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,.35);flex-direction:column;display:flex;gap:2px}.pc_compDropRow{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 8px;text-align:left;font-size:12px;line-height:16px;flex-direction:column;display:flex;gap:2px}.pc_compDropRow:hover{background:var(--dsw-alias-bg-layer-2)}.pc_compDropUrl{color:var(--dsw-alias-label-tertiary);font-size:11px;word-break:break-all}.pc_compToggle{position:fixed;left:336px;top:20px;z-index:46;opacity:.55;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:rgba(22,27,34,.72);font:inherit;cursor:pointer;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;backdrop-filter:blur(4px);transition:opacity .15s ease}.pc_compToggle:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain{position:fixed;right:70px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:border-color .15s ease}.pc_toolbarMain:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain[data-active=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolbarGroup{position:fixed;right:70px;top:56px;z-index:70;flex-direction:column;gap:8px;display:flex;transform-origin:top right;animation:pcDrawerIn .3s cubic-bezier(.34,1.56,.64,1)}@media (max-width:1160px){.pc_toolbarMain{top:104px}.pc_toolbarGroup{top:140px}.pc_aiToggle{top:104px}.pc_aiEmpower{top:132px}.pc_sourcesFloat{top:188px}.pc_modeFloat{top:288px}}@keyframes pcDrawerIn{from{opacity:0;transform:translateX(28px) scale(.94)}to{opacity:1;transform:translateX(0) scale(1)}}.pc_toolItem{opacity:.85;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_toolItem:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_switch{width:34px;height:18px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);position:relative;cursor:pointer;flex:none;transition:background .15s ease,border-color .15s ease}.pc_switch:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_switch[data-on=true]{background:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.pc_switchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;transition:left .15s ease}.pc_switch[data-on=true] .pc_switchKnob{left:18px}.pc_aiSpinner{width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}.pc_aiSpinBtn{position:fixed;right:152px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px}.pc_aiSpinBtn:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_tag[data-bad=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}";
10
10
  const tagId = "@noob-stupid/dsh-plugin-console/PluginConsoleTab.css";
11
11
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
12
12
  const tag = document.createElement("style");
@@ -56,6 +56,11 @@ window.__ModuleLoader__.load({
56
56
  pcSwitch: "pc_switch",
57
57
  pcSwitchKnob: "pc_switchKnob",
58
58
  sourcesFloat: "pc_sourcesFloat",
59
+ srcUrl: "pc_srcUrl",
60
+ accWrap: "pc_accWrap",
61
+ acc: "pc_acc",
62
+ accHead: "pc_accHead",
63
+ accBody: "pc_accBody",
59
64
  modeFloat: "pc_modeFloat",
60
65
  trashBtn: "pc_trashBtn",
61
66
  consentRemember: "pc_consentRemember",
@@ -241,8 +246,9 @@ window.__ModuleLoader__.load({
241
246
  toolbarOpenTitle: "展开功能包",
242
247
  toolbarCloseTitle: "收起功能包",
243
248
  repoLandLabel: "仓库落地",
244
- repoLandTitle: "仓库落地:从 GitHub 克隆任意项目到本地(~/.dsh/repos/,不限于 DSH 插件)",
245
- repoLandPlaceholder: "输入 owner/repo 或 GitHub 链接,如 deepseek-ai/deepseek-harness",
249
+ repoLandTitle: "仓库落地:用 Git 源「{source}」克隆任意项目到本地(~/.dsh/repos/,不限于 DSH 插件)",
250
+ repoLandSourceUnknown: "已配置的 Git 源",
251
+ repoLandPlaceholder: "输入 owner/repo 或仓库链接,如 deepseek-ai/deepseek-harness",
246
252
  repoLandBusy: "克隆中…(大仓库可能较慢)",
247
253
  repoLandDone: "已落地到:",
248
254
  repoLandOpenFolder: "打开文件夹",
@@ -266,9 +272,19 @@ window.__ModuleLoader__.load({
266
272
  dismissFailure: "关闭此条提示",
267
273
  sourcesBtn: "软件源",
268
274
  sourcesTitle: "软件源管理",
269
- sourcesDesc: "安装源(registry):安装时按主→备依次尝试;支持私有 / 内网 registry",
275
+ sourcesDesc: "分工:① 软件源 = 下载 npm 包(安装用);② 索引源 = 市场首页清单 JSON;③ Git 源 = 克隆仓库代码(无 npm 包时);④ 搜索源 = 搜索时查哪个平台——搜到之后仍按 ①/③ 下载",
270
276
  sourcePrimary: "主源",
271
277
  setPrimary: "设为主源",
278
+ registryScan: "扫描软件源",
279
+ registryScanHint: "逐个探测每个软件源:是否可达、响应延迟、以及该源上 dsh-plugin-console 的最新版本(用于判断主源是否最优)",
280
+ registryScanning: "正在扫描…",
281
+ registryScanSummary: "扫描完成:{ok}/{total} 个可达",
282
+ registryScanBest: "最新版本 {version} 来自:{name}",
283
+ registryScanNoVersion: "该源上没有这个包",
284
+ registryScanFail: "不可达",
285
+ setPrimaryHint: "设为主源:优先使用它,失败时自动回退到其他源",
286
+ editSourceHint: "编辑:修改这个源的名称与地址",
287
+ removeSourceHint: "删除:从列表中移除这个源(不影响已安装的插件)",
272
288
  removeSource: "删除",
273
289
  sourceName: "名称",
274
290
  sourceUrl: "地址(https://…)",
@@ -282,6 +298,21 @@ window.__ModuleLoader__.load({
282
298
  searchSourcesTitle: "搜索源",
283
299
  searchSourcesDesc: "搜索平台(点击登录标切换)。自定义源用 URL 模板:{q}=关键词、{page}=页码",
284
300
  addSearchSource: "添加搜索源",
301
+ indexSourcesTitle: "索引源",
302
+ indexSourcesDesc: "市场静态索引的下载地址(主源优先,其余依次重试)。可换成公司内网自建服务——注意:索引「内容」由那份 JSON 决定,把公共索引与内网私有插件索引一并托管即可在内网浏览;想同时看到两边条目,请打开下面的「合并所有索引源」",
303
+ indexMergeLabel: "合并所有索引源",
304
+ indexMergeDesc: "开启后:所有索引源的结果合并去重展示(公共索引 + 公司内网私有索引同时可见);关闭时按主→备只用一个源(内网优先,更快)",
305
+ addIndexSource: "添加索引源",
306
+ indexUrlPlaceholder: "索引 JSON 地址(https:// 或本机/私网 http://)",
307
+ gitSourcesTitle: "Git 源",
308
+ gitSourcesDesc: "克隆仓库时用的地址模板({owner}/{repo} 占位符)。下面这个列表就是「自定义 Git 源」——内置两条是默认值,点「添加 Git 源」即可换成你自己的:Gitee = https://gitee.com/{owner}/{repo}.git;GitLab = https://gitlab.com/{owner}/{repo}.git;自建 Gitea = https://你的域名/{owner}/{repo}.git;镜像代理 = https://镜像站/https://github.com/{owner}/{repo}.git;本地裸仓库 = file:///D:/repos/{owner}/{repo}.git。主源优先,失败自动回退下一个",
309
+ addGitSource: "添加 Git 源",
310
+ gitUrlPlaceholder: "如 https://gitee.com/{owner}/{repo}.git",
311
+ gitSourceBtn: "Git 源",
312
+ marketIndexOffline: "离线数据 · 缓存于 {time}(索引源不可达,已回退上次成功结果)",
313
+ marketIndexFrom: "索引来源:{source}",
314
+ marketIndexFailed: "市场索引加载失败",
315
+ unknown: "未知",
285
316
  searchUrlPlaceholder: "URL 模板(必须含 {q})",
286
317
  invalidSearchUrl: "搜索 URL 模板必须包含 {q} 占位符",
287
318
  headersPlaceholder: "请求头(可选):每行一个,格式 名称: 值,如 Authorization: Bearer 令牌",
@@ -558,8 +589,9 @@ window.__ModuleLoader__.load({
558
589
  toolbarOpenTitle: "Expand feature pack",
559
590
  toolbarCloseTitle: "Collapse feature pack",
560
591
  repoLandLabel: "Repo land",
561
- repoLandTitle: "Repo land: clone any GitHub project to ~/.dsh/repos/ (not limited to DSH plugins)",
562
- repoLandPlaceholder: "owner/repo or GitHub URL, e.g. deepseek-ai/deepseek-harness",
592
+ repoLandTitle: "Repo land: clone any project to ~/.dsh/repos/ via git source \"{source}\" (not limited to DSH plugins)",
593
+ repoLandSourceUnknown: "the configured git source",
594
+ repoLandPlaceholder: "owner/repo or repo URL, e.g. deepseek-ai/deepseek-harness",
563
595
  repoLandBusy: "Cloning… (large repos may take a while)",
564
596
  repoLandDone: "Landed at: ",
565
597
  repoLandOpenFolder: "Open folder",
@@ -583,9 +615,19 @@ window.__ModuleLoader__.load({
583
615
  dismissFailure: "Dismiss this notice",
584
616
  sourcesBtn: "Sources",
585
617
  sourcesTitle: "Software sources",
586
- sourcesDesc: "Install registries, tried primary-first; private / intranet registries supported",
618
+ sourcesDesc: "Roles: ① registry = download npm packages (install); ② index sources = market list JSON; ③ git sources = clone repo code (when no npm package); ④ search sources = where to search — results are still downloaded via ①/③",
587
619
  sourcePrimary: "Primary",
588
620
  setPrimary: "Set primary",
621
+ registryScan: "Scan sources",
622
+ registryScanHint: "Probe each npm registry: reachability, latency, and the latest dsh-plugin-console version it serves (to pick the best primary)",
623
+ registryScanning: "Scanning…",
624
+ registryScanSummary: "Scan complete: {ok}/{total} reachable",
625
+ registryScanBest: "Newest {version} comes from: {name}",
626
+ registryScanNoVersion: "Package not on this registry",
627
+ registryScanFail: "unreachable",
628
+ setPrimaryHint: "Set primary: tried first, falls back to the others on failure",
629
+ editSourceHint: "Edit: change this source's name and URL",
630
+ removeSourceHint: "Remove: delete this source from the list (installed plugins unaffected)",
589
631
  removeSource: "Remove",
590
632
  sourceName: "Name",
591
633
  sourceUrl: "URL (https://…)",
@@ -599,6 +641,21 @@ window.__ModuleLoader__.load({
599
641
  searchSourcesTitle: "Search sources",
600
642
  searchSourcesDesc: "Search platforms (switch via the pill). Custom sources use a URL template: {q}=keyword, {page}=page number",
601
643
  addSearchSource: "Add search source",
644
+ indexSourcesTitle: "Index sources",
645
+ indexSourcesDesc: "Download URLs for the static market index (primary first, others retried in order). Point this at an intranet service — note the index CONTENT comes from that JSON, so host a merged public+private index there. To see both sides at once, turn on \"Merge all index sources\" below",
646
+ indexMergeLabel: "Merge all index sources",
647
+ indexMergeDesc: "On: results from all index sources are merged and de-duplicated (public index + company intranet private index visible together). Off: only one source is used, primary first (intranet-friendly, faster)",
648
+ addIndexSource: "Add index source",
649
+ indexUrlPlaceholder: "Index JSON URL (https:// or local/intranet http://)",
650
+ gitSourcesTitle: "Git sources",
651
+ gitSourcesDesc: "URL template for cloning ({owner}/{repo} placeholders). This list IS the custom git-source list — the two built-ins are just defaults; click Add git source to swap in your own: Gitee = https://gitee.com/{owner}/{repo}.git; GitLab = https://gitlab.com/{owner}/{repo}.git; self-hosted Gitea = https://your-domain/{owner}/{repo}.git; mirror proxy = https://mirror/https://github.com/{owner}/{repo}.git; local bare repo = file:///D:/repos/{owner}/{repo}.git. Primary first, falls back on failure",
652
+ addGitSource: "Add Git source",
653
+ gitUrlPlaceholder: "e.g. https://gitee.com/{owner}/{repo}.git",
654
+ gitSourceBtn: "Git sources",
655
+ marketIndexOffline: "Offline data · cached {time} (index sources unreachable, showing last successful result)",
656
+ marketIndexFrom: "Index source: {source}",
657
+ marketIndexFailed: "Failed to load market index",
658
+ unknown: "unknown",
602
659
  searchUrlPlaceholder: "URL template (must contain {q})",
603
660
  invalidSearchUrl: "Search URL template must contain the {q} placeholder",
604
661
  headersPlaceholder: "Headers (optional): one per line, format Name: Value, e.g. Authorization: Bearer token",
@@ -965,23 +1022,31 @@ window.__ModuleLoader__.load({
965
1022
  return out;
966
1023
  }
967
1024
  /** 批量识别搜索结果:官方通道(根包 dsh.bundle)/ 聚合仓库(private+workspaces,子包才是插件)/ 普通项目。 */
968
- async function enrichOfficialBundle(items) {
969
- return Promise.all(items.map(async (item) => {
970
- let official = null;
971
- let aggregate = false;
972
- const pkgText = await fetchRawText(item.fullName, item.defaultBranch, "package.json", item.source ?? "github");
973
- if (pkgText !== null) {
974
- try {
975
- const pkg = JSON.parse(pkgText);
976
- if (typeof pkg.dsh?.bundle?.patch === "string") {
977
- official = true;
978
- } else if (pkg.private === true && (Array.isArray(pkg.workspaces) || /(^|-)dsh[-/]/u.test(String(pkg.name ?? "")))) {
979
- aggregate = true;
980
- }
981
- } catch {}
982
- }
983
- return { ...item, official, aggregate };
984
- }));
1025
+ /** 补标「官方 / 聚合」标记。每条要发网络请求(raw 多通道竞速),
1026
+ * 因此限制并发(默认 6 条一批),避免打满浏览器连接数拖慢整页。 */
1027
+ async function enrichOfficialBundle(items, concurrency = 6) {
1028
+ const out = [];
1029
+ for (let i = 0; i < items.length; i += concurrency) {
1030
+ const batch = items.slice(i, i + concurrency);
1031
+ const done = await Promise.all(batch.map(async (item) => {
1032
+ let official = null;
1033
+ let aggregate = false;
1034
+ const pkgText = await fetchRawText(item.fullName, item.defaultBranch, "package.json", item.source ?? "github");
1035
+ if (pkgText !== null) {
1036
+ try {
1037
+ const pkg = JSON.parse(pkgText);
1038
+ if (typeof pkg.dsh?.bundle?.patch === "string") {
1039
+ official = true;
1040
+ } else if (pkg.private === true && (Array.isArray(pkg.workspaces) || /(^|-)dsh[-/]/u.test(String(pkg.name ?? "")))) {
1041
+ aggregate = true;
1042
+ }
1043
+ } catch {}
1044
+ }
1045
+ return { ...item, official, aggregate };
1046
+ }));
1047
+ out.push(...done);
1048
+ }
1049
+ return out;
985
1050
  }
986
1051
  /** 源地址校验(与宿主端一致):https 任意;http 仅限本机/私网(内网源常用 http)。 */
987
1052
  function isAllowedSourceUrl(url) {
@@ -1028,6 +1093,87 @@ window.__ModuleLoader__.load({
1028
1093
  const [indexData, setIndexData] = react.useState(null);
1029
1094
  // 索引浏览当前展示条数(分页展示,避免一次渲染 500 条)
1030
1095
  const [indexShown, setIndexShown] = react.useState(50);
1096
+ // 已补标(官方/聚合标记)到的索引位置:随「加载更多」增量推进,避免一次性发上千请求
1097
+ const [enrichedUpTo, setEnrichedUpTo] = react.useState(0);
1098
+ /** 合并一条补标结果(不动已有标记,避免 null 覆盖)。 */
1099
+ function mergeEnrichMark(e, b) {
1100
+ return {
1101
+ ...e,
1102
+ official: e.official !== null ? e.official : (b?.official ?? null),
1103
+ aggregate: e.aggregate === true || b?.aggregate === true,
1104
+ aggregateInstallable: b?.aggregateInstallable === true,
1105
+ hasSkill: e.hasSkill === true || b?.hasSkill === true,
1106
+ hasSuite: e.hasSuite === true || b?.hasSuite === true,
1107
+ };
1108
+ }
1109
+ /** 服务端 /enrich 兜底:并发限流 12 + 24h 缓存,补齐客户端直连失败/遗漏的标记
1110
+ * (每次最多 30 条,按需分批;结果按位置合并回索引与当前展示切片)。 */
1111
+ function enrichRangeServer(from, slice) {
1112
+ const BATCH = 30;
1113
+ for (let i = 0; i < slice.length; i += BATCH) {
1114
+ const batch = slice.slice(i, i + BATCH);
1115
+ const start = from + i;
1116
+ call("/plugin-console/enrich", { items: batch }).then(
1117
+ (r) => {
1118
+ if (r === null || !Array.isArray(r.items)) return;
1119
+ const got = r.items;
1120
+ setIndexData((prev) => {
1121
+ if (prev === null || prev.loaded !== true) return prev;
1122
+ const items = [...prev.items];
1123
+ got.forEach((e, k) => {
1124
+ const idx = start + k;
1125
+ if (idx < items.length) items[idx] = mergeEnrichMark(e, items[idx]);
1126
+ });
1127
+ return { ...prev, items };
1128
+ });
1129
+ setMarket((prev) => {
1130
+ if (prev === null || prev.status !== "ready" || prev.fromIndex !== true) return prev;
1131
+ return {
1132
+ ...prev,
1133
+ data: prev.data.map((it) => {
1134
+ const hit = got.find((e) => e.fullName === it.fullName);
1135
+ return hit ? mergeEnrichMark(hit, it) : it;
1136
+ }),
1137
+ };
1138
+ });
1139
+ },
1140
+ () => {},
1141
+ );
1142
+ }
1143
+ }
1144
+ /** 增量补标索引区间 [from, to):首屏先补前 50 条,之后随「加载更多」继续往下补。 */
1145
+ function enrichRange(from, to, list) {
1146
+ const slice = (list ?? []).slice(from, to);
1147
+ if (slice.length === 0) return;
1148
+ enrichOfficialBundle(slice).then((enriched) => {
1149
+ if (!Array.isArray(enriched)) return;
1150
+ setIndexData((prev) => {
1151
+ if (prev === null || prev.loaded !== true) return prev;
1152
+ const items = [...prev.items];
1153
+ enriched.forEach((e, i) => {
1154
+ const idx = from + i;
1155
+ if (idx < items.length) items[idx] = mergeEnrichMark(e, items[idx]);
1156
+ });
1157
+ return { ...prev, items };
1158
+ });
1159
+ // 同步刷新当前展示的切片(引用变化才会重渲染)
1160
+ setMarket((prev) => {
1161
+ if (prev === null || prev.status !== "ready" || prev.fromIndex !== true) return prev;
1162
+ return {
1163
+ ...prev,
1164
+ data: prev.data.map((it) => {
1165
+ const hit = enriched.find((e) => e.fullName === it.fullName);
1166
+ return hit ? mergeEnrichMark(hit, it) : it;
1167
+ }),
1168
+ };
1169
+ });
1170
+ setEnrichedUpTo((prev) => Math.max(prev, to));
1171
+ });
1172
+ // ② 服务端 /enrich 兜底:延后 1.5 秒执行(不抢首屏带宽),走 24h 缓存 + 并发限流通道
1173
+ if (typeof window.setTimeout === "function") {
1174
+ window.setTimeout(() => enrichRangeServer(from, slice), 1500);
1175
+ }
1176
+ }
1031
1177
  // 市场总模式:'plugins' = 插件市场 / 'skills' = 技能市场(localStorage 持久化)
1032
1178
  const [mode, setMode] = react.useState(() => {
1033
1179
  try { return localStorage.getItem("pc-market-mode") === "skills" ? "skills" : "plugins"; } catch { return "plugins"; }
@@ -1310,7 +1456,7 @@ window.__ModuleLoader__.load({
1310
1456
  if (aiJob === null || aiJob.status !== "plan-ready") return;
1311
1457
  const steps = (aiJob.steps ?? []).map((s) => s.index).filter((i) => aiSelected[i]);
1312
1458
  if (steps.length === 0) {
1313
- setMessage(t("aiNeedSteps"));
1459
+ setMessage(t("aiEmpowerNeedSteps"));
1314
1460
  return;
1315
1461
  }
1316
1462
  if (!window.confirm(t("aiConfirmDeploy").replace("{n}", String(steps.length)).replace("{name}", aiJob.displayName ?? aiJob.source))) {
@@ -1392,10 +1538,22 @@ window.__ModuleLoader__.load({
1392
1538
  const [sourceName, setSourceName] = react.useState("");
1393
1539
  const [sourceUrl, setSourceUrl] = react.useState("");
1394
1540
  const [sourcesBusy, setSourcesBusy] = react.useState(false);
1541
+ // 软件源扫描结果:null=未扫描 / {status:'scanning'} / {status:'ready', results, scannedAt}
1542
+ const [regScan, setRegScan] = react.useState(null);
1395
1543
  // registry 行内编辑
1396
1544
  const [editReg, setEditReg] = react.useState(null);
1545
+ const [indexSourceName, setIndexSourceName] = react.useState("");
1546
+ const [indexSourceUrl, setIndexSourceUrl] = react.useState("");
1547
+ const [editIndex, setEditIndex] = react.useState(null);
1548
+ const [gitSourceName, setGitSourceName] = react.useState("");
1549
+ const [gitSourceUrl, setGitSourceUrl] = react.useState("");
1550
+ const [editGit, setEditGit] = react.useState(null);
1551
+ // 软件源弹窗折叠分区:软件源默认展开,其余收起(避免弹窗过长)
1552
+ const [openSections, setOpenSections] = react.useState({ registries: true, index: false, git: false, search: false, gitee: false });
1397
1553
  // 搜索源列表(内置 + 自定义,来自配置)
1398
1554
  const [searchSourcesList, setSearchSourcesList] = react.useState(null);
1555
+ // Git 源列表(「仓库落地」提示动态显示当前主源,避免写死 GitHub)
1556
+ const [gitSourcesList, setGitSourcesList] = react.useState(null);
1399
1557
  // 自定义搜索源添加表单
1400
1558
  const [searchSourceName, setSearchSourceName] = react.useState("");
1401
1559
  const [searchSourceUrl, setSearchSourceUrl] = react.useState("");
@@ -1436,37 +1594,37 @@ window.__ModuleLoader__.load({
1436
1594
  // 挂载时拉取软件源配置(搜索源菜单用,含自定义源)
1437
1595
  react.useEffect(() => {
1438
1596
  call("/plugin-console/sources").then(
1439
- (data) => setSearchSourcesList(data.sources.searchSources ?? []),
1597
+ (data) => {
1598
+ setSearchSourcesList(data.sources.searchSources ?? []);
1599
+ setGitSourcesList(data.sources.gitSources ?? []);
1600
+ },
1440
1601
  () => {},
1441
1602
  );
1442
1603
  }, []);
1443
1604
  // 挂载时加载静态插件索引(GitHub 源空查询时秒开浏览,零 API 调用)
1444
1605
  react.useEffect(() => {
1445
- call("/plugin-console/market-index").then(
1606
+ call("/plugin-console/market-index", {}).then(
1446
1607
  (data) => {
1447
1608
  if (data && Array.isArray(data.items)) {
1448
- setIndexData({ items: data.items, skills: Array.isArray(data.skills) ? data.skills : [], loaded: true });
1449
- // ★「只看官方」需要官方标记:索引条目补标(网络/服务端此前判定失败时不动已有标记,避免 null 覆盖)
1450
- // 服务端 /enrich 已带 24h 结果缓存时,此处仅兜底浏览器直连失败部分。
1451
- const base = data.items;
1452
- enrichOfficialBundle(base).then((enriched) => {
1453
- if (!Array.isArray(enriched)) return;
1454
- const merged = enriched.map((e, i) => {
1455
- const b = base[i] ?? {};
1456
- return {
1457
- ...e,
1458
- official: e.official !== null ? e.official : (b.official ?? null),
1459
- aggregate: e.aggregate === true || b.aggregate === true,
1460
- aggregateInstallable: b.aggregateInstallable === true,
1461
- hasSkill: e.hasSkill === true || b.hasSkill === true,
1462
- hasSuite: e.hasSuite === true || b.hasSuite === true,
1463
- };
1464
- });
1465
- setIndexData((prev) => (prev !== null && prev.loaded === true ? { ...prev, items: merged } : prev));
1609
+ setIndexData({
1610
+ items: data.items,
1611
+ skills: Array.isArray(data.skills) ? data.skills : [],
1612
+ loaded: true,
1613
+ offline: data.offline === true,
1614
+ cachedAt: typeof data.cachedAt === "number" ? data.cachedAt : null,
1615
+ sourceName: typeof data.sourceName === "string" ? data.sourceName : null,
1466
1616
  });
1617
+ // ★「只看官方」需要官方标记:先补首屏 50 条,其余随「加载更多」增量补
1618
+ //(每条要发网络请求,全量 500 条会打满浏览器连接数,导致打开插件页明显变慢)
1619
+ const runEnrich = () => enrichRange(0, 50, data.items);
1620
+ if (typeof window.requestIdleCallback === "function") {
1621
+ window.requestIdleCallback(() => runEnrich(), { timeout: 2000 });
1622
+ } else {
1623
+ window.setTimeout(runEnrich, 400);
1624
+ }
1467
1625
  }
1468
1626
  },
1469
- () => {},
1627
+ (error) => setMessage(t("marketIndexFailed") + ":" + (error?.message ?? t("unknown"))),
1470
1628
  );
1471
1629
  // 市场状态记忆:关闭前搜索过 → 重开时自动恢复该搜索(query 已从 localStorage 初始化)
1472
1630
  if (query !== "") {
@@ -1808,6 +1966,8 @@ window.__ModuleLoader__.load({
1808
1966
  const more = sourceData.slice(0, indexShown + next * 50);
1809
1967
  setMarket({ status: "ready", data: more, direct: false, source: "github", fromIndex: true });
1810
1968
  setIndexShown(indexShown + next * 50);
1969
+ // 新增的这段继续补「官方/聚合」标记(与首屏同样的增量策略)
1970
+ if (mode !== "skills") enrichRange(enrichedUpTo, indexShown + next * 50, indexData.items);
1811
1971
  setLoadingMore(false);
1812
1972
  return;
1813
1973
  }
@@ -2096,10 +2256,73 @@ window.__ModuleLoader__.load({
2096
2256
  }
2097
2257
  sourcesAction({ action: "add", name: sourceName.trim(), url: sourceUrl.trim() }, () => { setSourceName(""); setSourceUrl(""); });
2098
2258
  };
2259
+ /** 软件源扫描:服务端并发探测每个源(可达性/延迟/最新版本),结果显示在源列表行内。 */
2260
+ const scanRegistries = () => {
2261
+ setRegScan({ status: "scanning" });
2262
+ call("/plugin-console/registry-scan", {}).then(
2263
+ (data) => setRegScan({ status: "ready", results: Array.isArray(data.results) ? data.results : [], scannedAt: typeof data.scannedAt === "number" ? data.scannedAt : null }),
2264
+ (error) => { setRegScan(null); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
2265
+ );
2266
+ };
2267
+ // 扫描结果派生视图:每条源的命中结果 + 可达计数 + 最新版本来自哪个源
2268
+ const scanRows = regScan !== null && regScan.status === "ready" ? regScan.results : [];
2269
+ const scanOf = (id) => scanRows.find((row) => row.id === id) ?? null;
2270
+ const scanOkCount = scanRows.filter((row) => row.ok === true).length;
2271
+ const scanBest = (() => {
2272
+ const withVersion = scanRows.filter((row) => row.ok === true && typeof row.latest === "string");
2273
+ if (withVersion.length === 0) return null;
2274
+ const parse = (v) => String(v).split(".").map((n) => Number.parseInt(n, 10) || 0);
2275
+ const newer = (a, b) => {
2276
+ const [pa, pb] = [parse(a), parse(b)];
2277
+ for (let i = 0; i < 3; i += 1) if (pa[i] !== pb[i]) return pa[i] > pb[i];
2278
+ return false;
2279
+ };
2280
+ return withVersion.reduce((best, row) => (best === null || newer(row.latest, best.latest) ? row : best), null);
2281
+ })();
2099
2282
  const saveEditReg = () => {
2100
2283
  if (editReg === null) return;
2101
2284
  sourcesAction({ action: "edit", id: editReg.id, name: editReg.name, url: editReg.url }, () => setEditReg(null));
2102
2285
  };
2286
+ const addIndexSource = () => {
2287
+ if (!isAllowedSourceUrl(indexSourceUrl.trim())) {
2288
+ setMessage(t("failed") + ":" + t("invalidSourceUrl"));
2289
+ return;
2290
+ }
2291
+ sourcesAction({ action: "add-index", name: indexSourceName.trim(), url: indexSourceUrl.trim() }, () => { setIndexSourceName(""); setIndexSourceUrl(""); });
2292
+ };
2293
+ const saveEditIndex = () => {
2294
+ if (editIndex === null) return;
2295
+ sourcesAction({ action: "edit-index", id: editIndex.id, name: editIndex.name, url: editIndex.url }, () => setEditIndex(null));
2296
+ };
2297
+ const addGitSource = () => {
2298
+ const tpl = gitSourceUrl.trim();
2299
+ if (!tpl.includes("{owner}") || !tpl.includes("{repo}")) {
2300
+ setMessage(t("failed") + ":" + t("gitUrlPlaceholder"));
2301
+ return;
2302
+ }
2303
+ if (!isAllowedSourceUrl(tpl)) {
2304
+ setMessage(t("failed") + ":" + t("invalidSourceUrl"));
2305
+ return;
2306
+ }
2307
+ sourcesAction({ action: "add-git", name: gitSourceName.trim(), urlTemplate: tpl }, () => { setGitSourceName(""); setGitSourceUrl(""); });
2308
+ };
2309
+ const saveEditGit = () => {
2310
+ if (editGit === null) return;
2311
+ sourcesAction({ action: "edit-git", id: editGit.id, name: editGit.name, urlTemplate: editGit.urlTemplate }, () => setEditGit(null));
2312
+ };
2313
+ /** 折叠分区(软件源弹窗):标题可点,展开/收起各自独立;软件源默认展开。 */
2314
+ const accSection = (key, title, children) => {
2315
+ const open = openSections[key] === true;
2316
+ return el("div", { key, className: styles.acc },
2317
+ el("button", {
2318
+ type: "button",
2319
+ className: styles.accHead,
2320
+ "data-open": open ? "true" : "false",
2321
+ "aria-expanded": open ? "true" : "false",
2322
+ onClick: () => setOpenSections((prev) => ({ ...prev, [key]: !prev[key] })),
2323
+ }, (open ? "▾ " : "▸ ") + title),
2324
+ open ? el("div", { className: styles.accBody }, ...children) : null);
2325
+ };
2103
2326
  const addSearchSource = () => {
2104
2327
  if (!isAllowedSourceUrl(searchSourceUrl.trim()) || !searchSourceUrl.includes("{q}")) {
2105
2328
  setMessage(t("failed") + ":" + t("invalidSearchUrl"));
@@ -2284,6 +2507,12 @@ window.__ModuleLoader__.load({
2284
2507
  : source === "gitee"
2285
2508
  ? "Gitee"
2286
2509
  : ((searchSourcesList !== null ? searchSourcesList.find((s) => s.id === source)?.name : undefined) ?? source);
2510
+ // 仓库落地提示:动态带上当前主 Git 源名称(Git 源可自定义,不能写死 GitHub)
2511
+ const repoLandTitleText = () => {
2512
+ const primary = (gitSourcesList ?? []).find((s) => s.primary === true);
2513
+ const label = primary?.name ?? t("repoLandSourceUnknown");
2514
+ return t("repoLandTitle").replace("{source}", label);
2515
+ };
2287
2516
  const extraIds = new Set((state.status === "ready" ? state.data.patch?.inserts ?? [] : []));
2288
2517
  const extraCount = state.status === "ready" ? state.data.entries.filter((entry) => entry.extra === true || extraIds.has(entry.rowId)).length : 0;
2289
2518
  const pkgRootOf = (m) => { const mm = String(m ?? ""); const x = mm.match(/^(@[^/]+\/[^/]+)(?:\/.*)?$/u); return x ? x[1] : mm; };
@@ -2655,7 +2884,7 @@ window.__ModuleLoader__.load({
2655
2884
  ? el("button", {
2656
2885
  type: "button",
2657
2886
  className: styles.toggle,
2658
- title: t("repoLandTitle"),
2887
+ title: repoLandTitleText(),
2659
2888
  onClick: () => repoLandEntry(item.fullName),
2660
2889
  }, repoLanded.some((r) => r.repo === item.fullName) ? t("repoLandLanded") + " ✓" : t("repoLandEntry"))
2661
2890
  : null,
@@ -2953,7 +3182,7 @@ window.__ModuleLoader__.load({
2953
3182
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
2954
3183
  el("strong", { className: styles.name }, t("repoLandLabel")),
2955
3184
  el("button", { type: "button", className: styles.trashBtn, style: { fontSize: 14, padding: "4px 8px" }, title: t("closeModal"), "aria-label": t("closeModal"), onClick: () => { setRepoLandOpen(false); setRepoLandResult(null); } }, "✕")),
2956
- el("p", { className: styles.message }, t("repoLandTitle")),
3185
+ el("p", { className: styles.message }, repoLandTitleText()),
2957
3186
  el("div", { className: styles.rowTop, style: { flexWrap: "wrap" } },
2958
3187
  el("span", { className: styles.message }, t("repoLandDirLabel") + ":" + (repoLandDir || "—")),
2959
3188
  el("input", { type: "text", value: repoLandDirInput, onChange: (event) => setRepoLandDirInput(event.currentTarget.value), style: { flex: 1, minWidth: 120, font: "inherit", padding: "4px 8px", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-1)", color: "var(--dsw-alias-label-primary)" } }),
@@ -3199,7 +3428,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3199
3428
  type: "button",
3200
3429
  className: styles.toolItem,
3201
3430
  "data-active": repoLandOn ? "true" : "false",
3202
- title: t("repoLandTitle"),
3431
+ title: repoLandTitleText(),
3203
3432
  "aria-label": t("repoLandLabel"),
3204
3433
  onClick: () => { setRepoLandOn((v) => { const n = !v; try { localStorage.setItem("pc-repo-land", n ? "1" : "0"); } catch {} return n; }); setRepoLandOpen(true); repoLandRefresh(); },
3205
3434
  }, t("repoLandLabel")),
@@ -3276,6 +3505,11 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3276
3505
  ? t("skillsNote")
3277
3506
  : t("skillsGithubOnly"))
3278
3507
  : (searchSource === "github" ? t("direct") : t("directOther").replace("{source}", sourceDisplayName(searchSource)))),
3508
+ indexData !== null && indexData.offline === true
3509
+ ? el("p", { className: styles.message, "data-warn": "true" },
3510
+ t("marketIndexOffline").replace("{time}", indexData.cachedAt !== null ? new Date(indexData.cachedAt).toLocaleString() : "—")
3511
+ + (indexData.sourceName !== null ? " · " + t("marketIndexFrom").replace("{source}", indexData.sourceName) : ""))
3512
+ : null,
3279
3513
  el("div", { className: styles.search, id: "pc-market-search" },
3280
3514
  el("div", { className: styles.searchInner },
3281
3515
  el("input", {
@@ -3384,7 +3618,10 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3384
3618
  }, "✕")),
3385
3619
  el("p", { className: styles.message, "data-error": "true" }, job.error ?? ""),
3386
3620
  el("div", { className: styles.rowTop },
3387
- el("button", { type: "button", className: styles.toggle, onClick: () => startJob(job.repo, job.packageName, job.source ?? "github") }, t("retry")))),
3621
+ el("button", { type: "button", className: styles.toggle, onClick: () => startJob(job.repo, job.packageName, job.source ?? "github") }, t("retry")),
3622
+ job.hint === "repo-land"
3623
+ ? el("button", { type: "button", className: styles.toggle, title: repoLandTitleText(), onClick: () => { setRepoLandOpen(true); repoLandEntry(job.repo); } }, t("repoLandEntry"))
3624
+ : null)),
3388
3625
  ),
3389
3626
  repoInfo !== null
3390
3627
  ? el("aside", { className: styles.floatPanel },
@@ -3546,8 +3783,9 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3546
3783
  el("p", { className: styles.message }, t("sourcesDesc")),
3547
3784
  sourcesData === null
3548
3785
  ? el("p", { className: styles.status }, t("loading"))
3549
- : el("div", { style: { flexDirection: "column", gap: "8px", display: "flex" } },
3550
- sourcesData.registries.map((src) =>
3786
+ : el("div", { className: styles.accWrap },
3787
+ accSection("registries", t("sourcesBtn"), [
3788
+ ...sourcesData.registries.map((src) =>
3551
3789
  editReg !== null && editReg.id === src.id
3552
3790
  ? el("div", { key: src.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3553
3791
  el("input", { type: "text", value: editReg.name, onChange: (event) => setEditReg({ ...editReg, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
@@ -3557,15 +3795,99 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3557
3795
  : el("div", { key: src.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3558
3796
  el("div", { className: styles.rowTop, style: { flex: 1, minWidth: 0 } },
3559
3797
  el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, src.name + (src.primary ? "(" + t("sourcePrimary") + ")" : "")),
3560
- el("code", { className: styles.srcUrl }, src.url)),
3798
+ el("code", { className: styles.srcUrl }, src.url),
3799
+ (() => {
3800
+ const hit = scanOf(src.id);
3801
+ if (hit === null) return null;
3802
+ const title = hit.ok === true
3803
+ ? hit.url + " · " + hit.ms + "ms" + (hit.versions !== null ? " · " + hit.versions + " 个版本" : "") + (hit.latest === null ? " · " + t("registryScanNoVersion") : "")
3804
+ : hit.url + " · " + (hit.error ?? t("registryScanFail")) + " · " + hit.ms + "ms";
3805
+ return el("span", {
3806
+ className: styles.tag,
3807
+ "data-enabled": hit.ok === true ? "true" : undefined,
3808
+ "data-bad": hit.ok === true ? undefined : "true",
3809
+ title,
3810
+ }, hit.ok === true
3811
+ ? "✓ " + hit.ms + "ms" + (hit.latest !== null ? " · v" + hit.latest : " · " + t("registryScanNoVersion"))
3812
+ : "✗ " + (hit.error ?? t("registryScanFail")));
3813
+ })()),
3561
3814
  el("div", { className: styles.rowTop },
3562
- src.primary ? null : el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-primary", id: src.id }) }, t("setPrimary")),
3563
- el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => setEditReg({ id: src.id, name: src.name, url: src.url }) }, t("editSource"))))),
3815
+ src.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-primary", id: src.id }) }, t("setPrimary")),
3816
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditReg({ id: src.id, name: src.name, url: src.url }) }, t("editSource"))))),
3564
3817
  el("div", { className: styles.rowTop },
3565
3818
  el("input", { type: "text", placeholder: t("sourceName"), value: sourceName, onChange: (event) => setSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3566
3819
  el("input", { type: "text", placeholder: t("sourceUrl"), value: sourceUrl, onChange: (event) => setSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3567
3820
  el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addSource }, t("addSource"))),
3568
- el("strong", { className: styles.name }, t("searchSourcesTitle")),
3821
+ el("div", { className: styles.rowTop },
3822
+ el("button", {
3823
+ type: "button",
3824
+ className: styles.toggle,
3825
+ title: t("registryScanHint"),
3826
+ disabled: regScan !== null && regScan.status === "scanning",
3827
+ onClick: scanRegistries,
3828
+ }, regScan !== null && regScan.status === "scanning" ? t("registryScanning") : t("registryScan")),
3829
+ regScan !== null && regScan.status === "scanning" ? el("span", { className: styles.spinner }) : null,
3830
+ regScan !== null && regScan.status === "ready"
3831
+ ? el("span", { className: styles.message },
3832
+ t("registryScanSummary").replace("{ok}", String(scanOkCount)).replace("{total}", String(scanRows.length))
3833
+ + (scanBest !== null ? " · " + t("registryScanBest").replace("{version}", scanBest.latest).replace("{name}", scanBest.name) : ""))
3834
+ : null),
3835
+ ]),
3836
+ accSection("index", t("indexSourcesTitle"), [
3837
+ el("p", { className: styles.message }, t("indexSourcesDesc")),
3838
+ (sourcesData.indexSources ?? []).map((s) =>
3839
+ editIndex !== null && editIndex.id === s.id
3840
+ ? el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3841
+ el("input", { type: "text", value: editIndex.name, onChange: (event) => setEditIndex({ ...editIndex, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
3842
+ el("input", { type: "text", value: editIndex.url, onChange: (event) => setEditIndex({ ...editIndex, url: event.currentTarget.value }), style: { flex: 2, minWidth: 120 } }),
3843
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: saveEditIndex }, t("saveSource")),
3844
+ el("button", { type: "button", className: styles.toggle, onClick: () => setEditIndex(null) }, t("cancelEdit")))
3845
+ : el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3846
+ el("div", { className: styles.rowTop, style: { flex: 1, minWidth: 0 } },
3847
+ el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, s.name + (s.primary ? "(" + t("sourcePrimary") + ")" : "")),
3848
+ el("code", { className: styles.srcUrl }, s.url)),
3849
+ el("div", { className: styles.rowTop },
3850
+ s.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-index-primary", id: s.id }) }, t("setPrimary")),
3851
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditIndex({ id: s.id, name: s.name, url: s.url }) }, t("editSource")),
3852
+ el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-index", id: s.id }) }, t("removeSource"))))),
3853
+ el("div", { className: styles.rowTop },
3854
+ el("input", { type: "text", placeholder: t("sourceName"), value: indexSourceName, onChange: (event) => setIndexSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3855
+ el("input", { type: "text", placeholder: t("indexUrlPlaceholder"), value: indexSourceUrl, onChange: (event) => setIndexSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3856
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addIndexSource }, t("addIndexSource"))),
3857
+ el("div", { className: styles.rowTop },
3858
+ el("button", {
3859
+ type: "button",
3860
+ className: styles.toggle,
3861
+ "data-active": sourcesData.indexMerge === true ? "true" : "false",
3862
+ title: t("indexMergeDesc"),
3863
+ disabled: sourcesBusy,
3864
+ onClick: () => sourcesAction({ action: "set-index-merge", merge: sourcesData.indexMerge !== true }),
3865
+ }, t("indexMergeLabel") + ":" + (sourcesData.indexMerge === true ? t("on") : t("off")))),
3866
+ el("p", { className: styles.message }, t("indexMergeDesc")),
3867
+ ]),
3868
+ accSection("git", t("gitSourcesTitle"), [
3869
+ el("p", { className: styles.message }, t("gitSourcesDesc")),
3870
+ (sourcesData.gitSources ?? []).map((s) =>
3871
+ editGit !== null && editGit.id === s.id
3872
+ ? el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3873
+ el("input", { type: "text", value: editGit.name, onChange: (event) => setEditGit({ ...editGit, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
3874
+ el("input", { type: "text", value: editGit.urlTemplate, onChange: (event) => setEditGit({ ...editGit, urlTemplate: event.currentTarget.value }), style: { flex: 2, minWidth: 120 } }),
3875
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: saveEditGit }, t("saveSource")),
3876
+ el("button", { type: "button", className: styles.toggle, onClick: () => setEditGit(null) }, t("cancelEdit")))
3877
+ : el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3878
+ el("div", { className: styles.rowTop, style: { flex: 1, minWidth: 0 } },
3879
+ el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, s.name + (s.primary ? "(" + t("sourcePrimary") + ")" : "")),
3880
+ el("code", { className: styles.srcUrl }, s.urlTemplate)),
3881
+ el("div", { className: styles.rowTop },
3882
+ s.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-git-primary", id: s.id }) }, t("setPrimary")),
3883
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditGit({ id: s.id, name: s.name, urlTemplate: s.urlTemplate }) }, t("editSource")),
3884
+ el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-git", id: s.id }) }, t("removeSource"))))),
3885
+ el("div", { className: styles.rowTop },
3886
+ el("input", { type: "text", placeholder: t("sourceName"), value: gitSourceName, onChange: (event) => setGitSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3887
+ el("input", { type: "text", placeholder: t("gitUrlPlaceholder"), value: gitSourceUrl, onChange: (event) => setGitSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3888
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addGitSource }, t("addGitSource"))),
3889
+ ]),
3890
+ accSection("search", t("searchSourcesTitle"), [
3569
3891
  el("p", { className: styles.message }, t("searchSourcesDesc")),
3570
3892
  (sourcesData.searchSources ?? []).map((s) =>
3571
3893
  el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
@@ -3576,7 +3898,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3576
3898
  ? el("span", { className: styles.tag, title: t("headersPlaceholder") }, "🔒 " + Object.keys(s.headers).length)
3577
3899
  : null),
3578
3900
  s.type === "custom"
3579
- ? el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-search", id: s.id }) }, t("removeSource"))
3901
+ ? el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-search", id: s.id }) }, t("removeSource"))
3580
3902
  : null)),
3581
3903
  el("div", { className: styles.rowTop },
3582
3904
  el("input", { type: "text", placeholder: t("sourceName"), value: searchSourceName, onChange: (event) => setSearchSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
@@ -3589,7 +3911,8 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3589
3911
  onChange: (event) => setSearchSourceHeaders(event.currentTarget.value),
3590
3912
  style: { width: "100%", boxSizing: "border-box", font: "inherit", resize: "vertical" },
3591
3913
  }),
3592
- el("strong", { className: styles.name }, t("giteeTitle")),
3914
+ ]),
3915
+ accSection("gitee", t("giteeTitle"), [
3593
3916
  el("p", { className: styles.message }, t("giteeDesc").replace("{port}", String(window.location.port || "3080"))),
3594
3917
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
3595
3918
  el("span", { className: styles.tag },
@@ -3604,7 +3927,9 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3604
3927
  el("button", { type: "button", className: styles.toggle, disabled: giteeStatus !== null && !giteeStatus.clientConfigured, onClick: startGiteeOauth }, t("giteeLoginBtn")),
3605
3928
  giteeStatus !== null && giteeStatus.hasToken
3606
3929
  ? el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "gitee-clear" }) }, t("giteeClear"))
3607
- : null)),
3930
+ : null),
3931
+ ]),
3932
+ ),
3608
3933
  el("div", { className: styles.rowTop },
3609
3934
  el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "reset" }) }, t("resetSources")),
3610
3935
  el("button", { type: "button", className: styles.toggle, onClick: () => setSourcesOpen(false) }, t("closeModal")))))