66 * found in the LICENSE file at https://angular.dev/license
77 */
88
9- import { existsSync } from 'fs' ;
10- import { stat } from 'fs/promises' ;
119import { dirname , join , relative } from 'path' ;
1210import { z } from 'zod' ;
13- import { execAsync } from './process-executor ' ;
11+ import { CommandError , Host , LocalWorkspaceHost } from '../host ' ;
1412import { McpToolDeclaration , declareTool } from './tool-registry' ;
1513
1614interface Transformation {
@@ -102,10 +100,10 @@ function createToolOutput(structuredContent: ModernizeOutput) {
102100 } ;
103101}
104102
105- function findAngularJsonDir ( startDir : string ) : string | null {
103+ function findAngularJsonDir ( startDir : string , host : Host ) : string | null {
106104 let currentDir = startDir ;
107105 while ( true ) {
108- if ( existsSync ( join ( currentDir , 'angular.json' ) ) ) {
106+ if ( host . existsSync ( join ( currentDir , 'angular.json' ) ) ) {
109107 return currentDir ;
110108 }
111109 const parentDir = dirname ( currentDir ) ;
@@ -116,7 +114,7 @@ function findAngularJsonDir(startDir: string): string | null {
116114 }
117115}
118116
119- export async function runModernization ( input : ModernizeInput ) {
117+ export async function runModernization ( input : ModernizeInput , host : Host ) {
120118 const transformationNames = input . transformations ?? [ ] ;
121119 const directories = input . directories ?? [ ] ;
122120
@@ -138,9 +136,9 @@ export async function runModernization(input: ModernizeInput) {
138136 }
139137
140138 const firstDir = directories [ 0 ] ;
141- const executionDir = ( await stat ( firstDir ) ) . isDirectory ( ) ? firstDir : dirname ( firstDir ) ;
139+ const executionDir = ( await host . stat ( firstDir ) ) . isDirectory ( ) ? firstDir : dirname ( firstDir ) ;
142140
143- const angularProjectRoot = findAngularJsonDir ( executionDir ) ;
141+ const angularProjectRoot = findAngularJsonDir ( executionDir , host ) ;
144142 if ( ! angularProjectRoot ) {
145143 return createToolOutput ( {
146144 instructions : [ 'Could not find an angular.json file in the current or parent directories.' ] ,
@@ -164,9 +162,12 @@ export async function runModernization(input: ModernizeInput) {
164162 // Simple case, run the command.
165163 for ( const dir of directories ) {
166164 const relativePath = relative ( angularProjectRoot , dir ) || '.' ;
167- const command = `ng generate @angular/core:${ transformation . name } --path ${ relativePath } ` ;
165+ const command = 'ng' ;
166+ const args = [ 'generate' , `@angular/core:${ transformation . name } ` , '--path' , relativePath ] ;
168167 try {
169- const { stdout, stderr } = await execAsync ( command , { cwd : angularProjectRoot } ) ;
168+ const { stdout, stderr } = await host . runCommand ( command , args , {
169+ cwd : angularProjectRoot ,
170+ } ) ;
170171 if ( stdout ) {
171172 stdoutMessages . push ( stdout ) ;
172173 }
@@ -177,6 +178,14 @@ export async function runModernization(input: ModernizeInput) {
177178 `Migration ${ transformation . name } on directory ${ relativePath } completed successfully.` ,
178179 ) ;
179180 } catch ( e ) {
181+ if ( e instanceof CommandError ) {
182+ if ( e . stdout ) {
183+ stdoutMessages . push ( e . stdout ) ;
184+ }
185+ if ( e . stderr ) {
186+ stderrMessages . push ( e . stderr ) ;
187+ }
188+ }
180189 stderrMessages . push ( ( e as Error ) . message ) ;
181190 instructions . push (
182191 `Migration ${ transformation . name } on directory ${ relativePath } failed.` ,
@@ -228,5 +237,5 @@ ${TRANSFORMATIONS.map((t) => ` * ${t.name}: ${t.description}`).join('\n')}
228237 outputSchema : modernizeOutputSchema . shape ,
229238 isLocalOnly : true ,
230239 isReadOnly : false ,
231- factory : ( ) => runModernization ,
240+ factory : ( ) => ( input ) => runModernization ( input , LocalWorkspaceHost ) ,
232241} ) ;
0 commit comments