@noob-stupid/dsh-plugin-console 0.5.33 → 0.5.35
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 +516 -220
- package/lib/server/domain/compat-verdict.js +241 -0
- package/lib/server/domain/compat.js +84 -16
- package/lib/server/domain/framework-cleanup.js +225 -24
- package/lib/server/domain/framework-residuals.js +52 -3
- package/lib/server/domain/market-search.js +242 -0
- package/lib/server/domain/settings-api-scan.js +16 -1
- package/lib/server/routes/market.js +108 -35
- package/lib/server/routes/plugins.js +24 -13
- package/lib/server/routes/state.js +14 -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_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:max(88px,21vh);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:calc(max(88px,21vh) + 36px);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:max(150px,30vh)}.pc_toolbarGroup{top:calc(max(150px,30vh) + 36px)}.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)}.pc_progress{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;margin:0;font-variant-numeric:tabular-nums}.pc_consentCard{border:2px solid var(--dsw-alias-state-warning-primary);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:12px 14px;flex-direction:column;gap:8px;display:flex;box-shadow:0 0 0 3px rgba(255,176,32,.10)}.pc_consentCountdown{margin-left:auto;flex:none;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--dsw-alias-state-warning-primary)}.pc_consentApprove{border:1px solid var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:0 0;font:inherit;font-weight:600;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_consentApprove:hover{border-color:var(--dsw-alias-state-business-primary);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_note[data-truncated=true]{color:var(--dsw-alias-state-warning-primary)}.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:max(88px,21vh);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:calc(max(88px,21vh) + 36px);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:max(150px,30vh)}.pc_toolbarGroup{top:calc(max(150px,30vh) + 36px)}.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)}.pc_progress{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px;margin:0;font-variant-numeric:tabular-nums}.pc_consentCard{border:2px solid var(--dsw-alias-state-warning-primary);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:12px 14px;flex-direction:column;gap:8px;display:flex;box-shadow:0 0 0 3px rgba(255,176,32,.10)}.pc_consentCountdown{margin-left:auto;flex:none;font-size:14px;font-weight:600;font-variant-numeric:tabular-nums;color:var(--dsw-alias-state-warning-primary)}.pc_consentApprove{border:1px solid var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:0 0;font:inherit;font-weight:600;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_consentApprove:hover{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-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");
|
|
@@ -208,6 +208,9 @@ window.__ModuleLoader__.load({
|
|
|
208
208
|
riskyEnableConfirm: "确认强行启用",
|
|
209
209
|
riskyEnableCancel: "取消",
|
|
210
210
|
adoptableDetected: "检测到已适配:当前版本 {version} 已通过源码扫描,点「已适配,立即解锁」即可启用(不会自动开启)",
|
|
211
|
+
adoptableRescinded: "判据已更新:旧版扫描给出的「不兼容」结论已撤回(当前判据下源码扫描干净,版本不变也算)。点「已适配,立即解锁」即可启用(不会自动开启)",
|
|
212
|
+
compatRescindedTag: "判据已撤回·可解锁",
|
|
213
|
+
compatRescindedHint: "这条禁用是旧判据的误报:当前判据重算后不再判「不兼容」。点上方「已适配,立即解锁」即可启用;补丁由你确认后才改。",
|
|
211
214
|
compatGateLabel: "兼容门",
|
|
212
215
|
compatGateAutoDisable: "升级时自动禁用不适配插件",
|
|
213
216
|
compatGateAutoDetect: "打开时自动检测已适配(仅提示)",
|
|
@@ -361,6 +364,10 @@ window.__ModuleLoader__.load({
|
|
|
361
364
|
noMatch: "没有匹配的插件。",
|
|
362
365
|
loadMore: "加载更多",
|
|
363
366
|
loadingMore: "加载中…",
|
|
367
|
+
marketCount: "共 {total} 条 / 已显示 {shown} 条",
|
|
368
|
+
marketCountKnown: "已显示 {shown} 条",
|
|
369
|
+
marketTruncated: "结果已截断,可继续加载",
|
|
370
|
+
marketTruncatedEnd: "结果已截断,没有更多了",
|
|
364
371
|
backToSearch: "回到搜索",
|
|
365
372
|
collapseResults: "收起搜索结果",
|
|
366
373
|
expandResults: "展开搜索结果",
|
|
@@ -760,6 +767,9 @@ window.__ModuleLoader__.load({
|
|
|
760
767
|
riskyEnableConfirm: "Force enable",
|
|
761
768
|
riskyEnableCancel: "Cancel",
|
|
762
769
|
adoptableDetected: "Now compatible: version {version} passed the source scan — click \"Adapted - unlock now\" to enable it (never auto-enabled)",
|
|
770
|
+
adoptableRescinded: "Criteria updated: the older scan's \"incompatible\" verdict has been withdrawn (the current criteria find the source clean even without a version change). Click \"Adapted - unlock now\" to enable it (never auto-enabled)",
|
|
771
|
+
compatRescindedTag: "Verdict withdrawn - unlockable",
|
|
772
|
+
compatRescindedHint: "This disable came from a false positive of the older criteria: recomputing with the current criteria no longer says \"incompatible\". Click \"Adapted - unlock now\" above; your patch is only changed after you confirm.",
|
|
763
773
|
compatGateLabel: "Compat gate",
|
|
764
774
|
compatGateAutoDisable: "Auto-disable incompatible plugins on upgrade",
|
|
765
775
|
compatGateAutoDetect: "Detect adapted plugins on open (hint only)",
|
|
@@ -909,6 +919,10 @@ window.__ModuleLoader__.load({
|
|
|
909
919
|
noMatch: "No matching plugins.",
|
|
910
920
|
loadMore: "Load more",
|
|
911
921
|
loadingMore: "Loading…",
|
|
922
|
+
marketCount: "{total} found / {shown} shown",
|
|
923
|
+
marketCountKnown: "{shown} shown",
|
|
924
|
+
marketTruncated: "Results truncated — you can keep loading",
|
|
925
|
+
marketTruncatedEnd: "Results truncated — no more available",
|
|
912
926
|
backToSearch: "Back to search",
|
|
913
927
|
collapseResults: "Collapse results",
|
|
914
928
|
expandResults: "Expand results",
|
|
@@ -1196,6 +1210,199 @@ window.__ModuleLoader__.load({
|
|
|
1196
1210
|
const PHASE_KEYS = { pending: "pending", loading: "loadingPhase", active: "active", failed: "failed", unloading: "unloading" };
|
|
1197
1211
|
const GITHUB_API = "https://api.github.com";
|
|
1198
1212
|
const GITHUB_RAW = "https://raw.githubusercontent.com";
|
|
1213
|
+
|
|
1214
|
+
// ★★ 市场搜索的**唯一**排序区(0.5.35)★★
|
|
1215
|
+
// 用户定案:「所有的搜索链,都应该以名字相似为主排序,然后才往下按 star 走」。
|
|
1216
|
+
// 这里是服务端 lib/server/domain/market-search.js 里同一标记块(// <<<market-rank:begin/end>>>)的
|
|
1217
|
+
// **逐字移植**:本文件是单文件打包产物(window.__ModuleLoader__.load),不能 import,
|
|
1218
|
+
// 所以两端共用一份**文本**,由 tests/test-market-rank-canonical.mjs 断言"去缩进后逐字相等"
|
|
1219
|
+
// (改一边不改另一边 = 直接红灯)。排序语义只有这一份判据,任何搜索链都只许调它。
|
|
1220
|
+
// <<<market-rank:begin>>>
|
|
1221
|
+
/** 排序层级(越小越靠前)。Tier 0-6 与用户定案逐条对应;NOT_MATCHED 只是"没有名字/描述命中"。 */
|
|
1222
|
+
const RANK_TIER = Object.freeze({
|
|
1223
|
+
FULL_NAME_EXACT: 0,
|
|
1224
|
+
NAME_EXACT: 1,
|
|
1225
|
+
NAME_PREFIX: 2,
|
|
1226
|
+
NAME_SUBSTRING: 3,
|
|
1227
|
+
NAME_TOKENS: 4,
|
|
1228
|
+
DESCRIPTION_OR_TOPICS: 5,
|
|
1229
|
+
README: 6,
|
|
1230
|
+
NOT_MATCHED: 7,
|
|
1231
|
+
})
|
|
1232
|
+
|
|
1233
|
+
/** 归一化:小写 + 去掉尾部 `.git` / 首尾空白。所有判据都用它,避免大小写与 `.git` 差异漏判。 */
|
|
1234
|
+
function normalizeSearchName(value) {
|
|
1235
|
+
return String(value ?? '').trim().replace(/\.git$/iu, '').toLowerCase()
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/** 查询词按分隔符切出的 token(≥2 字符,去重保序)——用于 Tier 4「token 全命中」判据。 */
|
|
1239
|
+
function queryTokens(query) {
|
|
1240
|
+
const q = normalizeSearchName(query)
|
|
1241
|
+
if (q === '') return []
|
|
1242
|
+
const out = []
|
|
1243
|
+
for (const tk of q.split(/[\s\-_/.]+/u)) {
|
|
1244
|
+
if (tk.length >= 2 && !out.includes(tk)) out.push(tk)
|
|
1245
|
+
}
|
|
1246
|
+
return out
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
/** 条目的两个名字形态(都归一化):`full` = owner/repo,`short` = 裸名(缺 name 时从 full 取尾段)。 */
|
|
1250
|
+
function itemNameForms(item) {
|
|
1251
|
+
const full = normalizeSearchName(item?.fullName ?? item?.full_name)
|
|
1252
|
+
const short = normalizeSearchName(item?.name) || (full === '' ? '' : (full.split('/').pop() ?? ''))
|
|
1253
|
+
return { full, short }
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
/** 名字里按分隔符切出的 token(小写)。`dsh-connection-card-host` → [dsh, connection, card, host]。 */
|
|
1257
|
+
function nameTokens(name) {
|
|
1258
|
+
return String(name ?? '').toLowerCase().split(/[\s\-_/.]+/u).filter(Boolean)
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
/** description / topics 是不是命中查询词(整词子串,大小写不敏感)。 */
|
|
1262
|
+
function textHitsQuery(query, item) {
|
|
1263
|
+
const q = normalizeSearchName(query)
|
|
1264
|
+
if (q === '') return false
|
|
1265
|
+
const desc = normalizeSearchName(item?.description)
|
|
1266
|
+
if (desc !== '' && desc.includes(q)) return true
|
|
1267
|
+
const topics = Array.isArray(item?.topics) ? item.topics : []
|
|
1268
|
+
return topics.some((topic) => normalizeSearchName(topic).includes(q))
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/** README 命中:优先看条目**自带**的 readme 文本;没有就认标记位(服务端 in:readme 重查补进来的条目)。
|
|
1272
|
+
* 标记位是"这条是从 README 检索面捞到的"的既成事实,不编造内容。 */
|
|
1273
|
+
function readmeHitsQuery(query, item) {
|
|
1274
|
+
const q = normalizeSearchName(query)
|
|
1275
|
+
if (q === '') return false
|
|
1276
|
+
const readme = normalizeSearchName(item?.readme)
|
|
1277
|
+
if (readme !== '' && readme.includes(q)) return true
|
|
1278
|
+
return item?.viaReadme === true
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/** 名字相似度分层(唯一判据;越小越靠前)。owner/repo 查询只按 full_name 判 Tier 0,
|
|
1282
|
+
* 避免"同名不同 owner"被当成逐字命中(与用户"输入确切名字要排第一"的预期一致)。 */
|
|
1283
|
+
function rankTier(query, item) {
|
|
1284
|
+
const q = normalizeSearchName(query)
|
|
1285
|
+
if (q === '') return RANK_TIER.NOT_MATCHED
|
|
1286
|
+
const { full, short } = itemNameForms(item)
|
|
1287
|
+
const tokens = queryTokens(query)
|
|
1288
|
+
const hasOwner = q.includes('/')
|
|
1289
|
+
const target = short !== '' ? short : full
|
|
1290
|
+
if (full !== '' && full === q) return RANK_TIER.FULL_NAME_EXACT
|
|
1291
|
+
if (!hasOwner && short !== '' && short === q) return RANK_TIER.NAME_EXACT
|
|
1292
|
+
if (target !== '' && target.startsWith(q)) return RANK_TIER.NAME_PREFIX
|
|
1293
|
+
if (target !== '' && target.includes(q)) return RANK_TIER.NAME_SUBSTRING
|
|
1294
|
+
if (tokens.length > 0) {
|
|
1295
|
+
const owned = nameTokens(full !== '' ? full : short)
|
|
1296
|
+
if (tokens.every((tk) => owned.includes(tk))) return RANK_TIER.NAME_TOKENS
|
|
1297
|
+
}
|
|
1298
|
+
if (textHitsQuery(query, item)) return RANK_TIER.DESCRIPTION_OR_TOPICS
|
|
1299
|
+
if (readmeHitsQuery(query, item)) return RANK_TIER.README
|
|
1300
|
+
return RANK_TIER.NOT_MATCHED
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
/** 星数(缺省 0;非数字按 0 处理——索引/GitHub 都是外部数据,不能拿它当数字用)。 */
|
|
1304
|
+
function starsOf(item) {
|
|
1305
|
+
const n = item?.stars ?? item?.stargazers_count
|
|
1306
|
+
return typeof n === 'number' && Number.isFinite(n) ? n : 0
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
/** 更新时间戳(毫秒)。缺省/非法一律 0("没给时间"排最后;绝不编造"刚更新")。 */
|
|
1310
|
+
function updatedAtOf(item) {
|
|
1311
|
+
const raw = item?.updatedAt ?? item?.updated_at
|
|
1312
|
+
if (typeof raw === 'number' && Number.isFinite(raw)) return raw
|
|
1313
|
+
if (typeof raw === 'string' && raw !== '') {
|
|
1314
|
+
const parsed = Date.parse(raw)
|
|
1315
|
+
if (Number.isFinite(parsed)) return parsed
|
|
1316
|
+
}
|
|
1317
|
+
return 0
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
/** 确定性兜底 tiebreaker:同层同星同时间时按 full_name 字典序(分页不抖动)。 */
|
|
1321
|
+
function nameOf(item) {
|
|
1322
|
+
return normalizeSearchName(item?.fullName ?? item?.full_name ?? item?.name)
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
/** 统一比较器:Tier 0-6 升序 → stars 降序 → updatedAt 降序 → full_name 升序。
|
|
1326
|
+
* 「名字相似为主、同层才比 star」的全部语义都在这一个函数里;所有搜索链只许调它。 */
|
|
1327
|
+
function compareByRank(query) {
|
|
1328
|
+
return (a, b) => {
|
|
1329
|
+
const ta = rankTier(query, a)
|
|
1330
|
+
const tb = rankTier(query, b)
|
|
1331
|
+
if (ta !== tb) return ta - tb
|
|
1332
|
+
const sa = starsOf(a)
|
|
1333
|
+
const sb = starsOf(b)
|
|
1334
|
+
if (sa !== sb) return sb - sa
|
|
1335
|
+
const ua = updatedAtOf(a)
|
|
1336
|
+
const ub = updatedAtOf(b)
|
|
1337
|
+
if (ua !== ub) return ub - ua
|
|
1338
|
+
const na = nameOf(a)
|
|
1339
|
+
const nb = nameOf(b)
|
|
1340
|
+
return na < nb ? -1 : (na > nb ? 1 : 0)
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/** **唯一入口**:按用户定案排序(返回**新数组**;条目对象一个字段都不动 —— 只改顺序不改内容)。
|
|
1345
|
+
* 分页幂等的根本保证:同一数组同一 query 的排序结果逐位相同(比较器无随机、无时间依赖)。 */
|
|
1346
|
+
function rankSearchResults(items, query) {
|
|
1347
|
+
const list = Array.isArray(items) ? items.slice() : []
|
|
1348
|
+
if (list.length < 2) return list
|
|
1349
|
+
return list.sort(compareByRank(query))
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
/** 分层结果(UI 角标/说明与测试用):[{ tier, items }] 只含**真的命中**(Tier 0-6)的层,层序固定。 */
|
|
1353
|
+
function rankTiers(items, query) {
|
|
1354
|
+
const buckets = new Map()
|
|
1355
|
+
for (const item of Array.isArray(items) ? items : []) {
|
|
1356
|
+
const tier = rankTier(query, item)
|
|
1357
|
+
if (tier > RANK_TIER.README) continue
|
|
1358
|
+
if (!buckets.has(tier)) buckets.set(tier, [])
|
|
1359
|
+
buckets.get(tier).push(item)
|
|
1360
|
+
}
|
|
1361
|
+
return [...buckets.keys()].sort((a, b) => a - b).map((tier) => ({ tier, items: buckets.get(tier) }))
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* 分页 + 截断口径(纯函数;GitHub search 的 `total_count` 与 `per_page` 都进这里):
|
|
1366
|
+
* · shown 本次实际显示的条目数
|
|
1367
|
+
* · total 数据源报的**总命中数**(未知传 null → UI 只说"已显示 M 条",绝不编造总数)
|
|
1368
|
+
* · hasMore 还能不能往下翻(`page*perPage < total` **且没有翻过数据源硬上限**;总数为 null 时退化为"本页满页")
|
|
1369
|
+
* · truncated 结果被截断了(总数 > 本次已取到的范围)——UI 必须**明说**,不许让用户以为"就是没有"
|
|
1370
|
+
* · reason 截断的**可读原因**(GitHub API 最多 1000 条 / 索引封顶 / 无 total 但满页)
|
|
1371
|
+
* 幂等:同一 (page, perPage, total) 永远同一结论。
|
|
1372
|
+
*
|
|
1373
|
+
* ★ 0.5.35 实测(真机 GitHub,2026-10-03):`per_page=20&page=51`(第 1001 条起)不是"返回空"而是
|
|
1374
|
+
* **HTTP 422 `Only the first 1000 search results are available`** —— 也就是说越过上限再翻页必然报错。
|
|
1375
|
+
* 所以 hasMore 在 `page*perPage >= min(total, cap)` 时必须为 false:按钮不给,用户就不会点出一个错误。
|
|
1376
|
+
* 它也在标记块**之内**:浏览器那一半用同一份口径算「加载更多」与「共 N 条」。
|
|
1377
|
+
*/
|
|
1378
|
+
function buildPageEnvelope({ shown = 0, total = null, page = 1, perPage = 20, cap = 1000, capReason = null } = {}) {
|
|
1379
|
+
const n = Number.isFinite(shown) && shown > 0 ? shown : 0
|
|
1380
|
+
const p = Number.isFinite(page) && page > 0 ? Math.floor(page) : 1
|
|
1381
|
+
const size = Number.isFinite(perPage) && perPage > 0 ? Math.floor(perPage) : 20
|
|
1382
|
+
const known = typeof total === 'number' && Number.isFinite(total) && total >= 0 ? Math.floor(total) : null
|
|
1383
|
+
const capValue = Number.isFinite(cap) && cap > 0 ? Math.floor(cap) : Infinity
|
|
1384
|
+
const fetched = p * size
|
|
1385
|
+
// 数据源硬上限之内还能取到条数(GitHub search 只有前 1000 条;越过就是 422,不是空页)
|
|
1386
|
+
const reachable = known === null ? Infinity : Math.min(known, capValue)
|
|
1387
|
+
// hasMore 只由**总数与上限**决定(`shown > 0`):本页返回 0 条就是到底了,不许再让用户点空按钮,
|
|
1388
|
+
// 也不许让用户点到必然 422 的那一页。
|
|
1389
|
+
const hasMore = known === null ? n >= size : (n > 0 && fetched < reachable)
|
|
1390
|
+
// 截断分两种,都必须让用户看见(而不是以为"就是没有"):
|
|
1391
|
+
// ① 数据源硬上限(GitHub search 只给前 1000 条)→ 这是**始终**成立的事实,与翻到第几页无关;
|
|
1392
|
+
// ② 本次只取到前 fetched 条(还有更多没取)→ 翻页可解。
|
|
1393
|
+
const overCap = known !== null && known > cap
|
|
1394
|
+
const truncated = overCap || (known === null ? n >= size : known > fetched)
|
|
1395
|
+
let reason = null
|
|
1396
|
+
if (overCap) reason = capReason !== null ? capReason : `数据源最多只返回前 ${cap} 条(命中 ${known} 条)`
|
|
1397
|
+
else if (known === null && n >= size) reason = '数据源未返回总数(只能按每页满页判断还有更多)'
|
|
1398
|
+
else if (known !== null && known > fetched) reason = `共 ${known} 条,本次只取到前 ${Math.min(fetched, known)} 条`
|
|
1399
|
+
// 已经翻到/翻过硬上限:再说"可继续加载"就是骗人(GitHub 第 1001 条起是 422)
|
|
1400
|
+
if (overCap && fetched >= cap) {
|
|
1401
|
+
reason = capReason !== null ? capReason : `数据源最多只返回前 ${cap} 条(命中 ${known} 条):已翻到第 ${fetched} 条,无法再往下`
|
|
1402
|
+
}
|
|
1403
|
+
return { shown: n, total: known, page: p, perPage: size, hasMore, truncated, reason }
|
|
1404
|
+
}
|
|
1405
|
+
// <<<market-rank:end>>>
|
|
1199
1406
|
const el = react.createElement;
|
|
1200
1407
|
function moduleShortName(moduleName) {
|
|
1201
1408
|
return (moduleName.startsWith("@") ? moduleName.slice(moduleName.indexOf("/") + 1) : moduleName)
|
|
@@ -1231,9 +1438,12 @@ window.__ModuleLoader__.load({
|
|
|
1231
1438
|
// 补丁与行状态零变化 ⇒ 用户观感"点了没反应"。
|
|
1232
1439
|
// 现在只有**真的检测到已适配**(adoptable 是服务端 detectAdoptablePending 给出的对象)才出按钮;
|
|
1233
1440
|
// 其余情况不给这个承诺,原因照旧由正文那行(pendingCompatHint + checkNote)如实展示。
|
|
1441
|
+
// 0.5.34 加法:`compatRescinded`(记录里的 fail 是旧判据的误报、已被当前判据撤回)同样给一键解锁入口 ——
|
|
1442
|
+
// 这类行**没有版本变化**,旧判据要求"版本变化"会让用户被永久钉在「待适配」(真机 dshmarket 就是这样)。
|
|
1443
|
+
// 判据本身没放宽:adoptable 仍是服务端算出来的对象(真 fail 的行根本拿不到它)。
|
|
1234
1444
|
function canAdaptUnlock(entry) {
|
|
1235
1445
|
return entry !== null && entry !== undefined
|
|
1236
|
-
&& entry.pendingCompat === true
|
|
1446
|
+
&& (entry.pendingCompat === true || entry.compatRescinded === true)
|
|
1237
1447
|
&& entry.adoptable !== null && entry.adoptable !== undefined
|
|
1238
1448
|
&& typeof entry.adoptable === "object";
|
|
1239
1449
|
}
|
|
@@ -1254,9 +1464,9 @@ window.__ModuleLoader__.load({
|
|
|
1254
1464
|
return data;
|
|
1255
1465
|
}
|
|
1256
1466
|
/** 执行「建议动作」:与 call() 的关键差别 ——**服务端把"动作失败"也当结果返回**
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1467
|
+
* (`{ ok:false, partial:true, exitCode, reason, stderr }`),而 call() 的统一约定会把
|
|
1468
|
+
* `data.ok === false` 抛成一句没信息量的 "HTTP 200"(真机体验:失败原因看不见)。
|
|
1469
|
+
* 所以这里直接读响应体,只把"协议级失败(HTTP != 2xx / 网络异常)"当错误抛。 */
|
|
1260
1470
|
async function callAction(payload) {
|
|
1261
1471
|
const response = await fetch("/plugin-console/run-suggested", {
|
|
1262
1472
|
method: "POST",
|
|
@@ -1275,7 +1485,7 @@ window.__ModuleLoader__.load({
|
|
|
1275
1485
|
try { void navigator.clipboard.writeText(String(text)); return true } catch { return false }
|
|
1276
1486
|
}
|
|
1277
1487
|
/** 重启服务(按钮 / 工具项 / 自更新后共用):服务端在「本实例由桌面端外壳托管」等场景会**拒绝**
|
|
1278
|
-
|
|
1488
|
+
* 并回结构化短句 —— 必须把它显示出来,否则按钮看起来是「点了没反应」(旧实现把错误吞掉了)。 */
|
|
1279
1489
|
function restartServiceViaServer(setMessage, options) {
|
|
1280
1490
|
const reload = (options ?? {}).reload !== false;
|
|
1281
1491
|
if (reload) setMessage(t("restarting"));
|
|
@@ -1333,12 +1543,14 @@ window.__ModuleLoader__.load({
|
|
|
1333
1543
|
return null;
|
|
1334
1544
|
}
|
|
1335
1545
|
}
|
|
1336
|
-
/** 浏览器直连 GitHub 搜索;失败抛错由调用方回退到服务端通道。
|
|
1546
|
+
/** 浏览器直连 GitHub 搜索;失败抛错由调用方回退到服务端通道。
|
|
1547
|
+
* ★ 0.5.35:结果顺序不再照 GitHub 的 `sort=stars` 直接用 —— 回到调用点过**唯一**排序函数
|
|
1548
|
+
* (名字相似分层,同层才比 star)。`total` 一起带回来,供"共 N 条 / 还有更多"的口径。 */
|
|
1337
1549
|
async function searchFromGithub(q, page, all) {
|
|
1338
1550
|
const base = (q ?? "").trim() || "dsh-plugin";
|
|
1339
1551
|
const query = all ? base : (base + " topic:dsh-plugin");
|
|
1340
1552
|
const data = await githubFetch(`${GITHUB_API}/search/repositories?q=${encodeURIComponent(query)}&sort=stars&order=desc&per_page=20&page=${Math.max(page || 1, 1)}`);
|
|
1341
|
-
|
|
1553
|
+
const items = (data.items ?? []).map((item) => ({
|
|
1342
1554
|
fullName: item.full_name,
|
|
1343
1555
|
description: item.description ?? "",
|
|
1344
1556
|
htmlUrl: item.html_url,
|
|
@@ -1347,6 +1559,8 @@ window.__ModuleLoader__.load({
|
|
|
1347
1559
|
defaultBranch: item.default_branch ?? "main",
|
|
1348
1560
|
topics: item.topics ?? [],
|
|
1349
1561
|
}));
|
|
1562
|
+
const total = typeof data.total_count === "number" ? data.total_count : null;
|
|
1563
|
+
return { items, total };
|
|
1350
1564
|
}
|
|
1351
1565
|
/** 提取 SKILL.md frontmatter 摘要(name / description / whenToUse,与宿主端同规则)。 */
|
|
1352
1566
|
function summarizeSkillFrontmatter(text) {
|
|
@@ -1382,8 +1596,8 @@ window.__ModuleLoader__.load({
|
|
|
1382
1596
|
return { name, description, whenToUse };
|
|
1383
1597
|
}
|
|
1384
1598
|
/** 浏览器直连读取仓库元数据 + package.json + README 摘要。
|
|
1385
|
-
|
|
1386
|
-
|
|
1599
|
+
* 搜索结果自带描述/star/分支信息,seed 存在时跳过 api.github.com 请求
|
|
1600
|
+
* (该接口在黑洞期会挂起很久,是"查看没反应"的根因)。 */
|
|
1387
1601
|
async function repoInfoFromGithub(repo, seed) {
|
|
1388
1602
|
let branch = "main";
|
|
1389
1603
|
let metaDescription = "";
|
|
@@ -1490,7 +1704,7 @@ window.__ModuleLoader__.load({
|
|
|
1490
1704
|
}
|
|
1491
1705
|
/** 批量识别搜索结果:官方通道(根包 dsh.bundle)/ 聚合仓库(private+workspaces,子包才是插件)/ 普通项目。 */
|
|
1492
1706
|
/** 补标「官方 / 聚合」标记。每条要发网络请求(raw 多通道竞速),
|
|
1493
|
-
|
|
1707
|
+
* 因此限制并发(默认 6 条一批),避免打满浏览器连接数拖慢整页。 */
|
|
1494
1708
|
async function enrichOfficialBundle(items, concurrency = 6) {
|
|
1495
1709
|
const out = [];
|
|
1496
1710
|
for (let i = 0; i < items.length; i += concurrency) {
|
|
@@ -1578,7 +1792,7 @@ window.__ModuleLoader__.load({
|
|
|
1578
1792
|
};
|
|
1579
1793
|
}
|
|
1580
1794
|
/** 服务端 /enrich 兜底:并发限流 12 + 24h 缓存,补齐客户端直连失败/遗漏的标记
|
|
1581
|
-
|
|
1795
|
+
* (每次最多 30 条,按需分批;结果按位置合并回索引与当前展示切片)。 */
|
|
1582
1796
|
function enrichRangeServer(from, slice) {
|
|
1583
1797
|
const BATCH = 30;
|
|
1584
1798
|
for (let i = 0; i < slice.length; i += BATCH) {
|
|
@@ -2524,50 +2738,52 @@ window.__ModuleLoader__.load({
|
|
|
2524
2738
|
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
2525
2739
|
);
|
|
2526
2740
|
};
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2741
|
+
// 0.5.35 改错(**用户"第二次搜索变成一大堆高星无关仓库"的元凶**):这里原来有一套
|
|
2742
|
+
// 「本地索引模糊匹配 + 编辑距离 ≤2」,命中就直接 return —— 它把 12 条**按星数排**的无关条目
|
|
2743
|
+
// 当最终结果(用户搜 dsh-connection-card-host,索引里根本没有这个新仓库,靠 token 相似
|
|
2744
|
+
// 捞出 dsh-desktop ★29812 这类),既埋没了逐字同名,也把「加载更多」变成了死路
|
|
2745
|
+
// (只有 12 条,按钮的 length>=20 条件不成立)。
|
|
2746
|
+
// 判据统一到唯一的名字分层排序(本文件上方 <<<market-rank>>> 区 + 服务端同一份),
|
|
2747
|
+
// 非空查询一律走真实搜索链(浏览器直连 → 失败回落服务端),不再有"索引抢先 return"。
|
|
2748
|
+
/** 服务端/直连结果里的分页口径(纯函数移植:与服务端 buildPageEnvelope 同一份)。
|
|
2749
|
+
* 返回 null 表示"这个数据源没给口径"(不是"没有更多")——调用方保留既有提示,不谎报。 */
|
|
2750
|
+
const envelopeOf = (data, page, perPage = 20) => {
|
|
2751
|
+
if (data === null || typeof data !== "object" || typeof data.hasMore !== "boolean") return null;
|
|
2752
|
+
return {
|
|
2753
|
+
shown: typeof data.shown === "number" ? data.shown : 0,
|
|
2754
|
+
total: typeof data.total === "number" ? data.total : null,
|
|
2755
|
+
hasMore: data.hasMore,
|
|
2756
|
+
truncated: data.truncated === true,
|
|
2757
|
+
reason: typeof data.reason === "string" && data.reason !== "" ? data.reason : null,
|
|
2758
|
+
page,
|
|
2759
|
+
perPage,
|
|
2760
|
+
};
|
|
2543
2761
|
};
|
|
2544
|
-
|
|
2545
|
-
const
|
|
2546
|
-
const
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
if (best <= 2) scored.push({ it, s: 1000 - best * 100 });
|
|
2563
|
-
}
|
|
2564
|
-
scored.sort((a, b) => b.s - a.s);
|
|
2565
|
-
return scored.slice(0, 12).map((x) => x.it);
|
|
2762
|
+
/** 浏览器直连 GitHub 只有 total_count/per_page 可依据:用**同一个** buildPageEnvelope 算口径。 */
|
|
2763
|
+
const envelopeFromGithub = (total, shownCount, page, perPage = 20) => {
|
|
2764
|
+
const env = buildPageEnvelope({
|
|
2765
|
+
shown: typeof shownCount === "number" ? shownCount : 0,
|
|
2766
|
+
total: typeof total === "number" ? total : null, page, perPage,
|
|
2767
|
+
});
|
|
2768
|
+
return { shown: env.shown, total: env.total, hasMore: env.hasMore, truncated: env.truncated, reason: env.reason, page: env.page, perPage: env.perPage };
|
|
2769
|
+
};
|
|
2770
|
+
/** 本地索引浏览切片的口径(索引是本地的,总数就取索引自身长度,绝不编造)。 */
|
|
2771
|
+
const envelopeFromIndex = (list, shownNow, page, perPage = 50) => {
|
|
2772
|
+
const env = buildPageEnvelope({ shown: shownNow, total: Array.isArray(list) ? list.length : null, page, perPage });
|
|
2773
|
+
return { shown: env.shown, total: env.total, hasMore: env.hasMore, truncated: env.truncated, reason: env.reason, page: env.page, perPage: env.perPage };
|
|
2774
|
+
};
|
|
2775
|
+
/** 合并/补标之后重算"已显示 M 条"(total/hasMore/truncated 是数据源的事实,不因合并而改)。 */
|
|
2776
|
+
const repaginate = (hints, list) => {
|
|
2777
|
+
if (hints === null || hints === undefined) return hints;
|
|
2778
|
+
const shown = Array.isArray(list) ? list.length : 0;
|
|
2779
|
+
return { ...hints, shown };
|
|
2566
2780
|
};
|
|
2567
2781
|
/** 合并服务端"增量检索"结果(npm 包名映射 / in:readme 重查 / 代码搜索子包):
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2782
|
+
* npm 命中置顶,其余按增量顺序追加,最后接原有直连结果,全部按 fullName 去重。
|
|
2783
|
+
* 背景(2026-09-20):浏览器直连 GitHub 搜索成功时不会走服务端路由,而未登录用户恰恰只能走直连
|
|
2784
|
+
* →「只存在于 npm 包名 / README / 仓库文件里」的名字(如 web-all)永远补不上。
|
|
2785
|
+
* 0.5.35:合并后的**最终顺序**由唯一排序函数(rankSearchResults)决定 —— 这里的 npm 前置
|
|
2786
|
+
* 只是"合并时别把 npm 命中丢掉",不再冒充排序判据。 */
|
|
2571
2787
|
function mergeSearchExtras(base, extras) {
|
|
2572
2788
|
const seen = new Set();
|
|
2573
2789
|
const npm = [];
|
|
@@ -2588,13 +2804,19 @@ window.__ModuleLoader__.load({
|
|
|
2588
2804
|
return out;
|
|
2589
2805
|
}
|
|
2590
2806
|
/** 用 enrich 结果**就地更新**市场列表(按 fullName 打补丁),而不是整表替换——
|
|
2591
|
-
|
|
2807
|
+
* 否则并行补进来的「增量检索」条目(npm 包名/子包)会被 enrich 回调冲掉。 */
|
|
2592
2808
|
const applyEnriched = (enriched) => setMarket((m) => {
|
|
2593
2809
|
if (m === null || m.status !== "ready" || !Array.isArray(enriched)) return m;
|
|
2594
2810
|
const byName = new Map(enriched.map((x) => [x.fullName, x]));
|
|
2595
2811
|
return { ...m, data: m.data.map((x) => byName.get(x.fullName) ?? x) };
|
|
2596
2812
|
});
|
|
2813
|
+
/** 搜索批次序号:每次 search() 递增。**晚到的旧响应一律丢弃** —— 上一版两条链(浏览器直连
|
|
2814
|
+
* 与"增量检索")+ enrich 回调各自 setMarket,点的时机不同就出现"点两次结果不同"的竞态。 */
|
|
2815
|
+
const searchSeqRef = react.useRef(0);
|
|
2597
2816
|
const search = () => {
|
|
2817
|
+
const seq = searchSeqRef.current + 1;
|
|
2818
|
+
searchSeqRef.current = seq;
|
|
2819
|
+
const current = () => searchSeqRef.current === seq;
|
|
2598
2820
|
setMarket({ status: "loading" });
|
|
2599
2821
|
setRepoInfo(null);
|
|
2600
2822
|
setMarketPage(1);
|
|
@@ -2605,36 +2827,39 @@ window.__ModuleLoader__.load({
|
|
|
2605
2827
|
return;
|
|
2606
2828
|
}
|
|
2607
2829
|
if (query.trim() === "" && indexData !== null && indexData.loaded) {
|
|
2608
|
-
|
|
2830
|
+
const shown = indexData.skills.slice(0, indexShown);
|
|
2831
|
+
setMarket({ status: "ready", data: shown, hints: envelopeFromIndex(indexData.skills, shown.length, 1, 50), direct: false, source: "github", fromIndex: true });
|
|
2609
2832
|
return;
|
|
2610
2833
|
}
|
|
2611
2834
|
call("/plugin-console/search", { q: query, page: 1, skills: true }).then(
|
|
2612
|
-
(data) => {
|
|
2613
|
-
|
|
2835
|
+
(data) => {
|
|
2836
|
+
if (!current()) return;
|
|
2837
|
+
const items = rankSearchResults(data.items ?? [], query);
|
|
2838
|
+
const hints = envelopeOf(data, 1) ?? envelopeFromIndex(items, items.length, 1);
|
|
2839
|
+
setMarket({ status: "ready", data: items, hints, direct: false, source: "github", skills: true });
|
|
2840
|
+
},
|
|
2841
|
+
(error) => { if (current()) setMarket({ status: "error", error: friendlyGithubError(error) }); },
|
|
2614
2842
|
);
|
|
2615
2843
|
return;
|
|
2616
2844
|
}
|
|
2617
2845
|
// 静态索引浏览:GitHub 源 + 空查询时展示 dsh-plugin topic 全量索引(秒开、零 API 调用)
|
|
2618
2846
|
if (searchSource === "github" && !multiSource && query.trim() === "" && indexData !== null && indexData.loaded) {
|
|
2619
|
-
|
|
2847
|
+
const shown = indexData.items.slice(0, indexShown);
|
|
2848
|
+
setMarket({ status: "ready", data: shown, hints: envelopeFromIndex(indexData.items, shown.length, 1, 50), direct: false, source: "github", fromIndex: true });
|
|
2620
2849
|
return;
|
|
2621
2850
|
}
|
|
2622
|
-
//
|
|
2623
|
-
//
|
|
2624
|
-
|
|
2625
|
-
const local = fuzzyMatchIndex(query, indexData.items);
|
|
2626
|
-
if (local.length > 0) {
|
|
2627
|
-
setMarket({ status: "ready", data: local, direct: false, source: "github", fromIndex: true, fuzzy: true });
|
|
2628
|
-
return;
|
|
2629
|
-
}
|
|
2630
|
-
}
|
|
2851
|
+
// 0.5.35 改错:这里原来还有一条「非空查询先做本地索引模糊匹配,命中即 return」的链 ——
|
|
2852
|
+
// 它就是"第二次搜索变成一大堆高星无关仓库 / 没有加载更多"的元凶(见上方说明),已删除。
|
|
2853
|
+
// 非空查询现在只有一条链:真实搜索(直连 GitHub → 失败回落服务端),结果统一走名字分层排序。
|
|
2631
2854
|
if (multiSource) {
|
|
2632
2855
|
// 多源汇总:GitHub + 全部自定义源并行(服务端合并,自带标记)
|
|
2633
2856
|
call("/plugin-console/search", { q: query, page: 1, multi: true }).then(
|
|
2634
2857
|
(data) => {
|
|
2635
|
-
|
|
2858
|
+
if (!current()) return;
|
|
2859
|
+
const items = rankSearchResults(data.items ?? [], query);
|
|
2860
|
+
setMarket({ status: "ready", data: items, hints: envelopeOf(data, 1), direct: false, source: "all", multi: true });
|
|
2636
2861
|
},
|
|
2637
|
-
(error) => setMarket({ status: "error", error: friendlyGithubError(error) }),
|
|
2862
|
+
(error) => { if (current()) setMarket({ status: "error", error: friendlyGithubError(error) }); },
|
|
2638
2863
|
);
|
|
2639
2864
|
return;
|
|
2640
2865
|
}
|
|
@@ -2642,27 +2867,34 @@ window.__ModuleLoader__.load({
|
|
|
2642
2867
|
// Gitee / 自定义源:走服务端平台检索(浏览器直连通道对这些平台不可靠)
|
|
2643
2868
|
call("/plugin-console/search", { q: query, page: 1, source: searchSource }).then(
|
|
2644
2869
|
(data) => {
|
|
2645
|
-
|
|
2646
|
-
|
|
2870
|
+
if (!current()) return;
|
|
2871
|
+
const items = rankSearchResults(data.items ?? [], query);
|
|
2872
|
+
setMarket({ status: "ready", data: items, hints: envelopeOf(data, 1), direct: false, source: searchSource });
|
|
2873
|
+
enrichOfficialBundle(items).then((enriched) => {
|
|
2874
|
+
if (!current()) return;
|
|
2647
2875
|
applyEnriched(enriched);
|
|
2648
2876
|
});
|
|
2649
2877
|
},
|
|
2650
|
-
(error) => setMarket({ status: "error", error: friendlyGithubError(error) }),
|
|
2878
|
+
(error) => { if (current()) setMarket({ status: "error", error: friendlyGithubError(error) }); },
|
|
2651
2879
|
);
|
|
2652
2880
|
return;
|
|
2653
2881
|
}
|
|
2654
2882
|
searchFromGithub(query, 1, repoLandOn).then(
|
|
2655
|
-
(
|
|
2656
|
-
|
|
2657
|
-
|
|
2883
|
+
({ items: rawItems, total: rawTotal }) => {
|
|
2884
|
+
if (!current()) return;
|
|
2885
|
+
// 秒出直连数据(**同样过唯一排序函数**:直连链与服务端链的结果顺序必须一致,
|
|
2886
|
+
// 否则"点两次结果不同"的观感还在)
|
|
2887
|
+
const items = rankSearchResults(rawItems, query);
|
|
2888
|
+
setMarket({ status: "ready", data: items, hints: envelopeFromGithub(rawTotal, items.length, 1), direct: true });
|
|
2658
2889
|
// 并行补标记:
|
|
2659
2890
|
// ① 客户端浏览器直连读根包 package.json(快,官方/聚合标记立即可筛)
|
|
2660
|
-
enrichOfficialBundle(
|
|
2891
|
+
enrichOfficialBundle(items).then((enriched) => {
|
|
2892
|
+
if (!current()) return;
|
|
2661
2893
|
applyEnriched(enriched);
|
|
2662
2894
|
});
|
|
2663
2895
|
// ② 服务端 curl 双通道 enrich(聚合子包 dsh.bundle 检查 → aggregateInstallable),后台补更精确标记
|
|
2664
|
-
call("/plugin-console/enrich", { items
|
|
2665
|
-
(r) => { if (r && Array.isArray(r.items)) applyEnriched(r.items); },
|
|
2896
|
+
call("/plugin-console/enrich", { items }).then(
|
|
2897
|
+
(r) => { if (current() && r && Array.isArray(r.items)) applyEnriched(r.items); },
|
|
2666
2898
|
() => {},
|
|
2667
2899
|
);
|
|
2668
2900
|
// ③ 服务端"增量检索"(并行、不阻塞首屏):npm 包名映射 + in:readme 重查 + 代码搜索子包。
|
|
@@ -2670,9 +2902,16 @@ window.__ModuleLoader__.load({
|
|
|
2670
2902
|
if (query.trim() !== "") {
|
|
2671
2903
|
call("/plugin-console/search", { q: query, page: 1, extras: true, all: repoLandOn === true }).then(
|
|
2672
2904
|
(r) => {
|
|
2905
|
+
if (!current()) return;
|
|
2673
2906
|
if (r !== null && r.codeSearchSkipped === true) setMessage(t("searchLoginHint"));
|
|
2674
2907
|
if (r === null || !Array.isArray(r.items) || r.items.length === 0) return;
|
|
2675
|
-
|
|
2908
|
+
// 合并后**再排一次**(唯一排序函数):npm/README 命中该进哪一层由分层判据决定,
|
|
2909
|
+
// 不由"谁是后到的"决定。
|
|
2910
|
+
setMarket((m) => {
|
|
2911
|
+
if (m === null || m.status !== "ready") return m;
|
|
2912
|
+
const merged = rankSearchResults(mergeSearchExtras(m.data, r.items), query);
|
|
2913
|
+
return { ...m, data: merged, hints: repaginate(m.hints, merged) };
|
|
2914
|
+
});
|
|
2676
2915
|
},
|
|
2677
2916
|
() => {},
|
|
2678
2917
|
);
|
|
@@ -2680,34 +2919,52 @@ window.__ModuleLoader__.load({
|
|
|
2680
2919
|
},
|
|
2681
2920
|
() => call("/plugin-console/search", { q: query, page: 1 }).then(
|
|
2682
2921
|
(data) => {
|
|
2683
|
-
|
|
2684
|
-
|
|
2922
|
+
if (!current()) return;
|
|
2923
|
+
const items = rankSearchResults(data.items ?? [], query);
|
|
2924
|
+
setMarket({ status: "ready", data: items, hints: envelopeOf(data, 1), direct: false });
|
|
2685
2925
|
enrichOfficialBundle(items).then((enriched) => {
|
|
2926
|
+
if (!current()) return;
|
|
2686
2927
|
applyEnriched(enriched);
|
|
2687
2928
|
});
|
|
2688
2929
|
},
|
|
2689
|
-
(error) => setMarket({ status: "error", error: friendlyGithubError(error) }),
|
|
2930
|
+
(error) => { if (current()) setMarket({ status: "error", error: friendlyGithubError(error) }); },
|
|
2690
2931
|
),
|
|
2691
2932
|
);
|
|
2692
2933
|
};
|
|
2934
|
+
/** 翻页合并:按 fullName 去重("+N 条"的新条目才追加)→ 全表**再排一次**(唯一排序函数,
|
|
2935
|
+
* 所以跨页顺序与数据源给的单页顺序一致)→ 重算口径(total/hasMore/truncated 是数据源事实)。 */
|
|
2936
|
+
const appendPage = (prevList, pageItems, baseHints, mergeHints, page, perPage = 20) => {
|
|
2937
|
+
const seen = new Set();
|
|
2938
|
+
const merged = [];
|
|
2939
|
+
for (const item of [...(Array.isArray(prevList) ? prevList : []), ...(Array.isArray(pageItems) ? pageItems : [])]) {
|
|
2940
|
+
const key = item?.fullName ?? JSON.stringify(item);
|
|
2941
|
+
if (seen.has(key)) continue;
|
|
2942
|
+
seen.add(key);
|
|
2943
|
+
merged.push(item);
|
|
2944
|
+
}
|
|
2945
|
+
const ranked = rankSearchResults(merged, query);
|
|
2946
|
+
const src = mergeHints ?? baseHints;
|
|
2947
|
+
const hints = src === null || src === undefined
|
|
2948
|
+
? null
|
|
2949
|
+
: { ...src, shown: ranked.length, page, perPage };
|
|
2950
|
+
return { data: ranked, hints };
|
|
2951
|
+
};
|
|
2693
2952
|
const loadMore = () => {
|
|
2694
2953
|
if (loadingMore || market === null || market.status !== "ready") return;
|
|
2695
2954
|
const next = marketPage + 1;
|
|
2955
|
+
const seq = searchSeqRef.current;
|
|
2956
|
+
const current = () => searchSeqRef.current === seq;
|
|
2696
2957
|
setLoadingMore(true);
|
|
2697
2958
|
setMarketPage(next);
|
|
2959
|
+
const baseHints = market.hints ?? null;
|
|
2698
2960
|
if (mode === "skills" && !market.fromIndex) {
|
|
2699
|
-
// 技能搜索分页:服务端三 topic
|
|
2961
|
+
// 技能搜索分页:服务端三 topic 并集池切片(skills: true)
|
|
2700
2962
|
call("/plugin-console/search", { q: query, page: next, skills: true }).then(
|
|
2701
2963
|
(data) => {
|
|
2702
|
-
|
|
2703
|
-
const
|
|
2704
|
-
const
|
|
2705
|
-
|
|
2706
|
-
if (seen.has(item.fullName)) continue;
|
|
2707
|
-
seen.add(item.fullName);
|
|
2708
|
-
deduped.push(item);
|
|
2709
|
-
}
|
|
2710
|
-
setMarket({ status: "ready", data: deduped, direct: false, source: "github", skills: true });
|
|
2964
|
+
if (!current()) { setLoadingMore(false); return; }
|
|
2965
|
+
const hints = envelopeOf(data, next) ?? envelopeFromIndex(market.data, market.data.length, next);
|
|
2966
|
+
const page_ = appendPage(market.data, data.items, baseHints, hints, next);
|
|
2967
|
+
setMarket({ status: "ready", data: page_.data, hints: page_.hints, direct: false, source: "github", skills: true });
|
|
2711
2968
|
setLoadingMore(false);
|
|
2712
2969
|
},
|
|
2713
2970
|
(error) => {
|
|
@@ -2721,7 +2978,10 @@ window.__ModuleLoader__.load({
|
|
|
2721
2978
|
// 索引浏览:本地继续展示更多(技能模式浏览技能索引段)
|
|
2722
2979
|
const sourceData = mode === "skills" ? indexData.skills : indexData.items;
|
|
2723
2980
|
const more = sourceData.slice(0, indexShown + next * 50);
|
|
2724
|
-
setMarket({
|
|
2981
|
+
setMarket({
|
|
2982
|
+
status: "ready", data: more, direct: false, source: "github", fromIndex: true,
|
|
2983
|
+
hints: envelopeFromIndex(sourceData, more.length, next, 50),
|
|
2984
|
+
});
|
|
2725
2985
|
setIndexShown(indexShown + next * 50);
|
|
2726
2986
|
// 新增的这段继续补「官方/聚合」标记(与首屏同样的增量策略)
|
|
2727
2987
|
if (mode !== "skills") enrichRange(enrichedUpTo, indexShown + next * 50, indexData.items);
|
|
@@ -2731,7 +2991,10 @@ window.__ModuleLoader__.load({
|
|
|
2731
2991
|
if (multiSource) {
|
|
2732
2992
|
call("/plugin-console/search", { q: query, page: next, multi: true }).then(
|
|
2733
2993
|
(data) => {
|
|
2734
|
-
|
|
2994
|
+
if (!current()) { setLoadingMore(false); return; }
|
|
2995
|
+
const hints = envelopeOf(data, next) ?? envelopeFromIndex(market.data, market.data.length, next);
|
|
2996
|
+
const page_ = appendPage(market.data, data.items, baseHints, hints, next);
|
|
2997
|
+
setMarket({ status: "ready", data: page_.data, hints: page_.hints, direct: false, source: "all", multi: true });
|
|
2735
2998
|
setLoadingMore(false);
|
|
2736
2999
|
},
|
|
2737
3000
|
(error) => {
|
|
@@ -2744,11 +3007,16 @@ window.__ModuleLoader__.load({
|
|
|
2744
3007
|
if (searchSource !== "github") {
|
|
2745
3008
|
call("/plugin-console/search", { q: query, page: next, source: searchSource }).then(
|
|
2746
3009
|
(data) => {
|
|
2747
|
-
|
|
3010
|
+
if (!current()) { setLoadingMore(false); return; }
|
|
3011
|
+
const hints = envelopeOf(data, next) ?? envelopeFromIndex(market.data, market.data.length, next);
|
|
3012
|
+
const page_ = appendPage(market.data, data.items, baseHints, hints, next);
|
|
3013
|
+
setMarket({ status: "ready", data: page_.data, hints: page_.hints, direct: false, source: searchSource });
|
|
2748
3014
|
setLoadingMore(false);
|
|
2749
3015
|
enrichOfficialBundle(data.items).then((enriched) => {
|
|
3016
|
+
if (!current()) return;
|
|
3017
|
+
const byName = new Map(enriched.map((x) => [x.fullName, x]));
|
|
2750
3018
|
setMarket((m) => (m !== null && m.status === "ready"
|
|
2751
|
-
? { ...m, data:
|
|
3019
|
+
? { ...m, data: m.data.map((x) => byName.get(x.fullName) ?? x) }
|
|
2752
3020
|
: m));
|
|
2753
3021
|
});
|
|
2754
3022
|
},
|
|
@@ -2760,33 +3028,38 @@ window.__ModuleLoader__.load({
|
|
|
2760
3028
|
return;
|
|
2761
3029
|
}
|
|
2762
3030
|
searchFromGithub(query, next).then(
|
|
2763
|
-
(
|
|
2764
|
-
|
|
3031
|
+
({ items: rawItems, total: rawTotal }) => {
|
|
3032
|
+
if (!current()) { setLoadingMore(false); return; }
|
|
3033
|
+
const hints = envelopeFromGithub(rawTotal, rawItems.length, next);
|
|
3034
|
+
const page_ = appendPage(market.data, rawItems, baseHints, hints, next);
|
|
3035
|
+
setMarket({ status: "ready", data: page_.data, hints: page_.hints, direct: true });
|
|
2765
3036
|
setLoadingMore(false);
|
|
2766
|
-
// 并行补标记:客户端快速(根包)+
|
|
2767
|
-
|
|
3037
|
+
// 并行补标记:客户端快速(根包)+ 服务端完整(子包检查)。
|
|
3038
|
+
// 按 fullName **就地更新**(不再靠"取末尾 N 条"的假设——排序变了,末尾不一定是新页)。
|
|
3039
|
+
const patchByName = (list) => {
|
|
3040
|
+
const byName = new Map(list.map((x) => [x.fullName, x]));
|
|
2768
3041
|
setMarket((m) => (m !== null && m.status === "ready"
|
|
2769
|
-
? { ...m, data:
|
|
3042
|
+
? { ...m, data: m.data.map((x) => byName.get(x.fullName) ?? x) }
|
|
2770
3043
|
: m));
|
|
2771
|
-
}
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
setMarket((m) => (m !== null && m.status === "ready"
|
|
2776
|
-
? { ...m, data: [...m.data.slice(0, m.data.length - r.items.length), ...r.items] }
|
|
2777
|
-
: m));
|
|
2778
|
-
}
|
|
2779
|
-
},
|
|
3044
|
+
};
|
|
3045
|
+
enrichOfficialBundle(rawItems).then((enriched) => { if (current()) patchByName(enriched); });
|
|
3046
|
+
call("/plugin-console/enrich", { items: rawItems }).then(
|
|
3047
|
+
(r) => { if (current() && r && Array.isArray(r.items)) patchByName(r.items); },
|
|
2780
3048
|
() => {},
|
|
2781
3049
|
);
|
|
2782
3050
|
},
|
|
2783
3051
|
() => call("/plugin-console/search", { q: query, page: next }).then(
|
|
2784
3052
|
(data) => {
|
|
2785
|
-
|
|
3053
|
+
if (!current()) { setLoadingMore(false); return; }
|
|
3054
|
+
const hints = envelopeOf(data, next) ?? envelopeFromIndex(market.data, market.data.length, next);
|
|
3055
|
+
const page_ = appendPage(market.data, data.items, baseHints, hints, next);
|
|
3056
|
+
setMarket({ status: "ready", data: page_.data, hints: page_.hints, direct: false });
|
|
2786
3057
|
setLoadingMore(false);
|
|
2787
3058
|
enrichOfficialBundle(data.items).then((enriched) => {
|
|
3059
|
+
if (!current()) return;
|
|
3060
|
+
const byName = new Map(enriched.map((x) => [x.fullName, x]));
|
|
2788
3061
|
setMarket((m) => (m !== null && m.status === "ready"
|
|
2789
|
-
? { ...m, data:
|
|
3062
|
+
? { ...m, data: m.data.map((x) => byName.get(x.fullName) ?? x) }
|
|
2790
3063
|
: m));
|
|
2791
3064
|
});
|
|
2792
3065
|
},
|
|
@@ -2979,8 +3252,8 @@ window.__ModuleLoader__.load({
|
|
|
2979
3252
|
);
|
|
2980
3253
|
};
|
|
2981
3254
|
/** 安装进度文案:服务端 progress{channel,phase,index,total,name,done} → 一行人话。
|
|
2982
|
-
|
|
2983
|
-
|
|
3255
|
+
* 2026-09-20 真装实测:11 个子包的聚合仓库跑 19 分钟,面板只有"安装中"——用户不知道
|
|
3256
|
+
* 在第几个、还剩几个、当前装的是谁。这里把服务端下发的进度翻成"第 i/n 个:<名字>"。 */
|
|
2984
3257
|
const progressText = (progress) => {
|
|
2985
3258
|
if (progress === null || progress === undefined) return "";
|
|
2986
3259
|
if (progress.done === true) return t("progressDone").replace("{total}", String(progress.total ?? 0));
|
|
@@ -2993,7 +3266,7 @@ window.__ModuleLoader__.load({
|
|
|
2993
3266
|
.replace("{name}", progress.name ?? "");
|
|
2994
3267
|
};
|
|
2995
3268
|
/** 授权倒计时(剩余 mm:ss):服务端只给请求时间 + 超时上限,剩余量在前端算。
|
|
2996
|
-
|
|
3269
|
+
* 轮询每 2s 触发一次重渲染,倒计时随之刷新,不需要额外的定时器。 */
|
|
2997
3270
|
const consentRemaining = (job) => {
|
|
2998
3271
|
const consent = job?.aiConsent ?? null;
|
|
2999
3272
|
if (consent === null || consent.pending !== true || typeof consent.since !== "number") return null;
|
|
@@ -3007,10 +3280,10 @@ window.__ModuleLoader__.load({
|
|
|
3007
3280
|
};
|
|
3008
3281
|
//#region install-diagnosis-lines
|
|
3009
3282
|
/** 安装诊断短句(2026-09-26 加法):把服务端下发的 diagnosis / entryCheck / integrity 折成
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3283
|
+
* **一两行短句**(解释性长文一律不进面板 —— 用户明确要求;长文案只挂 title 悬浮提示)。
|
|
3284
|
+
* 返回 [{ key, text, level, title }]:level 为 null(中性)| "warn" | "error",
|
|
3285
|
+
* 直接映射既有 styles.message + data-warn / data-error 约定,不新增徽章 / 按钮 / class。
|
|
3286
|
+
* 无问题时不产出任何行(不占版面);摘要「已校验 …」按需求作为极短一行保留。 */
|
|
3014
3287
|
const diagLines = (job) => {
|
|
3015
3288
|
const view = job === null || job === undefined ? {} : job;
|
|
3016
3289
|
const lines = [];
|
|
@@ -3099,7 +3372,7 @@ window.__ModuleLoader__.load({
|
|
|
3099
3372
|
title: line.title === null || line.title === undefined ? undefined : line.title,
|
|
3100
3373
|
}, line.text);
|
|
3101
3374
|
/** 安装诊断卡(加法):**装成功但装后校验 / 摘要校验有问题**的作业 → 一张卡片;
|
|
3102
|
-
|
|
3375
|
+
* 无问题(或只有「已校验 …」这类中性行)返回 null,不占版面、不加按钮/徽章。 */
|
|
3103
3376
|
const diagCardEl = (job) => {
|
|
3104
3377
|
const lines = diagLines(job).filter((line) => line.level !== null);
|
|
3105
3378
|
if (lines.length === 0) return null;
|
|
@@ -3318,8 +3591,8 @@ window.__ModuleLoader__.load({
|
|
|
3318
3591
|
};
|
|
3319
3592
|
}, []);
|
|
3320
3593
|
/** 搜索结果卡片上的"添加到本地":直接启动安装任务(服务端解析包名与类型),
|
|
3321
|
-
|
|
3322
|
-
|
|
3594
|
+
* 点击立即出现进度卡片——不再先浏览器取包名(黑洞期直连失败会拖到 40s 无反馈)。
|
|
3595
|
+
* 技能条目走技能通道,套装条目走套装通道。 */
|
|
3323
3596
|
const addLocal = (item) => {
|
|
3324
3597
|
if (installing !== null) return;
|
|
3325
3598
|
setInstalling(item.fullName);
|
|
@@ -3490,7 +3763,11 @@ window.__ModuleLoader__.load({
|
|
|
3490
3763
|
entry.pendingCompat === true
|
|
3491
3764
|
? el("p", { className: styles.status, "data-pending": entry.adoptable ? "false" : "true" },
|
|
3492
3765
|
entry.adoptable
|
|
3493
|
-
?
|
|
3766
|
+
? (entry.adoptable.basis === "verdict-rescinded"
|
|
3767
|
+
// 0.5.34:旧判据的误报已被当前判据撤回(真机 dshmarket 现场)——如实说是"判据更新",
|
|
3768
|
+
// 不能说成"插件已适配"(那会让人以为作者发过新版)
|
|
3769
|
+
? t("adoptableRescinded").replace("{version}", String(entry.adoptable.version ?? "?"))
|
|
3770
|
+
: t("adoptableDetected").replace("{version}", String(entry.adoptable.version ?? "?")).replace("{prev}", String(compatInfo?.version ?? "?")))
|
|
3494
3771
|
: t("pendingCompatHint") + (compatInfo && compatInfo.checkNote ? ";已知校验:" + compatInfo.checkNote : ""))
|
|
3495
3772
|
: null,
|
|
3496
3773
|
meta !== null && meta.version ? el("div", { className: styles.rowTop },
|
|
@@ -3607,9 +3884,10 @@ window.__ModuleLoader__.load({
|
|
|
3607
3884
|
type: "button",
|
|
3608
3885
|
className: styles.toggle,
|
|
3609
3886
|
disabled: !entry.toggleable || busy === entry.entryId || entry.pendingCompat === true,
|
|
3610
|
-
|
|
3887
|
+
// 0.5.34:结论已被当前判据撤回的行不再显示「待适配」(旧判据的误报不许当事实展示)
|
|
3888
|
+
title: entry.pendingCompat === true ? (entry.compatRescinded === true ? t("compatRescindedHint") : t("pendingCompatHint")) : undefined,
|
|
3611
3889
|
onClick: () => toggle(entry, !entry.enabled),
|
|
3612
|
-
}, busy === entry.entryId ? t("loadingPhase") : (entry.pendingCompat === true ? t("pendingCompatTag") : t(entry.enabled ? "off" : "on"))),
|
|
3890
|
+
}, busy === entry.entryId ? t("loadingPhase") : (entry.pendingCompat === true ? (entry.compatRescinded === true ? t("compatRescindedTag") : t("pendingCompatTag")) : t(entry.enabled ? "off" : "on"))),
|
|
3613
3891
|
el("button", {
|
|
3614
3892
|
type: "button",
|
|
3615
3893
|
className: styles.toggle,
|
|
@@ -4087,25 +4365,25 @@ window.__ModuleLoader__.load({
|
|
|
4087
4365
|
// (老服务端没有该字段时回落 !supported),并给一个手动关闭入口 —— 关闭只影响展示:
|
|
4088
4366
|
// 服务端记的是「这个框架版本我看过了」,版本一变会重新提示;supported 与门控语义一个字都不变。
|
|
4089
4367
|
state.status === "ready" && state.data.compat
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4368
|
+
&& (state.data.compat.noticeVisible === undefined
|
|
4369
|
+
? !state.data.compat.supported
|
|
4370
|
+
: state.data.compat.noticeVisible === true)
|
|
4371
|
+
&& !compatNoticeClosed
|
|
4372
|
+
? el("p", { className: styles.message, "data-error": "true" },
|
|
4373
|
+
state.data.compat.notice,
|
|
4374
|
+
" ",
|
|
4375
|
+
el("button", {
|
|
4376
|
+
type: "button",
|
|
4377
|
+
style: { marginLeft: "8px", cursor: "pointer" },
|
|
4378
|
+
title: t("compatNoticeDismiss"),
|
|
4379
|
+
onClick: () => {
|
|
4380
|
+
// 失败不收起(关了却还在服务端显示会造成「点了没反应」的错觉)
|
|
4381
|
+
call("/plugin-console/compat-ack", { webAppVersion: state.data.compat?.webAppVersion })
|
|
4382
|
+
.then(() => setCompatNoticeClosed(true), () => {});
|
|
4383
|
+
},
|
|
4384
|
+
}, t("compatNoticeDismiss")),
|
|
4385
|
+
)
|
|
4386
|
+
: null,
|
|
4109
4387
|
state.status === "ready" && comps.length > 0 && details === null && repoInfo === null
|
|
4110
4388
|
? el("button", {
|
|
4111
4389
|
type: "button",
|
|
@@ -4297,7 +4575,7 @@ window.__ModuleLoader__.load({
|
|
|
4297
4575
|
el("p", { className: styles.message }, t("compatGateHint")),
|
|
4298
4576
|
el("p", { className: styles.status, "data-pending": gatePendingCount > 0 ? "true" : undefined },
|
|
4299
4577
|
gatePendingCount > 0 ? t("gatePendingInfo").replace("{n}", String(gatePendingCount)) : t("gatePendingNone")),
|
|
4300
|
-
|
|
4578
|
+
el("p", { className: styles.status, "data-pending": gatePendingCount > 0 ? "true" : undefined },
|
|
4301
4579
|
gatePendingCount > 0 ? t("gatePendingInfo").replace("{n}", String(gatePendingCount)) : t("gatePendingNone")),
|
|
4302
4580
|
// 明细清单(2026-09-24 用户要求:面板要能看到是哪些插件,有列表数据)
|
|
4303
4581
|
gateRows !== null && gateRows.pendingCount + gateRows.adoptedCount > 0
|
|
@@ -4451,49 +4729,49 @@ window.__ModuleLoader__.load({
|
|
|
4451
4729
|
);
|
|
4452
4730
|
},
|
|
4453
4731
|
}, "🧹 " + t("cleanResiduals")),
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4732
|
+
el("button", {
|
|
4733
|
+
type: "button",
|
|
4734
|
+
style: { position: "fixed", left: 12, bottom: 44, zIndex: 1000, opacity: 0.75 },
|
|
4735
|
+
title: t("cleanFrameworkResiduals"),
|
|
4736
|
+
onClick: () => {
|
|
4737
|
+
// 2026-09-28 加法:框架残留清理(顶层旧版本目录 / framework-backups)。两步走:
|
|
4738
|
+
// 先 dryRun 出报告 → window.confirm 让用户看清要动什么 → 才带 confirm:true 真执行。
|
|
4739
|
+
// 服务端默认 dryRun,所以「误点一下」不会动任何文件。
|
|
4740
|
+
const SCOPES = ["framework", "frameworkBackups", "pnpmEntities"];
|
|
4741
|
+
setMessage(t("cleanFrameworkResiduals") + "…");
|
|
4742
|
+
call("/plugin-console/clean-residuals", { scope: SCOPES }).then(
|
|
4743
|
+
(report) => {
|
|
4744
|
+
const fw = report && report.framework ? report.framework : null;
|
|
4745
|
+
const bk = report && report.frameworkBackups ? report.frameworkBackups : null;
|
|
4746
|
+
const pe = report && report.pnpmEntities ? report.pnpmEntities : null;
|
|
4747
|
+
const stale = fw && Array.isArray(fw.planned) ? fw.planned.length : 0;
|
|
4748
|
+
const pend = bk && Array.isArray(bk.plannedRemove) ? bk.plannedRemove : [];
|
|
4749
|
+
const mb = Math.round(pend.reduce((s, it) => s + (it && Number.isFinite(it.sizeBytes) ? it.sizeBytes : 0), 0) / 1048576);
|
|
4750
|
+
const entities = pe && Number.isFinite(pe.entityCount) ? pe.entityCount : 0;
|
|
4751
|
+
const head = t("cleanFrameworkResiduals") + ":" + t("cfStale").replace("{n}", String(stale))
|
|
4752
|
+
+ "、" + t("cfBackups").replace("{n}", String(pend.length)).replace("{mb}", String(mb))
|
|
4753
|
+
+ (entities > 0 ? ";" + t("cfEntities").replace("{n}", String(entities)) : "");
|
|
4754
|
+
if (stale === 0 && pend.length === 0) { setMessage(head + ";" + t("cfNothing")); return; }
|
|
4755
|
+
if (!window.confirm(head + "\n" + t("cfConfirm"))) { setMessage(head + ";" + t("cfCancelled")); return; }
|
|
4756
|
+
setMessage(t("cfRunning"));
|
|
4757
|
+
call("/plugin-console/clean-residuals", { scope: SCOPES, confirm: true, keep: 1 }).then(
|
|
4758
|
+
(done) => {
|
|
4759
|
+
const renamed = done && done.framework && Array.isArray(done.framework.renamed) ? done.framework.renamed.length : 0;
|
|
4760
|
+
const relinked = done && done.framework && Array.isArray(done.framework.relinked) ? done.framework.relinked.length : 0;
|
|
4761
|
+
const removed = done && done.frameworkBackups && Array.isArray(done.frameworkBackups.removed) ? done.frameworkBackups.removed.length : 0;
|
|
4762
|
+
const freed = done && done.frameworkBackups && Number.isFinite(done.frameworkBackups.freedBytes) ? Math.round(done.frameworkBackups.freedBytes / 1048576) : 0;
|
|
4763
|
+
const failed = (done && done.framework && Array.isArray(done.framework.failed) ? done.framework.failed.length : 0)
|
|
4764
|
+
+ (done && done.frameworkBackups && Array.isArray(done.frameworkBackups.failed) ? done.frameworkBackups.failed.length : 0);
|
|
4765
|
+
setMessage(t("cfDone").replace("{renamed}", String(renamed)).replace("{linked}", String(relinked)).replace("{removed}", String(removed)).replace("{mb}", String(freed))
|
|
4766
|
+
+ (failed > 0 ? ";" + t("cfFailed").replace("{n}", String(failed)) : ""));
|
|
4767
|
+
},
|
|
4768
|
+
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
4769
|
+
);
|
|
4770
|
+
},
|
|
4771
|
+
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
4772
|
+
);
|
|
4773
|
+
},
|
|
4774
|
+
}, "🧰 " + t("cleanFrameworkResiduals")),
|
|
4497
4775
|
fwShowCard
|
|
4498
4776
|
? el("div", { className: styles.detail },
|
|
4499
4777
|
el("div", { className: styles.rowTop },
|
|
@@ -4557,30 +4835,30 @@ window.__ModuleLoader__.load({
|
|
|
4557
4835
|
? t("marketTitle")
|
|
4558
4836
|
: t("marketTitleOther").replace("{source}", sourceDisplayName(searchSource)))),
|
|
4559
4837
|
el("div", { id: "pc-ghwrap", className: styles.ghwrap },
|
|
4560
|
-
selfUpdate !== null ? el("button", {
|
|
4561
|
-
type: "button",
|
|
4562
|
-
className: styles.ghpill,
|
|
4563
|
-
title: t("hubUpdateAvailable") + " v" + selfUpdate.latest,
|
|
4564
|
-
onClick: () => {
|
|
4565
|
-
setMessage(t("installing"));
|
|
4566
|
-
call("/plugin-console/self-update", {}).then(
|
|
4567
|
-
(data) => {
|
|
4568
|
-
if (data && data.ok === true) {
|
|
4569
|
-
// 未写进 lockfile 时必须**显眼**说清(用户实测报告:只铺文件不写 lock → 之后任何 pnpm 操作
|
|
4570
|
-
// 都会把版本还原,而用户以为升级成功了)
|
|
4571
|
-
const lockWarn = data.lockUpdated === false && typeof data.lockNote === "string" && data.lockNote !== ""
|
|
4572
|
-
? "⚠️ " + data.lockNote
|
|
4573
|
-
: "";
|
|
4574
|
-
setMessage((data.note ?? "已更新") + (lockWarn === "" ? "" : "。" + lockWarn) + ",正在重启生效…");
|
|
4575
|
-
restartServiceViaServer(setMessage, { reload: false });
|
|
4576
|
-
} else {
|
|
4577
|
-
setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
4578
|
-
}
|
|
4579
|
-
},
|
|
4580
|
-
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
4581
|
-
);
|
|
4582
|
-
}
|
|
4583
|
-
}, "⬇ " + t("hubUpdateAvailable") + " v" + selfUpdate.latest) : null,
|
|
4838
|
+
selfUpdate !== null ? el("button", {
|
|
4839
|
+
type: "button",
|
|
4840
|
+
className: styles.ghpill,
|
|
4841
|
+
title: t("hubUpdateAvailable") + " v" + selfUpdate.latest,
|
|
4842
|
+
onClick: () => {
|
|
4843
|
+
setMessage(t("installing"));
|
|
4844
|
+
call("/plugin-console/self-update", {}).then(
|
|
4845
|
+
(data) => {
|
|
4846
|
+
if (data && data.ok === true) {
|
|
4847
|
+
// 未写进 lockfile 时必须**显眼**说清(用户实测报告:只铺文件不写 lock → 之后任何 pnpm 操作
|
|
4848
|
+
// 都会把版本还原,而用户以为升级成功了)
|
|
4849
|
+
const lockWarn = data.lockUpdated === false && typeof data.lockNote === "string" && data.lockNote !== ""
|
|
4850
|
+
? "⚠️ " + data.lockNote
|
|
4851
|
+
: "";
|
|
4852
|
+
setMessage((data.note ?? "已更新") + (lockWarn === "" ? "" : "。" + lockWarn) + ",正在重启生效…");
|
|
4853
|
+
restartServiceViaServer(setMessage, { reload: false });
|
|
4854
|
+
} else {
|
|
4855
|
+
setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
4856
|
+
}
|
|
4857
|
+
},
|
|
4858
|
+
(error) => setMessage(t("safetySwitchFailed") + ":" + friendlyGithubError(error).message),
|
|
4859
|
+
);
|
|
4860
|
+
}
|
|
4861
|
+
}, "⬇ " + t("hubUpdateAvailable") + " v" + selfUpdate.latest) : null,
|
|
4584
4862
|
el("button", {
|
|
4585
4863
|
type: "button",
|
|
4586
4864
|
className: styles.ghpill,
|
|
@@ -4908,7 +5186,25 @@ setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
|
4908
5186
|
el("button", { type: "button", onClick: search }, t("search")),
|
|
4909
5187
|
),
|
|
4910
5188
|
!marketCollapsed && marketRows.length > 0 ? el("ul", { className: styles.market }, marketRows) : null,
|
|
4911
|
-
|
|
5189
|
+
// 0.5.35:结果状态行 —— "共 N 条 / 已显示 M 条"(数据源没给总数时只报"已显示 M 条",
|
|
5190
|
+
// 绝不编造总数);**被截断**时明说"可继续加载"(而不是让用户以为"就是没有")。
|
|
5191
|
+
!marketCollapsed && market !== null && market.status === "ready" && market.data.length > 0
|
|
5192
|
+
? el("p", { className: styles.note, "data-truncated": market.hints !== null && market.hints !== undefined && market.hints.truncated === true ? "true" : "false" },
|
|
5193
|
+
(market.hints !== null && market.hints !== undefined && typeof market.hints.total === "number"
|
|
5194
|
+
? t("marketCount").replace("{total}", String(market.hints.total)).replace("{shown}", String(market.data.length))
|
|
5195
|
+
: t("marketCountKnown").replace("{shown}", String(market.data.length)))
|
|
5196
|
+
+ (market.hints !== null && market.hints !== undefined && market.hints.truncated === true
|
|
5197
|
+
? " · " + (market.hints.hasMore === true ? t("marketTruncated") : t("marketTruncatedEnd"))
|
|
5198
|
+
+ (typeof market.hints.reason === "string" && market.hints.reason !== "" ? ":" + market.hints.reason : "")
|
|
5199
|
+
: ""))
|
|
5200
|
+
: null,
|
|
5201
|
+
// 「加载更多」的判据从"长度 ≥ 20"改成**数据源给的口径**(hints.hasMore):
|
|
5202
|
+
// 旧判据下 3 条命中就不渲染按钮(用户"无从往下看"),而满 20 条又会在到底之后继续给空按钮。
|
|
5203
|
+
// hints 缺失(老响应/本地索引以外的场景)时退回旧判据,不假装知道。
|
|
5204
|
+
!marketCollapsed && market !== null && market.status === "ready"
|
|
5205
|
+
&& (market.hints !== null && market.hints !== undefined
|
|
5206
|
+
? market.hints.hasMore === true
|
|
5207
|
+
: market.data.length >= 20)
|
|
4912
5208
|
? el("div", { className: styles.descTopbar },
|
|
4913
5209
|
el("button", {
|
|
4914
5210
|
type: "button",
|
|
@@ -5345,11 +5641,11 @@ setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
|
5345
5641
|
// 所以做法是「就地抽屉」,而不是往别人的 DOM 里注入(注入会在对方更新时碎掉)。
|
|
5346
5642
|
// 原 tab(id=console)与悬浮面板一行未动。
|
|
5347
5643
|
/** 「建议动作」执行框(2026-09-27 加法,用户明确要求):安装结果旁的一个**小**框 ——
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5644
|
+
* 一句短说明 + 等宽只读命令 + 「执行」「复制」+ 执行中状态 + 结果/错误回显 + 可关闭。
|
|
5645
|
+
* 边界(与服务端同一条):面板只发**结构化动作**(`suggestedAction.payload`),
|
|
5646
|
+
* 命令字符串仅用于展示/复制;服务端只认白名单动作类型(见 domain/plugin-actions.js)。
|
|
5647
|
+
* 只用既有 styles.*(detail / rowTop / phase / name / message / note / toggle / trashBtn),
|
|
5648
|
+
* 不新增徽章、不新增独立面板 —— 长解释一律进悬浮 title。 */
|
|
5353
5649
|
function SuggestedActionBox({ job, t }) {
|
|
5354
5650
|
const [state, setState] = react.useState({ phase: "idle", text: null, level: null, title: null, closed: false });
|
|
5355
5651
|
// 2026-09-27 加法(选项 2):第二个显式动作的状态(「允许这些构建脚本」)。
|
|
@@ -5490,7 +5786,7 @@ setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
|
5490
5786
|
title: overwrite.title === null ? undefined : overwrite.title,
|
|
5491
5787
|
}, overwrite.text)));
|
|
5492
5788
|
}
|
|
5493
|
-
|
|
5789
|
+
|
|
5494
5790
|
function PluginSafetyTab({ t }) {
|
|
5495
5791
|
const [open, setOpen] = react.useState(false);
|
|
5496
5792
|
const [status, setStatus] = react.useState(null);
|
|
@@ -5724,4 +6020,4 @@ setMessage(t("safetySwitchFailed") + ":" + (data?.reason ?? "未知"));
|
|
|
5724
6020
|
exports.canAdaptUnlock = canAdaptUnlock;
|
|
5725
6021
|
return module.exports;
|
|
5726
6022
|
}
|
|
5727
|
-
});
|
|
6023
|
+
});
|