momo-ai 1.0.5 → 1.0.7
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/.momo/advanced/refer.json +50 -0
- package/README.md +83 -35
- package/package.json +3 -2
- package/src/_agent/trae/momo-datamodel.json +5 -0
- package/src/_agent/trae/momo-module-req.json +5 -0
- package/src/_agent/trae/momo-system-req.json +5 -0
- package/src/_agent/trae/momo-task.json +5 -0
- package/src/_template/LAIN/AGENTS.md +93 -86
- package/src/_template/MCP/.gitkeep +0 -0
- package/src/_template/PROMPT/plan.md.ejs +1 -1
- package/src/_template/PROMPT/trae/momo-datamodel.ejs +8 -0
- package/src/_template/PROMPT/trae/momo-module-req.ejs +11 -0
- package/src/_template/PROMPT/trae/momo-system-req.ejs +9 -0
- package/src/_template/PROMPT/trae/momo-task.ejs +11 -0
- package/src/commander/agent.json +12 -0
- package/src/commander/agentcfg.json +5 -0
- package/src/commander/console.json +7 -0
- package/src/commander/lain.json +7 -0
- package/src/commander/project.json +12 -0
- package/src/executor/executeAgent.js +214 -0
- package/src/executor/executeAgentCfg.js +195 -0
- package/src/executor/executeConsole.js +115 -0
- package/src/executor/executeInit.js +97 -2
- package/src/executor/executeOpen.js +22 -21
- package/src/executor/executeProject.js +296 -0
- package/src/executor/index.js +10 -1
- package/src/lain.js +142 -0
- package/src/terminal/commandHelp.js +16 -0
- package/src/terminal/commandLlm.js +195 -0
- package/src/terminal/commandQuit.js +12 -0
- package/src/terminal/commandTest.js +21 -0
- package/src/terminal/index.js +25 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
const Ec = require('../epic');
|
|
2
|
-
const {
|
|
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
|
-
{
|
|
12
|
-
{
|
|
13
|
-
{
|
|
14
|
-
{
|
|
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
|
|
117
|
-
|
|
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},请确保已正确安装`);
|
|
@@ -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
|
+
};
|
package/src/executor/index.js
CHANGED
|
@@ -14,6 +14,11 @@ const executeActors = require('./executeActors');
|
|
|
14
14
|
const executeRun = require('./executeRun');
|
|
15
15
|
const executeTasks = require('./executeTasks');
|
|
16
16
|
const executeUnlock = require('./executeUnlock');
|
|
17
|
+
const executeProject = require('./executeProject');
|
|
18
|
+
const executeAgentCfg = require('./executeAgentCfg');
|
|
19
|
+
const executeAgent = require('./executeAgent');
|
|
20
|
+
const executeConsole = require('./executeConsole');
|
|
21
|
+
|
|
17
22
|
const exported = {
|
|
18
23
|
executeHelp,
|
|
19
24
|
executeInit,
|
|
@@ -30,6 +35,10 @@ const exported = {
|
|
|
30
35
|
executeActors,
|
|
31
36
|
executeRun,
|
|
32
37
|
executeTasks,
|
|
33
|
-
executeUnlock
|
|
38
|
+
executeUnlock,
|
|
39
|
+
executeProject,
|
|
40
|
+
executeAgentCfg,
|
|
41
|
+
executeAgent,
|
|
42
|
+
executeConsole
|
|
34
43
|
};
|
|
35
44
|
module.exports = exported;
|
package/src/lain.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Lain Console - 独立的交互式控制台入口
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const readline = require('readline');
|
|
8
|
+
const colors = require('colors');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const terminalCommands = require('./terminal');
|
|
12
|
+
|
|
13
|
+
// 设置颜色主题
|
|
14
|
+
colors.setTheme({
|
|
15
|
+
silly: 'rainbow',
|
|
16
|
+
input: 'grey',
|
|
17
|
+
verbose: 'cyan',
|
|
18
|
+
prompt: 'red',
|
|
19
|
+
info: 'green',
|
|
20
|
+
data: 'blue',
|
|
21
|
+
help: 'cyan',
|
|
22
|
+
warn: 'yellow',
|
|
23
|
+
debug: 'magenta',
|
|
24
|
+
error: 'red'
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// 显示欢迎界面和菜单
|
|
28
|
+
const showMenu = () => {
|
|
29
|
+
// 清屏
|
|
30
|
+
process.stdout.write('\x1Bc');
|
|
31
|
+
|
|
32
|
+
// 显示标准头部信息
|
|
33
|
+
showHeader();
|
|
34
|
+
|
|
35
|
+
// 使用96个字符宽度
|
|
36
|
+
const width = 96;
|
|
37
|
+
const headerBorder = '='.repeat(width).blue;
|
|
38
|
+
const footerBorder = '-'.repeat(width).blue;
|
|
39
|
+
|
|
40
|
+
console.log('');
|
|
41
|
+
console.log(headerBorder);
|
|
42
|
+
const title = 'Momo AI / Lain Console';
|
|
43
|
+
const padding = ' '.repeat(Math.floor((width - title.length) / 2) - 1);
|
|
44
|
+
console.log(`${padding}${title}`.bold.brightCyan);
|
|
45
|
+
console.log(headerBorder);
|
|
46
|
+
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log('欢迎使用 Momo AI / Lain 控制台!'.green);
|
|
49
|
+
console.log('这是一个交互式命令行界面。'.yellow);
|
|
50
|
+
console.log('');
|
|
51
|
+
|
|
52
|
+
console.log('可用命令:'.bold);
|
|
53
|
+
console.log(' help - 显示帮助信息'.white);
|
|
54
|
+
console.log(' test - 执行测试命令'.white);
|
|
55
|
+
console.log(' llm - 查看大模型配置信息'.white);
|
|
56
|
+
console.log(' quit - 退出控制台'.white);
|
|
57
|
+
console.log('');
|
|
58
|
+
|
|
59
|
+
console.log('请在提示符后输入命令。'.gray);
|
|
60
|
+
console.log(footerBorder);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// 显示标准头部信息
|
|
64
|
+
const showHeader = () => {
|
|
65
|
+
const appInfo = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'));
|
|
66
|
+
|
|
67
|
+
console.log(`[Momo AI]`.green.bold + ` ----------------- Rachel Momo / AI工具项 ------------------`.rainbow);
|
|
68
|
+
console.log(`[Momo AI]`.green.bold + ' 应用名称: '.bold + 'Rachel Momo / SDD');
|
|
69
|
+
console.log(`[Momo AI]`.green.bold + ' 工具主页: '.bold + appInfo.homepage.blue);
|
|
70
|
+
console.log(`[Momo AI]`.green.bold + ` 工具版本: ` + `${appInfo.version}`.red + ' ' + `( Node >= 22.x )`.yellow);
|
|
71
|
+
console.log(`[Momo AI]`.green.bold);
|
|
72
|
+
console.log(`[Momo AI]`.green.bold + ` ----------------- AI 系统启动…… ----------------------------`.rainbow);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// 处理用户输入
|
|
76
|
+
const handleInput = (input, commands) => {
|
|
77
|
+
const command = input.trim().toLowerCase();
|
|
78
|
+
|
|
79
|
+
// 创建命令上下文
|
|
80
|
+
const context = {
|
|
81
|
+
commands: commands
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
switch (command) {
|
|
85
|
+
case '':
|
|
86
|
+
// 空命令,不处理
|
|
87
|
+
break;
|
|
88
|
+
case 'help':
|
|
89
|
+
commands.help(context);
|
|
90
|
+
break;
|
|
91
|
+
case 'test':
|
|
92
|
+
commands.test(context);
|
|
93
|
+
break;
|
|
94
|
+
case 'llm':
|
|
95
|
+
commands.llm(context);
|
|
96
|
+
break;
|
|
97
|
+
case 'quit':
|
|
98
|
+
commands.quit(context);
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
console.log('');
|
|
102
|
+
console.log(`未知命令: ${command}`.brightRed);
|
|
103
|
+
console.log('输入 "help" 查看可用命令。'.yellow);
|
|
104
|
+
console.log('');
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// 主函数
|
|
109
|
+
const main = async () => {
|
|
110
|
+
showMenu();
|
|
111
|
+
|
|
112
|
+
// 创建 readline 接口
|
|
113
|
+
const rl = readline.createInterface({
|
|
114
|
+
input: process.stdin,
|
|
115
|
+
output: process.stdout,
|
|
116
|
+
prompt: '[Lain AI] > '.cyan.bold
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
rl.prompt();
|
|
120
|
+
|
|
121
|
+
rl.on('line', (line) => {
|
|
122
|
+
const input = line.trim();
|
|
123
|
+
handleInput(input, terminalCommands);
|
|
124
|
+
rl.prompt();
|
|
125
|
+
}).on('close', () => {
|
|
126
|
+
console.log('\n' + '感谢使用 Momo AI / Lain 控制台,再见!'.brightGreen + '\n');
|
|
127
|
+
process.exit(0);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// 处理 Ctrl+C
|
|
131
|
+
process.on('SIGINT', () => {
|
|
132
|
+
console.log('\n\n' + '感谢使用 Momo AI / Lain 控制台,再见!'.brightGreen + '\n');
|
|
133
|
+
rl.close();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// 启动程序
|
|
139
|
+
main().catch(err => {
|
|
140
|
+
console.error('启动控制台时出错:', err);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Help command implementation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const helpCommand = (context) => {
|
|
6
|
+
console.log('');
|
|
7
|
+
console.log('帮助信息:'.bold.brightYellow);
|
|
8
|
+
|
|
9
|
+
console.log(' help - 显示此帮助信息'.white);
|
|
10
|
+
console.log(' test - 执行测试命令'.white);
|
|
11
|
+
console.log(' llm - 查看大模型配置信息'.white);
|
|
12
|
+
console.log(' quit - 退出控制台'.white);
|
|
13
|
+
console.log('');
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = helpCommand;
|