@zqagent/core 0.3.16 → 0.3.25
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 +161 -51
- 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 +161 -51
- 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
|
|
@@ -8986,6 +9020,7 @@ function markLoaded(langId) {
|
|
|
8986
9020
|
failedAt.delete(langId);
|
|
8987
9021
|
}
|
|
8988
9022
|
var inflight = /* @__PURE__ */ new Map();
|
|
9023
|
+
var readyCache = /* @__PURE__ */ new Map();
|
|
8989
9024
|
function grammarDir() {
|
|
8990
9025
|
const explicit = process.env.ZQAGENT_REPOMAP_GRAMMAR_DIR?.trim();
|
|
8991
9026
|
if (explicit) return explicit;
|
|
@@ -9009,10 +9044,7 @@ function verify(spec, buf) {
|
|
|
9009
9044
|
return sha256Hex(buf) === spec.sha256;
|
|
9010
9045
|
}
|
|
9011
9046
|
function readLocal(spec) {
|
|
9012
|
-
const
|
|
9013
|
-
const explicit = process.env.ZQAGENT_REPOMAP_GRAMMAR_DIR?.trim();
|
|
9014
|
-
if (explicit) candidates.push(path14.join(explicit, `${spec.id}.wasm`));
|
|
9015
|
-
for (const file of candidates) {
|
|
9047
|
+
for (const file of localCandidates(spec)) {
|
|
9016
9048
|
try {
|
|
9017
9049
|
const buf = fs11.readFileSync(file);
|
|
9018
9050
|
if (verify(spec, buf)) return new Uint8Array(buf);
|
|
@@ -9021,6 +9053,24 @@ function readLocal(spec) {
|
|
|
9021
9053
|
}
|
|
9022
9054
|
return null;
|
|
9023
9055
|
}
|
|
9056
|
+
function localCandidates(spec) {
|
|
9057
|
+
const candidates = [cachePath(spec)];
|
|
9058
|
+
const explicit = process.env.ZQAGENT_REPOMAP_GRAMMAR_DIR?.trim();
|
|
9059
|
+
if (explicit) candidates.push(path14.join(explicit, `${spec.id}.wasm`));
|
|
9060
|
+
return candidates;
|
|
9061
|
+
}
|
|
9062
|
+
function localSignature(spec) {
|
|
9063
|
+
const parts = [];
|
|
9064
|
+
for (const file of localCandidates(spec)) {
|
|
9065
|
+
try {
|
|
9066
|
+
const st = fs11.statSync(file);
|
|
9067
|
+
parts.push(`${st.mtimeMs}:${st.size}`);
|
|
9068
|
+
} catch {
|
|
9069
|
+
parts.push("-");
|
|
9070
|
+
}
|
|
9071
|
+
}
|
|
9072
|
+
return parts.join("|");
|
|
9073
|
+
}
|
|
9024
9074
|
async function download(spec) {
|
|
9025
9075
|
if (offline()) return null;
|
|
9026
9076
|
for (const build of CDN_TEMPLATES) {
|
|
@@ -9079,7 +9129,13 @@ async function loadGrammar(langId) {
|
|
|
9079
9129
|
function grammarReady(langId) {
|
|
9080
9130
|
if (resolved.get(langId)) return true;
|
|
9081
9131
|
const spec = GRAMMARS[langId];
|
|
9082
|
-
|
|
9132
|
+
if (!spec) return false;
|
|
9133
|
+
const sig = localSignature(spec);
|
|
9134
|
+
const hit = readyCache.get(langId);
|
|
9135
|
+
if (hit && hit.sig === sig) return hit.ready;
|
|
9136
|
+
const ready = readLocal(spec) !== null;
|
|
9137
|
+
readyCache.set(langId, { sig, ready });
|
|
9138
|
+
return ready;
|
|
9083
9139
|
}
|
|
9084
9140
|
|
|
9085
9141
|
// src/repomap/extract/index.ts
|
|
@@ -9098,10 +9154,10 @@ async function extractFile(relPath, source) {
|
|
|
9098
9154
|
const bytes = await loadGrammar(lang);
|
|
9099
9155
|
if (bytes) {
|
|
9100
9156
|
const ts = await extractWithTreeSitter(lang, bytes, source, MAX_SYMBOLS_PER_FILE);
|
|
9101
|
-
if (ts) return { symbols: ts.symbols, pkg: ts.pkg, via: "tree-sitter" };
|
|
9157
|
+
if (ts) return { symbols: ts.symbols, pkg: ts.pkg, reexports: ts.reexports, via: "tree-sitter" };
|
|
9102
9158
|
}
|
|
9103
9159
|
const re = extractWithRegex(lang, source, MAX_SYMBOLS_PER_FILE);
|
|
9104
|
-
return { symbols: re.symbols, pkg: re.pkg, via: "regex" };
|
|
9160
|
+
return { symbols: re.symbols, pkg: re.pkg, reexports: re.reexports, via: "regex" };
|
|
9105
9161
|
}
|
|
9106
9162
|
function wantsContent(relPath) {
|
|
9107
9163
|
if (!langOf(relPath)) return false;
|
|
@@ -9288,6 +9344,10 @@ function hasLayerWord(name) {
|
|
|
9288
9344
|
}
|
|
9289
9345
|
var ENTRY_RE = /(^|\/)(main|index|program|startup|app|application|bootstrap|mod|__init__)(\.|\/)/i;
|
|
9290
9346
|
var ENTRY_SUFFIX_RE = /(application|program|startup)\.(java|kt|cs|scala)$/i;
|
|
9347
|
+
function isEntryFile(relPath, sourceRoots = []) {
|
|
9348
|
+
if (ENTRY_SUFFIX_RE.test(relPath)) return true;
|
|
9349
|
+
return ENTRY_RE.test(relPath) && depthFromSourceRoot(relPath, sourceRoots) <= 1;
|
|
9350
|
+
}
|
|
9291
9351
|
var TEST_RE = /(^|\/)(test|tests|__tests__|__mocks__|spec|specs|e2e)(\/|$)|\.(test|spec)\.[a-z]+$|test\.(java|kt|cs)$|_test\.(go|py|rb)$/i;
|
|
9292
9352
|
var DOC_RE = /(^|\/)(docs?|examples?|samples?|demo|benchmarks?|bench|fixtures?)(\/|$)|\.(md|mdx|rst|txt|adoc)$/i;
|
|
9293
9353
|
var GENERATED_RE = /\.(min|generated|designer)\.|_pb2?\.|\.g\.(cs|java)$|(^|\/)gen\//i;
|
|
@@ -9323,7 +9383,7 @@ function scorePath(relPath, sourceRoots) {
|
|
|
9323
9383
|
score += W.sourceRoot;
|
|
9324
9384
|
}
|
|
9325
9385
|
const depth = depthFromSourceRoot(relPath, sourceRoots);
|
|
9326
|
-
if (
|
|
9386
|
+
if (isEntryFile(relPath, sourceRoots)) {
|
|
9327
9387
|
score += W.entry;
|
|
9328
9388
|
}
|
|
9329
9389
|
const base = relPath.slice(relPath.lastIndexOf("/") + 1).replace(/\.[^.]+$/, "");
|
|
@@ -9351,7 +9411,7 @@ function rankFiles(paths, sourceRoots, hasSymbols) {
|
|
|
9351
9411
|
|
|
9352
9412
|
// src/repomap/types.ts
|
|
9353
9413
|
init_esm_shims();
|
|
9354
|
-
var REPOMAP_CACHE_VERSION =
|
|
9414
|
+
var REPOMAP_CACHE_VERSION = 5;
|
|
9355
9415
|
|
|
9356
9416
|
// src/repomap/indexer.ts
|
|
9357
9417
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -9559,6 +9619,7 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9559
9619
|
size: stat.size,
|
|
9560
9620
|
symbols: ex.symbols,
|
|
9561
9621
|
pkg: ex.pkg,
|
|
9622
|
+
reexports: ex.reexports,
|
|
9562
9623
|
via: ex.via
|
|
9563
9624
|
};
|
|
9564
9625
|
} catch {
|
|
@@ -9566,15 +9627,18 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9566
9627
|
}
|
|
9567
9628
|
await yieldToLoop();
|
|
9568
9629
|
}
|
|
9569
|
-
const
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9630
|
+
const retained = {};
|
|
9631
|
+
for (const [rel, v] of Object.entries(result)) {
|
|
9632
|
+
if (v.symbols.length > 0 || (v.reexports ?? 0) > 0 || isEntryFile(rel, shape.sourceRoots)) {
|
|
9633
|
+
retained[rel] = v;
|
|
9634
|
+
}
|
|
9635
|
+
}
|
|
9636
|
+
const ranked = rankFiles(Object.keys(retained), shape.sourceRoots);
|
|
9573
9637
|
const scan = {
|
|
9574
9638
|
files: files.length,
|
|
9575
9639
|
// 报「地图里有多少文件」而不是「本次新提取了多少」:命中缓存时
|
|
9576
|
-
//
|
|
9577
|
-
indexed: Object.keys(
|
|
9640
|
+
// 后者为 0,模型会误判结构图为空(实测曾把 1324 个文件报成 0)
|
|
9641
|
+
indexed: Object.keys(retained).length,
|
|
9578
9642
|
truncated: enumTruncated || limit < rankedAll.length,
|
|
9579
9643
|
elapsedMs: Date.now() - started
|
|
9580
9644
|
};
|
|
@@ -9591,7 +9655,7 @@ async function buildRepoMap(root, opts = {}) {
|
|
|
9591
9655
|
shape
|
|
9592
9656
|
});
|
|
9593
9657
|
}
|
|
9594
|
-
return { root: absRoot, scale, scan, ranked, files:
|
|
9658
|
+
return { root: absRoot, scale, scan, ranked, files: retained, shape };
|
|
9595
9659
|
} catch {
|
|
9596
9660
|
return empty;
|
|
9597
9661
|
}
|
|
@@ -9632,6 +9696,11 @@ var GENERIC_SYMBOLS = /* @__PURE__ */ new Set([
|
|
|
9632
9696
|
function meaningful(symbols) {
|
|
9633
9697
|
return symbols.filter((s) => s.name.length > 3 && !GENERIC_SYMBOLS.has(s.name));
|
|
9634
9698
|
}
|
|
9699
|
+
function symbolRef(s, withRange = false) {
|
|
9700
|
+
if (s.line === void 0 || s.name.includes(":")) return s.name;
|
|
9701
|
+
const end = withRange && s.endLine !== void 0 && s.endLine > s.line ? `-${s.endLine}` : "";
|
|
9702
|
+
return `${s.name}:${s.line}${end}`;
|
|
9703
|
+
}
|
|
9635
9704
|
var GROUP_FILE_LIMIT = { small: 5, medium: 4, large: 1 };
|
|
9636
9705
|
var BREADTH_SHARE = 0.5;
|
|
9637
9706
|
var TAIL_RESERVE = 64;
|
|
@@ -9655,7 +9724,7 @@ function baseName(relPath) {
|
|
|
9655
9724
|
function symbolsInline(symbols) {
|
|
9656
9725
|
const kept = meaningful(symbols);
|
|
9657
9726
|
if (kept.length === 0) return "";
|
|
9658
|
-
const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => s
|
|
9727
|
+
const names = kept.slice(0, MAX_SYMBOLS_PER_LINE).map((s) => symbolRef(s));
|
|
9659
9728
|
const more = kept.length > MAX_SYMBOLS_PER_LINE ? ", \u2026" : "";
|
|
9660
9729
|
return names.join(", ") + more;
|
|
9661
9730
|
}
|
|
@@ -9663,14 +9732,14 @@ function buildGroups(map) {
|
|
|
9663
9732
|
const groups = /* @__PURE__ */ new Map();
|
|
9664
9733
|
for (const { path: rel } of map.ranked) {
|
|
9665
9734
|
const entry = map.files[rel];
|
|
9666
|
-
if (!entry
|
|
9735
|
+
if (!entry) continue;
|
|
9667
9736
|
const label = groupLabelOf(rel, entry.pkg);
|
|
9668
9737
|
let g = groups.get(label);
|
|
9669
9738
|
if (!g) {
|
|
9670
9739
|
g = { label, files: [] };
|
|
9671
9740
|
groups.set(label, g);
|
|
9672
9741
|
}
|
|
9673
|
-
g.files.push({ path: rel, symbols: entry.symbols });
|
|
9742
|
+
g.files.push({ path: rel, symbols: entry.symbols, reexports: entry.reexports });
|
|
9674
9743
|
}
|
|
9675
9744
|
return [...groups.values()];
|
|
9676
9745
|
}
|
|
@@ -9681,12 +9750,20 @@ function moduleLine(mod, info) {
|
|
|
9681
9750
|
return ` ${label} (${info.files} \u6587\u4EF6)${layers ? ` ${layers}` : ""}${entry}`;
|
|
9682
9751
|
}
|
|
9683
9752
|
function renderLarge(map, budget) {
|
|
9753
|
+
const bestOfModule = /* @__PURE__ */ new Map();
|
|
9754
|
+
for (const r of map.ranked) {
|
|
9755
|
+
const slash = r.path.indexOf("/");
|
|
9756
|
+
const mod = slash < 0 ? "." : r.path.slice(0, slash);
|
|
9757
|
+
const prev = bestOfModule.get(mod);
|
|
9758
|
+
if (prev === void 0 || r.score > prev) bestOfModule.set(mod, r.score);
|
|
9759
|
+
}
|
|
9684
9760
|
const perModule = /* @__PURE__ */ new Map();
|
|
9685
9761
|
for (const rel of Object.keys(map.files)) {
|
|
9686
9762
|
const slash = rel.indexOf("/");
|
|
9687
9763
|
const first = slash < 0 ? "." : rel.slice(0, slash);
|
|
9688
9764
|
const bucket = perModule.get(first) ?? {
|
|
9689
9765
|
files: 0,
|
|
9766
|
+
best: bestOfModule.get(first) ?? Number.NEGATIVE_INFINITY,
|
|
9690
9767
|
layers: /* @__PURE__ */ new Set(),
|
|
9691
9768
|
entryDepth: Number.POSITIVE_INFINITY
|
|
9692
9769
|
};
|
|
@@ -9706,7 +9783,9 @@ function renderLarge(map, budget) {
|
|
|
9706
9783
|
}
|
|
9707
9784
|
perModule.set(first, bucket);
|
|
9708
9785
|
}
|
|
9709
|
-
const sorted = [...perModule.entries()].sort(
|
|
9786
|
+
const sorted = [...perModule.entries()].sort(
|
|
9787
|
+
(a, b) => b[1].best - a[1].best || b[1].files - a[1].files || a[0].localeCompare(b[0])
|
|
9788
|
+
);
|
|
9710
9789
|
const lines = [];
|
|
9711
9790
|
const lineBudget = Math.max(200, budget - TAIL_RESERVE);
|
|
9712
9791
|
let used = 0;
|
|
@@ -9728,8 +9807,13 @@ function renderLarge(map, budget) {
|
|
|
9728
9807
|
return lines.join("\n");
|
|
9729
9808
|
}
|
|
9730
9809
|
function fileLine(f) {
|
|
9731
|
-
const
|
|
9732
|
-
|
|
9810
|
+
const name = baseName(f.path);
|
|
9811
|
+
if (f.symbols.length > 0) {
|
|
9812
|
+
const sym = symbolsInline(f.symbols);
|
|
9813
|
+
return ` ${name}${sym ? `: ${sym}` : ""}`;
|
|
9814
|
+
}
|
|
9815
|
+
if (f.reexports) return ` ${name}: (\u518D\u5BFC\u51FA ${f.reexports})`;
|
|
9816
|
+
return ` ${name}: (\u5165\u53E3)`;
|
|
9733
9817
|
}
|
|
9734
9818
|
function renderDetailed(map, budget) {
|
|
9735
9819
|
const limit = GROUP_FILE_LIMIT[map.scale === "medium" ? "medium" : "small"];
|
|
@@ -9764,23 +9848,36 @@ function renderDetailed(map, budget) {
|
|
|
9764
9848
|
const out = [];
|
|
9765
9849
|
for (const b of blocks) out.push(b.header, ...b.lines);
|
|
9766
9850
|
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`);
|
|
9851
|
+
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
9852
|
return out.join("\n");
|
|
9769
9853
|
}
|
|
9854
|
+
function shapeLine(shape) {
|
|
9855
|
+
if (!shape) return "";
|
|
9856
|
+
const parts = [];
|
|
9857
|
+
const kinds = shape.kinds.filter((k) => k !== "npm" || !shape.kinds.includes("npm-workspace"));
|
|
9858
|
+
if (kinds.length) parts.push(kinds.slice(0, 3).join(" \xB7 "));
|
|
9859
|
+
if (shape.modules.length > 1) parts.push(`${shape.modules.length} \u6A21\u5757`);
|
|
9860
|
+
const roots = [...new Set(shape.sourceRoots)].sort((a, b) => a.split("/").length - b.split("/").length || a.localeCompare(b)).slice(0, 3);
|
|
9861
|
+
if (roots.length) parts.push(`\u6E90\u7801\u6839 ${roots.join(", ")}`);
|
|
9862
|
+
return parts.length ? `\u9879\u76EE\u5F62\u6001: ${parts.join(" \xB7 ")}` : "";
|
|
9863
|
+
}
|
|
9770
9864
|
function renderRepoMap(map) {
|
|
9771
9865
|
if (map.ranked.length === 0 && !map.shape) return "";
|
|
9772
9866
|
const budget = renderBudget(map.scale);
|
|
9773
|
-
const
|
|
9867
|
+
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";
|
|
9868
|
+
const shape = shapeLine(map.shape);
|
|
9869
|
+
const head = shape ? `${title}
|
|
9870
|
+
${shape}` : title;
|
|
9774
9871
|
const bodyBudget = Math.max(200, budget - head.length - 1);
|
|
9775
9872
|
const body = map.scale === "large" ? renderLarge(map, bodyBudget) : renderDetailed(map, bodyBudget);
|
|
9776
|
-
if (!body.trim()) return
|
|
9873
|
+
if (!body.trim()) return shape;
|
|
9777
9874
|
const text = `${head}
|
|
9778
9875
|
${body}`;
|
|
9779
9876
|
if (text.length <= budget) return text;
|
|
9780
9877
|
return cutAtLine(text, budget);
|
|
9781
9878
|
}
|
|
9782
9879
|
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";
|
|
9880
|
+
const marker = "\n\u2026\uFF08\u7ED3\u6784\u56FE\u5DF2\u622A\u65AD\uFF0C\u7528 repo_map \u5DE5\u5177\u6309\u76EE\u5F55\u67E5\u770B\uFF09";
|
|
9784
9881
|
const room = budget - marker.length;
|
|
9785
9882
|
if (room <= 0) return marker.slice(1);
|
|
9786
9883
|
const cut = text.slice(0, room);
|
|
@@ -9890,10 +9987,12 @@ function attachRepoMap(engine, opts) {
|
|
|
9890
9987
|
const original = spec.func;
|
|
9891
9988
|
engine.registry.register(
|
|
9892
9989
|
async (args, ctx) => {
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9990
|
+
try {
|
|
9991
|
+
return await original(args, ctx);
|
|
9992
|
+
} finally {
|
|
9993
|
+
invalidateRepoMap(workspace);
|
|
9994
|
+
schedule();
|
|
9995
|
+
}
|
|
9897
9996
|
},
|
|
9898
9997
|
spec.metadata,
|
|
9899
9998
|
spec.schema,
|
|
@@ -13088,17 +13187,26 @@ function registerSearchTool(registry, workspace) {
|
|
|
13088
13187
|
// src/tools/repoMap.ts
|
|
13089
13188
|
init_esm_shims();
|
|
13090
13189
|
var MAX_CHARS = 16e3;
|
|
13190
|
+
function filesUnder(map, prefix) {
|
|
13191
|
+
const keys = Object.keys(map.files);
|
|
13192
|
+
if (!prefix) return keys;
|
|
13193
|
+
if (prefix === ".") return keys.filter((rel) => !rel.includes("/"));
|
|
13194
|
+
return keys.filter((rel) => rel === prefix || rel.startsWith(`${prefix}/`));
|
|
13195
|
+
}
|
|
13091
13196
|
function renderSubset(map, prefix, maxFiles) {
|
|
13092
13197
|
const order = new Map(map.ranked.map((r, i) => [r.path, i]));
|
|
13093
|
-
const under =
|
|
13198
|
+
const under = filesUnder(map, prefix).sort(
|
|
13199
|
+
(a, b) => (order.get(a) ?? Infinity) - (order.get(b) ?? Infinity)
|
|
13200
|
+
);
|
|
13094
13201
|
const matched = under.slice(0, maxFiles);
|
|
13095
13202
|
if (matched.length === 0) return null;
|
|
13096
13203
|
const entries = [];
|
|
13097
13204
|
let used = 0;
|
|
13098
13205
|
for (const rel of matched) {
|
|
13099
13206
|
const f = map.files[rel];
|
|
13100
|
-
const sym = f.symbols.slice(0, 8).map((s) => s
|
|
13101
|
-
const
|
|
13207
|
+
const sym = f.symbols.slice(0, 8).map((s) => symbolRef(s, true)).join(", ");
|
|
13208
|
+
const body = f.symbols.length > 0 ? sym : f.reexports ? `(\u518D\u5BFC\u51FA ${f.reexports})` : "(\u5165\u53E3)";
|
|
13209
|
+
const line = `${rel}: ${body}`;
|
|
13102
13210
|
if (used + line.length + 1 > MAX_CHARS) break;
|
|
13103
13211
|
entries.push(line);
|
|
13104
13212
|
used += line.length + 1;
|
|
@@ -13130,18 +13238,20 @@ function registerRepoMapTool(registry, workspace) {
|
|
|
13130
13238
|
if (sub) return sub;
|
|
13131
13239
|
return { error: `\u6CA1\u6709\u5339\u914D\u7684\u76EE\u5F55\uFF1A${path31}` };
|
|
13132
13240
|
}
|
|
13133
|
-
const groups = buildGroups(map).slice(0, 40).map((g) =>
|
|
13134
|
-
|
|
13135
|
-
|
|
13136
|
-
|
|
13137
|
-
|
|
13241
|
+
const groups = buildGroups(map).slice(0, 40).map((g) => {
|
|
13242
|
+
const dir = g.files[0]?.path.split("/").slice(0, -1).join("/") || ".";
|
|
13243
|
+
return {
|
|
13244
|
+
label: g.label,
|
|
13245
|
+
files: filesUnder(map, dir).length,
|
|
13246
|
+
...dir === g.label ? {} : { path: dir }
|
|
13247
|
+
};
|
|
13248
|
+
});
|
|
13138
13249
|
return {
|
|
13139
13250
|
scale: map.scale,
|
|
13140
13251
|
files: map.scan.files,
|
|
13141
13252
|
indexed: map.scan.indexed,
|
|
13142
13253
|
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"'
|
|
13254
|
+
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
13255
|
};
|
|
13146
13256
|
},
|
|
13147
13257
|
{ category: "search", riskLevel: "low", capabilities: ["repo_map"], requiresApproval: false },
|