@zqagent/core 0.3.16 → 0.3.22

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/index.cjs CHANGED
@@ -8861,6 +8861,9 @@ function nameOf(node) {
8861
8861
  if (typeNode?.text) return typeNode.text.split("<")[0].trim();
8862
8862
  return null;
8863
8863
  }
8864
+ function spanOf(node) {
8865
+ return { line: node.startPosition.row + 1, endLine: node.endPosition.row + 1 };
8866
+ }
8864
8867
  var MAX_COLLECT = 200;
8865
8868
  var VARIABLE_DECLARATIONS = /* @__PURE__ */ new Set(["lexical_declaration", "variable_declaration"]);
8866
8869
  var MODULE_CONTAINERS = /* @__PURE__ */ new Set([
@@ -8898,7 +8901,12 @@ function collectVariables(node, out, exported) {
8898
8901
  if (!nameNode || nameNode.type !== "identifier") continue;
8899
8902
  const isFn = isFunctionValue(decl);
8900
8903
  if (!isFn && !exported) continue;
8901
- out.push({ name: nameNode.text, kind: isFn ? "function" : "const", exported });
8904
+ out.push({
8905
+ name: nameNode.text,
8906
+ kind: isFn ? "function" : "const",
8907
+ exported,
8908
+ ...spanOf(decl)
8909
+ });
8902
8910
  }
8903
8911
  }
8904
8912
  function collect(node, ruleTypes, out, max, depth, exported = false, lang = "", inModule = false) {
@@ -8914,7 +8922,12 @@ function collect(node, ruleTypes, out, max, depth, exported = false, lang = "",
8914
8922
  const name = nameOf(child);
8915
8923
  const usable = name && !name.includes("\n") && name.length <= 80;
8916
8924
  if (usable) {
8917
- out.push({ name, kind, exported: isExport || isPublicDeclaration(child, lang, name) });
8925
+ out.push({
8926
+ name,
8927
+ kind,
8928
+ exported: isExport || isPublicDeclaration(child, lang, name),
8929
+ ...spanOf(child)
8930
+ });
8918
8931
  if (RECORD_AND_DESCEND.has(child.type) && depth < MAX_DEPTH) {
8919
8932
  collect(child, ruleTypes, out, max, depth + 1, isExport, lang, MODULE_CONTAINERS.has(child.type));
8920
8933
  }
@@ -8929,7 +8942,8 @@ function collect(node, ruleTypes, out, max, depth, exported = false, lang = "",
8929
8942
  out.push({
8930
8943
  name: nameNode.text,
8931
8944
  kind: "type",
8932
- exported: isPublicDeclaration(spec, lang, nameNode.text)
8945
+ exported: isPublicDeclaration(spec, lang, nameNode.text),
8946
+ ...spanOf(spec)
8933
8947
  });
8934
8948
  }
8935
8949
  continue;
@@ -8958,10 +8972,13 @@ function prioritizeSymbols(symbols, maxSymbols) {
8958
8972
  seen.add(s.name);
8959
8973
  return true;
8960
8974
  });
8961
- if (unique.length <= maxSymbols) return unique.map(({ name, kind }) => ({ name, kind }));
8962
- const exported = unique.filter((s) => s.exported);
8963
- const inner = unique.filter((s) => !s.exported);
8964
- return [...exported, ...inner].slice(0, maxSymbols).map(({ name, kind }) => ({ name, kind }));
8975
+ const trimmed = unique.length <= maxSymbols ? unique : [...unique.filter((s) => s.exported), ...unique.filter((s) => !s.exported)].slice(
8976
+ 0,
8977
+ maxSymbols
8978
+ );
8979
+ return trimmed.map(
8980
+ (s) => s.line === void 0 ? { name: s.name, kind: s.kind } : { name: s.name, kind: s.kind, line: s.line, endLine: s.endLine }
8981
+ );
8965
8982
  }
8966
8983
  function packageOf(tree, packageNode) {
8967
8984
  if (!packageNode) return void 0;
@@ -8972,6 +8989,14 @@ function packageOf(tree, packageNode) {
8972
8989
  }
8973
8990
  return void 0;
8974
8991
  }
8992
+ function countReexports(tree) {
8993
+ let n = 0;
8994
+ for (const child of tree.rootNode.children) {
8995
+ if (child.type !== "export_statement") continue;
8996
+ if (child.childForFieldName("source")) n += 1;
8997
+ }
8998
+ return n;
8999
+ }
8975
9000
  async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
8976
9001
  const rule = TS_RULES[langId];
8977
9002
  if (!rule) return null;
@@ -8995,7 +9020,8 @@ async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
8995
9020
  }
8996
9021
  return {
8997
9022
  symbols: prioritizeSymbols(symbols, maxSymbols),
8998
- pkg: packageOf(tree, rule.packageNode)
9023
+ pkg: packageOf(tree, rule.packageNode),
9024
+ reexports: countReexports(tree)
8999
9025
  };
9000
9026
  } catch {
9001
9027
  return null;
@@ -9008,6 +9034,13 @@ async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
9008
9034
  // src/repomap/extract/regex.ts
9009
9035
  init_cjs_shims();
9010
9036
  var MAX_LINE_CHARS = 500;
9037
+ var REEXPORT_RE = /^export\s+(?:\*\s*(?:as\s+[\w$]+\s*)?|type\s*(?:\*\s*|\{[^}]*\}\s*)|\{[^}]*\}\s*)from\s+['"]/gm;
9038
+ var BLOCK_COMMENT_RE = /\/\*[\s\S]*?\*\//g;
9039
+ function countReexports2(source, langId) {
9040
+ if (langId !== "typescript" && langId !== "tsx" && langId !== "javascript") return 0;
9041
+ const text = source.includes("/*") ? source.replace(BLOCK_COMMENT_RE, "") : source;
9042
+ return text.match(REEXPORT_RE)?.length ?? 0;
9043
+ }
9011
9044
  function stripBlockComments(line, state) {
9012
9045
  let out = "";
9013
9046
  let i = 0;
@@ -9041,7 +9074,8 @@ function extractWithRegex(langId, source, maxSymbols) {
9041
9074
  let pkg;
9042
9075
  const state = { inBlock: false };
9043
9076
  const lines = source.split("\n");
9044
- for (const raw of lines) {
9077
+ for (let i = 0; i < lines.length; i++) {
9078
+ const raw = lines[i];
9045
9079
  if (symbols.length >= maxSymbols) break;
9046
9080
  const stripped = stripBlockComments(raw, state);
9047
9081
  const line = /^\s/.test(raw) ? stripped : stripped.replace(/^\s+/, "");
@@ -9054,9 +9088,9 @@ function extractWithRegex(langId, source, maxSymbols) {
9054
9088
  if (!name) continue;
9055
9089
  if (seen.has(name)) continue;
9056
9090
  seen.add(name);
9057
- symbols.push({ name, kind: rule.kind });
9091
+ symbols.push({ name, kind: rule.kind, line: i + 1 });
9058
9092
  }
9059
- return { symbols, pkg };
9093
+ return { symbols, pkg, reexports: countReexports2(source, langId) };
9060
9094
  }
9061
9095
 
9062
9096
  // src/repomap/grammar.ts
@@ -9226,10 +9260,10 @@ async function extractFile(relPath, source) {
9226
9260
  const bytes = await loadGrammar(lang);
9227
9261
  if (bytes) {
9228
9262
  const ts = await extractWithTreeSitter(lang, bytes, source, MAX_SYMBOLS_PER_FILE);
9229
- if (ts) return { symbols: ts.symbols, pkg: ts.pkg, via: "tree-sitter" };
9263
+ if (ts) return { symbols: ts.symbols, pkg: ts.pkg, reexports: ts.reexports, via: "tree-sitter" };
9230
9264
  }
9231
9265
  const re = extractWithRegex(lang, source, MAX_SYMBOLS_PER_FILE);
9232
- return { symbols: re.symbols, pkg: re.pkg, via: "regex" };
9266
+ return { symbols: re.symbols, pkg: re.pkg, reexports: re.reexports, via: "regex" };
9233
9267
  }
9234
9268
  function wantsContent(relPath) {
9235
9269
  if (!langOf(relPath)) return false;
@@ -9416,6 +9450,10 @@ function hasLayerWord(name) {
9416
9450
  }
9417
9451
  var ENTRY_RE = /(^|\/)(main|index|program|startup|app|application|bootstrap|mod|__init__)(\.|\/)/i;
9418
9452
  var ENTRY_SUFFIX_RE = /(application|program|startup)\.(java|kt|cs|scala)$/i;
9453
+ function isEntryFile(relPath, sourceRoots = []) {
9454
+ if (ENTRY_SUFFIX_RE.test(relPath)) return true;
9455
+ return ENTRY_RE.test(relPath) && depthFromSourceRoot(relPath, sourceRoots) <= 1;
9456
+ }
9419
9457
  var TEST_RE = /(^|\/)(test|tests|__tests__|__mocks__|spec|specs|e2e)(\/|$)|\.(test|spec)\.[a-z]+$|test\.(java|kt|cs)$|_test\.(go|py|rb)$/i;
9420
9458
  var DOC_RE = /(^|\/)(docs?|examples?|samples?|demo|benchmarks?|bench|fixtures?)(\/|$)|\.(md|mdx|rst|txt|adoc)$/i;
9421
9459
  var GENERATED_RE = /\.(min|generated|designer)\.|_pb2?\.|\.g\.(cs|java)$|(^|\/)gen\//i;
@@ -9451,7 +9489,7 @@ function scorePath(relPath, sourceRoots) {
9451
9489
  score += W.sourceRoot;
9452
9490
  }
9453
9491
  const depth = depthFromSourceRoot(relPath, sourceRoots);
9454
- if (ENTRY_SUFFIX_RE.test(relPath) || ENTRY_RE.test(relPath) && depth <= 1) {
9492
+ if (isEntryFile(relPath, sourceRoots)) {
9455
9493
  score += W.entry;
9456
9494
  }
9457
9495
  const base = relPath.slice(relPath.lastIndexOf("/") + 1).replace(/\.[^.]+$/, "");
@@ -9479,7 +9517,7 @@ function rankFiles(paths, sourceRoots, hasSymbols) {
9479
9517
 
9480
9518
  // src/repomap/types.ts
9481
9519
  init_cjs_shims();
9482
- var REPOMAP_CACHE_VERSION = 3;
9520
+ var REPOMAP_CACHE_VERSION = 5;
9483
9521
 
9484
9522
  // src/repomap/indexer.ts
9485
9523
  var import_node_crypto2 = require("crypto");
@@ -9687,6 +9725,7 @@ async function buildRepoMap(root, opts = {}) {
9687
9725
  size: stat.size,
9688
9726
  symbols: ex.symbols,
9689
9727
  pkg: ex.pkg,
9728
+ reexports: ex.reexports,
9690
9729
  via: ex.via
9691
9730
  };
9692
9731
  } catch {
@@ -9694,15 +9733,18 @@ async function buildRepoMap(root, opts = {}) {
9694
9733
  }
9695
9734
  await yieldToLoop();
9696
9735
  }
9697
- const withSymbols = new Set(
9698
- Object.entries(result).filter(([, v]) => v.symbols.length > 0).map(([k]) => k)
9699
- );
9700
- const ranked = rankFiles([...withSymbols], shape.sourceRoots);
9736
+ const retained = {};
9737
+ for (const [rel, v] of Object.entries(result)) {
9738
+ if (v.symbols.length > 0 || (v.reexports ?? 0) > 0 || isEntryFile(rel, shape.sourceRoots)) {
9739
+ retained[rel] = v;
9740
+ }
9741
+ }
9742
+ const ranked = rankFiles(Object.keys(retained), shape.sourceRoots);
9701
9743
  const scan = {
9702
9744
  files: files.length,
9703
9745
  // 报「地图里有多少文件」而不是「本次新提取了多少」:命中缓存时
9704
- // 后者是 0,模型会以为结构图是空的(实测曾把 1324 个文件报成 0)
9705
- indexed: Object.keys(result).length,
9746
+ // 后者为 0,模型会误判结构图为空(实测曾把 1324 个文件报成 0)
9747
+ indexed: Object.keys(retained).length,
9706
9748
  truncated: enumTruncated || limit < rankedAll.length,
9707
9749
  elapsedMs: Date.now() - started
9708
9750
  };
@@ -9719,7 +9761,7 @@ async function buildRepoMap(root, opts = {}) {
9719
9761
  shape
9720
9762
  });
9721
9763
  }
9722
- return { root: absRoot, scale, scan, ranked, files: result, shape };
9764
+ return { root: absRoot, scale, scan, ranked, files: retained, shape };
9723
9765
  } catch {
9724
9766
  return empty;
9725
9767
  }
@@ -9760,6 +9802,11 @@ var GENERIC_SYMBOLS = /* @__PURE__ */ new Set([
9760
9802
  function meaningful(symbols) {
9761
9803
  return symbols.filter((s) => s.name.length > 3 && !GENERIC_SYMBOLS.has(s.name));
9762
9804
  }
9805
+ function symbolRef(s, withRange = false) {
9806
+ if (s.line === void 0 || s.name.includes(":")) return s.name;
9807
+ const end = withRange && s.endLine !== void 0 && s.endLine > s.line ? `-${s.endLine}` : "";
9808
+ return `${s.name}:${s.line}${end}`;
9809
+ }
9763
9810
  var GROUP_FILE_LIMIT = { small: 5, medium: 4, large: 1 };
9764
9811
  var BREADTH_SHARE = 0.5;
9765
9812
  var TAIL_RESERVE = 64;
@@ -9783,7 +9830,7 @@ function baseName(relPath) {
9783
9830
  function symbolsInline(symbols) {
9784
9831
  const kept = meaningful(symbols);
9785
9832
  if (kept.length === 0) return "";
9786
- const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => s.name);
9833
+ const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => symbolRef(s));
9787
9834
  const more = kept.length > MAX_SYMBOLS_PER_LINE ? ", \u2026" : "";
9788
9835
  return names.join(", ") + more;
9789
9836
  }
@@ -9791,14 +9838,14 @@ function buildGroups(map) {
9791
9838
  const groups = /* @__PURE__ */ new Map();
9792
9839
  for (const { path: rel } of map.ranked) {
9793
9840
  const entry = map.files[rel];
9794
- if (!entry || entry.symbols.length === 0) continue;
9841
+ if (!entry) continue;
9795
9842
  const label = groupLabelOf(rel, entry.pkg);
9796
9843
  let g = groups.get(label);
9797
9844
  if (!g) {
9798
9845
  g = { label, files: [] };
9799
9846
  groups.set(label, g);
9800
9847
  }
9801
- g.files.push({ path: rel, symbols: entry.symbols });
9848
+ g.files.push({ path: rel, symbols: entry.symbols, reexports: entry.reexports });
9802
9849
  }
9803
9850
  return [...groups.values()];
9804
9851
  }
@@ -9809,12 +9856,20 @@ function moduleLine(mod, info) {
9809
9856
  return ` ${label} (${info.files} \u6587\u4EF6)${layers ? ` ${layers}` : ""}${entry}`;
9810
9857
  }
9811
9858
  function renderLarge(map, budget) {
9859
+ const bestOfModule = /* @__PURE__ */ new Map();
9860
+ for (const r of map.ranked) {
9861
+ const slash = r.path.indexOf("/");
9862
+ const mod = slash < 0 ? "." : r.path.slice(0, slash);
9863
+ const prev = bestOfModule.get(mod);
9864
+ if (prev === void 0 || r.score > prev) bestOfModule.set(mod, r.score);
9865
+ }
9812
9866
  const perModule = /* @__PURE__ */ new Map();
9813
9867
  for (const rel of Object.keys(map.files)) {
9814
9868
  const slash = rel.indexOf("/");
9815
9869
  const first = slash < 0 ? "." : rel.slice(0, slash);
9816
9870
  const bucket = perModule.get(first) ?? {
9817
9871
  files: 0,
9872
+ best: bestOfModule.get(first) ?? Number.NEGATIVE_INFINITY,
9818
9873
  layers: /* @__PURE__ */ new Set(),
9819
9874
  entryDepth: Number.POSITIVE_INFINITY
9820
9875
  };
@@ -9834,7 +9889,9 @@ function renderLarge(map, budget) {
9834
9889
  }
9835
9890
  perModule.set(first, bucket);
9836
9891
  }
9837
- const sorted = [...perModule.entries()].sort((a, b) => b[1].files - a[1].files);
9892
+ const sorted = [...perModule.entries()].sort(
9893
+ (a, b) => b[1].best - a[1].best || b[1].files - a[1].files || a[0].localeCompare(b[0])
9894
+ );
9838
9895
  const lines = [];
9839
9896
  const lineBudget = Math.max(200, budget - TAIL_RESERVE);
9840
9897
  let used = 0;
@@ -9856,8 +9913,13 @@ function renderLarge(map, budget) {
9856
9913
  return lines.join("\n");
9857
9914
  }
9858
9915
  function fileLine(f) {
9859
- const sym = symbolsInline(f.symbols);
9860
- return ` ${baseName(f.path)}${sym ? `: ${sym}` : ""}`;
9916
+ const name = baseName(f.path);
9917
+ if (f.symbols.length > 0) {
9918
+ const sym = symbolsInline(f.symbols);
9919
+ return ` ${name}${sym ? `: ${sym}` : ""}`;
9920
+ }
9921
+ if (f.reexports) return ` ${name}: (\u518D\u5BFC\u51FA ${f.reexports})`;
9922
+ return ` ${name}: (\u5165\u53E3)`;
9861
9923
  }
9862
9924
  function renderDetailed(map, budget) {
9863
9925
  const limit = GROUP_FILE_LIMIT[map.scale === "medium" ? "medium" : "small"];
@@ -9892,23 +9954,36 @@ function renderDetailed(map, budget) {
9892
9954
  const out = [];
9893
9955
  for (const b of blocks) out.push(b.header, ...b.lines);
9894
9956
  const omitted = map.ranked.length - shownFiles;
9895
- if (omitted > 0) out.push(`\u2026 \u53E6\u6709 ${omitted} \u4E2A\u6587\u4EF6\u672A\u5217\u51FA\uFF0C\u7528 repo_map \u5DE5\u5177\u67E5\u770B`);
9957
+ if (omitted > 0) out.push(`\u2026 \u53E6\u6709 ${omitted} \u4E2A\u6587\u4EF6\u672A\u5217\u51FA\uFF0C\u7528 repo_map \u5DE5\u5177\u6309\u76EE\u5F55\u67E5\u770B`);
9896
9958
  return out.join("\n");
9897
9959
  }
9960
+ function shapeLine(shape) {
9961
+ if (!shape) return "";
9962
+ const parts = [];
9963
+ const kinds = shape.kinds.filter((k) => k !== "npm" || !shape.kinds.includes("npm-workspace"));
9964
+ if (kinds.length) parts.push(kinds.slice(0, 3).join(" \xB7 "));
9965
+ if (shape.modules.length > 1) parts.push(`${shape.modules.length} \u6A21\u5757`);
9966
+ const roots = [...new Set(shape.sourceRoots)].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).slice(0, 3);
9967
+ if (roots.length) parts.push(`\u6E90\u7801\u6839 ${roots.join(", ")}`);
9968
+ return parts.length ? `\u9879\u76EE\u5F62\u6001: ${parts.join(" \xB7 ")}` : "";
9969
+ }
9898
9970
  function renderRepoMap(map) {
9899
9971
  if (map.ranked.length === 0 && !map.shape) return "";
9900
9972
  const budget = renderBudget(map.scale);
9901
- const head = map.scale === "large" ? "\u4EE3\u7801\u7ED3\u6784\uFF08\u81EA\u52A8\u6458\u8981 \xB7 \u5927\u578B\u9879\u76EE\uFF1B\u6309\u6A21\u5757\u4E0B\u94BB\u7528 repo_map \u5DE5\u5177\uFF09" : "\u4EE3\u7801\u7ED3\u6784\uFF08\u81EA\u52A8\u751F\u6210\uFF1B\u66F4\u7EC6\u7684\u89C6\u56FE\u7528 repo_map \u5DE5\u5177\uFF09";
9973
+ const title = map.scale === "large" ? "\u4EE3\u7801\u7ED3\u6784\uFF08\u81EA\u52A8\u6458\u8981 \xB7 \u5927\u578B\u9879\u76EE\uFF1B\u6309\u6A21\u5757\u4E0B\u94BB\u7528 repo_map \u5DE5\u5177\uFF09" : "\u4EE3\u7801\u7ED3\u6784\uFF08\u81EA\u52A8\u751F\u6210\uFF1B\u7B26\u53F7\u540E\u7684\u6570\u5B57\u662F\u884C\u53F7\uFF1B\u66F4\u7EC6\u7684\u89C6\u56FE\u7528 repo_map \u5DE5\u5177\uFF09";
9974
+ const shape = shapeLine(map.shape);
9975
+ const head = shape ? `${title}
9976
+ ${shape}` : title;
9902
9977
  const bodyBudget = Math.max(200, budget - head.length - 1);
9903
9978
  const body = map.scale === "large" ? renderLarge(map, bodyBudget) : renderDetailed(map, bodyBudget);
9904
- if (!body.trim()) return "";
9979
+ if (!body.trim()) return shape;
9905
9980
  const text = `${head}
9906
9981
  ${body}`;
9907
9982
  if (text.length <= budget) return text;
9908
9983
  return cutAtLine(text, budget);
9909
9984
  }
9910
9985
  function cutAtLine(text, budget) {
9911
- const marker = "\n\u2026\uFF08\u7ED3\u6784\u56FE\u5DF2\u622A\u65AD\uFF0C\u7528 repo_map \u5DE5\u5177\u67E5\u770B\uFF09";
9986
+ const marker = "\n\u2026\uFF08\u7ED3\u6784\u56FE\u5DF2\u622A\u65AD\uFF0C\u7528 repo_map \u5DE5\u5177\u6309\u76EE\u5F55\u67E5\u770B\uFF09";
9912
9987
  const room = budget - marker.length;
9913
9988
  if (room <= 0) return marker.slice(1);
9914
9989
  const cut = text.slice(0, room);
@@ -13213,17 +13288,26 @@ function registerSearchTool(registry, workspace) {
13213
13288
  // src/tools/repoMap.ts
13214
13289
  init_cjs_shims();
13215
13290
  var MAX_CHARS = 16e3;
13291
+ function filesUnder(map, prefix) {
13292
+ const keys = Object.keys(map.files);
13293
+ if (!prefix) return keys;
13294
+ if (prefix === ".") return keys.filter((rel) => !rel.includes("/"));
13295
+ return keys.filter((rel) => rel === prefix || rel.startsWith(`${prefix}/`));
13296
+ }
13216
13297
  function renderSubset(map, prefix, maxFiles) {
13217
13298
  const order = new Map(map.ranked.map((r, i) => [r.path, i]));
13218
- const under = Object.keys(map.files).filter((rel) => !prefix || rel === prefix || rel.startsWith(`${prefix}/`)).sort((a, b) => (order.get(a) ?? Infinity) - (order.get(b) ?? Infinity));
13299
+ const under = filesUnder(map, prefix).sort(
13300
+ (a, b) => (order.get(a) ?? Infinity) - (order.get(b) ?? Infinity)
13301
+ );
13219
13302
  const matched = under.slice(0, maxFiles);
13220
13303
  if (matched.length === 0) return null;
13221
13304
  const entries = [];
13222
13305
  let used = 0;
13223
13306
  for (const rel of matched) {
13224
13307
  const f = map.files[rel];
13225
- const sym = f.symbols.slice(0, 8).map((s) => s.name).join(", ");
13226
- const line = `${rel}${sym ? `: ${sym}` : ""}`;
13308
+ const sym = f.symbols.slice(0, 8).map((s) => symbolRef(s, true)).join(", ");
13309
+ const body = f.symbols.length > 0 ? sym : f.reexports ? `(\u518D\u5BFC\u51FA ${f.reexports})` : "(\u5165\u53E3)";
13310
+ const line = `${rel}: ${body}`;
13227
13311
  if (used + line.length + 1 > MAX_CHARS) break;
13228
13312
  entries.push(line);
13229
13313
  used += line.length + 1;
@@ -13255,18 +13339,20 @@ function registerRepoMapTool(registry, workspace) {
13255
13339
  if (sub) return sub;
13256
13340
  return { error: `\u6CA1\u6709\u5339\u914D\u7684\u76EE\u5F55\uFF1A${path30}` };
13257
13341
  }
13258
- const groups = buildGroups(map).slice(0, 40).map((g) => ({
13259
- label: g.label,
13260
- files: g.files.length,
13261
- path: g.files[0]?.path.split("/").slice(0, -1).join("/") || "."
13262
- }));
13342
+ const groups = buildGroups(map).slice(0, 40).map((g) => {
13343
+ const dir = g.files[0]?.path.split("/").slice(0, -1).join("/") || ".";
13344
+ return {
13345
+ label: g.label,
13346
+ files: filesUnder(map, dir).length,
13347
+ ...dir === g.label ? {} : { path: dir }
13348
+ };
13349
+ });
13263
13350
  return {
13264
13351
  scale: map.scale,
13265
13352
  files: map.scan.files,
13266
13353
  indexed: map.scan.indexed,
13267
13354
  groups,
13268
- map: renderRepoMap(map),
13269
- hint: '\u7528 path \u53C2\u6570\u53EF\u53EA\u770B\u67D0\u4E2A\u6A21\u5757/\u76EE\u5F55\uFF08\u53D6 groups[].path\uFF09\uFF0C\u4F8B\u5982 path="packages/core/src"'
13355
+ hint: '\u7ED3\u6784\u56FE\u5DF2\u5728\u7CFB\u7EDF\u63D0\u793A\u8BCD\u91CC\uFF0C\u8FD9\u91CC\u53EA\u7ED9\u5168\u5C40\u5206\u7EC4\uFF08files \u542B\u5B50\u76EE\u5F55\uFF09\u3002\u7528 path \u53C2\u6570\u6309\u76EE\u5F55\u4E0B\u94BB\uFF1A\u5206\u7EC4\u6807\u9898\u662F\u5305\u540D\u65F6\u7528 groups[].path\uFF0C\u5426\u5219\u76F4\u63A5\u7528 label\uFF0C\u4F8B\u5982 path="packages/core/src"'
13270
13356
  };
13271
13357
  },
13272
13358
  { category: "search", riskLevel: "low", capabilities: ["repo_map"], requiresApproval: false },