koishi-plugin-mai-bridge 0.1.0
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 +110 -0
- package/client/index.ts +11 -0
- package/client/page.vue +148 -0
- package/client/tsconfig.json +11 -0
- package/deploy/Dockerfile.maimai-koishi +35 -0
- package/dist/index.js +2 -0
- package/out/bridge/agreements.d.ts +12 -0
- package/out/bridge/agreements.js +47 -0
- package/out/bridge/convert.d.ts +25 -0
- package/out/bridge/convert.js +274 -0
- package/out/bridge/docker.d.ts +30 -0
- package/out/bridge/docker.js +229 -0
- package/out/bridge/external-logs.d.ts +29 -0
- package/out/bridge/external-logs.js +166 -0
- package/out/bridge/history.d.ts +27 -0
- package/out/bridge/history.js +195 -0
- package/out/bridge/logging.d.ts +7 -0
- package/out/bridge/logging.js +77 -0
- package/out/bridge/prepare.d.ts +42 -0
- package/out/bridge/prepare.js +199 -0
- package/out/bridge/process.d.ts +31 -0
- package/out/bridge/process.js +208 -0
- package/out/bridge/routes.d.ts +17 -0
- package/out/bridge/routes.js +85 -0
- package/out/bridge/runtime-key.d.ts +3 -0
- package/out/bridge/runtime-key.js +34 -0
- package/out/bridge/transport.d.ts +39 -0
- package/out/bridge/transport.js +197 -0
- package/out/bridge/webui-token.d.ts +9 -0
- package/out/bridge/webui-token.js +36 -0
- package/out/commands/index.d.ts +5 -0
- package/out/commands/index.js +64 -0
- package/out/config.d.ts +52 -0
- package/out/config.js +77 -0
- package/out/console.d.ts +16 -0
- package/out/console.js +24 -0
- package/out/index.d.ts +11 -0
- package/out/index.js +32 -0
- package/out/locales.d.ts +18 -0
- package/out/locales.js +21 -0
- package/out/service.d.ts +61 -0
- package/out/service.js +558 -0
- package/out/setup/postinstall.d.ts +1 -0
- package/out/setup/postinstall.js +98 -0
- package/out/types.d.ts +165 -0
- package/out/types.js +2 -0
- package/out/utils/command.d.ts +2 -0
- package/out/utils/command.js +20 -0
- package/out/utils/paths.d.ts +4 -0
- package/out/utils/paths.js +17 -0
- package/out/utils/spawn.d.ts +13 -0
- package/out/utils/spawn.js +53 -0
- package/package.json +74 -0
- package/patches/maimai-koishi.patch +553 -0
- package/scripts/postinstall.js +10 -0
- package/src/bridge/agreements.ts +60 -0
- package/src/bridge/convert.ts +308 -0
- package/src/bridge/docker.ts +244 -0
- package/src/bridge/external-logs.ts +171 -0
- package/src/bridge/history.ts +199 -0
- package/src/bridge/logging.ts +71 -0
- package/src/bridge/prepare.ts +226 -0
- package/src/bridge/process.ts +214 -0
- package/src/bridge/routes.ts +82 -0
- package/src/bridge/runtime-key.ts +36 -0
- package/src/bridge/transport.ts +211 -0
- package/src/bridge/webui-token.ts +41 -0
- package/src/commands/index.ts +69 -0
- package/src/config.ts +126 -0
- package/src/console.ts +39 -0
- package/src/index.ts +36 -0
- package/src/locales/en-US.yml +6 -0
- package/src/locales/zh-CN.yml +6 -0
- package/src/locales.ts +19 -0
- package/src/service.ts +567 -0
- package/src/setup/postinstall.ts +99 -0
- package/src/types.ts +178 -0
- package/src/utils/command.ts +15 -0
- package/src/utils/paths.ts +15 -0
- package/src/utils/spawn.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# mai-bridge
|
|
2
|
+
|
|
3
|
+
将 maibot 作为 Docker 托管的消息回复后端运行,使用 mai.ko 桥接 Koishi 与 maibot 的消息收发。
|
|
4
|
+
|
|
5
|
+
mai-bridge 不重写 maibot 的对话链、记忆系统和插件机制。它负责在 Koishi 侧完成三件事:
|
|
6
|
+
|
|
7
|
+
- 自动准备 MaiBot 源码,应用 Koishi 适配补丁。
|
|
8
|
+
- 构建并启动 `maimai-ko` Docker 容器。
|
|
9
|
+
- 把 Koishi 消息转发给 maibot,再把 maibot 回复发回原会话。
|
|
10
|
+
|
|
11
|
+
## 安装
|
|
12
|
+
|
|
13
|
+
在 Koishi 控制台打开插件市场,搜索并安装:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
mai-bridge
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
插件包名:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
koishi-plugin-mai-bridge
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
同时需要启用 Koishi 的 HTTP 服务:
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
@koishijs/plugin-http
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 运行要求
|
|
32
|
+
|
|
33
|
+
默认模式使用 Docker。
|
|
34
|
+
|
|
35
|
+
Koishi 所在环境需要能执行 Docker 命令,并能访问 Docker socket:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
/var/run/docker.sock
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
如果 Koishi 本身也运行在 Docker 内,需要把 Docker socket 挂载进 Koishi 容器,并确保容器里有 `docker`、`git`、`patch` 命令。
|
|
42
|
+
|
|
43
|
+
## 基础配置
|
|
44
|
+
|
|
45
|
+
插件市场安装后,进入插件配置页。
|
|
46
|
+
|
|
47
|
+
常用配置:
|
|
48
|
+
|
|
49
|
+
```yaml
|
|
50
|
+
processMode: docker
|
|
51
|
+
autoPrepareMaibot: true
|
|
52
|
+
acceptMaibotAgreements: true
|
|
53
|
+
dockerContainerName: maimai-ko
|
|
54
|
+
dockerImageName: maimai-ko:latest
|
|
55
|
+
apiHost: maimai-ko
|
|
56
|
+
apiPort: 8090
|
|
57
|
+
webuiEnabled: true
|
|
58
|
+
webuiHost: 0.0.0.0
|
|
59
|
+
webuiPort: 8002
|
|
60
|
+
messageMode: coexist
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
说明:
|
|
64
|
+
|
|
65
|
+
- `processMode` 保持 `docker`,插件会自动拉取 MaiBot、打补丁、构建镜像并启动容器。
|
|
66
|
+
- `acceptMaibotAgreements` 默认关闭。确认接受 MaiBot 的 EULA 和隐私条款后再开启。
|
|
67
|
+
- `apiKey` 可以留空。插件会生成并复用运行期密钥。
|
|
68
|
+
- `dockerNetwork` 按你的 Koishi Docker 网络填写。Koishi 需要能通过 `apiHost` 访问 `maimai-ko`。
|
|
69
|
+
- `webuiPublicUrl` 可填写反代或宿主机映射后的 WebUI 地址,用于 Koishi 控制台显示入口。
|
|
70
|
+
|
|
71
|
+
## 消息模式
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
messageMode: coexist
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
可选值:
|
|
78
|
+
|
|
79
|
+
- `coexist`:消息转发给 maibot 后,继续交给其他 Koishi 插件处理。
|
|
80
|
+
- `exclusive`:消息转发给 maibot 后,不再交给后续插件。
|
|
81
|
+
- `command`:只有命中指定前缀时才转发。
|
|
82
|
+
|
|
83
|
+
## 常用命令
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
mai.ko.status
|
|
87
|
+
mai.ko.prepare
|
|
88
|
+
mai.ko.docker.start
|
|
89
|
+
mai.ko.docker.stop
|
|
90
|
+
mai.ko.docker.restart
|
|
91
|
+
mai.ko.reconnect
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 开发
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm install
|
|
98
|
+
npm test -- --reporter dot
|
|
99
|
+
npm run build
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
发布 npm 前检查打包内容:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npm pack --dry-run
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 许可证
|
|
109
|
+
|
|
110
|
+
GPL-3.0-or-later
|
package/client/index.ts
ADDED
package/client/page.vue
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<k-layout>
|
|
3
|
+
<k-card>
|
|
4
|
+
<template #header>
|
|
5
|
+
<span>mai.ko 托管状态</span>
|
|
6
|
+
</template>
|
|
7
|
+
<p>进程:{{ status?.process.state || 'unknown' }}</p>
|
|
8
|
+
<p>准备:{{ status?.prepare.state || 'unknown' }} / {{ status?.prepare.root || '-' }}</p>
|
|
9
|
+
<p>Docker:{{ status?.docker.state || 'unknown' }} / {{ status?.docker.containerName || '-' }}</p>
|
|
10
|
+
<p>Bridge:{{ status?.transport.state || 'unknown' }}</p>
|
|
11
|
+
<p v-if="status?.bridge">中转:Koishi 收 {{ status.bridge.koishiReceived }} / 发往 mai.ko {{ status.bridge.maimSent }} / 收到 mai.ko {{ status.bridge.maimReceived }} / 回发 Koishi {{ status.bridge.koishiSent }}</p>
|
|
12
|
+
<p v-if="status?.bridge">中转异常:路由失败 {{ status.bridge.routeMissed }} / 发送失败 {{ status.bridge.sendFailed }}</p>
|
|
13
|
+
<p>WebUI:{{ webuiText }}</p>
|
|
14
|
+
<p v-if="status?.webui.token?.value">WebUI Token:<code>{{ status.webui.token.value }}</code></p>
|
|
15
|
+
<p v-else-if="status?.webui.token?.lastError">WebUI Token:{{ status.webui.token.lastError }}</p>
|
|
16
|
+
<p>PID:{{ status?.process.pid || '-' }}</p>
|
|
17
|
+
<p v-if="status?.process.blockedReason">阻塞原因:{{ status.process.blockedReason }}</p>
|
|
18
|
+
<p v-if="status?.prepare.blockedReason">准备阻塞:{{ status.prepare.blockedReason }}</p>
|
|
19
|
+
<p v-if="status?.prepare.lastError">准备错误:{{ status.prepare.lastError }}</p>
|
|
20
|
+
<p v-if="status?.docker.lastError">Docker 错误:{{ status.docker.lastError }}</p>
|
|
21
|
+
<p v-if="status?.transport.lastError">Bridge 错误:{{ status.transport.lastError }}</p>
|
|
22
|
+
<p v-if="status?.bridge?.lastError">中转错误:{{ status.bridge.lastError }}</p>
|
|
23
|
+
<k-button @click="refresh">刷新</k-button>
|
|
24
|
+
<k-button @click="start">启动</k-button>
|
|
25
|
+
<k-button @click="stop">停止</k-button>
|
|
26
|
+
<k-button @click="restart">重启</k-button>
|
|
27
|
+
<k-button @click="reconnect">重连</k-button>
|
|
28
|
+
<k-button @click="prepare">准备</k-button>
|
|
29
|
+
<k-button @click="dockerStart">Docker 启动</k-button>
|
|
30
|
+
<k-button @click="dockerStop">Docker 停止</k-button>
|
|
31
|
+
<k-button @click="dockerRestart">Docker 重启</k-button>
|
|
32
|
+
<k-button v-if="status?.webui.enabled && status?.webui.url" @click="openWebui">打开 WebUI</k-button>
|
|
33
|
+
<p v-if="status?.logsHint">{{ status.logsHint }}</p>
|
|
34
|
+
<pre v-if="status?.logs.length">{{ status.logs.slice(-20).join('\n') }}</pre>
|
|
35
|
+
</k-card>
|
|
36
|
+
</k-layout>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<script setup lang="ts">
|
|
40
|
+
import { computed, onMounted, ref } from 'vue'
|
|
41
|
+
import { send } from '@koishijs/client'
|
|
42
|
+
|
|
43
|
+
interface RuntimeStatus {
|
|
44
|
+
prepare: {
|
|
45
|
+
state: string
|
|
46
|
+
root: string
|
|
47
|
+
gitUrl: string
|
|
48
|
+
gitRef: string
|
|
49
|
+
patchApplied?: boolean
|
|
50
|
+
patchChecksum?: string
|
|
51
|
+
commit?: string
|
|
52
|
+
blockedReason?: string
|
|
53
|
+
lastError?: string
|
|
54
|
+
updatedAt?: number
|
|
55
|
+
}
|
|
56
|
+
docker: {
|
|
57
|
+
state: string
|
|
58
|
+
containerName: string
|
|
59
|
+
imageName: string
|
|
60
|
+
lastError?: string
|
|
61
|
+
updatedAt?: number
|
|
62
|
+
}
|
|
63
|
+
process: {
|
|
64
|
+
state: string
|
|
65
|
+
pid?: number
|
|
66
|
+
blockedReason?: string
|
|
67
|
+
}
|
|
68
|
+
transport: {
|
|
69
|
+
state: string
|
|
70
|
+
lastError?: string
|
|
71
|
+
}
|
|
72
|
+
bridge: {
|
|
73
|
+
koishiReceived: number
|
|
74
|
+
maimSent: number
|
|
75
|
+
maimReceived: number
|
|
76
|
+
koishiSent: number
|
|
77
|
+
routeMissed: number
|
|
78
|
+
sendFailed: number
|
|
79
|
+
lastError?: string
|
|
80
|
+
}
|
|
81
|
+
webui: {
|
|
82
|
+
enabled: boolean
|
|
83
|
+
host: string
|
|
84
|
+
port: number
|
|
85
|
+
url?: string
|
|
86
|
+
publicUrl?: string
|
|
87
|
+
token?: {
|
|
88
|
+
value?: string
|
|
89
|
+
source?: string
|
|
90
|
+
path?: string
|
|
91
|
+
lastError?: string
|
|
92
|
+
loggedAt?: number
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
logs: string[]
|
|
96
|
+
logsHint?: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const status = ref<RuntimeStatus>()
|
|
100
|
+
const webuiText = computed(() => {
|
|
101
|
+
if (!status.value) return 'unknown'
|
|
102
|
+
if (!status.value.webui.enabled) return 'disabled'
|
|
103
|
+
return status.value.webui.url || `${status.value.webui.host}:${status.value.webui.port}`
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
async function refresh() {
|
|
107
|
+
status.value = await send('mai-ko/status')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async function start() {
|
|
111
|
+
status.value = await send('mai-ko/start')
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function stop() {
|
|
115
|
+
status.value = await send('mai-ko/stop')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function restart() {
|
|
119
|
+
status.value = await send('mai-ko/restart')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function reconnect() {
|
|
123
|
+
status.value = await send('mai-ko/reconnect')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function prepare() {
|
|
127
|
+
status.value = await send('mai-ko/prepare')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function dockerStart() {
|
|
131
|
+
status.value = await send('mai-ko/docker-start')
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function dockerStop() {
|
|
135
|
+
status.value = await send('mai-ko/docker-stop')
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function dockerRestart() {
|
|
139
|
+
status.value = await send('mai-ko/docker-restart')
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function openWebui() {
|
|
143
|
+
if (!status.value?.webui.url) return
|
|
144
|
+
window.open(status.value.webui.url, '_blank', 'noopener,noreferrer')
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
onMounted(refresh)
|
|
148
|
+
</script>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
FROM python:3.13-slim
|
|
2
|
+
|
|
3
|
+
WORKDIR /MaiMBot
|
|
4
|
+
|
|
5
|
+
ENV MAIBOT_LEGACY_0X_UPGRADE_CONFIRMED=1
|
|
6
|
+
ENV PATH="/MaiMBot/.venv/bin:${PATH}"
|
|
7
|
+
ENV UV_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
8
|
+
ENV UV_LINK_MODE=copy
|
|
9
|
+
ENV PIP_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple"
|
|
10
|
+
|
|
11
|
+
COPY pyproject.toml uv.lock ./
|
|
12
|
+
|
|
13
|
+
RUN sed -i \
|
|
14
|
+
-e 's|http://deb.debian.org/debian|http://mirrors.tuna.tsinghua.edu.cn/debian|g' \
|
|
15
|
+
-e 's|http://security.debian.org/debian-security|http://mirrors.tuna.tsinghua.edu.cn/debian-security|g' \
|
|
16
|
+
/etc/apt/sources.list.d/debian.sources
|
|
17
|
+
|
|
18
|
+
RUN apt-get update \
|
|
19
|
+
&& apt-get install -y --no-install-recommends git curl ca-certificates \
|
|
20
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
21
|
+
|
|
22
|
+
RUN pip install --no-cache-dir uv
|
|
23
|
+
|
|
24
|
+
RUN uv sync --frozen --no-dev --no-install-project
|
|
25
|
+
|
|
26
|
+
RUN python -m playwright install-deps chromium \
|
|
27
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
28
|
+
|
|
29
|
+
COPY . .
|
|
30
|
+
|
|
31
|
+
RUN chmod +x docker-entrypoint.sh
|
|
32
|
+
|
|
33
|
+
EXPOSE 8000 8001 8090
|
|
34
|
+
|
|
35
|
+
ENTRYPOINT [ "./docker-entrypoint.sh" ]
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{defineComponent as Z,ref as ee,computed as te,onMounted as oe,resolveComponent as p,openBlock as a,createBlock as F,withCtx as r,createVNode as s,createElementVNode as d,toDisplayString as o,createElementBlock as n,createCommentVNode as u,createTextVNode as l}from"vue";import{send as k}from"@koishijs/client";const ae={key:0},re={key:1},ne={key:2},ue={key:3},le={key:4},ie={key:5},se={key:6},ke={key:7},de={key:8},ve={key:9},pe={key:11},ce={key:12},fe=Z({__name:"page",setup(c){const e=ee(),P=te(()=>e.value?e.value.webui.enabled?e.value.webui.url||`${e.value.webui.host}:${e.value.webui.port}`:"disabled":"unknown");async function f(){e.value=await k("mai-ko/status")}async function h(){e.value=await k("mai-ko/start")}async function q(){e.value=await k("mai-ko/stop")}async function z(){e.value=await k("mai-ko/restart")}async function A(){e.value=await k("mai-ko/reconnect")}async function G(){e.value=await k("mai-ko/prepare")}async function J(){e.value=await k("mai-ko/docker-start")}async function L(){e.value=await k("mai-ko/docker-stop")}async function O(){e.value=await k("mai-ko/docker-restart")}function Q(){var v;(v=e.value)!=null&&v.webui.url&&window.open(e.value.webui.url,"_blank","noopener,noreferrer")}return oe(f),(v,t)=>{const i=p("k-button"),X=p("k-card"),Y=p("k-layout");return a(),F(Y,null,{default:r(()=>[s(X,null,{header:r(()=>[...t[0]||(t[0]=[d("span",null,"mai.ko 托管状态",-1)])]),default:r(()=>{var b,m,w,_,y,g,C,E,D,R,x,B,I,N,S,W,T,U,V,H,K,M,$,j;return[d("p",null,"进程:"+o(((b=e.value)==null?void 0:b.process.state)||"unknown"),1),d("p",null,"准备:"+o(((m=e.value)==null?void 0:m.prepare.state)||"unknown")+" / "+o(((w=e.value)==null?void 0:w.prepare.root)||"-"),1),d("p",null,"Docker:"+o(((_=e.value)==null?void 0:_.docker.state)||"unknown")+" / "+o(((y=e.value)==null?void 0:y.docker.containerName)||"-"),1),d("p",null,"Bridge:"+o(((g=e.value)==null?void 0:g.transport.state)||"unknown"),1),(C=e.value)!=null&&C.bridge?(a(),n("p",ae,"中转:Koishi 收 "+o(e.value.bridge.koishiReceived)+" / 发往 mai.ko "+o(e.value.bridge.maimSent)+" / 收到 mai.ko "+o(e.value.bridge.maimReceived)+" / 回发 Koishi "+o(e.value.bridge.koishiSent),1)):u("v-if",true),(E=e.value)!=null&&E.bridge?(a(),n("p",re,"中转异常:路由失败 "+o(e.value.bridge.routeMissed)+" / 发送失败 "+o(e.value.bridge.sendFailed),1)):u("v-if",true),d("p",null,"WebUI:"+o(P.value),1),(R=(D=e.value)==null?void 0:D.webui.token)!=null&&R.value?(a(),n("p",ne,[t[1]||(t[1]=l("WebUI Token:",-1)),d("code",null,o(e.value.webui.token.value),1)])):(B=(x=e.value)==null?void 0:x.webui.token)!=null&&B.lastError?(a(),n("p",ue,"WebUI Token:"+o(e.value.webui.token.lastError),1)):u("v-if",true),d("p",null,"PID:"+o(((I=e.value)==null?void 0:I.process.pid)||"-"),1),(N=e.value)!=null&&N.process.blockedReason?(a(),n("p",le,"阻塞原因:"+o(e.value.process.blockedReason),1)):u("v-if",true),(S=e.value)!=null&&S.prepare.blockedReason?(a(),n("p",ie,"准备阻塞:"+o(e.value.prepare.blockedReason),1)):u("v-if",true),(W=e.value)!=null&&W.prepare.lastError?(a(),n("p",se,"准备错误:"+o(e.value.prepare.lastError),1)):u("v-if",true),(T=e.value)!=null&&T.docker.lastError?(a(),n("p",ke,"Docker 错误:"+o(e.value.docker.lastError),1)):u("v-if",true),(U=e.value)!=null&&U.transport.lastError?(a(),n("p",de,"Bridge 错误:"+o(e.value.transport.lastError),1)):u("v-if",true),(H=(V=e.value)==null?void 0:V.bridge)!=null&&H.lastError?(a(),n("p",ve,"中转错误:"+o(e.value.bridge.lastError),1)):u("v-if",true),s(i,{onClick:f},{default:r(()=>[...t[2]||(t[2]=[l("刷新",-1)])]),_:1}),s(i,{onClick:h},{default:r(()=>[...t[3]||(t[3]=[l("启动",-1)])]),_:1}),s(i,{onClick:q},{default:r(()=>[...t[4]||(t[4]=[l("停止",-1)])]),_:1}),s(i,{onClick:z},{default:r(()=>[...t[5]||(t[5]=[l("重启",-1)])]),_:1}),s(i,{onClick:A},{default:r(()=>[...t[6]||(t[6]=[l("重连",-1)])]),_:1}),s(i,{onClick:G},{default:r(()=>[...t[7]||(t[7]=[l("准备",-1)])]),_:1}),s(i,{onClick:J},{default:r(()=>[...t[8]||(t[8]=[l("Docker 启动",-1)])]),_:1}),s(i,{onClick:L},{default:r(()=>[...t[9]||(t[9]=[l("Docker 停止",-1)])]),_:1}),s(i,{onClick:O},{default:r(()=>[...t[10]||(t[10]=[l("Docker 重启",-1)])]),_:1}),(K=e.value)!=null&&K.webui.enabled&&((M=e.value)!=null&&M.webui.url)?(a(),F(i,{key:10,onClick:Q},{default:r(()=>[...t[11]||(t[11]=[l("打开 WebUI",-1)])]),_:1})):u("v-if",true),($=e.value)!=null&&$.logsHint?(a(),n("p",pe,o(e.value.logsHint),1)):u("v-if",true),(j=e.value)!=null&&j.logs.length?(a(),n("pre",ce,o(e.value.logs.slice(-20).join(`
|
|
2
|
+
`)),1)):u("v-if",true)]}),_:1})]),_:1})}}}),we=c=>{c.page({name:"mai.ko",path:"/mai-ko",authority:3,component:fe})};export{we as default};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface AgreementOptions {
|
|
2
|
+
accept: boolean;
|
|
3
|
+
env?: NodeJS.ProcessEnv;
|
|
4
|
+
}
|
|
5
|
+
export type AgreementResult = {
|
|
6
|
+
ok: true;
|
|
7
|
+
env: Record<string, string>;
|
|
8
|
+
} | {
|
|
9
|
+
ok: false;
|
|
10
|
+
reason: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function prepareAgreementEnv(root: string, options: AgreementOptions): AgreementResult;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prepareAgreementEnv = prepareAgreementEnv;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
function prepareAgreementEnv(root, options) {
|
|
8
|
+
const eula = (0, path_1.join)(root, 'EULA.md');
|
|
9
|
+
const privacy = (0, path_1.join)(root, 'PRIVACY.md');
|
|
10
|
+
if (!(0, fs_1.existsSync)(eula) || !(0, fs_1.existsSync)(privacy)) {
|
|
11
|
+
return {
|
|
12
|
+
ok: false,
|
|
13
|
+
reason: 'mai.ko EULA/Privacy files are missing. Check maibotRoot or finish MaiBot preparation first.',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
const eulaHash = md5(eula);
|
|
17
|
+
const privacyHash = md5(privacy);
|
|
18
|
+
const currentEnv = options.env || process.env;
|
|
19
|
+
const eulaConfirmed = isAgreementConfirmed(root, 'eula.confirmed', 'EULA_AGREE', eulaHash, currentEnv);
|
|
20
|
+
const privacyConfirmed = isAgreementConfirmed(root, 'privacy.confirmed', 'PRIVACY_AGREE', privacyHash, currentEnv);
|
|
21
|
+
if (eulaConfirmed && privacyConfirmed)
|
|
22
|
+
return { ok: true, env: {} };
|
|
23
|
+
if (!options.accept) {
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
reason: 'mai.ko EULA/Privacy is not confirmed. Run mai.ko once manually or set acceptMaibotAgreements=true.',
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
ok: true,
|
|
31
|
+
env: {
|
|
32
|
+
EULA_AGREE: eulaHash,
|
|
33
|
+
PRIVACY_AGREE: privacyHash,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function isAgreementConfirmed(root, fileName, envName, expected, env) {
|
|
38
|
+
if (env[envName] === expected)
|
|
39
|
+
return true;
|
|
40
|
+
const path = (0, path_1.join)(root, fileName);
|
|
41
|
+
if (!(0, fs_1.existsSync)(path))
|
|
42
|
+
return false;
|
|
43
|
+
return (0, fs_1.readFileSync)(path, 'utf8').trim() === expected;
|
|
44
|
+
}
|
|
45
|
+
function md5(path) {
|
|
46
|
+
return (0, crypto_1.createHash)('md5').update((0, fs_1.readFileSync)(path)).digest('hex');
|
|
47
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Awaitable, type Fragment, type Session } from 'koishi';
|
|
2
|
+
import type { Config } from '../config';
|
|
3
|
+
import type { KoishiRoute, MaimApiMessage } from '../types';
|
|
4
|
+
export interface SessionToMaimOptions {
|
|
5
|
+
resolveImage?: (source: string) => Awaitable<string | undefined>;
|
|
6
|
+
replyContext?: ReplyContext;
|
|
7
|
+
}
|
|
8
|
+
export interface ReplyContext {
|
|
9
|
+
targetMessageId: string;
|
|
10
|
+
targetMessageContent?: string;
|
|
11
|
+
targetMessageSenderId?: string;
|
|
12
|
+
targetMessageSenderNickname?: string;
|
|
13
|
+
targetMessageSenderCardname?: string;
|
|
14
|
+
contextCount?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function sessionToMaimMessage(session: Session, route: KoishiRoute, apiKey: string, options?: SessionToMaimOptions): Promise<MaimApiMessage>;
|
|
17
|
+
export declare function maimMessageToFragment(message: MaimApiMessage): Fragment;
|
|
18
|
+
export declare function getRouteIdFromMaim(message: MaimApiMessage): string | undefined;
|
|
19
|
+
export declare function getFallbackRouteHints(message: MaimApiMessage): {
|
|
20
|
+
channelId: string | undefined;
|
|
21
|
+
userId: string | undefined;
|
|
22
|
+
selfId: string | undefined;
|
|
23
|
+
isDirect: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function shouldForwardSession(session: Session, config: Config): boolean;
|