projscan 0.10.0 → 0.12.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 (242) hide show
  1. package/README.md +56 -19
  2. package/dist/analyzers/unusedDependencyCheck.js +69 -17
  3. package/dist/analyzers/unusedDependencyCheck.js.map +1 -1
  4. package/dist/cli/_shared.d.ts +16 -0
  5. package/dist/cli/_shared.js +210 -0
  6. package/dist/cli/_shared.js.map +1 -0
  7. package/dist/cli/commands/analyze.d.ts +1 -0
  8. package/dist/cli/commands/analyze.js +87 -0
  9. package/dist/cli/commands/analyze.js.map +1 -0
  10. package/dist/cli/commands/audit.d.ts +1 -0
  11. package/dist/cli/commands/audit.js +47 -0
  12. package/dist/cli/commands/audit.js.map +1 -0
  13. package/dist/cli/commands/badge.d.ts +1 -0
  14. package/dist/cli/commands/badge.js +45 -0
  15. package/dist/cli/commands/badge.js.map +1 -0
  16. package/dist/cli/commands/ci.d.ts +1 -0
  17. package/dist/cli/commands/ci.js +57 -0
  18. package/dist/cli/commands/ci.js.map +1 -0
  19. package/dist/cli/commands/coupling.d.ts +1 -0
  20. package/dist/cli/commands/coupling.js +83 -0
  21. package/dist/cli/commands/coupling.js.map +1 -0
  22. package/dist/cli/commands/coverage.d.ts +1 -0
  23. package/dist/cli/commands/coverage.js +63 -0
  24. package/dist/cli/commands/coverage.js.map +1 -0
  25. package/dist/cli/commands/dependencies.d.ts +1 -0
  26. package/dist/cli/commands/dependencies.js +45 -0
  27. package/dist/cli/commands/dependencies.js.map +1 -0
  28. package/dist/cli/commands/diagram.d.ts +1 -0
  29. package/dist/cli/commands/diagram.js +45 -0
  30. package/dist/cli/commands/diagram.js.map +1 -0
  31. package/dist/cli/commands/diff.d.ts +1 -0
  32. package/dist/cli/commands/diff.js +70 -0
  33. package/dist/cli/commands/diff.js.map +1 -0
  34. package/dist/cli/commands/doctor.d.ts +1 -0
  35. package/dist/cli/commands/doctor.js +62 -0
  36. package/dist/cli/commands/doctor.js.map +1 -0
  37. package/dist/cli/commands/explain.d.ts +1 -0
  38. package/dist/cli/commands/explain.js +42 -0
  39. package/dist/cli/commands/explain.js.map +1 -0
  40. package/dist/cli/commands/file.d.ts +1 -0
  41. package/dist/cli/commands/file.js +45 -0
  42. package/dist/cli/commands/file.js.map +1 -0
  43. package/dist/cli/commands/fix.d.ts +1 -0
  44. package/dist/cli/commands/fix.js +70 -0
  45. package/dist/cli/commands/fix.js.map +1 -0
  46. package/dist/cli/commands/help.d.ts +1 -0
  47. package/dist/cli/commands/help.js +11 -0
  48. package/dist/cli/commands/help.js.map +1 -0
  49. package/dist/cli/commands/hotspots.d.ts +1 -0
  50. package/dist/cli/commands/hotspots.js +74 -0
  51. package/dist/cli/commands/hotspots.js.map +1 -0
  52. package/dist/cli/commands/mcp.d.ts +1 -0
  53. package/dist/cli/commands/mcp.js +21 -0
  54. package/dist/cli/commands/mcp.js.map +1 -0
  55. package/dist/cli/commands/outdated.d.ts +1 -0
  56. package/dist/cli/commands/outdated.js +51 -0
  57. package/dist/cli/commands/outdated.js.map +1 -0
  58. package/dist/cli/commands/prDiff.d.ts +1 -0
  59. package/dist/cli/commands/prDiff.js +59 -0
  60. package/dist/cli/commands/prDiff.js.map +1 -0
  61. package/dist/cli/commands/search.d.ts +1 -0
  62. package/dist/cli/commands/search.js +233 -0
  63. package/dist/cli/commands/search.js.map +1 -0
  64. package/dist/cli/commands/structure.d.ts +1 -0
  65. package/dist/cli/commands/structure.js +58 -0
  66. package/dist/cli/commands/structure.js.map +1 -0
  67. package/dist/cli/commands/upgrade.d.ts +1 -0
  68. package/dist/cli/commands/upgrade.js +44 -0
  69. package/dist/cli/commands/upgrade.js.map +1 -0
  70. package/dist/cli/commands/workspaces.d.ts +1 -0
  71. package/dist/cli/commands/workspaces.js +35 -0
  72. package/dist/cli/commands/workspaces.js.map +1 -0
  73. package/dist/cli/index.js +45 -1132
  74. package/dist/cli/index.js.map +1 -1
  75. package/dist/core/ast.d.ts +2 -0
  76. package/dist/core/ast.js +35 -2
  77. package/dist/core/ast.js.map +1 -1
  78. package/dist/core/codeGraph.d.ts +2 -0
  79. package/dist/core/codeGraph.js +2 -0
  80. package/dist/core/codeGraph.js.map +1 -1
  81. package/dist/core/couplingAnalyzer.d.ts +18 -0
  82. package/dist/core/couplingAnalyzer.js +174 -0
  83. package/dist/core/couplingAnalyzer.js.map +1 -0
  84. package/dist/core/fileInspector.d.ts +1 -1
  85. package/dist/core/fileInspector.js +31 -1
  86. package/dist/core/fileInspector.js.map +1 -1
  87. package/dist/core/hotspotAnalyzer.d.ts +13 -0
  88. package/dist/core/hotspotAnalyzer.js +29 -6
  89. package/dist/core/hotspotAnalyzer.js.map +1 -1
  90. package/dist/core/indexCache.js +6 -3
  91. package/dist/core/indexCache.js.map +1 -1
  92. package/dist/core/languages/LanguageAdapter.d.ts +1 -1
  93. package/dist/core/languages/goAdapter.d.ts +2 -0
  94. package/dist/core/languages/goAdapter.js +138 -0
  95. package/dist/core/languages/goAdapter.js.map +1 -0
  96. package/dist/core/languages/goCallSites.d.ts +20 -0
  97. package/dist/core/languages/goCallSites.js +42 -0
  98. package/dist/core/languages/goCallSites.js.map +1 -0
  99. package/dist/core/languages/goCyclomatic.d.ts +21 -0
  100. package/dist/core/languages/goCyclomatic.js +55 -0
  101. package/dist/core/languages/goCyclomatic.js.map +1 -0
  102. package/dist/core/languages/goExports.d.ts +26 -0
  103. package/dist/core/languages/goExports.js +89 -0
  104. package/dist/core/languages/goExports.js.map +1 -0
  105. package/dist/core/languages/goImports.d.ts +26 -0
  106. package/dist/core/languages/goImports.js +64 -0
  107. package/dist/core/languages/goImports.js.map +1 -0
  108. package/dist/core/languages/goManifests.d.ts +19 -0
  109. package/dist/core/languages/goManifests.js +56 -0
  110. package/dist/core/languages/goManifests.js.map +1 -0
  111. package/dist/core/languages/javaAdapter.d.ts +2 -0
  112. package/dist/core/languages/javaAdapter.js +148 -0
  113. package/dist/core/languages/javaAdapter.js.map +1 -0
  114. package/dist/core/languages/javaCallSites.d.ts +16 -0
  115. package/dist/core/languages/javaCallSites.js +45 -0
  116. package/dist/core/languages/javaCallSites.js.map +1 -0
  117. package/dist/core/languages/javaCyclomatic.d.ts +21 -0
  118. package/dist/core/languages/javaCyclomatic.js +49 -0
  119. package/dist/core/languages/javaCyclomatic.js.map +1 -0
  120. package/dist/core/languages/javaExports.d.ts +25 -0
  121. package/dist/core/languages/javaExports.js +80 -0
  122. package/dist/core/languages/javaExports.js.map +1 -0
  123. package/dist/core/languages/javaImports.d.ts +25 -0
  124. package/dist/core/languages/javaImports.js +49 -0
  125. package/dist/core/languages/javaImports.js.map +1 -0
  126. package/dist/core/languages/javaManifests.d.ts +25 -0
  127. package/dist/core/languages/javaManifests.js +86 -0
  128. package/dist/core/languages/javaManifests.js.map +1 -0
  129. package/dist/core/languages/pythonAdapter.js +8 -1
  130. package/dist/core/languages/pythonAdapter.js.map +1 -1
  131. package/dist/core/languages/pythonCallSites.d.ts +19 -0
  132. package/dist/core/languages/pythonCallSites.js +40 -0
  133. package/dist/core/languages/pythonCallSites.js.map +1 -0
  134. package/dist/core/languages/pythonCyclomatic.d.ts +18 -0
  135. package/dist/core/languages/pythonCyclomatic.js +45 -0
  136. package/dist/core/languages/pythonCyclomatic.js.map +1 -0
  137. package/dist/core/languages/registry.js +4 -1
  138. package/dist/core/languages/registry.js.map +1 -1
  139. package/dist/core/languages/rubyAdapter.d.ts +2 -0
  140. package/dist/core/languages/rubyAdapter.js +131 -0
  141. package/dist/core/languages/rubyAdapter.js.map +1 -0
  142. package/dist/core/languages/rubyCallSites.d.ts +16 -0
  143. package/dist/core/languages/rubyCallSites.js +34 -0
  144. package/dist/core/languages/rubyCallSites.js.map +1 -0
  145. package/dist/core/languages/rubyCyclomatic.d.ts +19 -0
  146. package/dist/core/languages/rubyCyclomatic.js +47 -0
  147. package/dist/core/languages/rubyCyclomatic.js.map +1 -0
  148. package/dist/core/languages/rubyExports.d.ts +24 -0
  149. package/dist/core/languages/rubyExports.js +53 -0
  150. package/dist/core/languages/rubyExports.js.map +1 -0
  151. package/dist/core/languages/rubyImports.d.ts +12 -0
  152. package/dist/core/languages/rubyImports.js +75 -0
  153. package/dist/core/languages/rubyImports.js.map +1 -0
  154. package/dist/core/languages/rubyManifests.d.ts +20 -0
  155. package/dist/core/languages/rubyManifests.js +55 -0
  156. package/dist/core/languages/rubyManifests.js.map +1 -0
  157. package/dist/core/languages/treeSitterLoader.js +4 -1
  158. package/dist/core/languages/treeSitterLoader.js.map +1 -1
  159. package/dist/core/monorepo.d.ts +20 -0
  160. package/dist/core/monorepo.js +270 -0
  161. package/dist/core/monorepo.js.map +1 -0
  162. package/dist/core/outdatedDetector.d.ts +13 -2
  163. package/dist/core/outdatedDetector.js +86 -16
  164. package/dist/core/outdatedDetector.js.map +1 -1
  165. package/dist/core/prDiff.d.ts +43 -0
  166. package/dist/core/prDiff.js +298 -0
  167. package/dist/core/prDiff.js.map +1 -0
  168. package/dist/core/telemetry.d.ts +90 -0
  169. package/dist/core/telemetry.js +199 -0
  170. package/dist/core/telemetry.js.map +1 -0
  171. package/dist/grammars/tree-sitter-go.wasm +0 -0
  172. package/dist/grammars/tree-sitter-java.wasm +0 -0
  173. package/dist/grammars/tree-sitter-ruby.wasm +0 -0
  174. package/dist/mcp/tools/_shared.d.ts +24 -0
  175. package/dist/mcp/tools/_shared.js +82 -0
  176. package/dist/mcp/tools/_shared.js.map +1 -0
  177. package/dist/mcp/tools/analyze.d.ts +2 -0
  178. package/dist/mcp/tools/analyze.js +55 -0
  179. package/dist/mcp/tools/analyze.js.map +1 -0
  180. package/dist/mcp/tools/audit.d.ts +2 -0
  181. package/dist/mcp/tools/audit.js +32 -0
  182. package/dist/mcp/tools/audit.js.map +1 -0
  183. package/dist/mcp/tools/coupling.d.ts +2 -0
  184. package/dist/mcp/tools/coupling.js +67 -0
  185. package/dist/mcp/tools/coupling.js.map +1 -0
  186. package/dist/mcp/tools/coverage.d.ts +2 -0
  187. package/dist/mcp/tools/coverage.js +53 -0
  188. package/dist/mcp/tools/coverage.js.map +1 -0
  189. package/dist/mcp/tools/dependencies.d.ts +2 -0
  190. package/dist/mcp/tools/dependencies.js +16 -0
  191. package/dist/mcp/tools/dependencies.js.map +1 -0
  192. package/dist/mcp/tools/doctor.d.ts +2 -0
  193. package/dist/mcp/tools/doctor.js +30 -0
  194. package/dist/mcp/tools/doctor.js.map +1 -0
  195. package/dist/mcp/tools/explain.d.ts +2 -0
  196. package/dist/mcp/tools/explain.js +30 -0
  197. package/dist/mcp/tools/explain.js.map +1 -0
  198. package/dist/mcp/tools/file.d.ts +2 -0
  199. package/dist/mcp/tools/file.js +22 -0
  200. package/dist/mcp/tools/file.js.map +1 -0
  201. package/dist/mcp/tools/graph.d.ts +2 -0
  202. package/dist/mcp/tools/graph.js +69 -0
  203. package/dist/mcp/tools/graph.js.map +1 -0
  204. package/dist/mcp/tools/hotspots.d.ts +2 -0
  205. package/dist/mcp/tools/hotspots.js +64 -0
  206. package/dist/mcp/tools/hotspots.js.map +1 -0
  207. package/dist/mcp/tools/outdated.d.ts +2 -0
  208. package/dist/mcp/tools/outdated.js +36 -0
  209. package/dist/mcp/tools/outdated.js.map +1 -0
  210. package/dist/mcp/tools/prDiff.d.ts +2 -0
  211. package/dist/mcp/tools/prDiff.js +38 -0
  212. package/dist/mcp/tools/prDiff.js.map +1 -0
  213. package/dist/mcp/tools/search.d.ts +2 -0
  214. package/dist/mcp/tools/search.js +167 -0
  215. package/dist/mcp/tools/search.js.map +1 -0
  216. package/dist/mcp/tools/structure.d.ts +2 -0
  217. package/dist/mcp/tools/structure.js +34 -0
  218. package/dist/mcp/tools/structure.js.map +1 -0
  219. package/dist/mcp/tools/upgrade.d.ts +2 -0
  220. package/dist/mcp/tools/upgrade.js +38 -0
  221. package/dist/mcp/tools/upgrade.js.map +1 -0
  222. package/dist/mcp/tools/workspaces.d.ts +2 -0
  223. package/dist/mcp/tools/workspaces.js +13 -0
  224. package/dist/mcp/tools/workspaces.js.map +1 -0
  225. package/dist/mcp/tools.d.ts +12 -6
  226. package/dist/mcp/tools.js +40 -605
  227. package/dist/mcp/tools.js.map +1 -1
  228. package/dist/reporters/consoleReporter.d.ts +4 -1
  229. package/dist/reporters/consoleReporter.js +113 -0
  230. package/dist/reporters/consoleReporter.js.map +1 -1
  231. package/dist/reporters/jsonReporter.d.ts +4 -1
  232. package/dist/reporters/jsonReporter.js +9 -0
  233. package/dist/reporters/jsonReporter.js.map +1 -1
  234. package/dist/reporters/markdownReporter.d.ts +4 -1
  235. package/dist/reporters/markdownReporter.js +103 -3
  236. package/dist/reporters/markdownReporter.js.map +1 -1
  237. package/dist/tool-manifest.json +358 -0
  238. package/dist/types.d.ts +115 -0
  239. package/dist/utils/cache.d.ts +3 -0
  240. package/dist/utils/cache.js +51 -0
  241. package/dist/utils/cache.js.map +1 -0
  242. package/package.json +7 -3
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
 
21
21
  AI coding agents are becoming the primary interface to code. Today, when you ask your agent *"which files implement auth?"* or *"what breaks if I bump React from 18 to 19?"* - it either guesses from names, or it shells out to grep and reads raw output not built for it.
22
22
 
23
- **projscan is the first code-intelligence tool built for agents, not for humans.** Your agent gets a fast, AST-accurate, context-budget-aware view of your codebase through 13 structured MCP tools. It can query the import graph, find symbol definitions, preview upgrades, rank hotspots - without loading the file tree into its context.
23
+ **projscan is the first code-intelligence tool built for agents, not for humans.** Your agent gets a fast, AST-accurate, context-budget-aware view of your codebase through 17 structured MCP tools. It can query the import graph, find symbol definitions, preview upgrades, rank hotspots, diff structural changes between refs, and surface coupling/cycle hotspots - without loading the file tree into its context.
24
24
 
25
25
  Humans get the same thing through the CLI.
26
26
 
@@ -190,7 +190,7 @@ This outputs a [shields.io](https://shields.io) badge URL and markdown snippet y
190
190
 
191
191
  ## What It Detects
192
192
 
193
- **Languages**: TypeScript, JavaScript, Python (full AST analysis for all three), plus file-level detection for Go, Rust, Java, Ruby, C/C++, PHP, Swift, Kotlin, and 20+ more.
193
+ **Languages**: TypeScript, JavaScript, Python, Go, Java, and Ruby (full AST analysis for all six), plus file-level detection for Rust, C/C++, PHP, Swift, Kotlin, and 20+ more.
194
194
 
195
195
  **Frameworks**: React, Next.js, Vue, Nuxt, Svelte, Angular, Express, Fastify, NestJS, Vite, Tailwind CSS, Prisma, and more
196
196
 
@@ -206,23 +206,55 @@ Python repos now get the same treatment JS/TS has had since 0.6:
206
206
 
207
207
  `projscan_upgrade` remains Node-only for now - a Python equivalent (reading pip / poetry metadata) is on the roadmap.
208
208
 
209
- **Issues**:
210
- - Missing linting (ESLint) and formatting (Prettier) configuration
211
- - Missing test framework
212
- - Missing `.editorconfig`
213
- - Large utility directories (architecture smell)
214
- - Excessive, deprecated, or wildcard-versioned dependencies
215
- - Missing lockfile
216
- - Committed `.env` files and private keys (security)
217
- - Hardcoded secrets - AWS keys, GitHub tokens, Slack tokens, generic passwords (security)
218
- - Missing `.env` in `.gitignore` (security)
209
+ ### Go (0.11)
210
+
211
+ Go flows through the same pipeline as JS/TS and Python:
212
+
213
+ - **AST-accurate import graph** via tree-sitter-go. Single-line and parenthesized import blocks, aliased imports, dot-imports.
214
+ - **Capitalization-rule export visibility** - uppercase identifiers are public, lowercase are private. Captures `func`, method, `var`, `const`, `type` (struct/interface).
215
+ - **`go.mod` module-path resolution** - imports prefixed with the module path resolve into the repo; stdlib and third-party are external.
216
+ - **Cyclomatic complexity** counted from `if`, `for`, `switch` cases, select communication cases, `&&`/`||`. Default cases and `defer`/`go` don't count.
217
+
218
+ ### Coupling and cycles (0.11)
219
+
220
+ `projscan coupling` (CLI + MCP tool) reports per-file fan-in / fan-out / instability (Bob Martin's I = Ce / (Ca + Ce)) and detects circular imports via Tarjan SCC. Cross-package edges are flagged when running on a monorepo.
221
+
222
+ ### PR-aware structural diff (0.11)
223
+
224
+ `projscan pr-diff` returns the structural diff between two refs: exports added/removed/renamed, imports added/removed, call sites added/removed, ΔCC, Δfan-in. Spins up a temporary git worktree at the base ref to build a clean second graph. Renames are detected via similarity scoring (max of normalized Levenshtein and shared-affix fraction, threshold 0.5).
225
+
226
+ ### Monorepo support (0.11)
227
+
228
+ Detects npm/yarn workspaces, `pnpm-workspace.yaml`, Lerna, modern Nx (`nx.json#workspaceLayout` + `project.json` scan), legacy Nx (`workspace.json#projects`), and a `packages/*` + `apps/*` + `libs/*` fallback. `projscan workspaces` lists every package; `--package <name>` (or the `package` MCP arg) scopes most commands to a single workspace.
229
+
230
+ Cache version bumped 2 → 3 in 0.11 (CC stored per file). Existing v2 caches are discarded on first run and rebuilt automatically.
219
231
 
220
232
  ## Performance
221
233
 
222
- - **5,000 files** analyzed in under 1.5 seconds
223
- - **20,000 files** analyzed in under 3 seconds
234
+ Reference numbers from `npm run bench` on an Apple M3 Pro running Node 25:
235
+
236
+ | Repo | Files | analyze | doctor | hotspots | coupling | search |
237
+ |------|-------|---------|--------|----------|----------|--------|
238
+ | projscan itself | ~120 | 320–470 ms | 320–340 ms | 360–470 ms | 140–260 ms | 200–320 ms |
239
+ | Synthetic medium | 500 | 200–220 ms | 190 ms | 220–230 ms | 150–190 ms | 170–210 ms |
240
+
241
+ Cold-cache times shown; warm-cache times are similar because most commands rebuild the graph anyway. Run `npm run bench` against your own machine to recalibrate.
242
+
224
243
  - **Zero network requests** - everything runs locally
225
- - **6 runtime dependencies** - still minimal footprint (the two tree-sitter packages add ~640 KB of vendored wasm)
244
+ - **11 runtime dependencies** - still minimal (the five tree-sitter grammars bring ~3.3 MB of vendored wasm: web-tree-sitter ~190 KB, tree-sitter-python ~450 KB, tree-sitter-go ~210 KB, tree-sitter-java ~405 KB, tree-sitter-ruby ~2.0 MB)
245
+
246
+ ## Optional features
247
+
248
+ projscan keeps the install slim by default. One feature is gated behind an optional peer dependency:
249
+
250
+ - **Semantic search** uses local embeddings via `@xenova/transformers` (~25 MB quantized model, downloads on first use, then cached). Without it, `projscan search` falls back to BM25 lexical search and prints a one-line tip pointing here. Install when you want it:
251
+
252
+ ```bash
253
+ npm install @xenova/transformers
254
+ projscan search "cache invalidation" --semantic
255
+ ```
256
+
257
+ See [AI Agent Integration → Semantic search](#semantic-search-090-opt-in) for details.
226
258
 
227
259
  ## CI/CD Integration
228
260
 
@@ -429,17 +461,19 @@ claude mcp add projscan -- npx projscan mcp
429
461
  - *"What breaks if I bump chalk to 6?"* → `projscan_upgrade { package: "chalk" }`
430
462
  - *"Where should I refactor first?"* → `projscan_hotspots`
431
463
 
432
- ### The 13 MCP tools
464
+ ### The 16 MCP tools
433
465
 
434
- **Structural (0.6.0 - new, agent-native):**
466
+ **Structural (0.6.0 / 0.11 - agent-native):**
435
467
  - **`projscan_graph`** - query the AST-based code graph. Directions: `imports`, `exports`, `importers`, `symbol_defs`, `package_importers`. Millisecond responses on a warm cache.
436
468
  - **`projscan_search`** - fast search across `symbols` (exported names), `files` (path substring), or `content` (source substring with line + excerpt). Replaces the temptation to shell out to grep.
469
+ - **`projscan_coupling`** *(0.11)* - per-file fan-in / fan-out / instability + circular-import cycles (Tarjan SCC). Filter by `direction: cycles_only | high_fan_in | high_fan_out`.
470
+ - **`projscan_pr_diff`** *(0.11)* - structural diff between two git refs. Returns added/removed/modified files with explicit lists of exports, imports, and call sites that changed, plus ΔCC and Δfan-in.
437
471
 
438
472
  **Analysis:**
439
473
  - `projscan_analyze` - full project report
440
474
  - `projscan_doctor` - health score + issues
441
- - `projscan_hotspots` - risk-ranked files (churn × complexity × issues × ownership × coverage)
442
- - `projscan_file` - per-file risk + ownership + related issues
475
+ - `projscan_hotspots` - risk-ranked files (churn × **AST cyclomatic complexity** × issues × ownership × coverage; falls back to LOC for non-AST languages)
476
+ - `projscan_file` - per-file risk + ownership + related issues + CC + fan-in/fan-out
443
477
  - `projscan_explain` - per-file purpose, imports, exports, smells
444
478
  - `projscan_structure` - directory tree
445
479
  - `projscan_coverage` - scariest untested files (coverage × hotspots)
@@ -450,6 +484,9 @@ claude mcp add projscan -- npx projscan mcp
450
484
  - `projscan_audit` - normalized `npm audit`
451
485
  - `projscan_upgrade` - upgrade preview (CHANGELOG + importers, offline)
452
486
 
487
+ **Workspace (0.11):**
488
+ - `projscan_workspaces` - list monorepo packages (npm/yarn/pnpm/Nx/Turbo/Lerna). Use the `name` as the `package` arg on `projscan_hotspots` / `projscan_coupling` to scope.
489
+
453
490
  ### Context-window budgeting
454
491
 
455
492
  **Every MCP tool accepts an optional `max_tokens` argument.** Set it and projscan serializes the result, and - if over budget - truncates the largest array field record-by-record until it fits. Responses include a `_budget` sidecar when truncated so your agent knows it got a partial view.
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { buildImportGraph } from '../core/importGraph.js';
3
+ import { buildImportGraph, toPackageName } from '../core/importGraph.js';
4
+ import { detectWorkspaces } from '../core/monorepo.js';
4
5
  import { findDependencyLines } from '../utils/packageJsonLocator.js';
5
6
  /**
6
7
  * Patterns for packages that are typically not imported directly from source
@@ -68,7 +69,52 @@ function isImplicitlyUsed(pkg) {
68
69
  return IMPLICIT_USE_PREFIXES.some((prefix) => pkg.startsWith(prefix));
69
70
  }
70
71
  export async function check(rootPath, files) {
71
- const pkgPath = path.join(rootPath, 'package.json');
72
+ // Build the import graph once across the whole repo. We slice it per-package
73
+ // below for workspace-aware mode.
74
+ const fullGraph = await buildImportGraph(rootPath, files);
75
+ // Workspace detection. When the repo is a single package (kind 'none') or a
76
+ // root-only manifest with no real workspaces, we degrade to the original
77
+ // single-manifest path for full backward compatibility.
78
+ const ws = await detectWorkspaces(rootPath);
79
+ const realWorkspaces = ws.packages.filter((p) => !p.isRoot);
80
+ const isMonorepo = ws.kind !== 'none' && realWorkspaces.length > 0;
81
+ if (!isMonorepo) {
82
+ return await checkOnePackage(rootPath, '', fullGraph, files);
83
+ }
84
+ // Workspace-aware: check the root manifest (if any) AND each workspace package.
85
+ // Each gets its own deps-vs-imports comparison, scoped to the files that
86
+ // belong to that package by longest-prefix path matching.
87
+ const issues = [];
88
+ const rootPkg = ws.packages.find((p) => p.isRoot);
89
+ if (rootPkg) {
90
+ // Root manifest: only consider files NOT under any workspace package dir.
91
+ const claimedPrefixes = realWorkspaces
92
+ .map((p) => p.relativePath)
93
+ .filter((p) => p.length > 0);
94
+ const rootFiles = files.filter((f) => !claimedPrefixes.some((prefix) => f.relativePath.startsWith(prefix + '/')));
95
+ issues.push(...(await checkOnePackage(rootPath, '', fullGraph, rootFiles)));
96
+ }
97
+ for (const wp of realWorkspaces) {
98
+ const pkgDir = path.join(rootPath, wp.relativePath);
99
+ const prefix = wp.relativePath + '/';
100
+ const wpFiles = files.filter((f) => f.relativePath === wp.relativePath || f.relativePath.startsWith(prefix));
101
+ issues.push(...(await checkOnePackage(pkgDir, wp.relativePath, fullGraph, wpFiles)));
102
+ }
103
+ return issues;
104
+ }
105
+ /**
106
+ * Run the unused-dependency check against one package.json.
107
+ *
108
+ * @param packageDir absolute path to the directory containing package.json.
109
+ * @param locationPrefix path prefix (relative to repo root) used in issue
110
+ * `locations.file`. Empty string for the repo root; e.g. `packages/foo` for
111
+ * a workspace package - produces locations like `packages/foo/package.json`.
112
+ * @param fullGraph repo-wide import graph (built once and reused).
113
+ * @param scopedFiles file list this manifest is responsible for. We slice the
114
+ * global graph down to imports from these files only.
115
+ */
116
+ async function checkOnePackage(packageDir, locationPrefix, fullGraph, scopedFiles) {
117
+ const pkgPath = path.join(packageDir, 'package.json');
72
118
  let raw;
73
119
  try {
74
120
  raw = await fs.readFile(pkgPath, 'utf-8');
@@ -88,36 +134,42 @@ export async function check(rootPath, files) {
88
134
  const allDeclared = new Set([...Object.keys(dependencies), ...Object.keys(devDependencies)]);
89
135
  if (allDeclared.size === 0)
90
136
  return [];
91
- const graph = await buildImportGraph(rootPath, files);
92
- // Also treat packages invoked from package.json scripts as used.
93
- // e.g., "build": "tsc" means we should not flag typescript.
137
+ // Project per-package usage: walk only the files this manifest covers and
138
+ // collect their external package names from the full graph's byFile map.
139
+ const usedPackages = new Set();
140
+ for (const f of scopedFiles) {
141
+ const specifiers = fullGraph.byFile.get(f.relativePath);
142
+ if (!specifiers)
143
+ continue;
144
+ for (const spec of specifiers) {
145
+ const name = toPackageName(spec);
146
+ if (name)
147
+ usedPackages.add(name);
148
+ }
149
+ }
94
150
  const scriptUsedBinaries = extractScriptBinaries(pkg);
95
- const locations = await findDependencyLines(rootPath);
151
+ const locations = await findDependencyLines(packageDir);
152
+ const locationFile = locationPrefix ? `${locationPrefix}/package.json` : 'package.json';
96
153
  const unused = [];
97
154
  for (const name of allDeclared) {
98
- if (graph.externalPackages.has(name))
155
+ if (usedPackages.has(name))
99
156
  continue;
100
157
  if (isImplicitlyUsed(name))
101
158
  continue;
102
159
  if (scriptUsedBinaries.has(name))
103
160
  continue;
104
- // skip scoped bin lookups (e.g., "npx some-tool") - covered by scriptUsedBinaries
105
161
  const isDev = name in devDependencies;
106
162
  const line = locations?.lineOfDependency.get(name);
163
+ const inWorkspace = locationPrefix ? ` (workspace: ${locationPrefix})` : '';
107
164
  unused.push({
108
- id: `unused-dependency-${name}`,
109
- title: `Unused ${isDev ? 'dev' : ''} dependency: ${name}`.replace(' ', ' ').trim(),
110
- description: `The package "${name}" is declared in package.json but never imported from source. If it's used only in package.json scripts or as a plugin, add it to the projscan allowlist via .projscanrc → disableRules.`,
165
+ id: locationPrefix ? `unused-dependency-${locationPrefix}-${name}` : `unused-dependency-${name}`,
166
+ title: `Unused ${isDev ? 'dev' : ''} dependency: ${name}${inWorkspace}`.replace(' ', ' ').trim(),
167
+ description: `The package "${name}" is declared in ${locationFile} but never imported from source files under that package. If it's used only in package.json scripts or as a plugin, add it to the projscan allowlist via .projscanrc → disableRules.`,
111
168
  severity: isDev ? 'info' : 'warning',
112
169
  category: 'dependencies',
113
170
  fixAvailable: false,
114
171
  locations: locations
115
- ? [
116
- {
117
- file: 'package.json',
118
- line: line ?? 1,
119
- },
120
- ]
172
+ ? [{ file: locationFile, line: line ?? 1 }]
121
173
  : undefined,
122
174
  });
123
175
  }
@@ -1 +1 @@
1
- {"version":3,"file":"unusedDependencyCheck.js","sourceRoot":"","sources":["../../src/analyzers/unusedDependencyCheck.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"unusedDependencyCheck.js","sourceRoot":"","sources":["../../src/analyzers/unusedDependencyCheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { Command } from 'commander';
2
+ import type { ArchitectureLayer, FileExplanation, Issue, ProjscanConfig, ReportFormat, FileEntry, DirectoryNode } from '../types.js';
3
+ export declare const pkg: any;
4
+ export declare const program: Command;
5
+ export declare function getFormat(): ReportFormat;
6
+ export declare function getRootPath(): string;
7
+ export declare function loadProjectConfig(): Promise<ProjscanConfig>;
8
+ export declare function filterIssuesByChangedFiles(issues: Issue[], rootPath: string, baseRef?: string): Promise<Issue[]>;
9
+ export declare function setupLogLevel(): void;
10
+ export declare function maybeBanner(): void;
11
+ export declare function maybeCompactBanner(): void;
12
+ /** Walk a DirectoryNode to find the node whose `path` matches targetPath. */
13
+ export declare function sliceCliTree(node: DirectoryNode, targetPath: string): DirectoryNode | null;
14
+ export declare function analyzeFile(filePath: string, content: string): FileExplanation;
15
+ export declare function buildArchitectureLayers(files: FileEntry[], frameworkNames: string[]): ArchitectureLayer[];
16
+ export declare function promptYesNo(question: string): Promise<boolean>;
@@ -0,0 +1,210 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import path from 'node:path';
4
+ import readline from 'node:readline';
5
+ import { readFileSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { extractImports, extractExports, inferPurpose, detectFileIssues, } from '../core/fileInspector.js';
8
+ import { setLogLevel } from '../utils/logger.js';
9
+ import { showBanner, showCompactBanner } from '../utils/banner.js';
10
+ import { loadConfig } from '../utils/config.js';
11
+ import { getChangedFiles } from '../utils/changedFiles.js';
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ export const pkg = JSON.parse(readFileSync(path.resolve(__dirname, '../../package.json'), 'utf-8'));
14
+ export const program = new Command();
15
+ program
16
+ .name('projscan')
17
+ .description('Instant codebase insights - doctor, x-ray, and architecture map for any repository')
18
+ .version(pkg.version)
19
+ .option('--format <type>', 'output format: console, json, markdown, sarif', 'console')
20
+ .option('--config <path>', 'path to .projscanrc config file')
21
+ .option('--verbose', 'enable verbose output')
22
+ .option('--quiet', 'suppress non-essential output');
23
+ export function getFormat() {
24
+ const opts = program.opts();
25
+ const f = opts.format;
26
+ if (f === 'json' || f === 'markdown' || f === 'sarif')
27
+ return f;
28
+ return 'console';
29
+ }
30
+ export function getRootPath() {
31
+ return process.cwd();
32
+ }
33
+ export async function loadProjectConfig() {
34
+ const opts = program.opts();
35
+ const explicit = typeof opts.config === 'string' ? opts.config : undefined;
36
+ try {
37
+ const { config, source } = await loadConfig(getRootPath(), explicit);
38
+ if (source && !opts.quiet && getFormat() === 'console') {
39
+ console.error(chalk.dim(` [config: ${path.relative(getRootPath(), source) || source}]`));
40
+ }
41
+ return config;
42
+ }
43
+ catch (err) {
44
+ const msg = err instanceof Error ? err.message : String(err);
45
+ console.error(chalk.red(` Config error: ${msg}`));
46
+ process.exit(1);
47
+ }
48
+ }
49
+ export async function filterIssuesByChangedFiles(issues, rootPath, baseRef) {
50
+ const result = await getChangedFiles(rootPath, baseRef);
51
+ if (!result.available) {
52
+ if (getFormat() === 'console' && !program.opts().quiet) {
53
+ console.error(chalk.yellow(` [--changed-only: ${result.reason ?? 'unavailable'} - reporting all issues]`));
54
+ }
55
+ return issues;
56
+ }
57
+ if (getFormat() === 'console' && !program.opts().quiet) {
58
+ console.error(chalk.dim(` [--changed-only: base=${result.baseRef}, ${result.files.length} file(s)]`));
59
+ }
60
+ const set = new Set(result.files);
61
+ const filtered = issues.filter((issue) => {
62
+ if (!issue.locations || issue.locations.length === 0)
63
+ return false;
64
+ return issue.locations.some((loc) => set.has(loc.file));
65
+ });
66
+ const dropped = issues.length - filtered.length;
67
+ if (dropped > 0 && !program.opts().quiet) {
68
+ const unlocated = issues.filter((i) => !i.locations || i.locations.length === 0).length;
69
+ const message = unlocated > 0
70
+ ? ` [--changed-only: ${dropped} issue(s) filtered out; ${unlocated} had no file location]`
71
+ : ` [--changed-only: ${dropped} issue(s) outside the changed-file set]`;
72
+ if (getFormat() === 'console') {
73
+ console.error(chalk.dim(message));
74
+ }
75
+ else {
76
+ console.error(message.trim());
77
+ }
78
+ }
79
+ return filtered;
80
+ }
81
+ export function setupLogLevel() {
82
+ const opts = program.opts();
83
+ if (opts.verbose)
84
+ setLogLevel('debug');
85
+ else if (opts.quiet)
86
+ setLogLevel('quiet');
87
+ }
88
+ export function maybeBanner() {
89
+ const opts = program.opts();
90
+ if (!opts.quiet && getFormat() === 'console') {
91
+ try {
92
+ showBanner();
93
+ }
94
+ catch (err) {
95
+ console.error(chalk.dim(` [banner error: ${err instanceof Error ? err.message : String(err)}]`));
96
+ }
97
+ }
98
+ }
99
+ export function maybeCompactBanner() {
100
+ const opts = program.opts();
101
+ if (!opts.quiet && getFormat() === 'console') {
102
+ try {
103
+ showCompactBanner();
104
+ }
105
+ catch (err) {
106
+ console.error(chalk.dim(` [banner error: ${err instanceof Error ? err.message : String(err)}]`));
107
+ }
108
+ }
109
+ }
110
+ /** Walk a DirectoryNode to find the node whose `path` matches targetPath. */
111
+ export function sliceCliTree(node, targetPath) {
112
+ if (node.path === targetPath)
113
+ return node;
114
+ for (const child of node.children) {
115
+ const hit = sliceCliTree(child, targetPath);
116
+ if (hit)
117
+ return hit;
118
+ }
119
+ return null;
120
+ }
121
+ export function analyzeFile(filePath, content) {
122
+ const lines = content.split('\n');
123
+ const imports = extractImports(content);
124
+ const exports = extractExports(content);
125
+ const purpose = inferPurpose(filePath, exports);
126
+ const potentialIssues = detectFileIssues(content, lines.length);
127
+ return {
128
+ filePath: path.relative(process.cwd(), filePath),
129
+ purpose,
130
+ imports,
131
+ exports,
132
+ potentialIssues,
133
+ lineCount: lines.length,
134
+ };
135
+ }
136
+ export function buildArchitectureLayers(files, frameworkNames) {
137
+ const layers = [];
138
+ const dirs = new Set(files.map((f) => f.directory.split(path.sep)[0]).filter(Boolean));
139
+ const frontendDirs = ['pages', 'components', 'views', 'layouts', 'public', 'app', 'styles'];
140
+ const frontendMatches = frontendDirs.filter((d) => dirs.has(d) || dirs.has(`src/${d}`));
141
+ const frontendFrameworks = frameworkNames.filter((f) => ['React', 'Next.js', 'Vue.js', 'Nuxt.js', 'Svelte', 'SvelteKit', 'Angular', 'Solid.js'].includes(f));
142
+ if (frontendMatches.length > 0 || frontendFrameworks.length > 0) {
143
+ layers.push({
144
+ name: 'Frontend',
145
+ technologies: frontendFrameworks.length > 0 ? frontendFrameworks : ['Static'],
146
+ directories: frontendMatches,
147
+ });
148
+ }
149
+ const apiDirs = ['api', 'routes', 'controllers', 'endpoints'];
150
+ const apiMatches = apiDirs.filter((d) => dirs.has(d) || dirs.has(`src/${d}`));
151
+ const apiFrameworks = frameworkNames.filter((f) => ['Express', 'Fastify', 'NestJS', 'Hono', 'Koa', 'Apollo Server', 'tRPC'].includes(f));
152
+ if (apiMatches.length > 0 || apiFrameworks.length > 0) {
153
+ layers.push({
154
+ name: 'API Layer',
155
+ technologies: apiFrameworks.length > 0 ? apiFrameworks : ['HTTP'],
156
+ directories: apiMatches,
157
+ });
158
+ }
159
+ const serviceDirs = ['services', 'lib', 'core', 'domain', 'modules'];
160
+ const serviceMatches = serviceDirs.filter((d) => dirs.has(d) || dirs.has(`src/${d}`));
161
+ if (serviceMatches.length > 0) {
162
+ layers.push({
163
+ name: 'Services',
164
+ technologies: inferServiceTech(files, serviceMatches),
165
+ directories: serviceMatches,
166
+ });
167
+ }
168
+ const dbDirs = ['db', 'database', 'prisma', 'migrations', 'models', 'entities'];
169
+ const dbMatches = dbDirs.filter((d) => dirs.has(d) || dirs.has(`src/${d}`));
170
+ const dbFrameworks = frameworkNames.filter((f) => ['Prisma', 'Drizzle ORM', 'Mongoose', 'TypeORM', 'Sequelize'].includes(f));
171
+ if (dbMatches.length > 0 || dbFrameworks.length > 0) {
172
+ layers.push({
173
+ name: 'Database',
174
+ technologies: dbFrameworks.length > 0 ? dbFrameworks : ['Database'],
175
+ directories: dbMatches,
176
+ });
177
+ }
178
+ if (layers.length === 0) {
179
+ const topDirs = [...dirs].slice(0, 5);
180
+ layers.push({
181
+ name: 'Application',
182
+ technologies: frameworkNames.length > 0 ? frameworkNames : ['Unknown'],
183
+ directories: topDirs,
184
+ });
185
+ }
186
+ return layers;
187
+ }
188
+ function inferServiceTech(files, serviceDirs) {
189
+ const techs = [];
190
+ const serviceFiles = files.filter((f) => serviceDirs.some((d) => f.directory.startsWith(d)));
191
+ const hasTsFiles = serviceFiles.some((f) => f.extension === '.ts' || f.extension === '.tsx');
192
+ const hasJsFiles = serviceFiles.some((f) => f.extension === '.js' || f.extension === '.jsx');
193
+ if (hasTsFiles)
194
+ techs.push('TypeScript');
195
+ else if (hasJsFiles)
196
+ techs.push('JavaScript');
197
+ if (techs.length === 0)
198
+ techs.push('Mixed');
199
+ return techs;
200
+ }
201
+ export function promptYesNo(question) {
202
+ return new Promise((resolve) => {
203
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
204
+ rl.question(question, (answer) => {
205
+ rl.close();
206
+ resolve(answer.toLowerCase().startsWith('y'));
207
+ });
208
+ });
209
+ }
210
+ //# sourceMappingURL=_shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_shared.js","sourceRoot":"","sources":["../../src/cli/_shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function registerAnalyze(): void;
@@ -0,0 +1,87 @@
1
+ import ora from 'ora';
2
+ import chalk from 'chalk';
3
+ import path from 'node:path';
4
+ import { program, pkg, getFormat, getRootPath, loadProjectConfig, setupLogLevel, maybeBanner, filterIssuesByChangedFiles, } from '../_shared.js';
5
+ import { scanRepository } from '../../core/repositoryScanner.js';
6
+ import { detectLanguages } from '../../core/languageDetector.js';
7
+ import { detectFrameworks } from '../../core/frameworkDetector.js';
8
+ import { analyzeDependencies } from '../../core/dependencyAnalyzer.js';
9
+ import { collectIssues } from '../../core/issueEngine.js';
10
+ import { detectWorkspaces, filterFilesByPackage } from '../../core/monorepo.js';
11
+ import { applyConfigToIssues } from '../../utils/config.js';
12
+ import { reportAnalysis } from '../../reporters/consoleReporter.js';
13
+ import { reportAnalysisJson } from '../../reporters/jsonReporter.js';
14
+ import { reportAnalysisMarkdown } from '../../reporters/markdownReporter.js';
15
+ import { reportAnalysisSarif } from '../../reporters/sarifReporter.js';
16
+ export function registerAnalyze() {
17
+ program
18
+ .command('analyze', { isDefault: true })
19
+ .description('Analyze repository and show project report')
20
+ .option('--changed-only', 'only report issues on files changed vs base ref')
21
+ .option('--base-ref <ref>', 'git base ref for --changed-only (default: origin/main)')
22
+ .option('--package <name>', 'monorepo: scope issues to a single workspace package')
23
+ .action(async (cmdOpts) => {
24
+ setupLogLevel();
25
+ maybeBanner();
26
+ const rootPath = getRootPath();
27
+ const format = getFormat();
28
+ const config = await loadProjectConfig();
29
+ const spinner = format === 'console' ? ora('Scanning repository...').start() : null;
30
+ try {
31
+ const scan = await scanRepository(rootPath, { ignore: config.ignore });
32
+ if (spinner)
33
+ spinner.text = 'Detecting languages...';
34
+ const languages = detectLanguages(scan.files);
35
+ if (spinner)
36
+ spinner.text = 'Detecting frameworks...';
37
+ const frameworks = await detectFrameworks(rootPath, scan.files);
38
+ if (spinner)
39
+ spinner.text = 'Analyzing dependencies...';
40
+ const dependencies = await analyzeDependencies(rootPath);
41
+ if (spinner)
42
+ spinner.text = 'Checking for issues...';
43
+ let issues = await collectIssues(rootPath, scan.files);
44
+ issues = applyConfigToIssues(issues, config);
45
+ if (cmdOpts.changedOnly) {
46
+ issues = await filterIssuesByChangedFiles(issues, rootPath, cmdOpts.baseRef ?? config.baseRef);
47
+ }
48
+ if (cmdOpts.package) {
49
+ const ws = await detectWorkspaces(rootPath);
50
+ const allowed = new Set(filterFilesByPackage(ws, cmdOpts.package, scan.files.map((f) => f.relativePath)));
51
+ issues = issues.filter((i) => (i.locations ?? []).some((l) => l.file && allowed.has(l.file)));
52
+ }
53
+ if (spinner)
54
+ spinner.stop();
55
+ const report = {
56
+ projectName: path.basename(rootPath),
57
+ rootPath,
58
+ scan,
59
+ languages,
60
+ frameworks,
61
+ dependencies,
62
+ issues,
63
+ timestamp: new Date().toISOString(),
64
+ };
65
+ switch (format) {
66
+ case 'json':
67
+ reportAnalysisJson(report);
68
+ break;
69
+ case 'markdown':
70
+ reportAnalysisMarkdown(report);
71
+ break;
72
+ case 'sarif':
73
+ reportAnalysisSarif(issues, pkg.version);
74
+ break;
75
+ default:
76
+ reportAnalysis(report);
77
+ }
78
+ }
79
+ catch (error) {
80
+ if (spinner)
81
+ spinner.fail('Analysis failed');
82
+ console.error(chalk.red(error instanceof Error ? error.message : String(error)));
83
+ process.exit(1);
84
+ }
85
+ });
86
+ }
87
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/cli/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,OAAO,EACP,GAAG,EACH,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAGvE,MAAM,UAAU,eAAe;IAC7B,OAAO;SACJ,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACvC,WAAW,CAAC,4CAA4C,CAAC;SACzD,MAAM,CAAC,gBAAgB,EAAE,iDAAiD,CAAC;SAC3E,MAAM,CAAC,kBAAkB,EAAE,wDAAwD,CAAC;SACpF,MAAM,CAAC,kBAAkB,EAAE,sDAAsD,CAAC;SAClF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,aAAa,EAAE,CAAC;QAChB,WAAW,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,iBAAiB,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAEpF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACvE,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,GAAG,wBAAwB,CAAC;YACrD,MAAM,SAAS,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAE9C,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,GAAG,yBAAyB,CAAC;YACtD,MAAM,UAAU,GAAG,MAAM,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAEhE,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,GAAG,2BAA2B,CAAC;YACxD,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,QAAQ,CAAC,CAAC;YAEzD,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,GAAG,wBAAwB,CAAC;YACrD,IAAI,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YACvD,MAAM,GAAG,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;YAC7C,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,MAAM,GAAG,MAAM,0BAA0B,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC;YACjG,CAAC;YACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC1G,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAChG,CAAC;YAED,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,EAAE,CAAC;YAE5B,MAAM,MAAM,GAAmB;gBAC7B,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBACpC,QAAQ;gBACR,IAAI;gBACJ,SAAS;gBACT,UAAU;gBACV,YAAY;gBACZ,MAAM;gBACN,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YAEF,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,MAAM;oBACT,kBAAkB,CAAC,MAAM,CAAC,CAAC;oBAC3B,MAAM;gBACR,KAAK,UAAU;oBACb,sBAAsB,CAAC,MAAM,CAAC,CAAC;oBAC/B,MAAM;gBACR,KAAK,OAAO;oBACV,mBAAmB,CAAC,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;oBACzC,MAAM;gBACR;oBACE,cAAc,CAAC,MAAM,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC7C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function registerAudit(): void;