koishi-plugin-adapter-debugger 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/lib/index.cjs +190 -0
- package/lib/index.d.ts +20 -0
- package/lib/index.d.ts.map +1 -0
- package/package.json +48 -0
- package/readme.md +33 -0
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let koishi = require("koishi");
|
|
3
|
+
//#region src/actions.ts
|
|
4
|
+
/**
|
|
5
|
+
* 当前可调试的 koishi 标准动作预设。
|
|
6
|
+
*
|
|
7
|
+
* 来源:koishi-plugin-adapter-napuketto 的 `NapukettoInternal` 实现的方法
|
|
8
|
+
* (src/actions/internal.ts)。参数为 koishi 标准签名。
|
|
9
|
+
*/
|
|
10
|
+
const ACTION_PRESETS = [
|
|
11
|
+
{
|
|
12
|
+
method: "getSelf",
|
|
13
|
+
description: "获取登录账号自身信息",
|
|
14
|
+
argNames: [],
|
|
15
|
+
args: []
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
method: "sendMessage",
|
|
19
|
+
description: "发送消息(content 为字符串或元素数组)",
|
|
20
|
+
argNames: ["channelId", "content"],
|
|
21
|
+
args: ["{channelId}", "hello"]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
method: "deleteMessage",
|
|
25
|
+
description: "撤回消息",
|
|
26
|
+
argNames: ["channelId", "messageId"],
|
|
27
|
+
args: ["{channelId}", ""]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
method: "getMessageList",
|
|
31
|
+
description: "拉取消息历史",
|
|
32
|
+
argNames: ["channelId", "limit"],
|
|
33
|
+
args: ["{channelId}", 20]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
method: "markAsRead",
|
|
37
|
+
description: "标记已读",
|
|
38
|
+
argNames: ["channelId"],
|
|
39
|
+
args: ["{channelId}"]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
method: "getGroupList",
|
|
43
|
+
description: "群列表(数据来自 GroupCache)",
|
|
44
|
+
argNames: [],
|
|
45
|
+
args: []
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
method: "getFriendList",
|
|
49
|
+
description: "好友列表",
|
|
50
|
+
argNames: [],
|
|
51
|
+
args: []
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
/** 按方法名查找预设,找不到返回 undefined。 */
|
|
55
|
+
function findPreset(method) {
|
|
56
|
+
return ACTION_PRESETS.find((preset) => preset.method === method);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 执行一次 koishi 标准动作调用:
|
|
60
|
+
* `bot.internal[method](...args)` → 适配器映射 → IPC action → kernel API。
|
|
61
|
+
*
|
|
62
|
+
* 参数组装:预设模板为基底,`rawParams`(命令行的 `key=value` 覆盖表)
|
|
63
|
+
* 按 argNames 一一覆盖;`{channelId}` 占位符替换为当前会话频道。
|
|
64
|
+
*/
|
|
65
|
+
async function runAction(ctx, bot, method, rawParams, channelId) {
|
|
66
|
+
const preset = findPreset(method);
|
|
67
|
+
const args = preset ? [...preset.args] : [];
|
|
68
|
+
preset?.argNames.forEach((name, index) => {
|
|
69
|
+
if (name in rawParams) args[index] = rawParams[name];
|
|
70
|
+
});
|
|
71
|
+
if (channelId) args.forEach((arg, index) => {
|
|
72
|
+
if (typeof arg === "string") args[index] = arg.replaceAll("{channelId}", channelId);
|
|
73
|
+
});
|
|
74
|
+
const internal = bot.internal;
|
|
75
|
+
const fn = internal?.[method];
|
|
76
|
+
if (typeof fn !== "function") return {
|
|
77
|
+
ok: false,
|
|
78
|
+
method,
|
|
79
|
+
elapsedMs: 0,
|
|
80
|
+
error: `适配器未实现 koishi 标准方法 ${method}(bot.internal.${method} 不是函数)`
|
|
81
|
+
};
|
|
82
|
+
ctx.logger("tools").debug(`[adbg] 调用 bot.internal.${method}`, args);
|
|
83
|
+
const startedAt = Date.now();
|
|
84
|
+
try {
|
|
85
|
+
const value = await fn.apply(internal, args);
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
method,
|
|
89
|
+
elapsedMs: Date.now() - startedAt,
|
|
90
|
+
value
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
ctx.logger("tools").error(`[adbg] bot.internal.${method} 调用失败`, error);
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
method,
|
|
97
|
+
elapsedMs: Date.now() - startedAt,
|
|
98
|
+
error: error instanceof Error ? error.message : String(error)
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/index.ts
|
|
104
|
+
const name = "adapter-debugger";
|
|
105
|
+
const usage = `
|
|
106
|
+
<div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
|
107
|
+
<h2 style="margin-top: 0; color: #4a6ee0;">🛠️ 适配器协议调试器</h2>
|
|
108
|
+
<p>🔌 针对 <strong>NapukettoQQ</strong> 适配器(<code>koishi-plugin-adapter-napuketto</code>)的标准动作诊断工具</p>
|
|
109
|
+
<p>🧪 调用 koishi 标准 <code>bot.internal</code> 方法,逐一验证适配器 → IPC → kernel 链路是否可用</p>
|
|
110
|
+
<p>⚠️ 仅适用于 <strong>napuketto</strong> 平台,调试工具请谨慎授权</p>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
|
114
|
+
<h2 style="margin-top: 0; color: #e0574a;">⚡ 命令</h2>
|
|
115
|
+
<ul>
|
|
116
|
+
<li><code>adbg.list</code> — 列出已收录的标准动作及参数模板</li>
|
|
117
|
+
<li><code>adbg.run <method> [key=value ...]</code> — 调用指定标准方法并展示耗时与结果</li>
|
|
118
|
+
</ul>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div style="border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
|
|
122
|
+
<h2 style="margin-top: 0; color: #4a6ee0;">🧩 已收录方法</h2>
|
|
123
|
+
<ul>
|
|
124
|
+
<li><code>getSelf</code> — 登录账号自身信息</li>
|
|
125
|
+
<li><code>sendMessage</code> — 发送消息</li>
|
|
126
|
+
<li><code>deleteMessage</code> — 撤回消息</li>
|
|
127
|
+
<li><code>getMessageList</code> — 拉取消息历史</li>
|
|
128
|
+
<li><code>markAsRead</code> — 标记已读</li>
|
|
129
|
+
<li><code>getGroupList</code> — 群列表</li>
|
|
130
|
+
<li><code>getFriendList</code> — 好友列表</li>
|
|
131
|
+
</ul>
|
|
132
|
+
<p>📌 方法清单对应 adapter 的 <code>NapukettoInternal</code> 实现,随 adapter 扩充同步更新</p>
|
|
133
|
+
</div>
|
|
134
|
+
`;
|
|
135
|
+
const Config = koishi.Schema.object({
|
|
136
|
+
minAuthority: koishi.Schema.number().default(3).min(0).max(5).step(1).description("使用调试指令所需的最低用户权限等级(0-5)。默认 3。"),
|
|
137
|
+
timeout: koishi.Schema.number().default(15e3).min(1e3).step(1e3).description("单次 action 调用超时(毫秒)。默认 15000。"),
|
|
138
|
+
maxOutputLength: koishi.Schema.number().default(1500).min(200).step(100).description("结果文本最大长度,超出部分省略。默认 1500。")
|
|
139
|
+
});
|
|
140
|
+
/**
|
|
141
|
+
* 获取 napuketto 平台的可调试 bot(koishi 上下文 API:ctx.bots 遍历)。
|
|
142
|
+
* 优先取当前会话所在 bot;否则取第一个 napuketto bot。
|
|
143
|
+
*/
|
|
144
|
+
function getDebugBot(ctx, session) {
|
|
145
|
+
const bots = ctx.bots;
|
|
146
|
+
if (!bots) return null;
|
|
147
|
+
const candidates = [...bots.values()].filter((bot) => bot.platform === "onebot");
|
|
148
|
+
if (candidates.length === 0) return null;
|
|
149
|
+
const current = session?.bot;
|
|
150
|
+
return current?.platform === "onebot" ? current : candidates[0];
|
|
151
|
+
}
|
|
152
|
+
/** 将结果对象渲染为聊天文本(含耗时),并截断超长输出。 */
|
|
153
|
+
function renderResult(result, maxLength) {
|
|
154
|
+
const text = `${result.ok ? `✅ 调用成功(耗时 ${result.elapsedMs}ms)` : `❌ 调用失败(耗时 ${result.elapsedMs}ms)`}\n${result.ok ? JSON.stringify(result.value, null, 2) : `错误:${result.error}`}`;
|
|
155
|
+
return text.length > maxLength ? `${text.slice(0, maxLength)}\n…(已截断,完整输出见日志)` : text;
|
|
156
|
+
}
|
|
157
|
+
/** 渲染标准动作预设清单。 */
|
|
158
|
+
function renderPresetList(presets) {
|
|
159
|
+
return presets.map((preset) => preset.method).join("\n");
|
|
160
|
+
}
|
|
161
|
+
function apply(ctx, config) {
|
|
162
|
+
ctx.logger("tools").info("adapter-debugger 插件已加载");
|
|
163
|
+
ctx.command("adbg.list", "列出 NapukettoQQ 适配器的标准动作及参数模板", { authority: config.minAuthority }).action(async ({ session }) => {
|
|
164
|
+
if (!session) return "无法获取会话信息。";
|
|
165
|
+
if (session.platform !== "onebot") return "该指令仅支持 napuketto 平台。";
|
|
166
|
+
return renderPresetList(ACTION_PRESETS);
|
|
167
|
+
});
|
|
168
|
+
ctx.command("adbg.run <method:string> [params...]", "调用 NapukettoQQ 适配器的标准动作", { authority: config.minAuthority }).action(async ({ session }, method, ...tokens) => {
|
|
169
|
+
if (!session) return "无法获取会话信息。";
|
|
170
|
+
if (session.platform !== "onebot") return "该指令仅支持 napuketto 平台。";
|
|
171
|
+
const bot = getDebugBot(ctx, session);
|
|
172
|
+
if (!bot) return "未找到可用的 napuketto bot。";
|
|
173
|
+
const params = {};
|
|
174
|
+
for (const token of tokens) {
|
|
175
|
+
const separator = token.indexOf("=");
|
|
176
|
+
if (separator === -1) return `无效参数:${token}(应为 key=value 形式)`;
|
|
177
|
+
const key = token.slice(0, separator);
|
|
178
|
+
const raw = token.slice(separator + 1);
|
|
179
|
+
if (/^-?\d+$/.test(raw)) params[key] = Number(raw);
|
|
180
|
+
else if (raw === "true" || raw === "false") params[key] = raw === "true";
|
|
181
|
+
else params[key] = raw;
|
|
182
|
+
}
|
|
183
|
+
return renderResult(await runAction(ctx, bot, method, params, session.channelId), config.maxOutputLength);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
exports.Config = Config;
|
|
188
|
+
exports.apply = apply;
|
|
189
|
+
exports.name = name;
|
|
190
|
+
exports.usage = usage;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Context, Schema } from "koishi";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
declare const name = "adapter-debugger";
|
|
4
|
+
declare const usage = "\n<div style=\"border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);\">\n <h2 style=\"margin-top: 0; color: #4a6ee0;\">🛠️ 适配器协议调试器</h2>\n <p>🔌 针对 <strong>NapukettoQQ</strong> 适配器(<code>koishi-plugin-adapter-napuketto</code>)的标准动作诊断工具</p>\n <p>🧪 调用 koishi 标准 <code>bot.internal</code> 方法,逐一验证适配器 → IPC → kernel 链路是否可用</p>\n <p>⚠️ 仅适用于 <strong>napuketto</strong> 平台,调试工具请谨慎授权</p>\n</div>\n\n<div style=\"border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);\">\n <h2 style=\"margin-top: 0; color: #e0574a;\">⚡ 命令</h2>\n <ul>\n <li><code>adbg.list</code> — 列出已收录的标准动作及参数模板</li>\n <li><code>adbg.run <method> [key=value ...]</code> — 调用指定标准方法并展示耗时与结果</li>\n </ul>\n</div>\n\n<div style=\"border-radius: 10px; border: 1px solid #ddd; padding: 16px; margin-bottom: 20px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);\">\n <h2 style=\"margin-top: 0; color: #4a6ee0;\">🧩 已收录方法</h2>\n <ul>\n <li><code>getSelf</code> — 登录账号自身信息</li>\n <li><code>sendMessage</code> — 发送消息</li>\n <li><code>deleteMessage</code> — 撤回消息</li>\n <li><code>getMessageList</code> — 拉取消息历史</li>\n <li><code>markAsRead</code> — 标记已读</li>\n <li><code>getGroupList</code> — 群列表</li>\n <li><code>getFriendList</code> — 好友列表</li>\n </ul>\n <p>📌 方法清单对应 adapter 的 <code>NapukettoInternal</code> 实现,随 adapter 扩充同步更新</p>\n</div>\n";
|
|
5
|
+
interface Config {
|
|
6
|
+
/**
|
|
7
|
+
* 使用调试指令所需的最低用户权限等级。
|
|
8
|
+
* Koishi 默认权限:0 未授权,1 普通用户,2 管理员,3 超管,4+ 自定义。
|
|
9
|
+
*/
|
|
10
|
+
minAuthority: number;
|
|
11
|
+
/** 单次 action 调用超时(毫秒)。 */
|
|
12
|
+
timeout: number;
|
|
13
|
+
/** 结果文本最大长度(超出截断)。 */
|
|
14
|
+
maxOutputLength: number;
|
|
15
|
+
}
|
|
16
|
+
declare const Config: Schema<Config>;
|
|
17
|
+
declare function apply(ctx: Context, config: Config): void;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { Config, apply, name, usage };
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;cAsBa;cAEA;UA+BI;;;;;EAKb;;EAEA;;EAEA;;cAGS,QAAQ,OAAO;iBAyDZ,MAAM,KAAK,SAAS,QAAQ"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "koishi-plugin-adapter-debugger",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "调试 NapukettoQQ 适配器的协议 action(逐一验证是否可用)",
|
|
5
|
+
"contributors": [
|
|
6
|
+
"Oppenheymu <oppenheymu@gmail.com>"
|
|
7
|
+
],
|
|
8
|
+
"main": "lib/index.cjs",
|
|
9
|
+
"types": "lib/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./lib/index.d.ts",
|
|
13
|
+
"development": "./src/index.ts",
|
|
14
|
+
"default": "./lib/index.cjs"
|
|
15
|
+
},
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"lib"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"chatbot",
|
|
27
|
+
"koishi",
|
|
28
|
+
"plugin",
|
|
29
|
+
"napuketto",
|
|
30
|
+
"debugger",
|
|
31
|
+
"adapter"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "pnpm --dir ../.. exec tsdown -W -F koishi-plugin-adapter-debugger",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"koishi": "^4.17.4"
|
|
39
|
+
},
|
|
40
|
+
"koishi": {
|
|
41
|
+
"description": {
|
|
42
|
+
"en": "Debug & test NapukettoQQ adapter protocol actions",
|
|
43
|
+
"zh": "调试 NapukettoQQ 适配器的协议 action(逐一验证是否可用)"
|
|
44
|
+
},
|
|
45
|
+
"service": {}
|
|
46
|
+
},
|
|
47
|
+
"type": "module"
|
|
48
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# koishi-plugin-adapter-debugger
|
|
2
|
+
|
|
3
|
+
调试 [koishi-plugin-adapter-napuketto](https://github.com/Oppenheymu/koishi-plugin-adapter-napuketto) 协议 action 的诊断插件。
|
|
4
|
+
|
|
5
|
+
## 用途
|
|
6
|
+
|
|
7
|
+
NapukettoQQ 适配器通过 `bot.internal._request(action, params)` 走 IPC 调用 kernel API。
|
|
8
|
+
本插件用于在真实运行环境中逐一验证这些协议 action 是否可用、返回什么数据、报什么错。
|
|
9
|
+
|
|
10
|
+
## 已收录的 action(IPC 动作表)
|
|
11
|
+
|
|
12
|
+
来源:`NapukettoQQ/packages/loader/src/host/ipc/ipc-actions.ts`
|
|
13
|
+
|
|
14
|
+
| action | 说明 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `login.getSelf` | 登录账号自身信息 |
|
|
17
|
+
| `msg.sendMessage` | 发送消息(canonical elements) |
|
|
18
|
+
| `msg.recallMessage` | 撤回消息 |
|
|
19
|
+
| `msg.fetchMessages` | 拉取消息历史 |
|
|
20
|
+
| `msg.markRead` | 标记已读 |
|
|
21
|
+
| `group.getGroupList` | 群列表 |
|
|
22
|
+
| `friend.getFriendList` | 好友列表 |
|
|
23
|
+
|
|
24
|
+
## 开发
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm build # tsc -b 编译
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
TODO:
|
|
31
|
+
- [ ] `adbg.list` — 列出已知 action 与参数模板
|
|
32
|
+
- [ ] `adbg.run <action> [key=value ...]` — 执行任意 action 并展示耗时/结果/错误
|
|
33
|
+
- [ ] 错误码解析(NOT_FOUND / TIMEOUT / CLOSED / kernel 错误码)
|