@bgicli/bgicli 2.4.9 → 2.6.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/dist/bgi.js CHANGED
@@ -13605,11 +13605,12 @@ var BGI_DIR = (0, import_path2.join)((0, import_os.homedir)(), ".bgicli");
13605
13605
  var TOOLS_DIR = (0, import_path2.join)(BGI_DIR, "tools");
13606
13606
  var SKILLS_DIR = (0, import_path2.join)(BGI_DIR, "skills");
13607
13607
  var USER_SKILLS_DIR = (0, import_path2.join)(BGI_DIR, "user-skills");
13608
+ var CUSTOM_SKILLS_DIR = (0, import_path2.join)(BGI_DIR, "custom-skills");
13608
13609
  var DATABASES_FILE = (0, import_path2.join)(BGI_DIR, "databases.json");
13609
13610
  var DATA_VERSION_FILE = (0, import_path2.join)(BGI_DIR, ".data-version");
13610
13611
  var CONFIG_FILE = (0, import_path2.join)(BGI_DIR, "config.json");
13611
13612
  function ensureDirs() {
13612
- for (const dir of [BGI_DIR, TOOLS_DIR, SKILLS_DIR, USER_SKILLS_DIR]) {
13613
+ for (const dir of [BGI_DIR, TOOLS_DIR, SKILLS_DIR, USER_SKILLS_DIR, CUSTOM_SKILLS_DIR]) {
13613
13614
  if (!(0, import_fs2.existsSync)(dir)) (0, import_fs2.mkdirSync)(dir, { recursive: true });
13614
13615
  }
13615
13616
  }
@@ -13619,12 +13620,18 @@ function loadConfig() {
13619
13620
  const def = {
13620
13621
  provider: DEFAULT_PROVIDER,
13621
13622
  model: PROVIDERS[DEFAULT_PROVIDER].defaultModel,
13622
- apiKeys: {}
13623
+ apiKeys: {},
13624
+ permanentSkills: ["web-search"]
13623
13625
  };
13624
13626
  saveConfig(def);
13625
13627
  return def;
13626
13628
  }
13627
- return JSON.parse((0, import_fs2.readFileSync)(CONFIG_FILE, "utf8"));
13629
+ const cfg = JSON.parse((0, import_fs2.readFileSync)(CONFIG_FILE, "utf8"));
13630
+ if (!cfg.permanentSkills) {
13631
+ cfg.permanentSkills = ["web-search"];
13632
+ saveConfig(cfg);
13633
+ }
13634
+ return cfg;
13628
13635
  }
13629
13636
  function saveConfig(cfg) {
13630
13637
  ensureDirs();
@@ -14267,6 +14274,7 @@ ${shortSummary}`);
14267
14274
  }
14268
14275
 
14269
14276
  // src/chat.ts
14277
+ var BRAND = "bgi".toUpperCase();
14270
14278
  async function chat(messages, config, systemPrompt2, stats, signal) {
14271
14279
  const prov = PROVIDERS[config.provider];
14272
14280
  if (!prov) throw new Error(`Unknown provider: ${config.provider}`);
@@ -14461,7 +14469,7 @@ async function streamOnce(client, messages, model, signal) {
14461
14469
  let finishReason = null;
14462
14470
  let inputTokens = 0;
14463
14471
  let outputTokens = 0;
14464
- process.stdout.write(source_default.green("BGI \u203A "));
14472
+ process.stdout.write(source_default.green(`${BRAND} \u203A `));
14465
14473
  for await (const chunk of stream) {
14466
14474
  if (chunk.usage) {
14467
14475
  inputTokens = chunk.usage.prompt_tokens ?? 0;
@@ -17192,7 +17200,8 @@ function clearCheckpoints(sessionId) {
17192
17200
 
17193
17201
  // src/index.ts
17194
17202
  var import_fs7 = require("fs");
17195
- var VERSION2 = "2.4.9";
17203
+ var VERSION2 = "2.6.0";
17204
+ var BRAND2 = "bgi".toLowerCase();
17196
17205
  var SKILLHUB_HUBS = {
17197
17206
  bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
17198
17207
  clawhub: { label: "clawhub.ai", apiBase: "https://clawhub.ai", backend: "clawhub" },
@@ -17335,6 +17344,10 @@ var SESSION_CTX = {
17335
17344
  };
17336
17345
  var dbRegistry = { version: 1, lastScan: null, databases: {} };
17337
17346
  var systemPrompt = "";
17347
+ var debugMode = false;
17348
+ var debugFilePath = "";
17349
+ var debugRound = 0;
17350
+ var permanentSkillIds = /* @__PURE__ */ new Set();
17338
17351
  function installBundledData() {
17339
17352
  const bundledData = (0, import_path6.join)(__dirname, "..", "data");
17340
17353
  if (!(0, import_fs6.existsSync)(bundledData)) return;
@@ -17383,13 +17396,31 @@ function installBundledData() {
17383
17396
  }
17384
17397
  }
17385
17398
  function printBanner() {
17386
- console.log(source_default.cyan.bold(`
17399
+ if (BRAND2 === "bio") {
17400
+ console.log(source_default.cyan.bold(`
17401
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
17402
+ \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
17403
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17404
+ \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17405
+ \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
17406
+ \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D v${VERSION2}`));
17407
+ } else if (BRAND2 === "mbp") {
17408
+ console.log(source_default.cyan.bold(`
17409
+ \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
17410
+ \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
17411
+ \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17412
+ \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17413
+ \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
17414
+ \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D v${VERSION2}`));
17415
+ } else {
17416
+ console.log(source_default.cyan.bold(`
17387
17417
  \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
17388
17418
  \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
17389
17419
  \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17390
17420
  \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
17391
17421
  \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
17392
17422
  \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D v${VERSION2}`));
17423
+ }
17393
17424
  console.log(source_default.dim(" \u751F\u7269\u4FE1\u606F\u5B66 AI \u7EC8\u7AEF\u52A9\u624B \u2014 Bioinformatics AI Terminal"));
17394
17425
  console.log();
17395
17426
  }
@@ -17559,8 +17590,9 @@ function collectAllSkills() {
17559
17590
  }
17560
17591
  });
17561
17592
  };
17562
- addFrom(SKILLS_DIR, "skill");
17563
- addFrom(USER_SKILLS_DIR, "user");
17593
+ addFrom(SKILLS_DIR, "bio");
17594
+ addFrom(USER_SKILLS_DIR, "downloaded");
17595
+ addFrom(CUSTOM_SKILLS_DIR, "custom");
17564
17596
  return entries;
17565
17597
  }
17566
17598
  function listSkills(keyword) {
@@ -17648,6 +17680,14 @@ function parseSkillMeta(content) {
17648
17680
  };
17649
17681
  }
17650
17682
  async function injectSkill(id, history, injectedSkills, rl, skipConfirm = false) {
17683
+ if (injectedSkills.has(id)) {
17684
+ if (permanentSkillIds.has(id)) {
17685
+ console.log(source_default.dim(` [${id}] \u662F\u5E38\u9A7B\u6280\u80FD\uFF0C\u5DF2\u81EA\u52A8\u52A0\u8F7D\u5230\u7CFB\u7EDF\u63D0\u793A\u4E2D\uFF0C\u65E0\u9700\u624B\u52A8\u6FC0\u6D3B`));
17686
+ } else {
17687
+ console.log(source_default.dim(` [${id}] \u5DF2\u5728\u5F53\u524D\u4F1A\u8BDD\u4E2D\u52A0\u8F7D`));
17688
+ }
17689
+ return false;
17690
+ }
17651
17691
  const all = collectAllSkills();
17652
17692
  const match = all.find((e2) => e2.id === id) || all.find((e2) => e2.id.startsWith(id)) || all.find((e2) => e2.id.includes(id));
17653
17693
  if (!match) {
@@ -18552,7 +18592,7 @@ ${paramSummary}
18552
18592
  const label = parts.slice(3).join(" ") || `${type} (${genome})`;
18553
18593
  const entry = addDbEntry(dbRegistry, { label, type, genome, path: dbPath, source: "manual" });
18554
18594
  saveDbRegistry(dbRegistry);
18555
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18595
+ rebuildSystemPrompt();
18556
18596
  console.log(source_default.green(`\u2713 \u5DF2\u6DFB\u52A0\u6570\u636E\u5E93: ${entry.label}`));
18557
18597
  console.log(` id: ${source_default.cyan(entry.id)}`);
18558
18598
  console.log(` \u8DEF\u5F84: ${source_default.dim(entry.path)}`);
@@ -18568,7 +18608,7 @@ ${paramSummary}
18568
18608
  const removed = removeDbEntry(dbRegistry, dbArg.trim());
18569
18609
  if (removed) {
18570
18610
  saveDbRegistry(dbRegistry);
18571
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18611
+ rebuildSystemPrompt();
18572
18612
  console.log(source_default.green(`\u2713 \u5DF2\u79FB\u9664\u6570\u636E\u5E93: ${dbArg}`));
18573
18613
  } else {
18574
18614
  console.log(source_default.red(`\u672A\u627E\u5230\u6570\u636E\u5E93 id: ${dbArg}\uFF0C\u4F7F\u7528 /db list \u67E5\u770B\u5DF2\u6CE8\u518C\u5217\u8868`));
@@ -18603,7 +18643,7 @@ ${paramSummary}
18603
18643
  if (addedCount > 0) {
18604
18644
  dbRegistry.lastScan = (/* @__PURE__ */ new Date()).toISOString();
18605
18645
  saveDbRegistry(dbRegistry);
18606
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18646
+ rebuildSystemPrompt();
18607
18647
  console.log(source_default.green(`
18608
18648
  \u2713 \u65B0\u589E ${addedCount} \u4E2A\u6570\u636E\u5E93\u5230\u6CE8\u518C\u8868`));
18609
18649
  } else {
@@ -18685,11 +18725,18 @@ ${summary}` },
18685
18725
  \u5F53\u524D\u5DF2\u52A0\u8F7D\u7684 Skills (${injectedSkills.size} \u4E2A):
18686
18726
  `));
18687
18727
  for (const [id, name] of injectedSkills) {
18688
- console.log(` ${source_default.green("\u25CF")} ${source_default.cyan(id)} ${source_default.dim("\u2014 " + name)}`);
18689
- console.log(source_default.dim(` /unload ${id} \u53EF\u5378\u8F7D\u6B64 Skill`));
18728
+ const isPerm = permanentSkillIds.has(id);
18729
+ const icon = isPerm ? source_default.yellow("\u26A1") : source_default.green("\u25CF");
18730
+ const tag = isPerm ? source_default.yellow(" [\u5E38\u9A7B]") : "";
18731
+ console.log(` ${icon} ${source_default.cyan(id)}${tag} ${source_default.dim("\u2014 " + name)}`);
18732
+ if (isPerm) {
18733
+ console.log(source_default.dim(` /unpin ${id} \u53EF\u53D6\u6D88\u5E38\u9A7B`));
18734
+ } else {
18735
+ console.log(source_default.dim(` /unload ${id} \u53EF\u5378\u8F7D\u6B64 Skill`));
18736
+ }
18690
18737
  }
18691
18738
  console.log();
18692
- console.log(source_default.dim("\u63D0\u793A: /clear \u6E05\u7A7A\u5168\u90E8\u5BF9\u8BDD\u548C Skills | /unload <id> \u5378\u8F7D\u5355\u4E2A"));
18739
+ console.log(source_default.dim("\u63D0\u793A: /clear \u6E05\u7A7A\u5168\u90E8\u5BF9\u8BDD\u548C Skills | /unload <id> \u5378\u8F7D | /unpin <id> \u53D6\u6D88\u5E38\u9A7B"));
18693
18740
  }
18694
18741
  break;
18695
18742
  }
@@ -18706,6 +18753,11 @@ ${summary}` },
18706
18753
  console.log(source_default.dim("\u4F7F\u7528 /skills \u67E5\u770B\u5F53\u524D\u5DF2\u52A0\u8F7D\u7684 Skills"));
18707
18754
  break;
18708
18755
  }
18756
+ if (permanentSkillIds.has(targetId)) {
18757
+ console.log(source_default.yellow(`"${targetId}" \u662F\u5E38\u9A7B\u6280\u80FD\uFF0C\u65E0\u6CD5\u901A\u8FC7 /unload \u5378\u8F7D`));
18758
+ console.log(source_default.dim(` \u4F7F\u7528 /unpin ${targetId} \u53EF\u5C06\u5176\u4ECE\u5E38\u9A7B\u5217\u8868\u4E2D\u79FB\u9664\uFF08\u4E0B\u6B21\u4F1A\u8BDD\u751F\u6548\uFF09`));
18759
+ break;
18760
+ }
18709
18761
  const SKILL_MARKER = `[Skill \u5DF2\u52A0\u8F7D: ${targetId}]`;
18710
18762
  let removed = 0;
18711
18763
  for (let i2 = history.length - 1; i2 >= 0; i2--) {
@@ -18786,29 +18838,118 @@ ${summary}` },
18786
18838
  }
18787
18839
  case "cat": {
18788
18840
  console.log(source_default.bold.cyan("\n\u2500\u2500\u2500 Skill \u5206\u7C7B\u76EE\u5F55 \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"));
18789
- console.log(source_default.dim(" \u4F7F\u7528 /sk <id> \u6FC0\u6D3B\u6280\u80FD \xB7 \u4F7F\u7528 /sk <\u5173\u952E\u8BCD> \u641C\u7D22\n"));
18841
+ console.log(source_default.dim(" \u4F7F\u7528 /sk <id> \u6FC0\u6D3B \xB7 /sk <\u5173\u952E\u8BCD> \u641C\u7D22 \xB7 /pin <id> \u8BBE\u4E3A\u5E38\u9A7B\n"));
18842
+ const allInstalled = collectAllSkills();
18843
+ const permIds = Array.from(permanentSkillIds);
18844
+ console.log(` \u26A1 ${source_default.bold.yellow("\u5E38\u9A7B Skills")} ${source_default.dim("(\u6BCF\u8F6E\u5BF9\u8BDD\u81EA\u52A8\u52A0\u5165\u4E0A\u4E0B\u6587)")}`);
18845
+ if (permIds.length === 0) {
18846
+ console.log(source_default.dim(" \u6682\u65E0\u5E38\u9A7B\u6280\u80FD\uFF0C\u4F7F\u7528 /pin <id> \u6DFB\u52A0"));
18847
+ } else {
18848
+ for (const id of permIds) {
18849
+ const entry = allInstalled.find((e2) => e2.id === id);
18850
+ const skillPath = entry ? (0, import_path6.join)(entry.dir, id, "SKILL.md") : "";
18851
+ const name = skillPath && (0, import_fs6.existsSync)(skillPath) ? parseSkillMeta((0, import_fs6.readFileSync)(skillPath, "utf8")).name || id : id;
18852
+ console.log(` ${source_default.yellow(id)} ${source_default.dim("\u2014 " + name)}`);
18853
+ }
18854
+ console.log(source_default.dim(" /unpin <id> \u53D6\u6D88\u5E38\u9A7B"));
18855
+ }
18856
+ console.log();
18857
+ const routedIds = new Set(SKILL_ROUTES.map((r2) => r2.id));
18790
18858
  const byCategory = {};
18791
18859
  for (const route of SKILL_ROUTES) {
18792
- (byCategory[route.category] ??= []).push({ id: route.id, dir: "", tag: route.tag });
18860
+ (byCategory[route.category] ??= []).push(route);
18793
18861
  }
18862
+ console.log(` \u{1F9EC} ${source_default.bold.cyan("\u751F\u7269\u4FE1\u606F Skills")} ${source_default.dim("(\u9700\u6FC0\u6D3B /sk <id>)")}`);
18794
18863
  for (const [catKey, meta] of Object.entries(SKILL_CATEGORIES)) {
18795
- const items = byCategory[catKey];
18796
- if (!items || items.length === 0) continue;
18797
- console.log(` ${meta.icon} ${source_default.bold(meta.label)}`);
18798
- for (const item of items) {
18799
- const route = SKILL_ROUTES.find((r2) => r2.id === item.id);
18800
- console.log(` ${source_default.cyan(item.id)} ${source_default.dim("\u2014 " + route.name)}`);
18864
+ const routes = byCategory[catKey];
18865
+ if (!routes || routes.length === 0) continue;
18866
+ console.log(` ${source_default.bold(meta.icon + " " + meta.label)}`);
18867
+ for (const route of routes) {
18868
+ console.log(` ${source_default.cyan(route.id)} ${source_default.dim("\u2014 " + route.name)}`);
18801
18869
  }
18802
- console.log();
18803
18870
  }
18804
- const routedIds = new Set(SKILL_ROUTES.map((r2) => r2.id));
18805
- const allInstalled = collectAllSkills();
18806
- const unrouted = allInstalled.filter((e2) => !routedIds.has(e2.id));
18807
- if (unrouted.length > 0) {
18808
- console.log(` \u{1F4E6} ${source_default.bold("\u66F4\u591A Skills")} ${source_default.dim(`(${unrouted.length} \u4E2A\uFF0C\u4F7F\u7528\u5173\u952E\u8BCD\u641C\u7D22)`)}`);
18809
- console.log(source_default.dim(" /sk <\u5173\u952E\u8BCD>\uFF0C\u4F8B: /sk ehr /sk clinical /sk imaging"));
18810
- console.log();
18871
+ const bioUnrouted = allInstalled.filter(
18872
+ (e2) => e2.tag === "bio" && !routedIds.has(e2.id) && !permanentSkillIds.has(e2.id)
18873
+ );
18874
+ if (bioUnrouted.length > 0) {
18875
+ console.log(source_default.dim(` \u2026 \u8FD8\u6709 ${bioUnrouted.length} \u4E2A\uFF0C\u4F7F\u7528 /sk <\u5173\u952E\u8BCD> \u641C\u7D22`));
18876
+ }
18877
+ console.log();
18878
+ const downloaded = allInstalled.filter((e2) => e2.tag === "downloaded");
18879
+ console.log(` \u{1F4E6} ${source_default.bold.green("\u5DF2\u5B89\u88C5 Skills")} ${source_default.dim(`(${downloaded.length} \u4E2A\uFF0C/install \u4E0B\u8F7D \u9700\u6FC0\u6D3B)`)}`);
18880
+ if (downloaded.length === 0) {
18881
+ console.log(source_default.dim(" \u6682\u65E0\uFF0C\u4F7F\u7528 /install <slug> \u4ECE clawhub \u5B89\u88C5"));
18882
+ } else {
18883
+ for (const e2 of downloaded.slice(0, 10)) {
18884
+ const skillPath = (0, import_path6.join)(e2.dir, e2.id, "SKILL.md");
18885
+ const name = (0, import_fs6.existsSync)(skillPath) ? parseSkillMeta((0, import_fs6.readFileSync)(skillPath, "utf8")).name || e2.id : e2.id;
18886
+ console.log(` ${source_default.green(e2.id)} ${source_default.dim("\u2014 " + name)}`);
18887
+ }
18888
+ if (downloaded.length > 10)
18889
+ console.log(source_default.dim(` \u2026 \u8FD8\u6709 ${downloaded.length - 10} \u4E2A\uFF0C\u4F7F\u7528 /sk <\u5173\u952E\u8BCD> \u641C\u7D22`));
18890
+ }
18891
+ console.log();
18892
+ const custom = allInstalled.filter((e2) => e2.tag === "custom");
18893
+ console.log(` \u270F\uFE0F ${source_default.bold("\u81EA\u5B9A\u4E49 Skills")} ${source_default.dim(`(${custom.length} \u4E2A\uFF0C\u653E\u5165 ${CUSTOM_SKILLS_DIR} \u9700\u6FC0\u6D3B)`)}`);
18894
+ if (custom.length === 0) {
18895
+ console.log(source_default.dim(` \u6682\u65E0\uFF0C\u5728 ${CUSTOM_SKILLS_DIR}/<skill-id>/SKILL.md \u521B\u5EFA`));
18896
+ } else {
18897
+ for (const e2 of custom) {
18898
+ const skillPath = (0, import_path6.join)(e2.dir, e2.id, "SKILL.md");
18899
+ const name = (0, import_fs6.existsSync)(skillPath) ? parseSkillMeta((0, import_fs6.readFileSync)(skillPath, "utf8")).name || e2.id : e2.id;
18900
+ console.log(` ${source_default.white(e2.id)} ${source_default.dim("\u2014 " + name)}`);
18901
+ }
18902
+ }
18903
+ console.log();
18904
+ break;
18905
+ }
18906
+ case "pin": {
18907
+ if (!arg) {
18908
+ console.log("\u7528\u6CD5: /pin <skill-id>");
18909
+ console.log(source_default.dim("\u5C06\u6307\u5B9A Skill \u8BBE\u4E3A\u5E38\u9A7B\uFF0C\u6BCF\u6B21\u5BF9\u8BDD\u81EA\u52A8\u52A0\u5165\u4E0A\u4E0B\u6587"));
18910
+ break;
18911
+ }
18912
+ const allForPin = collectAllSkills();
18913
+ const pinEntry = allForPin.find((e2) => e2.id === arg) || allForPin.find((e2) => e2.id.startsWith(arg)) || allForPin.find((e2) => e2.id.includes(arg));
18914
+ if (!pinEntry) {
18915
+ console.log(source_default.red(`\u627E\u4E0D\u5230 Skill: ${arg}\u3002\u4F7F\u7528 /sk <\u5173\u952E\u8BCD> \u641C\u7D22`));
18916
+ break;
18917
+ }
18918
+ const pinCfg = loadConfig();
18919
+ const perms = pinCfg.permanentSkills ?? [];
18920
+ if (perms.includes(pinEntry.id)) {
18921
+ console.log(source_default.yellow(`"${pinEntry.id}" \u5DF2\u662F\u5E38\u9A7B\u6280\u80FD`));
18922
+ break;
18923
+ }
18924
+ pinCfg.permanentSkills = [...perms, pinEntry.id];
18925
+ saveConfig(pinCfg);
18926
+ rebuildSystemPrompt();
18927
+ const pinPath = (0, import_path6.join)(pinEntry.dir, pinEntry.id, "SKILL.md");
18928
+ if ((0, import_fs6.existsSync)(pinPath)) {
18929
+ const { name } = parseSkillMeta((0, import_fs6.readFileSync)(pinPath, "utf8"));
18930
+ injectedSkills.set(pinEntry.id, name || pinEntry.id);
18931
+ } else {
18932
+ injectedSkills.set(pinEntry.id, pinEntry.id);
18933
+ }
18934
+ console.log(source_default.green(`\u2713 "${pinEntry.id}" \u5DF2\u8BBE\u4E3A\u5E38\u9A7B\u6280\u80FD\uFF0C\u7CFB\u7EDF\u63D0\u793A\u5DF2\u66F4\u65B0`));
18935
+ break;
18936
+ }
18937
+ case "unpin": {
18938
+ if (!arg) {
18939
+ console.log("\u7528\u6CD5: /unpin <skill-id>");
18940
+ console.log(source_default.dim("\u5C06\u6307\u5B9A Skill \u4ECE\u5E38\u9A7B\u5217\u8868\u79FB\u9664\uFF08\u5F53\u524D\u4F1A\u8BDD\u4ECD\u6709\u6548\uFF0C\u4E0B\u6B21\u4F1A\u8BDD\u8D77\u751F\u6548\uFF09"));
18941
+ break;
18811
18942
  }
18943
+ const unpinCfg = loadConfig();
18944
+ const unpinPerms = unpinCfg.permanentSkills ?? [];
18945
+ if (!unpinPerms.includes(arg)) {
18946
+ console.log(source_default.yellow(`"${arg}" \u4E0D\u5728\u5E38\u9A7B\u5217\u8868\u4E2D`));
18947
+ break;
18948
+ }
18949
+ unpinCfg.permanentSkills = unpinPerms.filter((id) => id !== arg);
18950
+ saveConfig(unpinCfg);
18951
+ rebuildSystemPrompt();
18952
+ console.log(source_default.green(`\u2713 "${arg}" \u5DF2\u4ECE\u5E38\u9A7B\u5217\u8868\u79FB\u9664\uFF08\u5F53\u524D\u4F1A\u8BDD\u4ECD\u6709\u6548\uFF0C\u4E0B\u6B21\u4F1A\u8BDD\u8D77\u751F\u6548\uFF09`));
18812
18953
  break;
18813
18954
  }
18814
18955
  case "cd": {
@@ -18847,7 +18988,73 @@ ${summary}` },
18847
18988
  }
18848
18989
  return {};
18849
18990
  }
18991
+ function rebuildSystemPrompt() {
18992
+ systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18993
+ const cfg = loadConfig();
18994
+ const ids = cfg.permanentSkills ?? [];
18995
+ permanentSkillIds = new Set(ids);
18996
+ if (ids.length === 0) return;
18997
+ const all = collectAllSkills();
18998
+ const parts = [];
18999
+ for (const id of ids) {
19000
+ const entry = all.find((e2) => e2.id === id);
19001
+ if (!entry) continue;
19002
+ const skillPath = (0, import_path6.join)(entry.dir, entry.id, "SKILL.md");
19003
+ if (!(0, import_fs6.existsSync)(skillPath)) continue;
19004
+ const content = (0, import_fs6.readFileSync)(skillPath, "utf8");
19005
+ parts.push(`
19006
+ ### \u5E38\u9A7B\u6280\u80FD: ${id}
19007
+
19008
+ ${content}`);
19009
+ }
19010
+ if (parts.length > 0) {
19011
+ systemPrompt += "\n\n---\n\n# \u5E38\u9A7B\u6280\u80FD (Permanent Skills \u2014 \u5DF2\u81EA\u52A8\u6FC0\u6D3B\uFF0C\u6BCF\u8F6E\u5BF9\u8BDD\u5747\u6709\u6548)\n" + parts.join("\n");
19012
+ }
19013
+ }
19014
+ function appendDebugRound(sysPrompt, msgs, response, elapsedMs, tokensIn, tokensOut) {
19015
+ if (!debugFilePath) return;
19016
+ debugRound++;
19017
+ const ts = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN");
19018
+ const lines = [];
19019
+ lines.push(`## \u7B2C ${debugRound} \u8F6E (${ts})`);
19020
+ lines.push("");
19021
+ lines.push("### \u7CFB\u7EDF\u63D0\u793A (System Prompt)");
19022
+ lines.push("");
19023
+ lines.push("```text");
19024
+ lines.push(sysPrompt);
19025
+ lines.push("```");
19026
+ lines.push("");
19027
+ lines.push(`### \u5BF9\u8BDD\u8F93\u5165 (${msgs.length} \u6761\u6D88\u606F)`);
19028
+ lines.push("");
19029
+ msgs.forEach((m2, i2) => {
19030
+ const isLast = i2 === msgs.length - 1;
19031
+ const label = isLast ? `[${i2 + 1}] ${m2.role}\uFF08\u5F53\u524D\u8F93\u5165\uFF09` : `[${i2 + 1}] ${m2.role}`;
19032
+ lines.push(`#### ${label}`);
19033
+ lines.push("");
19034
+ const content = typeof m2.content === "string" ? m2.content : JSON.stringify(m2.content, null, 2);
19035
+ lines.push("```");
19036
+ lines.push(content);
19037
+ lines.push("```");
19038
+ lines.push("");
19039
+ });
19040
+ lines.push("### \u6A21\u578B\u8F93\u51FA");
19041
+ lines.push("");
19042
+ lines.push(response);
19043
+ lines.push("");
19044
+ lines.push("### \u7EDF\u8BA1");
19045
+ lines.push("");
19046
+ lines.push(`| \u6307\u6807 | \u503C |`);
19047
+ lines.push(`|------|-----|`);
19048
+ lines.push(`| \u8017\u65F6 | ${(elapsedMs / 1e3).toFixed(2)}s |`);
19049
+ lines.push(`| \u8F93\u5165 tokens | ${tokensIn} |`);
19050
+ lines.push(`| \u8F93\u51FA tokens | ${tokensOut} |`);
19051
+ lines.push("");
19052
+ lines.push("---");
19053
+ lines.push("");
19054
+ (0, import_fs6.appendFileSync)(debugFilePath, lines.join("\n"), "utf8");
19055
+ }
18850
19056
  async function main() {
19057
+ debugMode = process.argv.includes("--debug");
18851
19058
  installBundledData();
18852
19059
  printBanner();
18853
19060
  await checkAndAutoUpdate().catch(() => {
@@ -18873,8 +19080,15 @@ async function main() {
18873
19080
  console.log(` ${source_default.bold("\u670D\u52A1\u5546:")} ${prov?.name ?? cfg.provider}`);
18874
19081
  console.log(` ${source_default.bold("\u6A21\u578B:")} ${source_default.green(cfg.model)}`);
18875
19082
  console.log(` ${source_default.bold("Skills:")} ${skillsLabel} ${source_default.dim("(/sk \u641C\u7D22 /cat \u5206\u7C7B\u76EE\u5F55)")}`);
19083
+ if (permanentSkillIds.size > 0) {
19084
+ const permList = Array.from(permanentSkillIds).join(", ");
19085
+ console.log(` ${source_default.bold("\u5E38\u9A7B:")} ${source_default.yellow("\u26A1 " + permList)} ${source_default.dim("(/pin \u6DFB\u52A0 /unpin \u79FB\u9664)")}`);
19086
+ }
18876
19087
  console.log(` ${source_default.bold("\u5DE5\u5177:")} bash \xB7 read_file \xB7 write_file \xB7 list_dir \xB7 search_files`);
18877
19088
  console.log(` ${source_default.bold("\u65B0\u529F\u80FD:")} /sessions /resume /checkpoint /run /check-env /install /diff`);
19089
+ if (debugMode) {
19090
+ console.log(source_default.bold.yellow(" [DEBUG \u6A21\u5F0F] \u6BCF\u8F6E\u5C06\u6253\u5370\u5B8C\u6574 Prompt \u53CA Token \u7EDF\u8BA1"));
19091
+ }
18878
19092
  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"));
18879
19093
  const lastSess = getLastSession();
18880
19094
  if (lastSess) {
@@ -18903,10 +19117,43 @@ async function main() {
18903
19117
  }
18904
19118
  console.log();
18905
19119
  }
18906
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
19120
+ rebuildSystemPrompt();
19121
+ if (debugMode) {
19122
+ const debugDir = (0, import_path6.join)(BGI_DIR, "debug");
19123
+ (0, import_fs6.mkdirSync)(debugDir, { recursive: true });
19124
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
19125
+ debugFilePath = (0, import_path6.join)(debugDir, `debug-${ts}.md`);
19126
+ (0, import_fs6.writeFileSync)(
19127
+ debugFilePath,
19128
+ [
19129
+ "# BGI CLI Debug Log",
19130
+ "",
19131
+ `- \u4F1A\u8BDD\u5F00\u59CB: ${(/* @__PURE__ */ new Date()).toLocaleString("zh-CN")}`,
19132
+ `- \u6A21\u578B: ${cfg.model}`,
19133
+ `- \u670D\u52A1\u5546: ${prov?.name ?? cfg.provider}`,
19134
+ "",
19135
+ "---",
19136
+ ""
19137
+ ].join("\n"),
19138
+ "utf8"
19139
+ );
19140
+ console.log(source_default.bold.yellow(` [DEBUG] \u8BB0\u5F55\u6587\u4EF6: ${debugFilePath}`));
19141
+ console.log();
19142
+ }
18907
19143
  let history = [];
18908
19144
  let thinkMode = false;
18909
19145
  const injectedSkills = /* @__PURE__ */ new Map();
19146
+ {
19147
+ const allForSeed = collectAllSkills();
19148
+ for (const id of Array.from(permanentSkillIds)) {
19149
+ const entry = allForSeed.find((e2) => e2.id === id);
19150
+ if (entry) {
19151
+ const sp = (0, import_path6.join)(entry.dir, entry.id, "SKILL.md");
19152
+ const { name } = (0, import_fs6.existsSync)(sp) ? parseSkillMeta((0, import_fs6.readFileSync)(sp, "utf8")) : { name: "" };
19153
+ injectedSkills.set(id, name || id);
19154
+ }
19155
+ }
19156
+ }
18910
19157
  const sessionId = newSessionId();
18911
19158
  const sessionCreatedAt = (/* @__PURE__ */ new Date()).toISOString();
18912
19159
  SESSION_CTX.id = sessionId;
@@ -18978,32 +19225,48 @@ async function main() {
18978
19225
  console.log(` \u6267\u884C\u547D\u4EE4: ${source_default.green("\u2713 " + sessionStats.successCmds + " \u6210\u529F")} ${sessionStats.failCmds > 0 ? source_default.yellow("\u2717 " + sessionStats.failCmds + " \u5931\u8D25") : source_default.dim("\u2717 0 \u5931\u8D25")}`);
18979
19226
  console.log(source_default.bold.cyan("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"));
18980
19227
  rl.close();
18981
- let ans = "n";
18982
- try {
18983
- const exitRl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
18984
- exitRl.on("SIGINT", () => {
18985
- exitRl.close();
18986
- process.exit(0);
18987
- });
18988
- process.once("SIGINT", () => {
18989
- exitRl.close();
18990
- process.exit(0);
18991
- });
18992
- ans = await Promise.race([
18993
- new Promise((res) => {
18994
- exitRl.question(source_default.cyan("\n \u662F\u5426\u4FDD\u5B58\u672C\u6B21\u4F1A\u8BDD\u8BB0\u5FC6\uFF1F[y/N] "), (a2) => {
18995
- exitRl.close();
18996
- res(a2.trim().toLowerCase());
18997
- });
18998
- }),
18999
- new Promise((res) => setTimeout(() => {
19000
- exitRl.close();
19001
- res("n");
19002
- }, 15e3))
19003
- ]);
19004
- } catch {
19228
+ async function askExitQuestion(prompt) {
19229
+ let answer = "n";
19230
+ try {
19231
+ const eRl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
19232
+ eRl.on("SIGINT", () => {
19233
+ eRl.close();
19234
+ process.exit(0);
19235
+ });
19236
+ process.once("SIGINT", () => {
19237
+ eRl.close();
19238
+ process.exit(0);
19239
+ });
19240
+ answer = await Promise.race([
19241
+ new Promise((res) => {
19242
+ eRl.question(prompt, (a2) => {
19243
+ eRl.close();
19244
+ res(a2.trim().toLowerCase());
19245
+ });
19246
+ }),
19247
+ new Promise((res) => setTimeout(() => {
19248
+ eRl.close();
19249
+ res("n");
19250
+ }, 15e3))
19251
+ ]);
19252
+ } catch {
19253
+ }
19254
+ return answer;
19255
+ }
19256
+ const memAns = await askExitQuestion(source_default.cyan("\n \u662F\u5426\u4FDD\u5B58\u672C\u6B21\u4F1A\u8BDD\u8BB0\u5FC6\uFF1F[y/N] "));
19257
+ if (memAns === "y") saveSessionMemory();
19258
+ if (debugMode && debugFilePath && (0, import_fs6.existsSync)(debugFilePath)) {
19259
+ console.log(source_default.dim(`
19260
+ Debug \u6587\u4EF6: ${debugFilePath}`));
19261
+ const delAns = await askExitQuestion(source_default.yellow(" \u662F\u5426\u5220\u9664 debug \u8BB0\u5F55\u6587\u4EF6\uFF1F[y/N] "));
19262
+ if (delAns === "y") {
19263
+ try {
19264
+ (0, import_fs6.rmSync)(debugFilePath);
19265
+ console.log(source_default.dim(" \u5DF2\u5220\u9664"));
19266
+ } catch {
19267
+ }
19268
+ }
19005
19269
  }
19006
- if (ans === "y") saveSessionMemory();
19007
19270
  console.log(source_default.dim("\n\u518D\u89C1\uFF01"));
19008
19271
  process.exit(0);
19009
19272
  }
@@ -19113,8 +19376,21 @@ ${expanded}` : expanded;
19113
19376
  try {
19114
19377
  const currentCfg = loadConfig();
19115
19378
  currentAbortController = new AbortController();
19379
+ const debugT0 = debugMode ? Date.now() : 0;
19380
+ const debugTokensBefore = debugMode ? { in: sessionStats.inputTokens, out: sessionStats.outputTokens } : null;
19116
19381
  const reply = await chat(history, currentCfg, systemPrompt, sessionStats, currentAbortController.signal);
19117
19382
  currentAbortController = null;
19383
+ if (debugMode && debugTokensBefore && reply) {
19384
+ const elapsedMs = Date.now() - debugT0;
19385
+ const dIn = sessionStats.inputTokens - debugTokensBefore.in;
19386
+ const dOut = sessionStats.outputTokens - debugTokensBefore.out;
19387
+ try {
19388
+ appendDebugRound(systemPrompt, history, reply, elapsedMs, dIn, dOut);
19389
+ } catch {
19390
+ }
19391
+ console.log(source_default.bold.yellow(`
19392
+ [DEBUG] \u5DF2\u8BB0\u5F55 \u2192 ${debugFilePath}`));
19393
+ }
19118
19394
  if (!reply && history[history.length - 1]?.role === "user") {
19119
19395
  history.pop();
19120
19396
  console.log();