projscan 0.12.0 → 0.14.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.
Files changed (105) hide show
  1. package/README.md +18 -13
  2. package/dist/analyzers/crossPackageImportCheck.d.ts +13 -0
  3. package/dist/analyzers/crossPackageImportCheck.js +136 -0
  4. package/dist/analyzers/crossPackageImportCheck.js.map +1 -0
  5. package/dist/analyzers/cycleCheck.d.ts +12 -0
  6. package/dist/analyzers/cycleCheck.js +65 -0
  7. package/dist/analyzers/cycleCheck.js.map +1 -0
  8. package/dist/cli/commands/audit.js +8 -2
  9. package/dist/cli/commands/audit.js.map +1 -1
  10. package/dist/cli/commands/dependencies.js +4 -3
  11. package/dist/cli/commands/dependencies.js.map +1 -1
  12. package/dist/cli/commands/explainIssue.d.ts +1 -0
  13. package/dist/cli/commands/explainIssue.js +49 -0
  14. package/dist/cli/commands/explainIssue.js.map +1 -0
  15. package/dist/cli/commands/fixSuggest.d.ts +1 -0
  16. package/dist/cli/commands/fixSuggest.js +71 -0
  17. package/dist/cli/commands/fixSuggest.js.map +1 -0
  18. package/dist/cli/commands/review.d.ts +1 -0
  19. package/dist/cli/commands/review.js +66 -0
  20. package/dist/cli/commands/review.js.map +1 -0
  21. package/dist/cli/index.js +6 -0
  22. package/dist/cli/index.js.map +1 -1
  23. package/dist/core/ast.d.ts +20 -0
  24. package/dist/core/ast.js +190 -0
  25. package/dist/core/ast.js.map +1 -1
  26. package/dist/core/auditRunner.d.ts +8 -0
  27. package/dist/core/auditRunner.js +50 -1
  28. package/dist/core/auditRunner.js.map +1 -1
  29. package/dist/core/codeGraph.d.ts +7 -1
  30. package/dist/core/codeGraph.js +2 -0
  31. package/dist/core/codeGraph.js.map +1 -1
  32. package/dist/core/dependencyAnalyzer.d.ts +15 -1
  33. package/dist/core/dependencyAnalyzer.js +115 -18
  34. package/dist/core/dependencyAnalyzer.js.map +1 -1
  35. package/dist/core/explainIssue.d.ts +9 -0
  36. package/dist/core/explainIssue.js +106 -0
  37. package/dist/core/explainIssue.js.map +1 -0
  38. package/dist/core/fileInspector.js +12 -0
  39. package/dist/core/fileInspector.js.map +1 -1
  40. package/dist/core/fixSuggest.d.ts +41 -0
  41. package/dist/core/fixSuggest.js +327 -0
  42. package/dist/core/fixSuggest.js.map +1 -0
  43. package/dist/core/indexCache.js +5 -1
  44. package/dist/core/indexCache.js.map +1 -1
  45. package/dist/core/issueEngine.js +18 -0
  46. package/dist/core/issueEngine.js.map +1 -1
  47. package/dist/core/languages/goAdapter.js +5 -0
  48. package/dist/core/languages/goAdapter.js.map +1 -1
  49. package/dist/core/languages/goFunctions.d.ts +24 -0
  50. package/dist/core/languages/goFunctions.js +99 -0
  51. package/dist/core/languages/goFunctions.js.map +1 -0
  52. package/dist/core/languages/javaAdapter.js +5 -0
  53. package/dist/core/languages/javaAdapter.js.map +1 -1
  54. package/dist/core/languages/javaFunctions.d.ts +22 -0
  55. package/dist/core/languages/javaFunctions.js +87 -0
  56. package/dist/core/languages/javaFunctions.js.map +1 -0
  57. package/dist/core/languages/pythonAdapter.js +5 -0
  58. package/dist/core/languages/pythonAdapter.js.map +1 -1
  59. package/dist/core/languages/pythonFunctions.d.ts +23 -0
  60. package/dist/core/languages/pythonFunctions.js +87 -0
  61. package/dist/core/languages/pythonFunctions.js.map +1 -0
  62. package/dist/core/languages/rubyAdapter.js +5 -0
  63. package/dist/core/languages/rubyAdapter.js.map +1 -1
  64. package/dist/core/languages/rubyFunctions.d.ts +22 -0
  65. package/dist/core/languages/rubyFunctions.js +91 -0
  66. package/dist/core/languages/rubyFunctions.js.map +1 -0
  67. package/dist/core/review.d.ts +21 -0
  68. package/dist/core/review.js +457 -0
  69. package/dist/core/review.js.map +1 -0
  70. package/dist/index.d.ts +5 -1
  71. package/dist/index.js +3 -0
  72. package/dist/index.js.map +1 -1
  73. package/dist/mcp/tools/audit.js +7 -2
  74. package/dist/mcp/tools/audit.js.map +1 -1
  75. package/dist/mcp/tools/dependencies.js +11 -5
  76. package/dist/mcp/tools/dependencies.js.map +1 -1
  77. package/dist/mcp/tools/explainIssue.d.ts +2 -0
  78. package/dist/mcp/tools/explainIssue.js +30 -0
  79. package/dist/mcp/tools/explainIssue.js.map +1 -0
  80. package/dist/mcp/tools/file.js +1 -1
  81. package/dist/mcp/tools/file.js.map +1 -1
  82. package/dist/mcp/tools/fixSuggest.d.ts +2 -0
  83. package/dist/mcp/tools/fixSuggest.js +57 -0
  84. package/dist/mcp/tools/fixSuggest.js.map +1 -0
  85. package/dist/mcp/tools/hotspots.js +40 -1
  86. package/dist/mcp/tools/hotspots.js.map +1 -1
  87. package/dist/mcp/tools/review.d.ts +2 -0
  88. package/dist/mcp/tools/review.js +54 -0
  89. package/dist/mcp/tools/review.js.map +1 -0
  90. package/dist/mcp/tools.js +6 -0
  91. package/dist/mcp/tools.js.map +1 -1
  92. package/dist/reporters/consoleReporter.d.ts +9 -1
  93. package/dist/reporters/consoleReporter.js +177 -0
  94. package/dist/reporters/consoleReporter.js.map +1 -1
  95. package/dist/reporters/jsonReporter.d.ts +9 -1
  96. package/dist/reporters/jsonReporter.js +9 -0
  97. package/dist/reporters/jsonReporter.js.map +1 -1
  98. package/dist/reporters/markdownReporter.d.ts +9 -1
  99. package/dist/reporters/markdownReporter.js +141 -0
  100. package/dist/reporters/markdownReporter.js.map +1 -1
  101. package/dist/tool-manifest.json +96 -8
  102. package/dist/types.d.ts +228 -0
  103. package/dist/utils/config.js +27 -0
  104. package/dist/utils/config.js.map +1 -1
  105. package/package.json +4 -2
@@ -0,0 +1,327 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs/promises';
3
+ const TEMPLATES = [
4
+ // ── Dependencies ──────────────────────────────────────────
5
+ {
6
+ match: (i) => i.id.startsWith('unused-dependency-'),
7
+ render: (i) => ({
8
+ issueId: i.id,
9
+ severity: i.severity,
10
+ category: i.category,
11
+ headline: `Unused dependency: ${parseDepName(i.id)}`,
12
+ why: 'Declaring a package you never import bloats install size, slows CI, and confuses reviewers about what the project actually depends on. ' +
13
+ 'projscan flags it because no source file under this manifest imports the name.',
14
+ where: i.locations ?? [],
15
+ instruction: `Either (a) remove "${parseDepName(i.id)}" from the relevant package.json dependencies/devDependencies block, or ` +
16
+ `(b) confirm it's used implicitly (e.g. plugin loaded by tooling, type-only import) and add it to .projscanrc \`disableRules: ["${i.id}"]\` ` +
17
+ 'so projscan stops flagging it. Run the test suite + a build after the change.',
18
+ suggestedTest: 'After removal: `npm install && npm test && npm run build`. CI must pass on all three matrix entries.',
19
+ }),
20
+ },
21
+ {
22
+ match: (i) => i.id === 'dep-risk-no-lockfile',
23
+ render: (i) => ({
24
+ issueId: i.id,
25
+ severity: i.severity,
26
+ category: i.category,
27
+ headline: 'No lockfile found',
28
+ why: 'Without a lockfile, every install resolves transitive deps fresh - which means CI and the contributor next door can each get different versions. ' +
29
+ 'Reproducible builds need a locked dependency tree.',
30
+ where: [{ file: 'package.json' }],
31
+ instruction: 'Run `npm install` (or `pnpm install` / `yarn install` / `bun install` depending on what the team uses) at the repo root, then commit the resulting lockfile. ' +
32
+ "Add it to .gitignore exceptions if your top-level .gitignore overshadows it. Don't hand-edit lockfiles.",
33
+ suggestedTest: 'After committing the lockfile, run `npm ci` (which fails if the lockfile is out of sync) - it should succeed.',
34
+ }),
35
+ },
36
+ {
37
+ match: (i) => i.id === 'dep-risk-excessive-dependencies' || i.id === 'dep-risk-many-dependencies',
38
+ render: (i) => ({
39
+ issueId: i.id,
40
+ severity: i.severity,
41
+ category: i.category,
42
+ headline: i.title,
43
+ why: 'High dependency counts compound supply-chain risk and slow installs. Beyond ~50 prod deps, projects rarely need every one - some are dead, some are duplicates, some have native replacements.',
44
+ where: [{ file: 'package.json' }],
45
+ instruction: 'Run `projscan_dependencies` to see the full list, then `projscan_outdated` and `projscan_audit` for surface area. ' +
46
+ 'For each dep that looks suspicious, run `projscan_graph { direction: "package_importers", target: "<name>" }` to see what (if anything) actually uses it. ' +
47
+ 'Drop the ones with zero importers; consider native replacements for shimming-shaped deps (e.g. `lodash/get` → optional chaining).',
48
+ }),
49
+ },
50
+ {
51
+ match: (i) => i.id.startsWith('dep-risk-') &&
52
+ !['dep-risk-no-lockfile', 'dep-risk-excessive-dependencies', 'dep-risk-many-dependencies'].includes(i.id),
53
+ render: (i) => {
54
+ const name = i.id.slice('dep-risk-'.length);
55
+ return {
56
+ issueId: i.id,
57
+ severity: i.severity,
58
+ category: i.category,
59
+ headline: i.title,
60
+ why: i.description,
61
+ where: i.locations ?? [{ file: 'package.json' }],
62
+ instruction: `Audit "${name}": call \`projscan_graph { direction: "package_importers", target: "${name}" }\` to see who imports it. ` +
63
+ `If it can be replaced with a lighter/native alternative, plan that migration; if it must stay, pin to an exact version (drop the \`^\` / \`>=\`) and document the choice.`,
64
+ };
65
+ },
66
+ },
67
+ {
68
+ match: (i) => i.id.startsWith('audit-'),
69
+ render: (i) => {
70
+ const name = i.id.slice('audit-'.length);
71
+ return {
72
+ issueId: i.id,
73
+ severity: i.severity,
74
+ category: i.category,
75
+ headline: i.title,
76
+ why: 'A vulnerability in a dep means whatever class of attack it enables (RCE, prototype pollution, ReDoS, etc.) is reachable through your dependency surface. ' +
77
+ 'Severity reflects the published advisory.',
78
+ where: i.locations ?? [{ file: 'package.json' }],
79
+ instruction: `Try \`npm audit fix\` first - it bumps to the nearest non-vulnerable version when one exists. If that fails: run \`projscan_upgrade { package: "${name}" }\` to preview the upgrade impact, ` +
80
+ 'then bump manually. If no patched version exists yet, consider replacing the dep or pinning to a specific transitive resolution via npm `overrides`.',
81
+ };
82
+ },
83
+ },
84
+ // ── Architecture ──────────────────────────────────────────
85
+ {
86
+ match: (i) => i.id.startsWith('cycle-detected-'),
87
+ render: (i) => ({
88
+ issueId: i.id,
89
+ severity: i.severity,
90
+ category: i.category,
91
+ headline: 'Circular import',
92
+ why: 'Circular imports defeat module-init order, break tree-shaking, and produce undefined-at-import errors that only surface in some build configurations. ' +
93
+ 'They also make refactoring brittle: every file in the cycle has to change together.',
94
+ where: i.locations ?? [],
95
+ instruction: 'Identify the leaf concept being passed around the cycle. The fix pattern is one of: ' +
96
+ '(1) extract that concept into a NEW shared module that all participants import (interface, types, constants), ' +
97
+ '(2) invert one of the dependencies via dependency injection (pass the value in, don\'t import it), or ' +
98
+ '(3) merge two participants if they\'re semantically one unit. Run `projscan coupling --cycles-only` after the fix to confirm the cycle is gone.',
99
+ suggestedTest: 'After: `projscan coupling --cycles-only` should not list these files.',
100
+ }),
101
+ },
102
+ {
103
+ match: (i) => i.id.startsWith('large-') && i.id.endsWith('-dir'),
104
+ render: (i) => ({
105
+ issueId: i.id,
106
+ severity: i.severity,
107
+ category: i.category,
108
+ headline: i.title,
109
+ why: 'Catch-all directories (utils/helpers/lib/shared) are the project graveyard. Every file under one is implicitly "miscellaneous", which means changes touching it also rarely have a clear owner.',
110
+ where: i.locations ?? [],
111
+ instruction: 'Group the files under the flagged directory by domain (e.g. `auth/`, `format/`, `validation/`) using `projscan_graph` to see which symbols are imported together. ' +
112
+ 'Move them into domain-named subdirectories. Update imports - your editor\'s rename-and-update should handle the bulk; finish with a `projscan analyze` to verify no leftover imports broke.',
113
+ }),
114
+ },
115
+ {
116
+ match: (i) => i.id === 'dead-code' || i.id.startsWith('dead-code-'),
117
+ render: (i) => ({
118
+ issueId: i.id,
119
+ severity: i.severity,
120
+ category: i.category,
121
+ headline: 'Dead export (no importers)',
122
+ why: "An export with zero importers either (a) was orphaned by a refactor and is genuinely dead, or (b) is part of the project's public API and projscan can't see who consumes it. " +
123
+ 'Either case deserves resolution: cleanup or an explicit "public" annotation.',
124
+ where: i.locations ?? [],
125
+ instruction: 'For each flagged file: confirm with `projscan_graph { direction: "importers", target: "<file>" }`. ' +
126
+ 'If the result is genuinely empty AND this isn\'t package.json#main / #exports, delete the file (or just the unused exports). ' +
127
+ 'If it IS public surface (entry point, re-exported), add it to package.json#exports or list the file in .projscanrc `disableRules: ["dead-code"]`.',
128
+ }),
129
+ },
130
+ // ── Test / lint / format presence ─────────────────────────
131
+ {
132
+ match: (i) => i.id === 'missing-test-framework' || i.id === 'missing-python-test-framework',
133
+ render: (i) => ({
134
+ issueId: i.id,
135
+ severity: i.severity,
136
+ category: i.category,
137
+ headline: i.title,
138
+ why: 'No test runner means no regression coverage and no CI gate to defend against future regressions. The cost of getting one wired up early is small; the cost of retrofitting one onto a year of code is large.',
139
+ where: [{ file: 'package.json' }],
140
+ instruction: i.id.includes('python')
141
+ ? 'Add pytest: `pip install -D pytest && python -m pytest --version`. Create a `tests/` directory with one trivial passing test (`def test_smoke(): assert True`). Add `[tool.pytest.ini_options]` to pyproject.toml or a `pytest.ini` so the runner knows where to look.'
142
+ : 'Add vitest: `npm i -D vitest` then add `"test": "vitest run"` to package.json scripts. Create `src/__smoke__.test.ts` with one trivial passing test. Wire `npm test` into your CI workflow.',
143
+ suggestedTest: 'After: `npm test` (or `pytest`) should exit 0 with at least the one smoke test passing.',
144
+ }),
145
+ },
146
+ {
147
+ match: (i) => i.id === 'no-test-files' || i.id === 'no-python-test-files',
148
+ render: (i) => ({
149
+ issueId: i.id,
150
+ severity: i.severity,
151
+ category: i.category,
152
+ headline: i.title,
153
+ why: 'Test framework is configured but no test files exist. The runner is plumbed; the safety net isn\'t.',
154
+ where: [],
155
+ instruction: 'Pick the most-changed file (run `projscan_hotspots`) and write the first test against it. Even one test transforms the project: it proves the runner works, exercises the import graph, and gives the next contributor a template. Aim for behavior tests, not 100% coverage.',
156
+ }),
157
+ },
158
+ {
159
+ match: (i) => i.id === 'missing-linter' ||
160
+ i.id === 'missing-python-linter' ||
161
+ i.id === 'missing-formatter' ||
162
+ i.id === 'missing-python-formatter',
163
+ render: (i) => ({
164
+ issueId: i.id,
165
+ severity: i.severity,
166
+ category: i.category,
167
+ headline: i.title,
168
+ why: "Style debates eat review time. A linter + formatter pair makes them moot - the tools own the rule, code review owns the design. Without them, you'll re-litigate the same questions every PR.",
169
+ where: [{ file: 'package.json' }],
170
+ instruction: i.id.includes('python')
171
+ ? 'Add ruff: `pip install -D ruff` and create a `ruff.toml` (or `[tool.ruff]` in pyproject.toml) with `select = ["E", "F", "I"]`. Run `ruff check . --fix` once to bring the codebase to baseline.'
172
+ : 'Add eslint + prettier: `npm i -D eslint prettier` (and the typescript-eslint preset if TS). Create `eslint.config.js` and `.prettierrc.json`. Run once with `--fix` to baseline; commit the result before further changes so the diff stays clean.',
173
+ suggestedTest: 'After: `npm run lint` and `npm run format -- --check` should both pass.',
174
+ }),
175
+ },
176
+ // ── Cross-package import policy (0.14.0) ─────────────────
177
+ {
178
+ match: (i) => i.id.startsWith('cross-package-violation-'),
179
+ render: (i) => ({
180
+ issueId: i.id,
181
+ severity: i.severity,
182
+ category: i.category,
183
+ headline: i.title,
184
+ why: 'Cross-package imports that bypass a package\'s declared entry surface make refactoring inside that package impossible without breaking its consumers. The .projscanrc `monorepo.importPolicy` block flagged this specific edge.',
185
+ where: i.locations ?? [],
186
+ instruction: 'Either (a) replace the deep import with the package\'s public entry (its `main` / `exports`), (b) export the desired symbol from that public entry if it\'s genuinely shared, or ' +
187
+ '(c) widen the .projscanrc importPolicy `allow` list if this edge is intentional. Prefer (a) or (b) - the policy exists to keep refactoring options open.',
188
+ }),
189
+ },
190
+ ];
191
+ const FALLBACK = {
192
+ match: () => true,
193
+ render: (i) => ({
194
+ issueId: i.id,
195
+ severity: i.severity,
196
+ category: i.category,
197
+ headline: i.title,
198
+ why: i.description,
199
+ where: i.locations ?? [],
200
+ instruction: severityInstruction(i),
201
+ }),
202
+ };
203
+ function severityInstruction(i) {
204
+ switch (i.severity) {
205
+ case 'error':
206
+ return `Resolve ${i.title}: read the description, locate the file(s), and apply the fix the description suggests. After the change, run \`projscan_doctor\` and confirm this issue (id: ${i.id}) no longer appears.`;
207
+ case 'warning':
208
+ return `Address ${i.title} when convenient. The description explains the rationale; apply the fix at the location(s) listed. If the warning is a false positive in your context, add ${i.id} to .projscanrc \`disableRules\` with a brief comment.`;
209
+ default:
210
+ return `Informational: ${i.title}. No action strictly required - this signal is for awareness. If you want to silence it, add ${i.id} to .projscanrc \`disableRules\`.`;
211
+ }
212
+ }
213
+ function parseDepName(issueId) {
214
+ // unused-dependency-foo or unused-dependency-packages/a-foo
215
+ // The workspace-aware id has the form `unused-dependency-<workspace>-<name>`
216
+ // but we can't disambiguate without parsing locations; the simple suffix
217
+ // is right in the common case (single-package).
218
+ const tail = issueId.replace(/^unused-dependency-/, '');
219
+ return tail || '<unknown>';
220
+ }
221
+ /**
222
+ * Pick a template for the issue. Always returns a suggestion - the fallback
223
+ * catches anything without a tailored template. Async because some templates
224
+ * reach into the file system or git for context (none today, but the surface
225
+ * is async-ready).
226
+ */
227
+ export async function suggestFixForIssue(issue, rootPath) {
228
+ for (const tpl of TEMPLATES) {
229
+ if (tpl.match(issue)) {
230
+ return await Promise.resolve(tpl.render(issue, { rootPath }));
231
+ }
232
+ }
233
+ return await Promise.resolve(FALLBACK.render(issue, { rootPath }));
234
+ }
235
+ /**
236
+ * Synchronous one-line preview for inline use in projscan_doctor output.
237
+ * Returns the headline a template would render. We can't run the full
238
+ * template synchronously (some are async-shaped); the headline is a
239
+ * lightweight projection that doesn't need IO.
240
+ */
241
+ export function previewSuggestionForIssue(issue) {
242
+ const headline = staticHeadlineFor(issue);
243
+ if (!headline)
244
+ return null;
245
+ return { summary: headline };
246
+ }
247
+ function staticHeadlineFor(issue) {
248
+ if (issue.id.startsWith('unused-dependency-'))
249
+ return `Remove or wire up "${parseDepName(issue.id)}".`;
250
+ if (issue.id === 'dep-risk-no-lockfile')
251
+ return 'Run `npm install` and commit the lockfile.';
252
+ if (issue.id.startsWith('dep-risk-'))
253
+ return `Audit "${issue.id.slice('dep-risk-'.length)}" or pin to an exact version.`;
254
+ if (issue.id.startsWith('audit-'))
255
+ return 'Try `npm audit fix`, then upgrade or pin manually.';
256
+ if (issue.id.startsWith('cycle-detected-'))
257
+ return 'Break the cycle by extracting a shared module.';
258
+ if (issue.id.startsWith('large-') && issue.id.endsWith('-dir'))
259
+ return 'Split the directory by domain.';
260
+ if (issue.id === 'dead-code' || issue.id.startsWith('dead-code-'))
261
+ return 'Confirm with `projscan_graph importers` then delete or expose.';
262
+ if (issue.id === 'missing-test-framework' || issue.id === 'missing-python-test-framework')
263
+ return issue.id.includes('python') ? 'Install pytest + write one smoke test.' : 'Install vitest + write one smoke test.';
264
+ if (issue.id === 'no-test-files' || issue.id === 'no-python-test-files')
265
+ return 'Write the first test against your top hotspot.';
266
+ if (issue.id === 'missing-linter' ||
267
+ issue.id === 'missing-python-linter' ||
268
+ issue.id === 'missing-formatter' ||
269
+ issue.id === 'missing-python-formatter')
270
+ return issue.id.includes('python') ? 'Add ruff and run `ruff check . --fix` once.' : 'Add eslint + prettier; baseline with `--fix`.';
271
+ if (issue.id.startsWith('cross-package-violation-'))
272
+ return 'Use the package\'s public entry, or widen the importPolicy.';
273
+ return null;
274
+ }
275
+ /**
276
+ * Locate an issue in a doctor result by id. The MCP tool calls this to
277
+ * resolve a fix-suggest request; the issue payload comes from
278
+ * `collectIssues` in the same flow.
279
+ */
280
+ export function findIssue(issues, issueId) {
281
+ return issues.find((i) => i.id === issueId) ?? null;
282
+ }
283
+ /**
284
+ * Construct a synthetic Issue when the caller passes file + rule instead of
285
+ * a known id. Useful when an agent wants guidance for a class of issue
286
+ * without first running doctor. The synthetic issue mimics the schema
287
+ * collectIssues would produce, so the same template registry handles it.
288
+ */
289
+ export function syntheticIssue(rule, file, severity = 'warning') {
290
+ return {
291
+ id: rule,
292
+ title: rule,
293
+ description: `Synthetic issue for rule "${rule}" on file "${file}".`,
294
+ severity,
295
+ category: rule.split('-')[0] ?? 'unknown',
296
+ fixAvailable: false,
297
+ locations: file ? [{ file }] : undefined,
298
+ };
299
+ }
300
+ /**
301
+ * Read a small excerpt of a file around a 1-based line number. Used by
302
+ * projscan_explain_issue for the "show me the surrounding code" panel.
303
+ * Returns null on any IO failure so callers can render gracefully.
304
+ */
305
+ export async function readExcerpt(rootPath, loc, context = 3) {
306
+ if (!loc.file)
307
+ return null;
308
+ const abs = path.isAbsolute(loc.file) ? loc.file : path.join(rootPath, loc.file);
309
+ let raw;
310
+ try {
311
+ raw = await fs.readFile(abs, 'utf-8');
312
+ }
313
+ catch {
314
+ return null;
315
+ }
316
+ const all = raw.split('\n');
317
+ const center = loc.line ?? 1;
318
+ const start = Math.max(1, center - context);
319
+ const end = Math.min(all.length, (loc.endLine ?? center) + context);
320
+ return {
321
+ file: loc.file,
322
+ startLine: start,
323
+ endLine: end,
324
+ lines: all.slice(start - 1, end),
325
+ };
326
+ }
327
+ //# sourceMappingURL=fixSuggest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixSuggest.js","sourceRoot":"","sources":["../../src/core/fixSuggest.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,9 @@ const CACHE_FILE = 'graph.json';
5
5
  // v2: added `adapterId` for multi-language routing.
6
6
  // v3: added `cyclomaticComplexity` per file (0.11 "Signal Quality"). Older
7
7
  // caches are discarded on load so we never read back missing CC as 0.
8
- const CACHE_VERSION = 3;
8
+ // v4: added `functions: [{name, line, endLine, cyclomaticComplexity}]` per
9
+ // file (0.13 "Agent Review"). v3 caches are discarded on first 0.13 run.
10
+ const CACHE_VERSION = 4;
9
11
  /**
10
12
  * Load a previously cached code graph, if present and valid. Returns undefined
11
13
  * when there's no cache or the cache is incompatible - caller should rebuild.
@@ -37,6 +39,7 @@ export async function loadCachedGraph(rootPath) {
37
39
  callSites: entry.callSites,
38
40
  lineCount: entry.lineCount,
39
41
  cyclomaticComplexity: entry.cyclomaticComplexity,
42
+ functions: entry.functions ?? [],
40
43
  mtimeMs: entry.mtimeMs,
41
44
  parseOk: entry.parseOk,
42
45
  parseReason: entry.parseReason,
@@ -75,6 +78,7 @@ export async function saveCachedGraph(rootPath, graph) {
75
78
  callSites: entry.callSites,
76
79
  lineCount: entry.lineCount,
77
80
  cyclomaticComplexity: entry.cyclomaticComplexity,
81
+ functions: entry.functions ?? [],
78
82
  mtimeMs: entry.mtimeMs,
79
83
  parseOk: entry.parseOk,
80
84
  parseReason: entry.parseReason,
@@ -1 +1 @@
1
- {"version":3,"file":"indexCache.js","sourceRoot":"","sources":["../../src/core/indexCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"indexCache.js","sourceRoot":"","sources":["../../src/core/indexCache.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,9 @@ import { check as dependencyRiskCheck } from '../analyzers/dependencyRiskCheck.j
6
6
  import { check as securityCheck } from '../analyzers/securityCheck.js';
7
7
  import { check as unusedDependencyCheck } from '../analyzers/unusedDependencyCheck.js';
8
8
  import { check as deadCodeCheck } from '../analyzers/deadCodeCheck.js';
9
+ import { check as cycleCheck } from '../analyzers/cycleCheck.js';
10
+ import { check as crossPackageImportCheck } from '../analyzers/crossPackageImportCheck.js';
11
+ import { previewSuggestionForIssue } from './fixSuggest.js';
9
12
  import { check as pythonTestCheck } from '../analyzers/pythonTestCheck.js';
10
13
  import { check as pythonLinterCheck } from '../analyzers/pythonLinterCheck.js';
11
14
  import { check as pythonDependencyRiskCheck } from '../analyzers/pythonDependencyRiskCheck.js';
@@ -19,6 +22,12 @@ const checkers = [
19
22
  securityCheck,
20
23
  unusedDependencyCheck,
21
24
  deadCodeCheck,
25
+ // 0.13.0: lift Tarjan-detected import cycles into doctor's issue list.
26
+ // Builds the graph via the cache, so repeated runs in a session amortize.
27
+ cycleCheck,
28
+ // 0.14.0: cross-package import policy. No-op unless the user configured
29
+ // `monorepo.importPolicy` in .projscanrc and the repo is a monorepo.
30
+ crossPackageImportCheck,
22
31
  // Python analyzers - each early-exits on zero .py files so JS/TS repos
23
32
  // see zero new issues.
24
33
  pythonTestCheck,
@@ -32,6 +41,15 @@ export async function collectIssues(rootPath, files) {
32
41
  // Sort by severity: error > warning > info
33
42
  const severityOrder = { error: 0, warning: 1, info: 2 };
34
43
  issues.sort((a, b) => (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3));
44
+ // 0.14.0: attach a one-line `suggestedAction` to each issue when the
45
+ // fix-suggest registry has a template. Cheap (synchronous projection,
46
+ // no IO); agents calling projscan_doctor see actionable hints inline
47
+ // and can call projscan_fix_suggest for the full structured prompt.
48
+ for (const issue of issues) {
49
+ const preview = previewSuggestionForIssue(issue);
50
+ if (preview)
51
+ issue.suggestedAction = preview;
52
+ }
35
53
  return issues;
36
54
  }
37
55
  //# sourceMappingURL=issueEngine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"issueEngine.js","sourceRoot":"","sources":["../../src/core/issueEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,IAAI,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,IAAI,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAC/F,OAAO,EAAE,KAAK,IAAI,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAInG,MAAM,QAAQ,GAAc;IAC1B,WAAW;IACX,aAAa;IACb,SAAS;IACT,iBAAiB;IACjB,mBAAmB;IACnB,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uEAAuE;IACvE,uBAAuB;IACvB,eAAe;IACf,iBAAiB;IACjB,yBAAyB;IACzB,2BAA2B;CAC5B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,KAAkB;IACtE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE9B,2CAA2C;IAC3C,MAAM,aAAa,GAA2B,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAChF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE3F,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"issueEngine.js","sourceRoot":"","sources":["../../src/core/issueEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,IAAI,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AACnF,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AACvF,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,KAAK,IAAI,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAC3F,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,KAAK,IAAI,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,IAAI,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AAC/F,OAAO,EAAE,KAAK,IAAI,2BAA2B,EAAE,MAAM,6CAA6C,CAAC;AAInG,MAAM,QAAQ,GAAc;IAC1B,WAAW;IACX,aAAa;IACb,SAAS;IACT,iBAAiB;IACjB,mBAAmB;IACnB,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uEAAuE;IACvE,0EAA0E;IAC1E,UAAU;IACV,wEAAwE;IACxE,qEAAqE;IACrE,uBAAuB;IACvB,uEAAuE;IACvE,uBAAuB;IACvB,eAAe;IACf,iBAAiB;IACjB,yBAAyB;IACzB,2BAA2B;CAC5B,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,KAAkB;IACtE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE9B,2CAA2C;IAC3C,MAAM,aAAa,GAA2B,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAChF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE3F,qEAAqE;IACrE,sEAAsE;IACtE,qEAAqE;IACrE,oEAAoE;IACpE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;QACjD,IAAI,OAAO;YAAE,KAAK,CAAC,eAAe,GAAG,OAAO,CAAC;IAC/C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -3,6 +3,7 @@ import { createParserFor } from './treeSitterLoader.js';
3
3
  import { extractGoImports } from './goImports.js';
4
4
  import { extractGoExports } from './goExports.js';
5
5
  import { extractGoCyclomatic } from './goCyclomatic.js';
6
+ import { extractGoFunctions } from './goFunctions.js';
6
7
  import { extractGoCallSites } from './goCallSites.js';
7
8
  import { detectGoProject } from './goManifests.js';
8
9
  const GO_EXTENSIONS = new Set(['.go']);
@@ -34,6 +35,7 @@ export const goAdapter = {
34
35
  callSites: [],
35
36
  lineCount: content ? content.split('\n').length : 0,
36
37
  cyclomaticComplexity: 0,
38
+ functions: [],
37
39
  };
38
40
  }
39
41
  const root = tree.rootNode;
@@ -41,6 +43,7 @@ export const goAdapter = {
41
43
  const exports = extractGoExports(root);
42
44
  const cyclomaticComplexity = extractGoCyclomatic(root);
43
45
  const callSites = extractGoCallSites(root);
46
+ const functions = extractGoFunctions(root);
44
47
  return {
45
48
  ok: true,
46
49
  imports,
@@ -48,6 +51,7 @@ export const goAdapter = {
48
51
  callSites,
49
52
  lineCount: content ? content.split('\n').length : 0,
50
53
  cyclomaticComplexity,
54
+ functions,
51
55
  };
52
56
  }
53
57
  catch (err) {
@@ -60,6 +64,7 @@ export const goAdapter = {
60
64
  callSites: [],
61
65
  lineCount: content ? content.split('\n').length : 0,
62
66
  cyclomaticComplexity: 0,
67
+ functions: [],
63
68
  };
64
69
  }
65
70
  },
@@ -1 +1 @@
1
- {"version":3,"file":"goAdapter.js","sourceRoot":"","sources":["../../../src/core/languages/goAdapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"goAdapter.js","sourceRoot":"","sources":["../../../src/core/languages/goAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { FunctionInfo } from '../ast.js';
2
+ interface TsNode {
3
+ type: string;
4
+ text: string;
5
+ startPosition: {
6
+ row: number;
7
+ column: number;
8
+ };
9
+ endPosition: {
10
+ row: number;
11
+ column: number;
12
+ };
13
+ namedChildren: TsNode[];
14
+ childForFieldName?: (name: string) => TsNode | null;
15
+ }
16
+ /**
17
+ * Per-function McCabe CC for Go. Walks `function_declaration` (top-level
18
+ * funcs) and `method_declaration` (methods on a receiver). Methods are named
19
+ * `Receiver.Method`. Function literals (`func() { ... }`) are not extracted
20
+ * as separate functions in 0.13.0; they fold into the enclosing function's
21
+ * CC.
22
+ */
23
+ export declare function extractGoFunctions(root: TsNode): FunctionInfo[];
24
+ export {};
@@ -0,0 +1,99 @@
1
+ const GO_DECISION_NODES = new Set([
2
+ 'if_statement',
3
+ 'for_statement',
4
+ 'expression_case',
5
+ 'type_case',
6
+ 'communication_case',
7
+ ]);
8
+ /**
9
+ * Per-function McCabe CC for Go. Walks `function_declaration` (top-level
10
+ * funcs) and `method_declaration` (methods on a receiver). Methods are named
11
+ * `Receiver.Method`. Function literals (`func() { ... }`) are not extracted
12
+ * as separate functions in 0.13.0; they fold into the enclosing function's
13
+ * CC.
14
+ */
15
+ export function extractGoFunctions(root) {
16
+ const out = [];
17
+ walk(root, out);
18
+ return out;
19
+ }
20
+ function walk(node, out) {
21
+ if (node.type === 'function_declaration' || node.type === 'method_declaration') {
22
+ const fnName = nameOfGoFunction(node);
23
+ const line = node.startPosition.row + 1;
24
+ const endLine = node.endPosition.row + 1;
25
+ const cc = countDecisions(node);
26
+ out.push({ name: fnName, line, endLine, cyclomaticComplexity: cc });
27
+ // Don't recurse into the body for FunctionInfo - we don't track func
28
+ // literals separately in 0.13.0 (they're not addressable by name anyway).
29
+ return;
30
+ }
31
+ for (const child of node.namedChildren)
32
+ walk(child, out);
33
+ }
34
+ function nameOfGoFunction(node) {
35
+ // function_declaration has a `name` field (identifier).
36
+ if (node.type === 'function_declaration') {
37
+ const n = node.childForFieldName ? node.childForFieldName('name') : findChild(node, 'identifier');
38
+ return n?.text ?? '<anonymous>';
39
+ }
40
+ // method_declaration has `receiver` + `name`. Receiver is a parameter_list.
41
+ if (node.type === 'method_declaration') {
42
+ const nameNode = node.childForFieldName ? node.childForFieldName('name') : findChild(node, 'field_identifier');
43
+ const fnName = nameNode?.text ?? '<anonymous>';
44
+ const receiver = node.childForFieldName ? node.childForFieldName('receiver') : null;
45
+ if (receiver) {
46
+ // Receiver text is like `(x *Foo)` or `(Foo)`. Extract the type name.
47
+ const recvType = extractReceiverType(receiver.text);
48
+ if (recvType)
49
+ return `${recvType}.${fnName}`;
50
+ }
51
+ return fnName;
52
+ }
53
+ return '<anonymous>';
54
+ }
55
+ function extractReceiverType(text) {
56
+ // Strip surrounding parens; extract the last identifier-shaped token (skipping `*`).
57
+ const inner = text.replace(/^\(|\)$/g, '').trim();
58
+ // forms: `Foo` | `f Foo` | `f *Foo` | `*Foo` | `Foo[T]` | `f Foo[T]`
59
+ const m = /(?:\*)?([A-Za-z_][A-Za-z0-9_]*)(?:\[[^\]]*\])?\s*$/.exec(inner);
60
+ return m ? m[1] : null;
61
+ }
62
+ function countDecisions(fnNode) {
63
+ let count = 0;
64
+ const body = fnNode.childForFieldName ? fnNode.childForFieldName('body') : null;
65
+ if (!body)
66
+ return 1;
67
+ walkSkipNested(body, (n) => {
68
+ if (GO_DECISION_NODES.has(n.type)) {
69
+ count++;
70
+ return;
71
+ }
72
+ if (n.type === 'binary_expression') {
73
+ if (/(\s|^)(\|\||&&)(\s|$)/.test(n.text))
74
+ count++;
75
+ }
76
+ });
77
+ return count + 1;
78
+ }
79
+ function walkSkipNested(node, visit) {
80
+ visit(node);
81
+ for (const child of node.namedChildren) {
82
+ if (child.type === 'function_declaration' ||
83
+ child.type === 'method_declaration' ||
84
+ child.type === 'func_literal') {
85
+ // Skip: nested function literals fold into their own implicit "function"
86
+ // but we don't emit them. The enclosing function's CC still counts the
87
+ // call/decision points around the literal but not those *inside* it.
88
+ continue;
89
+ }
90
+ walkSkipNested(child, visit);
91
+ }
92
+ }
93
+ function findChild(node, type) {
94
+ for (const c of node.namedChildren)
95
+ if (c.type === type)
96
+ return c;
97
+ return null;
98
+ }
99
+ //# sourceMappingURL=goFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"goFunctions.js","sourceRoot":"","sources":["../../../src/core/languages/goFunctions.ts"],"names":[],"mappings":"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"}