purecontext-mcp 1.5.2 → 1.11.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 +18 -10
- package/AGENT_REFERENCE.md +684 -561
- package/CHANGELOG.md +567 -445
- package/CODE-HISTORY.md +29 -1
- package/FRAMEWORK-ADAPTERS.md +368 -351
- package/FULL-INSTALLATION-GUIDE.md +351 -341
- package/README.md +411 -339
- package/REFACTORING-SAFELY.md +338 -279
- package/SAFE-CHANGES.md +208 -156
- package/USER-GUIDE.md +3 -1
- package/WHY-PURECONTEXT.md +103 -73
- package/WORKFLOW-PR-REVIEW.md +245 -199
- package/dist/adapters/astro-preprocessor.d.ts +25 -0
- package/dist/adapters/astro-preprocessor.d.ts.map +1 -0
- package/dist/adapters/astro-preprocessor.js +50 -0
- package/dist/adapters/astro-preprocessor.js.map +1 -0
- package/dist/adapters/astro.d.ts +13 -0
- package/dist/adapters/astro.d.ts.map +1 -0
- package/dist/adapters/astro.js +83 -0
- package/dist/adapters/astro.js.map +1 -0
- package/dist/adapters/detect-utils.d.ts +38 -0
- package/dist/adapters/detect-utils.d.ts.map +1 -0
- package/dist/adapters/detect-utils.js +95 -0
- package/dist/adapters/detect-utils.js.map +1 -0
- package/dist/adapters/nuxt.d.ts +20 -0
- package/dist/adapters/nuxt.d.ts.map +1 -1
- package/dist/adapters/nuxt.js +128 -13
- package/dist/adapters/nuxt.js.map +1 -1
- package/dist/adapters/svelte-preprocessor.d.ts +29 -0
- package/dist/adapters/svelte-preprocessor.d.ts.map +1 -0
- package/dist/adapters/svelte-preprocessor.js +83 -0
- package/dist/adapters/svelte-preprocessor.js.map +1 -0
- package/dist/adapters/svelte.d.ts +13 -0
- package/dist/adapters/svelte.d.ts.map +1 -0
- package/dist/adapters/svelte.js +96 -0
- package/dist/adapters/svelte.js.map +1 -0
- package/dist/adapters/vue.d.ts.map +1 -1
- package/dist/adapters/vue.js +87 -20
- package/dist/adapters/vue.js.map +1 -1
- package/dist/bin.d.ts +16 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +21 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli/hooks.d.ts +2 -2
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +123 -135
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/install-writers.d.ts.map +1 -1
- package/dist/cli/install-writers.js +281 -36
- package/dist/cli/install-writers.js.map +1 -1
- package/dist/cli/resolve-node.d.ts +53 -0
- package/dist/cli/resolve-node.d.ts.map +1 -0
- package/dist/cli/resolve-node.js +84 -0
- package/dist/cli/resolve-node.js.map +1 -0
- package/dist/config/config-loader.js +24 -0
- package/dist/config/config-loader.js.map +1 -1
- package/dist/config/config-schema.d.ts +71 -0
- package/dist/config/config-schema.d.ts.map +1 -1
- package/dist/config/config-schema.js +102 -0
- package/dist/config/config-schema.js.map +1 -1
- package/dist/core/db/api-keys.d.ts +1 -1
- package/dist/core/db/api-keys.d.ts.map +1 -1
- package/dist/core/db/api-keys.js +39 -39
- package/dist/core/db/api-keys.js.map +1 -1
- package/dist/core/db/co-change-store.d.ts +34 -0
- package/dist/core/db/co-change-store.d.ts.map +1 -0
- package/dist/core/db/co-change-store.js +78 -0
- package/dist/core/db/co-change-store.js.map +1 -0
- package/dist/core/db/schema.d.ts +3 -3
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +12 -30
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/db/sqlite-loader.d.ts +51 -0
- package/dist/core/db/sqlite-loader.d.ts.map +1 -0
- package/dist/core/db/sqlite-loader.js +94 -0
- package/dist/core/db/sqlite-loader.js.map +1 -0
- package/dist/core/db/wasm-sqlite.d.ts +4 -0
- package/dist/core/db/wasm-sqlite.d.ts.map +1 -0
- package/dist/core/db/wasm-sqlite.js +270 -0
- package/dist/core/db/wasm-sqlite.js.map +1 -0
- package/dist/core/diff-parser.d.ts.map +1 -1
- package/dist/core/diff-parser.js +6 -1
- package/dist/core/diff-parser.js.map +1 -1
- package/dist/core/git-log-reader.d.ts +28 -0
- package/dist/core/git-log-reader.d.ts.map +1 -1
- package/dist/core/git-log-reader.js +74 -3
- package/dist/core/git-log-reader.js.map +1 -1
- package/dist/core/index-manager.d.ts.map +1 -1
- package/dist/core/index-manager.js +29 -3
- package/dist/core/index-manager.js.map +1 -1
- package/dist/core/indexing-worker.d.ts +2 -0
- package/dist/core/indexing-worker.d.ts.map +1 -1
- package/dist/core/indexing-worker.js +2 -0
- package/dist/core/indexing-worker.js.map +1 -1
- package/dist/core/watcher/file-watcher.d.ts +6 -0
- package/dist/core/watcher/file-watcher.d.ts.map +1 -1
- package/dist/core/watcher/file-watcher.js +11 -1
- package/dist/core/watcher/file-watcher.js.map +1 -1
- package/dist/graph/path-resolver.js +86 -17
- package/dist/graph/path-resolver.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/dist/node-guard.d.ts +15 -0
- package/dist/node-guard.d.ts.map +1 -0
- package/dist/node-guard.js +33 -0
- package/dist/node-guard.js.map +1 -0
- package/dist/server/admin-api.d.ts +1 -1
- package/dist/server/admin-api.d.ts.map +1 -1
- package/dist/server/admin-api.js +2 -2
- package/dist/server/admin-api.js.map +1 -1
- package/dist/server/auth/api-key.d.ts +1 -1
- package/dist/server/auth/api-key.d.ts.map +1 -1
- package/dist/server/mcp-server.d.ts.map +1 -1
- package/dist/server/mcp-server.js +25 -0
- package/dist/server/mcp-server.js.map +1 -1
- package/dist/server/tools/analyze-diff.d.ts +8 -0
- package/dist/server/tools/analyze-diff.d.ts.map +1 -1
- package/dist/server/tools/analyze-diff.js +80 -16
- package/dist/server/tools/analyze-diff.js.map +1 -1
- package/dist/server/tools/change-synthesis.d.ts +90 -0
- package/dist/server/tools/change-synthesis.d.ts.map +1 -0
- package/dist/server/tools/change-synthesis.js +236 -0
- package/dist/server/tools/change-synthesis.js.map +1 -0
- package/dist/server/tools/co-change.d.ts +65 -0
- package/dist/server/tools/co-change.d.ts.map +1 -0
- package/dist/server/tools/co-change.js +146 -0
- package/dist/server/tools/co-change.js.map +1 -0
- package/dist/server/tools/compare-change-impact.d.ts +58 -0
- package/dist/server/tools/compare-change-impact.d.ts.map +1 -0
- package/dist/server/tools/compare-change-impact.js +0 -0
- package/dist/server/tools/compare-change-impact.js.map +1 -0
- package/dist/server/tools/find-refactoring-opportunities.d.ts +1 -1
- package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -1
- package/dist/server/tools/get-architecture-snapshot.js +28 -14
- package/dist/server/tools/get-architecture-snapshot.js.map +1 -1
- package/dist/server/tools/get-churn-metrics.d.ts.map +1 -1
- package/dist/server/tools/get-churn-metrics.js +1 -12
- package/dist/server/tools/get-churn-metrics.js.map +1 -1
- package/dist/server/tools/get-co-change.d.ts +37 -0
- package/dist/server/tools/get-co-change.d.ts.map +1 -0
- package/dist/server/tools/get-co-change.js +120 -0
- package/dist/server/tools/get-co-change.js.map +1 -0
- package/dist/server/tools/get-context-bundle.d.ts.map +1 -1
- package/dist/server/tools/get-context-bundle.js +56 -3
- package/dist/server/tools/get-context-bundle.js.map +1 -1
- package/dist/server/tools/get-entry-points.d.ts +1 -1
- package/dist/server/tools/get-symbol-risk.d.ts +25 -0
- package/dist/server/tools/get-symbol-risk.d.ts.map +1 -0
- package/dist/server/tools/get-symbol-risk.js +60 -0
- package/dist/server/tools/get-symbol-risk.js.map +1 -0
- package/dist/server/tools/get-symbol-source.d.ts +2 -0
- package/dist/server/tools/get-symbol-source.d.ts.map +1 -1
- package/dist/server/tools/get-symbol-source.js +18 -1
- package/dist/server/tools/get-symbol-source.js.map +1 -1
- package/dist/server/tools/index-repo.d.ts.map +1 -1
- package/dist/server/tools/index-repo.js +8 -2
- package/dist/server/tools/index-repo.js.map +1 -1
- package/dist/server/tools/prepare-change.d.ts +61 -0
- package/dist/server/tools/prepare-change.d.ts.map +1 -0
- package/dist/server/tools/prepare-change.js +262 -0
- package/dist/server/tools/prepare-change.js.map +1 -0
- package/dist/server/tools/search-symbols.d.ts +2 -0
- package/dist/server/tools/search-symbols.d.ts.map +1 -1
- package/dist/server/tools/search-symbols.js +33 -0
- package/dist/server/tools/search-symbols.js.map +1 -1
- package/dist/server/tools/symbol-lines.d.ts +25 -0
- package/dist/server/tools/symbol-lines.d.ts.map +1 -0
- package/dist/server/tools/symbol-lines.js +40 -0
- package/dist/server/tools/symbol-lines.js.map +1 -0
- package/dist/server/tools/symbol-risk.d.ts +109 -0
- package/dist/server/tools/symbol-risk.d.ts.map +1 -0
- package/dist/server/tools/symbol-risk.js +251 -0
- package/dist/server/tools/symbol-risk.js.map +1 -0
- package/dist/server/tools/verify-change.d.ts +40 -0
- package/dist/server/tools/verify-change.d.ts.map +1 -0
- package/dist/server/tools/verify-change.js +149 -0
- package/dist/server/tools/verify-change.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/01-introduction.md +2 -2
- package/docs/02-installation.md +97 -89
- package/docs/03-quick-start.md +138 -135
- package/docs/04-configuration.md +247 -214
- package/docs/05-cli-reference.md +236 -219
- package/docs/06-tools-reference.md +902 -499
- package/docs/14-transport-modes.md +170 -167
- package/docs/18-git-history.md +43 -0
- package/docs/23-performance.md +123 -121
- package/docs/26-troubleshooting.md +249 -234
- package/grammars/README.md +88 -0
- package/package.json +7 -25
- package/AGENT_INSTRUCTIONS_SHORT.md +0 -150
package/WORKFLOW-PR-REVIEW.md
CHANGED
|
@@ -1,199 +1,245 @@
|
|
|
1
|
-
# Workflow: Reviewing a Pull Request
|
|
2
|
-
|
|
3
|
-
**Scenario:** It's Tuesday morning. You open GitHub and find a pull request sitting in your queue: "Migrate user authentication to OAuth2 — 40 files changed." You're the designated reviewer. The author is a colleague you trust, but this is a large, cross-cutting change affecting the core authentication flow. You have about 45 minutes before your next meeting.
|
|
4
|
-
|
|
5
|
-
Without context, you'd start reading diffs top to bottom, hoping to understand the intent as you go. With PureContext, you start by understanding the impact, then read strategically.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Step 1: Understand the scope before reading anything
|
|
10
|
-
|
|
11
|
-
**You:** "I have a PR to review — 40 files changed in the authentication migration. Before I read any diffs, give me a symbol-level analysis of what actually changed."
|
|
12
|
-
|
|
13
|
-
**Claude** calls `analyze_diff(base: "main", head: "feature/oauth2-migration")`:
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
Symbols modified (signature changed — potential breaking changes):
|
|
17
|
-
authenticateUser() apps/auth/validator.py signature changed
|
|
18
|
-
require_auth apps/auth/decorators.py implementation changed
|
|
19
|
-
UserPermissions apps/core/types.py fields added
|
|
20
|
-
|
|
21
|
-
Symbols modified (implementation only — no signature change):
|
|
22
|
-
JWTMiddleware apps/auth/middleware.py replaced internally
|
|
23
|
-
createSession() apps/auth/session.py updated token format
|
|
24
|
-
... (12 more)
|
|
25
|
-
|
|
26
|
-
Symbols added (new in this PR):
|
|
27
|
-
OAuthClient apps/auth/oauth2.py new class
|
|
28
|
-
exchangeOAuthCode() apps/auth/oauth2.py new
|
|
29
|
-
refreshOAuthToken() apps/auth/oauth2.py new
|
|
30
|
-
OAuthCallbackView apps/auth/views.py new
|
|
31
|
-
... (8 more)
|
|
32
|
-
|
|
33
|
-
Symbols deleted:
|
|
34
|
-
generateLegacyToken() apps/auth/legacy.py removed
|
|
35
|
-
OldSessionManager apps/auth/sessions.py removed
|
|
36
|
-
validateBasicAuth() apps/auth/basic.py removed
|
|
37
|
-
|
|
38
|
-
Blast radius of modified symbols: 47 files
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
**
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
**
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
**
|
|
198
|
-
|
|
199
|
-
|
|
1
|
+
# Workflow: Reviewing a Pull Request
|
|
2
|
+
|
|
3
|
+
**Scenario:** It's Tuesday morning. You open GitHub and find a pull request sitting in your queue: "Migrate user authentication to OAuth2 — 40 files changed." You're the designated reviewer. The author is a colleague you trust, but this is a large, cross-cutting change affecting the core authentication flow. You have about 45 minutes before your next meeting.
|
|
4
|
+
|
|
5
|
+
Without context, you'd start reading diffs top to bottom, hoping to understand the intent as you go. With PureContext, you start by understanding the impact, then read strategically.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Step 1: Understand the scope before reading anything
|
|
10
|
+
|
|
11
|
+
**You:** "I have a PR to review — 40 files changed in the authentication migration. Before I read any diffs, give me a symbol-level analysis of what actually changed."
|
|
12
|
+
|
|
13
|
+
**Claude** calls `analyze_diff(base: "main", head: "feature/oauth2-migration")`:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Symbols modified (signature changed — potential breaking changes):
|
|
17
|
+
authenticateUser() apps/auth/validator.py signature changed
|
|
18
|
+
require_auth apps/auth/decorators.py implementation changed
|
|
19
|
+
UserPermissions apps/core/types.py fields added
|
|
20
|
+
|
|
21
|
+
Symbols modified (implementation only — no signature change):
|
|
22
|
+
JWTMiddleware apps/auth/middleware.py replaced internally
|
|
23
|
+
createSession() apps/auth/session.py updated token format
|
|
24
|
+
... (12 more)
|
|
25
|
+
|
|
26
|
+
Symbols added (new in this PR):
|
|
27
|
+
OAuthClient apps/auth/oauth2.py new class
|
|
28
|
+
exchangeOAuthCode() apps/auth/oauth2.py new
|
|
29
|
+
refreshOAuthToken() apps/auth/oauth2.py new
|
|
30
|
+
OAuthCallbackView apps/auth/views.py new
|
|
31
|
+
... (8 more)
|
|
32
|
+
|
|
33
|
+
Symbols deleted:
|
|
34
|
+
generateLegacyToken() apps/auth/legacy.py removed
|
|
35
|
+
OldSessionManager apps/auth/sessions.py removed
|
|
36
|
+
validateBasicAuth() apps/auth/basic.py removed
|
|
37
|
+
|
|
38
|
+
Blast radius of modified symbols: 47 files
|
|
39
|
+
|
|
40
|
+
Aggregate risk: HIGH
|
|
41
|
+
authenticate_user high (78/100) — 6 dependents · churn 9/90d · signature changed
|
|
42
|
+
require_auth high (71/100) — wraps 134 views · co-changes with middleware tests
|
|
43
|
+
|
|
44
|
+
missingCoChange (historically move with the edited files, but NOT in this PR):
|
|
45
|
+
apps/auth/sso_config.py (confidence 0.62) ← SSO config usually changes with the auth flow
|
|
46
|
+
tests/auth/test_sso.py (confidence 0.55)
|
|
47
|
+
|
|
48
|
+
coverageGaps (changed symbols with no detected test):
|
|
49
|
+
OAuthCallbackView apps/auth/views.py
|
|
50
|
+
|
|
51
|
+
recommendedTests:
|
|
52
|
+
tests/auth/test_middleware.py · tests/auth/test_decorators.py
|
|
53
|
+
|
|
54
|
+
architecturalFlags:
|
|
55
|
+
(none — changed files don't currently sit on a cycle or cross a layer boundary)
|
|
56
|
+
|
|
57
|
+
Review priority: CRITICAL (signature breaks + high aggregate risk)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
In 30 seconds you know — without reading a diff:
|
|
61
|
+
- The signature of `authenticateUser` changed and it scores **high** composite risk — everything that calls it must be checked
|
|
62
|
+
- `require_auth` was modified — it wraps 134 view functions, so behavior changes here affect the entire application
|
|
63
|
+
- Three symbols were deleted — are they truly dead, or are there call sites the PR missed?
|
|
64
|
+
- The real blast radius is 47 files, not 40 (some impact is indirect)
|
|
65
|
+
- **`missingCoChange` is the senior-reviewer instinct made explicit:** `sso_config.py` and `test_sso.py` historically move with the auth flow but aren't in this PR — likely an omission to ask the author about
|
|
66
|
+
- `OAuthCallbackView` ships with no test
|
|
67
|
+
|
|
68
|
+
`analyze_diff` returns all of this in one call (the risk / co-change / test / flag sections default on; switch any off for cheap runs). This frames your entire review before you've read a diff.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Step 2: Verify the deleted symbols were actually unused
|
|
73
|
+
|
|
74
|
+
The deleted symbols are the first concern. Deleting code that's still called causes a runtime error.
|
|
75
|
+
|
|
76
|
+
**You:** "Three symbols were deleted. Verify that they had no importers in main — confirm they were actually dead code before this PR."
|
|
77
|
+
|
|
78
|
+
**Claude** calls `get_blast_radius` on each deleted symbol against the main branch index:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
generateLegacyToken() — 0 importers in main (confirmed dead)
|
|
82
|
+
OldSessionManager — 0 importers in main (confirmed dead)
|
|
83
|
+
validateBasicAuth() — 0 importers in main (confirmed dead)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
All three confirmed dead. The author cleaned up dead code correctly. This concern is closed.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step 3: Check the signature change for `authenticateUser`
|
|
91
|
+
|
|
92
|
+
A signature change to a function is the highest-risk change in any PR. It means every call site needs to handle the new interface.
|
|
93
|
+
|
|
94
|
+
**You:** "authenticateUser changed its signature. Show me the old signature, the new one, and all the places that call it."
|
|
95
|
+
|
|
96
|
+
**Claude** retrieves the symbol history for `authenticateUser` and the current source:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Old signature (main):
|
|
100
|
+
def authenticate_user(username: str, password: str) -> Optional[User]
|
|
101
|
+
|
|
102
|
+
New signature (this PR):
|
|
103
|
+
def authenticate_user(credentials: OAuthCredentials | PasswordCredentials) -> AuthResult
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The parameter type changed from two positional strings to a union type, and the return type changed from `Optional[User]` to `AuthResult`. This is a significant interface change.
|
|
107
|
+
|
|
108
|
+
**Claude** calls `find_references(symbolId: "authenticateUser")` on the current branch:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
authenticate_user() is called in 6 places:
|
|
112
|
+
|
|
113
|
+
apps/auth/views.py:45 LoginView.post() ← using new signature ✓
|
|
114
|
+
apps/users/tests/test_auth.py:23 test_login() ← updated ✓
|
|
115
|
+
apps/users/tests/test_auth.py:67 test_lockout() ← updated ✓
|
|
116
|
+
apps/api/auth.py:89 api_login() ← using new signature ✓
|
|
117
|
+
apps/admin/views.py:134 admin_login() ← still using old signature ✗
|
|
118
|
+
apps/integrations/sso.py:67 sso_authenticate() ← still using old signature ✗
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Two call sites weren't updated. `admin_login` and `sso_authenticate` are still passing two positional string arguments. This is a bug in the PR — it would pass type checking if the types weren't enforced strictly, but would fail at runtime.
|
|
122
|
+
|
|
123
|
+
You've found the blocking issue in the PR. Two minutes into the review.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Step 4: Verify the critical path
|
|
128
|
+
|
|
129
|
+
`require_auth` is the decorator used by 134 views. It was modified. You need to know the modification is backward compatible.
|
|
130
|
+
|
|
131
|
+
**You:** "require_auth was modified. Show me what changed and verify that all 134 views that use it still work with the new implementation."
|
|
132
|
+
|
|
133
|
+
**Claude** retrieves the new source for `require_auth`:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
def require_auth(view_func):
|
|
137
|
+
@wraps(view_func)
|
|
138
|
+
def wrapper(request, *args, **kwargs):
|
|
139
|
+
# NEW: Accept both JWT (legacy) and OAuth2 Bearer tokens
|
|
140
|
+
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
|
|
141
|
+
if auth_header.startswith('Bearer '):
|
|
142
|
+
user = authenticate_oauth_token(auth_header[7:])
|
|
143
|
+
else:
|
|
144
|
+
user = authenticate_jwt_token(request) # legacy path preserved
|
|
145
|
+
if user is None:
|
|
146
|
+
return HttpResponse(status=401)
|
|
147
|
+
request.user = user
|
|
148
|
+
return view_func(request, *args, **kwargs)
|
|
149
|
+
return wrapper
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The implementation accepts both token formats — OAuth2 Bearer tokens and the legacy JWT. The 134 decorated views don't need to be updated because the decorator handles the transition transparently. This is a good implementation decision, and it's verifiable from the code.
|
|
153
|
+
|
|
154
|
+
**You:** "This looks correct — it's a compatible shim. But check: is there any test that specifically covers the JWT fallback path in the new implementation?"
|
|
155
|
+
|
|
156
|
+
**Claude** calls `search_symbols(query: "authenticate_jwt_token", filePath: "tests/**")`:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
authenticate_jwt_token referenced in tests:
|
|
160
|
+
tests/auth/test_middleware.py test_jwt_fallback() ← exists ✓
|
|
161
|
+
tests/auth/test_decorators.py test_require_auth() ← exists ✓
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The fallback path is tested. The implementation is sound.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Step 5: Check for any missed text-level dependencies
|
|
169
|
+
|
|
170
|
+
Symbol analysis catches structured dependencies. But JWT-specific string patterns — cache keys, token format strings, configuration keys — might be missed.
|
|
171
|
+
|
|
172
|
+
**You:** "Search for any remaining references to the old JWT configuration key or the old session format that might have been missed."
|
|
173
|
+
|
|
174
|
+
**Claude** calls `search_text(query: "JWT_SECRET", filePath: "**/*.py")`:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
Remaining JWT_SECRET references:
|
|
178
|
+
apps/auth/oauth2.py:156 settings.JWT_SECRET ← why does the new OAuth module reference this?
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Unexpected. The new OAuth2 module references `JWT_SECRET`. You open the source:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
# Temporary: use JWT_SECRET as the OAuth state parameter signing key
|
|
185
|
+
# TODO: Replace with dedicated OAUTH_STATE_SECRET before merge
|
|
186
|
+
state_sig = hmac.new(settings.JWT_SECRET.encode(), ...)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The author left a TODO comment but didn't create a separate configuration key. This is a code smell — the OAuth implementation is reusing the JWT secret for a different purpose, which violates key isolation. Flag it in the review.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Step 6: Did the migration make the architecture worse?
|
|
194
|
+
|
|
195
|
+
A 40-file migration is exactly the kind of change that quietly introduces a new import cycle or layer violation. If a baseline architecture snapshot was taken on `main` (e.g. in CI before the branch diverged), `compare_change_impact` reports only what *this* change introduced.
|
|
196
|
+
|
|
197
|
+
**You:** "Did this PR introduce any new import cycles or layer violations versus main?"
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
compare_change_impact(repoId, baselineSnapshotId: "main-baseline") →
|
|
201
|
+
|
|
202
|
+
verdict: "regressed"
|
|
203
|
+
newCycles: [ [ "apps/auth/oauth2.py", "apps/auth/views.py", "apps/auth/oauth2.py" ] ]
|
|
204
|
+
newLayerViolations: [ ]
|
|
205
|
+
resolvedCycles: [ ]
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
A new cycle between `oauth2.py` and `views.py` that did not exist on `main` — introduced by this PR. Unlike `analyze_diff`'s `architecturalFlags` (which flag *pre-existing* structure), this is a genuine regression to raise. (The PR author can run the same check locally before pushing — and `verify_change` to confirm they covered the `missingCoChange` files surfaced in Step 1.)
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## The review summary
|
|
213
|
+
|
|
214
|
+
45 minutes, structured review. Findings:
|
|
215
|
+
|
|
216
|
+
| Finding | Severity | Location |
|
|
217
|
+
|---------|----------|----------|
|
|
218
|
+
| `authenticate_user` called with old signature | **Blocking** | `admin/views.py:134`, `integrations/sso.py:67` |
|
|
219
|
+
| New import cycle introduced (oauth2 ⇄ views) | **Blocking** | `auth/oauth2.py` ⇄ `auth/views.py` |
|
|
220
|
+
| JWT secret reused as OAuth state signing key | **Major** — flag before merge | `auth/oauth2.py:156` |
|
|
221
|
+
| SSO config historically co-changes but absent from PR | **Question for author** | `auth/sso_config.py` |
|
|
222
|
+
| `OAuthCallbackView` ships with no test | **Minor** | `auth/views.py` |
|
|
223
|
+
| Deleted symbols confirmed dead | **Pass** | legacy.py, sessions.py, basic.py |
|
|
224
|
+
| `require_auth` shim correctly backward compatible | **Pass** | auth/decorators.py |
|
|
225
|
+
| Legacy fallback path covered by tests | **Pass** | tests/auth/ |
|
|
226
|
+
|
|
227
|
+
You found two real issues — one blocking, one major — before reading most of the diff. The blocking issue (two call sites using the wrong signature) would have been a runtime error in production. The major issue (key reuse) is a security design problem.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## What made this review effective
|
|
232
|
+
|
|
233
|
+
**Start with impact, not diffs.** `analyze_diff` gave you the symbol-level map before you read anything. You knew where to focus.
|
|
234
|
+
|
|
235
|
+
**Verify deletions first.** Deleted code that's still called is the most dangerous class of PR error. Checking blast radius for deleted symbols takes 30 seconds and catches the worst case.
|
|
236
|
+
|
|
237
|
+
**Find all call sites for signature changes.** `find_references` across the branch revealed the two missed call sites that static analysis alone might have missed in a dynamically typed codebase.
|
|
238
|
+
|
|
239
|
+
**Use text search for string-level dependencies.** Symbol analysis doesn't catch JWT_SECRET usage in string context. Text search does.
|
|
240
|
+
|
|
241
|
+
**Know when to stop.** With the two blocking issues identified and the critical path verified, you have what you need to write a meaningful review. You don't need to read all 40 diffs to give a quality review — you need to read the right ones.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
→ Reference: [MCP Tools Reference](docs/06-tools-reference.md) — `analyze_diff`, `compare_change_impact`, `verify_change`, `prepare_change`, `find_references`, `get_blast_radius`, `get_symbol_history`, `search_text`
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astro component pre-processor.
|
|
3
|
+
*
|
|
4
|
+
* An .astro file begins with an optional "frontmatter" block fenced by `---`
|
|
5
|
+
* lines at the very top of the file; its contents are TypeScript. The remainder
|
|
6
|
+
* is HTML-like template with JSX-style expressions and component usage, which we
|
|
7
|
+
* do not index for symbols.
|
|
8
|
+
*
|
|
9
|
+
* This extracts the leading frontmatter as a single TypeScript ProcessedBlock.
|
|
10
|
+
*
|
|
11
|
+
* Byte-offset correctness:
|
|
12
|
+
* offsetInOriginal is computed from Buffer.byteLength() of the prefix up to and
|
|
13
|
+
* including the opening fence, never from string character indices.
|
|
14
|
+
*/
|
|
15
|
+
import type { ProcessedBlock } from '../core/types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Extract the leading `---`-fenced frontmatter of an Astro component as a single
|
|
18
|
+
* TypeScript block. The fence must be the first non-whitespace content in the
|
|
19
|
+
* file (`---` appearing later in markup is ignored).
|
|
20
|
+
*
|
|
21
|
+
* Returns [] when there is no leading frontmatter.
|
|
22
|
+
* Throws ParseError when a leading fence is opened but never closed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function splitAstroSFC(source: Buffer, filePath: string): ProcessedBlock[];
|
|
25
|
+
//# sourceMappingURL=astro-preprocessor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro-preprocessor.d.ts","sourceRoot":"","sources":["../../src/adapters/astro-preprocessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAKvD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CA6BhF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astro component pre-processor.
|
|
3
|
+
*
|
|
4
|
+
* An .astro file begins with an optional "frontmatter" block fenced by `---`
|
|
5
|
+
* lines at the very top of the file; its contents are TypeScript. The remainder
|
|
6
|
+
* is HTML-like template with JSX-style expressions and component usage, which we
|
|
7
|
+
* do not index for symbols.
|
|
8
|
+
*
|
|
9
|
+
* This extracts the leading frontmatter as a single TypeScript ProcessedBlock.
|
|
10
|
+
*
|
|
11
|
+
* Byte-offset correctness:
|
|
12
|
+
* offsetInOriginal is computed from Buffer.byteLength() of the prefix up to and
|
|
13
|
+
* including the opening fence, never from string character indices.
|
|
14
|
+
*/
|
|
15
|
+
import { ParseError } from '../core/errors.js';
|
|
16
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
17
|
+
/**
|
|
18
|
+
* Extract the leading `---`-fenced frontmatter of an Astro component as a single
|
|
19
|
+
* TypeScript block. The fence must be the first non-whitespace content in the
|
|
20
|
+
* file (`---` appearing later in markup is ignored).
|
|
21
|
+
*
|
|
22
|
+
* Returns [] when there is no leading frontmatter.
|
|
23
|
+
* Throws ParseError when a leading fence is opened but never closed.
|
|
24
|
+
*/
|
|
25
|
+
export function splitAstroSFC(source, filePath) {
|
|
26
|
+
const str = source.toString('utf8');
|
|
27
|
+
// The opening fence must be the first non-whitespace content. A line of
|
|
28
|
+
// exactly `---` (optionally with trailing spaces) starting the file.
|
|
29
|
+
const openMatch = str.match(/^\s*---[ \t]*\r?\n/);
|
|
30
|
+
if (!openMatch) {
|
|
31
|
+
return []; // no frontmatter
|
|
32
|
+
}
|
|
33
|
+
const openLen = openMatch[0].length; // chars consumed by leading ws + `---` + newline
|
|
34
|
+
const rest = str.slice(openLen);
|
|
35
|
+
// Closing fence: a line that is exactly `---` (optionally trailing spaces).
|
|
36
|
+
const closeMatch = rest.match(/\r?\n[ \t]*---[ \t]*(?:\r?\n|$)/);
|
|
37
|
+
if (!closeMatch) {
|
|
38
|
+
throw new ParseError(`Malformed Astro component: unterminated frontmatter fence`, filePath);
|
|
39
|
+
}
|
|
40
|
+
const innerContent = rest.slice(0, closeMatch.index);
|
|
41
|
+
const offsetInOriginal = Buffer.byteLength(str.slice(0, openLen), 'utf8');
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
content: Buffer.from(innerContent, 'utf8'),
|
|
45
|
+
language: 'typescript',
|
|
46
|
+
offsetInOriginal,
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=astro-preprocessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro-preprocessor.js","sourceRoot":"","sources":["../../src/adapters/astro-preprocessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,iFAAiF;AAEjF;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,QAAgB;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEpC,wEAAwE;IACxE,qEAAqE;IACrE,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAClD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,CAAC,CAAC,iBAAiB;IAC9B,CAAC;IAED,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,iDAAiD;IACtF,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAEhC,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACjE,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,UAAU,CAAC,2DAA2D,EAAE,QAAQ,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAE1E,OAAO;QACL;YACE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC;YAC1C,QAAQ,EAAE,YAAY;YACtB,gBAAgB;SACjB;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Astro framework adapter.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* 1. Detect Astro projects (package.json declares `astro`/`@astrojs/*`,
|
|
6
|
+
* an astro.config.* file, or `.astro` files present — incl. monorepo sub-apps).
|
|
7
|
+
* 2. Pre-process .astro components: extract the leading `---` frontmatter as a
|
|
8
|
+
* TypeScript block via astro-preprocessor.
|
|
9
|
+
* 3. Emit one `component` symbol per .astro file (name derived from filename).
|
|
10
|
+
*/
|
|
11
|
+
import type { FrameworkAdapter } from '../core/types.js';
|
|
12
|
+
export declare const astroAdapter: FrameworkAdapter;
|
|
13
|
+
//# sourceMappingURL=astro.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.d.ts","sourceRoot":"","sources":["../../src/adapters/astro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,kBAAkB,CAAC;AAyB7E,eAAO,MAAM,YAAY,EAAE,gBA0D1B,CAAC"}
|