dsh-shlr-bilitoolkit 0.1.16 → 0.1.18
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/AGENTS.md +6 -6
- package/dist/dsh.d.ts +5 -0
- package/dist/dsh.js +178 -41
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
(Agent 必读)
|
|
1
|
+
# AGENTS.md — dsh-shlr-bilitoolkit(Agent 必读)
|
|
2
2
|
|
|
3
3
|
## 登录(务必遵守)
|
|
4
|
-
用户要登录 B
|
|
5
|
-
**必须调用
|
|
6
|
-
|
|
7
|
-
禁止:只给链接、用 ASCII/文本二维码、让用户自己跑命令。用户扫码确认后调用 `bili_login_status` 完成登录并保存 Cookie。
|
|
4
|
+
用户要登录 B 站,或任何操作返回未登录(-101 / 未登录 / CookieError)时:
|
|
5
|
+
**必须调用 bili_gen_qr,并把返回的二维码图片展示给用户扫码**——用 qrDataUrl 以 Markdown 图片 `` 渲染(或引用 qrImageUrl / qrImagePath)。
|
|
6
|
+
禁止只给链接、用 ASCII、让用户自己跑命令。用户确认后调 bili_login_status 完成登录。
|
|
8
7
|
|
|
9
8
|
## 其它
|
|
10
|
-
|
|
9
|
+
- 非常驻的 B 站能力懒加载:`bili_open()` 看分组,`bili_open({ group })` 打开(下一轮生效)。
|
|
10
|
+
- 写操作会真实修改账号状态,执行前先与用户确认。
|
package/dist/dsh.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface DshTool {
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function toLosslessJson(value: unknown): unknown;
|
|
33
33
|
export declare const TOOLS: DshTool[];
|
|
34
|
+
export declare const CORE_IDS: string[];
|
|
35
|
+
export declare const GROUPS: Record<string, {
|
|
36
|
+
hint: string;
|
|
37
|
+
ids: string[];
|
|
38
|
+
}>;
|
|
34
39
|
export declare function apply(ctx: any): void;
|
|
35
40
|
export * from "./index.js";
|
|
36
41
|
export { BiliClient, Video, User, Page, PlayInfo, Subtitle, Collection };
|
package/dist/dsh.js
CHANGED
|
@@ -1066,49 +1066,186 @@ export const TOOLS = [
|
|
|
1066
1066
|
},
|
|
1067
1067
|
},
|
|
1068
1068
|
];
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1069
|
+
let toolsRegistry = null;
|
|
1070
|
+
const openGroups = new Map();
|
|
1071
|
+
const groupLru = [];
|
|
1072
|
+
const MAX_OPEN_GROUPS = 3;
|
|
1073
|
+
// 常驻核心:登录链路必须随时可用 + 最常用的几个读取
|
|
1074
|
+
export const CORE_IDS = [
|
|
1075
|
+
"bili_gen_qr",
|
|
1076
|
+
"bili_login_status",
|
|
1077
|
+
"bili_recommend",
|
|
1078
|
+
"bili_video_detail",
|
|
1079
|
+
"bili_search",
|
|
1080
|
+
];
|
|
1081
|
+
// 能力分组(group -> 提示 + 工具 id)。核心工具也会出现在所属组里,便于目录展示,
|
|
1082
|
+
// 但打开时不会重复注册(见 bili_open 里的 CORE_IDS 判断)。
|
|
1083
|
+
export const GROUPS = {
|
|
1084
|
+
video: {
|
|
1085
|
+
hint: "视频:推荐 / 详情 / 字幕 / 分P / 播放地址 / 互动状态",
|
|
1086
|
+
ids: ["bili_recommend", "bili_video_detail", "bili_video_subtitle", "bili_video_pagelist", "bili_video_playurl", "bili_video_status"],
|
|
1087
|
+
},
|
|
1088
|
+
search: { hint: "搜索视频或用户", ids: ["bili_search"] },
|
|
1089
|
+
space: { hint: "用户空间:资料 / 投稿 / 合集", ids: ["bili_space_info", "bili_space_videos", "bili_space_collections", "bili_space_collection"] },
|
|
1090
|
+
article: { hint: "专栏:详情 / 某用户的专栏列表", ids: ["bili_article_view", "bili_article_list"] },
|
|
1091
|
+
dynamic: { hint: "动态:动态流 / 某用户动态 / 详情 / 发布 / 转发 / 点赞 / 删除", ids: ["bili_dynamic_feed", "bili_dynamic_space", "bili_dynamic_detail", "bili_dynamic_publish", "bili_dynamic_repost", "bili_dynamic_like", "bili_dynamic_delete"] },
|
|
1092
|
+
comment: { hint: "评论:列表 / 发表 / 楼中楼 / 回复 / 删除 / 点赞(视频·动态·专栏)", ids: ["bili_comment_list", "bili_comment_send", "bili_comment_replies", "bili_comment_reply", "bili_comment_delete", "bili_comment_like"] },
|
|
1093
|
+
social: { hint: "互动:点赞 / 投币 / 收藏·取消收藏 / 关注·取关 / 是否关注 / 三连", ids: ["bili_like", "bili_coin", "bili_favorite", "bili_follow", "bili_user_following", "bili_triple"] },
|
|
1094
|
+
favorite: { hint: "收藏夹:列表 / 内容 / 新建 / 删除", ids: ["bili_fav_folders", "bili_fav_folder_videos", "bili_fav_folder_create", "bili_fav_folder_delete"] },
|
|
1095
|
+
relation: { hint: "关注关系:关注/粉丝列表 / 关注粉丝统计", ids: ["bili_relation_list", "bili_relation_stat"] },
|
|
1096
|
+
message: { hint: "私信:发送 / 未读 / 聊天记录 / 撤回", ids: ["bili_send_message", "bili_message_unread", "bili_message_history", "bili_message_recall"] },
|
|
1097
|
+
notify: { hint: "消息中心:未读 / 回复·@·赞 列表", ids: ["bili_notify_unread", "bili_notify_list"] },
|
|
1098
|
+
profile: { hint: "个人资料:查看 / 修改", ids: ["bili_profile_info", "bili_profile_update"] },
|
|
1099
|
+
misc: { hint: "维护:清空本地缓存", ids: ["bili_cache_clear"] },
|
|
1100
|
+
};
|
|
1101
|
+
const TOOL_BY_ID = new Map(TOOLS.map((t) => [t.id, t]));
|
|
1102
|
+
function groupOfTool(id) {
|
|
1103
|
+
for (const [g, def] of Object.entries(GROUPS)) {
|
|
1104
|
+
if (def.ids.includes(id))
|
|
1105
|
+
return g;
|
|
1106
|
+
}
|
|
1107
|
+
return "";
|
|
1108
|
+
}
|
|
1109
|
+
function closeGroup(group) {
|
|
1110
|
+
const disposers = openGroups.get(group);
|
|
1111
|
+
if (disposers)
|
|
1112
|
+
for (const d of disposers) {
|
|
1113
|
+
try {
|
|
1114
|
+
d();
|
|
1115
|
+
}
|
|
1116
|
+
catch { /* ignore */ }
|
|
1078
1117
|
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1118
|
+
openGroups.delete(group);
|
|
1119
|
+
const i = groupLru.indexOf(group);
|
|
1120
|
+
if (i >= 0)
|
|
1121
|
+
groupLru.splice(i, 1);
|
|
1122
|
+
}
|
|
1123
|
+
/** 把一个内部 DshTool 编译成官方 defineTool 定义。 */
|
|
1124
|
+
function buildDef(tool) {
|
|
1125
|
+
const output = {
|
|
1126
|
+
schema: { type: "object", additionalProperties: true },
|
|
1127
|
+
render: tool.render ??
|
|
1128
|
+
((_args, value) => [{ type: "text", text: textOf(value) }]),
|
|
1129
|
+
};
|
|
1130
|
+
if (tool.presentationMeta)
|
|
1131
|
+
output.presentationMeta = tool.presentationMeta;
|
|
1132
|
+
const options = {
|
|
1133
|
+
name: tool.id,
|
|
1134
|
+
description: tool.description,
|
|
1135
|
+
parameters: toDshParameters(tool.parameters),
|
|
1136
|
+
output,
|
|
1137
|
+
async execute(args) {
|
|
1138
|
+
return toLosslessJson(await tool.handler(args));
|
|
1139
|
+
},
|
|
1140
|
+
};
|
|
1141
|
+
if (tool.presentResult)
|
|
1142
|
+
options.presentResult = tool.presentResult;
|
|
1143
|
+
return defineTool(options);
|
|
1144
|
+
}
|
|
1145
|
+
const lazyTools = [
|
|
1146
|
+
{
|
|
1147
|
+
id: "bili_open",
|
|
1148
|
+
description: "B 站能力开关。不带参数调用=列出所有能力分组;带 group(分组名)或 tool(工具名)调用=打开该组,打开后下一轮起可调用。同时最多保留 3 组,超出自动关闭最久未用的。",
|
|
1149
|
+
parameters: {
|
|
1150
|
+
type: "object",
|
|
1151
|
+
properties: {
|
|
1152
|
+
group: { type: "string", description: "分组名(不带参调用可列出)" },
|
|
1153
|
+
tool: { type: "string", description: "或直接给工具名,自动打开其所在组" },
|
|
1087
1154
|
},
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1155
|
+
},
|
|
1156
|
+
handler: async (a) => {
|
|
1157
|
+
// 不带参数:列出能力目录
|
|
1158
|
+
if (a.group == null && a.tool == null) {
|
|
1159
|
+
return {
|
|
1160
|
+
groups: Object.entries(GROUPS).map(([name, g]) => ({
|
|
1161
|
+
group: name,
|
|
1162
|
+
hint: g.hint,
|
|
1163
|
+
tools: g.ids,
|
|
1164
|
+
open: openGroups.has(name),
|
|
1165
|
+
})),
|
|
1166
|
+
how: "带 group 或 tool 再次调用本工具即可打开;同时最多保留 3 组。",
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
if (!toolsRegistry) {
|
|
1170
|
+
return { ok: false, message: "当前运行时不支持动态注册,懒加载不可用" };
|
|
1171
|
+
}
|
|
1172
|
+
let group = String(a.group ?? "").trim();
|
|
1173
|
+
if (!group && a.tool)
|
|
1174
|
+
group = groupOfTool(String(a.tool));
|
|
1175
|
+
if (!group || !GROUPS[group]) {
|
|
1176
|
+
return { ok: false, message: `未知分组/工具,可用分组:${Object.keys(GROUPS).join(", ")}` };
|
|
1177
|
+
}
|
|
1178
|
+
if (openGroups.has(group)) {
|
|
1179
|
+
const i = groupLru.indexOf(group);
|
|
1180
|
+
if (i >= 0)
|
|
1181
|
+
groupLru.splice(i, 1);
|
|
1182
|
+
groupLru.push(group);
|
|
1183
|
+
return { ok: true, group, alreadyOpen: true, tools: GROUPS[group].ids };
|
|
1184
|
+
}
|
|
1185
|
+
while (groupLru.length >= MAX_OPEN_GROUPS) {
|
|
1186
|
+
const oldest = groupLru.shift();
|
|
1187
|
+
if (oldest)
|
|
1188
|
+
closeGroup(oldest);
|
|
1189
|
+
}
|
|
1190
|
+
const disposers = [];
|
|
1191
|
+
const loaded = [];
|
|
1192
|
+
for (const id of GROUPS[group].ids) {
|
|
1193
|
+
if (CORE_IDS.includes(id)) {
|
|
1194
|
+
loaded.push(id);
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
const t = TOOL_BY_ID.get(id);
|
|
1198
|
+
if (!t)
|
|
1199
|
+
continue;
|
|
1200
|
+
try {
|
|
1201
|
+
const d = toolsRegistry.register(buildDef(t));
|
|
1202
|
+
if (typeof d === "function")
|
|
1203
|
+
disposers.push(d);
|
|
1204
|
+
loaded.push(id);
|
|
1205
|
+
}
|
|
1206
|
+
catch { /* 单个注册失败不影响其它 */ }
|
|
1207
|
+
}
|
|
1208
|
+
openGroups.set(group, disposers);
|
|
1209
|
+
groupLru.push(group);
|
|
1210
|
+
return { ok: true, group, tools: loaded, note: "该组工具已打开,下一轮起可调用。" };
|
|
1211
|
+
},
|
|
1212
|
+
},
|
|
1213
|
+
];
|
|
1214
|
+
/** 用最可用的注册入口注册一个内部工具。 */
|
|
1215
|
+
function registerOne(ctx, tool) {
|
|
1216
|
+
const def = buildDef(tool);
|
|
1217
|
+
if (ctx?.tools?.register)
|
|
1218
|
+
ctx.tools.register(def);
|
|
1219
|
+
else if (typeof ctx?.registerTool === "function") {
|
|
1220
|
+
ctx.registerTool({ id: tool.id, description: tool.description, parameters: tool.parameters, handler: tool.handler });
|
|
1221
|
+
}
|
|
1222
|
+
else if (ctx?.services?.tools?.register) {
|
|
1223
|
+
ctx.services.tools.register(def);
|
|
1224
|
+
}
|
|
1225
|
+
else if (typeof ctx?.provide === "function") {
|
|
1226
|
+
ctx.provide(`tools:${tool.id}`, tool);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
export function apply(ctx) {
|
|
1230
|
+
// 捕获工具注册表,供 bili_open 动态注册 / bili_close 卸载
|
|
1231
|
+
toolsRegistry =
|
|
1232
|
+
ctx?.tools && typeof ctx.tools.register === "function" ? ctx.tools : null;
|
|
1233
|
+
// 懒加载机制工具始终注册
|
|
1234
|
+
for (const t of lazyTools)
|
|
1235
|
+
registerOne(ctx, t);
|
|
1236
|
+
// BILI_LAZY=0 可强制关闭懒加载(全部注册),用于兜底
|
|
1237
|
+
const lazyDisabled = process.env.BILI_LAZY === "0" || process.env.BILI_LAZY === "false";
|
|
1238
|
+
if (!toolsRegistry || lazyDisabled) {
|
|
1239
|
+
// 运行时不支持动态注册 / 手动关闭:退化为全部注册(功能完整,但不省 token)
|
|
1240
|
+
for (const t of TOOLS)
|
|
1241
|
+
registerOne(ctx, t);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
// 仅注册常驻核心,其余按需通过 bili_open 打开
|
|
1245
|
+
for (const id of CORE_IDS) {
|
|
1246
|
+
const t = TOOL_BY_ID.get(id);
|
|
1247
|
+
if (t)
|
|
1248
|
+
registerOne(ctx, t);
|
|
1112
1249
|
}
|
|
1113
1250
|
}
|
|
1114
1251
|
// 同时导出库的全部公共 API(BiliClient / 各 API 类 / 模型等),
|