@itz4blitz/agentful 0.2.1 → 0.3.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.
@@ -1,778 +0,0 @@
1
- /**
2
- * Smart Agent Generation System
3
- *
4
- * Analyzes codebase and generates contextually-aware agents
5
- * that understand the project's tech stack, patterns, and conventions.
6
- */
7
-
8
- import fs from 'fs/promises';
9
- import path from 'path';
10
- import { fileURLToPath } from 'url';
11
- import TemplateEngine from './template-engine.js';
12
-
13
- const __filename = fileURLToPath(import.meta.url);
14
- const __dirname = path.dirname(__filename);
15
-
16
- /**
17
- * Default core agent types registry
18
- * Users can extend this by passing custom agent types to the constructor
19
- */
20
- const DEFAULT_CORE_AGENT_TYPES = ['backend', 'frontend', 'tester', 'reviewer', 'fixer'];
21
-
22
- /**
23
- * Default agent patterns configuration
24
- * Defines how each agent type should extract patterns from the codebase
25
- */
26
- const DEFAULT_AGENT_PATTERNS = {
27
- backend: {
28
- directories: ['src/repositories', 'src/services', 'src/controllers', 'src/routes', 'api'],
29
- keywords: ['repository', 'service', 'controller', 'route', 'handler'],
30
- },
31
- frontend: {
32
- directories: ['src/components', 'src/pages', 'src/app', 'components', 'pages'],
33
- keywords: ['component', 'hook', 'page', 'view'],
34
- },
35
- tester: {
36
- directories: ['tests', 'test', '__tests__', '__tests__', 'spec'],
37
- keywords: ['describe', 'test', 'it', 'expect', 'mock'],
38
- },
39
- reviewer: {
40
- directories: ['src'],
41
- keywords: ['export', 'function', 'class', 'interface'],
42
- },
43
- fixer: {
44
- directories: ['src'],
45
- keywords: ['error', 'bug', 'fix', 'throw'],
46
- },
47
- };
48
-
49
- class AgentGenerator {
50
- /**
51
- * @param {string} projectPath - Path to the project
52
- * @param {object} analysis - Project analysis results
53
- * @param {object} options - Configuration options
54
- * @param {string[]} options.customAgentTypes - Additional core agent types to generate
55
- * @param {object} options.customAgentPatterns - Pattern configurations for custom agent types
56
- */
57
- constructor(projectPath, analysis, options = {}) {
58
- this.projectPath = projectPath;
59
- this.analysis = analysis;
60
- this.templatesDir = path.join(__dirname, '../templates/agents');
61
- this.agentsDir = path.join(projectPath, '.claude/agents/auto-generated');
62
-
63
- // Extensible agent type registry
64
- this.coreAgentTypes = [...DEFAULT_CORE_AGENT_TYPES];
65
- this.agentPatterns = { ...DEFAULT_AGENT_PATTERNS };
66
-
67
- // Apply custom agent types if provided
68
- if (options.customAgentTypes && Array.isArray(options.customAgentTypes)) {
69
- this.coreAgentTypes.push(...options.customAgentTypes);
70
- }
71
-
72
- // Apply custom agent patterns if provided
73
- if (options.customAgentPatterns && typeof options.customAgentPatterns === 'object') {
74
- Object.assign(this.agentPatterns, options.customAgentPatterns);
75
- }
76
- }
77
-
78
- /**
79
- * Register a custom agent type at runtime
80
- * @param {string} type - Agent type name
81
- * @param {object} pattern - Pattern configuration for the agent type
82
- * @param {string[]} pattern.directories - Directories to scan for this agent type
83
- * @param {string[]} pattern.keywords - Keywords to look for in code
84
- */
85
- registerAgentType(type, pattern) {
86
- if (!this.coreAgentTypes.includes(type)) {
87
- this.coreAgentTypes.push(type);
88
- }
89
-
90
- if (pattern) {
91
- this.agentPatterns[type] = pattern;
92
- }
93
- }
94
-
95
- /**
96
- * Get all registered core agent types
97
- * @returns {string[]} List of core agent types
98
- */
99
- getCoreAgentTypes() {
100
- return [...this.coreAgentTypes];
101
- }
102
-
103
- /**
104
- * Get pattern configuration for a specific agent type
105
- * @param {string} type - Agent type name
106
- * @returns {object|null} Pattern configuration or null if not found
107
- */
108
- getAgentPattern(type) {
109
- return this.agentPatterns[type] || null;
110
- }
111
-
112
- /**
113
- * Load custom agent types from a configuration file
114
- * @param {string} configPath - Path to the configuration file (JSON)
115
- * @returns {Promise<void>}
116
- */
117
- async loadCustomAgentTypesFromConfig(configPath) {
118
- try {
119
- const content = await fs.readFile(configPath, 'utf-8');
120
- const config = JSON.parse(content);
121
-
122
- if (config.customAgentTypes && Array.isArray(config.customAgentTypes)) {
123
- for (const agentConfig of config.customAgentTypes) {
124
- if (agentConfig.type && agentConfig.pattern) {
125
- this.registerAgentType(agentConfig.type, agentConfig.pattern);
126
- }
127
- }
128
- }
129
-
130
- console.log(`✅ Loaded custom agent types from ${configPath}`);
131
- } catch (error) {
132
- console.warn(`⚠️ Could not load custom agent types from ${configPath}: ${error.message}`);
133
- }
134
- }
135
-
136
- /**
137
- * Main entry point - generates all agents based on analysis
138
- */
139
- async generateAgents() {
140
- console.log('🤖 Generating agents...');
141
-
142
- // Ensure agents directory exists
143
- await fs.mkdir(this.agentsDir, { recursive: true });
144
-
145
- // Generate core agents (always)
146
- const coreAgents = await this.generateCoreAgents();
147
-
148
- // Generate domain agents (conditional based on detected domains)
149
- const domainAgents = await this.generateDomainAgents();
150
-
151
- // Generate tech-specific agents (conditional based on tech stack)
152
- const techAgents = await this.generateTechAgents();
153
-
154
- // Update architecture.json with generated agent info
155
- await this.updateArchitectureConfig({
156
- core: coreAgents,
157
- domains: domainAgents,
158
- tech: techAgents,
159
- });
160
-
161
- console.log(`✅ Generated ${coreAgents.length + domainAgents.length + techAgents.length} agents`);
162
-
163
- return {
164
- core: coreAgents,
165
- domains: domainAgents,
166
- tech: techAgents,
167
- };
168
- }
169
-
170
- /**
171
- * Generate core agents (always needed)
172
- */
173
- async generateCoreAgents() {
174
- const agents = [];
175
-
176
- for (const type of this.coreAgentTypes) {
177
- const agentPath = path.join(this.agentsDir, `${type}.md`);
178
- const template = await this.loadTemplate(`${type}-agent.template.md`);
179
-
180
- if (!template) {
181
- console.warn(`⚠️ No template found for ${type}, skipping`);
182
- continue;
183
- }
184
-
185
- // Extract patterns from actual code
186
- const patterns = await this.extractPatterns(type);
187
-
188
- // Interpolate template with project-specific data
189
- const content = TemplateEngine.render(template, {
190
- language: this.analysis.primaryLanguage || 'javascript',
191
- framework: this.analysis.primaryFramework || 'custom',
192
- patterns: patterns.code,
193
- conventions: patterns.conventions,
194
- samples: patterns.samples,
195
- generated_at: new Date().toISOString(),
196
- });
197
-
198
- await fs.writeFile(agentPath, content);
199
- agents.push({ type, path: agentPath });
200
- }
201
-
202
- return agents;
203
- }
204
-
205
- /**
206
- * Generate domain-specific agents (auth, billing, etc.)
207
- */
208
- async generateDomainAgents() {
209
- const domains = this.analysis.domains || [];
210
- const agents = [];
211
-
212
- for (const domain of domains) {
213
- const agentPath = path.join(this.agentsDir, `${domain.name}-agent.md`);
214
-
215
- // Extract domain-specific code samples
216
- const samples = await this.extractDomainSamples(domain);
217
-
218
- // Generate domain context
219
- const domainContext = {
220
- domain: domain.name,
221
- features: domain.features || [],
222
- language: this.analysis.primaryLanguage || 'javascript',
223
- framework: this.analysis.primaryFramework || 'custom',
224
- confidence: domain.confidence || 0.5,
225
- codeSamples: samples.code,
226
- patterns: samples.patterns,
227
- endpoints: samples.endpoints,
228
- models: samples.models,
229
- generated_at: new Date().toISOString(),
230
- };
231
-
232
- const template = await this.loadTemplate('domain-agent.template.md');
233
- const content = TemplateEngine.render(template, domainContext);
234
-
235
- await fs.writeFile(agentPath, content);
236
- agents.push({ type: domain.name, path: agentPath });
237
- }
238
-
239
- return agents;
240
- }
241
-
242
- /**
243
- * Generate tech-specific agents (Next.js, Prisma, etc.)
244
- */
245
- async generateTechAgents() {
246
- const techStack = this.analysis.techStack || {};
247
- const agents = [];
248
-
249
- // Framework-specific agents
250
- if (techStack.framework) {
251
- const framework = techStack.framework.toLowerCase();
252
- if (['nextjs', 'nuxt', 'remix'].includes(framework)) {
253
- const agent = await this.generateFrameworkAgent(framework);
254
- if (agent) agents.push(agent);
255
- }
256
- }
257
-
258
- // ORM-specific agents
259
- if (techStack.orm) {
260
- const orm = techStack.orm.toLowerCase();
261
- if (['prisma', 'drizzle', 'typeorm', 'mongoose'].includes(orm)) {
262
- const agent = await this.generateORMAgent(orm);
263
- if (agent) agents.push(agent);
264
- }
265
- }
266
-
267
- // Database-specific agents
268
- if (techStack.database) {
269
- const db = techStack.database.toLowerCase();
270
- if (['postgresql', 'mongodb', 'mysql', 'sqlite'].includes(db)) {
271
- const agent = await this.generateDatabaseAgent(db);
272
- if (agent) agents.push(agent);
273
- }
274
- }
275
-
276
- return agents;
277
- }
278
-
279
- /**
280
- * Generate framework-specific agent
281
- */
282
- async generateFrameworkAgent(framework) {
283
- const agentPath = path.join(this.agentsDir, `${framework}-agent.md`);
284
- const template = await this.loadTemplate('tech-agent.template.md');
285
-
286
- if (!template) return null;
287
-
288
- const samples = await this.extractFrameworkSamples(framework);
289
-
290
- const content = TemplateEngine.render(template, {
291
- tech: framework,
292
- techType: 'framework',
293
- language: this.analysis.primaryLanguage || 'javascript',
294
- framework: framework,
295
- patterns: samples.patterns,
296
- conventions: samples.conventions,
297
- samples: samples.code,
298
- generated_at: new Date().toISOString(),
299
- });
300
-
301
- await fs.writeFile(agentPath, content);
302
- return { type: framework, path: agentPath };
303
- }
304
-
305
- /**
306
- * Generate ORM-specific agent
307
- */
308
- async generateORMAgent(orm) {
309
- const agentPath = path.join(this.agentsDir, `${orm}-agent.md`);
310
- const template = await this.loadTemplate('tech-agent.template.md');
311
-
312
- if (!template) return null;
313
-
314
- const samples = await this.extractORMSamples(orm);
315
-
316
- const content = TemplateEngine.render(template, {
317
- tech: orm,
318
- techType: 'orm',
319
- language: this.analysis.primaryLanguage || 'javascript',
320
- framework: this.analysis.primaryFramework || 'custom',
321
- patterns: samples.patterns,
322
- conventions: samples.conventions,
323
- samples: samples.code,
324
- generated_at: new Date().toISOString(),
325
- });
326
-
327
- await fs.writeFile(agentPath, content);
328
- return { type: orm, path: agentPath };
329
- }
330
-
331
- /**
332
- * Generate database-specific agent
333
- */
334
- async generateDatabaseAgent(database) {
335
- const agentPath = path.join(this.agentsDir, `${database}-agent.md`);
336
- const template = await this.loadTemplate('tech-agent.template.md');
337
-
338
- if (!template) return null;
339
-
340
- const samples = await this.extractDatabaseSamples(database);
341
-
342
- const content = TemplateEngine.render(template, {
343
- tech: database,
344
- techType: 'database',
345
- language: this.analysis.primaryLanguage || 'javascript',
346
- framework: this.analysis.primaryFramework || 'custom',
347
- patterns: samples.patterns,
348
- conventions: samples.conventions,
349
- samples: samples.code,
350
- generated_at: new Date().toISOString(),
351
- });
352
-
353
- await fs.writeFile(agentPath, content);
354
- return { type: database, path: agentPath };
355
- }
356
-
357
- /**
358
- * Extract code patterns for a specific agent type
359
- */
360
- async extractPatterns(agentType) {
361
- const patterns = {
362
- code: [],
363
- conventions: [],
364
- samples: [],
365
- };
366
-
367
- // Get pattern configuration from registry
368
- const config = this.agentPatterns[agentType];
369
- if (!config) {
370
- console.warn(`⚠️ No pattern configuration found for agent type: ${agentType}`);
371
- return patterns;
372
- }
373
-
374
- // Scan directories for patterns
375
- for (const dir of config.directories) {
376
- const dirPath = path.join(this.projectPath, dir);
377
- try {
378
- const files = await this.scanDirectory(dirPath, 10); // Sample up to 10 files
379
-
380
- for (const file of files) {
381
- const content = await fs.readFile(file, 'utf-8');
382
- const relativePath = path.relative(this.projectPath, file);
383
-
384
- // Extract code samples
385
- if (content.length > 0 && content.length < 2000) {
386
- patterns.samples.push({
387
- path: relativePath,
388
- content: content,
389
- });
390
- }
391
-
392
- // Identify patterns
393
- for (const keyword of config.keywords) {
394
- if (content.toLowerCase().includes(keyword)) {
395
- patterns.code.push({
396
- keyword,
397
- context: this.extractContext(content, keyword),
398
- });
399
- }
400
- }
401
- }
402
- } catch (error) {
403
- // Directory doesn't exist, skip
404
- }
405
- }
406
-
407
- // Detect naming conventions
408
- patterns.conventions = await this.detectConventions(agentType);
409
-
410
- return patterns;
411
- }
412
-
413
- /**
414
- * Extract domain-specific code samples
415
- */
416
- async extractDomainSamples(domain) {
417
- const samples = {
418
- code: [],
419
- patterns: [],
420
- endpoints: [],
421
- models: [],
422
- };
423
-
424
- // Find domain-specific files
425
- const domainPatterns = {
426
- 'auth-agent': ['auth', 'user', 'login', 'register', 'session', 'token'],
427
- 'billing-agent': ['billing', 'payment', 'subscription', 'invoice', 'stripe'],
428
- 'content-agent': ['content', 'post', 'article', 'blog', 'page'],
429
- 'notification-agent': ['notification', 'email', 'sms', 'push'],
430
- };
431
-
432
- const keywords = domainPatterns[domain.name] || [domain.name];
433
-
434
- // Scan for domain files
435
- const files = await this.findFilesByKeywords(keywords, 5);
436
-
437
- for (const file of files) {
438
- const content = await fs.readFile(file, 'utf-8');
439
- const relativePath = path.relative(this.projectPath, file);
440
-
441
- samples.code.push({
442
- path: relativePath,
443
- content: content.substring(0, 1500), // Limit size
444
- });
445
-
446
- // Extract API endpoints
447
- if (content.includes('router.') || content.includes('app.') || content.includes('@Get')) {
448
- samples.endpoints.push(...this.extractEndpoints(content, relativePath));
449
- }
450
-
451
- // Extract data models
452
- if (content.includes('model') || content.includes('schema') || content.includes('interface')) {
453
- samples.models.push(...this.extractModels(content, relativePath));
454
- }
455
- }
456
-
457
- return samples;
458
- }
459
-
460
- /**
461
- * Extract framework-specific samples
462
- */
463
- async extractFrameworkSamples(framework) {
464
- const samples = {
465
- code: [],
466
- patterns: [],
467
- conventions: [],
468
- };
469
-
470
- const frameworkPatterns = {
471
- nextjs: ['app/', 'pages/', 'middleware.ts', 'next.config'],
472
- nuxt: ['pages/', 'components/', 'nuxt.config'],
473
- remix: ['routes/', 'app/routes/', 'loader', 'action'],
474
- };
475
-
476
- const patterns = frameworkPatterns[framework] || [];
477
-
478
- for (const pattern of patterns) {
479
- const files = await this.findFilesByPattern(pattern, 3);
480
-
481
- for (const file of files) {
482
- const content = await fs.readFile(file, 'utf-8');
483
- const relativePath = path.relative(this.projectPath, file);
484
-
485
- samples.code.push({
486
- path: relativePath,
487
- content: content.substring(0, 1000),
488
- });
489
- }
490
- }
491
-
492
- return samples;
493
- }
494
-
495
- /**
496
- * Extract ORM-specific samples
497
- */
498
- async extractORMSamples(orm) {
499
- const samples = {
500
- code: [],
501
- patterns: [],
502
- conventions: [],
503
- };
504
-
505
- const ormFiles = {
506
- prisma: ['schema.prisma', 'client.ts'],
507
- drizzle: ['schema.ts', 'db.ts'],
508
- typeorm: ['entity.ts', 'repository.ts'],
509
- mongoose: ['model.ts', 'schema.ts'],
510
- };
511
-
512
- const files = ormFiles[orm] || [];
513
-
514
- for (const file of files) {
515
- const foundFiles = await this.findFilesByPattern(file, 2);
516
-
517
- for (const foundFile of foundFiles) {
518
- const content = await fs.readFile(foundFile, 'utf-8');
519
- const relativePath = path.relative(this.projectPath, foundFile);
520
-
521
- samples.code.push({
522
- path: relativePath,
523
- content: content.substring(0, 1000),
524
- });
525
- }
526
- }
527
-
528
- return samples;
529
- }
530
-
531
- /**
532
- * Extract database-specific samples
533
- */
534
- async extractDatabaseSamples(database) {
535
- const samples = {
536
- code: [],
537
- patterns: [],
538
- conventions: [],
539
- };
540
-
541
- // Look for migration files, SQL files, etc.
542
- const patterns = ['migrations/', '*.sql', 'schema.sql', 'seeds/'];
543
-
544
- for (const pattern of patterns) {
545
- const files = await this.findFilesByPattern(pattern, 3);
546
-
547
- for (const file of files) {
548
- const content = await fs.readFile(file, 'utf-8');
549
- const relativePath = path.relative(this.projectPath, file);
550
-
551
- samples.code.push({
552
- path: relativePath,
553
- content: content.substring(0, 1000),
554
- });
555
- }
556
- }
557
-
558
- return samples;
559
- }
560
-
561
- /**
562
- * Scan directory for files
563
- */
564
- async scanDirectory(dirPath, maxFiles = 10) {
565
- const files = [];
566
-
567
- try {
568
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
569
-
570
- for (const entry of entries) {
571
- if (files.length >= maxFiles) break;
572
-
573
- const fullPath = path.join(dirPath, entry.name);
574
-
575
- if (entry.isDirectory()) {
576
- const subFiles = await this.scanDirectory(fullPath, maxFiles - files.length);
577
- files.push(...subFiles);
578
- } else if (entry.isFile() && this.isSourceFile(entry.name)) {
579
- files.push(fullPath);
580
- }
581
- }
582
- } catch (error) {
583
- // Directory doesn't exist or can't be read
584
- }
585
-
586
- return files;
587
- }
588
-
589
- /**
590
- * Find files by keywords in name
591
- */
592
- async findFilesByKeywords(keywords, maxFiles = 5) {
593
- const allFiles = [];
594
-
595
- for (const keyword of keywords) {
596
- const files = await this.findFilesByPattern(keyword, maxFiles);
597
- allFiles.push(...files);
598
- }
599
-
600
- return allFiles.slice(0, maxFiles);
601
- }
602
-
603
- /**
604
- * Find files by pattern
605
- */
606
- async findFilesByPattern(pattern, maxFiles = 5) {
607
- const files = [];
608
-
609
- const scanDir = async (dirPath) => {
610
- try {
611
- const entries = await fs.readdir(dirPath, { withFileTypes: true });
612
-
613
- for (const entry of entries) {
614
- if (files.length >= maxFiles) return;
615
-
616
- const fullPath = path.join(dirPath, entry.name);
617
-
618
- if (entry.isDirectory()) {
619
- // Skip node_modules and similar
620
- if (!['node_modules', '.git', 'dist', 'build'].includes(entry.name)) {
621
- await scanDir(fullPath);
622
- }
623
- } else if (entry.isFile()) {
624
- if (entry.name.toLowerCase().includes(pattern.toLowerCase()) ||
625
- fullPath.toLowerCase().includes(pattern.toLowerCase())) {
626
- files.push(fullPath);
627
- }
628
- }
629
- }
630
- } catch (error) {
631
- // Can't read directory
632
- }
633
- };
634
-
635
- await scanDir(this.projectPath);
636
- return files;
637
- }
638
-
639
- /**
640
- * Check if file is a source file
641
- */
642
- isSourceFile(filename) {
643
- const extensions = ['.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.rs'];
644
- return extensions.some(ext => filename.endsWith(ext));
645
- }
646
-
647
- /**
648
- * Extract context around a keyword
649
- */
650
- extractContext(content, keyword) {
651
- const lines = content.split('\n');
652
- const context = [];
653
-
654
- for (let i = 0; i < lines.length; i++) {
655
- if (lines[i].toLowerCase().includes(keyword.toLowerCase())) {
656
- const start = Math.max(0, i - 2);
657
- const end = Math.min(lines.length, i + 3);
658
- context.push(lines.slice(start, end).join('\n'));
659
- }
660
- }
661
-
662
- return context.slice(0, 3); // Max 3 contexts
663
- }
664
-
665
- /**
666
- * Detect naming conventions
667
- */
668
- async detectConventions(agentType) {
669
- const conventions = [];
670
-
671
- // Sample some files to detect conventions
672
- const files = await this.findFilesByPattern('.ts', 5);
673
-
674
- for (const file of files) {
675
- const content = await fs.readFile(file, 'utf-8');
676
-
677
- // Detect import style
678
- if (content.includes('@/')) {
679
- conventions.push('Uses @ alias for imports');
680
- }
681
-
682
- // Detect naming patterns
683
- if (content.match(/class \w+/)) {
684
- conventions.push('Uses class-based components');
685
- }
686
-
687
- if (content.match(/export (const|function) \w+/)) {
688
- conventions.push('Uses functional exports');
689
- }
690
- }
691
-
692
- return [...new Set(conventions)]; // Deduplicate
693
- }
694
-
695
- /**
696
- * Extract API endpoints from code
697
- */
698
- extractEndpoints(content, filePath) {
699
- const endpoints = [];
700
- const lines = content.split('\n');
701
-
702
- for (const line of lines) {
703
- if (line.includes('router.') || line.includes('app.')) {
704
- endpoints.push({
705
- file: filePath,
706
- code: line.trim(),
707
- });
708
- }
709
- }
710
-
711
- return endpoints.slice(0, 5);
712
- }
713
-
714
- /**
715
- * Extract data models from code
716
- */
717
- extractModels(content, filePath) {
718
- const models = [];
719
- const lines = content.split('\n');
720
-
721
- for (const line of lines) {
722
- if (line.includes('model ') || line.includes('schema ') || line.includes('interface ')) {
723
- models.push({
724
- file: filePath,
725
- code: line.trim(),
726
- });
727
- }
728
- }
729
-
730
- return models.slice(0, 5);
731
- }
732
-
733
- /**
734
- * Load template file
735
- */
736
- async loadTemplate(templateName) {
737
- const templatePath = path.join(this.templatesDir, templateName);
738
-
739
- try {
740
- return await fs.readFile(templatePath, 'utf-8');
741
- } catch (error) {
742
- console.warn(`Template not found: ${templateName}`);
743
- return null;
744
- }
745
- }
746
-
747
- /**
748
- * Update architecture.json with agent info
749
- */
750
- async updateArchitectureConfig(agents) {
751
- const configPath = path.join(this.projectPath, '.agentful/architecture.json');
752
-
753
- let config = {};
754
-
755
- try {
756
- const content = await fs.readFile(configPath, 'utf-8');
757
- config = JSON.parse(content);
758
- } catch (error) {
759
- // Config doesn't exist yet
760
- }
761
-
762
- config.agents = {
763
- generated: {
764
- core: agents.core.map(a => a.type),
765
- domains: agents.domains.map(a => a.type),
766
- tech: agents.tech.map(a => a.type),
767
- },
768
- generatedAt: new Date().toISOString(),
769
- };
770
-
771
- await fs.writeFile(configPath, JSON.stringify(config, null, 2));
772
- }
773
- }
774
-
775
- export default AgentGenerator;
776
-
777
- // Export default configurations for use by consumers
778
- export { DEFAULT_CORE_AGENT_TYPES, DEFAULT_AGENT_PATTERNS };