@noob-stupid/dsh-plugin-console 0.3.28 → 0.3.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/lib/client.js +297 -38
  2. package/lib/index.js +466 -41
  3. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -6,7 +6,7 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
8
  //#region styles
9
- const css = ".pc_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}.pc_section h3{margin:0;font-size:13px;font-weight:600;line-height:20px}.pc_message{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0}.pc_messageRow{display:flex;align-items:center;gap:10px}.pc_spinner{width:14px;height:14px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}@keyframes pcspin{to{transform:rotate(360deg)}}.pc_message[data-error=true]{color:var(--dsw-alias-state-error-primary)}.pc_list{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none;display:grid}.pc_row{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_rowTop{align-items:center;gap:8px;display:flex}.pc_name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pc_tag{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:16px;flex:none}.pc_tag[data-enabled=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-user=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_tag[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_status[data-pending=true]{color:var(--dsw-alias-state-warning-primary)}.pc_toggle[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-skill=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-system=true]{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}.pc_tag[data-disabled=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tag[data-suite=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-error=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tabGroup{display:inline-flex;gap:4px;align-items:center}.pc_meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;gap:6px;display:flex;align-items:center}.pc_phase[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.pc_phase[data-phase=active]{color:var(--dsw-alias-state-success-primary)}.pc_toggle{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_toggle:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_toggle:disabled{opacity:.5;cursor:default}.pc_search{gap:8px;display:flex}.pc_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;flex:1;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 12px;font-size:13px}.pc_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.pc_search button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:0 14px;font-size:13px}.pc_search button:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_market{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pc_item{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_itemTop{align-items:center;gap:8px;display:flex}.pc_itemTop a{color:var(--dsw-alias-state-business-primary);font-size:13px;font-weight:600;text-decoration:none;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pc_stars{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none}.pc_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_item button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:3px 10px;align-self:flex-start;font-size:12px}.pc_item button:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_item button:disabled{opacity:.5;cursor:default}.pc_detail{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_status{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_note{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0}.pc_marketHead{display:flex;align-items:center;justify-content:space-between;gap:10px}.pc_descWrap{flex-direction:column;display:flex}.pc_installedHead{display:flex;align-items:center;gap:10px}.pc_backTopWrap{position:fixed;top:56px;right:20px;z-index:100;display:flex;flex-direction:column;gap:8px}.pc_backTop{width:34px;height:34px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:rgba(22,27,34,.72);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;backdrop-filter:blur(4px);opacity:.7}.pc_backTop:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_descTopbar{display:flex;justify-content:flex-end;margin:2px 0}.pc_ghpill{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 10px;font-size:11px;line-height:18px}.pc_ghpill[data-on=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_extraBtn{opacity:.75;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 10px;font-size:12px;line-height:16px;flex:none;transition:opacity .15s ease,border-color 1.5s ease,color 1.5s ease}.pc_extraBtn:hover{opacity:1}.pc_extraBtn[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_extraBtn[data-flash=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_view{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px;flex:none}.pc_floatPanel{position:fixed;left:20px;top:50%;transform:translateY(-50%);width:340px;max-height:75vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:50;flex-direction:column;gap:8px;display:flex}.pc_refresh{position:sticky;bottom:14px;align-self:flex-end;margin-top:8px;z-index:60;opacity:.45;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:.45;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:.45;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_aiToggle:hover{opacity:.9}.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:.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_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:.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_modeFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_trashBtn{border:0;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:12px;line-height:16px;padding:2px 6px;flex:none;display:flex;align-items:center;border-radius:6px;transition:color .15s ease}.pc_trashBtn:hover{color:var(--dsw-alias-state-error-primary)}.pc_consentRemember{display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-secondary);cursor:pointer}.pc_modalBackdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center}.pc_modalCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:16px 18px;max-width:420px;width:calc(100% - 48px);flex-direction:column;gap:10px;display:flex;box-shadow:0 12px 32px rgba(0,0,0,.25)}.pc_ghpill{background:0 0;cursor:pointer}.pc_ghwrap{position:relative;display:inline-flex}.pc_sourceMenu{position:absolute;right:0;top:calc(100% + 6px);z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:4px;flex-direction:column;display:flex;min-width:120px;box-shadow:0 8px 24px rgba(0,0,0,.18)}.pc_sourceOpt{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 10px;text-align:left;font-size:12px;line-height:16px}.pc_sourceOpt[data-active=true]{color:var(--dsw-alias-state-business-primary);font-weight:600}.pc_sourceOpt:hover{background:var(--dsw-alias-bg-layer-3)}.pc_aiEmpower{position:fixed;right:20px;top:48px;z-index:70;opacity:.45;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_aiEmpower:hover{opacity:.9}.pc_aiEmpower[data-busy=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_aiEmpower[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_compCard{position:fixed;left:8px;top:20px;width:320px;max-height:70vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:45;flex-direction:column;gap:8px;display:flex}.pc_compCard .pc_rowTop{flex-wrap:wrap}.pc_compCard .pc_toggle{padding:3px 8px;font-size:11px}.pc_compCard[data-hidden=true]{display:none}.pc_compDrop{background:rgba(24,28,34,.92);backdrop-filter:blur(6px);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,.35);flex-direction:column;display:flex;gap:2px}.pc_compDropRow{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 8px;text-align:left;font-size:12px;line-height:16px;flex-direction:column;display:flex;gap:2px}.pc_compDropRow:hover{background:var(--dsw-alias-bg-layer-2)}.pc_compDropUrl{color:var(--dsw-alias-label-tertiary);font-size:11px;word-break:break-all}.pc_compToggle{position:fixed;left:336px;top:20px;z-index:46;opacity:.55;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:rgba(22,27,34,.72);font:inherit;cursor:pointer;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;backdrop-filter:blur(4px);transition:opacity .15s ease}.pc_compToggle:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain{position:fixed;right:70px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:border-color .15s ease}.pc_toolbarMain:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain[data-active=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolbarGroup{position:fixed;right:70px;top:56px;z-index:70;flex-direction:column;gap:8px;display:flex;transform-origin:top right;animation:pcDrawerIn .3s cubic-bezier(.34,1.56,.64,1)}@keyframes pcDrawerIn{from{opacity:0;transform:translateX(28px) scale(.94)}to{opacity:1;transform:translateX(0) scale(1)}}.pc_toolItem{opacity:.85;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_toolItem:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_switch{width:34px;height:18px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);position:relative;cursor:pointer;flex:none;transition:background .15s ease,border-color .15s ease}.pc_switch:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_switch[data-on=true]{background:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.pc_switchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;transition:left .15s ease}.pc_switch[data-on=true] .pc_switchKnob{left:18px}.pc_aiSpinner{width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}.pc_aiSpinBtn{position:fixed;right:152px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px}.pc_aiSpinBtn:hover{border-color:var(--dsw-alias-state-business-primary)}";
9
+ const css = ".pc_section{width:100%;max-width:760px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:14px;display:flex}.pc_section h3{margin:0;font-size:13px;font-weight:600;line-height:20px}.pc_message{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px;margin:0}.pc_messageRow{display:flex;align-items:center;gap:10px}.pc_spinner{width:14px;height:14px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}@keyframes pcspin{to{transform:rotate(360deg)}}.pc_message[data-error=true]{color:var(--dsw-alias-state-error-primary)}.pc_message[data-warn=true]{color:var(--dsw-alias-state-warning-primary)}.pc_list{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin:0;padding:0;list-style:none;display:grid}.pc_row{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_rowTop{align-items:center;gap:8px;display:flex}.pc_name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1}.pc_tag{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:16px;flex:none}.pc_tag[data-enabled=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-user=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_tag[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_status[data-pending=true]{color:var(--dsw-alias-state-warning-primary)}.pc_toggle[data-pending=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-skill=true]{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_tag[data-system=true]{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}.pc_tag[data-disabled=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tag[data-suite=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_tag[data-error=true]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.pc_tabGroup{display:inline-flex;gap:4px;align-items:center}.pc_meta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;gap:6px;display:flex;align-items:center}.pc_phase[data-phase=failed]{color:var(--dsw-alias-state-error-primary)}.pc_phase[data-phase=active]{color:var(--dsw-alias-state-success-primary)}.pc_toggle{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 12px;align-self:flex-start}.pc_toggle:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_toggle:disabled{opacity:.5;cursor:default}.pc_search{gap:8px;display:flex}.pc_search input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;flex:1;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;outline:none;padding:0 12px;font-size:13px}.pc_search input:focus-visible{border-color:var(--dsw-alias-state-business-primary)}.pc_search button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:0 14px;font-size:13px}.pc_search button:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_market{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}.pc_item{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;min-width:0;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_itemTop{align-items:center;gap:8px;display:flex}.pc_itemTop a{color:var(--dsw-alias-state-business-primary);font-size:13px;font-weight:600;text-decoration:none;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pc_stars{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none}.pc_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_item button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:3px 10px;align-self:flex-start;font-size:12px}.pc_item button:hover:not(:disabled){border-color:var(--dsw-alias-state-business-primary)}.pc_item button:disabled{opacity:.5;cursor:default}.pc_detail{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:10px 12px;flex-direction:column;gap:6px;display:flex}.pc_status{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0}.pc_note{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;margin:0}.pc_marketHead{display:flex;align-items:center;justify-content:space-between;gap:10px}.pc_descWrap{flex-direction:column;display:flex}.pc_installedHead{display:flex;align-items:center;gap:10px}.pc_backTopWrap{position:fixed;top:56px;right:20px;z-index:100;display:flex;flex-direction:column;gap:8px}.pc_backTop{width:34px;height:34px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:rgba(22,27,34,.72);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);cursor:pointer;backdrop-filter:blur(4px);opacity:.7}.pc_backTop:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_descTopbar{display:flex;justify-content:flex-end;margin:2px 0}.pc_ghpill{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 10px;font-size:11px;line-height:18px}.pc_ghpill[data-on=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.pc_extraBtn{opacity:.75;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:4px 10px;font-size:12px;line-height:16px;flex:none;transition:opacity .15s ease,border-color 1.5s ease,color 1.5s ease}.pc_extraBtn:hover{opacity:1}.pc_extraBtn[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_extraBtn[data-flash=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_view{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0;font:inherit;cursor:pointer;border-radius:6px;padding:2px 10px;font-size:12px;line-height:18px;flex:none}.pc_floatPanel{position:fixed;left:20px;top:50%;transform:translateY(-50%);width:340px;max-height:75vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:50;flex-direction:column;gap:8px;display:flex}.pc_refresh{position:sticky;bottom:14px;align-self:flex-end;margin-top:8px;z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_refresh:hover{opacity:.9}.pc_date{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px;flex:none}.pc_searchInner{position:relative;flex:1;display:flex;align-items:center;min-width:0}.pc_searchInner input{padding-right:32px;width:100%}.pc_starBtn{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:13px;line-height:1;padding:4px 8px;border-radius:6px;opacity:.75;transition:opacity .15s ease;flex:none}.pc_starBtn:hover{opacity:1}.pc_starBtn[data-active=true]{opacity:1;color:var(--dsw-alias-state-business-primary)}.pc_restartBtn{position:fixed;right:20px;top:50%;transform:translateY(-50%);z-index:60;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:transparent;font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_restartBtn:hover{opacity:.9}.pc_relaunchFloat{position:fixed;left:20px;top:50%;transform:translateY(-50%);z-index:70;opacity:.85;border:1px solid var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_relaunchFloat:hover{opacity:1}.pc_aiToggle{position:fixed;right:20px;top:20px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiToggle:hover{opacity:1}.pc_aiToggle[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_sourcesFloat{position:fixed;right:20px;top:104px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_sourcesFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat{position:fixed;right:20px;top:204px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_modeFloat:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_modeFloat[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_trashBtn{border:0;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;font-size:12px;line-height:16px;padding:2px 6px;flex:none;display:flex;align-items:center;border-radius:6px;transition:color .15s ease}.pc_trashBtn:hover{color:var(--dsw-alias-state-error-primary)}.pc_consentRemember{display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-secondary);cursor:pointer}.pc_modalBackdrop{position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:1000;display:flex;align-items:center;justify-content:center}.pc_modalCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;padding:16px 18px;width:min(760px,calc(100vw - 64px));max-height:calc(100vh - 96px);overflow-y:auto;overscroll-behavior:contain;flex-direction:column;gap:10px;display:flex;box-shadow:0 12px 32px rgba(0,0,0,.25)}.pc_modalCard::-webkit-scrollbar{width:8px}.pc_modalCard::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:4px}.pc_srcUrl{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--dsw-alias-label-tertiary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}.pc_accWrap{display:flex;flex-direction:column;gap:8px}.pc_acc{border:1px solid var(--dsw-alias-border-l2);border-radius:10px;overflow:hidden;background:var(--dsw-alias-bg-layer-2)}.pc_accHead{width:100%;text-align:left;background:transparent;border:0;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;font-weight:600;line-height:20px;padding:8px 12px;cursor:pointer;display:flex;align-items:center;gap:6px}.pc_accHead:hover{background:var(--dsw-alias-bg-layer-3)}.pc_accHead[data-open=true]{border-bottom:1px solid var(--dsw-alias-border-l2)}.pc_accBody{padding:10px 12px;display:flex;flex-direction:column;gap:8px}.pc_ghpill{background:0 0;cursor:pointer}.pc_ghwrap{position:relative;display:inline-flex}.pc_sourceMenu{position:absolute;right:0;top:calc(100% + 6px);z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:4px;flex-direction:column;display:flex;min-width:120px;box-shadow:0 8px 24px rgba(0,0,0,.18)}.pc_sourceOpt{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 10px;text-align:left;font-size:12px;line-height:16px}.pc_sourceOpt[data-active=true]{color:var(--dsw-alias-state-business-primary);font-weight:600}.pc_sourceOpt:hover{background:var(--dsw-alias-bg-layer-3)}.pc_aiEmpower{position:fixed;right:20px;top:48px;z-index:70;opacity:1;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_aiEmpower:hover{opacity:.9}.pc_aiEmpower[data-busy=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_aiEmpower[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_compCard{position:fixed;left:8px;top:20px;width:320px;max-height:70vh;overflow-y:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:10px;padding:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);z-index:45;flex-direction:column;gap:8px;display:flex}.pc_compCard .pc_rowTop{flex-wrap:wrap}.pc_compCard .pc_toggle{padding:3px 8px;font-size:11px}.pc_compCard[data-hidden=true]{display:none}.pc_compDrop{background:rgba(24,28,34,.92);backdrop-filter:blur(6px);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:4px;box-shadow:0 8px 24px rgba(0,0,0,.35);flex-direction:column;display:flex;gap:2px}.pc_compDropRow{border:0;background:0 0;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;padding:6px 8px;text-align:left;font-size:12px;line-height:16px;flex-direction:column;display:flex;gap:2px}.pc_compDropRow:hover{background:var(--dsw-alias-bg-layer-2)}.pc_compDropUrl{color:var(--dsw-alias-label-tertiary);font-size:11px;word-break:break-all}.pc_compToggle{position:fixed;left:336px;top:20px;z-index:46;opacity:.55;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:rgba(22,27,34,.72);font:inherit;cursor:pointer;width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;line-height:1;backdrop-filter:blur(4px);transition:opacity .15s ease}.pc_compToggle:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain{position:fixed;right:70px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:border-color .15s ease}.pc_toolbarMain:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_toolbarMain[data-active=true]{border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolbarGroup{position:fixed;right:70px;top:56px;z-index:70;flex-direction:column;gap:8px;display:flex;transform-origin:top right;animation:pcDrawerIn .3s cubic-bezier(.34,1.56,.64,1)}@media (max-width:1160px){.pc_toolbarMain{top:104px}.pc_toolbarGroup{top:140px}.pc_aiToggle{top:104px}.pc_aiEmpower{top:132px}.pc_sourcesFloat{top:188px}.pc_modeFloat{top:288px}}@keyframes pcDrawerIn{from{opacity:0;transform:translateX(28px) scale(.94)}to{opacity:1;transform:translateX(0) scale(1)}}.pc_toolItem{opacity:.85;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);font:inherit;cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px;transition:opacity .15s ease}.pc_toolItem:hover{opacity:1;border-color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-active=true]{opacity:1;border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-alias-state-business-primary)}.pc_toolItem[data-mode=true]{opacity:1;border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary)}.pc_switch{width:34px;height:18px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);position:relative;cursor:pointer;flex:none;transition:background .15s ease,border-color .15s ease}.pc_switch:hover{border-color:var(--dsw-alias-state-business-primary)}.pc_switch[data-on=true]{background:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.pc_switchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;transition:left .15s ease}.pc_switch[data-on=true] .pc_switchKnob{left:18px}.pc_aiSpinner{width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:pcspin 1s linear infinite;flex:none}.pc_aiSpinBtn{position:fixed;right:152px;top:20px;z-index:71;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border-radius:8px;padding:6px 10px;display:flex;align-items:center;gap:6px;font-size:12px;line-height:16px}.pc_aiSpinBtn:hover{border-color:var(--dsw-alias-state-business-primary)}";
10
10
  const tagId = "@noob-stupid/dsh-plugin-console/PluginConsoleTab.css";
11
11
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
12
12
  const tag = document.createElement("style");
@@ -56,6 +56,11 @@ window.__ModuleLoader__.load({
56
56
  pcSwitch: "pc_switch",
57
57
  pcSwitchKnob: "pc_switchKnob",
58
58
  sourcesFloat: "pc_sourcesFloat",
59
+ srcUrl: "pc_srcUrl",
60
+ accWrap: "pc_accWrap",
61
+ acc: "pc_acc",
62
+ accHead: "pc_accHead",
63
+ accBody: "pc_accBody",
59
64
  modeFloat: "pc_modeFloat",
60
65
  trashBtn: "pc_trashBtn",
61
66
  consentRemember: "pc_consentRemember",
@@ -114,6 +119,8 @@ window.__ModuleLoader__.load({
114
119
  familyCollapse: "收起",
115
120
  familyUpdate: "全家桶版本检测",
116
121
  familyCheckUpdate: "批量检测更新",
122
+ familyUpdateBtn: "更新",
123
+ familyCheckUpdateTip: "检测到新版本后此处出现「更新」按钮,点击开始整包更新(含子包版本对齐与适配校验)",
117
124
  adaptUnlockBtn: "已适配,立即解锁",
118
125
  adaptUnlockHint: "已安装版本经源码扫描确认适配当前框架:立即移除禁用块并解锁启用",
119
126
  adaptUnlockDone: "已适配解锁:刷新后该行可正常启用",
@@ -239,8 +246,9 @@ window.__ModuleLoader__.load({
239
246
  toolbarOpenTitle: "展开功能包",
240
247
  toolbarCloseTitle: "收起功能包",
241
248
  repoLandLabel: "仓库落地",
242
- repoLandTitle: "仓库落地:从 GitHub 克隆任意项目到本地(~/.dsh/repos/,不限于 DSH 插件)",
243
- repoLandPlaceholder: "输入 owner/repo 或 GitHub 链接,如 deepseek-ai/deepseek-harness",
249
+ repoLandTitle: "仓库落地:用 Git 源「{source}」克隆任意项目到本地(~/.dsh/repos/,不限于 DSH 插件)",
250
+ repoLandSourceUnknown: "已配置的 Git 源",
251
+ repoLandPlaceholder: "输入 owner/repo 或仓库链接,如 deepseek-ai/deepseek-harness",
244
252
  repoLandBusy: "克隆中…(大仓库可能较慢)",
245
253
  repoLandDone: "已落地到:",
246
254
  repoLandOpenFolder: "打开文件夹",
@@ -264,9 +272,12 @@ window.__ModuleLoader__.load({
264
272
  dismissFailure: "关闭此条提示",
265
273
  sourcesBtn: "软件源",
266
274
  sourcesTitle: "软件源管理",
267
- sourcesDesc: "安装源(registry):安装时按主→备依次尝试;支持私有 / 内网 registry",
275
+ sourcesDesc: "分工:① 软件源 = 下载 npm 包(安装用);② 索引源 = 市场首页清单 JSON;③ Git 源 = 克隆仓库代码(无 npm 包时);④ 搜索源 = 搜索时查哪个平台——搜到之后仍按 ①/③ 下载",
268
276
  sourcePrimary: "主源",
269
277
  setPrimary: "设为主源",
278
+ setPrimaryHint: "设为主源:优先使用它,失败时自动回退到其他源",
279
+ editSourceHint: "编辑:修改这个源的名称与地址",
280
+ removeSourceHint: "删除:从列表中移除这个源(不影响已安装的插件)",
270
281
  removeSource: "删除",
271
282
  sourceName: "名称",
272
283
  sourceUrl: "地址(https://…)",
@@ -280,6 +291,21 @@ window.__ModuleLoader__.load({
280
291
  searchSourcesTitle: "搜索源",
281
292
  searchSourcesDesc: "搜索平台(点击登录标切换)。自定义源用 URL 模板:{q}=关键词、{page}=页码",
282
293
  addSearchSource: "添加搜索源",
294
+ indexSourcesTitle: "索引源",
295
+ indexSourcesDesc: "市场静态索引的下载地址(主源优先,其余依次重试)。可换成公司内网自建服务——注意:索引「内容」由那份 JSON 决定,把公共索引与内网私有插件索引一并托管即可在内网浏览;想同时看到两边条目,请打开下面的「合并所有索引源」",
296
+ indexMergeLabel: "合并所有索引源",
297
+ indexMergeDesc: "开启后:所有索引源的结果合并去重展示(公共索引 + 公司内网私有索引同时可见);关闭时按主→备只用一个源(内网优先,更快)",
298
+ addIndexSource: "添加索引源",
299
+ indexUrlPlaceholder: "索引 JSON 地址(https:// 或本机/私网 http://)",
300
+ gitSourcesTitle: "Git 源",
301
+ gitSourcesDesc: "克隆仓库时用的地址模板({owner}/{repo} 占位符)。下面这个列表就是「自定义 Git 源」——内置两条是默认值,点「添加 Git 源」即可换成你自己的:Gitee = https://gitee.com/{owner}/{repo}.git;GitLab = https://gitlab.com/{owner}/{repo}.git;自建 Gitea = https://你的域名/{owner}/{repo}.git;镜像代理 = https://镜像站/https://github.com/{owner}/{repo}.git;本地裸仓库 = file:///D:/repos/{owner}/{repo}.git。主源优先,失败自动回退下一个",
302
+ addGitSource: "添加 Git 源",
303
+ gitUrlPlaceholder: "如 https://gitee.com/{owner}/{repo}.git",
304
+ gitSourceBtn: "Git 源",
305
+ marketIndexOffline: "离线数据 · 缓存于 {time}(索引源不可达,已回退上次成功结果)",
306
+ marketIndexFrom: "索引来源:{source}",
307
+ marketIndexFailed: "市场索引加载失败",
308
+ unknown: "未知",
283
309
  searchUrlPlaceholder: "URL 模板(必须含 {q})",
284
310
  invalidSearchUrl: "搜索 URL 模板必须包含 {q} 占位符",
285
311
  headersPlaceholder: "请求头(可选):每行一个,格式 名称: 值,如 Authorization: Bearer 令牌",
@@ -429,6 +455,8 @@ window.__ModuleLoader__.load({
429
455
  familyCollapse: "Collapse",
430
456
  familyUpdate: "Family version check",
431
457
  familyCheckUpdate: "Check all",
458
+ familyUpdateBtn: "Update",
459
+ familyCheckUpdateTip: "When a newer version is detected this Update button appears; click to start the full-family update (subpackage alignment + adapt check)",
432
460
  adaptUnlockBtn: "Adapted - unlock now",
433
461
  adaptUnlockHint: "Installed version passed the source scan for the current framework: unlock immediately",
434
462
  adaptUnlockDone: "Unlocked: refresh and the row is enabled",
@@ -554,8 +582,9 @@ window.__ModuleLoader__.load({
554
582
  toolbarOpenTitle: "Expand feature pack",
555
583
  toolbarCloseTitle: "Collapse feature pack",
556
584
  repoLandLabel: "Repo land",
557
- repoLandTitle: "Repo land: clone any GitHub project to ~/.dsh/repos/ (not limited to DSH plugins)",
558
- repoLandPlaceholder: "owner/repo or GitHub URL, e.g. deepseek-ai/deepseek-harness",
585
+ repoLandTitle: "Repo land: clone any project to ~/.dsh/repos/ via git source \"{source}\" (not limited to DSH plugins)",
586
+ repoLandSourceUnknown: "the configured git source",
587
+ repoLandPlaceholder: "owner/repo or repo URL, e.g. deepseek-ai/deepseek-harness",
559
588
  repoLandBusy: "Cloning… (large repos may take a while)",
560
589
  repoLandDone: "Landed at: ",
561
590
  repoLandOpenFolder: "Open folder",
@@ -579,9 +608,12 @@ window.__ModuleLoader__.load({
579
608
  dismissFailure: "Dismiss this notice",
580
609
  sourcesBtn: "Sources",
581
610
  sourcesTitle: "Software sources",
582
- sourcesDesc: "Install registries, tried primary-first; private / intranet registries supported",
611
+ sourcesDesc: "Roles: ① registry = download npm packages (install); ② index sources = market list JSON; ③ git sources = clone repo code (when no npm package); ④ search sources = where to search — results are still downloaded via ①/③",
583
612
  sourcePrimary: "Primary",
584
613
  setPrimary: "Set primary",
614
+ setPrimaryHint: "Set primary: tried first, falls back to the others on failure",
615
+ editSourceHint: "Edit: change this source's name and URL",
616
+ removeSourceHint: "Remove: delete this source from the list (installed plugins unaffected)",
585
617
  removeSource: "Remove",
586
618
  sourceName: "Name",
587
619
  sourceUrl: "URL (https://…)",
@@ -595,6 +627,21 @@ window.__ModuleLoader__.load({
595
627
  searchSourcesTitle: "Search sources",
596
628
  searchSourcesDesc: "Search platforms (switch via the pill). Custom sources use a URL template: {q}=keyword, {page}=page number",
597
629
  addSearchSource: "Add search source",
630
+ indexSourcesTitle: "Index sources",
631
+ indexSourcesDesc: "Download URLs for the static market index (primary first, others retried in order). Point this at an intranet service — note the index CONTENT comes from that JSON, so host a merged public+private index there. To see both sides at once, turn on \"Merge all index sources\" below",
632
+ indexMergeLabel: "Merge all index sources",
633
+ indexMergeDesc: "On: results from all index sources are merged and de-duplicated (public index + company intranet private index visible together). Off: only one source is used, primary first (intranet-friendly, faster)",
634
+ addIndexSource: "Add index source",
635
+ indexUrlPlaceholder: "Index JSON URL (https:// or local/intranet http://)",
636
+ gitSourcesTitle: "Git sources",
637
+ gitSourcesDesc: "URL template for cloning ({owner}/{repo} placeholders). This list IS the custom git-source list — the two built-ins are just defaults; click Add git source to swap in your own: Gitee = https://gitee.com/{owner}/{repo}.git; GitLab = https://gitlab.com/{owner}/{repo}.git; self-hosted Gitea = https://your-domain/{owner}/{repo}.git; mirror proxy = https://mirror/https://github.com/{owner}/{repo}.git; local bare repo = file:///D:/repos/{owner}/{repo}.git. Primary first, falls back on failure",
638
+ addGitSource: "Add Git source",
639
+ gitUrlPlaceholder: "e.g. https://gitee.com/{owner}/{repo}.git",
640
+ gitSourceBtn: "Git sources",
641
+ marketIndexOffline: "Offline data · cached {time} (index sources unreachable, showing last successful result)",
642
+ marketIndexFrom: "Index source: {source}",
643
+ marketIndexFailed: "Failed to load market index",
644
+ unknown: "unknown",
598
645
  searchUrlPlaceholder: "URL template (must contain {q})",
599
646
  invalidSearchUrl: "Search URL template must contain the {q} placeholder",
600
647
  headersPlaceholder: "Headers (optional): one per line, format Name: Value, e.g. Authorization: Bearer token",
@@ -1007,6 +1054,7 @@ window.__ModuleLoader__.load({
1007
1054
  const [restartHint, setRestartHint] = react.useState(false);
1008
1055
  const [jobs, setJobs] = react.useState({});
1009
1056
  const [familyCollapsed, setFamilyCollapsed] = react.useState({});
1057
+ const [familyCheck, setFamilyCheck] = react.useState({});
1010
1058
  const [query, setQuery] = react.useState(() => {
1011
1059
  try { return localStorage.getItem("pc-market-query") ?? ""; } catch { return ""; }
1012
1060
  });
@@ -1149,6 +1197,16 @@ window.__ModuleLoader__.load({
1149
1197
  const [toolbarOpen, setToolbarOpen] = react.useState(() => {
1150
1198
  try { return localStorage.getItem("pc-toolbar-open") === "1"; } catch { return false; }
1151
1199
  });
1200
+ // 功能包位置:长按拖动,持久化 localStorage(每次打开沿用上次位置)
1201
+ const [toolbarPos, setToolbarPos] = react.useState(() => {
1202
+ try {
1203
+ const v = JSON.parse(localStorage.getItem("pc-toolbar-pos") || "null");
1204
+ if (v && Number.isFinite(v.left) && Number.isFinite(v.top)) return { left: v.left, top: v.top };
1205
+ } catch {}
1206
+ return null;
1207
+ });
1208
+ const [dragPos, setDragPos] = react.useState(null);
1209
+ const dragRef = react.useRef({ long: null, active: false, justDragged: false, grabX: 0, grabY: 0, base: null });
1152
1210
  const [repoLandOn, setRepoLandOn] = react.useState(() => {
1153
1211
  try { return localStorage.getItem("pc-repo-land") === "1"; } catch { return false; }
1154
1212
  });
@@ -1295,7 +1353,7 @@ window.__ModuleLoader__.load({
1295
1353
  if (aiJob === null || aiJob.status !== "plan-ready") return;
1296
1354
  const steps = (aiJob.steps ?? []).map((s) => s.index).filter((i) => aiSelected[i]);
1297
1355
  if (steps.length === 0) {
1298
- setMessage(t("aiNeedSteps"));
1356
+ setMessage(t("aiEmpowerNeedSteps"));
1299
1357
  return;
1300
1358
  }
1301
1359
  if (!window.confirm(t("aiConfirmDeploy").replace("{n}", String(steps.length)).replace("{name}", aiJob.displayName ?? aiJob.source))) {
@@ -1379,8 +1437,18 @@ window.__ModuleLoader__.load({
1379
1437
  const [sourcesBusy, setSourcesBusy] = react.useState(false);
1380
1438
  // registry 行内编辑
1381
1439
  const [editReg, setEditReg] = react.useState(null);
1440
+ const [indexSourceName, setIndexSourceName] = react.useState("");
1441
+ const [indexSourceUrl, setIndexSourceUrl] = react.useState("");
1442
+ const [editIndex, setEditIndex] = react.useState(null);
1443
+ const [gitSourceName, setGitSourceName] = react.useState("");
1444
+ const [gitSourceUrl, setGitSourceUrl] = react.useState("");
1445
+ const [editGit, setEditGit] = react.useState(null);
1446
+ // 软件源弹窗折叠分区:软件源默认展开,其余收起(避免弹窗过长)
1447
+ const [openSections, setOpenSections] = react.useState({ registries: true, index: false, git: false, search: false, gitee: false });
1382
1448
  // 搜索源列表(内置 + 自定义,来自配置)
1383
1449
  const [searchSourcesList, setSearchSourcesList] = react.useState(null);
1450
+ // Git 源列表(「仓库落地」提示动态显示当前主源,避免写死 GitHub)
1451
+ const [gitSourcesList, setGitSourcesList] = react.useState(null);
1384
1452
  // 自定义搜索源添加表单
1385
1453
  const [searchSourceName, setSearchSourceName] = react.useState("");
1386
1454
  const [searchSourceUrl, setSearchSourceUrl] = react.useState("");
@@ -1421,16 +1489,26 @@ window.__ModuleLoader__.load({
1421
1489
  // 挂载时拉取软件源配置(搜索源菜单用,含自定义源)
1422
1490
  react.useEffect(() => {
1423
1491
  call("/plugin-console/sources").then(
1424
- (data) => setSearchSourcesList(data.sources.searchSources ?? []),
1492
+ (data) => {
1493
+ setSearchSourcesList(data.sources.searchSources ?? []);
1494
+ setGitSourcesList(data.sources.gitSources ?? []);
1495
+ },
1425
1496
  () => {},
1426
1497
  );
1427
1498
  }, []);
1428
1499
  // 挂载时加载静态插件索引(GitHub 源空查询时秒开浏览,零 API 调用)
1429
1500
  react.useEffect(() => {
1430
- call("/plugin-console/market-index").then(
1501
+ call("/plugin-console/market-index", {}).then(
1431
1502
  (data) => {
1432
1503
  if (data && Array.isArray(data.items)) {
1433
- setIndexData({ items: data.items, skills: Array.isArray(data.skills) ? data.skills : [], loaded: true });
1504
+ setIndexData({
1505
+ items: data.items,
1506
+ skills: Array.isArray(data.skills) ? data.skills : [],
1507
+ loaded: true,
1508
+ offline: data.offline === true,
1509
+ cachedAt: typeof data.cachedAt === "number" ? data.cachedAt : null,
1510
+ sourceName: typeof data.sourceName === "string" ? data.sourceName : null,
1511
+ });
1434
1512
  // ★「只看官方」需要官方标记:索引条目补标(网络/服务端此前判定失败时不动已有标记,避免 null 覆盖)
1435
1513
  // 服务端 /enrich 已带 24h 结果缓存时,此处仅兜底浏览器直连失败部分。
1436
1514
  const base = data.items;
@@ -1451,7 +1529,7 @@ window.__ModuleLoader__.load({
1451
1529
  });
1452
1530
  }
1453
1531
  },
1454
- () => {},
1532
+ (error) => setMessage(t("marketIndexFailed") + ":" + (error?.message ?? t("unknown"))),
1455
1533
  );
1456
1534
  // 市场状态记忆:关闭前搜索过 → 重开时自动恢复该搜索(query 已从 localStorage 初始化)
1457
1535
  if (query !== "") {
@@ -2085,6 +2163,46 @@ window.__ModuleLoader__.load({
2085
2163
  if (editReg === null) return;
2086
2164
  sourcesAction({ action: "edit", id: editReg.id, name: editReg.name, url: editReg.url }, () => setEditReg(null));
2087
2165
  };
2166
+ const addIndexSource = () => {
2167
+ if (!isAllowedSourceUrl(indexSourceUrl.trim())) {
2168
+ setMessage(t("failed") + ":" + t("invalidSourceUrl"));
2169
+ return;
2170
+ }
2171
+ sourcesAction({ action: "add-index", name: indexSourceName.trim(), url: indexSourceUrl.trim() }, () => { setIndexSourceName(""); setIndexSourceUrl(""); });
2172
+ };
2173
+ const saveEditIndex = () => {
2174
+ if (editIndex === null) return;
2175
+ sourcesAction({ action: "edit-index", id: editIndex.id, name: editIndex.name, url: editIndex.url }, () => setEditIndex(null));
2176
+ };
2177
+ const addGitSource = () => {
2178
+ const tpl = gitSourceUrl.trim();
2179
+ if (!tpl.includes("{owner}") || !tpl.includes("{repo}")) {
2180
+ setMessage(t("failed") + ":" + t("gitUrlPlaceholder"));
2181
+ return;
2182
+ }
2183
+ if (!isAllowedSourceUrl(tpl)) {
2184
+ setMessage(t("failed") + ":" + t("invalidSourceUrl"));
2185
+ return;
2186
+ }
2187
+ sourcesAction({ action: "add-git", name: gitSourceName.trim(), urlTemplate: tpl }, () => { setGitSourceName(""); setGitSourceUrl(""); });
2188
+ };
2189
+ const saveEditGit = () => {
2190
+ if (editGit === null) return;
2191
+ sourcesAction({ action: "edit-git", id: editGit.id, name: editGit.name, urlTemplate: editGit.urlTemplate }, () => setEditGit(null));
2192
+ };
2193
+ /** 折叠分区(软件源弹窗):标题可点,展开/收起各自独立;软件源默认展开。 */
2194
+ const accSection = (key, title, children) => {
2195
+ const open = openSections[key] === true;
2196
+ return el("div", { key, className: styles.acc },
2197
+ el("button", {
2198
+ type: "button",
2199
+ className: styles.accHead,
2200
+ "data-open": open ? "true" : "false",
2201
+ "aria-expanded": open ? "true" : "false",
2202
+ onClick: () => setOpenSections((prev) => ({ ...prev, [key]: !prev[key] })),
2203
+ }, (open ? "▾ " : "▸ ") + title),
2204
+ open ? el("div", { className: styles.accBody }, ...children) : null);
2205
+ };
2088
2206
  const addSearchSource = () => {
2089
2207
  if (!isAllowedSourceUrl(searchSourceUrl.trim()) || !searchSourceUrl.includes("{q}")) {
2090
2208
  setMessage(t("failed") + ":" + t("invalidSearchUrl"));
@@ -2269,6 +2387,12 @@ window.__ModuleLoader__.load({
2269
2387
  : source === "gitee"
2270
2388
  ? "Gitee"
2271
2389
  : ((searchSourcesList !== null ? searchSourcesList.find((s) => s.id === source)?.name : undefined) ?? source);
2390
+ // 仓库落地提示:动态带上当前主 Git 源名称(Git 源可自定义,不能写死 GitHub)
2391
+ const repoLandTitleText = () => {
2392
+ const primary = (gitSourcesList ?? []).find((s) => s.primary === true);
2393
+ const label = primary?.name ?? t("repoLandSourceUnknown");
2394
+ return t("repoLandTitle").replace("{source}", label);
2395
+ };
2272
2396
  const extraIds = new Set((state.status === "ready" ? state.data.patch?.inserts ?? [] : []));
2273
2397
  const extraCount = state.status === "ready" ? state.data.entries.filter((entry) => entry.extra === true || extraIds.has(entry.rowId)).length : 0;
2274
2398
  const pkgRootOf = (m) => { const mm = String(m ?? ""); const x = mm.match(/^(@[^/]+\/[^/]+)(?:\/.*)?$/u); return x ? x[1] : mm; };
@@ -2287,12 +2411,15 @@ window.__ModuleLoader__.load({
2287
2411
  if (m.startsWith("@deepseek-ai/")) return null;
2288
2412
  return pkgRootOf(m);
2289
2413
  };
2290
- const familyCounts = new Map();
2414
+ const familyCounts = new Map(); // root → Set(moduleName):仅按不同子包名聚合;同一包的重复行不算全家桶(2026-09-06 i18n 重复行事故)
2291
2415
  for (const entry of (state.status === "ready" ? state.data.entries : [])) {
2292
2416
  const root = famRootOf(entry);
2293
2417
  if (root === null) continue;
2294
- familyCounts.set(root, (familyCounts.get(root) ?? 0) + 1);
2418
+ const set = familyCounts.get(root) ?? new Set();
2419
+ set.add(String(entry.moduleName ?? ""));
2420
+ familyCounts.set(root, set);
2295
2421
  }
2422
+ const familySize = (root) => (familyCounts.get(root)?.size ?? 0);
2296
2423
  const familyCards = filteredEntries.map((entry) => {
2297
2424
  const familyRoot = String(entry.moduleName ?? "").startsWith("@deepseek-ai/") ? null : pkgRootOf(entry.moduleName);
2298
2425
  void familyRoot;
@@ -2401,7 +2528,7 @@ window.__ModuleLoader__.load({
2401
2528
  el("strong", { className: styles.name, title: entry.moduleName }, (() => {
2402
2529
  const famRoot = famRootOf(entry);
2403
2530
  const mn = String(entry.moduleName ?? "");
2404
- return famRoot !== null && (familyCounts.get(famRoot) ?? 0) > 1 && mn.startsWith(famRoot + "/")
2531
+ return famRoot !== null && familySize(famRoot) > 1 && mn.startsWith(famRoot + "/")
2405
2532
  ? mn.slice(famRoot.length + 1)
2406
2533
  : moduleShortName(entry.moduleName);
2407
2534
  })()),
@@ -2484,12 +2611,12 @@ window.__ModuleLoader__.load({
2484
2611
  const familySeen = new Set();
2485
2612
  for (const entry of filteredEntries) {
2486
2613
  const root = famRootOf(entry);
2487
- if (root === null || (familyCounts.get(root) ?? 0) <= 1 || familySeen.has(root)) continue;
2614
+ if (root === null || familySize(root) <= 1 || familySeen.has(root)) continue;
2488
2615
  familySeen.add(root);
2489
2616
  familyHeaders.push(el("div", { key: "family-" + root, className: styles.detail, style: { border: "1px solid var(--dsw-alias-state-business-primary)", borderRadius: 10, padding: "8px 12px", gridColumn: "1 / -1" } },
2490
2617
  el("div", { className: styles.rowTop, style: { alignItems: "center" } },
2491
2618
  el("strong", { className: styles.name, style: { flex: "0 1 auto", minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, title: root }, root.replace(/^@[^/]+\//u, "").replace(/^dsh-/u, "")),
2492
- el("span", { className: styles.tag, "data-user": "true" }, t("familyTag") + " · " + (familyCounts.get(root) ?? 0) + " " + t("familySubs")),
2619
+ el("span", { className: styles.tag, "data-user": "true" }, t("familyTag") + " · " + familySize(root) + " " + t("familySubs")),
2493
2620
  el("button", {
2494
2621
  type: "button",
2495
2622
  className: styles.toggle,
@@ -2503,11 +2630,26 @@ window.__ModuleLoader__.load({
2503
2630
  onClick: () => {
2504
2631
  setMessage(t("checkingUpdate"));
2505
2632
  call("/plugin-console/check-update", { packageName: root }).then(
2506
- (d) => setMessage(t("familyUpdate") + ":" + root + " " + (d?.latest ?? "?") + (d?.migrate && d.migrate.compatible ? " → " + d.migrate.to + " v" + d.migrate.latest : "") + (d?.error ? "(" + d.error + ")" : "")),
2633
+ (d) => {
2634
+ const installed = state.status === "ready"
2635
+ ? (state.data.entries.find((e) => e.moduleName === root) ?? {}).version ?? null
2636
+ : null;
2637
+ setFamilyCheck((prev) => ({ ...prev, [root]: { latest: d?.latest ?? null, installed } }));
2638
+ setMessage(t("familyUpdate") + ":" + root + " " + (d?.latest ?? "?") + (d?.migrate && d.migrate.compatible ? " → " + d.migrate.to + " v" + d.migrate.latest : "") + (d?.error ? "(" + d.error + ")" : ""));
2639
+ },
2507
2640
  (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
2508
2641
  );
2509
2642
  },
2510
2643
  }, t("familyCheckUpdate")),
2644
+ familyCheck[root] && familyCheck[root].latest !== null && familyCheck[root].latest !== familyCheck[root].installed
2645
+ ? el("button", {
2646
+ type: "button",
2647
+ className: styles.toggle,
2648
+ style: { whiteSpace: "nowrap", flexShrink: 0 },
2649
+ title: t("familyCheckUpdateTip"),
2650
+ onClick: () => startJob("", root, "github", "plugin", true),
2651
+ }, t("familyUpdateBtn") + " " + familyCheck[root].latest)
2652
+ : null,
2511
2653
  el("button", {
2512
2654
  type: "button",
2513
2655
  className: styles.toggle,
@@ -2517,7 +2659,9 @@ window.__ModuleLoader__.load({
2517
2659
  if (!window.confirm(t("familyUnlockAllConfirm"))) return;
2518
2660
  call("/plugin-console/adapt-unlock-all", { root }).then(
2519
2661
  (d) => {
2520
- setMessage(t("familyUnlockAllDone") + ":" + (d.unlocked ?? []).length + " 行" + (Array.isArray(d.kept) && d.kept.length > 0 ? ";保留 " + d.kept.length + " 行(未通过校验)" : ""));
2662
+ const unlockedCount = (d?.unlocked ?? []).length;
2663
+ if (unlockedCount === 0 && typeof d?.note === "string") { setMessage(d.note); return; }
2664
+ setMessage(t("familyUnlockAllDone") + ":" + unlockedCount + " 行" + (Array.isArray(d?.kept) && d.kept.length > 0 ? ";保留 " + d.kept.length + " 行(未通过校验)" : ""));
2521
2665
  window.setTimeout(() => window.location.reload(), 1500);
2522
2666
  },
2523
2667
  (e) => setMessage(t("failed") + ":" + friendlyGithubError(e).message),
@@ -2533,7 +2677,7 @@ window.__ModuleLoader__.load({
2533
2677
  const e = filteredEntries[i];
2534
2678
  if (e === undefined) { nonFamilyCards.push(card); return; }
2535
2679
  const root = famRootOf(e);
2536
- if (root === null || (familyCounts.get(root) ?? 0) <= 1) { nonFamilyCards.push(card); return; }
2680
+ if (root === null || familySize(root) <= 1) { nonFamilyCards.push(card); return; }
2537
2681
  if (!familySections.has(root)) familySections.set(root, { head: familyHeaders.find((h) => h && h.key === "family-" + root) ?? null, cards: [] });
2538
2682
  familySections.get(root).cards.push(card);
2539
2683
  });
@@ -2620,7 +2764,7 @@ window.__ModuleLoader__.load({
2620
2764
  ? el("button", {
2621
2765
  type: "button",
2622
2766
  className: styles.toggle,
2623
- title: t("repoLandTitle"),
2767
+ title: repoLandTitleText(),
2624
2768
  onClick: () => repoLandEntry(item.fullName),
2625
2769
  }, repoLanded.some((r) => r.repo === item.fullName) ? t("repoLandLanded") + " ✓" : t("repoLandEntry"))
2626
2770
  : null,
@@ -2918,7 +3062,7 @@ window.__ModuleLoader__.load({
2918
3062
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
2919
3063
  el("strong", { className: styles.name }, t("repoLandLabel")),
2920
3064
  el("button", { type: "button", className: styles.trashBtn, style: { fontSize: 14, padding: "4px 8px" }, title: t("closeModal"), "aria-label": t("closeModal"), onClick: () => { setRepoLandOpen(false); setRepoLandResult(null); } }, "✕")),
2921
- el("p", { className: styles.message }, t("repoLandTitle")),
3065
+ el("p", { className: styles.message }, repoLandTitleText()),
2922
3066
  el("div", { className: styles.rowTop, style: { flexWrap: "wrap" } },
2923
3067
  el("span", { className: styles.message }, t("repoLandDirLabel") + ":" + (repoLandDir || "—")),
2924
3068
  el("input", { type: "text", value: repoLandDirInput, onChange: (event) => setRepoLandDirInput(event.currentTarget.value), style: { flex: 1, minWidth: 120, font: "inherit", padding: "4px 8px", borderRadius: 6, border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-1)", color: "var(--dsw-alias-label-primary)" } }),
@@ -3098,14 +3242,62 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3098
3242
  "data-active": toolbarOpen ? "true" : "false",
3099
3243
  title: t(toolbarOpen ? "toolbarCloseTitle" : "toolbarOpenTitle"),
3100
3244
  "aria-label": t("toolbarLabel"),
3101
- onClick: () => setToolbarOpen((v) => {
3102
- const next = !v;
3103
- try { localStorage.setItem("pc-toolbar-open", next ? "1" : "0"); } catch {}
3104
- return next;
3105
- }),
3245
+ style: (dragPos ?? toolbarPos) !== null
3246
+ ? { left: (dragPos ?? toolbarPos).left, top: (dragPos ?? toolbarPos).top, right: "auto", touchAction: "none", userSelect: "none" }
3247
+ : { touchAction: "none", userSelect: "none" },
3248
+ onPointerDown: (e) => {
3249
+ const cur = dragPos ?? toolbarPos ?? { left: Math.max(8, window.innerWidth - 70 - 110), top: 20 };
3250
+ dragRef.current.grabX = e.clientX - cur.left;
3251
+ dragRef.current.grabY = e.clientY - cur.top;
3252
+ dragRef.current.base = cur;
3253
+ dragRef.current.active = false;
3254
+ dragRef.current.justDragged = false;
3255
+ try { e.currentTarget.setPointerCapture?.(e.pointerId); } catch {}
3256
+ dragRef.current.long = window.setTimeout(() => {
3257
+ dragRef.current.active = true;
3258
+ setDragPos(cur);
3259
+ }, 450);
3260
+ },
3261
+ onPointerMove: (e) => {
3262
+ if (!dragRef.current.active) return;
3263
+ const w = window.innerWidth;
3264
+ const h = window.innerHeight;
3265
+ const bw = e.currentTarget.offsetWidth || 96;
3266
+ const bh = e.currentTarget.offsetHeight || 30;
3267
+ const left = Math.max(8, Math.min(w - bw - 8, e.clientX - dragRef.current.grabX));
3268
+ const top = Math.max(8, Math.min(h - bh - 8, e.clientY - dragRef.current.grabY));
3269
+ setDragPos({ left, top });
3270
+ },
3271
+ onPointerUp: () => {
3272
+ if (dragRef.current.long !== null) { window.clearTimeout(dragRef.current.long); dragRef.current.long = null; }
3273
+ if (dragRef.current.active) {
3274
+ const p = dragPos;
3275
+ if (p !== null) {
3276
+ try { localStorage.setItem("pc-toolbar-pos", JSON.stringify(p)); } catch {}
3277
+ setToolbarPos(p);
3278
+ }
3279
+ dragRef.current.active = false;
3280
+ dragRef.current.justDragged = true;
3281
+ window.setTimeout(() => { dragRef.current.justDragged = false; }, 300);
3282
+ setDragPos(null);
3283
+ }
3284
+ },
3285
+ onPointerCancel: () => {
3286
+ if (dragRef.current.long !== null) { window.clearTimeout(dragRef.current.long); dragRef.current.long = null; }
3287
+ dragRef.current.active = false;
3288
+ setDragPos(null);
3289
+ },
3290
+ onClick: (e) => {
3291
+ if (dragRef.current.justDragged) { e.preventDefault(); dragRef.current.justDragged = false; return; }
3292
+ setToolbarOpen((v) => {
3293
+ const next = !v;
3294
+ try { localStorage.setItem("pc-toolbar-open", next ? "1" : "0"); } catch {}
3295
+ return next;
3296
+ });
3297
+ },
3106
3298
  }, t("toolbarLabel") + (toolbarOpen ? " ▾" : " ▸")),
3107
3299
  toolbarOpen
3108
- ? el("div", { className: styles.toolbarGroup },
3300
+ ? el("div", { className: styles.toolbarGroup, style: (dragPos ?? toolbarPos) !== null ? { left: (dragPos ?? toolbarPos).left, top: (dragPos ?? toolbarPos).top + 36, right: "auto" } : undefined },
3109
3301
  el("button", {
3110
3302
  type: "button",
3111
3303
  className: styles.toolItem,
@@ -3116,7 +3308,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3116
3308
  type: "button",
3117
3309
  className: styles.toolItem,
3118
3310
  "data-active": repoLandOn ? "true" : "false",
3119
- title: t("repoLandTitle"),
3311
+ title: repoLandTitleText(),
3120
3312
  "aria-label": t("repoLandLabel"),
3121
3313
  onClick: () => { setRepoLandOn((v) => { const n = !v; try { localStorage.setItem("pc-repo-land", n ? "1" : "0"); } catch {} return n; }); setRepoLandOpen(true); repoLandRefresh(); },
3122
3314
  }, t("repoLandLabel")),
@@ -3193,6 +3385,11 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3193
3385
  ? t("skillsNote")
3194
3386
  : t("skillsGithubOnly"))
3195
3387
  : (searchSource === "github" ? t("direct") : t("directOther").replace("{source}", sourceDisplayName(searchSource)))),
3388
+ indexData !== null && indexData.offline === true
3389
+ ? el("p", { className: styles.message, "data-warn": "true" },
3390
+ t("marketIndexOffline").replace("{time}", indexData.cachedAt !== null ? new Date(indexData.cachedAt).toLocaleString() : "—")
3391
+ + (indexData.sourceName !== null ? " · " + t("marketIndexFrom").replace("{source}", indexData.sourceName) : ""))
3392
+ : null,
3196
3393
  el("div", { className: styles.search, id: "pc-market-search" },
3197
3394
  el("div", { className: styles.searchInner },
3198
3395
  el("input", {
@@ -3301,7 +3498,10 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3301
3498
  }, "✕")),
3302
3499
  el("p", { className: styles.message, "data-error": "true" }, job.error ?? ""),
3303
3500
  el("div", { className: styles.rowTop },
3304
- el("button", { type: "button", className: styles.toggle, onClick: () => startJob(job.repo, job.packageName, job.source ?? "github") }, t("retry")))),
3501
+ el("button", { type: "button", className: styles.toggle, onClick: () => startJob(job.repo, job.packageName, job.source ?? "github") }, t("retry")),
3502
+ job.hint === "repo-land"
3503
+ ? el("button", { type: "button", className: styles.toggle, title: repoLandTitleText(), onClick: () => { setRepoLandOpen(true); repoLandEntry(job.repo); } }, t("repoLandEntry"))
3504
+ : null)),
3305
3505
  ),
3306
3506
  repoInfo !== null
3307
3507
  ? el("aside", { className: styles.floatPanel },
@@ -3463,8 +3663,9 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3463
3663
  el("p", { className: styles.message }, t("sourcesDesc")),
3464
3664
  sourcesData === null
3465
3665
  ? el("p", { className: styles.status }, t("loading"))
3466
- : el("div", { style: { flexDirection: "column", gap: "8px", display: "flex" } },
3467
- sourcesData.registries.map((src) =>
3666
+ : el("div", { className: styles.accWrap },
3667
+ accSection("registries", t("sourcesBtn"), [
3668
+ ...sourcesData.registries.map((src) =>
3468
3669
  editReg !== null && editReg.id === src.id
3469
3670
  ? el("div", { key: src.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3470
3671
  el("input", { type: "text", value: editReg.name, onChange: (event) => setEditReg({ ...editReg, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
@@ -3476,13 +3677,68 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3476
3677
  el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, src.name + (src.primary ? "(" + t("sourcePrimary") + ")" : "")),
3477
3678
  el("code", { className: styles.srcUrl }, src.url)),
3478
3679
  el("div", { className: styles.rowTop },
3479
- src.primary ? null : el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-primary", id: src.id }) }, t("setPrimary")),
3480
- el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => setEditReg({ id: src.id, name: src.name, url: src.url }) }, t("editSource"))))),
3680
+ src.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-primary", id: src.id }) }, t("setPrimary")),
3681
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditReg({ id: src.id, name: src.name, url: src.url }) }, t("editSource"))))),
3481
3682
  el("div", { className: styles.rowTop },
3482
3683
  el("input", { type: "text", placeholder: t("sourceName"), value: sourceName, onChange: (event) => setSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3483
3684
  el("input", { type: "text", placeholder: t("sourceUrl"), value: sourceUrl, onChange: (event) => setSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3484
3685
  el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addSource }, t("addSource"))),
3485
- el("strong", { className: styles.name }, t("searchSourcesTitle")),
3686
+ ]),
3687
+ accSection("index", t("indexSourcesTitle"), [
3688
+ el("p", { className: styles.message }, t("indexSourcesDesc")),
3689
+ (sourcesData.indexSources ?? []).map((s) =>
3690
+ editIndex !== null && editIndex.id === s.id
3691
+ ? el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3692
+ el("input", { type: "text", value: editIndex.name, onChange: (event) => setEditIndex({ ...editIndex, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
3693
+ el("input", { type: "text", value: editIndex.url, onChange: (event) => setEditIndex({ ...editIndex, url: event.currentTarget.value }), style: { flex: 2, minWidth: 120 } }),
3694
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: saveEditIndex }, t("saveSource")),
3695
+ el("button", { type: "button", className: styles.toggle, onClick: () => setEditIndex(null) }, t("cancelEdit")))
3696
+ : el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3697
+ el("div", { className: styles.rowTop, style: { flex: 1, minWidth: 0 } },
3698
+ el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, s.name + (s.primary ? "(" + t("sourcePrimary") + ")" : "")),
3699
+ el("code", { className: styles.srcUrl }, s.url)),
3700
+ el("div", { className: styles.rowTop },
3701
+ s.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-index-primary", id: s.id }) }, t("setPrimary")),
3702
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditIndex({ id: s.id, name: s.name, url: s.url }) }, t("editSource")),
3703
+ el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-index", id: s.id }) }, t("removeSource"))))),
3704
+ el("div", { className: styles.rowTop },
3705
+ el("input", { type: "text", placeholder: t("sourceName"), value: indexSourceName, onChange: (event) => setIndexSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3706
+ el("input", { type: "text", placeholder: t("indexUrlPlaceholder"), value: indexSourceUrl, onChange: (event) => setIndexSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3707
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addIndexSource }, t("addIndexSource"))),
3708
+ el("div", { className: styles.rowTop },
3709
+ el("button", {
3710
+ type: "button",
3711
+ className: styles.toggle,
3712
+ "data-active": sourcesData.indexMerge === true ? "true" : "false",
3713
+ title: t("indexMergeDesc"),
3714
+ disabled: sourcesBusy,
3715
+ onClick: () => sourcesAction({ action: "set-index-merge", merge: sourcesData.indexMerge !== true }),
3716
+ }, t("indexMergeLabel") + ":" + (sourcesData.indexMerge === true ? t("on") : t("off")))),
3717
+ el("p", { className: styles.message }, t("indexMergeDesc")),
3718
+ ]),
3719
+ accSection("git", t("gitSourcesTitle"), [
3720
+ el("p", { className: styles.message }, t("gitSourcesDesc")),
3721
+ (sourcesData.gitSources ?? []).map((s) =>
3722
+ editGit !== null && editGit.id === s.id
3723
+ ? el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3724
+ el("input", { type: "text", value: editGit.name, onChange: (event) => setEditGit({ ...editGit, name: event.currentTarget.value }), style: { flex: 1, minWidth: 80 } }),
3725
+ el("input", { type: "text", value: editGit.urlTemplate, onChange: (event) => setEditGit({ ...editGit, urlTemplate: event.currentTarget.value }), style: { flex: 2, minWidth: 120 } }),
3726
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: saveEditGit }, t("saveSource")),
3727
+ el("button", { type: "button", className: styles.toggle, onClick: () => setEditGit(null) }, t("cancelEdit")))
3728
+ : el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
3729
+ el("div", { className: styles.rowTop, style: { flex: 1, minWidth: 0 } },
3730
+ el("strong", { className: styles.name, style: { flex: "none", maxWidth: "35%" } }, s.name + (s.primary ? "(" + t("sourcePrimary") + ")" : "")),
3731
+ el("code", { className: styles.srcUrl }, s.urlTemplate)),
3732
+ el("div", { className: styles.rowTop },
3733
+ s.primary ? null : el("button", { type: "button", className: styles.toggle, title: t("setPrimaryHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "set-git-primary", id: s.id }) }, t("setPrimary")),
3734
+ el("button", { type: "button", className: styles.toggle, title: t("editSourceHint"), disabled: sourcesBusy, onClick: () => setEditGit({ id: s.id, name: s.name, urlTemplate: s.urlTemplate }) }, t("editSource")),
3735
+ el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-git", id: s.id }) }, t("removeSource"))))),
3736
+ el("div", { className: styles.rowTop },
3737
+ el("input", { type: "text", placeholder: t("sourceName"), value: gitSourceName, onChange: (event) => setGitSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
3738
+ el("input", { type: "text", placeholder: t("gitUrlPlaceholder"), value: gitSourceUrl, onChange: (event) => setGitSourceUrl(event.currentTarget.value), style: { flex: 2, minWidth: 0 } }),
3739
+ el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: addGitSource }, t("addGitSource"))),
3740
+ ]),
3741
+ accSection("search", t("searchSourcesTitle"), [
3486
3742
  el("p", { className: styles.message }, t("searchSourcesDesc")),
3487
3743
  (sourcesData.searchSources ?? []).map((s) =>
3488
3744
  el("div", { key: s.id, className: styles.rowTop, style: { justifyContent: "space-between" } },
@@ -3493,7 +3749,7 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3493
3749
  ? el("span", { className: styles.tag, title: t("headersPlaceholder") }, "🔒 " + Object.keys(s.headers).length)
3494
3750
  : null),
3495
3751
  s.type === "custom"
3496
- ? el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-search", id: s.id }) }, t("removeSource"))
3752
+ ? el("button", { type: "button", className: styles.toggle, title: t("removeSourceHint"), disabled: sourcesBusy, onClick: () => sourcesAction({ action: "remove-search", id: s.id }) }, t("removeSource"))
3497
3753
  : null)),
3498
3754
  el("div", { className: styles.rowTop },
3499
3755
  el("input", { type: "text", placeholder: t("sourceName"), value: searchSourceName, onChange: (event) => setSearchSourceName(event.currentTarget.value), style: { flex: 1, minWidth: 0 } }),
@@ -3506,7 +3762,8 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3506
3762
  onChange: (event) => setSearchSourceHeaders(event.currentTarget.value),
3507
3763
  style: { width: "100%", boxSizing: "border-box", font: "inherit", resize: "vertical" },
3508
3764
  }),
3509
- el("strong", { className: styles.name }, t("giteeTitle")),
3765
+ ]),
3766
+ accSection("gitee", t("giteeTitle"), [
3510
3767
  el("p", { className: styles.message }, t("giteeDesc").replace("{port}", String(window.location.port || "3080"))),
3511
3768
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
3512
3769
  el("span", { className: styles.tag },
@@ -3521,7 +3778,9 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
3521
3778
  el("button", { type: "button", className: styles.toggle, disabled: giteeStatus !== null && !giteeStatus.clientConfigured, onClick: startGiteeOauth }, t("giteeLoginBtn")),
3522
3779
  giteeStatus !== null && giteeStatus.hasToken
3523
3780
  ? el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "gitee-clear" }) }, t("giteeClear"))
3524
- : null)),
3781
+ : null),
3782
+ ]),
3783
+ ),
3525
3784
  el("div", { className: styles.rowTop },
3526
3785
  el("button", { type: "button", className: styles.toggle, disabled: sourcesBusy, onClick: () => sourcesAction({ action: "reset" }) }, t("resetSources")),
3527
3786
  el("button", { type: "button", className: styles.toggle, onClick: () => setSourcesOpen(false) }, t("closeModal")))))