@bgicli/bgicli 2.8.5 → 2.8.7

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
@@ -15294,40 +15294,45 @@ async function streamOnce(client, messages, model, signal) {
15294
15294
  text += s2;
15295
15295
  normalWritten = true;
15296
15296
  };
15297
+ let thinkLinePartial = "";
15298
+ let thinkLineCount = 0;
15299
+ const flushThinkLine = (line) => {
15300
+ const chunks = line.match(/.{1,78}/g) ?? [""];
15301
+ for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15302
+ `));
15303
+ thinkLineCount++;
15304
+ };
15305
+ const writeThinkChunk = (s2) => {
15306
+ thinkLinePartial += s2;
15307
+ const parts = thinkLinePartial.split("\n");
15308
+ for (let i2 = 0; i2 < parts.length - 1; i2++) {
15309
+ if (parts[i2] !== "") flushThinkLine(parts[i2]);
15310
+ }
15311
+ thinkLinePartial = parts[parts.length - 1];
15312
+ };
15297
15313
  const startThinkBlock = () => {
15298
15314
  inThink = true;
15299
15315
  thinkBuf = "";
15300
15316
  thinkStartMs = Date.now();
15317
+ thinkLineCount = 0;
15318
+ thinkLinePartial = "";
15301
15319
  if (!normalWritten) process.stdout.write("\n");
15302
- process.stdout.write(source_default.dim(" \u280B \u601D\u8003\u4E2D..."));
15303
- spinIdx = 0;
15304
- spinInterval = setInterval(() => {
15305
- spinIdx = (spinIdx + 1) % SPIN_FRAMES.length;
15306
- process.stdout.write(`\r${source_default.dim(` ${SPIN_FRAMES[spinIdx]} \u601D\u8003\u4E2D...`)}`);
15307
- }, 80);
15320
+ process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(44)}
15321
+ `));
15308
15322
  };
15309
15323
  const endThinkBlock = () => {
15310
15324
  if (spinInterval) {
15311
15325
  clearInterval(spinInterval);
15312
15326
  spinInterval = null;
15313
15327
  }
15314
- process.stdout.write("\r\x1B[K");
15328
+ if (thinkLinePartial.trim()) flushThinkLine(thinkLinePartial);
15329
+ thinkLinePartial = "";
15315
15330
  const elapsed = ((Date.now() - thinkStartMs) / 1e3).toFixed(1);
15316
- const trimmed = thinkBuf.trim();
15317
- if (trimmed) {
15318
- const W2 = 44;
15319
- const suffix = ` \u2713 ${elapsed}s`;
15320
- process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(W2)}
15321
- `));
15322
- for (const line of trimmed.split("\n")) {
15323
- const chunks = line.match(/.{1,78}/g) ?? [""];
15324
- for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15325
- `));
15326
- }
15327
- process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15331
+ const suffix = ` \u2713 ${elapsed}s`;
15332
+ const W2 = 44;
15333
+ process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15328
15334
 
15329
15335
  `));
15330
- }
15331
15336
  inThink = false;
15332
15337
  thinkBuf = "";
15333
15338
  };
@@ -15357,11 +15362,15 @@ async function streamOnce(client, messages, model, signal) {
15357
15362
  const closeIdx = pendingBuf.indexOf(THINK_CLOSE);
15358
15363
  if (closeIdx === -1) {
15359
15364
  const hold = partialTagLen(pendingBuf, THINK_CLOSE);
15360
- thinkBuf += pendingBuf.slice(0, pendingBuf.length - hold);
15365
+ const safe2 = pendingBuf.slice(0, pendingBuf.length - hold);
15366
+ thinkBuf += safe2;
15367
+ writeThinkChunk(safe2);
15361
15368
  pendingBuf = hold > 0 ? pendingBuf.slice(-hold) : "";
15362
15369
  break;
15363
15370
  }
15364
- thinkBuf += pendingBuf.slice(0, closeIdx);
15371
+ const safe = pendingBuf.slice(0, closeIdx);
15372
+ thinkBuf += safe;
15373
+ writeThinkChunk(safe);
15365
15374
  pendingBuf = pendingBuf.slice(closeIdx + THINK_CLOSE.length);
15366
15375
  endThinkBlock();
15367
15376
  if (!normalWritten) process.stdout.write(source_default.green(`${BRAND} \u203A `));
@@ -17774,24 +17783,6 @@ var SKILL_ROUTES = [
17774
17783
  ]
17775
17784
  }
17776
17785
  ];
17777
- function routeSkill(message) {
17778
- const lower = message.toLowerCase();
17779
- const scores = /* @__PURE__ */ new Map();
17780
- for (const route of SKILL_ROUTES) {
17781
- let score = 0;
17782
- for (const kw of route.keywords) {
17783
- if (lower.includes(kw.toLowerCase())) {
17784
- score += 1 + kw.length * 0.1;
17785
- }
17786
- }
17787
- if (score > 0) scores.set(route.id, { route, score });
17788
- }
17789
- const sorted = Array.from(scores.values()).sort((a2, b2) => b2.score - a2.score).slice(0, 5);
17790
- return {
17791
- routes: sorted.map((v2) => v2.route),
17792
- topScore: sorted[0]?.score ?? 0
17793
- };
17794
- }
17795
17786
 
17796
17787
  // src/sessions.ts
17797
17788
  var import_fs5 = require("fs");
@@ -17919,7 +17910,7 @@ function clearCheckpoints(sessionId) {
17919
17910
 
17920
17911
  // src/index.ts
17921
17912
  var import_fs7 = require("fs");
17922
- var VERSION2 = "2.8.5";
17913
+ var VERSION2 = "2.8.7";
17923
17914
  var BRAND2 = "bgi".toLowerCase();
17924
17915
  var SKILLHUB_HUBS = {
17925
17916
  bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
@@ -18391,7 +18382,6 @@ async function llmRecommendSkills(userQuery) {
18391
18382
  const cfg = loadConfig();
18392
18383
  const ep = getActiveEndpoint(cfg);
18393
18384
  if (!ep.url) return [];
18394
- if (!ep.apiKey) return [];
18395
18385
  const baseURL = ep.url;
18396
18386
  const model = getCurrentModel(cfg);
18397
18387
  const apiKey = ep.apiKey;
@@ -18409,7 +18399,8 @@ async function llmRecommendSkills(userQuery) {
18409
18399
  if (catalogLines.length === 0) return [];
18410
18400
  const catalog = catalogLines.join("\n");
18411
18401
  const systemMsg = `\u4F60\u662F\u4E00\u4E2A\u751F\u7269\u4FE1\u606F\u5B66 Skill \u63A8\u8350\u52A9\u624B\u3002
18412
- \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 5 \u4E2A\uFF08\u6216\u66F4\u5C11\uFF09\u3002
18402
+ \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 1-3 \u4E2A\u3002
18403
+ \u53EA\u63A8\u8350\u771F\u6B63\u9700\u8981\u7684\uFF0C\u4E0D\u8981\u51D1\u6570\u3002\u5982\u679C\u6CA1\u6709\u5408\u9002\u7684\u5C31\u8FD4\u56DE\u7A7A\u6570\u7EC4 []\u3002
18413
18404
 
18414
18405
  Skill \u76EE\u5F55\uFF08\u683C\u5F0F: id|\u540D\u79F0 \u2014 \u7B80\u4ECB\uFF09\uFF1A
18415
18406
  ${catalog}
@@ -18427,15 +18418,16 @@ ${catalog}
18427
18418
  { role: "system", content: systemMsg },
18428
18419
  { role: "user", content: userQuery }
18429
18420
  ],
18430
- temperature: 0.2,
18431
- max_tokens: 800
18421
+ temperature: 0.1,
18422
+ max_tokens: 400
18432
18423
  });
18433
18424
  const text = resp.choices[0]?.message?.content ?? "";
18434
- const jsonMatch = text.match(/\[[\s\S]*\]/);
18425
+ const stripped = text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
18426
+ const jsonMatch = stripped.match(/\[[\s\S]*\]/);
18435
18427
  if (!jsonMatch) return [];
18436
18428
  const parsed = JSON.parse(jsonMatch[0]);
18437
18429
  const validIds = new Set(all.map((e2) => e2.id));
18438
- return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 5);
18430
+ return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 3);
18439
18431
  } catch {
18440
18432
  return [];
18441
18433
  }
@@ -20180,33 +20172,52 @@ async function main() {
20180
20172
  console.log();
20181
20173
  continue;
20182
20174
  }
20183
- const { routes: suggestedRoutes, topScore } = routeSkill(trimmed);
20184
- const newRoutes = suggestedRoutes.filter((r2) => !injectedSkills.has(r2.id));
20185
- if (newRoutes.length === 1 && topScore >= 8) {
20186
- await injectSkill(newRoutes[0].id, history, injectedSkills, rl, false);
20187
- } else if (newRoutes.length >= 1 && topScore >= 2) {
20188
- const candidates = newRoutes.slice(0, 3);
20189
- console.log();
20190
- console.log(source_default.bold.yellow("\u250C\u2500 \u{1F50D} \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20191
- candidates.forEach((r2, i2) => {
20192
- console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20193
- });
20194
- console.log(source_default.bold.yellow("\u2514\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"));
20195
- const pickPrompt = candidates.length > 1 ? ` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A ` : ` \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A `;
20196
- const skillChoice = await question(rl, source_default.yellow(pickPrompt));
20197
- const choiceTrimmed = skillChoice.trim().toLowerCase();
20198
- if (choiceTrimmed !== "" && choiceTrimmed !== "n") {
20199
- let indices;
20200
- if (candidates.length === 1) {
20201
- indices = choiceTrimmed === "y" || choiceTrimmed === "" ? [0] : [];
20202
- } else {
20203
- indices = choiceTrimmed.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < candidates.length);
20175
+ {
20176
+ const SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
20177
+ let spinIdx2 = 0;
20178
+ process.stdout.write(source_default.dim(" \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD..."));
20179
+ const spinTimer = setInterval(() => {
20180
+ spinIdx2 = (spinIdx2 + 1) % SPIN.length;
20181
+ process.stdout.write(`\r${source_default.dim(` ${SPIN[spinIdx2]} \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD...`)}`);
20182
+ }, 80);
20183
+ let recs = [];
20184
+ try {
20185
+ recs = await llmRecommendSkills(trimmed);
20186
+ } catch {
20187
+ }
20188
+ clearInterval(spinTimer);
20189
+ process.stdout.write("\r\x1B[K");
20190
+ const newRecs = recs.filter((r2) => !injectedSkills.has(r2.id));
20191
+ if (newRecs.length === 1) {
20192
+ console.log();
20193
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20194
+ console.log(`\u2502 ${source_default.bold.cyan("[1]")} ${source_default.cyan(newRecs[0].id)}${source_default.dim(" \u2014")} ${newRecs[0].name}`);
20195
+ console.log(source_default.dim(`\u2502 ${newRecs[0].reason}`));
20196
+ console.log(source_default.bold.yellow("\u2514\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"));
20197
+ const skillChoice = await question(rl, source_default.yellow(" \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A "));
20198
+ const c2 = skillChoice.trim().toLowerCase();
20199
+ if (c2 === "" || c2 === "y") {
20200
+ await injectSkill(newRecs[0].id, history, injectedSkills, rl, true);
20204
20201
  }
20205
- for (const idx of indices) {
20206
- await injectSkill(candidates[idx].id, history, injectedSkills, rl, true);
20202
+ console.log();
20203
+ } else if (newRecs.length > 1) {
20204
+ console.log();
20205
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20206
+ newRecs.forEach((r2, i2) => {
20207
+ console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20208
+ console.log(source_default.dim(`\u2502 ${r2.reason}`));
20209
+ });
20210
+ console.log(source_default.bold.yellow("\u2514\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"));
20211
+ const skillChoice = await question(rl, source_default.yellow(` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A `));
20212
+ const c2 = skillChoice.trim().toLowerCase();
20213
+ if (c2 !== "" && c2 !== "n") {
20214
+ const indices = c2.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < newRecs.length);
20215
+ for (const idx of indices) {
20216
+ await injectSkill(newRecs[idx].id, history, injectedSkills, rl, true);
20217
+ }
20207
20218
  }
20219
+ console.log();
20208
20220
  }
20209
- console.log();
20210
20221
  }
20211
20222
  const expanded = expandFileRefs(trimmed);
20212
20223
  const userContent = thinkMode ? `/think
package/dist/bio.js CHANGED
@@ -15294,40 +15294,45 @@ async function streamOnce(client, messages, model, signal) {
15294
15294
  text += s2;
15295
15295
  normalWritten = true;
15296
15296
  };
15297
+ let thinkLinePartial = "";
15298
+ let thinkLineCount = 0;
15299
+ const flushThinkLine = (line) => {
15300
+ const chunks = line.match(/.{1,78}/g) ?? [""];
15301
+ for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15302
+ `));
15303
+ thinkLineCount++;
15304
+ };
15305
+ const writeThinkChunk = (s2) => {
15306
+ thinkLinePartial += s2;
15307
+ const parts = thinkLinePartial.split("\n");
15308
+ for (let i2 = 0; i2 < parts.length - 1; i2++) {
15309
+ if (parts[i2] !== "") flushThinkLine(parts[i2]);
15310
+ }
15311
+ thinkLinePartial = parts[parts.length - 1];
15312
+ };
15297
15313
  const startThinkBlock = () => {
15298
15314
  inThink = true;
15299
15315
  thinkBuf = "";
15300
15316
  thinkStartMs = Date.now();
15317
+ thinkLineCount = 0;
15318
+ thinkLinePartial = "";
15301
15319
  if (!normalWritten) process.stdout.write("\n");
15302
- process.stdout.write(source_default.dim(" \u280B \u601D\u8003\u4E2D..."));
15303
- spinIdx = 0;
15304
- spinInterval = setInterval(() => {
15305
- spinIdx = (spinIdx + 1) % SPIN_FRAMES.length;
15306
- process.stdout.write(`\r${source_default.dim(` ${SPIN_FRAMES[spinIdx]} \u601D\u8003\u4E2D...`)}`);
15307
- }, 80);
15320
+ process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(44)}
15321
+ `));
15308
15322
  };
15309
15323
  const endThinkBlock = () => {
15310
15324
  if (spinInterval) {
15311
15325
  clearInterval(spinInterval);
15312
15326
  spinInterval = null;
15313
15327
  }
15314
- process.stdout.write("\r\x1B[K");
15328
+ if (thinkLinePartial.trim()) flushThinkLine(thinkLinePartial);
15329
+ thinkLinePartial = "";
15315
15330
  const elapsed = ((Date.now() - thinkStartMs) / 1e3).toFixed(1);
15316
- const trimmed = thinkBuf.trim();
15317
- if (trimmed) {
15318
- const W2 = 44;
15319
- const suffix = ` \u2713 ${elapsed}s`;
15320
- process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(W2)}
15321
- `));
15322
- for (const line of trimmed.split("\n")) {
15323
- const chunks = line.match(/.{1,78}/g) ?? [""];
15324
- for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15325
- `));
15326
- }
15327
- process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15331
+ const suffix = ` \u2713 ${elapsed}s`;
15332
+ const W2 = 44;
15333
+ process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15328
15334
 
15329
15335
  `));
15330
- }
15331
15336
  inThink = false;
15332
15337
  thinkBuf = "";
15333
15338
  };
@@ -15357,11 +15362,15 @@ async function streamOnce(client, messages, model, signal) {
15357
15362
  const closeIdx = pendingBuf.indexOf(THINK_CLOSE);
15358
15363
  if (closeIdx === -1) {
15359
15364
  const hold = partialTagLen(pendingBuf, THINK_CLOSE);
15360
- thinkBuf += pendingBuf.slice(0, pendingBuf.length - hold);
15365
+ const safe2 = pendingBuf.slice(0, pendingBuf.length - hold);
15366
+ thinkBuf += safe2;
15367
+ writeThinkChunk(safe2);
15361
15368
  pendingBuf = hold > 0 ? pendingBuf.slice(-hold) : "";
15362
15369
  break;
15363
15370
  }
15364
- thinkBuf += pendingBuf.slice(0, closeIdx);
15371
+ const safe = pendingBuf.slice(0, closeIdx);
15372
+ thinkBuf += safe;
15373
+ writeThinkChunk(safe);
15365
15374
  pendingBuf = pendingBuf.slice(closeIdx + THINK_CLOSE.length);
15366
15375
  endThinkBlock();
15367
15376
  if (!normalWritten) process.stdout.write(source_default.green(`${BRAND} \u203A `));
@@ -17774,24 +17783,6 @@ var SKILL_ROUTES = [
17774
17783
  ]
17775
17784
  }
17776
17785
  ];
17777
- function routeSkill(message) {
17778
- const lower = message.toLowerCase();
17779
- const scores = /* @__PURE__ */ new Map();
17780
- for (const route of SKILL_ROUTES) {
17781
- let score = 0;
17782
- for (const kw of route.keywords) {
17783
- if (lower.includes(kw.toLowerCase())) {
17784
- score += 1 + kw.length * 0.1;
17785
- }
17786
- }
17787
- if (score > 0) scores.set(route.id, { route, score });
17788
- }
17789
- const sorted = Array.from(scores.values()).sort((a2, b2) => b2.score - a2.score).slice(0, 5);
17790
- return {
17791
- routes: sorted.map((v2) => v2.route),
17792
- topScore: sorted[0]?.score ?? 0
17793
- };
17794
- }
17795
17786
 
17796
17787
  // src/sessions.ts
17797
17788
  var import_fs5 = require("fs");
@@ -17919,7 +17910,7 @@ function clearCheckpoints(sessionId) {
17919
17910
 
17920
17911
  // src/index.ts
17921
17912
  var import_fs7 = require("fs");
17922
- var VERSION2 = "2.8.5";
17913
+ var VERSION2 = "2.8.7";
17923
17914
  var BRAND2 = "bio".toLowerCase();
17924
17915
  var SKILLHUB_HUBS = {
17925
17916
  bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
@@ -18391,7 +18382,6 @@ async function llmRecommendSkills(userQuery) {
18391
18382
  const cfg = loadConfig();
18392
18383
  const ep = getActiveEndpoint(cfg);
18393
18384
  if (!ep.url) return [];
18394
- if (!ep.apiKey) return [];
18395
18385
  const baseURL = ep.url;
18396
18386
  const model = getCurrentModel(cfg);
18397
18387
  const apiKey = ep.apiKey;
@@ -18409,7 +18399,8 @@ async function llmRecommendSkills(userQuery) {
18409
18399
  if (catalogLines.length === 0) return [];
18410
18400
  const catalog = catalogLines.join("\n");
18411
18401
  const systemMsg = `\u4F60\u662F\u4E00\u4E2A\u751F\u7269\u4FE1\u606F\u5B66 Skill \u63A8\u8350\u52A9\u624B\u3002
18412
- \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 5 \u4E2A\uFF08\u6216\u66F4\u5C11\uFF09\u3002
18402
+ \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 1-3 \u4E2A\u3002
18403
+ \u53EA\u63A8\u8350\u771F\u6B63\u9700\u8981\u7684\uFF0C\u4E0D\u8981\u51D1\u6570\u3002\u5982\u679C\u6CA1\u6709\u5408\u9002\u7684\u5C31\u8FD4\u56DE\u7A7A\u6570\u7EC4 []\u3002
18413
18404
 
18414
18405
  Skill \u76EE\u5F55\uFF08\u683C\u5F0F: id|\u540D\u79F0 \u2014 \u7B80\u4ECB\uFF09\uFF1A
18415
18406
  ${catalog}
@@ -18427,15 +18418,16 @@ ${catalog}
18427
18418
  { role: "system", content: systemMsg },
18428
18419
  { role: "user", content: userQuery }
18429
18420
  ],
18430
- temperature: 0.2,
18431
- max_tokens: 800
18421
+ temperature: 0.1,
18422
+ max_tokens: 400
18432
18423
  });
18433
18424
  const text = resp.choices[0]?.message?.content ?? "";
18434
- const jsonMatch = text.match(/\[[\s\S]*\]/);
18425
+ const stripped = text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
18426
+ const jsonMatch = stripped.match(/\[[\s\S]*\]/);
18435
18427
  if (!jsonMatch) return [];
18436
18428
  const parsed = JSON.parse(jsonMatch[0]);
18437
18429
  const validIds = new Set(all.map((e2) => e2.id));
18438
- return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 5);
18430
+ return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 3);
18439
18431
  } catch {
18440
18432
  return [];
18441
18433
  }
@@ -20180,33 +20172,52 @@ async function main() {
20180
20172
  console.log();
20181
20173
  continue;
20182
20174
  }
20183
- const { routes: suggestedRoutes, topScore } = routeSkill(trimmed);
20184
- const newRoutes = suggestedRoutes.filter((r2) => !injectedSkills.has(r2.id));
20185
- if (newRoutes.length === 1 && topScore >= 8) {
20186
- await injectSkill(newRoutes[0].id, history, injectedSkills, rl, false);
20187
- } else if (newRoutes.length >= 1 && topScore >= 2) {
20188
- const candidates = newRoutes.slice(0, 3);
20189
- console.log();
20190
- console.log(source_default.bold.yellow("\u250C\u2500 \u{1F50D} \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20191
- candidates.forEach((r2, i2) => {
20192
- console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20193
- });
20194
- console.log(source_default.bold.yellow("\u2514\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"));
20195
- const pickPrompt = candidates.length > 1 ? ` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A ` : ` \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A `;
20196
- const skillChoice = await question(rl, source_default.yellow(pickPrompt));
20197
- const choiceTrimmed = skillChoice.trim().toLowerCase();
20198
- if (choiceTrimmed !== "" && choiceTrimmed !== "n") {
20199
- let indices;
20200
- if (candidates.length === 1) {
20201
- indices = choiceTrimmed === "y" || choiceTrimmed === "" ? [0] : [];
20202
- } else {
20203
- indices = choiceTrimmed.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < candidates.length);
20175
+ {
20176
+ const SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
20177
+ let spinIdx2 = 0;
20178
+ process.stdout.write(source_default.dim(" \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD..."));
20179
+ const spinTimer = setInterval(() => {
20180
+ spinIdx2 = (spinIdx2 + 1) % SPIN.length;
20181
+ process.stdout.write(`\r${source_default.dim(` ${SPIN[spinIdx2]} \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD...`)}`);
20182
+ }, 80);
20183
+ let recs = [];
20184
+ try {
20185
+ recs = await llmRecommendSkills(trimmed);
20186
+ } catch {
20187
+ }
20188
+ clearInterval(spinTimer);
20189
+ process.stdout.write("\r\x1B[K");
20190
+ const newRecs = recs.filter((r2) => !injectedSkills.has(r2.id));
20191
+ if (newRecs.length === 1) {
20192
+ console.log();
20193
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20194
+ console.log(`\u2502 ${source_default.bold.cyan("[1]")} ${source_default.cyan(newRecs[0].id)}${source_default.dim(" \u2014")} ${newRecs[0].name}`);
20195
+ console.log(source_default.dim(`\u2502 ${newRecs[0].reason}`));
20196
+ console.log(source_default.bold.yellow("\u2514\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"));
20197
+ const skillChoice = await question(rl, source_default.yellow(" \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A "));
20198
+ const c2 = skillChoice.trim().toLowerCase();
20199
+ if (c2 === "" || c2 === "y") {
20200
+ await injectSkill(newRecs[0].id, history, injectedSkills, rl, true);
20204
20201
  }
20205
- for (const idx of indices) {
20206
- await injectSkill(candidates[idx].id, history, injectedSkills, rl, true);
20202
+ console.log();
20203
+ } else if (newRecs.length > 1) {
20204
+ console.log();
20205
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20206
+ newRecs.forEach((r2, i2) => {
20207
+ console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20208
+ console.log(source_default.dim(`\u2502 ${r2.reason}`));
20209
+ });
20210
+ console.log(source_default.bold.yellow("\u2514\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"));
20211
+ const skillChoice = await question(rl, source_default.yellow(` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A `));
20212
+ const c2 = skillChoice.trim().toLowerCase();
20213
+ if (c2 !== "" && c2 !== "n") {
20214
+ const indices = c2.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < newRecs.length);
20215
+ for (const idx of indices) {
20216
+ await injectSkill(newRecs[idx].id, history, injectedSkills, rl, true);
20217
+ }
20207
20218
  }
20219
+ console.log();
20208
20220
  }
20209
- console.log();
20210
20221
  }
20211
20222
  const expanded = expandFileRefs(trimmed);
20212
20223
  const userContent = thinkMode ? `/think
package/dist/mbp.js CHANGED
@@ -15294,40 +15294,45 @@ async function streamOnce(client, messages, model, signal) {
15294
15294
  text += s2;
15295
15295
  normalWritten = true;
15296
15296
  };
15297
+ let thinkLinePartial = "";
15298
+ let thinkLineCount = 0;
15299
+ const flushThinkLine = (line) => {
15300
+ const chunks = line.match(/.{1,78}/g) ?? [""];
15301
+ for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15302
+ `));
15303
+ thinkLineCount++;
15304
+ };
15305
+ const writeThinkChunk = (s2) => {
15306
+ thinkLinePartial += s2;
15307
+ const parts = thinkLinePartial.split("\n");
15308
+ for (let i2 = 0; i2 < parts.length - 1; i2++) {
15309
+ if (parts[i2] !== "") flushThinkLine(parts[i2]);
15310
+ }
15311
+ thinkLinePartial = parts[parts.length - 1];
15312
+ };
15297
15313
  const startThinkBlock = () => {
15298
15314
  inThink = true;
15299
15315
  thinkBuf = "";
15300
15316
  thinkStartMs = Date.now();
15317
+ thinkLineCount = 0;
15318
+ thinkLinePartial = "";
15301
15319
  if (!normalWritten) process.stdout.write("\n");
15302
- process.stdout.write(source_default.dim(" \u280B \u601D\u8003\u4E2D..."));
15303
- spinIdx = 0;
15304
- spinInterval = setInterval(() => {
15305
- spinIdx = (spinIdx + 1) % SPIN_FRAMES.length;
15306
- process.stdout.write(`\r${source_default.dim(` ${SPIN_FRAMES[spinIdx]} \u601D\u8003\u4E2D...`)}`);
15307
- }, 80);
15320
+ process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(44)}
15321
+ `));
15308
15322
  };
15309
15323
  const endThinkBlock = () => {
15310
15324
  if (spinInterval) {
15311
15325
  clearInterval(spinInterval);
15312
15326
  spinInterval = null;
15313
15327
  }
15314
- process.stdout.write("\r\x1B[K");
15328
+ if (thinkLinePartial.trim()) flushThinkLine(thinkLinePartial);
15329
+ thinkLinePartial = "";
15315
15330
  const elapsed = ((Date.now() - thinkStartMs) / 1e3).toFixed(1);
15316
- const trimmed = thinkBuf.trim();
15317
- if (trimmed) {
15318
- const W2 = 44;
15319
- const suffix = ` \u2713 ${elapsed}s`;
15320
- process.stdout.write(source_default.dim(` \u256D${"\u2500".repeat(W2)}
15321
- `));
15322
- for (const line of trimmed.split("\n")) {
15323
- const chunks = line.match(/.{1,78}/g) ?? [""];
15324
- for (const c2 of chunks) process.stdout.write(source_default.dim(` \u2502 ${c2}
15325
- `));
15326
- }
15327
- process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15331
+ const suffix = ` \u2713 ${elapsed}s`;
15332
+ const W2 = 44;
15333
+ process.stdout.write(source_default.dim(` \u2570${"\u2500".repeat(Math.max(0, W2 - suffix.length))}${suffix}
15328
15334
 
15329
15335
  `));
15330
- }
15331
15336
  inThink = false;
15332
15337
  thinkBuf = "";
15333
15338
  };
@@ -15357,11 +15362,15 @@ async function streamOnce(client, messages, model, signal) {
15357
15362
  const closeIdx = pendingBuf.indexOf(THINK_CLOSE);
15358
15363
  if (closeIdx === -1) {
15359
15364
  const hold = partialTagLen(pendingBuf, THINK_CLOSE);
15360
- thinkBuf += pendingBuf.slice(0, pendingBuf.length - hold);
15365
+ const safe2 = pendingBuf.slice(0, pendingBuf.length - hold);
15366
+ thinkBuf += safe2;
15367
+ writeThinkChunk(safe2);
15361
15368
  pendingBuf = hold > 0 ? pendingBuf.slice(-hold) : "";
15362
15369
  break;
15363
15370
  }
15364
- thinkBuf += pendingBuf.slice(0, closeIdx);
15371
+ const safe = pendingBuf.slice(0, closeIdx);
15372
+ thinkBuf += safe;
15373
+ writeThinkChunk(safe);
15365
15374
  pendingBuf = pendingBuf.slice(closeIdx + THINK_CLOSE.length);
15366
15375
  endThinkBlock();
15367
15376
  if (!normalWritten) process.stdout.write(source_default.green(`${BRAND} \u203A `));
@@ -17774,24 +17783,6 @@ var SKILL_ROUTES = [
17774
17783
  ]
17775
17784
  }
17776
17785
  ];
17777
- function routeSkill(message) {
17778
- const lower = message.toLowerCase();
17779
- const scores = /* @__PURE__ */ new Map();
17780
- for (const route of SKILL_ROUTES) {
17781
- let score = 0;
17782
- for (const kw of route.keywords) {
17783
- if (lower.includes(kw.toLowerCase())) {
17784
- score += 1 + kw.length * 0.1;
17785
- }
17786
- }
17787
- if (score > 0) scores.set(route.id, { route, score });
17788
- }
17789
- const sorted = Array.from(scores.values()).sort((a2, b2) => b2.score - a2.score).slice(0, 5);
17790
- return {
17791
- routes: sorted.map((v2) => v2.route),
17792
- topScore: sorted[0]?.score ?? 0
17793
- };
17794
- }
17795
17786
 
17796
17787
  // src/sessions.ts
17797
17788
  var import_fs5 = require("fs");
@@ -17919,7 +17910,7 @@ function clearCheckpoints(sessionId) {
17919
17910
 
17920
17911
  // src/index.ts
17921
17912
  var import_fs7 = require("fs");
17922
- var VERSION2 = "2.8.5";
17913
+ var VERSION2 = "2.8.7";
17923
17914
  var BRAND2 = "mbp".toLowerCase();
17924
17915
  var SKILLHUB_HUBS = {
17925
17916
  bgi: { label: "BGI \u672C\u5730", apiBase: "", backend: "local" },
@@ -18391,7 +18382,6 @@ async function llmRecommendSkills(userQuery) {
18391
18382
  const cfg = loadConfig();
18392
18383
  const ep = getActiveEndpoint(cfg);
18393
18384
  if (!ep.url) return [];
18394
- if (!ep.apiKey) return [];
18395
18385
  const baseURL = ep.url;
18396
18386
  const model = getCurrentModel(cfg);
18397
18387
  const apiKey = ep.apiKey;
@@ -18409,7 +18399,8 @@ async function llmRecommendSkills(userQuery) {
18409
18399
  if (catalogLines.length === 0) return [];
18410
18400
  const catalog = catalogLines.join("\n");
18411
18401
  const systemMsg = `\u4F60\u662F\u4E00\u4E2A\u751F\u7269\u4FE1\u606F\u5B66 Skill \u63A8\u8350\u52A9\u624B\u3002
18412
- \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 5 \u4E2A\uFF08\u6216\u66F4\u5C11\uFF09\u3002
18402
+ \u7528\u6237\u4F1A\u63CF\u8FF0\u4ED6\u4EEC\u60F3\u505A\u7684\u5206\u6790\u4EFB\u52A1\uFF0C\u4F60\u9700\u8981\u4ECE\u4E0B\u9762\u7684 Skill \u76EE\u5F55\u4E2D\u63A8\u8350\u6700\u76F8\u5173\u7684 1-3 \u4E2A\u3002
18403
+ \u53EA\u63A8\u8350\u771F\u6B63\u9700\u8981\u7684\uFF0C\u4E0D\u8981\u51D1\u6570\u3002\u5982\u679C\u6CA1\u6709\u5408\u9002\u7684\u5C31\u8FD4\u56DE\u7A7A\u6570\u7EC4 []\u3002
18413
18404
 
18414
18405
  Skill \u76EE\u5F55\uFF08\u683C\u5F0F: id|\u540D\u79F0 \u2014 \u7B80\u4ECB\uFF09\uFF1A
18415
18406
  ${catalog}
@@ -18427,15 +18418,16 @@ ${catalog}
18427
18418
  { role: "system", content: systemMsg },
18428
18419
  { role: "user", content: userQuery }
18429
18420
  ],
18430
- temperature: 0.2,
18431
- max_tokens: 800
18421
+ temperature: 0.1,
18422
+ max_tokens: 400
18432
18423
  });
18433
18424
  const text = resp.choices[0]?.message?.content ?? "";
18434
- const jsonMatch = text.match(/\[[\s\S]*\]/);
18425
+ const stripped = text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
18426
+ const jsonMatch = stripped.match(/\[[\s\S]*\]/);
18435
18427
  if (!jsonMatch) return [];
18436
18428
  const parsed = JSON.parse(jsonMatch[0]);
18437
18429
  const validIds = new Set(all.map((e2) => e2.id));
18438
- return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 5);
18430
+ return parsed.filter((r2) => r2.id && validIds.has(r2.id)).slice(0, 3);
18439
18431
  } catch {
18440
18432
  return [];
18441
18433
  }
@@ -20180,33 +20172,52 @@ async function main() {
20180
20172
  console.log();
20181
20173
  continue;
20182
20174
  }
20183
- const { routes: suggestedRoutes, topScore } = routeSkill(trimmed);
20184
- const newRoutes = suggestedRoutes.filter((r2) => !injectedSkills.has(r2.id));
20185
- if (newRoutes.length === 1 && topScore >= 8) {
20186
- await injectSkill(newRoutes[0].id, history, injectedSkills, rl, false);
20187
- } else if (newRoutes.length >= 1 && topScore >= 2) {
20188
- const candidates = newRoutes.slice(0, 3);
20189
- console.log();
20190
- console.log(source_default.bold.yellow("\u250C\u2500 \u{1F50D} \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20191
- candidates.forEach((r2, i2) => {
20192
- console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20193
- });
20194
- console.log(source_default.bold.yellow("\u2514\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"));
20195
- const pickPrompt = candidates.length > 1 ? ` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A ` : ` \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A `;
20196
- const skillChoice = await question(rl, source_default.yellow(pickPrompt));
20197
- const choiceTrimmed = skillChoice.trim().toLowerCase();
20198
- if (choiceTrimmed !== "" && choiceTrimmed !== "n") {
20199
- let indices;
20200
- if (candidates.length === 1) {
20201
- indices = choiceTrimmed === "y" || choiceTrimmed === "" ? [0] : [];
20202
- } else {
20203
- indices = choiceTrimmed.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < candidates.length);
20175
+ {
20176
+ const SPIN = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
20177
+ let spinIdx2 = 0;
20178
+ process.stdout.write(source_default.dim(" \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD..."));
20179
+ const spinTimer = setInterval(() => {
20180
+ spinIdx2 = (spinIdx2 + 1) % SPIN.length;
20181
+ process.stdout.write(`\r${source_default.dim(` ${SPIN[spinIdx2]} \u6B63\u5728\u68C0\u7D22\u76F8\u5173\u6280\u80FD...`)}`);
20182
+ }, 80);
20183
+ let recs = [];
20184
+ try {
20185
+ recs = await llmRecommendSkills(trimmed);
20186
+ } catch {
20187
+ }
20188
+ clearInterval(spinTimer);
20189
+ process.stdout.write("\r\x1B[K");
20190
+ const newRecs = recs.filter((r2) => !injectedSkills.has(r2.id));
20191
+ if (newRecs.length === 1) {
20192
+ console.log();
20193
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20194
+ console.log(`\u2502 ${source_default.bold.cyan("[1]")} ${source_default.cyan(newRecs[0].id)}${source_default.dim(" \u2014")} ${newRecs[0].name}`);
20195
+ console.log(source_default.dim(`\u2502 ${newRecs[0].reason}`));
20196
+ console.log(source_default.bold.yellow("\u2514\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"));
20197
+ const skillChoice = await question(rl, source_default.yellow(" \u6FC0\u6D3B\u6B64\u6280\u80FD\uFF1F[Y/n] \u203A "));
20198
+ const c2 = skillChoice.trim().toLowerCase();
20199
+ if (c2 === "" || c2 === "y") {
20200
+ await injectSkill(newRecs[0].id, history, injectedSkills, rl, true);
20204
20201
  }
20205
- for (const idx of indices) {
20206
- await injectSkill(candidates[idx].id, history, injectedSkills, rl, true);
20202
+ console.log();
20203
+ } else if (newRecs.length > 1) {
20204
+ console.log();
20205
+ console.log(source_default.bold.yellow("\u250C\u2500 \u68C0\u6D4B\u5230\u76F8\u5173\u6280\u80FD \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"));
20206
+ newRecs.forEach((r2, i2) => {
20207
+ console.log(`\u2502 ${source_default.bold.cyan(`[${i2 + 1}]`)} ${source_default.cyan(r2.id)}${source_default.dim(" \u2014")} ${r2.name}`);
20208
+ console.log(source_default.dim(`\u2502 ${r2.reason}`));
20209
+ });
20210
+ console.log(source_default.bold.yellow("\u2514\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"));
20211
+ const skillChoice = await question(rl, source_default.yellow(` \u6FC0\u6D3B\u54EA\u4E2A\u6280\u80FD\uFF1F\u8F93\u5165\u7F16\u53F7 (\u5982 1 \u6216 1,2)\uFF0C\u56DE\u8F66\u8DF3\u8FC7 \u203A `));
20212
+ const c2 = skillChoice.trim().toLowerCase();
20213
+ if (c2 !== "" && c2 !== "n") {
20214
+ const indices = c2.split(",").map((s2) => parseInt(s2.trim(), 10) - 1).filter((i2) => i2 >= 0 && i2 < newRecs.length);
20215
+ for (const idx of indices) {
20216
+ await injectSkill(newRecs[idx].id, history, injectedSkills, rl, true);
20217
+ }
20207
20218
  }
20219
+ console.log();
20208
20220
  }
20209
- console.log();
20210
20221
  }
20211
20222
  const expanded = expandFileRefs(trimmed);
20212
20223
  const userContent = thinkMode ? `/think
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bgicli/bgicli",
3
- "version": "2.8.5",
3
+ "version": "2.8.7",
4
4
  "description": "BGI CLI — Bioinformatics AI terminal for Chinese researchers (百炼/DeepSeek/Kimi/Qwen)",
5
5
  "bin": {
6
6
  "bgi": "dist/bgi.js",