@zeyue0329/xiaoma-cli 1.0.37 → 1.0.38
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/.idea/workspace.xml +27 -26
- package/JAVA-BACKEND-COMMANDS-REFERENCE.md +62 -52
- package/JAVA-BACKEND-ITERATION-GUIDE.md +125 -18
- package/README.md +1 -1
- package/common/utils/bmad-doc-template.md +5 -5
- package/dist/agents/analyst.txt +35 -5
- package/dist/agents/architect.txt +217 -31
- package/dist/agents/automation-orchestrator.txt +4 -4
- package/dist/agents/dev.txt +3 -3
- package/dist/agents/full-requirement-orchestrator.txt +11 -11
- package/dist/agents/qa.txt +102 -102
- package/dist/agents/sm.txt +6 -6
- package/dist/agents/ux-expert.txt +6 -1
- package/dist/agents/workflow-executor.txt +879 -0
- package/dist/agents/xiaoma-master.txt +258 -37
- package/dist/teams/team-all.txt +1223 -445
- package/dist/teams/team-fullstack-with-database.txt +384 -446
- package/dist/teams/team-fullstack.txt +258 -37
- package/dist/teams/team-ide-minimal.txt +111 -111
- package/dist/teams/team-no-ui.txt +252 -36
- package/docs/architecture-sharding-modification.md +623 -0
- package/docs/automated-requirements-analysis-outputs.md +896 -0
- package/package.json +1 -1
- package/tools/builders/web-builder.js +292 -142
- package/tools/bump-all-versions.js +50 -32
- package/tools/cli.js +52 -47
- package/tools/flattener/aggregate.js +30 -12
- package/tools/flattener/binary.js +46 -43
- package/tools/flattener/discovery.js +23 -15
- package/tools/flattener/files.js +6 -6
- package/tools/flattener/ignoreRules.js +122 -121
- package/tools/flattener/main.js +249 -144
- package/tools/flattener/projectRoot.js +74 -69
- package/tools/flattener/prompts.js +12 -10
- package/tools/flattener/stats.helpers.js +90 -61
- package/tools/flattener/stats.js +1 -1
- package/tools/flattener/test-matrix.js +225 -170
- package/tools/flattener/xml.js +31 -23
- package/tools/installer/bin/xiaoma.js +199 -153
- package/tools/installer/lib/config-loader.js +76 -47
- package/tools/installer/lib/file-manager.js +101 -44
- package/tools/installer/lib/ide-base-setup.js +49 -39
- package/tools/installer/lib/ide-setup.js +694 -380
- package/tools/installer/lib/installer.js +802 -469
- package/tools/installer/lib/memory-profiler.js +22 -12
- package/tools/installer/lib/module-manager.js +16 -14
- package/tools/installer/lib/resource-locator.js +61 -35
- package/tools/lib/dependency-resolver.js +34 -23
- package/tools/lib/yaml-utils.js +7 -2
- package/tools/preview-release-notes.js +33 -25
- package/tools/shared/bannerArt.js +3 -3
- package/tools/sync-installer-version.js +16 -7
- package/tools/upgraders/v3-to-v4-upgrader.js +244 -163
- package/tools/version-bump.js +24 -18
- package/tools/xiaoma-npx-wrapper.js +15 -10
- package/tools/yaml-format.js +60 -36
- package/xiaoma-core/agent-teams/team-fullstack-with-database.yaml +0 -1
- package/xiaoma-core/agents/automated-fix-validator.yaml +2 -1
- package/xiaoma-core/agents/automated-quality-validator.yaml +10 -5
- package/xiaoma-core/agents/automation-orchestrator.md +4 -4
- package/xiaoma-core/agents/dev.md +4 -4
- package/xiaoma-core/agents/enhanced-workflow-orchestrator.yaml +2 -1
- package/xiaoma-core/agents/full-requirement-orchestrator.md +11 -11
- package/xiaoma-core/agents/global-requirements-auditor.yaml +11 -3
- package/xiaoma-core/agents/intelligent-template-adapter.yaml +19 -5
- package/xiaoma-core/agents/master-execution-engine.yaml +19 -5
- package/xiaoma-core/agents/workflow-executor.md +8 -4
- package/xiaoma-core/agents/xiaoma-master.md +1 -1
- package/xiaoma-core/data/test-levels-framework.md +12 -12
- package/xiaoma-core/tasks/analyze-existing-database.md +1 -1
- package/xiaoma-core/tasks/apply-qa-fixes.md +3 -3
- package/xiaoma-core/tasks/batch-story-generation.md +22 -22
- package/xiaoma-core/tasks/create-enhanced-story-with-database.md +6 -6
- package/xiaoma-core/tasks/nfr-assess.md +6 -6
- package/xiaoma-core/tasks/project-integration-testing.md +42 -42
- package/xiaoma-core/tasks/qa-gate.md +23 -23
- package/xiaoma-core/tasks/review-story.md +18 -18
- package/xiaoma-core/tasks/risk-profile.md +25 -25
- package/xiaoma-core/tasks/serial-development-orchestration.md +51 -51
- package/xiaoma-core/tasks/test-design.md +9 -9
- package/xiaoma-core/tasks/trace-requirements.md +21 -21
- package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +35 -5
- package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +77 -11
- package/xiaoma-core/templates/front-end-spec-tmpl.yaml +6 -1
- package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +140 -20
- package/xiaoma-core/templates/global-qa-monitoring-tmpl.yaml +2 -1
- package/xiaoma-core/templates/requirements-coverage-audit.yaml +2 -1
- package/xiaoma-core/workflows/automated-requirements-analysis.yaml +4 -4
- package/dist/agents/database-architect.txt +0 -322
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
const fs = require(
|
|
2
|
-
const path = require(
|
|
3
|
-
const DependencyResolver = require(
|
|
4
|
-
const yamlUtilities = require(
|
|
1
|
+
const fs = require("node:fs").promises;
|
|
2
|
+
const path = require("node:path");
|
|
3
|
+
const DependencyResolver = require("../lib/dependency-resolver");
|
|
4
|
+
const yamlUtilities = require("../lib/yaml-utils");
|
|
5
5
|
|
|
6
6
|
class WebBuilder {
|
|
7
7
|
constructor(options = {}) {
|
|
8
8
|
this.rootDir = options.rootDir || process.cwd();
|
|
9
|
-
this.outputDirs = options.outputDirs || [path.join(this.rootDir,
|
|
9
|
+
this.outputDirs = options.outputDirs || [path.join(this.rootDir, "dist")];
|
|
10
10
|
this.resolver = new DependencyResolver(this.rootDir);
|
|
11
11
|
this.templatePath = path.join(
|
|
12
12
|
this.rootDir,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"tools",
|
|
14
|
+
"md-assets",
|
|
15
|
+
"web-agent-startup-instructions.md",
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
parseYaml(content) {
|
|
20
|
-
const yaml = require(
|
|
20
|
+
const yaml = require("js-yaml");
|
|
21
21
|
return yaml.load(content);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
convertToWebPath(filePath, bundleRoot =
|
|
24
|
+
convertToWebPath(filePath, bundleRoot = "xiaoma-core") {
|
|
25
25
|
// Convert absolute paths to web bundle paths with dot prefix
|
|
26
26
|
// All resources get installed under the bundle root, so use that path
|
|
27
27
|
const relativePath = path.relative(this.rootDir, filePath);
|
|
28
28
|
const pathParts = relativePath.split(path.sep);
|
|
29
29
|
|
|
30
30
|
let resourcePath;
|
|
31
|
-
if (pathParts[0] ===
|
|
31
|
+
if (pathParts[0] === "expansion-packs") {
|
|
32
32
|
// For expansion packs, remove 'expansion-packs/packname' and use the rest
|
|
33
|
-
resourcePath = pathParts.slice(2).join(
|
|
33
|
+
resourcePath = pathParts.slice(2).join("/");
|
|
34
34
|
} else {
|
|
35
35
|
// For xiaoma-core, common, etc., remove the first part
|
|
36
|
-
resourcePath = pathParts.slice(1).join(
|
|
36
|
+
resourcePath = pathParts.slice(1).join("/");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
return `.${bundleRoot}/${resourcePath}`;
|
|
@@ -41,22 +41,22 @@ class WebBuilder {
|
|
|
41
41
|
|
|
42
42
|
generateWebInstructions(bundleType, packName = null) {
|
|
43
43
|
// Generate dynamic web instructions based on bundle type
|
|
44
|
-
const rootExample = packName ? `.${packName}` :
|
|
44
|
+
const rootExample = packName ? `.${packName}` : ".xiaoma-core";
|
|
45
45
|
const examplePath = packName
|
|
46
46
|
? `.${packName}/folder/filename.md`
|
|
47
|
-
:
|
|
47
|
+
: ".xiaoma-core/folder/filename.md";
|
|
48
48
|
const personasExample = packName
|
|
49
49
|
? `.${packName}/personas/analyst.md`
|
|
50
|
-
:
|
|
50
|
+
: ".xiaoma-core/personas/analyst.md";
|
|
51
51
|
const tasksExample = packName
|
|
52
52
|
? `.${packName}/tasks/create-story.md`
|
|
53
|
-
:
|
|
53
|
+
: ".xiaoma-core/tasks/create-story.md";
|
|
54
54
|
const utilitiesExample = packName
|
|
55
55
|
? `.${packName}/utils/template-format.md`
|
|
56
|
-
:
|
|
56
|
+
: ".xiaoma-core/utils/template-format.md";
|
|
57
57
|
const tasksReference = packName
|
|
58
58
|
? `.${packName}/tasks/create-story.md`
|
|
59
|
-
:
|
|
59
|
+
: ".xiaoma-core/tasks/create-story.md";
|
|
60
60
|
|
|
61
61
|
return `# Web Agent Bundle Instructions
|
|
62
62
|
|
|
@@ -122,14 +122,16 @@ These references map directly to bundle sections:
|
|
|
122
122
|
|
|
123
123
|
// Write to all output directories
|
|
124
124
|
for (const outputDir of this.outputDirs) {
|
|
125
|
-
const outputPath = path.join(outputDir,
|
|
125
|
+
const outputPath = path.join(outputDir, "agents");
|
|
126
126
|
await fs.mkdir(outputPath, { recursive: true });
|
|
127
127
|
const outputFile = path.join(outputPath, `${agentId}.txt`);
|
|
128
|
-
await fs.writeFile(outputFile, bundle,
|
|
128
|
+
await fs.writeFile(outputFile, bundle, "utf8");
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
console.log(
|
|
132
|
+
console.log(
|
|
133
|
+
`Built ${agents.length} agent bundles in ${this.outputDirs.length} locations`,
|
|
134
|
+
);
|
|
133
135
|
}
|
|
134
136
|
|
|
135
137
|
async buildTeams() {
|
|
@@ -141,58 +143,76 @@ These references map directly to bundle sections:
|
|
|
141
143
|
|
|
142
144
|
// Write to all output directories
|
|
143
145
|
for (const outputDir of this.outputDirs) {
|
|
144
|
-
const outputPath = path.join(outputDir,
|
|
146
|
+
const outputPath = path.join(outputDir, "teams");
|
|
145
147
|
await fs.mkdir(outputPath, { recursive: true });
|
|
146
148
|
const outputFile = path.join(outputPath, `${teamId}.txt`);
|
|
147
|
-
await fs.writeFile(outputFile, bundle,
|
|
149
|
+
await fs.writeFile(outputFile, bundle, "utf8");
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
console.log(
|
|
153
|
+
console.log(
|
|
154
|
+
`Built ${teams.length} team bundles in ${this.outputDirs.length} locations`,
|
|
155
|
+
);
|
|
152
156
|
}
|
|
153
157
|
|
|
154
158
|
async buildAgentBundle(agentId) {
|
|
155
159
|
const dependencies = await this.resolver.resolveAgentDependencies(agentId);
|
|
156
|
-
const template = this.generateWebInstructions(
|
|
160
|
+
const template = this.generateWebInstructions("agent");
|
|
157
161
|
|
|
158
162
|
const sections = [template];
|
|
159
163
|
|
|
160
164
|
// Add agent configuration
|
|
161
|
-
const agentPath = this.convertToWebPath(
|
|
162
|
-
|
|
165
|
+
const agentPath = this.convertToWebPath(
|
|
166
|
+
dependencies.agent.path,
|
|
167
|
+
"xiaoma-core",
|
|
168
|
+
);
|
|
169
|
+
sections.push(
|
|
170
|
+
this.formatSection(agentPath, dependencies.agent.content, "xiaoma-core"),
|
|
171
|
+
);
|
|
163
172
|
|
|
164
173
|
// Add all dependencies
|
|
165
174
|
for (const resource of dependencies.resources) {
|
|
166
|
-
const resourcePath = this.convertToWebPath(resource.path,
|
|
167
|
-
sections.push(
|
|
175
|
+
const resourcePath = this.convertToWebPath(resource.path, "xiaoma-core");
|
|
176
|
+
sections.push(
|
|
177
|
+
this.formatSection(resourcePath, resource.content, "xiaoma-core"),
|
|
178
|
+
);
|
|
168
179
|
}
|
|
169
180
|
|
|
170
|
-
return sections.join(
|
|
181
|
+
return sections.join("\n");
|
|
171
182
|
}
|
|
172
183
|
|
|
173
184
|
async buildTeamBundle(teamId) {
|
|
174
185
|
const dependencies = await this.resolver.resolveTeamDependencies(teamId);
|
|
175
|
-
const template = this.generateWebInstructions(
|
|
186
|
+
const template = this.generateWebInstructions("team");
|
|
176
187
|
|
|
177
188
|
const sections = [template];
|
|
178
189
|
|
|
179
190
|
// Add team configuration
|
|
180
|
-
const teamPath = this.convertToWebPath(
|
|
181
|
-
|
|
191
|
+
const teamPath = this.convertToWebPath(
|
|
192
|
+
dependencies.team.path,
|
|
193
|
+
"xiaoma-core",
|
|
194
|
+
);
|
|
195
|
+
sections.push(
|
|
196
|
+
this.formatSection(teamPath, dependencies.team.content, "xiaoma-core"),
|
|
197
|
+
);
|
|
182
198
|
|
|
183
199
|
// Add all agents
|
|
184
200
|
for (const agent of dependencies.agents) {
|
|
185
|
-
const agentPath = this.convertToWebPath(agent.path,
|
|
186
|
-
sections.push(
|
|
201
|
+
const agentPath = this.convertToWebPath(agent.path, "xiaoma-core");
|
|
202
|
+
sections.push(
|
|
203
|
+
this.formatSection(agentPath, agent.content, "xiaoma-core"),
|
|
204
|
+
);
|
|
187
205
|
}
|
|
188
206
|
|
|
189
207
|
// Add all deduplicated resources
|
|
190
208
|
for (const resource of dependencies.resources) {
|
|
191
|
-
const resourcePath = this.convertToWebPath(resource.path,
|
|
192
|
-
sections.push(
|
|
209
|
+
const resourcePath = this.convertToWebPath(resource.path, "xiaoma-core");
|
|
210
|
+
sections.push(
|
|
211
|
+
this.formatSection(resourcePath, resource.content, "xiaoma-core"),
|
|
212
|
+
);
|
|
193
213
|
}
|
|
194
214
|
|
|
195
|
-
return sections.join(
|
|
215
|
+
return sections.join("\n");
|
|
196
216
|
}
|
|
197
217
|
|
|
198
218
|
processAgentContent(content) {
|
|
@@ -208,50 +228,53 @@ These references map directly to bundle sections:
|
|
|
208
228
|
|
|
209
229
|
// Parse YAML and remove root and IDE-FILE-RESOLUTION properties
|
|
210
230
|
try {
|
|
211
|
-
const yaml = require(
|
|
231
|
+
const yaml = require("js-yaml");
|
|
212
232
|
const parsed = yaml.load(yamlContent);
|
|
213
233
|
|
|
214
234
|
// Remove the properties if they exist at root level
|
|
215
235
|
delete parsed.root;
|
|
216
|
-
delete parsed[
|
|
217
|
-
delete parsed[
|
|
236
|
+
delete parsed["IDE-FILE-RESOLUTION"];
|
|
237
|
+
delete parsed["REQUEST-RESOLUTION"];
|
|
218
238
|
|
|
219
239
|
// Also remove from activation-instructions if they exist
|
|
220
|
-
if (
|
|
221
|
-
parsed[
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
240
|
+
if (
|
|
241
|
+
parsed["activation-instructions"] &&
|
|
242
|
+
Array.isArray(parsed["activation-instructions"])
|
|
243
|
+
) {
|
|
244
|
+
parsed["activation-instructions"] = parsed[
|
|
245
|
+
"activation-instructions"
|
|
246
|
+
].filter((instruction) => {
|
|
247
|
+
return (
|
|
248
|
+
typeof instruction === "string" &&
|
|
249
|
+
!instruction.startsWith("IDE-FILE-RESOLUTION:") &&
|
|
250
|
+
!instruction.startsWith("REQUEST-RESOLUTION:")
|
|
251
|
+
);
|
|
252
|
+
});
|
|
230
253
|
}
|
|
231
254
|
|
|
232
255
|
// Reconstruct the YAML
|
|
233
256
|
const cleanedYaml = yaml.dump(parsed, { lineWidth: -1 });
|
|
234
257
|
|
|
235
258
|
// Get the agent name from the YAML for the header
|
|
236
|
-
const agentName = parsed.agent?.id ||
|
|
259
|
+
const agentName = parsed.agent?.id || "agent";
|
|
237
260
|
|
|
238
261
|
// Build the new content with just the agent header and YAML
|
|
239
262
|
const newHeader = `# ${agentName}\n\nCRITICAL: 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`;
|
|
240
263
|
const afterYaml = content.slice(Math.max(0, yamlEndIndex));
|
|
241
264
|
|
|
242
|
-
return newHeader +
|
|
265
|
+
return newHeader + "```yaml\n" + cleanedYaml.trim() + "\n```" + afterYaml;
|
|
243
266
|
} catch (error) {
|
|
244
|
-
console.warn(
|
|
267
|
+
console.warn("Failed to process agent YAML:", error.message);
|
|
245
268
|
// If parsing fails, return original content
|
|
246
269
|
return content;
|
|
247
270
|
}
|
|
248
271
|
}
|
|
249
272
|
|
|
250
|
-
formatSection(path, content, bundleRoot =
|
|
251
|
-
const separator =
|
|
273
|
+
formatSection(path, content, bundleRoot = "xiaoma-core") {
|
|
274
|
+
const separator = "====================";
|
|
252
275
|
|
|
253
276
|
// Process agent content if this is an agent file
|
|
254
|
-
if (path.includes(
|
|
277
|
+
if (path.includes("/agents/")) {
|
|
255
278
|
content = this.processAgentContent(content);
|
|
256
279
|
}
|
|
257
280
|
|
|
@@ -262,17 +285,17 @@ These references map directly to bundle sections:
|
|
|
262
285
|
`${separator} START: ${path} ${separator}`,
|
|
263
286
|
content.trim(),
|
|
264
287
|
`${separator} END: ${path} ${separator}`,
|
|
265
|
-
|
|
266
|
-
].join(
|
|
288
|
+
"",
|
|
289
|
+
].join("\n");
|
|
267
290
|
}
|
|
268
291
|
|
|
269
292
|
replaceRootReferences(content, bundleRoot) {
|
|
270
293
|
// Replace {root} with the appropriate bundle root path
|
|
271
|
-
return content.replaceAll(
|
|
294
|
+
return content.replaceAll("{root}", `.${bundleRoot}`);
|
|
272
295
|
}
|
|
273
296
|
|
|
274
297
|
async validate() {
|
|
275
|
-
console.log(
|
|
298
|
+
console.log("Validating agent configurations...");
|
|
276
299
|
const agents = await this.resolver.listAgents();
|
|
277
300
|
for (const agentId of agents) {
|
|
278
301
|
try {
|
|
@@ -284,7 +307,7 @@ These references map directly to bundle sections:
|
|
|
284
307
|
}
|
|
285
308
|
}
|
|
286
309
|
|
|
287
|
-
console.log(
|
|
310
|
+
console.log("\nValidating team configurations...");
|
|
288
311
|
const teams = await this.resolver.listTeams();
|
|
289
312
|
for (const teamId of teams) {
|
|
290
313
|
try {
|
|
@@ -309,8 +332,10 @@ These references map directly to bundle sections:
|
|
|
309
332
|
}
|
|
310
333
|
|
|
311
334
|
async buildExpansionPack(packName, options = {}) {
|
|
312
|
-
const packDir = path.join(this.rootDir,
|
|
313
|
-
const outputDirectories = [
|
|
335
|
+
const packDir = path.join(this.rootDir, "expansion-packs", packName);
|
|
336
|
+
const outputDirectories = [
|
|
337
|
+
path.join(this.rootDir, "dist", "expansion-packs", packName),
|
|
338
|
+
];
|
|
314
339
|
|
|
315
340
|
// Clean output directories if requested
|
|
316
341
|
if (options.clean !== false) {
|
|
@@ -324,27 +349,31 @@ These references map directly to bundle sections:
|
|
|
324
349
|
}
|
|
325
350
|
|
|
326
351
|
// Build individual agents first
|
|
327
|
-
const agentsDir = path.join(packDir,
|
|
352
|
+
const agentsDir = path.join(packDir, "agents");
|
|
328
353
|
try {
|
|
329
354
|
const agentFiles = await fs.readdir(agentsDir);
|
|
330
|
-
const agentMarkdownFiles = agentFiles.filter((f) => f.endsWith(
|
|
355
|
+
const agentMarkdownFiles = agentFiles.filter((f) => f.endsWith(".md"));
|
|
331
356
|
|
|
332
357
|
if (agentMarkdownFiles.length > 0) {
|
|
333
358
|
console.log(` Building individual agents for ${packName}:`);
|
|
334
359
|
|
|
335
360
|
for (const agentFile of agentMarkdownFiles) {
|
|
336
|
-
const agentName = agentFile.replace(
|
|
361
|
+
const agentName = agentFile.replace(".md", "");
|
|
337
362
|
console.log(` - ${agentName}`);
|
|
338
363
|
|
|
339
364
|
// Build individual agent bundle
|
|
340
|
-
const bundle = await this.buildExpansionAgentBundle(
|
|
365
|
+
const bundle = await this.buildExpansionAgentBundle(
|
|
366
|
+
packName,
|
|
367
|
+
packDir,
|
|
368
|
+
agentName,
|
|
369
|
+
);
|
|
341
370
|
|
|
342
371
|
// Write to all output directories
|
|
343
372
|
for (const outputDir of outputDirectories) {
|
|
344
|
-
const agentsOutputDir = path.join(outputDir,
|
|
373
|
+
const agentsOutputDir = path.join(outputDir, "agents");
|
|
345
374
|
await fs.mkdir(agentsOutputDir, { recursive: true });
|
|
346
375
|
const outputFile = path.join(agentsOutputDir, `${agentName}.txt`);
|
|
347
|
-
await fs.writeFile(outputFile, bundle,
|
|
376
|
+
await fs.writeFile(outputFile, bundle, "utf8");
|
|
348
377
|
}
|
|
349
378
|
}
|
|
350
379
|
}
|
|
@@ -353,28 +382,39 @@ These references map directly to bundle sections:
|
|
|
353
382
|
}
|
|
354
383
|
|
|
355
384
|
// Build team bundle
|
|
356
|
-
const agentTeamsDir = path.join(packDir,
|
|
385
|
+
const agentTeamsDir = path.join(packDir, "agent-teams");
|
|
357
386
|
try {
|
|
358
387
|
const teamFiles = await fs.readdir(agentTeamsDir);
|
|
359
|
-
const teamFile = teamFiles.find((f) => f.endsWith(
|
|
388
|
+
const teamFile = teamFiles.find((f) => f.endsWith(".yaml"));
|
|
360
389
|
|
|
361
390
|
if (teamFile) {
|
|
362
391
|
console.log(` Building team bundle for ${packName}`);
|
|
363
392
|
const teamConfigPath = path.join(agentTeamsDir, teamFile);
|
|
364
393
|
|
|
365
394
|
// Build expansion pack as a team bundle
|
|
366
|
-
const bundle = await this.buildExpansionTeamBundle(
|
|
395
|
+
const bundle = await this.buildExpansionTeamBundle(
|
|
396
|
+
packName,
|
|
397
|
+
packDir,
|
|
398
|
+
teamConfigPath,
|
|
399
|
+
);
|
|
367
400
|
|
|
368
401
|
// Write to all output directories
|
|
369
402
|
for (const outputDir of outputDirectories) {
|
|
370
|
-
const teamsOutputDir = path.join(outputDir,
|
|
403
|
+
const teamsOutputDir = path.join(outputDir, "teams");
|
|
371
404
|
await fs.mkdir(teamsOutputDir, { recursive: true });
|
|
372
|
-
const outputFile = path.join(
|
|
373
|
-
|
|
374
|
-
|
|
405
|
+
const outputFile = path.join(
|
|
406
|
+
teamsOutputDir,
|
|
407
|
+
teamFile.replace(".yaml", ".txt"),
|
|
408
|
+
);
|
|
409
|
+
await fs.writeFile(outputFile, bundle, "utf8");
|
|
410
|
+
console.log(
|
|
411
|
+
` ✓ Created bundle: ${path.relative(this.rootDir, outputFile)}`,
|
|
412
|
+
);
|
|
375
413
|
}
|
|
376
414
|
} else {
|
|
377
|
-
console.warn(
|
|
415
|
+
console.warn(
|
|
416
|
+
` ⚠ No team configuration found in ${packName}/agent-teams/`,
|
|
417
|
+
);
|
|
378
418
|
}
|
|
379
419
|
} catch {
|
|
380
420
|
console.warn(` ⚠ No agent-teams directory found for ${packName}`);
|
|
@@ -382,12 +422,12 @@ These references map directly to bundle sections:
|
|
|
382
422
|
}
|
|
383
423
|
|
|
384
424
|
async buildExpansionAgentBundle(packName, packDir, agentName) {
|
|
385
|
-
const template = this.generateWebInstructions(
|
|
425
|
+
const template = this.generateWebInstructions("expansion-agent", packName);
|
|
386
426
|
const sections = [template];
|
|
387
427
|
|
|
388
428
|
// Add agent configuration
|
|
389
|
-
const agentPath = path.join(packDir,
|
|
390
|
-
const agentContent = await fs.readFile(agentPath,
|
|
429
|
+
const agentPath = path.join(packDir, "agents", `${agentName}.md`);
|
|
430
|
+
const agentContent = await fs.readFile(agentPath, "utf8");
|
|
391
431
|
const agentWebPath = this.convertToWebPath(agentPath, packName);
|
|
392
432
|
sections.push(this.formatSection(agentWebPath, agentContent, packName));
|
|
393
433
|
|
|
@@ -395,22 +435,40 @@ These references map directly to bundle sections:
|
|
|
395
435
|
const yamlContent = yamlUtilities.extractYamlFromAgent(agentContent);
|
|
396
436
|
if (yamlContent) {
|
|
397
437
|
try {
|
|
398
|
-
const yaml = require(
|
|
438
|
+
const yaml = require("js-yaml");
|
|
399
439
|
const agentConfig = yaml.load(yamlContent);
|
|
400
440
|
|
|
401
441
|
if (agentConfig.dependencies) {
|
|
402
442
|
// Add resources, first try expansion pack, then core
|
|
403
|
-
for (const [resourceType, resources] of Object.entries(
|
|
443
|
+
for (const [resourceType, resources] of Object.entries(
|
|
444
|
+
agentConfig.dependencies,
|
|
445
|
+
)) {
|
|
404
446
|
if (Array.isArray(resources)) {
|
|
405
447
|
for (const resourceName of resources) {
|
|
406
448
|
let found = false;
|
|
407
449
|
|
|
408
450
|
// Try expansion pack first
|
|
409
|
-
const resourcePath = path.join(
|
|
451
|
+
const resourcePath = path.join(
|
|
452
|
+
packDir,
|
|
453
|
+
resourceType,
|
|
454
|
+
resourceName,
|
|
455
|
+
);
|
|
410
456
|
try {
|
|
411
|
-
const resourceContent = await fs.readFile(
|
|
412
|
-
|
|
413
|
-
|
|
457
|
+
const resourceContent = await fs.readFile(
|
|
458
|
+
resourcePath,
|
|
459
|
+
"utf8",
|
|
460
|
+
);
|
|
461
|
+
const resourceWebPath = this.convertToWebPath(
|
|
462
|
+
resourcePath,
|
|
463
|
+
packName,
|
|
464
|
+
);
|
|
465
|
+
sections.push(
|
|
466
|
+
this.formatSection(
|
|
467
|
+
resourceWebPath,
|
|
468
|
+
resourceContent,
|
|
469
|
+
packName,
|
|
470
|
+
),
|
|
471
|
+
);
|
|
414
472
|
found = true;
|
|
415
473
|
} catch {
|
|
416
474
|
// Not in expansion pack, continue
|
|
@@ -420,14 +478,19 @@ These references map directly to bundle sections:
|
|
|
420
478
|
if (!found) {
|
|
421
479
|
const corePath = path.join(
|
|
422
480
|
this.rootDir,
|
|
423
|
-
|
|
481
|
+
"xiaoma-core",
|
|
424
482
|
resourceType,
|
|
425
483
|
resourceName,
|
|
426
484
|
);
|
|
427
485
|
try {
|
|
428
|
-
const coreContent = await fs.readFile(corePath,
|
|
429
|
-
const coreWebPath = this.convertToWebPath(
|
|
430
|
-
|
|
486
|
+
const coreContent = await fs.readFile(corePath, "utf8");
|
|
487
|
+
const coreWebPath = this.convertToWebPath(
|
|
488
|
+
corePath,
|
|
489
|
+
packName,
|
|
490
|
+
);
|
|
491
|
+
sections.push(
|
|
492
|
+
this.formatSection(coreWebPath, coreContent, packName),
|
|
493
|
+
);
|
|
431
494
|
found = true;
|
|
432
495
|
} catch {
|
|
433
496
|
// Not in core either, continue
|
|
@@ -436,11 +499,25 @@ These references map directly to bundle sections:
|
|
|
436
499
|
|
|
437
500
|
// If not found in core, try common folder
|
|
438
501
|
if (!found) {
|
|
439
|
-
const commonPath = path.join(
|
|
502
|
+
const commonPath = path.join(
|
|
503
|
+
this.rootDir,
|
|
504
|
+
"common",
|
|
505
|
+
resourceType,
|
|
506
|
+
resourceName,
|
|
507
|
+
);
|
|
440
508
|
try {
|
|
441
|
-
const commonContent = await fs.readFile(commonPath,
|
|
442
|
-
const commonWebPath = this.convertToWebPath(
|
|
443
|
-
|
|
509
|
+
const commonContent = await fs.readFile(commonPath, "utf8");
|
|
510
|
+
const commonWebPath = this.convertToWebPath(
|
|
511
|
+
commonPath,
|
|
512
|
+
packName,
|
|
513
|
+
);
|
|
514
|
+
sections.push(
|
|
515
|
+
this.formatSection(
|
|
516
|
+
commonWebPath,
|
|
517
|
+
commonContent,
|
|
518
|
+
packName,
|
|
519
|
+
),
|
|
520
|
+
);
|
|
444
521
|
found = true;
|
|
445
522
|
} catch {
|
|
446
523
|
// Not in common either, continue
|
|
@@ -457,32 +534,35 @@ These references map directly to bundle sections:
|
|
|
457
534
|
}
|
|
458
535
|
}
|
|
459
536
|
} catch (error) {
|
|
460
|
-
console.debug(
|
|
537
|
+
console.debug(
|
|
538
|
+
`Failed to parse agent YAML for ${agentName}:`,
|
|
539
|
+
error.message,
|
|
540
|
+
);
|
|
461
541
|
}
|
|
462
542
|
}
|
|
463
543
|
|
|
464
|
-
return sections.join(
|
|
544
|
+
return sections.join("\n");
|
|
465
545
|
}
|
|
466
546
|
|
|
467
547
|
async buildExpansionTeamBundle(packName, packDir, teamConfigPath) {
|
|
468
|
-
const template = this.generateWebInstructions(
|
|
548
|
+
const template = this.generateWebInstructions("expansion-team", packName);
|
|
469
549
|
|
|
470
550
|
const sections = [template];
|
|
471
551
|
|
|
472
552
|
// Add team configuration and parse to get agent list
|
|
473
|
-
const teamContent = await fs.readFile(teamConfigPath,
|
|
474
|
-
const teamFileName = path.basename(teamConfigPath,
|
|
553
|
+
const teamContent = await fs.readFile(teamConfigPath, "utf8");
|
|
554
|
+
const teamFileName = path.basename(teamConfigPath, ".yaml");
|
|
475
555
|
const teamConfig = this.parseYaml(teamContent);
|
|
476
556
|
const teamWebPath = this.convertToWebPath(teamConfigPath, packName);
|
|
477
557
|
sections.push(this.formatSection(teamWebPath, teamContent, packName));
|
|
478
558
|
|
|
479
559
|
// Get list of expansion pack agents
|
|
480
560
|
const expansionAgents = new Set();
|
|
481
|
-
const agentsDir = path.join(packDir,
|
|
561
|
+
const agentsDir = path.join(packDir, "agents");
|
|
482
562
|
try {
|
|
483
563
|
const agentFiles = await fs.readdir(agentsDir);
|
|
484
|
-
for (const agentFile of agentFiles.filter((f) => f.endsWith(
|
|
485
|
-
const agentName = agentFile.replace(
|
|
564
|
+
for (const agentFile of agentFiles.filter((f) => f.endsWith(".md"))) {
|
|
565
|
+
const agentName = agentFile.replace(".md", "");
|
|
486
566
|
expansionAgents.add(agentName);
|
|
487
567
|
}
|
|
488
568
|
} catch {
|
|
@@ -491,13 +571,19 @@ These references map directly to bundle sections:
|
|
|
491
571
|
|
|
492
572
|
// Build a map of all available expansion pack resources for override checking
|
|
493
573
|
const expansionResources = new Map();
|
|
494
|
-
const resourceDirectories = [
|
|
574
|
+
const resourceDirectories = [
|
|
575
|
+
"templates",
|
|
576
|
+
"tasks",
|
|
577
|
+
"checklists",
|
|
578
|
+
"workflows",
|
|
579
|
+
"data",
|
|
580
|
+
];
|
|
495
581
|
for (const resourceDir of resourceDirectories) {
|
|
496
582
|
const resourcePath = path.join(packDir, resourceDir);
|
|
497
583
|
try {
|
|
498
584
|
const resourceFiles = await fs.readdir(resourcePath);
|
|
499
585
|
for (const resourceFile of resourceFiles.filter(
|
|
500
|
-
(f) => f.endsWith(
|
|
586
|
+
(f) => f.endsWith(".md") || f.endsWith(".yaml"),
|
|
501
587
|
)) {
|
|
502
588
|
expansionResources.set(`${resourceDir}#${resourceFile}`, true);
|
|
503
589
|
}
|
|
@@ -510,9 +596,11 @@ These references map directly to bundle sections:
|
|
|
510
596
|
const agentsToProcess = teamConfig.agents || [];
|
|
511
597
|
|
|
512
598
|
// Ensure xiaoma-orchestrator is always included for teams
|
|
513
|
-
if (!agentsToProcess.includes(
|
|
514
|
-
console.warn(
|
|
515
|
-
|
|
599
|
+
if (!agentsToProcess.includes("xiaoma-orchestrator")) {
|
|
600
|
+
console.warn(
|
|
601
|
+
` ⚠ Team ${teamFileName} missing xiaoma-orchestrator, adding automatically`,
|
|
602
|
+
);
|
|
603
|
+
agentsToProcess.unshift("xiaoma-orchestrator");
|
|
516
604
|
}
|
|
517
605
|
|
|
518
606
|
// Track all dependencies from all agents (deduplicated)
|
|
@@ -522,9 +610,14 @@ These references map directly to bundle sections:
|
|
|
522
610
|
if (expansionAgents.has(agentId)) {
|
|
523
611
|
// Use expansion pack version (override)
|
|
524
612
|
const agentPath = path.join(agentsDir, `${agentId}.md`);
|
|
525
|
-
const agentContent = await fs.readFile(agentPath,
|
|
526
|
-
const expansionAgentWebPath = this.convertToWebPath(
|
|
527
|
-
|
|
613
|
+
const agentContent = await fs.readFile(agentPath, "utf8");
|
|
614
|
+
const expansionAgentWebPath = this.convertToWebPath(
|
|
615
|
+
agentPath,
|
|
616
|
+
packName,
|
|
617
|
+
);
|
|
618
|
+
sections.push(
|
|
619
|
+
this.formatSection(expansionAgentWebPath, agentContent, packName),
|
|
620
|
+
);
|
|
528
621
|
|
|
529
622
|
// Parse and collect dependencies from expansion agent
|
|
530
623
|
const agentYaml = agentContent.match(/```yaml\n([\s\S]*?)\n```/);
|
|
@@ -532,52 +625,83 @@ These references map directly to bundle sections:
|
|
|
532
625
|
try {
|
|
533
626
|
const agentConfig = this.parseYaml(agentYaml[1]);
|
|
534
627
|
if (agentConfig.dependencies) {
|
|
535
|
-
for (const [resourceType, resources] of Object.entries(
|
|
628
|
+
for (const [resourceType, resources] of Object.entries(
|
|
629
|
+
agentConfig.dependencies,
|
|
630
|
+
)) {
|
|
536
631
|
if (Array.isArray(resources)) {
|
|
537
632
|
for (const resourceName of resources) {
|
|
538
633
|
const key = `${resourceType}#${resourceName}`;
|
|
539
634
|
if (!allDependencies.has(key)) {
|
|
540
|
-
allDependencies.set(key, {
|
|
635
|
+
allDependencies.set(key, {
|
|
636
|
+
type: resourceType,
|
|
637
|
+
name: resourceName,
|
|
638
|
+
});
|
|
541
639
|
}
|
|
542
640
|
}
|
|
543
641
|
}
|
|
544
642
|
}
|
|
545
643
|
}
|
|
546
644
|
} catch (error) {
|
|
547
|
-
console.debug(
|
|
645
|
+
console.debug(
|
|
646
|
+
`Failed to parse agent YAML for ${agentId}:`,
|
|
647
|
+
error.message,
|
|
648
|
+
);
|
|
548
649
|
}
|
|
549
650
|
}
|
|
550
651
|
} else {
|
|
551
652
|
// Use core BMad version
|
|
552
653
|
try {
|
|
553
|
-
const coreAgentPath = path.join(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
654
|
+
const coreAgentPath = path.join(
|
|
655
|
+
this.rootDir,
|
|
656
|
+
"xiaoma-core",
|
|
657
|
+
"agents",
|
|
658
|
+
`${agentId}.md`,
|
|
659
|
+
);
|
|
660
|
+
const coreAgentContent = await fs.readFile(coreAgentPath, "utf8");
|
|
661
|
+
const coreAgentWebPath = this.convertToWebPath(
|
|
662
|
+
coreAgentPath,
|
|
663
|
+
packName,
|
|
664
|
+
);
|
|
665
|
+
sections.push(
|
|
666
|
+
this.formatSection(coreAgentWebPath, coreAgentContent, packName),
|
|
667
|
+
);
|
|
557
668
|
|
|
558
669
|
// Parse and collect dependencies from core agent
|
|
559
|
-
const yamlContent = yamlUtilities.extractYamlFromAgent(
|
|
670
|
+
const yamlContent = yamlUtilities.extractYamlFromAgent(
|
|
671
|
+
coreAgentContent,
|
|
672
|
+
true,
|
|
673
|
+
);
|
|
560
674
|
if (yamlContent) {
|
|
561
675
|
try {
|
|
562
676
|
const agentConfig = this.parseYaml(yamlContent);
|
|
563
677
|
if (agentConfig.dependencies) {
|
|
564
|
-
for (const [resourceType, resources] of Object.entries(
|
|
678
|
+
for (const [resourceType, resources] of Object.entries(
|
|
679
|
+
agentConfig.dependencies,
|
|
680
|
+
)) {
|
|
565
681
|
if (Array.isArray(resources)) {
|
|
566
682
|
for (const resourceName of resources) {
|
|
567
683
|
const key = `${resourceType}#${resourceName}`;
|
|
568
684
|
if (!allDependencies.has(key)) {
|
|
569
|
-
allDependencies.set(key, {
|
|
685
|
+
allDependencies.set(key, {
|
|
686
|
+
type: resourceType,
|
|
687
|
+
name: resourceName,
|
|
688
|
+
});
|
|
570
689
|
}
|
|
571
690
|
}
|
|
572
691
|
}
|
|
573
692
|
}
|
|
574
693
|
}
|
|
575
694
|
} catch (error) {
|
|
576
|
-
console.debug(
|
|
695
|
+
console.debug(
|
|
696
|
+
`Failed to parse agent YAML for ${agentId}:`,
|
|
697
|
+
error.message,
|
|
698
|
+
);
|
|
577
699
|
}
|
|
578
700
|
}
|
|
579
701
|
} catch {
|
|
580
|
-
console.warn(
|
|
702
|
+
console.warn(
|
|
703
|
+
` ⚠ Agent ${agentId} not found in core or expansion pack`,
|
|
704
|
+
);
|
|
581
705
|
}
|
|
582
706
|
}
|
|
583
707
|
}
|
|
@@ -592,9 +716,14 @@ These references map directly to bundle sections:
|
|
|
592
716
|
// We know it exists in expansion pack, find and load it
|
|
593
717
|
const expansionPath = path.join(packDir, dep.type, dep.name);
|
|
594
718
|
try {
|
|
595
|
-
const content = await fs.readFile(expansionPath,
|
|
596
|
-
const expansionWebPath = this.convertToWebPath(
|
|
597
|
-
|
|
719
|
+
const content = await fs.readFile(expansionPath, "utf8");
|
|
720
|
+
const expansionWebPath = this.convertToWebPath(
|
|
721
|
+
expansionPath,
|
|
722
|
+
packName,
|
|
723
|
+
);
|
|
724
|
+
sections.push(
|
|
725
|
+
this.formatSection(expansionWebPath, content, packName),
|
|
726
|
+
);
|
|
598
727
|
console.log(` ✓ Using expansion override for ${key}`);
|
|
599
728
|
found = true;
|
|
600
729
|
} catch {
|
|
@@ -604,9 +733,14 @@ These references map directly to bundle sections:
|
|
|
604
733
|
|
|
605
734
|
// If not found in expansion pack (or doesn't exist there), try core
|
|
606
735
|
if (!found) {
|
|
607
|
-
const corePath = path.join(
|
|
736
|
+
const corePath = path.join(
|
|
737
|
+
this.rootDir,
|
|
738
|
+
"xiaoma-core",
|
|
739
|
+
dep.type,
|
|
740
|
+
dep.name,
|
|
741
|
+
);
|
|
608
742
|
try {
|
|
609
|
-
const content = await fs.readFile(corePath,
|
|
743
|
+
const content = await fs.readFile(corePath, "utf8");
|
|
610
744
|
const coreWebPath = this.convertToWebPath(corePath, packName);
|
|
611
745
|
sections.push(this.formatSection(coreWebPath, content, packName));
|
|
612
746
|
found = true;
|
|
@@ -617,9 +751,14 @@ These references map directly to bundle sections:
|
|
|
617
751
|
|
|
618
752
|
// If not found in core, try common folder
|
|
619
753
|
if (!found) {
|
|
620
|
-
const commonPath = path.join(
|
|
754
|
+
const commonPath = path.join(
|
|
755
|
+
this.rootDir,
|
|
756
|
+
"common",
|
|
757
|
+
dep.type,
|
|
758
|
+
dep.name,
|
|
759
|
+
);
|
|
621
760
|
try {
|
|
622
|
-
const content = await fs.readFile(commonPath,
|
|
761
|
+
const content = await fs.readFile(commonPath, "utf8");
|
|
623
762
|
const commonWebPath = this.convertToWebPath(commonPath, packName);
|
|
624
763
|
sections.push(this.formatSection(commonWebPath, content, packName));
|
|
625
764
|
found = true;
|
|
@@ -629,7 +768,9 @@ These references map directly to bundle sections:
|
|
|
629
768
|
}
|
|
630
769
|
|
|
631
770
|
if (!found) {
|
|
632
|
-
console.warn(
|
|
771
|
+
console.warn(
|
|
772
|
+
` ⚠ Dependency ${key} not found in expansion pack or core`,
|
|
773
|
+
);
|
|
633
774
|
}
|
|
634
775
|
}
|
|
635
776
|
|
|
@@ -639,18 +780,23 @@ These references map directly to bundle sections:
|
|
|
639
780
|
try {
|
|
640
781
|
const resourceFiles = await fs.readdir(resourcePath);
|
|
641
782
|
for (const resourceFile of resourceFiles.filter(
|
|
642
|
-
(f) => f.endsWith(
|
|
783
|
+
(f) => f.endsWith(".md") || f.endsWith(".yaml"),
|
|
643
784
|
)) {
|
|
644
785
|
const filePath = path.join(resourcePath, resourceFile);
|
|
645
|
-
const fileContent = await fs.readFile(filePath,
|
|
646
|
-
const fileName = resourceFile.replace(/\.(md|yaml)$/,
|
|
786
|
+
const fileContent = await fs.readFile(filePath, "utf8");
|
|
787
|
+
const fileName = resourceFile.replace(/\.(md|yaml)$/, "");
|
|
647
788
|
|
|
648
789
|
// Only add if not already included as a dependency
|
|
649
790
|
const resourceKey = `${resourceDir}#${fileName}`;
|
|
650
791
|
if (!allDependencies.has(resourceKey)) {
|
|
651
792
|
const fullResourcePath = path.join(resourcePath, resourceFile);
|
|
652
|
-
const resourceWebPath = this.convertToWebPath(
|
|
653
|
-
|
|
793
|
+
const resourceWebPath = this.convertToWebPath(
|
|
794
|
+
fullResourcePath,
|
|
795
|
+
packName,
|
|
796
|
+
);
|
|
797
|
+
sections.push(
|
|
798
|
+
this.formatSection(resourceWebPath, fileContent, packName),
|
|
799
|
+
);
|
|
654
800
|
}
|
|
655
801
|
}
|
|
656
802
|
} catch {
|
|
@@ -658,16 +804,20 @@ These references map directly to bundle sections:
|
|
|
658
804
|
}
|
|
659
805
|
}
|
|
660
806
|
|
|
661
|
-
return sections.join(
|
|
807
|
+
return sections.join("\n");
|
|
662
808
|
}
|
|
663
809
|
|
|
664
810
|
async listExpansionPacks() {
|
|
665
|
-
const expansionPacksDir = path.join(this.rootDir,
|
|
811
|
+
const expansionPacksDir = path.join(this.rootDir, "expansion-packs");
|
|
666
812
|
try {
|
|
667
|
-
const entries = await fs.readdir(expansionPacksDir, {
|
|
668
|
-
|
|
813
|
+
const entries = await fs.readdir(expansionPacksDir, {
|
|
814
|
+
withFileTypes: true,
|
|
815
|
+
});
|
|
816
|
+
return entries
|
|
817
|
+
.filter((entry) => entry.isDirectory())
|
|
818
|
+
.map((entry) => entry.name);
|
|
669
819
|
} catch {
|
|
670
|
-
console.warn(
|
|
820
|
+
console.warn("No expansion-packs directory found");
|
|
671
821
|
return [];
|
|
672
822
|
}
|
|
673
823
|
}
|