bmad-method 4.30.2 → 4.30.4
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/CHANGELOG.md +15 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +3 -3
- package/bmad-core/agents/analyst.md +6 -6
- package/bmad-core/agents/architect.md +8 -3
- package/bmad-core/agents/bmad-master.md +2 -1
- package/bmad-core/agents/pm.md +7 -2
- package/bmad-core/agents/po.md +2 -5
- package/bmad-core/agents/qa.md +0 -1
- package/bmad-core/agents/sm.md +3 -3
- package/bmad-core/agents/ux-expert.md +2 -5
- package/bmad-core/core-config.yaml +0 -1
- package/dist/agents/analyst.txt +1 -1
- package/dist/agents/bmad-master.txt +1 -1
- package/dist/agents/bmad-orchestrator.txt +1 -1
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.txt +2409 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.txt +1480 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.txt +826 -0
- package/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +10690 -0
- package/dist/teams/team-all.txt +1 -1
- package/dist/teams/team-fullstack.txt +1 -1
- package/dist/teams/team-ide-minimal.txt +1 -1
- package/dist/teams/team-no-ui.txt +1 -1
- package/docs/bmad-workflow-guide.md +1 -1
- package/docs/how-to-contribute-with-pull-requests.md +2 -2
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +2 -2
- package/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +13 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +72 -0
- package/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +78 -0
- package/expansion-packs/{bmad-creator-tools/agents/bmad-the-creator.md → bmad-2d-unity-game-dev/agents/game-sm.md} +26 -28
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +201 -0
- package/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +160 -0
- package/expansion-packs/bmad-2d-unity-game-dev/config.yaml +6 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +251 -0
- package/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +590 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +111 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +217 -0
- package/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +308 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +545 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +356 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +343 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +256 -0
- package/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +484 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +183 -0
- package/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +175 -0
- package/expansion-packs/bmad-infrastructure-devops/config.yaml +2 -2
- package/package.json +7 -10
- package/tools/bump-all-versions.js +8 -9
- package/tools/bump-expansion-version.js +40 -35
- package/tools/installer/bin/bmad.js +8 -21
- package/tools/installer/lib/file-manager.js +76 -44
- package/tools/installer/lib/ide-base-setup.js +227 -0
- package/tools/installer/lib/ide-setup.js +8 -58
- package/tools/installer/lib/installer.js +99 -121
- package/tools/installer/lib/memory-profiler.js +224 -0
- package/tools/installer/lib/module-manager.js +110 -0
- package/tools/installer/lib/resource-locator.js +310 -0
- package/tools/installer/package.json +1 -1
- package/tools/semantic-release-sync-installer.js +20 -21
- package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +0 -2008
- package/expansion-packs/bmad-creator-tools/README.md +0 -8
- package/expansion-packs/bmad-creator-tools/config.yaml +0 -6
- package/expansion-packs/bmad-creator-tools/tasks/create-agent.md +0 -200
- package/expansion-packs/bmad-creator-tools/tasks/generate-expansion-pack.md +0 -1020
- package/expansion-packs/bmad-creator-tools/templates/agent-teams-tmpl.yaml +0 -178
- package/expansion-packs/bmad-creator-tools/templates/agent-tmpl.yaml +0 -154
- package/expansion-packs/bmad-creator-tools/templates/expansion-pack-plan-tmpl.yaml +0 -120
- package/tools/bump-core-version.js +0 -57
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
const fs = require("fs-extra");
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const crypto = require("crypto");
|
|
4
|
-
const glob = require("glob");
|
|
5
4
|
const yaml = require("js-yaml");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
// Initialize ES modules
|
|
11
|
-
async function initializeModules() {
|
|
12
|
-
if (!chalk) {
|
|
13
|
-
chalk = (await import("chalk")).default;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const { createReadStream, createWriteStream, promises: fsPromises } = require('fs');
|
|
7
|
+
const { pipeline } = require('stream/promises');
|
|
8
|
+
const resourceLocator = require('./resource-locator');
|
|
16
9
|
|
|
17
10
|
class FileManager {
|
|
18
11
|
constructor() {
|
|
@@ -23,10 +16,19 @@ class FileManager {
|
|
|
23
16
|
async copyFile(source, destination) {
|
|
24
17
|
try {
|
|
25
18
|
await fs.ensureDir(path.dirname(destination));
|
|
26
|
-
|
|
19
|
+
|
|
20
|
+
// Use streaming for large files (> 10MB)
|
|
21
|
+
const stats = await fs.stat(source);
|
|
22
|
+
if (stats.size > 10 * 1024 * 1024) {
|
|
23
|
+
await pipeline(
|
|
24
|
+
createReadStream(source),
|
|
25
|
+
createWriteStream(destination)
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
await fs.copy(source, destination);
|
|
29
|
+
}
|
|
27
30
|
return true;
|
|
28
31
|
} catch (error) {
|
|
29
|
-
await initializeModules();
|
|
30
32
|
console.error(chalk.red(`Failed to copy ${source}:`), error.message);
|
|
31
33
|
return false;
|
|
32
34
|
}
|
|
@@ -35,10 +37,28 @@ class FileManager {
|
|
|
35
37
|
async copyDirectory(source, destination) {
|
|
36
38
|
try {
|
|
37
39
|
await fs.ensureDir(destination);
|
|
38
|
-
|
|
40
|
+
|
|
41
|
+
// Use streaming copy for large directories
|
|
42
|
+
const files = await resourceLocator.findFiles('**/*', {
|
|
43
|
+
cwd: source,
|
|
44
|
+
nodir: true
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Process files in batches to avoid memory issues
|
|
48
|
+
const batchSize = 50;
|
|
49
|
+
for (let i = 0; i < files.length; i += batchSize) {
|
|
50
|
+
const batch = files.slice(i, i + batchSize);
|
|
51
|
+
await Promise.all(
|
|
52
|
+
batch.map(file =>
|
|
53
|
+
this.copyFile(
|
|
54
|
+
path.join(source, file),
|
|
55
|
+
path.join(destination, file)
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
39
60
|
return true;
|
|
40
61
|
} catch (error) {
|
|
41
|
-
await initializeModules();
|
|
42
62
|
console.error(
|
|
43
63
|
chalk.red(`Failed to copy directory ${source}:`),
|
|
44
64
|
error.message
|
|
@@ -48,7 +68,7 @@ class FileManager {
|
|
|
48
68
|
}
|
|
49
69
|
|
|
50
70
|
async copyGlobPattern(pattern, sourceDir, destDir, rootValue = null) {
|
|
51
|
-
const files =
|
|
71
|
+
const files = await resourceLocator.findFiles(pattern, { cwd: sourceDir });
|
|
52
72
|
const copied = [];
|
|
53
73
|
|
|
54
74
|
for (const file of files) {
|
|
@@ -75,12 +95,15 @@ class FileManager {
|
|
|
75
95
|
|
|
76
96
|
async calculateFileHash(filePath) {
|
|
77
97
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
98
|
+
// Use streaming for hash calculation to reduce memory usage
|
|
99
|
+
const stream = createReadStream(filePath);
|
|
100
|
+
const hash = crypto.createHash("sha256");
|
|
101
|
+
|
|
102
|
+
for await (const chunk of stream) {
|
|
103
|
+
hash.update(chunk);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return hash.digest("hex").slice(0, 16);
|
|
84
107
|
} catch (error) {
|
|
85
108
|
return null;
|
|
86
109
|
}
|
|
@@ -93,15 +116,14 @@ class FileManager {
|
|
|
93
116
|
this.manifestFile
|
|
94
117
|
);
|
|
95
118
|
|
|
96
|
-
// Read version from
|
|
97
|
-
const coreConfigPath = path.join(__dirname, "../../../bmad-core/core-config.yaml");
|
|
119
|
+
// Read version from package.json
|
|
98
120
|
let coreVersion = "unknown";
|
|
99
121
|
try {
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
coreVersion =
|
|
122
|
+
const packagePath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
123
|
+
const packageJson = require(packagePath);
|
|
124
|
+
coreVersion = packageJson.version;
|
|
103
125
|
} catch (error) {
|
|
104
|
-
console.warn("Could not read version from
|
|
126
|
+
console.warn("Could not read version from package.json, using 'unknown'");
|
|
105
127
|
}
|
|
106
128
|
|
|
107
129
|
const manifest = {
|
|
@@ -304,7 +326,6 @@ class FileManager {
|
|
|
304
326
|
|
|
305
327
|
return true;
|
|
306
328
|
} catch (error) {
|
|
307
|
-
await initializeModules();
|
|
308
329
|
console.error(chalk.red(`Failed to modify core-config.yaml:`), error.message);
|
|
309
330
|
return false;
|
|
310
331
|
}
|
|
@@ -312,22 +333,35 @@ class FileManager {
|
|
|
312
333
|
|
|
313
334
|
async copyFileWithRootReplacement(source, destination, rootValue) {
|
|
314
335
|
try {
|
|
315
|
-
//
|
|
316
|
-
const
|
|
317
|
-
const content = await fs.readFile(source, 'utf8');
|
|
318
|
-
|
|
319
|
-
// Replace {root} with the specified root value
|
|
320
|
-
const updatedContent = content.replace(/\{root\}/g, rootValue);
|
|
336
|
+
// Check file size to determine if we should stream
|
|
337
|
+
const stats = await fs.stat(source);
|
|
321
338
|
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
339
|
+
if (stats.size > 5 * 1024 * 1024) { // 5MB threshold
|
|
340
|
+
// Use streaming for large files
|
|
341
|
+
const { Transform } = require('stream');
|
|
342
|
+
const replaceStream = new Transform({
|
|
343
|
+
transform(chunk, encoding, callback) {
|
|
344
|
+
const modified = chunk.toString().replace(/\{root\}/g, rootValue);
|
|
345
|
+
callback(null, modified);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
await this.ensureDirectory(path.dirname(destination));
|
|
350
|
+
await pipeline(
|
|
351
|
+
createReadStream(source, { encoding: 'utf8' }),
|
|
352
|
+
replaceStream,
|
|
353
|
+
createWriteStream(destination, { encoding: 'utf8' })
|
|
354
|
+
);
|
|
355
|
+
} else {
|
|
356
|
+
// Regular approach for smaller files
|
|
357
|
+
const content = await fsPromises.readFile(source, 'utf8');
|
|
358
|
+
const updatedContent = content.replace(/\{root\}/g, rootValue);
|
|
359
|
+
await this.ensureDirectory(path.dirname(destination));
|
|
360
|
+
await fsPromises.writeFile(destination, updatedContent, 'utf8');
|
|
361
|
+
}
|
|
327
362
|
|
|
328
363
|
return true;
|
|
329
364
|
} catch (error) {
|
|
330
|
-
await initializeModules();
|
|
331
365
|
console.error(chalk.red(`Failed to copy ${source} with root replacement:`), error.message);
|
|
332
366
|
return false;
|
|
333
367
|
}
|
|
@@ -335,11 +369,10 @@ class FileManager {
|
|
|
335
369
|
|
|
336
370
|
async copyDirectoryWithRootReplacement(source, destination, rootValue, fileExtensions = ['.md', '.yaml', '.yml']) {
|
|
337
371
|
try {
|
|
338
|
-
await initializeModules(); // Ensure chalk is initialized
|
|
339
372
|
await this.ensureDirectory(destination);
|
|
340
373
|
|
|
341
374
|
// Get all files in source directory
|
|
342
|
-
const files =
|
|
375
|
+
const files = await resourceLocator.findFiles('**/*', {
|
|
343
376
|
cwd: source,
|
|
344
377
|
nodir: true
|
|
345
378
|
});
|
|
@@ -369,7 +402,6 @@ class FileManager {
|
|
|
369
402
|
|
|
370
403
|
return true;
|
|
371
404
|
} catch (error) {
|
|
372
|
-
await initializeModules();
|
|
373
405
|
console.error(chalk.red(`Failed to copy directory ${source} with root replacement:`), error.message);
|
|
374
406
|
return false;
|
|
375
407
|
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base IDE Setup - Common functionality for all IDE setups
|
|
3
|
+
* Reduces duplication and provides shared methods
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const fs = require("fs-extra");
|
|
8
|
+
const yaml = require("js-yaml");
|
|
9
|
+
const chalk = require("chalk");
|
|
10
|
+
const fileManager = require("./file-manager");
|
|
11
|
+
const resourceLocator = require("./resource-locator");
|
|
12
|
+
const { extractYamlFromAgent } = require("../../lib/yaml-utils");
|
|
13
|
+
|
|
14
|
+
class BaseIdeSetup {
|
|
15
|
+
constructor() {
|
|
16
|
+
this._agentCache = new Map();
|
|
17
|
+
this._pathCache = new Map();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get all agent IDs with caching
|
|
22
|
+
*/
|
|
23
|
+
async getAllAgentIds(installDir) {
|
|
24
|
+
const cacheKey = `all-agents:${installDir}`;
|
|
25
|
+
if (this._agentCache.has(cacheKey)) {
|
|
26
|
+
return this._agentCache.get(cacheKey);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const allAgents = new Set();
|
|
30
|
+
|
|
31
|
+
// Get core agents
|
|
32
|
+
const coreAgents = await this.getCoreAgentIds(installDir);
|
|
33
|
+
coreAgents.forEach(id => allAgents.add(id));
|
|
34
|
+
|
|
35
|
+
// Get expansion pack agents
|
|
36
|
+
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
37
|
+
for (const pack of expansionPacks) {
|
|
38
|
+
const packAgents = await this.getExpansionPackAgents(pack.path);
|
|
39
|
+
packAgents.forEach(id => allAgents.add(id));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = Array.from(allAgents);
|
|
43
|
+
this._agentCache.set(cacheKey, result);
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get core agent IDs
|
|
49
|
+
*/
|
|
50
|
+
async getCoreAgentIds(installDir) {
|
|
51
|
+
const coreAgents = [];
|
|
52
|
+
const corePaths = [
|
|
53
|
+
path.join(installDir, ".bmad-core", "agents"),
|
|
54
|
+
path.join(installDir, "bmad-core", "agents")
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
for (const agentsDir of corePaths) {
|
|
58
|
+
if (await fileManager.pathExists(agentsDir)) {
|
|
59
|
+
const files = await resourceLocator.findFiles("*.md", { cwd: agentsDir });
|
|
60
|
+
coreAgents.push(...files.map(file => path.basename(file, ".md")));
|
|
61
|
+
break; // Use first found
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return coreAgents;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Find agent path with caching
|
|
70
|
+
*/
|
|
71
|
+
async findAgentPath(agentId, installDir) {
|
|
72
|
+
const cacheKey = `agent-path:${agentId}:${installDir}`;
|
|
73
|
+
if (this._pathCache.has(cacheKey)) {
|
|
74
|
+
return this._pathCache.get(cacheKey);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Use resource locator for efficient path finding
|
|
78
|
+
let agentPath = await resourceLocator.getAgentPath(agentId);
|
|
79
|
+
|
|
80
|
+
if (!agentPath) {
|
|
81
|
+
// Check installation-specific paths
|
|
82
|
+
const possiblePaths = [
|
|
83
|
+
path.join(installDir, ".bmad-core", "agents", `${agentId}.md`),
|
|
84
|
+
path.join(installDir, "bmad-core", "agents", `${agentId}.md`),
|
|
85
|
+
path.join(installDir, "common", "agents", `${agentId}.md`)
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
for (const testPath of possiblePaths) {
|
|
89
|
+
if (await fileManager.pathExists(testPath)) {
|
|
90
|
+
agentPath = testPath;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (agentPath) {
|
|
97
|
+
this._pathCache.set(cacheKey, agentPath);
|
|
98
|
+
}
|
|
99
|
+
return agentPath;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get agent title from metadata
|
|
104
|
+
*/
|
|
105
|
+
async getAgentTitle(agentId, installDir) {
|
|
106
|
+
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
107
|
+
if (!agentPath) return agentId;
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const content = await fileManager.readFile(agentPath);
|
|
111
|
+
const yamlContent = extractYamlFromAgent(content);
|
|
112
|
+
if (yamlContent) {
|
|
113
|
+
const metadata = yaml.load(yamlContent);
|
|
114
|
+
return metadata.agent_name || agentId;
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// Fallback to agent ID
|
|
118
|
+
}
|
|
119
|
+
return agentId;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get installed expansion packs
|
|
124
|
+
*/
|
|
125
|
+
async getInstalledExpansionPacks(installDir) {
|
|
126
|
+
const cacheKey = `expansion-packs:${installDir}`;
|
|
127
|
+
if (this._pathCache.has(cacheKey)) {
|
|
128
|
+
return this._pathCache.get(cacheKey);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const expansionPacks = [];
|
|
132
|
+
|
|
133
|
+
// Check for dot-prefixed expansion packs
|
|
134
|
+
const dotExpansions = await resourceLocator.findFiles(".bmad-*", { cwd: installDir });
|
|
135
|
+
|
|
136
|
+
for (const dotExpansion of dotExpansions) {
|
|
137
|
+
if (dotExpansion !== ".bmad-core") {
|
|
138
|
+
const packPath = path.join(installDir, dotExpansion);
|
|
139
|
+
const packName = dotExpansion.substring(1); // remove the dot
|
|
140
|
+
expansionPacks.push({
|
|
141
|
+
name: packName,
|
|
142
|
+
path: packPath
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check other dot folders that have config.yaml
|
|
148
|
+
const allDotFolders = await resourceLocator.findFiles(".*", { cwd: installDir });
|
|
149
|
+
for (const folder of allDotFolders) {
|
|
150
|
+
if (!folder.startsWith(".bmad-") && folder !== ".bmad-core") {
|
|
151
|
+
const packPath = path.join(installDir, folder);
|
|
152
|
+
const configPath = path.join(packPath, "config.yaml");
|
|
153
|
+
if (await fileManager.pathExists(configPath)) {
|
|
154
|
+
expansionPacks.push({
|
|
155
|
+
name: folder.substring(1), // remove the dot
|
|
156
|
+
path: packPath
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this._pathCache.set(cacheKey, expansionPacks);
|
|
163
|
+
return expansionPacks;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get expansion pack agents
|
|
168
|
+
*/
|
|
169
|
+
async getExpansionPackAgents(packPath) {
|
|
170
|
+
const agentsDir = path.join(packPath, "agents");
|
|
171
|
+
if (!(await fileManager.pathExists(agentsDir))) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const agentFiles = await resourceLocator.findFiles("*.md", { cwd: agentsDir });
|
|
176
|
+
return agentFiles.map(file => path.basename(file, ".md"));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create agent rule content (shared logic)
|
|
181
|
+
*/
|
|
182
|
+
async createAgentRuleContent(agentId, agentPath, installDir, format = 'mdc') {
|
|
183
|
+
const agentContent = await fileManager.readFile(agentPath);
|
|
184
|
+
const agentTitle = await this.getAgentTitle(agentId, installDir);
|
|
185
|
+
const yamlContent = extractYamlFromAgent(agentContent);
|
|
186
|
+
|
|
187
|
+
let content = "";
|
|
188
|
+
|
|
189
|
+
if (format === 'mdc') {
|
|
190
|
+
// MDC format for Cursor
|
|
191
|
+
content = "---\n";
|
|
192
|
+
content += "description: \n";
|
|
193
|
+
content += "globs: []\n";
|
|
194
|
+
content += "alwaysApply: false\n";
|
|
195
|
+
content += "---\n\n";
|
|
196
|
+
content += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
197
|
+
content += `This rule is triggered when the user types \`@${agentId}\` and activates the ${agentTitle} agent persona.\n\n`;
|
|
198
|
+
content += "## Agent Activation\n\n";
|
|
199
|
+
content += "CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
|
|
200
|
+
content += "```yaml\n";
|
|
201
|
+
content += yamlContent || agentContent.replace(/^#.*$/m, "").trim();
|
|
202
|
+
content += "\n```\n\n";
|
|
203
|
+
content += "## File Reference\n\n";
|
|
204
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
205
|
+
content += `The complete agent definition is available in [${relativePath}](mdc:${relativePath}).\n\n`;
|
|
206
|
+
content += "## Usage\n\n";
|
|
207
|
+
content += `When the user types \`@${agentId}\`, activate this ${agentTitle} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
208
|
+
} else if (format === 'claude') {
|
|
209
|
+
// Claude Code format
|
|
210
|
+
content = `# /${agentId} Command\n\n`;
|
|
211
|
+
content += `When this command is used, adopt the following agent persona:\n\n`;
|
|
212
|
+
content += agentContent;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return content;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Clear all caches
|
|
220
|
+
*/
|
|
221
|
+
clearCache() {
|
|
222
|
+
this._agentCache.clear();
|
|
223
|
+
this._pathCache.clear();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = BaseIdeSetup;
|
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const fs = require("fs-extra");
|
|
3
3
|
const yaml = require("js-yaml");
|
|
4
|
+
const chalk = require("chalk");
|
|
5
|
+
const inquirer = require("inquirer");
|
|
4
6
|
const fileManager = require("./file-manager");
|
|
5
7
|
const configLoader = require("./config-loader");
|
|
6
8
|
const { extractYamlFromAgent } = require("../../lib/yaml-utils");
|
|
9
|
+
const BaseIdeSetup = require("./ide-base-setup");
|
|
10
|
+
const resourceLocator = require("./resource-locator");
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
let chalk;
|
|
10
|
-
let inquirer;
|
|
11
|
-
|
|
12
|
-
// Initialize ES modules
|
|
13
|
-
async function initializeModules() {
|
|
14
|
-
if (!chalk) {
|
|
15
|
-
chalk = (await import("chalk")).default;
|
|
16
|
-
}
|
|
17
|
-
if (!inquirer) {
|
|
18
|
-
inquirer = (await import("inquirer")).default;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
class IdeSetup {
|
|
12
|
+
class IdeSetup extends BaseIdeSetup {
|
|
23
13
|
constructor() {
|
|
14
|
+
super();
|
|
24
15
|
this.ideAgentConfig = null;
|
|
25
16
|
}
|
|
26
17
|
|
|
@@ -42,7 +33,6 @@ class IdeSetup {
|
|
|
42
33
|
}
|
|
43
34
|
|
|
44
35
|
async setup(ide, installDir, selectedAgent = null, spinner = null, preConfiguredSettings = null) {
|
|
45
|
-
await initializeModules();
|
|
46
36
|
const ideConfig = await configLoader.getIdeConfiguration(ide);
|
|
47
37
|
|
|
48
38
|
if (!ideConfig) {
|
|
@@ -80,53 +70,17 @@ class IdeSetup {
|
|
|
80
70
|
await fileManager.ensureDirectory(cursorRulesDir);
|
|
81
71
|
|
|
82
72
|
for (const agentId of agents) {
|
|
83
|
-
// Find the agent file
|
|
84
73
|
const agentPath = await this.findAgentPath(agentId, installDir);
|
|
85
74
|
|
|
86
75
|
if (agentPath) {
|
|
87
|
-
const
|
|
76
|
+
const mdcContent = await this.createAgentRuleContent(agentId, agentPath, installDir, 'mdc');
|
|
88
77
|
const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
|
|
89
|
-
|
|
90
|
-
// Create MDC content with proper format
|
|
91
|
-
let mdcContent = "---\n";
|
|
92
|
-
mdcContent += "description: \n";
|
|
93
|
-
mdcContent += "globs: []\n";
|
|
94
|
-
mdcContent += "alwaysApply: false\n";
|
|
95
|
-
mdcContent += "---\n\n";
|
|
96
|
-
mdcContent += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
97
|
-
mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${await this.getAgentTitle(
|
|
98
|
-
agentId,
|
|
99
|
-
installDir
|
|
100
|
-
)} agent persona.\n\n`;
|
|
101
|
-
mdcContent += "## Agent Activation\n\n";
|
|
102
|
-
mdcContent +=
|
|
103
|
-
"CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
|
|
104
|
-
mdcContent += "```yaml\n";
|
|
105
|
-
// Extract just the YAML content from the agent file
|
|
106
|
-
const yamlContent = extractYamlFromAgent(agentContent);
|
|
107
|
-
if (yamlContent) {
|
|
108
|
-
mdcContent += yamlContent;
|
|
109
|
-
} else {
|
|
110
|
-
// If no YAML found, include the whole content minus the header
|
|
111
|
-
mdcContent += agentContent.replace(/^#.*$/m, "").trim();
|
|
112
|
-
}
|
|
113
|
-
mdcContent += "\n```\n\n";
|
|
114
|
-
mdcContent += "## File Reference\n\n";
|
|
115
|
-
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
116
|
-
mdcContent += `The complete agent definition is available in [${relativePath}](mdc:${relativePath}).\n\n`;
|
|
117
|
-
mdcContent += "## Usage\n\n";
|
|
118
|
-
mdcContent += `When the user types \`@${agentId}\`, activate this ${await this.getAgentTitle(
|
|
119
|
-
agentId,
|
|
120
|
-
installDir
|
|
121
|
-
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
122
|
-
|
|
123
78
|
await fileManager.writeFile(mdcPath, mdcContent);
|
|
124
79
|
console.log(chalk.green(`✓ Created rule: ${agentId}.mdc`));
|
|
125
80
|
}
|
|
126
81
|
}
|
|
127
82
|
|
|
128
83
|
console.log(chalk.green(`\n✓ Created Cursor rules in ${cursorRulesDir}`));
|
|
129
|
-
|
|
130
84
|
return true;
|
|
131
85
|
}
|
|
132
86
|
|
|
@@ -827,7 +781,6 @@ class IdeSetup {
|
|
|
827
781
|
}
|
|
828
782
|
|
|
829
783
|
async setupGeminiCli(installDir) {
|
|
830
|
-
await initializeModules();
|
|
831
784
|
const geminiDir = path.join(installDir, ".gemini");
|
|
832
785
|
const bmadMethodDir = path.join(geminiDir, "bmad-method");
|
|
833
786
|
await fileManager.ensureDirectory(bmadMethodDir);
|
|
@@ -928,8 +881,6 @@ class IdeSetup {
|
|
|
928
881
|
}
|
|
929
882
|
|
|
930
883
|
async setupGitHubCopilot(installDir, selectedAgent, spinner = null, preConfiguredSettings = null) {
|
|
931
|
-
await initializeModules();
|
|
932
|
-
|
|
933
884
|
// Configure VS Code workspace settings first to avoid UI conflicts with loading spinners
|
|
934
885
|
await this.configureVsCodeSettings(installDir, spinner, preConfiguredSettings);
|
|
935
886
|
|
|
@@ -960,7 +911,7 @@ class IdeSetup {
|
|
|
960
911
|
|
|
961
912
|
let chatmodeContent = `---
|
|
962
913
|
description: "${description.replace(/"/g, '\\"')}"
|
|
963
|
-
tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'usages']
|
|
914
|
+
tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems', 'usages', 'editFiles', 'runCommands', 'runTasks', 'runTests', 'search', 'searchResults', 'terminalLastCommand', 'terminalSelection', 'testFailure']
|
|
964
915
|
---
|
|
965
916
|
|
|
966
917
|
`;
|
|
@@ -978,7 +929,6 @@ tools: ['changes', 'codebase', 'fetch', 'findTestFiles', 'githubRepo', 'problems
|
|
|
978
929
|
}
|
|
979
930
|
|
|
980
931
|
async configureVsCodeSettings(installDir, spinner, preConfiguredSettings = null) {
|
|
981
|
-
await initializeModules(); // Ensure inquirer is loaded
|
|
982
932
|
const vscodeDir = path.join(installDir, ".vscode");
|
|
983
933
|
const settingsPath = path.join(vscodeDir, "settings.json");
|
|
984
934
|
|