@bgicli/bgicli 2.8.3 → 2.8.5

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 (4) hide show
  1. package/dist/bgi.js +123 -26
  2. package/dist/bio.js +123 -26
  3. package/dist/mbp.js +123 -26
  4. package/package.json +1 -1
package/dist/bgi.js CHANGED
@@ -15172,13 +15172,20 @@ ${label} `);
15172
15172
  clearSpinner();
15173
15173
  process.stdout.write(`${label}
15174
15174
  `);
15175
+ let heartbeatActive = false;
15175
15176
  heartbeat = setInterval(() => {
15176
- if (Date.now() - lastChunkTime >= 5e3) {
15177
- const totalSecs = ((Date.now() - t0) / 1e3).toFixed(0);
15178
- process.stdout.write(source_default.dim(`
15179
- \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`));
15177
+ if (Date.now() - lastChunkTime >= 3e3) {
15178
+ const totalSecs = ((Date.now() - t0) / 1e3).toFixed(1);
15179
+ if (!heartbeatActive) {
15180
+ process.stdout.write("\n");
15181
+ heartbeatActive = true;
15182
+ }
15183
+ process.stdout.write(`\r${source_default.dim(` \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`)}\x1B[K`);
15184
+ } else if (heartbeatActive) {
15185
+ process.stdout.write("\r\x1B[K");
15186
+ heartbeatActive = false;
15180
15187
  }
15181
- }, 5e3);
15188
+ }, 100);
15182
15189
  }
15183
15190
  let i2 = 0;
15184
15191
  while (i2 < chunk.length) {
@@ -17912,12 +17919,12 @@ function clearCheckpoints(sessionId) {
17912
17919
 
17913
17920
  // src/index.ts
17914
17921
  var import_fs7 = require("fs");
17915
- var VERSION2 = "2.8.3";
17922
+ var VERSION2 = "2.8.5";
17916
17923
  var BRAND2 = "bgi".toLowerCase();
17917
17924
  var SKILLHUB_HUBS = {
17918
- bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
17925
+ bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
17919
17926
  clawhub: { label: "clawhub.ai", apiBase: "https://clawhub.ai", backend: "clawhub" },
17920
- tencent: { label: "Tencent", apiBase: "https://lightmake.site", backend: "tencent" }
17927
+ tencent: { label: "\u817E\u8BAF SkillHub", apiBase: "https://skillhub.tencent.com", backend: "tencent" }
17921
17928
  };
17922
17929
  function httpGetJson(url) {
17923
17930
  const mod = url.startsWith("https") ? import_https2.get : require("http").get;
@@ -17940,9 +17947,58 @@ function httpGetJson(url) {
17940
17947
  req.on("error", reject);
17941
17948
  });
17942
17949
  }
17950
+ function searchLocalSkills(query, limit2) {
17951
+ const kw = query.toLowerCase();
17952
+ const results = [];
17953
+ const seen = /* @__PURE__ */ new Set();
17954
+ const scanDir = (dir) => {
17955
+ if (!(0, import_fs6.existsSync)(dir)) return;
17956
+ let entries;
17957
+ try {
17958
+ entries = (0, import_fs6.readdirSync)(dir);
17959
+ } catch {
17960
+ return;
17961
+ }
17962
+ for (const entry of entries) {
17963
+ if (seen.has(entry)) continue;
17964
+ const skillDir = (0, import_path6.join)(dir, entry);
17965
+ try {
17966
+ if (!(0, import_fs6.statSync)(skillDir).isDirectory()) continue;
17967
+ } catch {
17968
+ continue;
17969
+ }
17970
+ let name = entry;
17971
+ let summary = "";
17972
+ const mdPath = (0, import_path6.join)(skillDir, "SKILL.md");
17973
+ if ((0, import_fs6.existsSync)(mdPath)) {
17974
+ try {
17975
+ const lines = (0, import_fs6.readFileSync)(mdPath, "utf8").split("\n").slice(0, 30);
17976
+ for (const line of lines) {
17977
+ const nm = line.match(/^name:\s*["']?(.+?)["']?\s*$/);
17978
+ const sd = line.match(/^short-description:\s*["']?(.+?)["']?\s*$/);
17979
+ const dsc = line.match(/^description:\s*["']?(.+?)["']?\s*$/);
17980
+ if (nm) name = nm[1].trim();
17981
+ if (sd) summary = sd[1].trim();
17982
+ else if (dsc && !summary) summary = dsc[1].trim();
17983
+ }
17984
+ } catch {
17985
+ }
17986
+ }
17987
+ if (entry.toLowerCase().includes(kw) || name.toLowerCase().includes(kw) || summary.toLowerCase().includes(kw)) {
17988
+ seen.add(entry);
17989
+ results.push({ slug: entry, name, summary });
17990
+ }
17991
+ }
17992
+ };
17993
+ scanDir(BIO_SKILLS_DIR);
17994
+ scanDir(USER_SKILLS_DIR);
17995
+ return results.slice(0, limit2);
17996
+ }
17943
17997
  async function searchSkillHub(query, hub, limit2 = 10) {
17944
17998
  const cfg = SKILLHUB_HUBS[hub];
17945
- if (cfg.backend === "tencent") {
17999
+ if (cfg.backend === "local") {
18000
+ return searchLocalSkills(query, limit2);
18001
+ } else if (cfg.backend === "tencent") {
17946
18002
  const data = await httpGetJson(
17947
18003
  `${cfg.apiBase}/api/skills?page=1&pageSize=${limit2}&keyword=${encodeURIComponent(query)}`
17948
18004
  );
@@ -17952,7 +18008,7 @@ async function searchSkillHub(query, hub, limit2 = 10) {
17952
18008
  name: s2.name,
17953
18009
  summary: s2.description ?? "",
17954
18010
  version: s2.version,
17955
- owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*clawhub\.ai\/([^/]+)\/.*/, "$1") : void 0)
18011
+ owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*skillhub\.tencent\.com\/([^/]+)\/.*/, "$1") : void 0)
17956
18012
  }));
17957
18013
  } else {
17958
18014
  const data = await httpGetJson(
@@ -18229,7 +18285,7 @@ function printHelp() {
18229
18285
  console.log(source_default.bold.cyan("\u2500\u2500\u2500 Skill \u5411\u5BFC \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"));
18230
18286
  console.log(` ${source_default.cyan("/run")} <skill-id> \u4EA4\u4E92\u5F0F\u53C2\u6570\u5411\u5BFC\uFF0C\u81EA\u52A8\u751F\u6210\u5E76\u6267\u884C\u5206\u6790\u811A\u672C`);
18231
18287
  console.log(` ${source_default.cyan("/check-env")} [id] \u68C0\u6D4B Skill \u6240\u9700 R/Python \u5305\u662F\u5426\u5DF2\u5B89\u88C5`);
18232
- console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u5728 SkillHub \u641C\u7D22\u5E76\u4E0B\u8F7D\u6280\u80FD ${source_default.dim("[--hub=bgi|clawhub|tencent]")}`);
18288
+ console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u641C\u7D22 Skills ${source_default.dim("[--hub=bgi|clawhub|tencent|all]")}`);
18233
18289
  console.log(` ${source_default.cyan("/install")} <url|slug> \u4ECE GitHub \u6216 SkillHub \u5B89\u88C5 Skill\uFF08\u542B\u5B89\u5168\u626B\u63CF\uFF09`);
18234
18290
  console.log(` ${source_default.cyan("/uninstall")} <id> \u5378\u8F7D\u5DF2\u5B89\u88C5\u7684\u7B2C\u4E09\u65B9 Skill`);
18235
18291
  console.log();
@@ -19107,30 +19163,71 @@ ${paramSummary}
19107
19163
  // ── /search SkillHub ─────────────────────────────────────────────────────
19108
19164
  case "search": {
19109
19165
  if (!arg) {
19110
- console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent]");
19111
- console.log(source_default.dim("\u793A\u4F8B: /search rnaseq"));
19112
- console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19113
- console.log(source_default.dim(" /search genomics --hub=clawhub"));
19114
- console.log(source_default.dim("\n\u9ED8\u8BA4\u641C\u7D22 BGI \u5185\u7F51 SkillHub (http://172.16.218.40:8080)"));
19166
+ console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent|all]");
19167
+ console.log(source_default.dim(" bgi \u2014 BGI \u672C\u5730\u5DF2\u5B89\u88C5 Skills\uFF08\u9ED8\u8BA4\uFF0C\u6781\u5FEB\uFF09"));
19168
+ console.log(source_default.dim(" clawhub \u2014 clawhub.ai \u5B98\u65B9 SkillHub"));
19169
+ console.log(source_default.dim(" tencent \u2014 \u817E\u8BAF SkillHub (skillhub.tencent.com)"));
19170
+ console.log(source_default.dim(" all \u2014 \u540C\u65F6\u641C\u7D22\u5168\u90E8\u4E09\u4E2A\u6765\u6E90"));
19171
+ console.log(source_default.dim("\n\u793A\u4F8B:"));
19172
+ console.log(source_default.dim(" /search rnaseq"));
19173
+ console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19174
+ console.log(source_default.dim(" /search genomics --hub=all"));
19115
19175
  break;
19116
19176
  }
19117
- let hubKey = "bgi";
19118
19177
  const hubMatch = arg.match(/--hub=(\w+)/);
19119
19178
  const query = arg.replace(/--hub=\w+/g, "").trim();
19120
- if (hubMatch) {
19121
- const hk = hubMatch[1];
19122
- if (hk in SKILLHUB_HUBS) hubKey = hk;
19123
- else {
19124
- console.log(source_default.red(`\u672A\u77E5 hub: ${hubMatch[1]}\uFF0C\u53EF\u9009: bgi, clawhub, tencent`));
19125
- break;
19126
- }
19127
- }
19179
+ const hubArg = hubMatch ? hubMatch[1] : "bgi";
19128
19180
  if (!query) {
19129
19181
  console.log(source_default.yellow("\u8BF7\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD"));
19130
19182
  break;
19131
19183
  }
19184
+ if (hubArg === "all") {
19185
+ console.log(source_default.dim(`
19186
+ \u6B63\u5728\u641C\u7D22\u5168\u90E8 SkillHub: "${query}"...
19187
+ `));
19188
+ const hubKeys = ["bgi", "clawhub", "tencent"];
19189
+ const allResults = [];
19190
+ await Promise.all(hubKeys.map(async (hk) => {
19191
+ try {
19192
+ const results = await searchSkillHub(query, hk, 5);
19193
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results });
19194
+ } catch (e2) {
19195
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results: [], error: e2 instanceof Error ? e2.message : String(e2) });
19196
+ }
19197
+ }));
19198
+ allResults.sort((a2, b2) => hubKeys.indexOf(a2.hub) - hubKeys.indexOf(b2.hub));
19199
+ _lastSearchResults = [];
19200
+ let globalIdx = 1;
19201
+ for (const { label, results, error } of allResults) {
19202
+ if (error) {
19203
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500`) + source_default.red(` \u641C\u7D22\u5931\u8D25: ${error}`));
19204
+ } else if (results.length === 0) {
19205
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500 \u65E0\u7ED3\u679C`));
19206
+ } else {
19207
+ console.log(source_default.bold.dim(` \u2500\u2500 ${label} (${results.length}) \u2500\u2500`));
19208
+ for (const s2 of results) {
19209
+ const ver = s2.version ? source_default.dim(` v${s2.version}`) : "";
19210
+ const owner = s2.owner ? source_default.dim(` @${s2.owner}`) : "";
19211
+ console.log(` ${source_default.cyan(`[${globalIdx}]`)} ${source_default.bold(s2.name)}${owner}${ver}`);
19212
+ console.log(` ${source_default.dim(s2.summary.substring(0, 90))}${s2.summary.length > 90 ? "\u2026" : ""}`);
19213
+ console.log(` ${source_default.dim(`slug: ${s2.slug}`)}`);
19214
+ _lastSearchResults.push(s2);
19215
+ globalIdx++;
19216
+ }
19217
+ }
19218
+ console.log();
19219
+ }
19220
+ if (_lastSearchResults.length > 0)
19221
+ console.log(source_default.dim(`\u5B89\u88C5: /install <slug> \u6216 /install <\u5E8F\u53F7> (\u5982: /install 1)`));
19222
+ break;
19223
+ }
19224
+ if (!(hubArg in SKILLHUB_HUBS)) {
19225
+ console.log(source_default.red(`\u672A\u77E5 hub: ${hubArg}\uFF0C\u53EF\u9009: bgi, clawhub, tencent, all`));
19226
+ break;
19227
+ }
19228
+ const hubKey = hubArg;
19132
19229
  const hubLabel = SKILLHUB_HUBS[hubKey].label;
19133
- process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel} SkillHub: "${query}"...
19230
+ process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel}: "${query}"...
19134
19231
  `));
19135
19232
  try {
19136
19233
  const results = await searchSkillHub(query, hubKey, 10);
package/dist/bio.js CHANGED
@@ -15172,13 +15172,20 @@ ${label} `);
15172
15172
  clearSpinner();
15173
15173
  process.stdout.write(`${label}
15174
15174
  `);
15175
+ let heartbeatActive = false;
15175
15176
  heartbeat = setInterval(() => {
15176
- if (Date.now() - lastChunkTime >= 5e3) {
15177
- const totalSecs = ((Date.now() - t0) / 1e3).toFixed(0);
15178
- process.stdout.write(source_default.dim(`
15179
- \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`));
15177
+ if (Date.now() - lastChunkTime >= 3e3) {
15178
+ const totalSecs = ((Date.now() - t0) / 1e3).toFixed(1);
15179
+ if (!heartbeatActive) {
15180
+ process.stdout.write("\n");
15181
+ heartbeatActive = true;
15182
+ }
15183
+ process.stdout.write(`\r${source_default.dim(` \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`)}\x1B[K`);
15184
+ } else if (heartbeatActive) {
15185
+ process.stdout.write("\r\x1B[K");
15186
+ heartbeatActive = false;
15180
15187
  }
15181
- }, 5e3);
15188
+ }, 100);
15182
15189
  }
15183
15190
  let i2 = 0;
15184
15191
  while (i2 < chunk.length) {
@@ -17912,12 +17919,12 @@ function clearCheckpoints(sessionId) {
17912
17919
 
17913
17920
  // src/index.ts
17914
17921
  var import_fs7 = require("fs");
17915
- var VERSION2 = "2.8.3";
17922
+ var VERSION2 = "2.8.5";
17916
17923
  var BRAND2 = "bio".toLowerCase();
17917
17924
  var SKILLHUB_HUBS = {
17918
- bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
17925
+ bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
17919
17926
  clawhub: { label: "clawhub.ai", apiBase: "https://clawhub.ai", backend: "clawhub" },
17920
- tencent: { label: "Tencent", apiBase: "https://lightmake.site", backend: "tencent" }
17927
+ tencent: { label: "\u817E\u8BAF SkillHub", apiBase: "https://skillhub.tencent.com", backend: "tencent" }
17921
17928
  };
17922
17929
  function httpGetJson(url) {
17923
17930
  const mod = url.startsWith("https") ? import_https2.get : require("http").get;
@@ -17940,9 +17947,58 @@ function httpGetJson(url) {
17940
17947
  req.on("error", reject);
17941
17948
  });
17942
17949
  }
17950
+ function searchLocalSkills(query, limit2) {
17951
+ const kw = query.toLowerCase();
17952
+ const results = [];
17953
+ const seen = /* @__PURE__ */ new Set();
17954
+ const scanDir = (dir) => {
17955
+ if (!(0, import_fs6.existsSync)(dir)) return;
17956
+ let entries;
17957
+ try {
17958
+ entries = (0, import_fs6.readdirSync)(dir);
17959
+ } catch {
17960
+ return;
17961
+ }
17962
+ for (const entry of entries) {
17963
+ if (seen.has(entry)) continue;
17964
+ const skillDir = (0, import_path6.join)(dir, entry);
17965
+ try {
17966
+ if (!(0, import_fs6.statSync)(skillDir).isDirectory()) continue;
17967
+ } catch {
17968
+ continue;
17969
+ }
17970
+ let name = entry;
17971
+ let summary = "";
17972
+ const mdPath = (0, import_path6.join)(skillDir, "SKILL.md");
17973
+ if ((0, import_fs6.existsSync)(mdPath)) {
17974
+ try {
17975
+ const lines = (0, import_fs6.readFileSync)(mdPath, "utf8").split("\n").slice(0, 30);
17976
+ for (const line of lines) {
17977
+ const nm = line.match(/^name:\s*["']?(.+?)["']?\s*$/);
17978
+ const sd = line.match(/^short-description:\s*["']?(.+?)["']?\s*$/);
17979
+ const dsc = line.match(/^description:\s*["']?(.+?)["']?\s*$/);
17980
+ if (nm) name = nm[1].trim();
17981
+ if (sd) summary = sd[1].trim();
17982
+ else if (dsc && !summary) summary = dsc[1].trim();
17983
+ }
17984
+ } catch {
17985
+ }
17986
+ }
17987
+ if (entry.toLowerCase().includes(kw) || name.toLowerCase().includes(kw) || summary.toLowerCase().includes(kw)) {
17988
+ seen.add(entry);
17989
+ results.push({ slug: entry, name, summary });
17990
+ }
17991
+ }
17992
+ };
17993
+ scanDir(BIO_SKILLS_DIR);
17994
+ scanDir(USER_SKILLS_DIR);
17995
+ return results.slice(0, limit2);
17996
+ }
17943
17997
  async function searchSkillHub(query, hub, limit2 = 10) {
17944
17998
  const cfg = SKILLHUB_HUBS[hub];
17945
- if (cfg.backend === "tencent") {
17999
+ if (cfg.backend === "local") {
18000
+ return searchLocalSkills(query, limit2);
18001
+ } else if (cfg.backend === "tencent") {
17946
18002
  const data = await httpGetJson(
17947
18003
  `${cfg.apiBase}/api/skills?page=1&pageSize=${limit2}&keyword=${encodeURIComponent(query)}`
17948
18004
  );
@@ -17952,7 +18008,7 @@ async function searchSkillHub(query, hub, limit2 = 10) {
17952
18008
  name: s2.name,
17953
18009
  summary: s2.description ?? "",
17954
18010
  version: s2.version,
17955
- owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*clawhub\.ai\/([^/]+)\/.*/, "$1") : void 0)
18011
+ owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*skillhub\.tencent\.com\/([^/]+)\/.*/, "$1") : void 0)
17956
18012
  }));
17957
18013
  } else {
17958
18014
  const data = await httpGetJson(
@@ -18229,7 +18285,7 @@ function printHelp() {
18229
18285
  console.log(source_default.bold.cyan("\u2500\u2500\u2500 Skill \u5411\u5BFC \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"));
18230
18286
  console.log(` ${source_default.cyan("/run")} <skill-id> \u4EA4\u4E92\u5F0F\u53C2\u6570\u5411\u5BFC\uFF0C\u81EA\u52A8\u751F\u6210\u5E76\u6267\u884C\u5206\u6790\u811A\u672C`);
18231
18287
  console.log(` ${source_default.cyan("/check-env")} [id] \u68C0\u6D4B Skill \u6240\u9700 R/Python \u5305\u662F\u5426\u5DF2\u5B89\u88C5`);
18232
- console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u5728 SkillHub \u641C\u7D22\u5E76\u4E0B\u8F7D\u6280\u80FD ${source_default.dim("[--hub=bgi|clawhub|tencent]")}`);
18288
+ console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u641C\u7D22 Skills ${source_default.dim("[--hub=bgi|clawhub|tencent|all]")}`);
18233
18289
  console.log(` ${source_default.cyan("/install")} <url|slug> \u4ECE GitHub \u6216 SkillHub \u5B89\u88C5 Skill\uFF08\u542B\u5B89\u5168\u626B\u63CF\uFF09`);
18234
18290
  console.log(` ${source_default.cyan("/uninstall")} <id> \u5378\u8F7D\u5DF2\u5B89\u88C5\u7684\u7B2C\u4E09\u65B9 Skill`);
18235
18291
  console.log();
@@ -19107,30 +19163,71 @@ ${paramSummary}
19107
19163
  // ── /search SkillHub ─────────────────────────────────────────────────────
19108
19164
  case "search": {
19109
19165
  if (!arg) {
19110
- console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent]");
19111
- console.log(source_default.dim("\u793A\u4F8B: /search rnaseq"));
19112
- console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19113
- console.log(source_default.dim(" /search genomics --hub=clawhub"));
19114
- console.log(source_default.dim("\n\u9ED8\u8BA4\u641C\u7D22 BGI \u5185\u7F51 SkillHub (http://172.16.218.40:8080)"));
19166
+ console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent|all]");
19167
+ console.log(source_default.dim(" bgi \u2014 BGI \u672C\u5730\u5DF2\u5B89\u88C5 Skills\uFF08\u9ED8\u8BA4\uFF0C\u6781\u5FEB\uFF09"));
19168
+ console.log(source_default.dim(" clawhub \u2014 clawhub.ai \u5B98\u65B9 SkillHub"));
19169
+ console.log(source_default.dim(" tencent \u2014 \u817E\u8BAF SkillHub (skillhub.tencent.com)"));
19170
+ console.log(source_default.dim(" all \u2014 \u540C\u65F6\u641C\u7D22\u5168\u90E8\u4E09\u4E2A\u6765\u6E90"));
19171
+ console.log(source_default.dim("\n\u793A\u4F8B:"));
19172
+ console.log(source_default.dim(" /search rnaseq"));
19173
+ console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19174
+ console.log(source_default.dim(" /search genomics --hub=all"));
19115
19175
  break;
19116
19176
  }
19117
- let hubKey = "bgi";
19118
19177
  const hubMatch = arg.match(/--hub=(\w+)/);
19119
19178
  const query = arg.replace(/--hub=\w+/g, "").trim();
19120
- if (hubMatch) {
19121
- const hk = hubMatch[1];
19122
- if (hk in SKILLHUB_HUBS) hubKey = hk;
19123
- else {
19124
- console.log(source_default.red(`\u672A\u77E5 hub: ${hubMatch[1]}\uFF0C\u53EF\u9009: bgi, clawhub, tencent`));
19125
- break;
19126
- }
19127
- }
19179
+ const hubArg = hubMatch ? hubMatch[1] : "bgi";
19128
19180
  if (!query) {
19129
19181
  console.log(source_default.yellow("\u8BF7\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD"));
19130
19182
  break;
19131
19183
  }
19184
+ if (hubArg === "all") {
19185
+ console.log(source_default.dim(`
19186
+ \u6B63\u5728\u641C\u7D22\u5168\u90E8 SkillHub: "${query}"...
19187
+ `));
19188
+ const hubKeys = ["bgi", "clawhub", "tencent"];
19189
+ const allResults = [];
19190
+ await Promise.all(hubKeys.map(async (hk) => {
19191
+ try {
19192
+ const results = await searchSkillHub(query, hk, 5);
19193
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results });
19194
+ } catch (e2) {
19195
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results: [], error: e2 instanceof Error ? e2.message : String(e2) });
19196
+ }
19197
+ }));
19198
+ allResults.sort((a2, b2) => hubKeys.indexOf(a2.hub) - hubKeys.indexOf(b2.hub));
19199
+ _lastSearchResults = [];
19200
+ let globalIdx = 1;
19201
+ for (const { label, results, error } of allResults) {
19202
+ if (error) {
19203
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500`) + source_default.red(` \u641C\u7D22\u5931\u8D25: ${error}`));
19204
+ } else if (results.length === 0) {
19205
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500 \u65E0\u7ED3\u679C`));
19206
+ } else {
19207
+ console.log(source_default.bold.dim(` \u2500\u2500 ${label} (${results.length}) \u2500\u2500`));
19208
+ for (const s2 of results) {
19209
+ const ver = s2.version ? source_default.dim(` v${s2.version}`) : "";
19210
+ const owner = s2.owner ? source_default.dim(` @${s2.owner}`) : "";
19211
+ console.log(` ${source_default.cyan(`[${globalIdx}]`)} ${source_default.bold(s2.name)}${owner}${ver}`);
19212
+ console.log(` ${source_default.dim(s2.summary.substring(0, 90))}${s2.summary.length > 90 ? "\u2026" : ""}`);
19213
+ console.log(` ${source_default.dim(`slug: ${s2.slug}`)}`);
19214
+ _lastSearchResults.push(s2);
19215
+ globalIdx++;
19216
+ }
19217
+ }
19218
+ console.log();
19219
+ }
19220
+ if (_lastSearchResults.length > 0)
19221
+ console.log(source_default.dim(`\u5B89\u88C5: /install <slug> \u6216 /install <\u5E8F\u53F7> (\u5982: /install 1)`));
19222
+ break;
19223
+ }
19224
+ if (!(hubArg in SKILLHUB_HUBS)) {
19225
+ console.log(source_default.red(`\u672A\u77E5 hub: ${hubArg}\uFF0C\u53EF\u9009: bgi, clawhub, tencent, all`));
19226
+ break;
19227
+ }
19228
+ const hubKey = hubArg;
19132
19229
  const hubLabel = SKILLHUB_HUBS[hubKey].label;
19133
- process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel} SkillHub: "${query}"...
19230
+ process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel}: "${query}"...
19134
19231
  `));
19135
19232
  try {
19136
19233
  const results = await searchSkillHub(query, hubKey, 10);
package/dist/mbp.js CHANGED
@@ -15172,13 +15172,20 @@ ${label} `);
15172
15172
  clearSpinner();
15173
15173
  process.stdout.write(`${label}
15174
15174
  `);
15175
+ let heartbeatActive = false;
15175
15176
  heartbeat = setInterval(() => {
15176
- if (Date.now() - lastChunkTime >= 5e3) {
15177
- const totalSecs = ((Date.now() - t0) / 1e3).toFixed(0);
15178
- process.stdout.write(source_default.dim(`
15179
- \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`));
15177
+ if (Date.now() - lastChunkTime >= 3e3) {
15178
+ const totalSecs = ((Date.now() - t0) / 1e3).toFixed(1);
15179
+ if (!heartbeatActive) {
15180
+ process.stdout.write("\n");
15181
+ heartbeatActive = true;
15182
+ }
15183
+ process.stdout.write(`\r${source_default.dim(` \u2502 \u23F1 \u8FD0\u884C\u4E2D... ${totalSecs}s`)}\x1B[K`);
15184
+ } else if (heartbeatActive) {
15185
+ process.stdout.write("\r\x1B[K");
15186
+ heartbeatActive = false;
15180
15187
  }
15181
- }, 5e3);
15188
+ }, 100);
15182
15189
  }
15183
15190
  let i2 = 0;
15184
15191
  while (i2 < chunk.length) {
@@ -17912,12 +17919,12 @@ function clearCheckpoints(sessionId) {
17912
17919
 
17913
17920
  // src/index.ts
17914
17921
  var import_fs7 = require("fs");
17915
- var VERSION2 = "2.8.3";
17922
+ var VERSION2 = "2.8.5";
17916
17923
  var BRAND2 = "mbp".toLowerCase();
17917
17924
  var SKILLHUB_HUBS = {
17918
- bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
17925
+ bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
17919
17926
  clawhub: { label: "clawhub.ai", apiBase: "https://clawhub.ai", backend: "clawhub" },
17920
- tencent: { label: "Tencent", apiBase: "https://lightmake.site", backend: "tencent" }
17927
+ tencent: { label: "\u817E\u8BAF SkillHub", apiBase: "https://skillhub.tencent.com", backend: "tencent" }
17921
17928
  };
17922
17929
  function httpGetJson(url) {
17923
17930
  const mod = url.startsWith("https") ? import_https2.get : require("http").get;
@@ -17940,9 +17947,58 @@ function httpGetJson(url) {
17940
17947
  req.on("error", reject);
17941
17948
  });
17942
17949
  }
17950
+ function searchLocalSkills(query, limit2) {
17951
+ const kw = query.toLowerCase();
17952
+ const results = [];
17953
+ const seen = /* @__PURE__ */ new Set();
17954
+ const scanDir = (dir) => {
17955
+ if (!(0, import_fs6.existsSync)(dir)) return;
17956
+ let entries;
17957
+ try {
17958
+ entries = (0, import_fs6.readdirSync)(dir);
17959
+ } catch {
17960
+ return;
17961
+ }
17962
+ for (const entry of entries) {
17963
+ if (seen.has(entry)) continue;
17964
+ const skillDir = (0, import_path6.join)(dir, entry);
17965
+ try {
17966
+ if (!(0, import_fs6.statSync)(skillDir).isDirectory()) continue;
17967
+ } catch {
17968
+ continue;
17969
+ }
17970
+ let name = entry;
17971
+ let summary = "";
17972
+ const mdPath = (0, import_path6.join)(skillDir, "SKILL.md");
17973
+ if ((0, import_fs6.existsSync)(mdPath)) {
17974
+ try {
17975
+ const lines = (0, import_fs6.readFileSync)(mdPath, "utf8").split("\n").slice(0, 30);
17976
+ for (const line of lines) {
17977
+ const nm = line.match(/^name:\s*["']?(.+?)["']?\s*$/);
17978
+ const sd = line.match(/^short-description:\s*["']?(.+?)["']?\s*$/);
17979
+ const dsc = line.match(/^description:\s*["']?(.+?)["']?\s*$/);
17980
+ if (nm) name = nm[1].trim();
17981
+ if (sd) summary = sd[1].trim();
17982
+ else if (dsc && !summary) summary = dsc[1].trim();
17983
+ }
17984
+ } catch {
17985
+ }
17986
+ }
17987
+ if (entry.toLowerCase().includes(kw) || name.toLowerCase().includes(kw) || summary.toLowerCase().includes(kw)) {
17988
+ seen.add(entry);
17989
+ results.push({ slug: entry, name, summary });
17990
+ }
17991
+ }
17992
+ };
17993
+ scanDir(BIO_SKILLS_DIR);
17994
+ scanDir(USER_SKILLS_DIR);
17995
+ return results.slice(0, limit2);
17996
+ }
17943
17997
  async function searchSkillHub(query, hub, limit2 = 10) {
17944
17998
  const cfg = SKILLHUB_HUBS[hub];
17945
- if (cfg.backend === "tencent") {
17999
+ if (cfg.backend === "local") {
18000
+ return searchLocalSkills(query, limit2);
18001
+ } else if (cfg.backend === "tencent") {
17946
18002
  const data = await httpGetJson(
17947
18003
  `${cfg.apiBase}/api/skills?page=1&pageSize=${limit2}&keyword=${encodeURIComponent(query)}`
17948
18004
  );
@@ -17952,7 +18008,7 @@ async function searchSkillHub(query, hub, limit2 = 10) {
17952
18008
  name: s2.name,
17953
18009
  summary: s2.description ?? "",
17954
18010
  version: s2.version,
17955
- owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*clawhub\.ai\/([^/]+)\/.*/, "$1") : void 0)
18011
+ owner: s2.ownerName ?? (s2.homepage ? s2.homepage.replace(/.*skillhub\.tencent\.com\/([^/]+)\/.*/, "$1") : void 0)
17956
18012
  }));
17957
18013
  } else {
17958
18014
  const data = await httpGetJson(
@@ -18229,7 +18285,7 @@ function printHelp() {
18229
18285
  console.log(source_default.bold.cyan("\u2500\u2500\u2500 Skill \u5411\u5BFC \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"));
18230
18286
  console.log(` ${source_default.cyan("/run")} <skill-id> \u4EA4\u4E92\u5F0F\u53C2\u6570\u5411\u5BFC\uFF0C\u81EA\u52A8\u751F\u6210\u5E76\u6267\u884C\u5206\u6790\u811A\u672C`);
18231
18287
  console.log(` ${source_default.cyan("/check-env")} [id] \u68C0\u6D4B Skill \u6240\u9700 R/Python \u5305\u662F\u5426\u5DF2\u5B89\u88C5`);
18232
- console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u5728 SkillHub \u641C\u7D22\u5E76\u4E0B\u8F7D\u6280\u80FD ${source_default.dim("[--hub=bgi|clawhub|tencent]")}`);
18288
+ console.log(` ${source_default.cyan("/search")} <\u5173\u952E\u8BCD> \u641C\u7D22 Skills ${source_default.dim("[--hub=bgi|clawhub|tencent|all]")}`);
18233
18289
  console.log(` ${source_default.cyan("/install")} <url|slug> \u4ECE GitHub \u6216 SkillHub \u5B89\u88C5 Skill\uFF08\u542B\u5B89\u5168\u626B\u63CF\uFF09`);
18234
18290
  console.log(` ${source_default.cyan("/uninstall")} <id> \u5378\u8F7D\u5DF2\u5B89\u88C5\u7684\u7B2C\u4E09\u65B9 Skill`);
18235
18291
  console.log();
@@ -19107,30 +19163,71 @@ ${paramSummary}
19107
19163
  // ── /search SkillHub ─────────────────────────────────────────────────────
19108
19164
  case "search": {
19109
19165
  if (!arg) {
19110
- console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent]");
19111
- console.log(source_default.dim("\u793A\u4F8B: /search rnaseq"));
19112
- console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19113
- console.log(source_default.dim(" /search genomics --hub=clawhub"));
19114
- console.log(source_default.dim("\n\u9ED8\u8BA4\u641C\u7D22 BGI \u5185\u7F51 SkillHub (http://172.16.218.40:8080)"));
19166
+ console.log("\u7528\u6CD5: /search <\u5173\u952E\u8BCD> [--hub=bgi|clawhub|tencent|all]");
19167
+ console.log(source_default.dim(" bgi \u2014 BGI \u672C\u5730\u5DF2\u5B89\u88C5 Skills\uFF08\u9ED8\u8BA4\uFF0C\u6781\u5FEB\uFF09"));
19168
+ console.log(source_default.dim(" clawhub \u2014 clawhub.ai \u5B98\u65B9 SkillHub"));
19169
+ console.log(source_default.dim(" tencent \u2014 \u817E\u8BAF SkillHub (skillhub.tencent.com)"));
19170
+ console.log(source_default.dim(" all \u2014 \u540C\u65F6\u641C\u7D22\u5168\u90E8\u4E09\u4E2A\u6765\u6E90"));
19171
+ console.log(source_default.dim("\n\u793A\u4F8B:"));
19172
+ console.log(source_default.dim(" /search rnaseq"));
19173
+ console.log(source_default.dim(" /search \u86CB\u767D\u8D28\u7ED3\u6784\u9884\u6D4B --hub=tencent"));
19174
+ console.log(source_default.dim(" /search genomics --hub=all"));
19115
19175
  break;
19116
19176
  }
19117
- let hubKey = "bgi";
19118
19177
  const hubMatch = arg.match(/--hub=(\w+)/);
19119
19178
  const query = arg.replace(/--hub=\w+/g, "").trim();
19120
- if (hubMatch) {
19121
- const hk = hubMatch[1];
19122
- if (hk in SKILLHUB_HUBS) hubKey = hk;
19123
- else {
19124
- console.log(source_default.red(`\u672A\u77E5 hub: ${hubMatch[1]}\uFF0C\u53EF\u9009: bgi, clawhub, tencent`));
19125
- break;
19126
- }
19127
- }
19179
+ const hubArg = hubMatch ? hubMatch[1] : "bgi";
19128
19180
  if (!query) {
19129
19181
  console.log(source_default.yellow("\u8BF7\u63D0\u4F9B\u641C\u7D22\u5173\u952E\u8BCD"));
19130
19182
  break;
19131
19183
  }
19184
+ if (hubArg === "all") {
19185
+ console.log(source_default.dim(`
19186
+ \u6B63\u5728\u641C\u7D22\u5168\u90E8 SkillHub: "${query}"...
19187
+ `));
19188
+ const hubKeys = ["bgi", "clawhub", "tencent"];
19189
+ const allResults = [];
19190
+ await Promise.all(hubKeys.map(async (hk) => {
19191
+ try {
19192
+ const results = await searchSkillHub(query, hk, 5);
19193
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results });
19194
+ } catch (e2) {
19195
+ allResults.push({ hub: hk, label: SKILLHUB_HUBS[hk].label, results: [], error: e2 instanceof Error ? e2.message : String(e2) });
19196
+ }
19197
+ }));
19198
+ allResults.sort((a2, b2) => hubKeys.indexOf(a2.hub) - hubKeys.indexOf(b2.hub));
19199
+ _lastSearchResults = [];
19200
+ let globalIdx = 1;
19201
+ for (const { label, results, error } of allResults) {
19202
+ if (error) {
19203
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500`) + source_default.red(` \u641C\u7D22\u5931\u8D25: ${error}`));
19204
+ } else if (results.length === 0) {
19205
+ console.log(source_default.dim(` \u2500\u2500 ${label} \u2500\u2500 \u65E0\u7ED3\u679C`));
19206
+ } else {
19207
+ console.log(source_default.bold.dim(` \u2500\u2500 ${label} (${results.length}) \u2500\u2500`));
19208
+ for (const s2 of results) {
19209
+ const ver = s2.version ? source_default.dim(` v${s2.version}`) : "";
19210
+ const owner = s2.owner ? source_default.dim(` @${s2.owner}`) : "";
19211
+ console.log(` ${source_default.cyan(`[${globalIdx}]`)} ${source_default.bold(s2.name)}${owner}${ver}`);
19212
+ console.log(` ${source_default.dim(s2.summary.substring(0, 90))}${s2.summary.length > 90 ? "\u2026" : ""}`);
19213
+ console.log(` ${source_default.dim(`slug: ${s2.slug}`)}`);
19214
+ _lastSearchResults.push(s2);
19215
+ globalIdx++;
19216
+ }
19217
+ }
19218
+ console.log();
19219
+ }
19220
+ if (_lastSearchResults.length > 0)
19221
+ console.log(source_default.dim(`\u5B89\u88C5: /install <slug> \u6216 /install <\u5E8F\u53F7> (\u5982: /install 1)`));
19222
+ break;
19223
+ }
19224
+ if (!(hubArg in SKILLHUB_HUBS)) {
19225
+ console.log(source_default.red(`\u672A\u77E5 hub: ${hubArg}\uFF0C\u53EF\u9009: bgi, clawhub, tencent, all`));
19226
+ break;
19227
+ }
19228
+ const hubKey = hubArg;
19132
19229
  const hubLabel = SKILLHUB_HUBS[hubKey].label;
19133
- process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel} SkillHub: "${query}"...
19230
+ process.stdout.write(source_default.dim(`\u6B63\u5728\u641C\u7D22 ${hubLabel}: "${query}"...
19134
19231
  `));
19135
19232
  try {
19136
19233
  const results = await searchSkillHub(query, hubKey, 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgicli/bgicli",
3
- "version": "2.8.3",
3
+ "version": "2.8.5",
4
4
  "description": "BGI CLI — Bioinformatics AI terminal for Chinese researchers (百炼/DeepSeek/Kimi/Qwen)",
5
5
  "bin": {
6
6
  "bgi": "dist/bgi.js",