@bgicli/bgicli 2.4.0 → 2.4.2

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.
Files changed (3) hide show
  1. package/README.md +57 -11
  2. package/dist/bgi.js +26 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  - ✅ **开箱即用** — `npm install -g @bgicli/bgicli` 即可
6
6
  - ✅ **内置 889 个技能** — 21 个生信工作流 + 868 个 OpenClaw 医学技能,自动安装
7
7
  - ✅ **智能技能路由** — 描述任务自动激活对应技能,无需手动搜索
8
- - ✅ **中国 AI 服务商** — 百炼(DashScope)聚合:Qwen3.5、DeepSeek、Kimi、MiniMax 等 20+ 模型
8
+ - ✅ **中国 AI 服务商** — 百炼(DashScope)聚合:Qwen、DeepSeek、Kimi、MiniMax 等 20+ 模型
9
9
  - ✅ **真实工具调用** — 执行 bash、读写文件、运行 R/Python 脚本
10
10
  - ✅ **内网支持** — 可接入公司私有化部署的大模型
11
11
 
@@ -91,7 +91,7 @@ bgi # 启动
91
91
  ### 服务商 / 模型
92
92
  | 命令 | 说明 |
93
93
  |------|------|
94
- | `/provider <name>` | 切换服务商 (`bailian` / `intranet` / `custom`) |
94
+ | `/provider <name>` | 切换服务商(`bailian` / `intranet` / `custom`) |
95
95
  | `/model <name>` | 切换模型 |
96
96
  | `/models` | 列出当前服务商所有可用模型 |
97
97
  | `/providers` | 列出所有服务商 |
@@ -116,6 +116,34 @@ bgi # 启动
116
116
  | `/save [文件名]` | 保存对话为 Markdown 文件 |
117
117
  | `/think [on\|off]` | 切换思考模式(Qwen3 `/think` 前缀) |
118
118
 
119
+ ### 断点与恢复
120
+ | 命令 | 说明 |
121
+ |------|------|
122
+ | `/checkpoint` | 保存当前对话断点(含激活的技能) |
123
+ | `/checkpoint save [标签]` | 保存断点并指定标签 |
124
+ | `/checkpoint list` | 列出本次会话所有断点 |
125
+ | `/checkpoint restore <id>` | 恢复到指定断点 |
126
+
127
+ > 适合长时间分析任务中途保存进度,防止意外中断丢失上下文。
128
+
129
+ ### 数据库管理
130
+ | 命令 | 说明 |
131
+ |------|------|
132
+ | `/db list` | 列出已注册的参考数据库 |
133
+ | `/db add <路径> [基因组] [类型] [说明]` | 手动注册数据库路径 |
134
+ | `/db scan [目录]` | 自动扫描文件系统查找已知数据库 |
135
+ | `/db rm <id>` | 删除数据库记录 |
136
+ | `/db download [名称]` | 显示标准数据库下载命令 |
137
+
138
+ > 注册后 AI 可自动引用正确路径,无需每次手动指定。支持 hg38/hg19/mm10 基因组、STAR/HISAT2 索引、GTF 注释等。
139
+
140
+ ### 安全扫描
141
+ | 命令 | 说明 |
142
+ |------|------|
143
+ | `/scan <命令>` | 扫描命令安全风险,输出 CRITICAL / HIGH / MEDIUM / LOW 等级 |
144
+
145
+ > AI 执行每条 bash 命令前均自动扫描;CRITICAL 级别命令将被拦截。
146
+
119
147
  ### 文件与目录
120
148
  | 命令 | 说明 |
121
149
  |------|------|
@@ -124,11 +152,27 @@ bgi # 启动
124
152
  | `/tools` | 列出 AI 可调用的工具 |
125
153
  | `@路径` | 消息中内嵌文件内容(如 `@data.csv 里有什么?`) |
126
154
 
155
+ ### 会话报告与记忆
156
+ 退出时(双击 Ctrl+C 或输入 `exit`)自动显示会话报告:
157
+ - 运行时长
158
+ - 消耗 Token(输入 / 输出)
159
+ - 执行命令成功 / 失败次数
160
+ - 可选保存会话记忆到 `~/.bgicli/memory/`
161
+
127
162
  ### 其他
128
163
  | 命令 | 说明 |
129
164
  |------|------|
130
165
  | `/help` | 显示帮助 |
131
- | `exit` / `quit` / `q` | 退出 |
166
+ | `exit` / `quit` / `q` | 退出(显示会话报告) |
167
+
168
+ ---
169
+
170
+ ## 快捷键
171
+
172
+ | 快捷键 | 说明 |
173
+ |--------|------|
174
+ | `Ctrl+C`(单次) | 中断当前 AI 任务(保留对话历史) |
175
+ | `Ctrl+C`(连按两次) | 退出程序(显示会话报告) |
132
176
 
133
177
  ---
134
178
 
@@ -195,14 +239,16 @@ npm link
195
239
 
196
240
  ```
197
241
  bgi
198
- ├── src/index.ts — CLI 主入口、命令处理、智能路由
199
- ├── src/chat.ts 流式对话引擎(工具调用循环)
200
- ├── src/tools.ts — 工具实现(bash / read_file / write_file 等)
201
- ├── src/skillRouter.ts 关键词路由表(35个核心技能自动匹配)
202
- ├── src/prompt.ts 生物信息学系统提示
203
- ├── src/providers.ts 中国 AI 服务商配置
204
- ├── src/config.ts 配置管理(~/.bgicli/config.json)
205
- └── data/ 内置数据(工作流 + Skills + Python 工具)
242
+ ├── src/index.ts — CLI 主入口、命令处理、智能路由、会话管理
243
+ ├── src/chat.ts 流式对话引擎(工具调用循环、进度渲染)
244
+ ├── src/tools.ts — 工具实现(bash / read_file / write_file 等)
245
+ ├── src/security.ts 命令安全扫描(CRITICAL / HIGH / MEDIUM / LOW)
246
+ ├── src/databases.ts 参考数据库注册与管理
247
+ ├── src/skillRouter.ts 关键词路由表(35个核心技能自动匹配)
248
+ ├── src/prompt.ts 生物信息学系统提示
249
+ ├── src/providers.ts 中国 AI 服务商配置
250
+ ├── src/config.ts — 配置管理(~/.bgicli/config.json)
251
+ └── data/ — 内置数据(工作流 + Skills + Python 工具)
206
252
  ```
207
253
 
208
254
  ---
package/dist/bgi.js CHANGED
@@ -13605,10 +13605,12 @@ var BGI_DIR = (0, import_path2.join)((0, import_os.homedir)(), ".bgicli");
13605
13605
  var WORKFLOWS_DIR = (0, import_path2.join)(BGI_DIR, "workflows");
13606
13606
  var TOOLS_DIR = (0, import_path2.join)(BGI_DIR, "tools");
13607
13607
  var SKILLS_DIR = (0, import_path2.join)(BGI_DIR, "skills");
13608
+ var USER_SKILLS_DIR = (0, import_path2.join)(BGI_DIR, "user-skills");
13608
13609
  var DATABASES_FILE = (0, import_path2.join)(BGI_DIR, "databases.json");
13610
+ var DATA_VERSION_FILE = (0, import_path2.join)(BGI_DIR, ".data-version");
13609
13611
  var CONFIG_FILE = (0, import_path2.join)(BGI_DIR, "config.json");
13610
13612
  function ensureDirs() {
13611
- for (const dir of [BGI_DIR, WORKFLOWS_DIR, TOOLS_DIR, SKILLS_DIR]) {
13613
+ for (const dir of [BGI_DIR, WORKFLOWS_DIR, TOOLS_DIR, SKILLS_DIR, USER_SKILLS_DIR]) {
13612
13614
  if (!(0, import_fs2.existsSync)(dir)) (0, import_fs2.mkdirSync)(dir, { recursive: true });
13613
13615
  }
13614
13616
  }
@@ -15999,7 +16001,7 @@ function clearCheckpoints(sessionId) {
15999
16001
 
16000
16002
  // src/index.ts
16001
16003
  var import_fs7 = require("fs");
16002
- var VERSION2 = "2.4.0";
16004
+ var VERSION2 = "2.4.2";
16003
16005
  var SKILLHUB_HUBS = {
16004
16006
  bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
16005
16007
  clawhub: { label: "clawhub.ai", apiBase: "https://clawhub.ai", backend: "clawhub" },
@@ -16146,6 +16148,8 @@ function installBundledData() {
16146
16148
  const bundledData = (0, import_path6.join)(__dirname, "..", "data");
16147
16149
  if (!(0, import_fs6.existsSync)(bundledData)) return;
16148
16150
  ensureDirs();
16151
+ const installedDataVersion = (0, import_fs6.existsSync)(DATA_VERSION_FILE) ? (0, import_fs6.readFileSync)(DATA_VERSION_FILE, "utf8").trim() : "";
16152
+ const needsUpdate = installedDataVersion !== VERSION2;
16149
16153
  const targets = [
16150
16154
  { src: (0, import_path6.join)(bundledData, "workflows"), dest: WORKFLOWS_DIR, name: "Skills (\u751F\u4FE1\u5DE5\u4F5C\u6D41)" },
16151
16155
  { src: (0, import_path6.join)(bundledData, "skills"), dest: SKILLS_DIR, name: "Skills (\u533B\u5B66\u4E13\u79D1)" },
@@ -16155,18 +16159,24 @@ function installBundledData() {
16155
16159
  for (const { src, dest, name } of targets) {
16156
16160
  if (!(0, import_fs6.existsSync)(src)) continue;
16157
16161
  const isEmpty = !(0, import_fs6.existsSync)(dest) || (0, import_fs6.readdirSync)(dest).length === 0;
16158
- if (isEmpty) {
16162
+ if (isEmpty || needsUpdate) {
16159
16163
  (0, import_fs6.mkdirSync)(dest, { recursive: true });
16160
- (0, import_fs6.cpSync)(src, dest, { recursive: true });
16164
+ (0, import_fs6.cpSync)(src, dest, { recursive: true, force: true });
16161
16165
  if (!installed) {
16162
- process.stdout.write(source_default.dim("\u6B63\u5728\u521D\u59CB\u5316\u5185\u7F6E\u6570\u636E...\n"));
16166
+ process.stdout.write(source_default.dim(needsUpdate && !isEmpty ? `\u66F4\u65B0\u5185\u7F6E\u6570\u636E\u5230 v${VERSION2}...
16167
+ ` : "\u6B63\u5728\u521D\u59CB\u5316\u5185\u7F6E\u6570\u636E...\n"));
16163
16168
  installed = true;
16164
16169
  }
16165
- process.stdout.write(source_default.green(` \u2713 ${name} \u5DF2\u5B89\u88C5
16170
+ process.stdout.write(source_default.green(` \u2713 ${name} \u5DF2${needsUpdate && !isEmpty ? "\u66F4\u65B0" : "\u5B89\u88C5"}
16166
16171
  `));
16167
16172
  }
16168
16173
  }
16169
- if (installed) console.log();
16174
+ if (installed) {
16175
+ (0, import_fs6.writeFileSync)(DATA_VERSION_FILE, VERSION2, "utf8");
16176
+ console.log();
16177
+ } else if (needsUpdate) {
16178
+ (0, import_fs6.writeFileSync)(DATA_VERSION_FILE, VERSION2, "utf8");
16179
+ }
16170
16180
  }
16171
16181
  function printBanner() {
16172
16182
  console.log(source_default.cyan.bold(`
@@ -16347,6 +16357,7 @@ function collectAllSkills() {
16347
16357
  };
16348
16358
  addFrom(SKILLS_DIR, "skill");
16349
16359
  addFrom(WORKFLOWS_DIR, "skill");
16360
+ addFrom(USER_SKILLS_DIR, "user");
16350
16361
  return entries;
16351
16362
  }
16352
16363
  function listSkills(keyword) {
@@ -17173,7 +17184,7 @@ ${paramSummary}
17173
17184
  const isGitHub = installArg.includes("github.com") || installArg.includes("gitlab") || installArg.includes("bitbucket") || /^[^/]+\/[^/]+$/.test(installArg);
17174
17185
  if (!isGitHub && !installArg.startsWith("http")) {
17175
17186
  const slug = installArg.trim();
17176
- const installTarget2 = (0, import_path6.join)(SKILLS_DIR, slug);
17187
+ const installTarget2 = (0, import_path6.join)(USER_SKILLS_DIR, slug);
17177
17188
  if ((0, import_fs6.existsSync)(installTarget2)) {
17178
17189
  console.log(source_default.yellow(`Skill "${slug}" \u5DF2\u5B58\u5728\uFF0C\u5982\u9700\u66F4\u65B0\u8BF7\u5148 /uninstall ${slug}`));
17179
17190
  break;
@@ -17213,7 +17224,7 @@ ${paramSummary}
17213
17224
  repoUrl = `https://github.com/${repoUrl}`;
17214
17225
  }
17215
17226
  const repoName = repoUrl.replace(/\.git$/, "").split("/").pop() ?? "unknown-skill";
17216
- const installTarget = (0, import_path6.join)(SKILLS_DIR, repoName);
17227
+ const installTarget = (0, import_path6.join)(USER_SKILLS_DIR, repoName);
17217
17228
  if ((0, import_fs6.existsSync)(installTarget)) {
17218
17229
  console.log(source_default.yellow(`Skill "${repoName}" \u5DF2\u5B58\u5728\uFF0C\u5982\u9700\u66F4\u65B0\u8BF7\u5148 /uninstall ${repoName}`));
17219
17230
  break;
@@ -17246,7 +17257,7 @@ ${paramSummary}
17246
17257
  console.log("\u7528\u6CD5: /uninstall <skill-id>");
17247
17258
  break;
17248
17259
  }
17249
- const uninstallPath = (0, import_path6.join)(SKILLS_DIR, arg);
17260
+ const uninstallPath = (0, import_fs6.existsSync)((0, import_path6.join)(USER_SKILLS_DIR, arg)) ? (0, import_path6.join)(USER_SKILLS_DIR, arg) : (0, import_path6.join)(SKILLS_DIR, arg);
17250
17261
  if (!(0, import_fs6.existsSync)(uninstallPath)) {
17251
17262
  console.log(source_default.red(`\u672A\u627E\u5230\u5DF2\u5B89\u88C5\u7684 Skill: ${arg}`));
17252
17263
  console.log(source_default.dim("\u6CE8\u610F: \u53EA\u80FD\u5378\u8F7D\u901A\u8FC7 /install \u5B89\u88C5\u7684\u7B2C\u4E09\u65B9 Skill"));
@@ -17651,11 +17662,14 @@ async function main() {
17651
17662
  await firstRunIfNeeded(rl);
17652
17663
  const cfg = loadConfig();
17653
17664
  const prov = PROVIDERS[cfg.provider];
17654
- const totalSkills = collectAllSkills().length;
17665
+ const allSkillsList = collectAllSkills();
17666
+ const totalSkills = allSkillsList.length;
17667
+ const userSkillCount = allSkillsList.filter((e2) => e2.tag === "user").length;
17668
+ const skillsLabel = totalSkills > 0 ? source_default.green(`${totalSkills} \u4E2A`) + (userSkillCount > 0 ? source_default.dim(` (\u542B ${userSkillCount} \u4E2A\u7528\u6237\u5B89\u88C5)`) : "") : source_default.yellow("\u672A\u5B89\u88C5");
17655
17669
  console.log(source_default.bold.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
17656
17670
  console.log(` ${source_default.bold("\u670D\u52A1\u5546:")} ${prov?.name ?? cfg.provider}`);
17657
17671
  console.log(` ${source_default.bold("\u6A21\u578B:")} ${source_default.green(cfg.model)}`);
17658
- console.log(` ${source_default.bold("Skills:")} ${totalSkills > 0 ? source_default.green(`${totalSkills} \u4E2A`) : source_default.yellow("\u672A\u5B89\u88C5")} ${source_default.dim("(/sk \u641C\u7D22 /cat \u5206\u7C7B\u76EE\u5F55)")}`);
17672
+ console.log(` ${source_default.bold("Skills:")} ${skillsLabel} ${source_default.dim("(/sk \u641C\u7D22 /cat \u5206\u7C7B\u76EE\u5F55)")}`);
17659
17673
  console.log(` ${source_default.bold("\u5DE5\u5177:")} bash \xB7 read_file \xB7 write_file \xB7 list_dir \xB7 search_files`);
17660
17674
  console.log(` ${source_default.bold("\u65B0\u529F\u80FD:")} /sessions /resume /checkpoint /run /check-env /install /diff`);
17661
17675
  console.log(source_default.bold.cyan("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgicli/bgicli",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "BGI CLI — Bioinformatics AI terminal for Chinese researchers (百炼/DeepSeek/Kimi/Qwen)",
5
5
  "bin": {
6
6
  "bgi": "dist/bgi.js"