purecontext-mcp 1.1.8 → 1.2.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/AGENT_INSTRUCTIONS.md +393 -0
- package/AGENT_INSTRUCTIONS_SHORT.md +53 -0
- package/AST-SEARCH.md +274 -0
- package/CHANGELOG.md +62 -0
- package/CODE-INTELLIGENCE.md +369 -0
- package/HEALTH-DASHBOARDS.md +241 -0
- package/README.md +7 -0
- package/REFACTORING-SAFELY.md +279 -0
- package/UNDERSTANDING-RELATIONSHIPS.md +240 -0
- package/USER-GUIDE.md +14 -0
- package/VISUALIZING-CODE.md +199 -0
- package/WORKFLOW-TECH-DEBT.md +286 -0
- package/dist/core/db/dep-store.d.ts +75 -0
- package/dist/core/db/dep-store.d.ts.map +1 -1
- package/dist/core/db/dep-store.js +277 -0
- package/dist/core/db/dep-store.js.map +1 -1
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +12 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/index-manager.js +1 -1
- package/dist/core/index-manager.js.map +1 -1
- package/dist/core/types.d.ts +5 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/graph/diagram-renderer.d.ts +83 -0
- package/dist/graph/diagram-renderer.d.ts.map +1 -0
- package/dist/graph/diagram-renderer.js +294 -0
- package/dist/graph/diagram-renderer.js.map +1 -0
- package/dist/graph/graph-traversal.d.ts +92 -0
- package/dist/graph/graph-traversal.d.ts.map +1 -1
- package/dist/graph/graph-traversal.js +440 -2
- package/dist/graph/graph-traversal.js.map +1 -1
- package/dist/server/mcp-server.d.ts.map +1 -1
- package/dist/server/mcp-server.js +145 -0
- package/dist/server/mcp-server.js.map +1 -1
- package/dist/server/tools/check-delete-safe.d.ts +50 -0
- package/dist/server/tools/check-delete-safe.d.ts.map +1 -0
- package/dist/server/tools/check-delete-safe.js +308 -0
- package/dist/server/tools/check-delete-safe.js.map +1 -0
- package/dist/server/tools/check-move-safe.d.ts +44 -0
- package/dist/server/tools/check-move-safe.d.ts.map +1 -0
- package/dist/server/tools/check-move-safe.js +266 -0
- package/dist/server/tools/check-move-safe.js.map +1 -0
- package/dist/server/tools/check-rename-safe.d.ts +48 -0
- package/dist/server/tools/check-rename-safe.d.ts.map +1 -0
- package/dist/server/tools/check-rename-safe.js +218 -0
- package/dist/server/tools/check-rename-safe.js.map +1 -0
- package/dist/server/tools/diff-health-radar.d.ts +44 -0
- package/dist/server/tools/diff-health-radar.d.ts.map +1 -0
- package/dist/server/tools/diff-health-radar.js +192 -0
- package/dist/server/tools/diff-health-radar.js.map +1 -0
- package/dist/server/tools/find-cycles.d.ts +31 -0
- package/dist/server/tools/find-cycles.d.ts.map +1 -0
- package/dist/server/tools/find-cycles.js +85 -0
- package/dist/server/tools/find-cycles.js.map +1 -0
- package/dist/server/tools/find-implementations.d.ts +47 -0
- package/dist/server/tools/find-implementations.d.ts.map +1 -0
- package/dist/server/tools/find-implementations.js +167 -0
- package/dist/server/tools/find-implementations.js.map +1 -0
- package/dist/server/tools/find-untested-symbols.d.ts +52 -0
- package/dist/server/tools/find-untested-symbols.d.ts.map +1 -0
- package/dist/server/tools/find-untested-symbols.js +308 -0
- package/dist/server/tools/find-untested-symbols.js.map +1 -0
- package/dist/server/tools/get-architecture-snapshot.d.ts +43 -0
- package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -0
- package/dist/server/tools/get-architecture-snapshot.js +292 -0
- package/dist/server/tools/get-architecture-snapshot.js.map +1 -0
- package/dist/server/tools/get-call-hierarchy.d.ts +43 -0
- package/dist/server/tools/get-call-hierarchy.d.ts.map +1 -0
- package/dist/server/tools/get-call-hierarchy.js +119 -0
- package/dist/server/tools/get-call-hierarchy.js.map +1 -0
- package/dist/server/tools/get-class-hierarchy.d.ts +36 -0
- package/dist/server/tools/get-class-hierarchy.d.ts.map +1 -0
- package/dist/server/tools/get-class-hierarchy.js +125 -0
- package/dist/server/tools/get-class-hierarchy.js.map +1 -0
- package/dist/server/tools/get-complexity-hotspots.d.ts +50 -0
- package/dist/server/tools/get-complexity-hotspots.d.ts.map +1 -0
- package/dist/server/tools/get-complexity-hotspots.js +282 -0
- package/dist/server/tools/get-complexity-hotspots.js.map +1 -0
- package/dist/server/tools/get-coupling-map.d.ts +39 -0
- package/dist/server/tools/get-coupling-map.d.ts.map +1 -0
- package/dist/server/tools/get-coupling-map.js +107 -0
- package/dist/server/tools/get-coupling-map.js.map +1 -0
- package/dist/server/tools/get-debt-report.d.ts +44 -0
- package/dist/server/tools/get-debt-report.d.ts.map +1 -0
- package/dist/server/tools/get-debt-report.js +606 -0
- package/dist/server/tools/get-debt-report.js.map +1 -0
- package/dist/server/tools/get-entry-points.d.ts +79 -0
- package/dist/server/tools/get-entry-points.d.ts.map +1 -0
- package/dist/server/tools/get-entry-points.js +362 -0
- package/dist/server/tools/get-entry-points.js.map +1 -0
- package/dist/server/tools/get-public-api.d.ts +53 -0
- package/dist/server/tools/get-public-api.d.ts.map +1 -0
- package/dist/server/tools/get-public-api.js +218 -0
- package/dist/server/tools/get-public-api.js.map +1 -0
- package/dist/server/tools/get-test-coverage-map.d.ts +66 -0
- package/dist/server/tools/get-test-coverage-map.d.ts.map +1 -0
- package/dist/server/tools/get-test-coverage-map.js +588 -0
- package/dist/server/tools/get-test-coverage-map.js.map +1 -0
- package/dist/server/tools/get-todos.d.ts +51 -0
- package/dist/server/tools/get-todos.d.ts.map +1 -0
- package/dist/server/tools/get-todos.js +180 -0
- package/dist/server/tools/get-todos.js.map +1 -0
- package/dist/server/tools/get-type-graph.d.ts +73 -0
- package/dist/server/tools/get-type-graph.d.ts.map +1 -0
- package/dist/server/tools/get-type-graph.js +437 -0
- package/dist/server/tools/get-type-graph.js.map +1 -0
- package/dist/server/tools/health-radar.d.ts +50 -0
- package/dist/server/tools/health-radar.d.ts.map +1 -0
- package/dist/server/tools/health-radar.js +426 -0
- package/dist/server/tools/health-radar.js.map +1 -0
- package/dist/server/tools/plan-refactoring.d.ts +74 -0
- package/dist/server/tools/plan-refactoring.d.ts.map +1 -0
- package/dist/server/tools/plan-refactoring.js +644 -0
- package/dist/server/tools/plan-refactoring.js.map +1 -0
- package/dist/server/tools/render-call-graph.d.ts +40 -0
- package/dist/server/tools/render-call-graph.d.ts.map +1 -0
- package/dist/server/tools/render-call-graph.js +215 -0
- package/dist/server/tools/render-call-graph.js.map +1 -0
- package/dist/server/tools/render-class-hierarchy.d.ts +42 -0
- package/dist/server/tools/render-class-hierarchy.d.ts.map +1 -0
- package/dist/server/tools/render-class-hierarchy.js +265 -0
- package/dist/server/tools/render-class-hierarchy.js.map +1 -0
- package/dist/server/tools/render-dep-matrix.d.ts +38 -0
- package/dist/server/tools/render-dep-matrix.d.ts.map +1 -0
- package/dist/server/tools/render-dep-matrix.js +186 -0
- package/dist/server/tools/render-dep-matrix.js.map +1 -0
- package/dist/server/tools/render-diagram.d.ts +47 -0
- package/dist/server/tools/render-diagram.d.ts.map +1 -0
- package/dist/server/tools/render-diagram.js +266 -0
- package/dist/server/tools/render-diagram.js.map +1 -0
- package/dist/server/tools/render-import-graph.d.ts +41 -0
- package/dist/server/tools/render-import-graph.d.ts.map +1 -0
- package/dist/server/tools/render-import-graph.js +158 -0
- package/dist/server/tools/render-import-graph.js.map +1 -0
- package/dist/server/tools/search-ast.d.ts +55 -0
- package/dist/server/tools/search-ast.d.ts.map +1 -0
- package/dist/server/tools/search-ast.js +279 -0
- package/dist/server/tools/search-ast.js.map +1 -0
- package/dist/server/tools/search-by-complexity.d.ts +92 -0
- package/dist/server/tools/search-by-complexity.d.ts.map +1 -0
- package/dist/server/tools/search-by-complexity.js +268 -0
- package/dist/server/tools/search-by-complexity.js.map +1 -0
- package/dist/server/tools/search-by-decorator.d.ts +48 -0
- package/dist/server/tools/search-by-decorator.d.ts.map +1 -0
- package/dist/server/tools/search-by-decorator.js +518 -0
- package/dist/server/tools/search-by-decorator.js.map +1 -0
- package/dist/server/tools/search-by-signature.d.ts +56 -0
- package/dist/server/tools/search-by-signature.d.ts.map +1 -0
- package/dist/server/tools/search-by-signature.js +200 -0
- package/dist/server/tools/search-by-signature.js.map +1 -0
- package/dist/ui/assets/BlastRadius-QdgESOL8.js +1 -0
- package/dist/ui/assets/{DependencyGraph-B60SMPbX.js → DependencyGraph-BSMhzwWV.js} +1 -1
- package/dist/ui/assets/{NotFound-Bsg8Wppk.js → NotFound-CipFP_s1.js} +1 -1
- package/dist/ui/assets/{RepoDetail-Cie0D4_s.js → RepoDetail-Dfp5z5Kq.js} +1 -1
- package/dist/ui/assets/{RepoList-CldNt89M.js → RepoList-BKtST3hB.js} +1 -1
- package/dist/ui/assets/{Search-CgvpHMOi.js → Search-DzhGDViy.js} +1 -1
- package/dist/ui/assets/{SymbolView-B9h0LZTz.js → SymbolView-ryVEwAHG.js} +1 -1
- package/dist/ui/assets/{index-DADf5y_L.css → index-Ny8gn9F0.css} +1 -1
- package/dist/ui/assets/{index-eK0wMkUR.js → index-nX2chMqi.js} +2 -2
- package/dist/ui/assets/{useSearch-KAl3Qyi2.js → useSearch-BnBCRKui.js} +1 -1
- package/dist/ui/index.html +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/dev/jcodemunch-gap-analysis.md +198 -0
- package/package.json +9 -1
- package/user-manual.md +2466 -0
- package/dist/ui/assets/BlastRadius-RP7vJEyQ.js +0 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-move-safe.ts
|
|
3
|
+
*
|
|
4
|
+
* MCP tool: check_move_safe
|
|
5
|
+
*
|
|
6
|
+
* Pre-flight check for moving a file to a new location. Returns:
|
|
7
|
+
* - All import statements that need updating (importUpdates), with exact
|
|
8
|
+
* current and new paths, plus the line number of each import.
|
|
9
|
+
* - Whether the move would introduce import cycles at the new location
|
|
10
|
+
* (wouldIntroduceCycles).
|
|
11
|
+
*
|
|
12
|
+
* Safety definition:
|
|
13
|
+
* safe: false — if the move would place the file in an existing import cycle
|
|
14
|
+
* (the cycle moves with the file to its new location).
|
|
15
|
+
* safe: true — if all affected imports can be updated mechanically and the
|
|
16
|
+
* new location has no cycle involvement.
|
|
17
|
+
*
|
|
18
|
+
* Note: all moves are mechanically doable — the only hard blocker is cycle
|
|
19
|
+
* risk. `importUpdates` is the primary output: an exact checklist of the
|
|
20
|
+
* import statements that must be updated after the move.
|
|
21
|
+
*/
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
24
|
+
export declare const name = "check_move_safe";
|
|
25
|
+
export declare const description: string;
|
|
26
|
+
export declare const inputSchema: {
|
|
27
|
+
repoId: z.ZodString;
|
|
28
|
+
filePath: z.ZodString;
|
|
29
|
+
newFilePath: z.ZodString;
|
|
30
|
+
checkCycles: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
};
|
|
32
|
+
export interface ImportUpdate {
|
|
33
|
+
importerFilePath: string;
|
|
34
|
+
currentImportPath: string;
|
|
35
|
+
newImportPath: string;
|
|
36
|
+
line: number;
|
|
37
|
+
}
|
|
38
|
+
export declare function handler(args: {
|
|
39
|
+
repoId: string;
|
|
40
|
+
filePath: string;
|
|
41
|
+
newFilePath: string;
|
|
42
|
+
checkCycles?: boolean;
|
|
43
|
+
}): Promise<CallToolResult>;
|
|
44
|
+
//# sourceMappingURL=check-move-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-move-safe.d.ts","sourceRoot":"","sources":["../../../src/server/tools/check-move-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,eAAO,MAAM,WAAW,QAM0D,CAAC;AAEnF,eAAO,MAAM,WAAW;;;;;CAevB,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAyJD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2H1B"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-move-safe.ts
|
|
3
|
+
*
|
|
4
|
+
* MCP tool: check_move_safe
|
|
5
|
+
*
|
|
6
|
+
* Pre-flight check for moving a file to a new location. Returns:
|
|
7
|
+
* - All import statements that need updating (importUpdates), with exact
|
|
8
|
+
* current and new paths, plus the line number of each import.
|
|
9
|
+
* - Whether the move would introduce import cycles at the new location
|
|
10
|
+
* (wouldIntroduceCycles).
|
|
11
|
+
*
|
|
12
|
+
* Safety definition:
|
|
13
|
+
* safe: false — if the move would place the file in an existing import cycle
|
|
14
|
+
* (the cycle moves with the file to its new location).
|
|
15
|
+
* safe: true — if all affected imports can be updated mechanically and the
|
|
16
|
+
* new location has no cycle involvement.
|
|
17
|
+
*
|
|
18
|
+
* Note: all moves are mechanically doable — the only hard blocker is cycle
|
|
19
|
+
* risk. `importUpdates` is the primary output: an exact checklist of the
|
|
20
|
+
* import statements that must be updated after the move.
|
|
21
|
+
*/
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
import { dirname, extname, relative, sep } from 'path';
|
|
24
|
+
import { openDatabase, getRepo } from '../../core/db/schema.js';
|
|
25
|
+
import { getFileContent } from '../../core/db/file-store.js';
|
|
26
|
+
import { getImportersOf, getAllDepEdges } from '../../core/db/dep-store.js';
|
|
27
|
+
import { buildMeta } from './_meta.js';
|
|
28
|
+
export const name = 'check_move_safe';
|
|
29
|
+
export const description = 'Pre-flight check for moving a file to a new location. Returns a checklist of ' +
|
|
30
|
+
'import statements that need updating (importUpdates) plus cycle-risk analysis ' +
|
|
31
|
+
'(wouldIntroduceCycles). ' +
|
|
32
|
+
'safe: false only when the move would place the file inside an existing import cycle. ' +
|
|
33
|
+
'All moves are mechanically doable — importUpdates gives you the exact edits needed. ' +
|
|
34
|
+
'Use find_importers to preview which files depend on a module before moving it.';
|
|
35
|
+
export const inputSchema = {
|
|
36
|
+
repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
|
|
37
|
+
filePath: z
|
|
38
|
+
.string()
|
|
39
|
+
.describe('Current file path relative to the repo root (e.g. "src/utils/hash.ts")'),
|
|
40
|
+
newFilePath: z
|
|
41
|
+
.string()
|
|
42
|
+
.describe('Proposed new location relative to the repo root (e.g. "src/core/hash.ts")'),
|
|
43
|
+
checkCycles: z
|
|
44
|
+
.boolean()
|
|
45
|
+
.optional()
|
|
46
|
+
.describe('Simulate the move in the dependency graph and detect any import cycles ' +
|
|
47
|
+
'that would involve the new location. Default true.'),
|
|
48
|
+
};
|
|
49
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
50
|
+
/** Normalize path separators to forward slashes. */
|
|
51
|
+
function normalizeSep(p) {
|
|
52
|
+
return p.split(sep).join('/');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compute the new import specifier from `importerFilePath` to `newTargetPath`,
|
|
56
|
+
* preserving whether the original specifier had a file extension.
|
|
57
|
+
*
|
|
58
|
+
* Examples:
|
|
59
|
+
* importerFilePath = 'src/main.ts', newTargetPath = 'src/core/hash.ts',
|
|
60
|
+
* currentSpecifier = './utils/hash'
|
|
61
|
+
* → './core/hash' (no extension, matching original)
|
|
62
|
+
*
|
|
63
|
+
* importerFilePath = 'src/deep/nested/consumer.ts', newTargetPath = 'src/deep/parser.ts',
|
|
64
|
+
* currentSpecifier = '../../lib/parser'
|
|
65
|
+
* → '../parser'
|
|
66
|
+
*/
|
|
67
|
+
function computeNewImportPath(importerFilePath, newTargetPath, currentSpecifier) {
|
|
68
|
+
const importerDir = dirname(importerFilePath);
|
|
69
|
+
const rawRelative = normalizeSep(relative(normalizeSep(importerDir), normalizeSep(newTargetPath)));
|
|
70
|
+
// Add './' prefix when the path doesn't start with '../'
|
|
71
|
+
const withPrefix = rawRelative.startsWith('../') ? rawRelative : `./${rawRelative}`;
|
|
72
|
+
// Match extension presence from the original specifier
|
|
73
|
+
if (!extname(currentSpecifier)) {
|
|
74
|
+
// Original had no extension → strip extension from computed path
|
|
75
|
+
const ext = extname(withPrefix);
|
|
76
|
+
return ext ? withPrefix.slice(0, -ext.length) : withPrefix;
|
|
77
|
+
}
|
|
78
|
+
return withPrefix;
|
|
79
|
+
}
|
|
80
|
+
/** Find the 1-based line number of the first import containing `specifier`. */
|
|
81
|
+
function findImportLine(content, specifier) {
|
|
82
|
+
if (!content)
|
|
83
|
+
return 0;
|
|
84
|
+
const text = content.toString('utf8');
|
|
85
|
+
const lines = text.split('\n');
|
|
86
|
+
// Match the raw specifier surrounded by any quote character
|
|
87
|
+
const escaped = specifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
88
|
+
const re = new RegExp(`['"\`]${escaped}['"\`]`);
|
|
89
|
+
for (let i = 0; i < lines.length; i++) {
|
|
90
|
+
if (re.test(lines[i]))
|
|
91
|
+
return i + 1;
|
|
92
|
+
}
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the import specifier used by `importerFile` when importing `targetFile`.
|
|
97
|
+
* Returns the first matching edge's specifier, or an empty string if not found.
|
|
98
|
+
*/
|
|
99
|
+
function getSpecifier(db, repoId, importerFile, targetFile) {
|
|
100
|
+
const row = db
|
|
101
|
+
.prepare(`SELECT specifier FROM dep_edges
|
|
102
|
+
WHERE repo_id = ? AND source_file = ? AND target_file = ?
|
|
103
|
+
LIMIT 1`)
|
|
104
|
+
.get(repoId, importerFile, targetFile);
|
|
105
|
+
return row?.specifier ?? '';
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Detect all import cycles in a modified dependency graph where `oldPath` has
|
|
109
|
+
* been renamed to `newPath`. Returns cycles that involve `newPath`.
|
|
110
|
+
*
|
|
111
|
+
* Uses the same DFS algorithm as findImportCycles: each cycle is reported
|
|
112
|
+
* exactly once, rooted at its lexicographically smallest file.
|
|
113
|
+
*/
|
|
114
|
+
function detectCyclesAfterMove(edges, oldPath, newPath, maxCycles = 20) {
|
|
115
|
+
// Build adjacency list with oldPath renamed to newPath
|
|
116
|
+
const adj = new Map();
|
|
117
|
+
for (const edge of edges) {
|
|
118
|
+
if (edge.sourceFile === edge.targetFile)
|
|
119
|
+
continue;
|
|
120
|
+
const src = edge.sourceFile === oldPath ? newPath : edge.sourceFile;
|
|
121
|
+
const tgt = edge.targetFile === oldPath ? newPath : edge.targetFile;
|
|
122
|
+
if (src === tgt)
|
|
123
|
+
continue;
|
|
124
|
+
const srcList = adj.get(src) ?? [];
|
|
125
|
+
if (!srcList.includes(tgt))
|
|
126
|
+
srcList.push(tgt);
|
|
127
|
+
adj.set(src, srcList);
|
|
128
|
+
if (!adj.has(tgt))
|
|
129
|
+
adj.set(tgt, []);
|
|
130
|
+
}
|
|
131
|
+
for (const v of adj.values())
|
|
132
|
+
v.sort();
|
|
133
|
+
const found = [];
|
|
134
|
+
const cap = maxCycles + 1;
|
|
135
|
+
const nodes = [...adj.keys()].sort();
|
|
136
|
+
function dfs(start, path, pathSet) {
|
|
137
|
+
if (found.length >= cap)
|
|
138
|
+
return;
|
|
139
|
+
const cur = path[path.length - 1];
|
|
140
|
+
for (const next of adj.get(cur) ?? []) {
|
|
141
|
+
if (found.length >= cap)
|
|
142
|
+
return;
|
|
143
|
+
if (next === start && path.length >= 2) {
|
|
144
|
+
found.push([...path]);
|
|
145
|
+
}
|
|
146
|
+
else if (!pathSet.has(next) && next > start) {
|
|
147
|
+
pathSet.add(next);
|
|
148
|
+
path.push(next);
|
|
149
|
+
dfs(start, path, pathSet);
|
|
150
|
+
path.pop();
|
|
151
|
+
pathSet.delete(next);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const node of nodes) {
|
|
156
|
+
if (found.length >= cap)
|
|
157
|
+
break;
|
|
158
|
+
dfs(node, [node], new Set([node]));
|
|
159
|
+
}
|
|
160
|
+
// Return only cycles that involve the new (moved) path, capped at maxCycles
|
|
161
|
+
return found.filter((c) => c.includes(newPath)).slice(0, maxCycles);
|
|
162
|
+
}
|
|
163
|
+
// ─── Handler ──────────────────────────────────────────────────────────────────
|
|
164
|
+
export async function handler(args) {
|
|
165
|
+
const t0 = Date.now();
|
|
166
|
+
const { repoId, filePath, newFilePath, checkCycles = true } = args;
|
|
167
|
+
// Normalize separators so the paths match what's stored in the DB
|
|
168
|
+
const normalizedFilePath = normalizeSep(filePath);
|
|
169
|
+
const normalizedNewFilePath = normalizeSep(newFilePath);
|
|
170
|
+
if (normalizedFilePath === normalizedNewFilePath) {
|
|
171
|
+
const output = {
|
|
172
|
+
safe: true,
|
|
173
|
+
verdict: 'Safe to move: source and destination paths are the same (no-op).',
|
|
174
|
+
filePath: normalizedFilePath,
|
|
175
|
+
newFilePath: normalizedNewFilePath,
|
|
176
|
+
importUpdates: [],
|
|
177
|
+
importUpdateCount: 0,
|
|
178
|
+
newCycles: [],
|
|
179
|
+
wouldIntroduceCycles: false,
|
|
180
|
+
_tokenEstimate: 0,
|
|
181
|
+
_meta: buildMeta({ timingMs: Date.now() - t0 }),
|
|
182
|
+
};
|
|
183
|
+
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
184
|
+
}
|
|
185
|
+
const db = openDatabase(repoId);
|
|
186
|
+
try {
|
|
187
|
+
const repo = getRepo(db, repoId);
|
|
188
|
+
if (!repo) {
|
|
189
|
+
return {
|
|
190
|
+
content: [
|
|
191
|
+
{
|
|
192
|
+
type: 'text',
|
|
193
|
+
text: JSON.stringify({
|
|
194
|
+
error: `Repo "${repoId}" not found. Run index_folder first.`,
|
|
195
|
+
}),
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
isError: true,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
// ── 1. Find all direct importers ──────────────────────────────────────────
|
|
202
|
+
const importerFiles = getImportersOf(db, repoId, normalizedFilePath);
|
|
203
|
+
// ── 2. Build ImportUpdate list ────────────────────────────────────────────
|
|
204
|
+
const importUpdates = [];
|
|
205
|
+
for (const importerFilePath of importerFiles) {
|
|
206
|
+
const specifier = getSpecifier(db, repoId, importerFilePath, normalizedFilePath);
|
|
207
|
+
if (!specifier)
|
|
208
|
+
continue; // edge without specifier — skip
|
|
209
|
+
const newImportPath = computeNewImportPath(importerFilePath, normalizedNewFilePath, specifier);
|
|
210
|
+
const content = getFileContent(db, repoId, importerFilePath);
|
|
211
|
+
const line = findImportLine(content, specifier);
|
|
212
|
+
importUpdates.push({
|
|
213
|
+
importerFilePath,
|
|
214
|
+
currentImportPath: specifier,
|
|
215
|
+
newImportPath,
|
|
216
|
+
line,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
// Sort by importer path for deterministic output
|
|
220
|
+
importUpdates.sort((a, b) => a.importerFilePath.localeCompare(b.importerFilePath));
|
|
221
|
+
// ── 3. Cycle detection ────────────────────────────────────────────────────
|
|
222
|
+
let newCycles = [];
|
|
223
|
+
if (checkCycles) {
|
|
224
|
+
const allEdges = getAllDepEdges(db, repoId);
|
|
225
|
+
newCycles = detectCyclesAfterMove(allEdges, normalizedFilePath, normalizedNewFilePath);
|
|
226
|
+
}
|
|
227
|
+
const wouldIntroduceCycles = newCycles.length > 0;
|
|
228
|
+
// ── 4. Verdict ────────────────────────────────────────────────────────────
|
|
229
|
+
const safe = !wouldIntroduceCycles;
|
|
230
|
+
let verdict;
|
|
231
|
+
if (safe) {
|
|
232
|
+
const count = importUpdates.length;
|
|
233
|
+
if (count === 0) {
|
|
234
|
+
verdict = 'Safe to move: no importers found. No import statements need updating.';
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
verdict =
|
|
238
|
+
`Safe to move: ${count} import statement${count !== 1 ? 's' : ''} will need updating across ` +
|
|
239
|
+
`${new Set(importUpdates.map((u) => u.importerFilePath)).size} file${importUpdates.length !== 1 ? 's' : ''}. No cycles.`;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
verdict =
|
|
244
|
+
`Move introduces ${newCycles.length} import cycle${newCycles.length !== 1 ? 's' : ''} at the new location. ` +
|
|
245
|
+
`${importUpdates.length} import statement${importUpdates.length !== 1 ? 's' : ''} also need updating.`;
|
|
246
|
+
}
|
|
247
|
+
const responseText = JSON.stringify({ importUpdates, newCycles });
|
|
248
|
+
const output = {
|
|
249
|
+
safe,
|
|
250
|
+
verdict,
|
|
251
|
+
filePath: normalizedFilePath,
|
|
252
|
+
newFilePath: normalizedNewFilePath,
|
|
253
|
+
importUpdates,
|
|
254
|
+
importUpdateCount: importUpdates.length,
|
|
255
|
+
newCycles,
|
|
256
|
+
wouldIntroduceCycles,
|
|
257
|
+
_tokenEstimate: Math.ceil(responseText.length / 4),
|
|
258
|
+
_meta: buildMeta({ timingMs: Date.now() - t0 }),
|
|
259
|
+
};
|
|
260
|
+
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
db.close();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
//# sourceMappingURL=check-move-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-move-safe.js","sourceRoot":"","sources":["../../../src/server/tools/check-move-safe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-rename-safe.ts
|
|
3
|
+
*
|
|
4
|
+
* MCP tool: check_rename_safe
|
|
5
|
+
*
|
|
6
|
+
* Pre-flight check for renaming a symbol. Returns a binary verdict, all
|
|
7
|
+
* affected files, and the specific lines that will need updating — so an
|
|
8
|
+
* agent can decide whether to proceed without manually inspecting raw
|
|
9
|
+
* reference lists.
|
|
10
|
+
*
|
|
11
|
+
* Safety rules:
|
|
12
|
+
* safe: false — if conflicts exist (newName already present in the same file)
|
|
13
|
+
* safe: false — if any reference is a string-literal (runtime string that
|
|
14
|
+
* won't be fixed by a text rename, requires human judgment)
|
|
15
|
+
* safe: true — all other cases (comment references are included but not
|
|
16
|
+
* blockers)
|
|
17
|
+
*
|
|
18
|
+
* changeType detection (in priority order):
|
|
19
|
+
* 'comment' — line starts with // or * (JSDoc)
|
|
20
|
+
* 'import' — line contains the `import` keyword
|
|
21
|
+
* 'string-literal' — symbol name appears inside quote characters
|
|
22
|
+
* 'type-reference' — line contains `type` or `interface` keyword
|
|
23
|
+
* 'call' — default
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
27
|
+
export declare const name = "check_rename_safe";
|
|
28
|
+
export declare const description: string;
|
|
29
|
+
export declare const inputSchema: {
|
|
30
|
+
repoId: z.ZodString;
|
|
31
|
+
symbolId: z.ZodString;
|
|
32
|
+
newName: z.ZodString;
|
|
33
|
+
checkConflicts: z.ZodOptional<z.ZodBoolean>;
|
|
34
|
+
};
|
|
35
|
+
export interface AffectedSite {
|
|
36
|
+
filePath: string;
|
|
37
|
+
line: number;
|
|
38
|
+
column: number;
|
|
39
|
+
context: string;
|
|
40
|
+
changeType: 'call' | 'import' | 'type-reference' | 'string-literal' | 'comment';
|
|
41
|
+
}
|
|
42
|
+
export declare function handler(args: {
|
|
43
|
+
repoId: string;
|
|
44
|
+
symbolId: string;
|
|
45
|
+
newName: string;
|
|
46
|
+
checkConflicts?: boolean;
|
|
47
|
+
}): Promise<CallToolResult>;
|
|
48
|
+
//# sourceMappingURL=check-rename-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rename-safe.d.ts","sourceRoot":"","sources":["../../../src/server/tools/check-rename-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,eAAO,MAAM,IAAI,sBAAsB,CAAC;AAExC,eAAO,MAAM,WAAW,QAK0B,CAAC;AAEnD,eAAO,MAAM,WAAW;;;;;CAWvB,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,CAAC;CACjF;AAyDD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,cAAc,CAAC,CA6J1B"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* check-rename-safe.ts
|
|
3
|
+
*
|
|
4
|
+
* MCP tool: check_rename_safe
|
|
5
|
+
*
|
|
6
|
+
* Pre-flight check for renaming a symbol. Returns a binary verdict, all
|
|
7
|
+
* affected files, and the specific lines that will need updating — so an
|
|
8
|
+
* agent can decide whether to proceed without manually inspecting raw
|
|
9
|
+
* reference lists.
|
|
10
|
+
*
|
|
11
|
+
* Safety rules:
|
|
12
|
+
* safe: false — if conflicts exist (newName already present in the same file)
|
|
13
|
+
* safe: false — if any reference is a string-literal (runtime string that
|
|
14
|
+
* won't be fixed by a text rename, requires human judgment)
|
|
15
|
+
* safe: true — all other cases (comment references are included but not
|
|
16
|
+
* blockers)
|
|
17
|
+
*
|
|
18
|
+
* changeType detection (in priority order):
|
|
19
|
+
* 'comment' — line starts with // or * (JSDoc)
|
|
20
|
+
* 'import' — line contains the `import` keyword
|
|
21
|
+
* 'string-literal' — symbol name appears inside quote characters
|
|
22
|
+
* 'type-reference' — line contains `type` or `interface` keyword
|
|
23
|
+
* 'call' — default
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { openDatabase, getRepo } from '../../core/db/schema.js';
|
|
27
|
+
import { getSymbolById } from '../../core/db/symbol-store.js';
|
|
28
|
+
import { getAllFilesWithContent } from '../../core/db/file-store.js';
|
|
29
|
+
import { buildMeta } from './_meta.js';
|
|
30
|
+
export const name = 'check_rename_safe';
|
|
31
|
+
export const description = 'Pre-flight check for renaming a symbol. Returns a verdict, all affected files, ' +
|
|
32
|
+
'and the specific lines that will need updating. ' +
|
|
33
|
+
'safe: false when the new name conflicts with an existing symbol or when string-literal ' +
|
|
34
|
+
'references exist that require manual updates. ' +
|
|
35
|
+
'Use search_symbols to find the symbolId first.';
|
|
36
|
+
export const inputSchema = {
|
|
37
|
+
repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
|
|
38
|
+
symbolId: z.string().describe('Symbol ID of the symbol to rename'),
|
|
39
|
+
newName: z.string().min(1).describe('Proposed new name for the symbol'),
|
|
40
|
+
checkConflicts: z
|
|
41
|
+
.boolean()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Check if newName already exists in the same file (default true). ' +
|
|
44
|
+
'Set false to skip conflict detection for speed.'),
|
|
45
|
+
};
|
|
46
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
47
|
+
function escapeRegex(str) {
|
|
48
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Classify a reference line into a change type.
|
|
52
|
+
* Checked in priority order so that the most specific match wins.
|
|
53
|
+
*/
|
|
54
|
+
function detectChangeType(lineContent, symbolName) {
|
|
55
|
+
const trimmed = lineContent.trim();
|
|
56
|
+
// Comment: line starts with // or * (JSDoc block) or /*
|
|
57
|
+
if (/^(\/\/|\*|\/\*)/.test(trimmed)) {
|
|
58
|
+
return 'comment';
|
|
59
|
+
}
|
|
60
|
+
// Import statement
|
|
61
|
+
if (/\bimport\b/.test(trimmed)) {
|
|
62
|
+
return 'import';
|
|
63
|
+
}
|
|
64
|
+
// String literal: symbol name appears inside quote characters
|
|
65
|
+
const escaped = escapeRegex(symbolName);
|
|
66
|
+
if (new RegExp(`['"\`][^'"\`]*\\b${escaped}\\b[^'"\`]*['"\`]`).test(trimmed)) {
|
|
67
|
+
return 'string-literal';
|
|
68
|
+
}
|
|
69
|
+
// Type reference: `type` or `interface` keyword on this line
|
|
70
|
+
if (/\btype\b/.test(trimmed) || /\binterface\b/.test(trimmed)) {
|
|
71
|
+
return 'type-reference';
|
|
72
|
+
}
|
|
73
|
+
// Default: call / variable usage
|
|
74
|
+
return 'call';
|
|
75
|
+
}
|
|
76
|
+
// ─── Handler ──────────────────────────────────────────────────────────────────
|
|
77
|
+
export async function handler(args) {
|
|
78
|
+
const t0 = Date.now();
|
|
79
|
+
const { repoId, symbolId, newName, checkConflicts = true } = args;
|
|
80
|
+
const db = openDatabase(repoId);
|
|
81
|
+
try {
|
|
82
|
+
const repo = getRepo(db, repoId);
|
|
83
|
+
if (!repo) {
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
text: JSON.stringify({
|
|
89
|
+
error: `Repo "${repoId}" not found. Run index_folder first.`,
|
|
90
|
+
}),
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
isError: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const symbol = getSymbolById(db, repoId, symbolId);
|
|
97
|
+
if (!symbol) {
|
|
98
|
+
return {
|
|
99
|
+
content: [
|
|
100
|
+
{
|
|
101
|
+
type: 'text',
|
|
102
|
+
text: JSON.stringify({
|
|
103
|
+
error: `Symbol "${symbolId}" not found in repo "${repoId}".`,
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// No-op: renaming to the same name is always safe
|
|
111
|
+
if (symbol.name === newName) {
|
|
112
|
+
const output = {
|
|
113
|
+
safe: true,
|
|
114
|
+
verdict: `Safe to rename: new name is the same as the current name (no-op).`,
|
|
115
|
+
symbolName: symbol.name,
|
|
116
|
+
newName,
|
|
117
|
+
conflicts: [],
|
|
118
|
+
affectedSites: [],
|
|
119
|
+
affectedFileCount: 0,
|
|
120
|
+
_tokenEstimate: 0,
|
|
121
|
+
_meta: buildMeta({ timingMs: Date.now() - t0 }),
|
|
122
|
+
};
|
|
123
|
+
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
124
|
+
}
|
|
125
|
+
// ── 1. Find all references ────────────────────────────────────────────────
|
|
126
|
+
const affectedSites = [];
|
|
127
|
+
const pattern = new RegExp(`\\b${escapeRegex(symbol.name)}\\b`);
|
|
128
|
+
// Definition file is excluded from reference scan (we don't list the
|
|
129
|
+
// declaration itself as an affected site — only call/import sites)
|
|
130
|
+
const definitionFile = symbol.filePath;
|
|
131
|
+
const files = getAllFilesWithContent(db, repoId);
|
|
132
|
+
for (const { path, rawContent } of files) {
|
|
133
|
+
if (!rawContent)
|
|
134
|
+
continue;
|
|
135
|
+
if (path === definitionFile)
|
|
136
|
+
continue;
|
|
137
|
+
const text = rawContent.toString('utf8');
|
|
138
|
+
const lines = text.split('\n');
|
|
139
|
+
for (let i = 0; i < lines.length; i++) {
|
|
140
|
+
const line = lines[i];
|
|
141
|
+
if (!pattern.test(line))
|
|
142
|
+
continue;
|
|
143
|
+
const match = pattern.exec(line);
|
|
144
|
+
const column = match ? match.index + 1 : 1; // 1-based
|
|
145
|
+
affectedSites.push({
|
|
146
|
+
filePath: path,
|
|
147
|
+
line: i + 1,
|
|
148
|
+
column,
|
|
149
|
+
context: line.length > 120 ? line.slice(0, 120) : line,
|
|
150
|
+
changeType: detectChangeType(line, symbol.name),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ── 2. Conflict detection ─────────────────────────────────────────────────
|
|
155
|
+
const conflicts = [];
|
|
156
|
+
if (checkConflicts) {
|
|
157
|
+
// Look for any symbol with newName in the same file as the declaration
|
|
158
|
+
const conflictRows = db
|
|
159
|
+
.prepare(`SELECT name, file_path, kind FROM symbols
|
|
160
|
+
WHERE repo_id = ? AND name = ? AND file_path = ?`)
|
|
161
|
+
.all(repoId, newName, definitionFile);
|
|
162
|
+
for (const row of conflictRows) {
|
|
163
|
+
conflicts.push(`${row.name} (${row.kind}) in ${row.file_path}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ── 3. Compute verdict ────────────────────────────────────────────────────
|
|
167
|
+
const hasStringLiterals = affectedSites.some((s) => s.changeType === 'string-literal');
|
|
168
|
+
const safe = conflicts.length === 0 && !hasStringLiterals;
|
|
169
|
+
const uniqueFiles = new Set(affectedSites.map((s) => s.filePath));
|
|
170
|
+
const affectedFileCount = uniqueFiles.size;
|
|
171
|
+
const callCount = affectedSites.filter((s) => s.changeType === 'call').length;
|
|
172
|
+
const importCount = affectedSites.filter((s) => s.changeType === 'import').length;
|
|
173
|
+
const stringLitCount = affectedSites.filter((s) => s.changeType === 'string-literal').length;
|
|
174
|
+
const commentCount = affectedSites.filter((s) => s.changeType === 'comment').length;
|
|
175
|
+
const typeRefCount = affectedSites.filter((s) => s.changeType === 'type-reference').length;
|
|
176
|
+
let verdict;
|
|
177
|
+
if (!safe) {
|
|
178
|
+
const reasons = [];
|
|
179
|
+
if (conflicts.length > 0) {
|
|
180
|
+
reasons.push(`"${newName}" conflicts with an existing symbol`);
|
|
181
|
+
}
|
|
182
|
+
if (hasStringLiterals) {
|
|
183
|
+
reasons.push(`${stringLitCount} string-literal reference(s) require manual update`);
|
|
184
|
+
}
|
|
185
|
+
verdict = `Not safe to rename: ${reasons.join('; ')}. ${affectedFileCount} file(s) affected.`;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
const breakdown = [];
|
|
189
|
+
if (callCount > 0)
|
|
190
|
+
breakdown.push(`${callCount} call site${callCount > 1 ? 's' : ''}`);
|
|
191
|
+
if (importCount > 0)
|
|
192
|
+
breakdown.push(`${importCount} import${importCount > 1 ? 's' : ''}`);
|
|
193
|
+
if (typeRefCount > 0)
|
|
194
|
+
breakdown.push(`${typeRefCount} type reference${typeRefCount > 1 ? 's' : ''}`);
|
|
195
|
+
if (commentCount > 0)
|
|
196
|
+
breakdown.push(`${commentCount} comment${commentCount > 1 ? 's' : ''}`);
|
|
197
|
+
const detail = breakdown.length > 0 ? ` (${breakdown.join(', ')})` : '';
|
|
198
|
+
verdict = `Safe to rename: ${affectedFileCount} file${affectedFileCount !== 1 ? 's' : ''} affected${detail}. No conflicts.`;
|
|
199
|
+
}
|
|
200
|
+
const responseText = JSON.stringify(affectedSites);
|
|
201
|
+
const output = {
|
|
202
|
+
safe,
|
|
203
|
+
verdict,
|
|
204
|
+
symbolName: symbol.name,
|
|
205
|
+
newName,
|
|
206
|
+
conflicts,
|
|
207
|
+
affectedSites,
|
|
208
|
+
affectedFileCount,
|
|
209
|
+
_tokenEstimate: Math.ceil(responseText.length / 4),
|
|
210
|
+
_meta: buildMeta({ timingMs: Date.now() - t0 }),
|
|
211
|
+
};
|
|
212
|
+
return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
db.close();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=check-rename-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-rename-safe.js","sourceRoot":"","sources":["../../../src/server/tools/check-rename-safe.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* diff-health-radar.ts
|
|
3
|
+
*
|
|
4
|
+
* MCP tool: diff_health_radar
|
|
5
|
+
*
|
|
6
|
+
* Compare health radar scores between two indexed repos (or two states of the
|
|
7
|
+
* same codebase). Primary use cases:
|
|
8
|
+
*
|
|
9
|
+
* • PR review: index main branch → index feature branch → compare
|
|
10
|
+
* • Refactoring validation: index before → refactor → re-index → compare
|
|
11
|
+
* • Cross-repo benchmark: compare health of two different projects
|
|
12
|
+
*
|
|
13
|
+
* Runs health_radar on both repos, then computes per-axis deltas (head − base).
|
|
14
|
+
* Positive delta = improvement; negative delta = regression.
|
|
15
|
+
*
|
|
16
|
+
* Output:
|
|
17
|
+
* • base snapshot — health scores from baseRepoId
|
|
18
|
+
* • head snapshot — health scores from headRepoId
|
|
19
|
+
* • axes delta map — score change per axis with trend label
|
|
20
|
+
* • overallDelta — change in overall health (head − base)
|
|
21
|
+
* • trend — 'improved' | 'degraded' | 'stable' (based on overallDelta)
|
|
22
|
+
* • regressions — axis names that degraded by > SIGNIFICANT_DELTA
|
|
23
|
+
* • improvements — axis names that improved by > SIGNIFICANT_DELTA
|
|
24
|
+
*
|
|
25
|
+
* A delta of +5 or more is treated as a meaningful improvement.
|
|
26
|
+
* A delta of −5 or more (negative) is treated as a meaningful regression.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
30
|
+
export declare const name = "diff_health_radar";
|
|
31
|
+
export declare const description: string;
|
|
32
|
+
export declare const inputSchema: {
|
|
33
|
+
baseRepoId: z.ZodString;
|
|
34
|
+
headRepoId: z.ZodString;
|
|
35
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
36
|
+
includeStability: z.ZodOptional<z.ZodBoolean>;
|
|
37
|
+
};
|
|
38
|
+
export declare function handler(args: {
|
|
39
|
+
baseRepoId: string;
|
|
40
|
+
headRepoId: string;
|
|
41
|
+
scope?: string;
|
|
42
|
+
includeStability?: boolean;
|
|
43
|
+
}): Promise<CallToolResult>;
|
|
44
|
+
//# sourceMappingURL=diff-health-radar.d.ts.map
|