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.
- package/LICENSE +21 -0
- package/README.md +185 -0
- package/dist/analysis-builder.d.ts +13 -0
- package/dist/analysis-builder.js +268 -0
- package/dist/analysis-builder.js.map +1 -0
- package/dist/anti-pattern-detector.d.ts +9 -0
- package/dist/anti-pattern-detector.js +58 -0
- package/dist/anti-pattern-detector.js.map +1 -0
- package/dist/architecture-detector.d.ts +7 -0
- package/dist/architecture-detector.js +212 -0
- package/dist/architecture-detector.js.map +1 -0
- package/dist/ast-parser.d.ts +5 -0
- package/dist/ast-parser.js +635 -0
- package/dist/ast-parser.js.map +1 -0
- package/dist/benchmark/code-generator.d.ts +20 -0
- package/dist/benchmark/code-generator.js +206 -0
- package/dist/benchmark/code-generator.js.map +1 -0
- package/dist/benchmark/pr-miner.d.ts +61 -0
- package/dist/benchmark/pr-miner.js +304 -0
- package/dist/benchmark/pr-miner.js.map +1 -0
- package/dist/benchmark/pr-runner.d.ts +58 -0
- package/dist/benchmark/pr-runner.js +346 -0
- package/dist/benchmark/pr-runner.js.map +1 -0
- package/dist/benchmark/pr-scorer.d.ts +48 -0
- package/dist/benchmark/pr-scorer.js +222 -0
- package/dist/benchmark/pr-scorer.js.map +1 -0
- package/dist/benchmark/pr-task-gen.d.ts +16 -0
- package/dist/benchmark/pr-task-gen.js +129 -0
- package/dist/benchmark/pr-task-gen.js.map +1 -0
- package/dist/benchmark/report.d.ts +9 -0
- package/dist/benchmark/report.js +131 -0
- package/dist/benchmark/report.js.map +1 -0
- package/dist/benchmark/runner.d.ts +6 -0
- package/dist/benchmark/runner.js +183 -0
- package/dist/benchmark/runner.js.map +1 -0
- package/dist/benchmark/scorer.d.ts +6 -0
- package/dist/benchmark/scorer.js +549 -0
- package/dist/benchmark/scorer.js.map +1 -0
- package/dist/benchmark/shuffler.d.ts +5 -0
- package/dist/benchmark/shuffler.js +70 -0
- package/dist/benchmark/shuffler.js.map +1 -0
- package/dist/benchmark/statistics.d.ts +36 -0
- package/dist/benchmark/statistics.js +159 -0
- package/dist/benchmark/statistics.js.map +1 -0
- package/dist/benchmark/task-generator.d.ts +20 -0
- package/dist/benchmark/task-generator.js +388 -0
- package/dist/benchmark/task-generator.js.map +1 -0
- package/dist/benchmark/types.d.ts +111 -0
- package/dist/benchmark/types.js +3 -0
- package/dist/benchmark/types.js.map +1 -0
- package/dist/bin/autodocs-engine.d.ts +2 -0
- package/dist/bin/autodocs-engine.js +296 -0
- package/dist/bin/autodocs-engine.js.map +1 -0
- package/dist/bin/benchmark.d.ts +14 -0
- package/dist/bin/benchmark.js +172 -0
- package/dist/bin/benchmark.js.map +1 -0
- package/dist/bin/check.d.ts +13 -0
- package/dist/bin/check.js +79 -0
- package/dist/bin/check.js.map +1 -0
- package/dist/bin/init.d.ts +11 -0
- package/dist/bin/init.js +268 -0
- package/dist/bin/init.js.map +1 -0
- package/dist/bin/serve.d.ts +4 -0
- package/dist/bin/serve.js +29 -0
- package/dist/bin/serve.js.map +1 -0
- package/dist/budget-validator.d.ts +22 -0
- package/dist/budget-validator.js +119 -0
- package/dist/budget-validator.js.map +1 -0
- package/dist/command-extractor.d.ts +10 -0
- package/dist/command-extractor.js +276 -0
- package/dist/command-extractor.js.map +1 -0
- package/dist/config-analyzer.d.ts +5 -0
- package/dist/config-analyzer.js +364 -0
- package/dist/config-analyzer.js.map +1 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.js +172 -0
- package/dist/config.js.map +1 -0
- package/dist/contribution-patterns.d.ts +6 -0
- package/dist/contribution-patterns.js +263 -0
- package/dist/contribution-patterns.js.map +1 -0
- package/dist/convention-extractor.d.ts +17 -0
- package/dist/convention-extractor.js +90 -0
- package/dist/convention-extractor.js.map +1 -0
- package/dist/cross-package.d.ts +5 -0
- package/dist/cross-package.js +71 -0
- package/dist/cross-package.js.map +1 -0
- package/dist/dependency-analyzer.d.ts +5 -0
- package/dist/dependency-analyzer.js +233 -0
- package/dist/dependency-analyzer.js.map +1 -0
- package/dist/detectors/build-tool.d.ts +2 -0
- package/dist/detectors/build-tool.js +67 -0
- package/dist/detectors/build-tool.js.map +1 -0
- package/dist/detectors/component-patterns.d.ts +2 -0
- package/dist/detectors/component-patterns.js +49 -0
- package/dist/detectors/component-patterns.js.map +1 -0
- package/dist/detectors/data-fetching.d.ts +2 -0
- package/dist/detectors/data-fetching.js +127 -0
- package/dist/detectors/data-fetching.js.map +1 -0
- package/dist/detectors/database.d.ts +2 -0
- package/dist/detectors/database.js +54 -0
- package/dist/detectors/database.js.map +1 -0
- package/dist/detectors/error-handling.d.ts +2 -0
- package/dist/detectors/error-handling.js +47 -0
- package/dist/detectors/error-handling.js.map +1 -0
- package/dist/detectors/export-patterns.d.ts +2 -0
- package/dist/detectors/export-patterns.js +64 -0
- package/dist/detectors/export-patterns.js.map +1 -0
- package/dist/detectors/file-naming.d.ts +2 -0
- package/dist/detectors/file-naming.js +74 -0
- package/dist/detectors/file-naming.js.map +1 -0
- package/dist/detectors/graphql-patterns.d.ts +2 -0
- package/dist/detectors/graphql-patterns.js +47 -0
- package/dist/detectors/graphql-patterns.js.map +1 -0
- package/dist/detectors/hook-patterns.d.ts +2 -0
- package/dist/detectors/hook-patterns.js +105 -0
- package/dist/detectors/hook-patterns.js.map +1 -0
- package/dist/detectors/import-patterns.d.ts +2 -0
- package/dist/detectors/import-patterns.js +88 -0
- package/dist/detectors/import-patterns.js.map +1 -0
- package/dist/detectors/telemetry-patterns.d.ts +2 -0
- package/dist/detectors/telemetry-patterns.js +42 -0
- package/dist/detectors/telemetry-patterns.js.map +1 -0
- package/dist/detectors/test-framework-ecosystem.d.ts +2 -0
- package/dist/detectors/test-framework-ecosystem.js +95 -0
- package/dist/detectors/test-framework-ecosystem.js.map +1 -0
- package/dist/detectors/test-patterns.d.ts +2 -0
- package/dist/detectors/test-patterns.js +60 -0
- package/dist/detectors/test-patterns.js.map +1 -0
- package/dist/detectors/web-framework.d.ts +2 -0
- package/dist/detectors/web-framework.js +51 -0
- package/dist/detectors/web-framework.js.map +1 -0
- package/dist/deterministic-formatter.d.ts +54 -0
- package/dist/deterministic-formatter.js +922 -0
- package/dist/deterministic-formatter.js.map +1 -0
- package/dist/diff-analyzer.d.ts +7 -0
- package/dist/diff-analyzer.js +126 -0
- package/dist/diff-analyzer.js.map +1 -0
- package/dist/example-extractor.d.ts +6 -0
- package/dist/example-extractor.js +115 -0
- package/dist/example-extractor.js.map +1 -0
- package/dist/existing-docs.d.ts +36 -0
- package/dist/existing-docs.js +257 -0
- package/dist/existing-docs.js.map +1 -0
- package/dist/file-discovery.d.ts +6 -0
- package/dist/file-discovery.js +154 -0
- package/dist/file-discovery.js.map +1 -0
- package/dist/git-history.d.ts +41 -0
- package/dist/git-history.js +401 -0
- package/dist/git-history.js.map +1 -0
- package/dist/impact-classifier.d.ts +22 -0
- package/dist/impact-classifier.js +87 -0
- package/dist/impact-classifier.js.map +1 -0
- package/dist/impact-radius.d.ts +23 -0
- package/dist/impact-radius.js +130 -0
- package/dist/impact-radius.js.map +1 -0
- package/dist/import-chain.d.ts +12 -0
- package/dist/import-chain.js +93 -0
- package/dist/import-chain.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/inferability.d.ts +16 -0
- package/dist/inferability.js +142 -0
- package/dist/inferability.js.map +1 -0
- package/dist/llm/adapter.d.ts +33 -0
- package/dist/llm/adapter.js +202 -0
- package/dist/llm/adapter.js.map +1 -0
- package/dist/llm/client.d.ts +5 -0
- package/dist/llm/client.js +68 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/hierarchical.d.ts +23 -0
- package/dist/llm/hierarchical.js +126 -0
- package/dist/llm/hierarchical.js.map +1 -0
- package/dist/llm/serializer.d.ts +19 -0
- package/dist/llm/serializer.js +363 -0
- package/dist/llm/serializer.js.map +1 -0
- package/dist/llm/template-selector.d.ts +7 -0
- package/dist/llm/template-selector.js +21 -0
- package/dist/llm/template-selector.js.map +1 -0
- package/dist/llm-adapter.d.ts +2 -0
- package/dist/llm-adapter.js +5 -0
- package/dist/llm-adapter.js.map +1 -0
- package/dist/mcp/cache.d.ts +30 -0
- package/dist/mcp/cache.js +112 -0
- package/dist/mcp/cache.js.map +1 -0
- package/dist/mcp/errors.d.ts +21 -0
- package/dist/mcp/errors.js +27 -0
- package/dist/mcp/errors.js.map +1 -0
- package/dist/mcp/queries.d.ts +27 -0
- package/dist/mcp/queries.js +121 -0
- package/dist/mcp/queries.js.map +1 -0
- package/dist/mcp/server.d.ts +14 -0
- package/dist/mcp/server.js +131 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +39 -0
- package/dist/mcp/tools.js +249 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mermaid-generator.d.ts +6 -0
- package/dist/mermaid-generator.js +59 -0
- package/dist/mermaid-generator.js.map +1 -0
- package/dist/meta-tool-detector.d.ts +23 -0
- package/dist/meta-tool-detector.js +177 -0
- package/dist/meta-tool-detector.js.map +1 -0
- package/dist/output-validator.d.ts +6 -0
- package/dist/output-validator.js +471 -0
- package/dist/output-validator.js.map +1 -0
- package/dist/pattern-fingerprinter.d.ts +7 -0
- package/dist/pattern-fingerprinter.js +241 -0
- package/dist/pattern-fingerprinter.js.map +1 -0
- package/dist/pipeline.d.ts +5 -0
- package/dist/pipeline.js +374 -0
- package/dist/pipeline.js.map +1 -0
- package/dist/plugin-loader.d.ts +19 -0
- package/dist/plugin-loader.js +124 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/role-inferrer.d.ts +5 -0
- package/dist/role-inferrer.js +159 -0
- package/dist/role-inferrer.js.map +1 -0
- package/dist/symbol-graph.d.ts +11 -0
- package/dist/symbol-graph.js +613 -0
- package/dist/symbol-graph.js.map +1 -0
- package/dist/templates/agents-md.d.ts +20 -0
- package/dist/templates/agents-md.js +346 -0
- package/dist/templates/agents-md.js.map +1 -0
- package/dist/templates/claude-md.d.ts +4 -0
- package/dist/templates/claude-md.js +23 -0
- package/dist/templates/claude-md.js.map +1 -0
- package/dist/templates/cursorrules.d.ts +4 -0
- package/dist/templates/cursorrules.js +18 -0
- package/dist/templates/cursorrules.js.map +1 -0
- package/dist/tier-classifier.d.ts +7 -0
- package/dist/tier-classifier.js +32 -0
- package/dist/tier-classifier.js.map +1 -0
- package/dist/types.d.ts +428 -0
- package/dist/types.js +42 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow-rules.d.ts +18 -0
- package/dist/workflow-rules.js +131 -0
- package/dist/workflow-rules.js.map +1 -0
- 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,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
|