momo-ai 1.0.9 → 1.0.11
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/README.md +4 -0
- package/package.json +1 -1
- package/src/_template/PROMPT/trae/momo-datamodel.ejs +2 -1
- package/src/commander/commit.json +12 -0
- package/src/commander/pull.json +6 -0
- package/src/commander/push.json +6 -0
- package/src/executor/executeCommit.js +202 -0
- package/src/executor/executeInit.js +7 -12
- package/src/executor/executePull.js +127 -0
- package/src/executor/executePush.js +180 -0
- package/src/executor/executeTasks.js +5 -3
- package/src/executor/index.js +7 -1
package/README.md
CHANGED
|
@@ -71,6 +71,10 @@ momo init # 初始化当前项目
|
|
|
71
71
|
momo repo -a https://xxx/repo.git # 克隆远程代码库 -> source/repo/develop-01(名称靠解析) -> git submodule
|
|
72
72
|
momo repo -a xxx -i 10 # 克隆远程代码库(10个副本)
|
|
73
73
|
|
|
74
|
+
momo pull # 从远程拉取最新代码 source/develop-xx
|
|
75
|
+
momo commit -m "提交信息" # 提交本地变更形成新的 commits
|
|
76
|
+
momo push # 推送本地 commits 到远程代码库
|
|
77
|
+
|
|
74
78
|
momo open # 交互式使用 TRAE / Lingma / Cursor / Kiro 打开当前项目
|
|
75
79
|
|
|
76
80
|
momo project -s "项目路径" # 将路径中的显示拷贝到当前项目的 reference 目录下,若不提供 -s 则直接列举所有支持的项目类型
|
package/package.json
CHANGED
|
@@ -4,5 +4,6 @@
|
|
|
4
4
|
分析 reference/ 下的项目,查找对应的数据模型,根据查找的数据模型更新 specification/project-model.md 文档作为当前项目所需的领域模型核心文档
|
|
5
5
|
|
|
6
6
|
1. 主要分析实体模型、关系模型、常量和枚举等。
|
|
7
|
-
2.
|
|
7
|
+
2. 基本需求文档参考 `specification/project.md`。
|
|
8
|
+
3. 若有推荐遗漏的模型在输出的 `specification/project-model.md` 中补充说明。
|
|
8
9
|
<!-- END -->
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
|
+
const util = require('util');
|
|
5
|
+
const Ec = require('../epic');
|
|
6
|
+
|
|
7
|
+
// 将 exec 转换为 Promise 版本
|
|
8
|
+
const execAsync = util.promisify(exec);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 检查目录是否为 Git 仓库
|
|
12
|
+
* @param {string} dirPath 目录路径
|
|
13
|
+
* @returns {Promise<boolean>} 是否为 Git 仓库
|
|
14
|
+
*/
|
|
15
|
+
const _isGitRepo = async (dirPath) => {
|
|
16
|
+
try {
|
|
17
|
+
await execAsync('git rev-parse --git-dir', { cwd: dirPath });
|
|
18
|
+
return true;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 检查是否有更改需要提交
|
|
26
|
+
* @param {string} dirPath 目录路径
|
|
27
|
+
* @returns {Promise<boolean>} 是否有更改
|
|
28
|
+
*/
|
|
29
|
+
const _hasChanges = async (dirPath) => {
|
|
30
|
+
try {
|
|
31
|
+
const { stdout } = await execAsync('git status --porcelain', { cwd: dirPath });
|
|
32
|
+
return stdout.trim() !== '';
|
|
33
|
+
} catch (error) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 添加所有更改
|
|
40
|
+
* @param {string} dirPath 目录路径
|
|
41
|
+
*/
|
|
42
|
+
const _addAllChanges = async (dirPath) => {
|
|
43
|
+
try {
|
|
44
|
+
Ec.waiting(`正在添加更改: ${dirPath}`);
|
|
45
|
+
const { stdout, stderr } = await execAsync('git add .', { cwd: dirPath });
|
|
46
|
+
|
|
47
|
+
if (stdout) {
|
|
48
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
49
|
+
}
|
|
50
|
+
if (stderr) {
|
|
51
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Ec.waiting(`✅ 成功添加更改: ${dirPath}`);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
Ec.error(`❌ 添加更改失败 ${dirPath}: ${error.message}`);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 提交更改
|
|
63
|
+
* @param {string} dirPath 目录路径
|
|
64
|
+
* @param {string} message 提交信息
|
|
65
|
+
*/
|
|
66
|
+
const _commitChanges = async (dirPath, message) => {
|
|
67
|
+
try {
|
|
68
|
+
Ec.waiting(`正在提交更改: ${dirPath}`);
|
|
69
|
+
const command = `git commit -m "${message}"`;
|
|
70
|
+
const { stdout, stderr } = await execAsync(command, { cwd: dirPath });
|
|
71
|
+
|
|
72
|
+
if (stdout) {
|
|
73
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
74
|
+
}
|
|
75
|
+
if (stderr) {
|
|
76
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
Ec.waiting(`✅ 成功提交更改: ${dirPath}`);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
// 检查是否是因为没有更改导致的错误
|
|
82
|
+
if (error.message.includes('nothing to commit')) {
|
|
83
|
+
Ec.waiting(`⚠️ ${dirPath} 没有需要提交的更改`);
|
|
84
|
+
} else {
|
|
85
|
+
Ec.error(`❌ 提交更改失败 ${dirPath}: ${error.message}`);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 提交 submodule 更改
|
|
93
|
+
* @param {string} dirPath 目录路径
|
|
94
|
+
* @param {string} message 提交信息
|
|
95
|
+
*/
|
|
96
|
+
const _commitSubmodules = async (dirPath, message) => {
|
|
97
|
+
try {
|
|
98
|
+
Ec.waiting(`正在提交 Submodule 更改: ${dirPath}`);
|
|
99
|
+
// 添加 submodule 更改
|
|
100
|
+
await execAsync('git add .', { cwd: dirPath });
|
|
101
|
+
// 提交更改
|
|
102
|
+
const command = `git commit -m "${message}"`;
|
|
103
|
+
const { stdout, stderr } = await execAsync(command, { cwd: dirPath });
|
|
104
|
+
|
|
105
|
+
if (stdout) {
|
|
106
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
107
|
+
}
|
|
108
|
+
if (stderr) {
|
|
109
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
Ec.waiting(`✅ 成功提交 Submodule 更改: ${dirPath}`);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
// 检查是否是因为没有更改导致的错误
|
|
115
|
+
if (error.message.includes('nothing to commit')) {
|
|
116
|
+
Ec.waiting(`⚠️ ${dirPath} Submodule 没有需要提交的更改`);
|
|
117
|
+
} else {
|
|
118
|
+
Ec.error(`❌ 提交 Submodule 更改失败 ${dirPath}: ${error.message}`);
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
module.exports = async (options) => {
|
|
125
|
+
// 参数提取
|
|
126
|
+
const parsed = Ec.parseArgument(options);
|
|
127
|
+
const message = parsed.message || parsed.m;
|
|
128
|
+
|
|
129
|
+
// 验证参数
|
|
130
|
+
if (!message) {
|
|
131
|
+
Ec.error("❌ 请提供提交信息 (-m, --message)");
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
// 获取 source 目录路径
|
|
137
|
+
const sourceDir = path.resolve(process.cwd(), 'source');
|
|
138
|
+
|
|
139
|
+
// 检查 source 目录是否存在
|
|
140
|
+
if (!fs.existsSync(sourceDir)) {
|
|
141
|
+
Ec.error("❌ 未找到 source 目录");
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 获取所有 develop-xx 目录
|
|
146
|
+
const files = fs.readdirSync(sourceDir);
|
|
147
|
+
const developDirs = files.filter(file =>
|
|
148
|
+
fs.statSync(path.join(sourceDir, file)).isDirectory() &&
|
|
149
|
+
file.match(/^develop-\d+$/)
|
|
150
|
+
).sort();
|
|
151
|
+
|
|
152
|
+
if (developDirs.length === 0) {
|
|
153
|
+
Ec.waiting("🔍 未找到任何 develop 副本目录");
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
Ec.waiting(`共找到 ${developDirs.length} 个 develop 副本目录`);
|
|
158
|
+
|
|
159
|
+
// 遍历所有 develop 目录并提交更改
|
|
160
|
+
for (const dir of developDirs) {
|
|
161
|
+
const fullPath = path.join(sourceDir, dir);
|
|
162
|
+
|
|
163
|
+
// 添加分割线
|
|
164
|
+
Ec.waiting("--------------------------------------------------");
|
|
165
|
+
|
|
166
|
+
// 检查是否为 Git 仓库
|
|
167
|
+
const isGitRepo = await _isGitRepo(fullPath);
|
|
168
|
+
if (!isGitRepo) {
|
|
169
|
+
Ec.waiting(`⚠️ ${fullPath} 不是 Git 仓库,跳过`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 检查是否有更改
|
|
174
|
+
const hasChange = await _hasChanges(fullPath);
|
|
175
|
+
if (!hasChange) {
|
|
176
|
+
Ec.waiting(`⚠️ ${fullPath} 没有需要提交的更改`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 添加并提交更改
|
|
181
|
+
await _addAllChanges(fullPath);
|
|
182
|
+
await _commitChanges(fullPath, message);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 添加分割线
|
|
186
|
+
Ec.waiting("--------------------------------------------------");
|
|
187
|
+
|
|
188
|
+
// 提交主仓库的 submodule 更新
|
|
189
|
+
const hasSubmoduleChanges = await _hasChanges(process.cwd());
|
|
190
|
+
if (hasSubmoduleChanges) {
|
|
191
|
+
await _commitSubmodules(process.cwd(), `Update submodules: ${message}`);
|
|
192
|
+
} else {
|
|
193
|
+
Ec.waiting("⚠️ 主仓库没有 submodule 更改需要提交");
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
Ec.info('✅ 所有副本更改提交完成!');
|
|
197
|
+
process.exit(0);
|
|
198
|
+
} catch (error) {
|
|
199
|
+
Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
@@ -79,8 +79,7 @@ const _ioFile = async (baseDir) => {
|
|
|
79
79
|
const templateFiles = [
|
|
80
80
|
{
|
|
81
81
|
source: "specification/project.md",
|
|
82
|
-
target: "specification/project.md"
|
|
83
|
-
protect: true // 标记为受保护文件
|
|
82
|
+
target: "specification/project.md"
|
|
84
83
|
},
|
|
85
84
|
{
|
|
86
85
|
source: "specification/project-model.md",
|
|
@@ -106,11 +105,8 @@ const _ioFile = async (baseDir) => {
|
|
|
106
105
|
|
|
107
106
|
// 检查源文件是否存在且目标文件已存在
|
|
108
107
|
if (fs.existsSync(sourcePath) && fs.existsSync(targetPath)) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
hasExistingFiles = true;
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
108
|
+
hasExistingFiles = true;
|
|
109
|
+
break;
|
|
114
110
|
}
|
|
115
111
|
}
|
|
116
112
|
|
|
@@ -265,11 +261,11 @@ const _ioFile = async (baseDir) => {
|
|
|
265
261
|
|
|
266
262
|
// 检查目标文件是否已存在
|
|
267
263
|
if (fs.existsSync(targetPath)) {
|
|
268
|
-
//
|
|
269
|
-
if (file.
|
|
270
|
-
Ec.waiting("
|
|
264
|
+
// 跳过 specification/ 目录下的所有文件
|
|
265
|
+
if (file.target.startsWith("specification/")) {
|
|
266
|
+
Ec.waiting("跳过文件:" + file.target + " ".yellow + "(specification目录下的文件可能已被修改)".yellow);
|
|
271
267
|
} else if (shouldOverwrite) {
|
|
272
|
-
//
|
|
268
|
+
// 目标文件已存在,根据用户选择决定是否覆盖(非specification目录下的文件)
|
|
273
269
|
Ec.waiting("覆盖模板文件:" + file.target);
|
|
274
270
|
await fsAsync.copyFile(sourcePath, targetPath);
|
|
275
271
|
} else {
|
|
@@ -416,7 +412,6 @@ module.exports = (options) => {
|
|
|
416
412
|
.then(() => _ioFile(basePath))
|
|
417
413
|
.then(() => {
|
|
418
414
|
Ec.info('✅ SPEC / 项目初始化完成!');
|
|
419
|
-
Ec.waiting('💡 注意:specification/project.md 文件需要人工填写项目基本信息和需求信息');
|
|
420
415
|
// 关闭 readline 接口
|
|
421
416
|
Ec.askClose();
|
|
422
417
|
// 退出程序
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
|
+
const util = require('util');
|
|
5
|
+
const Ec = require('../epic');
|
|
6
|
+
|
|
7
|
+
// 将 exec 转换为 Promise 版本
|
|
8
|
+
const execAsync = util.promisify(exec);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 检查目录是否为 Git 仓库
|
|
12
|
+
* @param {string} dirPath 目录路径
|
|
13
|
+
* @returns {Promise<boolean>} 是否为 Git 仓库
|
|
14
|
+
*/
|
|
15
|
+
const _isGitRepo = async (dirPath) => {
|
|
16
|
+
try {
|
|
17
|
+
await execAsync('git rev-parse --git-dir', { cwd: dirPath });
|
|
18
|
+
return true;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 从远程拉取最新代码
|
|
26
|
+
* @param {string} dirPath 目录路径
|
|
27
|
+
*/
|
|
28
|
+
const _pullRepo = async (dirPath) => {
|
|
29
|
+
try {
|
|
30
|
+
Ec.waiting(`正在从远程拉取代码: ${dirPath}`);
|
|
31
|
+
const { stdout, stderr } = await execAsync('git pull', { cwd: dirPath });
|
|
32
|
+
|
|
33
|
+
if (stdout) {
|
|
34
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
35
|
+
}
|
|
36
|
+
if (stderr) {
|
|
37
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Ec.waiting(`✅ 成功拉取代码: ${dirPath}`);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
Ec.error(`❌ 拉取代码失败 ${dirPath}: ${error.message}`);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 更新 submodule
|
|
49
|
+
* @param {string} dirPath 目录路径
|
|
50
|
+
*/
|
|
51
|
+
const _updateSubmodules = async (dirPath) => {
|
|
52
|
+
try {
|
|
53
|
+
Ec.waiting(`正在更新 Submodule: ${dirPath}`);
|
|
54
|
+
const { stdout, stderr } = await execAsync('git submodule update --remote --merge', { cwd: dirPath });
|
|
55
|
+
|
|
56
|
+
if (stdout) {
|
|
57
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
58
|
+
}
|
|
59
|
+
if (stderr) {
|
|
60
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Ec.waiting(`✅ 成功更新 Submodule: ${dirPath}`);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
Ec.error(`❌ 更新 Submodule 失败 ${dirPath}: ${error.message}`);
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
module.exports = async (options) => {
|
|
71
|
+
// 参数提取
|
|
72
|
+
const parsed = Ec.parseArgument(options);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// 获取 source 目录路径
|
|
76
|
+
const sourceDir = path.resolve(process.cwd(), 'source');
|
|
77
|
+
|
|
78
|
+
// 检查 source 目录是否存在
|
|
79
|
+
if (!fs.existsSync(sourceDir)) {
|
|
80
|
+
Ec.error("❌ 未找到 source 目录");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 获取所有 develop-xx 目录
|
|
85
|
+
const files = fs.readdirSync(sourceDir);
|
|
86
|
+
const developDirs = files.filter(file =>
|
|
87
|
+
fs.statSync(path.join(sourceDir, file)).isDirectory() &&
|
|
88
|
+
file.match(/^develop-\d+$/)
|
|
89
|
+
).sort();
|
|
90
|
+
|
|
91
|
+
if (developDirs.length === 0) {
|
|
92
|
+
Ec.waiting("🔍 未找到任何 develop 副本目录");
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Ec.waiting(`共找到 ${developDirs.length} 个 develop 副本目录`);
|
|
97
|
+
|
|
98
|
+
// 遍历所有 develop 目录并拉取代码
|
|
99
|
+
for (const dir of developDirs) {
|
|
100
|
+
const fullPath = path.join(sourceDir, dir);
|
|
101
|
+
|
|
102
|
+
// 添加分割线
|
|
103
|
+
Ec.waiting("--------------------------------------------------");
|
|
104
|
+
|
|
105
|
+
// 检查是否为 Git 仓库
|
|
106
|
+
const isGitRepo = await _isGitRepo(fullPath);
|
|
107
|
+
if (!isGitRepo) {
|
|
108
|
+
Ec.waiting(`⚠️ ${fullPath} 不是 Git 仓库,跳过`);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 拉取最新代码
|
|
113
|
+
await _pullRepo(fullPath);
|
|
114
|
+
|
|
115
|
+
// 更新 submodule
|
|
116
|
+
await _updateSubmodules(fullPath);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 添加结束分割线
|
|
120
|
+
Ec.waiting("--------------------------------------------------");
|
|
121
|
+
Ec.info('✅ 所有副本代码拉取完成!');
|
|
122
|
+
process.exit(0);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
|
+
const util = require('util');
|
|
5
|
+
const Ec = require('../epic');
|
|
6
|
+
|
|
7
|
+
// 将 exec 转换为 Promise 版本
|
|
8
|
+
const execAsync = util.promisify(exec);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 检查目录是否为 Git 仓库
|
|
12
|
+
* @param {string} dirPath 目录路径
|
|
13
|
+
* @returns {Promise<boolean>} 是否为 Git 仓库
|
|
14
|
+
*/
|
|
15
|
+
const _isGitRepo = async (dirPath) => {
|
|
16
|
+
try {
|
|
17
|
+
await execAsync('git rev-parse --git-dir', { cwd: dirPath });
|
|
18
|
+
return true;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 从远程拉取最新代码
|
|
26
|
+
* @param {string} dirPath 目录路径
|
|
27
|
+
*/
|
|
28
|
+
const _pullRepo = async (dirPath) => {
|
|
29
|
+
try {
|
|
30
|
+
Ec.waiting(`正在从远程拉取代码: ${dirPath}`);
|
|
31
|
+
const { stdout, stderr } = await execAsync('git pull', { cwd: dirPath });
|
|
32
|
+
|
|
33
|
+
if (stdout) {
|
|
34
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
35
|
+
}
|
|
36
|
+
if (stderr) {
|
|
37
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Ec.waiting(`✅ 成功拉取代码: ${dirPath}`);
|
|
41
|
+
return true;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
Ec.error(`❌ 拉取代码失败 ${dirPath}: ${error.message}`);
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 推送更改到远程仓库
|
|
50
|
+
* @param {string} dirPath 目录路径
|
|
51
|
+
*/
|
|
52
|
+
const _pushRepo = async (dirPath) => {
|
|
53
|
+
try {
|
|
54
|
+
Ec.waiting(`正在推送更改到远程: ${dirPath}`);
|
|
55
|
+
const { stdout, stderr } = await execAsync('git push', { cwd: dirPath });
|
|
56
|
+
|
|
57
|
+
if (stdout) {
|
|
58
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
59
|
+
}
|
|
60
|
+
if (stderr) {
|
|
61
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Ec.waiting(`✅ 成功推送更改: ${dirPath}`);
|
|
65
|
+
return true;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
Ec.error(`❌ 推送更改失败 ${dirPath}: ${error.message}`);
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 推送 submodule 更改
|
|
74
|
+
* @param {string} dirPath 目录路径
|
|
75
|
+
*/
|
|
76
|
+
const _pushSubmodules = async (dirPath) => {
|
|
77
|
+
try {
|
|
78
|
+
Ec.waiting(`正在推送 Submodule 更改: ${dirPath}`);
|
|
79
|
+
const { stdout, stderr } = await execAsync('git push', { cwd: dirPath });
|
|
80
|
+
|
|
81
|
+
if (stdout) {
|
|
82
|
+
Ec.waiting(`输出: ${stdout.trim()}`);
|
|
83
|
+
}
|
|
84
|
+
if (stderr) {
|
|
85
|
+
Ec.waiting(`进度: ${stderr.trim()}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Ec.waiting(`✅ 成功推送 Submodule 更改: ${dirPath}`);
|
|
89
|
+
return true;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
Ec.error(`❌ 推送 Submodule 更改失败 ${dirPath}: ${error.message}`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
module.exports = async (options) => {
|
|
97
|
+
// 参数提取
|
|
98
|
+
const parsed = Ec.parseArgument(options);
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
// 获取 source 目录路径
|
|
102
|
+
const sourceDir = path.resolve(process.cwd(), 'source');
|
|
103
|
+
|
|
104
|
+
// 检查 source 目录是否存在
|
|
105
|
+
if (!fs.existsSync(sourceDir)) {
|
|
106
|
+
Ec.error("❌ 未找到 source 目录");
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 获取所有 develop-xx 目录
|
|
111
|
+
const files = fs.readdirSync(sourceDir);
|
|
112
|
+
const developDirs = files.filter(file =>
|
|
113
|
+
fs.statSync(path.join(sourceDir, file)).isDirectory() &&
|
|
114
|
+
file.match(/^develop-\d+$/)
|
|
115
|
+
).sort();
|
|
116
|
+
|
|
117
|
+
if (developDirs.length === 0) {
|
|
118
|
+
Ec.waiting("🔍 未找到任何 develop 副本目录");
|
|
119
|
+
process.exit(0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Ec.waiting(`共找到 ${developDirs.length} 个 develop 副本目录`);
|
|
123
|
+
|
|
124
|
+
let successCount = 0;
|
|
125
|
+
let failCount = 0;
|
|
126
|
+
|
|
127
|
+
// 遍历所有 develop 目录并推送更改
|
|
128
|
+
for (const dir of developDirs) {
|
|
129
|
+
const fullPath = path.join(sourceDir, dir);
|
|
130
|
+
|
|
131
|
+
// 添加分割线
|
|
132
|
+
Ec.waiting("--------------------------------------------------");
|
|
133
|
+
|
|
134
|
+
// 检查是否为 Git 仓库
|
|
135
|
+
const isGitRepo = await _isGitRepo(fullPath);
|
|
136
|
+
if (!isGitRepo) {
|
|
137
|
+
Ec.waiting(`⚠️ ${fullPath} 不是 Git 仓库,跳过`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 先拉取最新代码
|
|
142
|
+
const pullSuccess = await _pullRepo(fullPath);
|
|
143
|
+
if (!pullSuccess) {
|
|
144
|
+
Ec.error(`❌ 拉取代码失败,跳过推送: ${fullPath}`);
|
|
145
|
+
failCount++;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 推送更改
|
|
150
|
+
const pushSuccess = await _pushRepo(fullPath);
|
|
151
|
+
if (pushSuccess) {
|
|
152
|
+
successCount++;
|
|
153
|
+
} else {
|
|
154
|
+
failCount++;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 添加分割线
|
|
159
|
+
Ec.waiting("--------------------------------------------------");
|
|
160
|
+
|
|
161
|
+
// 推送主仓库的 submodule 更新
|
|
162
|
+
const pushSubSuccess = await _pushSubmodules(process.cwd());
|
|
163
|
+
if (pushSubSuccess) {
|
|
164
|
+
successCount++;
|
|
165
|
+
} else {
|
|
166
|
+
failCount++;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (failCount === 0) {
|
|
170
|
+
Ec.info(`✅ 所有副本推送完成!成功: ${successCount}, 失败: ${failCount}`);
|
|
171
|
+
process.exit(0);
|
|
172
|
+
} else {
|
|
173
|
+
Ec.error(`❌ 推送完成,但有 ${failCount} 个副本失败!成功: ${successCount}, 失败: ${failCount}`);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
@@ -197,7 +197,7 @@ module.exports = async (options) => {
|
|
|
197
197
|
} else {
|
|
198
198
|
Ec.waiting(`⚠️ 发现 ${taskInstances.length} 个重复任务 ${taskName}:`);
|
|
199
199
|
taskInstances.forEach((task, index) => {
|
|
200
|
-
Ec.waiting(` ${index + 1}. ${task.path}`);
|
|
200
|
+
Ec.waiting(` ${String(index + 1).padStart(3, '0')}. ${task.path}`);
|
|
201
201
|
});
|
|
202
202
|
|
|
203
203
|
// 执行剪切板任务
|
|
@@ -266,8 +266,10 @@ module.exports = async (options) => {
|
|
|
266
266
|
// 列出所有任务(包含路径和状态,状态在前)
|
|
267
267
|
Ec.waiting(`📊 共找到 ${tasks.length} 个任务:`);
|
|
268
268
|
tasks.forEach((task, index) => {
|
|
269
|
+
const paddedIndex = String(index + 1).padStart(3, '0');
|
|
269
270
|
const coloredName = task.name.cyan;
|
|
270
|
-
|
|
271
|
+
const coloredPath = task.path.yellow; // 使用黄色高亮路径
|
|
272
|
+
Ec.waiting(`${paddedIndex}. ${coloredName} | ${task.title} / ${coloredPath}`);
|
|
271
273
|
});
|
|
272
274
|
|
|
273
275
|
// 执行剪切板任务(使用第一个任务)
|
|
@@ -288,7 +290,7 @@ module.exports = async (options) => {
|
|
|
288
290
|
* @param {Array} taskInstances 任务实例列表
|
|
289
291
|
*/
|
|
290
292
|
const _handleClipboardTask = async (taskName, taskInstances) => {
|
|
291
|
-
//
|
|
293
|
+
// 读取模板文件并填充参数,然后拷贝到剪贴板
|
|
292
294
|
const templatePath = path.resolve(__dirname, '../_template/PROMPT/tasks.md.ejs');
|
|
293
295
|
|
|
294
296
|
if (fs.existsSync(templatePath)) {
|
package/src/executor/index.js
CHANGED
|
@@ -18,6 +18,9 @@ const executeProject = require('./executeProject');
|
|
|
18
18
|
const executeAgentCfg = require('./executeAgentCfg');
|
|
19
19
|
const executeAgent = require('./executeAgent');
|
|
20
20
|
const executeConsole = require('./executeConsole');
|
|
21
|
+
const executePull = require('./executePull');
|
|
22
|
+
const executeCommit = require('./executeCommit');
|
|
23
|
+
const executePush = require('./executePush');
|
|
21
24
|
|
|
22
25
|
const exported = {
|
|
23
26
|
executeHelp,
|
|
@@ -39,6 +42,9 @@ const exported = {
|
|
|
39
42
|
executeProject,
|
|
40
43
|
executeAgentCfg,
|
|
41
44
|
executeAgent,
|
|
42
|
-
executeConsole
|
|
45
|
+
executeConsole,
|
|
46
|
+
executePull,
|
|
47
|
+
executeCommit,
|
|
48
|
+
executePush
|
|
43
49
|
};
|
|
44
50
|
module.exports = exported;
|