bmad-method 5.0.0-beta.2 → 5.0.1

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 (131) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +3 -3
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +3 -3
  3. package/.github/workflows/discord.yaml +11 -2
  4. package/.github/workflows/format-check.yaml +42 -0
  5. package/.github/workflows/manual-release.yaml +173 -0
  6. package/.husky/pre-commit +3 -0
  7. package/.vscode/settings.json +26 -1
  8. package/CHANGELOG.md +0 -11
  9. package/README.md +2 -0
  10. package/bmad-core/agent-teams/team-all.yaml +1 -1
  11. package/bmad-core/agents/bmad-orchestrator.md +1 -1
  12. package/bmad-core/agents/dev.md +4 -4
  13. package/bmad-core/data/bmad-kb.md +1 -1
  14. package/bmad-core/data/test-levels-framework.md +12 -12
  15. package/bmad-core/tasks/facilitate-brainstorming-session.md +1 -1
  16. package/bmad-core/tasks/nfr-assess.md +10 -10
  17. package/bmad-core/tasks/qa-gate.md +23 -23
  18. package/bmad-core/tasks/review-story.md +18 -18
  19. package/bmad-core/tasks/risk-profile.md +25 -25
  20. package/bmad-core/tasks/test-design.md +9 -9
  21. package/bmad-core/tasks/trace-requirements.md +21 -21
  22. package/bmad-core/templates/architecture-tmpl.yaml +49 -49
  23. package/bmad-core/templates/brainstorming-output-tmpl.yaml +5 -5
  24. package/bmad-core/templates/brownfield-architecture-tmpl.yaml +31 -31
  25. package/bmad-core/templates/brownfield-prd-tmpl.yaml +13 -13
  26. package/bmad-core/templates/competitor-analysis-tmpl.yaml +19 -6
  27. package/bmad-core/templates/front-end-architecture-tmpl.yaml +21 -9
  28. package/bmad-core/templates/front-end-spec-tmpl.yaml +24 -24
  29. package/bmad-core/templates/fullstack-architecture-tmpl.yaml +122 -104
  30. package/bmad-core/templates/market-research-tmpl.yaml +2 -2
  31. package/bmad-core/templates/prd-tmpl.yaml +9 -9
  32. package/bmad-core/templates/project-brief-tmpl.yaml +4 -4
  33. package/bmad-core/templates/qa-gate-tmpl.yaml +9 -9
  34. package/bmad-core/templates/story-tmpl.yaml +12 -12
  35. package/bmad-core/workflows/brownfield-fullstack.yaml +9 -9
  36. package/bmad-core/workflows/brownfield-service.yaml +1 -1
  37. package/bmad-core/workflows/brownfield-ui.yaml +1 -1
  38. package/bmad-core/workflows/greenfield-fullstack.yaml +1 -1
  39. package/bmad-core/workflows/greenfield-service.yaml +1 -1
  40. package/bmad-core/workflows/greenfield-ui.yaml +1 -1
  41. package/common/utils/bmad-doc-template.md +5 -5
  42. package/dist/agents/analyst.txt +28 -15
  43. package/dist/agents/architect.txt +220 -190
  44. package/dist/agents/bmad-master.txt +298 -255
  45. package/dist/agents/bmad-orchestrator.txt +1 -1
  46. package/dist/agents/pm.txt +20 -20
  47. package/dist/agents/po.txt +11 -11
  48. package/dist/agents/qa.txt +275 -618
  49. package/dist/agents/sm.txt +11 -11
  50. package/dist/agents/ux-expert.txt +23 -23
  51. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +109 -109
  52. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.txt +75 -77
  53. package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.txt +41 -41
  54. package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +483 -474
  55. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.txt +1 -1
  56. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +149 -149
  57. package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +20 -20
  58. package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +371 -358
  59. package/dist/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.txt +25 -25
  60. package/dist/teams/team-all.txt +581 -881
  61. package/dist/teams/team-fullstack.txt +316 -273
  62. package/dist/teams/team-ide-minimal.txt +276 -619
  63. package/dist/teams/team-no-ui.txt +281 -238
  64. package/docs/versioning-and-releases.md +114 -44
  65. package/eslint.config.mjs +119 -0
  66. package/expansion-packs/Complete AI Agent System - Blank Templates & Google Cloud Setup/PART 1 - Google Cloud Vertex AI Setup Documentation/1.4 Deployment Configuration/1.4.2 - cloudbuild.yaml +26 -26
  67. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +4 -4
  68. package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +1 -1
  69. package/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +26 -28
  70. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +50 -50
  71. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +23 -23
  72. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +24 -24
  73. package/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +42 -42
  74. package/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
  75. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +5 -5
  76. package/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +1 -1
  77. package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +3 -3
  78. package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +1 -1
  79. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +23 -23
  80. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +63 -63
  81. package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +20 -20
  82. package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +65 -65
  83. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +5 -5
  84. package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +1 -1
  85. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +20 -20
  86. package/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +7 -7
  87. package/package.json +62 -39
  88. package/prettier.config.mjs +32 -0
  89. package/release_notes.md +30 -0
  90. package/tools/bmad-npx-wrapper.js +10 -10
  91. package/tools/builders/web-builder.js +124 -130
  92. package/tools/bump-all-versions.js +42 -33
  93. package/tools/bump-expansion-version.js +23 -16
  94. package/tools/cli.js +10 -12
  95. package/tools/flattener/aggregate.js +10 -10
  96. package/tools/flattener/binary.js +44 -17
  97. package/tools/flattener/discovery.js +19 -18
  98. package/tools/flattener/files.js +6 -6
  99. package/tools/flattener/ignoreRules.js +125 -125
  100. package/tools/flattener/main.js +201 -304
  101. package/tools/flattener/projectRoot.js +75 -73
  102. package/tools/flattener/prompts.js +9 -9
  103. package/tools/flattener/stats.helpers.js +131 -67
  104. package/tools/flattener/stats.js +3 -3
  105. package/tools/flattener/test-matrix.js +201 -193
  106. package/tools/flattener/xml.js +33 -31
  107. package/tools/installer/bin/bmad.js +130 -89
  108. package/tools/installer/config/ide-agent-config.yaml +1 -1
  109. package/tools/installer/config/install.config.yaml +2 -2
  110. package/tools/installer/lib/config-loader.js +46 -42
  111. package/tools/installer/lib/file-manager.js +91 -113
  112. package/tools/installer/lib/ide-base-setup.js +57 -56
  113. package/tools/installer/lib/ide-setup.js +375 -343
  114. package/tools/installer/lib/installer.js +875 -714
  115. package/tools/installer/lib/memory-profiler.js +54 -53
  116. package/tools/installer/lib/module-manager.js +19 -15
  117. package/tools/installer/lib/resource-locator.js +26 -28
  118. package/tools/installer/package.json +19 -19
  119. package/tools/lib/dependency-resolver.js +26 -30
  120. package/tools/lib/yaml-utils.js +7 -7
  121. package/tools/preview-release-notes.js +66 -0
  122. package/tools/shared/bannerArt.js +3 -3
  123. package/tools/sync-installer-version.js +7 -9
  124. package/tools/update-expansion-version.js +14 -15
  125. package/tools/upgraders/v3-to-v4-upgrader.js +203 -294
  126. package/tools/version-bump.js +41 -26
  127. package/tools/yaml-format.js +56 -43
  128. package/.github/workflows/promote-to-stable.yml +0 -144
  129. package/.github/workflows/release.yaml +0 -60
  130. package/.releaserc.json +0 -21
  131. package/tools/semantic-release-sync-installer.js +0 -30
@@ -1,11 +1,9 @@
1
- #!/usr/bin/env node
2
-
3
- const fs = require('fs');
4
- const path = require('path');
1
+ const fs = require('node:fs');
2
+ const path = require('node:path');
5
3
  const yaml = require('js-yaml');
6
4
 
7
- const args = process.argv.slice(2);
8
- const bumpType = args[0] || 'minor'; // default to minor
5
+ const arguments_ = process.argv.slice(2);
6
+ const bumpType = arguments_[0] || 'minor'; // default to minor
9
7
 
10
8
  if (!['major', 'minor', 'patch'].includes(bumpType)) {
11
9
  console.log('Usage: node bump-all-versions.js [major|minor|patch]');
@@ -15,22 +13,26 @@ if (!['major', 'minor', 'patch'].includes(bumpType)) {
15
13
 
16
14
  function bumpVersion(currentVersion, type) {
17
15
  const [major, minor, patch] = currentVersion.split('.').map(Number);
18
-
16
+
19
17
  switch (type) {
20
- case 'major':
18
+ case 'major': {
21
19
  return `${major + 1}.0.0`;
22
- case 'minor':
20
+ }
21
+ case 'minor': {
23
22
  return `${major}.${minor + 1}.0`;
24
- case 'patch':
23
+ }
24
+ case 'patch': {
25
25
  return `${major}.${minor}.${patch + 1}`;
26
- default:
26
+ }
27
+ default: {
27
28
  return currentVersion;
29
+ }
28
30
  }
29
31
  }
30
32
 
31
33
  async function bumpAllVersions() {
32
34
  const updatedItems = [];
33
-
35
+
34
36
  // First, bump the core version (package.json)
35
37
  const packagePath = path.join(__dirname, '..', 'package.json');
36
38
  try {
@@ -38,69 +40,76 @@ async function bumpAllVersions() {
38
40
  const packageJson = JSON.parse(packageContent);
39
41
  const oldCoreVersion = packageJson.version || '1.0.0';
40
42
  const newCoreVersion = bumpVersion(oldCoreVersion, bumpType);
41
-
43
+
42
44
  packageJson.version = newCoreVersion;
43
-
45
+
44
46
  fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + '\n');
45
-
46
- updatedItems.push({ type: 'core', name: 'BMad Core', oldVersion: oldCoreVersion, newVersion: newCoreVersion });
47
+
48
+ updatedItems.push({
49
+ type: 'core',
50
+ name: 'BMad Core',
51
+ oldVersion: oldCoreVersion,
52
+ newVersion: newCoreVersion,
53
+ });
47
54
  console.log(`✓ BMad Core (package.json): ${oldCoreVersion} → ${newCoreVersion}`);
48
55
  } catch (error) {
49
56
  console.error(`✗ Failed to update BMad Core: ${error.message}`);
50
57
  }
51
-
58
+
52
59
  // Then, bump all expansion packs
53
60
  const expansionPacksDir = path.join(__dirname, '..', 'expansion-packs');
54
-
61
+
55
62
  try {
56
63
  const entries = fs.readdirSync(expansionPacksDir, { withFileTypes: true });
57
-
64
+
58
65
  for (const entry of entries) {
59
66
  if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'README.md') {
60
67
  const packId = entry.name;
61
68
  const configPath = path.join(expansionPacksDir, packId, 'config.yaml');
62
-
69
+
63
70
  if (fs.existsSync(configPath)) {
64
71
  try {
65
72
  const configContent = fs.readFileSync(configPath, 'utf8');
66
73
  const config = yaml.load(configContent);
67
74
  const oldVersion = config.version || '1.0.0';
68
75
  const newVersion = bumpVersion(oldVersion, bumpType);
69
-
76
+
70
77
  config.version = newVersion;
71
-
78
+
72
79
  const updatedYaml = yaml.dump(config, { indent: 2 });
73
80
  fs.writeFileSync(configPath, updatedYaml);
74
-
81
+
75
82
  updatedItems.push({ type: 'expansion', name: packId, oldVersion, newVersion });
76
83
  console.log(`✓ ${packId}: ${oldVersion} → ${newVersion}`);
77
-
78
84
  } catch (error) {
79
85
  console.error(`✗ Failed to update ${packId}: ${error.message}`);
80
86
  }
81
87
  }
82
88
  }
83
89
  }
84
-
90
+
85
91
  if (updatedItems.length > 0) {
86
- const coreCount = updatedItems.filter(i => i.type === 'core').length;
87
- const expansionCount = updatedItems.filter(i => i.type === 'expansion').length;
88
-
89
- console.log(`\n✓ Successfully bumped ${updatedItems.length} item(s) with ${bumpType} version bump`);
92
+ const coreCount = updatedItems.filter((index) => index.type === 'core').length;
93
+ const expansionCount = updatedItems.filter((index) => index.type === 'expansion').length;
94
+
95
+ console.log(
96
+ `\n✓ Successfully bumped ${updatedItems.length} item(s) with ${bumpType} version bump`,
97
+ );
90
98
  if (coreCount > 0) console.log(` - ${coreCount} core`);
91
99
  if (expansionCount > 0) console.log(` - ${expansionCount} expansion pack(s)`);
92
-
100
+
93
101
  console.log('\nNext steps:');
94
102
  console.log('1. Test the changes');
95
- console.log('2. Commit: git add -A && git commit -m "chore: bump all versions (' + bumpType + ')"');
103
+ console.log(
104
+ '2. Commit: git add -A && git commit -m "chore: bump all versions (' + bumpType + ')"',
105
+ );
96
106
  } else {
97
107
  console.log('No items found to update');
98
108
  }
99
-
100
109
  } catch (error) {
101
110
  console.error('Error reading expansion packs directory:', error.message);
102
111
  process.exit(1);
103
112
  }
104
113
  }
105
114
 
106
- bumpAllVersions();
115
+ bumpAllVersions();
@@ -1,17 +1,15 @@
1
- #!/usr/bin/env node
2
-
3
1
  // Load required modules
4
- const fs = require('fs');
5
- const path = require('path');
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
6
4
  const yaml = require('js-yaml');
7
5
 
8
6
  // Parse CLI arguments
9
- const args = process.argv.slice(2);
10
- const packId = args[0];
11
- const bumpType = args[1] || 'minor';
7
+ const arguments_ = process.argv.slice(2);
8
+ const packId = arguments_[0];
9
+ const bumpType = arguments_[1] || 'minor';
12
10
 
13
11
  // Validate arguments
14
- if (!packId || args.length > 2) {
12
+ if (!packId || arguments_.length > 2) {
15
13
  console.log('Usage: node bump-expansion-version.js <expansion-pack-id> [major|minor|patch]');
16
14
  console.log('Default: minor');
17
15
  console.log('Example: node bump-expansion-version.js bmad-creator-tools patch');
@@ -28,10 +26,18 @@ function bumpVersion(currentVersion, type) {
28
26
  const [major, minor, patch] = currentVersion.split('.').map(Number);
29
27
 
30
28
  switch (type) {
31
- case 'major': return `${major + 1}.0.0`;
32
- case 'minor': return `${major}.${minor + 1}.0`;
33
- case 'patch': return `${major}.${minor}.${patch + 1}`;
34
- default: return currentVersion;
29
+ case 'major': {
30
+ return `${major + 1}.0.0`;
31
+ }
32
+ case 'minor': {
33
+ return `${major}.${minor + 1}.0`;
34
+ }
35
+ case 'patch': {
36
+ return `${major}.${minor}.${patch + 1}`;
37
+ }
38
+ default: {
39
+ return currentVersion;
40
+ }
35
41
  }
36
42
  }
37
43
 
@@ -47,11 +53,11 @@ async function updateVersion() {
47
53
  const packsDir = path.join(__dirname, '..', 'expansion-packs');
48
54
  const entries = fs.readdirSync(packsDir, { withFileTypes: true });
49
55
 
50
- entries.forEach(entry => {
56
+ for (const entry of entries) {
51
57
  if (entry.isDirectory() && !entry.name.startsWith('.')) {
52
58
  console.log(` - ${entry.name}`);
53
59
  }
54
- });
60
+ }
55
61
 
56
62
  process.exit(1);
57
63
  }
@@ -72,8 +78,9 @@ async function updateVersion() {
72
78
  console.log(`\n✓ Successfully bumped ${packId} with ${bumpType} version bump`);
73
79
  console.log('\nNext steps:');
74
80
  console.log(`1. Test the changes`);
75
- console.log(`2. Commit: git add -A && git commit -m "chore: bump ${packId} version (${bumpType})"`);
76
-
81
+ console.log(
82
+ `2. Commit: git add -A && git commit -m "chore: bump ${packId} version (${bumpType})"`,
83
+ );
77
84
  } catch (error) {
78
85
  console.error('Error updating version:', error.message);
79
86
  process.exit(1);
package/tools/cli.js CHANGED
@@ -1,10 +1,8 @@
1
- #!/usr/bin/env node
2
-
3
1
  const { Command } = require('commander');
4
2
  const WebBuilder = require('./builders/web-builder');
5
3
  const V3ToV4Upgrader = require('./upgraders/v3-to-v4-upgrader');
6
4
  const IdeSetup = require('./installer/lib/ide-setup');
7
- const path = require('path');
5
+ const path = require('node:path');
8
6
 
9
7
  const program = new Command();
10
8
 
@@ -23,7 +21,7 @@ program
23
21
  .option('--no-clean', 'Skip cleaning output directories')
24
22
  .action(async (options) => {
25
23
  const builder = new WebBuilder({
26
- rootDir: process.cwd()
24
+ rootDir: process.cwd(),
27
25
  });
28
26
 
29
27
  try {
@@ -66,7 +64,7 @@ program
66
64
  .option('--no-clean', 'Skip cleaning output directories')
67
65
  .action(async (options) => {
68
66
  const builder = new WebBuilder({
69
- rootDir: process.cwd()
67
+ rootDir: process.cwd(),
70
68
  });
71
69
 
72
70
  try {
@@ -92,7 +90,7 @@ program
92
90
  const builder = new WebBuilder({ rootDir: process.cwd() });
93
91
  const agents = await builder.resolver.listAgents();
94
92
  console.log('Available agents:');
95
- agents.forEach(agent => console.log(` - ${agent}`));
93
+ for (const agent of agents) console.log(` - ${agent}`);
96
94
  process.exit(0);
97
95
  });
98
96
 
@@ -103,7 +101,7 @@ program
103
101
  const builder = new WebBuilder({ rootDir: process.cwd() });
104
102
  const expansions = await builder.listExpansionPacks();
105
103
  console.log('Available expansion packs:');
106
- expansions.forEach(expansion => console.log(` - ${expansion}`));
104
+ for (const expansion of expansions) console.log(` - ${expansion}`);
107
105
  process.exit(0);
108
106
  });
109
107
 
@@ -116,19 +114,19 @@ program
116
114
  // Validate by attempting to build all agents and teams
117
115
  const agents = await builder.resolver.listAgents();
118
116
  const teams = await builder.resolver.listTeams();
119
-
117
+
120
118
  console.log('Validating agents...');
121
119
  for (const agent of agents) {
122
120
  await builder.resolver.resolveAgentDependencies(agent);
123
121
  console.log(` ✓ ${agent}`);
124
122
  }
125
-
123
+
126
124
  console.log('\nValidating teams...');
127
125
  for (const team of teams) {
128
126
  await builder.resolver.resolveTeamDependencies(team);
129
127
  console.log(` ✓ ${team}`);
130
128
  }
131
-
129
+
132
130
  console.log('\nAll configurations are valid!');
133
131
  } catch (error) {
134
132
  console.error('Validation failed:', error.message);
@@ -147,8 +145,8 @@ program
147
145
  await upgrader.upgrade({
148
146
  projectPath: options.project,
149
147
  dryRun: options.dryRun,
150
- backup: options.backup
148
+ backup: options.backup,
151
149
  });
152
150
  });
153
151
 
154
- program.parse();
152
+ program.parse();
@@ -1,7 +1,7 @@
1
- const fs = require("fs-extra");
2
- const path = require("node:path");
3
- const os = require("node:os");
4
- const { isBinaryFile } = require("./binary.js");
1
+ const fs = require('fs-extra');
2
+ const path = require('node:path');
3
+ const os = require('node:os');
4
+ const { isBinaryFile } = require('./binary.js');
5
5
 
6
6
  /**
7
7
  * Aggregate file contents with bounded concurrency.
@@ -22,7 +22,7 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
22
22
  // Automatic concurrency selection based on CPU count and workload size.
23
23
  // - Base on 2x logical CPUs, clamped to [2, 64]
24
24
  // - For very small workloads, avoid excessive parallelism
25
- const cpuCount = (os.cpus && Array.isArray(os.cpus()) ? os.cpus().length : (os.cpus?.length || 4));
25
+ const cpuCount = os.cpus && Array.isArray(os.cpus()) ? os.cpus().length : os.cpus?.length || 4;
26
26
  let concurrency = Math.min(64, Math.max(2, (Number(cpuCount) || 4) * 2));
27
27
  if (files.length > 0 && files.length < concurrency) {
28
28
  concurrency = Math.max(1, Math.min(concurrency, Math.ceil(files.length / 2)));
@@ -37,16 +37,16 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
37
37
 
38
38
  const binary = await isBinaryFile(filePath);
39
39
  if (binary) {
40
- const size = (await fs.stat(filePath)).size;
40
+ const { size } = await fs.stat(filePath);
41
41
  results.binaryFiles.push({ path: relativePath, absolutePath: filePath, size });
42
42
  } else {
43
- const content = await fs.readFile(filePath, "utf8");
43
+ const content = await fs.readFile(filePath, 'utf8');
44
44
  results.textFiles.push({
45
45
  path: relativePath,
46
46
  absolutePath: filePath,
47
47
  content,
48
48
  size: content.length,
49
- lines: content.split("\n").length,
49
+ lines: content.split('\n').length,
50
50
  });
51
51
  }
52
52
  } catch (error) {
@@ -63,8 +63,8 @@ async function aggregateFileContents(files, rootDir, spinner = null) {
63
63
  }
64
64
  }
65
65
 
66
- for (let i = 0; i < files.length; i += concurrency) {
67
- const slice = files.slice(i, i + concurrency);
66
+ for (let index = 0; index < files.length; index += concurrency) {
67
+ const slice = files.slice(index, index + concurrency);
68
68
  await Promise.all(slice.map(processOne));
69
69
  }
70
70
 
@@ -1,6 +1,6 @@
1
- const fsp = require("node:fs/promises");
2
- const path = require("node:path");
3
- const { Buffer } = require("node:buffer");
1
+ const fsp = require('node:fs/promises');
2
+ const path = require('node:path');
3
+ const { Buffer } = require('node:buffer');
4
4
 
5
5
  /**
6
6
  * Efficiently determine if a file is binary without reading the whole file.
@@ -13,25 +13,54 @@ async function isBinaryFile(filePath) {
13
13
  try {
14
14
  const stats = await fsp.stat(filePath);
15
15
  if (stats.isDirectory()) {
16
- throw new Error("EISDIR: illegal operation on a directory");
16
+ throw new Error('EISDIR: illegal operation on a directory');
17
17
  }
18
18
 
19
19
  const binaryExtensions = new Set([
20
- ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".ico", ".svg",
21
- ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx",
22
- ".zip", ".tar", ".gz", ".rar", ".7z",
23
- ".exe", ".dll", ".so", ".dylib",
24
- ".mp3", ".mp4", ".avi", ".mov", ".wav",
25
- ".ttf", ".otf", ".woff", ".woff2",
26
- ".bin", ".dat", ".db", ".sqlite",
20
+ '.jpg',
21
+ '.jpeg',
22
+ '.png',
23
+ '.gif',
24
+ '.bmp',
25
+ '.ico',
26
+ '.svg',
27
+ '.pdf',
28
+ '.doc',
29
+ '.docx',
30
+ '.xls',
31
+ '.xlsx',
32
+ '.ppt',
33
+ '.pptx',
34
+ '.zip',
35
+ '.tar',
36
+ '.gz',
37
+ '.rar',
38
+ '.7z',
39
+ '.exe',
40
+ '.dll',
41
+ '.so',
42
+ '.dylib',
43
+ '.mp3',
44
+ '.mp4',
45
+ '.avi',
46
+ '.mov',
47
+ '.wav',
48
+ '.ttf',
49
+ '.otf',
50
+ '.woff',
51
+ '.woff2',
52
+ '.bin',
53
+ '.dat',
54
+ '.db',
55
+ '.sqlite',
27
56
  ]);
28
57
 
29
- const ext = path.extname(filePath).toLowerCase();
30
- if (binaryExtensions.has(ext)) return true;
58
+ const extension = path.extname(filePath).toLowerCase();
59
+ if (binaryExtensions.has(extension)) return true;
31
60
  if (stats.size === 0) return false;
32
61
 
33
62
  const sampleSize = Math.min(4096, stats.size);
34
- const fd = await fsp.open(filePath, "r");
63
+ const fd = await fsp.open(filePath, 'r');
35
64
  try {
36
65
  const buffer = Buffer.allocUnsafe(sampleSize);
37
66
  const { bytesRead } = await fd.read(buffer, 0, sampleSize, 0);
@@ -41,9 +70,7 @@ async function isBinaryFile(filePath) {
41
70
  await fd.close();
42
71
  }
43
72
  } catch (error) {
44
- console.warn(
45
- `Warning: Could not determine if file is binary: ${filePath} - ${error.message}`,
46
- );
73
+ console.warn(`Warning: Could not determine if file is binary: ${filePath} - ${error.message}`);
47
74
  return false;
48
75
  }
49
76
  }
@@ -1,18 +1,21 @@
1
- const path = require("node:path");
2
- const { execFile } = require("node:child_process");
3
- const { promisify } = require("node:util");
4
- const { glob } = require("glob");
5
- const { loadIgnore } = require("./ignoreRules.js");
1
+ const path = require('node:path');
2
+ const { execFile } = require('node:child_process');
3
+ const { promisify } = require('node:util');
4
+ const { glob } = require('glob');
5
+ const { loadIgnore } = require('./ignoreRules.js');
6
6
 
7
7
  const pExecFile = promisify(execFile);
8
8
 
9
9
  async function isGitRepo(rootDir) {
10
10
  try {
11
- const { stdout } = await pExecFile("git", [
12
- "rev-parse",
13
- "--is-inside-work-tree",
14
- ], { cwd: rootDir });
15
- return String(stdout || "").toString().trim() === "true";
11
+ const { stdout } = await pExecFile('git', ['rev-parse', '--is-inside-work-tree'], {
12
+ cwd: rootDir,
13
+ });
14
+ return (
15
+ String(stdout || '')
16
+ .toString()
17
+ .trim() === 'true'
18
+ );
16
19
  } catch {
17
20
  return false;
18
21
  }
@@ -20,12 +23,10 @@ async function isGitRepo(rootDir) {
20
23
 
21
24
  async function gitListFiles(rootDir) {
22
25
  try {
23
- const { stdout } = await pExecFile("git", [
24
- "ls-files",
25
- "-co",
26
- "--exclude-standard",
27
- ], { cwd: rootDir });
28
- return String(stdout || "")
26
+ const { stdout } = await pExecFile('git', ['ls-files', '-co', '--exclude-standard'], {
27
+ cwd: rootDir,
28
+ });
29
+ return String(stdout || '')
29
30
  .split(/\r?\n/)
30
31
  .map((s) => s.trim())
31
32
  .filter(Boolean);
@@ -48,14 +49,14 @@ async function discoverFiles(rootDir, options = {}) {
48
49
  const { filter } = await loadIgnore(rootDir);
49
50
 
50
51
  // Try git first
51
- if (preferGit && await isGitRepo(rootDir)) {
52
+ if (preferGit && (await isGitRepo(rootDir))) {
52
53
  const relFiles = await gitListFiles(rootDir);
53
54
  const filteredRel = relFiles.filter((p) => filter(p));
54
55
  return filteredRel.map((p) => path.resolve(rootDir, p));
55
56
  }
56
57
 
57
58
  // Glob fallback
58
- const globbed = await glob("**/*", {
59
+ const globbed = await glob('**/*', {
59
60
  cwd: rootDir,
60
61
  nodir: true,
61
62
  dot: true,
@@ -1,8 +1,8 @@
1
- const path = require("node:path");
2
- const discovery = require("./discovery.js");
3
- const ignoreRules = require("./ignoreRules.js");
4
- const { isBinaryFile } = require("./binary.js");
5
- const { aggregateFileContents } = require("./aggregate.js");
1
+ const path = require('node:path');
2
+ const discovery = require('./discovery.js');
3
+ const ignoreRules = require('./ignoreRules.js');
4
+ const { isBinaryFile } = require('./binary.js');
5
+ const { aggregateFileContents } = require('./aggregate.js');
6
6
 
7
7
  // Backward-compatible signature; delegate to central loader
8
8
  async function parseGitignore(gitignorePath) {
@@ -14,7 +14,7 @@ async function discoverFiles(rootDir) {
14
14
  // Delegate to discovery module which respects .gitignore and defaults
15
15
  return await discovery.discoverFiles(rootDir, { preferGit: true });
16
16
  } catch (error) {
17
- console.error("Error discovering files:", error.message);
17
+ console.error('Error discovering files:', error.message);
18
18
  return [];
19
19
  }
20
20
  }