@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 +128 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -4
- package/dist/index.d.ts +25 -4
- package/dist/index.js +128 -42
- package/dist/index.js.map +1 -1
- package/dist/internal/update/controller.cjs +1 -1
- package/dist/internal/update/controller.js +1 -1
- package/dist/internal/update/platform.cjs +1 -1
- package/dist/internal/update/platform.js +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -519,6 +519,13 @@ type SymbolKind = "class" | "interface" | "struct" | "enum" | "record" | "trait"
|
|
|
519
519
|
interface SymbolNode {
|
|
520
520
|
name: string;
|
|
521
521
|
kind: SymbolKind;
|
|
522
|
+
/**
|
|
523
|
+
* 声明起始行(1 起始)。渲染成 `Name:12`,模型可直接 `read_file start_line=12`,
|
|
524
|
+
* 省掉先 grep 一行号的那一轮 —— 一轮工具调用要重发整个上下文,比这几个字符贵得多。
|
|
525
|
+
*/
|
|
526
|
+
line?: number;
|
|
527
|
+
/** 声明结束行;与 {@link line} 相同时渲染层只写一个行号 */
|
|
528
|
+
endLine?: number;
|
|
522
529
|
}
|
|
523
530
|
/** 单文件的索引结果 */
|
|
524
531
|
interface FileSymbols {
|
|
@@ -532,6 +539,14 @@ interface FileSymbols {
|
|
|
532
539
|
* 比目录结构可靠,用于渲染分组;取不到则缺省。
|
|
533
540
|
*/
|
|
534
541
|
pkg?: string;
|
|
542
|
+
/**
|
|
543
|
+
* 再导出语句数(`export * from "./x"` / `export { a } from "./x"`)。
|
|
544
|
+
*
|
|
545
|
+
* barrel 文件(`index.ts` 只有再导出)提取不到任何符号,但它往往是**全仓
|
|
546
|
+
* 被 import 最多的文件**,是「该从哪个包入口开始」的最佳答案。没有这个计数,
|
|
547
|
+
* 索引器会把它连同其它 0 符号文件一起丢掉,包入口在结构图里彻底不可见。
|
|
548
|
+
*/
|
|
549
|
+
reexports?: number;
|
|
535
550
|
/** 该文件由哪个提取器处理(诊断用) */
|
|
536
551
|
via: "tree-sitter" | "regex" | "path-only";
|
|
537
552
|
}
|
|
@@ -546,7 +561,7 @@ interface RepoMapCache {
|
|
|
546
561
|
scan: {
|
|
547
562
|
/** 枚举到的文件总数(可能远大于 indexed) */
|
|
548
563
|
files: number;
|
|
549
|
-
/**
|
|
564
|
+
/** 进地图的文件数(有声明 / 纯 barrel / 入口;受 MAX_FILES 封顶) */
|
|
550
565
|
indexed: number;
|
|
551
566
|
/** 是否因上限被截断 */
|
|
552
567
|
truncated: boolean;
|
|
@@ -591,9 +606,14 @@ interface RepoMap {
|
|
|
591
606
|
root: string;
|
|
592
607
|
scale: Scale;
|
|
593
608
|
scan: RepoMapCache["scan"];
|
|
594
|
-
/** 已排序的文件(score
|
|
609
|
+
/** 已排序的文件(score 降序),与 {@link files} 的键集完全一致 */
|
|
595
610
|
ranked: RankedFile[];
|
|
596
|
-
/**
|
|
611
|
+
/**
|
|
612
|
+
* path → 索引结果,**只含进地图的文件**:有顶层声明、纯 barrel、或模块入口。
|
|
613
|
+
*
|
|
614
|
+
* 解析成功但三者都不满足的文件(例如只有顶层调用的脚本)不在这里 —— 它们在
|
|
615
|
+
* 结构图里只能占一行而不提供任何定位信息。索引磁盘缓存仍保留它们以支持增量。
|
|
616
|
+
*/
|
|
597
617
|
files: Record<string, FileSymbols>;
|
|
598
618
|
shape?: ProjectShape;
|
|
599
619
|
}
|
|
@@ -608,7 +628,8 @@ interface RepoMap {
|
|
|
608
628
|
*
|
|
609
629
|
* token 上的取舍(都按"能否帮模型少走一轮"来判断):
|
|
610
630
|
* - 目录路径只写一次(分组标题),不在每行重复
|
|
611
|
-
* -
|
|
631
|
+
* - 符号写「名字 + 行号」,不写 kind:行号能省掉先 grep 定位的那一轮,
|
|
632
|
+
* kind 省不了任何一次工具调用
|
|
612
633
|
* - 不画树形符号(`├──` 每行要花 4-8 个 token)
|
|
613
634
|
*/
|
|
614
635
|
|
package/dist/index.d.ts
CHANGED
|
@@ -519,6 +519,13 @@ type SymbolKind = "class" | "interface" | "struct" | "enum" | "record" | "trait"
|
|
|
519
519
|
interface SymbolNode {
|
|
520
520
|
name: string;
|
|
521
521
|
kind: SymbolKind;
|
|
522
|
+
/**
|
|
523
|
+
* 声明起始行(1 起始)。渲染成 `Name:12`,模型可直接 `read_file start_line=12`,
|
|
524
|
+
* 省掉先 grep 一行号的那一轮 —— 一轮工具调用要重发整个上下文,比这几个字符贵得多。
|
|
525
|
+
*/
|
|
526
|
+
line?: number;
|
|
527
|
+
/** 声明结束行;与 {@link line} 相同时渲染层只写一个行号 */
|
|
528
|
+
endLine?: number;
|
|
522
529
|
}
|
|
523
530
|
/** 单文件的索引结果 */
|
|
524
531
|
interface FileSymbols {
|
|
@@ -532,6 +539,14 @@ interface FileSymbols {
|
|
|
532
539
|
* 比目录结构可靠,用于渲染分组;取不到则缺省。
|
|
533
540
|
*/
|
|
534
541
|
pkg?: string;
|
|
542
|
+
/**
|
|
543
|
+
* 再导出语句数(`export * from "./x"` / `export { a } from "./x"`)。
|
|
544
|
+
*
|
|
545
|
+
* barrel 文件(`index.ts` 只有再导出)提取不到任何符号,但它往往是**全仓
|
|
546
|
+
* 被 import 最多的文件**,是「该从哪个包入口开始」的最佳答案。没有这个计数,
|
|
547
|
+
* 索引器会把它连同其它 0 符号文件一起丢掉,包入口在结构图里彻底不可见。
|
|
548
|
+
*/
|
|
549
|
+
reexports?: number;
|
|
535
550
|
/** 该文件由哪个提取器处理(诊断用) */
|
|
536
551
|
via: "tree-sitter" | "regex" | "path-only";
|
|
537
552
|
}
|
|
@@ -546,7 +561,7 @@ interface RepoMapCache {
|
|
|
546
561
|
scan: {
|
|
547
562
|
/** 枚举到的文件总数(可能远大于 indexed) */
|
|
548
563
|
files: number;
|
|
549
|
-
/**
|
|
564
|
+
/** 进地图的文件数(有声明 / 纯 barrel / 入口;受 MAX_FILES 封顶) */
|
|
550
565
|
indexed: number;
|
|
551
566
|
/** 是否因上限被截断 */
|
|
552
567
|
truncated: boolean;
|
|
@@ -591,9 +606,14 @@ interface RepoMap {
|
|
|
591
606
|
root: string;
|
|
592
607
|
scale: Scale;
|
|
593
608
|
scan: RepoMapCache["scan"];
|
|
594
|
-
/** 已排序的文件(score
|
|
609
|
+
/** 已排序的文件(score 降序),与 {@link files} 的键集完全一致 */
|
|
595
610
|
ranked: RankedFile[];
|
|
596
|
-
/**
|
|
611
|
+
/**
|
|
612
|
+
* path → 索引结果,**只含进地图的文件**:有顶层声明、纯 barrel、或模块入口。
|
|
613
|
+
*
|
|
614
|
+
* 解析成功但三者都不满足的文件(例如只有顶层调用的脚本)不在这里 —— 它们在
|
|
615
|
+
* 结构图里只能占一行而不提供任何定位信息。索引磁盘缓存仍保留它们以支持增量。
|
|
616
|
+
*/
|
|
597
617
|
files: Record<string, FileSymbols>;
|
|
598
618
|
shape?: ProjectShape;
|
|
599
619
|
}
|
|
@@ -608,7 +628,8 @@ interface RepoMap {
|
|
|
608
628
|
*
|
|
609
629
|
* token 上的取舍(都按"能否帮模型少走一轮"来判断):
|
|
610
630
|
* - 目录路径只写一次(分组标题),不在每行重复
|
|
611
|
-
* -
|
|
631
|
+
* - 符号写「名字 + 行号」,不写 kind:行号能省掉先 grep 定位的那一轮,
|
|
632
|
+
* kind 省不了任何一次工具调用
|
|
612
633
|
* - 不画树形符号(`├──` 每行要花 4-8 个 token)
|
|
613
634
|
*/
|
|
614
635
|
|
package/dist/index.js
CHANGED
|
@@ -8733,6 +8733,9 @@ function nameOf(node) {
|
|
|
8733
8733
|
if (typeNode?.text) return typeNode.text.split("<")[0].trim();
|
|
8734
8734
|
return null;
|
|
8735
8735
|
}
|
|
8736
|
+
function spanOf(node) {
|
|
8737
|
+
return { line: node.startPosition.row + 1, endLine: node.endPosition.row + 1 };
|
|
8738
|
+
}
|
|
8736
8739
|
var MAX_COLLECT = 200;
|
|
8737
8740
|
var VARIABLE_DECLARATIONS = /* @__PURE__ */ new Set(["lexical_declaration", "variable_declaration"]);
|
|
8738
8741
|
var MODULE_CONTAINERS = /* @__PURE__ */ new Set([
|
|
@@ -8770,7 +8773,12 @@ function collectVariables(node, out, exported) {
|
|
|
8770
8773
|
if (!nameNode || nameNode.type !== "identifier") continue;
|
|
8771
8774
|
const isFn = isFunctionValue(decl);
|
|
8772
8775
|
if (!isFn && !exported) continue;
|
|
8773
|
-
out.push({
|
|
8776
|
+
out.push({
|
|
8777
|
+
name: nameNode.text,
|
|
8778
|
+
kind: isFn ? "function" : "const",
|
|
8779
|
+
exported,
|
|
8780
|
+
...spanOf(decl)
|
|
8781
|
+
});
|
|
8774
8782
|
}
|
|
8775
8783
|
}
|
|
8776
8784
|
function collect(node, ruleTypes, out, max, depth, exported = false, lang = "", inModule = false) {
|
|
@@ -8786,7 +8794,12 @@ function collect(node, ruleTypes, out, max, depth, exported = false, lang = "",
|
|
|
8786
8794
|
const name = nameOf(child);
|
|
8787
8795
|
const usable = name && !name.includes("\n") && name.length <= 80;
|
|
8788
8796
|
if (usable) {
|
|
8789
|
-
out.push({
|
|
8797
|
+
out.push({
|
|
8798
|
+
name,
|
|
8799
|
+
kind,
|
|
8800
|
+
exported: isExport || isPublicDeclaration(child, lang, name),
|
|
8801
|
+
...spanOf(child)
|
|
8802
|
+
});
|
|
8790
8803
|
if (RECORD_AND_DESCEND.has(child.type) && depth < MAX_DEPTH) {
|
|
8791
8804
|
collect(child, ruleTypes, out, max, depth + 1, isExport, lang, MODULE_CONTAINERS.has(child.type));
|
|
8792
8805
|
}
|
|
@@ -8801,7 +8814,8 @@ function collect(node, ruleTypes, out, max, depth, exported = false, lang = "",
|
|
|
8801
8814
|
out.push({
|
|
8802
8815
|
name: nameNode.text,
|
|
8803
8816
|
kind: "type",
|
|
8804
|
-
exported: isPublicDeclaration(spec, lang, nameNode.text)
|
|
8817
|
+
exported: isPublicDeclaration(spec, lang, nameNode.text),
|
|
8818
|
+
...spanOf(spec)
|
|
8805
8819
|
});
|
|
8806
8820
|
}
|
|
8807
8821
|
continue;
|
|
@@ -8830,10 +8844,13 @@ function prioritizeSymbols(symbols, maxSymbols) {
|
|
|
8830
8844
|
seen.add(s.name);
|
|
8831
8845
|
return true;
|
|
8832
8846
|
});
|
|
8833
|
-
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8847
|
+
const trimmed = unique.length <= maxSymbols ? unique : [...unique.filter((s) => s.exported), ...unique.filter((s) => !s.exported)].slice(
|
|
8848
|
+
0,
|
|
8849
|
+
maxSymbols
|
|
8850
|
+
);
|
|
8851
|
+
return trimmed.map(
|
|
8852
|
+
(s) => s.line === void 0 ? { name: s.name, kind: s.kind } : { name: s.name, kind: s.kind, line: s.line, endLine: s.endLine }
|
|
8853
|
+
);
|
|
8837
8854
|
}
|
|
8838
8855
|
function packageOf(tree, packageNode) {
|
|
8839
8856
|
if (!packageNode) return void 0;
|
|
@@ -8844,6 +8861,14 @@ function packageOf(tree, packageNode) {
|
|
|
8844
8861
|
}
|
|
8845
8862
|
return void 0;
|
|
8846
8863
|
}
|
|
8864
|
+
function countReexports(tree) {
|
|
8865
|
+
let n = 0;
|
|
8866
|
+
for (const child of tree.rootNode.children) {
|
|
8867
|
+
if (child.type !== "export_statement") continue;
|
|
8868
|
+
if (child.childForFieldName("source")) n += 1;
|
|
8869
|
+
}
|
|
8870
|
+
return n;
|
|
8871
|
+
}
|
|
8847
8872
|
async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
|
|
8848
8873
|
const rule = TS_RULES[langId];
|
|
8849
8874
|
if (!rule) return null;
|
|
@@ -8867,7 +8892,8 @@ async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
|
|
|
8867
8892
|
}
|
|
8868
8893
|
return {
|
|
8869
8894
|
symbols: prioritizeSymbols(symbols, maxSymbols),
|
|
8870
|
-
pkg: packageOf(tree, rule.packageNode)
|
|
8895
|
+
pkg: packageOf(tree, rule.packageNode),
|
|
8896
|
+
reexports: countReexports(tree)
|
|
8871
8897
|
};
|
|
8872
8898
|
} catch {
|
|
8873
8899
|
return null;
|
|
@@ -8880,6 +8906,13 @@ async function extractWithTreeSitter(langId, bytes, source, maxSymbols) {
|
|
|
8880
8906
|
// src/repomap/extract/regex.ts
|
|
8881
8907
|
init_esm_shims();
|
|
8882
8908
|
var MAX_LINE_CHARS = 500;
|
|
8909
|
+
var REEXPORT_RE = /^export\s+(?:\*\s*(?:as\s+[\w$]+\s*)?|type\s*(?:\*\s*|\{[^}]*\}\s*)|\{[^}]*\}\s*)from\s+['"]/gm;
|
|
8910
|
+
var BLOCK_COMMENT_RE = /\/\*[\s\S]*?\*\//g;
|
|
8911
|
+
function countReexports2(source, langId) {
|
|
8912
|
+
if (langId !== "typescript" && langId !== "tsx" && langId !== "javascript") return 0;
|
|
8913
|
+
const text = source.includes("/*") ? source.replace(BLOCK_COMMENT_RE, "") : source;
|
|
8914
|
+
return text.match(REEXPORT_RE)?.length ?? 0;
|
|
8915
|
+
}
|
|
8883
8916
|
function stripBlockComments(line, state) {
|
|
8884
8917
|
let out = "";
|
|
8885
8918
|
let i = 0;
|
|
@@ -8913,7 +8946,8 @@ function extractWithRegex(langId, source, maxSymbols) {
|
|
|
8913
8946
|
let pkg;
|
|
8914
8947
|
const state = { inBlock: false };
|
|
8915
8948
|
const lines = source.split("\n");
|
|
8916
|
-
for (
|
|
8949
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8950
|
+
const raw = lines[i];
|
|
8917
8951
|
if (symbols.length >= maxSymbols) break;
|
|
8918
8952
|
const stripped = stripBlockComments(raw, state);
|
|
8919
8953
|
const line = /^\s/.test(raw) ? stripped : stripped.replace(/^\s+/, "");
|
|
@@ -8926,9 +8960,9 @@ function extractWithRegex(langId, source, maxSymbols) {
|
|
|
8926
8960
|
if (!name) continue;
|
|
8927
8961
|
if (seen.has(name)) continue;
|
|
8928
8962
|
seen.add(name);
|
|
8929
|
-
symbols.push({ name, kind: rule.kind });
|
|
8963
|
+
symbols.push({ name, kind: rule.kind, line: i + 1 });
|
|
8930
8964
|
}
|
|
8931
|
-
return { symbols, pkg };
|
|
8965
|
+
return { symbols, pkg, reexports: countReexports2(source, langId) };
|
|
8932
8966
|
}
|
|
8933
8967
|
|
|
8934
8968
|
// src/repomap/grammar.ts
|
|
@@ -9098,10 +9132,10 @@ async function extractFile(relPath, source) {
|
|
|
9098
9132
|
const bytes = await loadGrammar(lang);
|
|
9099
9133
|
if (bytes) {
|
|
9100
9134
|
const ts = await extractWithTreeSitter(lang, bytes, source, MAX_SYMBOLS_PER_FILE);
|
|
9101
|
-
if (ts) return { symbols: ts.symbols, pkg: ts.pkg, via: "tree-sitter" };
|
|
9135
|
+
if (ts) return { symbols: ts.symbols, pkg: ts.pkg, reexports: ts.reexports, via: "tree-sitter" };
|
|
9102
9136
|
}
|
|
9103
9137
|
const re = extractWithRegex(lang, source, MAX_SYMBOLS_PER_FILE);
|
|
9104
|
-
return { symbols: re.symbols, pkg: re.pkg, via: "regex" };
|
|
9138
|
+
return { symbols: re.symbols, pkg: re.pkg, reexports: re.reexports, via: "regex" };
|
|
9105
9139
|
}
|
|
9106
9140
|
function wantsContent(relPath) {
|
|
9107
9141
|
if (!langOf(relPath)) return false;
|
|
@@ -9288,6 +9322,10 @@ function hasLayerWord(name) {
|
|
|
9288
9322
|
}
|
|
9289
9323
|
var ENTRY_RE = /(^|\/)(main|index|program|startup|app|application|bootstrap|mod|__init__)(\.|\/)/i;
|
|
9290
9324
|
var ENTRY_SUFFIX_RE = /(application|program|startup)\.(java|kt|cs|scala)$/i;
|
|
9325
|
+
function isEntryFile(relPath, sourceRoots = []) {
|
|
9326
|
+
if (ENTRY_SUFFIX_RE.test(relPath)) return true;
|
|
9327
|
+
return ENTRY_RE.test(relPath) && depthFromSourceRoot(relPath, sourceRoots) <= 1;
|
|
9328
|
+
}
|
|
9291
9329
|
var TEST_RE = /(^|\/)(test|tests|__tests__|__mocks__|spec|specs|e2e)(\/|$)|\.(test|spec)\.[a-z]+$|test\.(java|kt|cs)$|_test\.(go|py|rb)$/i;
|
|
9292
9330
|
var DOC_RE = /(^|\/)(docs?|examples?|samples?|demo|benchmarks?|bench|fixtures?)(\/|$)|\.(md|mdx|rst|txt|adoc)$/i;
|
|
9293
9331
|
var GENERATED_RE = /\.(min|generated|designer)\.|_pb2?\.|\.g\.(cs|java)$|(^|\/)gen\//i;
|
|
@@ -9323,7 +9361,7 @@ function scorePath(relPath, sourceRoots) {
|
|
|
9323
9361
|
score += W.sourceRoot;
|
|
9324
9362
|
}
|
|
9325
9363
|
const depth = depthFromSourceRoot(relPath, sourceRoots);
|
|
9326
|
-
if (
|
|
9364
|
+
if (isEntryFile(relPath, sourceRoots)) {
|
|
9327
9365
|
score += W.entry;
|
|
9328
9366
|
}
|
|
9329
9367
|
const base = relPath.slice(relPath.lastIndexOf("/") + 1).replace(/\.[^.]+$/, "");
|
|
@@ -9351,7 +9389,7 @@ function rankFiles(paths, sourceRoots, hasSymbols) {
|
|
|
9351
9389
|
|
|
9352
9390
|
// src/repomap/types.ts
|
|
9353
9391
|
init_esm_shims();
|
|
9354
|
-
var REPOMAP_CACHE_VERSION =
|
|
9392
|
+
var REPOMAP_CACHE_VERSION = 5;
|
|
9355
9393
|
|
|
9356
9394
|
// src/repomap/indexer.ts
|
|
9357
9395
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -9559,6 +9597,7 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9559
9597
|
size: stat.size,
|
|
9560
9598
|
symbols: ex.symbols,
|
|
9561
9599
|
pkg: ex.pkg,
|
|
9600
|
+
reexports: ex.reexports,
|
|
9562
9601
|
via: ex.via
|
|
9563
9602
|
};
|
|
9564
9603
|
} catch {
|
|
@@ -9566,15 +9605,18 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9566
9605
|
}
|
|
9567
9606
|
await yieldToLoop();
|
|
9568
9607
|
}
|
|
9569
|
-
const
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9608
|
+
const retained = {};
|
|
9609
|
+
for (const [rel, v] of Object.entries(result)) {
|
|
9610
|
+
if (v.symbols.length > 0 || (v.reexports ?? 0) > 0 || isEntryFile(rel, shape.sourceRoots)) {
|
|
9611
|
+
retained[rel] = v;
|
|
9612
|
+
}
|
|
9613
|
+
}
|
|
9614
|
+
const ranked = rankFiles(Object.keys(retained), shape.sourceRoots);
|
|
9573
9615
|
const scan = {
|
|
9574
9616
|
files: files.length,
|
|
9575
9617
|
// 报「地图里有多少文件」而不是「本次新提取了多少」:命中缓存时
|
|
9576
|
-
//
|
|
9577
|
-
indexed: Object.keys(
|
|
9618
|
+
// 后者为 0,模型会误判结构图为空(实测曾把 1324 个文件报成 0)
|
|
9619
|
+
indexed: Object.keys(retained).length,
|
|
9578
9620
|
truncated: enumTruncated || limit < rankedAll.length,
|
|
9579
9621
|
elapsedMs: Date.now() - started
|
|
9580
9622
|
};
|
|
@@ -9591,7 +9633,7 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9591
9633
|
shape
|
|
9592
9634
|
});
|
|
9593
9635
|
}
|
|
9594
|
-
return { root: absRoot, scale, scan, ranked, files:
|
|
9636
|
+
return { root: absRoot, scale, scan, ranked, files: retained, shape };
|
|
9595
9637
|
} catch {
|
|
9596
9638
|
return empty;
|
|
9597
9639
|
}
|
|
@@ -9632,6 +9674,11 @@ var GENERIC_SYMBOLS = /* @__PURE__ */ new Set([
|
|
|
9632
9674
|
function meaningful(symbols) {
|
|
9633
9675
|
return symbols.filter((s) => s.name.length > 3 && !GENERIC_SYMBOLS.has(s.name));
|
|
9634
9676
|
}
|
|
9677
|
+
function symbolRef(s, withRange = false) {
|
|
9678
|
+
if (s.line === void 0 || s.name.includes(":")) return s.name;
|
|
9679
|
+
const end = withRange && s.endLine !== void 0 && s.endLine > s.line ? `-${s.endLine}` : "";
|
|
9680
|
+
return `${s.name}:${s.line}${end}`;
|
|
9681
|
+
}
|
|
9635
9682
|
var GROUP_FILE_LIMIT = { small: 5, medium: 4, large: 1 };
|
|
9636
9683
|
var BREADTH_SHARE = 0.5;
|
|
9637
9684
|
var TAIL_RESERVE = 64;
|
|
@@ -9655,7 +9702,7 @@ function baseName(relPath) {
|
|
|
9655
9702
|
function symbolsInline(symbols) {
|
|
9656
9703
|
const kept = meaningful(symbols);
|
|
9657
9704
|
if (kept.length === 0) return "";
|
|
9658
|
-
const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => s
|
|
9705
|
+
const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => symbolRef(s));
|
|
9659
9706
|
const more = kept.length > MAX_SYMBOLS_PER_LINE ? ", \u2026" : "";
|
|
9660
9707
|
return names.join(", ") + more;
|
|
9661
9708
|
}
|
|
@@ -9663,14 +9710,14 @@ function buildGroups(map) {
|
|
|
9663
9710
|
const groups = /* @__PURE__ */ new Map();
|
|
9664
9711
|
for (const { path: rel } of map.ranked) {
|
|
9665
9712
|
const entry = map.files[rel];
|
|
9666
|
-
if (!entry
|
|
9713
|
+
if (!entry) continue;
|
|
9667
9714
|
const label = groupLabelOf(rel, entry.pkg);
|
|
9668
9715
|
let g = groups.get(label);
|
|
9669
9716
|
if (!g) {
|
|
9670
9717
|
g = { label, files: [] };
|
|
9671
9718
|
groups.set(label, g);
|
|
9672
9719
|
}
|
|
9673
|
-
g.files.push({ path: rel, symbols: entry.symbols });
|
|
9720
|
+
g.files.push({ path: rel, symbols: entry.symbols, reexports: entry.reexports });
|
|
9674
9721
|
}
|
|
9675
9722
|
return [...groups.values()];
|
|
9676
9723
|
}
|
|
@@ -9681,12 +9728,20 @@ function moduleLine(mod, info) {
|
|
|
9681
9728
|
return ` ${label} (${info.files} \u6587\u4EF6)${layers ? ` ${layers}` : ""}${entry}`;
|
|
9682
9729
|
}
|
|
9683
9730
|
function renderLarge(map, budget) {
|
|
9731
|
+
const bestOfModule = /* @__PURE__ */ new Map();
|
|
9732
|
+
for (const r of map.ranked) {
|
|
9733
|
+
const slash = r.path.indexOf("/");
|
|
9734
|
+
const mod = slash < 0 ? "." : r.path.slice(0, slash);
|
|
9735
|
+
const prev = bestOfModule.get(mod);
|
|
9736
|
+
if (prev === void 0 || r.score > prev) bestOfModule.set(mod, r.score);
|
|
9737
|
+
}
|
|
9684
9738
|
const perModule = /* @__PURE__ */ new Map();
|
|
9685
9739
|
for (const rel of Object.keys(map.files)) {
|
|
9686
9740
|
const slash = rel.indexOf("/");
|
|
9687
9741
|
const first = slash < 0 ? "." : rel.slice(0, slash);
|
|
9688
9742
|
const bucket = perModule.get(first) ?? {
|
|
9689
9743
|
files: 0,
|
|
9744
|
+
best: bestOfModule.get(first) ?? Number.NEGATIVE_INFINITY,
|
|
9690
9745
|
layers: /* @__PURE__ */ new Set(),
|
|
9691
9746
|
entryDepth: Number.POSITIVE_INFINITY
|
|
9692
9747
|
};
|
|
@@ -9706,7 +9761,9 @@ function renderLarge(map, budget) {
|
|
|
9706
9761
|
}
|
|
9707
9762
|
perModule.set(first, bucket);
|
|
9708
9763
|
}
|
|
9709
|
-
const sorted = [...perModule.entries()].sort(
|
|
9764
|
+
const sorted = [...perModule.entries()].sort(
|
|
9765
|
+
(a, b) => b[1].best - a[1].best || b[1].files - a[1].files || a[0].localeCompare(b[0])
|
|
9766
|
+
);
|
|
9710
9767
|
const lines = [];
|
|
9711
9768
|
const lineBudget = Math.max(200, budget - TAIL_RESERVE);
|
|
9712
9769
|
let used = 0;
|
|
@@ -9728,8 +9785,13 @@ function renderLarge(map, budget) {
|
|
|
9728
9785
|
return lines.join("\n");
|
|
9729
9786
|
}
|
|
9730
9787
|
function fileLine(f) {
|
|
9731
|
-
const
|
|
9732
|
-
|
|
9788
|
+
const name = baseName(f.path);
|
|
9789
|
+
if (f.symbols.length > 0) {
|
|
9790
|
+
const sym = symbolsInline(f.symbols);
|
|
9791
|
+
return ` ${name}${sym ? `: ${sym}` : ""}`;
|
|
9792
|
+
}
|
|
9793
|
+
if (f.reexports) return ` ${name}: (\u518D\u5BFC\u51FA ${f.reexports})`;
|
|
9794
|
+
return ` ${name}: (\u5165\u53E3)`;
|
|
9733
9795
|
}
|
|
9734
9796
|
function renderDetailed(map, budget) {
|
|
9735
9797
|
const limit = GROUP_FILE_LIMIT[map.scale === "medium" ? "medium" : "small"];
|
|
@@ -9764,23 +9826,36 @@ function renderDetailed(map, budget) {
|
|
|
9764
9826
|
const out = [];
|
|
9765
9827
|
for (const b of blocks) out.push(b.header, ...b.lines);
|
|
9766
9828
|
const omitted = map.ranked.length - shownFiles;
|
|
9767
|
-
if (omitted > 0) out.push(`\u2026 \u53E6\u6709 ${omitted} \u4E2A\u6587\u4EF6\u672A\u5217\u51FA\uFF0C\u7528 repo_map \u5DE5\u5177\u67E5\u770B`);
|
|
9829
|
+
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`);
|
|
9768
9830
|
return out.join("\n");
|
|
9769
9831
|
}
|
|
9832
|
+
function shapeLine(shape) {
|
|
9833
|
+
if (!shape) return "";
|
|
9834
|
+
const parts = [];
|
|
9835
|
+
const kinds = shape.kinds.filter((k) => k !== "npm" || !shape.kinds.includes("npm-workspace"));
|
|
9836
|
+
if (kinds.length) parts.push(kinds.slice(0, 3).join(" \xB7 "));
|
|
9837
|
+
if (shape.modules.length > 1) parts.push(`${shape.modules.length} \u6A21\u5757`);
|
|
9838
|
+
const roots = [...new Set(shape.sourceRoots)].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).slice(0, 3);
|
|
9839
|
+
if (roots.length) parts.push(`\u6E90\u7801\u6839 ${roots.join(", ")}`);
|
|
9840
|
+
return parts.length ? `\u9879\u76EE\u5F62\u6001: ${parts.join(" \xB7 ")}` : "";
|
|
9841
|
+
}
|
|
9770
9842
|
function renderRepoMap(map) {
|
|
9771
9843
|
if (map.ranked.length === 0 && !map.shape) return "";
|
|
9772
9844
|
const budget = renderBudget(map.scale);
|
|
9773
|
-
const
|
|
9845
|
+
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";
|
|
9846
|
+
const shape = shapeLine(map.shape);
|
|
9847
|
+
const head = shape ? `${title}
|
|
9848
|
+
${shape}` : title;
|
|
9774
9849
|
const bodyBudget = Math.max(200, budget - head.length - 1);
|
|
9775
9850
|
const body = map.scale === "large" ? renderLarge(map, bodyBudget) : renderDetailed(map, bodyBudget);
|
|
9776
|
-
if (!body.trim()) return
|
|
9851
|
+
if (!body.trim()) return shape;
|
|
9777
9852
|
const text = `${head}
|
|
9778
9853
|
${body}`;
|
|
9779
9854
|
if (text.length <= budget) return text;
|
|
9780
9855
|
return cutAtLine(text, budget);
|
|
9781
9856
|
}
|
|
9782
9857
|
function cutAtLine(text, budget) {
|
|
9783
|
-
const marker = "\n\u2026\uFF08\u7ED3\u6784\u56FE\u5DF2\u622A\u65AD\uFF0C\u7528 repo_map \u5DE5\u5177\u67E5\u770B\uFF09";
|
|
9858
|
+
const marker = "\n\u2026\uFF08\u7ED3\u6784\u56FE\u5DF2\u622A\u65AD\uFF0C\u7528 repo_map \u5DE5\u5177\u6309\u76EE\u5F55\u67E5\u770B\uFF09";
|
|
9784
9859
|
const room = budget - marker.length;
|
|
9785
9860
|
if (room <= 0) return marker.slice(1);
|
|
9786
9861
|
const cut = text.slice(0, room);
|
|
@@ -13088,17 +13163,26 @@ function registerSearchTool(registry, workspace) {
|
|
|
13088
13163
|
// src/tools/repoMap.ts
|
|
13089
13164
|
init_esm_shims();
|
|
13090
13165
|
var MAX_CHARS = 16e3;
|
|
13166
|
+
function filesUnder(map, prefix) {
|
|
13167
|
+
const keys = Object.keys(map.files);
|
|
13168
|
+
if (!prefix) return keys;
|
|
13169
|
+
if (prefix === ".") return keys.filter((rel) => !rel.includes("/"));
|
|
13170
|
+
return keys.filter((rel) => rel === prefix || rel.startsWith(`${prefix}/`));
|
|
13171
|
+
}
|
|
13091
13172
|
function renderSubset(map, prefix, maxFiles) {
|
|
13092
13173
|
const order = new Map(map.ranked.map((r, i) => [r.path, i]));
|
|
13093
|
-
const under =
|
|
13174
|
+
const under = filesUnder(map, prefix).sort(
|
|
13175
|
+
(a, b) => (order.get(a) ?? Infinity) - (order.get(b) ?? Infinity)
|
|
13176
|
+
);
|
|
13094
13177
|
const matched = under.slice(0, maxFiles);
|
|
13095
13178
|
if (matched.length === 0) return null;
|
|
13096
13179
|
const entries = [];
|
|
13097
13180
|
let used = 0;
|
|
13098
13181
|
for (const rel of matched) {
|
|
13099
13182
|
const f = map.files[rel];
|
|
13100
|
-
const sym = f.symbols.slice(0, 8).map((s) => s
|
|
13101
|
-
const
|
|
13183
|
+
const sym = f.symbols.slice(0, 8).map((s) => symbolRef(s, true)).join(", ");
|
|
13184
|
+
const body = f.symbols.length > 0 ? sym : f.reexports ? `(\u518D\u5BFC\u51FA ${f.reexports})` : "(\u5165\u53E3)";
|
|
13185
|
+
const line = `${rel}: ${body}`;
|
|
13102
13186
|
if (used + line.length + 1 > MAX_CHARS) break;
|
|
13103
13187
|
entries.push(line);
|
|
13104
13188
|
used += line.length + 1;
|
|
@@ -13130,18 +13214,20 @@ function registerRepoMapTool(registry, workspace) {
|
|
|
13130
13214
|
if (sub) return sub;
|
|
13131
13215
|
return { error: `\u6CA1\u6709\u5339\u914D\u7684\u76EE\u5F55\uFF1A${path31}` };
|
|
13132
13216
|
}
|
|
13133
|
-
const groups = buildGroups(map).slice(0, 40).map((g) =>
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13217
|
+
const groups = buildGroups(map).slice(0, 40).map((g) => {
|
|
13218
|
+
const dir = g.files[0]?.path.split("/").slice(0, -1).join("/") || ".";
|
|
13219
|
+
return {
|
|
13220
|
+
label: g.label,
|
|
13221
|
+
files: filesUnder(map, dir).length,
|
|
13222
|
+
...dir === g.label ? {} : { path: dir }
|
|
13223
|
+
};
|
|
13224
|
+
});
|
|
13138
13225
|
return {
|
|
13139
13226
|
scale: map.scale,
|
|
13140
13227
|
files: map.scan.files,
|
|
13141
13228
|
indexed: map.scan.indexed,
|
|
13142
13229
|
groups,
|
|
13143
|
-
|
|
13144
|
-
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"'
|
|
13230
|
+
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"'
|
|
13145
13231
|
};
|
|
13146
13232
|
},
|
|
13147
13233
|
{ category: "search", riskLevel: "low", capabilities: ["repo_map"], requiresApproval: false },
|