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
@@ -0,0 +1,276 @@
1
+ // src/command-extractor.ts — Module 6: Command Extractor
2
+ // Errata applied: E-29 (auto-detect monorepo root)
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { resolve, join, dirname, relative } from "node:path";
5
+ const CATEGORY_PATTERNS = {
6
+ build: ["build", "compile", "transpile"],
7
+ test: ["test:unit", "test", "jest", "vitest"],
8
+ lint: ["lint", "eslint"],
9
+ start: ["start", "dev", "serve"],
10
+ };
11
+ const OTHER_PATTERNS = {
12
+ typecheck: ["typecheck", "type-check", "tsc"],
13
+ format: ["format", "prettier"],
14
+ };
15
+ /**
16
+ * Extract build/test/lint/start commands from package.json scripts.
17
+ */
18
+ export function extractCommands(packageDir, rootDir, warnings = []) {
19
+ const absPackageDir = resolve(packageDir);
20
+ // E-29: Auto-detect monorepo root if not provided
21
+ const resolvedRoot = rootDir ? resolve(rootDir) : autoDetectRoot(absPackageDir);
22
+ const pm = detectPackageManager(resolvedRoot ?? absPackageDir);
23
+ const pkgScripts = readScripts(absPackageDir);
24
+ const rootScripts = resolvedRoot && resolvedRoot !== absPackageDir
25
+ ? readScripts(resolvedRoot)
26
+ : {};
27
+ const commands = {
28
+ packageManager: pm,
29
+ other: [],
30
+ };
31
+ // Map primary categories
32
+ for (const [category, patterns] of Object.entries(CATEGORY_PATTERNS)) {
33
+ const cmd = resolveCommand(category, patterns, pkgScripts, rootScripts, pm, absPackageDir);
34
+ if (cmd) {
35
+ if (category === "build")
36
+ commands.build = cmd;
37
+ else if (category === "test")
38
+ commands.test = cmd;
39
+ else if (category === "lint")
40
+ commands.lint = cmd;
41
+ else if (category === "start")
42
+ commands.start = cmd;
43
+ }
44
+ }
45
+ // Map "other" categories
46
+ for (const [category, patterns] of Object.entries(OTHER_PATTERNS)) {
47
+ const cmd = resolveCommand(category, patterns, pkgScripts, rootScripts, pm, absPackageDir);
48
+ if (cmd) {
49
+ commands.other.push(cmd);
50
+ }
51
+ }
52
+ return commands;
53
+ }
54
+ function resolveCommand(category, patterns, pkgScripts, rootScripts, pm, packageDir) {
55
+ const pkgMatch = findScript(pkgScripts, patterns);
56
+ const rootMatch = findScript(rootScripts, patterns);
57
+ if (rootMatch && pkgMatch && pkgScripts[pkgMatch]?.includes("../")) {
58
+ // Package delegates to root → root is primary
59
+ const cmd = {
60
+ run: formatRun(pm, rootMatch),
61
+ source: `root package.json scripts.${rootMatch}`,
62
+ };
63
+ cmd.variants = [{ name: "package-level", run: formatRun(pm, pkgMatch) }];
64
+ addVariants(cmd, rootMatch, rootScripts, pm);
65
+ return cmd;
66
+ }
67
+ else if (pkgMatch) {
68
+ const cmd = {
69
+ run: formatRun(pm, pkgMatch),
70
+ source: `package.json scripts.${pkgMatch}`,
71
+ };
72
+ addVariants(cmd, pkgMatch, pkgScripts, pm);
73
+ return cmd;
74
+ }
75
+ else if (rootMatch) {
76
+ const cmd = {
77
+ run: formatRun(pm, rootMatch),
78
+ source: `root package.json scripts.${rootMatch}`,
79
+ };
80
+ addVariants(cmd, rootMatch, rootScripts, pm);
81
+ return cmd;
82
+ }
83
+ return undefined;
84
+ }
85
+ function detectPackageManager(dir) {
86
+ if (existsSync(join(dir, "bun.lockb")))
87
+ return "bun";
88
+ if (existsSync(join(dir, "pnpm-lock.yaml")))
89
+ return "pnpm";
90
+ if (existsSync(join(dir, "yarn.lock")))
91
+ return "yarn";
92
+ if (existsSync(join(dir, "package-lock.json")))
93
+ return "npm";
94
+ // Check packageManager field
95
+ try {
96
+ const pkgJson = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
97
+ if (typeof pkgJson.packageManager === "string") {
98
+ if (pkgJson.packageManager.startsWith("yarn"))
99
+ return "yarn";
100
+ if (pkgJson.packageManager.startsWith("pnpm"))
101
+ return "pnpm";
102
+ if (pkgJson.packageManager.startsWith("bun"))
103
+ return "bun";
104
+ }
105
+ }
106
+ catch {
107
+ // No package.json
108
+ }
109
+ return "npm";
110
+ }
111
+ function readScripts(dir) {
112
+ try {
113
+ const pkgJson = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8"));
114
+ return pkgJson.scripts ?? {};
115
+ }
116
+ catch {
117
+ return {};
118
+ }
119
+ }
120
+ function findScript(scripts, patterns) {
121
+ for (const pattern of patterns) {
122
+ if (pattern in scripts)
123
+ return pattern;
124
+ }
125
+ return undefined;
126
+ }
127
+ function formatRun(pm, script) {
128
+ switch (pm) {
129
+ case "yarn":
130
+ return `yarn ${script}`;
131
+ case "pnpm":
132
+ return `pnpm ${script}`;
133
+ case "bun":
134
+ return `bun run ${script}`;
135
+ case "npm":
136
+ default:
137
+ return `npm run ${script}`;
138
+ }
139
+ }
140
+ function addVariants(cmd, primary, scripts, pm) {
141
+ const prefix = primary + ":";
142
+ const variants = cmd.variants ?? [];
143
+ for (const key of Object.keys(scripts)) {
144
+ if (key.startsWith(prefix) && key !== primary) {
145
+ const suffix = key.slice(prefix.length);
146
+ variants.push({ name: suffix, run: formatRun(pm, key) });
147
+ }
148
+ }
149
+ if (variants.length > 0)
150
+ cmd.variants = variants;
151
+ }
152
+ /**
153
+ * E-29: Walk up from packageDir looking for monorepo root.
154
+ */
155
+ function autoDetectRoot(packageDir) {
156
+ let dir = dirname(packageDir);
157
+ const root = resolve("/");
158
+ while (dir !== root) {
159
+ try {
160
+ const pkgJsonPath = join(dir, "package.json");
161
+ if (existsSync(pkgJsonPath)) {
162
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
163
+ if (pkgJson.workspaces)
164
+ return dir;
165
+ }
166
+ if (existsSync(join(dir, "pnpm-workspace.yaml")))
167
+ return dir;
168
+ }
169
+ catch {
170
+ // Skip
171
+ }
172
+ dir = dirname(dir);
173
+ }
174
+ return undefined;
175
+ }
176
+ // ─── W3-1: Workspace-wide command scanning ──────────────────────────────────
177
+ const OPERATIONAL_PATTERNS = [
178
+ // Database
179
+ /^db[:\-]/, /^migrate/, /^seed/,
180
+ // Workers/queues
181
+ /^dev[:\-](worker|listener|queue)/, /^sync[:\-]/, /^worker/,
182
+ // Deployment
183
+ /^deploy/, /^release/,
184
+ // Code generation
185
+ /^generate/, /^codegen/,
186
+ // Email
187
+ /^email/,
188
+ ];
189
+ /**
190
+ * W3-1: Scan ALL package.json files in the workspace for operational commands.
191
+ * Finds commands matching operational patterns (db:*, sync:*, worker*, deploy*, generate*).
192
+ */
193
+ export function scanWorkspaceCommands(rootDir, warnings = [], analyzedPackageNames) {
194
+ const absRoot = resolve(rootDir);
195
+ const pm = detectPackageManager(absRoot);
196
+ const commands = [];
197
+ const seen = new Set();
198
+ const packageJsonPaths = findAllPackageJsons(absRoot);
199
+ for (const pkgJsonPath of packageJsonPaths) {
200
+ try {
201
+ const content = readFileSync(pkgJsonPath, "utf-8");
202
+ const pkgJson = JSON.parse(content);
203
+ const scripts = pkgJson.scripts ?? {};
204
+ const pkgName = pkgJson.name ?? relative(absRoot, dirname(pkgJsonPath));
205
+ const pkgRelPath = relative(absRoot, dirname(pkgJsonPath)) || ".";
206
+ for (const [scriptName, scriptValue] of Object.entries(scripts)) {
207
+ if (typeof scriptValue !== "string")
208
+ continue;
209
+ if (!OPERATIONAL_PATTERNS.some((p) => p.test(scriptName)))
210
+ continue;
211
+ // Deduplicate by script name + command value
212
+ const dedupeKey = `${scriptName}:${scriptValue}`;
213
+ if (seen.has(dedupeKey))
214
+ continue;
215
+ seen.add(dedupeKey);
216
+ const category = categorizeScript(scriptName);
217
+ commands.push({
218
+ run: formatRun(pm, scriptName),
219
+ scriptName,
220
+ packageName: pkgName,
221
+ packagePath: pkgRelPath,
222
+ category,
223
+ });
224
+ }
225
+ }
226
+ catch {
227
+ // Skip malformed package.json
228
+ }
229
+ }
230
+ return commands;
231
+ }
232
+ function categorizeScript(name) {
233
+ if (/^db[:\-]|^migrate|^seed/.test(name))
234
+ return "database";
235
+ if (/^dev[:\-](worker|listener|queue)|^sync[:\-]|^worker/.test(name))
236
+ return "workers";
237
+ if (/^deploy|^release/.test(name))
238
+ return "deployment";
239
+ if (/^generate|^codegen/.test(name))
240
+ return "codegen";
241
+ if (/^email/.test(name))
242
+ return "email";
243
+ return "operational";
244
+ }
245
+ /**
246
+ * Find all package.json files in a workspace, excluding node_modules and dist.
247
+ */
248
+ function findAllPackageJsons(rootDir) {
249
+ const results = [];
250
+ function walk(dir, depth) {
251
+ if (depth > 6)
252
+ return; // Prevent deep recursion
253
+ try {
254
+ const entries = readdirSync(dir, { withFileTypes: true });
255
+ for (const entry of entries) {
256
+ if (entry.name === "node_modules" || entry.name === "dist" ||
257
+ entry.name === ".git" || entry.name === "build" ||
258
+ entry.name === "out" || entry.name === "coverage")
259
+ continue;
260
+ const fullPath = join(dir, entry.name);
261
+ if (entry.isFile() && entry.name === "package.json") {
262
+ results.push(fullPath);
263
+ }
264
+ else if (entry.isDirectory()) {
265
+ walk(fullPath, depth + 1);
266
+ }
267
+ }
268
+ }
269
+ catch {
270
+ // Skip unreadable dirs
271
+ }
272
+ }
273
+ walk(rootDir, 0);
274
+ return results;
275
+ }
276
+ //# sourceMappingURL=command-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-extractor.js","sourceRoot":"","sources":["../src/command-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { ConfigAnalysis, Warning } from "./types.js";
2
+ /**
3
+ * Analyze config files in a package directory (and optionally its monorepo root).
4
+ */
5
+ export declare function analyzeConfig(packageDir: string, rootDir?: string, warnings?: Warning[]): ConfigAnalysis;
@@ -0,0 +1,364 @@
1
+ // src/config-analyzer.ts — Improvement 1: Config File Analysis
2
+ // Parses turbo.json, biome.json, tsconfig.json, eslint config, prettier config,
3
+ // justfile, Makefile, nx.json, .env.example to extract actionable settings.
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ /**
7
+ * Analyze config files in a package directory (and optionally its monorepo root).
8
+ */
9
+ export function analyzeConfig(packageDir, rootDir, warnings = []) {
10
+ const result = {};
11
+ // TypeScript config (package-level first, then root)
12
+ result.typescript = parseTypeScriptConfig(packageDir, rootDir, warnings);
13
+ // Build tool (root-level: turbo.json, nx.json)
14
+ result.buildTool = detectBuildTool(packageDir, rootDir, warnings);
15
+ // Linter
16
+ result.linter = detectLinter(packageDir, rootDir, warnings);
17
+ // Formatter
18
+ result.formatter = detectFormatter(packageDir, rootDir, warnings);
19
+ // Task runner (justfile, Makefile)
20
+ result.taskRunner = detectTaskRunner(packageDir, rootDir, warnings);
21
+ // Environment variables
22
+ result.envVars = detectEnvVars(packageDir, rootDir);
23
+ return result;
24
+ }
25
+ // ─── TypeScript Config ──────────────────────────────────────────────────────
26
+ function parseTypeScriptConfig(packageDir, rootDir, warnings = []) {
27
+ // Try package-level first, then root
28
+ const candidates = [
29
+ join(packageDir, "tsconfig.json"),
30
+ ...(rootDir ? [join(rootDir, "tsconfig.json")] : []),
31
+ ];
32
+ for (const configPath of candidates) {
33
+ if (!existsSync(configPath))
34
+ continue;
35
+ try {
36
+ const raw = readFileSync(configPath, "utf-8");
37
+ // Strip single-line and multi-line comments for JSONC support
38
+ const cleaned = stripJsonComments(raw);
39
+ const config = JSON.parse(cleaned);
40
+ const co = config.compilerOptions ?? {};
41
+ return {
42
+ strict: co.strict ?? false,
43
+ target: co.target ?? "unknown",
44
+ module: co.module ?? "unknown",
45
+ moduleResolution: co.moduleResolution ?? "unknown",
46
+ paths: co.paths ?? undefined,
47
+ jsx: co.jsx ?? undefined,
48
+ };
49
+ }
50
+ catch {
51
+ warnings.push({
52
+ level: "warn",
53
+ module: "config-analyzer",
54
+ message: `Failed to parse ${configPath}`,
55
+ });
56
+ }
57
+ }
58
+ return undefined;
59
+ }
60
+ // ─── Build Tool ─────────────────────────────────────────────────────────────
61
+ function detectBuildTool(packageDir, rootDir, warnings = []) {
62
+ // Check turbo.json (root or package)
63
+ const turboLocations = [
64
+ ...(rootDir ? [join(rootDir, "turbo.json")] : []),
65
+ join(packageDir, "turbo.json"),
66
+ ];
67
+ for (const turboPath of turboLocations) {
68
+ if (!existsSync(turboPath))
69
+ continue;
70
+ try {
71
+ const raw = readFileSync(turboPath, "utf-8");
72
+ const cleaned = stripJsonComments(raw);
73
+ const config = JSON.parse(cleaned);
74
+ // Turbo v2: tasks is top-level object with task names as keys
75
+ // Turbo v1: pipeline is top-level object with task names as keys
76
+ const tasksObj = config.tasks ?? config.pipeline ?? {};
77
+ const taskNames = Object.keys(tasksObj).map((t) => t.replace(/^\/\/.*/, "").trim()).filter(Boolean);
78
+ return {
79
+ name: "turbo",
80
+ taskNames,
81
+ configFile: turboPath.startsWith(rootDir ?? "") ? "turbo.json" : turboPath,
82
+ };
83
+ }
84
+ catch {
85
+ warnings.push({
86
+ level: "warn",
87
+ module: "config-analyzer",
88
+ message: `Failed to parse turbo.json at ${turboPath}`,
89
+ });
90
+ }
91
+ }
92
+ // Check nx.json
93
+ const nxLocations = [
94
+ ...(rootDir ? [join(rootDir, "nx.json")] : []),
95
+ join(packageDir, "nx.json"),
96
+ ];
97
+ for (const nxPath of nxLocations) {
98
+ if (!existsSync(nxPath))
99
+ continue;
100
+ try {
101
+ const raw = readFileSync(nxPath, "utf-8");
102
+ const config = JSON.parse(raw);
103
+ const taskNames = [];
104
+ // Nx: targetDefaults has task names as keys
105
+ if (config.targetDefaults) {
106
+ taskNames.push(...Object.keys(config.targetDefaults));
107
+ }
108
+ // Nx: tasksRunnerOptions may define tasks
109
+ if (config.tasksRunnerOptions) {
110
+ // The runner itself doesn't list tasks, but its presence confirms Nx
111
+ }
112
+ return {
113
+ name: "nx",
114
+ taskNames,
115
+ configFile: "nx.json",
116
+ };
117
+ }
118
+ catch {
119
+ warnings.push({
120
+ level: "warn",
121
+ module: "config-analyzer",
122
+ message: `Failed to parse nx.json at ${nxPath}`,
123
+ });
124
+ }
125
+ }
126
+ // Check for lerna.json
127
+ const lernaLocations = [
128
+ ...(rootDir ? [join(rootDir, "lerna.json")] : []),
129
+ join(packageDir, "lerna.json"),
130
+ ];
131
+ for (const lernaPath of lernaLocations) {
132
+ if (existsSync(lernaPath)) {
133
+ return {
134
+ name: "lerna",
135
+ taskNames: [],
136
+ configFile: "lerna.json",
137
+ };
138
+ }
139
+ }
140
+ return undefined;
141
+ }
142
+ // ─── Linter ─────────────────────────────────────────────────────────────────
143
+ function detectLinterIn(dir) {
144
+ // Biome
145
+ for (const name of ["biome.json", "biome.jsonc"]) {
146
+ if (existsSync(join(dir, name))) {
147
+ return { name: "biome", configFile: name };
148
+ }
149
+ }
150
+ // ESLint
151
+ const eslintFiles = [
152
+ "eslint.config.js", "eslint.config.mjs", "eslint.config.cjs", "eslint.config.ts",
153
+ ".eslintrc.json", ".eslintrc.js", ".eslintrc.cjs", ".eslintrc.yaml", ".eslintrc.yml", ".eslintrc",
154
+ ];
155
+ for (const name of eslintFiles) {
156
+ if (existsSync(join(dir, name))) {
157
+ return { name: "eslint", configFile: name };
158
+ }
159
+ }
160
+ return undefined;
161
+ }
162
+ function detectLinter(packageDir, rootDir, _warnings = []) {
163
+ // Check package dir FIRST — package-level config takes priority
164
+ const pkgResult = detectLinterIn(packageDir);
165
+ if (pkgResult)
166
+ return pkgResult;
167
+ // Fall back to root
168
+ if (rootDir) {
169
+ return detectLinterIn(rootDir);
170
+ }
171
+ return undefined;
172
+ }
173
+ // ─── Formatter ──────────────────────────────────────────────────────────────
174
+ function detectFormatterIn(dir) {
175
+ // Biome
176
+ for (const name of ["biome.json", "biome.jsonc"]) {
177
+ if (existsSync(join(dir, name))) {
178
+ try {
179
+ const raw = readFileSync(join(dir, name), "utf-8");
180
+ const cleaned = stripJsonComments(raw);
181
+ const config = JSON.parse(cleaned);
182
+ if (config.formatter?.enabled !== false) {
183
+ return { name: "biome", configFile: name };
184
+ }
185
+ }
186
+ catch {
187
+ return { name: "biome", configFile: name };
188
+ }
189
+ }
190
+ }
191
+ // Prettier
192
+ const prettierFiles = [
193
+ ".prettierrc", ".prettierrc.json", ".prettierrc.js", ".prettierrc.cjs", ".prettierrc.mjs",
194
+ ".prettierrc.yaml", ".prettierrc.yml", ".prettierrc.toml",
195
+ "prettier.config.js", "prettier.config.mjs", "prettier.config.cjs",
196
+ ];
197
+ for (const name of prettierFiles) {
198
+ if (existsSync(join(dir, name))) {
199
+ return { name: "prettier", configFile: name };
200
+ }
201
+ }
202
+ return undefined;
203
+ }
204
+ function detectFormatter(packageDir, rootDir, _warnings = []) {
205
+ // Check package dir FIRST — package-level config takes priority
206
+ const pkgResult = detectFormatterIn(packageDir);
207
+ if (pkgResult)
208
+ return pkgResult;
209
+ // Fall back to root
210
+ if (rootDir) {
211
+ return detectFormatterIn(rootDir);
212
+ }
213
+ return undefined;
214
+ }
215
+ // ─── Task Runner ────────────────────────────────────────────────────────────
216
+ function detectTaskRunner(packageDir, rootDir, _warnings = []) {
217
+ const dirs = rootDir ? [packageDir, rootDir] : [packageDir];
218
+ for (const dir of dirs) {
219
+ // Justfile
220
+ for (const name of ["justfile", "Justfile", ".justfile"]) {
221
+ const path = join(dir, name);
222
+ if (!existsSync(path))
223
+ continue;
224
+ try {
225
+ const content = readFileSync(path, "utf-8");
226
+ const targets = parseJustfileTargets(content);
227
+ return { name: "just", targets, configFile: name };
228
+ }
229
+ catch {
230
+ return { name: "just", targets: [], configFile: name };
231
+ }
232
+ }
233
+ }
234
+ for (const dir of dirs) {
235
+ // Makefile
236
+ for (const name of ["Makefile", "makefile", "GNUmakefile"]) {
237
+ const path = join(dir, name);
238
+ if (!existsSync(path))
239
+ continue;
240
+ try {
241
+ const content = readFileSync(path, "utf-8");
242
+ const targets = parseMakefileTargets(content);
243
+ return { name: "make", targets, configFile: name };
244
+ }
245
+ catch {
246
+ return { name: "make", targets: [], configFile: name };
247
+ }
248
+ }
249
+ }
250
+ return undefined;
251
+ }
252
+ /**
253
+ * Parse justfile target names. Targets are lines like "target-name:" at the start of a line.
254
+ */
255
+ function parseJustfileTargets(content) {
256
+ const targets = [];
257
+ for (const line of content.split("\n")) {
258
+ // Justfile recipe: name starts at column 0, followed by optional params and ":"
259
+ const match = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*(?:\(.*?\))?\s*:/);
260
+ if (match && !line.startsWith("#") && !line.startsWith(" ") && !line.startsWith("\t")) {
261
+ targets.push(match[1]);
262
+ }
263
+ }
264
+ return targets;
265
+ }
266
+ /**
267
+ * Parse Makefile target names. Targets are lines like "target:" at the start of a line.
268
+ */
269
+ function parseMakefileTargets(content) {
270
+ const targets = [];
271
+ for (const line of content.split("\n")) {
272
+ // Makefile target: starts at column 0, name followed by ":"
273
+ const match = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*)\s*:/);
274
+ if (match && !line.startsWith("\t") && !line.startsWith("#") && !match[1].startsWith(".")) {
275
+ targets.push(match[1]);
276
+ }
277
+ }
278
+ return targets;
279
+ }
280
+ // ─── Environment Variables ──────────────────────────────────────────────────
281
+ function detectEnvVars(packageDir, rootDir) {
282
+ const dirs = rootDir ? [packageDir, rootDir] : [packageDir];
283
+ const envFiles = [".env.example", ".env.sample", ".env.template", ".env.local.example"];
284
+ for (const dir of dirs) {
285
+ for (const name of envFiles) {
286
+ const path = join(dir, name);
287
+ if (!existsSync(path))
288
+ continue;
289
+ try {
290
+ const content = readFileSync(path, "utf-8");
291
+ const vars = [];
292
+ for (const line of content.split("\n")) {
293
+ const trimmed = line.trim();
294
+ if (!trimmed || trimmed.startsWith("#"))
295
+ continue;
296
+ const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)\s*=/);
297
+ if (match)
298
+ vars.push(match[1]);
299
+ }
300
+ if (vars.length > 0)
301
+ return vars;
302
+ }
303
+ catch {
304
+ // skip
305
+ }
306
+ }
307
+ }
308
+ return undefined;
309
+ }
310
+ // ─── Helpers ────────────────────────────────────────────────────────────────
311
+ /**
312
+ * Strip single-line (//) and multi-line comments from JSON (JSONC support).
313
+ */
314
+ function stripJsonComments(json) {
315
+ let result = "";
316
+ let inString = false;
317
+ let inSingleComment = false;
318
+ let inMultiComment = false;
319
+ for (let i = 0; i < json.length; i++) {
320
+ const ch = json[i];
321
+ const next = json[i + 1];
322
+ if (inSingleComment) {
323
+ if (ch === "\n") {
324
+ inSingleComment = false;
325
+ result += ch;
326
+ }
327
+ continue;
328
+ }
329
+ if (inMultiComment) {
330
+ if (ch === "*" && next === "/") {
331
+ inMultiComment = false;
332
+ i++;
333
+ }
334
+ continue;
335
+ }
336
+ if (inString) {
337
+ result += ch;
338
+ if (ch === "\\" && i + 1 < json.length) {
339
+ result += json[++i];
340
+ }
341
+ else if (ch === '"') {
342
+ inString = false;
343
+ }
344
+ continue;
345
+ }
346
+ if (ch === '"') {
347
+ inString = true;
348
+ result += ch;
349
+ }
350
+ else if (ch === "/" && next === "/") {
351
+ inSingleComment = true;
352
+ i++;
353
+ }
354
+ else if (ch === "/" && next === "*") {
355
+ inMultiComment = true;
356
+ i++;
357
+ }
358
+ else {
359
+ result += ch;
360
+ }
361
+ }
362
+ return result;
363
+ }
364
+ //# sourceMappingURL=config-analyzer.js.map