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,279 @@
|
|
|
1
|
+
# Refactoring Safely
|
|
2
|
+
|
|
3
|
+
Refactoring is risky not because the changes are hard, but because the side effects are invisible. You rename a function and forget about the string-literal reference in a config file. You delete a helper and miss the one call site that imported it from a different path. You move a file and half the codebase's import paths silently break.
|
|
4
|
+
|
|
5
|
+
PureContext's refactoring safety tools give you a complete impact analysis before you make any change — so you know exactly what you're dealing with before you start.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Before renaming a symbol
|
|
10
|
+
|
|
11
|
+
Renaming a function, class, or constant affects every file that references it. The question is always: *exactly how many places, which ones, and are there any that a text-replace can't fix automatically?*
|
|
12
|
+
|
|
13
|
+
**Scenario:** You're renaming `validateToken` to `verifyAuthToken` to align with the new naming convention. Before you do it in your editor, get the full picture.
|
|
14
|
+
|
|
15
|
+
> "I want to rename validateToken to verifyAuthToken. Is that safe? Show me everywhere it's used."
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
check_rename_safe(repoId, symbolId: "validateToken-id", newName: "verifyAuthToken") →
|
|
19
|
+
|
|
20
|
+
safe: true
|
|
21
|
+
verdict: "Rename is safe. All references are in import statements and call sites
|
|
22
|
+
that can be updated automatically. No string-literal references detected."
|
|
23
|
+
|
|
24
|
+
Affected files (12):
|
|
25
|
+
src/auth/index.ts:3 import — import { validateToken } from './validator'
|
|
26
|
+
src/auth/index.ts:47 call — const result = validateToken(req.headers.auth)
|
|
27
|
+
src/api/middleware/auth.ts:12 import — import { validateToken } ...
|
|
28
|
+
src/api/middleware/auth.ts:67 call — validateToken(bearer)
|
|
29
|
+
src/api/routes/login.ts:23 call — if (!validateToken(session)) ...
|
|
30
|
+
test/auth/validator.test.ts:15 call — expect(validateToken('expired')).toBe(false)
|
|
31
|
+
test/auth/validator.test.ts:31 call — validateToken(validToken)
|
|
32
|
+
... (5 more)
|
|
33
|
+
|
|
34
|
+
No conflicts: "verifyAuthToken" does not exist in any of these files.
|
|
35
|
+
No string-literal references that require manual updates.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Safe to proceed. All 12 references are structured code — imports and call sites — that any rename tool can update mechanically. No surprises.
|
|
39
|
+
|
|
40
|
+
**When it's not safe:**
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
check_rename_safe(repoId, symbolId: "processPayment-id", newName: "handlePayment") →
|
|
44
|
+
|
|
45
|
+
safe: false
|
|
46
|
+
blockers:
|
|
47
|
+
1. String-literal reference found:
|
|
48
|
+
src/config/routes.json:34 "handler": "processPayment"
|
|
49
|
+
← This is a string, not a code reference. A rename tool won't catch it.
|
|
50
|
+
|
|
51
|
+
2. Name conflict:
|
|
52
|
+
src/billing/processor.ts already contains a symbol named "handlePayment"
|
|
53
|
+
← Two functions with the same name in the same import scope will conflict.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Two blockers. The string-literal reference in `routes.json` needs a manual update — it's used as a string key to look up the handler dynamically. The name conflict needs to be resolved before the rename can proceed.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Before deleting a symbol
|
|
61
|
+
|
|
62
|
+
Deleting code that's still called causes runtime errors. `check_delete_safe` finds every live reference before you delete anything.
|
|
63
|
+
|
|
64
|
+
**Scenario:** You think `formatDateLegacy` is dead code. You want to confirm before deleting it.
|
|
65
|
+
|
|
66
|
+
> "Is formatDateLegacy safe to delete?"
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
check_delete_safe(repoId, symbolId: "formatDateLegacy-id") →
|
|
70
|
+
|
|
71
|
+
safe: true
|
|
72
|
+
verdict: "No live references found. Symbol is unexported. Safe to delete."
|
|
73
|
+
|
|
74
|
+
Risks found:
|
|
75
|
+
test-subject test/utils/date.test.ts:45 — test file references this symbol
|
|
76
|
+
(informational — deleting will require updating the test)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
No production code references it. The only reference is in a test file — which is expected and will need to be cleaned up alongside the deletion. Safe to proceed.
|
|
80
|
+
|
|
81
|
+
**When there are live references:**
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
check_delete_safe(repoId, symbolId: "getUserById-id") →
|
|
85
|
+
|
|
86
|
+
safe: false
|
|
87
|
+
verdict: "3 live references found. Deletion would cause runtime errors."
|
|
88
|
+
|
|
89
|
+
Risks:
|
|
90
|
+
live-reference src/api/routes/users.ts:67
|
|
91
|
+
const user = getUserById(req.params.id);
|
|
92
|
+
|
|
93
|
+
live-reference src/workers/sync.ts:34
|
|
94
|
+
const admin = getUserById(config.adminId);
|
|
95
|
+
|
|
96
|
+
exported-symbol (symbol is exported — may be consumed by external packages)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Not safe. Two active call sites would break immediately. The exported flag also indicates external consumers may exist outside the indexed codebase.
|
|
100
|
+
|
|
101
|
+
**Checking an entire file for deletion:**
|
|
102
|
+
|
|
103
|
+
> "I want to delete src/legacy/auth-v1.ts entirely. What would break?"
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
check_delete_safe(repoId, filePath: "src/legacy/auth-v1.ts") →
|
|
107
|
+
|
|
108
|
+
safe: false (aggregate verdict across 8 symbols in this file)
|
|
109
|
+
|
|
110
|
+
Breakdown:
|
|
111
|
+
generateLegacyToken() → safe: true (0 references)
|
|
112
|
+
validateBasicAuth() → safe: true (0 references)
|
|
113
|
+
LegacySession → safe: false (2 live references)
|
|
114
|
+
live-reference src/api/middleware/legacy-compat.ts:23
|
|
115
|
+
live-reference src/workers/migrate-sessions.ts:67
|
|
116
|
+
... (5 more symbols, all safe)
|
|
117
|
+
|
|
118
|
+
Summary: 2 of 8 symbols have live references. Remove references first.
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
You can delete most of the file immediately. Two symbols — `LegacySession` — need their callers updated first. The tool tells you exactly which two files.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Before moving a file
|
|
126
|
+
|
|
127
|
+
Moving a file changes all the import paths that reference it. `check_move_safe` shows you every import that will need updating, and flags any that require manual intervention.
|
|
128
|
+
|
|
129
|
+
**Scenario:** You're reorganizing the project structure and want to move `src/utils/auth-helpers.ts` into `src/auth/helpers.ts`.
|
|
130
|
+
|
|
131
|
+
> "If I move auth-helpers.ts to src/auth/helpers.ts, what import paths will break?"
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
check_move_safe(repoId,
|
|
135
|
+
filePath: "src/utils/auth-helpers.ts",
|
|
136
|
+
newFilePath: "src/auth/helpers.ts") →
|
|
137
|
+
|
|
138
|
+
safe: true
|
|
139
|
+
verdict: "All 9 import references use relative paths and can be updated automatically."
|
|
140
|
+
|
|
141
|
+
Import updates needed (9 files):
|
|
142
|
+
src/api/middleware/auth.ts:2
|
|
143
|
+
current: import { hashToken } from '../../utils/auth-helpers'
|
|
144
|
+
updated: import { hashToken } from '../auth/helpers'
|
|
145
|
+
|
|
146
|
+
src/auth/validator.ts:1
|
|
147
|
+
current: import { compareHash } from '../utils/auth-helpers'
|
|
148
|
+
updated: import { compareHash } from './helpers'
|
|
149
|
+
|
|
150
|
+
src/core/session.ts:3
|
|
151
|
+
current: import { generateSecret } from '../utils/auth-helpers'
|
|
152
|
+
updated: import { generateSecret } from '../auth/helpers'
|
|
153
|
+
|
|
154
|
+
... (6 more, all relative paths)
|
|
155
|
+
|
|
156
|
+
manualUpdatesRequired: false
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
All relative paths — a find-and-replace-style operation can handle this automatically.
|
|
160
|
+
|
|
161
|
+
**When manual updates are required:**
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
check_move_safe(repoId,
|
|
165
|
+
filePath: "src/core/database.ts",
|
|
166
|
+
newFilePath: "src/db/database.ts") →
|
|
167
|
+
|
|
168
|
+
safe: false
|
|
169
|
+
manualUpdatesRequired: true
|
|
170
|
+
|
|
171
|
+
Problems:
|
|
172
|
+
src/config/jest.config.ts:14
|
|
173
|
+
moduleNameMapper: { '@core/database': './src/core/database' }
|
|
174
|
+
← Path alias in Jest config — not a TypeScript import. Requires manual update.
|
|
175
|
+
|
|
176
|
+
src/build/webpack.config.js:56
|
|
177
|
+
resolve: { alias: { 'core/database': path.resolve('./src/core/database') } }
|
|
178
|
+
← Webpack alias. Requires manual update.
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The TypeScript imports can be updated automatically. The Jest and Webpack configs use the old path as a string — those need manual updates before the move.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Getting a complete refactoring plan
|
|
186
|
+
|
|
187
|
+
When the scope is larger — breaking a circular dependency, extracting a module, reducing coupling — `plan_refactoring` synthesizes all the individual safety checks into a sequenced, risk-annotated action plan.
|
|
188
|
+
|
|
189
|
+
**Scenario:** You want to rename a widely-used symbol, and you want a step-by-step plan rather than a raw impact list.
|
|
190
|
+
|
|
191
|
+
> "Give me a complete refactoring plan for renaming validateToken to verifyAuthToken."
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
plan_refactoring(repoId, goal: "rename-symbol",
|
|
195
|
+
symbolId: "validateToken-id", newName: "verifyAuthToken") →
|
|
196
|
+
|
|
197
|
+
Goal: rename-symbol
|
|
198
|
+
Estimated files: 12
|
|
199
|
+
Estimated risk: low
|
|
200
|
+
|
|
201
|
+
Steps (execute in order):
|
|
202
|
+
|
|
203
|
+
1. [LOW RISK] Update test references (2 files)
|
|
204
|
+
test/auth/validator.test.ts — update 2 call sites
|
|
205
|
+
test/integration/auth.test.ts — update 1 import + 3 calls
|
|
206
|
+
Reason: Start with tests — they validate the rename worked correctly.
|
|
207
|
+
|
|
208
|
+
2. [LOW RISK] Update leaf callers (4 files)
|
|
209
|
+
src/api/routes/login.ts — update 1 call site
|
|
210
|
+
src/api/routes/refresh.ts — update 1 call site
|
|
211
|
+
src/workers/session-cleanup.ts — update 1 call site
|
|
212
|
+
src/api/middleware/auth.ts — update 1 import + 2 calls
|
|
213
|
+
Reason: These files import validateToken but nothing else imports them in this context.
|
|
214
|
+
|
|
215
|
+
3. [MEDIUM RISK] Update hub callers (2 files)
|
|
216
|
+
src/auth/index.ts — update export re-export
|
|
217
|
+
src/core/auth.ts — update 1 import + 4 calls
|
|
218
|
+
Reason: These are imported by 8+ other files. Change here last.
|
|
219
|
+
|
|
220
|
+
4. [FINAL] Rename the declaration
|
|
221
|
+
src/auth/validator.ts — rename the function
|
|
222
|
+
Reason: Always rename the declaration last, after all references are updated.
|
|
223
|
+
|
|
224
|
+
Warnings:
|
|
225
|
+
- After step 4, run index_folder to update the symbol index.
|
|
226
|
+
- Run tests after each step to catch regressions early.
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
The plan is sequenced bottom-up: leaf files first, hub files last, the declaration itself final. This minimizes the window between "declaration renamed" and "all references updated," reducing the chance of a broken build.
|
|
230
|
+
|
|
231
|
+
**Other refactoring goals:**
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
plan_refactoring(repoId, goal: "delete-symbol", symbolId: "...")
|
|
235
|
+
→ sequenced steps for removing all references then deleting
|
|
236
|
+
|
|
237
|
+
plan_refactoring(repoId, goal: "break-cycle", filePath: "src/core/auth.ts")
|
|
238
|
+
→ identifies the specific import causing the cycle and how to break it
|
|
239
|
+
|
|
240
|
+
plan_refactoring(repoId, goal: "extract-module",
|
|
241
|
+
filePath: "src/utils/helpers.ts", newFilePath: "src/format/currency.ts")
|
|
242
|
+
→ step-by-step extraction with all affected import updates
|
|
243
|
+
|
|
244
|
+
plan_refactoring(repoId, goal: "reduce-coupling", filePath: "src/core/auth.ts")
|
|
245
|
+
→ identifies the highest-coupling imports and suggests what to decouple
|
|
246
|
+
|
|
247
|
+
plan_refactoring(repoId, goal: "general", filePath: "src/utils/helpers.ts")
|
|
248
|
+
→ open-ended: surfaces the top structural issues in this file
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## The pre-change pattern
|
|
254
|
+
|
|
255
|
+
For any significant structural change, this is the workflow:
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
1. Run the relevant safety check
|
|
259
|
+
check_rename_safe / check_delete_safe / check_move_safe
|
|
260
|
+
→ get the verdict and full impact list
|
|
261
|
+
|
|
262
|
+
2. If safe: get the sequenced plan
|
|
263
|
+
plan_refactoring(goal: "...")
|
|
264
|
+
→ step-by-step with risk annotations
|
|
265
|
+
|
|
266
|
+
3. Execute from leaf to hub, test after each step
|
|
267
|
+
|
|
268
|
+
4. Re-index after all changes
|
|
269
|
+
index_folder(path, force: false)
|
|
270
|
+
→ incremental, picks up only what changed
|
|
271
|
+
|
|
272
|
+
5. Verify no dead code was created
|
|
273
|
+
find_dead_code(repoId)
|
|
274
|
+
→ check nothing is now unreferenced
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
→ Reference: [MCP Tools Reference](docs/06-tools-reference.md) — `check_rename_safe`, `check_delete_safe`, `check_move_safe`, `plan_refactoring`
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Understanding Code Relationships
|
|
2
|
+
|
|
3
|
+
The dependency graph gives you the broad picture — what imports what. But most real questions about a codebase go deeper: *who implements this interface?*, *what does this function call at runtime?*, *why is this module so hard to change?*, *where are the circular imports that are blocking our refactoring?*
|
|
4
|
+
|
|
5
|
+
PureContext has a dedicated set of tools for answering these structural questions without reading source files.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Finding all implementations of an interface
|
|
10
|
+
|
|
11
|
+
When you're working with a codebase that uses interfaces heavily — whether for dependency injection, plugin systems, or polymorphism — you regularly need to know: *what concrete classes actually implement this?*
|
|
12
|
+
|
|
13
|
+
**Scenario:** You're changing the `UserRepository` interface to add a new method. Before you change the interface, you need to know which classes implement it so you can update them all.
|
|
14
|
+
|
|
15
|
+
> "Which classes implement the UserRepository interface?"
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
find_implementations(symbolId: "UserRepository-id") →
|
|
19
|
+
|
|
20
|
+
Interface: UserRepository (src/core/repositories/user.ts)
|
|
21
|
+
|
|
22
|
+
Implementations:
|
|
23
|
+
PostgresUserRepository src/db/postgres/user-repo.ts implements all 7 methods ✓
|
|
24
|
+
InMemoryUserRepository src/test/mocks/user-repo.ts implements all 7 methods ✓
|
|
25
|
+
CachedUserRepository src/cache/user-repo.ts missing: batchGet, streamAll ✗
|
|
26
|
+
|
|
27
|
+
Total: 3 implementations
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
You can see immediately that `CachedUserRepository` is incomplete — it's missing two methods. Adding a third method to the interface will require updating all three classes. You know the scope before you change a single line.
|
|
31
|
+
|
|
32
|
+
**Including abstract subclasses:**
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
find_implementations(symbolId: "UserRepository-id", includeAbstract: true)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This surfaces abstract classes that extend the interface — useful in Java or Kotlin codebases where abstract base classes form an intermediate layer.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Understanding the call hierarchy
|
|
43
|
+
|
|
44
|
+
`get_blast_radius` tells you which *files* import a symbol. `get_call_hierarchy` tells you how a function is actually *called at runtime* — the actual call stack, structured as a tree.
|
|
45
|
+
|
|
46
|
+
**Scenario:** You're investigating a performance issue. The `generateReport` function is slow, but you're not sure if the problem is in the function itself or in something it calls deep down.
|
|
47
|
+
|
|
48
|
+
> "Show me what generateReport calls, three levels deep."
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
get_call_hierarchy(symbolId: "generateReport-id", direction: "callees", maxDepth: 3) →
|
|
52
|
+
|
|
53
|
+
generateReport() [root]
|
|
54
|
+
├── fetchReportData() depth 1 — called 1×
|
|
55
|
+
│ ├── queryUserEvents() depth 2 — called 1×
|
|
56
|
+
│ │ └── buildSQLQuery() depth 3 — called 3×
|
|
57
|
+
│ └── queryMetrics() depth 2 — called 1×
|
|
58
|
+
│ └── buildSQLQuery() depth 3 — called 1× [cyclic: seen above]
|
|
59
|
+
├── formatReportRows() depth 1 — called 1×
|
|
60
|
+
│ └── formatCurrency() depth 2 — called N×
|
|
61
|
+
└── generatePDF() depth 1 — called 1×
|
|
62
|
+
└── compressOutput() depth 2 — called 1×
|
|
63
|
+
|
|
64
|
+
Total nodes: 10
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`buildSQLQuery` is called four times from two different paths. `formatCurrency` is called in a loop. The tree structure lets you see exactly where the CPU time is going without running a profiler.
|
|
68
|
+
|
|
69
|
+
**Checking who calls a function:**
|
|
70
|
+
|
|
71
|
+
> "Who calls sendEmail? I need to know all the places it's triggered."
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
get_call_hierarchy(symbolId: "sendEmail-id", direction: "callers", maxDepth: 2) →
|
|
75
|
+
|
|
76
|
+
sendEmail() [root]
|
|
77
|
+
├── triggerWelcomeEmail() depth 1 — src/onboarding/welcome.ts
|
|
78
|
+
├── sendPasswordReset() depth 1 — src/auth/password.ts
|
|
79
|
+
│ └── resetPassword() depth 2 — src/api/routes/auth.ts
|
|
80
|
+
├── notifyPaymentFailed() depth 1 — src/billing/notify.ts
|
|
81
|
+
└── weeklyDigest() depth 1 — src/workers/digest.ts
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Four callers, one with a caller of its own. This is the full list of places that trigger email sending — a complete picture for changing the email system.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Tracing inheritance chains
|
|
89
|
+
|
|
90
|
+
When working with class hierarchies — especially in enterprise codebases with deep inheritance — you need to understand both directions: what does a class inherit from, and what inherits from it?
|
|
91
|
+
|
|
92
|
+
**Scenario:** You're refactoring `BaseController`. Before you change it, you want to know the full inheritance chain.
|
|
93
|
+
|
|
94
|
+
> "Show me the full class hierarchy for BaseController."
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
get_class_hierarchy(symbolId: "BaseController-id", direction: "both") →
|
|
98
|
+
|
|
99
|
+
Ancestors (BaseController extends):
|
|
100
|
+
BaseController → Object (external, not indexed)
|
|
101
|
+
|
|
102
|
+
Descendants (classes that extend BaseController):
|
|
103
|
+
BaseController
|
|
104
|
+
├── AuthenticatedController
|
|
105
|
+
│ ├── UserController
|
|
106
|
+
│ ├── AdminController
|
|
107
|
+
│ └── ApiController
|
|
108
|
+
│ ├── RestApiController
|
|
109
|
+
│ └── GraphQLController
|
|
110
|
+
└── PublicController
|
|
111
|
+
└── LandingController
|
|
112
|
+
|
|
113
|
+
Total: 9 nodes
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Seven classes will be affected by changes to `BaseController`. The deepest chains (`RestApiController`, `GraphQLController`) are four levels of inheritance — a sign that these might benefit from composition instead.
|
|
117
|
+
|
|
118
|
+
**Checking ancestors only:**
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
get_class_hierarchy(symbolId: "UserController-id", direction: "ancestors")
|
|
122
|
+
→ UserController → AuthenticatedController → BaseController → Object
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Finding circular dependencies
|
|
128
|
+
|
|
129
|
+
Circular imports are one of the most common causes of "this module is impossible to change independently." They also cause subtle initialization bugs and make testing harder.
|
|
130
|
+
|
|
131
|
+
**Scenario:** You've noticed that changes to `src/core/` always seem to require changes in `src/utils/`, and vice versa. You suspect a circular dependency.
|
|
132
|
+
|
|
133
|
+
> "Find all circular imports in the codebase. Start with cycles involving the core directory."
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
find_cycles(filePath: "src/core/") →
|
|
137
|
+
|
|
138
|
+
Cycle 1 (severity: error — tight 2-node cycle):
|
|
139
|
+
src/core/billing.ts → src/utils/currency.ts → src/core/billing.ts
|
|
140
|
+
|
|
141
|
+
Cycle 2 (severity: error — tight 3-node cycle):
|
|
142
|
+
src/core/auth.ts → src/models/user.ts → src/core/session.ts → src/core/auth.ts
|
|
143
|
+
|
|
144
|
+
Cycle 3 (severity: warning — longer chain):
|
|
145
|
+
src/core/events.ts → src/handlers/payment.ts → src/core/billing.ts
|
|
146
|
+
→ src/core/events.ts
|
|
147
|
+
|
|
148
|
+
Total: 3 cycles found
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The first cycle is the one you suspected — `billing.ts` and `currency.ts` are mutually dependent. Breaking this cycle (typically by extracting the shared types into a third module that both can import) is the fix.
|
|
152
|
+
|
|
153
|
+
**Checking cycles in the whole repo:**
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
find_cycles(maxCycles: 50) → finds all cycles up to the limit
|
|
157
|
+
find_cycles(minLength: 3) → skips direct mutual imports, shows only longer chains
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Measuring coupling
|
|
163
|
+
|
|
164
|
+
Coupling tells you which files are the most dangerous to change — not because they're complex, but because everything else depends on them.
|
|
165
|
+
|
|
166
|
+
**Scenario:** You're planning a major refactoring sprint. Before you start, you want to know which files have the highest coupling — both in terms of what they import and what imports them.
|
|
167
|
+
|
|
168
|
+
> "Which files in src/ have the highest coupling? I want to know where the structural risk is."
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
get_coupling_map(repoId, topN: 10) →
|
|
172
|
+
|
|
173
|
+
src/utils/helpers.ts
|
|
174
|
+
efferentCoupling (imports): 3 ← imports only 3 files
|
|
175
|
+
afferentCoupling (imported by): 41 ← but 41 files depend on it
|
|
176
|
+
instability: 0.07 ← near 0 = maximally stable = risky to change
|
|
177
|
+
|
|
178
|
+
src/core/auth.ts
|
|
179
|
+
efferentCoupling: 12
|
|
180
|
+
afferentCoupling: 28
|
|
181
|
+
instability: 0.30 ← stable hub
|
|
182
|
+
|
|
183
|
+
src/api/middleware/logging.ts
|
|
184
|
+
efferentCoupling: 18
|
|
185
|
+
afferentCoupling: 2
|
|
186
|
+
instability: 0.90 ← near 1 = leaf node = safe to change
|
|
187
|
+
|
|
188
|
+
...
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`helpers.ts` is the hidden risk: 41 files depend on it, but it only imports 3 things. Its instability score of 0.07 means it's a stable hub — every change to it ripples out to 41 files. That's the file to touch last, if at all.
|
|
192
|
+
|
|
193
|
+
**Inspecting a single file's dependency list:**
|
|
194
|
+
|
|
195
|
+
> "Who depends on src/core/auth.ts, and what does auth.ts itself depend on?"
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
get_coupling_map(repoId, filePath: "src/core/auth.ts", direction: "both") →
|
|
199
|
+
|
|
200
|
+
Imports (efferent — what auth.ts depends on):
|
|
201
|
+
src/models/user.ts
|
|
202
|
+
src/db/queries/auth.ts
|
|
203
|
+
src/utils/crypto.ts
|
|
204
|
+
... (9 more)
|
|
205
|
+
|
|
206
|
+
Imported by (afferent — what depends on auth.ts):
|
|
207
|
+
src/api/middleware/auth-guard.ts
|
|
208
|
+
src/api/routes/login.ts
|
|
209
|
+
src/workers/session-cleanup.ts
|
|
210
|
+
... (25 more)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Putting it together: pre-refactoring analysis
|
|
216
|
+
|
|
217
|
+
Before a significant structural refactoring, combine these tools:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
1. find_cycles(repoId)
|
|
221
|
+
→ identify which circular deps are blocking modularization
|
|
222
|
+
|
|
223
|
+
2. get_coupling_map(repoId, topN: 20)
|
|
224
|
+
→ rank files by coupling to find the stable hubs
|
|
225
|
+
|
|
226
|
+
3. get_class_hierarchy(symbolId)
|
|
227
|
+
→ understand inheritance depth in affected areas
|
|
228
|
+
|
|
229
|
+
4. find_implementations(symbolId)
|
|
230
|
+
→ know how many classes implement interfaces you plan to change
|
|
231
|
+
|
|
232
|
+
5. get_call_hierarchy(symbolId, direction: "callers")
|
|
233
|
+
→ verify you've found all callers before changing a function signature
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
This analysis takes minutes and replaces hours of manual code reading.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
→ Reference: [MCP Tools Reference](docs/06-tools-reference.md) — `find_implementations`, `get_call_hierarchy`, `get_class_hierarchy`, `find_cycles`, `get_coupling_map`
|
package/USER-GUIDE.md
CHANGED
|
@@ -20,6 +20,10 @@ For parameter-level documentation — every tool input, output, and flag — see
|
|
|
20
20
|
|
|
21
21
|
- [Making Changes Safely](safe-changes.md) — Blast radius analysis before touching anything, context bundles for understanding dependencies, the full pre-change workflow, and architectural violation detection
|
|
22
22
|
|
|
23
|
+
- [Understanding Code Relationships](understanding-relationships.md) — Call hierarchies, class hierarchies, interface implementations, circular dependency detection, and coupling maps
|
|
24
|
+
|
|
25
|
+
- [Refactoring Safely](refactoring-safely.md) — Pre-flight checks before renaming, deleting, or moving symbols. Sequenced, risk-annotated refactoring plans for structural changes.
|
|
26
|
+
|
|
23
27
|
- [Understanding Code History](code-history.md) — Symbol-level git history (not file-level), churn analysis for identifying risk, ownership mapping, and PR analysis before you read a diff
|
|
24
28
|
|
|
25
29
|
---
|
|
@@ -32,6 +36,14 @@ For parameter-level documentation — every tool input, output, and flag — see
|
|
|
32
36
|
|
|
33
37
|
- [Code Health & Architecture Analysis](code-health.md) — Quality metrics, anti-pattern detection, auto-generated architecture docs, CI enforcement, and finding refactoring opportunities before they become crises
|
|
34
38
|
|
|
39
|
+
- [Health Dashboards & Debt Reporting](health-dashboards.md) — Five-axis health radar, before/after PR comparisons, and comprehensive debt reports with prioritized action items
|
|
40
|
+
|
|
41
|
+
- [Visualizing Code Structure](visualizing-code.md) — Mermaid and DOT diagrams of import graphs, call graphs, class hierarchies, and dependency matrices. Architecture snapshots for tracking structural change over time.
|
|
42
|
+
|
|
43
|
+
- [AST-Level Search](ast-search.md) — Find any tree-sitter node type, search by type signature pattern, find symbols by decorator, and filter by complexity thresholds
|
|
44
|
+
|
|
45
|
+
- [Code Intelligence](code-intelligence.md) — Entry points, public API surface, TODO inventory, complexity hotspots, type graphs, untested symbols, and coverage mapping
|
|
46
|
+
|
|
35
47
|
---
|
|
36
48
|
|
|
37
49
|
## For teams and enterprise
|
|
@@ -50,6 +62,8 @@ Complete end-to-end examples showing how PureContext fits into real development
|
|
|
50
62
|
|
|
51
63
|
- [Reviewing a Pull Request](workflow-pr-review.md) — A 40-file authentication migration PR: structured review in 45 minutes that found two real issues before reading most of the diff
|
|
52
64
|
|
|
65
|
+
- [Running a Tech Debt Sprint](workflow-tech-debt.md) — Full lifecycle of a two-week debt reduction sprint: assessment, planning, safe execution, and proving the improvement with snapshots
|
|
66
|
+
|
|
53
67
|
---
|
|
54
68
|
|
|
55
69
|
## Reference Manual
|