sverklo 0.2.16 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/bin/sverklo.js +38 -5
- package/dist/bin/sverklo.js.map +1 -1
- package/dist/src/indexer/graph-builder.js +11 -2
- package/dist/src/indexer/graph-builder.js.map +1 -1
- package/dist/src/indexer/indexer.d.ts +2 -0
- package/dist/src/indexer/indexer.js +4 -0
- package/dist/src/indexer/indexer.js.map +1 -1
- package/dist/src/indexer/watcher.js +31 -0
- package/dist/src/indexer/watcher.js.map +1 -1
- package/dist/src/init.js +11 -0
- package/dist/src/init.js.map +1 -1
- package/dist/src/memory/import.js +6 -32
- package/dist/src/memory/import.js.map +1 -1
- package/dist/src/search/hybrid-search.js +18 -3
- package/dist/src/search/hybrid-search.js.map +1 -1
- package/dist/src/search/token-budget.js +13 -3
- package/dist/src/search/token-budget.js.map +1 -1
- package/dist/src/server/dashboard-html.js +6 -1
- package/dist/src/server/dashboard-html.js.map +1 -1
- package/dist/src/server/http-server.js +27 -1
- package/dist/src/server/http-server.js.map +1 -1
- package/dist/src/server/tools/audit.js +92 -53
- package/dist/src/server/tools/audit.js.map +1 -1
- package/dist/src/server/tools/dependencies.js +3 -2
- package/dist/src/server/tools/dependencies.js.map +1 -1
- package/dist/src/server/tools/diff-search.js +3 -2
- package/dist/src/server/tools/diff-search.js.map +1 -1
- package/dist/src/server/tools/find-references.js +3 -2
- package/dist/src/server/tools/find-references.js.map +1 -1
- package/dist/src/server/tools/impact.d.ts +4 -0
- package/dist/src/server/tools/impact.js +77 -1
- package/dist/src/server/tools/impact.js.map +1 -1
- package/dist/src/server/tools/lookup.js +3 -2
- package/dist/src/server/tools/lookup.js.map +1 -1
- package/dist/src/server/tools/overview.js +3 -2
- package/dist/src/server/tools/overview.js.map +1 -1
- package/dist/src/server/tools/review-diff.js +111 -76
- package/dist/src/server/tools/review-diff.js.map +1 -1
- package/dist/src/server/tools/search.js +4 -2
- package/dist/src/server/tools/search.js.map +1 -1
- package/dist/src/server/tools/search.test.js +2 -2
- package/dist/src/utils/budget.d.ts +11 -0
- package/dist/src/utils/budget.js +26 -0
- package/dist/src/utils/budget.js.map +1 -0
- package/dist/src/utils/config-file.d.ts +28 -0
- package/dist/src/utils/config-file.js +94 -0
- package/dist/src/utils/config-file.js.map +1 -0
- package/dist/src/utils/ignore.js +6 -0
- package/dist/src/utils/ignore.js.map +1 -1
- package/dist/src/workspace/cli.d.ts +17 -0
- package/dist/src/workspace/cli.js +205 -0
- package/dist/src/workspace/cli.js.map +1 -0
- package/dist/src/workspace/cross-db.d.ts +49 -0
- package/dist/src/workspace/cross-db.js +192 -0
- package/dist/src/workspace/cross-db.js.map +1 -0
- package/dist/src/workspace/cross-indexer.d.ts +16 -0
- package/dist/src/workspace/cross-indexer.js +288 -0
- package/dist/src/workspace/cross-indexer.js.map +1 -0
- package/dist/src/workspace/graphql-consumer.d.ts +13 -0
- package/dist/src/workspace/graphql-consumer.js +293 -0
- package/dist/src/workspace/graphql-consumer.js.map +1 -0
- package/dist/src/workspace/graphql-extractor.d.ts +13 -0
- package/dist/src/workspace/graphql-extractor.js +172 -0
- package/dist/src/workspace/graphql-extractor.js.map +1 -0
- package/dist/src/workspace/workspace-config.d.ts +32 -0
- package/dist/src/workspace/workspace-config.js +91 -0
- package/dist/src/workspace/workspace-config.js.map +1 -0
- package/package.json +5 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveBudget } from "../../utils/budget.js";
|
|
1
2
|
export const findReferencesTool = {
|
|
2
3
|
name: "sverklo_refs",
|
|
3
4
|
description: "Find all references to a symbol across the codebase. Shows where a function, class, or type is imported, called, or used. Matches on identifier word boundaries by default — `embed` does NOT match `embeddingStore`. Pass `exact: false` to opt into substring matching.",
|
|
@@ -14,7 +15,7 @@ export const findReferencesTool = {
|
|
|
14
15
|
},
|
|
15
16
|
token_budget: {
|
|
16
17
|
type: "number",
|
|
17
|
-
description: "Max tokens to return (default:
|
|
18
|
+
description: "Max tokens to return (default: 2000)",
|
|
18
19
|
},
|
|
19
20
|
},
|
|
20
21
|
required: ["symbol"],
|
|
@@ -51,7 +52,7 @@ export function handleFindReferences(indexer, args) {
|
|
|
51
52
|
return 'Error: `symbol` is required. Usage: sverklo_refs symbol:"MyClass".';
|
|
52
53
|
}
|
|
53
54
|
const exact = args.exact !== false; // default true
|
|
54
|
-
const tokenBudget = args
|
|
55
|
+
const tokenBudget = resolveBudget(args, "refs", null, 2000);
|
|
55
56
|
const matches = buildSymbolMatcher(symbol, exact);
|
|
56
57
|
// Use FTS to find candidate chunks mentioning the symbol at all.
|
|
57
58
|
// FTS still does substring-ish matching on the chunk body, but we
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"find-references.js","sourceRoot":"","sources":["../../../../src/server/tools/find-references.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"find-references.js","sourceRoot":"","sources":["../../../../src/server/tools/find-references.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { findWorkspaceForProject, getWorkspaceDbPath } from "../../workspace/workspace-config.js";
|
|
2
|
+
import { CrossRepoDb } from "../../workspace/cross-db.js";
|
|
1
3
|
export const impactTool = {
|
|
2
4
|
name: "sverklo_impact",
|
|
3
|
-
description: "Refactor blast-radius: callers of a symbol with confidence scoring. Run before editing.",
|
|
5
|
+
description: "Refactor blast-radius: callers of a symbol with confidence scoring. Run before editing. Use cross_repo:true to see impact across linked projects in a workspace.",
|
|
4
6
|
inputSchema: {
|
|
5
7
|
type: "object",
|
|
6
8
|
properties: {
|
|
@@ -12,6 +14,10 @@ export const impactTool = {
|
|
|
12
14
|
type: "number",
|
|
13
15
|
description: "Max references to return (default 50)",
|
|
14
16
|
},
|
|
17
|
+
cross_repo: {
|
|
18
|
+
type: "boolean",
|
|
19
|
+
description: "Include cross-repo impact from workspace projects (default false)",
|
|
20
|
+
},
|
|
15
21
|
},
|
|
16
22
|
required: ["symbol"],
|
|
17
23
|
},
|
|
@@ -97,6 +103,76 @@ export function handleImpact(indexer, args) {
|
|
|
97
103
|
parts.push(` L${line} — ${chunkLabel}`);
|
|
98
104
|
}
|
|
99
105
|
}
|
|
106
|
+
// Cross-repo impact (if requested and workspace exists)
|
|
107
|
+
if (args.cross_repo) {
|
|
108
|
+
const crossSection = getCrossRepoImpact(indexer, symbol);
|
|
109
|
+
if (crossSection) {
|
|
110
|
+
parts.push("\n" + crossSection);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return parts.join("\n");
|
|
114
|
+
}
|
|
115
|
+
function getCrossRepoImpact(indexer, symbol) {
|
|
116
|
+
try {
|
|
117
|
+
const wsConfig = findWorkspaceForProject(indexer.rootPath);
|
|
118
|
+
if (!wsConfig) {
|
|
119
|
+
return "\n_No workspace found for this project. Create one with `sverklo workspace init <name> <path1> <path2>`._";
|
|
120
|
+
}
|
|
121
|
+
const db = new CrossRepoDb(getWorkspaceDbPath(wsConfig.workspace));
|
|
122
|
+
try {
|
|
123
|
+
// Find contracts matching this symbol
|
|
124
|
+
const contracts = db.getContractBySymbol(symbol);
|
|
125
|
+
if (contracts.length === 0) {
|
|
126
|
+
// Try with Type.field pattern
|
|
127
|
+
const fieldContracts = db.getContractBySymbol(`%.${symbol}`);
|
|
128
|
+
if (fieldContracts.length === 0) {
|
|
129
|
+
return null; // No cross-repo contracts for this symbol
|
|
130
|
+
}
|
|
131
|
+
return formatCrossImpact(db, fieldContracts, wsConfig.workspace);
|
|
132
|
+
}
|
|
133
|
+
return formatCrossImpact(db, contracts, wsConfig.workspace);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
db.close();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return null; // Silently skip cross-repo if anything fails
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function formatCrossImpact(db, contracts, workspaceName) {
|
|
144
|
+
const parts = [`\n## Cross-repo impact (workspace: ${workspaceName})`];
|
|
145
|
+
let totalEdges = 0;
|
|
146
|
+
for (const contract of contracts) {
|
|
147
|
+
const edges = db.getCrossEdgesForContract(contract.id);
|
|
148
|
+
if (edges.length === 0)
|
|
149
|
+
continue;
|
|
150
|
+
totalEdges += edges.length;
|
|
151
|
+
parts.push(`\n### ${contract.symbolName} (${contract.interfaceType} ${contract.symbolKind})`);
|
|
152
|
+
parts.push(` defined in: \`${contract.sourceFile}:${contract.fileLine || "?"}\``);
|
|
153
|
+
// Group edges by project
|
|
154
|
+
const byProject = new Map();
|
|
155
|
+
for (const edge of edges) {
|
|
156
|
+
const arr = byProject.get(edge.consumerProjectId) || [];
|
|
157
|
+
arr.push(edge);
|
|
158
|
+
byProject.set(edge.consumerProjectId, arr);
|
|
159
|
+
}
|
|
160
|
+
for (const [projectId, projectEdges] of byProject) {
|
|
161
|
+
const project = db.getProject(projectId);
|
|
162
|
+
const projectName = project?.name || projectId;
|
|
163
|
+
parts.push(`\n **${projectName}** (${projectEdges.length} reference${projectEdges.length === 1 ? "" : "s"}):`);
|
|
164
|
+
for (const edge of projectEdges.slice(0, 20)) {
|
|
165
|
+
const conf = edge.confidence < 1.0 ? ` (confidence: ${edge.confidence})` : "";
|
|
166
|
+
parts.push(` · \`${edge.consumerFile}:${edge.consumerLine || "?"}\` — ${edge.consumerSymbol} [${edge.edgeType}]${conf}`);
|
|
167
|
+
}
|
|
168
|
+
if (projectEdges.length > 20) {
|
|
169
|
+
parts.push(` _...and ${projectEdges.length - 20} more_`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (totalEdges === 0)
|
|
174
|
+
return null;
|
|
175
|
+
parts.unshift(""); // blank line before section
|
|
100
176
|
return parts.join("\n");
|
|
101
177
|
}
|
|
102
178
|
//# sourceMappingURL=impact.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impact.js","sourceRoot":"","sources":["../../../../src/server/tools/impact.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"impact.js","sourceRoot":"","sources":["../../../../src/server/tools/impact.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatLookup } from "../../search/token-budget.js";
|
|
2
|
+
import { resolveBudget } from "../../utils/budget.js";
|
|
2
3
|
// Issue #6: on the first call, sverklo_lookup paid a ~1.6s penalty while
|
|
3
4
|
// warming up prepared statements via fileStore.getAll() to build a
|
|
4
5
|
// pagerank-by-file map. The getByNameWithFile JOIN below returns the
|
|
@@ -28,7 +29,7 @@ export const lookupTool = {
|
|
|
28
29
|
},
|
|
29
30
|
token_budget: {
|
|
30
31
|
type: "number",
|
|
31
|
-
description: "Max tokens to return (default:
|
|
32
|
+
description: "Max tokens to return (default: 2000)",
|
|
32
33
|
},
|
|
33
34
|
},
|
|
34
35
|
required: ["symbol"],
|
|
@@ -46,7 +47,7 @@ export function handleLookup(indexer, args) {
|
|
|
46
47
|
"The tool schema names this parameter `symbol`, not `name` — common typo.");
|
|
47
48
|
}
|
|
48
49
|
const type = args.type || "any";
|
|
49
|
-
const tokenBudget = args
|
|
50
|
+
const tokenBudget = resolveBudget(args, "lookup", null, 2000);
|
|
50
51
|
// Single JOIN'd query — chunks come back pre-sorted by pagerank DESC
|
|
51
52
|
// and carry the containing file's path, so no full fileStore scan.
|
|
52
53
|
let chunks = indexer.chunkStore.getByNameWithFile(symbol, 20);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../../../src/server/tools/lookup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../../../src/server/tools/lookup.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,yEAAyE;AACzE,mEAAmE;AACnE,qEAAqE;AACrE,mEAAmE;AAEnE,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,4HAA4H;IAC9H,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;YACD,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE;oBACJ,UAAU;oBACV,OAAO;oBACP,MAAM;oBACN,WAAW;oBACX,QAAQ;oBACR,UAAU;oBACV,KAAK;iBACN;gBACD,WAAW,EAAE,uBAAuB;aACrC;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,sCAAsC;aACpD;SACF;QACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;KACrB;CACF,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,OAAgB,EAChB,IAA6B;IAE7B,kEAAkE;IAClE,iEAAiE;IACjE,mEAAmE;IACnE,mEAAmE;IACnE,sDAAsD;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACvD,OAAO,CACL,wEAAwE;YACxE,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAI,IAAI,CAAC,IAA0B,IAAI,KAAK,CAAC;IACvD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAE9D,qEAAqE;IACrE,mEAAmE;IACnE,IAAI,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,iBAAiB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAE9D,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACjD,CAAC;IAED,oEAAoE;IACpE,mEAAmE;IACnE,+CAA+C;IAC/C,MAAM,YAAY,GAAG,IAAI,GAAG,EAAsB,CAAC;IACnD,OAAO,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatOverview } from "../../search/token-budget.js";
|
|
2
|
+
import { resolveBudget } from "../../utils/budget.js";
|
|
2
3
|
export const overviewTool = {
|
|
3
4
|
name: "sverklo_overview",
|
|
4
5
|
description: "Get a structural map of the codebase. Shows the most important files and their key symbols ranked by dependency importance (PageRank). Use this FIRST when starting work on an unfamiliar codebase or directory.",
|
|
@@ -11,14 +12,14 @@ export const overviewTool = {
|
|
|
11
12
|
},
|
|
12
13
|
token_budget: {
|
|
13
14
|
type: "number",
|
|
14
|
-
description: "Max tokens to return (default:
|
|
15
|
+
description: "Max tokens to return (default: 3000)",
|
|
15
16
|
},
|
|
16
17
|
},
|
|
17
18
|
},
|
|
18
19
|
};
|
|
19
20
|
export function handleOverview(indexer, args) {
|
|
20
21
|
const path = args.path;
|
|
21
|
-
const tokenBudget = args
|
|
22
|
+
const tokenBudget = resolveBudget(args, "overview", null, 3000);
|
|
22
23
|
const files = indexer.fileStore.getAll(); // already sorted by pagerank DESC
|
|
23
24
|
const entries = [];
|
|
24
25
|
for (const file of files) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../../../src/server/tools/overview.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAsB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../../../../src/server/tools/overview.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAsB,MAAM,8BAA8B,CAAC;AAClF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,kNAAkN;IACpN,WAAW,EAAE;QACX,IAAI,EAAE,QAAiB;QACvB,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,+CAA+C;aAC7D;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,sCAAsC;aACpD;SACF;KACF;CACF,CAAC;AAEF,MAAM,UAAU,cAAc,CAC5B,OAAgB,EAChB,IAA6B;IAE7B,MAAM,IAAI,GAAG,IAAI,CAAC,IAA0B,CAAC;IAC7C,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAEhE,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,kCAAkC;IAE5E,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAClD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { basename } from "node:path";
|
|
|
3
3
|
import { computeRiskScore, formatRiskBadge } from "./risk-score.js";
|
|
4
4
|
import { isTestPath, candidateTestNames } from "./test-paths.js";
|
|
5
5
|
import { getDiffHunks, runAllHeuristics } from "./diff-heuristics.js";
|
|
6
|
+
import { resolveBudget } from "../../utils/budget.js";
|
|
6
7
|
export const reviewDiffTool = {
|
|
7
8
|
name: "sverklo_review_diff",
|
|
8
9
|
description: "Diff-aware context bundler for code review. Takes a git ref or range and returns: " +
|
|
@@ -29,7 +30,7 @@ export const reviewDiffTool = {
|
|
|
29
30
|
},
|
|
30
31
|
token_budget: {
|
|
31
32
|
type: "number",
|
|
32
|
-
description: "Max tokens to return. Default:
|
|
33
|
+
description: "Max tokens to return. Default: 4000.",
|
|
33
34
|
},
|
|
34
35
|
},
|
|
35
36
|
},
|
|
@@ -38,7 +39,7 @@ export function handleReviewDiff(indexer, args) {
|
|
|
38
39
|
const ref = args.ref || "main..HEAD";
|
|
39
40
|
const includeSimilarity = args.include_added_similarity !== false;
|
|
40
41
|
const maxFiles = args.max_files || 25;
|
|
41
|
-
const tokenBudget = args
|
|
42
|
+
const tokenBudget = resolveBudget(args, "review_diff", null, 4000);
|
|
42
43
|
// ─── 1. Get list of changed files ───
|
|
43
44
|
const changedFiles = getChangedFiles(indexer.rootPath, ref);
|
|
44
45
|
if (changedFiles === null) {
|
|
@@ -245,47 +246,73 @@ export function handleReviewDiff(indexer, args) {
|
|
|
245
246
|
// class of bug that symbol-level analysis alone cannot see.
|
|
246
247
|
const diffHunks = getDiffHunks(indexer.rootPath, ref);
|
|
247
248
|
const heuristicFindings = runAllHeuristics(diffHunks);
|
|
248
|
-
// ─── 7. Format output ───
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
249
|
+
// ─── 7. Format output with section-level budgeting ───
|
|
250
|
+
const sections = [];
|
|
251
|
+
let usedTokens = 0;
|
|
252
|
+
const maxTokens = tokenBudget;
|
|
253
|
+
function addSection(section) {
|
|
254
|
+
const cost = Math.ceil(section.length / 3.5);
|
|
255
|
+
if (usedTokens + cost > maxTokens) {
|
|
256
|
+
sections.push("\n_[remaining sections omitted to fit token_budget]_");
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
sections.push(section);
|
|
260
|
+
usedTokens += cost;
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
// Header
|
|
264
|
+
{
|
|
265
|
+
const headerLines = [];
|
|
266
|
+
headerLines.push(`# Diff Review: \`${ref}\``);
|
|
267
|
+
headerLines.push("");
|
|
268
|
+
headerLines.push(`**${changedFiles.length} file${changedFiles.length === 1 ? "" : "s"} changed** ` +
|
|
269
|
+
`(${addedSymbols.length} added, ${removedSymbols.length} removed, ${modifiedFiles.length} modified)`);
|
|
270
|
+
if (truncated) {
|
|
271
|
+
headerLines.push(`_Showing first ${maxFiles} files; ${changedFiles.length - maxFiles} more not analyzed._`);
|
|
272
|
+
}
|
|
273
|
+
headerLines.push("");
|
|
274
|
+
if (!addSection(headerLines.join("\n")))
|
|
275
|
+
return sections.join("\n");
|
|
256
276
|
}
|
|
257
|
-
parts.push("");
|
|
258
277
|
// Changed files table
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
278
|
+
{
|
|
279
|
+
const cfLines = [];
|
|
280
|
+
cfLines.push("## Changed files");
|
|
281
|
+
for (const cf of cappedFiles) {
|
|
282
|
+
const indexed = fileCache.get(cf.path);
|
|
283
|
+
const pr = indexed ? ` (PR ${indexed.pagerank.toFixed(2)})` : "";
|
|
284
|
+
const impact = fileImpact.get(cf.path);
|
|
285
|
+
const impactNote = impact && impact.importers > 0 ? ` ← ${impact.importers} importer${impact.importers === 1 ? "" : "s"}` : "";
|
|
286
|
+
const risk = riskByFile.get(cf.path);
|
|
287
|
+
const riskNote = risk ? ` · ${formatRiskBadge(risk)}` : "";
|
|
288
|
+
cfLines.push(`- **${cf.status}** \`${cf.path}\` +${cf.added} -${cf.removed}${pr}${impactNote}${riskNote}`);
|
|
289
|
+
}
|
|
290
|
+
cfLines.push("");
|
|
291
|
+
if (!addSection(cfLines.join("\n")))
|
|
292
|
+
return sections.join("\n");
|
|
268
293
|
}
|
|
269
|
-
|
|
270
|
-
// Risk hot-list: surface high/critical files with their reasons so a
|
|
271
|
-
// reviewer can immediately see *why* a file is flagged.
|
|
294
|
+
// Risk hot-list
|
|
272
295
|
const riskRanked = [...riskByFile.entries()]
|
|
273
296
|
.filter(([, r]) => r.level === "high" || r.level === "critical")
|
|
274
297
|
.sort((a, b) => b[1].total - a[1].total);
|
|
275
298
|
if (riskRanked.length > 0) {
|
|
276
|
-
|
|
277
|
-
|
|
299
|
+
const riskLines = [];
|
|
300
|
+
riskLines.push("## ⚠️ Highest-risk files");
|
|
301
|
+
riskLines.push("_Risk score combines: untested, security-sensitive paths, fan-in, caller count, dangling refs, churn._");
|
|
278
302
|
for (const [path, score] of riskRanked.slice(0, 8)) {
|
|
279
|
-
|
|
303
|
+
riskLines.push(`- ${formatRiskBadge(score)} \`${path}\``);
|
|
280
304
|
if (score.reasons.length > 0) {
|
|
281
|
-
|
|
305
|
+
riskLines.push(` _${score.reasons.join("; ")}_`);
|
|
282
306
|
}
|
|
283
307
|
}
|
|
284
|
-
|
|
308
|
+
riskLines.push("");
|
|
309
|
+
if (!addSection(riskLines.join("\n")))
|
|
310
|
+
return sections.join("\n");
|
|
285
311
|
}
|
|
286
312
|
// Removed symbols + dangling refs (the most important section for safety)
|
|
287
313
|
if (removedSymbols.length > 0) {
|
|
288
|
-
|
|
314
|
+
const remLines = [];
|
|
315
|
+
remLines.push("## Removed symbols");
|
|
289
316
|
let dangerCount = 0;
|
|
290
317
|
for (const sym of removedSymbols.slice(0, 15)) {
|
|
291
318
|
const refs = danglingRefs.get(sym.name);
|
|
@@ -294,62 +321,70 @@ export function handleReviewDiff(indexer, args) {
|
|
|
294
321
|
const refLabel = refCount === 0
|
|
295
322
|
? "0 dangling refs (safe to remove)"
|
|
296
323
|
: `**${refCount} dangling reference${refCount === 1 ? "" : "s"}** in ${refs.files.length} file${refs.files.length === 1 ? "" : "s"}`;
|
|
297
|
-
|
|
324
|
+
remLines.push(`- ${danger} \`${sym.name}\` (${sym.type}) @ ${sym.file}:${sym.line} — ${refLabel}`);
|
|
298
325
|
if (refCount > 0) {
|
|
299
326
|
dangerCount++;
|
|
300
327
|
for (const f of refs.files.slice(0, 3)) {
|
|
301
|
-
|
|
328
|
+
remLines.push(` · ${f}`);
|
|
302
329
|
}
|
|
303
330
|
if (refs.files.length > 3) {
|
|
304
|
-
|
|
331
|
+
remLines.push(` · ...and ${refs.files.length - 3} more (call sverklo_impact for full list)`);
|
|
305
332
|
}
|
|
306
333
|
}
|
|
307
334
|
}
|
|
308
335
|
if (dangerCount > 0) {
|
|
309
|
-
|
|
310
|
-
|
|
336
|
+
remLines.push("");
|
|
337
|
+
remLines.push(`**⚠️ ${dangerCount} removed symbol${dangerCount === 1 ? " has" : "s have"} remaining references — review carefully.**`);
|
|
311
338
|
}
|
|
312
|
-
|
|
339
|
+
remLines.push("");
|
|
340
|
+
if (!addSection(remLines.join("\n")))
|
|
341
|
+
return sections.join("\n");
|
|
313
342
|
}
|
|
314
343
|
// Added symbols + duplication warnings
|
|
315
344
|
if (addedSymbols.length > 0) {
|
|
316
|
-
|
|
345
|
+
const addLines = [];
|
|
346
|
+
addLines.push("## Added symbols");
|
|
317
347
|
for (const sym of addedSymbols.slice(0, 15)) {
|
|
318
|
-
|
|
348
|
+
addLines.push(`- \`${sym.name}\` (${sym.type}) @ ${sym.file}:${sym.line}`);
|
|
319
349
|
}
|
|
320
350
|
if (addedSymbols.length > 15) {
|
|
321
|
-
|
|
351
|
+
addLines.push(` _...and ${addedSymbols.length - 15} more_`);
|
|
322
352
|
}
|
|
323
|
-
|
|
353
|
+
addLines.push("");
|
|
324
354
|
if (duplicateCandidates.length > 0) {
|
|
325
|
-
|
|
355
|
+
addLines.push("### ⚠️ Possible duplicates");
|
|
326
356
|
for (const dup of duplicateCandidates) {
|
|
327
|
-
|
|
357
|
+
addLines.push(`- **${dup.added.name}** added in \`${dup.added.file}\` — already exists in:`);
|
|
328
358
|
for (const s of dup.similar.slice(0, 3)) {
|
|
329
|
-
|
|
359
|
+
addLines.push(` · ${s.file}:${s.line}`);
|
|
330
360
|
}
|
|
331
361
|
}
|
|
332
|
-
|
|
362
|
+
addLines.push("");
|
|
333
363
|
}
|
|
364
|
+
if (!addSection(addLines.join("\n")))
|
|
365
|
+
return sections.join("\n");
|
|
334
366
|
}
|
|
335
367
|
// Modified files with high impact (> 3 importers)
|
|
336
368
|
const highImpactFiles = Array.from(fileImpact.entries())
|
|
337
369
|
.filter(([, v]) => v.importers >= 3)
|
|
338
370
|
.sort((a, b) => b[1].importers - a[1].importers);
|
|
339
371
|
if (highImpactFiles.length > 0) {
|
|
340
|
-
|
|
341
|
-
|
|
372
|
+
const hiLines = [];
|
|
373
|
+
hiLines.push("## High-impact modifications");
|
|
374
|
+
hiLines.push("_These files are imported by many others — changes cascade widely._");
|
|
342
375
|
for (const [path, impact] of highImpactFiles.slice(0, 10)) {
|
|
343
|
-
|
|
376
|
+
hiLines.push(`- \`${path}\` ← ${impact.importers} importer${impact.importers === 1 ? "" : "s"}`);
|
|
344
377
|
}
|
|
345
|
-
|
|
378
|
+
hiLines.push("");
|
|
379
|
+
if (!addSection(hiLines.join("\n")))
|
|
380
|
+
return sections.join("\n");
|
|
346
381
|
}
|
|
347
382
|
// Structural heuristic findings (unguarded stream calls, etc.)
|
|
348
383
|
if (heuristicFindings.length > 0) {
|
|
349
|
-
|
|
350
|
-
|
|
384
|
+
const hLines = [];
|
|
385
|
+
hLines.push("## ⚠️ Structural warnings");
|
|
386
|
+
hLines.push("_These are heuristic matches over the diff text. Some may be false positives; " +
|
|
351
387
|
"each finding carries a short explanation so you can triage quickly._");
|
|
352
|
-
// Group by heuristic so the reviewer can judge each class at a glance.
|
|
353
388
|
const grouped = new Map();
|
|
354
389
|
for (const f of heuristicFindings) {
|
|
355
390
|
const arr = grouped.get(f.heuristic) || [];
|
|
@@ -357,42 +392,42 @@ export function handleReviewDiff(indexer, args) {
|
|
|
357
392
|
grouped.set(f.heuristic, arr);
|
|
358
393
|
}
|
|
359
394
|
for (const [heuristic, findings] of grouped) {
|
|
360
|
-
|
|
395
|
+
hLines.push(`### ${heuristic} (${findings.length})`);
|
|
361
396
|
for (const f of findings.slice(0, 6)) {
|
|
362
397
|
const badge = f.severity === "high" ? "🔴" : f.severity === "medium" ? "🟡" : "🟢";
|
|
363
|
-
|
|
364
|
-
|
|
398
|
+
hLines.push(`- ${badge} \`${f.file}:${f.line}\` — ${f.message}`);
|
|
399
|
+
hLines.push(` \`${f.snippet}\``);
|
|
365
400
|
}
|
|
366
401
|
if (findings.length > 6) {
|
|
367
|
-
|
|
402
|
+
hLines.push(` _...and ${findings.length - 6} more_`);
|
|
368
403
|
}
|
|
369
404
|
}
|
|
370
|
-
|
|
405
|
+
hLines.push("");
|
|
406
|
+
if (!addSection(hLines.join("\n")))
|
|
407
|
+
return sections.join("\n");
|
|
371
408
|
}
|
|
372
409
|
// Recommendations
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
410
|
+
{
|
|
411
|
+
const recLines = [];
|
|
412
|
+
recLines.push("## Suggested next checks");
|
|
413
|
+
if (removedSymbols.length > 0) {
|
|
414
|
+
const dangerNames = removedSymbols
|
|
415
|
+
.filter((s) => (danglingRefs.get(s.name)?.count ?? 0) > 0)
|
|
416
|
+
.map((s) => s.name);
|
|
417
|
+
if (dangerNames.length > 0) {
|
|
418
|
+
recLines.push(`- Run \`sverklo_impact symbol:"${dangerNames[0]}"\` to see all callers of removed symbols`);
|
|
419
|
+
}
|
|
380
420
|
}
|
|
421
|
+
if (modifiedFiles.length > 0) {
|
|
422
|
+
recLines.push(`- Run \`sverklo_diff_search query:"..."\` to search semantically within these files`);
|
|
423
|
+
}
|
|
424
|
+
if (addedSymbols.length > 0 && duplicateCandidates.length === 0) {
|
|
425
|
+
recLines.push(`- New symbols look unique — no duplication detected against indexed code`);
|
|
426
|
+
}
|
|
427
|
+
recLines.push(`- For exact-match checks, fall back to \`grep -r 'symbol' .\``);
|
|
428
|
+
addSection(recLines.join("\n"));
|
|
381
429
|
}
|
|
382
|
-
|
|
383
|
-
parts.push(`- Run \`sverklo_diff_search query:"..."\` to search semantically within these files`);
|
|
384
|
-
}
|
|
385
|
-
if (addedSymbols.length > 0 && duplicateCandidates.length === 0) {
|
|
386
|
-
parts.push(`- New symbols look unique — no duplication detected against indexed code`);
|
|
387
|
-
}
|
|
388
|
-
parts.push(`- For exact-match checks, fall back to \`grep -r 'symbol' .\``);
|
|
389
|
-
let output = parts.join("\n");
|
|
390
|
-
// Enforce token budget
|
|
391
|
-
const maxChars = tokenBudget * 3.5;
|
|
392
|
-
if (output.length > maxChars) {
|
|
393
|
-
output = output.slice(0, maxChars) + "\n\n_[truncated to fit token budget]_";
|
|
394
|
-
}
|
|
395
|
-
return output;
|
|
430
|
+
return sections.join("\n");
|
|
396
431
|
}
|
|
397
432
|
// ─── git helpers ───
|
|
398
433
|
function getChangedFiles(rootPath, ref) {
|