@bgicli/bgicli 2.5.0 → 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.
@@ -0,0 +1,73 @@
1
+ ---
2
+ id: web-search
3
+ name: Web Search (网络搜索)
4
+ category: utility
5
+ short-description: Search the internet using DuckDuckGo API and curl/Python for any query.
6
+ ---
7
+
8
+ # Web Search 网络搜索
9
+
10
+ 当用户需要搜索互联网、查找最新信息、核实事实、或查询非文献数据库内容时,使用以下方法通过 bash 工具执行网络搜索。
11
+
12
+ ## 规则
13
+ - 直接搜索,不要事先询问"是否需要搜索"
14
+ - 搜索到内容后,整合总结后再回复,不要直接粘贴原始 JSON
15
+ - 如果首次搜索结果不理想,换关键词重试一次
16
+ - 中文问题优先用中文关键词;专业术语用英文效果更好
17
+
18
+ ## 方法一:DuckDuckGo Instant Answer(无需 API Key,适合快速摘要)
19
+
20
+ ```bash
21
+ python3 - <<'EOF'
22
+ import urllib.request, urllib.parse, json, sys
23
+
24
+ query = "YOUR_QUERY_HERE"
25
+ url = "https://api.duckduckgo.com/?q=" + urllib.parse.quote(query) + "&format=json&no_html=1&skip_disambig=1"
26
+ try:
27
+ with urllib.request.urlopen(url, timeout=10) as r:
28
+ d = json.loads(r.read())
29
+ if d.get("AbstractText"):
30
+ print("摘要:", d["AbstractText"])
31
+ print("来源:", d.get("AbstractURL", ""))
32
+ topics = [t for t in d.get("RelatedTopics", []) if isinstance(t, dict) and t.get("Text")]
33
+ for t in topics[:6]:
34
+ print("•", t["Text"])
35
+ if t.get("FirstURL"):
36
+ print(" ", t["FirstURL"])
37
+ except Exception as e:
38
+ print("搜索失败:", e, file=sys.stderr)
39
+ EOF
40
+ ```
41
+
42
+ ## 方法二:获取并解析具体网页内容
43
+
44
+ ```bash
45
+ python3 - <<'EOF'
46
+ import urllib.request, re, sys
47
+
48
+ url = "https://TARGET_URL_HERE"
49
+ try:
50
+ req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
51
+ with urllib.request.urlopen(req, timeout=15) as r:
52
+ html = r.read().decode("utf-8", errors="ignore")
53
+ text = re.sub(r"<script[^>]*>[\s\S]*?</script>", "", html, flags=re.I)
54
+ text = re.sub(r"<style[^>]*>[\s\S]*?</style>", "", text, flags=re.I)
55
+ text = re.sub(r"<[^>]+>", " ", text)
56
+ text = re.sub(r"\s{3,}", "\n\n", text)
57
+ print(text[:4000])
58
+ except Exception as e:
59
+ print("获取失败:", e, file=sys.stderr)
60
+ EOF
61
+ ```
62
+
63
+ ## 方法三:curl 快速搜索
64
+
65
+ ```bash
66
+ curl -sA "Mozilla/5.0" "https://api.duckduckgo.com/?q=QUERY&format=json&no_html=1" \
67
+ | python3 -c "
68
+ import json,sys
69
+ d=json.load(sys.stdin)
70
+ print(d.get('AbstractText',''))
71
+ [print('•',t['Text']) for t in d.get('RelatedTopics',[])[:5] if isinstance(t,dict) and t.get('Text')]
72
+ "
73
+ ```
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();
@@ -17193,7 +17200,7 @@ function clearCheckpoints(sessionId) {
17193
17200
 
17194
17201
  // src/index.ts
17195
17202
  var import_fs7 = require("fs");
17196
- var VERSION2 = "2.5.0";
17203
+ var VERSION2 = "2.6.0";
17197
17204
  var BRAND2 = "bgi".toLowerCase();
17198
17205
  var SKILLHUB_HUBS = {
17199
17206
  bgi: { label: "BGI\u5185\u7F51", apiBase: "https://clawhub.ai", backend: "clawhub" },
@@ -17337,6 +17344,10 @@ var SESSION_CTX = {
17337
17344
  };
17338
17345
  var dbRegistry = { version: 1, lastScan: null, databases: {} };
17339
17346
  var systemPrompt = "";
17347
+ var debugMode = false;
17348
+ var debugFilePath = "";
17349
+ var debugRound = 0;
17350
+ var permanentSkillIds = /* @__PURE__ */ new Set();
17340
17351
  function installBundledData() {
17341
17352
  const bundledData = (0, import_path6.join)(__dirname, "..", "data");
17342
17353
  if (!(0, import_fs6.existsSync)(bundledData)) return;
@@ -17579,8 +17590,9 @@ function collectAllSkills() {
17579
17590
  }
17580
17591
  });
17581
17592
  };
17582
- addFrom(SKILLS_DIR, "skill");
17583
- addFrom(USER_SKILLS_DIR, "user");
17593
+ addFrom(SKILLS_DIR, "bio");
17594
+ addFrom(USER_SKILLS_DIR, "downloaded");
17595
+ addFrom(CUSTOM_SKILLS_DIR, "custom");
17584
17596
  return entries;
17585
17597
  }
17586
17598
  function listSkills(keyword) {
@@ -17668,6 +17680,14 @@ function parseSkillMeta(content) {
17668
17680
  };
17669
17681
  }
17670
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
+ }
17671
17691
  const all = collectAllSkills();
17672
17692
  const match = all.find((e2) => e2.id === id) || all.find((e2) => e2.id.startsWith(id)) || all.find((e2) => e2.id.includes(id));
17673
17693
  if (!match) {
@@ -18572,7 +18592,7 @@ ${paramSummary}
18572
18592
  const label = parts.slice(3).join(" ") || `${type} (${genome})`;
18573
18593
  const entry = addDbEntry(dbRegistry, { label, type, genome, path: dbPath, source: "manual" });
18574
18594
  saveDbRegistry(dbRegistry);
18575
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18595
+ rebuildSystemPrompt();
18576
18596
  console.log(source_default.green(`\u2713 \u5DF2\u6DFB\u52A0\u6570\u636E\u5E93: ${entry.label}`));
18577
18597
  console.log(` id: ${source_default.cyan(entry.id)}`);
18578
18598
  console.log(` \u8DEF\u5F84: ${source_default.dim(entry.path)}`);
@@ -18588,7 +18608,7 @@ ${paramSummary}
18588
18608
  const removed = removeDbEntry(dbRegistry, dbArg.trim());
18589
18609
  if (removed) {
18590
18610
  saveDbRegistry(dbRegistry);
18591
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18611
+ rebuildSystemPrompt();
18592
18612
  console.log(source_default.green(`\u2713 \u5DF2\u79FB\u9664\u6570\u636E\u5E93: ${dbArg}`));
18593
18613
  } else {
18594
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`));
@@ -18623,7 +18643,7 @@ ${paramSummary}
18623
18643
  if (addedCount > 0) {
18624
18644
  dbRegistry.lastScan = (/* @__PURE__ */ new Date()).toISOString();
18625
18645
  saveDbRegistry(dbRegistry);
18626
- systemPrompt = buildSystemPrompt(buildDbPromptSection(dbRegistry));
18646
+ rebuildSystemPrompt();
18627
18647
  console.log(source_default.green(`
18628
18648
  \u2713 \u65B0\u589E ${addedCount} \u4E2A\u6570\u636E\u5E93\u5230\u6CE8\u518C\u8868`));
18629
18649
  } else {
@@ -18705,11 +18725,18 @@ ${summary}` },
18705
18725
  \u5F53\u524D\u5DF2\u52A0\u8F7D\u7684 Skills (${injectedSkills.size} \u4E2A):
18706
18726
  `));
18707
18727
  for (const [id, name] of injectedSkills) {
18708
- console.log(` ${source_default.green("\u25CF")} ${source_default.cyan(id)} ${source_default.dim("\u2014 " + name)}`);
18709
- 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
+ }
18710
18737
  }
18711
18738
  console.log();
18712
- 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"));
18713
18740
  }
18714
18741
  break;
18715
18742
  }
@@ -18726,6 +18753,11 @@ ${summary}` },
18726
18753
  console.log(source_default.dim("\u4F7F\u7528 /skills \u67E5\u770B\u5F53\u524D\u5DF2\u52A0\u8F7D\u7684 Skills"));
18727
18754
  break;
18728
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
+ }
18729
18761
  const SKILL_MARKER = `[Skill \u5DF2\u52A0\u8F7D: ${targetId}]`;
18730
18762
  let removed = 0;
18731
18763
  for (let i2 = history.length - 1; i2 >= 0; i2--) {
@@ -18806,29 +18838,118 @@ ${summary}` },
18806
18838
  }
18807
18839
  case "cat": {
18808
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"));
18809
- 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));
18810
18858
  const byCategory = {};
18811
18859
  for (const route of SKILL_ROUTES) {
18812
- (byCategory[route.category] ??= []).push({ id: route.id, dir: "", tag: route.tag });
18860
+ (byCategory[route.category] ??= []).push(route);
18813
18861
  }
18862
+ console.log(` \u{1F9EC} ${source_default.bold.cyan("\u751F\u7269\u4FE1\u606F Skills")} ${source_default.dim("(\u9700\u6FC0\u6D3B /sk <id>)")}`);
18814
18863
  for (const [catKey, meta] of Object.entries(SKILL_CATEGORIES)) {
18815
- const items = byCategory[catKey];
18816
- if (!items || items.length === 0) continue;
18817
- console.log(` ${meta.icon} ${source_default.bold(meta.label)}`);
18818
- for (const item of items) {
18819
- const route = SKILL_ROUTES.find((r2) => r2.id === item.id);
18820
- 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)}`);
18821
18869
  }
18822
- console.log();
18823
18870
  }
18824
- const routedIds = new Set(SKILL_ROUTES.map((r2) => r2.id));
18825
- const allInstalled = collectAllSkills();
18826
- const unrouted = allInstalled.filter((e2) => !routedIds.has(e2.id));
18827
- if (unrouted.length > 0) {
18828
- console.log(` \u{1F4E6} ${source_default.bold("\u66F4\u591A Skills")} ${source_default.dim(`(${unrouted.length} \u4E2A\uFF0C\u4F7F\u7528\u5173\u952E\u8BCD\u641C\u7D22)`)}`);
18829
- console.log(source_default.dim(" /sk <\u5173\u952E\u8BCD>\uFF0C\u4F8B: /sk ehr /sk clinical /sk imaging"));
18830
- 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;
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;
18831
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`));
18832
18953
  break;
18833
18954
  }
18834
18955
  case "cd": {
@@ -18867,7 +18988,73 @@ ${summary}` },
18867
18988
  }
18868
18989
  return {};
18869
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
+ }
18870
19056
  async function main() {
19057
+ debugMode = process.argv.includes("--debug");
18871
19058
  installBundledData();
18872
19059
  printBanner();
18873
19060
  await checkAndAutoUpdate().catch(() => {
@@ -18893,8 +19080,15 @@ async function main() {
18893
19080
  console.log(` ${source_default.bold("\u670D\u52A1\u5546:")} ${prov?.name ?? cfg.provider}`);
18894
19081
  console.log(` ${source_default.bold("\u6A21\u578B:")} ${source_default.green(cfg.model)}`);
18895
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
+ }
18896
19087
  console.log(` ${source_default.bold("\u5DE5\u5177:")} bash \xB7 read_file \xB7 write_file \xB7 list_dir \xB7 search_files`);
18897
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
+ }
18898
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"));
18899
19093
  const lastSess = getLastSession();
18900
19094
  if (lastSess) {
@@ -18923,10 +19117,43 @@ async function main() {
18923
19117
  }
18924
19118
  console.log();
18925
19119
  }
18926
- 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
+ }
18927
19143
  let history = [];
18928
19144
  let thinkMode = false;
18929
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
+ }
18930
19157
  const sessionId = newSessionId();
18931
19158
  const sessionCreatedAt = (/* @__PURE__ */ new Date()).toISOString();
18932
19159
  SESSION_CTX.id = sessionId;
@@ -18998,32 +19225,48 @@ async function main() {
18998
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")}`);
18999
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"));
19000
19227
  rl.close();
19001
- let ans = "n";
19002
- try {
19003
- const exitRl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
19004
- exitRl.on("SIGINT", () => {
19005
- exitRl.close();
19006
- process.exit(0);
19007
- });
19008
- process.once("SIGINT", () => {
19009
- exitRl.close();
19010
- process.exit(0);
19011
- });
19012
- ans = await Promise.race([
19013
- new Promise((res) => {
19014
- exitRl.question(source_default.cyan("\n \u662F\u5426\u4FDD\u5B58\u672C\u6B21\u4F1A\u8BDD\u8BB0\u5FC6\uFF1F[y/N] "), (a2) => {
19015
- exitRl.close();
19016
- res(a2.trim().toLowerCase());
19017
- });
19018
- }),
19019
- new Promise((res) => setTimeout(() => {
19020
- exitRl.close();
19021
- res("n");
19022
- }, 15e3))
19023
- ]);
19024
- } 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
+ }
19025
19269
  }
19026
- if (ans === "y") saveSessionMemory();
19027
19270
  console.log(source_default.dim("\n\u518D\u89C1\uFF01"));
19028
19271
  process.exit(0);
19029
19272
  }
@@ -19133,8 +19376,21 @@ ${expanded}` : expanded;
19133
19376
  try {
19134
19377
  const currentCfg = loadConfig();
19135
19378
  currentAbortController = new AbortController();
19379
+ const debugT0 = debugMode ? Date.now() : 0;
19380
+ const debugTokensBefore = debugMode ? { in: sessionStats.inputTokens, out: sessionStats.outputTokens } : null;
19136
19381
  const reply = await chat(history, currentCfg, systemPrompt, sessionStats, currentAbortController.signal);
19137
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
+ }
19138
19394
  if (!reply && history[history.length - 1]?.role === "user") {
19139
19395
  history.pop();
19140
19396
  console.log();