koishi-plugin-new-auth 0.4.0 → 0.4.6
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 +8 -2
- package/dist/index.js +1 -1
- package/dist/style.css +1 -1
- package/lib/index.d.ts +35 -15
- package/lib/index.js +309 -78
- package/newauth.md +2 -2
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -48,6 +48,10 @@ newauth.role.create <id> <name> [scopeType]
|
|
|
48
48
|
newauth.member.add <roleId> <uid> [scope]
|
|
49
49
|
newauth.member.remove <roleId> <uid> [scope]
|
|
50
50
|
newauth.role.copy <sourceRoleId> <targetRoleId> [scope]
|
|
51
|
+
newauth.guild.commands [query]
|
|
52
|
+
newauth.guild.allow <roleId> <command>
|
|
53
|
+
newauth.guild.deny <roleId> <command>
|
|
54
|
+
newauth.guild.inherit <roleId> <command>
|
|
51
55
|
newauth.plugin.assign <plugin> <target> [scope]
|
|
52
56
|
```
|
|
53
57
|
|
|
@@ -62,6 +66,8 @@ newauth.plugin.assign <plugin> <target> [scope]
|
|
|
62
66
|
|
|
63
67
|
`newauth.assign` 与待配置 WebUI 的角色勾选行为一致:列出的角色写为允许,其他角色在该作用域下写为关闭,并把待配置指令变为已配置。
|
|
64
68
|
|
|
69
|
+
`newauth.guild.*` 是当前群的自治入口,只能由 Bot 管理员或当前群群主使用,只能修改当前群、已配置且允许群内自治的指令,不能修改全局权限或 Bot 管理员角色。
|
|
70
|
+
|
|
65
71
|
## 内置角色
|
|
66
72
|
|
|
67
73
|
```txt
|
|
@@ -83,7 +89,7 @@ guest
|
|
|
83
89
|
- 以角色为入口的指令权限编辑;
|
|
84
90
|
- 全局默认和单群作用域切换;
|
|
85
91
|
- 待配置指令审查和角色勾选分配;
|
|
86
|
-
- 旧 `authority`
|
|
92
|
+
- 旧 `authority` 建议与基于 ChatLuna 模型的 AI 分配审查表;
|
|
87
93
|
- 指令状态和群内自治开关;
|
|
88
94
|
- 自定义角色创建、显式成员管理;
|
|
89
95
|
- 从其他角色复制权限;
|
|
@@ -91,4 +97,4 @@ guest
|
|
|
91
97
|
|
|
92
98
|
WebUI 是 Koishi 实例管理员界面,Console 入口和所有事件都要求 `authority: 4`。群主自治只应影响允许自治的单群指令,不等于进入实例管理面板。
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
AI 自动分配不会按关键词硬编码推断。安装并启用 ChatLuna 后,newauth 会读取 ChatLuna 已加载的聊天模型,WebUI 中选择模型后再把指令元数据和角色列表交给该模型,让模型返回允许的角色;WebUI 会先显示审查表并填入勾选项,只有管理员点击保存后才写入策略。模型不可用或返回无效时回退到旧 `authority` 建议。
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineComponent as _e,ref as d,computed as c,watch as W,openBlock as s,createElementBlock as u,createElementVNode as t,toDisplayString as o,withDirectives as p,Fragment as k,renderList as y,vModelSelect as C,normalizeClass as w,createCommentVNode as L,withModifiers as ee,vModelText as T,vModelCheckbox as Ce,createTextVNode as F}from"vue";import{store as le,send as b}from"@koishijs/client";const we={class:"new-auth-page"},Ie={class:"topbar"},$e={class:"top-actions"},Se=["value"],Pe=["disabled"],Re=["disabled"],Ve={class:"tabs"},Ae={key:0,class:"error"},Ue={key:1,class:"role-layout"},xe={class:"role-list"},Me=["onClick"],Te=["disabled"],Oe={key:0,class:"detail"},Ge={class:"detail-head"},Ne={class:"detail-tools"},Be=["value"],De=["disabled"],Ee={class:"check"},Le={class:"member-panel"},Fe={class:"member-list"},Ke=["disabled","onClick"],qe=["value"],ze=["disabled"],je={class:"filters"},He={class:"command-list"},Je={class:"command-main"},Qe={class:"state-buttons"},We=["onClick"],Xe=["onClick"],Ye=["onClick"],Ze={key:2,class:"pending-grid"},el={class:"role-picker"},ll=["checked","onChange"],tl={class:"row-actions"},nl=["disabled","onClick"],ol=["disabled","onClick"],sl=["disabled","onClick"],ul={key:0,class:"empty"},il={key:3,class:"commands-table"},al={class:"filters"},dl={class:"plugin-bulk"},rl=["value"],vl=["disabled"],cl=["disabled"],pl=["disabled"],gl=["disabled"],bl={class:"command-main"},fl={class:"command-controls"},kl={class:"check"},yl=["checked","onChange"],hl=["value","onChange"],ml=_e({__name:"new-auth",setup(A){const f=d("roles"),a=d("global"),v=d(""),h=d(""),I=d("all"),K=d(false),r=d(false),O=d(""),$=d(""),U=d(""),q=d("guild"),x=d(""),G=d("global"),N=d(""),m=d(""),_=d({}),S=c(()=>le.newauth||{roles:[],commands:[],policies:[],members:[],scopes:[{id:"global",name:"全局默认"}],pendingCount:0}),P=c(()=>S.value.roles),B=c(()=>S.value.commands),z=c(()=>S.value.policies),te=c(()=>S.value.members),ne=c(()=>{var n;return(n=S.value.scopes)!=null&&n.length?S.value.scopes:[{id:"global",name:"全局默认"}]}),R=c(()=>B.value.filter(n=>n.status==="pending")),V=c(()=>P.value.find(n=>n.id===v.value)),X=c(()=>te.value.filter(n=>n.roleId===v.value)),oe=c(()=>P.value.filter(n=>n.id!==v.value)),se=c(()=>[...new Set(B.value.map(n=>n.plugin))].sort());W(P,n=>{!v.value&&n.length&&(v.value=n[0].id)},{immediate:true}),W(a,n=>{G.value=n==="global"?"global":n}),W([R,z,a],()=>{for(const n of R.value)D(n)},{immediate:true});const Y=c(()=>{const n=h.value.toLowerCase();return B.value.filter(l=>I.value!=="all"&&l.status!==I.value?false:n?[l.id,l.name,l.commandPath,l.plugin,l.description].some(e=>e==null?void 0:e.toLowerCase().includes(n)):true)}),ue=c(()=>V.value?Y.value.filter(n=>{var l,e;return K.value||((l=V.value)==null?void 0:l.id)==="bot-admin"||((e=V.value)==null?void 0:e.scopeType)==="global"?true:n.allowGuildOverride}):[]);function j(n){const l=z.value.find(e=>e.scope===a.value&&e.roleId===v.value&&e.commandId===n);return(l==null?void 0:l.state)||"inherit"}async function g(n){r.value=true,O.value="";try{await n}catch(l){O.value=l instanceof Error?l.message:String(l)}finally{r.value=false}}async function ie(){return g((async()=>{const n=await b("newauth/getData");le.newauth=n})())}function H(n,l){return g(b("newauth/setPolicy",{scope:a.value,roleId:v.value,commandId:n,state:l}))}function M(n){return`${a.value}:${n}`}function ae(n){const l=z.value.filter(e=>e.scope===a.value&&e.commandId===n.id&&e.state==="allow").map(e=>e.roleId);return l.length?l:[...n.autoAssign.roles]}function D(n){const l=M(n.id);_.value[l]||(_.value[l]=ae(n))}function de(n,l){return D(n),_.value[M(n.id)].includes(l)}function re(n,l,e){D(n);const i=M(n.id),J=e.target.checked,Q=new Set(_.value[i]);J?Q.add(l):Q.delete(l),_.value[i]=[...Q]}function Z(n,l){_.value[M(n.id)]=[...l==="legacy"?n.suggestion.roles:n.autoAssign.roles]}function ve(n){return D(n),g(b("newauth/configureCommandRoles",{commandId:n.id,scope:a.value,roleIds:_.value[M(n.id)]}))}function ce(){return g(b("newauth/autoAssignPending",{scope:a.value,mode:"advisor"}))}function pe(n,l){const e=l.target;return g(b("newauth/setGuildOverride",{commandId:n.id,allowGuildOverride:e.checked}))}function ge(n,l){const e=l.target;return g(b("newauth/setCommandStatus",{commandId:n.id,status:e.value}))}function be(){return g((async()=>{await b("newauth/createRole",{id:$.value,name:U.value,scopeType:q.value}),v.value=$.value,$.value="",U.value=""})())}function fe(){return g((async()=>{await b("newauth/addMember",{roleId:v.value,uid:x.value,scope:G.value}),x.value=""})())}function ke(n){return g(b("newauth/removeMember",{roleId:n.roleId,uid:`${n.platform}:${n.userId}`,scope:n.scope}))}function ye(){return g(b("newauth/copyRolePolicies",{sourceRoleId:N.value,targetRoleId:v.value,scope:a.value}))}function he(n){return`${n.roleId}:${n.platform}:${n.userId}:${n.scope}`}function E(n){return g(b("newauth/assignPluginCommands",{plugin:m.value,scope:a.value,target:n}))}function me(n){return n==="global"?"全局":"群内"}return(n,l)=>(s(),u("main",we,[t("header",Ie,[t("div",null,[l[20]||(l[20]=t("h1",null,"新权限",-1)),t("p",null,o(P.value.length)+" 个角色 / "+o(B.value.length)+" 个指令 / "+o(R.value.length)+" 个待配置",1)]),t("div",$e,[p(t("select",{"onUpdate:modelValue":l[0]||(l[0]=e=>a.value=e),class:"scope-select"},[(s(true),u(k,null,y(ne.value,e=>(s(),u("option",{key:e.id,value:e.id},o(e.name),9,Se))),128))],512),[[C,a.value]]),t("button",{class:"primary",disabled:r.value||!R.value.length,onClick:ce}," AI 自动分配待配置 ",8,Pe),t("button",{disabled:r.value,onClick:ie},"刷新",8,Re)])]),t("nav",Ve,[t("button",{class:w({active:f.value==="roles"}),onClick:l[1]||(l[1]=e=>f.value="roles")},"角色",2),t("button",{class:w({active:f.value==="pending"}),onClick:l[2]||(l[2]=e=>f.value="pending")},"待配置",2),t("button",{class:w({active:f.value==="commands"}),onClick:l[3]||(l[3]=e=>f.value="commands")},"指令",2)]),O.value?(s(),u("p",Ae,o(O.value),1)):L("v-if",true),f.value==="roles"?(s(),u("section",Ue,[t("aside",xe,[(s(true),u(k,null,y(P.value,e=>(s(),u("button",{key:e.id,class:w(["role-item",{active:e.id===v.value}]),onClick:i=>v.value=e.id},[t("span",null,[t("strong",null,o(e.name),1),t("small",null,o(e.builtin?"内置角色":"自定义角色")+" / "+o(me(e.scopeType)),1)]),t("em",null,o(e.allowCount),1)],10,Me))),128)),t("form",{class:"role-create",onSubmit:ee(be,["prevent"])},[p(t("input",{"onUpdate:modelValue":l[4]||(l[4]=e=>$.value=e),placeholder:"custom:music-admin"},null,512),[[T,$.value,void 0,{trim:true}]]),p(t("input",{"onUpdate:modelValue":l[5]||(l[5]=e=>U.value=e),placeholder:"角色名称"},null,512),[[T,U.value,void 0,{trim:true}]]),p(t("select",{"onUpdate:modelValue":l[6]||(l[6]=e=>q.value=e)},[...l[21]||(l[21]=[t("option",{value:"guild"},"群内角色",-1),t("option",{value:"global"},"全局角色",-1)])],512),[[C,q.value]]),t("button",{class:"primary",disabled:r.value||!$.value||!U.value},"创建角色",8,Te)],32)]),V.value?(s(),u("section",Oe,[t("div",Ge,[t("div",null,[t("h2",null,o(V.value.name),1),t("p",null,o(V.value.id),1)]),t("div",Ne,[p(t("select",{"onUpdate:modelValue":l[7]||(l[7]=e=>N.value=e)},[l[22]||(l[22]=t("option",{disabled:"",value:""},"复制来源",-1)),(s(true),u(k,null,y(oe.value,e=>(s(),u("option",{key:e.id,value:e.id},o(e.name),9,Be))),128))],512),[[C,N.value]]),t("button",{disabled:r.value||!N.value,onClick:ye},"复制权限",8,De),t("label",Ee,[p(t("input",{type:"checkbox","onUpdate:modelValue":l[8]||(l[8]=e=>K.value=e)},null,512),[[Ce,K.value]]),l[23]||(l[23]=F(" 审计模式 ",-1))])])]),t("section",Le,[t("div",null,[l[24]||(l[24]=t("strong",null,"成员",-1)),t("small",null,o(X.value.length)+" 个显式成员",1)]),t("div",Fe,[(s(true),u(k,null,y(X.value,e=>(s(),u("span",{key:he(e),class:"member-chip"},[F(o(e.platform)+":"+o(e.userId)+" / "+o(e.scope)+" ",1),t("button",{disabled:r.value,onClick:i=>ke(e)},"移除",8,Ke)]))),128))]),t("form",{class:"member-add",onSubmit:ee(fe,["prevent"])},[p(t("input",{"onUpdate:modelValue":l[9]||(l[9]=e=>x.value=e),placeholder:"platform:userId"},null,512),[[T,x.value,void 0,{trim:true}]]),p(t("select",{"onUpdate:modelValue":l[10]||(l[10]=e=>G.value=e)},[l[25]||(l[25]=t("option",{value:"global"},"global",-1)),a.value!=="global"?(s(),u("option",{key:0,value:a.value},o(a.value),9,qe)):L("v-if",true)],512),[[C,G.value]]),t("button",{class:"primary",disabled:r.value||!x.value},"添加成员",8,ze)],32)]),t("div",je,[p(t("input",{"onUpdate:modelValue":l[11]||(l[11]=e=>h.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[T,h.value,void 0,{trim:true}]]),p(t("select",{"onUpdate:modelValue":l[12]||(l[12]=e=>I.value=e)},[...l[26]||(l[26]=[t("option",{value:"all"},"全部状态",-1),t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],512),[[C,I.value]])]),t("div",He,[(s(true),u(k,null,y(ue.value,e=>(s(),u("article",{key:e.id,class:"command-row"},[t("div",Je,[t("strong",null,o(e.name),1),t("span",null,o(e.commandPath),1),t("small",null,o(e.plugin)+" / legacy "+o(e.legacyAuthority)+" / "+o(e.suggestion.label),1)]),t("div",Qe,[t("button",{class:w({active:j(e.id)==="inherit"}),onClick:i=>H(e.id,"inherit")}," 继承 ",10,We),t("button",{class:w({active:j(e.id)==="allow"}),onClick:i=>H(e.id,"allow")}," 开 ",10,Xe),t("button",{class:w({active:j(e.id)==="deny"}),onClick:i=>H(e.id,"deny")}," 关 ",10,Ye)])]))),128))])])):L("v-if",true)])):f.value==="pending"?(s(),u("section",Ze,[(s(true),u(k,null,y(R.value,e=>(s(),u("article",{key:e.id,class:"pending-item"},[t("div",null,[t("strong",null,o(e.name),1),t("span",null,o(e.commandPath),1),t("small",null,o(e.plugin)+" / legacy "+o(e.legacyAuthority),1)]),t("dl",null,[l[27]||(l[27]=t("dt",null,"旧建议",-1)),t("dd",null,o(e.suggestion.label),1),l[28]||(l[28]=t("dt",null,"AI 建议",-1)),t("dd",null,o(e.autoAssign.label)+":"+o(e.autoAssign.reason),1)]),t("div",el,[(s(true),u(k,null,y(P.value,i=>(s(),u("label",{key:`${e.id}:${i.id}`,class:"check"},[t("input",{type:"checkbox",checked:de(e,i.id),onChange:J=>re(e,i.id,J)},null,40,ll),F(" "+o(i.name),1)]))),128))]),t("div",tl,[t("button",{disabled:r.value,onClick:i=>Z(e,"legacy")},"填入旧建议",8,nl),t("button",{disabled:r.value,onClick:i=>Z(e,"advisor")},"填入 AI 建议",8,ol),t("button",{class:"primary",disabled:r.value,onClick:i=>ve(e)},"保存分配",8,sl)])]))),128)),R.value.length?L("v-if",true):(s(),u("p",ul,"没有待配置指令。"))])):(s(),u("section",il,[t("div",al,[p(t("input",{"onUpdate:modelValue":l[13]||(l[13]=e=>h.value=e),placeholder:"搜索指令、插件、描述"},null,512),[[T,h.value,void 0,{trim:true}]]),p(t("select",{"onUpdate:modelValue":l[14]||(l[14]=e=>I.value=e)},[...l[29]||(l[29]=[t("option",{value:"all"},"全部状态",-1),t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],512),[[C,I.value]])]),t("div",dl,[p(t("select",{"onUpdate:modelValue":l[15]||(l[15]=e=>m.value=e)},[l[30]||(l[30]=t("option",{disabled:"",value:""},"选择插件",-1)),(s(true),u(k,null,y(se.value,e=>(s(),u("option",{key:e,value:e},o(e),9,rl))),128))],512),[[C,m.value]]),t("button",{disabled:r.value||!m.value,onClick:l[16]||(l[16]=e=>E("legacy"))},"采用插件建议",8,vl),t("button",{disabled:r.value||!m.value,onClick:l[17]||(l[17]=e=>E("guild-member"))},"给群成员",8,cl),t("button",{disabled:r.value||!m.value,onClick:l[18]||(l[18]=e=>E("guild-admin"))},"给群管理员",8,pl),t("button",{disabled:r.value||!m.value,onClick:l[19]||(l[19]=e=>E("bot-admin"))},"仅 Bot 管理员",8,gl)]),(s(true),u(k,null,y(Y.value,e=>(s(),u("article",{key:e.id,class:"command-row"},[t("div",bl,[t("strong",null,o(e.name),1),t("span",null,o(e.id),1),t("small",null,o(e.plugin)+" / "+o(e.commandPath)+" / "+o(e.autoAssign.label),1)]),t("div",fl,[t("label",kl,[t("input",{type:"checkbox",checked:e.allowGuildOverride,onChange:i=>pe(e,i)},null,40,yl),l[31]||(l[31]=F(" 群内自治 ",-1))]),t("select",{value:e.status,onChange:i=>ge(e,i)},[...l[32]||(l[32]=[t("option",{value:"pending"},"待配置",-1),t("option",{value:"configured"},"已配置",-1),t("option",{value:"disabled"},"已禁用",-1)])],40,hl)])]))),128))]))]))}}),_l=(A,f)=>{const a=A.__vccOpts||A;for(const[v,h]of f)a[v]=h;return a},Cl=_l(ml,[["__scopeId","data-v-6014eba6"]]),$l=A=>{A.page({name:"新权限",path:"/new-auth",icon:"⌗",fields:["newauth"],authority:4,component:Cl})};export{$l as default};
|
|
1
|
+
import{defineComponent as Te,ref as c,computed as b,watch as Q,resolveComponent as W,openBlock as u,createElementBlock as a,createElementVNode as l,toDisplayString as n,withDirectives as k,Fragment as w,renderList as C,vModelSelect as P,createVNode as i,withCtx as d,createTextVNode as v,createCommentVNode as U,normalizeClass as X,vModelText as F,vModelCheckbox as Oe}from"vue";import{store as ge,send as _}from"@koishijs/client";const Ge={class:"new-auth-page"},Le={class:"page-head"},Be={class:"head-actions"},De={class:"scope-control"},Ee=["value"],Fe={class:"summary-grid"},Ke={class:"summary-item"},je={class:"summary-item"},qe={class:"summary-item warning"},ze={class:"summary-item"},He={key:0,class:"error"},Je={key:1,class:"role-workspace"},Qe={class:"role-rail"},We={class:"rail-title"},Xe=["onClick"],Ye={class:"role-copy"},Ze={class:"role-count"},el={class:"disclosure"},ll={class:"stack compact"},tl={key:0,class:"role-detail"},sl={class:"card-title"},nl={class:"scope-badge"},ol={class:"role-facts"},ul={class:"card-title"},al={class:"inline-check"},il={class:"filters"},dl={class:"search-box"},rl={class:"command-list"},vl={class:"command-main"},cl={class:"state-buttons"},pl=["onClick"],gl=["onClick"],fl=["onClick"],bl={key:0,class:"empty"},ml={class:"disclosure advanced"},kl={class:"advanced-grid"},yl={class:"sub-panel"},_l={class:"sub-head"},hl={class:"member-list"},wl=["disabled","onClick"],Cl={key:0,class:"muted"},Il={class:"inline-form"},Sl=["value"],Al={class:"sub-panel"},$l={class:"sub-head"},Vl={class:"inline-form"},Rl=["value"],Pl={key:2,class:"pending-stack"},Ml={class:"card-title"},xl={class:"ai-controls"},Ul=["disabled"],Nl=["value"],Tl={key:0,class:"review-table"},Ol={class:"pending-list"},Gl={class:"pending-main"},Ll={class:"command-main"},Bl={class:"role-picker"},Dl=["checked","onChange"],El={class:"inline-disclosure"},Fl={class:"row-actions"},Kl={key:0,class:"empty"},jl={key:3,class:"audit-stack"},ql={class:"disclosure advanced"},zl={class:"bulk-panel"},Hl=["value"],Jl={class:"card-title"},Ql={class:"filters"},Wl={class:"search-box"},Xl={class:"audit-list"},Yl={class:"command-main"},Zl={class:"audit-controls"},et={class:"inline-check"},lt=["checked","onChange"],tt=["value","onChange"],st=Te({__name:"new-auth",setup(L){const N=c("roles"),r=c("global"),m=c(""),M=c(""),T=c("all"),Y=c(false),g=c(false),K=c(""),O=c(""),B=c(""),Z=c("guild"),D=c(""),j=c("global"),q=c(""),x=c(""),A=c(""),$=c({}),ee=c({}),h=b(()=>ge.newauth||{roles:[],commands:[],policies:[],members:[],scopes:[{id:"global",name:"全局默认"}],pendingCount:0,autoAssignAvailable:false,aiModels:[],defaultAiModel:""}),V=b(()=>h.value.roles),E=b(()=>h.value.commands),le=b(()=>h.value.policies),fe=b(()=>h.value.members),de=b(()=>{var s;return(s=h.value.scopes)!=null&&s.length?h.value.scopes:[{id:"global",name:"全局默认"}]}),re=b(()=>h.value.aiModels||[]),te=b(()=>{var s;return((s=de.value.find(e=>e.id===r.value))==null?void 0:s.name)||r.value}),I=b(()=>E.value.filter(s=>s.status==="pending")),ve=b(()=>I.value.filter(s=>ee.value[s.id])),S=b(()=>V.value.find(s=>s.id===m.value)),se=b(()=>fe.value.filter(s=>s.roleId===m.value)),be=b(()=>V.value.filter(s=>s.id!==m.value)),me=b(()=>[...new Set(E.value.map(s=>s.plugin))].sort());Q(V,s=>{!m.value&&s.length&&(m.value=s[0].id)},{immediate:true}),Q(r,s=>{j.value=s==="global"?"global":s}),Q(h,s=>{var e,o;A.value||(A.value=s.defaultAiModel||((o=(e=s.aiModels)==null?void 0:e[0])==null?void 0:o.id)||"")},{immediate:true}),Q([I,le,r],()=>{for(const s of I.value)z(s)},{immediate:true});const ne=b(()=>{const s=M.value.toLowerCase();return E.value.filter(e=>T.value!=="all"&&e.status!==T.value?false:s?[e.id,e.name,e.commandPath,e.plugin,e.description].some(o=>o==null?void 0:o.toLowerCase().includes(s)):true)}),oe=b(()=>S.value?ne.value.filter(s=>{var e,o;return Y.value||((e=S.value)==null?void 0:e.id)==="bot-admin"||((o=S.value)==null?void 0:o.scopeType)==="global"?true:s.allowGuildOverride}):[]);function ue(s){const e=le.value.find(o=>o.scope===r.value&&o.roleId===m.value&&o.commandId===s);return(e==null?void 0:e.state)||"inherit"}async function y(s){g.value=true,K.value="";try{await s}catch(e){K.value=e instanceof Error?e.message:String(e)}finally{g.value=false}}async function ke(){return y((async()=>{const s=await _("newauth/getData");ge.newauth=s})())}function ae(s,e){return y(_("newauth/setPolicy",{scope:r.value,roleId:m.value,commandId:s,state:e}))}function G(s){return`${r.value}:${s}`}function ye(s){const e=le.value.filter(o=>o.scope===r.value&&o.commandId===s.id&&o.state==="allow").map(o=>o.roleId);return e.length?e:[...s.suggestion.roles]}function z(s){const e=G(s.id);$.value[e]||($.value[e]=ye(s))}function _e(s,e){return z(s),$.value[G(s.id)].includes(e)}function he(s,e,o){z(s);const p=G(s.id),ie=o.target.checked,R=new Set($.value[p]);ie?R.add(e):R.delete(e),$.value[p]=[...R]}function we(s,e){$.value[G(s.id)]=[...s.suggestion.roles]}function H(s){return ee.value[s.id]||s.autoAssign}function Ce(s){return H(s).roles.map(e=>{var o;return((o=V.value.find(p=>p.id===e))==null?void 0:o.name)||e}).join("、")||"无"}function ce(s,e){ee.value[s.id]=e,$.value[G(s.id)]=[...e.roles]}function Ie(s){return y((async()=>{const e=await _("newauth/generateAiSuggestion",{commandId:s.id,model:A.value});ce(s,e)})())}function Se(){return y((async()=>{const s=await _("newauth/generateAiSuggestions",{model:A.value});for(const e of I.value){const o=s.suggestions[e.id];o&&ce(e,o)}})())}function Ae(s){return z(s),y(_("newauth/configureCommandRoles",{commandId:s.id,scope:r.value,roleIds:$.value[G(s.id)]}))}function $e(s,e){const o=e.target;return y(_("newauth/setGuildOverride",{commandId:s.id,allowGuildOverride:o.checked}))}function Ve(s,e){const o=e.target;return y(_("newauth/setCommandStatus",{commandId:s.id,status:o.value}))}function Re(){return y((async()=>{await _("newauth/createRole",{id:O.value,name:B.value,scopeType:Z.value}),m.value=O.value,O.value="",B.value=""})())}function Pe(){return y((async()=>{await _("newauth/addMember",{roleId:m.value,uid:D.value,scope:j.value}),D.value=""})())}function Me(s){return y(_("newauth/removeMember",{roleId:s.roleId,uid:`${s.platform}:${s.userId}`,scope:s.scope}))}function xe(){return y(_("newauth/copyRolePolicies",{sourceRoleId:q.value,targetRoleId:m.value,scope:r.value}))}function Ue(s){return`${s.roleId}:${s.platform}:${s.userId}:${s.scope}`}function J(s){return y(_("newauth/assignPluginCommands",{plugin:x.value,scope:r.value,target:s}))}function pe(s){return s==="global"?"全局":"群内"}return(s,e)=>{const o=W("k-icon"),p=W("k-button"),ie=W("k-tab"),R=W("k-card");return u(),a("main",Ge,[l("header",Le,[l("div",null,[e[19]||(e[19]=l("h1",null,"新权限",-1)),l("p",null,n(te.value)+" / "+n(I.value.length)+" 个待配置指令",1)]),l("div",Be,[l("label",De,[e[20]||(e[20]=l("span",null,"范围",-1)),k(l("select",{"onUpdate:modelValue":e[0]||(e[0]=t=>r.value=t),class:"control"},[(u(true),a(w,null,C(de.value,t=>(u(),a("option",{key:t.id,value:t.id},n(t.name),9,Ee))),128))],512),[[P,r.value]])]),i(p,{disabled:g.value,onClick:ke},{default:d(()=>[i(o,{name:"redo"}),e[21]||(e[21]=v(" 刷新 ",-1))]),_:1},8,["disabled"])])]),l("section",Fe,[l("div",Ke,[e[22]||(e[22]=l("span",null,"角色",-1)),l("strong",null,n(V.value.length),1)]),l("div",je,[e[23]||(e[23]=l("span",null,"指令",-1)),l("strong",null,n(E.value.length),1)]),l("div",qe,[e[24]||(e[24]=l("span",null,"待配置",-1)),l("strong",null,n(I.value.length),1)]),l("div",ze,[e[25]||(e[25]=l("span",null,"AI",-1)),l("strong",null,n(h.value.autoAssignAvailable?"可用":"未接入"),1)])]),i(ie,{modelValue:N.value,"onUpdate:modelValue":e[1]||(e[1]=t=>N.value=t),data:{roles:"角色",pending:"待配置",commands:"指令审计"}},null,8,["modelValue"]),K.value?(u(),a("p",He,n(K.value),1)):U("v-if",true),N.value==="roles"?(u(),a("section",Je,[l("aside",Qe,[l("div",We,[e[26]||(e[26]=l("strong",null,"角色",-1)),l("span",null,n(V.value.length),1)]),(u(true),a(w,null,C(V.value,t=>(u(),a("button",{key:t.id,class:X(["role-item",{active:t.id===m.value}]),onClick:f=>m.value=t.id},[l("span",Ye,[l("strong",null,n(t.name),1),l("small",null,n(t.builtin?"内置":"自定义")+" / "+n(pe(t.scopeType)),1)]),l("span",Ze,n(t.allowCount),1)],10,Xe))),128)),l("details",el,[l("summary",null,[i(o,{name:"user"}),e[27]||(e[27]=v(" 新建角色 ",-1))]),l("div",ll,[k(l("input",{"onUpdate:modelValue":e[2]||(e[2]=t=>O.value=t),class:"control",placeholder:"custom:music-admin"},null,512),[[F,O.value,void 0,{trim:true}]]),k(l("input",{"onUpdate:modelValue":e[3]||(e[3]=t=>B.value=t),class:"control",placeholder:"角色名称"},null,512),[[F,B.value,void 0,{trim:true}]]),k(l("select",{"onUpdate:modelValue":e[4]||(e[4]=t=>Z.value=t),class:"control"},[...e[28]||(e[28]=[l("option",{value:"guild"},"群内角色",-1),l("option",{value:"global"},"全局角色",-1)])],512),[[P,Z.value]]),i(p,{solid:"",disabled:g.value||!O.value||!B.value,onClick:Re},{default:d(()=>[i(o,{name:"check-full"}),e[29]||(e[29]=v(" 创建 ",-1))]),_:1},8,["disabled"])])])]),S.value?(u(),a("section",tl,[i(R,{class:"role-summary"},{header:d(()=>[l("div",sl,[l("div",null,[l("h2",null,n(S.value.name),1),l("p",null,n(S.value.id),1)]),l("span",nl,n(pe(S.value.scopeType)),1)])]),default:d(()=>[l("div",ol,[l("span",null,n(S.value.builtin?"内置角色":"自定义角色"),1),l("span",null,n(te.value),1),l("span",null,n(S.value.allowCount)+" 个全局允许",1)])]),_:1}),i(R,{class:"permission-card"},{header:d(()=>[l("div",ul,[l("div",null,[e[30]||(e[30]=l("h2",null,"指令权限",-1)),l("p",null,n(oe.value.length)+" 个当前可见指令",1)]),l("label",al,[k(l("input",{type:"checkbox","onUpdate:modelValue":e[5]||(e[5]=t=>Y.value=t)},null,512),[[Oe,Y.value]]),e[31]||(e[31]=v(" 审计模式 ",-1))])])]),default:d(()=>[l("div",il,[l("label",dl,[i(o,{name:"search"}),k(l("input",{"onUpdate:modelValue":e[6]||(e[6]=t=>M.value=t),placeholder:"搜索指令、插件、描述"},null,512),[[F,M.value,void 0,{trim:true}]])]),k(l("select",{"onUpdate:modelValue":e[7]||(e[7]=t=>T.value=t),class:"control"},[...e[32]||(e[32]=[l("option",{value:"all"},"全部状态",-1),l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],512),[[P,T.value]])]),l("div",rl,[(u(true),a(w,null,C(oe.value,t=>(u(),a("article",{key:t.id,class:"command-row"},[l("div",vl,[l("strong",null,n(t.name),1),l("span",null,n(t.commandPath),1),l("small",null,n(t.plugin)+" / "+n(t.suggestion.label),1)]),l("div",cl,[l("button",{class:X({active:ue(t.id)==="inherit"}),onClick:f=>ae(t.id,"inherit")}," 继承 ",10,pl),l("button",{class:X({active:ue(t.id)==="allow"}),onClick:f=>ae(t.id,"allow")}," 开 ",10,gl),l("button",{class:X({active:ue(t.id)==="deny"}),onClick:f=>ae(t.id,"deny")}," 关 ",10,fl)])]))),128)),oe.value.length?U("v-if",true):(u(),a("p",bl,"没有匹配的指令。"))])]),_:1}),l("details",ml,[l("summary",null,[i(o,{name:"tools"}),e[33]||(e[33]=v(" 高级管理 ",-1))]),l("div",kl,[l("section",yl,[l("div",_l,[e[34]||(e[34]=l("strong",null,"显式成员",-1)),l("span",null,n(se.value.length),1)]),l("div",hl,[(u(true),a(w,null,C(se.value,t=>(u(),a("span",{key:Ue(t),class:"member-chip"},[v(n(t.platform)+":"+n(t.userId)+" / "+n(t.scope)+" ",1),l("button",{disabled:g.value,onClick:f=>Me(t)},"移除",8,wl)]))),128)),se.value.length?U("v-if",true):(u(),a("p",Cl,"无显式成员。"))]),l("div",Il,[k(l("input",{"onUpdate:modelValue":e[8]||(e[8]=t=>D.value=t),class:"control",placeholder:"platform:userId"},null,512),[[F,D.value,void 0,{trim:true}]]),k(l("select",{"onUpdate:modelValue":e[9]||(e[9]=t=>j.value=t),class:"control"},[e[35]||(e[35]=l("option",{value:"global"},"global",-1)),r.value!=="global"?(u(),a("option",{key:0,value:r.value},n(r.value),9,Sl)):U("v-if",true)],512),[[P,j.value]]),i(p,{solid:"",disabled:g.value||!D.value,onClick:Pe},{default:d(()=>[...e[36]||(e[36]=[v("添加",-1)])]),_:1},8,["disabled"])])]),l("section",Al,[l("div",$l,[e[37]||(e[37]=l("strong",null,"复制权限",-1)),l("span",null,n(te.value),1)]),l("div",Vl,[k(l("select",{"onUpdate:modelValue":e[10]||(e[10]=t=>q.value=t),class:"control"},[e[38]||(e[38]=l("option",{disabled:"",value:""},"复制来源",-1)),(u(true),a(w,null,C(be.value,t=>(u(),a("option",{key:t.id,value:t.id},n(t.name),9,Rl))),128))],512),[[P,q.value]]),i(p,{disabled:g.value||!q.value,onClick:xe},{default:d(()=>[i(o,{name:"clipboard-list"}),e[39]||(e[39]=v(" 复制 ",-1))]),_:1},8,["disabled"])])])])])])):U("v-if",true)])):N.value==="pending"?(u(),a("section",Pl,[i(R,null,{header:d(()=>[l("div",Ml,[l("div",null,[e[40]||(e[40]=l("h2",null,"待配置指令",-1)),l("p",null,n(I.value.length)+" 个新增指令等待实例管理员确认",1)]),l("div",xl,[k(l("select",{"onUpdate:modelValue":e[11]||(e[11]=t=>A.value=t),class:"control",disabled:g.value||!re.value.length},[e[41]||(e[41]=l("option",{disabled:"",value:""},"选择 ChatLuna 模型",-1)),(u(true),a(w,null,C(re.value,t=>(u(),a("option",{key:t.id,value:t.id},n(t.id),9,Nl))),128))],8,Ul),[[P,A.value]]),i(p,{solid:"",disabled:g.value||!I.value.length||!h.value.autoAssignAvailable||!A.value,onClick:Se},{default:d(()=>[i(o,{name:"start"}),e[42]||(e[42]=v(" AI 生成审查表 ",-1))]),_:1},8,["disabled"])])])]),default:d(()=>[ve.value.length?(u(),a("table",Tl,[e[43]||(e[43]=l("thead",null,[l("tr",null,[l("th",null,"指令"),l("th",null,"建议角色"),l("th",null,"理由")])],-1)),l("tbody",null,[(u(true),a(w,null,C(ve.value,t=>(u(),a("tr",{key:`review:${t.id}`},[l("td",null,n(t.commandPath),1),l("td",null,n(Ce(t)),1),l("td",null,n(H(t).reason),1)]))),128))])])):U("v-if",true),l("div",Ol,[(u(true),a(w,null,C(I.value,t=>(u(),a("article",{key:t.id,class:"pending-row"},[l("div",Gl,[l("div",Ll,[l("strong",null,n(t.name),1),l("span",null,n(t.commandPath),1),l("small",null,n(t.plugin)+" / legacy "+n(t.legacyAuthority),1)]),l("dl",null,[e[44]||(e[44]=l("dt",null,"旧建议",-1)),l("dd",null,n(t.suggestion.label),1),e[45]||(e[45]=l("dt",null,"AI",-1)),l("dd",null,n(H(t).label)+":"+n(H(t).reason),1)])]),l("div",Bl,[(u(true),a(w,null,C(V.value,f=>(u(),a("label",{key:`${t.id}:${f.id}`,class:"check-tile"},[l("input",{type:"checkbox",checked:_e(t,f.id),onChange:Ne=>he(t,f.id,Ne)},null,40,Dl),v(" "+n(f.name),1)]))),128))]),l("details",El,[e[46]||(e[46]=l("summary",null,"元数据",-1)),l("code",null,n(t.id),1),l("p",null,n(t.description||"无描述"),1)]),l("div",Fl,[i(p,{disabled:g.value,onClick:f=>we(t)},{default:d(()=>[...e[47]||(e[47]=[v("填入旧建议",-1)])]),_:1},8,["disabled","onClick"]),i(p,{disabled:g.value||!h.value.autoAssignAvailable||!A.value,onClick:f=>Ie(t)},{default:d(()=>[i(o,{name:"start"}),e[48]||(e[48]=v(" AI 建议 ",-1))]),_:1},8,["disabled","onClick"]),i(p,{solid:"",disabled:g.value,onClick:f=>Ae(t)},{default:d(()=>[i(o,{name:"check-full"}),e[49]||(e[49]=v(" 保存分配 ",-1))]),_:1},8,["disabled","onClick"])])]))),128)),I.value.length?U("v-if",true):(u(),a("p",Kl,"没有待配置指令。"))])]),_:1})])):(u(),a("section",jl,[l("details",ql,[l("summary",null,[i(o,{name:"tools"}),e[50]||(e[50]=v(" 批量操作 ",-1))]),l("div",zl,[k(l("select",{"onUpdate:modelValue":e[12]||(e[12]=t=>x.value=t),class:"control"},[e[51]||(e[51]=l("option",{disabled:"",value:""},"选择插件",-1)),(u(true),a(w,null,C(me.value,t=>(u(),a("option",{key:t,value:t},n(t),9,Hl))),128))],512),[[P,x.value]]),i(p,{disabled:g.value||!x.value,onClick:e[13]||(e[13]=t=>J("legacy"))},{default:d(()=>[...e[52]||(e[52]=[v("采用插件建议",-1)])]),_:1},8,["disabled"]),i(p,{disabled:g.value||!x.value,onClick:e[14]||(e[14]=t=>J("guild-member"))},{default:d(()=>[...e[53]||(e[53]=[v("给群成员",-1)])]),_:1},8,["disabled"]),i(p,{disabled:g.value||!x.value,onClick:e[15]||(e[15]=t=>J("guild-admin"))},{default:d(()=>[...e[54]||(e[54]=[v("给群管理员",-1)])]),_:1},8,["disabled"]),i(p,{disabled:g.value||!x.value,onClick:e[16]||(e[16]=t=>J("bot-admin"))},{default:d(()=>[...e[55]||(e[55]=[v("仅 Bot 管理员",-1)])]),_:1},8,["disabled"])])]),i(R,null,{header:d(()=>[l("div",Jl,[l("div",null,[e[56]||(e[56]=l("h2",null,"指令审计",-1)),l("p",null,n(ne.value.length)+" / "+n(E.value.length),1)])])]),default:d(()=>[l("div",Ql,[l("label",Wl,[i(o,{name:"search"}),k(l("input",{"onUpdate:modelValue":e[17]||(e[17]=t=>M.value=t),placeholder:"搜索指令、插件、描述"},null,512),[[F,M.value,void 0,{trim:true}]])]),k(l("select",{"onUpdate:modelValue":e[18]||(e[18]=t=>T.value=t),class:"control"},[...e[57]||(e[57]=[l("option",{value:"all"},"全部状态",-1),l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],512),[[P,T.value]])]),l("div",Xl,[(u(true),a(w,null,C(ne.value,t=>(u(),a("article",{key:t.id,class:"audit-row"},[l("div",Yl,[l("strong",null,n(t.name),1),l("span",null,n(t.commandPath),1),l("small",null,n(t.plugin)+" / "+n(t.id),1)]),l("div",Zl,[l("label",et,[l("input",{type:"checkbox",checked:t.allowGuildOverride,onChange:f=>$e(t,f)},null,40,lt),e[58]||(e[58]=v(" 群内自治 ",-1))]),l("select",{value:t.status,class:"control",onChange:f=>Ve(t,f)},[...e[59]||(e[59]=[l("option",{value:"pending"},"待配置",-1),l("option",{value:"configured"},"已配置",-1),l("option",{value:"disabled"},"已禁用",-1)])],40,tt)])]))),128))])]),_:1})]))])}}}),nt=(L,N)=>{const r=L.__vccOpts||L;for(const[m,M]of N)r[m]=M;return r},ot=nt(st,[["__scopeId","data-v-3935e256"]]),it=L=>{L.page({name:"新权限",path:"/new-auth",icon:"⌗",fields:["newauth"],authority:4,component:ot})};export{it as default};
|
package/dist/style.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.new-auth-page[data-v-6014eba6]{min-height:100vh;background:#eef2f6;color:#18222d;padding:20px}.topbar[data-v-6014eba6],.detail-head[data-v-6014eba6],.filters[data-v-6014eba6],.row-actions[data-v-6014eba6],.command-controls[data-v-6014eba6],.top-actions[data-v-6014eba6],.detail-tools[data-v-6014eba6],.member-add[data-v-6014eba6],.plugin-bulk[data-v-6014eba6]{display:flex;align-items:center;gap:12px}.topbar[data-v-6014eba6]{justify-content:space-between;border:1px solid #d7dee8;border-radius:8px;background:#fff;box-shadow:0 8px 24px #20304814;padding:16px}h1[data-v-6014eba6],h2[data-v-6014eba6],p[data-v-6014eba6]{margin:0}h1[data-v-6014eba6]{font-size:26px;line-height:1.2}h2[data-v-6014eba6]{font-size:20px}p[data-v-6014eba6],small[data-v-6014eba6],span[data-v-6014eba6],dd[data-v-6014eba6],dt[data-v-6014eba6]{color:#607083}button[data-v-6014eba6],select[data-v-6014eba6],input[data-v-6014eba6]{border:1px solid #c9d3df;border-radius:6px;background:#fff;color:#18222d;min-height:34px;padding:0 10px;font:inherit}button[data-v-6014eba6]{cursor:pointer;transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}button[data-v-6014eba6]:not(:disabled):hover,select[data-v-6014eba6]:focus,input[data-v-6014eba6]:focus{border-color:#2d6cdf;box-shadow:0 0 0 3px #2d6cdf1f;outline:none}button[data-v-6014eba6]:disabled{cursor:not-allowed;opacity:.55}.primary[data-v-6014eba6]{background:#1d6f68;border-color:#1d6f68;color:#fff}.tabs[data-v-6014eba6]{display:flex;gap:6px;margin:16px 0}.tabs button[data-v-6014eba6]{background:#f8fafc}.tabs button.active[data-v-6014eba6],.state-buttons button.active[data-v-6014eba6]{background:#17202b;border-color:#17202b;color:#fff}.role-layout[data-v-6014eba6]{display:grid;grid-template-columns:minmax(220px,280px) 1fr;gap:16px}.role-list[data-v-6014eba6]{display:grid;gap:8px;align-content:start}.role-create[data-v-6014eba6]{display:grid;gap:8px;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:10px;box-shadow:0 4px 14px #2030480d}.role-item[data-v-6014eba6]{display:flex;justify-content:space-between;align-items:center;min-height:58px;text-align:left}.role-item span[data-v-6014eba6],.command-main[data-v-6014eba6]{display:grid;gap:3px;min-width:0}.role-item.active[data-v-6014eba6]{border-color:#2d6cdf;box-shadow:inset 3px 0 #2d6cdf,0 4px 14px #2d6cdf1f}.role-item em[data-v-6014eba6]{font-style:normal;color:#9a5a00}.detail[data-v-6014eba6]{min-width:0}.detail-head[data-v-6014eba6]{justify-content:space-between;margin-bottom:12px}.detail-tools[data-v-6014eba6]{flex-wrap:wrap;justify-content:flex-end}.member-panel[data-v-6014eba6]{display:grid;gap:10px;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:12px;margin-bottom:12px;box-shadow:0 4px 14px #2030480d}.member-panel>div[data-v-6014eba6]:first-child{display:flex;justify-content:space-between;gap:12px}.member-list[data-v-6014eba6]{display:flex;flex-wrap:wrap;gap:6px;min-height:28px}.member-chip[data-v-6014eba6]{display:inline-flex;align-items:center;gap:6px;border:1px solid #c9d3df;border-radius:999px;background:#f8fafc;padding:3px 4px 3px 10px}.member-chip button[data-v-6014eba6]{min-height:24px;padding:0 8px;border-radius:999px}.filters[data-v-6014eba6]{margin-bottom:12px}.plugin-bulk[data-v-6014eba6]{flex-wrap:wrap;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:10px;margin-bottom:12px;box-shadow:0 4px 14px #2030480d}.filters input[data-v-6014eba6]{flex:1;min-width:180px}.command-list[data-v-6014eba6],.pending-grid[data-v-6014eba6],.commands-table[data-v-6014eba6]{display:grid;gap:8px}.command-row[data-v-6014eba6],.pending-item[data-v-6014eba6]{background:#fff;border:1px solid #d7dee8;border-radius:8px;padding:12px;box-shadow:0 4px 14px #2030480d}.command-row[data-v-6014eba6]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center}.command-main strong[data-v-6014eba6],.command-main span[data-v-6014eba6],.command-main small[data-v-6014eba6]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.state-buttons[data-v-6014eba6]{display:grid;grid-template-columns:repeat(3,54px);gap:6px}.pending-grid[data-v-6014eba6]{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.pending-item[data-v-6014eba6]{display:grid;gap:10px}.role-picker[data-v-6014eba6]{display:grid;grid-template-columns:repeat(auto-fill,minmax(128px,1fr));gap:8px}.role-picker .check[data-v-6014eba6]{border:1px solid #d7dee8;border-radius:6px;background:#f8fafc;min-height:32px;padding:0 8px}dl[data-v-6014eba6]{display:grid;grid-template-columns:58px 1fr;gap:4px 8px;margin:0}dd[data-v-6014eba6]{margin:0}.check[data-v-6014eba6]{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.check input[data-v-6014eba6]{min-height:0}.error[data-v-6014eba6]{border:1px solid #e2a15d;background:#fff6e9;color:#85510d;border-radius:6px;padding:10px;margin-bottom:12px}.empty[data-v-6014eba6]{padding:24px 0}@media (max-width: 760px){.new-auth-page[data-v-6014eba6]{padding:12px}.topbar[data-v-6014eba6],.detail-head[data-v-6014eba6],.command-row[data-v-6014eba6]{grid-template-columns:1fr;display:grid}.top-actions[data-v-6014eba6],.filters[data-v-6014eba6],.command-controls[data-v-6014eba6],.detail-tools[data-v-6014eba6],.member-add[data-v-6014eba6],.plugin-bulk[data-v-6014eba6]{flex-wrap:wrap}.role-layout[data-v-6014eba6]{grid-template-columns:1fr}.state-buttons[data-v-6014eba6]{grid-template-columns:repeat(3,minmax(0,1fr))}}
|
|
1
|
+
.new-auth-page[data-v-3935e256]{min-height:100vh;background:#eef2f6;color:#18222d;padding:20px}.topbar[data-v-3935e256],.detail-head[data-v-3935e256],.filters[data-v-3935e256],.row-actions[data-v-3935e256],.command-controls[data-v-3935e256],.top-actions[data-v-3935e256],.detail-tools[data-v-3935e256],.member-add[data-v-3935e256],.plugin-bulk[data-v-3935e256]{display:flex;align-items:center;gap:12px}.topbar[data-v-3935e256]{justify-content:space-between;border:1px solid #d7dee8;border-radius:8px;background:#fff;box-shadow:0 8px 24px #20304814;padding:16px}h1[data-v-3935e256],h2[data-v-3935e256],p[data-v-3935e256]{margin:0}h1[data-v-3935e256]{font-size:26px;line-height:1.2}h2[data-v-3935e256]{font-size:20px}p[data-v-3935e256],small[data-v-3935e256],span[data-v-3935e256],dd[data-v-3935e256],dt[data-v-3935e256]{color:#607083}button[data-v-3935e256],select[data-v-3935e256],input[data-v-3935e256]{border:1px solid #c9d3df;border-radius:6px;background:#fff;color:#18222d;min-height:34px;padding:0 10px;font:inherit}button[data-v-3935e256]{cursor:pointer;transition:border-color .16s ease,box-shadow .16s ease,background .16s ease}button[data-v-3935e256]:not(:disabled):hover,select[data-v-3935e256]:focus,input[data-v-3935e256]:focus{border-color:#2d6cdf;box-shadow:0 0 0 3px #2d6cdf1f;outline:none}button[data-v-3935e256]:disabled{cursor:not-allowed;opacity:.55}.primary[data-v-3935e256]{background:#1d6f68;border-color:#1d6f68;color:#fff}.tabs[data-v-3935e256]{display:flex;gap:6px;margin:16px 0}.tabs button[data-v-3935e256]{background:#f8fafc}.tabs button.active[data-v-3935e256],.state-buttons button.active[data-v-3935e256]{background:#17202b;border-color:#17202b;color:#fff}.role-layout[data-v-3935e256]{display:grid;grid-template-columns:minmax(220px,280px) 1fr;gap:16px}.role-list[data-v-3935e256]{display:grid;gap:8px;align-content:start}.role-create[data-v-3935e256]{display:grid;gap:8px;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:10px;box-shadow:0 4px 14px #2030480d}.role-item[data-v-3935e256]{display:flex;justify-content:space-between;align-items:center;min-height:58px;text-align:left}.role-item span[data-v-3935e256],.command-main[data-v-3935e256]{display:grid;gap:3px;min-width:0}.role-item.active[data-v-3935e256]{border-color:#2d6cdf;box-shadow:inset 3px 0 #2d6cdf,0 4px 14px #2d6cdf1f}.role-item em[data-v-3935e256]{font-style:normal;color:#9a5a00}.detail[data-v-3935e256]{min-width:0}.detail-head[data-v-3935e256]{justify-content:space-between;margin-bottom:12px}.detail-tools[data-v-3935e256]{flex-wrap:wrap;justify-content:flex-end}.member-panel[data-v-3935e256]{display:grid;gap:10px;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:12px;margin-bottom:12px;box-shadow:0 4px 14px #2030480d}.member-panel>div[data-v-3935e256]:first-child{display:flex;justify-content:space-between;gap:12px}.member-list[data-v-3935e256]{display:flex;flex-wrap:wrap;gap:6px;min-height:28px}.member-chip[data-v-3935e256]{display:inline-flex;align-items:center;gap:6px;border:1px solid #c9d3df;border-radius:999px;background:#f8fafc;padding:3px 4px 3px 10px}.member-chip button[data-v-3935e256]{min-height:24px;padding:0 8px;border-radius:999px}.filters[data-v-3935e256]{margin-bottom:12px}.plugin-bulk[data-v-3935e256]{flex-wrap:wrap;border:1px solid #d7dee8;border-radius:8px;background:#fff;padding:10px;margin-bottom:12px;box-shadow:0 4px 14px #2030480d}.filters input[data-v-3935e256]{flex:1;min-width:180px}.command-list[data-v-3935e256],.pending-panel[data-v-3935e256],.commands-table[data-v-3935e256]{display:grid;gap:8px}.command-row[data-v-3935e256],.pending-item[data-v-3935e256]{background:#fff;border:1px solid #d7dee8;border-radius:8px;padding:12px;box-shadow:0 4px 14px #2030480d}.command-row[data-v-3935e256]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center}.state-buttons[data-v-3935e256]{display:grid;grid-template-columns:repeat(3,54px);gap:6px}.pending-panel[data-v-3935e256]{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}.review-table[data-v-3935e256]{grid-column:1 / -1;width:100%;border-collapse:collapse;overflow:hidden;border:1px solid #d7dee8;border-radius:8px;background:#fff;box-shadow:0 4px 14px #2030480d}.review-table th[data-v-3935e256],.review-table td[data-v-3935e256]{border-bottom:1px solid #e5ebf1;padding:10px;text-align:left;vertical-align:top}.review-table th[data-v-3935e256]{background:#f8fafc;color:#314155;font-weight:600}.review-table tr:last-child td[data-v-3935e256]{border-bottom:0}.pending-item[data-v-3935e256]{display:grid;gap:10px}.role-picker[data-v-3935e256]{display:grid;grid-template-columns:repeat(auto-fill,minmax(128px,1fr));gap:8px}.role-picker .check[data-v-3935e256]{border:1px solid #d7dee8;border-radius:6px;background:#f8fafc;min-height:32px;padding:0 8px}dl[data-v-3935e256]{display:grid;grid-template-columns:58px 1fr;gap:4px 8px;margin:0}dd[data-v-3935e256]{margin:0}.check[data-v-3935e256]{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.check input[data-v-3935e256]{min-height:0}.error[data-v-3935e256]{border:1px solid #e2a15d;background:#fff6e9;color:#85510d;border-radius:6px;padding:10px;margin-bottom:12px}.empty[data-v-3935e256]{padding:24px 0}@media (max-width: 760px){.new-auth-page[data-v-3935e256]{padding:12px}.topbar[data-v-3935e256],.detail-head[data-v-3935e256],.command-row[data-v-3935e256]{grid-template-columns:1fr;display:grid}.top-actions[data-v-3935e256],.filters[data-v-3935e256],.command-controls[data-v-3935e256],.detail-tools[data-v-3935e256],.member-add[data-v-3935e256],.plugin-bulk[data-v-3935e256]{flex-wrap:wrap}.role-layout[data-v-3935e256]{grid-template-columns:1fr}.state-buttons[data-v-3935e256]{grid-template-columns:repeat(3,minmax(0,1fr))}}.new-auth-page[data-v-3935e256]{min-height:100vh;box-sizing:border-box;background:var(--k-page-bg);color:var(--k-text-dark);padding:24px}.page-head[data-v-3935e256],.summary-grid[data-v-3935e256],.role-workspace[data-v-3935e256],.card-title[data-v-3935e256],.head-actions[data-v-3935e256],.filters[data-v-3935e256],.row-actions[data-v-3935e256],.audit-controls[data-v-3935e256],.bulk-panel[data-v-3935e256],.inline-form[data-v-3935e256],.ai-controls[data-v-3935e256],.role-facts[data-v-3935e256]{display:flex;align-items:center;gap:12px}.page-head[data-v-3935e256]{justify-content:space-between;margin-bottom:18px}.page-head h1[data-v-3935e256],.card-title h2[data-v-3935e256]{margin:0;color:var(--k-text-dark);letter-spacing:0}.page-head h1[data-v-3935e256]{font-size:26px;line-height:1.2}.page-head p[data-v-3935e256],.card-title p[data-v-3935e256],.muted[data-v-3935e256],small[data-v-3935e256],dt[data-v-3935e256],dd[data-v-3935e256]{margin:0;color:var(--k-text-normal)}.head-actions[data-v-3935e256]{flex-wrap:wrap;justify-content:flex-end}.scope-control[data-v-3935e256]{display:grid;gap:4px;color:var(--k-text-light);font-size:12px}.control[data-v-3935e256],.search-box input[data-v-3935e256],button[data-v-3935e256]{box-sizing:border-box;border:1px solid var(--k-color-border);border-radius:6px;background:var(--k-card-bg);color:var(--k-text-dark);min-height:32px;font:inherit}.control[data-v-3935e256],.search-box input[data-v-3935e256]{padding:0 10px}.control[data-v-3935e256]:focus,.search-box input[data-v-3935e256]:focus{border-color:var(--k-color-active);box-shadow:0 0 0 2px var(--k-color-primary-fade);outline:none}.summary-grid[data-v-3935e256]{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));margin-bottom:18px}.summary-item[data-v-3935e256]{display:grid;gap:6px;border:1px solid var(--k-card-border);border-radius:8px;background:var(--k-card-bg);box-shadow:var(--k-card-shadow);padding:14px 16px}.summary-item span[data-v-3935e256]{color:var(--k-text-normal)}.summary-item strong[data-v-3935e256]{color:var(--k-text-dark);font-size:24px}.summary-item.warning strong[data-v-3935e256]{color:var(--k-color-warning)}.k-horizontal-tab[data-v-3935e256]{display:inline-block;margin:0 0 18px}.role-workspace[data-v-3935e256]{align-items:flex-start;display:grid;grid-template-columns:minmax(220px,280px) minmax(0,1fr);gap:18px}.role-rail[data-v-3935e256],.role-detail[data-v-3935e256],.pending-stack[data-v-3935e256],.audit-stack[data-v-3935e256]{display:grid;gap:12px}.role-rail[data-v-3935e256]{position:sticky;top:16px}.rail-title[data-v-3935e256]{display:flex;justify-content:space-between;color:var(--k-text-normal);padding:0 2px}.role-item[data-v-3935e256]{width:100%;display:flex;justify-content:space-between;align-items:center;gap:12px;min-height:58px;padding:10px 12px;text-align:left;background:var(--k-card-bg);border-color:var(--k-card-border);box-shadow:var(--k-card-shadow)}.role-item[data-v-3935e256]:hover{background:var(--k-hover-bg)}.role-item.active[data-v-3935e256]{border-color:var(--k-color-active);box-shadow:inset 3px 0 0 var(--k-color-active),var(--k-card-shadow)}.role-copy[data-v-3935e256]{display:grid;gap:3px;min-width:0}.role-copy strong[data-v-3935e256],.command-main strong[data-v-3935e256]{color:var(--k-text-dark)}.role-count[data-v-3935e256],.scope-badge[data-v-3935e256]{color:var(--k-color-warning);font-weight:700}.card-title[data-v-3935e256]{justify-content:space-between;width:100%;align-items:flex-start}.role-facts[data-v-3935e256]{flex-wrap:wrap}.role-facts span[data-v-3935e256],.scope-badge[data-v-3935e256]{border:1px solid var(--k-color-divider);border-radius:999px;padding:3px 9px;background:var(--k-hover-bg)}.filters[data-v-3935e256]{margin:0 0 12px}.search-box[data-v-3935e256]{flex:1;display:flex;align-items:center;gap:8px;border:1px solid var(--k-color-border);border-radius:6px;background:var(--k-card-bg);min-width:220px;padding:0 10px}.search-box input[data-v-3935e256]{flex:1;border:0;box-shadow:none;min-width:0;padding:0}.command-list[data-v-3935e256],.pending-list[data-v-3935e256],.audit-list[data-v-3935e256]{display:grid;gap:8px}.command-row[data-v-3935e256],.pending-row[data-v-3935e256],.audit-row[data-v-3935e256]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:12px;align-items:center;border:1px solid var(--k-color-divider);border-radius:8px;background:var(--k-card-bg);padding:12px}.pending-row[data-v-3935e256]{grid-template-columns:minmax(280px,1.1fr) minmax(260px,1fr) auto}.command-main[data-v-3935e256]{display:grid;gap:3px;min-width:0}.command-main strong[data-v-3935e256],.command-main span[data-v-3935e256],.command-main small[data-v-3935e256]{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.state-buttons[data-v-3935e256]{display:grid;grid-template-columns:repeat(3,56px);gap:6px}.state-buttons button[data-v-3935e256]{background:transparent;color:var(--k-text-normal);min-height:30px;padding:0 8px}.state-buttons button.active[data-v-3935e256]{background:var(--k-color-active);border-color:var(--k-color-active);color:#fff}.inline-check[data-v-3935e256],.check-tile[data-v-3935e256]{display:inline-flex;align-items:center;gap:6px;color:var(--k-text-normal);white-space:nowrap}.role-picker[data-v-3935e256]{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:8px}.check-tile[data-v-3935e256]{border:1px solid var(--k-color-divider);border-radius:6px;background:var(--k-hover-bg);min-height:32px;padding:0 8px}.review-table[data-v-3935e256]{margin-bottom:12px;width:100%;border-collapse:collapse;border:1px solid var(--k-color-divider);border-radius:8px;overflow:hidden;background:var(--k-card-bg)}.review-table th[data-v-3935e256],.review-table td[data-v-3935e256]{border-bottom:1px solid var(--k-color-divider);padding:10px 12px;text-align:left;vertical-align:top}.review-table th[data-v-3935e256]{color:var(--k-text-dark);background:var(--k-hover-bg)}dl[data-v-3935e256]{display:grid;grid-template-columns:58px minmax(0,1fr);gap:4px 10px;margin:8px 0 0}dd[data-v-3935e256]{min-width:0}.disclosure[data-v-3935e256]{border:1px solid var(--k-color-divider);border-radius:8px;background:var(--k-card-bg);box-shadow:var(--k-card-shadow);padding:0}.disclosure summary[data-v-3935e256],.inline-disclosure summary[data-v-3935e256]{display:flex;align-items:center;gap:8px;cursor:pointer;color:var(--k-text-dark);padding:10px 12px;-webkit-user-select:none;user-select:none}.stack[data-v-3935e256],.advanced-grid[data-v-3935e256],.bulk-panel[data-v-3935e256]{padding:0 12px 12px}.stack[data-v-3935e256]{display:grid;gap:8px}.advanced-grid[data-v-3935e256]{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}.sub-panel[data-v-3935e256]{display:grid;gap:10px;border:1px solid var(--k-color-divider);border-radius:8px;padding:12px}.sub-head[data-v-3935e256]{display:flex;justify-content:space-between;color:var(--k-text-normal)}.member-list[data-v-3935e256]{display:flex;flex-wrap:wrap;gap:6px}.member-chip[data-v-3935e256]{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--k-color-divider);border-radius:999px;background:var(--k-hover-bg);padding:3px 4px 3px 10px}.member-chip button[data-v-3935e256]{min-height:24px;border-radius:999px;padding:0 8px}.ai-controls[data-v-3935e256],.bulk-panel[data-v-3935e256],.inline-form[data-v-3935e256],.row-actions[data-v-3935e256],.audit-controls[data-v-3935e256]{flex-wrap:wrap;justify-content:flex-end}.ai-controls .control[data-v-3935e256]{min-width:260px}.inline-disclosure[data-v-3935e256]{color:var(--k-text-normal)}.inline-disclosure summary[data-v-3935e256]{padding:0}.inline-disclosure code[data-v-3935e256]{display:block;margin-top:6px;color:var(--k-text-normal);font-family:var(--font-family-code)}.error[data-v-3935e256]{border:1px solid var(--k-color-warning);background:var(--k-color-warning-fade);color:var(--k-color-warning);border-radius:8px;padding:10px 12px;margin-bottom:12px}.empty[data-v-3935e256]{color:var(--k-text-normal);padding:24px 0}@media (max-width: 900px){.summary-grid[data-v-3935e256]{grid-template-columns:repeat(2,minmax(0,1fr))}.role-workspace[data-v-3935e256],.pending-row[data-v-3935e256],.command-row[data-v-3935e256],.audit-row[data-v-3935e256]{grid-template-columns:1fr}.role-rail[data-v-3935e256]{position:static}.card-title[data-v-3935e256],.page-head[data-v-3935e256]{flex-wrap:wrap}}
|
package/lib/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ type RoleType = 'builtin' | 'custom';
|
|
|
9
9
|
type ScopeType = 'global' | 'guild';
|
|
10
10
|
type CommandStatus = 'pending' | 'configured' | 'disabled';
|
|
11
11
|
type PolicyState = 'inherit' | 'allow' | 'deny';
|
|
12
|
-
type AutoAssignKind = '
|
|
12
|
+
type AutoAssignKind = 'ai' | 'legacy';
|
|
13
13
|
type PluginAssignTarget = 'legacy' | 'bot-admin' | 'guild-owner' | 'guild-admin' | 'guild-member';
|
|
14
14
|
export interface NewAuthCommandRecord {
|
|
15
15
|
id: string;
|
|
@@ -75,12 +75,9 @@ declare module '@koishijs/plugin-console' {
|
|
|
75
75
|
'newauth/setGuildOverride'(payload: SetGuildOverridePayload): Promise<{
|
|
76
76
|
success: true;
|
|
77
77
|
}>;
|
|
78
|
-
'newauth/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
'newauth/autoAssignPending'(payload?: AutoAssignPayload): Promise<{
|
|
82
|
-
success: true;
|
|
83
|
-
count: number;
|
|
78
|
+
'newauth/generateAiSuggestion'(payload: AiSuggestionPayload): Promise<AutoAssignSuggestion>;
|
|
79
|
+
'newauth/generateAiSuggestions'(payload?: AiSuggestionsPayload): Promise<{
|
|
80
|
+
suggestions: Record<string, AutoAssignSuggestion>;
|
|
84
81
|
}>;
|
|
85
82
|
'newauth/configureCommandRoles'(payload: ConfigureCommandRolesPayload): Promise<{
|
|
86
83
|
success: true;
|
|
@@ -112,6 +109,8 @@ export interface NewAuthConsoleData {
|
|
|
112
109
|
scopes: ScopeView[];
|
|
113
110
|
pendingCount: number;
|
|
114
111
|
autoAssignAvailable: boolean;
|
|
112
|
+
aiModels: AiModelView[];
|
|
113
|
+
defaultAiModel: string;
|
|
115
114
|
}
|
|
116
115
|
export interface RoleView extends NewAuthRoleRecord {
|
|
117
116
|
allowCount: number;
|
|
@@ -133,6 +132,11 @@ export interface AutoAssignSuggestion extends RoleSuggestion {
|
|
|
133
132
|
kind: AutoAssignKind;
|
|
134
133
|
reason: string;
|
|
135
134
|
}
|
|
135
|
+
export interface AiModelView {
|
|
136
|
+
id: string;
|
|
137
|
+
name: string;
|
|
138
|
+
platform: string;
|
|
139
|
+
}
|
|
136
140
|
interface SetPolicyPayload {
|
|
137
141
|
scope: string;
|
|
138
142
|
roleId: string;
|
|
@@ -147,14 +151,12 @@ interface SetGuildOverridePayload {
|
|
|
147
151
|
commandId: string;
|
|
148
152
|
allowGuildOverride: boolean;
|
|
149
153
|
}
|
|
150
|
-
interface
|
|
154
|
+
interface AiSuggestionPayload {
|
|
151
155
|
commandId: string;
|
|
152
|
-
|
|
153
|
-
mode?: 'legacy' | 'advisor';
|
|
156
|
+
model?: string;
|
|
154
157
|
}
|
|
155
|
-
interface
|
|
156
|
-
|
|
157
|
-
mode?: 'legacy' | 'advisor';
|
|
158
|
+
interface AiSuggestionsPayload {
|
|
159
|
+
model?: string;
|
|
158
160
|
}
|
|
159
161
|
interface ConfigureCommandRolesPayload {
|
|
160
162
|
commandId: string;
|
|
@@ -192,12 +194,16 @@ export declare function apply(ctx: Context, config: Config): void;
|
|
|
192
194
|
export declare class NewAuthService extends Service {
|
|
193
195
|
config: Config;
|
|
194
196
|
private commandCache;
|
|
197
|
+
private commandLocks;
|
|
195
198
|
private adminSet;
|
|
196
199
|
private ownerRoleNames;
|
|
197
200
|
private adminRoleNames;
|
|
198
201
|
constructor(ctx: Context, config: Config);
|
|
199
202
|
start(): Promise<void>;
|
|
200
203
|
registerCommand(command: Command): Promise<string | undefined>;
|
|
204
|
+
private writeCommandRecord;
|
|
205
|
+
private ensureSelfCommandPolicies;
|
|
206
|
+
private cleanupSelfCommandDuplicates;
|
|
201
207
|
intercept(argv: Argv): Promise<string | undefined>;
|
|
202
208
|
canExecute(session: Session, commandId: string): Promise<{
|
|
203
209
|
allowed: boolean;
|
|
@@ -263,9 +269,18 @@ export declare class NewAuthService extends Service {
|
|
|
263
269
|
setCommandStatus(input: string, status: CommandStatus): Promise<NewAuthCommandRecord>;
|
|
264
270
|
setCommandGuildOverride(input: string, allowGuildOverride: boolean): Promise<NewAuthCommandRecord>;
|
|
265
271
|
setCommandPolicy(scope: string, roleId: string, input: string, state: PolicyState): Promise<NewAuthCommandRecord>;
|
|
266
|
-
applySuggestedPolicy(input: string, scope?: string
|
|
272
|
+
applySuggestedPolicy(input: string, scope?: string): Promise<NewAuthCommandRecord>;
|
|
267
273
|
configureCommandRoles(input: string, scope?: string, roleIds?: string[]): Promise<NewAuthCommandRecord>;
|
|
268
|
-
|
|
274
|
+
generateAiSuggestion(input: string, model?: string): Promise<AutoAssignSuggestion>;
|
|
275
|
+
generateAiSuggestionsForPending(model?: string): Promise<Record<string, AutoAssignSuggestion>>;
|
|
276
|
+
listGuildManageableCommands(session: Session, query?: string): Promise<{
|
|
277
|
+
command: NewAuthCommandRecord;
|
|
278
|
+
states: string[];
|
|
279
|
+
}[]>;
|
|
280
|
+
setGuildManagedPolicy(session: Session, roleId: string, input: string, state: PolicyState): Promise<{
|
|
281
|
+
command: NewAuthCommandRecord;
|
|
282
|
+
scope: string;
|
|
283
|
+
}>;
|
|
269
284
|
assignPluginCommands(plugin: string, scope?: string, target?: PluginAssignTarget): Promise<number>;
|
|
270
285
|
getCommand(input: string): Promise<NewAuthCommandRecord>;
|
|
271
286
|
private ensureBuiltinRoles;
|
|
@@ -275,7 +290,12 @@ export declare class NewAuthService extends Service {
|
|
|
275
290
|
private resolveCommandInput;
|
|
276
291
|
private setPolicy;
|
|
277
292
|
private getEffectivePolicy;
|
|
293
|
+
private ensureGuildManager;
|
|
278
294
|
private getAutoAssignSuggestion;
|
|
295
|
+
private getDefaultAiModel;
|
|
296
|
+
private listAiModels;
|
|
297
|
+
private hasAiAdvisor;
|
|
298
|
+
private getAiAssignSuggestion;
|
|
279
299
|
private ensureRoleMember;
|
|
280
300
|
private ensureRoleExists;
|
|
281
301
|
private hasPlatformRole;
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ exports.apply = apply;
|
|
|
5
5
|
const koishi_1 = require("koishi");
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
exports.name = 'new-auth';
|
|
8
|
-
exports.inject = { required: ['database'], optional: ['console'] };
|
|
8
|
+
exports.inject = { required: ['database'], optional: ['console', 'chatluna'] };
|
|
9
9
|
const BUILTIN_ROLES = [
|
|
10
10
|
{
|
|
11
11
|
id: 'bot-admin',
|
|
@@ -40,7 +40,7 @@ const BUILTIN_ROLES = [
|
|
|
40
40
|
];
|
|
41
41
|
const OWNER_ROLE_NAMES = ['owner', 'guild-owner'];
|
|
42
42
|
const ADMIN_ROLE_NAMES = ['admin', 'administrator', 'guild-admin', 'moderator'];
|
|
43
|
-
const DEFAULT_ALLOW_GUILD_OVERRIDE_AUTHORITY_MAX =
|
|
43
|
+
const DEFAULT_ALLOW_GUILD_OVERRIDE_AUTHORITY_MAX = 2;
|
|
44
44
|
const GRANT_RUNTIME_COMMAND_PERMISSION = true;
|
|
45
45
|
const RAISE_LEGACY_AUTHORITY = false;
|
|
46
46
|
exports.Config = koishi_1.Schema.object({
|
|
@@ -110,7 +110,7 @@ function apply(ctx, config) {
|
|
|
110
110
|
ctx.on('command-updated', command => service.registerCommand(command));
|
|
111
111
|
ctx.before('command/execute', async (argv) => {
|
|
112
112
|
return service.intercept(argv);
|
|
113
|
-
});
|
|
113
|
+
}, true);
|
|
114
114
|
registerManagementCommands(ctx, config, service);
|
|
115
115
|
ctx.inject(['console'], (ctx) => {
|
|
116
116
|
registerConsole(ctx, service);
|
|
@@ -120,6 +120,7 @@ class NewAuthService extends koishi_1.Service {
|
|
|
120
120
|
constructor(ctx, config) {
|
|
121
121
|
super(ctx, 'newauth', true);
|
|
122
122
|
this.commandCache = new Map();
|
|
123
|
+
this.commandLocks = new Map();
|
|
123
124
|
this.config = config;
|
|
124
125
|
this.adminSet = new Set(config.botAdmins.map(normalizeKey));
|
|
125
126
|
this.ownerRoleNames = new Set(OWNER_ROLE_NAMES.map(normalizeKey));
|
|
@@ -136,6 +137,17 @@ class NewAuthService extends koishi_1.Service {
|
|
|
136
137
|
return;
|
|
137
138
|
const now = new Date();
|
|
138
139
|
const record = this.createCommandRecord(command, now);
|
|
140
|
+
const previous = this.commandLocks.get(record.id) || Promise.resolve(undefined);
|
|
141
|
+
const next = previous.then(() => this.writeCommandRecord(command, record, now));
|
|
142
|
+
this.commandLocks.set(record.id, next);
|
|
143
|
+
next.finally(() => {
|
|
144
|
+
if (this.commandLocks.get(record.id) === next)
|
|
145
|
+
this.commandLocks.delete(record.id);
|
|
146
|
+
});
|
|
147
|
+
return next;
|
|
148
|
+
}
|
|
149
|
+
async writeCommandRecord(command, record, now) {
|
|
150
|
+
await this.cleanupSelfCommandDuplicates(record);
|
|
139
151
|
const [existing] = await this.ctx.database.get('new_auth_command', { id: record.id });
|
|
140
152
|
if (existing) {
|
|
141
153
|
const next = {
|
|
@@ -147,17 +159,41 @@ class NewAuthService extends koishi_1.Service {
|
|
|
147
159
|
legacyAuthority: record.legacyAuthority,
|
|
148
160
|
updatedAt: now,
|
|
149
161
|
};
|
|
162
|
+
if (this.isSelfCommand(command)) {
|
|
163
|
+
next.status = 'configured';
|
|
164
|
+
}
|
|
150
165
|
await this.ctx.database.set('new_auth_command', record.id, next);
|
|
151
166
|
this.commandCache.set(record.id, { ...existing, ...next });
|
|
167
|
+
await this.ensureSelfCommandPolicies(record);
|
|
152
168
|
return record.id;
|
|
153
169
|
}
|
|
154
170
|
await this.ctx.database.create('new_auth_command', record);
|
|
155
171
|
this.commandCache.set(record.id, record);
|
|
156
|
-
|
|
157
|
-
await this.setPolicy('global', 'bot-admin', record.id, 'allow');
|
|
158
|
-
}
|
|
172
|
+
await this.ensureSelfCommandPolicies(record);
|
|
159
173
|
return record.id;
|
|
160
174
|
}
|
|
175
|
+
async ensureSelfCommandPolicies(record) {
|
|
176
|
+
if (!isSelfCommandPath(record.commandPath))
|
|
177
|
+
return;
|
|
178
|
+
await this.setPolicy('global', 'bot-admin', record.id, 'allow');
|
|
179
|
+
if (isGuildAutonomyCommandPath(record.commandPath)) {
|
|
180
|
+
await this.setPolicy('global', 'guild-owner', record.id, 'allow');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async cleanupSelfCommandDuplicates(record) {
|
|
184
|
+
if (!isSelfCommandPath(record.commandPath))
|
|
185
|
+
return;
|
|
186
|
+
const staleRecords = await this.ctx.database.get('new_auth_command', {
|
|
187
|
+
commandPath: record.commandPath,
|
|
188
|
+
});
|
|
189
|
+
for (const stale of staleRecords) {
|
|
190
|
+
if (stale.id === record.id)
|
|
191
|
+
continue;
|
|
192
|
+
await this.ctx.database.remove('new_auth_policy', { commandId: stale.id });
|
|
193
|
+
await this.ctx.database.remove('new_auth_command', { id: stale.id });
|
|
194
|
+
this.commandCache.delete(stale.id);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
161
197
|
async intercept(argv) {
|
|
162
198
|
const { command, session, options } = argv;
|
|
163
199
|
if (!command || !session)
|
|
@@ -317,6 +353,8 @@ class NewAuthService extends koishi_1.Service {
|
|
|
317
353
|
const globalAllow = new Set(policies
|
|
318
354
|
.filter(policy => policy.scope === 'global' && policy.state === 'allow')
|
|
319
355
|
.map(policy => `${policy.roleId}:${policy.commandId}`));
|
|
356
|
+
const aiModels = this.listAiModels();
|
|
357
|
+
const defaultAiModel = this.getDefaultAiModel();
|
|
320
358
|
return {
|
|
321
359
|
roles: roles.map(role => ({
|
|
322
360
|
...role,
|
|
@@ -333,7 +371,9 @@ class NewAuthService extends koishi_1.Service {
|
|
|
333
371
|
members,
|
|
334
372
|
scopes,
|
|
335
373
|
pendingCount: commands.filter(command => command.status === 'pending').length,
|
|
336
|
-
autoAssignAvailable:
|
|
374
|
+
autoAssignAvailable: this.hasAiAdvisor(defaultAiModel || aiModels[0]?.id),
|
|
375
|
+
aiModels,
|
|
376
|
+
defaultAiModel,
|
|
337
377
|
};
|
|
338
378
|
}
|
|
339
379
|
async addBotAdmin(uid) {
|
|
@@ -426,11 +466,9 @@ class NewAuthService extends koishi_1.Service {
|
|
|
426
466
|
}
|
|
427
467
|
return command;
|
|
428
468
|
}
|
|
429
|
-
async applySuggestedPolicy(input, scope = 'global'
|
|
469
|
+
async applySuggestedPolicy(input, scope = 'global') {
|
|
430
470
|
const command = await this.resolveCommandInput(input);
|
|
431
|
-
const suggestion =
|
|
432
|
-
? this.getAutoAssignSuggestion(command)
|
|
433
|
-
: getLegacySuggestion(command.legacyAuthority);
|
|
471
|
+
const suggestion = getLegacySuggestion(command.legacyAuthority);
|
|
434
472
|
await this.applyRolesToCommand(scope, command.id, suggestion.roles);
|
|
435
473
|
if (command.status === 'pending') {
|
|
436
474
|
await this.setCommandStatus(command.id, 'configured');
|
|
@@ -445,19 +483,58 @@ class NewAuthService extends koishi_1.Service {
|
|
|
445
483
|
}
|
|
446
484
|
return command;
|
|
447
485
|
}
|
|
448
|
-
async
|
|
486
|
+
async generateAiSuggestion(input, model) {
|
|
487
|
+
const command = await this.resolveCommandInput(input);
|
|
488
|
+
return this.getAiAssignSuggestion(command, model);
|
|
489
|
+
}
|
|
490
|
+
async generateAiSuggestionsForPending(model) {
|
|
449
491
|
const commands = await this.listCommands({ pending: true });
|
|
492
|
+
const suggestions = {};
|
|
450
493
|
for (const command of commands) {
|
|
451
|
-
await this.
|
|
494
|
+
suggestions[command.id] = await this.getAiAssignSuggestion(command, model);
|
|
452
495
|
}
|
|
453
|
-
return
|
|
496
|
+
return suggestions;
|
|
497
|
+
}
|
|
498
|
+
async listGuildManageableCommands(session, query) {
|
|
499
|
+
const scope = await this.ensureGuildManager(session);
|
|
500
|
+
const commands = (await this.listCommands({ all: true, query }))
|
|
501
|
+
.filter(command => command.status === 'configured' && command.allowGuildOverride);
|
|
502
|
+
const roles = ['guild-member', 'guild-admin', 'guild-owner'];
|
|
503
|
+
const rows = [];
|
|
504
|
+
for (const command of commands) {
|
|
505
|
+
const states = [];
|
|
506
|
+
for (const roleId of roles) {
|
|
507
|
+
states.push(`${roleId}:${await this.getEffectivePolicy(scope, roleId, command.id)}`);
|
|
508
|
+
}
|
|
509
|
+
rows.push({ command, states });
|
|
510
|
+
}
|
|
511
|
+
return rows;
|
|
512
|
+
}
|
|
513
|
+
async setGuildManagedPolicy(session, roleId, input, state) {
|
|
514
|
+
const scope = await this.ensureGuildManager(session);
|
|
515
|
+
const role = await this.ensureRoleExists(roleId);
|
|
516
|
+
if (role.scopeType !== 'guild') {
|
|
517
|
+
throw new Error('群内自治只能配置群内角色');
|
|
518
|
+
}
|
|
519
|
+
if (role.id === 'bot-admin') {
|
|
520
|
+
throw new Error('群内自治不能配置 Bot 管理员');
|
|
521
|
+
}
|
|
522
|
+
const command = await this.resolveCommandInput(input);
|
|
523
|
+
if (command.status !== 'configured') {
|
|
524
|
+
throw new Error('该指令尚未由 Koishi 管理员配置');
|
|
525
|
+
}
|
|
526
|
+
if (!command.allowGuildOverride) {
|
|
527
|
+
throw new Error('该指令不允许群内自治');
|
|
528
|
+
}
|
|
529
|
+
await this.setPolicy(scope, role.id, command.id, state);
|
|
530
|
+
return { command, scope };
|
|
454
531
|
}
|
|
455
532
|
async assignPluginCommands(plugin, scope = 'global', target = 'legacy') {
|
|
456
533
|
const commands = (await this.listCommands({ all: true }))
|
|
457
534
|
.filter(command => command.plugin === plugin);
|
|
458
535
|
for (const command of commands) {
|
|
459
536
|
if (target === 'legacy') {
|
|
460
|
-
await this.applySuggestedPolicy(command.id, scope
|
|
537
|
+
await this.applySuggestedPolicy(command.id, scope);
|
|
461
538
|
}
|
|
462
539
|
else {
|
|
463
540
|
await this.applyRolesToCommand(scope, command.id, getAssignTargetRoles(target));
|
|
@@ -526,15 +603,16 @@ class NewAuthService extends koishi_1.Service {
|
|
|
526
603
|
createdAt: now,
|
|
527
604
|
updatedAt: now,
|
|
528
605
|
};
|
|
529
|
-
if (this.getAutoAssignSuggestion(record).kind === 'admin') {
|
|
530
|
-
record.allowGuildOverride = false;
|
|
531
|
-
}
|
|
532
606
|
return record;
|
|
533
607
|
}
|
|
534
608
|
getDescription(command) {
|
|
535
609
|
const key = `commands.${command.name}.description`;
|
|
536
610
|
const value = this.ctx.i18n.get(key);
|
|
537
|
-
|
|
611
|
+
if (typeof value === 'string')
|
|
612
|
+
return value;
|
|
613
|
+
if (Array.isArray(value))
|
|
614
|
+
return stringifyI18nValue(value[0]);
|
|
615
|
+
return stringifyI18nValue(value);
|
|
538
616
|
}
|
|
539
617
|
async resolveCommandInput(input) {
|
|
540
618
|
const normalized = input.trim();
|
|
@@ -573,69 +651,113 @@ class NewAuthService extends koishi_1.Service {
|
|
|
573
651
|
});
|
|
574
652
|
return global?.state ?? 'inherit';
|
|
575
653
|
}
|
|
654
|
+
async ensureGuildManager(session) {
|
|
655
|
+
if (!session?.platform || !session.guildId || session.isDirect) {
|
|
656
|
+
throw new Error('只能在群聊中管理群内自治');
|
|
657
|
+
}
|
|
658
|
+
const roles = await this.resolveRoles(session);
|
|
659
|
+
if (!roles.includes('bot-admin') && !roles.includes('guild-owner')) {
|
|
660
|
+
throw new Error('只有 Bot 管理员或当前群群主可以管理群内自治');
|
|
661
|
+
}
|
|
662
|
+
return getScope(session);
|
|
663
|
+
}
|
|
576
664
|
getAutoAssignSuggestion(command) {
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
665
|
+
const fallback = getLegacySuggestion(command.legacyAuthority);
|
|
666
|
+
return {
|
|
667
|
+
kind: 'legacy',
|
|
668
|
+
roles: fallback.roles,
|
|
669
|
+
label: '等待 AI 分配',
|
|
670
|
+
reason: '未调用 AI 时只显示旧 authority 建议,不做关键词推断。',
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
getDefaultAiModel() {
|
|
674
|
+
const chatluna = this.ctx.chatluna;
|
|
675
|
+
const defaultModel = chatluna?.currentConfig?.defaultModel ?? chatluna?.config?.defaultModel;
|
|
676
|
+
return typeof defaultModel === 'string' && defaultModel !== '无' ? defaultModel : '';
|
|
677
|
+
}
|
|
678
|
+
listAiModels() {
|
|
679
|
+
const chatluna = this.ctx.chatluna;
|
|
680
|
+
const models = chatluna?.platform?.listAllModels?.(1)?.value ?? [];
|
|
681
|
+
const seen = new Set();
|
|
682
|
+
const result = [];
|
|
683
|
+
for (const model of models) {
|
|
684
|
+
const id = typeof model?.toModelName === 'function'
|
|
685
|
+
? String(model.toModelName())
|
|
686
|
+
: model?.platform && model?.name
|
|
687
|
+
? `${model.platform}/${model.name}`
|
|
688
|
+
: '';
|
|
689
|
+
if (!id || seen.has(id))
|
|
690
|
+
continue;
|
|
691
|
+
seen.add(id);
|
|
692
|
+
result.push({
|
|
693
|
+
id,
|
|
694
|
+
platform: String(model.platform ?? id.split('/')[0] ?? ''),
|
|
695
|
+
name: String(model.name ?? id),
|
|
696
|
+
});
|
|
598
697
|
}
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
698
|
+
const defaultModel = this.getDefaultAiModel();
|
|
699
|
+
if (defaultModel && !seen.has(defaultModel)) {
|
|
700
|
+
const index = defaultModel.indexOf('/');
|
|
701
|
+
result.unshift({
|
|
702
|
+
id: defaultModel,
|
|
703
|
+
platform: index > 0 ? defaultModel.slice(0, index) : '',
|
|
704
|
+
name: index > 0 ? defaultModel.slice(index + 1) : defaultModel,
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
return result.sort((a, b) => a.id.localeCompare(b.id));
|
|
708
|
+
}
|
|
709
|
+
hasAiAdvisor(model) {
|
|
710
|
+
const chatluna = this.ctx.chatluna;
|
|
711
|
+
const selectedModel = model || this.getDefaultAiModel();
|
|
712
|
+
return typeof chatluna?.createChatModel === 'function'
|
|
713
|
+
&& !!selectedModel;
|
|
714
|
+
}
|
|
715
|
+
async getAiAssignSuggestion(command, modelName) {
|
|
716
|
+
const fallback = getLegacySuggestion(command.legacyAuthority);
|
|
717
|
+
const selectedModel = modelName || this.getDefaultAiModel();
|
|
718
|
+
if (!this.hasAiAdvisor(selectedModel)) {
|
|
604
719
|
return {
|
|
605
|
-
kind: '
|
|
606
|
-
roles:
|
|
607
|
-
label:
|
|
608
|
-
reason: '
|
|
720
|
+
kind: 'legacy',
|
|
721
|
+
roles: fallback.roles,
|
|
722
|
+
label: fallback.label,
|
|
723
|
+
reason: 'ChatLuna 默认模型不可用,已回退到旧 authority 建议。',
|
|
609
724
|
};
|
|
610
725
|
}
|
|
611
|
-
|
|
612
|
-
|
|
726
|
+
try {
|
|
727
|
+
const roles = await this.listRoles();
|
|
728
|
+
const chatluna = this.ctx.chatluna;
|
|
729
|
+
const modelRef = await chatluna.createChatModel(selectedModel);
|
|
730
|
+
const model = modelRef?.value;
|
|
731
|
+
if (typeof model?.invoke !== 'function')
|
|
732
|
+
throw new Error('ChatLuna 模型未就绪');
|
|
733
|
+
const output = await model.invoke(buildAiAdvisorPrompt(command, roles), {
|
|
734
|
+
maxTokens: 512,
|
|
735
|
+
signal: AbortSignal.timeout(60000),
|
|
736
|
+
configurable: {
|
|
737
|
+
conversationId: 'newauth-permission-advisor',
|
|
738
|
+
userId: 'newauth',
|
|
739
|
+
},
|
|
740
|
+
});
|
|
741
|
+
const parsed = parseAiAdvisorOutput(output);
|
|
742
|
+
const knownRoles = new Set(roles.map(role => role.id));
|
|
743
|
+
const selected = [...new Set(parsed.roles)].filter(roleId => knownRoles.has(roleId));
|
|
744
|
+
if (!selected.length)
|
|
745
|
+
throw new Error('AI 没有返回有效角色');
|
|
613
746
|
return {
|
|
614
|
-
kind: '
|
|
615
|
-
roles:
|
|
616
|
-
label: '
|
|
617
|
-
reason: '
|
|
747
|
+
kind: 'ai',
|
|
748
|
+
roles: selected,
|
|
749
|
+
label: selected.map(roleId => roles.find(role => role.id === roleId)?.name ?? roleId).join('、'),
|
|
750
|
+
reason: parsed.reason || '由 ChatLuna 默认模型生成。',
|
|
618
751
|
};
|
|
619
752
|
}
|
|
620
|
-
|
|
621
|
-
'help', 'sign', 'rank', 'weather', 'search', 'music', 'play', 'query',
|
|
622
|
-
'帮助', '签到', '排行', '天气', '搜索', '点歌', '播放', '查询',
|
|
623
|
-
];
|
|
624
|
-
if (publicUse.some(keyword => text.includes(keyword))) {
|
|
753
|
+
catch (error) {
|
|
625
754
|
return {
|
|
626
|
-
kind: '
|
|
627
|
-
roles:
|
|
628
|
-
label:
|
|
629
|
-
reason:
|
|
755
|
+
kind: 'legacy',
|
|
756
|
+
roles: fallback.roles,
|
|
757
|
+
label: fallback.label,
|
|
758
|
+
reason: `AI 分配失败,已回退到旧 authority 建议:${error instanceof Error ? error.message : String(error)}`,
|
|
630
759
|
};
|
|
631
760
|
}
|
|
632
|
-
const fallback = getLegacySuggestion(command.legacyAuthority);
|
|
633
|
-
return {
|
|
634
|
-
kind: 'legacy',
|
|
635
|
-
roles: fallback.roles,
|
|
636
|
-
label: fallback.label,
|
|
637
|
-
reason: '未命中明确语义,回退到旧 authority 建议。',
|
|
638
|
-
};
|
|
639
761
|
}
|
|
640
762
|
async ensureRoleMember(roleId, platform, userId, scope) {
|
|
641
763
|
await this.ensureRoleExists(roleId);
|
|
@@ -720,13 +842,12 @@ function registerConsole(ctx, service) {
|
|
|
720
842
|
ctx.console.addListener('newauth/setGuildOverride', async (payload) => {
|
|
721
843
|
return ok(service.setCommandGuildOverride(payload.commandId, payload.allowGuildOverride));
|
|
722
844
|
}, { authority: 4 });
|
|
723
|
-
ctx.console.addListener('newauth/
|
|
724
|
-
return
|
|
845
|
+
ctx.console.addListener('newauth/generateAiSuggestion', async (payload) => {
|
|
846
|
+
return service.generateAiSuggestion(payload.commandId, payload.model);
|
|
725
847
|
}, { authority: 4 });
|
|
726
|
-
ctx.console.addListener('newauth/
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
return { success: true, count };
|
|
848
|
+
ctx.console.addListener('newauth/generateAiSuggestions', async (payload = {}) => {
|
|
849
|
+
const suggestions = await service.generateAiSuggestionsForPending(payload.model);
|
|
850
|
+
return { suggestions };
|
|
730
851
|
}, { authority: 4 });
|
|
731
852
|
ctx.console.addListener('newauth/configureCommandRoles', async (payload) => {
|
|
732
853
|
return ok(service.configureCommandRoles(payload.commandId, payload.scope, payload.roleIds));
|
|
@@ -854,6 +975,38 @@ function registerManagementCommands(ctx, config, service) {
|
|
|
854
975
|
const count = await service.copyRolePolicies(sourceRoleId, targetRoleId, scope);
|
|
855
976
|
return `已复制 ${count} 条策略:${sourceRoleId} -> ${targetRoleId} (${scope})`;
|
|
856
977
|
});
|
|
978
|
+
ctx.command('newauth.guild', '管理当前群的新权限自治', { authority: 0 })
|
|
979
|
+
.action(async ({ session }) => {
|
|
980
|
+
const rows = await service.listGuildManageableCommands(session);
|
|
981
|
+
return [
|
|
982
|
+
`当前群可自治指令:${rows.length}`,
|
|
983
|
+
'使用 newauth.guild.commands 查看列表。',
|
|
984
|
+
].join('\n');
|
|
985
|
+
});
|
|
986
|
+
ctx.command('newauth.guild.commands [query:text]', '列出当前群可自治指令', { authority: 0 })
|
|
987
|
+
.action(async ({ session }, query) => {
|
|
988
|
+
const rows = await service.listGuildManageableCommands(session, query);
|
|
989
|
+
if (!rows.length)
|
|
990
|
+
return '当前群没有可自治指令。';
|
|
991
|
+
return rows.map(({ command, states }) => {
|
|
992
|
+
return `${command.commandPath} (${command.id}) ${states.join(' ')}`;
|
|
993
|
+
}).join('\n');
|
|
994
|
+
});
|
|
995
|
+
ctx.command('newauth.guild.allow <roleId> <command>', '允许当前群角色使用可自治指令', { authority: 0 })
|
|
996
|
+
.action(async ({ session }, roleId, command) => {
|
|
997
|
+
const result = await service.setGuildManagedPolicy(session, roleId, command, 'allow');
|
|
998
|
+
return `已允许:${result.scope} ${roleId} -> ${result.command.commandPath}`;
|
|
999
|
+
});
|
|
1000
|
+
ctx.command('newauth.guild.deny <roleId> <command>', '关闭当前群角色使用可自治指令', { authority: 0 })
|
|
1001
|
+
.action(async ({ session }, roleId, command) => {
|
|
1002
|
+
const result = await service.setGuildManagedPolicy(session, roleId, command, 'deny');
|
|
1003
|
+
return `已关闭:${result.scope} ${roleId} -> ${result.command.commandPath}`;
|
|
1004
|
+
});
|
|
1005
|
+
ctx.command('newauth.guild.inherit <roleId> <command>', '恢复当前群角色的继承策略', { authority: 0 })
|
|
1006
|
+
.action(async ({ session }, roleId, command) => {
|
|
1007
|
+
const result = await service.setGuildManagedPolicy(session, roleId, command, 'inherit');
|
|
1008
|
+
return `已恢复继承:${result.scope} ${roleId} -> ${result.command.commandPath}`;
|
|
1009
|
+
});
|
|
857
1010
|
ctx.command('newauth.plugin.assign <plugin> <target> [scope]', '批量配置插件指令', { authority })
|
|
858
1011
|
.action(async (_, plugin, target, scope = 'global') => {
|
|
859
1012
|
if (!['legacy', 'bot-admin', 'guild-owner', 'guild-admin', 'guild-member'].includes(target)) {
|
|
@@ -912,18 +1065,96 @@ function getAssignTargetRoles(target) {
|
|
|
912
1065
|
return ['guild-owner'];
|
|
913
1066
|
return ['bot-admin'];
|
|
914
1067
|
}
|
|
1068
|
+
function buildAiAdvisorPrompt(command, roles) {
|
|
1069
|
+
const roleLines = roles.map(role => {
|
|
1070
|
+
return `- ${role.id}: ${role.name},${role.scopeType === 'global' ? '全局' : '群内'},${role.builtin ? '内置' : '自定义'}`;
|
|
1071
|
+
}).join('\n');
|
|
1072
|
+
return [
|
|
1073
|
+
'你是 Koishi Bot 的指令权限分配助手。请根据指令元数据判断此指令应该分配给哪些角色。',
|
|
1074
|
+
'必须遵守:群主不是 Bot 管理员;实例级、配置级、文件/数据库/插件/执行类能力应保守;不确定时选择 bot-admin。',
|
|
1075
|
+
'只允许返回 JSON,不要 Markdown,不要解释 JSON 之外的内容。',
|
|
1076
|
+
'JSON 格式:{"roles":["role-id"],"reason":"一句中文理由"}',
|
|
1077
|
+
'',
|
|
1078
|
+
'可选角色:',
|
|
1079
|
+
roleLines,
|
|
1080
|
+
'',
|
|
1081
|
+
'指令:',
|
|
1082
|
+
JSON.stringify({
|
|
1083
|
+
id: command.id,
|
|
1084
|
+
name: command.name,
|
|
1085
|
+
commandPath: command.commandPath,
|
|
1086
|
+
aliases: command.aliases,
|
|
1087
|
+
plugin: command.plugin,
|
|
1088
|
+
description: command.description,
|
|
1089
|
+
legacyAuthority: command.legacyAuthority,
|
|
1090
|
+
}, null, 2),
|
|
1091
|
+
].join('\n');
|
|
1092
|
+
}
|
|
1093
|
+
function parseAiAdvisorOutput(output) {
|
|
1094
|
+
const text = extractMessageText(output);
|
|
1095
|
+
const fenced = /```(?:json)?\s*([\s\S]*?)```/.exec(text);
|
|
1096
|
+
const raw = fenced?.[1] ?? /\{[\s\S]*\}/.exec(text)?.[0] ?? text;
|
|
1097
|
+
const parsed = JSON.parse(raw);
|
|
1098
|
+
if (!Array.isArray(parsed.roles))
|
|
1099
|
+
throw new Error('AI 返回格式缺少 roles 数组');
|
|
1100
|
+
return {
|
|
1101
|
+
roles: parsed.roles.filter(role => typeof role === 'string'),
|
|
1102
|
+
reason: typeof parsed.reason === 'string' ? parsed.reason : '',
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
function extractMessageText(value) {
|
|
1106
|
+
if (value == null)
|
|
1107
|
+
return '';
|
|
1108
|
+
if (typeof value === 'string')
|
|
1109
|
+
return value;
|
|
1110
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
1111
|
+
return String(value);
|
|
1112
|
+
if (Array.isArray(value))
|
|
1113
|
+
return value.map(extractMessageText).join('');
|
|
1114
|
+
if (typeof value === 'object') {
|
|
1115
|
+
const record = value;
|
|
1116
|
+
if ('content' in record)
|
|
1117
|
+
return extractMessageText(record.content);
|
|
1118
|
+
if ('text' in record)
|
|
1119
|
+
return extractMessageText(record.text);
|
|
1120
|
+
}
|
|
1121
|
+
return String(value);
|
|
1122
|
+
}
|
|
915
1123
|
function omitPrimary(record, key) {
|
|
916
1124
|
const { [key]: _value, ...rest } = record;
|
|
917
1125
|
return rest;
|
|
918
1126
|
}
|
|
919
1127
|
function isSelfCommandPath(commandPath) {
|
|
920
|
-
return commandPath === 'newauth'
|
|
1128
|
+
return commandPath === 'newauth'
|
|
1129
|
+
|| commandPath.startsWith('newauth/')
|
|
1130
|
+
|| commandPath.startsWith('newauth.');
|
|
1131
|
+
}
|
|
1132
|
+
function isGuildAutonomyCommandPath(commandPath) {
|
|
1133
|
+
return commandPath === 'newauth.guild'
|
|
1134
|
+
|| commandPath.startsWith('newauth.guild.');
|
|
921
1135
|
}
|
|
922
1136
|
function inferPlugin(command) {
|
|
1137
|
+
if (isSelfCommandPath(command.name))
|
|
1138
|
+
return 'new-auth';
|
|
923
1139
|
const source = command.caller?.scope || command.ctx?.scope;
|
|
924
1140
|
const plugin = source?.plugin?.name || source?.uid || source?.id || 'unknown';
|
|
925
1141
|
return String(plugin).replace(/^koishi-plugin-/, '') || 'unknown';
|
|
926
1142
|
}
|
|
1143
|
+
function stringifyI18nValue(value) {
|
|
1144
|
+
if (value == null)
|
|
1145
|
+
return '';
|
|
1146
|
+
if (typeof value === 'string')
|
|
1147
|
+
return value;
|
|
1148
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
1149
|
+
return String(value);
|
|
1150
|
+
if (Array.isArray(value))
|
|
1151
|
+
return value.map(stringifyI18nValue).filter(Boolean).join('\n');
|
|
1152
|
+
if (typeof value === 'object') {
|
|
1153
|
+
const record = value;
|
|
1154
|
+
return stringifyI18nValue(record['zh-CN'] ?? record.zh ?? record[''] ?? Object.values(record)[0]);
|
|
1155
|
+
}
|
|
1156
|
+
return '';
|
|
1157
|
+
}
|
|
927
1158
|
function makeCommandId(plugin, commandPath) {
|
|
928
1159
|
return `command:${normalizeSegment(plugin)}:${normalizeSegment(commandPath)}`;
|
|
929
1160
|
}
|
package/newauth.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-new-auth",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "Koishi 的角色与作用域指令权限系统。",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"service": {
|
|
50
50
|
"required": [
|
|
51
51
|
"database"
|
|
52
|
+
],
|
|
53
|
+
"optional": [
|
|
54
|
+
"console",
|
|
55
|
+
"chatluna"
|
|
52
56
|
]
|
|
53
57
|
}
|
|
54
58
|
}
|