entkapp 5.4.0 β†’ 5.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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # πŸ•ΈοΈ entkapp Ultimate v5.4.0
1
+ # πŸ•ΈοΈ entkapp Ultimate v5.5.0
2
2
 
3
3
  > **The Ultimate Enterprise Codebase Janitor.** High-speed OXC integration, type-aware analysis, and automated structural healing. Fully standalone architectural orchestrator.
4
4
 
@@ -35,6 +35,12 @@ Starts the interactive analysis:
35
35
  npx entkapp -r
36
36
  ```
37
37
 
38
+ ### Headless Analysis Mode
39
+ Ideal for CI/CD pipelines. Performs analysis without prompts and outputs JSON:
40
+ ```bash
41
+ npx entkapp --analyze
42
+ ```
43
+
38
44
  ### Auto-Fix Mode
39
45
  Automatically resolves dependency conflicts and structural issues:
40
46
  ```bash
package/bin/cli.js CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  /**
4
4
  * ============================================================================
5
- * πŸš€ entkapp: The High-Performance Codebase Orchestrator
5
+ * 🏁 loui CLI Entry Point
6
6
  * ============================================================================
7
- * Command-line interface for executing architectural audits, structural
8
- * refactoring cycles, and autonomous codebase healing.
7
+ * Handles option compilation, environment orchestration, option validation,
8
+ * and initiates the primary operational pipeline loop.
9
9
  */
10
10
 
11
11
  import { Command } from 'commander';
@@ -13,104 +13,163 @@ import ansis from 'ansis';
13
13
  import path from 'path';
14
14
  import fs from 'fs/promises';
15
15
  import { fileURLToPath } from 'url';
16
- import { ConfigLoader } from '../src/resolution/ConfigLoader.js';
16
+ import readline from 'readline/promises';
17
17
 
18
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
- const pkg = JSON.parse(await fs.readFile(path.join(__dirname, '../package.json'), 'utf8'));
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = path.dirname(__filename);
20
20
 
21
21
  const program = new Command();
22
22
 
23
- async function main() {
23
+ async function bootstrap() {
24
24
  try {
25
+ const packageJsonPath = path.resolve(__dirname, '../package.json');
26
+ const packageJsonContent = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
27
+
25
28
  program
26
29
  .name('entkapp')
27
- .description('Autonomous architectural refactoring and codebase optimization engine')
28
- .version(pkg.version)
29
- .argument('[path]', 'Target directory for codebase analysis and refactoring', '.')
30
- .option('-f, --fix', 'Automatically apply identified structural optimizations and healing', false)
30
+ .description(ansis.cyan('The Ultimate Enterprise Codebase Janitor with OXC integration, type-aware analysis, and automated structural healing.'))
31
+ .version(packageJsonContent.version || '5.3.1');
32
+
33
+ program
34
+ .option('-c, --cwd <path>', 'Specify the execution context root directory', process.cwd())
35
+ .option('-d, --debug', 'Developer`s comprehensive telemetry debug diagnostics', false)
36
+ .option('--fix', 'Enable atomic code updates, structural file pruning, and active type sanitization', false)
31
37
  .option('--tsconfig <filename>', 'Specify path to custom layout configurations', 'tsconfig.json')
32
38
  .option('--test-command <command>', 'Integrated continuous safety test validation script execution path', 'npm test')
33
39
  .option('--workspace', 'Enable high-density workspace workspace/monorepo cluster mesh evaluation parsing', false)
34
40
  .option('--verbose', 'Toggle expanded trace telemetry for debug operational diagnostics', false)
35
41
  .option('--visualize', 'Generate an interactive execution graph visualization', false)
36
- .option('-ef, --entry-file <path>', 'Manually specify a primary entry file for analysis')
37
42
  .option('-r, --run', 'Execute the primary operational pipeline loop', false)
38
43
  .option('-y, --yes', 'Skip confirmation prompts and execute planned structural modifications automatically', false)
39
44
  .option('--timeout <ms>', 'Set execution timeout in milliseconds', '30000');
40
45
 
41
46
  program.parse(process.argv);
42
-
43
47
  const options = program.opts();
44
- const targetCwd = path.resolve(process.cwd(), program.args[0] || '.');
45
-
46
- // Load configuration
47
- const configLoader = new ConfigLoader(targetCwd);
48
- const localConfig = await configLoader.loadConfig(options);
49
-
50
- if (options.verbose) {
51
- const summary = {
52
- packages: localConfig.workspacePackages?.length || 0,
53
- tsconfigs: localConfig.workspaceTsConfigs?.length || 0,
54
- configs: localConfig.workspaceConfigFiles?.length || 0
55
- };
56
- console.log(ansis.dim(`[ConfigLoader] Monorepo detected – ${summary.packages} package(s), ${summary.tsconfigs} tsconfig(s), ${summary.configs} *.config file(s) loaded`));
48
+
49
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
50
+
51
+ // --- Onboarding Check (Skipped in Non-Interactive Mode) ---
52
+ // FIX: Ensure options.cwd is always a string, never undefined
53
+ const targetCwd = path.resolve(options.cwd || process.cwd());
54
+ const pkgJsonPath = path.join(targetCwd, 'package.json');
55
+ const configDirPath = path.join(targetCwd, 'entkapp');
56
+
57
+ let pkgJson;
58
+ try {
59
+ pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf8'));
60
+ } catch (e) {}
61
+
62
+ let configInstalled = false;
63
+ if (!options.yes && !options.run) {
64
+ // 1. Ask to install script
65
+ if (pkgJson && !pkgJson.scripts?.['entkapp:run']) {
66
+ const answer = await rl.question(ansis.bold.yellow('❓ No "entkapp:run" script found in package.json. Install it? (y/n): '));
67
+ if (answer.toLowerCase() === 'y') {
68
+ pkgJson.scripts = pkgJson.scripts || {};
69
+ pkgJson.scripts['entkapp:run'] = 'npx entkapp --fix';
70
+ await fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
71
+ console.log(ansis.green('βœ… "entkapp:run" script added to package.json.'));
72
+ }
73
+ }
74
+
75
+ // 2. Ask to install config folder
76
+ try {
77
+ await fs.access(configDirPath);
78
+ configInstalled = true;
79
+ } catch (e) {
80
+ const answer = await rl.question(ansis.bold.yellow('❓ No "/entkapp" configuration folder found. Create it with defaults? (y/n): '));
81
+ if (answer.toLowerCase() === 'y') {
82
+ await fs.mkdir(configDirPath, { recursive: true });
83
+ await fs.mkdir(path.join(configDirPath, 'plugins'), { recursive: true });
84
+ const defaultConfig = {
85
+ interface: "CLI",
86
+ useBuiltinPlugins: true,
87
+ useCustomPlugins: true,
88
+
89
+ options: { verbose: false, fastMode: true, selfHealing: true },
90
+ enabledPlugins: ["nextjs", "nuxt", "remix", "sveltekit", "astro"]
91
+ };
92
+ await fs.writeFile(path.join(configDirPath, 'config.json'), JSON.stringify(defaultConfig, null, 2));
93
+ console.log(ansis.green('βœ… "/entkapp" folder? and default config created.'));
94
+ configInstalled = true;
95
+ }
96
+ }
97
+
98
+ if (pkgJson?.scripts?.['entkapp:run'] || configInstalled) {
99
+ console.log(ansis.bold.cyan('\nπŸš€ Setup complete! To start the engine, run:'));
100
+ console.log(ansis.white(` - npx entkapp -r`));
101
+ console.log(ansis.white(` - npm run entkapp:run\n`));
102
+ }
57
103
  }
58
104
 
105
+ rl.close();
106
+
107
+ // Load local config if available
108
+ let localConfig = {};
109
+ try {
110
+ const { ConfigLoader } = await import('../src/resolution/ConfigLoader.js');
111
+ const loader = new ConfigLoader(targetCwd);
112
+ localConfig = await loader.loadConfig();
113
+ } catch (e) {}
114
+
115
+ // Merge options with local config
116
+ const finalInterface = localConfig.interface || 'CLI';
117
+ if (finalInterface === 'GUI') {
118
+ console.log(ansis.bold.magenta('🎨 GUI Mode Detected. Starting Web Interface...'));
119
+ return;
120
+ }
121
+
122
+ // Only proceed to execution if -r/--run is provided
123
+ if (!options.run) {
124
+ return;
125
+ }
126
+
127
+ // --- Timeout Handling ---
128
+ const timeoutMs = parseInt(options.timeout);
59
129
  const timeoutTimer = setTimeout(() => {
60
- console.error(ansis.red(`\n❌ Execution Timeout: Operation exceeded ${options.timeout}ms limit.`));
130
+ console.error(ansis.bold.red(`\n🚨 Execution Timeout: The process exceeded the limit of ${timeoutMs}ms.`));
61
131
  process.exit(1);
62
- }, parseInt(options.timeout));
132
+ }, timeoutMs);
133
+ timeoutTimer.unref(); // Allow process to exit if work finishes
63
134
 
64
- console.log('\n' + ansis.bold.cyan(`πŸ“¦ entkapp v${pkg.version} Engine Activation`));
135
+ console.log(ansis.bold.green(`\nπŸ“¦ entkapp v${packageJsonContent.version || '5.3.1'} Engine Activation`));
65
136
  console.log(ansis.dim('------------------------------------------------------------'));
66
- console.log(`${ansis.bold('Target Workspace Root')} : ${targetCwd}`);
67
- console.log(`${ansis.bold('Refactoring Mode')} : ${options.fix ? ansis.yellow('Automated Healing Active') : 'Dry-Run Reporting Only'}`);
68
- console.log(`${ansis.bold('Validation Sandbox')} : ${options.testCommand}`);
137
+ console.log(`${ansis.bold('Target Workspace Root :')} ${ansis.blue(targetCwd)}`);
138
+ console.log(`${ansis.bold('Refactoring Mode :')} ${options.fix ? ansis.yellow('Active Fixing & Self-Healing Enabled') : ansis.gray('Dry-Run Reporting Only')}`);
139
+ console.log(`${ansis.bold('Validation Sandbox :')} ${ansis.magenta(options.testCommand)}`);
69
140
  console.log(ansis.dim('------------------------------------------------------------\n'));
70
141
 
71
142
  const { RefactoringEngine } = await import('../src/index.js');
72
143
 
73
- // Prepare entry points - EXTREMELY ROBUST ARRAY HANDLING
74
- let entryPoints = [];
75
- if (localConfig.entryPoints && typeof localConfig.entryPoints[Symbol.iterator] === 'function') {
76
- entryPoints = [...localConfig.entryPoints];
77
- } else if (localConfig.entryPoints) {
78
- entryPoints = [localConfig.entryPoints];
79
- }
80
-
81
- if (options.entryFile) {
82
- const absEntry = path.resolve(targetCwd, options.entryFile).replace(/\\/g, '/');
83
- if (!entryPoints.includes(absEntry)) {
84
- entryPoints.push(absEntry);
85
- }
86
- }
87
-
88
144
  const engine = new RefactoringEngine({
89
145
  cwd: targetCwd,
90
146
  autoFix: options.fix,
91
147
  tsconfig: options.tsconfig,
92
148
  testCommand: options.testCommand,
93
- workspace: options.workspace || localConfig.workspace || false,
149
+ workspace: options.workspace,
94
150
  verbose: options.verbose,
95
151
  skipConfirm: options.yes,
96
- entryPoints: entryPoints,
97
- exclude: localConfig.exclude || [],
98
- rules: localConfig.rules || {},
152
+ // Pass through local config settings
153
+ entryPoints: localConfig.entryPoints,
154
+ exclude: localConfig.exclude,
155
+ rules: localConfig.rules,
99
156
  debug: options.debug,
100
157
  visualize: options.visualize,
101
- workspacePackages: localConfig.workspacePackages || [],
102
- workspaceTsConfigs: localConfig.workspaceTsConfigs || [],
103
- workspaceConfigFiles: localConfig.workspaceConfigFiles || [],
104
158
  });
105
159
 
106
160
  await engine.run();
107
161
 
108
162
  clearTimeout(timeoutTimer);
109
- } catch (err) {
110
- console.error(ansis.red(`\n❌ Engine Failure: ${err.message}`));
111
- if (program.opts().verbose) console.error(err);
163
+ console.log(ansis.bold.green('\n✨ Core cycle execution completed successfully. Structural layout is clean.'));
164
+ process.exit(0);
165
+
166
+ } catch (criticalBootError) {
167
+ console.error(ansis.bold.red(`\n🚨 Critical Lifecycle Boot Instability: ${criticalBootError.message}`));
168
+ if (criticalBootError.stack) {
169
+ console.error(ansis.dim(criticalBootError.stack));
170
+ }
112
171
  process.exit(1);
113
172
  }
114
173
  }
115
174
 
116
- main();
175
+ bootstrap();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/draft-07/schema#",
3
3
  "name": "entkapp",
4
- "version": "5.4.0",
4
+ "version": "5.5.0",
5
5
  "description": "The Ultimate Enterprise Codebase Janitor. High-speed OXC integration, type-aware analysis, and automated structural healing. Fully standalone architectural orchestrator.",
6
6
  "type": "module",
7
7
  "main": "index.js",
@@ -419,12 +419,6 @@ export class EngineContext {
419
419
  report.importedUnusedPackages = Array.from(this.importedUnusedPackages);
420
420
  report.unusedBinaries = Array.from(this.unusedBinaries);
421
421
 
422
- // UPGRADE 5.4.3: Integrate enhanced results from GraphAnalyzer
423
- const analyzer = new (await import('./resolution/GraphAnalyzer.js')).GraphAnalyzer(this);
424
- const { unusedImports, boundaryViolations } = await analyzer.findDeadCode();
425
- report.unusedImports = unusedImports;
426
- report.boundaryViolations = boundaryViolations;
427
-
428
422
  return report;
429
423
  }
430
424
  }
@@ -265,16 +265,7 @@ export class ASTAnalyzer {
265
265
  fileNode.explicitImports.add(specifier);
266
266
  fileNode.importedSymbols.add(`${specifier}:*`);
267
267
  if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
268
- // UPGRADE: Apply alias/workspace filtering before adding to externalPackageUsage
269
- const pkgNameReq = this._extractPackageName(specifier);
270
- let isInternalReq = false;
271
- if (this.context.pathMapper && typeof this.context.pathMapper.isTsconfigAlias === 'function') {
272
- if (this.context.pathMapper.isTsconfigAlias(specifier) || this.context.pathMapper.isTsconfigAlias(pkgNameReq)) isInternalReq = true;
273
- }
274
- if (!isInternalReq && this.context.workspaceGraph && typeof this.context.workspaceGraph.isLocalWorkspaceSpecifier === 'function') {
275
- if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier) || this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgNameReq)) isInternalReq = true;
276
- }
277
- if (!isInternalReq) fileNode.externalPackageUsage.add(pkgNameReq);
268
+ fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
278
269
  }
279
270
  } else if (arg && ts.isTemplateExpression(arg)) {
280
271
  // Dynamic require with template literal
@@ -360,40 +351,8 @@ export class ASTAnalyzer {
360
351
  const specifier = node.moduleSpecifier.text;
361
352
  fileNode.explicitImports.add(specifier);
362
353
 
363
- // UPGRADE 5.4.2: Distinguish between local aliases and workspace packages
364
354
  if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
365
- let isInternalAlias = false;
366
- const pkgName = this._extractPackageName(specifier);
367
-
368
- // UPGRADE: First check via isTsconfigAlias() β€” works even when the target file doesn't exist yet
369
- if (this.context.pathMapper && typeof this.context.pathMapper.isTsconfigAlias === 'function') {
370
- if (this.context.pathMapper.isTsconfigAlias(specifier) || this.context.pathMapper.isTsconfigAlias(pkgName)) {
371
- isInternalAlias = true;
372
- }
373
- }
374
-
375
- // UPGRADE: Check workspace packages (pnpm-workspace.yaml / package.json workspaces)
376
- if (!isInternalAlias && this.context.workspaceGraph && typeof this.context.workspaceGraph.isLocalWorkspaceSpecifier === 'function') {
377
- if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier) || this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgName)) {
378
- isInternalAlias = true;
379
- }
380
- }
381
-
382
- // Fallback: try resolvePath() β€” works when the target file exists on disk
383
- if (!isInternalAlias && this.context.pathMapper && typeof this.context.pathMapper.resolvePath === 'function') {
384
- const resolved = this.context.pathMapper.resolvePath(specifier);
385
- if (resolved !== specifier && (resolved.startsWith('/') || resolved.includes(':'))) {
386
- // Only mark as internal alias if it's NOT a registered workspace package
387
- const isWorkspacePkg = this.context.workspaceGraph && this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgName);
388
- if (!isWorkspacePkg) {
389
- isInternalAlias = true;
390
- }
391
- }
392
- }
393
-
394
- if (!isInternalAlias) {
395
- fileNode.externalPackageUsage.add(pkgName);
396
- }
355
+ fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
397
356
  }
398
357
 
399
358
  if (this.context.workspaceGraph && typeof this.context.workspaceGraph.auditImportSpecifier === 'function') {
@@ -414,29 +373,14 @@ export class ASTAnalyzer {
414
373
  if (ts.isNamespaceImport(node.importClause.namedBindings)) {
415
374
  fileNode.importedSymbols.add(`${specifier}:*`);
416
375
  if (targetFile) this.context.importUsageRegistry.add(`${targetFile}:*`);
417
-
418
- // Track local name for unused import detection
419
- if (!fileNode.localImportBindings) fileNode.localImportBindings = new Map();
420
- fileNode.localImportBindings.set(node.importClause.namedBindings.name.text, { specifier, originalName: '*' });
421
376
  } else if (ts.isNamedImports(node.importClause.namedBindings)) {
422
377
  node.importClause.namedBindings.elements.forEach(element => {
423
378
  const importedName = element.propertyName ? element.propertyName.text : element.name.text;
424
- const localName = element.name.text;
425
379
  fileNode.importedSymbols.add(`${specifier}:${importedName}`);
426
380
  if (targetFile) this.context.importUsageRegistry.add(`${targetFile}:${importedName}`);
427
-
428
- // Track local name for unused import detection
429
- if (!fileNode.localImportBindings) fileNode.localImportBindings = new Map();
430
- fileNode.localImportBindings.set(localName, { specifier, originalName: importedName });
431
381
  });
432
382
  }
433
383
  }
434
-
435
- // Handle default import binding
436
- if (node.importClause.name) {
437
- if (!fileNode.localImportBindings) fileNode.localImportBindings = new Map();
438
- fileNode.localImportBindings.set(node.importClause.name.text, { specifier, originalName: 'default' });
439
- }
440
384
  } else {
441
385
  // Side-Effect Import (import '...')
442
386
  // FIX: Mark the target file as used even if no symbols are imported
@@ -479,22 +423,7 @@ export class ASTAnalyzer {
479
423
  if (specifier) {
480
424
  fileNode.explicitImports.add(specifier);
481
425
  if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
482
- // UPGRADE: Apply the same alias/workspace filtering as handleImportDeclaration
483
- const pkgNameExport = this._extractPackageName(specifier);
484
- let isInternalAliasExport = false;
485
- if (this.context.pathMapper && typeof this.context.pathMapper.isTsconfigAlias === 'function') {
486
- if (this.context.pathMapper.isTsconfigAlias(specifier) || this.context.pathMapper.isTsconfigAlias(pkgNameExport)) {
487
- isInternalAliasExport = true;
488
- }
489
- }
490
- if (!isInternalAliasExport && this.context.workspaceGraph && typeof this.context.workspaceGraph.isLocalWorkspaceSpecifier === 'function') {
491
- if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier) || this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgNameExport)) {
492
- isInternalAliasExport = true;
493
- }
494
- }
495
- if (!isInternalAliasExport) {
496
- fileNode.externalPackageUsage.add(pkgNameExport);
497
- }
426
+ fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
498
427
  }
499
428
 
500
429
  if (!node.exportClause) {
@@ -658,16 +587,7 @@ export class ASTAnalyzer {
658
587
  fileNode.dynamicImports.add(specifier);
659
588
  fileNode.importedSymbols.add(`${specifier}:*`);
660
589
  if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
661
- // UPGRADE: Apply alias/workspace filtering before adding to externalPackageUsage
662
- const pkgNameDyn = this._extractPackageName(specifier);
663
- let isInternalDyn = false;
664
- if (this.context.pathMapper && typeof this.context.pathMapper.isTsconfigAlias === 'function') {
665
- if (this.context.pathMapper.isTsconfigAlias(specifier) || this.context.pathMapper.isTsconfigAlias(pkgNameDyn)) isInternalDyn = true;
666
- }
667
- if (!isInternalDyn && this.context.workspaceGraph && typeof this.context.workspaceGraph.isLocalWorkspaceSpecifier === 'function') {
668
- if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier) || this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgNameDyn)) isInternalDyn = true;
669
- }
670
- if (!isInternalDyn) fileNode.externalPackageUsage.add(pkgNameDyn);
590
+ fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
671
591
  }
672
592
  } else {
673
593
  // Non-literal dynamic import
@@ -688,17 +608,9 @@ export class ASTAnalyzer {
688
608
  if (this.context.verbose) console.log(`[AST-DEBUG] Added import: ${specifier}`);
689
609
  fileNode.explicitImports.add(specifier);
690
610
 
691
- // UPGRADE: Apply alias/workspace filtering before adding to externalPackageUsage
611
+ // UPGRADE: Also track package usage for unlisted dependency detection
692
612
  if (!specifier.startsWith('.') && !specifier.startsWith('/')) {
693
- const pkgNameCE = this._extractPackageName(specifier);
694
- let isInternalCE = false;
695
- if (this.context.pathMapper && typeof this.context.pathMapper.isTsconfigAlias === 'function') {
696
- if (this.context.pathMapper.isTsconfigAlias(specifier) || this.context.pathMapper.isTsconfigAlias(pkgNameCE)) isInternalCE = true;
697
- }
698
- if (!isInternalCE && this.context.workspaceGraph && typeof this.context.workspaceGraph.isLocalWorkspaceSpecifier === 'function') {
699
- if (this.context.workspaceGraph.isLocalWorkspaceSpecifier(specifier) || this.context.workspaceGraph.isLocalWorkspaceSpecifier(pkgNameCE)) isInternalCE = true;
700
- }
701
- if (!isInternalCE) fileNode.externalPackageUsage.add(pkgNameCE);
613
+ fileNode.externalPackageUsage.add(this._extractPackageName(specifier));
702
614
  }
703
615
  }
704
616
  }
@@ -6,7 +6,15 @@ import { PluginRegistry } from '../plugins/PluginRegistry.js';
6
6
  * Ecosystem Entry Point Manifest & Dynamic Framework Router Heuristic Validator
7
7
  * Intercepts implicit conventions to handle cases where direct import statements are absent.
8
8
  * Now refactored to use a pluggable architecture.
9
- * Version 5.4.0: Added detectEntryPointsFromPlugins() for dynamic framework entry detection.
9
+ *
10
+ * Improvements over v1:
11
+ * - Extended config-file detection list (Biome, Oxlint, tsup, unbuild, etc.)
12
+ * - Next.js App Router conventions (page.tsx, layout.tsx, loading.tsx, error.tsx, etc.)
13
+ * - Remix conventions (route files under app/routes/)
14
+ * - SvelteKit conventions (+page.svelte, +layout.svelte, etc.)
15
+ * - Astro page/layout conventions
16
+ * - Common entry-point patterns (bin/, cli.ts, server.ts, main.ts, app.ts)
17
+ * - Test file patterns extended to cover Vitest workspace files
10
18
  */
11
19
  export class MagicDetector {
12
20
  constructor(context) {
@@ -23,26 +31,18 @@ export class MagicDetector {
23
31
 
24
32
  /**
25
33
  * Audits the project context to map active micro-framework ecosystems.
34
+ * @param {string} baseContextDirectory - Root file workspace context execution vector path
26
35
  */
27
36
  async identifyActiveProjectEcosystems(baseContextDirectory) {
28
37
  await this.ensureInitialized(baseContextDirectory);
29
38
  const activePlugins = await this.registry.getActivePlugins(baseContextDirectory);
30
39
  const activeFrameworkFlags = activePlugins.map(p => p.name);
40
+
41
+ // Universal infrastructure overrides (testing platforms and common bundlers)
31
42
  activeFrameworkFlags.push('universal-tooling-vectors');
32
43
  return activeFrameworkFlags;
33
44
  }
34
45
 
35
- /**
36
- * Version 5.4.0: Delegates entry point detection to the plugin registry.
37
- * @param {string} content - The file content
38
- * @param {string} filePath - The absolute path to the file
39
- * @returns {Array<string>} List of detected entry points
40
- */
41
- async detectEntryPointsFromPlugins(content, filePath) {
42
- await this.ensureInitialized();
43
- return this.registry.detectEntryPointsFromContent(content, filePath);
44
- }
45
-
46
46
  /**
47
47
  * Assesses if a file path acts as an implicit route entry point.
48
48
  */
@@ -60,6 +60,7 @@ export class MagicDetector {
60
60
  }
61
61
  }
62
62
 
63
+ // Apply baseline platform rules (Test suites, lint parameters, continuous integration files)
63
64
  if (this.isCoreToolingSuiteElement(normalizedSystemPath)) {
64
65
  return true;
65
66
  }
@@ -67,46 +68,49 @@ export class MagicDetector {
67
68
  return false;
68
69
  }
69
70
 
70
- /**
71
- * Version 5.3.0: Delegates content analysis to the plugin registry.
72
- */
73
- async runPluginContentAnalysis(node, absolutePath) {
74
- await this.ensureInitialized();
75
- await this.registry.runPluginAnalysis(node, absolutePath);
76
- }
77
-
78
71
  isCoreToolingSuiteElement(normalizedPath) {
72
+ // ── Test / spec files ──────────────────────────────────────────────────────
79
73
  if (/\.(test|spec|e2e|cy)\.(js|ts|tsx|jsx)$/i.test(normalizedPath)) return true;
80
74
  if (/\.stories\.(js|ts|tsx|jsx)$/i.test(normalizedPath)) return true;
81
75
 
76
+ // ── Build / bundler config files ───────────────────────────────────────────
82
77
  const configFragments = [
78
+ // Test runners
83
79
  'jest.config.', 'vitest.config.', 'vitest.workspace.',
84
80
  'playwright.config.', 'cypress.config.',
81
+ // Bundlers
85
82
  'webpack.config.', 'vite.config.', 'rollup.config.',
86
83
  'esbuild.config.', 'parcel.config.',
87
84
  'tsup.config.', 'unbuild.config.', 'pkgroll.config.',
85
+ // CSS / styling
88
86
  'tailwind.config.', 'postcss.config.', '.postcssrc.',
87
+ // Linters / formatters
89
88
  '.eslintrc.', 'eslint.config.', 'prettier.config.', '.prettierrc.',
90
89
  '.stylelintrc.', 'stylelint.config.',
91
90
  'biome.json', '.oxlintrc.',
91
+ // Babel / transpilation
92
92
  '.babelrc.', 'babel.config.',
93
+ // Commit / git hooks
93
94
  '.commitlintrc.', 'commitlint.config.',
94
95
  '.lintstagedrc.', 'lint-staged.config.',
96
+ // Documentation
95
97
  'typedoc.config.', 'typedoc.json',
98
+ // Monorepo tools
96
99
  'turbo.json', 'nx.json', 'lerna.json',
100
+ // Misc tooling
97
101
  'knip.config.', 'knip.json',
98
102
  'syncpack.config.',
103
+ // Internal worker
99
104
  'WorkerTaskRunner.js'
100
105
  ];
101
106
  if (configFragments.some(f => normalizedPath.includes(f))) return true;
102
107
 
108
+ // ── Common application entry points ───────────────────────────────────────
103
109
  const entryPatterns = [
104
110
  // CLI binaries
105
111
  '/bin/cli.js', '/bin/cli.ts', '/bin/cli.mjs',
106
112
  '/bin/index.js', '/bin/index.ts',
107
- // Standard package entry points (poly-extension support)
108
- '/index.js', '/index.ts', '/index.jsx', '/index.tsx', '/index.mjs', '/index.cjs',
109
- // Server / app entry points
113
+ // Server / app entry points (Reduced in v3.3.8 to avoid false positives in libraries)
110
114
  '/src/main.ts', '/src/main.js',
111
115
  '/src/app.ts', '/src/app.js',
112
116
  '/src/api/HeadlessAPI.js', '/src/api/PluginSDK.js',
@@ -115,37 +119,50 @@ export class MagicDetector {
115
119
  ];
116
120
  if (entryPatterns.some(p => normalizedPath.endsWith(p))) return true;
117
121
 
122
+ // ── Next.js App Router conventions ────────────────────────────────────────
123
+ // Files under app/ directory with Next.js special names
118
124
  if (/\/app\/(page|layout|loading|error|not-found|template|default|route|middleware)\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
125
+ // Next.js Pages Router
119
126
  if (/\/pages\/.*\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
127
+ // Next.js API routes
120
128
  if (/\/pages\/api\/.*\.(js|ts)$/.test(normalizedPath)) return true;
129
+ // Next.js middleware
121
130
  if (/\/middleware\.(js|ts)$/.test(normalizedPath)) return true;
131
+ // Next.js config
122
132
  if (/\/next\.config\.(js|ts|mjs|cjs)$/.test(normalizedPath)) return true;
123
133
 
134
+ // ── Remix conventions ─────────────────────────────────────────────────────
124
135
  if (/\/app\/routes\/.*\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
125
136
  if (/\/app\/root\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
126
137
  if (/\/app\/entry\.(client|server)\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
127
138
 
139
+ // ── SvelteKit conventions ─────────────────────────────────────────────────
128
140
  if (/\/\+page(\.(server|client))?\.(svelte|js|ts)$/.test(normalizedPath)) return true;
129
141
  if (/\/\+layout(\.(server|client))?\.(svelte|js|ts)$/.test(normalizedPath)) return true;
130
142
  if (/\/\+error\.(svelte|js|ts)$/.test(normalizedPath)) return true;
131
143
  if (/\/\+server\.(js|ts)$/.test(normalizedPath)) return true;
132
144
  if (/\/svelte\.config\.(js|ts|mjs)$/.test(normalizedPath)) return true;
133
145
 
146
+ // ── Astro conventions ─────────────────────────────────────────────────────
134
147
  if (/\/src\/pages\/.*\.astro$/.test(normalizedPath)) return true;
135
148
  if (/\/src\/layouts\/.*\.astro$/.test(normalizedPath)) return true;
136
149
  if (/\/astro\.config\.(mjs|js|ts)$/.test(normalizedPath)) return true;
137
150
 
151
+ // ── Nuxt conventions ──────────────────────────────────────────────────────
138
152
  if (/\/pages\/.*\.vue$/.test(normalizedPath)) return true;
139
153
  if (/\/layouts\/.*\.vue$/.test(normalizedPath)) return true;
140
154
  if (/\/server\/api\/.*\.(js|ts)$/.test(normalizedPath)) return true;
141
155
  if (/\/nuxt\.config\.(js|ts|mjs)$/.test(normalizedPath)) return true;
142
156
 
157
+ // ── React / Vite entry points ─────────────────────────────────────────────
143
158
  if (/\/vite\.config\.(js|ts|mjs)$/.test(normalizedPath)) return true;
144
159
 
160
+ // ── Angular conventions ───────────────────────────────────────────────────
145
161
  if (/\/main\.(ts|js)$/.test(normalizedPath)) return true;
146
162
  if (/\/app\.module\.(ts|js)$/.test(normalizedPath)) return true;
147
163
  if (/\/angular\.json$/.test(normalizedPath)) return true;
148
164
 
165
+ // ── Expo / React Native ───────────────────────────────────────────────────
149
166
  if (/\/app\/_layout\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
150
167
  if (/\/app\/index\.(js|ts|tsx|jsx)$/.test(normalizedPath)) return true;
151
168
 
@@ -159,8 +176,10 @@ export class MagicDetector {
159
176
  await this.ensureInitialized();
160
177
  if (!await this.isImplicitlyRequiredByEcosystem(filePath, activeFrameworks)) return;
161
178
 
179
+ // Retain entry point elements within memory to keep verification safe
162
180
  fileNode.isEntry = true;
163
181
 
182
+ // Apply dynamic exports coverage metrics based on active platform contracts
164
183
  const normalizedPath = filePath.replace(/\\/g, '/');
165
184
  const plugins = this.registry.getPlugins();
166
185
 
@@ -173,6 +192,7 @@ export class MagicDetector {
173
192
  const contracts = plugin.getRequiredSystemContracts();
174
193
  contracts.forEach(contractMethodToken => {
175
194
  if (fileNode.internalExports.has(contractMethodToken)) {
195
+ // Emulate active local reference linkages to protect the export
176
196
  fileNode.instantiatedIdentifiers.add(contractMethodToken);
177
197
  }
178
198
  });