projscan 1.4.0 → 1.6.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 +24 -7
- package/dist/cli/commands/applyFix.d.ts +7 -0
- package/dist/cli/commands/applyFix.js +113 -0
- package/dist/cli/commands/applyFix.js.map +1 -0
- package/dist/cli/commands/coverage.js +13 -0
- package/dist/cli/commands/coverage.js.map +1 -1
- package/dist/cli/commands/doctor.js +18 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/explain.js +1 -0
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/impact.js +25 -1
- package/dist/cli/commands/impact.js.map +1 -1
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.js +70 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/installHook.d.ts +9 -0
- package/dist/cli/commands/installHook.js +90 -0
- package/dist/cli/commands/installHook.js.map +1 -0
- package/dist/cli/commands/memory.d.ts +11 -0
- package/dist/cli/commands/memory.js +175 -0
- package/dist/cli/commands/memory.js.map +1 -0
- package/dist/cli/commands/taint.d.ts +6 -0
- package/dist/cli/commands/taint.js +74 -0
- package/dist/cli/commands/taint.js.map +1 -0
- package/dist/cli/commands/workspace.d.ts +11 -0
- package/dist/cli/commands/workspace.js +115 -0
- package/dist/cli/commands/workspace.js.map +1 -0
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/applyFix.d.ts +52 -0
- package/dist/core/applyFix.js +220 -0
- package/dist/core/applyFix.js.map +1 -0
- package/dist/core/ast.d.ts +9 -0
- package/dist/core/ast.js +35 -4
- package/dist/core/ast.js.map +1 -1
- package/dist/core/codeGraph.js +190 -241
- package/dist/core/codeGraph.js.map +1 -1
- package/dist/core/fileInspector.js +40 -44
- package/dist/core/fileInspector.js.map +1 -1
- package/dist/core/fixSuggest.d.ts +6 -0
- package/dist/core/fixSuggest.js +195 -0
- package/dist/core/fixSuggest.js.map +1 -1
- package/dist/core/hotspotAnalyzer.js +65 -19
- package/dist/core/hotspotAnalyzer.js.map +1 -1
- package/dist/core/impact.d.ts +8 -0
- package/dist/core/impact.js +41 -3
- package/dist/core/impact.js.map +1 -1
- package/dist/core/indexCache.js +4 -1
- package/dist/core/indexCache.js.map +1 -1
- package/dist/core/issueEngine.js +24 -0
- package/dist/core/issueEngine.js.map +1 -1
- package/dist/core/languages/csharpImports.js +6 -4
- package/dist/core/languages/csharpImports.js.map +1 -1
- package/dist/core/memory.d.ts +154 -0
- package/dist/core/memory.js +277 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/review.d.ts +25 -1
- package/dist/core/review.js +133 -2
- package/dist/core/review.js.map +1 -1
- package/dist/core/taint.d.ts +91 -0
- package/dist/core/taint.js +185 -0
- package/dist/core/taint.js.map +1 -0
- package/dist/core/workspace.d.ts +62 -0
- package/dist/core/workspace.js +127 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/mcp/prompts.js +274 -0
- package/dist/mcp/prompts.js.map +1 -1
- package/dist/mcp/server.js +162 -146
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tokenBudget.d.ts +22 -0
- package/dist/mcp/tokenBudget.js +26 -0
- package/dist/mcp/tokenBudget.js.map +1 -1
- package/dist/mcp/tools/applyFix.d.ts +16 -0
- package/dist/mcp/tools/applyFix.js +91 -0
- package/dist/mcp/tools/applyFix.js.map +1 -0
- package/dist/mcp/tools/doctor.js +65 -2
- package/dist/mcp/tools/doctor.js.map +1 -1
- package/dist/mcp/tools/explain.js +4 -3
- package/dist/mcp/tools/explain.js.map +1 -1
- package/dist/mcp/tools/explainIssue.js +3 -2
- package/dist/mcp/tools/explainIssue.js.map +1 -1
- package/dist/mcp/tools/file.js +3 -2
- package/dist/mcp/tools/file.js.map +1 -1
- package/dist/mcp/tools/graph.js +16 -11
- package/dist/mcp/tools/graph.js.map +1 -1
- package/dist/mcp/tools/impact.js +36 -3
- package/dist/mcp/tools/impact.js.map +1 -1
- package/dist/mcp/tools/memory.d.ts +19 -0
- package/dist/mcp/tools/memory.js +134 -0
- package/dist/mcp/tools/memory.js.map +1 -0
- package/dist/mcp/tools/review.js +25 -4
- package/dist/mcp/tools/review.js.map +1 -1
- package/dist/mcp/tools/taint.d.ts +15 -0
- package/dist/mcp/tools/taint.js +67 -0
- package/dist/mcp/tools/taint.js.map +1 -0
- package/dist/mcp/tools/upgrade.js +3 -2
- package/dist/mcp/tools/upgrade.js.map +1 -1
- package/dist/mcp/tools/workspaceGraph.d.ts +18 -0
- package/dist/mcp/tools/workspaceGraph.js +188 -0
- package/dist/mcp/tools/workspaceGraph.js.map +1 -0
- package/dist/mcp/tools.js +8 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reporters/consoleReporter.d.ts +12 -1
- package/dist/reporters/consoleReporter.js +289 -179
- package/dist/reporters/consoleReporter.js.map +1 -1
- package/dist/reporters/markdownReporter.js +185 -128
- package/dist/reporters/markdownReporter.js.map +1 -1
- package/dist/tool-manifest.json +129 -6
- package/dist/types.d.ts +67 -0
- package/dist/utils/config.js +93 -53
- package/dist/utils/config.js.map +1 -1
- package/package.json +9 -2
package/dist/mcp/tools/doctor.js
CHANGED
|
@@ -4,11 +4,15 @@ import { calculateScore } from '../../utils/scoreCalculator.js';
|
|
|
4
4
|
import { PACKAGE_ARG_SCHEMA, resolvePackageFilter } from './_shared.js';
|
|
5
5
|
export const doctorTool = {
|
|
6
6
|
name: 'projscan_doctor',
|
|
7
|
-
description: 'Run a health check on the project. Returns a 0-100 score, letter grade, and the list of issues (linting, formatting, tests, security, architecture).',
|
|
7
|
+
description: 'Run a health check on the project. Returns a 0-100 score, letter grade, and the list of issues (linting, formatting, tests, security, architecture). Pass `max_cost_tokens` (1.5+) for adaptive shaping: <3000 returns verdict-only (score + counts), <7000 returns a summary (top issues), otherwise full.',
|
|
8
8
|
inputSchema: {
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
11
11
|
package: PACKAGE_ARG_SCHEMA,
|
|
12
|
+
max_cost_tokens: {
|
|
13
|
+
type: 'number',
|
|
14
|
+
description: '1.5+ — adaptive shape budget. <3000 returns verdict-only (score + grade + per-severity counts); <7000 returns a summary (top-5 issues by severity, no descriptions); otherwise the full issue list. Different from `max_tokens` (post-hoc truncation): the tool reshapes BEFORE serializing.',
|
|
15
|
+
},
|
|
12
16
|
},
|
|
13
17
|
},
|
|
14
18
|
handler: async (args, rootPath) => {
|
|
@@ -24,7 +28,66 @@ export const doctorTool = {
|
|
|
24
28
|
});
|
|
25
29
|
}
|
|
26
30
|
const health = calculateScore(issues);
|
|
27
|
-
|
|
31
|
+
// 1.5+ — adaptive shape based on max_cost_tokens. With no budget,
|
|
32
|
+
// returns the full report unchanged (preserves 1.4-and-earlier
|
|
33
|
+
// shape; no `tier` field). With a budget, picks a tier and shapes
|
|
34
|
+
// — `tier` is surfaced and lifted into _cost.tier by the dispatcher.
|
|
35
|
+
const maxCostTokens = typeof args.max_cost_tokens === 'number' && Number.isFinite(args.max_cost_tokens)
|
|
36
|
+
? args.max_cost_tokens
|
|
37
|
+
: undefined;
|
|
38
|
+
if (maxCostTokens === undefined)
|
|
39
|
+
return { health, issues };
|
|
40
|
+
return shapeDoctorForBudget(health, issues, maxCostTokens);
|
|
28
41
|
},
|
|
29
42
|
};
|
|
43
|
+
function selectDoctorTier(maxCostTokens) {
|
|
44
|
+
if (!Number.isFinite(maxCostTokens) || maxCostTokens <= 0)
|
|
45
|
+
return 'full';
|
|
46
|
+
if (maxCostTokens < 3000)
|
|
47
|
+
return 'verdict-only';
|
|
48
|
+
if (maxCostTokens < 7000)
|
|
49
|
+
return 'summary';
|
|
50
|
+
return 'full';
|
|
51
|
+
}
|
|
52
|
+
function shapeDoctorForBudget(health, issues, maxCostTokens) {
|
|
53
|
+
const tier = selectDoctorTier(maxCostTokens);
|
|
54
|
+
const counts = countBySeverityAndCategory(issues);
|
|
55
|
+
if (tier === 'verdict-only') {
|
|
56
|
+
return { health, counts, tier };
|
|
57
|
+
}
|
|
58
|
+
if (tier === 'summary') {
|
|
59
|
+
// Top 5 of each severity, with the heavy `description` and
|
|
60
|
+
// `locations` fields stripped.
|
|
61
|
+
const top = (sev) => issues
|
|
62
|
+
.filter((i) => i.severity === sev)
|
|
63
|
+
.slice(0, 5)
|
|
64
|
+
.map((i) => ({ id: i.id, title: i.title, severity: i.severity, category: i.category }));
|
|
65
|
+
return {
|
|
66
|
+
health,
|
|
67
|
+
counts,
|
|
68
|
+
topIssues: {
|
|
69
|
+
error: top('error'),
|
|
70
|
+
warning: top('warning'),
|
|
71
|
+
info: top('info'),
|
|
72
|
+
},
|
|
73
|
+
tier,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return { health, issues, counts, tier };
|
|
77
|
+
}
|
|
78
|
+
function countBySeverityAndCategory(issues) {
|
|
79
|
+
const bySeverity = { error: 0, warning: 0, info: 0 };
|
|
80
|
+
const byCategory = {};
|
|
81
|
+
for (const i of issues) {
|
|
82
|
+
if (i.severity === 'error')
|
|
83
|
+
bySeverity.error += 1;
|
|
84
|
+
else if (i.severity === 'warning')
|
|
85
|
+
bySeverity.warning += 1;
|
|
86
|
+
else if (i.severity === 'info')
|
|
87
|
+
bySeverity.info += 1;
|
|
88
|
+
const cat = i.category ?? 'other';
|
|
89
|
+
byCategory[cat] = (byCategory[cat] ?? 0) + 1;
|
|
90
|
+
}
|
|
91
|
+
return { bySeverity, byCategory };
|
|
92
|
+
}
|
|
30
93
|
//# sourceMappingURL=doctor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/mcp/tools/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAgB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/mcp/tools/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,12 +16,13 @@ export const explainTool = {
|
|
|
16
16
|
},
|
|
17
17
|
handler: async (args, rootPath) => {
|
|
18
18
|
const rel = typeof args.file === 'string' ? args.file : '';
|
|
19
|
-
if (!rel)
|
|
20
|
-
throw new Error('file argument is required');
|
|
19
|
+
if (!rel) {
|
|
20
|
+
throw new Error('file argument is required: pass a repo-relative path (e.g. "src/auth.ts").');
|
|
21
|
+
}
|
|
21
22
|
const absolutePath = path.resolve(rootPath, rel);
|
|
22
23
|
const resolvedRoot = path.resolve(rootPath);
|
|
23
24
|
if (!absolutePath.startsWith(resolvedRoot + path.sep) && absolutePath !== resolvedRoot) {
|
|
24
|
-
throw new Error(
|
|
25
|
+
throw new Error(`file must be inside the project root (got "${rel}"; absolute or "../" paths are rejected for security).`);
|
|
25
26
|
}
|
|
26
27
|
const content = await fs.readFile(absolutePath, 'utf-8');
|
|
27
28
|
return explainFile(absolutePath, content, rootPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/mcp/tools/explain.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,kIAAkI;IACpI,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/mcp/tools/explain.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AAEzD,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACT,kIAAkI;IACpI,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,4EAA4E,CAC7E,CAAC;QACJ,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACjD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC5C,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY,KAAK,YAAY,EAAE,CAAC;YACvF,MAAM,IAAI,KAAK,CACb,8CAA8C,GAAG,wDAAwD,CAC1G,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACzD,OAAO,WAAW,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;CACF,CAAC"}
|
|
@@ -16,8 +16,9 @@ export const explainIssueTool = {
|
|
|
16
16
|
},
|
|
17
17
|
handler: async (args, rootPath) => {
|
|
18
18
|
const issueId = typeof args.issue_id === 'string' ? args.issue_id : '';
|
|
19
|
-
if (!issueId)
|
|
20
|
-
throw new Error('issue_id is required');
|
|
19
|
+
if (!issueId) {
|
|
20
|
+
throw new Error('issue_id is required. Get one from projscan_doctor or projscan_analyze (each issue has an `id` field).');
|
|
21
|
+
}
|
|
21
22
|
const scan = await scanRepository(rootPath);
|
|
22
23
|
const issues = await collectIssues(rootPath, scan.files);
|
|
23
24
|
const explanation = await explainIssue(rootPath, issues, issueId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explainIssue.js","sourceRoot":"","sources":["../../../src/mcp/tools/explainIssue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,CAAC,MAAM,gBAAgB,GAAY;IACvC,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EACT,0TAA0T;IAC5T,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uEAAuE;aACrF;SACF;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,OAAO;
|
|
1
|
+
{"version":3,"file":"explainIssue.js","sourceRoot":"","sources":["../../../src/mcp/tools/explainIssue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,MAAM,CAAC,MAAM,gBAAgB,GAAY;IACvC,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EACT,0TAA0T;IAC5T,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,uEAAuE;aACrF;SACF;QACD,QAAQ,EAAE,CAAC,UAAU,CAAC;KACvB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,wGAAwG,CACzG,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,0BAA0B,OAAO,0BAA0B,EAAE,CAAC;QACjG,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IACxC,CAAC;CACF,CAAC"}
|
package/dist/mcp/tools/file.js
CHANGED
|
@@ -14,8 +14,9 @@ export const fileTool = {
|
|
|
14
14
|
},
|
|
15
15
|
handler: async (args, rootPath) => {
|
|
16
16
|
const rel = typeof args.file === 'string' ? args.file : '';
|
|
17
|
-
if (!rel)
|
|
18
|
-
throw new Error('file argument is required');
|
|
17
|
+
if (!rel) {
|
|
18
|
+
throw new Error('file argument is required: pass a repo-relative path (e.g. "src/auth.ts"). Use projscan_search { scope: "files" } to find one.');
|
|
19
|
+
}
|
|
19
20
|
return await inspectFile(rootPath, rel);
|
|
20
21
|
},
|
|
21
22
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/mcp/tools/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAG1D,MAAM,CAAC,MAAM,QAAQ,GAAY;IAC/B,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,2RAA2R;IAC7R,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,GAAG;
|
|
1
|
+
{"version":3,"file":"file.js","sourceRoot":"","sources":["../../../src/mcp/tools/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAG1D,MAAM,CAAC,MAAM,QAAQ,GAAY;IAC/B,IAAI,EAAE,eAAe;IACrB,WAAW,EACT,2RAA2R;IAC7R,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;SACF;QACD,QAAQ,EAAE,CAAC,MAAM,CAAC;KACnB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,gIAAgI,CACjI,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,WAAW,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;CACF,CAAC"}
|
package/dist/mcp/tools/graph.js
CHANGED
|
@@ -36,33 +36,38 @@ export const graphTool = {
|
|
|
36
36
|
const limit = Math.max(1, Math.min(500, typeof args.limit === 'number' ? args.limit : 50));
|
|
37
37
|
switch (direction) {
|
|
38
38
|
case 'imports': {
|
|
39
|
-
if (!file)
|
|
40
|
-
throw new Error('file argument
|
|
39
|
+
if (!file) {
|
|
40
|
+
throw new Error('direction=imports requires a `file` argument (repo-relative path, e.g. "src/auth.ts").');
|
|
41
|
+
}
|
|
41
42
|
return { file, imports: importsOf(graph, file).slice(0, limit) };
|
|
42
43
|
}
|
|
43
44
|
case 'exports': {
|
|
44
|
-
if (!file)
|
|
45
|
-
throw new Error('file argument
|
|
45
|
+
if (!file) {
|
|
46
|
+
throw new Error('direction=exports requires a `file` argument (repo-relative path).');
|
|
47
|
+
}
|
|
46
48
|
return { file, exports: exportsOf(graph, file).slice(0, limit) };
|
|
47
49
|
}
|
|
48
50
|
case 'importers': {
|
|
49
|
-
if (!file)
|
|
50
|
-
throw new Error('file argument
|
|
51
|
+
if (!file) {
|
|
52
|
+
throw new Error('direction=importers requires a `file` argument (repo-relative path).');
|
|
53
|
+
}
|
|
51
54
|
return { file, importers: filesImportingFile(graph, file).slice(0, limit) };
|
|
52
55
|
}
|
|
53
56
|
case 'symbol_defs': {
|
|
54
|
-
if (!symbol)
|
|
55
|
-
throw new Error('symbol argument
|
|
57
|
+
if (!symbol) {
|
|
58
|
+
throw new Error('direction=symbol_defs requires a `symbol` argument (the exported name to look up, e.g. "authenticate").');
|
|
59
|
+
}
|
|
56
60
|
return { symbol, definedIn: filesDefiningSymbol(graph, symbol).slice(0, limit) };
|
|
57
61
|
}
|
|
58
62
|
case 'package_importers': {
|
|
59
63
|
const pkg = symbol ?? file;
|
|
60
|
-
if (!pkg)
|
|
61
|
-
throw new Error('symbol
|
|
64
|
+
if (!pkg) {
|
|
65
|
+
throw new Error('direction=package_importers requires either `symbol` or `file` arg (the npm package name, e.g. "chalk").');
|
|
66
|
+
}
|
|
62
67
|
return { package: pkg, importers: filesImportingPackage(graph, pkg).slice(0, limit) };
|
|
63
68
|
}
|
|
64
69
|
default:
|
|
65
|
-
throw new Error(`unknown direction
|
|
70
|
+
throw new Error(`unknown direction "${direction}". Valid: imports, exports, importers, symbol_defs, package_importers.`);
|
|
66
71
|
}
|
|
67
72
|
},
|
|
68
73
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/mcp/tools/graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,SAAS,EACT,SAAS,GACV,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG5E,MAAM,CAAC,MAAM,SAAS,GAAY;IAChC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EACT,2PAA2P;IAC7P,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,gDAAgD;aAC9D;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,2GAA2G;aACzH;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,WAAW,EACT,+NAA+N;gBACjO,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,mBAAmB,CAAC;aAC9E;YACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oCAAoC,EAAE;YAC5E,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+CAA+C,EAAE;SAC7F;QACD,QAAQ,EAAE,CAAC,WAAW,CAAC;KACxB;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,MAAM,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAEvC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAE3F,QAAQ,SAAS,EAAE,CAAC;YAClB,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,IAAI,CAAC,IAAI;
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../../src/mcp/tools/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/tools/impact.js
CHANGED
|
@@ -2,6 +2,7 @@ import { scanRepository } from '../../core/repositoryScanner.js';
|
|
|
2
2
|
import { buildCodeGraph } from '../../core/codeGraph.js';
|
|
3
3
|
import { loadCachedGraph, saveCachedGraph } from '../../core/indexCache.js';
|
|
4
4
|
import { computeImpact } from '../../core/impact.js';
|
|
5
|
+
import { loadWorkspace } from '../../core/workspace.js';
|
|
5
6
|
import { paginate, listChecksum, readPageParams } from '../pagination.js';
|
|
6
7
|
import { emitProgress } from '../progress.js';
|
|
7
8
|
export const impactTool = {
|
|
@@ -22,6 +23,10 @@ export const impactTool = {
|
|
|
22
23
|
type: 'number',
|
|
23
24
|
description: 'Maximum BFS hops from the target. Default 10. Reports `truncated: true` when exceeded.',
|
|
24
25
|
},
|
|
26
|
+
cross_repo: {
|
|
27
|
+
type: 'boolean',
|
|
28
|
+
description: '1.6+ — when true, also fold in callers from sibling repos registered via `projscan workspace add`. Each cross-repo file is annotated with its repo name. Symbol-mode only; file-mode cross-repo requires path resolution that this first cut does not perform.',
|
|
29
|
+
},
|
|
25
30
|
cursor: { type: 'string', description: 'Opaque cursor from a previous response.' },
|
|
26
31
|
page_size: { type: 'number', description: 'Items per page (default 50, max 500).' },
|
|
27
32
|
max_tokens: { type: 'number', description: 'Cap response to roughly this many tokens.' },
|
|
@@ -31,10 +36,10 @@ export const impactTool = {
|
|
|
31
36
|
const file = typeof args.file === 'string' && args.file.length > 0 ? args.file : null;
|
|
32
37
|
const symbol = typeof args.symbol === 'string' && args.symbol.length > 0 ? args.symbol : null;
|
|
33
38
|
if (!file && !symbol) {
|
|
34
|
-
throw new Error('
|
|
39
|
+
throw new Error('projscan_impact needs exactly one of `file` (a repo-relative path) or `symbol` (an exported name). Pass `file` for "what files transitively import this?" and `symbol` for "what calls this exported name?"');
|
|
35
40
|
}
|
|
36
41
|
if (file && symbol) {
|
|
37
|
-
throw new Error('`file` and `symbol` are mutually exclusive
|
|
42
|
+
throw new Error('`file` and `symbol` are mutually exclusive — pass exactly one. Use `file` for file-level blast radius, `symbol` for symbol-level callers.');
|
|
38
43
|
}
|
|
39
44
|
const maxDistance = typeof args.max_distance === 'number' ? args.max_distance : undefined;
|
|
40
45
|
emitProgress(0, 3, 'scanning repository');
|
|
@@ -45,7 +50,12 @@ export const impactTool = {
|
|
|
45
50
|
await saveCachedGraph(rootPath, graph);
|
|
46
51
|
emitProgress(2, 3, 'computing impact');
|
|
47
52
|
const target = file ? { kind: 'file', value: file } : { kind: 'symbol', value: symbol };
|
|
48
|
-
const
|
|
53
|
+
const crossRepo = args.cross_repo === true;
|
|
54
|
+
const crossRepoGraphs = crossRepo ? await buildCrossRepoGraphs(rootPath) : undefined;
|
|
55
|
+
const report = computeImpact(graph, target, {
|
|
56
|
+
...(maxDistance !== undefined ? { maxDistance } : {}),
|
|
57
|
+
...(crossRepoGraphs ? { crossRepoGraphs } : {}),
|
|
58
|
+
});
|
|
49
59
|
const page = paginate(report.reachable, readPageParams(args), listChecksum(report.reachable));
|
|
50
60
|
emitProgress(3, 3, 'done');
|
|
51
61
|
return {
|
|
@@ -56,4 +66,27 @@ export const impactTool = {
|
|
|
56
66
|
};
|
|
57
67
|
},
|
|
58
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* 1.6+ — load the cross-repo workspace and build a CodeGraph for each
|
|
71
|
+
* registered sibling. Returns an empty Map if no workspace is
|
|
72
|
+
* registered or no siblings exist; the impact module handles that
|
|
73
|
+
* case as a no-op cross-repo fold.
|
|
74
|
+
*/
|
|
75
|
+
async function buildCrossRepoGraphs(rootPath) {
|
|
76
|
+
const out = new Map();
|
|
77
|
+
const workspace = await loadWorkspace(rootPath);
|
|
78
|
+
if (!workspace || workspace.repos.length === 0)
|
|
79
|
+
return out;
|
|
80
|
+
for (const repo of workspace.repos) {
|
|
81
|
+
try {
|
|
82
|
+
const scan = await scanRepository(repo.path);
|
|
83
|
+
const repoGraph = await buildCodeGraph(repo.path, scan.files);
|
|
84
|
+
out.set(repo.name, repoGraph);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Skip repos that fail to scan (transient I/O, missing dir, etc.).
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
59
92
|
//# sourceMappingURL=impact.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impact.js","sourceRoot":"","sources":["../../../src/mcp/tools/impact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"impact.js","sourceRoot":"","sources":["../../../src/mcp/tools/impact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { McpTool } from './_shared.js';
|
|
2
|
+
/**
|
|
3
|
+
* `projscan_memory` (1.5+) — surface the local Project Memory store
|
|
4
|
+
* so an agent (or the user via the CLI) can see which issues this
|
|
5
|
+
* project has been carrying across many runs and act on them.
|
|
6
|
+
*
|
|
7
|
+
* Subactions:
|
|
8
|
+
* - "current" (default): aggregate counts (total runs, rules tracked,
|
|
9
|
+
* stable-rule count, last update timestamp).
|
|
10
|
+
* - "stable": rules that have surfaced across enough runs over enough
|
|
11
|
+
* time to count as "user has accepted" — paired with a ready-to-paste
|
|
12
|
+
* `.projscanrc.disableRules` snippet.
|
|
13
|
+
* - "runs": every tracked rule with its observation history. Useful
|
|
14
|
+
* for debugging the memory's view of the project.
|
|
15
|
+
* - "forget": drop a single rule's history (requires `rule` arg).
|
|
16
|
+
*
|
|
17
|
+
* Read-only except `forget`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const memoryTool: McpTool;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { findAcceptedHotspots, findStableRules, forgetHotspot, forgetRule, loadMemory, saveMemory, } from '../../core/memory.js';
|
|
2
|
+
/**
|
|
3
|
+
* `projscan_memory` (1.5+) — surface the local Project Memory store
|
|
4
|
+
* so an agent (or the user via the CLI) can see which issues this
|
|
5
|
+
* project has been carrying across many runs and act on them.
|
|
6
|
+
*
|
|
7
|
+
* Subactions:
|
|
8
|
+
* - "current" (default): aggregate counts (total runs, rules tracked,
|
|
9
|
+
* stable-rule count, last update timestamp).
|
|
10
|
+
* - "stable": rules that have surfaced across enough runs over enough
|
|
11
|
+
* time to count as "user has accepted" — paired with a ready-to-paste
|
|
12
|
+
* `.projscanrc.disableRules` snippet.
|
|
13
|
+
* - "runs": every tracked rule with its observation history. Useful
|
|
14
|
+
* for debugging the memory's view of the project.
|
|
15
|
+
* - "forget": drop a single rule's history (requires `rule` arg).
|
|
16
|
+
*
|
|
17
|
+
* Read-only except `forget`.
|
|
18
|
+
*/
|
|
19
|
+
export const memoryTool = {
|
|
20
|
+
name: 'projscan_memory',
|
|
21
|
+
description: 'Inspect or prune the local Project Memory: which analyzer rules have been surfacing repeatedly without being addressed, and what to do about them. Use when an agent wants to know "what is this project tolerating and could quiet down via .projscanrc?"',
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
action: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: ['current', 'stable', 'runs', 'accepted', 'forget', 'forget-hotspot'],
|
|
28
|
+
description: 'Subaction. "current" returns aggregate counts. "stable" returns long-running rules with a config-snippet suggestion. "runs" returns every tracked rule. "accepted" (1.5+) returns files Project Memory marks as accepted load-bearing debt (top-K hotspot for ≥ 5 runs over ≥ 7 days without improving). "forget" drops one rule. "forget-hotspot" drops one file from hotspot memory.',
|
|
29
|
+
},
|
|
30
|
+
rule: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: '"forget" only — the rule id to drop from memory.',
|
|
33
|
+
},
|
|
34
|
+
file: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: '"forget-hotspot" only — the repo-relative path to drop from hotspot memory.',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
handler: async (args, rootPath) => {
|
|
41
|
+
const action = typeof args.action === 'string' ? args.action : 'current';
|
|
42
|
+
const memory = await loadMemory(rootPath);
|
|
43
|
+
switch (action) {
|
|
44
|
+
case 'current':
|
|
45
|
+
return summarize(memory);
|
|
46
|
+
case 'stable':
|
|
47
|
+
return stableView(memory);
|
|
48
|
+
case 'runs':
|
|
49
|
+
return runsView(memory);
|
|
50
|
+
case 'accepted':
|
|
51
|
+
return acceptedView(memory);
|
|
52
|
+
case 'forget': {
|
|
53
|
+
const rule = typeof args.rule === 'string' ? args.rule : '';
|
|
54
|
+
if (!rule)
|
|
55
|
+
throw new Error('forget action requires a "rule" argument');
|
|
56
|
+
const existed = forgetRule(memory, rule);
|
|
57
|
+
if (existed)
|
|
58
|
+
await saveMemory(rootPath, memory);
|
|
59
|
+
return { action: 'forget', rule, dropped: existed };
|
|
60
|
+
}
|
|
61
|
+
case 'forget-hotspot': {
|
|
62
|
+
const file = typeof args.file === 'string' ? args.file : '';
|
|
63
|
+
if (!file)
|
|
64
|
+
throw new Error('forget-hotspot action requires a "file" argument');
|
|
65
|
+
const existed = forgetHotspot(memory, file);
|
|
66
|
+
if (existed)
|
|
67
|
+
await saveMemory(rootPath, memory);
|
|
68
|
+
return { action: 'forget-hotspot', file, dropped: existed };
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unknown action "${action}". Valid actions: current, stable, runs, accepted, forget, forget-hotspot.`);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
function summarize(memory) {
|
|
76
|
+
const stableCount = findStableRules(memory).length;
|
|
77
|
+
const acceptedCount = findAcceptedHotspots(memory).length;
|
|
78
|
+
return {
|
|
79
|
+
schemaVersion: memory.schemaVersion,
|
|
80
|
+
totalRuns: memory.totalRuns,
|
|
81
|
+
rulesTracked: Object.keys(memory.rules).length,
|
|
82
|
+
hotspotsTracked: Object.keys(memory.hotspots ?? {}).length,
|
|
83
|
+
stableRuleCount: stableCount,
|
|
84
|
+
acceptedHotspotCount: acceptedCount,
|
|
85
|
+
lastUpdatedAt: memory.lastUpdatedAt,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function acceptedView(memory) {
|
|
89
|
+
const accepted = findAcceptedHotspots(memory);
|
|
90
|
+
return {
|
|
91
|
+
totalRuns: memory.totalRuns,
|
|
92
|
+
acceptedCount: accepted.length,
|
|
93
|
+
accepted: accepted.map((o) => ({
|
|
94
|
+
file: o.file,
|
|
95
|
+
runCount: o.runCount,
|
|
96
|
+
firstSeenAt: o.firstSeenAt,
|
|
97
|
+
lastSeenAt: o.lastSeenAt,
|
|
98
|
+
lastCc: o.lastCc,
|
|
99
|
+
lastChurn: o.lastChurn,
|
|
100
|
+
})),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function stableView(memory) {
|
|
104
|
+
const stable = findStableRules(memory);
|
|
105
|
+
// A ready-to-paste config snippet so the user can disable everything
|
|
106
|
+
// they've effectively accepted in one move.
|
|
107
|
+
const disableRulesSnippet = stable.length > 0
|
|
108
|
+
? {
|
|
109
|
+
disableRules: stable.map((r) => r.ruleId),
|
|
110
|
+
}
|
|
111
|
+
: undefined;
|
|
112
|
+
return {
|
|
113
|
+
totalRuns: memory.totalRuns,
|
|
114
|
+
stableCount: stable.length,
|
|
115
|
+
stable: stable.map((r) => ({
|
|
116
|
+
ruleId: r.ruleId,
|
|
117
|
+
runCount: r.runCount,
|
|
118
|
+
firstSeenAt: r.firstSeenAt,
|
|
119
|
+
lastSeenAt: r.lastSeenAt,
|
|
120
|
+
})),
|
|
121
|
+
...(disableRulesSnippet
|
|
122
|
+
? { configSuggestion: { '.projscanrc.json': disableRulesSnippet } }
|
|
123
|
+
: {}),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function runsView(memory) {
|
|
127
|
+
const all = Object.values(memory.rules).sort((a, b) => b.runCount - a.runCount);
|
|
128
|
+
return {
|
|
129
|
+
totalRuns: memory.totalRuns,
|
|
130
|
+
rulesTracked: all.length,
|
|
131
|
+
rules: all,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/mcp/tools/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/tools/review.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { computeReview } from '../../core/review.js';
|
|
1
|
+
import { computeReview, selectReviewTier, shapeReviewForTier } from '../../core/review.js';
|
|
2
2
|
import { detectWorkspaces, filterFilesByPackage } from '../../core/monorepo.js';
|
|
3
3
|
import { emitProgress } from '../progress.js';
|
|
4
4
|
export const reviewTool = {
|
|
5
5
|
name: 'projscan_review',
|
|
6
|
-
description: 'One-call PR review. Combines projscan_pr_diff + per-changed-file risk score + new/expanded import cycles + risky function additions + dependency changes, plus a verdict ("ok" | "review" | "block") with a one-line summary. Use when an agent is asked "is this PR safe to merge?" Defaults: base=origin/main (falls back to main/master/HEAD~1), head=HEAD.',
|
|
6
|
+
description: 'One-call PR review. Combines projscan_pr_diff + per-changed-file risk score + new/expanded import cycles + risky function additions + dependency changes, plus a verdict ("ok" | "review" | "block") with a one-line summary. Use when an agent is asked "is this PR safe to merge?" Defaults: base=origin/main (falls back to main/master/HEAD~1), head=HEAD. Pass `max_cost_tokens` (1.5+) to get a budget-shaped response: <3000 returns verdict-only, <7000 returns a summary, otherwise the full review.',
|
|
7
7
|
inputSchema: {
|
|
8
8
|
type: 'object',
|
|
9
9
|
properties: {
|
|
@@ -12,7 +12,14 @@ export const reviewTool = {
|
|
|
12
12
|
description: 'Base ref (branch, tag, sha). Default: origin/main, falling back to main/master/HEAD~1.',
|
|
13
13
|
},
|
|
14
14
|
head: { type: 'string', description: 'Head ref. Default: HEAD.' },
|
|
15
|
-
max_tokens: {
|
|
15
|
+
max_tokens: {
|
|
16
|
+
type: 'number',
|
|
17
|
+
description: 'Cap the response via post-hoc array trimming.',
|
|
18
|
+
},
|
|
19
|
+
max_cost_tokens: {
|
|
20
|
+
type: 'number',
|
|
21
|
+
description: '1.5+ — adaptive shape budget. Tool picks a tier based on this value: <3000 verdict-only, <7000 summary, otherwise full. Differs from `max_tokens` (post-hoc truncation): the tool reshapes the response BEFORE serializing, so an agent on a tight budget gets a response sized to fit instead of a truncated full one.',
|
|
22
|
+
},
|
|
16
23
|
package: {
|
|
17
24
|
type: 'string',
|
|
18
25
|
description: 'Optional. Workspace package name to scope all sections of the review to a single package.',
|
|
@@ -48,7 +55,21 @@ export const reviewTool = {
|
|
|
48
55
|
report.dependencyChanges = report.dependencyChanges.filter((d) => d.workspace === target);
|
|
49
56
|
}
|
|
50
57
|
emitProgress(4, 4, 'done');
|
|
51
|
-
|
|
58
|
+
// 1.5 — adaptive shape based on max_cost_tokens. With no budget,
|
|
59
|
+
// returns the full report unchanged. With a budget, picks a tier
|
|
60
|
+
// and reshapes — the response carries `tier` so the agent can
|
|
61
|
+
// detect what they got and re-call at a higher budget if needed.
|
|
62
|
+
const maxCostTokens = typeof args.max_cost_tokens === 'number' && Number.isFinite(args.max_cost_tokens)
|
|
63
|
+
? args.max_cost_tokens
|
|
64
|
+
: undefined;
|
|
65
|
+
const tier = selectReviewTier(maxCostTokens);
|
|
66
|
+
if (tier === 'full' && maxCostTokens === undefined) {
|
|
67
|
+
// Preserve existing 1.4-and-earlier shape (no `tier` field) when
|
|
68
|
+
// no budget was given. Adding the field unconditionally would be
|
|
69
|
+
// additive but slightly noisy on every call.
|
|
70
|
+
return report;
|
|
71
|
+
}
|
|
72
|
+
return shapeReviewForTier(report, tier);
|
|
52
73
|
},
|
|
53
74
|
};
|
|
54
75
|
//# sourceMappingURL=review.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/mcp/tools/review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/mcp/tools/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpTool } from './_shared.js';
|
|
2
|
+
/**
|
|
3
|
+
* `projscan_taint` (1.6+) — surface source-to-sink reachability flows
|
|
4
|
+
* over the per-function call graph. Sources (e.g. `process.env.X`,
|
|
5
|
+
* `req.body`) and sinks (e.g. `exec`, `eval`, `db.query`) come from a
|
|
6
|
+
* built-in default list; users add project-specific names via the
|
|
7
|
+
* `.projscanrc.json` `taint` block.
|
|
8
|
+
*
|
|
9
|
+
* The flow list is exact-match, dedup'd by (sourceFn, sinkFn). It does
|
|
10
|
+
* NOT track variable-level flow — if a function reads a source AND
|
|
11
|
+
* calls a sink (directly or transitively), it surfaces. False positives
|
|
12
|
+
* are expected for functions that launder taint safely; users can
|
|
13
|
+
* declare safe wrappers as sinks-with-disableRules.
|
|
14
|
+
*/
|
|
15
|
+
export declare const taintTool: McpTool;
|