|
|
|
@ -1,4 +1,14 @@ |
|
|
|
import { Rule, SchematicsException, Tree, apply, url, mergeWith, MergeStrategy, filter, chain } from '@angular-devkit/schematics'; |
|
|
|
import { |
|
|
|
Rule, |
|
|
|
SchematicsException, |
|
|
|
Tree, |
|
|
|
apply, |
|
|
|
url, |
|
|
|
mergeWith, |
|
|
|
MergeStrategy, |
|
|
|
filter, |
|
|
|
chain, |
|
|
|
} from '@angular-devkit/schematics'; |
|
|
|
import { join, normalize } from '@angular-devkit/core'; |
|
|
|
import { AiConfigSchema, AiTool } from './model'; |
|
|
|
import { getWorkspace } from '../../utils'; |
|
|
|
@ -10,21 +20,21 @@ export default function (options: AiConfigSchema): Rule { |
|
|
|
console.log(''); |
|
|
|
console.log('💡 Usage examples:'); |
|
|
|
console.log(' ng g @abp/ng.schematics:ai-config --tool=claude,cursor'); |
|
|
|
console.log(' ng g @abp/ng.schematics:ai-config --tool="claude, cursor"'); |
|
|
|
console.log(' ng g @abp/ng.schematics:ai-config --tool=gemini --tool=cursor'); |
|
|
|
console.log(' ng g @abp/ng.schematics:ai-config --tool=gemini --target-project=my-app'); |
|
|
|
console.log(''); |
|
|
|
console.log('Available tools: claude, copilot, cursor, gemini, junie, windsurf'); |
|
|
|
return tree; |
|
|
|
} |
|
|
|
|
|
|
|
const tools = options.tool |
|
|
|
.split(/[\s,]+/) |
|
|
|
.filter(t => t) as AiTool[]; |
|
|
|
const tools = options.tool.split(/[\s,]+/).filter(t => t) as AiTool[]; |
|
|
|
|
|
|
|
const validTools: AiTool[] = ['claude', 'copilot', 'cursor', 'gemini', 'junie', 'windsurf']; |
|
|
|
const invalidTools = tools.filter(tool => !validTools.includes(tool)); |
|
|
|
if (invalidTools.length > 0) { |
|
|
|
throw new SchematicsException( |
|
|
|
`Invalid AI tool(s): ${invalidTools.join(', ')}. Valid options are: ${validTools.join(', ')}` |
|
|
|
`Invalid AI tool(s): ${invalidTools.join(', ')}. Valid options are: ${validTools.join(', ')}`, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
@ -40,9 +50,7 @@ export default function (options: AiConfigSchema): Rule { |
|
|
|
const trimmedTargetProject = options.targetProject.trim(); |
|
|
|
const project = workspace.projects.get(trimmedTargetProject); |
|
|
|
if (!project) { |
|
|
|
throw new SchematicsException( |
|
|
|
`Project "${trimmedTargetProject}" not found in workspace.` |
|
|
|
); |
|
|
|
throw new SchematicsException(`Project "${trimmedTargetProject}" not found in workspace.`); |
|
|
|
} |
|
|
|
targetPath = normalize(project.root); |
|
|
|
} |
|
|
|
@ -51,24 +59,25 @@ export default function (options: AiConfigSchema): Rule { |
|
|
|
console.log(`📁 Target path: ${targetPath}`); |
|
|
|
console.log(`🤖 Selected tools: ${tools.join(', ')}`); |
|
|
|
|
|
|
|
const rules: Rule[] = tools |
|
|
|
.map(tool => generateConfigForTool(tool, targetPath, options.overwrite || false)); |
|
|
|
const rules: Rule[] = tools.map(tool => |
|
|
|
generateConfigForTool(tool, targetPath, options.overwrite || false), |
|
|
|
); |
|
|
|
|
|
|
|
return chain([ |
|
|
|
...rules, |
|
|
|
(tree: Tree) => { |
|
|
|
console.log('✅ AI configuration files generated successfully!'); |
|
|
|
console.log('\n📝 Generated files:'); |
|
|
|
|
|
|
|
|
|
|
|
tools.forEach(tool => { |
|
|
|
const configPath = getConfigPath(tool, targetPath); |
|
|
|
console.log(` - ${configPath}`); |
|
|
|
}); |
|
|
|
|
|
|
|
console.log('\n💡 Tip: Restart your IDE or AI tool to apply the new configurations.'); |
|
|
|
|
|
|
|
|
|
|
|
return tree; |
|
|
|
} |
|
|
|
}, |
|
|
|
]); |
|
|
|
}; |
|
|
|
} |
|
|
|
@ -76,7 +85,7 @@ export default function (options: AiConfigSchema): Rule { |
|
|
|
function generateConfigForTool(tool: AiTool, targetPath: string, overwrite: boolean): Rule { |
|
|
|
return (tree: Tree) => { |
|
|
|
const configPath = getConfigPath(tool, targetPath); |
|
|
|
|
|
|
|
|
|
|
|
if (tree.exists(configPath) && !overwrite) { |
|
|
|
console.log(`⚠️ Configuration file already exists: ${configPath}`); |
|
|
|
console.log(` Use --overwrite flag to replace existing files.`); |
|
|
|
@ -87,7 +96,7 @@ function generateConfigForTool(tool: AiTool, targetPath: string, overwrite: bool |
|
|
|
const source = apply(url(sourceDir), [ |
|
|
|
filter(path => { |
|
|
|
return !path.endsWith('.DS_Store'); |
|
|
|
}) |
|
|
|
}), |
|
|
|
]); |
|
|
|
|
|
|
|
return mergeWith(source, overwrite ? MergeStrategy.Overwrite : MergeStrategy.Default); |
|
|
|
@ -101,7 +110,7 @@ function getConfigPath(tool: AiTool, basePath: string): string { |
|
|
|
cursor: '.cursor/rules/cursor.mdc', |
|
|
|
gemini: '.gemini/GEMINI.md', |
|
|
|
junie: '.junie/guidelines.md', |
|
|
|
windsurf: '.windsurf/rules/guidelines.md' |
|
|
|
windsurf: '.windsurf/rules/guidelines.md', |
|
|
|
}; |
|
|
|
|
|
|
|
const configFile = configFiles[tool]; |
|
|
|
|