autodocs-engine 0.5.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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +185 -0
  3. package/dist/analysis-builder.d.ts +13 -0
  4. package/dist/analysis-builder.js +268 -0
  5. package/dist/analysis-builder.js.map +1 -0
  6. package/dist/anti-pattern-detector.d.ts +9 -0
  7. package/dist/anti-pattern-detector.js +58 -0
  8. package/dist/anti-pattern-detector.js.map +1 -0
  9. package/dist/architecture-detector.d.ts +7 -0
  10. package/dist/architecture-detector.js +212 -0
  11. package/dist/architecture-detector.js.map +1 -0
  12. package/dist/ast-parser.d.ts +5 -0
  13. package/dist/ast-parser.js +635 -0
  14. package/dist/ast-parser.js.map +1 -0
  15. package/dist/benchmark/code-generator.d.ts +20 -0
  16. package/dist/benchmark/code-generator.js +206 -0
  17. package/dist/benchmark/code-generator.js.map +1 -0
  18. package/dist/benchmark/pr-miner.d.ts +61 -0
  19. package/dist/benchmark/pr-miner.js +304 -0
  20. package/dist/benchmark/pr-miner.js.map +1 -0
  21. package/dist/benchmark/pr-runner.d.ts +58 -0
  22. package/dist/benchmark/pr-runner.js +346 -0
  23. package/dist/benchmark/pr-runner.js.map +1 -0
  24. package/dist/benchmark/pr-scorer.d.ts +48 -0
  25. package/dist/benchmark/pr-scorer.js +222 -0
  26. package/dist/benchmark/pr-scorer.js.map +1 -0
  27. package/dist/benchmark/pr-task-gen.d.ts +16 -0
  28. package/dist/benchmark/pr-task-gen.js +129 -0
  29. package/dist/benchmark/pr-task-gen.js.map +1 -0
  30. package/dist/benchmark/report.d.ts +9 -0
  31. package/dist/benchmark/report.js +131 -0
  32. package/dist/benchmark/report.js.map +1 -0
  33. package/dist/benchmark/runner.d.ts +6 -0
  34. package/dist/benchmark/runner.js +183 -0
  35. package/dist/benchmark/runner.js.map +1 -0
  36. package/dist/benchmark/scorer.d.ts +6 -0
  37. package/dist/benchmark/scorer.js +549 -0
  38. package/dist/benchmark/scorer.js.map +1 -0
  39. package/dist/benchmark/shuffler.d.ts +5 -0
  40. package/dist/benchmark/shuffler.js +70 -0
  41. package/dist/benchmark/shuffler.js.map +1 -0
  42. package/dist/benchmark/statistics.d.ts +36 -0
  43. package/dist/benchmark/statistics.js +159 -0
  44. package/dist/benchmark/statistics.js.map +1 -0
  45. package/dist/benchmark/task-generator.d.ts +20 -0
  46. package/dist/benchmark/task-generator.js +388 -0
  47. package/dist/benchmark/task-generator.js.map +1 -0
  48. package/dist/benchmark/types.d.ts +111 -0
  49. package/dist/benchmark/types.js +3 -0
  50. package/dist/benchmark/types.js.map +1 -0
  51. package/dist/bin/autodocs-engine.d.ts +2 -0
  52. package/dist/bin/autodocs-engine.js +296 -0
  53. package/dist/bin/autodocs-engine.js.map +1 -0
  54. package/dist/bin/benchmark.d.ts +14 -0
  55. package/dist/bin/benchmark.js +172 -0
  56. package/dist/bin/benchmark.js.map +1 -0
  57. package/dist/bin/check.d.ts +13 -0
  58. package/dist/bin/check.js +79 -0
  59. package/dist/bin/check.js.map +1 -0
  60. package/dist/bin/init.d.ts +11 -0
  61. package/dist/bin/init.js +268 -0
  62. package/dist/bin/init.js.map +1 -0
  63. package/dist/bin/serve.d.ts +4 -0
  64. package/dist/bin/serve.js +29 -0
  65. package/dist/bin/serve.js.map +1 -0
  66. package/dist/budget-validator.d.ts +22 -0
  67. package/dist/budget-validator.js +119 -0
  68. package/dist/budget-validator.js.map +1 -0
  69. package/dist/command-extractor.d.ts +10 -0
  70. package/dist/command-extractor.js +276 -0
  71. package/dist/command-extractor.js.map +1 -0
  72. package/dist/config-analyzer.d.ts +5 -0
  73. package/dist/config-analyzer.js +364 -0
  74. package/dist/config-analyzer.js.map +1 -0
  75. package/dist/config.d.ts +33 -0
  76. package/dist/config.js +172 -0
  77. package/dist/config.js.map +1 -0
  78. package/dist/contribution-patterns.d.ts +6 -0
  79. package/dist/contribution-patterns.js +263 -0
  80. package/dist/contribution-patterns.js.map +1 -0
  81. package/dist/convention-extractor.d.ts +17 -0
  82. package/dist/convention-extractor.js +90 -0
  83. package/dist/convention-extractor.js.map +1 -0
  84. package/dist/cross-package.d.ts +5 -0
  85. package/dist/cross-package.js +71 -0
  86. package/dist/cross-package.js.map +1 -0
  87. package/dist/dependency-analyzer.d.ts +5 -0
  88. package/dist/dependency-analyzer.js +233 -0
  89. package/dist/dependency-analyzer.js.map +1 -0
  90. package/dist/detectors/build-tool.d.ts +2 -0
  91. package/dist/detectors/build-tool.js +67 -0
  92. package/dist/detectors/build-tool.js.map +1 -0
  93. package/dist/detectors/component-patterns.d.ts +2 -0
  94. package/dist/detectors/component-patterns.js +49 -0
  95. package/dist/detectors/component-patterns.js.map +1 -0
  96. package/dist/detectors/data-fetching.d.ts +2 -0
  97. package/dist/detectors/data-fetching.js +127 -0
  98. package/dist/detectors/data-fetching.js.map +1 -0
  99. package/dist/detectors/database.d.ts +2 -0
  100. package/dist/detectors/database.js +54 -0
  101. package/dist/detectors/database.js.map +1 -0
  102. package/dist/detectors/error-handling.d.ts +2 -0
  103. package/dist/detectors/error-handling.js +47 -0
  104. package/dist/detectors/error-handling.js.map +1 -0
  105. package/dist/detectors/export-patterns.d.ts +2 -0
  106. package/dist/detectors/export-patterns.js +64 -0
  107. package/dist/detectors/export-patterns.js.map +1 -0
  108. package/dist/detectors/file-naming.d.ts +2 -0
  109. package/dist/detectors/file-naming.js +74 -0
  110. package/dist/detectors/file-naming.js.map +1 -0
  111. package/dist/detectors/graphql-patterns.d.ts +2 -0
  112. package/dist/detectors/graphql-patterns.js +47 -0
  113. package/dist/detectors/graphql-patterns.js.map +1 -0
  114. package/dist/detectors/hook-patterns.d.ts +2 -0
  115. package/dist/detectors/hook-patterns.js +105 -0
  116. package/dist/detectors/hook-patterns.js.map +1 -0
  117. package/dist/detectors/import-patterns.d.ts +2 -0
  118. package/dist/detectors/import-patterns.js +88 -0
  119. package/dist/detectors/import-patterns.js.map +1 -0
  120. package/dist/detectors/telemetry-patterns.d.ts +2 -0
  121. package/dist/detectors/telemetry-patterns.js +42 -0
  122. package/dist/detectors/telemetry-patterns.js.map +1 -0
  123. package/dist/detectors/test-framework-ecosystem.d.ts +2 -0
  124. package/dist/detectors/test-framework-ecosystem.js +95 -0
  125. package/dist/detectors/test-framework-ecosystem.js.map +1 -0
  126. package/dist/detectors/test-patterns.d.ts +2 -0
  127. package/dist/detectors/test-patterns.js +60 -0
  128. package/dist/detectors/test-patterns.js.map +1 -0
  129. package/dist/detectors/web-framework.d.ts +2 -0
  130. package/dist/detectors/web-framework.js +51 -0
  131. package/dist/detectors/web-framework.js.map +1 -0
  132. package/dist/deterministic-formatter.d.ts +54 -0
  133. package/dist/deterministic-formatter.js +922 -0
  134. package/dist/deterministic-formatter.js.map +1 -0
  135. package/dist/diff-analyzer.d.ts +7 -0
  136. package/dist/diff-analyzer.js +126 -0
  137. package/dist/diff-analyzer.js.map +1 -0
  138. package/dist/example-extractor.d.ts +6 -0
  139. package/dist/example-extractor.js +115 -0
  140. package/dist/example-extractor.js.map +1 -0
  141. package/dist/existing-docs.d.ts +36 -0
  142. package/dist/existing-docs.js +257 -0
  143. package/dist/existing-docs.js.map +1 -0
  144. package/dist/file-discovery.d.ts +6 -0
  145. package/dist/file-discovery.js +154 -0
  146. package/dist/file-discovery.js.map +1 -0
  147. package/dist/git-history.d.ts +41 -0
  148. package/dist/git-history.js +401 -0
  149. package/dist/git-history.js.map +1 -0
  150. package/dist/impact-classifier.d.ts +22 -0
  151. package/dist/impact-classifier.js +87 -0
  152. package/dist/impact-classifier.js.map +1 -0
  153. package/dist/impact-radius.d.ts +23 -0
  154. package/dist/impact-radius.js +130 -0
  155. package/dist/impact-radius.js.map +1 -0
  156. package/dist/import-chain.d.ts +12 -0
  157. package/dist/import-chain.js +93 -0
  158. package/dist/import-chain.js.map +1 -0
  159. package/dist/index.d.ts +40 -0
  160. package/dist/index.js +72 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/inferability.d.ts +16 -0
  163. package/dist/inferability.js +142 -0
  164. package/dist/inferability.js.map +1 -0
  165. package/dist/llm/adapter.d.ts +33 -0
  166. package/dist/llm/adapter.js +202 -0
  167. package/dist/llm/adapter.js.map +1 -0
  168. package/dist/llm/client.d.ts +5 -0
  169. package/dist/llm/client.js +68 -0
  170. package/dist/llm/client.js.map +1 -0
  171. package/dist/llm/hierarchical.d.ts +23 -0
  172. package/dist/llm/hierarchical.js +126 -0
  173. package/dist/llm/hierarchical.js.map +1 -0
  174. package/dist/llm/serializer.d.ts +19 -0
  175. package/dist/llm/serializer.js +363 -0
  176. package/dist/llm/serializer.js.map +1 -0
  177. package/dist/llm/template-selector.d.ts +7 -0
  178. package/dist/llm/template-selector.js +21 -0
  179. package/dist/llm/template-selector.js.map +1 -0
  180. package/dist/llm-adapter.d.ts +2 -0
  181. package/dist/llm-adapter.js +5 -0
  182. package/dist/llm-adapter.js.map +1 -0
  183. package/dist/mcp/cache.d.ts +30 -0
  184. package/dist/mcp/cache.js +112 -0
  185. package/dist/mcp/cache.js.map +1 -0
  186. package/dist/mcp/errors.d.ts +21 -0
  187. package/dist/mcp/errors.js +27 -0
  188. package/dist/mcp/errors.js.map +1 -0
  189. package/dist/mcp/queries.d.ts +27 -0
  190. package/dist/mcp/queries.js +121 -0
  191. package/dist/mcp/queries.js.map +1 -0
  192. package/dist/mcp/server.d.ts +14 -0
  193. package/dist/mcp/server.js +131 -0
  194. package/dist/mcp/server.js.map +1 -0
  195. package/dist/mcp/tools.d.ts +39 -0
  196. package/dist/mcp/tools.js +249 -0
  197. package/dist/mcp/tools.js.map +1 -0
  198. package/dist/mermaid-generator.d.ts +6 -0
  199. package/dist/mermaid-generator.js +59 -0
  200. package/dist/mermaid-generator.js.map +1 -0
  201. package/dist/meta-tool-detector.d.ts +23 -0
  202. package/dist/meta-tool-detector.js +177 -0
  203. package/dist/meta-tool-detector.js.map +1 -0
  204. package/dist/output-validator.d.ts +6 -0
  205. package/dist/output-validator.js +471 -0
  206. package/dist/output-validator.js.map +1 -0
  207. package/dist/pattern-fingerprinter.d.ts +7 -0
  208. package/dist/pattern-fingerprinter.js +241 -0
  209. package/dist/pattern-fingerprinter.js.map +1 -0
  210. package/dist/pipeline.d.ts +5 -0
  211. package/dist/pipeline.js +374 -0
  212. package/dist/pipeline.js.map +1 -0
  213. package/dist/plugin-loader.d.ts +19 -0
  214. package/dist/plugin-loader.js +124 -0
  215. package/dist/plugin-loader.js.map +1 -0
  216. package/dist/role-inferrer.d.ts +5 -0
  217. package/dist/role-inferrer.js +159 -0
  218. package/dist/role-inferrer.js.map +1 -0
  219. package/dist/symbol-graph.d.ts +11 -0
  220. package/dist/symbol-graph.js +613 -0
  221. package/dist/symbol-graph.js.map +1 -0
  222. package/dist/templates/agents-md.d.ts +20 -0
  223. package/dist/templates/agents-md.js +346 -0
  224. package/dist/templates/agents-md.js.map +1 -0
  225. package/dist/templates/claude-md.d.ts +4 -0
  226. package/dist/templates/claude-md.js +23 -0
  227. package/dist/templates/claude-md.js.map +1 -0
  228. package/dist/templates/cursorrules.d.ts +4 -0
  229. package/dist/templates/cursorrules.js +18 -0
  230. package/dist/templates/cursorrules.js.map +1 -0
  231. package/dist/tier-classifier.d.ts +7 -0
  232. package/dist/tier-classifier.js +32 -0
  233. package/dist/tier-classifier.js.map +1 -0
  234. package/dist/types.d.ts +428 -0
  235. package/dist/types.js +42 -0
  236. package/dist/types.js.map +1 -0
  237. package/dist/workflow-rules.d.ts +18 -0
  238. package/dist/workflow-rules.js +131 -0
  239. package/dist/workflow-rules.js.map +1 -0
  240. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 autodocs-engine contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # autodocs-engine
2
+
3
+ Deterministic codebase intelligence for AI coding tools.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/autodocs-engine)](https://www.npmjs.com/package/autodocs-engine)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+ [![Node.js](https://img.shields.io/node/v/autodocs-engine)](https://nodejs.org)
8
+
9
+ ## What It Does
10
+
11
+ Analyzes TypeScript/JavaScript codebases and extracts actionable intelligence — commands, conventions, file coupling patterns, contribution recipes, architecture — that AI coding tools need to write code that fits your project.
12
+
13
+ Two ways to use it:
14
+
15
+ 1. **MCP Server** — Live codebase queries via Model Context Protocol. AI tools ask for exactly the context they need, on demand.
16
+ 2. **AGENTS.md Generator** — Static context file for universal compatibility. Works with every tool that reads AGENTS.md, CLAUDE.md, or .cursorrules.
17
+
18
+ ## Quick Start
19
+
20
+ ```bash
21
+ # Generate a focused AGENTS.md (no API key needed)
22
+ npx autodocs-engine init --minimal
23
+
24
+ # Or start the MCP server for live queries
25
+ npx autodocs-engine serve
26
+ ```
27
+
28
+ ### MCP Server Setup (Claude Code)
29
+
30
+ ```bash
31
+ claude mcp add autodocs -- npx autodocs-engine serve
32
+ ```
33
+
34
+ This gives Claude Code 8 codebase intelligence tools:
35
+
36
+ | Tool | What It Returns |
37
+ |------|----------------|
38
+ | `get_commands` | Build, test, lint commands with exact flags |
39
+ | `get_architecture` | Directory structure, entry points, package type |
40
+ | `get_conventions` | DO/DON'T rules detected from your code |
41
+ | `get_workflow_rules` | File coupling and co-change patterns |
42
+ | `get_contribution_guide` | How to add new code in a specific directory |
43
+ | `get_exports` | Public API sorted by usage |
44
+ | `analyze_impact` | What breaks if you change a file |
45
+ | `list_packages` | Monorepo package inventory |
46
+
47
+ ## Why Minimal Mode?
48
+
49
+ Research shows comprehensive context files can actually **hurt** AI performance:
50
+
51
+ - LLM-generated AGENTS.md: **-0.5% to -2%** accuracy ([arxiv 2602.11988](https://arxiv.org/abs/2602.11988))
52
+ - Developer-written focused AGENTS.md: **+4%** accuracy, **-29% runtime** ([arxiv 2601.20404](https://arxiv.org/abs/2601.20404))
53
+
54
+ The difference: developer-written files are short, focused, and only include what the AI can't figure out on its own. That's exactly what `--minimal` generates.
55
+
56
+ **Minimal mode** (~200-450 tokens) includes only:
57
+ - Exact commands with flags (proven to help, never hurts)
58
+ - Workflow rules from git co-change analysis (patterns the AI can't discover from code)
59
+ - High-confidence conventions (only if ≥95% consistent and non-obvious)
60
+ - Non-obvious directories (with "non-exhaustive" qualifier to prevent anchoring)
61
+
62
+ **Full mode** (~1,500-2,500 tokens) adds public API, dependency graphs, all conventions, and architecture details. Use `--full` when you need comprehensive documentation.
63
+
64
+ ## How It Works
65
+
66
+ Unlike tools that dump code into an LLM or pack everything into one file, autodocs-engine uses deterministic static analysis:
67
+
68
+ 1. **Parse** — AST analysis via TypeScript Compiler API
69
+ 2. **Detect** — 8 convention detectors (naming, hooks, testing, frameworks, etc.)
70
+ 3. **Extract** — Commands from package.json, turbo.json, biome.json, and 10+ config formats
71
+ 4. **Graph** — Call graph, import chains, and git co-change analysis (Jaccard similarity)
72
+ 5. **Score** — Inferability scoring decides what's worth including vs. what the AI already knows
73
+ 6. **Generate** — 14/16 sections are deterministic (no LLM). Only architecture summary and domain terms use optional micro-LLM calls.
74
+
75
+ **No API key needed** for minimal mode or JSON output. The analysis is pure computation.
76
+
77
+ ## Output Formats
78
+
79
+ ```bash
80
+ npx autodocs-engine init --minimal # Focused AGENTS.md (~300 tokens)
81
+ npx autodocs-engine init # Full AGENTS.md (needs API key)
82
+ npx autodocs-engine analyze . --format json # Raw analysis JSON
83
+ npx autodocs-engine analyze . --format claude.md # CLAUDE.md format
84
+ npx autodocs-engine analyze . --format cursorrules # .cursorrules format
85
+ ```
86
+
87
+ ## Monorepo Support
88
+
89
+ Auto-detects workspace packages from `pnpm-workspace.yaml`, `workspaces` field in package.json, `turbo.json`, or `nx.json`:
90
+
91
+ ```bash
92
+ npx autodocs-engine init --minimal # Works for monorepos too
93
+ ```
94
+
95
+ For explicit control:
96
+
97
+ ```bash
98
+ npx autodocs-engine analyze packages/app packages/hooks packages/ui \
99
+ --format agents.md --hierarchical --root .
100
+ ```
101
+
102
+ ## Staleness Detection
103
+
104
+ Check if your AGENTS.md needs updating (for CI):
105
+
106
+ ```bash
107
+ npx autodocs-engine check
108
+ ```
109
+
110
+ Returns exit code 1 if conventions have drifted. Useful in CI pipelines to keep context files honest.
111
+
112
+ ## Tested On
113
+
114
+ | Repo | Files | Time | Token Count (minimal) |
115
+ |------|------:|-----:|:-----:|
116
+ | autodocs-engine | 115 | 450ms | ~443 |
117
+ | vitest | 1,200+ | 1.2s | ~307 |
118
+ | nitro | 469 | 220ms | ~121 |
119
+ | sanity | 3,746 | 1.6s | — |
120
+ | medusa | 720 | 316ms | — |
121
+
122
+ 501 tests. Zero type errors. Zero technology hallucinations across all tested repos.
123
+
124
+ ## Library API
125
+
126
+ ```typescript
127
+ import { analyze, generateMinimalAgentsMd } from 'autodocs-engine';
128
+
129
+ // Analyze (pure computation, no API key)
130
+ const analysis = await analyze({ packages: ['./packages/my-pkg'] });
131
+
132
+ // Generate minimal AGENTS.md (no API key)
133
+ const minimal = generateMinimalAgentsMd(analysis);
134
+
135
+ // Or use the full deterministic format (optional API key for 2 LLM sections)
136
+ import { formatDeterministic } from 'autodocs-engine';
137
+ const full = await formatDeterministic(analysis, config);
138
+ ```
139
+
140
+ ## Configuration
141
+
142
+ Optional `autodocs.config.json`:
143
+
144
+ ```json
145
+ {
146
+ "exclude": ["**/vendor/**", "**/generated/**"],
147
+ "conventions": { "disable": ["telemetry-patterns"] }
148
+ }
149
+ ```
150
+
151
+ Most options are auto-detected. Zero config is the default.
152
+
153
+ ## CLI Reference
154
+
155
+ ```
156
+ autodocs-engine init [--minimal] Generate AGENTS.md (zero-config)
157
+ autodocs-engine serve [path] Start MCP server
158
+ autodocs-engine check Check if AGENTS.md needs regeneration
159
+ autodocs-engine analyze [paths...] [options]
160
+
161
+ Options:
162
+ --minimal Focused output (<500 tokens, no API key needed)
163
+ --format, -f json | agents.md | claude.md | cursorrules
164
+ --output, -o Output directory (default: .)
165
+ --root Monorepo root directory
166
+ --hierarchical Root + per-package output
167
+ --merge Preserve human-written sections when regenerating
168
+ --verbose, -v Timing details
169
+ --dry-run Print to stdout (no file writes)
170
+ ```
171
+
172
+ ## Contributing
173
+
174
+ ```bash
175
+ git clone https://github.com/msiric/autodocs-engine.git
176
+ cd autodocs-engine
177
+ npm install
178
+ npm test # 501 tests
179
+ npm run typecheck # Zero errors
180
+ npm run build
181
+ ```
182
+
183
+ ## License
184
+
185
+ [MIT](LICENSE)
@@ -0,0 +1,13 @@
1
+ import type { ParsedFile, SymbolGraph, TierInfo, Convention, CommandSet, PackageArchitecture, PackageAnalysis, PublicAPIEntry, StructuredAnalysis, CrossPackageAnalysis, ResolvedConfig, Warning } from "./types.js";
2
+ /**
3
+ * E-31: Compute publicAPI from barrel exports. Called BEFORE Architecture Detector.
4
+ */
5
+ export declare function buildPublicAPI(symbolGraph: SymbolGraph, parsedFiles: ParsedFile[], maxEntries: number, warnings: Warning[]): PublicAPIEntry[];
6
+ /**
7
+ * Build a complete PackageAnalysis from all module outputs.
8
+ */
9
+ export declare function buildPackageAnalysis(packageDir: string, rootDir: string | undefined, parsedFiles: ParsedFile[], symbolGraph: SymbolGraph, tiers: Map<string, TierInfo>, conventions: Convention[], commands: CommandSet, architecture: PackageArchitecture, publicAPI: PublicAPIEntry[], warnings: Warning[]): PackageAnalysis;
10
+ /**
11
+ * Build the final StructuredAnalysis object.
12
+ */
13
+ export declare function buildStructuredAnalysis(packages: PackageAnalysis[], crossPackage: CrossPackageAnalysis | undefined, config: ResolvedConfig, warnings: Warning[], startTime: number): StructuredAnalysis;
@@ -0,0 +1,268 @@
1
+ // src/analysis-builder.ts — Module 9: Structured Analysis Builder
2
+ // Errata applied: E-31 (publicAPI computed before arch detector),
3
+ // E-32 (importCount per public symbol), E-13 (cap publicAPI)
4
+ import { readFileSync, existsSync } from "node:fs";
5
+ import { resolve, join, basename, dirname, extname, relative } from "node:path";
6
+ import { ENGINE_VERSION } from "./types.js";
7
+ /**
8
+ * E-31: Compute publicAPI from barrel exports. Called BEFORE Architecture Detector.
9
+ */
10
+ export function buildPublicAPI(symbolGraph, parsedFiles, maxEntries, warnings) {
11
+ // Fix B: Build a set of files that import from React (for hook classification)
12
+ const fileMap = new Map();
13
+ for (const pf of parsedFiles) {
14
+ fileMap.set(pf.relativePath, pf);
15
+ }
16
+ const REACT_MODULES = new Set(["react", "react-dom", "preact", "preact/hooks", "preact/compat"]);
17
+ const entries = symbolGraph.barrelExports.map((exp) => {
18
+ let kind = exp.kind;
19
+ // Ensure hook classification — Fix B: only if source file imports React
20
+ if ((kind === "function" || kind === "unknown") &&
21
+ exp.name.startsWith("use") &&
22
+ exp.name.length > 3 &&
23
+ exp.name[3] === exp.name[3].toUpperCase()) {
24
+ const sourceFile = fileMap.get(exp.definedIn);
25
+ const hasReactImport = sourceFile?.imports.some((imp) => REACT_MODULES.has(imp.moduleSpecifier)) ?? false;
26
+ kind = hasReactImport ? "hook" : "function";
27
+ }
28
+ return {
29
+ name: exp.name,
30
+ kind,
31
+ sourceFile: exp.definedIn,
32
+ signature: exp.signature,
33
+ isTypeOnly: exp.isTypeOnly,
34
+ description: exp.jsDocComment,
35
+ importCount: 0, // E-32: will be computed below
36
+ };
37
+ });
38
+ // E-32: Compute importCount per public symbol
39
+ // Pre-build symbol → count map in a single pass (avoids O(entries * files * imports))
40
+ const importCounts = new Map();
41
+ for (const pf of parsedFiles) {
42
+ for (const imp of pf.imports) {
43
+ for (const name of imp.importedNames) {
44
+ importCounts.set(name, (importCounts.get(name) ?? 0) + 1);
45
+ }
46
+ }
47
+ }
48
+ for (const entry of entries) {
49
+ entry.importCount = importCounts.get(entry.name) ?? 0;
50
+ }
51
+ // E-13 + Fix C: Cap publicAPI entries with multi-criteria ranking
52
+ if (entries.length > maxEntries) {
53
+ entries.sort(comparePublicAPIEntries);
54
+ warnings.push({
55
+ level: "info",
56
+ module: "analysis-builder",
57
+ message: `Public API truncated: showing top ${maxEntries} of ${entries.length} exports`,
58
+ });
59
+ return entries.slice(0, maxEntries);
60
+ }
61
+ return entries;
62
+ }
63
+ /**
64
+ * Fix C: Kind priority for export cap ranking.
65
+ * Higher priority kinds sort first.
66
+ */
67
+ const KIND_PRIORITY = {
68
+ hook: 0,
69
+ function: 1,
70
+ component: 2,
71
+ class: 3,
72
+ enum: 4,
73
+ const: 5,
74
+ type: 6,
75
+ interface: 7,
76
+ namespace: 8,
77
+ unknown: 9,
78
+ };
79
+ function comparePublicAPIEntries(a, b) {
80
+ // (a) Kind priority: hooks first, types last
81
+ const kindDiff = (KIND_PRIORITY[a.kind] ?? 9) - (KIND_PRIORITY[b.kind] ?? 9);
82
+ if (kindDiff !== 0)
83
+ return kindDiff;
84
+ // (b) Import count descending within same kind
85
+ const importDiff = (b.importCount ?? 0) - (a.importCount ?? 0);
86
+ if (importDiff !== 0)
87
+ return importDiff;
88
+ // (c) Alphabetical tiebreaker
89
+ return a.name.localeCompare(b.name);
90
+ }
91
+ /**
92
+ * Walk up from analysisDir to find nearest package.json with a name field.
93
+ * Stops at rootDir boundary or filesystem root.
94
+ */
95
+ function resolvePackageMetadata(analysisDir, rootDir) {
96
+ const absDir = resolve(analysisDir);
97
+ // Only walk up if rootDir is provided (monorepo context).
98
+ // Without rootDir, we don't know the boundary and could pick up unrelated package.json.
99
+ const stopAt = rootDir ? resolve(rootDir) : absDir;
100
+ let dir = absDir;
101
+ while (true) {
102
+ const pkgPath = join(dir, "package.json");
103
+ if (existsSync(pkgPath)) {
104
+ try {
105
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
106
+ if (pkg.name) {
107
+ return {
108
+ name: pkg.name,
109
+ version: pkg.version ?? "0.0.0",
110
+ description: pkg.description ?? "",
111
+ };
112
+ }
113
+ }
114
+ catch {
115
+ // Skip unparseable
116
+ }
117
+ }
118
+ // Stop at root dir boundary
119
+ if (dir === stopAt)
120
+ break;
121
+ const parent = dirname(dir);
122
+ if (parent === dir)
123
+ break; // reached filesystem root
124
+ dir = parent;
125
+ }
126
+ // Last resort: use the analysis directory name, but filter out meaningless names
127
+ const dirName = basename(resolve(analysisDir));
128
+ const MEANINGLESS_NAMES = new Set(["src", "lib", "dist", "app", "packages", "core", "main"]);
129
+ if (MEANINGLESS_NAMES.has(dirName)) {
130
+ const parentName = basename(dirname(resolve(analysisDir)));
131
+ return { name: parentName, version: "0.0.0", description: "" };
132
+ }
133
+ return { name: dirName, version: "0.0.0", description: "" };
134
+ }
135
+ /**
136
+ * Build a complete PackageAnalysis from all module outputs.
137
+ */
138
+ export function buildPackageAnalysis(packageDir, rootDir, parsedFiles, symbolGraph, tiers, conventions, commands, architecture, publicAPI, warnings) {
139
+ const absPackageDir = resolve(packageDir);
140
+ const absRootDir = rootDir ? resolve(rootDir) : absPackageDir;
141
+ // Resolve package metadata by walking up to nearest package.json with a name
142
+ const meta = resolvePackageMetadata(packageDir, rootDir);
143
+ let name = meta.name;
144
+ let version = meta.version;
145
+ let description = meta.description;
146
+ // Build FileInventory
147
+ const files = buildFileInventory(parsedFiles, tiers);
148
+ // Build DependencySummary
149
+ const dependencies = buildDependencies(parsedFiles, name);
150
+ // Empty publicAPI warning
151
+ if (publicAPI.length === 0) {
152
+ warnings.push({
153
+ level: "info",
154
+ module: "analysis-builder",
155
+ message: "No public API detected — package may not have a barrel file or may export nothing.",
156
+ });
157
+ }
158
+ return {
159
+ name,
160
+ version,
161
+ description,
162
+ relativePath: relative(absRootDir, absPackageDir) || ".",
163
+ files,
164
+ publicAPI,
165
+ conventions,
166
+ commands,
167
+ architecture,
168
+ dependencies,
169
+ role: { summary: "", purpose: "", whenToUse: "", inferredFrom: [] },
170
+ antiPatterns: [],
171
+ contributionPatterns: [],
172
+ };
173
+ }
174
+ function buildFileInventory(parsedFiles, tiers) {
175
+ const tier1Files = [];
176
+ const tier2Files = [];
177
+ let t1Lines = 0, t2Lines = 0, t3Lines = 0, t3Count = 0;
178
+ const byExtension = {};
179
+ for (const pf of parsedFiles) {
180
+ const tier = tiers.get(pf.relativePath);
181
+ const ext = extname(pf.relativePath);
182
+ byExtension[ext] = (byExtension[ext] ?? 0) + 1;
183
+ if (tier?.tier === 1) {
184
+ tier1Files.push(pf.relativePath);
185
+ t1Lines += pf.lineCount;
186
+ }
187
+ else if (tier?.tier === 2) {
188
+ tier2Files.push(pf.relativePath);
189
+ t2Lines += pf.lineCount;
190
+ }
191
+ else {
192
+ t3Count++;
193
+ t3Lines += pf.lineCount;
194
+ }
195
+ }
196
+ return {
197
+ total: parsedFiles.length,
198
+ byTier: {
199
+ tier1: { count: tier1Files.length, lines: t1Lines, files: tier1Files },
200
+ tier2: { count: tier2Files.length, lines: t2Lines, files: tier2Files },
201
+ tier3: { count: t3Count, lines: t3Lines },
202
+ },
203
+ byExtension,
204
+ };
205
+ }
206
+ function buildDependencies(parsedFiles, packageName) {
207
+ const internal = new Set();
208
+ const externalCounts = new Map();
209
+ // Detect org scope from package name
210
+ const scope = packageName.startsWith("@")
211
+ ? packageName.split("/")[0]
212
+ : null;
213
+ for (const pf of parsedFiles) {
214
+ for (const imp of pf.imports) {
215
+ if (imp.moduleSpecifier.startsWith("."))
216
+ continue; // relative
217
+ if (imp.isDynamic)
218
+ continue;
219
+ if (scope && imp.moduleSpecifier.startsWith(scope + "/")) {
220
+ internal.add(imp.moduleSpecifier);
221
+ }
222
+ else if (imp.moduleSpecifier.startsWith("@")) {
223
+ const pkg = imp.moduleSpecifier.split("/").slice(0, 2).join("/");
224
+ externalCounts.set(pkg, (externalCounts.get(pkg) ?? 0) + 1);
225
+ }
226
+ else {
227
+ const pkg = imp.moduleSpecifier.split("/")[0];
228
+ externalCounts.set(pkg, (externalCounts.get(pkg) ?? 0) + 1);
229
+ }
230
+ }
231
+ }
232
+ const external = [...externalCounts.entries()]
233
+ .map(([name, importCount]) => ({ name, importCount }))
234
+ .sort((a, b) => b.importCount - a.importCount);
235
+ return {
236
+ internal: [...internal].sort(),
237
+ external,
238
+ totalUniqueDependencies: internal.size + externalCounts.size,
239
+ };
240
+ }
241
+ /**
242
+ * Build the final StructuredAnalysis object.
243
+ */
244
+ export function buildStructuredAnalysis(packages, crossPackage, config, warnings, startTime) {
245
+ const publicConfig = {
246
+ ...config,
247
+ llm: {
248
+ provider: config.llm.provider,
249
+ model: config.llm.model,
250
+ baseUrl: config.llm.baseUrl,
251
+ maxOutputTokens: config.llm.maxOutputTokens,
252
+ },
253
+ };
254
+ const meta = {
255
+ engineVersion: ENGINE_VERSION,
256
+ analyzedAt: new Date().toISOString(),
257
+ rootDir: config.rootDir ?? config.packages[0] ?? ".",
258
+ config: publicConfig,
259
+ timingMs: Math.round(performance.now() - startTime),
260
+ };
261
+ return {
262
+ meta,
263
+ packages,
264
+ crossPackage,
265
+ warnings,
266
+ };
267
+ }
268
+ //# sourceMappingURL=analysis-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analysis-builder.js","sourceRoot":"","sources":["../src/analysis-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Convention, AntiPattern } from "./types.js";
2
+ /**
3
+ * Derive anti-patterns from conventions.
4
+ */
5
+ export declare function deriveAntiPatterns(conventions: Convention[]): AntiPattern[];
6
+ /**
7
+ * Derive shared anti-patterns from cross-package shared conventions.
8
+ */
9
+ export declare function deriveSharedAntiPatterns(sharedConventions: Convention[]): AntiPattern[];
@@ -0,0 +1,58 @@
1
+ // src/anti-pattern-detector.ts — Enhancement 3: Anti-Pattern Derivation
2
+ // Derives "DO NOT" rules by inverting strong conventions.
3
+ // W5-A: Removed inversion rules for deleted detectors (named exports, barrel imports,
4
+ // type-only imports, relative imports, displayName). Kept: file naming, testing, hooks.
5
+ const INVERSION_RULES = [
6
+ {
7
+ match: /kebab.?case/i,
8
+ rule: () => "Do NOT use camelCase or PascalCase for filenames",
9
+ reason: (c) => `${c.confidence.description} use kebab-case — the codebase exclusively uses kebab-case filenames`,
10
+ },
11
+ {
12
+ match: /camel.?case/i,
13
+ rule: () => "Do NOT use kebab-case or PascalCase for filenames",
14
+ reason: (c) => `${c.confidence.description} use camelCase — the codebase exclusively uses camelCase filenames`,
15
+ },
16
+ {
17
+ match: /co.?located tests/i,
18
+ rule: () => "Do NOT put tests in a separate __tests__ directory — co-locate tests with source",
19
+ reason: (c) => `${c.confidence.description} co-locate tests next to source files`,
20
+ },
21
+ {
22
+ match: /hooks return objects/i,
23
+ rule: () => "Do NOT return arrays from hooks (use { value, setter } not [value, setter])",
24
+ reason: (c) => `${c.confidence.description} return objects from hooks`,
25
+ },
26
+ ];
27
+ /**
28
+ * Derive anti-patterns from conventions.
29
+ */
30
+ export function deriveAntiPatterns(conventions) {
31
+ const antiPatterns = [];
32
+ for (const conv of conventions) {
33
+ const pct = conv.confidence.percentage;
34
+ if (pct < 80)
35
+ continue; // Only derive from strong conventions
36
+ const confidence = pct >= 95 ? "high" : "medium";
37
+ // Try each inversion rule
38
+ for (const rule of INVERSION_RULES) {
39
+ if (rule.match.test(conv.name)) {
40
+ antiPatterns.push({
41
+ rule: rule.rule(conv),
42
+ reason: rule.reason(conv),
43
+ confidence,
44
+ derivedFrom: conv.name,
45
+ });
46
+ break; // Only one inversion per convention
47
+ }
48
+ }
49
+ }
50
+ return antiPatterns;
51
+ }
52
+ /**
53
+ * Derive shared anti-patterns from cross-package shared conventions.
54
+ */
55
+ export function deriveSharedAntiPatterns(sharedConventions) {
56
+ return deriveAntiPatterns(sharedConventions);
57
+ }
58
+ //# sourceMappingURL=anti-pattern-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anti-pattern-detector.js","sourceRoot":"","sources":["../src/anti-pattern-detector.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,0DAA0D;AAI1D,sFAAsF;AACtF,wFAAwF;AACxF,MAAM,eAAe,GAIf;IACJ;QACE,KAAK,EAAE,cAAc;QACrB,IAAI,EAAE,GAAG,EAAE,CAAC,kDAAkD;QAC9D,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,sEAAsE;KACjH;IACD;QACE,KAAK,EAAE,cAAc;QACrB,IAAI,EAAE,GAAG,EAAE,CAAC,mDAAmD;QAC/D,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,oEAAoE;KAC/G;IACD;QACE,KAAK,EAAE,oBAAoB;QAC3B,IAAI,EAAE,GAAG,EAAE,CAAC,kFAAkF;QAC9F,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,uCAAuC;KAClF;IACD;QACE,KAAK,EAAE,uBAAuB;QAC9B,IAAI,EAAE,GAAG,EAAE,CAAC,6EAA6E;QACzF,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,WAAW,4BAA4B;KACvE;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAyB;IAC1D,MAAM,YAAY,GAAkB,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QACvC,IAAI,GAAG,GAAG,EAAE;YAAE,SAAS,CAAC,sCAAsC;QAE9D,MAAM,UAAU,GAAsB,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;QAEpE,0BAA0B;QAC1B,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,YAAY,CAAC,IAAI,CAAC;oBAChB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;oBACrB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;oBACzB,UAAU;oBACV,WAAW,EAAE,IAAI,CAAC,IAAI;iBACvB,CAAC,CAAC;gBACH,MAAM,CAAC,oCAAoC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,iBAA+B;IACtE,OAAO,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ParsedFile, PublicAPIEntry, PackageArchitecture, Warning } from "./types.js";
2
+ export declare function detectArchitecture(parsedFiles: ParsedFile[], packageDir: string, publicAPI: PublicAPIEntry[], barrelFile: string | undefined, warnings?: Warning[]): PackageArchitecture;
3
+ /**
4
+ * Enhancement 2: Detect file naming pattern from a set of filenames.
5
+ * Finds the longest common prefix and suffix, with the variable part as {...}.
6
+ */
7
+ export declare function detectFilePattern(filenames: string[]): string | undefined;