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
|
@@ -0,0 +1,214 @@
|
|
|
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
|
+
readFile: util.promisify(fs.readFile),
|
|
9
|
+
readdir: util.promisify(fs.readdir),
|
|
10
|
+
stat: util.promisify(fs.stat)
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 获取所有 agents 信息
|
|
15
|
+
* @returns {Array} agents 信息数组
|
|
16
|
+
*/
|
|
17
|
+
const _getAgents = () => {
|
|
18
|
+
const agentsDir = path.resolve(__dirname, '../_agent');
|
|
19
|
+
const agents = [];
|
|
20
|
+
|
|
21
|
+
if (!fs.existsSync(agentsDir)) {
|
|
22
|
+
return agents;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 遍历 _agent 目录下的所有子目录
|
|
26
|
+
const types = fs.readdirSync(agentsDir).filter(file =>
|
|
27
|
+
fs.statSync(path.join(agentsDir, file)).isDirectory()
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
// 遍历每个类型目录
|
|
31
|
+
types.forEach(type => {
|
|
32
|
+
const typeDir = path.join(agentsDir, type);
|
|
33
|
+
const files = fs.readdirSync(typeDir).filter(file => file.endsWith('.json'));
|
|
34
|
+
|
|
35
|
+
// 遍历每个 json 文件
|
|
36
|
+
files.forEach(file => {
|
|
37
|
+
try {
|
|
38
|
+
const filePath = path.join(typeDir, file);
|
|
39
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
40
|
+
const agentInfo = JSON.parse(content);
|
|
41
|
+
|
|
42
|
+
agents.push({
|
|
43
|
+
argName: file.replace('momo-', '').replace('.json', ''),
|
|
44
|
+
type: type,
|
|
45
|
+
id: agentInfo.id,
|
|
46
|
+
name: agentInfo.name,
|
|
47
|
+
uri: agentInfo.uri,
|
|
48
|
+
filePath: filePath
|
|
49
|
+
});
|
|
50
|
+
} catch (error) {
|
|
51
|
+
Ec.waiting(`⚠️ 无法解析文件: ${file} - ${error.message}`);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return agents;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 从 EJS 模板中提取内容
|
|
61
|
+
* @param {string} templatePath 模板路径
|
|
62
|
+
* @returns {Promise<string>} 提取的模板内容
|
|
63
|
+
*/
|
|
64
|
+
const _extractTemplateContent = async (templatePath) => {
|
|
65
|
+
try {
|
|
66
|
+
const content = await fsAsync.readFile(templatePath, 'utf8');
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
let beginIndex = -1;
|
|
69
|
+
let endIndex = -1;
|
|
70
|
+
|
|
71
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72
|
+
if (lines[i].includes('<!-- BEGIN -->')) {
|
|
73
|
+
beginIndex = i;
|
|
74
|
+
} else if (lines[i].includes('<!-- END -->')) {
|
|
75
|
+
endIndex = i;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (beginIndex !== -1 && endIndex !== -1) {
|
|
81
|
+
// 提取 BEGIN 和 END 之间的内容(不包括 BEGIN 和 END 行)
|
|
82
|
+
return lines.slice(beginIndex + 1, endIndex).join('\n');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return content;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
throw new Error(`无法读取模板文件: ${error.message}`);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 将内容复制到剪贴板
|
|
93
|
+
* @param {string} content 要复制的内容
|
|
94
|
+
*/
|
|
95
|
+
const _copyToClipboard = async (content) => {
|
|
96
|
+
const { outCopy } = require('../epic/momo.fn.out');
|
|
97
|
+
try {
|
|
98
|
+
// 先打印内容,按行打印并保留前缀
|
|
99
|
+
Ec.waiting('📄 提示词内容:');
|
|
100
|
+
Ec.waiting('----------------------------------------');
|
|
101
|
+
const lines = content.split('\n');
|
|
102
|
+
lines.forEach(line => {
|
|
103
|
+
Ec.waiting(line);
|
|
104
|
+
});
|
|
105
|
+
Ec.waiting('----------------------------------------');
|
|
106
|
+
|
|
107
|
+
// 再复制到剪贴板
|
|
108
|
+
await outCopy(content);
|
|
109
|
+
Ec.waiting('✅ 提示词已复制到剪贴板');
|
|
110
|
+
} catch (error) {
|
|
111
|
+
Ec.waiting(`复制到剪贴板失败: ${error.message}`);
|
|
112
|
+
// 提供备选方案
|
|
113
|
+
Ec.waiting('提示词内容:');
|
|
114
|
+
const lines = content.split('\n');
|
|
115
|
+
lines.forEach(line => {
|
|
116
|
+
Ec.waiting(line);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
module.exports = async (options) => {
|
|
122
|
+
// 参数提取
|
|
123
|
+
const parsed = Ec.parseArgument(options);
|
|
124
|
+
const agentName = parsed.agent || parsed.a;
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
// 获取所有 agents
|
|
128
|
+
const agents = _getAgents();
|
|
129
|
+
|
|
130
|
+
if (agents.length === 0) {
|
|
131
|
+
Ec.error("❌ 未找到任何 agents");
|
|
132
|
+
Ec.askClose();
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 如果没有提供 agent 参数,显示可用的 agents 并让用户选择
|
|
137
|
+
if (!agentName) {
|
|
138
|
+
Ec.waiting('可用的 Agents:');
|
|
139
|
+
agents.forEach((agent, index) => {
|
|
140
|
+
Ec.waiting(`${index + 1}. ${agent.argName.red.bold} (${agent.name}), id = ${agent.id}, uri = ${agent.uri}`);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// 获取用户选择
|
|
144
|
+
const answer = await Ec.ask('请选择要使用的 Agent (输入编号): ');
|
|
145
|
+
const selectedIndex = parseInt(answer) - 1;
|
|
146
|
+
|
|
147
|
+
// 验证选择
|
|
148
|
+
if (isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= agents.length) {
|
|
149
|
+
Ec.error("❌ 无效的选择");
|
|
150
|
+
Ec.askClose();
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 使用选择的 agent
|
|
155
|
+
const selectedAgent = agents[selectedIndex];
|
|
156
|
+
return await _processAgent(selectedAgent);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 查找指定的 agent
|
|
160
|
+
const agent = agents.find(a => a.argName === agentName);
|
|
161
|
+
if (!agent) {
|
|
162
|
+
Ec.error(`❌ 未找到名为 "${agentName}" 的 Agent`);
|
|
163
|
+
Ec.waiting('可用的 Agents:');
|
|
164
|
+
agents.forEach((a, index) => {
|
|
165
|
+
Ec.waiting(`${index + 1}. ${a.argName.red.bold} (${a.name}), id = ${a.id}, uri = ${a.uri}`);
|
|
166
|
+
});
|
|
167
|
+
Ec.askClose();
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 处理选中的 agent
|
|
172
|
+
await _processAgent(agent);
|
|
173
|
+
|
|
174
|
+
} catch (error) {
|
|
175
|
+
Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
|
|
176
|
+
Ec.askClose();
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 处理选中的 agent
|
|
183
|
+
* @param {Object} agent 选中的 agent 对象
|
|
184
|
+
*/
|
|
185
|
+
const _processAgent = async (agent) => {
|
|
186
|
+
try {
|
|
187
|
+
// 构建模板路径
|
|
188
|
+
const templatePath = path.resolve(__dirname, `../_template/PROMPT/${agent.type}/${agent.id}.ejs`);
|
|
189
|
+
|
|
190
|
+
// 检查模板文件是否存在
|
|
191
|
+
if (!fs.existsSync(templatePath)) {
|
|
192
|
+
Ec.error(`❌ 未找到模板文件: ${templatePath}`);
|
|
193
|
+
Ec.askClose();
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 提取模板内容
|
|
198
|
+
const content = await _extractTemplateContent(templatePath);
|
|
199
|
+
|
|
200
|
+
// 复制到剪贴板
|
|
201
|
+
await _copyToClipboard(content);
|
|
202
|
+
|
|
203
|
+
// 显示警告提示
|
|
204
|
+
Ec.waiting('');
|
|
205
|
+
Ec.warn('⚠️ 为了获得最佳效果,请在您的 IDE 工具窗口中选择对应的 Agent 来配合使用此提示词');
|
|
206
|
+
|
|
207
|
+
Ec.askClose();
|
|
208
|
+
process.exit(0);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
Ec.error(`❌ 处理 Agent 时发生错误: ${error.message}`);
|
|
211
|
+
Ec.askClose();
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 执行 console 命令 - 启动交互式控制台
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const readline = require('readline');
|
|
6
|
+
const colors = require('colors');
|
|
7
|
+
const Ec = require('../epic');
|
|
8
|
+
|
|
9
|
+
// 显示欢迎界面和菜单
|
|
10
|
+
const showMenu = () => {
|
|
11
|
+
// 清屏
|
|
12
|
+
process.stdout.write('\x1Bc');
|
|
13
|
+
|
|
14
|
+
// 显示标准头部信息
|
|
15
|
+
Ec.executeHeader("Rachel Momo / SDD");
|
|
16
|
+
|
|
17
|
+
// 使用96个字符宽度
|
|
18
|
+
const width = 96;
|
|
19
|
+
const headerBorder = '='.repeat(width).blue;
|
|
20
|
+
const footerBorder = '-'.repeat(width).blue;
|
|
21
|
+
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log(headerBorder);
|
|
24
|
+
const title = 'Momo AI / Lain Console';
|
|
25
|
+
const padding = ' '.repeat(Math.floor((width - title.length) / 2) - 1);
|
|
26
|
+
console.log(`${padding}${title}`.bold.brightCyan);
|
|
27
|
+
console.log(headerBorder);
|
|
28
|
+
|
|
29
|
+
console.log('');
|
|
30
|
+
console.log('欢迎使用 Momo AI / Lain 控制台!'.green);
|
|
31
|
+
console.log('这是一个交互式命令行界面。'.yellow);
|
|
32
|
+
console.log('');
|
|
33
|
+
|
|
34
|
+
console.log('可用命令:'.bold);
|
|
35
|
+
console.log(' help - 显示帮助信息'.white);
|
|
36
|
+
console.log(' exit - 退出控制台'.white);
|
|
37
|
+
console.log(' quit - 退出控制台'.white);
|
|
38
|
+
console.log('');
|
|
39
|
+
|
|
40
|
+
console.log('请在提示符后输入命令。'.gray);
|
|
41
|
+
console.log(footerBorder);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// 处理用户输入
|
|
45
|
+
const handleInput = (input) => {
|
|
46
|
+
const command = input.trim().toLowerCase();
|
|
47
|
+
|
|
48
|
+
switch (command) {
|
|
49
|
+
case '':
|
|
50
|
+
// 空命令,不处理
|
|
51
|
+
break;
|
|
52
|
+
case 'help':
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log('帮助信息:'.bold.brightYellow);
|
|
55
|
+
console.log(' help - 显示此帮助信息'.white);
|
|
56
|
+
console.log(' exit - 退出控制台'.white);
|
|
57
|
+
console.log(' quit - 退出控制台'.white);
|
|
58
|
+
console.log('');
|
|
59
|
+
break;
|
|
60
|
+
case 'exit':
|
|
61
|
+
case 'quit':
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log('感谢使用 Momo AI / Lain 控制台,再见!'.brightGreen);
|
|
64
|
+
console.log('');
|
|
65
|
+
process.exit(0);
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log(`未知命令: ${command}`.brightRed);
|
|
70
|
+
console.log('输入 "help" 查看可用命令。'.yellow);
|
|
71
|
+
console.log('');
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// 主函数
|
|
76
|
+
const executeConsole = async () => {
|
|
77
|
+
showMenu();
|
|
78
|
+
|
|
79
|
+
// 先关闭全局的 readline 接口,避免冲突
|
|
80
|
+
try {
|
|
81
|
+
const globalRl = require('../epic/momo.fn.log');
|
|
82
|
+
if (globalRl.askClose) {
|
|
83
|
+
globalRl.askClose();
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {
|
|
86
|
+
// 忽略错误
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 创建 readline 接口
|
|
90
|
+
const rl = readline.createInterface({
|
|
91
|
+
input: process.stdin,
|
|
92
|
+
output: process.stdout,
|
|
93
|
+
prompt: '[Lain AI] > '.cyan.bold
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
rl.prompt();
|
|
97
|
+
|
|
98
|
+
rl.on('line', (line) => {
|
|
99
|
+
const input = line.trim();
|
|
100
|
+
handleInput(input);
|
|
101
|
+
rl.prompt();
|
|
102
|
+
}).on('close', () => {
|
|
103
|
+
console.log('\n' + '感谢使用 Momo AI / Lain 控制台,再见!'.brightGreen + '\n');
|
|
104
|
+
process.exit(0);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// 处理 Ctrl+C
|
|
108
|
+
process.on('SIGINT', () => {
|
|
109
|
+
console.log('\n\n' + '感谢使用 Momo AI / Lain 控制台,再见!'.brightGreen + '\n');
|
|
110
|
+
rl.close();
|
|
111
|
+
process.exit(0);
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
module.exports = executeConsole;
|
|
@@ -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/",
|
|
@@ -148,7 +150,21 @@ const _ioFile = async (baseDir) => {
|
|
|
148
150
|
"integration/windsurf/",
|
|
149
151
|
"integration/github/",
|
|
150
152
|
"integration/claude-code/",
|
|
151
|
-
"integration/chatgpt/"
|
|
153
|
+
"integration/chatgpt/",
|
|
154
|
+
// 新增的 integration 目录(使用小写)
|
|
155
|
+
"integration/auggie/",
|
|
156
|
+
"integration/cline/",
|
|
157
|
+
"integration/roocode/",
|
|
158
|
+
"integration/codebuddy/",
|
|
159
|
+
"integration/costrict/",
|
|
160
|
+
"integration/crush/",
|
|
161
|
+
"integration/factory/",
|
|
162
|
+
"integration/gemini/",
|
|
163
|
+
"integration/opencode/",
|
|
164
|
+
"integration/kilo/",
|
|
165
|
+
"integration/codex/",
|
|
166
|
+
"integration/amazonq/",
|
|
167
|
+
"integration/qwen/"
|
|
152
168
|
];
|
|
153
169
|
|
|
154
170
|
// 为每个目录创建一个空的 .gitkeep 文件,确保目录被git跟踪
|
|
@@ -166,6 +182,70 @@ const _ioFile = async (baseDir) => {
|
|
|
166
182
|
}
|
|
167
183
|
}
|
|
168
184
|
|
|
185
|
+
// 为每个 integration 目录创建 config.json 文件
|
|
186
|
+
const integrationDirs = [
|
|
187
|
+
"integration/openspec/",
|
|
188
|
+
"integration/spec-kit/",
|
|
189
|
+
"integration/kiro/",
|
|
190
|
+
"integration/trea/",
|
|
191
|
+
"integration/cursor/",
|
|
192
|
+
"integration/lingma/",
|
|
193
|
+
"integration/qoder/",
|
|
194
|
+
"integration/windsurf/",
|
|
195
|
+
"integration/github/",
|
|
196
|
+
"integration/claude-code/",
|
|
197
|
+
"integration/chatgpt/",
|
|
198
|
+
// 新增的 integration 目录(使用小写)
|
|
199
|
+
"integration/auggie/",
|
|
200
|
+
"integration/cline/",
|
|
201
|
+
"integration/roocode/",
|
|
202
|
+
"integration/codebuddy/",
|
|
203
|
+
"integration/costrict/",
|
|
204
|
+
"integration/crush/",
|
|
205
|
+
"integration/factory/",
|
|
206
|
+
"integration/gemini/",
|
|
207
|
+
"integration/opencode/",
|
|
208
|
+
"integration/kilo/",
|
|
209
|
+
"integration/codex/",
|
|
210
|
+
"integration/amazonq/",
|
|
211
|
+
"integration/qwen/"
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
// 通用的 LLM 配置模板
|
|
215
|
+
const configTemplate = {
|
|
216
|
+
llm: "", // LLM 类型标识符
|
|
217
|
+
token: "", // API 访问令牌
|
|
218
|
+
baseUrl: "", // API 基础 URL(可选)
|
|
219
|
+
model: "", // 模型名称(可选)
|
|
220
|
+
temperature: 0.7, // 温度参数(可选)
|
|
221
|
+
maxTokens: 2048, // 最大令牌数(可选)
|
|
222
|
+
topP: 1.0, // Top-P 参数(可选)
|
|
223
|
+
frequencyPenalty: 0, // 频率惩罚(可选)
|
|
224
|
+
presencePenalty: 0 // 存在惩罚(可选)
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// 为每个 integration 目录创建 config.json
|
|
228
|
+
for (const dir of integrationDirs) {
|
|
229
|
+
const configPath = path.resolve(baseDir, dir, "config.json");
|
|
230
|
+
// 确保目录存在
|
|
231
|
+
const dirPath = path.dirname(configPath);
|
|
232
|
+
if (!fs.existsSync(dirPath)) {
|
|
233
|
+
await fsAsync.mkdir(dirPath, {recursive: true});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 如果文件不存在或用户选择覆盖,则创建 config.json
|
|
237
|
+
if (!fs.existsSync(configPath) || shouldOverwrite) {
|
|
238
|
+
// 根据目录名设置 llm 字段
|
|
239
|
+
const dirName = path.basename(dir);
|
|
240
|
+
const config = {...configTemplate, llm: dirName};
|
|
241
|
+
|
|
242
|
+
Ec.waiting("创建配置文件:" + configPath);
|
|
243
|
+
await fsAsync.writeFile(configPath, JSON.stringify(config, null, 4));
|
|
244
|
+
} else {
|
|
245
|
+
Ec.waiting("跳过文件:" + configPath);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
169
249
|
// 拷贝模板文件
|
|
170
250
|
for (const file of templateFiles) {
|
|
171
251
|
const sourcePath = path.resolve(templateDir, file.source);
|
|
@@ -255,7 +335,9 @@ const _ioFile = async (baseDir) => {
|
|
|
255
335
|
* .momo/advanced/ 高级配置说明
|
|
256
336
|
* /actor.md - 角色定制说明
|
|
257
337
|
* .momo/scripts/ 特殊脚本目录
|
|
258
|
-
*
|
|
338
|
+
* reference/
|
|
339
|
+
* /maven/ Maven 外置项目
|
|
340
|
+
* /npm/ NPM 外置项目
|
|
259
341
|
* specification/ 工作目录
|
|
260
342
|
* /project.md - 项目基本说明文件
|
|
261
343
|
* /project-model.md - 模型说明文件(通常是建模所需的核心概念模型)
|
|
@@ -295,6 +377,19 @@ const _ioFile = async (baseDir) => {
|
|
|
295
377
|
* github/ Github Copilot 目录
|
|
296
378
|
* claude-code/ Claude Code 目录
|
|
297
379
|
* chatgpt/ ChatGPT 目录
|
|
380
|
+
* auggie/ Auggie (Augment CLI) 目录
|
|
381
|
+
* cline/ Cline 目录
|
|
382
|
+
* roocode/ RooCode 目录
|
|
383
|
+
* codebuddy/ CodeBuddy Code (CLI) 目录
|
|
384
|
+
* costrict/ CoStrict 目录
|
|
385
|
+
* crush/ Crush 目录
|
|
386
|
+
* factory/ Factory Droid 目录
|
|
387
|
+
* gemini/ Gemini CLI 目录
|
|
388
|
+
* opencode/ OpenCode 目录
|
|
389
|
+
* kilo/ Kilo Code 目录
|
|
390
|
+
* codex/ Codex 目录
|
|
391
|
+
* amazonq/ Amazon Q Developer 目录
|
|
392
|
+
* qwen/ Qwen Code 目录
|
|
298
393
|
* @param options
|
|
299
394
|
*/
|
|
300
395
|
module.exports = (options) => {
|