aided-dev 1.0.5 → 1.0.7

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/dist/cli.js CHANGED
@@ -15,6 +15,7 @@ program
15
15
  .option('-m, --model <model>', 'Claude model to use', 'claude-sonnet-4-20250514')
16
16
  .option('-v, --verbose', 'Show detailed output')
17
17
  .option('-d, --dir <path>', 'Project directory', process.cwd())
18
+ .option('-a, --apply', 'Apply code changes directly to the repository')
18
19
  .action(async (prompt, options) => {
19
20
  if (!prompt) {
20
21
  program.help();
@@ -48,6 +49,7 @@ program
48
49
  repoPath: options.dir,
49
50
  model: options.model,
50
51
  verbose: options.verbose,
52
+ applyChanges: options.apply,
51
53
  });
52
54
  await orchestrator.run(prompt);
53
55
  }
@@ -256,10 +258,18 @@ program
256
258
  console.log(' aided "Document all REST API endpoints"');
257
259
  console.log('');
258
260
  console.log(chalk.cyan('Options:'));
261
+ console.log(' -a, --apply Apply code changes directly to repo');
259
262
  console.log(' -v, --verbose Show detailed agent output');
260
263
  console.log(' -d, --dir <path> Run in specific directory');
261
264
  console.log(' -m, --model <model> Use different Claude model');
262
265
  console.log('');
266
+ console.log(chalk.cyan('Examples with --apply:'));
267
+ console.log(chalk.dim(' # Create new feature and write files'));
268
+ console.log(' aided "Add user dashboard" --apply');
269
+ console.log('');
270
+ console.log(chalk.dim(' # Fix a bug in existing code'));
271
+ console.log(' aided "Fix: null check in auth middleware" --apply');
272
+ console.log('');
263
273
  console.log(chalk.cyan('Other Commands:'));
264
274
  console.log(' aided analyze Analyze project context');
265
275
  console.log(' aided agents List available AI agents');
@@ -6,6 +6,7 @@ export interface OrchestratorOptions {
6
6
  verbose?: boolean;
7
7
  skipPlanning?: boolean;
8
8
  outputDir?: string;
9
+ applyChanges?: boolean;
9
10
  }
10
11
  export interface WorkflowState {
11
12
  task: string;
@@ -24,6 +25,7 @@ export declare class Orchestrator {
24
25
  private verbose;
25
26
  private skipPlanning;
26
27
  private outputDir;
28
+ private applyChanges;
27
29
  private bmadLoader;
28
30
  private agents;
29
31
  private planner;
@@ -42,5 +44,6 @@ export declare class Orchestrator {
42
44
  private buildStepPrompt;
43
45
  private extractTextContent;
44
46
  private saveOutputs;
47
+ private applyCodeToRepo;
45
48
  private printSummary;
46
49
  }
@@ -14,6 +14,7 @@ export class Orchestrator {
14
14
  verbose;
15
15
  skipPlanning;
16
16
  outputDir;
17
+ applyChanges;
17
18
  bmadLoader;
18
19
  agents = new Map();
19
20
  planner = null;
@@ -28,6 +29,7 @@ export class Orchestrator {
28
29
  this.verbose = options.verbose || false;
29
30
  this.skipPlanning = options.skipPlanning || false;
30
31
  this.outputDir = options.outputDir || path.join(options.repoPath, '.aided-output');
32
+ this.applyChanges = options.applyChanges || false;
31
33
  this.bmadLoader = getLoader();
32
34
  }
33
35
  async loadAgents() {
@@ -255,7 +257,7 @@ export class Orchestrator {
255
257
  return files;
256
258
  }
257
259
  async scanDirectory(dirPath, files, relativePath, maxDepth) {
258
- if (maxDepth <= 0 || files.size > 50)
260
+ if (maxDepth <= 0 || files.size > 20)
259
261
  return;
260
262
  const sourceExtensions = ['.ts', '.js', '.py', '.go', '.rs', '.java', '.rb', '.php'];
261
263
  try {
@@ -274,11 +276,11 @@ export class Orchestrator {
274
276
  if (sourceExtensions.includes(ext)) {
275
277
  try {
276
278
  const content = fs.readFileSync(fullPath, 'utf-8');
277
- if (content.length < 8000) {
279
+ if (content.length < 4000) {
278
280
  files.set(relPath, content);
279
281
  }
280
282
  else {
281
- files.set(relPath, content.substring(0, 8000) + '\n\n... (truncated)');
283
+ files.set(relPath, content.substring(0, 4000) + '\n\n... (truncated)');
282
284
  }
283
285
  }
284
286
  catch {
@@ -361,10 +363,37 @@ Implement the code according to the specifications provided.
361
363
  - Follow the architecture/design if provided
362
364
  - Implement all required functionality
363
365
  - Include proper error handling
364
- - Add inline documentation
365
- - Follow framework conventions
366
+ - Follow framework conventions and existing patterns
366
367
 
367
- Output each file with its path and complete code.`,
368
+ ## CRITICAL: Output Format
369
+ You MUST output changes in this EXACT format for each file:
370
+
371
+ For NEW files:
372
+ \`\`\`
373
+ ===FILE: path/to/newfile.js
374
+ ===ACTION: CREATE
375
+ \`\`\`javascript
376
+ // complete file content here
377
+ \`\`\`
378
+ ===END_FILE
379
+ \`\`\`
380
+
381
+ For MODIFYING existing files:
382
+ \`\`\`
383
+ ===FILE: path/to/existing.js
384
+ ===ACTION: MODIFY
385
+ ===FIND:
386
+ \`\`\`javascript
387
+ // exact code to find and replace
388
+ \`\`\`
389
+ ===REPLACE:
390
+ \`\`\`javascript
391
+ // new code to replace with
392
+ \`\`\`
393
+ ===END_FILE
394
+ \`\`\`
395
+
396
+ Stay focused ONLY on the task. Do not add unnecessary features or refactor unrelated code.`,
368
397
  tests: `## Task
369
398
  ${task}
370
399
 
@@ -375,18 +404,45 @@ Generate comprehensive tests for the implementation:
375
404
  - Edge cases and error scenarios
376
405
  - Use appropriate test framework for the stack
377
406
 
378
- Output test files with paths and complete test code.`,
407
+ ## CRITICAL: Output Format
408
+ Output test files using this EXACT format:
409
+
410
+ \`\`\`
411
+ ===FILE: path/to/test.spec.js
412
+ ===ACTION: CREATE
413
+ \`\`\`javascript
414
+ // test file content
415
+ \`\`\`
416
+ ===END_FILE
417
+ \`\`\``,
379
418
  fix: `## Task
380
419
  ${task}
381
420
 
382
421
  ## Instructions
383
422
  Analyze and fix the reported issue:
384
423
  1. Identify the root cause
385
- 2. Implement the fix
386
- 3. Ensure no regressions
387
- 4. Document the changes
424
+ 2. Implement the MINIMAL fix required
425
+ 3. Do NOT refactor unrelated code
426
+ 4. Stay focused on the specific bug
427
+
428
+ ## CRITICAL: Output Format
429
+ Output fixes using this EXACT format:
430
+
431
+ \`\`\`
432
+ ===FILE: path/to/file.js
433
+ ===ACTION: MODIFY
434
+ ===FIND:
435
+ \`\`\`javascript
436
+ // exact buggy code
437
+ \`\`\`
438
+ ===REPLACE:
439
+ \`\`\`javascript
440
+ // fixed code
441
+ \`\`\`
442
+ ===END_FILE
443
+ \`\`\`
388
444
 
389
- Output the fixed code with explanations.`,
445
+ ONLY output changes needed for the fix. Do not touch unrelated code.`,
390
446
  design: `## Task
391
447
  ${task}
392
448
 
@@ -480,6 +536,119 @@ ${content}
480
536
  }
481
537
  return runDir;
482
538
  }
539
+ async applyCodeToRepo(state) {
540
+ const result = { created: [], modified: [], errors: [] };
541
+ for (const [key, content] of state.outputs) {
542
+ if (!key.includes('implementation') && !key.includes('code') && !key.includes('fix') && !key.includes('test')) {
543
+ continue;
544
+ }
545
+ const fileBlocks = content.split('===FILE:').slice(1);
546
+ for (const block of fileBlocks) {
547
+ try {
548
+ const endIndex = block.indexOf('===END_FILE');
549
+ const fileBlock = endIndex > -1 ? block.substring(0, endIndex) : block;
550
+ const filePathMatch = fileBlock.match(/^([^\n]+)/);
551
+ if (!filePathMatch)
552
+ continue;
553
+ const filePath = filePathMatch[1].trim();
554
+ if (filePath.includes('...') || filePath.includes('example') || !filePath.includes('.')) {
555
+ continue;
556
+ }
557
+ const normalizedPath = filePath.replace(/^\/+/, '').replace(/^\.\//, '');
558
+ const fullPath = path.join(this.repoPath, normalizedPath);
559
+ const actionMatch = fileBlock.match(/===ACTION:\s*(\w+)/);
560
+ const action = actionMatch ? actionMatch[1].toUpperCase() : 'CREATE';
561
+ if (action === 'CREATE') {
562
+ const codeMatch = fileBlock.match(/```(?:\w+)?\n([\s\S]*?)```/);
563
+ if (!codeMatch)
564
+ continue;
565
+ const code = codeMatch[1];
566
+ const dirPath = path.dirname(fullPath);
567
+ if (!fs.existsSync(dirPath)) {
568
+ fs.mkdirSync(dirPath, { recursive: true });
569
+ }
570
+ fs.writeFileSync(fullPath, code.trim() + '\n');
571
+ result.created.push(normalizedPath);
572
+ }
573
+ else if (action === 'MODIFY') {
574
+ const findMatch = fileBlock.match(/===FIND:\s*```(?:\w+)?\n([\s\S]*?)```/);
575
+ const replaceMatch = fileBlock.match(/===REPLACE:\s*```(?:\w+)?\n([\s\S]*?)```/);
576
+ if (!findMatch || !replaceMatch) {
577
+ result.errors.push(`${normalizedPath}: Missing FIND or REPLACE block`);
578
+ continue;
579
+ }
580
+ const findCode = findMatch[1].trim();
581
+ const replaceCode = replaceMatch[1].trim();
582
+ if (!fs.existsSync(fullPath)) {
583
+ result.errors.push(`${normalizedPath}: File not found`);
584
+ continue;
585
+ }
586
+ let fileContent = fs.readFileSync(fullPath, 'utf-8');
587
+ if (fileContent.includes(findCode)) {
588
+ fileContent = fileContent.replace(findCode, replaceCode);
589
+ fs.writeFileSync(fullPath, fileContent);
590
+ result.modified.push(normalizedPath);
591
+ }
592
+ else {
593
+ const normalizedFind = findCode.replace(/\s+/g, ' ').trim();
594
+ const normalizedContent = fileContent.replace(/\s+/g, ' ');
595
+ if (normalizedContent.includes(normalizedFind)) {
596
+ const lines = fileContent.split('\n');
597
+ const findLines = findCode.split('\n');
598
+ let startLine = -1;
599
+ for (let i = 0; i <= lines.length - findLines.length; i++) {
600
+ const segment = lines.slice(i, i + findLines.length).join('\n');
601
+ if (segment.replace(/\s+/g, ' ').trim() === normalizedFind) {
602
+ startLine = i;
603
+ break;
604
+ }
605
+ }
606
+ if (startLine >= 0) {
607
+ lines.splice(startLine, findLines.length, ...replaceCode.split('\n'));
608
+ fs.writeFileSync(fullPath, lines.join('\n'));
609
+ result.modified.push(normalizedPath);
610
+ }
611
+ else {
612
+ result.errors.push(`${normalizedPath}: Could not locate code to replace`);
613
+ }
614
+ }
615
+ else {
616
+ result.errors.push(`${normalizedPath}: Code to replace not found`);
617
+ }
618
+ }
619
+ }
620
+ }
621
+ catch (error) {
622
+ result.errors.push(`Error processing block: ${error}`);
623
+ }
624
+ }
625
+ if (result.created.length === 0 && result.modified.length === 0) {
626
+ const legacyPattern = /###\s+([^\n]+\.[a-zA-Z]+)\s*\n```(?:\w+)?\n([\s\S]*?)```/g;
627
+ let match;
628
+ while ((match = legacyPattern.exec(content)) !== null) {
629
+ const filePath = match[1].trim();
630
+ const code = match[2];
631
+ if (filePath.includes('...') || filePath.includes('example') || filePath.startsWith('//')) {
632
+ continue;
633
+ }
634
+ const normalizedPath = filePath.replace(/^\/+/, '').replace(/^\.\//, '');
635
+ const fullPath = path.join(this.repoPath, normalizedPath);
636
+ const dirPath = path.dirname(fullPath);
637
+ try {
638
+ if (!fs.existsSync(dirPath)) {
639
+ fs.mkdirSync(dirPath, { recursive: true });
640
+ }
641
+ fs.writeFileSync(fullPath, code.trim() + '\n');
642
+ result.created.push(normalizedPath);
643
+ }
644
+ catch (error) {
645
+ result.errors.push(`${normalizedPath}: ${error}`);
646
+ }
647
+ }
648
+ }
649
+ }
650
+ return result;
651
+ }
483
652
  async printSummary(state) {
484
653
  console.log('');
485
654
  if (state.errors.length > 0) {
@@ -491,6 +660,32 @@ ${content}
491
660
  else {
492
661
  console.log(chalk.green('✓ Workflow complete!'));
493
662
  }
663
+ if (this.applyChanges && state.outputs.size > 0) {
664
+ console.log('');
665
+ console.log(chalk.cyan('Applying code changes to repository...'));
666
+ const result = await this.applyCodeToRepo(state);
667
+ if (result.created.length > 0) {
668
+ console.log(chalk.green(`✓ Created ${result.created.length} files:`));
669
+ for (const file of result.created) {
670
+ console.log(chalk.green(` + ${file}`));
671
+ }
672
+ }
673
+ if (result.modified.length > 0) {
674
+ console.log(chalk.blue(`✓ Modified ${result.modified.length} files:`));
675
+ for (const file of result.modified) {
676
+ console.log(chalk.blue(` ~ ${file}`));
677
+ }
678
+ }
679
+ if (result.errors.length > 0) {
680
+ console.log(chalk.yellow(`⚠ ${result.errors.length} issues:`));
681
+ for (const error of result.errors) {
682
+ console.log(chalk.yellow(` ! ${error}`));
683
+ }
684
+ }
685
+ if (result.created.length === 0 && result.modified.length === 0) {
686
+ console.log(chalk.yellow(' No code changes to apply'));
687
+ }
688
+ }
494
689
  if (state.outputs.size > 0) {
495
690
  const outputPath = await this.saveOutputs(state);
496
691
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aided-dev",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "AI Development Team Orchestrator - BMAD-METHOD integration for automated code generation",
5
5
  "keywords": [
6
6
  "ai",