@noob-stupid/dsh-plugin-console 0.3.24 → 0.3.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -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-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)}";
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)}";
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");
@@ -48,6 +48,13 @@ window.__ModuleLoader__.load({
48
48
  compDropRow: "pc_compDropRow",
49
49
  compDropUrl: "pc_compDropUrl",
50
50
  compToggle: "pc_compToggle",
51
+ toolbarMain: "pc_toolbarMain",
52
+ toolbarGroup: "pc_toolbarGroup",
53
+ toolItem: "pc_toolItem",
54
+ aiSpinner: "pc_aiSpinner",
55
+ aiSpinBtn: "pc_aiSpinBtn",
56
+ pcSwitch: "pc_switch",
57
+ pcSwitchKnob: "pc_switchKnob",
51
58
  sourcesFloat: "pc_sourcesFloat",
52
59
  modeFloat: "pc_modeFloat",
53
60
  trashBtn: "pc_trashBtn",
@@ -94,6 +101,10 @@ window.__ModuleLoader__.load({
94
101
  enabledTag: "已启用",
95
102
  disabledTag: "已停用",
96
103
  userDisabledTag: "补丁停用",
104
+ pendingCompatTag: "待适配",
105
+ pendingCompatHint: "框架升级后被强制禁用:先点「检测更新」,如有新版按钮会变为「更新并适配」,点击后更新完成自动校验通过即解锁启用",
106
+ updateAndAdapt: "更新并适配",
107
+ aiEmpowerFrameworkCheck: "框架适配检测",
97
108
  userForcedTag: "补丁强制启用",
98
109
  protectedTag: "受保护",
99
110
  unobserved: "未挂载",
@@ -184,7 +195,11 @@ window.__ModuleLoader__.load({
184
195
  aiEmpowerType: "类型",
185
196
  aiEmpowerTypeMapping: { "pure-plugin": "纯插件", "service": "服务器组件", "config-only": "仅配置" },
186
197
  aiEmpowerSteps: "执行步骤(可勾选)",
187
- aiEmpowerRun: "执行所选步骤",
198
+ aiEmpowerRun: "同意并部署",
199
+ aiEmpowerNeedSteps: "请至少勾选一个步骤;勾选后点击「同意并部署」才会执行",
200
+ aiConfirmDeploy: "即将执行 {name} 的 {n} 个部署步骤(可能安装软件/写入配置/启动服务)。确认同意并部署?",
201
+ aiPlanHint: "⚠️ AI 只负责规划建议——部署前需要你明确同意:勾选步骤 → 同意并部署 →(二次确认)",
202
+ aiWorkspaceInfo: "调研工作区",
188
203
  aiEmpowerCancel: "取消",
189
204
  aiEmpowerWaiting: "等待 AI 分析文档并生成计划(约 1-5 分钟,会调用 DeepSeek API,可能产生费用)…",
190
205
  aiEmpowerExecuting: "AI 赋能执行中…",
@@ -205,6 +220,24 @@ window.__ModuleLoader__.load({
205
220
  compNoUrl: "暂无网址",
206
221
  compCollapseTitle: "收缩组件卡片",
207
222
  compExpandTitle: "展开组件卡片",
223
+ toolbarLabel: "功能包",
224
+ toolbarOpenTitle: "展开功能包",
225
+ toolbarCloseTitle: "收起功能包",
226
+ repoLandLabel: "仓库落地",
227
+ repoLandTitle: "仓库落地:从 GitHub 克隆任意项目到本地(~/.dsh/repos/,不限于 DSH 插件)",
228
+ repoLandPlaceholder: "输入 owner/repo 或 GitHub 链接,如 deepseek-ai/deepseek-harness",
229
+ repoLandBusy: "克隆中…(大仓库可能较慢)",
230
+ repoLandDone: "已落地到:",
231
+ repoLandOpenFolder: "打开文件夹",
232
+ repoLandExists: "该仓库已存在,无需重复落地",
233
+ repoLandDirLabel: "保存路径",
234
+ repoLandSaveDir: "保存路径",
235
+ repoLandList: "已落地仓库",
236
+ repoLandRemoveConfirm: "确认删除已落地仓库 {repo}(本地目录将被删除)?",
237
+ repoLandEntry: "仓库落地",
238
+ repoLandLanded: "已落地",
239
+ aiProgressTitle: "AI 赋能进行中,点击查看进度",
240
+ compAutoTitle: "自启动:开启后随 DSH 启动自动拉起该服务器(关闭则需手动启动)",
208
241
  compActionDone: "{action}:{name}",
209
242
  noComponents: "暂无已识别的服务器组件(用 AI 赋能部署后自动出现)",
210
243
  aiFallbackTitle: "关闭后:常规通道失败将直接取消安装,不再调用模型 API(零费用)",
@@ -326,6 +359,9 @@ window.__ModuleLoader__.load({
326
359
  frameworkUpgradeTitle: "框架升级:自动打包备份现有配置 → 停止并重启 DSH 服务 → npm 升级框架与配套包(失败自动回滚)→ 拉起服务并适配",
327
360
  frameworkUpgradeConfirm: "确认升级?(服务将自动重启)",
328
361
  frameworkUpgradeDone: "框架升级流程已执行",
362
+ frameworkRollbackBtn: "回滚到上一版",
363
+ frameworkRollbackTitle: "一键回滚到升级前版本:全树恢复(含依赖世界),脚本自动拉起服务",
364
+ frameworkRollbackDone: "已发起回滚:{from} → 恢复中,服务将短暂断开,请勿手动操作",
329
365
  frameworkUpgradeUpToDate: "(已是最新版本)",
330
366
  frameworkUpgradeCheckFailed: "(版本检测失败,无法确认是否有更新——请检查网络后重试)",
331
367
  frameworkUpToDate: "已是最新框架",
@@ -365,6 +401,10 @@ window.__ModuleLoader__.load({
365
401
  enabledTag: "Enabled",
366
402
  disabledTag: "Disabled",
367
403
  userDisabledTag: "Disabled by patch",
404
+ pendingCompatTag: "Pending adapt",
405
+ pendingCompatHint: "Force-disabled after framework upgrade: click Check update first; if a newer version exists the button becomes Update & adapt - click it and it unlocks automatically after the compat check",
406
+ updateAndAdapt: "Update & adapt",
407
+ aiEmpowerFrameworkCheck: "Framework compat check",
368
408
  userForcedTag: "Forced on by patch",
369
409
  protectedTag: "Protected",
370
410
  unobserved: "Not mounted",
@@ -455,7 +495,11 @@ window.__ModuleLoader__.load({
455
495
  aiEmpowerType: "Type",
456
496
  aiEmpowerTypeMapping: { "pure-plugin": "Pure plugin", "service": "Server component", "config-only": "Config only" },
457
497
  aiEmpowerSteps: "Steps to execute (selectable)",
458
- aiEmpowerRun: "Run selected steps",
498
+ aiEmpowerRun: "Approve & deploy",
499
+ aiEmpowerNeedSteps: "Select at least one step; then click Approve & deploy to execute",
500
+ aiConfirmDeploy: "About to run {n} deployment step(s) for {name} (may install software / write config / start services). Approve and deploy?",
501
+ aiPlanHint: "⚠️ AI only drafts the plan — deployment needs your explicit consent: select steps → Approve & deploy → (second confirmation)",
502
+ aiWorkspaceInfo: "Research workspace",
459
503
  aiEmpowerCancel: "Cancel",
460
504
  aiEmpowerWaiting: "AI is analyzing the docs and drafting the plan (1-5 min, calls DeepSeek API, may incur costs)…",
461
505
  aiEmpowerExecuting: "AI Empower executing…",
@@ -476,6 +520,24 @@ window.__ModuleLoader__.load({
476
520
  compNoUrl: "No URL yet",
477
521
  compCollapseTitle: "Collapse server card",
478
522
  compExpandTitle: "Expand server card",
523
+ toolbarLabel: "Feature pack",
524
+ toolbarOpenTitle: "Expand feature pack",
525
+ toolbarCloseTitle: "Collapse feature pack",
526
+ repoLandLabel: "Repo land",
527
+ repoLandTitle: "Repo land: clone any GitHub project to ~/.dsh/repos/ (not limited to DSH plugins)",
528
+ repoLandPlaceholder: "owner/repo or GitHub URL, e.g. deepseek-ai/deepseek-harness",
529
+ repoLandBusy: "Cloning… (large repos may take a while)",
530
+ repoLandDone: "Landed at: ",
531
+ repoLandOpenFolder: "Open folder",
532
+ repoLandExists: "Already exists — nothing to clone",
533
+ repoLandDirLabel: "Save path",
534
+ repoLandSaveDir: "Save path",
535
+ repoLandList: "Landed repos",
536
+ repoLandRemoveConfirm: "Delete landed repo {repo} (local folder will be removed)?",
537
+ repoLandEntry: "Repo land",
538
+ repoLandLanded: "Landed",
539
+ aiProgressTitle: "AI Empower in progress — click to view",
540
+ compAutoTitle: "Autostart: launch this server automatically when DSH starts (off = manual)",
479
541
  compActionDone: "{action}: {name}",
480
542
  noComponents: "No server components yet (they appear after an AI Empower deployment)",
481
543
  aiFallbackTitle: "When off: if regular channels fail, the install is cancelled directly without calling the model API (zero cost)",
@@ -603,6 +665,9 @@ window.__ModuleLoader__.load({
603
665
  frameworkUpToDateTitle: "Current DSH framework is already the latest (upgrade via the official flow or wait for a new release)",
604
666
  frameworkUseUpgrade: "deepseek-harness is the DSH framework itself, not a plugin; upgrade via the card's Framework Upgrade flow (shown when a new version exists)",
605
667
  relaunchBtn: "Relaunch service",
668
+ frameworkRollbackBtn: "Rollback to previous",
669
+ frameworkRollbackTitle: "One-click rollback to the previous framework version (full tree), service relaunches automatically",
670
+ frameworkRollbackDone: "Rollback started: {from} -> restoring, service will briefly disconnect",
606
671
  relaunchTitle: "During a framework upgrade the service may disconnect — click to manually relaunch the DSH service (the upgrade script also relaunches automatically)",
607
672
  relaunchDone: "Manual relaunch requested (starts the service if the port is not listening)",
608
673
  fwStepBackup: "Backup current config",
@@ -711,8 +776,9 @@ window.__ModuleLoader__.load({
711
776
  }
712
777
  }
713
778
  /** 浏览器直连 GitHub 搜索;失败抛错由调用方回退到服务端通道。 */
714
- async function searchFromGithub(q, page) {
715
- const query = (q ?? "").trim() || "dsh-plugin";
779
+ async function searchFromGithub(q, page, all) {
780
+ const base = (q ?? "").trim() || "dsh-plugin";
781
+ const query = all ? base : (base + " topic:dsh-plugin");
716
782
  const data = await githubFetch(`${GITHUB_API}/search/repositories?q=${encodeURIComponent(query)}&sort=stars&order=desc&per_page=20&page=${Math.max(page || 1, 1)}`);
717
783
  return (data.items ?? []).map((item) => ({
718
784
  fullName: item.full_name,
@@ -909,7 +975,9 @@ window.__ModuleLoader__.load({
909
975
  const [reloadHint, setReloadHint] = react.useState(false);
910
976
  const [restartHint, setRestartHint] = react.useState(false);
911
977
  const [jobs, setJobs] = react.useState({});
912
- const [query, setQuery] = react.useState("");
978
+ const [query, setQuery] = react.useState(() => {
979
+ try { return localStorage.getItem("pc-market-query") ?? ""; } catch { return ""; }
980
+ });
913
981
  const [market, setMarket] = react.useState(null);
914
982
  const [marketPage, setMarketPage] = react.useState(1);
915
983
  const [loadingMore, setLoadingMore] = react.useState(false);
@@ -999,12 +1067,16 @@ window.__ModuleLoader__.load({
999
1067
  // 自动版本比对结果:{ fullName: latest }(已安装且有新版)
1000
1068
  const [updateMap, setUpdateMap] = react.useState({});
1001
1069
  const [expandedDescs, setExpandedDescs] = react.useState({});
1002
- const [installedQuery, setInstalledQuery] = react.useState("");
1070
+ const [installedQuery, setInstalledQuery] = react.useState(() => {
1071
+ try { return localStorage.getItem("pc-market-installed-q") ?? ""; } catch { return ""; }
1072
+ });
1003
1073
  const [installedSearchOpen, setInstalledSearchOpen] = react.useState(false);
1004
1074
  const [extraOnly, setExtraOnly] = react.useState(true);
1005
1075
  // 点击切换时的高亮闪烁(1.5 秒后渐变回落)
1006
1076
  const [extraFlash, setExtraFlash] = react.useState(false);
1007
- const [officialOnly, setOfficialOnly] = react.useState(false);
1077
+ const [officialOnly, setOfficialOnly] = react.useState(() => {
1078
+ try { return localStorage.getItem("pc-market-official") === "1"; } catch { return false; }
1079
+ });
1008
1080
  // 多源汇总搜索(GitHub + 全部自定义源并行),localStorage 持久化
1009
1081
  const [multiSource, setMultiSource] = react.useState(() => {
1010
1082
  try { return localStorage.getItem("pc-multi-source") === "1"; } catch { return false; }
@@ -1021,6 +1093,20 @@ window.__ModuleLoader__.load({
1021
1093
  const [aiJob, setAiJob] = react.useState(null);
1022
1094
  const [aiSelected, setAiSelected] = react.useState({});
1023
1095
  const [aiRunning, setAiRunning] = react.useState(false);
1096
+ const [aiJobsList, setAiJobsList] = react.useState([]);
1097
+ // 并发任务列表:轻量视图轮询(服务端支持并行多个 AI 赋能)
1098
+ async function refreshAiList() {
1099
+ try {
1100
+ const data = await call("/plugin-console/ai-empower/list", {});
1101
+ if (data && data.ok === true) setAiJobsList(data.tasks ?? []);
1102
+ } catch {}
1103
+ }
1104
+ function aiSelect(jobId) {
1105
+ if (aiJob !== null && aiJob.jobId === jobId) return;
1106
+ setAiJob(null);
1107
+ setAiRunning(true);
1108
+ aiPoll(jobId);
1109
+ }
1024
1110
  // 服务器组件清单(AI 赋能注册的服务型组件)
1025
1111
  const [comps, setComps] = react.useState([]);
1026
1112
  const [compBusy, setCompBusy] = react.useState(null);
@@ -1028,6 +1114,73 @@ window.__ModuleLoader__.load({
1028
1114
  const [compCollapsed, setCompCollapsed] = react.useState(() => {
1029
1115
  try { return localStorage.getItem("pc-comp-collapsed") === "1"; } catch { return false; }
1030
1116
  });
1117
+ const [toolbarOpen, setToolbarOpen] = react.useState(() => {
1118
+ try { return localStorage.getItem("pc-toolbar-open") === "1"; } catch { return false; }
1119
+ });
1120
+ const [repoLandOn, setRepoLandOn] = react.useState(() => {
1121
+ try { return localStorage.getItem("pc-repo-land") === "1"; } catch { return false; }
1122
+ });
1123
+ const [repoLandOpen, setRepoLandOpen] = react.useState(false);
1124
+ const [repoLandInput, setRepoLandInput] = react.useState("");
1125
+ const [repoLandBusy, setRepoLandBusy] = react.useState(false);
1126
+ const [repoLandResult, setRepoLandResult] = react.useState(null);
1127
+ const [repoLanded, setRepoLanded] = react.useState([]);
1128
+ const [repoLandDir, setRepoLandDir] = react.useState("");
1129
+ const [repoLandDirInput, setRepoLandDirInput] = react.useState("");
1130
+ async function repoLandRefresh() {
1131
+ try {
1132
+ const data = await call("/plugin-console/repo-list", {});
1133
+ if (data && data.ok === true) {
1134
+ setRepoLanded(data.repos ?? []);
1135
+ setRepoLandDir(data.dir ?? "");
1136
+ setRepoLandDirInput(data.dir ?? "");
1137
+ }
1138
+ } catch {}
1139
+ }
1140
+ async function repoLandEntry(repo) {
1141
+ setRepoLandResult(null);
1142
+ try {
1143
+ const data = await call("/plugin-console/repo-clone", { repo });
1144
+ if (data && data.ok === true) setRepoLandResult({ ok: true, path: data.path });
1145
+ } catch (error) {
1146
+ setRepoLandResult({ ok: false, error: error.message });
1147
+ }
1148
+ repoLandRefresh();
1149
+ }
1150
+ async function repoLandSaveDir() {
1151
+ const dir = repoLandDirInput.trim();
1152
+ if (dir === "") return;
1153
+ try {
1154
+ const data = await call("/plugin-console/repo-land-config", { dir });
1155
+ if (data && data.ok === true) { setRepoLandDir(data.dir); repoLandRefresh(); }
1156
+ } catch (error) {
1157
+ setRepoLandResult({ ok: false, error: error.message });
1158
+ }
1159
+ }
1160
+ async function repoLandRemove(item) {
1161
+ if (!window.confirm(t("repoLandRemoveConfirm").replace("{repo}", item.repo))) return;
1162
+ try {
1163
+ await call("/plugin-console/repo-remove", { path: item.path });
1164
+ } catch {}
1165
+ repoLandRefresh();
1166
+ }
1167
+ async function repoLandStart() {
1168
+ const repo = repoLandInput.trim();
1169
+ if (repo === "" || repoLandBusy) return;
1170
+ setRepoLandBusy(true);
1171
+ setRepoLandResult(null);
1172
+ try {
1173
+ const data = await call("/plugin-console/repo-clone", { repo });
1174
+ if (data && data.ok === true) setRepoLandResult({ ok: true, path: data.path });
1175
+ } catch (error) {
1176
+ setRepoLandResult({ ok: false, error: error.message });
1177
+ }
1178
+ setRepoLandBusy(false);
1179
+ }
1180
+ async function repoLandOpenFolder() {
1181
+ if (repoLandResult === null || repoLandResult.ok !== true) return;
1182
+ try { await call("/plugin-console/repo-open", { path: repoLandResult.path }); } catch {}
1183
+ }
1031
1184
  const sectionRef = react.useRef(null);
1032
1185
  const [compCardTop, setCompCardTop] = react.useState(null);
1033
1186
  function measureCompCardTop() {
@@ -1057,6 +1210,7 @@ window.__ModuleLoader__.load({
1057
1210
  async function aiPoll(jobId) {
1058
1211
  try {
1059
1212
  const data = await call("/plugin-console/ai-empower/status", { jobId });
1213
+ refreshAiList();
1060
1214
  if (data && data.ok === true) {
1061
1215
  setAiJob(data);
1062
1216
  if (data.status === "running") {
@@ -1072,7 +1226,13 @@ window.__ModuleLoader__.load({
1072
1226
  refreshComps();
1073
1227
  }
1074
1228
  } catch (error) {
1075
- setAiJob((prev) => ({ ...(prev ?? {}), status: "failed", error: error.message }));
1229
+ // 任务已失效(如 DSH 重启导致内存任务丢失):清理本地记忆,下次挂载不再恢复
1230
+ if (/没有这个 AI 赋能任务/.test(error.message)) {
1231
+ try { localStorage.removeItem("pc-ai-job"); } catch {}
1232
+ setAiJob({ jobId: null, source: "", status: "failed", stage: "gone", error: "上次 AI 赋能任务已失效(DSH 重启中断),请重新发起" });
1233
+ } else {
1234
+ setAiJob((prev) => ({ ...(prev ?? {}), status: "failed", error: error.message }));
1235
+ }
1076
1236
  setAiRunning(false);
1077
1237
  }
1078
1238
  }
@@ -1088,7 +1248,11 @@ window.__ModuleLoader__.load({
1088
1248
  setAiJob(null);
1089
1249
  setAiRunning(true); try {
1090
1250
  const data = await call("/plugin-console/ai-empower/plan", { source });
1091
- if (data && data.ok === true) { setAiJob({ jobId: data.jobId, source, status: "running", stage: "planning" }); aiPoll(data.jobId); }
1251
+ if (data && data.ok === true) {
1252
+ try { localStorage.setItem("pc-ai-job", data.jobId); } catch {}
1253
+ setAiJob({ jobId: data.jobId, source, status: "running", stage: "planning" });
1254
+ aiPoll(data.jobId);
1255
+ }
1092
1256
  else { setAiRunning(false); setMessage(t("failed") + ":" + (data?.error ?? "未知")); }
1093
1257
  } catch (error) {
1094
1258
  setAiRunning(false);
@@ -1098,9 +1262,16 @@ window.__ModuleLoader__.load({
1098
1262
  async function aiRun() {
1099
1263
  if (aiJob === null || aiJob.status !== "plan-ready") return;
1100
1264
  const steps = (aiJob.steps ?? []).map((s) => s.index).filter((i) => aiSelected[i]);
1265
+ if (steps.length === 0) {
1266
+ setMessage(t("aiNeedSteps"));
1267
+ return;
1268
+ }
1269
+ if (!window.confirm(t("aiConfirmDeploy").replace("{n}", String(steps.length)).replace("{name}", aiJob.displayName ?? aiJob.source))) {
1270
+ return;
1271
+ }
1101
1272
  setAiRunning(true);
1102
1273
  try {
1103
- await call("/plugin-console/ai-empower/run", { jobId: aiJob.jobId, steps });
1274
+ await call("/plugin-console/ai-empower/run", { jobId: aiJob.jobId, steps, confirmed: true });
1104
1275
  aiPoll(aiJob.jobId);
1105
1276
  } catch (error) {
1106
1277
  setAiRunning(false);
@@ -1113,6 +1284,12 @@ window.__ModuleLoader__.load({
1113
1284
  setAiRunning(false);
1114
1285
  await aiPoll(aiJob.jobId).catch(() => {});
1115
1286
  }
1287
+ // 「取消」= 彻底终止并回到普通面板:清空任务状态 + 本地任务记忆(重开不再恢复旧任务)
1288
+ function aiResetLocal() {
1289
+ try { localStorage.removeItem("pc-ai-job"); } catch {}
1290
+ setAiJob(null);
1291
+ setAiRunning(false);
1292
+ }
1116
1293
  async function compAction(id, action) {
1117
1294
  setCompBusy(id);
1118
1295
  try {
@@ -1137,6 +1314,25 @@ window.__ModuleLoader__.load({
1137
1314
  setCompBusy(null);
1138
1315
  refreshComps();
1139
1316
  }
1317
+ // 面板重开时恢复 AI 赋能任务(服务端任务常驻内存+持久化,前端只需恢复轮询——关闭面板不会中断赋能)
1318
+ react.useEffect(() => {
1319
+ refreshAiList();
1320
+ repoLandRefresh();
1321
+ try {
1322
+ const jid = localStorage.getItem("pc-ai-job");
1323
+ if (jid) { setAiRunning(true); aiPoll(jid); }
1324
+ } catch {}
1325
+ }, []);
1326
+ async function compAuto(id, on) { setCompBusy(id);
1327
+ try {
1328
+ await call("/plugin-console/component/autostart", { id, enabled: on });
1329
+ setMessage((on ? "✔ 已开启自启动:" : "已关闭自启动:") + id);
1330
+ } catch (error) {
1331
+ setMessage(t("failed") + ":" + error.message);
1332
+ }
1333
+ setCompBusy(null);
1334
+ refreshComps();
1335
+ }
1140
1336
  const aiAutoDeclinedRef = react.useRef({});
1141
1337
  react.useEffect(() => {
1142
1338
  if (state.status === "ready") { refreshComps(); window.setTimeout(measureCompCardTop, 120); }
@@ -1203,6 +1399,10 @@ window.__ModuleLoader__.load({
1203
1399
  (data) => { if (data && Array.isArray(data.items)) setIndexData({ items: data.items, skills: Array.isArray(data.skills) ? data.skills : [], loaded: true }); },
1204
1400
  () => {},
1205
1401
  );
1402
+ // 市场状态记忆:关闭前搜索过 → 重开时自动恢复该搜索(query 已从 localStorage 初始化)
1403
+ if (query !== "") {
1404
+ search();
1405
+ }
1206
1406
  }, []);
1207
1407
  // 挂载时记录原始标题(AI 授权标题闪烁后恢复用)
1208
1408
  react.useEffect(() => {
@@ -1382,6 +1582,46 @@ window.__ModuleLoader__.load({
1382
1582
  (error) => setMessage(t("failed") + ":" + friendlyGithubError(error).message),
1383
1583
  ).finally(() => setBusy(null));
1384
1584
  };
1585
+ const levenshtein = (a, b) => {
1586
+ const m = a.length, n = b.length;
1587
+ if (m === 0) return n;
1588
+ if (n === 0) return m;
1589
+ const dp = new Array(n + 1);
1590
+ for (let j = 0; j <= n; j++) dp[j] = j;
1591
+ for (let i = 1; i <= m; i++) {
1592
+ let prev = dp[0];
1593
+ dp[0] = i;
1594
+ for (let j = 1; j <= n; j++) {
1595
+ const tmp = dp[j];
1596
+ dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
1597
+ prev = tmp;
1598
+ }
1599
+ }
1600
+ return dp[n];
1601
+ };
1602
+ // 本地索引模糊匹配:子串命中优先;其次编辑距离 ≤2 近似(opviking → OpenViking 这类)
1603
+ const fuzzyMatchIndex = (q, items) => {
1604
+ const ql = q.trim().toLowerCase();
1605
+ if (ql === "") return [];
1606
+ const scored = [];
1607
+ for (const it of items) {
1608
+ const text = String(it.fullName ?? it.name ?? it.repository ?? "").toLowerCase();
1609
+ const desc = String(it.description ?? "").toLowerCase();
1610
+ if (text.includes(ql) || desc.includes(ql)) {
1611
+ scored.push({ it, s: 100000 - text.length + (text.startsWith(ql) ? 10000 : 0) });
1612
+ continue;
1613
+ }
1614
+ if (ql.length < 4) continue;
1615
+ const tokens = text.split(/[-_/.]/u).filter(Boolean);
1616
+ let best = Infinity;
1617
+ for (const tk of tokens) best = Math.min(best, levenshtein(ql, tk));
1618
+ const qTokens = ql.split(/[\s\-_/.]+/u).filter(Boolean);
1619
+ for (const qt of qTokens) for (const tk of tokens) best = Math.min(best, levenshtein(qt, tk));
1620
+ if (best <= 2) scored.push({ it, s: 1000 - best * 100 });
1621
+ }
1622
+ scored.sort((a, b) => b.s - a.s);
1623
+ return scored.slice(0, 12).map((x) => x.it);
1624
+ };
1385
1625
  const search = () => {
1386
1626
  setMarket({ status: "loading" });
1387
1627
  setRepoInfo(null);
@@ -1407,6 +1647,15 @@ window.__ModuleLoader__.load({
1407
1647
  setMarket({ status: "ready", data: indexData.items.slice(0, indexShown), direct: false, source: "github", fromIndex: true });
1408
1648
  return;
1409
1649
  }
1650
+ // 本地索引模糊匹配:非空查询先对静态索引做近似匹配(opviking → OpenViking),命中即展示(置顶、秒开)
1651
+ // 仓库落地开关点亮(全库搜索)时跳过本地索引(本地只有 dsh-plugin 收录),走全库动态
1652
+ if (searchSource === "github" && !multiSource && !repoLandOn && indexData !== null && indexData.loaded && query.trim() !== "") {
1653
+ const local = fuzzyMatchIndex(query, indexData.items);
1654
+ if (local.length > 0) {
1655
+ setMarket({ status: "ready", data: local, direct: false, source: "github", fromIndex: true, fuzzy: true });
1656
+ return;
1657
+ }
1658
+ }
1410
1659
  if (multiSource) {
1411
1660
  // 多源汇总:GitHub + 全部自定义源并行(服务端合并,自带标记)
1412
1661
  call("/plugin-console/search", { q: query, page: 1, multi: true }).then(
@@ -1430,7 +1679,7 @@ window.__ModuleLoader__.load({
1430
1679
  );
1431
1680
  return;
1432
1681
  }
1433
- searchFromGithub(query, 1).then(
1682
+ searchFromGithub(query, 1, repoLandOn).then(
1434
1683
  (data) => {
1435
1684
  // 秒出直连数据
1436
1685
  setMarket({ status: "ready", data, direct: true });
@@ -1989,6 +2238,9 @@ window.__ModuleLoader__.load({
1989
2238
  const readme = details.data.readme;
1990
2239
  detailPanel = el("div", { className: styles.detail },
1991
2240
  meta !== null ? el("p", { className: styles.desc }, meta.description ?? t("noDetail")) : null,
2241
+ entry.pendingCompat === true
2242
+ ? el("p", { className: styles.status, "data-pending": "true" }, t("pendingCompatHint"))
2243
+ : null,
1992
2244
  meta !== null && meta.version ? el("div", { className: styles.rowTop },
1993
2245
  el("p", { className: styles.status }, t("versionLabel") + ":" + meta.version),
1994
2246
  el("button", {
@@ -2015,7 +2267,7 @@ window.__ModuleLoader__.load({
2015
2267
  className: styles.toggle,
2016
2268
  disabled: installing === entry.moduleName,
2017
2269
  onClick: () => startJob("", entry.moduleName, "github", "plugin", true),
2018
- }, installing === entry.moduleName ? t("installing") : t("updateNow"))),
2270
+ }, installing === entry.moduleName ? t("installing") : (entry.pendingCompat === true ? t("updateAndAdapt") : t("updateNow")))),
2019
2271
  Array.isArray(updateCheck.depsOutdated) && updateCheck.depsOutdated.length > 0
2020
2272
  ? el("p", { className: styles.status, "data-error": "true" },
2021
2273
  t("depsOutdatedHint") + ":" + updateCheck.depsOutdated.map((d) => `${d.name} ${d.current}→${d.required}`).join("、"))
@@ -2058,9 +2310,10 @@ window.__ModuleLoader__.load({
2058
2310
  el("button", {
2059
2311
  type: "button",
2060
2312
  className: styles.toggle,
2061
- disabled: !entry.toggleable || busy === entry.entryId,
2313
+ disabled: !entry.toggleable || busy === entry.entryId || entry.pendingCompat === true,
2314
+ title: entry.pendingCompat === true ? t("pendingCompatHint") : undefined,
2062
2315
  onClick: () => toggle(entry, !entry.enabled),
2063
- }, busy === entry.entryId ? t("loadingPhase") : t(entry.enabled ? "off" : "on")),
2316
+ }, busy === entry.entryId ? t("loadingPhase") : (entry.pendingCompat === true ? t("pendingCompatTag") : t(entry.enabled ? "off" : "on"))),
2064
2317
  el("button", {
2065
2318
  type: "button",
2066
2319
  className: styles.toggle,
@@ -2187,6 +2440,14 @@ window.__ModuleLoader__.load({
2187
2440
  disabled: repoInfo !== null && repoInfo.status === "loading" && repoInfo.repo === item.fullName,
2188
2441
  onClick: () => inspect(item),
2189
2442
  }, t("view")),
2443
+ repoLandOn && mode !== "skills"
2444
+ ? el("button", {
2445
+ type: "button",
2446
+ className: styles.toggle,
2447
+ title: t("repoLandTitle"),
2448
+ onClick: () => repoLandEntry(item.fullName),
2449
+ }, repoLanded.some((r) => r.repo === item.fullName) ? t("repoLandLanded") + " ✓" : t("repoLandEntry"))
2450
+ : null,
2190
2451
  el("button", {
2191
2452
  type: "button",
2192
2453
  className: styles.toggle,
@@ -2407,6 +2668,14 @@ window.__ModuleLoader__.load({
2407
2668
  el("span", { className: styles.tag, "data-enabled": c.running ? "true" : "false" }, c.running ? t("compRunning") : t("compStopped")),
2408
2669
  (c.running && c.healthy !== null) ? el("span", { className: styles.tag, "data-enabled": c.healthy ? "true" : "false" }, c.healthy ? t("compHealthy") : t("compUnhealthy")) : null,
2409
2670
  el("div", { className: styles.rowTop },
2671
+ el("div", {
2672
+ className: styles.pcSwitch,
2673
+ "data-on": c.autoStart === true ? "true" : "false",
2674
+ role: "switch",
2675
+ "aria-checked": c.autoStart === true ? "true" : "false",
2676
+ title: t("compAutoTitle"),
2677
+ onClick: () => compAuto(c.id, c.autoStart !== true),
2678
+ }, el("div", { className: styles.pcSwitchKnob })),
2410
2679
  el("button", { type: "button", className: styles.toggle, disabled: c.running || compBusy === c.id, onClick: () => compAction(c.id, "start") }, t("compStart")),
2411
2680
  el("button", { type: "button", className: styles.toggle, disabled: !c.running || compBusy === c.id, onClick: () => compAction(c.id, "stop") }, t("compStop")),
2412
2681
  el("button", { type: "button", className: styles.toggle, disabled: compBusy === c.id, onClick: () => compStatusOne(c.id) }, t("compStatus")),
@@ -2418,19 +2687,36 @@ window.__ModuleLoader__.load({
2418
2687
  el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
2419
2688
  el("strong", { className: styles.name }, t("aiEmpowerLabel")),
2420
2689
  el("button", { type: "button", className: styles.trashBtn, style: { fontSize: 14, padding: "4px 8px" }, title: t("closeModal"), "aria-label": t("closeModal"), onClick: () => setAiOpen(false) }, "✕")),
2690
+ aiJobsList.length > 1
2691
+ ? el("div", { style: { flexDirection: "column", gap: 6, display: "flex", maxHeight: 120, overflowY: "auto" } },
2692
+ aiJobsList.map((task) =>
2693
+ el("button", {
2694
+ key: task.jobId,
2695
+ type: "button",
2696
+ className: styles.toggle,
2697
+ style: aiJob !== null && aiJob.jobId === task.jobId ? { borderColor: "var(--dsw-alias-state-business-primary)", color: "var(--dsw-alias-state-business-primary)" } : undefined,
2698
+ onClick: () => aiSelect(task.jobId),
2699
+ }, (task.displayName ?? task.source) + ":" + (task.status === "running" ? (t("aiEmpowerExecuting") + (task.progress && task.progress.done ? "(" + task.progress.done + "/" + task.progress.total + ")" : "")) : task.status === "plan-ready" ? t("aiEmpowerPlanTitle") : task.status === "done" ? t("aiEmpowerDone") : task.status === "failed" ? t("aiEmpowerFail") : task.status ?? "?"))))
2700
+ : null,
2421
2701
  aiJob === null || (aiJob.status === "running" && aiJob.stage === "planning")
2422
2702
  ? el("div", { style: { flexDirection: "column", gap: "10px", display: "flex" } },
2423
2703
  el("section", null,
2424
2704
  el("input", { type: "text", placeholder: t("aiEmpowerSrcTitle"), value: aiSource, disabled: aiRunning, onChange: (event) => setAiSource(event.currentTarget.value), onKeyDown: (event) => { if (event.key === "Enter" && !aiRunning) aiStartPlan(); }, style: { width: "100%", boxSizing: "border-box", font: "inherit", padding: "6px 10px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-1)", color: "var(--dsw-alias-label-primary)" } }),
2425
2705
  el("div", { className: styles.rowTop },
2426
2706
  el("button", { type: "button", className: styles.toggle, disabled: aiRunning || aiSource.trim() === "", onClick: aiStartPlan }, t("aiEmpowerLabel")),
2427
- aiRunning ? el("span", { className: styles.message }, t("aiEmpowerWaiting")) : null)))
2707
+ aiRunning ? el("span", { className: styles.message }, t("aiEmpowerWaiting") + (aiJob?.source ? "(" + aiJob.source + ")" : "")) : null,
2708
+ aiRunning ? el("button", { type: "button", className: styles.toggle, onClick: () => { call("/plugin-console/ai-empower/cancel", { jobId: aiJob ? aiJob.jobId : "" }).catch(() => {}); aiResetLocal(); } }, t("aiEmpowerCancel")) : null)))
2428
2709
  : aiJob.status === "plan-ready"
2429
2710
  ? el("div", { style: { flexDirection: "column", gap: "10px", display: "flex" } },
2430
2711
  el("div", { className: styles.rowTop },
2431
2712
  el("strong", { className: styles.name }, (aiJob.displayName ?? aiJob.source) + ":"),
2432
2713
  el("span", { className: styles.tag }, t("aiEmpowerType") + ":" + (t("aiEmpowerTypeMapping")[aiJob.type] ?? aiJob.type ?? "?"))),
2433
- aiJob.summary ? el("p", { className: styles.message }, aiJob.summary) : null,
2714
+ aiJob.frameworkCheck
2715
+ ? el("p", { className: styles.status, "data-error": aiJob.frameworkCheck.check?.decision === "fail" ? "true" : undefined, title: aiJob.frameworkCheck.check?.reason ?? undefined }, t("aiEmpowerFrameworkCheck") + ":" + (aiJob.frameworkCheck.summary ?? "") + (aiJob.frameworkCheck.frameworkVersion ? "(框架 " + aiJob.frameworkCheck.frameworkVersion + ")" : ""))
2716
+ : null,
2717
+ aiJob?.workspace ? el("p", { className: styles.status }, t("aiWorkspaceInfo") + ":" + aiJob.workspace) : null,
2718
+ aiJob.summary ? el("p", { className: styles.message }, aiJob.summary) : null,
2719
+ el("p", { className: styles.message, "data-error": "true" }, t("aiPlanHint")),
2434
2720
  (aiJob.servers ?? []).length > 0
2435
2721
  ? el("p", { className: styles.message }, (aiJob.servers ?? []).map((s) => (s.name ?? "?") + (s.port ? "(端口 " + s.port + ")" : "")).join("、"))
2436
2722
  : null,
@@ -2442,13 +2728,46 @@ window.__ModuleLoader__.load({
2442
2728
  el("span", null, (s.index + 1) + ". [" + s.action + "] " + (s.description ?? "") + (s.path ? " → " + s.path : "")))),
2443
2729
  el("div", { className: styles.rowTop },
2444
2730
  el("button", { type: "button", className: styles.toggle, onClick: aiRun }, t("aiEmpowerRun")),
2445
- el("button", { type: "button", className: styles.toggle, onClick: () => { setAiJob(null); setAiRunning(false); } }, t("aiEmpowerCancel")))))
2731
+ el("button", { type: "button", className: styles.toggle, onClick: aiResetLocal }, t("aiEmpowerCancel")))))
2446
2732
  : el("div", { style: { flexDirection: "column", gap: "10px", display: "flex" } },
2447
- el("p", { className: styles.message, "data-error": aiJob.status === "failed" ? "true" : undefined }, aiJob.status === "done" ? t("aiEmpowerDone") : aiJob.status === "failed" ? t("aiEmpowerFail") + ":" + (aiJob.error ?? "?") : t("aiEmpowerExecuting") + "(" + (aiJob.progress?.done ?? 0) + "/" + (aiJob.progress?.total ?? "?") + ")"),
2733
+ el("p", { className: styles.message, "data-error": aiJob.status === "failed" ? "true" : undefined }, (aiJob.status === "done" ? t("aiEmpowerDone") : aiJob.status === "failed" ? t("aiEmpowerFail") + ":" + (aiJob.error ?? "?") : t("aiEmpowerExecuting")) + (aiJob.source ? "(" + aiJob.source + ")" : "") + (aiJob.status === "running" ? " " + (aiJob.progress?.done ?? 0) + "/" + (aiJob.progress?.total ?? "?") : "")),
2448
2734
  el("pre", { style: { maxHeight: 200, overflow: "auto", whiteSpace: "pre-wrap", wordBreak: "break-all", background: "var(--dsw-alias-bg-layer-2)", border: "1px solid var(--dsw-alias-border-l2)", borderRadius: 8, padding: 8, fontSize: 11, margin: 0, fontFamily: "inherit" } }, aiJob.logText ?? ""),
2449
2735
  el("div", { className: styles.rowTop },
2450
- (aiJob.status === "running") ? el("button", { type: "button", className: styles.toggle, onClick: aiCancel }, t("aiEmpowerCancel")) : null,
2451
- el("button", { type: "button", className: styles.toggle, onClick: () => { setAiJob(null); } }, t("closeModal"))))))
2736
+ (aiJob.status === "running") ? el("button", { type: "button", className: styles.toggle, onClick: async () => { await aiCancel(); aiResetLocal(); } }, t("aiEmpowerCancel")) : null,
2737
+ el("button", { type: "button", className: styles.toggle, onClick: aiResetLocal }, t("closeModal"))))))
2738
+ : null,
2739
+ repoLandOpen
2740
+ ? el("div", { className: styles.modalBackdrop },
2741
+ el("div", { className: styles.modalCard, style: { maxWidth: 560 } },
2742
+ el("div", { className: styles.rowTop, style: { justifyContent: "space-between" } },
2743
+ el("strong", { className: styles.name }, t("repoLandLabel")),
2744
+ 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); } }, "✕")),
2745
+ el("p", { className: styles.message }, t("repoLandTitle")),
2746
+ el("div", { className: styles.rowTop, style: { flexWrap: "wrap" } },
2747
+ el("span", { className: styles.message }, t("repoLandDirLabel") + ":" + (repoLandDir || "—")),
2748
+ 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)" } }),
2749
+ el("button", { type: "button", className: styles.toggle, onClick: repoLandSaveDir }, t("repoLandSaveDir"))),
2750
+ el("section", null,
2751
+ el("input", { type: "text", placeholder: t("repoLandPlaceholder"), value: repoLandInput, disabled: repoLandBusy, onChange: (event) => setRepoLandInput(event.currentTarget.value), onKeyDown: (event) => { if (event.key === "Enter" && !repoLandBusy) repoLandStart(); }, style: { width: "100%", boxSizing: "border-box", font: "inherit", padding: "6px 10px", borderRadius: 8, border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-1)", color: "var(--dsw-alias-label-primary)" } }),
2752
+ el("div", { className: styles.rowTop },
2753
+ el("button", { type: "button", className: styles.toggle, disabled: repoLandBusy || repoLandInput.trim() === "", onClick: repoLandStart }, repoLandBusy ? t("repoLandBusy") : t("repoLandLabel"))),
2754
+ repoLandResult !== null
2755
+ ? (repoLandResult.ok === true
2756
+ ? el("div", { className: styles.rowTop },
2757
+ el("p", { className: styles.message, style: { flex: 1, minWidth: 0, wordBreak: "break-all" } }, t("repoLandDone") + repoLandResult.path),
2758
+ el("button", { type: "button", className: styles.toggle, onClick: repoLandOpenFolder }, t("repoLandOpenFolder")))
2759
+ : el("p", { className: styles.message, "data-error": "true" }, t("failed") + ":" + (repoLandResult.error ?? "?")))
2760
+ : null,
2761
+ el("strong", { className: styles.name }, t("repoLandList") + "(" + repoLanded.length + ")"),
2762
+ repoLanded.length === 0
2763
+ ? el("p", { className: styles.status }, "—")
2764
+ : el("div", { style: { flexDirection: "column", gap: 6, display: "flex", maxHeight: 180, overflowY: "auto" } },
2765
+ repoLanded.map((item) =>
2766
+ el("div", { key: item.repo, className: styles.rowTop },
2767
+ el("strong", { className: styles.name, style: { flex: "1 1 auto" } }, item.repo),
2768
+ el("button", { type: "button", className: styles.toggle, onClick: () => { call("/plugin-console/repo-open", { path: item.path }).catch(() => {}); } }, t("repoLandOpenFolder")),
2769
+ el("button", { type: "button", className: styles.trashBtn, title: t("repoLandRemoveConfirm"), "aria-label": t("repoLandRemoveConfirm"), onClick: () => repoLandRemove(item) }, "✕"))))
2770
+ )))
2452
2771
  : null,
2453
2772
  state.status === "ready" && state.data.framework && state.data.framework.upgraded === true && !frameworkNoticeDismissed
2454
2773
  ? el("div", { className: styles.messageRow },
@@ -2502,7 +2821,28 @@ window.__ModuleLoader__.load({
2502
2821
  el("code", { className: styles.name }, (state2 === "ok" ? "✓ " : state2 === "cur" ? "⟳ " : state2 === "fail" ? "✕ " : "· ") + step.label),
2503
2822
  state2 === "cur" ? el("span", { className: styles.spinner }) : null));
2504
2823
  })),
2505
- frameworkStatus.message ? el("p", { className: styles.status, "data-error": frameworkStatus.status === "failed" ? "true" : undefined }, frameworkStatus.message) : null)
2824
+ frameworkStatus.message ? el("p", { className: styles.status, "data-error": frameworkStatus.status === "failed" ? "true" : undefined }, frameworkStatus.message) : null,
2825
+ (state.status === "ready" && state.data.rollback)
2826
+ ? el("div", { className: styles.rowTop },
2827
+ el("button", {
2828
+ type: "button",
2829
+ className: styles.toggle,
2830
+ title: t("frameworkRollbackTitle"),
2831
+ disabled: frameworkUpgrading,
2832
+ onClick: () => {
2833
+ setFrameworkUpgrading(true);
2834
+ call("/plugin-console/framework-rollback", {}).then(
2835
+ (data) => {
2836
+ setFrameworkUpgrading(false);
2837
+ setMessage(t("frameworkRollbackDone").replace("{from}", String(data?.from ?? "?")));
2838
+ setFrameworkStatus({ status: "rollback", message: t("frameworkRollbackDone").replace("{from}", String(data?.from ?? "?")) });
2839
+ pollFrameworkStatus();
2840
+ },
2841
+ (error) => { setFrameworkUpgrading(false); setMessage(t("failed") + ":" + friendlyGithubError(error).message); },
2842
+ );
2843
+ },
2844
+ }, t("frameworkRollbackBtn") + " → " + (state.data.rollback.from ?? "?")))
2845
+ : null)
2506
2846
  : null,
2507
2847
  message !== null ? el("div", { className: styles.messageRow }, el("p", { className: styles.message }, message), reloadHint ? el("button", { type: "button", className: styles.toggle, onClick: () => window.location.reload() }, t("reloadPage")) : null, restartHint ? el("button", { type: "button", className: styles.toggle, onClick: () => { setMessage(t("restarting")); call("/plugin-console/restart", {}).then(() => { window.setTimeout(() => window.location.reload(), 12000); }, () => {}); } }, t("restartService")) : null) : null,
2508
2848
  el("div", { className: styles.marketHead },
@@ -2567,53 +2907,85 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
2567
2907
  }, s.name)))
2568
2908
  : null,
2569
2909
  )),
2910
+ (aiRunning || aiJobsList.some((x) => x.status === "running"))
2911
+ ? el("button", {
2912
+ type: "button",
2913
+ className: styles.aiSpinBtn,
2914
+ title: t("aiProgressTitle"),
2915
+ "aria-label": t("aiProgressTitle"),
2916
+ onClick: () => setAiOpen(true),
2917
+ }, el("div", { className: styles.aiSpinner }))
2918
+ : null,
2570
2919
  el("button", {
2571
2920
  type: "button",
2572
- className: styles.restartBtn,
2573
- title: t("restartService"),
2574
- onClick: () => { setMessage(t("restarting")); call("/plugin-console/restart", {}).then(() => { window.setTimeout(() => window.location.reload(), 12000); }, () => {}); },
2575
- }, t("restartService")),
2576
- el("button", {
2577
- type: "button",
2578
- className: styles.aiToggle,
2579
- "data-active": aiFallback ? "true" : "false",
2580
- title: t("aiFallbackTitle"),
2581
- "aria-label": t("aiFallbackLabel"),
2582
- onClick: () => setAiFallback((v) => {
2921
+ className: styles.toolbarMain,
2922
+ "data-active": toolbarOpen ? "true" : "false",
2923
+ title: t(toolbarOpen ? "toolbarCloseTitle" : "toolbarOpenTitle"),
2924
+ "aria-label": t("toolbarLabel"),
2925
+ onClick: () => setToolbarOpen((v) => {
2583
2926
  const next = !v;
2584
- try { localStorage.setItem("pc-ai-fallback-v2", next ? "on" : "off"); } catch {}
2927
+ try { localStorage.setItem("pc-toolbar-open", next ? "1" : "0"); } catch {}
2585
2928
  return next;
2586
2929
  }),
2587
- }, t("aiFallbackLabel")),
2588
- el("button", {
2589
- type: "button",
2590
- className: styles.aiEmpower,
2591
- "data-busy": aiRunning ? "true" : "false",
2592
- "data-active": aiOpen ? "true" : "false",
2593
- title: t("aiEmpowerTitle"),
2594
- "aria-label": t("aiEmpowerLabel"),
2595
- onClick: () => setAiOpen((v) => !v),
2596
- }, t("aiEmpowerLabel")),
2597
- el("button", {
2598
- type: "button",
2599
- className: styles.sourcesFloat,
2600
- title: t("sourcesTitle"),
2601
- "aria-label": t("sourcesBtn"),
2602
- onClick: openSources,
2603
- }, t("sourcesBtn")),
2604
- el("button", {
2605
- type: "button",
2606
- className: styles.modeFloat,
2607
- "data-mode": mode === "skills" ? "true" : "false",
2608
- title: t("modeBtn"),
2609
- "aria-label": t("modeBtn"),
2610
- onClick: () => {
2611
- const next = mode === "plugins" ? "skills" : "plugins";
2612
- setMode(next);
2613
- try { localStorage.setItem("pc-market-mode", next); } catch {}
2614
- setMarket(null);
2615
- },
2616
- }, mode === "skills" ? t("pluginsMode") : t("skillsMode")),
2930
+ }, t("toolbarLabel") + (toolbarOpen ? " ▾" : " ▸")),
2931
+ toolbarOpen
2932
+ ? el("div", { className: styles.toolbarGroup },
2933
+ el("button", {
2934
+ type: "button",
2935
+ className: styles.toolItem,
2936
+ title: t("restartService"),
2937
+ onClick: () => { setMessage(t("restarting")); call("/plugin-console/restart", {}).then(() => { window.setTimeout(() => window.location.reload(), 12000); }, () => {}); },
2938
+ }, t("restartService")),
2939
+ el("button", {
2940
+ type: "button",
2941
+ className: styles.toolItem,
2942
+ "data-active": repoLandOn ? "true" : "false",
2943
+ title: t("repoLandTitle"),
2944
+ "aria-label": t("repoLandLabel"),
2945
+ onClick: () => { setRepoLandOn((v) => { const n = !v; try { localStorage.setItem("pc-repo-land", n ? "1" : "0"); } catch {} return n; }); setRepoLandOpen(true); repoLandRefresh(); },
2946
+ }, t("repoLandLabel")),
2947
+ el("button", {
2948
+ type: "button",
2949
+ className: styles.toolItem,
2950
+ "data-active": aiFallback ? "true" : "false",
2951
+ title: t("aiFallbackTitle"),
2952
+ "aria-label": t("aiFallbackLabel"),
2953
+ onClick: () => setAiFallback((v) => {
2954
+ const next = !v;
2955
+ try { localStorage.setItem("pc-ai-fallback-v2", next ? "on" : "off"); } catch {}
2956
+ return next;
2957
+ }),
2958
+ }, t("aiFallbackLabel")),
2959
+ el("button", {
2960
+ type: "button",
2961
+ className: styles.toolItem,
2962
+ "data-busy": aiRunning ? "true" : "false",
2963
+ "data-active": aiOpen ? "true" : "false",
2964
+ title: t("aiEmpowerTitle"),
2965
+ "aria-label": t("aiEmpowerLabel"),
2966
+ onClick: () => setAiOpen((v) => !v),
2967
+ }, t("aiEmpowerLabel")),
2968
+ el("button", {
2969
+ type: "button",
2970
+ className: styles.toolItem,
2971
+ title: t("sourcesTitle"),
2972
+ "aria-label": t("sourcesBtn"),
2973
+ onClick: openSources,
2974
+ }, t("sourcesBtn")),
2975
+ el("button", {
2976
+ type: "button",
2977
+ className: styles.toolItem,
2978
+ "data-mode": mode === "skills" ? "true" : "false",
2979
+ title: t("modeBtn"),
2980
+ "aria-label": t("modeBtn"),
2981
+ onClick: () => {
2982
+ const next = mode === "plugins" ? "skills" : "plugins";
2983
+ setMode(next);
2984
+ try { localStorage.setItem("pc-market-mode", next); } catch {}
2985
+ setMarket(null);
2986
+ },
2987
+ }, (mode === "skills" ? t("pluginsMode") : t("skillsMode"))))
2988
+ : null,
2617
2989
  market !== null && market.status === "ready" && market.data.length > 0
2618
2990
  ? el("div", { className: styles.backTopWrap },
2619
2991
  showBackTop
@@ -2660,7 +3032,11 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
2660
3032
  ? t("giteeRepoPlaceholder")
2661
3033
  : t("searchPlaceholderOther").replace("{source}", sourceDisplayName(searchSource))),
2662
3034
  "aria-label": t("search"),
2663
- onChange: (event) => setQuery(event.currentTarget.value),
3035
+ onChange: (event) => {
3036
+ const v = event.currentTarget.value;
3037
+ setQuery(v);
3038
+ try { localStorage.setItem("pc-market-query", v); } catch {}
3039
+ },
2664
3040
  onKeyDown: (event) => { if (event.key === "Enter") search(); },
2665
3041
  }),
2666
3042
  ),
@@ -2671,7 +3047,11 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
2671
3047
  "data-active": officialOnly ? "true" : "false",
2672
3048
  title: t("officialTitle"),
2673
3049
  "aria-label": t("officialOnlyToggle"),
2674
- onClick: () => setOfficialOnly((v) => !v),
3050
+ onClick: () => setOfficialOnly((v) => {
3051
+ const next = !v;
3052
+ try { localStorage.setItem("pc-market-official", next ? "1" : "0"); } catch {}
3053
+ return next;
3054
+ }),
2675
3055
  }, officialOnly ? "★" : "☆")
2676
3056
  : null,
2677
3057
  mode === "plugins"
@@ -2767,7 +3147,11 @@ setMessage(t("failed") + ":" + (data?.reason ?? "未知"));
2767
3147
  value: installedQuery,
2768
3148
  placeholder: t("searchInstalledPlaceholder"),
2769
3149
  "aria-label": t("searchInstalledPlaceholder"),
2770
- onChange: (event) => setInstalledQuery(event.currentTarget.value),
3150
+ onChange: (event) => {
3151
+ const v = event.currentTarget.value;
3152
+ setInstalledQuery(v);
3153
+ try { localStorage.setItem("pc-market-installed-q", v); } catch {}
3154
+ },
2771
3155
  }),
2772
3156
  el("button", {
2773
3157
  type: "button",