momo-ai 1.0.20 → 1.0.21

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 (103) hide show
  1. package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
  2. package/.claude/skills/algorithmic-art/SKILL.md +405 -0
  3. package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
  4. package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
  5. package/.claude/skills/r2mo-rad-lain/PROMPT.md +281 -0
  6. package/.claude/skills/r2mo-rad-lain/README.md +192 -0
  7. package/.claude/skills/r2mo-rad-lain/SKILL.md +412 -0
  8. package/.claude/skills/r2mo-rad-lain/examples/argument-parsing.js +154 -0
  9. package/.claude/skills/r2mo-rad-lain/examples/file-operations.js +182 -0
  10. package/.claude/skills/r2mo-rad-lain/file-utils-api.md +281 -0
  11. package/.claude/skills/r2mo-rad-lain/menu-api.md +187 -0
  12. package/.claude/skills/r2mo-rad-lain/scripts/file-utils.js +223 -0
  13. package/.claude/skills/r2mo-rad-lain/scripts/menu.js +289 -0
  14. package/.claude/skills/r2mo-rad-lain/scripts/yaml-parser.js +209 -0
  15. package/.claude/skills/r2mo-rad-lain/templates/command.json.template +13 -0
  16. package/.claude/skills/r2mo-rad-lain/templates/executor.js.template +32 -0
  17. package/.claude/skills/r2mo-rad-lain/templates/interactive-menu.js.template +221 -0
  18. package/.cursor/mcp.json +17 -0
  19. package/.obsidian/app.json +1 -0
  20. package/.obsidian/appearance.json +4 -0
  21. package/.obsidian/community-plugins.json +4 -0
  22. package/.obsidian/core-plugins.json +33 -0
  23. package/.obsidian/plugins/ai-agent/main.js +98495 -0
  24. package/.obsidian/plugins/ai-agent/manifest.json +11 -0
  25. package/.obsidian/plugins/ai-agent/styles.css +806 -0
  26. package/.obsidian/plugins/dataview/main.js +20876 -0
  27. package/.obsidian/plugins/dataview/manifest.json +11 -0
  28. package/.obsidian/plugins/dataview/styles.css +141 -0
  29. package/.obsidian/plugins/obsidian-excalidraw-plugin/main.js +10 -0
  30. package/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json +12 -0
  31. package/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css +1 -0
  32. package/.obsidian/plugins/templater-obsidian/main.js +45 -0
  33. package/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
  34. package/.obsidian/plugins/templater-obsidian/styles.css +226 -0
  35. package/.obsidian/plugins/terminal/main.js +200 -0
  36. package/.obsidian/plugins/terminal/manifest.json +14 -0
  37. package/.obsidian/plugins/terminal/styles.css +32 -0
  38. package/.obsidian/themes/AnuPpuccin/manifest.json +7 -0
  39. package/.obsidian/themes/AnuPpuccin/theme.css +9080 -0
  40. package/.obsidian/themes/Things/manifest.json +7 -0
  41. package/.obsidian/themes/Things/theme.css +1628 -0
  42. package/.obsidian/workspace.json +196 -0
  43. package/README.md +10 -123
  44. package/docs/images/logo.jpeg +0 -0
  45. package/install.sh +1 -0
  46. package/package.json +6 -2
  47. package/skills/r2mo-rad-lain/SKILL.md +101 -0
  48. package/src/_mcp/skills-server.mjs +70 -0
  49. package/src/_skill/repositories.json +16 -0
  50. package/src/commander/help.json +5 -0
  51. package/src/commander/mcp.json +13 -0
  52. package/src/commander/open.json +8 -2
  53. package/src/commander/skills.json +20 -0
  54. package/src/executor/executeEnv.js +48 -38
  55. package/src/executor/executeHelp.js +77 -16
  56. package/src/executor/executeInit.js +203 -149
  57. package/src/executor/executeMcp.js +290 -0
  58. package/src/executor/executeOpen.js +144 -125
  59. package/src/executor/executeSkills.js +747 -0
  60. package/src/executor/index.js +5 -39
  61. package/src/momo.js +2 -1
  62. package/src/utils/momo-args.js +39 -0
  63. package/src/utils/momo-file-utils.js +75 -0
  64. package/src/utils/momo-menu.js +54 -0
  65. package/src/commander/actor.json +0 -12
  66. package/src/commander/actors.json +0 -6
  67. package/src/commander/add.json +0 -12
  68. package/src/commander/agent.json +0 -12
  69. package/src/commander/agentcfg.json +0 -5
  70. package/src/commander/archive.json +0 -12
  71. package/src/commander/commit.json +0 -12
  72. package/src/commander/console.json +0 -7
  73. package/src/commander/lain.json +0 -7
  74. package/src/commander/list.json +0 -7
  75. package/src/commander/plan.json +0 -12
  76. package/src/commander/project.json +0 -12
  77. package/src/commander/pull.json +0 -6
  78. package/src/commander/push.json +0 -6
  79. package/src/commander/repo.json +0 -18
  80. package/src/commander/run.json +0 -18
  81. package/src/commander/show.json +0 -12
  82. package/src/commander/tasks.json +0 -18
  83. package/src/commander/unlock.json +0 -6
  84. package/src/commander/validate.json +0 -12
  85. package/src/executor/executeActor.js +0 -133
  86. package/src/executor/executeActors.js +0 -58
  87. package/src/executor/executeAdd.js +0 -307
  88. package/src/executor/executeAgent.js +0 -299
  89. package/src/executor/executeAgentCfg.js +0 -210
  90. package/src/executor/executeArchive.js +0 -124
  91. package/src/executor/executeCommit.js +0 -202
  92. package/src/executor/executeConsole.js +0 -142
  93. package/src/executor/executeList.js +0 -133
  94. package/src/executor/executePlan.js +0 -164
  95. package/src/executor/executeProject.js +0 -313
  96. package/src/executor/executePull.js +0 -127
  97. package/src/executor/executePush.js +0 -243
  98. package/src/executor/executeRepo.js +0 -238
  99. package/src/executor/executeRun.js +0 -644
  100. package/src/executor/executeShow.js +0 -164
  101. package/src/executor/executeTasks.js +0 -384
  102. package/src/executor/executeUnlock.js +0 -110
  103. package/src/executor/executeValidate.js +0 -210
@@ -1,133 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const Ec = require('../epic');
4
-
5
- /**
6
- * 从 Markdown 文件中提取编号信息
7
- * @param {string} filePath 文件路径
8
- * @param {string} dirName 目录名(用于从目录名中提取编号)
9
- * @returns {string} 编号信息或 'N/A'
10
- */
11
- const _extractId = (filePath, dirName) => {
12
- try {
13
- // 首先尝试从目录名中提取编号(MXX格式)
14
- const dirMatch = dirName.match(/^M\d{2}/);
15
- if (dirMatch) {
16
- return dirMatch[0];
17
- }
18
-
19
- if (!fs.existsSync(filePath)) {
20
- return 'N/A';
21
- }
22
-
23
- const content = fs.readFileSync(filePath, 'utf8');
24
-
25
- // 首先尝试查找 <!-- CODE: XXX --> 格式
26
- const codeMatch = content.match(/<!--\s*CODE:\s*(.+?)\s*-->/i);
27
- if (codeMatch) {
28
- return codeMatch[1].trim();
29
- }
30
-
31
- // 然后尝试从文件内容的标题中提取编号(MXX格式)
32
- const lines = content.split('\n');
33
- for (const line of lines) {
34
- // 匹配 # MXX 格式的标题(M后跟两位数字)
35
- const titleMatch = line.match(/^#\s+(M\d{2})/);
36
- if (titleMatch) {
37
- return titleMatch[1];
38
- }
39
- }
40
-
41
- // 如果没有找到CODE格式,尝试查找 "- 编号:" 格式
42
- for (const line of lines) {
43
- const idMatch = line.match(/-\s*编号[::]\s*(.+)/);
44
- if (idMatch) {
45
- return idMatch[1].trim();
46
- }
47
- }
48
-
49
- return 'N/A';
50
- } catch (error) {
51
- return 'N/A';
52
- }
53
- };
54
-
55
- /**
56
- * 统计任务数量
57
- * @param {string} tasksFile 任务文件路径
58
- * @returns {number} 任务数量
59
- */
60
- const _countTasks = (tasksFile) => {
61
- try {
62
- if (!fs.existsSync(tasksFile)) {
63
- return 0;
64
- }
65
-
66
- const content = fs.readFileSync(tasksFile, 'utf8');
67
- const lines = content.split('\n');
68
- let count = 0;
69
-
70
- // 匹配任务列表格式:
71
- // - [ ] 任务描述
72
- // - [xxx] 任务描述
73
- for (const line of lines) {
74
- if (line.trim().match(/^-\s*\[.*\]/)) {
75
- count++;
76
- }
77
- }
78
-
79
- return count;
80
- } catch (error) {
81
- return 0;
82
- }
83
- };
84
-
85
- module.exports = (options) => {
86
- try {
87
- // 构建路径
88
- const projectDir = process.cwd();
89
- const changesDir = path.join(projectDir, 'specification', 'changes');
90
-
91
- // 检查 changes 目录是否存在
92
- if (!fs.existsSync(changesDir)) {
93
- Ec.waiting('未找到任何需求');
94
- process.exit(0);
95
- }
96
-
97
- // 读取所有需求目录
98
- const requirements = fs.readdirSync(changesDir)
99
- .filter(item => {
100
- const itemPath = path.join(changesDir, item);
101
- return fs.statSync(itemPath).isDirectory();
102
- });
103
-
104
- if (requirements.length === 0) {
105
- Ec.waiting('未找到任何需求');
106
- process.exit(0);
107
- }
108
-
109
- // 显示表头(调整列宽和间距)
110
- const header = '编号'.padEnd(12) + '名称'.padEnd(32) + '任务数量';
111
- Ec.waiting(header);
112
-
113
- // 显示分隔线
114
- const separator = '-'.repeat(10) + ' ' + '-'.repeat(30) + ' ' + '-'.repeat(8);
115
- Ec.waiting(separator);
116
-
117
- // 显示需求列表
118
- requirements.forEach((requirement) => {
119
- const proposalFile = path.join(changesDir, requirement, 'proposal.md');
120
- const tasksFile = path.join(changesDir, requirement, 'tasks.md');
121
- const id = _extractId(proposalFile, requirement);
122
- const taskCount = _countTasks(tasksFile);
123
- const line = id.padEnd(12) + requirement.padEnd(32) + String(taskCount);
124
- Ec.waiting(line);
125
- });
126
-
127
- Ec.info(`✅ 共找到 ${requirements.length} 个需求`);
128
- process.exit(0);
129
- } catch (error) {
130
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
131
- process.exit(1);
132
- }
133
- };
@@ -1,164 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const Ec = require('../epic');
4
- const fsAsync = require('fs').promises;
5
- const { outCopy } = require('../epic/momo.fn.out');
6
-
7
- /**
8
- * 读取模板文件并提取 <!-- BEGIN --> 到 <!-- END --> 之间的内容
9
- * @param {string} templatePath 模板文件路径
10
- * @returns {Promise<string>} 提取的模板内容
11
- */
12
- const _readTemplate = async (templatePath) => {
13
- try {
14
- const content = await fsAsync.readFile(templatePath, 'utf8');
15
- const lines = content.split('\n');
16
- let beginIndex = -1;
17
- let endIndex = -1;
18
-
19
- for (let i = 0; i < lines.length; i++) {
20
- if (lines[i].includes('<!-- BEGIN -->')) {
21
- beginIndex = i;
22
- } else if (lines[i].includes('<!-- END -->')) {
23
- endIndex = i;
24
- break;
25
- }
26
- }
27
-
28
- if (beginIndex !== -1 && endIndex !== -1) {
29
- // 提取 BEGIN 和 END 之间的内容(不包括 BEGIN 和 END 行)
30
- return lines.slice(beginIndex + 1, endIndex).join('\n');
31
- }
32
-
33
- return content;
34
- } catch (error) {
35
- Ec.waiting(`读取模板文件失败: ${error.message}`);
36
- throw error;
37
- }
38
- };
39
-
40
- /**
41
- * 渲染 EJS 模板
42
- * @param {string} template 模板内容
43
- * @param {Object} data 数据对象
44
- * @returns {string} 渲染后的内容
45
- */
46
- const _renderTemplate = (template, data) => {
47
- let result = template;
48
- for (const key in data) {
49
- if (data.hasOwnProperty(key)) {
50
- const regex = new RegExp(`<%=\\s*${key}\\s*%>`, 'g');
51
- result = result.replace(regex, data[key]);
52
- }
53
- }
54
- return result;
55
- };
56
-
57
- /**
58
- * 检查需求目录是否存在
59
- * @param {string} changesDir changes目录路径
60
- * @param {string} requirementName 需求名称
61
- * @returns {boolean} 是否存在
62
- */
63
- const _isRequirementExists = (changesDir, requirementName) => {
64
- const requirementDir = path.join(changesDir, requirementName);
65
- return fs.existsSync(requirementDir);
66
- };
67
-
68
- /**
69
- * 将内容复制到剪贴板(去除换行符)
70
- * @param {string} content 要复制的内容
71
- * @param {string} requirementName 需求名称
72
- */
73
- const _copyToClipboard = async (content, requirementName) => {
74
- try {
75
- // 去除换行符,将内容合并为一行
76
- const contentWithoutNewlines = content.replace(/\r?\n|\r/g, ' ');
77
-
78
- // 使用统一的剪贴板函数
79
- await outCopy(contentWithoutNewlines);
80
- Ec.waiting('✅ 计划提示词已复制到剪贴板');
81
-
82
- // 保存内容到 .working 目录
83
- const workingDir = path.resolve(process.cwd(), '.working');
84
- const fileName = `REQ-${requirementName}.txt`;
85
- const filePath = path.join(workingDir, fileName);
86
-
87
- // 确保 .working 目录存在
88
- if (!fs.existsSync(workingDir)) {
89
- await fsAsync.mkdir(workingDir, { recursive: true });
90
- }
91
-
92
- // 写入文件
93
- await fsAsync.writeFile(filePath, content);
94
- Ec.waiting(`📄 计划提示词已保存到文件: ${filePath}`);
95
- } catch (error) {
96
- Ec.waiting(`复制到剪贴板失败: ${error.message}`);
97
- // 提供备选方案
98
- Ec.waiting('计划提示词内容:');
99
- console.log(content);
100
- if (process.platform === 'win32') {
101
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
102
- }
103
- }
104
- };
105
-
106
- module.exports = async (options) => {
107
- // 参数提取
108
- const parsed = Ec.parseArgument(options);
109
-
110
- // 获取需求名称
111
- const requirementName = parsed.name || parsed.n;
112
-
113
- // 验证参数
114
- if (!requirementName) {
115
- Ec.error("❌ 请提供需求名称 (-n, --name)");
116
- process.exit(1);
117
- }
118
-
119
- // 检查需求名称是否包含点号(扩展名)
120
- if (requirementName.includes('.')) {
121
- Ec.error("❌ 需求名称不能包含点号(.),以防止与文件扩展名混淆");
122
- process.exit(1);
123
- }
124
-
125
- // 在 Windows 上检查非法字符
126
- if (process.platform === 'win32') {
127
- const illegalChars = /[<>:"/\\|?*\x00-\x1F]/g;
128
- if (illegalChars.test(requirementName)) {
129
- Ec.error(`❌ 需求名称 "${requirementName}" 包含非法字符,请避免使用以下字符: < > : " / \\ | ? * 以及控制字符`);
130
- process.exit(1);
131
- }
132
- }
133
-
134
- Ec.waiting(`准备生成需求计划: ${requirementName}`);
135
-
136
- try {
137
- // 获取项目路径
138
- const projectDir = process.cwd();
139
- const changesDir = path.join(projectDir, 'specification', 'changes');
140
- const promptTemplatePath = path.join(__dirname, '../_template/PROMPT/plan.md.ejs');
141
-
142
- // 检查需求是否存在
143
- if (!_isRequirementExists(changesDir, requirementName)) {
144
- Ec.error(`❌ 需求 "${requirementName}" 不存在`);
145
- process.exit(1);
146
- }
147
-
148
- // 读取并处理提示词模板
149
- const templateContent = await _readTemplate(promptTemplatePath);
150
- const renderedContent = _renderTemplate(templateContent, { NAME: requirementName });
151
-
152
- // 将提示词复制到剪贴板
153
- await _copyToClipboard(renderedContent, requirementName);
154
-
155
- Ec.info(`✅ 成功生成需求 "${requirementName}" 的计划提示词`);
156
- process.exit(0);
157
- } catch (error) {
158
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
159
- if (process.platform === 'win32') {
160
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
161
- }
162
- process.exit(1);
163
- }
164
- };
@@ -1,313 +0,0 @@
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.json 配置文件路径
27
- * @returns {string} 模板中 refer.json 文件路径
28
- */
29
- const _getTemplateReferConfigPath = () => {
30
- return path.resolve(__dirname, '../_template/LAIN/.momo/advanced/refer.json');
31
- };
32
-
33
- /**
34
- * 获取默认的 refer 配置
35
- * @returns {Object} 默认配置对象
36
- */
37
- const _getDefaultReferConfig = () => {
38
- // 从模板文件读取默认配置
39
- const templateConfigPath = _getTemplateReferConfigPath();
40
- if (fs.existsSync(templateConfigPath)) {
41
- const content = fs.readFileSync(templateConfigPath, 'utf8');
42
- return JSON.parse(content);
43
- }
44
-
45
- // 如果模板文件不存在,返回硬编码的默认配置
46
- return {
47
- maven: {
48
- file: 'pom.xml',
49
- target: 'reference/maven'
50
- },
51
- gradle: {
52
- file: 'build.gradle',
53
- target: 'reference/gradle'
54
- },
55
- npm: {
56
- file: 'package.json',
57
- target: 'reference/npm'
58
- },
59
- rust: {
60
- file: 'Cargo.toml',
61
- target: 'reference/rust'
62
- },
63
- go: {
64
- file: 'go.mod',
65
- target: 'reference/go'
66
- },
67
- ruby: {
68
- file: 'Gemfile',
69
- target: 'reference/ruby'
70
- },
71
- python: {
72
- file: 'requirements.txt',
73
- target: 'reference/python'
74
- },
75
- php: {
76
- file: 'composer.json',
77
- target: 'reference/php'
78
- },
79
- dotnet: {
80
- file: 'project.csproj',
81
- target: 'reference/dotnet'
82
- },
83
- cmake: {
84
- file: 'CMakeLists.txt',
85
- target: 'reference/cmake'
86
- },
87
- make: {
88
- file: 'Makefile',
89
- target: 'reference/make'
90
- }
91
- };
92
- };
93
-
94
- /**
95
- * 读取或创建 refer.json 配置文件
96
- * @param {string} configPath 配置文件路径
97
- * @returns {Promise<Object>} 配置对象
98
- */
99
- const _readOrCreateReferConfig = async (configPath) => {
100
- // 确保 .momo/advanced 目录存在
101
- const configDir = path.dirname(configPath);
102
- if (!fs.existsSync(configDir)) {
103
- await fsAsync.mkdir(configDir, { recursive: true });
104
- }
105
-
106
- const defaultConfig = _getDefaultReferConfig();
107
-
108
- // 如果配置文件不存在,创建默认配置
109
- if (!fs.existsSync(configPath)) {
110
- await fsAsync.writeFile(configPath, JSON.stringify(defaultConfig, null, 4));
111
- Ec.waiting(`创建默认配置文件: ${path.relative(process.cwd(), configPath)}`);
112
- return defaultConfig;
113
- }
114
-
115
- // 读取现有配置
116
- try {
117
- const content = await fsAsync.readFile(configPath, 'utf8');
118
- const existingConfig = JSON.parse(content);
119
-
120
- // 检查是否需要更新配置(添加新的项目类型)
121
- let updated = false;
122
- for (const [key, value] of Object.entries(defaultConfig)) {
123
- if (!existingConfig[key]) {
124
- existingConfig[key] = value;
125
- updated = true;
126
- }
127
- }
128
-
129
- // 如果有更新,则写回文件
130
- if (updated) {
131
- await fsAsync.writeFile(configPath, JSON.stringify(existingConfig, null, 4));
132
- Ec.waiting(`更新配置文件: ${path.relative(process.cwd(), configPath)}`);
133
- }
134
-
135
- return existingConfig;
136
- } catch (error) {
137
- Ec.error(`配置文件格式错误: ${configPath}`);
138
- throw error;
139
- }
140
- };
141
-
142
- /**
143
- * 显示当前支持的项目类型(表格形式)
144
- * @param {Object} referConfig 引用配置
145
- */
146
- const _showSupportedTypes = (referConfig) => {
147
- Ec.waiting("当前支持的项目类型:");
148
-
149
- // 定义列宽
150
- const columnWidth = 24;
151
-
152
- // 表头
153
- const header = "Type".padEnd(columnWidth) +
154
- "ID File".padEnd(columnWidth) +
155
- "Store Path";
156
- Ec.waiting(header);
157
-
158
- // 分隔线
159
- const separator = "-".repeat(columnWidth - 1) + " " +
160
- "-".repeat(columnWidth - 1) + " " +
161
- "-".repeat(columnWidth - 1);
162
- Ec.waiting(separator);
163
-
164
- // 数据行
165
- for (const [type, config] of Object.entries(referConfig)) {
166
- const row = type.padEnd(columnWidth) +
167
- config.file.padEnd(columnWidth) +
168
- config.target;
169
- Ec.waiting(row);
170
- }
171
-
172
- Ec.info("使用方法: momo project -s \"项目路径\"");
173
- };
174
-
175
- /**
176
- * 检查路径是否为目录
177
- * @param {string} sourcePath 路径
178
- * @returns {Promise<boolean>} 是否为目录
179
- */
180
- const _isDirectory = async (sourcePath) => {
181
- try {
182
- const stats = await fsAsync.stat(sourcePath);
183
- return stats.isDirectory();
184
- } catch (error) {
185
- return false;
186
- }
187
- };
188
-
189
- /**
190
- * 检查目录中是否存在指定文件
191
- * @param {string} sourceDir 源目录
192
- * @param {string} fileName 文件名
193
- * @returns {Promise<boolean>} 是否存在文件
194
- */
195
- const _hasFile = async (sourceDir, fileName) => {
196
- try {
197
- const filePath = path.join(sourceDir, fileName);
198
- const stats = await fsAsync.stat(filePath);
199
- return stats.isFile();
200
- } catch (error) {
201
- return false;
202
- }
203
- };
204
-
205
- /**
206
- * 递归拷贝目录
207
- * @param {string} src 源目录
208
- * @param {string} dest 目标目录
209
- */
210
- const _copyDir = async (src, dest) => {
211
- const entries = await fsAsync.readdir(src, { withFileTypes: true });
212
- await fsAsync.mkdir(dest, { recursive: true });
213
-
214
- for (let entry of entries) {
215
- const srcPath = path.join(src, entry.name);
216
- const destPath = path.join(dest, entry.name);
217
-
218
- if (entry.isDirectory()) {
219
- await _copyDir(srcPath, destPath);
220
- } else {
221
- await fsAsync.copyFile(srcPath, destPath);
222
- }
223
- }
224
- };
225
-
226
- /**
227
- * 处理项目引用
228
- * @param {string} sourcePath 源项目路径
229
- * @param {Object} referConfig 引用配置
230
- * @param {string} baseDir 项目根目录
231
- */
232
- const _processProjectReference = async (sourcePath, referConfig, baseDir) => {
233
- // 检查源路径是否为目录
234
- if (!(await _isDirectory(sourcePath))) {
235
- Ec.error(`源路径必须是一个目录: ${sourcePath}`);
236
- process.exit(1);
237
- }
238
-
239
- Ec.waiting(`检查项目: ${sourcePath}`);
240
-
241
- // 遍历配置中的每种项目类型,但排除java类型
242
- for (const [type, config] of Object.entries(referConfig)) {
243
- // 跳过java类型处理
244
- if (type === 'java') {
245
- continue;
246
- }
247
-
248
- const { file, target } = config;
249
-
250
- // 检查源目录中是否存在指定文件
251
- if (await _hasFile(sourcePath, file)) {
252
- Ec.waiting(`检测到 ${type} 项目 (${file})`);
253
-
254
- // 构建目标目录路径
255
- const targetDir = path.resolve(baseDir, target);
256
-
257
- // 确保目标目录存在
258
- if (!fs.existsSync(targetDir)) {
259
- Ec.waiting(`创建目录: ${target}`);
260
- await fsAsync.mkdir(targetDir, { recursive: true });
261
- }
262
-
263
- // 生成目标子目录名称(使用源目录名称)
264
- const sourceDirName = path.basename(sourcePath);
265
- const finalTargetDir = path.join(targetDir, sourceDirName);
266
-
267
- // 拷贝项目
268
- try {
269
- Ec.waiting(`拷贝项目到: ${path.join(target, sourceDirName)}`);
270
- await _copyDir(sourcePath, finalTargetDir);
271
- Ec.waiting(`✅ ${type} 项目引用成功`);
272
- } catch (error) {
273
- Ec.error(`❌ 拷贝项目失败: ${error.message}`);
274
- throw error;
275
- }
276
- }
277
- }
278
- };
279
-
280
- module.exports = async (options) => {
281
- // 参数提取
282
- const parsed = Ec.parseArgument(options);
283
- const sourcePath = parsed.source;
284
-
285
- try {
286
- // 获取项目根目录
287
- const baseDir = process.cwd();
288
-
289
- // 获取 refer.json 配置文件路径
290
- const configPath = _getReferConfigPath(baseDir);
291
-
292
- // 读取或创建配置文件
293
- const referConfig = await _readOrCreateReferConfig(configPath);
294
-
295
- // 如果没有提供 source 参数,则显示支持的项目类型
296
- if (!sourcePath) {
297
- _showSupportedTypes(referConfig);
298
- Ec.askClose();
299
- process.exit(0);
300
- }
301
-
302
- // 处理项目引用
303
- await _processProjectReference(sourcePath, referConfig, baseDir);
304
-
305
- Ec.info("项目引用处理完成!");
306
- Ec.askClose();
307
- process.exit(0);
308
- } catch (error) {
309
- Ec.error(`执行过程中发生错误: ${error.message}`);
310
- Ec.askClose();
311
- process.exit(1);
312
- }
313
- };