@zeyue0329/xiaoma-cli 1.0.36 → 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.
Files changed (89) hide show
  1. package/.idea/workspace.xml +27 -26
  2. package/JAVA-BACKEND-COMMANDS-REFERENCE.md +62 -52
  3. package/JAVA-BACKEND-ITERATION-GUIDE.md +125 -18
  4. package/README.md +1 -1
  5. package/common/utils/bmad-doc-template.md +5 -5
  6. package/dist/agents/analyst.txt +35 -5
  7. package/dist/agents/architect.txt +217 -31
  8. package/dist/agents/automation-orchestrator.txt +4 -4
  9. package/dist/agents/dev.txt +3 -3
  10. package/dist/agents/full-requirement-orchestrator.txt +11 -11
  11. package/dist/agents/qa.txt +102 -102
  12. package/dist/agents/sm.txt +6 -6
  13. package/dist/agents/ux-expert.txt +6 -1
  14. package/dist/agents/workflow-executor.txt +879 -0
  15. package/dist/agents/xiaoma-master.txt +258 -37
  16. package/dist/teams/team-all.txt +1223 -445
  17. package/dist/teams/team-fullstack-with-database.txt +384 -446
  18. package/dist/teams/team-fullstack.txt +258 -37
  19. package/dist/teams/team-ide-minimal.txt +111 -111
  20. package/dist/teams/team-no-ui.txt +252 -36
  21. package/docs/architecture-sharding-modification.md +623 -0
  22. package/docs/automated-requirements-analysis-outputs.md +896 -0
  23. package/package.json +1 -1
  24. package/tools/builders/web-builder.js +292 -142
  25. package/tools/bump-all-versions.js +50 -32
  26. package/tools/cli.js +52 -47
  27. package/tools/flattener/aggregate.js +30 -12
  28. package/tools/flattener/binary.js +46 -43
  29. package/tools/flattener/discovery.js +23 -15
  30. package/tools/flattener/files.js +6 -6
  31. package/tools/flattener/ignoreRules.js +122 -121
  32. package/tools/flattener/main.js +249 -144
  33. package/tools/flattener/projectRoot.js +74 -69
  34. package/tools/flattener/prompts.js +12 -10
  35. package/tools/flattener/stats.helpers.js +90 -61
  36. package/tools/flattener/stats.js +1 -1
  37. package/tools/flattener/test-matrix.js +225 -170
  38. package/tools/flattener/xml.js +31 -23
  39. package/tools/installer/bin/xiaoma.js +199 -153
  40. package/tools/installer/lib/config-loader.js +76 -47
  41. package/tools/installer/lib/file-manager.js +101 -44
  42. package/tools/installer/lib/ide-base-setup.js +49 -39
  43. package/tools/installer/lib/ide-setup.js +694 -380
  44. package/tools/installer/lib/installer.js +802 -469
  45. package/tools/installer/lib/memory-profiler.js +22 -12
  46. package/tools/installer/lib/module-manager.js +16 -14
  47. package/tools/installer/lib/resource-locator.js +61 -35
  48. package/tools/lib/dependency-resolver.js +34 -23
  49. package/tools/lib/yaml-utils.js +7 -2
  50. package/tools/preview-release-notes.js +33 -25
  51. package/tools/shared/bannerArt.js +3 -3
  52. package/tools/sync-installer-version.js +16 -7
  53. package/tools/upgraders/v3-to-v4-upgrader.js +244 -163
  54. package/tools/version-bump.js +24 -18
  55. package/tools/xiaoma-npx-wrapper.js +15 -10
  56. package/tools/yaml-format.js +60 -36
  57. package/xiaoma-core/agent-teams/team-fullstack-with-database.yaml +0 -1
  58. package/xiaoma-core/agents/automated-fix-validator.yaml +2 -1
  59. package/xiaoma-core/agents/automated-quality-validator.yaml +10 -5
  60. package/xiaoma-core/agents/automation-orchestrator.md +4 -4
  61. package/xiaoma-core/agents/dev.md +4 -4
  62. package/xiaoma-core/agents/enhanced-workflow-orchestrator.yaml +2 -1
  63. package/xiaoma-core/agents/full-requirement-orchestrator.md +11 -11
  64. package/xiaoma-core/agents/global-requirements-auditor.yaml +11 -3
  65. package/xiaoma-core/agents/intelligent-template-adapter.yaml +19 -5
  66. package/xiaoma-core/agents/master-execution-engine.yaml +19 -5
  67. package/xiaoma-core/agents/workflow-executor.md +126 -18
  68. package/xiaoma-core/agents/xiaoma-master.md +1 -1
  69. package/xiaoma-core/data/test-levels-framework.md +12 -12
  70. package/xiaoma-core/tasks/analyze-existing-database.md +1 -1
  71. package/xiaoma-core/tasks/apply-qa-fixes.md +3 -3
  72. package/xiaoma-core/tasks/batch-story-generation.md +22 -22
  73. package/xiaoma-core/tasks/create-enhanced-story-with-database.md +6 -6
  74. package/xiaoma-core/tasks/nfr-assess.md +6 -6
  75. package/xiaoma-core/tasks/project-integration-testing.md +42 -42
  76. package/xiaoma-core/tasks/qa-gate.md +23 -23
  77. package/xiaoma-core/tasks/review-story.md +18 -18
  78. package/xiaoma-core/tasks/risk-profile.md +25 -25
  79. package/xiaoma-core/tasks/serial-development-orchestration.md +51 -51
  80. package/xiaoma-core/tasks/test-design.md +9 -9
  81. package/xiaoma-core/tasks/trace-requirements.md +21 -21
  82. package/xiaoma-core/templates/competitor-analysis-tmpl.yaml +35 -5
  83. package/xiaoma-core/templates/front-end-architecture-tmpl.yaml +77 -11
  84. package/xiaoma-core/templates/front-end-spec-tmpl.yaml +6 -1
  85. package/xiaoma-core/templates/fullstack-architecture-tmpl.yaml +140 -20
  86. package/xiaoma-core/templates/global-qa-monitoring-tmpl.yaml +2 -1
  87. package/xiaoma-core/templates/requirements-coverage-audit.yaml +2 -1
  88. package/xiaoma-core/workflows/automated-requirements-analysis.yaml +4 -4
  89. package/dist/agents/database-architect.txt +0 -322
@@ -1,11 +1,16 @@
1
- const fs = require('fs-extra');
2
- const path = require('node:path');
3
- const yaml = require('js-yaml');
4
- const { extractYamlFromAgent } = require('../../lib/yaml-utils');
1
+ const fs = require("fs-extra");
2
+ const path = require("node:path");
3
+ const yaml = require("js-yaml");
4
+ const { extractYamlFromAgent } = require("../../lib/yaml-utils");
5
5
 
6
6
  class ConfigLoader {
7
7
  constructor() {
8
- this.configPath = path.join(__dirname, '..', 'config', 'install.config.yaml');
8
+ this.configPath = path.join(
9
+ __dirname,
10
+ "..",
11
+ "config",
12
+ "install.config.yaml",
13
+ );
9
14
  this.config = null;
10
15
  }
11
16
 
@@ -13,7 +18,7 @@ class ConfigLoader {
13
18
  if (this.config) return this.config;
14
19
 
15
20
  try {
16
- const configContent = await fs.readFile(this.configPath, 'utf8');
21
+ const configContent = await fs.readFile(this.configPath, "utf8");
17
22
  this.config = yaml.load(configContent);
18
23
  return this.config;
19
24
  } catch (error) {
@@ -23,23 +28,23 @@ class ConfigLoader {
23
28
 
24
29
  async getInstallationOptions() {
25
30
  const config = await this.load();
26
- return config['installation-options'] || {};
31
+ return config["installation-options"] || {};
27
32
  }
28
33
 
29
34
  async getAvailableAgents() {
30
- const agentsDir = path.join(this.getBmadCorePath(), 'agents');
35
+ const agentsDir = path.join(this.getBmadCorePath(), "agents");
31
36
 
32
37
  try {
33
38
  const entries = await fs.readdir(agentsDir, { withFileTypes: true });
34
39
  const agents = [];
35
40
 
36
41
  for (const entry of entries) {
37
- if (entry.isFile() && entry.name.endsWith('.md')) {
42
+ if (entry.isFile() && entry.name.endsWith(".md")) {
38
43
  const agentPath = path.join(agentsDir, entry.name);
39
- const agentId = path.basename(entry.name, '.md');
44
+ const agentId = path.basename(entry.name, ".md");
40
45
 
41
46
  try {
42
- const agentContent = await fs.readFile(agentPath, 'utf8');
47
+ const agentContent = await fs.readFile(agentPath, "utf8");
43
48
 
44
49
  // Extract YAML block from agent file
45
50
  const yamlContentText = extractYamlFromAgent(agentContent);
@@ -51,11 +56,14 @@ class ConfigLoader {
51
56
  id: agentId,
52
57
  name: agentConfig.title || agentConfig.name || agentId,
53
58
  file: `xiaoma-core/agents/${entry.name}`,
54
- description: agentConfig.whenToUse || 'No description available',
59
+ description:
60
+ agentConfig.whenToUse || "No description available",
55
61
  });
56
62
  }
57
63
  } catch (error) {
58
- console.warn(`Failed to read agent ${entry.name}: ${error.message}`);
64
+ console.warn(
65
+ `Failed to read agent ${entry.name}: ${error.message}`,
66
+ );
59
67
  }
60
68
  }
61
69
  }
@@ -71,31 +79,41 @@ class ConfigLoader {
71
79
  }
72
80
 
73
81
  async getAvailableExpansionPacks() {
74
- const expansionPacksDir = path.join(this.getBmadCorePath(), '..', 'expansion-packs');
82
+ const expansionPacksDir = path.join(
83
+ this.getBmadCorePath(),
84
+ "..",
85
+ "expansion-packs",
86
+ );
75
87
 
76
88
  try {
77
- const entries = await fs.readdir(expansionPacksDir, { withFileTypes: true });
89
+ const entries = await fs.readdir(expansionPacksDir, {
90
+ withFileTypes: true,
91
+ });
78
92
  const expansionPacks = [];
79
93
 
80
94
  for (const entry of entries) {
81
- if (entry.isDirectory() && !entry.name.startsWith('.')) {
95
+ if (entry.isDirectory() && !entry.name.startsWith(".")) {
82
96
  const packPath = path.join(expansionPacksDir, entry.name);
83
- const configPath = path.join(packPath, 'config.yaml');
97
+ const configPath = path.join(packPath, "config.yaml");
84
98
 
85
99
  try {
86
100
  // Read config.yaml
87
- const configContent = await fs.readFile(configPath, 'utf8');
101
+ const configContent = await fs.readFile(configPath, "utf8");
88
102
  const config = yaml.load(configContent);
89
103
 
90
104
  expansionPacks.push({
91
105
  id: entry.name,
92
106
  name: config.name || entry.name,
93
107
  description:
94
- config['short-title'] || config.description || 'No description available',
108
+ config["short-title"] ||
109
+ config.description ||
110
+ "No description available",
95
111
  fullDescription:
96
- config.description || config['short-title'] || 'No description available',
97
- version: config.version || '1.0.0',
98
- author: config.author || 'XiaoMa Team',
112
+ config.description ||
113
+ config["short-title"] ||
114
+ "No description available",
115
+ version: config.version || "1.0.0",
116
+ author: config.author || "XiaoMa Team",
99
117
  packPath: packPath,
100
118
  dependencies: config.dependencies?.agents || [],
101
119
  });
@@ -107,17 +125,17 @@ class ConfigLoader {
107
125
 
108
126
  // Try to derive info from directory name as fallback
109
127
  const name = entry.name
110
- .split('-')
128
+ .split("-")
111
129
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
112
- .join(' ');
130
+ .join(" ");
113
131
 
114
132
  expansionPacks.push({
115
133
  id: entry.name,
116
134
  name: name,
117
- description: 'No description available',
118
- fullDescription: 'No description available',
119
- version: '1.0.0',
120
- author: 'XiaoMa Team',
135
+ description: "No description available",
136
+ fullDescription: "No description available",
137
+ version: "1.0.0",
138
+ author: "XiaoMa Team",
121
139
  packPath: packPath,
122
140
  dependencies: [],
123
141
  });
@@ -127,15 +145,19 @@ class ConfigLoader {
127
145
 
128
146
  return expansionPacks;
129
147
  } catch (error) {
130
- console.warn(`Failed to read expansion packs directory: ${error.message}`);
148
+ console.warn(
149
+ `Failed to read expansion packs directory: ${error.message}`,
150
+ );
131
151
  return [];
132
152
  }
133
153
  }
134
154
 
135
155
  async getAgentDependencies(agentId) {
136
156
  // Use DependencyResolver to dynamically parse agent dependencies
137
- const DependencyResolver = require('../../lib/dependency-resolver');
138
- const resolver = new DependencyResolver(path.join(__dirname, '..', '..', '..'));
157
+ const DependencyResolver = require("../../lib/dependency-resolver");
158
+ const resolver = new DependencyResolver(
159
+ path.join(__dirname, "..", "..", ".."),
160
+ );
139
161
 
140
162
  const agentDeps = await resolver.resolveAgentDependencies(agentId);
141
163
 
@@ -159,49 +181,52 @@ class ConfigLoader {
159
181
 
160
182
  async getIdeConfiguration(ide) {
161
183
  const config = await this.load();
162
- const ideConfigs = config['ide-configurations'] || {};
184
+ const ideConfigs = config["ide-configurations"] || {};
163
185
  return ideConfigs[ide] || null;
164
186
  }
165
187
 
166
188
  getBmadCorePath() {
167
189
  // Get the path to xiaoma-core relative to the installer (now under tools)
168
- return path.join(__dirname, '..', '..', '..', 'xiaoma-core');
190
+ return path.join(__dirname, "..", "..", "..", "xiaoma-core");
169
191
  }
170
192
 
171
193
  getDistPath() {
172
194
  // Get the path to dist directory relative to the installer
173
- return path.join(__dirname, '..', '..', '..', 'dist');
195
+ return path.join(__dirname, "..", "..", "..", "dist");
174
196
  }
175
197
 
176
198
  getAgentPath(agentId) {
177
- return path.join(this.getBmadCorePath(), 'agents', `${agentId}.md`);
199
+ return path.join(this.getBmadCorePath(), "agents", `${agentId}.md`);
178
200
  }
179
201
 
180
202
  async getAvailableTeams() {
181
- const teamsDir = path.join(this.getBmadCorePath(), 'agent-teams');
203
+ const teamsDir = path.join(this.getBmadCorePath(), "agent-teams");
182
204
 
183
205
  try {
184
206
  const entries = await fs.readdir(teamsDir, { withFileTypes: true });
185
207
  const teams = [];
186
208
 
187
209
  for (const entry of entries) {
188
- if (entry.isFile() && entry.name.endsWith('.yaml')) {
210
+ if (entry.isFile() && entry.name.endsWith(".yaml")) {
189
211
  const teamPath = path.join(teamsDir, entry.name);
190
212
 
191
213
  try {
192
- const teamContent = await fs.readFile(teamPath, 'utf8');
214
+ const teamContent = await fs.readFile(teamPath, "utf8");
193
215
  const teamConfig = yaml.load(teamContent);
194
216
 
195
217
  if (teamConfig.bundle) {
196
218
  teams.push({
197
- id: path.basename(entry.name, '.yaml'),
219
+ id: path.basename(entry.name, ".yaml"),
198
220
  name: teamConfig.bundle.name || entry.name,
199
- description: teamConfig.bundle.description || 'Team configuration',
200
- icon: teamConfig.bundle.icon || '📋',
221
+ description:
222
+ teamConfig.bundle.description || "Team configuration",
223
+ icon: teamConfig.bundle.icon || "📋",
201
224
  });
202
225
  }
203
226
  } catch (error) {
204
- console.warn(`Warning: Could not load team config ${entry.name}: ${error.message}`);
227
+ console.warn(
228
+ `Warning: Could not load team config ${entry.name}: ${error.message}`,
229
+ );
205
230
  }
206
231
  }
207
232
  }
@@ -214,13 +239,15 @@ class ConfigLoader {
214
239
  }
215
240
 
216
241
  getTeamPath(teamId) {
217
- return path.join(this.getBmadCorePath(), 'agent-teams', `${teamId}.yaml`);
242
+ return path.join(this.getBmadCorePath(), "agent-teams", `${teamId}.yaml`);
218
243
  }
219
244
 
220
245
  async getTeamDependencies(teamId) {
221
246
  // Use DependencyResolver to dynamically parse team dependencies
222
- const DependencyResolver = require('../../lib/dependency-resolver');
223
- const resolver = new DependencyResolver(path.join(__dirname, '..', '..', '..'));
247
+ const DependencyResolver = require("../../lib/dependency-resolver");
248
+ const resolver = new DependencyResolver(
249
+ path.join(__dirname, "..", "..", ".."),
250
+ );
224
251
 
225
252
  try {
226
253
  const teamDeps = await resolver.resolveTeamDependencies(teamId);
@@ -241,7 +268,7 @@ class ConfigLoader {
241
268
 
242
269
  // Add all resolved resources
243
270
  for (const resource of teamDeps.resources) {
244
- const filePath = `.xiaoma-core/${resource.type}/${resource.id}.${resource.type === 'workflows' ? 'yaml' : 'md'}`;
271
+ const filePath = `.xiaoma-core/${resource.type}/${resource.id}.${resource.type === "workflows" ? "yaml" : "md"}`;
245
272
  if (!depPaths.includes(filePath)) {
246
273
  depPaths.push(filePath);
247
274
  }
@@ -249,7 +276,9 @@ class ConfigLoader {
249
276
 
250
277
  return depPaths;
251
278
  } catch (error) {
252
- throw new Error(`Failed to resolve team dependencies for ${teamId}: ${error.message}`);
279
+ throw new Error(
280
+ `Failed to resolve team dependencies for ${teamId}: ${error.message}`,
281
+ );
253
282
  }
254
283
  }
255
284
  }
@@ -1,11 +1,15 @@
1
- const fs = require('fs-extra');
2
- const path = require('node:path');
3
- const crypto = require('node:crypto');
4
- const yaml = require('js-yaml');
5
- const chalk = require('chalk');
6
- const { createReadStream, createWriteStream, promises: fsPromises } = require('node:fs');
7
- const { pipeline } = require('node:stream/promises');
8
- const resourceLocator = require('./resource-locator');
1
+ const fs = require("fs-extra");
2
+ const path = require("node:path");
3
+ const crypto = require("node:crypto");
4
+ const yaml = require("js-yaml");
5
+ const chalk = require("chalk");
6
+ const {
7
+ createReadStream,
8
+ createWriteStream,
9
+ promises: fsPromises,
10
+ } = require("node:fs");
11
+ const { pipeline } = require("node:stream/promises");
12
+ const resourceLocator = require("./resource-locator");
9
13
 
10
14
  class FileManager {
11
15
  constructor() {}
@@ -31,7 +35,7 @@ class FileManager {
31
35
  await fs.ensureDir(destination);
32
36
 
33
37
  // Use streaming copy for large directories
34
- const files = await resourceLocator.findFiles('**/*', {
38
+ const files = await resourceLocator.findFiles("**/*", {
35
39
  cwd: source,
36
40
  nodir: true,
37
41
  });
@@ -41,12 +45,20 @@ class FileManager {
41
45
  for (let index = 0; index < files.length; index += batchSize) {
42
46
  const batch = files.slice(index, index + batchSize);
43
47
  await Promise.all(
44
- batch.map((file) => this.copyFile(path.join(source, file), path.join(destination, file))),
48
+ batch.map((file) =>
49
+ this.copyFile(
50
+ path.join(source, file),
51
+ path.join(destination, file),
52
+ ),
53
+ ),
45
54
  );
46
55
  }
47
56
  return true;
48
57
  } catch (error) {
49
- console.error(chalk.red(`Failed to copy directory ${source}:`), error.message);
58
+ console.error(
59
+ chalk.red(`Failed to copy directory ${source}:`),
60
+ error.message,
61
+ );
50
62
  return false;
51
63
  }
52
64
  }
@@ -61,11 +73,18 @@ class FileManager {
61
73
 
62
74
  // Use root replacement if rootValue is provided and file needs it
63
75
  const needsRootReplacement =
64
- rootValue && (file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml'));
76
+ rootValue &&
77
+ (file.endsWith(".md") ||
78
+ file.endsWith(".yaml") ||
79
+ file.endsWith(".yml"));
65
80
 
66
81
  let success = false;
67
82
  success = await (needsRootReplacement
68
- ? this.copyFileWithRootReplacement(sourcePath, destinationPath, rootValue)
83
+ ? this.copyFileWithRootReplacement(
84
+ sourcePath,
85
+ destinationPath,
86
+ rootValue,
87
+ )
69
88
  : this.copyFile(sourcePath, destinationPath));
70
89
 
71
90
  if (success) {
@@ -80,25 +99,35 @@ class FileManager {
80
99
  try {
81
100
  // Use streaming for hash calculation to reduce memory usage
82
101
  const stream = createReadStream(filePath);
83
- const hash = crypto.createHash('sha256');
102
+ const hash = crypto.createHash("sha256");
84
103
 
85
104
  for await (const chunk of stream) {
86
105
  hash.update(chunk);
87
106
  }
88
107
 
89
- return hash.digest('hex').slice(0, 16);
108
+ return hash.digest("hex").slice(0, 16);
90
109
  } catch {
91
110
  return null;
92
111
  }
93
112
  }
94
113
 
95
114
  async createManifest(installDir, config, files) {
96
- const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
115
+ const manifestPath = path.join(
116
+ installDir,
117
+ this.manifestDir,
118
+ this.manifestFile,
119
+ );
97
120
 
98
121
  // Read version from package.json
99
- let coreVersion = 'unknown';
122
+ let coreVersion = "unknown";
100
123
  try {
101
- const packagePath = path.join(__dirname, '..', '..', '..', 'package.json');
124
+ const packagePath = path.join(
125
+ __dirname,
126
+ "..",
127
+ "..",
128
+ "..",
129
+ "package.json",
130
+ );
102
131
  const packageJson = require(packagePath);
103
132
  coreVersion = packageJson.version;
104
133
  } catch {
@@ -135,10 +164,14 @@ class FileManager {
135
164
  }
136
165
 
137
166
  async readManifest(installDir) {
138
- const manifestPath = path.join(installDir, this.manifestDir, this.manifestFile);
167
+ const manifestPath = path.join(
168
+ installDir,
169
+ this.manifestDir,
170
+ this.manifestFile,
171
+ );
139
172
 
140
173
  try {
141
- const content = await fs.readFile(manifestPath, 'utf8');
174
+ const content = await fs.readFile(manifestPath, "utf8");
142
175
  return yaml.load(content);
143
176
  } catch {
144
177
  return null;
@@ -149,7 +182,7 @@ class FileManager {
149
182
  const manifestPath = path.join(installDir, `.${packId}`, this.manifestFile);
150
183
 
151
184
  try {
152
- const content = await fs.readFile(manifestPath, 'utf8');
185
+ const content = await fs.readFile(manifestPath, "utf8");
153
186
  return yaml.load(content);
154
187
  } catch {
155
188
  return null;
@@ -181,7 +214,7 @@ class FileManager {
181
214
  const filePath = path.join(installDir, file.path);
182
215
 
183
216
  // Skip checking the manifest file itself - it will always be different due to timestamps
184
- if (file.path.endsWith('install-manifest.yaml')) {
217
+ if (file.path.endsWith("install-manifest.yaml")) {
185
218
  continue;
186
219
  }
187
220
 
@@ -199,7 +232,7 @@ class FileManager {
199
232
  }
200
233
 
201
234
  async backupFile(filePath) {
202
- const backupPath = filePath + '.bak';
235
+ const backupPath = filePath + ".bak";
203
236
  let counter = 1;
204
237
  let finalBackupPath = backupPath;
205
238
 
@@ -227,7 +260,7 @@ class FileManager {
227
260
  }
228
261
 
229
262
  async readFile(filePath) {
230
- return fs.readFile(filePath, 'utf8');
263
+ return fs.readFile(filePath, "utf8");
231
264
  }
232
265
 
233
266
  async writeFile(filePath, content) {
@@ -243,7 +276,8 @@ class FileManager {
243
276
  const manifestPath = path.join(installDir, `.${packId}`, this.manifestFile);
244
277
 
245
278
  const manifest = {
246
- version: config.expansionPackVersion || require('../../../package.json').version,
279
+ version:
280
+ config.expansionPackVersion || require("../../../package.json").version,
247
281
  installed_at: new Date().toISOString(),
248
282
  install_type: config.installType,
249
283
  expansion_pack_id: config.expansionPackId,
@@ -272,11 +306,15 @@ class FileManager {
272
306
  }
273
307
 
274
308
  async modifyCoreConfig(installDir, config) {
275
- const coreConfigPath = path.join(installDir, '.xiaoma-core', 'core-config.yaml');
309
+ const coreConfigPath = path.join(
310
+ installDir,
311
+ ".xiaoma-core",
312
+ "core-config.yaml",
313
+ );
276
314
 
277
315
  try {
278
316
  // Read the existing core-config.yaml
279
- const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
317
+ const coreConfigContent = await fs.readFile(coreConfigPath, "utf8");
280
318
  const coreConfig = yaml.load(coreConfigContent);
281
319
 
282
320
  // Modify sharding settings if provided
@@ -285,7 +323,8 @@ class FileManager {
285
323
  }
286
324
 
287
325
  if (config.architectureSharded !== undefined) {
288
- coreConfig.architecture.architectureSharded = config.architectureSharded;
326
+ coreConfig.architecture.architectureSharded =
327
+ config.architectureSharded;
289
328
  }
290
329
 
291
330
  // Write back the modified config
@@ -293,7 +332,10 @@ class FileManager {
293
332
 
294
333
  return true;
295
334
  } catch (error) {
296
- console.error(chalk.red(`Failed to modify core-config.yaml:`), error.message);
335
+ console.error(
336
+ chalk.red(`Failed to modify core-config.yaml:`),
337
+ error.message,
338
+ );
297
339
  return false;
298
340
  }
299
341
  }
@@ -306,31 +348,34 @@ class FileManager {
306
348
  if (stats.size > 5 * 1024 * 1024) {
307
349
  // 5MB threshold
308
350
  // Use streaming for large files
309
- const { Transform } = require('node:stream');
351
+ const { Transform } = require("node:stream");
310
352
  const replaceStream = new Transform({
311
353
  transform(chunk, encoding, callback) {
312
- const modified = chunk.toString().replaceAll('{root}', rootValue);
354
+ const modified = chunk.toString().replaceAll("{root}", rootValue);
313
355
  callback(null, modified);
314
356
  },
315
357
  });
316
358
 
317
359
  await this.ensureDirectory(path.dirname(destination));
318
360
  await pipeline(
319
- createReadStream(source, { encoding: 'utf8' }),
361
+ createReadStream(source, { encoding: "utf8" }),
320
362
  replaceStream,
321
- createWriteStream(destination, { encoding: 'utf8' }),
363
+ createWriteStream(destination, { encoding: "utf8" }),
322
364
  );
323
365
  } else {
324
366
  // Regular approach for smaller files
325
- const content = await fsPromises.readFile(source, 'utf8');
326
- const updatedContent = content.replaceAll('{root}', rootValue);
367
+ const content = await fsPromises.readFile(source, "utf8");
368
+ const updatedContent = content.replaceAll("{root}", rootValue);
327
369
  await this.ensureDirectory(path.dirname(destination));
328
- await fsPromises.writeFile(destination, updatedContent, 'utf8');
370
+ await fsPromises.writeFile(destination, updatedContent, "utf8");
329
371
  }
330
372
 
331
373
  return true;
332
374
  } catch (error) {
333
- console.error(chalk.red(`Failed to copy ${source} with root replacement:`), error.message);
375
+ console.error(
376
+ chalk.red(`Failed to copy ${source} with root replacement:`),
377
+ error.message,
378
+ );
334
379
  return false;
335
380
  }
336
381
  }
@@ -339,13 +384,13 @@ class FileManager {
339
384
  source,
340
385
  destination,
341
386
  rootValue,
342
- fileExtensions = ['.md', '.yaml', '.yml'],
387
+ fileExtensions = [".md", ".yaml", ".yml"],
343
388
  ) {
344
389
  try {
345
390
  await this.ensureDirectory(destination);
346
391
 
347
392
  // Get all files in source directory
348
- const files = await resourceLocator.findFiles('**/*', {
393
+ const files = await resourceLocator.findFiles("**/*", {
349
394
  cwd: source,
350
395
  nodir: true,
351
396
  });
@@ -357,10 +402,18 @@ class FileManager {
357
402
  const destinationPath = path.join(destination, file);
358
403
 
359
404
  // Check if this file type should have {root} replacement
360
- const shouldReplace = fileExtensions.some((extension) => file.endsWith(extension));
405
+ const shouldReplace = fileExtensions.some((extension) =>
406
+ file.endsWith(extension),
407
+ );
361
408
 
362
409
  if (shouldReplace) {
363
- if (await this.copyFileWithRootReplacement(sourcePath, destinationPath, rootValue)) {
410
+ if (
411
+ await this.copyFileWithRootReplacement(
412
+ sourcePath,
413
+ destinationPath,
414
+ rootValue,
415
+ )
416
+ ) {
364
417
  replacedCount++;
365
418
  }
366
419
  } else {
@@ -370,7 +423,11 @@ class FileManager {
370
423
  }
371
424
 
372
425
  if (replacedCount > 0) {
373
- console.log(chalk.dim(` Processed ${replacedCount} files with {root} replacement`));
426
+ console.log(
427
+ chalk.dim(
428
+ ` Processed ${replacedCount} files with {root} replacement`,
429
+ ),
430
+ );
374
431
  }
375
432
 
376
433
  return true;
@@ -382,8 +439,8 @@ class FileManager {
382
439
  return false;
383
440
  }
384
441
  }
385
- manifestDir = '.xiaoma-core';
386
- manifestFile = 'install-manifest.yaml';
442
+ manifestDir = ".xiaoma-core";
443
+ manifestFile = "install-manifest.yaml";
387
444
  }
388
445
 
389
446
  module.exports = new FileManager();