aios-core 4.0.2 → 4.1.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.
Files changed (111) hide show
  1. package/.aios-core/cli/commands/migrate/analyze.js +6 -6
  2. package/.aios-core/cli/commands/migrate/backup.js +2 -2
  3. package/.aios-core/cli/commands/migrate/execute.js +4 -4
  4. package/.aios-core/cli/commands/migrate/index.js +5 -5
  5. package/.aios-core/cli/commands/migrate/rollback.js +6 -6
  6. package/.aios-core/cli/commands/migrate/update-imports.js +2 -2
  7. package/.aios-core/cli/commands/migrate/validate.js +2 -2
  8. package/.aios-core/cli/commands/pro/index.js +52 -0
  9. package/.aios-core/cli/index.js +1 -1
  10. package/.aios-core/core/ids/registry-updater.js +29 -3
  11. package/.aios-core/core/migration/migration-config.yaml +2 -2
  12. package/.aios-core/core/migration/module-mapping.yaml +2 -2
  13. package/.aios-core/core/registry/README.md +2 -2
  14. package/.aios-core/core/synapse/context/context-builder.js +34 -0
  15. package/.aios-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
  16. package/.aios-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
  17. package/.aios-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
  18. package/.aios-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
  19. package/.aios-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
  20. package/.aios-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
  21. package/.aios-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
  22. package/.aios-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
  23. package/.aios-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
  24. package/.aios-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
  25. package/.aios-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
  26. package/.aios-core/core/synapse/diagnostics/report-formatter.js +484 -0
  27. package/.aios-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
  28. package/.aios-core/core/synapse/engine.js +73 -20
  29. package/.aios-core/core/synapse/runtime/hook-runtime.js +60 -0
  30. package/.aios-core/core-config.yaml +6 -0
  31. package/.aios-core/data/agent-config-requirements.yaml +2 -2
  32. package/.aios-core/data/aios-kb.md +4 -4
  33. package/.aios-core/data/entity-registry.yaml +5 -5
  34. package/.aios-core/development/agents/architect.md +10 -10
  35. package/.aios-core/development/agents/devops.md +93 -50
  36. package/.aios-core/development/agents/qa.md +94 -40
  37. package/.aios-core/development/agents/ux-design-expert.md +25 -25
  38. package/.aios-core/development/scripts/activation-runtime.js +63 -0
  39. package/.aios-core/development/scripts/generate-greeting.js +9 -8
  40. package/.aios-core/development/scripts/unified-activation-pipeline.js +102 -2
  41. package/.aios-core/development/tasks/{db-expansion-pack-integration.md → db-squad-integration.md} +5 -5
  42. package/.aios-core/development/tasks/{integrate-expansion-pack.md → integrate-squad.md} +2 -2
  43. package/.aios-core/development/tasks/next.md +3 -3
  44. package/.aios-core/development/tasks/pr-automation.md +2 -2
  45. package/.aios-core/development/tasks/publish-npm.md +257 -0
  46. package/.aios-core/development/tasks/release-management.md +4 -4
  47. package/.aios-core/development/tasks/setup-github.md +1 -1
  48. package/.aios-core/development/tasks/squad-creator-migrate.md +1 -1
  49. package/.aios-core/development/tasks/squad-creator-sync-ide-command.md +14 -14
  50. package/.aios-core/development/tasks/update-aios.md +1 -1
  51. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-QUICK-REFERENCE.md +1 -1
  52. package/.aios-core/docs/standards/AIOS-COLOR-PALETTE-V2.1.md +5 -5
  53. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.1-COMPLETE.md +21 -21
  54. package/.aios-core/docs/standards/AIOS-LIVRO-DE-OURO-V2.2-SUMMARY.md +25 -25
  55. package/.aios-core/docs/standards/OPEN-SOURCE-VS-SERVICE-DIFFERENCES.md +4 -4
  56. package/.aios-core/docs/standards/QUALITY-GATES-SPECIFICATION.md +3 -3
  57. package/.aios-core/docs/standards/STANDARDS-INDEX.md +13 -13
  58. package/.aios-core/docs/standards/STORY-TEMPLATE-V2-SPECIFICATION.md +1 -1
  59. package/.aios-core/framework-config.yaml +4 -0
  60. package/.aios-core/infrastructure/scripts/codex-skills-sync/index.js +182 -0
  61. package/.aios-core/infrastructure/scripts/codex-skills-sync/validate.js +172 -0
  62. package/.aios-core/infrastructure/scripts/ide-sync/README.md +14 -0
  63. package/.aios-core/infrastructure/scripts/ide-sync/index.js +6 -0
  64. package/.aios-core/infrastructure/scripts/tool-resolver.js +4 -4
  65. package/.aios-core/infrastructure/scripts/validate-paths.js +142 -0
  66. package/.aios-core/infrastructure/templates/aios-sync.yaml.template +11 -11
  67. package/.aios-core/infrastructure/templates/github-workflows/README.md +1 -1
  68. package/.aios-core/install-manifest.yaml +190 -106
  69. package/.aios-core/local-config.yaml.template +2 -0
  70. package/.aios-core/product/README.md +2 -2
  71. package/.aios-core/product/data/integration-patterns.md +1 -1
  72. package/.aios-core/product/templates/ide-rules/cline-rules.md +1 -1
  73. package/.aios-core/product/templates/ide-rules/codex-rules.md +65 -0
  74. package/.aios-core/product/templates/ide-rules/copilot-rules.md +1 -1
  75. package/.aios-core/product/templates/ide-rules/roo-rules.md +1 -1
  76. package/.aios-core/user-guide.md +15 -14
  77. package/.aios-core/workflow-intelligence/engine/output-formatter.js +1 -1
  78. package/.claude/hooks/enforce-architecture-first.py +196 -0
  79. package/.claude/hooks/install-hooks.sh +41 -0
  80. package/.claude/hooks/mind-clone-governance.py +192 -0
  81. package/.claude/hooks/pre-commit-mmos-guard.sh +99 -0
  82. package/.claude/hooks/pre-commit-version-check.sh +156 -0
  83. package/.claude/hooks/read-protection.py +151 -0
  84. package/.claude/hooks/slug-validation.py +176 -0
  85. package/.claude/hooks/sql-governance.py +182 -0
  86. package/.claude/hooks/synapse-engine.js +9 -20
  87. package/.claude/hooks/write-path-validation.py +194 -0
  88. package/README.md +44 -14
  89. package/bin/aios-init.js +255 -184
  90. package/bin/aios-minimal.js +2 -2
  91. package/bin/aios.js +19 -19
  92. package/package.json +7 -4
  93. package/packages/aios-pro-cli/bin/aios-pro.js +75 -2
  94. package/packages/aios-pro-cli/package.json +5 -1
  95. package/packages/aios-pro-cli/src/recover.js +100 -0
  96. package/packages/installer/src/__tests__/performance-benchmark.js +382 -0
  97. package/packages/installer/src/config/ide-configs.js +12 -1
  98. package/packages/installer/src/config/templates/core-config-template.js +2 -2
  99. package/packages/installer/src/installer/aios-core-installer.js +2 -2
  100. package/packages/installer/src/installer/file-hasher.js +97 -0
  101. package/packages/installer/src/installer/post-install-validator.js +41 -1
  102. package/packages/installer/src/pro/pro-scaffolder.js +335 -0
  103. package/packages/installer/src/utils/aios-colors.js +2 -2
  104. package/packages/installer/src/wizard/feedback.js +1 -1
  105. package/packages/installer/src/wizard/ide-config-generator.js +2 -2
  106. package/packages/installer/src/wizard/index.js +58 -19
  107. package/packages/installer/src/wizard/pro-setup.js +547 -0
  108. package/packages/installer/src/wizard/questions.js +20 -14
  109. package/packages/installer/src/wizard/validators.js +1 -1
  110. package/scripts/package-synapse.js +323 -0
  111. package/scripts/validate-package-completeness.js +317 -0
package/bin/aios-init.js CHANGED
@@ -24,9 +24,36 @@ const path = require('path');
24
24
  const fs = require('fs');
25
25
  const fse = require('fs-extra');
26
26
  const yaml = require('js-yaml');
27
- const { execSync } = require('child_process');
27
+ const { execSync, exec, spawn } = require('child_process');
28
+ const { promisify } = require('util');
28
29
  const inquirer = require('inquirer');
29
30
  const chalk = require('chalk');
31
+ const ora = require('ora'); // INS-2 Performance: Progress indicators (AC9)
32
+
33
+ // INS-2 Performance: Promisified exec for async shell commands (AC7)
34
+ const execAsync = promisify(exec);
35
+
36
+ /**
37
+ * Execute command with inherited stdio (for npm install -g that needs user interaction)
38
+ * INS-2 Performance: Async version that doesn't block event loop
39
+ * @param {string} command - Command to execute
40
+ * @param {object} options - Spawn options
41
+ * @returns {Promise<void>}
42
+ */
43
+ function spawnAsync(command, options = {}) {
44
+ return new Promise((resolve, reject) => {
45
+ const [cmd, ...args] = command.split(' ');
46
+ const child = spawn(cmd, args, { stdio: 'inherit', shell: true, ...options });
47
+ child.on('close', (code) => {
48
+ if (code === 0) {
49
+ resolve();
50
+ } else {
51
+ reject(new Error(`Command failed with code ${code}`));
52
+ }
53
+ });
54
+ child.on('error', reject);
55
+ });
56
+ }
30
57
 
31
58
  // ASCII Art Banner (Clean blocky style like reference image)
32
59
  const BANNER = chalk.cyan(`
@@ -108,20 +135,23 @@ async function main() {
108
135
  console.log(chalk.blue('⚙️ Setting up project prerequisites...\n'));
109
136
 
110
137
  // Check for git repository
138
+ // INS-2 Performance: Use async exec (AC7)
111
139
  let hasGit = false;
112
140
  try {
113
- execSync('git rev-parse --git-dir', { cwd: projectRoot, stdio: 'ignore' });
141
+ await execAsync('git rev-parse --git-dir', { cwd: projectRoot });
114
142
  hasGit = true;
115
143
  } catch (_err) {
116
144
  // Not a git repo
117
145
  }
118
146
 
119
147
  if (!hasGit) {
148
+ // INS-2 Performance: Add spinner for git init (AC9)
149
+ const gitSpinner = ora('Initializing git repository...').start();
120
150
  try {
121
- execSync('git init', { cwd: projectRoot, stdio: 'ignore' });
122
- console.log(chalk.green('✓') + ' Git repository initialized');
151
+ await execAsync('git init', { cwd: projectRoot });
152
+ gitSpinner.succeed('Git repository initialized');
123
153
  } catch (_err) {
124
- console.error(chalk.red('✗') + ' Failed to initialize git repository');
154
+ gitSpinner.fail('Failed to initialize git repository');
125
155
  process.exit(1);
126
156
  }
127
157
  }
@@ -140,7 +170,8 @@ async function main() {
140
170
  author: '',
141
171
  license: 'ISC',
142
172
  };
143
- fs.writeFileSync(packageJsonPath, JSON.stringify(defaultPackage, null, 2));
173
+ // INS-2 Performance: Use async write instead of sync
174
+ await fse.writeFile(packageJsonPath, JSON.stringify(defaultPackage, null, 2));
144
175
  console.log(chalk.green('✓') + ' package.json created');
145
176
  }
146
177
 
@@ -151,7 +182,8 @@ async function main() {
151
182
 
152
183
  // If still no context, create minimal one
153
184
  if (!context) {
154
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
185
+ // INS-2 Performance: Use async read instead of sync
186
+ const packageJson = JSON.parse(await fse.readFile(packageJsonPath, 'utf8'));
155
187
  context = {
156
188
  projectRoot,
157
189
  packageName: packageJson.name,
@@ -328,10 +360,12 @@ async function main() {
328
360
  };
329
361
 
330
362
  const configPath = path.join(context.projectRoot, '.aios-installation-config.yaml');
331
- fs.writeFileSync(configPath, yaml.dump(config));
363
+ // INS-2 Performance: Use async write instead of sync
364
+ await fse.writeFile(configPath, yaml.dump(config));
332
365
 
333
366
  // Update .gitignore
334
- updateGitIgnore(installMode, context.projectRoot);
367
+ // INS-2 Performance: Now async
368
+ await updateGitIgnore(installMode, context.projectRoot);
335
369
 
336
370
  // Step 2: PM Tool
337
371
  console.log('');
@@ -350,7 +384,8 @@ async function main() {
350
384
  ]);
351
385
 
352
386
  // Save PM config
353
- savePMConfig(pmTool, {}, context.projectRoot);
387
+ // INS-2 Performance: Now async
388
+ await savePMConfig(pmTool, {}, context.projectRoot);
354
389
 
355
390
  // Step 3: IDE Selection (CHECKBOX with instructions)
356
391
  console.log('');
@@ -369,19 +404,19 @@ async function main() {
369
404
  message: chalk.white('Which IDE(s) will you use?'),
370
405
  choices: [
371
406
  {
372
- name: ' Claude Code ' + chalk.blue('(v2.1)') + chalk.gray(' - Recommended'),
407
+ name: ' Claude Code ' + chalk.blue('(v4)') + chalk.gray(' - Recommended'),
373
408
  value: 'claude',
374
409
  checked: true,
375
410
  },
376
- { name: ' Cursor ' + chalk.blue('(v2.1)'), value: 'cursor' },
377
- { name: ' Windsurf ' + chalk.blue('(v2.1)'), value: 'windsurf' },
378
- { name: ' Trae ' + chalk.blue('(v2.1)'), value: 'trae' },
379
- { name: ' Roo Code ' + chalk.blue('(v2.1)'), value: 'roo' },
380
- { name: ' Cline ' + chalk.blue('(v2.1)'), value: 'cline' },
381
- { name: ' Gemini CLI ' + chalk.blue('(v2.1)'), value: 'gemini' },
382
- { name: ' GitHub Copilot ' + chalk.blue('(v2.1)'), value: 'github-copilot' },
411
+ { name: ' Cursor ' + chalk.blue('(v4)'), value: 'cursor' },
412
+ { name: ' Windsurf ' + chalk.blue('(v4)'), value: 'windsurf' },
413
+ { name: ' Trae ' + chalk.blue('(v4)'), value: 'trae' },
414
+ { name: ' Roo Code ' + chalk.blue('(v4)'), value: 'roo' },
415
+ { name: ' Cline ' + chalk.blue('(v4)'), value: 'cline' },
416
+ { name: ' Gemini CLI ' + chalk.blue('(v4)'), value: 'gemini' },
417
+ { name: ' GitHub Copilot ' + chalk.blue('(v4)'), value: 'github-copilot' },
383
418
  {
384
- name: ' AntiGravity ' + chalk.blue('(v2.1)') + chalk.gray(' - Google AI IDE'),
419
+ name: ' AntiGravity ' + chalk.blue('(v4)') + chalk.gray(' - Google AI IDE'),
385
420
  value: 'antigravity',
386
421
  },
387
422
  new inquirer.Separator(chalk.gray('─'.repeat(40))),
@@ -409,15 +444,26 @@ async function main() {
409
444
  console.log('');
410
445
  console.log(chalk.blue('🔍 Checking CLI tools...'));
411
446
 
447
+ // INS-2 Performance: Check CLI tools in parallel (AC7)
448
+ const toolCheckResults = await Promise.all(
449
+ cliToolsToCheck.map(async (tool) => {
450
+ try {
451
+ const checkCmd = process.platform === 'win32' ? `where ${tool.command}` : `command -v ${tool.command}`;
452
+ await execAsync(checkCmd);
453
+ return { tool, installed: true };
454
+ } catch {
455
+ return { tool, installed: false };
456
+ }
457
+ })
458
+ );
459
+
412
460
  const missingTools = [];
413
- for (const tool of cliToolsToCheck) {
414
- try {
415
- const checkCmd = process.platform === 'win32' ? `where ${tool.command}` : `command -v ${tool.command}`;
416
- require('child_process').execSync(checkCmd, { stdio: 'ignore' });
417
- console.log(chalk.green('') + ` ${tool.name} is installed`);
418
- } catch {
419
- console.log(chalk.yellow('⚠') + ` ${tool.name} is not installed`);
420
- missingTools.push(tool);
461
+ for (const result of toolCheckResults) {
462
+ if (result.installed) {
463
+ console.log(chalk.green('') + ` ${result.tool.name} is installed`);
464
+ } else {
465
+ console.log(chalk.yellow('') + ` ${result.tool.name} is not installed`);
466
+ missingTools.push(result.tool);
421
467
  }
422
468
  }
423
469
 
@@ -437,7 +483,8 @@ async function main() {
437
483
  for (const tool of missingTools) {
438
484
  console.log(chalk.blue(`📥 Installing ${tool.name}...`));
439
485
  try {
440
- require('child_process').execSync(`npm install -g ${tool.npm}`, { stdio: 'inherit' });
486
+ // INS-2 Performance: Use async spawn instead of sync (AC7)
487
+ await spawnAsync(`npm install -g ${tool.npm}`);
441
488
  console.log(chalk.green('✓') + ` ${tool.name} installed successfully`);
442
489
 
443
490
  // Show post-install instructions
@@ -462,16 +509,16 @@ async function main() {
462
509
 
463
510
  // Step 4b: Copy AIOS Core files
464
511
  console.log('');
465
- console.log(chalk.blue('📦 Installing AIOS Core files...'));
466
512
 
467
513
  const sourceCoreDir = path.join(context.frameworkLocation, '.aios-core');
468
514
  const targetCoreDir = path.join(context.projectRoot, '.aios-core');
469
515
 
470
516
  if (fs.existsSync(sourceCoreDir)) {
517
+ // INS-2 Performance: Add spinner for file copy (AC9)
518
+ const copySpinner = ora('Installing AIOS Core files...').start();
471
519
  await fse.copy(sourceCoreDir, targetCoreDir);
472
- console.log(
473
- chalk.green('') +
474
- ' AIOS Core files installed ' +
520
+ copySpinner.succeed(
521
+ 'AIOS Core files installed ' +
475
522
  chalk.gray('(11 agents, 68 tasks, 23 templates)')
476
523
  );
477
524
 
@@ -540,10 +587,25 @@ async function main() {
540
587
  }
541
588
  }
542
589
 
590
+ // INS-2 Performance: Cache directory listings to avoid redundant readdirSync calls
591
+ // The same agent/task directories are read 6-7 times across IDE installations
592
+ // This reduces directory reads from 6-7x to 1x (AC3)
593
+ const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
594
+ const coreTasksSource = path.join(targetCoreDir, 'development', 'tasks');
595
+
596
+ // Cache agent files list (read once, use many times)
597
+ const cachedAgentFiles = fs.existsSync(coreAgentsSource)
598
+ ? fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md'))
599
+ : [];
600
+
601
+ // Cache task files list
602
+ const cachedTaskFiles = fs.existsSync(coreTasksSource)
603
+ ? fs.readdirSync(coreTasksSource).filter((f) => f.endsWith('.md'))
604
+ : [];
605
+
543
606
  // Step 2: Install AIOS CORE agents and tasks for Claude Code
544
- // v2.1: Agents and tasks are in development/ module
607
+ // v4: Agents and tasks are in development/ module
545
608
  if (ides.includes('claude')) {
546
- const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
547
609
  const coreAgentsTarget = path.join(
548
610
  context.projectRoot,
549
611
  '.claude',
@@ -552,7 +614,6 @@ async function main() {
552
614
  'agents'
553
615
  );
554
616
 
555
- const coreTasksSource = path.join(targetCoreDir, 'development', 'tasks');
556
617
  const coreTasksTarget = path.join(
557
618
  context.projectRoot,
558
619
  '.claude',
@@ -561,16 +622,14 @@ async function main() {
561
622
  'tasks'
562
623
  );
563
624
 
564
- if (fs.existsSync(coreAgentsSource)) {
625
+ if (cachedAgentFiles.length > 0) {
565
626
  await fse.copy(coreAgentsSource, coreAgentsTarget);
566
- const agentCount = fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md')).length;
567
- console.log(chalk.green('✓') + ` Claude Code CORE agents installed (${agentCount} agents)`);
627
+ console.log(chalk.green('✓') + ` Claude Code CORE agents installed (${cachedAgentFiles.length} agents)`);
568
628
  }
569
629
 
570
- if (fs.existsSync(coreTasksSource)) {
630
+ if (cachedTaskFiles.length > 0) {
571
631
  await fse.copy(coreTasksSource, coreTasksTarget);
572
- const taskCount = fs.readdirSync(coreTasksSource).filter((f) => f.endsWith('.md')).length;
573
- console.log(chalk.green('✓') + ` Claude Code CORE tasks installed (${taskCount} tasks)`);
632
+ console.log(chalk.green('✓') + ` Claude Code CORE tasks installed (${cachedTaskFiles.length} tasks)`);
574
633
  }
575
634
 
576
635
  // Create AIOS README for Claude Code
@@ -599,9 +658,9 @@ See .aios-core/user-guide.md for complete documentation.
599
658
  }
600
659
 
601
660
  // Step 3: Install AIOS CORE agents for Cursor
602
- // v2.1: Agents are in development/ module
661
+ // v4: Agents are in development/ module
662
+ // INS-2 Performance: Uses cached agent files list
603
663
  if (ides.includes('cursor')) {
604
- const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
605
664
  const cursorRulesTarget = path.join(
606
665
  context.projectRoot,
607
666
  '.cursor',
@@ -610,12 +669,11 @@ See .aios-core/user-guide.md for complete documentation.
610
669
  'agents'
611
670
  );
612
671
 
613
- if (fs.existsSync(coreAgentsSource)) {
672
+ if (cachedAgentFiles.length > 0) {
614
673
  await fse.ensureDir(cursorRulesTarget);
615
674
 
616
- // Convert .md files to .mdc for Cursor
617
- const agentFiles = fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md'));
618
- for (const agentFile of agentFiles) {
675
+ // Convert .md files to .mdc for Cursor (using cached list)
676
+ for (const agentFile of cachedAgentFiles) {
619
677
  const sourcePath = path.join(coreAgentsSource, agentFile);
620
678
  const targetFileName = agentFile.replace('.md', '.mdc');
621
679
  const targetPath = path.join(cursorRulesTarget, targetFileName);
@@ -623,7 +681,7 @@ See .aios-core/user-guide.md for complete documentation.
623
681
  }
624
682
 
625
683
  console.log(
626
- chalk.green('✓') + ` Cursor CORE rules installed (${agentFiles.length} agents)`
684
+ chalk.green('✓') + ` Cursor CORE rules installed (${cachedAgentFiles.length} agents)`
627
685
  );
628
686
  }
629
687
 
@@ -646,11 +704,11 @@ See .aios-core/user-guide.md for complete documentation.
646
704
  }
647
705
 
648
706
  // Step 4: Install AIOS CORE agents for other IDEs (Trae, Cline, Gemini, AntiGravity)
649
- // v2.1: Agents are in development/ module
707
+ // v4: Agents are in development/ module
708
+ // INS-2 Performance: Uses cached agent files list
650
709
  const otherIdeInstalls = ['trae', 'cline', 'gemini', 'antigravity'];
651
710
  for (const ide of otherIdeInstalls) {
652
711
  if (ides.includes(ide)) {
653
- const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
654
712
  const ideRulesDir = ide === 'gemini' ? '.gemini' : `.${ide}`;
655
713
  const ideRulesTarget = path.join(
656
714
  context.projectRoot,
@@ -660,12 +718,11 @@ See .aios-core/user-guide.md for complete documentation.
660
718
  'agents'
661
719
  );
662
720
 
663
- if (fs.existsSync(coreAgentsSource)) {
721
+ if (cachedAgentFiles.length > 0) {
664
722
  await fse.ensureDir(ideRulesTarget);
665
723
 
666
- // Copy agent files
667
- const agentFiles = fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md'));
668
- for (const agentFile of agentFiles) {
724
+ // Copy agent files (using cached list)
725
+ for (const agentFile of cachedAgentFiles) {
669
726
  const sourcePath = path.join(coreAgentsSource, agentFile);
670
727
  const targetPath = path.join(ideRulesTarget, agentFile);
671
728
  await fse.copy(sourcePath, targetPath);
@@ -673,24 +730,22 @@ See .aios-core/user-guide.md for complete documentation.
673
730
 
674
731
  const ideName = ide.charAt(0).toUpperCase() + ide.slice(1);
675
732
  console.log(
676
- chalk.green('✓') + ` ${ideName} CORE agents installed (${agentFiles.length} agents)`
733
+ chalk.green('✓') + ` ${ideName} CORE agents installed (${cachedAgentFiles.length} agents)`
677
734
  );
678
735
  }
679
736
  }
680
737
  }
681
738
 
682
739
  // Step 5: Install Roo Code modes
683
- // v2.1: Agents are in development/ module
740
+ // v4: Agents are in development/ module
741
+ // INS-2 Performance: Uses cached agent files list
684
742
  if (ides.includes('roo')) {
685
- const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
686
743
  const rooModesPath = path.join(context.projectRoot, '.roomodes');
687
744
 
688
- if (fs.existsSync(coreAgentsSource)) {
689
- const agentFiles = fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md'));
690
-
691
- // Create .roomodes JSON file
745
+ if (cachedAgentFiles.length > 0) {
746
+ // Create .roomodes JSON file (using cached list)
692
747
  const roomodes = {
693
- customModes: agentFiles.map((f) => {
748
+ customModes: cachedAgentFiles.map((f) => {
694
749
  const agentName = f.replace('.md', '');
695
750
  return {
696
751
  slug: `bmad-${agentName}`,
@@ -703,21 +758,21 @@ See .aios-core/user-guide.md for complete documentation.
703
758
  };
704
759
 
705
760
  await fse.writeFile(rooModesPath, JSON.stringify(roomodes, null, 2));
706
- console.log(chalk.green('✓') + ` Roo Code modes installed (${agentFiles.length} modes)`);
761
+ console.log(chalk.green('✓') + ` Roo Code modes installed (${cachedAgentFiles.length} modes)`);
707
762
  }
708
763
  }
709
764
 
710
765
  // Step 6: Install GitHub Copilot chat modes
711
- // v2.1: Agents are in development/ module
766
+ // v4: Agents are in development/ module
767
+ // INS-2 Performance: Uses cached agent files list
712
768
  if (ides.includes('github-copilot')) {
713
- const coreAgentsSource = path.join(targetCoreDir, 'development', 'agents');
714
769
  const copilotModesDir = path.join(context.projectRoot, '.github', 'chatmodes');
715
770
 
716
- if (fs.existsSync(coreAgentsSource)) {
771
+ if (cachedAgentFiles.length > 0) {
717
772
  await fse.ensureDir(copilotModesDir);
718
773
 
719
- const agentFiles = fs.readdirSync(coreAgentsSource).filter((f) => f.endsWith('.md'));
720
- for (const agentFile of agentFiles) {
774
+ // Copy agent files (using cached list)
775
+ for (const agentFile of cachedAgentFiles) {
721
776
  const sourcePath = path.join(coreAgentsSource, agentFile);
722
777
  const agentName = agentFile.replace('.md', '');
723
778
  const targetPath = path.join(copilotModesDir, `aios-${agentName}.md`);
@@ -725,52 +780,55 @@ See .aios-core/user-guide.md for complete documentation.
725
780
  }
726
781
 
727
782
  console.log(
728
- chalk.green('✓') + ` GitHub Copilot chat modes installed (${agentFiles.length} modes)`
783
+ chalk.green('✓') + ` GitHub Copilot chat modes installed (${cachedAgentFiles.length} modes)`
729
784
  );
730
785
  }
731
786
  }
732
787
  }
733
788
 
734
- // Step 7: Expansion Packs (CHECKBOX with visual)
735
- // Try multiple locations for expansion-packs (npm package vs local development vs npx)
789
+ // Step 7: Squads (CHECKBOX with visual)
790
+ // Try multiple locations for squads (npm package vs local development vs npx)
736
791
  // __dirname is the 'bin/' directory of the package, so '..' gives us the package root
737
792
  const packageRoot = path.resolve(__dirname, '..');
738
793
 
739
- const possibleExpansionDirs = [
740
- // Primary: relative to this script (works for npx and local)
741
- path.join(packageRoot, 'expansion-packs'),
742
- // Secondary: context-based framework location
743
- path.join(context.frameworkLocation, 'expansion-packs'),
744
- // Tertiary: installed in project's node_modules
745
- path.join(context.projectRoot, 'node_modules', '@synkra/aios-core', 'expansion-packs'),
746
- path.join(context.projectRoot, 'node_modules', '@aios', 'fullstack', 'expansion-packs'),
794
+ const possibleSquadsDirs = [
795
+ // Primary: relative to this script (works for npx and local) - squads/
796
+ path.join(packageRoot, 'squads'),
797
+ // Secondary: context-based framework location - squads/
798
+ path.join(context.frameworkLocation, 'squads'),
799
+ // Tertiary: installed in project's node_modules - squads/
800
+ path.join(context.projectRoot, 'node_modules', '@synkra/aios-core', 'squads'),
801
+ path.join(context.projectRoot, 'node_modules', '@aios', 'fullstack', 'squads'),
747
802
  ];
748
803
 
749
- let sourceExpansionDir = null;
750
- for (const dir of possibleExpansionDirs) {
804
+ let sourceSquadsDir = null;
805
+ for (const dir of possibleSquadsDirs) {
751
806
  if (fs.existsSync(dir)) {
752
- sourceExpansionDir = dir;
807
+ sourceSquadsDir = dir;
753
808
  break;
754
809
  }
755
810
  }
756
811
 
757
- const availablePacks = [];
758
- let expansionPacks = []; // Declare here to be accessible in summary
812
+ const availableSquads = [];
813
+ let selectedSquads = []; // Declare here to be accessible in summary
759
814
 
760
- if (sourceExpansionDir && fs.existsSync(sourceExpansionDir)) {
761
- let packs = fs
762
- .readdirSync(sourceExpansionDir)
763
- .filter((f) => fs.statSync(path.join(sourceExpansionDir, f)).isDirectory());
815
+ if (sourceSquadsDir && fs.existsSync(sourceSquadsDir)) {
816
+ // INS-2 Performance: Use withFileTypes to avoid separate statSync calls per entry
817
+ // This reduces N+1 syscalls to just 1 syscall for the entire directory
818
+ let squads = fs
819
+ .readdirSync(sourceSquadsDir, { withFileTypes: true })
820
+ .filter((dirent) => dirent.isDirectory())
821
+ .map((dirent) => dirent.name);
764
822
 
765
- // Filter for minimal mode - only show expansion-creator
823
+ // Filter for minimal mode - only show squad-creator
766
824
  if (isMinimalMode) {
767
- packs = packs.filter((pack) => pack === 'expansion-creator');
825
+ squads = squads.filter((squad) => squad === 'squad-creator');
768
826
  }
769
827
 
770
- availablePacks.push(...packs);
828
+ availableSquads.push(...squads);
771
829
  }
772
830
 
773
- if (availablePacks.length > 0) {
831
+ if (availableSquads.length > 0) {
774
832
  console.log('');
775
833
  console.log(chalk.gray('─'.repeat(80)));
776
834
  console.log(
@@ -783,96 +841,103 @@ See .aios-core/user-guide.md for complete documentation.
783
841
  const result = await inquirer.prompt([
784
842
  {
785
843
  type: 'checkbox',
786
- name: 'expansionPacks',
787
- message: chalk.white('Select expansion packs to install (optional)'),
788
- choices: availablePacks.map((pack) => ({
789
- name: ' ' + pack,
790
- value: pack,
844
+ name: 'selectedSquads',
845
+ message: chalk.white('Select squads to install (optional)'),
846
+ choices: availableSquads.map((squad) => ({
847
+ name: ' ' + squad,
848
+ value: squad,
791
849
  })),
792
850
  },
793
851
  ]);
794
852
 
795
- expansionPacks = result.expansionPacks; // Assign to outer scope variable
853
+ selectedSquads = result.selectedSquads; // Assign to outer scope variable
796
854
 
797
- if (expansionPacks.length > 0) {
855
+ if (selectedSquads.length > 0) {
798
856
  console.log('');
799
- console.log(chalk.blue('📦 Installing expansion packs...'));
800
-
801
- const targetExpansionDir = path.join(context.projectRoot, 'expansion-packs');
802
-
803
- for (const pack of expansionPacks) {
804
- const sourcePack = path.join(sourceExpansionDir, pack);
805
- const targetPack = path.join(targetExpansionDir, pack);
806
- await fse.copy(sourcePack, targetPack);
807
- console.log(chalk.green('✓') + ` Expansion pack installed: ${pack}`);
808
-
809
- // Install expansion pack agents/tasks for Claude Code
857
+ console.log(chalk.blue('📦 Installing squads...'));
858
+
859
+ // Always install to squads/ directory (modern naming)
860
+ const targetSquadsDir = path.join(context.projectRoot, 'squads');
861
+
862
+ // INS-2 Performance: Copy all squads in parallel first (AC6)
863
+ await Promise.all(
864
+ selectedSquads.map(async (squad) => {
865
+ const sourceSquad = path.join(sourceSquadsDir, squad);
866
+ const targetSquad = path.join(targetSquadsDir, squad);
867
+ await fse.copy(sourceSquad, targetSquad);
868
+ })
869
+ );
870
+ console.log(chalk.green('✓') + ` Squads copied: ${selectedSquads.join(', ')}`);
871
+
872
+ // Process IDE-specific installations sequentially for ordered logging
873
+ for (const squad of selectedSquads) {
874
+ const targetSquad = path.join(targetSquadsDir, squad);
875
+
876
+ // INS-2 Performance: Cache squad file lists once per squad (used by Claude, Cursor, etc.)
877
+ const squadAgentsSource = path.join(targetSquad, 'agents');
878
+ const squadTasksSource = path.join(targetSquad, 'tasks');
879
+ const squadReadmeSource = path.join(targetSquad, 'README.md');
880
+
881
+ // Cache squad agents/tasks lists (read once per squad, use for all IDEs)
882
+ const squadAgentFiles = fs.existsSync(squadAgentsSource)
883
+ ? fs.readdirSync(squadAgentsSource).filter((f) => f.endsWith('.md'))
884
+ : [];
885
+ const squadTaskFiles = fs.existsSync(squadTasksSource)
886
+ ? fs.readdirSync(squadTasksSource).filter((f) => f.endsWith('.md'))
887
+ : [];
888
+ const hasSquadReadme = fs.existsSync(squadReadmeSource);
889
+
890
+ // Install squad agents/tasks for Claude Code
810
891
  if (ides.includes('claude')) {
811
- const packAgentsSource = path.join(targetPack, 'agents');
812
- const packTasksSource = path.join(targetPack, 'tasks');
813
- const packReadmeSource = path.join(targetPack, 'README.md');
814
-
815
- const packClaudeTarget = path.join(context.projectRoot, '.claude', 'commands', pack);
816
-
817
- // Copy agents
818
- if (fs.existsSync(packAgentsSource)) {
819
- const packAgentsTarget = path.join(packClaudeTarget, 'agents');
820
- await fse.copy(packAgentsSource, packAgentsTarget);
821
- const agentCount = fs
822
- .readdirSync(packAgentsSource)
823
- .filter((f) => f.endsWith('.md')).length;
824
- console.log(chalk.green(' ✓') + ` Claude Code ${pack} agents (${agentCount} agents)`);
892
+ const squadClaudeTarget = path.join(context.projectRoot, '.claude', 'commands', squad);
893
+
894
+ // Copy agents (using cached list)
895
+ if (squadAgentFiles.length > 0) {
896
+ const squadAgentsTarget = path.join(squadClaudeTarget, 'agents');
897
+ await fse.copy(squadAgentsSource, squadAgentsTarget);
898
+ console.log(chalk.green(' ✓') + ` Claude Code ${squad} agents (${squadAgentFiles.length} agents)`);
825
899
  }
826
900
 
827
- // Copy tasks
828
- if (fs.existsSync(packTasksSource)) {
829
- const packTasksTarget = path.join(packClaudeTarget, 'tasks');
830
- await fse.copy(packTasksSource, packTasksTarget);
831
- const taskCount = fs
832
- .readdirSync(packTasksSource)
833
- .filter((f) => f.endsWith('.md')).length;
834
- console.log(chalk.green(' ✓') + ` Claude Code ${pack} tasks (${taskCount} tasks)`);
901
+ // Copy tasks (using cached list)
902
+ if (squadTaskFiles.length > 0) {
903
+ const squadTasksTarget = path.join(squadClaudeTarget, 'tasks');
904
+ await fse.copy(squadTasksSource, squadTasksTarget);
905
+ console.log(chalk.green(' ✓') + ` Claude Code ${squad} tasks (${squadTaskFiles.length} tasks)`);
835
906
  }
836
907
 
837
- // Copy README
838
- if (fs.existsSync(packReadmeSource)) {
839
- await fse.copy(packReadmeSource, path.join(packClaudeTarget, 'README.md'));
908
+ // Copy README (using cached check)
909
+ if (hasSquadReadme) {
910
+ await fse.copy(squadReadmeSource, path.join(squadClaudeTarget, 'README.md'));
840
911
  }
841
912
  }
842
913
 
843
- // Install expansion pack agents for Cursor
844
- if (ides.includes('cursor')) {
845
- const packAgentsSource = path.join(targetPack, 'agents');
846
- const packReadmeSource = path.join(targetPack, 'README.md');
847
-
848
- if (fs.existsSync(packAgentsSource)) {
849
- const cursorPackTarget = path.join(
850
- context.projectRoot,
851
- '.cursor',
852
- 'rules',
853
- pack,
854
- 'agents'
855
- );
856
- await fse.ensureDir(cursorPackTarget);
857
-
858
- // Convert .md files to .mdc for Cursor
859
- const agentFiles = fs.readdirSync(packAgentsSource).filter((f) => f.endsWith('.md'));
860
- for (const agentFile of agentFiles) {
861
- const sourcePath = path.join(packAgentsSource, agentFile);
862
- const targetFileName = agentFile.replace('.md', '.mdc');
863
- const targetPath = path.join(cursorPackTarget, targetFileName);
864
- await fse.copy(sourcePath, targetPath);
865
- }
914
+ // Install squad agents for Cursor
915
+ if (ides.includes('cursor') && squadAgentFiles.length > 0) {
916
+ const cursorSquadTarget = path.join(
917
+ context.projectRoot,
918
+ '.cursor',
919
+ 'rules',
920
+ squad,
921
+ 'agents'
922
+ );
923
+ await fse.ensureDir(cursorSquadTarget);
924
+
925
+ // Convert .md files to .mdc for Cursor (using cached list)
926
+ for (const agentFile of squadAgentFiles) {
927
+ const sourcePath = path.join(squadAgentsSource, agentFile);
928
+ const targetFileName = agentFile.replace('.md', '.mdc');
929
+ const targetPath = path.join(cursorSquadTarget, targetFileName);
930
+ await fse.copy(sourcePath, targetPath);
931
+ }
866
932
 
867
- console.log(chalk.green(' ✓') + ` Cursor ${pack} rules (${agentFiles.length} agents)`);
933
+ console.log(chalk.green(' ✓') + ` Cursor ${squad} rules (${squadAgentFiles.length} agents)`);
868
934
 
869
- // Copy README for Cursor
870
- if (fs.existsSync(packReadmeSource)) {
871
- await fse.copy(
872
- packReadmeSource,
873
- path.join(context.projectRoot, '.cursor', 'rules', pack, 'README.md')
874
- );
875
- }
935
+ // Copy README for Cursor (using cached check)
936
+ if (hasSquadReadme) {
937
+ await fse.copy(
938
+ squadReadmeSource,
939
+ path.join(context.projectRoot, '.cursor', 'rules', squad, 'README.md')
940
+ );
876
941
  }
877
942
  }
878
943
  }
@@ -881,7 +946,8 @@ See .aios-core/user-guide.md for complete documentation.
881
946
 
882
947
  // Post-installation validation (Story 6.19)
883
948
  console.log('');
884
- console.log(chalk.blue('🔍 Validating installation integrity...'));
949
+ // INS-2 Performance: Add spinner for validation (AC9)
950
+ const validationSpinner = ora('Validating installation integrity...').start();
885
951
 
886
952
  let validationPassed = true;
887
953
  try {
@@ -905,7 +971,7 @@ See .aios-core/user-guide.md for complete documentation.
905
971
  report.stats.corruptedFiles > 0
906
972
  ) {
907
973
  validationPassed = false;
908
- console.log(chalk.yellow('⚠') + ` Installation validation found issues:`);
974
+ validationSpinner.warn('Installation validation found issues:');
909
975
  console.log(chalk.dim(` - Missing files: ${report.stats.missingFiles}`));
910
976
  console.log(chalk.dim(` - Corrupted files: ${report.stats.corruptedFiles}`));
911
977
  console.log('');
@@ -915,14 +981,14 @@ See .aios-core/user-guide.md for complete documentation.
915
981
  chalk.yellow(' to fix issues')
916
982
  );
917
983
  } else {
918
- console.log(chalk.green('✓') + ` Installation verified (${report.stats.validFiles} files)`);
984
+ validationSpinner.succeed(`Installation verified (${report.stats.validFiles} files)`);
919
985
  }
920
986
  } catch (validationError) {
921
987
  // Log validation errors but don't fail installation
922
988
  // This allows installation to proceed even if validator module has issues
923
989
  // However, users should investigate validation errors manually
924
990
  validationPassed = false;
925
- console.log(chalk.yellow('⚠') + ' Post-installation validation encountered an error');
991
+ validationSpinner.warn('Post-installation validation encountered an error');
926
992
  console.log(chalk.dim(` Error: ${validationError.message}`));
927
993
  if (process.env.DEBUG || process.env.AIOS_DEBUG) {
928
994
  console.log(chalk.dim(` Stack: ${validationError.stack}`));
@@ -945,8 +1011,8 @@ See .aios-core/user-guide.md for complete documentation.
945
1011
  );
946
1012
  console.log(' ' + chalk.dim('PM Tool: ') + pmTool);
947
1013
 
948
- if (availablePacks.length > 0 && expansionPacks && expansionPacks.length > 0) {
949
- console.log(' ' + chalk.dim('Expansion Packs:') + ' ' + expansionPacks.join(', '));
1014
+ if (availableSquads.length > 0 && selectedSquads && selectedSquads.length > 0) {
1015
+ console.log(' ' + chalk.dim('Squads: ') + ' ' + selectedSquads.join(', '));
950
1016
  }
951
1017
 
952
1018
  console.log('');
@@ -958,9 +1024,9 @@ See .aios-core/user-guide.md for complete documentation.
958
1024
  console.log(' ' + chalk.dim('├─ CLAUDE.md') + ' - Main configuration');
959
1025
  console.log(' ' + chalk.dim('└─ commands/'));
960
1026
  console.log(' ' + chalk.dim(' ├─ AIOS/') + ' - Core agents & tasks');
961
- if (expansionPacks && expansionPacks.length > 0) {
962
- expansionPacks.forEach((pack) => {
963
- console.log(' ' + chalk.dim(` └─ ${pack}/`) + ' - Expansion pack commands');
1027
+ if (selectedSquads && selectedSquads.length > 0) {
1028
+ selectedSquads.forEach((squad) => {
1029
+ console.log(' ' + chalk.dim(` └─ ${squad}/`) + ' - Squad commands');
964
1030
  });
965
1031
  }
966
1032
  }
@@ -970,9 +1036,9 @@ See .aios-core/user-guide.md for complete documentation.
970
1036
  console.log(' ' + chalk.dim('├─ rules.md') + ' - Main configuration');
971
1037
  console.log(' ' + chalk.dim('└─ rules/'));
972
1038
  console.log(' ' + chalk.dim(' ├─ AIOS/') + ' - Core agent rules');
973
- if (expansionPacks && expansionPacks.length > 0) {
974
- expansionPacks.forEach((pack) => {
975
- console.log(' ' + chalk.dim(` └─ ${pack}/`) + ' - Expansion pack rules');
1039
+ if (selectedSquads && selectedSquads.length > 0) {
1040
+ selectedSquads.forEach((squad) => {
1041
+ console.log(' ' + chalk.dim(` └─ ${squad}/`) + ' - Squad rules');
976
1042
  });
977
1043
  }
978
1044
  }
@@ -1047,7 +1113,7 @@ See .aios-core/user-guide.md for complete documentation.
1047
1113
  console.log(' • Run ' + chalk.yellow('aios validate') + ' to verify installation integrity');
1048
1114
  console.log(' • Run ' + chalk.yellow('aios validate --repair') + ' to fix any missing files');
1049
1115
  console.log(' • Check .aios-core/user-guide.md for complete documentation');
1050
- console.log(' • Explore expansion-packs/ for additional capabilities');
1116
+ console.log(' • Explore squads/ for additional capabilities');
1051
1117
  console.log('');
1052
1118
  console.log(chalk.gray('═'.repeat(80)));
1053
1119
  console.log('');
@@ -1055,13 +1121,15 @@ See .aios-core/user-guide.md for complete documentation.
1055
1121
 
1056
1122
  /**
1057
1123
  * Updates .gitignore file based on installation mode
1124
+ * INS-2 Performance: Converted to async
1058
1125
  */
1059
- function updateGitIgnore(mode, projectRoot) {
1126
+ async function updateGitIgnore(mode, projectRoot) {
1060
1127
  const gitignorePath = path.join(projectRoot, '.gitignore');
1061
1128
 
1062
1129
  let gitignore = '';
1063
1130
  if (fs.existsSync(gitignorePath)) {
1064
- gitignore = fs.readFileSync(gitignorePath, 'utf8');
1131
+ // INS-2 Performance: Use async read
1132
+ gitignore = await fse.readFile(gitignorePath, 'utf8');
1065
1133
  }
1066
1134
 
1067
1135
  if (mode === 'project-development') {
@@ -1080,15 +1148,17 @@ function updateGitIgnore(mode, projectRoot) {
1080
1148
 
1081
1149
  if (!hasFrameworkSection) {
1082
1150
  gitignore += frameworkRules.join('\n');
1083
- fs.writeFileSync(gitignorePath, gitignore);
1151
+ // INS-2 Performance: Use async write
1152
+ await fse.writeFile(gitignorePath, gitignore);
1084
1153
  }
1085
1154
  }
1086
1155
  }
1087
1156
 
1088
1157
  /**
1089
1158
  * Save PM configuration
1159
+ * INS-2 Performance: Converted to async
1090
1160
  */
1091
- function savePMConfig(pmTool, config, projectRoot) {
1161
+ async function savePMConfig(pmTool, config, projectRoot) {
1092
1162
  const pmConfigData = {
1093
1163
  pm_tool: {
1094
1164
  type: pmTool,
@@ -1103,7 +1173,8 @@ function savePMConfig(pmTool, config, projectRoot) {
1103
1173
  };
1104
1174
 
1105
1175
  const configPath = path.join(projectRoot, '.aios-pm-config.yaml');
1106
- fs.writeFileSync(configPath, yaml.dump(pmConfigData));
1176
+ // INS-2 Performance: Use async write
1177
+ await fse.writeFile(configPath, yaml.dump(pmConfigData));
1107
1178
  }
1108
1179
 
1109
1180
  // Run installer with error handling