momo-ai 1.0.4 → 1.0.6

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.
@@ -0,0 +1,195 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const { spawn } = require('child_process');
4
+ const Ec = require('../epic');
5
+
6
+ /**
7
+ * 获取所有 agents 信息
8
+ * @returns {Array} agents 信息数组
9
+ */
10
+ const _getAgents = () => {
11
+ const agentsDir = path.resolve(__dirname, '../_agent');
12
+ const agents = [];
13
+
14
+ if (!fs.existsSync(agentsDir)) {
15
+ return agents;
16
+ }
17
+
18
+ // 遍历 _agent 目录下的所有子目录
19
+ const types = fs.readdirSync(agentsDir).filter(file =>
20
+ fs.statSync(path.join(agentsDir, file)).isDirectory()
21
+ );
22
+
23
+ // 遍历每个类型目录
24
+ types.forEach(type => {
25
+ const typeDir = path.join(agentsDir, type);
26
+ const files = fs.readdirSync(typeDir).filter(file => file.endsWith('.json'));
27
+
28
+ // 遍历每个 json 文件
29
+ files.forEach(file => {
30
+ try {
31
+ const filePath = path.join(typeDir, file);
32
+ const content = fs.readFileSync(filePath, 'utf8');
33
+ const agentInfo = JSON.parse(content);
34
+
35
+ agents.push({
36
+ argName: file.replace('momo-', '').replace('.json', ''),
37
+ type: type,
38
+ name: agentInfo.name,
39
+ id: agentInfo.id,
40
+ uri: agentInfo.uri,
41
+ filePath: filePath
42
+ });
43
+ } catch (error) {
44
+ Ec.waiting(`⚠️ 无法解析文件: ${file} - ${error.message}`);
45
+ }
46
+ });
47
+ });
48
+
49
+ return agents;
50
+ };
51
+
52
+ /**
53
+ * 显示 agents 表格
54
+ * @param {Array} agents agents 信息数组
55
+ */
56
+ const _showAgents = (agents) => {
57
+ if (agents.length === 0) {
58
+ Ec.waiting('未找到任何 agents');
59
+ return;
60
+ }
61
+
62
+ // 计算列宽
63
+ const columnWidth = 20;
64
+ const uriColumnWidth = 30;
65
+
66
+ // 表头
67
+ const header = "编号".padEnd(6) +
68
+ "Arg Name".padEnd(columnWidth) +
69
+ "Type".padEnd(columnWidth) +
70
+ "ID".padEnd(columnWidth) +
71
+ "URI".padEnd(uriColumnWidth) +
72
+ "Name";
73
+ Ec.waiting(header);
74
+
75
+ // 分隔线
76
+ const separator = "-".repeat(5) + " " +
77
+ "-".repeat(columnWidth - 1) + " " +
78
+ "-".repeat(columnWidth - 1) + " " +
79
+ "-".repeat(columnWidth - 1) + " " +
80
+ "-".repeat(uriColumnWidth - 1) + " " +
81
+ "-".repeat(columnWidth - 1);
82
+ Ec.waiting(separator);
83
+
84
+ // 数据行
85
+ agents.forEach((agent, index) => {
86
+ const row = `${(index + 1).toString().padEnd(6)}` +
87
+ `${agent.argName.padEnd(columnWidth).red.bold}` +
88
+ `${agent.type.padEnd(columnWidth)}` +
89
+ `${agent.id.padEnd(columnWidth)}` +
90
+ `${agent.uri.padEnd(uriColumnWidth)}` +
91
+ agent.name;
92
+ Ec.waiting(row);
93
+ });
94
+
95
+ Ec.waiting(separator);
96
+ Ec.waiting(`${(agents.length + 1).toString().padEnd(6)}退出`);
97
+ Ec.waiting('');
98
+ };
99
+
100
+ /**
101
+ * 在浏览器中打开 URI
102
+ * @param {string} uri 要打开的 URI
103
+ * @param {string} agentType agent 类型
104
+ */
105
+ const _openInBrowser = (uri, agentType) => {
106
+ Ec.waiting(`🚀 正在打开 ${agentType} 中的 agent...`);
107
+
108
+ let command;
109
+ switch (process.platform) {
110
+ case 'darwin': // macOS
111
+ command = `open "${uri}"`;
112
+ break;
113
+ case 'win32': // Windows
114
+ command = `start "" "${uri}"`;
115
+ break;
116
+ default: // Linux
117
+ command = `xdg-open "${uri}"`;
118
+ break;
119
+ }
120
+
121
+ const child = spawn(command, { shell: true });
122
+
123
+ child.on('error', (error) => {
124
+ Ec.waiting(`⚠️ 无法打开浏览器: ${error.message}`);
125
+ });
126
+
127
+ child.on('close', (code) => {
128
+ if (code === 0) {
129
+ Ec.waiting(`✅ 浏览器已打开,请确保您的 IDE 已启动`);
130
+ } else {
131
+ Ec.waiting(`⚠️ 浏览器打开失败,退出码: ${code}`);
132
+ }
133
+ });
134
+ };
135
+
136
+ /**
137
+ * 交互式选择 agents
138
+ * @param {Array} agents agents 信息数组
139
+ */
140
+ const _interactiveSelect = async (agents) => {
141
+ while (true) {
142
+ _showAgents(agents);
143
+ Ec.waiting('💡 提示: 请确保您的 IDE 已启动,以便正确配置 agent');
144
+ const answer = await Ec.ask('请输入编号选择 agent (或输入退出编号): ');
145
+
146
+ const selectedIndex = parseInt(answer) - 1;
147
+
148
+ // 检查是否选择退出
149
+ if (selectedIndex === agents.length) {
150
+ Ec.waiting('👋 再见!');
151
+ break;
152
+ }
153
+
154
+ // 检查选择是否有效
155
+ if (isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= agents.length) {
156
+ Ec.waiting('❌ 无效的选择,请重新输入');
157
+ continue;
158
+ }
159
+
160
+ // 打开选中的 agent
161
+ const selectedAgent = agents[selectedIndex];
162
+ _openInBrowser(selectedAgent.uri, selectedAgent.type);
163
+
164
+ // 等待一段时间让用户看到结果
165
+ await new Promise(resolve => setTimeout(resolve, 2000));
166
+ }
167
+ };
168
+
169
+ module.exports = async () => {
170
+ try {
171
+ Ec.waiting('🔍 正在枚举所有可用的 agents...');
172
+
173
+ // 获取所有 agents
174
+ const agents = _getAgents();
175
+
176
+ if (agents.length === 0) {
177
+ Ec.waiting('❌ 未找到任何 agents');
178
+ Ec.askClose();
179
+ process.exit(0);
180
+ }
181
+
182
+ Ec.waiting(`✅ 找到 ${agents.length} 个 agents`);
183
+ Ec.waiting('');
184
+
185
+ // 进入交互式选择
186
+ await _interactiveSelect(agents);
187
+
188
+ Ec.askClose();
189
+ process.exit(0);
190
+ } catch (error) {
191
+ Ec.error(`执行过程中发生错误: ${error.message}`);
192
+ Ec.askClose();
193
+ process.exit(1);
194
+ }
195
+ };
@@ -133,6 +133,8 @@ const _ioFile = async (baseDir) => {
133
133
  ".momo/prompt/",
134
134
  ".momo/template/",
135
135
  ".momo/scripts/",
136
+ "reference/maven",
137
+ "reference/npm",
136
138
  "specification/changes/",
137
139
  "specification/actor/",
138
140
  "specification/.archives/",
@@ -255,7 +257,9 @@ const _ioFile = async (baseDir) => {
255
257
  * .momo/advanced/ 高级配置说明
256
258
  * /actor.md - 角色定制说明
257
259
  * .momo/scripts/ 特殊脚本目录
258
- *
260
+ * reference/
261
+ * /maven/ Maven 外置项目
262
+ * /npm/ NPM 外置项目
259
263
  * specification/ 工作目录
260
264
  * /project.md - 项目基本说明文件
261
265
  * /project-model.md - 模型说明文件(通常是建模所需的核心概念模型)
@@ -1,19 +1,19 @@
1
1
  const Ec = require('../epic');
2
- const { spawn } = require('child_process');
2
+ const {spawn} = require('child_process');
3
3
 
4
4
  module.exports = async (options) => {
5
5
  // 参数提取
6
6
  const parsed = Ec.parseArgument(options);
7
-
7
+
8
8
  try {
9
9
  // 定义可用的AI工具
10
10
  const aiTools = [
11
- { name: 'Trae', command: 'trae' },
12
- { name: 'Cursor', command: 'cursor' },
13
- { name: 'Lingma', command: 'lingma' },
14
- { name: 'Kiro', command: 'kiro' }
11
+ {name: 'Trae', command: 'trae'},
12
+ {name: 'Cursor', command: 'cursor'},
13
+ {name: 'Lingma', command: 'lingma'},
14
+ {name: 'Kiro', command: 'kiro'}
15
15
  ];
16
-
16
+
17
17
  // 检查哪些工具可用
18
18
  const availableTools = [];
19
19
  for (const tool of aiTools) {
@@ -21,14 +21,14 @@ module.exports = async (options) => {
21
21
  availableTools.push(tool);
22
22
  }
23
23
  }
24
-
24
+
25
25
  // 如果没有可用工具,提示用户安装
26
26
  if (availableTools.length === 0) {
27
27
  Ec.error('❌ 未找到可用的AI工具,请确保已安装以下工具之一:Trae、Cursor、Lingma、Kiro');
28
28
  Ec.askClose();
29
29
  process.exit(1);
30
30
  }
31
-
31
+
32
32
  // 如果只有一个工具可用,直接使用它
33
33
  if (availableTools.length === 1) {
34
34
  const tool = availableTools[0];
@@ -45,7 +45,7 @@ module.exports = async (options) => {
45
45
  Ec.askClose();
46
46
  process.exit(0);
47
47
  }
48
-
48
+
49
49
  // 显示交互式选择菜单
50
50
  Ec.waiting('🔍 检测到多个可用的AI工具,请选择要使用的工具:');
51
51
  const choices = availableTools.map((tool, index) => {
@@ -59,18 +59,18 @@ module.exports = async (options) => {
59
59
  return `${index + 1}. ${toolDisplayName}`;
60
60
  }
61
61
  });
62
-
62
+
63
63
  // 添加退出选项
64
64
  choices.push(`${choices.length + 1}. 退出`);
65
-
65
+
66
66
  for (const choice of choices) {
67
67
  Ec.waiting(choice);
68
68
  }
69
-
69
+
70
70
  // 获取用户选择
71
71
  const answer = await Ec.ask('请输入选项编号: ');
72
72
  const selectedIndex = parseInt(answer) - 1;
73
-
73
+
74
74
  // 检查用户选择
75
75
  if (isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= availableTools.length) {
76
76
  if (selectedIndex === availableTools.length) {
@@ -82,7 +82,7 @@ module.exports = async (options) => {
82
82
  Ec.askClose();
83
83
  process.exit(1);
84
84
  }
85
-
85
+
86
86
  // 执行选择的工具
87
87
  const selectedTool = availableTools[selectedIndex];
88
88
  let toolDisplayName = selectedTool.name;
@@ -93,8 +93,9 @@ module.exports = async (options) => {
93
93
  await _openWithTool(selectedTool.command);
94
94
  Ec.askClose();
95
95
  process.exit(0);
96
-
96
+
97
97
  } catch (error) {
98
+ console.error(error);
98
99
  Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
99
100
  if (process.platform === 'win32') {
100
101
  Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
@@ -113,8 +114,8 @@ const _isCommandAvailable = async (command) => {
113
114
  return new Promise((resolve) => {
114
115
  // 在 Windows 上使用 where 命令,在其他系统上使用 which 命令
115
116
  const whereCmd = process.platform === 'win32' ? 'where' : 'which';
116
- const process = spawn(whereCmd, [command]);
117
- process.on('close', (code) => {
117
+ const childProcess = spawn(whereCmd, [command]);
118
+ childProcess.on('close', (code) => {
118
119
  resolve(code === 0);
119
120
  });
120
121
  });
@@ -127,11 +128,11 @@ const _isCommandAvailable = async (command) => {
127
128
  const _openWithTool = async (tool) => {
128
129
  return new Promise((resolve, reject) => {
129
130
  // 使用工具命令打开当前目录
130
- const child = spawn(tool, ['.'], {
131
+ const child = spawn(tool, ['.'], {
131
132
  stdio: 'inherit',
132
133
  cwd: process.cwd()
133
134
  });
134
-
135
+
135
136
  child.on('close', (code) => {
136
137
  if (code === 0) {
137
138
  Ec.info(`✅ 项目已成功在 ${tool} 中打开`);
@@ -141,7 +142,7 @@ const _openWithTool = async (tool) => {
141
142
  reject(new Error(`${tool} 执行失败,退出码: ${code}`));
142
143
  }
143
144
  });
144
-
145
+
145
146
  child.on('error', (error) => {
146
147
  if (error.code === 'ENOENT') {
147
148
  Ec.error(`❌ 未找到命令: ${tool},请确保已正确安装`);
@@ -1,8 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { spawn } = require('child_process');
4
3
  const Ec = require('../epic');
5
4
  const fsAsync = require('fs').promises;
5
+ const { outCopy } = require('../epic/momo.fn.out');
6
6
 
7
7
  /**
8
8
  * 读取模板文件并提取 <!-- BEGIN --> 到 <!-- END --> 之间的内容
@@ -75,21 +75,8 @@ const _copyToClipboard = async (content, requirementName) => {
75
75
  // 去除换行符,将内容合并为一行
76
76
  const contentWithoutNewlines = content.replace(/\r?\n|\r/g, ' ');
77
77
 
78
- // 根据操作系统选择合适的剪贴板命令
79
- let proc;
80
- if (process.platform === 'darwin') {
81
- // macOS
82
- proc = spawn('pbcopy', { stdio: 'pipe' });
83
- } else if (process.platform === 'win32') {
84
- // Windows
85
- proc = spawn('clip', { stdio: 'pipe' });
86
- } else {
87
- // Linux/其他系统,尝试使用xclip
88
- proc = spawn('xclip', ['-selection', 'clipboard'], { stdio: 'pipe' });
89
- }
90
-
91
- proc.stdin.write(contentWithoutNewlines);
92
- proc.stdin.end();
78
+ // 使用统一的剪贴板函数
79
+ await outCopy(contentWithoutNewlines);
93
80
  Ec.waiting('✅ 计划提示词已复制到剪贴板');
94
81
 
95
82
  // 保存内容到 .working 目录
@@ -0,0 +1,296 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const util = require('util');
4
+ const Ec = require('../epic');
5
+
6
+ // 将 fs 方法转换为 Promise 版本
7
+ const fsAsync = {
8
+ mkdir: util.promisify(fs.mkdir),
9
+ copyFile: util.promisify(fs.copyFile),
10
+ readdir: util.promisify(fs.readdir),
11
+ stat: util.promisify(fs.stat),
12
+ readFile: util.promisify(fs.readFile),
13
+ writeFile: util.promisify(fs.writeFile)
14
+ };
15
+
16
+ /**
17
+ * 获取或创建 refer.json 配置文件路径
18
+ * @param {string} baseDir 项目根目录
19
+ * @returns {string} refer.json 文件路径
20
+ */
21
+ const _getReferConfigPath = (baseDir) => {
22
+ return path.resolve(baseDir, '.momo', 'advanced', 'refer.json');
23
+ };
24
+
25
+ /**
26
+ * 获取默认的 refer 配置
27
+ * @returns {Object} 默认配置对象
28
+ */
29
+ const _getDefaultReferConfig = () => {
30
+ return {
31
+ maven: {
32
+ file: 'pom.xml',
33
+ target: 'reference/maven'
34
+ },
35
+ gradle: {
36
+ file: 'build.gradle',
37
+ target: 'reference/gradle'
38
+ },
39
+ npm: {
40
+ file: 'package.json',
41
+ target: 'reference/npm'
42
+ },
43
+ rust: {
44
+ file: 'Cargo.toml',
45
+ target: 'reference/rust'
46
+ },
47
+ go: {
48
+ file: 'go.mod',
49
+ target: 'reference/go'
50
+ },
51
+ ruby: {
52
+ file: 'Gemfile',
53
+ target: 'reference/ruby'
54
+ },
55
+ python: {
56
+ file: 'requirements.txt',
57
+ target: 'reference/python'
58
+ },
59
+ php: {
60
+ file: 'composer.json',
61
+ target: 'reference/php'
62
+ },
63
+ dotnet: {
64
+ file: 'project.csproj',
65
+ target: 'reference/dotnet'
66
+ },
67
+ java: {
68
+ file: 'pom.xml',
69
+ target: 'reference/java'
70
+ },
71
+ cmake: {
72
+ file: 'CMakeLists.txt',
73
+ target: 'reference/cmake'
74
+ },
75
+ make: {
76
+ file: 'Makefile',
77
+ target: 'reference/make'
78
+ }
79
+ };
80
+ };
81
+
82
+ /**
83
+ * 读取或创建 refer.json 配置文件
84
+ * @param {string} configPath 配置文件路径
85
+ * @returns {Promise<Object>} 配置对象
86
+ */
87
+ const _readOrCreateReferConfig = async (configPath) => {
88
+ // 确保 .momo/advanced 目录存在
89
+ const configDir = path.dirname(configPath);
90
+ if (!fs.existsSync(configDir)) {
91
+ await fsAsync.mkdir(configDir, { recursive: true });
92
+ }
93
+
94
+ const defaultConfig = _getDefaultReferConfig();
95
+
96
+ // 如果配置文件不存在,创建默认配置
97
+ if (!fs.existsSync(configPath)) {
98
+ await fsAsync.writeFile(configPath, JSON.stringify(defaultConfig, null, 4));
99
+ Ec.waiting(`创建默认配置文件: ${path.relative(process.cwd(), configPath)}`);
100
+ return defaultConfig;
101
+ }
102
+
103
+ // 读取现有配置
104
+ try {
105
+ const content = await fsAsync.readFile(configPath, 'utf8');
106
+ const existingConfig = JSON.parse(content);
107
+
108
+ // 检查是否需要更新配置(添加新的项目类型)
109
+ let updated = false;
110
+ for (const [key, value] of Object.entries(defaultConfig)) {
111
+ if (!existingConfig[key]) {
112
+ existingConfig[key] = value;
113
+ updated = true;
114
+ }
115
+ }
116
+
117
+ // 如果有更新,则写回文件
118
+ if (updated) {
119
+ await fsAsync.writeFile(configPath, JSON.stringify(existingConfig, null, 4));
120
+ Ec.waiting(`更新配置文件: ${path.relative(process.cwd(), configPath)}`);
121
+ }
122
+
123
+ return existingConfig;
124
+ } catch (error) {
125
+ Ec.error(`配置文件格式错误: ${configPath}`);
126
+ throw error;
127
+ }
128
+ };
129
+
130
+ /**
131
+ * 显示当前支持的项目类型(表格形式)
132
+ * @param {Object} referConfig 引用配置
133
+ */
134
+ const _showSupportedTypes = (referConfig) => {
135
+ Ec.waiting("当前支持的项目类型:");
136
+
137
+ // 定义列宽
138
+ const columnWidth = 24;
139
+
140
+ // 表头
141
+ const header = "Type".padEnd(columnWidth) +
142
+ "ID File".padEnd(columnWidth) +
143
+ "Store Path";
144
+ Ec.waiting(header);
145
+
146
+ // 分隔线
147
+ const separator = "-".repeat(columnWidth - 1) + " " +
148
+ "-".repeat(columnWidth - 1) + " " +
149
+ "-".repeat(columnWidth - 1);
150
+ Ec.waiting(separator);
151
+
152
+ // 数据行
153
+ for (const [type, config] of Object.entries(referConfig)) {
154
+ const row = type.padEnd(columnWidth) +
155
+ config.file.padEnd(columnWidth) +
156
+ config.target;
157
+ Ec.waiting(row);
158
+ }
159
+
160
+ Ec.info("使用方法: momo project -s \"项目路径\"");
161
+ };
162
+
163
+ /**
164
+ * 检查路径是否为目录
165
+ * @param {string} sourcePath 路径
166
+ * @returns {Promise<boolean>} 是否为目录
167
+ */
168
+ const _isDirectory = async (sourcePath) => {
169
+ try {
170
+ const stats = await fsAsync.stat(sourcePath);
171
+ return stats.isDirectory();
172
+ } catch (error) {
173
+ return false;
174
+ }
175
+ };
176
+
177
+ /**
178
+ * 检查目录中是否存在指定文件
179
+ * @param {string} sourceDir 源目录
180
+ * @param {string} fileName 文件名
181
+ * @returns {Promise<boolean>} 是否存在文件
182
+ */
183
+ const _hasFile = async (sourceDir, fileName) => {
184
+ try {
185
+ const filePath = path.join(sourceDir, fileName);
186
+ const stats = await fsAsync.stat(filePath);
187
+ return stats.isFile();
188
+ } catch (error) {
189
+ return false;
190
+ }
191
+ };
192
+
193
+ /**
194
+ * 递归拷贝目录
195
+ * @param {string} src 源目录
196
+ * @param {string} dest 目标目录
197
+ */
198
+ const _copyDir = async (src, dest) => {
199
+ const entries = await fsAsync.readdir(src, { withFileTypes: true });
200
+ await fsAsync.mkdir(dest, { recursive: true });
201
+
202
+ for (let entry of entries) {
203
+ const srcPath = path.join(src, entry.name);
204
+ const destPath = path.join(dest, entry.name);
205
+
206
+ if (entry.isDirectory()) {
207
+ await _copyDir(srcPath, destPath);
208
+ } else {
209
+ await fsAsync.copyFile(srcPath, destPath);
210
+ }
211
+ }
212
+ };
213
+
214
+ /**
215
+ * 处理项目引用
216
+ * @param {string} sourcePath 源项目路径
217
+ * @param {Object} referConfig 引用配置
218
+ * @param {string} baseDir 项目根目录
219
+ */
220
+ const _processProjectReference = async (sourcePath, referConfig, baseDir) => {
221
+ // 检查源路径是否为目录
222
+ if (!(await _isDirectory(sourcePath))) {
223
+ Ec.error(`源路径必须是一个目录: ${sourcePath}`);
224
+ process.exit(1);
225
+ }
226
+
227
+ Ec.waiting(`检查项目: ${sourcePath}`);
228
+
229
+ // 遍历配置中的每种项目类型
230
+ for (const [type, config] of Object.entries(referConfig)) {
231
+ const { file, target } = config;
232
+
233
+ // 检查源目录中是否存在指定文件
234
+ if (await _hasFile(sourcePath, file)) {
235
+ Ec.waiting(`检测到 ${type} 项目 (${file})`);
236
+
237
+ // 构建目标目录路径
238
+ const targetDir = path.resolve(baseDir, target);
239
+
240
+ // 确保目标目录存在
241
+ if (!fs.existsSync(targetDir)) {
242
+ Ec.waiting(`创建目录: ${target}`);
243
+ await fsAsync.mkdir(targetDir, { recursive: true });
244
+ }
245
+
246
+ // 生成目标子目录名称(使用源目录名称)
247
+ const sourceDirName = path.basename(sourcePath);
248
+ const finalTargetDir = path.join(targetDir, sourceDirName);
249
+
250
+ // 拷贝项目
251
+ try {
252
+ Ec.waiting(`拷贝项目到: ${path.join(target, sourceDirName)}`);
253
+ await _copyDir(sourcePath, finalTargetDir);
254
+ Ec.waiting(`✅ ${type} 项目引用成功`);
255
+ } catch (error) {
256
+ Ec.error(`❌ 拷贝项目失败: ${error.message}`);
257
+ throw error;
258
+ }
259
+ }
260
+ }
261
+ };
262
+
263
+ module.exports = async (options) => {
264
+ // 参数提取
265
+ const parsed = Ec.parseArgument(options);
266
+ const sourcePath = parsed.source;
267
+
268
+ try {
269
+ // 获取项目根目录
270
+ const baseDir = process.cwd();
271
+
272
+ // 获取 refer.json 配置文件路径
273
+ const configPath = _getReferConfigPath(baseDir);
274
+
275
+ // 读取或创建配置文件
276
+ const referConfig = await _readOrCreateReferConfig(configPath);
277
+
278
+ // 如果没有提供 source 参数,则显示支持的项目类型
279
+ if (!sourcePath) {
280
+ _showSupportedTypes(referConfig);
281
+ Ec.askClose();
282
+ process.exit(0);
283
+ }
284
+
285
+ // 处理项目引用
286
+ await _processProjectReference(sourcePath, referConfig, baseDir);
287
+
288
+ Ec.info("项目引用处理完成!");
289
+ Ec.askClose();
290
+ process.exit(0);
291
+ } catch (error) {
292
+ Ec.error(`执行过程中发生错误: ${error.message}`);
293
+ Ec.askClose();
294
+ process.exit(1);
295
+ }
296
+ };