koishi-plugin-new-auth 0.2.0 → 0.3.1

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/README.md CHANGED
@@ -80,6 +80,11 @@ The page provides:
80
80
  - pending command review;
81
81
  - legacy `authority` suggestions;
82
82
  - AI-style automatic assignment for pending commands;
83
- - command status and guild override toggles.
83
+ - command status and guild override toggles;
84
+ - custom role creation and explicit member management;
85
+ - copying command policies from one role to another;
86
+ - batch assigning all commands from one plugin.
84
87
 
85
88
  The automatic assignment advisor is conservative: dangerous instance-level commands are kept for `bot-admin`, group moderation commands go to `guild-admin` and `guild-owner`, normal user commands go to `guild-member` and above, and unclear commands fall back to the legacy authority suggestion.
89
+
90
+ Custom roles do not inherit from built-in roles. Use the WebUI copy action, or `newauth.role.copy`, to clone the current explicit policies from another role.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{defineComponent as H,ref as v,computed as c,watch as J,openBlock as o,createElementBlock as a,createElementVNode as t,toDisplayString as s,withDirectives as y,Fragment as m,renderList as x,vModelSelect as U,normalizeClass as g,createCommentVNode as G,vModelCheckbox as K,createTextVNode as T,vModelText as D}from"vue";import{store as E,send as k}from"@koishijs/client";const Q={class:"new-auth-page"},W={class:"topbar"},X={class:"top-actions"},Y=["value"],Z=["disabled"],ee=["disabled"],te={class:"tabs"},le={key:0,class:"error"},ne={key:1,class:"role-layout"},se={class:"role-list"},oe=["onClick"],ae={key:0,class:"detail"},ie={class:"detail-head"},ue={class:"check"},de={class:"filters"},re={class:"command-list"},ce={class:"command-main"},ve={class:"state-buttons"},pe=["onClick"],ge=["onClick"],he=["onClick"],_e={key:2,class:"pending-grid"},fe={class:"row-actions"},be=["disabled","onClick"],ye=["disabled","onClick"],ke={key:0,class:"empty"},Ce={key:3,class:"commands-table"},we={class:"filters"},me={class:"command-main"},xe={class:"command-controls"},Ae={class:"check"},Ie=["checked","onChange"],Ve=["value","onChange"],$e=H({__name:"new-auth",setup(C){const i=v("roles"),u=v("global"),d=v(""),p=v(""),h=v("all"),$=v(false),_=v(false),A=v(""),w=c(()=>E.newauth||{roles:[],commands:[],policies:[],scopes:[{id:"global",name:"全局默认"}],pendingCount:0}),I=c(()=>w.value.roles),P=c(()=>w.value.commands),L=c(()=>w.value.policies),B=c(()=>{var n;return(n=w.value.scopes)!=null&&n.length?w.value.scopes:[{id:"global",name:"全局默认"}]}),V=c(()=>P.value.filter(n=>n.status==="pending")),f=c(()=>I.value.find(n=>n.id===d.value));J(I,n=>{!d.value&&n.length&&(d.value=n[0].id)},{immediate:true});const M=c(()=>{const n=p.value.toLowerCase();return P.value.filter(l=>h.value!=="all"&&l.status!==h.value?false:n?[l.id,l.name,l.commandPath,l.plugin,l.description].some(e=>e==null?void 0:e.toLowerCase().includes(n)):true)}),F=c(()=>f.value?M.value.filter(n=>{var l,e;return $.value||((l=f.value)==null?void 0:l.id)==="bot-admin"||((e=f.value)==null?void 0:e.scopeType)==="global"?true:n.allowGuildOverride}):[]);function S(n){const l=L.value.find(e=>e.scope===u.value&&e.roleId===d.value&&e.commandId===n);return(l==null?void 0:l.state)||"inherit"}async function b(n){_.value=true,A.value="";try{await n}catch(l){A.value=l instanceof Error?l.message:String(l)}finally{_.value=false}}async function R(){return b((async()=>{const n=await k("newauth/getData");E.newauth=n})())}function O(n,l){return b(k("newauth/setPolicy",{scope:u.value,roleId:d.value,commandId:n,state:l}))}function N(n,l){return b(k("newauth/applySuggestion",{commandId:n,scope:u.value,mode:l}))}function q(){return b(k("newauth/autoAssignPending",{scope:u.value,mode:"advisor"}))}function z(n,l){const e=l.target;return b(k("newauth/setGuildOverride",{commandId:n.id,allowGuildOverride:e.checked}))}function j(n,l){const e=l.target;return b(k("newauth/setCommandStatus",{commandId:n.id,status:e.value}))}return(n,l)=>(o(),a("main",Q,[t("header",W,[t("div",null,[l[9]||(l[9]=t("h1",null,"新权限",-1)),t("p",null,s(I.value.length)+" 个角色 / "+s(P.value.length)+" 个指令 / "+s(V.value.length)+" 个待配置",1)]),t("div",X,[y(t("select",{"onUpdate:modelValue":l[0]||(l[0]=e=>u.value=e),class:"scope-select"},[(o(true),a(m,null,x(B.value,e=>(o(),a("option",{key:e.id,value:e.id},s(e.name),9,Y))),128))],512),[[U,u.value]]),t("button",{class:"primary",disabled:_.value||!V.value.length,onClick:q}," AI 自动分配待配置 ",8,Z),t("button",{disabled:_.value,onClick:R},"刷新",8,ee)])]),t("nav",te,[t("button",{class:g({active:i.value==="roles"}),onClick:l[1]||(l[1]=e=>i.value="roles")},"角色",2),t("button",{class:g({active:i.value==="pending"}),onClick:l[2]||(l[2]=e=>i.value="pending")},"待配置",2),t("button",{class:g({active:i.value==="commands"}),onClick:l[3]||(l[3]=e=>i.value="commands")},"指令",2)]),A.value?(o(),a("p",le,s(A.value),1)):G("v-if",true),i.value==="roles"?(o(),a("section",ne,[t("aside",se,[(o(true),a(m,null,x(I.value,e=>(o(),a("button",{key:e.id,class:g(["role-item",{active:e.id===d.value}]),onClick:r=>d.value=e.id},[t("span",null,[t("strong",null,s(e.name),1),t("small",null,s(e.builtin?"内置角色":"自定义角色")+" / "+s(e.scopeType),1)]),t("em",null,s(e.allowCount),1)],10,oe))),128))]),f.value?(o(),a("section",ae,[t("div",ie,[t("div",null,[t("h2",null,s(f.value.name),1),t("p",null,s(f.value.id),1)]),t("label",ue,[y(t("input",{type:"checkbox","onUpdate:modelValue":l[4]||(l[4]=e=>$.value=e)},null,512),[[K,$.value]]),l[10]||(l[10]=T(" 审计模式 ",-1))])]),t("div",de,[y(t("input",{"onUpdate:modelValue":l[5]||(l[5]=e=>p.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[D,p.value,void 0,{trim:true}]]),y(t("select",{"onUpdate:modelValue":l[6]||(l[6]=e=>h.value=e)},[...l[11]||(l[11]=[t("option",{value:"all"},"全部状态",-1),t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],512),[[U,h.value]])]),t("div",re,[(o(true),a(m,null,x(F.value,e=>(o(),a("article",{key:e.id,class:"command-row"},[t("div",ce,[t("strong",null,s(e.name),1),t("span",null,s(e.commandPath),1),t("small",null,s(e.plugin)+" / legacy "+s(e.legacyAuthority)+" / "+s(e.suggestion.label),1)]),t("div",ve,[t("button",{class:g({active:S(e.id)==="inherit"}),onClick:r=>O(e.id,"inherit")}," 继承 ",10,pe),t("button",{class:g({active:S(e.id)==="allow"}),onClick:r=>O(e.id,"allow")}," 开 ",10,ge),t("button",{class:g({active:S(e.id)==="deny"}),onClick:r=>O(e.id,"deny")}," 关 ",10,he)])]))),128))])])):G("v-if",true)])):i.value==="pending"?(o(),a("section",_e,[(o(true),a(m,null,x(V.value,e=>(o(),a("article",{key:e.id,class:"pending-item"},[t("div",null,[t("strong",null,s(e.name),1),t("span",null,s(e.commandPath),1),t("small",null,s(e.plugin)+" / legacy "+s(e.legacyAuthority),1)]),t("dl",null,[l[12]||(l[12]=t("dt",null,"旧建议",-1)),t("dd",null,s(e.suggestion.label),1),l[13]||(l[13]=t("dt",null,"AI 建议",-1)),t("dd",null,s(e.autoAssign.label)+":"+s(e.autoAssign.reason),1)]),t("div",fe,[t("button",{disabled:_.value,onClick:r=>N(e.id,"legacy")},"采用旧建议",8,be),t("button",{class:"primary",disabled:_.value,onClick:r=>N(e.id,"advisor")},"采用 AI 建议",8,ye)])]))),128)),V.value.length?G("v-if",true):(o(),a("p",ke,"没有待配置指令。"))])):(o(),a("section",Ce,[t("div",we,[y(t("input",{"onUpdate:modelValue":l[7]||(l[7]=e=>p.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[D,p.value,void 0,{trim:true}]]),y(t("select",{"onUpdate:modelValue":l[8]||(l[8]=e=>h.value=e)},[...l[14]||(l[14]=[t("option",{value:"all"},"全部状态",-1),t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],512),[[U,h.value]])]),(o(true),a(m,null,x(M.value,e=>(o(),a("article",{key:e.id,class:"command-row"},[t("div",me,[t("strong",null,s(e.name),1),t("span",null,s(e.id),1),t("small",null,s(e.plugin)+" / "+s(e.commandPath)+" / "+s(e.autoAssign.label),1)]),t("div",xe,[t("label",Ae,[t("input",{type:"checkbox",checked:e.allowGuildOverride,onChange:r=>z(e,r)},null,40,Ie),l[15]||(l[15]=T(" 群内自治 ",-1))]),t("select",{value:e.status,onChange:r=>j(e,r)},[...l[16]||(l[16]=[t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],40,Ve)])]))),128))]))]))}}),Pe=(C,i)=>{const u=C.__vccOpts||C;for(const[d,p]of i)u[d]=p;return u},Se=Pe($e,[["__scopeId","data-v-b49c6f52"]]),Ge=C=>{C.page({name:"新权限",path:"/new-auth",icon:"⌗",fields:["newauth"],authority:4,component:Se})};export{Ge as default};
1
+ import{defineComponent as ve,ref as i,computed as v,watch as H,openBlock as s,createElementBlock as u,createElementVNode as l,toDisplayString as o,withDirectives as c,Fragment as f,renderList as y,vModelSelect as _,normalizeClass as w,createCommentVNode as B,withModifiers as J,vModelText as x,vModelCheckbox as ce,createTextVNode as q}from"vue";import{store as Q,send as g}from"@koishijs/client";const pe={class:"new-auth-page"},ge={class:"topbar"},be={class:"top-actions"},me=["value"],fe=["disabled"],ye=["disabled"],ke={class:"tabs"},he={key:0,class:"error"},_e={key:1,class:"role-layout"},we={class:"role-list"},Ce=["onClick"],Ie=["disabled"],$e={key:0,class:"detail"},Ve={class:"detail-head"},Se={class:"detail-tools"},Ue=["value"],Pe=["disabled"],Re={class:"check"},xe={class:"member-panel"},Ae={class:"member-list"},Me=["disabled","onClick"],Oe=["value"],Te=["disabled"],Ge={class:"filters"},Ne={class:"command-list"},Be={class:"command-main"},De={class:"state-buttons"},Ee=["onClick"],Le=["onClick"],Fe=["onClick"],qe={key:2,class:"pending-grid"},ze={class:"row-actions"},Ke=["disabled","onClick"],je=["disabled","onClick"],He={key:0,class:"empty"},Je={key:3,class:"commands-table"},Qe={class:"filters"},We={class:"plugin-bulk"},Xe=["value"],Ye=["disabled"],Ze=["disabled"],el=["disabled"],ll=["disabled"],tl={class:"command-main"},nl={class:"command-controls"},ol={class:"check"},sl=["checked","onChange"],ul=["value","onChange"],al=ve({__name:"new-auth",setup(S){const b=i("roles"),a=i("global"),d=i(""),k=i(""),C=i("all"),D=i(false),r=i(false),A=i(""),I=i(""),U=i(""),E=i("guild"),P=i(""),M=i("global"),O=i(""),h=i(""),$=v(()=>Q.newauth||{roles:[],commands:[],policies:[],members:[],scopes:[{id:"global",name:"全局默认"}],pendingCount:0}),R=v(()=>$.value.roles),T=v(()=>$.value.commands),W=v(()=>$.value.policies),X=v(()=>$.value.members),Y=v(()=>{var n;return(n=$.value.scopes)!=null&&n.length?$.value.scopes:[{id:"global",name:"全局默认"}]}),G=v(()=>T.value.filter(n=>n.status==="pending")),V=v(()=>R.value.find(n=>n.id===d.value)),z=v(()=>X.value.filter(n=>n.roleId===d.value)),Z=v(()=>R.value.filter(n=>n.id!==d.value)),ee=v(()=>[...new Set(T.value.map(n=>n.plugin))].sort());H(R,n=>{!d.value&&n.length&&(d.value=n[0].id)},{immediate:true}),H(a,n=>{M.value=n==="global"?"global":n});const K=v(()=>{const n=k.value.toLowerCase();return T.value.filter(t=>C.value!=="all"&&t.status!==C.value?false:n?[t.id,t.name,t.commandPath,t.plugin,t.description].some(e=>e==null?void 0:e.toLowerCase().includes(n)):true)}),le=v(()=>V.value?K.value.filter(n=>{var t,e;return D.value||((t=V.value)==null?void 0:t.id)==="bot-admin"||((e=V.value)==null?void 0:e.scopeType)==="global"?true:n.allowGuildOverride}):[]);function L(n){const t=W.value.find(e=>e.scope===a.value&&e.roleId===d.value&&e.commandId===n);return(t==null?void 0:t.state)||"inherit"}async function p(n){r.value=true,A.value="";try{await n}catch(t){A.value=t instanceof Error?t.message:String(t)}finally{r.value=false}}async function te(){return p((async()=>{const n=await g("newauth/getData");Q.newauth=n})())}function F(n,t){return p(g("newauth/setPolicy",{scope:a.value,roleId:d.value,commandId:n,state:t}))}function j(n,t){return p(g("newauth/applySuggestion",{commandId:n,scope:a.value,mode:t}))}function ne(){return p(g("newauth/autoAssignPending",{scope:a.value,mode:"advisor"}))}function oe(n,t){const e=t.target;return p(g("newauth/setGuildOverride",{commandId:n.id,allowGuildOverride:e.checked}))}function se(n,t){const e=t.target;return p(g("newauth/setCommandStatus",{commandId:n.id,status:e.value}))}function ue(){return p((async()=>{await g("newauth/createRole",{id:I.value,name:U.value,scopeType:E.value}),d.value=I.value,I.value="",U.value=""})())}function ae(){return p((async()=>{await g("newauth/addMember",{roleId:d.value,uid:P.value,scope:M.value}),P.value=""})())}function ie(n){return p(g("newauth/removeMember",{roleId:n.roleId,uid:`${n.platform}:${n.userId}`,scope:n.scope}))}function de(){return p(g("newauth/copyRolePolicies",{sourceRoleId:O.value,targetRoleId:d.value,scope:a.value}))}function re(n){return`${n.roleId}:${n.platform}:${n.userId}:${n.scope}`}function N(n){return p(g("newauth/assignPluginCommands",{plugin:h.value,scope:a.value,target:n}))}return(n,t)=>(s(),u("main",pe,[l("header",ge,[l("div",null,[t[20]||(t[20]=l("h1",null,"新权限",-1)),l("p",null,o(R.value.length)+" 个角色 / "+o(T.value.length)+" 个指令 / "+o(G.value.length)+" 个待配置",1)]),l("div",be,[c(l("select",{"onUpdate:modelValue":t[0]||(t[0]=e=>a.value=e),class:"scope-select"},[(s(true),u(f,null,y(Y.value,e=>(s(),u("option",{key:e.id,value:e.id},o(e.name),9,me))),128))],512),[[_,a.value]]),l("button",{class:"primary",disabled:r.value||!G.value.length,onClick:ne}," AI 自动分配待配置 ",8,fe),l("button",{disabled:r.value,onClick:te},"刷新",8,ye)])]),l("nav",ke,[l("button",{class:w({active:b.value==="roles"}),onClick:t[1]||(t[1]=e=>b.value="roles")},"角色",2),l("button",{class:w({active:b.value==="pending"}),onClick:t[2]||(t[2]=e=>b.value="pending")},"待配置",2),l("button",{class:w({active:b.value==="commands"}),onClick:t[3]||(t[3]=e=>b.value="commands")},"指令",2)]),A.value?(s(),u("p",he,o(A.value),1)):B("v-if",true),b.value==="roles"?(s(),u("section",_e,[l("aside",we,[(s(true),u(f,null,y(R.value,e=>(s(),u("button",{key:e.id,class:w(["role-item",{active:e.id===d.value}]),onClick:m=>d.value=e.id},[l("span",null,[l("strong",null,o(e.name),1),l("small",null,o(e.builtin?"内置角色":"自定义角色")+" / "+o(e.scopeType),1)]),l("em",null,o(e.allowCount),1)],10,Ce))),128)),l("form",{class:"role-create",onSubmit:J(ue,["prevent"])},[c(l("input",{"onUpdate:modelValue":t[4]||(t[4]=e=>I.value=e),placeholder:"custom:music-admin"},null,512),[[x,I.value,void 0,{trim:true}]]),c(l("input",{"onUpdate:modelValue":t[5]||(t[5]=e=>U.value=e),placeholder:"角色名称"},null,512),[[x,U.value,void 0,{trim:true}]]),c(l("select",{"onUpdate:modelValue":t[6]||(t[6]=e=>E.value=e)},[...t[21]||(t[21]=[l("option",{value:"guild"},"群内角色",-1),l("option",{value:"global"},"全局角色",-1)])],512),[[_,E.value]]),l("button",{class:"primary",disabled:r.value||!I.value||!U.value},"创建角色",8,Ie)],32)]),V.value?(s(),u("section",$e,[l("div",Ve,[l("div",null,[l("h2",null,o(V.value.name),1),l("p",null,o(V.value.id),1)]),l("div",Se,[c(l("select",{"onUpdate:modelValue":t[7]||(t[7]=e=>O.value=e)},[t[22]||(t[22]=l("option",{disabled:"",value:""},"复制来源",-1)),(s(true),u(f,null,y(Z.value,e=>(s(),u("option",{key:e.id,value:e.id},o(e.name),9,Ue))),128))],512),[[_,O.value]]),l("button",{disabled:r.value||!O.value,onClick:de},"复制权限",8,Pe),l("label",Re,[c(l("input",{type:"checkbox","onUpdate:modelValue":t[8]||(t[8]=e=>D.value=e)},null,512),[[ce,D.value]]),t[23]||(t[23]=q(" 审计模式 ",-1))])])]),l("section",xe,[l("div",null,[t[24]||(t[24]=l("strong",null,"成员",-1)),l("small",null,o(z.value.length)+" 个显式成员",1)]),l("div",Ae,[(s(true),u(f,null,y(z.value,e=>(s(),u("span",{key:re(e),class:"member-chip"},[q(o(e.platform)+":"+o(e.userId)+" / "+o(e.scope)+" ",1),l("button",{disabled:r.value,onClick:m=>ie(e)},"移除",8,Me)]))),128))]),l("form",{class:"member-add",onSubmit:J(ae,["prevent"])},[c(l("input",{"onUpdate:modelValue":t[9]||(t[9]=e=>P.value=e),placeholder:"platform:userId"},null,512),[[x,P.value,void 0,{trim:true}]]),c(l("select",{"onUpdate:modelValue":t[10]||(t[10]=e=>M.value=e)},[t[25]||(t[25]=l("option",{value:"global"},"global",-1)),a.value!=="global"?(s(),u("option",{key:0,value:a.value},o(a.value),9,Oe)):B("v-if",true)],512),[[_,M.value]]),l("button",{class:"primary",disabled:r.value||!P.value},"添加成员",8,Te)],32)]),l("div",Ge,[c(l("input",{"onUpdate:modelValue":t[11]||(t[11]=e=>k.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[x,k.value,void 0,{trim:true}]]),c(l("select",{"onUpdate:modelValue":t[12]||(t[12]=e=>C.value=e)},[...t[26]||(t[26]=[l("option",{value:"all"},"全部状态",-1),l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],512),[[_,C.value]])]),l("div",Ne,[(s(true),u(f,null,y(le.value,e=>(s(),u("article",{key:e.id,class:"command-row"},[l("div",Be,[l("strong",null,o(e.name),1),l("span",null,o(e.commandPath),1),l("small",null,o(e.plugin)+" / legacy "+o(e.legacyAuthority)+" / "+o(e.suggestion.label),1)]),l("div",De,[l("button",{class:w({active:L(e.id)==="inherit"}),onClick:m=>F(e.id,"inherit")}," 继承 ",10,Ee),l("button",{class:w({active:L(e.id)==="allow"}),onClick:m=>F(e.id,"allow")}," 开 ",10,Le),l("button",{class:w({active:L(e.id)==="deny"}),onClick:m=>F(e.id,"deny")}," 关 ",10,Fe)])]))),128))])])):B("v-if",true)])):b.value==="pending"?(s(),u("section",qe,[(s(true),u(f,null,y(G.value,e=>(s(),u("article",{key:e.id,class:"pending-item"},[l("div",null,[l("strong",null,o(e.name),1),l("span",null,o(e.commandPath),1),l("small",null,o(e.plugin)+" / legacy "+o(e.legacyAuthority),1)]),l("dl",null,[t[27]||(t[27]=l("dt",null,"旧建议",-1)),l("dd",null,o(e.suggestion.label),1),t[28]||(t[28]=l("dt",null,"AI 建议",-1)),l("dd",null,o(e.autoAssign.label)+":"+o(e.autoAssign.reason),1)]),l("div",ze,[l("button",{disabled:r.value,onClick:m=>j(e.id,"legacy")},"采用旧建议",8,Ke),l("button",{class:"primary",disabled:r.value,onClick:m=>j(e.id,"advisor")},"采用 AI 建议",8,je)])]))),128)),G.value.length?B("v-if",true):(s(),u("p",He,"没有待配置指令。"))])):(s(),u("section",Je,[l("div",Qe,[c(l("input",{"onUpdate:modelValue":t[13]||(t[13]=e=>k.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[x,k.value,void 0,{trim:true}]]),c(l("select",{"onUpdate:modelValue":t[14]||(t[14]=e=>C.value=e)},[...t[29]||(t[29]=[l("option",{value:"all"},"全部状态",-1),l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],512),[[_,C.value]])]),l("div",We,[c(l("select",{"onUpdate:modelValue":t[15]||(t[15]=e=>h.value=e)},[t[30]||(t[30]=l("option",{disabled:"",value:""},"选择插件",-1)),(s(true),u(f,null,y(ee.value,e=>(s(),u("option",{key:e,value:e},o(e),9,Xe))),128))],512),[[_,h.value]]),l("button",{disabled:r.value||!h.value,onClick:t[16]||(t[16]=e=>N("legacy"))},"采用插件建议",8,Ye),l("button",{disabled:r.value||!h.value,onClick:t[17]||(t[17]=e=>N("guild-member"))},"给群成员",8,Ze),l("button",{disabled:r.value||!h.value,onClick:t[18]||(t[18]=e=>N("guild-admin"))},"给群管理员",8,el),l("button",{disabled:r.value||!h.value,onClick:t[19]||(t[19]=e=>N("bot-admin"))},"仅 Bot 管理员",8,ll)]),(s(true),u(f,null,y(K.value,e=>(s(),u("article",{key:e.id,class:"command-row"},[l("div",tl,[l("strong",null,o(e.name),1),l("span",null,o(e.id),1),l("small",null,o(e.plugin)+" / "+o(e.commandPath)+" / "+o(e.autoAssign.label),1)]),l("div",nl,[l("label",ol,[l("input",{type:"checkbox",checked:e.allowGuildOverride,onChange:m=>oe(e,m)},null,40,sl),t[31]||(t[31]=q(" 群内自治 ",-1))]),l("select",{value:e.status,onChange:m=>se(e,m)},[...t[32]||(t[32]=[l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],40,ul)])]))),128))]))]))}}),il=(S,b)=>{const a=S.__vccOpts||S;for(const[d,k]of b)a[d]=k;return a},dl=il(al,[["__scopeId","data-v-755ad7c8"]]),cl=S=>{S.page({name:"新权限",path:"/new-auth",icon:"⌗",fields:["newauth"],authority:4,component:dl})};export{cl as default};
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .new-auth-page[data-v-b49c6f52]{min-height:100vh;background:#f6f7f4;color:#1f2523;padding:20px}.topbar[data-v-b49c6f52],.detail-head[data-v-b49c6f52],.filters[data-v-b49c6f52],.row-actions[data-v-b49c6f52],.command-controls[data-v-b49c6f52],.top-actions[data-v-b49c6f52]{display:flex;align-items:center;gap:12px}.topbar[data-v-b49c6f52]{justify-content:space-between;border-bottom:1px solid #d9ded6;padding-bottom:16px}h1[data-v-b49c6f52],h2[data-v-b49c6f52],p[data-v-b49c6f52]{margin:0}h1[data-v-b49c6f52]{font-size:26px;line-height:1.2}h2[data-v-b49c6f52]{font-size:20px}p[data-v-b49c6f52],small[data-v-b49c6f52],span[data-v-b49c6f52],dd[data-v-b49c6f52],dt[data-v-b49c6f52]{color:#63706a}button[data-v-b49c6f52],select[data-v-b49c6f52],input[data-v-b49c6f52]{border:1px solid #c7cec8;border-radius:6px;background:#fff;color:#1f2523;min-height:34px;padding:0 10px;font:inherit}button[data-v-b49c6f52]{cursor:pointer}button[data-v-b49c6f52]:disabled{cursor:not-allowed;opacity:.55}.primary[data-v-b49c6f52]{background:#285e54;border-color:#285e54;color:#fff}.tabs[data-v-b49c6f52]{display:flex;gap:6px;margin:16px 0}.tabs button.active[data-v-b49c6f52],.state-buttons button.active[data-v-b49c6f52]{background:#25312d;border-color:#25312d;color:#fff}.role-layout[data-v-b49c6f52]{display:grid;grid-template-columns:minmax(220px,280px) 1fr;gap:16px}.role-list[data-v-b49c6f52]{display:grid;gap:8px;align-content:start}.role-item[data-v-b49c6f52]{display:flex;justify-content:space-between;align-items:center;min-height:58px;text-align:left}.role-item span[data-v-b49c6f52],.command-main[data-v-b49c6f52]{display:grid;gap:3px;min-width:0}.role-item.active[data-v-b49c6f52]{border-color:#285e54;box-shadow:inset 3px 0 #285e54}.role-item em[data-v-b49c6f52]{font-style:normal;color:#8b4a2f}.detail[data-v-b49c6f52]{min-width:0}.detail-head[data-v-b49c6f52]{justify-content:space-between;margin-bottom:12px}.filters[data-v-b49c6f52]{margin-bottom:12px}.filters input[data-v-b49c6f52]{flex:1;min-width:180px}.command-list[data-v-b49c6f52],.pending-grid[data-v-b49c6f52],.commands-table[data-v-b49c6f52]{display:grid;gap:8px}.command-row[data-v-b49c6f52],.pending-item[data-v-b49c6f52]{background:#fff;border:1px solid #d9ded6;border-radius:8px;padding:12px}.command-row[data-v-b49c6f52]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center}.command-main strong[data-v-b49c6f52],.command-main span[data-v-b49c6f52],.command-main small[data-v-b49c6f52]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.state-buttons[data-v-b49c6f52]{display:grid;grid-template-columns:repeat(3,54px);gap:6px}.pending-grid[data-v-b49c6f52]{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.pending-item[data-v-b49c6f52]{display:grid;gap:10px}dl[data-v-b49c6f52]{display:grid;grid-template-columns:58px 1fr;gap:4px 8px;margin:0}dd[data-v-b49c6f52]{margin:0}.check[data-v-b49c6f52]{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.check input[data-v-b49c6f52]{min-height:0}.error[data-v-b49c6f52]{border:1px solid #d9a09a;background:#fff1ef;color:#8a2d22;border-radius:6px;padding:10px;margin-bottom:12px}.empty[data-v-b49c6f52]{padding:24px 0}@media (max-width: 760px){.new-auth-page[data-v-b49c6f52]{padding:12px}.topbar[data-v-b49c6f52],.detail-head[data-v-b49c6f52],.command-row[data-v-b49c6f52]{grid-template-columns:1fr;display:grid}.top-actions[data-v-b49c6f52],.filters[data-v-b49c6f52],.command-controls[data-v-b49c6f52]{flex-wrap:wrap}.role-layout[data-v-b49c6f52]{grid-template-columns:1fr}.state-buttons[data-v-b49c6f52]{grid-template-columns:repeat(3,minmax(0,1fr))}}
1
+ .new-auth-page[data-v-755ad7c8]{min-height:100vh;background:#f6f7f4;color:#1f2523;padding:20px}.topbar[data-v-755ad7c8],.detail-head[data-v-755ad7c8],.filters[data-v-755ad7c8],.row-actions[data-v-755ad7c8],.command-controls[data-v-755ad7c8],.top-actions[data-v-755ad7c8],.detail-tools[data-v-755ad7c8],.member-add[data-v-755ad7c8],.plugin-bulk[data-v-755ad7c8]{display:flex;align-items:center;gap:12px}.topbar[data-v-755ad7c8]{justify-content:space-between;border-bottom:1px solid #d9ded6;padding-bottom:16px}h1[data-v-755ad7c8],h2[data-v-755ad7c8],p[data-v-755ad7c8]{margin:0}h1[data-v-755ad7c8]{font-size:26px;line-height:1.2}h2[data-v-755ad7c8]{font-size:20px}p[data-v-755ad7c8],small[data-v-755ad7c8],span[data-v-755ad7c8],dd[data-v-755ad7c8],dt[data-v-755ad7c8]{color:#63706a}button[data-v-755ad7c8],select[data-v-755ad7c8],input[data-v-755ad7c8]{border:1px solid #c7cec8;border-radius:6px;background:#fff;color:#1f2523;min-height:34px;padding:0 10px;font:inherit}button[data-v-755ad7c8]{cursor:pointer}button[data-v-755ad7c8]:disabled{cursor:not-allowed;opacity:.55}.primary[data-v-755ad7c8]{background:#285e54;border-color:#285e54;color:#fff}.tabs[data-v-755ad7c8]{display:flex;gap:6px;margin:16px 0}.tabs button.active[data-v-755ad7c8],.state-buttons button.active[data-v-755ad7c8]{background:#25312d;border-color:#25312d;color:#fff}.role-layout[data-v-755ad7c8]{display:grid;grid-template-columns:minmax(220px,280px) 1fr;gap:16px}.role-list[data-v-755ad7c8]{display:grid;gap:8px;align-content:start}.role-create[data-v-755ad7c8]{display:grid;gap:8px;border:1px solid #d9ded6;border-radius:8px;background:#fff;padding:10px}.role-item[data-v-755ad7c8]{display:flex;justify-content:space-between;align-items:center;min-height:58px;text-align:left}.role-item span[data-v-755ad7c8],.command-main[data-v-755ad7c8]{display:grid;gap:3px;min-width:0}.role-item.active[data-v-755ad7c8]{border-color:#285e54;box-shadow:inset 3px 0 #285e54}.role-item em[data-v-755ad7c8]{font-style:normal;color:#8b4a2f}.detail[data-v-755ad7c8]{min-width:0}.detail-head[data-v-755ad7c8]{justify-content:space-between;margin-bottom:12px}.detail-tools[data-v-755ad7c8]{flex-wrap:wrap;justify-content:flex-end}.member-panel[data-v-755ad7c8]{display:grid;gap:10px;border:1px solid #d9ded6;border-radius:8px;background:#fff;padding:12px;margin-bottom:12px}.member-panel>div[data-v-755ad7c8]:first-child{display:flex;justify-content:space-between;gap:12px}.member-list[data-v-755ad7c8]{display:flex;flex-wrap:wrap;gap:6px;min-height:28px}.member-chip[data-v-755ad7c8]{display:inline-flex;align-items:center;gap:6px;border:1px solid #c7cec8;border-radius:999px;background:#f6f7f4;padding:3px 4px 3px 10px}.member-chip button[data-v-755ad7c8]{min-height:24px;padding:0 8px;border-radius:999px}.filters[data-v-755ad7c8]{margin-bottom:12px}.plugin-bulk[data-v-755ad7c8]{flex-wrap:wrap;border:1px solid #d9ded6;border-radius:8px;background:#fff;padding:10px;margin-bottom:12px}.filters input[data-v-755ad7c8]{flex:1;min-width:180px}.command-list[data-v-755ad7c8],.pending-grid[data-v-755ad7c8],.commands-table[data-v-755ad7c8]{display:grid;gap:8px}.command-row[data-v-755ad7c8],.pending-item[data-v-755ad7c8]{background:#fff;border:1px solid #d9ded6;border-radius:8px;padding:12px}.command-row[data-v-755ad7c8]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center}.command-main strong[data-v-755ad7c8],.command-main span[data-v-755ad7c8],.command-main small[data-v-755ad7c8]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.state-buttons[data-v-755ad7c8]{display:grid;grid-template-columns:repeat(3,54px);gap:6px}.pending-grid[data-v-755ad7c8]{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.pending-item[data-v-755ad7c8]{display:grid;gap:10px}dl[data-v-755ad7c8]{display:grid;grid-template-columns:58px 1fr;gap:4px 8px;margin:0}dd[data-v-755ad7c8]{margin:0}.check[data-v-755ad7c8]{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.check input[data-v-755ad7c8]{min-height:0}.error[data-v-755ad7c8]{border:1px solid #d9a09a;background:#fff1ef;color:#8a2d22;border-radius:6px;padding:10px;margin-bottom:12px}.empty[data-v-755ad7c8]{padding:24px 0}@media (max-width: 760px){.new-auth-page[data-v-755ad7c8]{padding:12px}.topbar[data-v-755ad7c8],.detail-head[data-v-755ad7c8],.command-row[data-v-755ad7c8]{grid-template-columns:1fr;display:grid}.top-actions[data-v-755ad7c8],.filters[data-v-755ad7c8],.command-controls[data-v-755ad7c8],.detail-tools[data-v-755ad7c8],.member-add[data-v-755ad7c8],.plugin-bulk[data-v-755ad7c8]{flex-wrap:wrap}.role-layout[data-v-755ad7c8]{grid-template-columns:1fr}.state-buttons[data-v-755ad7c8]{grid-template-columns:repeat(3,minmax(0,1fr))}}
package/lib/index.d.ts CHANGED
@@ -10,6 +10,7 @@ type ScopeType = 'global' | 'guild';
10
10
  type CommandStatus = 'pending' | 'configured' | 'disabled';
11
11
  type PolicyState = 'inherit' | 'allow' | 'deny';
12
12
  type AutoAssignKind = 'public' | 'moderation' | 'owner' | 'admin' | 'legacy';
13
+ type PluginAssignTarget = 'legacy' | 'bot-admin' | 'guild-owner' | 'guild-admin' | 'guild-member';
13
14
  export interface NewAuthCommandRecord {
14
15
  id: string;
15
16
  name: string;
@@ -94,6 +95,10 @@ declare module '@koishijs/plugin-console' {
94
95
  success: true;
95
96
  count: number;
96
97
  }>;
98
+ 'newauth/assignPluginCommands'(payload: AssignPluginCommandsPayload): Promise<{
99
+ success: true;
100
+ count: number;
101
+ }>;
97
102
  }
98
103
  }
99
104
  export interface NewAuthConsoleData {
@@ -163,6 +168,11 @@ interface CopyRolePoliciesPayload {
163
168
  targetRoleId: string;
164
169
  scope: string;
165
170
  }
171
+ interface AssignPluginCommandsPayload {
172
+ plugin: string;
173
+ scope: string;
174
+ target: PluginAssignTarget;
175
+ }
166
176
  export interface Config {
167
177
  botAdmins: string[];
168
178
  trustLegacyAuthorityAsAdmin: boolean;
@@ -253,6 +263,7 @@ export declare class NewAuthService {
253
263
  setCommandPolicy(scope: string, roleId: string, input: string, state: PolicyState): Promise<NewAuthCommandRecord>;
254
264
  applySuggestedPolicy(input: string, scope?: string, mode?: 'legacy' | 'advisor'): Promise<NewAuthCommandRecord>;
255
265
  autoAssignPending(scope?: string, mode?: 'legacy' | 'advisor'): Promise<number>;
266
+ assignPluginCommands(plugin: string, scope?: string, target?: PluginAssignTarget): Promise<number>;
256
267
  getCommand(input: string): Promise<NewAuthCommandRecord>;
257
268
  private ensureBuiltinRoles;
258
269
  private applyRolesToCommand;
package/lib/index.js CHANGED
@@ -379,7 +379,7 @@ class NewAuthService {
379
379
  updatedAt: now,
380
380
  };
381
381
  if (existing) {
382
- await this.ctx.database.set('new_auth_role', id, record);
382
+ await this.ctx.database.set('new_auth_role', id, omitPrimary(record, 'id'));
383
383
  }
384
384
  else {
385
385
  await this.ctx.database.create('new_auth_role', record);
@@ -454,6 +454,22 @@ class NewAuthService {
454
454
  }
455
455
  return commands.length;
456
456
  }
457
+ async assignPluginCommands(plugin, scope = 'global', target = 'legacy') {
458
+ const commands = (await this.listCommands({ all: true }))
459
+ .filter(command => command.plugin === plugin);
460
+ for (const command of commands) {
461
+ if (target === 'legacy') {
462
+ await this.applySuggestedPolicy(command.id, scope, 'legacy');
463
+ }
464
+ else {
465
+ await this.applyRolesToCommand(scope, command.id, getAssignTargetRoles(target));
466
+ if (command.status === 'pending') {
467
+ await this.setCommandStatus(command.id, 'configured');
468
+ }
469
+ }
470
+ }
471
+ return commands.length;
472
+ }
457
473
  async getCommand(input) {
458
474
  const cached = this.commandCache.get(input);
459
475
  if (cached)
@@ -474,7 +490,7 @@ class NewAuthService {
474
490
  updatedAt: now,
475
491
  };
476
492
  if (existing) {
477
- await this.ctx.database.set('new_auth_role', role.id, record);
493
+ await this.ctx.database.set('new_auth_role', role.id, omitPrimary(record, 'id'));
478
494
  }
479
495
  else {
480
496
  await this.ctx.database.create('new_auth_role', record);
@@ -662,7 +678,7 @@ class NewAuthService {
662
678
  }
663
679
  }
664
680
  exports.NewAuthService = NewAuthService;
665
- function createConsoleServiceClass() {
681
+ function createConsoleServiceClass(service) {
666
682
  const { DataService } = require('@koishijs/plugin-console');
667
683
  return class NewAuthConsoleDataService extends DataService {
668
684
  constructor(ctx) {
@@ -672,7 +688,7 @@ function createConsoleServiceClass() {
672
688
  });
673
689
  }
674
690
  async get(_forced, _client) {
675
- return this.ctx.newauth.getConsoleData();
691
+ return service.getConsoleData();
676
692
  }
677
693
  };
678
694
  }
@@ -681,7 +697,7 @@ function registerConsole(ctx, service) {
681
697
  dev: (0, path_1.resolve)(__dirname, '../client/index.ts'),
682
698
  prod: (0, path_1.resolve)(__dirname, '../dist'),
683
699
  });
684
- ctx.plugin(createConsoleServiceClass());
700
+ ctx.plugin(createConsoleServiceClass(service));
685
701
  const ok = async (task) => {
686
702
  await task;
687
703
  ctx.console.refresh('newauth');
@@ -721,6 +737,11 @@ function registerConsole(ctx, service) {
721
737
  ctx.console.refresh('newauth');
722
738
  return { success: true, count };
723
739
  }, { authority: 4 });
740
+ ctx.console.addListener('newauth/assignPluginCommands', async (payload) => {
741
+ const count = await service.assignPluginCommands(payload.plugin, payload.scope, payload.target);
742
+ ctx.console.refresh('newauth');
743
+ return { success: true, count };
744
+ }, { authority: 4 });
724
745
  }
725
746
  function registerManagementCommands(ctx, config, service) {
726
747
  const authority = config.legacyAdminAuthority;
@@ -816,6 +837,14 @@ function registerManagementCommands(ctx, config, service) {
816
837
  const count = await service.copyRolePolicies(sourceRoleId, targetRoleId, scope);
817
838
  return `已复制 ${count} 条策略:${sourceRoleId} -> ${targetRoleId} (${scope})`;
818
839
  });
840
+ ctx.command('newauth.plugin.assign <plugin> <target> [scope]', '批量配置插件指令', { authority })
841
+ .action(async (_, plugin, target, scope = 'global') => {
842
+ if (!['legacy', 'bot-admin', 'guild-owner', 'guild-admin', 'guild-member'].includes(target)) {
843
+ return 'target 只能是 legacy、bot-admin、guild-owner、guild-admin 或 guild-member。';
844
+ }
845
+ const count = await service.assignPluginCommands(plugin, scope, target);
846
+ return `已批量配置 ${count} 个指令:${plugin} -> ${target} (${scope})`;
847
+ });
819
848
  }
820
849
  function inferLegacyAuthority(command) {
821
850
  if (typeof command.config.authority === 'number')
@@ -857,6 +886,19 @@ function getLegacySuggestion(authority) {
857
886
  label: '仅 Bot 管理员',
858
887
  };
859
888
  }
889
+ function getAssignTargetRoles(target) {
890
+ if (target === 'guild-member')
891
+ return ['guild-member', 'guild-admin', 'guild-owner'];
892
+ if (target === 'guild-admin')
893
+ return ['guild-admin', 'guild-owner'];
894
+ if (target === 'guild-owner')
895
+ return ['guild-owner'];
896
+ return ['bot-admin'];
897
+ }
898
+ function omitPrimary(record, key) {
899
+ const { [key]: _value, ...rest } = record;
900
+ return rest;
901
+ }
860
902
  function inferPlugin(command) {
861
903
  const source = command.caller?.scope || command.ctx?.scope;
862
904
  const plugin = source?.plugin?.name || source?.uid || source?.id || 'unknown';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koishi-plugin-new-auth",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Role and scope based command permission layer for Koishi.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",