The Kernel - Infrastructure and plugin lifecycle management
The @angular-modernizer/core package provides the foundational infrastructure for the Angular Modernization Platform. It contains the Kernel, file system abstractions, plugin management system, transformation pipeline, and advanced orchestration capabilities that power the entire platform.
The core package follows the "Infrastructure Only" principle - it provides domain-agnostic building blocks without any Angular-specific logic.
Kernel (Domain Agnostic)
- Plugin System (Contracts)
- File System (Abstraction)
- TypeScript Project (ts-morph)
- Transformation Pipeline (Coordinator + Execution Engine)
- Orchestration System (Parallel + Incremental + Workers)
- Cache Manager (AST Caching + Invalidation)
The Kernel is the central orchestrator that manages the entire platform lifecycle:
interface KernelConfig {
tsConfigPath?: string;
fileSystem?: FileSystemAdapter;
projectOptions?: Partial<ProjectOptions>;
plugins?: Plugin[];
transformationCoordinator?: TransformationCoordinator;
api?: unknown; // defaults to createPublicApi(project) when plugins are set
cacheConfig?: Partial<CacheConfig>;
resourceLimits?: ResourceLimits;
enableParallelExecution?: boolean; // default: true
}
class Kernel {
constructor(config?: KernelConfig); // All parameters optional
async initialize(): Promise<void>;
getProject(): Project;
getFileSystem(): FileSystemAdapter;
getCacheManager(): CacheManager | undefined;
getBuildValidator(): BuildValidator;
getPlugin(name: string): Plugin | undefined;
getAllPlugins(): Plugin[];
hasPlugin(name: string): boolean;
isInitialized(): boolean;
getConfig(): Readonly<KernelConfig>;
getProjectRoot(): string; // safe before initialize()
// Transformation API
transformFile(
sourceFile: SourceFile,
config?: TransformationConfig,
): Promise<TransformationResult>;
// Orchestration API
getParallelExecutor(): ParallelExecutor | undefined;
getIncrementalAnalyzer(): IncrementalAnalyzer | undefined;
getProgressReporter(): ProgressReporter | undefined;
getResourceManager(): ResourceManager | undefined;
getOrchestrationStats(): OrchestrationStats | undefined;
analyzeParallel(options?: ParallelAnalysisOptions): Promise<unknown[]>;
analyzeIncremental(options?: IncrementalAnalysisOptions): Promise<unknown>;
}
Key features:
Usage examples:
// Minimal setup
const kernel1 = new Kernel();
await kernel1.initialize();
// Explicit empty config
const kernel2 = new Kernel({});
await kernel2.initialize();
// Full configuration
const kernel3 = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
plugins: [new StandalonePlugin()],
});
await kernel3.initialize();
The platform uses a custom FileSystemAdapter interface to enable both production file system access and in-memory testing:
interface FileSystemAdapter {
readFile(path: string): Promise<string>;
writeFile(path: string, content: string): Promise<void>;
exists(path: string): Promise<boolean>;
readDirectory(path: string): Promise<string[]>;
deleteFile(path: string): Promise<void>;
createDirectory(path: string): Promise<void>;
fileExists(path: string): Promise<boolean>;
directoryExists(path: string): Promise<boolean>;
getFileStats(path: string): Promise<{ /* size, mtime, ... */ }>;
}
Production file system access with full ts-morph compatibility:
import { RealFileSystemAdapter } from '@angular-modernizer/core';
const fileSystem = new RealFileSystemAdapter();
const kernel = new Kernel({
fileSystem,
projectOptions: {
fileSystem: fileSystem,
},
});
Features:
FileSystemHost implementation for ts-morph compatibilityreadFileSync(), writeFileSync(), mkdirSync(), etc.Testing and development with in-memory file system:
import { InMemoryFileSystemAdapter } from '@angular-modernizer/core';
const fileSystem = new InMemoryFileSystemAdapter();
const kernel = new Kernel({
fileSystem,
projectOptions: {
useInMemoryFileSystem: true,
compilerOptions: {
target: 99, // ES2022
module: 199, // NodeNext
},
},
});
Features:
The Kernel provides comprehensive plugin lifecycle management:
class Kernel {
getPlugin(name: string): Plugin | undefined;
getAllPlugins(): Plugin[];
hasPlugin(name: string): boolean;
async initialize(): Promise<void>;
}
Plugin interface:
interface Plugin {
readonly name: string;
readonly version: string;
initialize(kernel: IKernel): Promise<void>;
getAnalysisRules(): AnalysisRule[];
getTransformRules(): TransformRule[];
getValidationRules(): ValidationRule[];
}
The core package provides a robust transformation pipeline for automated code modifications.
Orchestrates transformation operations across multiple plugins:
class TransformationCoordinator {
constructor(plugins: Plugin[], api: unknown);
async transformFile(
sourceFile: SourceFile,
project: Project,
config?: TransformationConfig,
): Promise<TransformationResult>;
}
Key responsibilities:
TransformRules across loaded plugins)TransformContext with dependency injection)TransformExecutionEngine)Safely executes individual transformation rules:
class TransformExecutionEngine {
async executeRule(
rule: TransformRule,
context: TransformContext,
): Promise<TransformResult>;
}
Key features:
interface TransformContext {
sourceFile: SourceFile;
project: Project;
api?: unknown;
config?: Record<string, unknown>;
filePath?: string;
type?: string;
options?: {
dryRun?: boolean;
autoSave?: boolean;
format?: boolean;
};
}
interface TransformResult {
ruleId: string;
modified: boolean;
message: string;
filePath?: string;
changeCount?: number;
metadata?: Record<string, unknown>;
}
Intelligent caching system for AST and analysis results with automatic invalidation.
The CacheManager provides significant performance improvements by caching expensive operations. It automatically invalidates cache entries when files change, using SHA-256 content hashing for accuracy.
interface CacheConfig {
enabled: boolean;
cacheDir: string;
maxSize: number;
maxAge: number;
version: string;
compression: boolean;
}
class CacheManager {
constructor(fileSystem: FileSystemAdapter, config?: Partial<CacheConfig>);
async initialize(): Promise<void>;
async getAst(filePath: string): Promise<CachedAst | null>;
async setAst(filePath: string, ast: string): Promise<void>;
async getAnalysisResult(filePath: string): Promise<CachedAnalysisResult | null>;
async setAnalysisResult(
filePath: string,
results: unknown[],
dependencies?: string[],
): Promise<void>;
async invalidate(filePath: string, type?: 'ast' | 'analysis'): Promise<void>;
async clear(): Promise<void>;
getStats(): CacheStats;
}
Key features:
clear() and size statistics touch only the manager's own entries, never other caches or files in the same directory<cacheDir>/(ast|analysis)/<name>.<hash>.(ast|analysis).json, independent of the date, so maxAge (24 hours) applies across midnightPerformance characteristics:
| Operation | Performance | Notes |
|---|---|---|
| Cache Hit | 50,657 ops/sec | 1.58x faster than writes |
| Cache Miss | 208,606 ops/sec | Ultra-fast null return |
| File Change Detection | 52,052 ops/sec | Unchanged files |
| Write with Compression | 60,157 ops/sec | 10KB with gzip |
| Statistics | 2.8M ops/sec | Nearly instant |
Usage example:
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
cacheConfig: {
enabled: true,
cacheDir: '.angular-modernizer-cache',
maxSize: 100 * 1024 * 1024, // 100MB
maxAge: 24 * 60 * 60 * 1000, // 24 hours
compression: true,
version: '1.0.0',
},
});
await kernel.initialize();
const cache = kernel.getCacheManager();
if (cache) {
const stats = cache.getStats();
console.log(`Hit rate: ${stats.hitRate.toFixed(1)}%`);
console.log(`Total entries: ${stats.totalEntries}`);
}
For detailed caching documentation, see CACHE.md.
Advanced parallel processing, incremental analysis, and resource management for large-scale Angular projects.
interface KernelConfig {
resourceLimits?: {
maxMemory?: number; // bytes, default: 80% of available
maxWorkers?: number; // default: CPU cores - 1
maxQueueSize?: number; // default: 1000
autoThrottle?: boolean; // default: true
};
enableParallelExecution?: boolean; // default: true
}
Key components:
ParallelExecutor - File-level parallelism with configurable worker pools. Supports both Promise-based execution and worker threads for true multi-threaded execution.
IncrementalAnalyzer - Git-based change detection for efficient re-analysis. Uses content hashing for file modification tracking and dependency graph analysis for transitive invalidation.
ProgressReporter - Real-time progress tracking with ETA calculation. Event-driven architecture for flexible integration.
ResourceManager - Memory monitoring with configurable heap limits and CPU usage tracking. Automatic resource management for large codebases.
WorkerPool - Node.js worker threads for true parallelism. Isolated V8 instances preventing memory interference. Health monitoring with automatic recycling.
Performance characteristics:
| Feature | Performance | Use Case |
|---|---|---|
| Parallel Execution | 1.5-4x speedup | Large codebases (100+ files) |
| Incremental Analysis | >90% cache hit rate | Repeated analysis runs |
| Worker Threads | 5-10x potential speedup | CPU-intensive tasks |
| Progress Reporting | Real-time with ETA | Long-running operations |
| Resource Management | Automatic throttling | Memory-constrained environments |
Usage examples:
// Parallel analysis over all project files and the rules of all plugins
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
plugins: [new SolidPlugin()],
resourceLimits: { maxWorkers: 4 },
});
await kernel.initialize();
const results = await kernel.analyzeParallel({
plugins: ['@angular-modernizer/plugin-solid'],
onProgress: (progress) => {
console.log(`${progress.percentage}% complete, ETA: ${progress.eta}ms`);
},
});
// Incremental analysis against a git base
const incrementalResult = await kernel.analyzeIncremental({
baseBranch: 'main',
includeDependents: true,
});
// Worker thread execution
const workerResults = await kernel.analyzeParallel({
useWorkerThreads: true,
tsConfigPath: './tsconfig.json',
workerScriptPath: getWorkerScriptPath(), // from @angular-modernizer/worker
maxWorkers: 4,
});
For detailed orchestration documentation, see the orchestration source files in src/orchestration/.
Privacy-first AI transformation feedback system for continuous learning and improvement.
The feedback collection system captures transformation outcomes, AI decision-making, and validation results in a privacy-preserving format that enables pattern learning without exposing sensitive code or business logic.
Key features:
.claude-feedback/ and platform root)import { FeedbackCollector } from '@angular-modernizer/core';
const collector = new FeedbackCollector({
projectRoot: '/path/to/project',
platformRoot: '/path/to/tsanalyzer',
storageLocation: 'both', // 'project', 'platform', or 'both' (default)
salt: 'unique-installation-salt',
});
const project = new Project({ tsConfigFilePath: 'tsconfig.json' });
const sessionId = await collector.startSession({ projectRoot: '/path/to/project', project });
const feedback: TransformationFeedback = {
transformationId: 'transform-1',
timestamp: new Date().toISOString(),
rule: {
ruleId: 'standalone-migration-v1',
ruleName: 'Migrate to Standalone Components',
ruleType: 'transform',
category: 'standalone-migration',
},
target: {
filePathHash: 'src/app/user.component.ts', // Will be hashed
fileType: 'component',
linesOfCode: 147,
complexity: 8.5,
},
decision: {
approach: 'Convert to standalone component',
alternatives: ['Keep NgModule', 'Partial migration'],
reasoning: 'File is isolated, no complex dependencies',
confidence: 0.95,
contextUsed: ['file-structure', 'dependencies'],
timeToDecision: 250,
},
execution: {
succeeded: true,
duration: 1200,
},
validation: {
build: { success: true, duration: 8500, errors: [], warnings: [] },
tests: { success: true, duration: 4200, coverage: 92.5 },
},
outcome: {
status: 'success',
quality: 'improved',
metrics: {
codeComplexity: { before: 10, after: 8, delta: -2 },
},
},
metadata: {
source: 'automatic',
collectorVersion: '1.0.0',
reliability: 1.0,
completenessScore: 95,
},
};
try {
await collector.recordTransformation(sessionId, feedback);
} catch (error) {
console.error('Validation failed:', error.message);
}
const outcome = await collector.endSession(sessionId);
console.log(`Success: ${outcome.successful}/${outcome.totalTransformations}`);
API reference:
class FeedbackCollector {
constructor(
config: FeedbackCollectorConfig,
privacyFilter?: PrivacyFilter,
feedbackStorage?: FeedbackStorage,
feedbackValidator?: FeedbackValidator,
);
async startSession(context: TransformContext): Promise<string>;
async recordTransformation(sessionId: string, feedback: TransformationFeedback): Promise<void>;
async endSession(sessionId: string): Promise<SessionOutcome>;
extractLearnings(feedback: TransformationFeedback): Learning[];
}
Anonymizes sensitive data before storage:
import { PrivacyFilter } from '@angular-modernizer/core';
const filter = new PrivacyFilter({
salt: 'unique-installation-salt',
strictMode: true,
});
const anonymized = filter.anonymize(feedback);
// File path hashing (preserves structure)
const hashedPath = filter.anonymizeFilePath('src/app/user/user.component.ts', 'salt');
// Result: "abc123/def456/ghi789/jkl012.component.ts"
// Bucket numeric values (hide exact numbers)
const complexityBucket = filter.bucketValue(8.5, [0, 5, 10, 20, 50]);
// Result: "small" (labels: tiny, small, medium, large, huge)
// Audit privacy before storage (returns a PrivacyAudit, does not throw)
const audit = filter.auditPrivacy(anonymized);
if (!audit.passed) {
console.error('Privacy audit failed:', {
hasCodeSnippets: audit.hasCodeSnippets,
hasRealFilePaths: audit.hasRealFilePaths,
hasProjectNames: audit.hasProjectNames,
hasBusinessLogic: audit.hasBusinessLogic,
});
}
Validates feedback quality with 6 checks:
import { FeedbackValidator } from '@angular-modernizer/core';
const validator = new FeedbackValidator({
minCompletenessScore: 70,
strictMode: false,
maxDuration: 600000,
});
const result = validator.validate(feedback);
if (!result.valid) {
console.error(`Validation failed (score: ${result.score}/100):`);
result.issues.forEach((issue) => {
console.error(` [${issue.severity}] ${issue.field}: ${issue.message}`);
});
}
Validation checks:
Detects anomalous feedback for quarantine:
import { OutlierDetector } from '@angular-modernizer/core';
const detector = new OutlierDetector();
const report = detector.detectOutliers(feedbackArray);
console.log(`Outlier rate: ${report.outlierRate * 100}%`);
report.outliers.forEach((outlier) => {
console.log(`${outlier.feedbackId}: ${outlier.reasons.join(', ')}`);
console.log(`Action: ${outlier.action}`); // 'quarantine' | 'flag' | 'purge'
});
Four outlier detection types:
Target: <3% outlier rate
Dual-location JSON Lines storage:
import { FeedbackStorage } from '@angular-modernizer/core';
const storage = new FeedbackStorage({
projectRoot: '/path/to/project',
platformRoot: '/path/to/tsanalyzer',
storageLocation: 'both',
});
await storage.initSession(sessionId, session);
await storage.appendTransformation(sessionId, feedback);
const loadedSession = await storage.loadSession(sessionId);
Storage paths:
{projectRoot}/.claude-feedback/sessions/{sessionId}.jsonl{platformRoot}/.claude-feedback/sessions/{sessionId}.jsonlThe MCP feedback tools (collect-feedback, review-feedback, suggest-improvements, analyze-parser-performance) always use the project and add a platform root only when ANGULAR_MODERNIZER_PLATFORM_ROOT is set.
Format: JSON Lines (one JSON object per line, append-only)
import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { StandalonePlugin } from '@angular-modernizer/plugin-standalone';
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
plugins: [new StandalonePlugin()],
});
await kernel.initialize();
const project = kernel.getProject();
const plugin = kernel.getPlugin('@angular-modernizer/plugin-standalone');
import { Kernel, InMemoryFileSystemAdapter } from '@angular-modernizer/core';
describe('MyPlugin', () => {
let kernel: Kernel;
beforeEach(async () => {
kernel = new Kernel({
fileSystem: new InMemoryFileSystemAdapter(),
projectOptions: {
useInMemoryFileSystem: true,
compilerOptions: {
target: 99, // ES2022
module: 199, // NodeNext
},
},
plugins: [new MyPlugin()],
});
await kernel.initialize();
});
it('should work with in-memory files', () => {
const project = kernel.getProject();
const sourceFile = project.createSourceFile(
'test.component.ts',
'@Component({}) export class TestComponent {}',
);
expect(sourceFile).toBeDefined();
});
});
import { Plugin, Kernel } from '@angular-modernizer/core';
class MyCustomPlugin implements Plugin {
readonly name = '@my-org/plugin-custom';
readonly version = '1.0.0';
readonly description = 'Custom analysis and transformation rules';
async initialize(kernel: Kernel): Promise<void> {
console.log('Custom plugin initialized');
}
getAnalysisRules(): AnalysisRule[] {
return [new MyAnalysisRule()];
}
getTransformRules(): TransformRule[] {
return [new MyTransformRule()];
}
getValidationRules(): ValidationRule[] {
return [];
}
}
const kernel = new Kernel({
plugins: [new MyCustomPlugin()],
});
The orchestration system automatically chooses between Promise-based and worker thread parallelism based on project complexity:
import { ParallelExecutor } from '@angular-modernizer/core';
const executor = new ParallelExecutor({ maxWorkers: 4 });
const results = await executor.executeParallel(sourceFiles, rules, {
autoSelectMode: true,
});
// Mode selection analyzes:
// - File count (30% weight)
// - Total LOC/size (35% weight)
// - Large file outliers (20% weight)
// - Current memory pressure (15% weight)
//
// Decision thresholds:
// - Score < 35: Promise mode (safe, fast startup)
// - Score 35-50: Promise mode with monitoring and fallback to workers
// - Score 50-75: Worker threads preferred
// - Score >= 75: Worker threads required
Promise mode monitoring and fallback:
const results = await executor.executeParallel(sourceFiles, rules, {
autoSelectMode: true,
enableMonitoring: true,
fallbackToWorkers: true,
workerScriptPath: getWorkerScriptPath(),
tsConfigPath: './tsconfig.json',
});
// If Promise mode hits 85% heap limit:
// -> Aborts execution
// -> Automatically switches to worker threads
// -> Completes analysis safely
Force override (always respected):
const results = await executor.executeParallel(sourceFiles, rules, {
useWorkerThreads: false, // Force Promise mode
});
The thresholds option exists in ParallelOptions but the mode selector currently always uses its default thresholds.
import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { SolidPlugin } from '@angular-modernizer/plugin-solid';
import { getWorkerScriptPath } from '@angular-modernizer/worker';
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
plugins: [new SolidPlugin()],
resourceLimits: { maxWorkers: 4, maxMemory: 512 * 1024 * 1024 },
});
await kernel.initialize();
// Promise mode with progress
const results = await kernel.analyzeParallel({
useWorkerThreads: false,
onProgress: (progress) => {
console.log(`Progress: ${progress.percentage}% (${progress.message})`);
},
});
// Worker threads
const workerResults = await kernel.analyzeParallel({
useWorkerThreads: true,
tsConfigPath: './tsconfig.json',
workerScriptPath: getWorkerScriptPath(),
});
// Incremental
const incrementalResult = await kernel.analyzeIncremental({
baseBranch: 'main',
includeDependents: true,
});
import { Kernel, RealFileSystemAdapter } from '@angular-modernizer/core';
import { StandalonePlugin } from '@angular-modernizer/plugin-standalone';
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
plugins: [new StandalonePlugin()],
});
await kernel.initialize();
const sourceFile = kernel.getProject().getSourceFile('component.ts');
const result = await kernel.transformFile(sourceFile, {
dryRun: false,
autoSave: true,
pluginConfig: {
'@angular-modernizer/plugin-standalone': {
migrationType: 'to-standalone',
},
},
});
console.log(`Success: ${result.success}`);
console.log(`Rules executed: ${result.ruleResults.length}`);
console.log(`Errors: ${result.errors.length}`);
The core package contains no Angular-specific logic:
// Correct: generic infrastructure
class Kernel {
// Manages any TypeScript project
// Works with any plugins
// Uses any file system
}
All configuration is optional with sensible defaults:
new Kernel();
new Kernel({});
new Kernel({ tsConfigPath: './tsconfig.json' });
new Kernel({ plugins: [plugin] });
All I/O operations are async for scalability:
await fileSystem.readFile('file.ts');
await fileSystem.writeFile('file.ts', content);
await kernel.initialize();
await plugin.initialize(kernel);
In-memory file system enables fast, isolated testing:
const kernel = new Kernel({
fileSystem: new InMemoryFileSystemAdapter(),
});
packages/core/
├── src/
│ ├── kernel.ts
│ ├── kernel-factory.ts # createKernel, findTsConfigPath
│ ├── file-system.ts # FileSystemAdapter, Real/InMemory adapters
│ ├── index.ts
│ ├── analysis/ # dependency graph, path aliases, false positives
│ ├── cache/ # CacheManager, MultiCacheFallbackManager
│ ├── config/ # ConfigLoader, config types
│ ├── feedback/ # FeedbackCollector, PrivacyFilter, storage
│ ├── fluent/ # FluentKernel pipeline
│ ├── orchestration/
│ │ ├── parallel-executor.ts
│ │ ├── mode-selector.ts
│ │ ├── incremental-analyzer.ts
│ │ ├── progress-reporter.ts
│ │ ├── promise-monitor.ts
│ │ ├── resource-manager.ts
│ │ ├── worker-pool.ts
│ │ ├── types.ts
│ │ └── index.ts
│ ├── parsers/ # parser strategies, external decorators
│ ├── pattern-analysis/
│ ├── rollback/ # BackupManager, GitIntegration, RollbackManager
│ ├── streaming/ # StreamingKernelWrapper, diffs
│ ├── testing/ # RealFsTestHelper
│ ├── transformation/
│ │ ├── transformation-coordinator.ts
│ │ ├── transform-execution-engine.ts
│ │ ├── transform-rule-executor.ts
│ │ ├── transformation-result-validator.ts
│ │ └── index.ts
│ ├── utils/
│ └── validation/ # build, TypeScript and pre/post-transform validation
├── __tests__/
├── schemas/ # angular-modernizer.schema.json
├── CACHE.md
├── package.json
├── tsconfig.json
├── jest.config.js
└── README.md
.angular-modernizer.jsonpnpm --filter @angular-modernizer/core test
pnpm --filter @angular-modernizer/core test --coverage
pnpm --filter @angular-modernizer/core bench
Test categories:
Worker thread tests run only with ENABLE_WORKER_TESTS=true.
Testing patterns:
describe('Kernel', () => {
describe('initialization', () => {
it('should initialize with minimal config', async () => {
const kernel = new Kernel();
await expect(kernel.initialize()).resolves.not.toThrow();
expect(kernel.isInitialized()).toBe(true);
});
it('should initialize with full config', async () => {
const kernel = new Kernel({
tsConfigPath: './tsconfig.json',
fileSystem: new RealFileSystemAdapter(),
plugins: [new TestPlugin()],
});
await kernel.initialize();
expect(kernel.getAllPlugins()).toHaveLength(1);
});
});
});
InMemoryFileSystemAdapter for testing to reduce memory footprintRealFileSystemAdapter uses async operations for scalabilityinitialize() aborts kernel.initialize() with Failed to initialize plugin "<name>"; plugin names must be uniqueKernel initialization fails:
const kernel = new Kernel({
tsConfigPath: './tsconfig.json', // Ensure this file exists
});
Plugin not found:
const kernel = new Kernel({
plugins: [new MyPlugin()],
});
await kernel.initialize();
console.log(kernel.getAllPlugins());
console.log(kernel.hasPlugin('my-plugin-name'));
File system errors:
const fileSystem = new RealFileSystemAdapter();
try {
await fileSystem.exists('./src');
} catch (error) {
console.error('File system error:', error);
}
If VSCode shows @typescript-eslint/no-unsafe-assignment errors but the build passes:
pnpm --filter @angular-modernizer/core buildnpx eslint packages/core/src/orchestration/promise-monitor.tsThis is a known issue with TypeScript language server type inference in certain contexts involving complex type narrowing. The satisfies operator can help:
private collectMetrics(): RuntimeMetrics {
return {
// ... properties
} satisfies RuntimeMetrics;
}
If you see FATAL ERROR: Reached heap limit Allocation failed with 500+ files:
const results = await kernel.analyzeParallel({
useWorkerThreads: true,
tsConfigPath: './tsconfig.json',
workerScriptPath: getWorkerScriptPath(),
maxWorkers: 4,
minFilesForWorkers: 200,
});
Worker threads use isolated heaps and avoid the V8 heap fragmentation that causes crashes in Promise-based parallelism.
If worker threads fail with "Cannot find module" errors, build all packages:
pnpm run build
# Or build worker specifically
pnpm --filter @angular-modernizer/worker build
Promise-based parallelism does not require building and works immediately.
The streaming path (deprecated on the MCP side, where tools use native progress and cancellation) is exported from the package root:
import {
StreamingKernelWrapper,
generateUnifiedDiff,
generateDiffSummary,
detectSyntaxErrors,
type FileDiff,
type DiffHunk,
type LineChange,
type SemanticAnnotation,
type AngularContext,
type SyntaxType,
type StreamingOptions,
type StreamingProgressEvent,
type StreamingTransformResult,
} from '@angular-modernizer/core';
src/orchestration/) - Orchestration and parallel processingMIT License - See LICENSE file for details
Core infrastructure of the Angular Modernizer: the Kernel with its plugin lifecycle and ts-morph project, file system adapters, configuration loading, transformation, validation, rollback, caching, orchestration, streaming, the fluent pipeline API and feedback collection. It holds no Angular-specific rules; those come from plugins.
Main entry points:
.angular-modernizer.jsonImport everything from
@angular-modernizer/core; submodule paths are not public.