dsh-shlr-bilitoolkit 0.1.15 → 0.1.17
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 +2 -1
- package/README.md +98 -0
- package/dist/dsh.d.ts +5 -0
- package/dist/dsh.js +196 -41
- package/package.json +1 -1
package/AGENTS.md
CHANGED
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# dsh-shlr-bilitoolkit
|
|
2
|
+
|
|
3
|
+
B 站(哔哩哔哩)接口封装的 **TypeScript** 移植版,作为 [dsh](https://dshmp.com)(DeepSeek Harness)插件提供「视频 / 搜索 / 空间 / 专栏 / 动态 / 评论 / 关注 / 消息中心」等读取能力,以及点赞、收藏、投币、关注、评论、私信、三连、发动态等写操作。
|
|
4
|
+
|
|
5
|
+
> 本项目从原 Python 工具箱(`bili/`)完整移植而来,并作为 dsh(cordis 体系)插件提供上述能力。
|
|
6
|
+
|
|
7
|
+
## 安装
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 已发布到 npm
|
|
11
|
+
dsh plugin --profile <name> add dsh-shlr-bilitoolkit@latest
|
|
12
|
+
|
|
13
|
+
# 本地开发 / 试运行
|
|
14
|
+
npm install
|
|
15
|
+
npm run build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
本地登录(独立获取 Cookie,终端打印 ASCII 二维码):
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install && npm run login
|
|
22
|
+
# 或指定 Cookie 文件
|
|
23
|
+
BILI_COOKIE_FILE=./my_cookies.json npm run login
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 插件入口
|
|
27
|
+
|
|
28
|
+
对齐官方 cordis 规范:`src/dsh.ts` 导出 `name` / `inject = ["tools"]` / `apply(ctx)`,在 `apply` 内用官方 `ctx.tools.register(defineTool({ name, description, parameters, output, execute }))` 注册每个工具。`defineTool` 来自 `@deepseek-ai/dsh-tools`,由宿主提供、插件不打包(保证单实例),已在 `peerDependencies` 声明。`cordis.patch.yml` 为组合包配置层(`- insert: - id: bili name: dsh-shlr-bilitoolkit`,按包名解析到 `main`)。较旧、没有 `ctx.tools` 的 dsh 仍保留 `ctx.registerTool` / `ctx.services.tools.register` 回退。
|
|
29
|
+
|
|
30
|
+
## 工具清单
|
|
31
|
+
|
|
32
|
+
同类能力已用参数合并(`type` / `target` / `action` / `list`),**功能未减少**。
|
|
33
|
+
|
|
34
|
+
- **读取**:
|
|
35
|
+
`bili_recommend` · `bili_video_detail` · `bili_video_subtitle` · `bili_search` · `bili_space_info` · `bili_space_videos` · `bili_article_view` · `bili_article_list` · `bili_dynamic_feed` · `bili_dynamic_space` · `bili_comment_list` · `bili_relation_list` · `bili_notify_unread` · `bili_notify_list` · `bili_fav_folders` · `bili_video_pagelist` · `bili_video_playurl` · `bili_video_status` · `bili_space_collections` · `bili_space_collection` · `bili_fav_folder_videos` · `bili_dynamic_detail` · `bili_message_unread` · `bili_message_history` · `bili_relation_stat` · `bili_user_following` · `bili_profile_info` · `bili_comment_replies`
|
|
36
|
+
- **写操作**(均会真实修改账号状态,需登录):
|
|
37
|
+
`bili_like` · `bili_follow` · `bili_favorite` · `bili_send_message` · `bili_triple` · `bili_dynamic_publish` · `bili_dynamic_repost` · `bili_coin` · `bili_fav_folder_create` · `bili_fav_folder_delete` · `bili_dynamic_like` · `bili_dynamic_delete` · `bili_comment_send` · `bili_comment_reply` · `bili_comment_delete` · `bili_comment_like` · `bili_message_recall` · `bili_profile_update`
|
|
38
|
+
- **辅助**:`bili_login_status`(查登录态)· `bili_gen_qr`(生成登录二维码)· `bili_cache_clear`(清空本地缓存)
|
|
39
|
+
|
|
40
|
+
合并工具的公共参数约定:
|
|
41
|
+
|
|
42
|
+
| 工具 | 参数 |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `bili_search` | `type=video\|user`,`order`(仅视频) |
|
|
45
|
+
| `bili_relation_list` | `type=followings\|followers` |
|
|
46
|
+
| `bili_notify_list` | `type=replies\|ats\|likes` |
|
|
47
|
+
| `bili_favorite` | `action=add\|remove` |
|
|
48
|
+
| `bili_video_subtitle` | `list=true` 时列字幕轨,否则取正文 |
|
|
49
|
+
| `bili_comment_*` | `target=video\|dynamic\|article`,`id`(bvid / 动态 id / 专栏 cv 号) |
|
|
50
|
+
| `bili_profile_update` | `uname` / `sex` / `birthday` / `sign`(至少一项) |
|
|
51
|
+
|
|
52
|
+
## 数据目录
|
|
53
|
+
|
|
54
|
+
Cookie / 缓存 / 二维码 / 设备号统一放在一个目录,默认 `bili_data/`(相对 dsh 工作目录),避免散落污染工作目录:
|
|
55
|
+
|
|
56
|
+
| 文件 | 用途 |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `bili_cookies.json` | 登录 Cookie(`SESSDATA` / `bili_jct`) |
|
|
59
|
+
| `bili_cache.json` | WBI 签名密钥 + `bvid→aid` 缓存(原子写、损坏自愈) |
|
|
60
|
+
| `bili_qrcode.png` | 最近一次生成的登录二维码 |
|
|
61
|
+
| `bili_device.json` | 私信设备号 `dev_id`(跨重启稳定,降低风控) |
|
|
62
|
+
|
|
63
|
+
可用环境变量:`BILI_DATA_DIR`(改目录)、`BILI_COOKIE_FILE` / `BILI_CACHE_FILE` / `BILI_QR_FILE` / `BILI_DEVICE_FILE`(精确指定单个文件)。兼容旧版:若新目录还没有 Cookie、而旧位置 `./bili_cookies.json` 有,会继续沿用。
|
|
64
|
+
|
|
65
|
+
## 给 Agent 的约定
|
|
66
|
+
|
|
67
|
+
仓库根目录的 [`AGENTS.md`](./AGENTS.md) 约定:需要登录时必须调用 `bili_gen_qr` 并把二维码**图片**展示给用户(而非只给链接或 ASCII)。把该 `AGENTS.md` 放到 dsh 工作目录,agent 即会遵守。
|
|
68
|
+
|
|
69
|
+
## 目录结构
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
src/
|
|
73
|
+
client.ts BiliClient:Session / Cookie / 请求 / 节流 / 重试 / 风控 / 表单编码
|
|
74
|
+
wbi.ts WbiSigner:w_rid / wts 签名(官方 mixin_key 算法,密钥落盘缓存 6h)
|
|
75
|
+
cache.ts JsonCache:本地 JSON 缓存(TTL / 原子写 / 损坏自愈)
|
|
76
|
+
errors.ts BiliApiError / CaptchaRequired / CookieError
|
|
77
|
+
models.ts 纯数据模型 + toDict()
|
|
78
|
+
formatting.ts 播放量 / 时长 / HTML 清理等展示格式化
|
|
79
|
+
pagination.ts iterPages:统一分页异步生成器
|
|
80
|
+
endpoints.ts 所有接口 URL 常量
|
|
81
|
+
apis/ video / search / space / comment / message / interact / dynamic /
|
|
82
|
+
article / relation / notify / profile / auth / download
|
|
83
|
+
dsh.ts dsh 插件入口:apply(ctx) + 工具清单
|
|
84
|
+
index.ts 对外导出
|
|
85
|
+
tests/ 离线单测(wbi 签名、格式化、缓存、lossless JSON 等)
|
|
86
|
+
cordis.patch.yml dsh 组合包配置层
|
|
87
|
+
scripts/login.ts npm run login 扫码登录脚本
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 与原 Python 版的差异 / 已知限制
|
|
91
|
+
|
|
92
|
+
- **写接口为表单编码**:`client.post` 默认把对象编码为 `application/x-www-form-urlencoded`,仅动态点赞等少数接口显式走 JSON(`jsonBody=true`)。
|
|
93
|
+
- **动态仅支持纯文字**:带图 / 投票 / 预约的富动态需额外图片上传流程,暂未实现。
|
|
94
|
+
- **下载 / ffmpeg**:`src/apis/download.ts` 为纯工具函数,未接入 dsh 工具。
|
|
95
|
+
|
|
96
|
+
## 风控说明
|
|
97
|
+
|
|
98
|
+
内置与原 Python 版一致的基础降风控策略:请求节流(默认 0.6s + 0~0.4s 抖动)、GET 退避重试、写操作不重试、HTTP 412 / `-412` 立即停手、WBI 签名。但单账号操作量上限、避免短时间切 IP/UA 等仍需使用习惯配合。设备号 `dev_id` 已落盘保持稳定。
|
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,204 @@ 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_cache_clear",
|
|
1078
|
+
"bili_recommend",
|
|
1079
|
+
"bili_video_detail",
|
|
1080
|
+
"bili_search",
|
|
1081
|
+
];
|
|
1082
|
+
// 能力分组(group -> 提示 + 工具 id)。核心工具也会出现在所属组里,便于目录展示,
|
|
1083
|
+
// 但打开时不会重复注册(见 bili_open 里的 CORE_IDS 判断)。
|
|
1084
|
+
export const GROUPS = {
|
|
1085
|
+
video: {
|
|
1086
|
+
hint: "视频:推荐 / 详情 / 字幕 / 分P / 播放地址 / 互动状态",
|
|
1087
|
+
ids: ["bili_recommend", "bili_video_detail", "bili_video_subtitle", "bili_video_pagelist", "bili_video_playurl", "bili_video_status"],
|
|
1088
|
+
},
|
|
1089
|
+
search: { hint: "搜索视频或用户", ids: ["bili_search"] },
|
|
1090
|
+
space: { hint: "用户空间:资料 / 投稿 / 合集", ids: ["bili_space_info", "bili_space_videos", "bili_space_collections", "bili_space_collection"] },
|
|
1091
|
+
article: { hint: "专栏:详情 / 某用户的专栏列表", ids: ["bili_article_view", "bili_article_list"] },
|
|
1092
|
+
dynamic: { hint: "动态:动态流 / 某用户动态 / 详情 / 发布 / 转发 / 点赞 / 删除", ids: ["bili_dynamic_feed", "bili_dynamic_space", "bili_dynamic_detail", "bili_dynamic_publish", "bili_dynamic_repost", "bili_dynamic_like", "bili_dynamic_delete"] },
|
|
1093
|
+
comment: { hint: "评论:列表 / 发表 / 楼中楼 / 回复 / 删除 / 点赞(视频·动态·专栏)", ids: ["bili_comment_list", "bili_comment_send", "bili_comment_replies", "bili_comment_reply", "bili_comment_delete", "bili_comment_like"] },
|
|
1094
|
+
social: { hint: "互动:点赞 / 投币 / 收藏·取消收藏 / 关注·取关 / 是否关注 / 三连", ids: ["bili_like", "bili_coin", "bili_favorite", "bili_follow", "bili_user_following", "bili_triple"] },
|
|
1095
|
+
favorite: { hint: "收藏夹:列表 / 内容 / 新建 / 删除", ids: ["bili_fav_folders", "bili_fav_folder_videos", "bili_fav_folder_create", "bili_fav_folder_delete"] },
|
|
1096
|
+
relation: { hint: "关注关系:关注/粉丝列表 / 关注粉丝统计", ids: ["bili_relation_list", "bili_relation_stat"] },
|
|
1097
|
+
message: { hint: "私信:发送 / 未读 / 聊天记录 / 撤回", ids: ["bili_send_message", "bili_message_unread", "bili_message_history", "bili_message_recall"] },
|
|
1098
|
+
notify: { hint: "消息中心:未读 / 回复·@·赞 列表", ids: ["bili_notify_unread", "bili_notify_list"] },
|
|
1099
|
+
profile: { hint: "个人资料:查看 / 修改", ids: ["bili_profile_info", "bili_profile_update"] },
|
|
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_catalog",
|
|
1148
|
+
description: "列出 B 站能力分组与每组包含的工具。要用某个 B 站能力但不确定工具名时,先调本工具,再调 bili_open 打开对应分组(打开后下一轮起该组工具可调用)。",
|
|
1149
|
+
parameters: { type: "object", properties: {} },
|
|
1150
|
+
handler: async () => ({
|
|
1151
|
+
groups: Object.entries(GROUPS).map(([name, g]) => ({
|
|
1152
|
+
group: name,
|
|
1153
|
+
hint: g.hint,
|
|
1154
|
+
tools: g.ids,
|
|
1155
|
+
open: openGroups.has(name),
|
|
1156
|
+
})),
|
|
1157
|
+
how: "bili_open({ group }) 或 bili_open({ tool }) 打开;bili_close({ group }) 关闭以节省上下文。",
|
|
1158
|
+
}),
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
id: "bili_open",
|
|
1162
|
+
description: "打开一组 B 站工具(group),或直接给工具名(tool)自动打开其所在组。打开后该组工具在下一轮即可调用。同时最多保留 3 组,超出会关闭最久未用的组。",
|
|
1163
|
+
parameters: {
|
|
1164
|
+
type: "object",
|
|
1165
|
+
properties: {
|
|
1166
|
+
group: { type: "string", description: "分组名(见 bili_catalog)" },
|
|
1167
|
+
tool: { type: "string", description: "或直接给工具名,自动打开其所在组" },
|
|
1087
1168
|
},
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1169
|
+
},
|
|
1170
|
+
handler: async (a) => {
|
|
1171
|
+
if (!toolsRegistry) {
|
|
1172
|
+
return { ok: false, message: "当前运行时不支持动态注册,懒加载不可用" };
|
|
1173
|
+
}
|
|
1174
|
+
let group = String(a.group ?? "").trim();
|
|
1175
|
+
if (!group && a.tool)
|
|
1176
|
+
group = groupOfTool(String(a.tool));
|
|
1177
|
+
if (!group || !GROUPS[group]) {
|
|
1178
|
+
return { ok: false, message: `未知分组/工具,可用分组:${Object.keys(GROUPS).join(", ")}` };
|
|
1179
|
+
}
|
|
1180
|
+
if (openGroups.has(group)) {
|
|
1181
|
+
const i = groupLru.indexOf(group);
|
|
1182
|
+
if (i >= 0)
|
|
1183
|
+
groupLru.splice(i, 1);
|
|
1184
|
+
groupLru.push(group);
|
|
1185
|
+
return { ok: true, group, alreadyOpen: true, tools: GROUPS[group].ids };
|
|
1186
|
+
}
|
|
1187
|
+
while (groupLru.length >= MAX_OPEN_GROUPS) {
|
|
1188
|
+
const oldest = groupLru.shift();
|
|
1189
|
+
if (oldest)
|
|
1190
|
+
closeGroup(oldest);
|
|
1191
|
+
}
|
|
1192
|
+
const disposers = [];
|
|
1193
|
+
const loaded = [];
|
|
1194
|
+
for (const id of GROUPS[group].ids) {
|
|
1195
|
+
if (CORE_IDS.includes(id)) {
|
|
1196
|
+
loaded.push(id);
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1199
|
+
const t = TOOL_BY_ID.get(id);
|
|
1200
|
+
if (!t)
|
|
1201
|
+
continue;
|
|
1202
|
+
try {
|
|
1203
|
+
const d = toolsRegistry.register(buildDef(t));
|
|
1204
|
+
if (typeof d === "function")
|
|
1205
|
+
disposers.push(d);
|
|
1206
|
+
loaded.push(id);
|
|
1207
|
+
}
|
|
1208
|
+
catch { /* 单个注册失败不影响其它 */ }
|
|
1209
|
+
}
|
|
1210
|
+
openGroups.set(group, disposers);
|
|
1211
|
+
groupLru.push(group);
|
|
1212
|
+
return { ok: true, group, tools: loaded, note: "该组工具已打开,下一轮起可调用。" };
|
|
1213
|
+
},
|
|
1214
|
+
},
|
|
1215
|
+
{
|
|
1216
|
+
id: "bili_close",
|
|
1217
|
+
description: "关闭一组已打开的 B 站工具,释放上下文。不确定分组名先用 bili_catalog。",
|
|
1218
|
+
parameters: {
|
|
1219
|
+
type: "object",
|
|
1220
|
+
properties: { group: { type: "string" } },
|
|
1221
|
+
required: ["group"],
|
|
1222
|
+
},
|
|
1223
|
+
handler: async (a) => {
|
|
1224
|
+
const group = String(a.group ?? "").trim();
|
|
1225
|
+
if (!openGroups.has(group))
|
|
1226
|
+
return { ok: false, message: "该组未打开" };
|
|
1227
|
+
closeGroup(group);
|
|
1228
|
+
return { ok: true, closed: group };
|
|
1229
|
+
},
|
|
1230
|
+
},
|
|
1231
|
+
];
|
|
1232
|
+
/** 用最可用的注册入口注册一个内部工具。 */
|
|
1233
|
+
function registerOne(ctx, tool) {
|
|
1234
|
+
const def = buildDef(tool);
|
|
1235
|
+
if (ctx?.tools?.register)
|
|
1236
|
+
ctx.tools.register(def);
|
|
1237
|
+
else if (typeof ctx?.registerTool === "function") {
|
|
1238
|
+
ctx.registerTool({ id: tool.id, description: tool.description, parameters: tool.parameters, handler: tool.handler });
|
|
1239
|
+
}
|
|
1240
|
+
else if (ctx?.services?.tools?.register) {
|
|
1241
|
+
ctx.services.tools.register(def);
|
|
1242
|
+
}
|
|
1243
|
+
else if (typeof ctx?.provide === "function") {
|
|
1244
|
+
ctx.provide(`tools:${tool.id}`, tool);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
export function apply(ctx) {
|
|
1248
|
+
// 捕获工具注册表,供 bili_open 动态注册 / bili_close 卸载
|
|
1249
|
+
toolsRegistry =
|
|
1250
|
+
ctx?.tools && typeof ctx.tools.register === "function" ? ctx.tools : null;
|
|
1251
|
+
// 懒加载机制工具始终注册
|
|
1252
|
+
for (const t of lazyTools)
|
|
1253
|
+
registerOne(ctx, t);
|
|
1254
|
+
// BILI_LAZY=0 可强制关闭懒加载(全部注册),用于兜底
|
|
1255
|
+
const lazyDisabled = process.env.BILI_LAZY === "0" || process.env.BILI_LAZY === "false";
|
|
1256
|
+
if (!toolsRegistry || lazyDisabled) {
|
|
1257
|
+
// 运行时不支持动态注册 / 手动关闭:退化为全部注册(功能完整,但不省 token)
|
|
1258
|
+
for (const t of TOOLS)
|
|
1259
|
+
registerOne(ctx, t);
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
// 仅注册常驻核心,其余按需通过 bili_open 打开
|
|
1263
|
+
for (const id of CORE_IDS) {
|
|
1264
|
+
const t = TOOL_BY_ID.get(id);
|
|
1265
|
+
if (t)
|
|
1266
|
+
registerOne(ctx, t);
|
|
1112
1267
|
}
|
|
1113
1268
|
}
|
|
1114
1269
|
// 同时导出库的全部公共 API(BiliClient / 各 API 类 / 模型等),
|