@planu/cli 0.48.1 → 0.49.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/dist/config/license-plans.json +2 -1
- package/dist/engine/scan-project/cross-module-analyzer.d.ts +3 -0
- package/dist/engine/scan-project/cross-module-analyzer.d.ts.map +1 -0
- package/dist/engine/scan-project/cross-module-analyzer.js +302 -0
- package/dist/engine/scan-project/cross-module-analyzer.js.map +1 -0
- package/dist/engine/scan-project/health-scorer.d.ts +3 -0
- package/dist/engine/scan-project/health-scorer.d.ts.map +1 -0
- package/dist/engine/scan-project/health-scorer.js +142 -0
- package/dist/engine/scan-project/health-scorer.js.map +1 -0
- package/dist/engine/scan-project/index.d.ts +7 -0
- package/dist/engine/scan-project/index.d.ts.map +1 -0
- package/dist/engine/scan-project/index.js +231 -0
- package/dist/engine/scan-project/index.js.map +1 -0
- package/dist/engine/scan-project/module-discoverer.d.ts +3 -0
- package/dist/engine/scan-project/module-discoverer.d.ts.map +1 -0
- package/dist/engine/scan-project/module-discoverer.js +388 -0
- package/dist/engine/scan-project/module-discoverer.js.map +1 -0
- package/dist/engine/scan-project/overview-generator.d.ts +3 -0
- package/dist/engine/scan-project/overview-generator.d.ts.map +1 -0
- package/dist/engine/scan-project/overview-generator.js +218 -0
- package/dist/engine/scan-project/overview-generator.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/tools/register-scan-tools.d.ts +3 -0
- package/dist/tools/register-scan-tools.d.ts.map +1 -0
- package/dist/tools/register-scan-tools.js +38 -0
- package/dist/tools/register-scan-tools.js.map +1 -0
- package/dist/tools/scan-project.d.ts +3 -0
- package/dist/tools/scan-project.d.ts.map +1 -0
- package/dist/tools/scan-project.js +22 -0
- package/dist/tools/scan-project.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/scan-project.d.ts +97 -0
- package/dist/types/scan-project.d.ts.map +1 -0
- package/dist/types/scan-project.js +3 -0
- package/dist/types/scan-project.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +2 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// engine/scan-project/index.ts — 4-phase orchestrator for scan_project (SPEC-134)
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { discoverModules } from './module-discoverer.js';
|
|
4
|
+
import { analyzeCrossModuleDependencies } from './cross-module-analyzer.js';
|
|
5
|
+
import { calculateProjectHealth } from './health-scorer.js';
|
|
6
|
+
import { generateProjectOverview } from './overview-generator.js';
|
|
7
|
+
import { runDeepAnalysis } from '../reverse-engineer/index.js';
|
|
8
|
+
import * as specStore from '../../storage/spec-store.js';
|
|
9
|
+
// Re-export submodules for barrel access
|
|
10
|
+
export { discoverModules } from './module-discoverer.js';
|
|
11
|
+
export { analyzeCrossModuleDependencies } from './cross-module-analyzer.js';
|
|
12
|
+
export { calculateProjectHealth } from './health-scorer.js';
|
|
13
|
+
export { generateProjectOverview } from './overview-generator.js';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Concurrency limiter (p-limit pattern — zero deps)
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
function pLimit(concurrency) {
|
|
18
|
+
let active = 0;
|
|
19
|
+
const queue = [];
|
|
20
|
+
function next() {
|
|
21
|
+
if (queue.length > 0 && active < concurrency) {
|
|
22
|
+
active++;
|
|
23
|
+
const run = queue.shift();
|
|
24
|
+
run?.();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return (fn) => new Promise((resolve, reject) => {
|
|
28
|
+
const run = () => {
|
|
29
|
+
fn()
|
|
30
|
+
.then(resolve)
|
|
31
|
+
.catch(reject)
|
|
32
|
+
.finally(() => {
|
|
33
|
+
active--;
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
queue.push(run);
|
|
38
|
+
next();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Phase 2: Parallel analysis with concurrency limit
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
async function analyzeModulesInParallel(projectPath, modules, concurrency) {
|
|
45
|
+
const limit = pLimit(concurrency);
|
|
46
|
+
const tasks = modules.map((mod) => limit(async () => {
|
|
47
|
+
try {
|
|
48
|
+
const modulePath = join(projectPath, mod.path);
|
|
49
|
+
const analysis = await runDeepAnalysis(modulePath);
|
|
50
|
+
return { module: mod, analysis, status: 'success' };
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
module: mod,
|
|
55
|
+
analysis: emptyAnalysis(),
|
|
56
|
+
error: error instanceof Error ? error.message : String(error),
|
|
57
|
+
status: 'failed',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
return Promise.all(tasks);
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Phase 4: Spec generation
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
async function generateSpecs(input, modules, moduleResults, crossAnalysis, healthScore) {
|
|
67
|
+
const specsGenerated = [];
|
|
68
|
+
const nextId = await getNextSpecId(input.projectId);
|
|
69
|
+
let currentId = nextId;
|
|
70
|
+
// Generate one spec per module
|
|
71
|
+
for (const mod of modules) {
|
|
72
|
+
const result = moduleResults.find((r) => r.module.name === mod.name);
|
|
73
|
+
const specId = `SPEC-${String(currentId).padStart(3, '0')}`;
|
|
74
|
+
const deps = crossAnalysis.dependencies.filter((d) => d.to === mod.name).map((d) => d.from);
|
|
75
|
+
const spec = buildScanSpec({
|
|
76
|
+
id: specId,
|
|
77
|
+
title: `Module: ${mod.name}`,
|
|
78
|
+
slug: `module-${mod.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}`,
|
|
79
|
+
scope: 'feature',
|
|
80
|
+
projectId: input.projectId,
|
|
81
|
+
tags: ['scan-project', `module:${mod.name}`, mod.language.toLowerCase()],
|
|
82
|
+
dependencies: deps,
|
|
83
|
+
gitBranch: `feat/${specId.toLowerCase()}-module-${mod.name.toLowerCase()}`,
|
|
84
|
+
reviewNotes: result?.error ? [`Analysis failed: ${result.error}`] : [],
|
|
85
|
+
});
|
|
86
|
+
await specStore.createSpec(input.projectId, spec);
|
|
87
|
+
specsGenerated.push(specId);
|
|
88
|
+
currentId++;
|
|
89
|
+
}
|
|
90
|
+
// Generate overview spec
|
|
91
|
+
const overviewSpecId = `SPEC-${String(currentId).padStart(3, '0')}`;
|
|
92
|
+
const overviewContent = input.generateOverview !== false
|
|
93
|
+
? generateProjectOverview(modules, moduleResults, crossAnalysis, healthScore)
|
|
94
|
+
: '';
|
|
95
|
+
const overviewSpec = buildScanSpec({
|
|
96
|
+
id: overviewSpecId,
|
|
97
|
+
title: 'Project Overview — Automated Scan',
|
|
98
|
+
slug: 'project-overview-scan',
|
|
99
|
+
scope: 'cross-module',
|
|
100
|
+
projectId: input.projectId,
|
|
101
|
+
tags: ['scan-project', 'overview'],
|
|
102
|
+
dependencies: specsGenerated,
|
|
103
|
+
gitBranch: `feat/${overviewSpecId.toLowerCase()}-project-overview`,
|
|
104
|
+
reviewNotes: overviewContent ? [overviewContent] : [],
|
|
105
|
+
});
|
|
106
|
+
await specStore.createSpec(input.projectId, overviewSpec);
|
|
107
|
+
return { specsGenerated, overviewSpecId };
|
|
108
|
+
}
|
|
109
|
+
const DEFAULT_ESTIMATION = {
|
|
110
|
+
devHours: 0,
|
|
111
|
+
reviewHours: 0,
|
|
112
|
+
recommendedModel: 'sonnet',
|
|
113
|
+
tokensOpus: 0,
|
|
114
|
+
tokensSonnet: 0,
|
|
115
|
+
apiCostUsd: 0,
|
|
116
|
+
hourlyRate: 0,
|
|
117
|
+
humanCostUsd: 0,
|
|
118
|
+
totalCostUsd: 0,
|
|
119
|
+
tokenOptimization: {
|
|
120
|
+
mode: 'local',
|
|
121
|
+
reasoning: 'scan-generated',
|
|
122
|
+
estimatedTokens: 0,
|
|
123
|
+
savings: 'N/A',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
function buildScanSpec(params) {
|
|
127
|
+
const now = new Date().toISOString();
|
|
128
|
+
return {
|
|
129
|
+
id: params.id,
|
|
130
|
+
title: params.title,
|
|
131
|
+
slug: params.slug,
|
|
132
|
+
type: 'feature',
|
|
133
|
+
scope: params.scope,
|
|
134
|
+
status: 'draft',
|
|
135
|
+
difficulty: 2,
|
|
136
|
+
risk: 'low',
|
|
137
|
+
projectId: params.projectId,
|
|
138
|
+
createdAt: now,
|
|
139
|
+
updatedAt: now,
|
|
140
|
+
specPath: '',
|
|
141
|
+
technicalPath: '',
|
|
142
|
+
estimation: DEFAULT_ESTIMATION,
|
|
143
|
+
actuals: null,
|
|
144
|
+
target: 'backend',
|
|
145
|
+
tags: params.tags,
|
|
146
|
+
dependencies: params.dependencies,
|
|
147
|
+
blockedBy: [],
|
|
148
|
+
gitBranch: params.gitBranch,
|
|
149
|
+
impactAnalysis: null,
|
|
150
|
+
reviewNotes: params.reviewNotes,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async function getNextSpecId(projectId) {
|
|
154
|
+
const existing = await specStore.listSpecs(projectId);
|
|
155
|
+
if (existing.length === 0) {
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
const maxId = existing.reduce((max, spec) => {
|
|
159
|
+
const match = /^SPEC-(\d+)$/.exec(spec.id);
|
|
160
|
+
const num = match?.[1] ? parseInt(match[1], 10) : 0;
|
|
161
|
+
return Math.max(max, num);
|
|
162
|
+
}, 0);
|
|
163
|
+
return maxId + 1;
|
|
164
|
+
}
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
// Empty analysis fallback (for failed modules)
|
|
167
|
+
// ---------------------------------------------------------------------------
|
|
168
|
+
function emptyAnalysis() {
|
|
169
|
+
return {
|
|
170
|
+
testCoverage: { testedModules: [], untestedModules: [], testToSourceRatio: 0 },
|
|
171
|
+
dependencyGraph: { nodes: [], cycles: [], hubs: [], orphans: [] },
|
|
172
|
+
apiRoutes: [],
|
|
173
|
+
complexityMetrics: [],
|
|
174
|
+
configAnalysis: { configFiles: [], envVars: [], featureFlags: [], infrastructure: [] },
|
|
175
|
+
analysisTimeMs: 0,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Main orchestrator — 4 phases
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
export async function scanProject(input) {
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
const concurrency = Math.min(Math.max(input.concurrency ?? 4, 1), 8);
|
|
184
|
+
// Phase 1: Discovery
|
|
185
|
+
const modules = await discoverModules(input.path, input.modules);
|
|
186
|
+
if (modules.length === 0) {
|
|
187
|
+
return emptyOutput(concurrency, Date.now() - startTime);
|
|
188
|
+
}
|
|
189
|
+
// Phase 2: Parallel analysis
|
|
190
|
+
const moduleResults = await analyzeModulesInParallel(input.path, modules, concurrency);
|
|
191
|
+
// Phase 3: Cross-module intelligence
|
|
192
|
+
const crossAnalysis = analyzeCrossModuleDependencies(moduleResults);
|
|
193
|
+
const healthScore = calculateProjectHealth(moduleResults, crossAnalysis);
|
|
194
|
+
// Phase 4: Spec generation
|
|
195
|
+
const { specsGenerated, overviewSpecId } = await generateSpecs(input, modules, moduleResults, crossAnalysis, healthScore);
|
|
196
|
+
return {
|
|
197
|
+
modulesDiscovered: modules.length,
|
|
198
|
+
modules: modules.map((m) => ({
|
|
199
|
+
name: m.name,
|
|
200
|
+
path: m.path,
|
|
201
|
+
files: m.estimatedFiles,
|
|
202
|
+
language: m.language,
|
|
203
|
+
})),
|
|
204
|
+
projectHealth: healthScore,
|
|
205
|
+
specsGenerated,
|
|
206
|
+
overviewSpecId,
|
|
207
|
+
crossModuleDeps: crossAnalysis.dependencies,
|
|
208
|
+
antipatterns: crossAnalysis.antipatterns,
|
|
209
|
+
teamPlan: undefined,
|
|
210
|
+
analysisTimeMs: Date.now() - startTime,
|
|
211
|
+
concurrencyUsed: concurrency,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
function emptyOutput(concurrency, timeMs) {
|
|
215
|
+
return {
|
|
216
|
+
modulesDiscovered: 0,
|
|
217
|
+
modules: [],
|
|
218
|
+
projectHealth: {
|
|
219
|
+
score: 0,
|
|
220
|
+
breakdown: { testCoverage: 0, techDebt: 0, archConsistency: 0, depHealth: 0 },
|
|
221
|
+
grade: 'F',
|
|
222
|
+
},
|
|
223
|
+
specsGenerated: [],
|
|
224
|
+
overviewSpecId: '',
|
|
225
|
+
crossModuleDeps: [],
|
|
226
|
+
antipatterns: [],
|
|
227
|
+
analysisTimeMs: timeMs,
|
|
228
|
+
concurrencyUsed: concurrency,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/scan-project/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-discoverer.d.ts","sourceRoot":"","sources":["../../../src/engine/scan-project/module-discoverer.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AA4Z7D,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAqB7B"}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
// engine/scan-project/module-discoverer.ts — Detects module boundaries in a project (SPEC-134)
|
|
2
|
+
// Language-agnostic: supports monorepo, package-based, framework-based, and directory-based detection.
|
|
3
|
+
import { readFile, readdir, stat } from 'node:fs/promises';
|
|
4
|
+
import { join, relative, basename } from 'node:path';
|
|
5
|
+
import { glob } from 'glob';
|
|
6
|
+
// === Constants ===
|
|
7
|
+
const IGNORE_PATTERNS = [
|
|
8
|
+
'node_modules',
|
|
9
|
+
'dist',
|
|
10
|
+
'build',
|
|
11
|
+
'.git',
|
|
12
|
+
'.next',
|
|
13
|
+
'__pycache__',
|
|
14
|
+
'target',
|
|
15
|
+
'.venv',
|
|
16
|
+
'venv',
|
|
17
|
+
'vendor',
|
|
18
|
+
'coverage',
|
|
19
|
+
'.cache',
|
|
20
|
+
];
|
|
21
|
+
const SOURCE_EXTENSIONS = '{ts,js,tsx,jsx,py,go,rs,java,kt,rb,cs,swift,dart}';
|
|
22
|
+
const LANGUAGE_EXTENSION_MAP = {
|
|
23
|
+
ts: 'TypeScript',
|
|
24
|
+
tsx: 'TypeScript',
|
|
25
|
+
js: 'JavaScript',
|
|
26
|
+
jsx: 'JavaScript',
|
|
27
|
+
py: 'Python',
|
|
28
|
+
go: 'Go',
|
|
29
|
+
rs: 'Rust',
|
|
30
|
+
java: 'Java',
|
|
31
|
+
kt: 'Kotlin',
|
|
32
|
+
rb: 'Ruby',
|
|
33
|
+
cs: 'C#',
|
|
34
|
+
swift: 'Swift',
|
|
35
|
+
dart: 'Dart',
|
|
36
|
+
};
|
|
37
|
+
const PACKAGE_MANIFESTS = [
|
|
38
|
+
'package.json',
|
|
39
|
+
'go.mod',
|
|
40
|
+
'Cargo.toml',
|
|
41
|
+
'pyproject.toml',
|
|
42
|
+
'requirements.txt',
|
|
43
|
+
];
|
|
44
|
+
// === Helpers ===
|
|
45
|
+
/** Returns true if a path segment should be ignored */
|
|
46
|
+
function isIgnored(segment) {
|
|
47
|
+
return IGNORE_PATTERNS.includes(segment) || segment.startsWith('.');
|
|
48
|
+
}
|
|
49
|
+
/** Counts source files in a directory using glob */
|
|
50
|
+
async function countSourceFiles(dirPath) {
|
|
51
|
+
const pattern = `**/*.${SOURCE_EXTENSIONS}`;
|
|
52
|
+
const files = await glob(pattern, {
|
|
53
|
+
cwd: dirPath,
|
|
54
|
+
ignore: IGNORE_PATTERNS.map((p) => `**/${p}/**`),
|
|
55
|
+
nodir: true,
|
|
56
|
+
});
|
|
57
|
+
return files.length;
|
|
58
|
+
}
|
|
59
|
+
/** Detects dominant language from file extensions in a directory */
|
|
60
|
+
async function detectLanguage(dirPath) {
|
|
61
|
+
const pattern = `**/*.${SOURCE_EXTENSIONS}`;
|
|
62
|
+
const files = await glob(pattern, {
|
|
63
|
+
cwd: dirPath,
|
|
64
|
+
ignore: IGNORE_PATTERNS.map((p) => `**/${p}/**`),
|
|
65
|
+
nodir: true,
|
|
66
|
+
});
|
|
67
|
+
const counts = {};
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
const ext = file.split('.').pop() ?? '';
|
|
70
|
+
counts[ext] = (counts[ext] ?? 0) + 1;
|
|
71
|
+
}
|
|
72
|
+
let dominant = 'unknown';
|
|
73
|
+
let max = 0;
|
|
74
|
+
for (const [ext, count] of Object.entries(counts)) {
|
|
75
|
+
if (count > max) {
|
|
76
|
+
max = count;
|
|
77
|
+
dominant = LANGUAGE_EXTENSION_MAP[ext] ?? ext;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return dominant;
|
|
81
|
+
}
|
|
82
|
+
/** Returns immediate subdirectories of a path, excluding ignored ones */
|
|
83
|
+
async function getSubdirs(dirPath) {
|
|
84
|
+
let entries;
|
|
85
|
+
try {
|
|
86
|
+
entries = await readdir(dirPath);
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const subdirs = [];
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
if (isIgnored(entry)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const fullPath = join(dirPath, entry);
|
|
98
|
+
const s = await stat(fullPath);
|
|
99
|
+
if (s.isDirectory()) {
|
|
100
|
+
subdirs.push(entry);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// skip unreadable entries
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return subdirs;
|
|
108
|
+
}
|
|
109
|
+
/** Checks if a file exists at the given path */
|
|
110
|
+
async function fileExists(filePath) {
|
|
111
|
+
try {
|
|
112
|
+
await stat(filePath);
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Reads a file safely, returns empty string on error */
|
|
120
|
+
async function safeRead(filePath) {
|
|
121
|
+
try {
|
|
122
|
+
return await readFile(filePath, 'utf8');
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// === Manual module resolution ===
|
|
129
|
+
async function resolveManualModules(projectPath, manualModules) {
|
|
130
|
+
const modules = [];
|
|
131
|
+
for (const modPath of manualModules) {
|
|
132
|
+
const fullPath = join(projectPath, modPath);
|
|
133
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
134
|
+
countSourceFiles(fullPath),
|
|
135
|
+
detectLanguage(fullPath),
|
|
136
|
+
]);
|
|
137
|
+
modules.push({
|
|
138
|
+
name: basename(modPath),
|
|
139
|
+
path: modPath,
|
|
140
|
+
estimatedFiles,
|
|
141
|
+
language,
|
|
142
|
+
detectionMethod: 'manual',
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return modules;
|
|
146
|
+
}
|
|
147
|
+
// === Monorepo detection ===
|
|
148
|
+
/** Parses workspace globs from pnpm-workspace.yaml content */
|
|
149
|
+
function parsePnpmWorkspaces(content) {
|
|
150
|
+
const lines = content.split('\n');
|
|
151
|
+
const globs = [];
|
|
152
|
+
let inPackages = false;
|
|
153
|
+
for (const line of lines) {
|
|
154
|
+
if (line.trim() === 'packages:') {
|
|
155
|
+
inPackages = true;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (inPackages) {
|
|
159
|
+
const match = /^\s+-\s+['"]?([^'"]+)['"]?/.exec(line);
|
|
160
|
+
if (match?.[1]) {
|
|
161
|
+
globs.push(match[1]);
|
|
162
|
+
}
|
|
163
|
+
else if (line.trim() && !line.startsWith(' ') && !line.startsWith('\t')) {
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return globs;
|
|
169
|
+
}
|
|
170
|
+
/** Extracts package globs from lerna.json or turbo.json content */
|
|
171
|
+
function parseJsonWorkspaces(content) {
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(content);
|
|
174
|
+
const packages = parsed.packages;
|
|
175
|
+
if (Array.isArray(packages)) {
|
|
176
|
+
return packages.filter((p) => typeof p === 'string');
|
|
177
|
+
}
|
|
178
|
+
const workspaces = parsed.workspaces;
|
|
179
|
+
if (Array.isArray(workspaces)) {
|
|
180
|
+
return workspaces.filter((p) => typeof p === 'string');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// ignore parse errors
|
|
185
|
+
}
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
async function detectMonorepo(projectPath) {
|
|
189
|
+
const pnpmWorkspace = join(projectPath, 'pnpm-workspace.yaml');
|
|
190
|
+
const lernaJson = join(projectPath, 'lerna.json');
|
|
191
|
+
const turboJson = join(projectPath, 'turbo.json');
|
|
192
|
+
let workspaceGlobs = [];
|
|
193
|
+
if (await fileExists(pnpmWorkspace)) {
|
|
194
|
+
const content = await safeRead(pnpmWorkspace);
|
|
195
|
+
workspaceGlobs = parsePnpmWorkspaces(content);
|
|
196
|
+
}
|
|
197
|
+
else if (await fileExists(lernaJson)) {
|
|
198
|
+
const content = await safeRead(lernaJson);
|
|
199
|
+
workspaceGlobs = parseJsonWorkspaces(content);
|
|
200
|
+
}
|
|
201
|
+
else if (await fileExists(turboJson)) {
|
|
202
|
+
// turbo.json itself doesn't define packages; fall back to package.json workspaces
|
|
203
|
+
const pkgJson = join(projectPath, 'package.json');
|
|
204
|
+
const content = await safeRead(pkgJson);
|
|
205
|
+
workspaceGlobs = parseJsonWorkspaces(content);
|
|
206
|
+
}
|
|
207
|
+
if (workspaceGlobs.length === 0) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const resolved = [];
|
|
211
|
+
for (const pattern of workspaceGlobs) {
|
|
212
|
+
// Append '/' to match only directories (glob treats trailing slash as dir-only)
|
|
213
|
+
const dirPattern = pattern.endsWith('/') ? pattern : `${pattern}/`;
|
|
214
|
+
const matches = await glob(dirPattern, {
|
|
215
|
+
cwd: projectPath,
|
|
216
|
+
ignore: IGNORE_PATTERNS.map((p) => `**/${p}/**`),
|
|
217
|
+
});
|
|
218
|
+
// Strip trailing slash glob may add
|
|
219
|
+
resolved.push(...matches.map((m) => m.replace(/\/$/, '')));
|
|
220
|
+
}
|
|
221
|
+
if (resolved.length === 0) {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
const modules = await Promise.all(resolved.map(async (relPath) => {
|
|
225
|
+
const fullPath = join(projectPath, relPath);
|
|
226
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
227
|
+
countSourceFiles(fullPath),
|
|
228
|
+
detectLanguage(fullPath),
|
|
229
|
+
]);
|
|
230
|
+
return {
|
|
231
|
+
name: basename(relPath),
|
|
232
|
+
path: relPath,
|
|
233
|
+
estimatedFiles,
|
|
234
|
+
language,
|
|
235
|
+
detectionMethod: 'monorepo',
|
|
236
|
+
};
|
|
237
|
+
}));
|
|
238
|
+
return modules;
|
|
239
|
+
}
|
|
240
|
+
// === Package-based detection ===
|
|
241
|
+
async function detectPackageBased(projectPath) {
|
|
242
|
+
const subdirs = await getSubdirs(projectPath);
|
|
243
|
+
const modules = [];
|
|
244
|
+
for (const subdir of subdirs) {
|
|
245
|
+
const fullPath = join(projectPath, subdir);
|
|
246
|
+
const hasManifest = await Promise.all(PACKAGE_MANIFESTS.map((m) => fileExists(join(fullPath, m))));
|
|
247
|
+
if (hasManifest.some(Boolean)) {
|
|
248
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
249
|
+
countSourceFiles(fullPath),
|
|
250
|
+
detectLanguage(fullPath),
|
|
251
|
+
]);
|
|
252
|
+
modules.push({
|
|
253
|
+
name: subdir,
|
|
254
|
+
path: subdir,
|
|
255
|
+
estimatedFiles,
|
|
256
|
+
language,
|
|
257
|
+
detectionMethod: 'package',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return modules.length > 0 ? modules : null;
|
|
262
|
+
}
|
|
263
|
+
// === Framework-based detection ===
|
|
264
|
+
/** Detects Next.js modules (app/ or pages/) */
|
|
265
|
+
async function detectNextJs(projectPath) {
|
|
266
|
+
const modules = [];
|
|
267
|
+
for (const dir of ['app', 'pages']) {
|
|
268
|
+
const fullPath = join(projectPath, dir);
|
|
269
|
+
if (await fileExists(fullPath)) {
|
|
270
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
271
|
+
countSourceFiles(fullPath),
|
|
272
|
+
detectLanguage(fullPath),
|
|
273
|
+
]);
|
|
274
|
+
modules.push({
|
|
275
|
+
name: dir,
|
|
276
|
+
path: dir,
|
|
277
|
+
estimatedFiles,
|
|
278
|
+
language,
|
|
279
|
+
detectionMethod: 'framework',
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return modules;
|
|
284
|
+
}
|
|
285
|
+
/** Detects Django apps (dirs containing apps.py alongside manage.py) */
|
|
286
|
+
async function detectDjango(projectPath) {
|
|
287
|
+
if (!(await fileExists(join(projectPath, 'manage.py')))) {
|
|
288
|
+
return [];
|
|
289
|
+
}
|
|
290
|
+
const subdirs = await getSubdirs(projectPath);
|
|
291
|
+
const modules = [];
|
|
292
|
+
for (const subdir of subdirs) {
|
|
293
|
+
const appsPy = join(projectPath, subdir, 'apps.py');
|
|
294
|
+
if (await fileExists(appsPy)) {
|
|
295
|
+
const fullPath = join(projectPath, subdir);
|
|
296
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
297
|
+
countSourceFiles(fullPath),
|
|
298
|
+
detectLanguage(fullPath),
|
|
299
|
+
]);
|
|
300
|
+
modules.push({
|
|
301
|
+
name: subdir,
|
|
302
|
+
path: subdir,
|
|
303
|
+
estimatedFiles,
|
|
304
|
+
language,
|
|
305
|
+
detectionMethod: 'framework',
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return modules;
|
|
310
|
+
}
|
|
311
|
+
/** Detects NestJS modules (dirs containing *.module.ts) */
|
|
312
|
+
async function detectNestJs(projectPath) {
|
|
313
|
+
const srcPath = join(projectPath, 'src');
|
|
314
|
+
const basePath = (await fileExists(srcPath)) ? srcPath : projectPath;
|
|
315
|
+
const subdirs = await getSubdirs(basePath);
|
|
316
|
+
const modules = [];
|
|
317
|
+
for (const subdir of subdirs) {
|
|
318
|
+
const fullPath = join(basePath, subdir);
|
|
319
|
+
const nestModules = await glob('*.module.ts', { cwd: fullPath, nodir: true });
|
|
320
|
+
if (nestModules.length > 0) {
|
|
321
|
+
const relPath = relative(projectPath, fullPath);
|
|
322
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
323
|
+
countSourceFiles(fullPath),
|
|
324
|
+
detectLanguage(fullPath),
|
|
325
|
+
]);
|
|
326
|
+
modules.push({
|
|
327
|
+
name: subdir,
|
|
328
|
+
path: relPath,
|
|
329
|
+
estimatedFiles,
|
|
330
|
+
language,
|
|
331
|
+
detectionMethod: 'framework',
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return modules;
|
|
336
|
+
}
|
|
337
|
+
async function detectFrameworkBased(projectPath) {
|
|
338
|
+
const [nextModules, djangoModules, nestModules] = await Promise.all([
|
|
339
|
+
detectNextJs(projectPath),
|
|
340
|
+
detectDjango(projectPath),
|
|
341
|
+
detectNestJs(projectPath),
|
|
342
|
+
]);
|
|
343
|
+
const all = [...nextModules, ...djangoModules, ...nestModules];
|
|
344
|
+
return all.length > 0 ? all : null;
|
|
345
|
+
}
|
|
346
|
+
// === Directory-based detection (fallback) ===
|
|
347
|
+
async function detectDirectoryBased(projectPath) {
|
|
348
|
+
const srcPath = join(projectPath, 'src');
|
|
349
|
+
const hasSrc = await fileExists(srcPath);
|
|
350
|
+
const basePath = hasSrc ? srcPath : projectPath;
|
|
351
|
+
const subdirs = await getSubdirs(basePath);
|
|
352
|
+
const modules = await Promise.all(subdirs.map(async (subdir) => {
|
|
353
|
+
const fullPath = join(basePath, subdir);
|
|
354
|
+
const relPath = relative(projectPath, fullPath);
|
|
355
|
+
const [estimatedFiles, language] = await Promise.all([
|
|
356
|
+
countSourceFiles(fullPath),
|
|
357
|
+
detectLanguage(fullPath),
|
|
358
|
+
]);
|
|
359
|
+
return {
|
|
360
|
+
name: subdir,
|
|
361
|
+
path: relPath,
|
|
362
|
+
estimatedFiles,
|
|
363
|
+
language,
|
|
364
|
+
detectionMethod: 'directory',
|
|
365
|
+
};
|
|
366
|
+
}));
|
|
367
|
+
return modules;
|
|
368
|
+
}
|
|
369
|
+
// === Public API ===
|
|
370
|
+
export async function discoverModules(projectPath, manualModules) {
|
|
371
|
+
if (manualModules && manualModules.length > 0) {
|
|
372
|
+
return resolveManualModules(projectPath, manualModules);
|
|
373
|
+
}
|
|
374
|
+
const monorepoModules = await detectMonorepo(projectPath);
|
|
375
|
+
if (monorepoModules) {
|
|
376
|
+
return monorepoModules;
|
|
377
|
+
}
|
|
378
|
+
const packageModules = await detectPackageBased(projectPath);
|
|
379
|
+
if (packageModules) {
|
|
380
|
+
return packageModules;
|
|
381
|
+
}
|
|
382
|
+
const frameworkModules = await detectFrameworkBased(projectPath);
|
|
383
|
+
if (frameworkModules) {
|
|
384
|
+
return frameworkModules;
|
|
385
|
+
}
|
|
386
|
+
return detectDirectoryBased(projectPath);
|
|
387
|
+
}
|
|
388
|
+
//# sourceMappingURL=module-discoverer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-discoverer.js","sourceRoot":"","sources":["../../../src/engine/scan-project/module-discoverer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DiscoveredModule, ModuleAnalysisResult, CrossModuleAnalysis, ScanHealthScore } from '../../types/scan-project.js';
|
|
2
|
+
export declare function generateProjectOverview(modules: DiscoveredModule[], moduleResults: ModuleAnalysisResult[], crossModuleAnalysis: CrossModuleAnalysis, healthScore: ScanHealthScore): string;
|
|
3
|
+
//# sourceMappingURL=overview-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overview-generator.d.ts","sourceRoot":"","sources":["../../../src/engine/scan-project/overview-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EAGhB,MAAM,6BAA6B,CAAC;AAMrC,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,aAAa,EAAE,oBAAoB,EAAE,EACrC,mBAAmB,EAAE,mBAAmB,EACxC,WAAW,EAAE,eAAe,GAC3B,MAAM,CAkBR"}
|