momo-ai 1.0.20 → 1.0.22

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 (162) 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/SKILL.md +101 -0
  6. package/.cursor/mcp.json +17 -0
  7. package/.obsidian/app.json +1 -0
  8. package/.obsidian/appearance.json +4 -0
  9. package/.obsidian/community-plugins.json +4 -0
  10. package/.obsidian/core-plugins.json +33 -0
  11. package/.obsidian/plugins/ai-agent/main.js +98495 -0
  12. package/.obsidian/plugins/ai-agent/manifest.json +11 -0
  13. package/.obsidian/plugins/ai-agent/styles.css +806 -0
  14. package/.obsidian/plugins/dataview/main.js +20876 -0
  15. package/.obsidian/plugins/dataview/manifest.json +11 -0
  16. package/.obsidian/plugins/dataview/styles.css +141 -0
  17. package/.obsidian/plugins/obsidian-excalidraw-plugin/main.js +10 -0
  18. package/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json +12 -0
  19. package/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css +1 -0
  20. package/.obsidian/plugins/templater-obsidian/main.js +45 -0
  21. package/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
  22. package/.obsidian/plugins/templater-obsidian/styles.css +226 -0
  23. package/.obsidian/plugins/terminal/main.js +200 -0
  24. package/.obsidian/plugins/terminal/manifest.json +14 -0
  25. package/.obsidian/plugins/terminal/styles.css +32 -0
  26. package/.obsidian/themes/AnuPpuccin/manifest.json +7 -0
  27. package/.obsidian/themes/AnuPpuccin/theme.css +9080 -0
  28. package/.obsidian/themes/Things/manifest.json +7 -0
  29. package/.obsidian/themes/Things/theme.css +1628 -0
  30. package/.obsidian/workspace.json +196 -0
  31. package/.trae/skills/algorithmic-art/LICENSE.txt +202 -0
  32. package/.trae/skills/algorithmic-art/SKILL.md +405 -0
  33. package/.trae/skills/algorithmic-art/templates/generator_template.js +223 -0
  34. package/.trae/skills/algorithmic-art/templates/viewer.html +599 -0
  35. package/.trae/skills/doc-coauthoring/SKILL.md +375 -0
  36. package/.trae/skills/frontend-design/LICENSE.txt +177 -0
  37. package/.trae/skills/frontend-design/SKILL.md +42 -0
  38. package/.trae/skills/r2mo-rad-lain/SKILL.md +101 -0
  39. package/README.md +12 -148
  40. package/docs/images/logo.jpeg +0 -0
  41. package/docs/images/r2mo-lain.png +0 -0
  42. package/install.sh +1 -0
  43. package/package.json +15 -11
  44. package/skills/r2mo-rad-domain/SKILL.md +70 -0
  45. package/skills/r2mo-rad-lain/SKILL.md +101 -0
  46. package/src/_mcp/skills-server.mjs +70 -0
  47. package/src/_skill/repositories.json +22 -0
  48. package/src/_template/LAIN/.obsidian/app.json +1 -0
  49. package/src/_template/LAIN/.obsidian/appearance.json +10 -0
  50. package/src/_template/LAIN/.obsidian/community-plugins.json +7 -0
  51. package/src/_template/LAIN/.obsidian/core-plugins.json +33 -0
  52. package/src/_template/LAIN/.obsidian/plugins/dataview/main.js +20876 -0
  53. package/src/_template/LAIN/.obsidian/plugins/dataview/manifest.json +11 -0
  54. package/src/_template/LAIN/.obsidian/plugins/dataview/styles.css +141 -0
  55. package/src/_template/LAIN/.obsidian/plugins/obsidian-excalidraw-plugin/data.json +815 -0
  56. package/src/_template/LAIN/.obsidian/plugins/obsidian-excalidraw-plugin/main.js +10 -0
  57. package/src/_template/LAIN/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json +12 -0
  58. package/src/_template/LAIN/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css +1 -0
  59. package/src/_template/LAIN/.obsidian/plugins/obsidian-kanban/main.js +153 -0
  60. package/src/_template/LAIN/.obsidian/plugins/obsidian-kanban/manifest.json +11 -0
  61. package/src/_template/LAIN/.obsidian/plugins/obsidian-kanban/styles.css +1 -0
  62. package/src/_template/LAIN/.obsidian/plugins/obsidian-plantuml/main.js +7732 -0
  63. package/src/_template/LAIN/.obsidian/plugins/obsidian-plantuml/manifest.json +10 -0
  64. package/src/_template/LAIN/.obsidian/plugins/obsidian-plantuml/styles.css +38 -0
  65. package/src/_template/LAIN/.obsidian/plugins/obsidian-tasks-plugin/main.js +504 -0
  66. package/src/_template/LAIN/.obsidian/plugins/obsidian-tasks-plugin/manifest.json +12 -0
  67. package/src/_template/LAIN/.obsidian/plugins/obsidian-tasks-plugin/styles.css +1 -0
  68. package/src/_template/LAIN/.obsidian/snippets/body-font.css +27 -0
  69. package/src/_template/LAIN/.obsidian/themes/Primary/manifest.json +9 -0
  70. package/src/_template/LAIN/.obsidian/themes/Primary/theme.css +3878 -0
  71. package/src/_template/LAIN/.obsidian/themes/Retro Windows/manifest.json +7 -0
  72. package/src/_template/LAIN/.obsidian/themes/Retro Windows/theme.css +582 -0
  73. package/src/_template/LAIN/.obsidian/themes/RetroOS 98/manifest.json +9 -0
  74. package/src/_template/LAIN/.obsidian/themes/RetroOS 98/theme.css +2566 -0
  75. package/src/_template/LAIN/.obsidian/types.json +28 -0
  76. package/src/_template/LAIN/.obsidian/workspace.json +184 -0
  77. package/src/_template/LAIN/AGENTS.md +170 -16
  78. package/src/_template/R2MO/domain-enhance.md +10 -0
  79. package/src/commander/app.json +13 -0
  80. package/src/commander/apply.json +13 -0
  81. package/src/commander/ask.json +6 -0
  82. package/src/commander/docs.json +13 -0
  83. package/src/commander/domain.json +19 -0
  84. package/src/commander/help.json +5 -0
  85. package/src/commander/init.json +1 -1
  86. package/src/commander/mcp.json +13 -0
  87. package/src/commander/mmr0.json +6 -0
  88. package/src/commander/mmr2.json +6 -0
  89. package/src/commander/open.json +8 -2
  90. package/src/executor/executeApp.js +133 -0
  91. package/src/executor/executeApply.js +611 -0
  92. package/src/executor/executeAsk.js +274 -0
  93. package/src/executor/executeDocs.js +498 -0
  94. package/src/executor/executeDomain.js +293 -0
  95. package/src/executor/executeEnv.js +48 -38
  96. package/src/executor/executeHelp.js +77 -16
  97. package/src/executor/executeInit.js +176 -346
  98. package/src/executor/executeMcp.js +363 -0
  99. package/src/executor/executeMmr0.js +488 -0
  100. package/src/executor/executeMmr2.js +880 -0
  101. package/src/executor/executeOpen.js +144 -125
  102. package/src/executor/index.js +17 -39
  103. package/src/momo.js +2 -1
  104. package/src/python/r2mo_proto.py +418 -0
  105. package/src/python/r2mo_proto_database.py +369 -0
  106. package/src/python/r2mo_proto_domain.py +458 -0
  107. package/src/utils/momo-args.js +39 -0
  108. package/src/utils/momo-file-utils.js +75 -0
  109. package/src/utils/momo-menu.js +84 -0
  110. package/src/_template/LAIN/.momo/advanced/actor.md +0 -42
  111. package/src/_template/LAIN/.momo/advanced/refer.json +0 -46
  112. package/src/_template/LAIN/.momo/scripts/submodule-clean.sh +0 -56
  113. package/src/_template/LAIN/changes/proposal.md +0 -39
  114. package/src/_template/LAIN/changes/tasks/task-detail.md +0 -45
  115. package/src/_template/LAIN/changes/tasks.md +0 -49
  116. package/src/_template/LAIN/execute/admin-n-f-dashboard.md +0 -53
  117. package/src/_template/LAIN/execute/admin-n-f-form.md +0 -51
  118. package/src/_template/LAIN/execute/admin-n-f-home.md +0 -49
  119. package/src/_template/LAIN/execute/admin-n-f-list.md +0 -52
  120. package/src/_template/LAIN/execute/admin-n-f-login.md +0 -56
  121. package/src/_template/LAIN/specification/project-model.md +0 -13
  122. package/src/_template/LAIN/specification/project.md +0 -73
  123. package/src/_template/LAIN/specification/requirement.md +0 -25
  124. package/src/commander/actor.json +0 -12
  125. package/src/commander/actors.json +0 -6
  126. package/src/commander/add.json +0 -12
  127. package/src/commander/agent.json +0 -12
  128. package/src/commander/agentcfg.json +0 -5
  129. package/src/commander/archive.json +0 -12
  130. package/src/commander/commit.json +0 -12
  131. package/src/commander/console.json +0 -7
  132. package/src/commander/lain.json +0 -7
  133. package/src/commander/list.json +0 -7
  134. package/src/commander/plan.json +0 -12
  135. package/src/commander/project.json +0 -12
  136. package/src/commander/pull.json +0 -6
  137. package/src/commander/push.json +0 -6
  138. package/src/commander/repo.json +0 -18
  139. package/src/commander/run.json +0 -18
  140. package/src/commander/show.json +0 -12
  141. package/src/commander/tasks.json +0 -18
  142. package/src/commander/unlock.json +0 -6
  143. package/src/commander/validate.json +0 -12
  144. package/src/executor/executeActor.js +0 -133
  145. package/src/executor/executeActors.js +0 -58
  146. package/src/executor/executeAdd.js +0 -307
  147. package/src/executor/executeAgent.js +0 -299
  148. package/src/executor/executeAgentCfg.js +0 -210
  149. package/src/executor/executeArchive.js +0 -124
  150. package/src/executor/executeCommit.js +0 -202
  151. package/src/executor/executeConsole.js +0 -142
  152. package/src/executor/executeList.js +0 -133
  153. package/src/executor/executePlan.js +0 -164
  154. package/src/executor/executeProject.js +0 -313
  155. package/src/executor/executePull.js +0 -127
  156. package/src/executor/executePush.js +0 -243
  157. package/src/executor/executeRepo.js +0 -238
  158. package/src/executor/executeRun.js +0 -644
  159. package/src/executor/executeShow.js +0 -164
  160. package/src/executor/executeTasks.js +0 -384
  161. package/src/executor/executeUnlock.js +0 -110
  162. package/src/executor/executeValidate.js +0 -210
@@ -1,307 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const util = require('util');
4
- const Ec = require('../epic');
5
- const fsAsync = require('fs').promises;
6
- const { outCopy } = require('../epic/momo.fn.out');
7
-
8
- /**
9
- * 读取模板文件并提取 <!-- BEGIN --> 到 <!-- END --> 之间的内容
10
- * @param {string} templatePath 模板文件路径
11
- * @returns {Promise<string>} 提取的模板内容
12
- */
13
- const _readTemplate = async (templatePath) => {
14
- try {
15
- const content = await fsAsync.readFile(templatePath, 'utf8');
16
- const lines = content.split('\n');
17
- let beginIndex = -1;
18
- let endIndex = -1;
19
-
20
- for (let i = 0; i < lines.length; i++) {
21
- if (lines[i].includes('<!-- BEGIN -->')) {
22
- beginIndex = i;
23
- } else if (lines[i].includes('<!-- END -->')) {
24
- endIndex = i;
25
- break;
26
- }
27
- }
28
-
29
- if (beginIndex !== -1 && endIndex !== -1) {
30
- // 提取 BEGIN 和 END 之间的内容(不包括 BEGIN 和 END 行)
31
- return lines.slice(beginIndex + 1, endIndex).join('\n');
32
- }
33
-
34
- return content;
35
- } catch (error) {
36
- Ec.waiting(`读取模板文件失败: ${error.message}`);
37
- if (process.platform === 'win32') {
38
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
39
- }
40
- throw error;
41
- }
42
- };
43
-
44
- /**
45
- * 渲染 EJS 模板
46
- * @param {string} template 模板内容
47
- * @param {Object} data 数据对象
48
- * @returns {string} 渲染后的内容
49
- */
50
- const _renderTemplate = (template, data) => {
51
- let result = template;
52
- for (const key in data) {
53
- if (data.hasOwnProperty(key)) {
54
- const regex = new RegExp(`<%=\\s*${key}\\s*%>`, 'g');
55
- result = result.replace(regex, data[key]);
56
- }
57
- }
58
- return result;
59
- };
60
-
61
- /**
62
- * 检查需求目录是否已存在
63
- * @param {string} changesDir changes目录路径
64
- * @param {string} requirementName 需求名称
65
- * @returns {boolean} 是否存在
66
- */
67
- const _isRequirementExists = (changesDir, requirementName) => {
68
- const requirementDir = path.join(changesDir, requirementName);
69
- return fs.existsSync(requirementDir);
70
- };
71
-
72
- /**
73
- * 从 Markdown 文件中提取第一个标题作为需求名称
74
- * @param {string} filePath 文件路径
75
- * @returns {Promise<string>} 第一个标题内容
76
- */
77
- const _extractTitleFromMarkdown = async (filePath) => {
78
- try {
79
- const content = await fsAsync.readFile(filePath, 'utf8');
80
- const lines = content.split('\n');
81
-
82
- for (const line of lines) {
83
- // 匹配 # 开头的标题行
84
- const titleMatch = line.match(/^#\s+(.+)$/);
85
- if (titleMatch) {
86
- return titleMatch[1].trim();
87
- }
88
- }
89
-
90
- // 如果没有找到标题,使用文件名(不含扩展名)作为需求名称
91
- const fileName = path.basename(filePath);
92
- return fileName.replace(/\.[^/.]+$/, ""); // 移除扩展名
93
- } catch (error) {
94
- Ec.waiting(`读取文件失败: ${error.message}`);
95
- throw error;
96
- }
97
- };
98
-
99
- /**
100
- * 创建需求目录并拷贝模板文件
101
- * @param {string} templateDir 模板目录
102
- * @param {string} targetDir 目标目录
103
- * @param {string} sourceFilePath 源文件路径(可选)
104
- */
105
- const _copyTemplateFiles = async (templateDir, targetDir, sourceFilePath = null) => {
106
- try {
107
- // 确保目标目录存在
108
- if (!fs.existsSync(targetDir)) {
109
- await fsAsync.mkdir(targetDir, { recursive: true });
110
- }
111
-
112
- let proposalSource = path.join(templateDir, 'proposal.md');
113
- const proposalTarget = path.join(targetDir, 'proposal.md');
114
-
115
- // 如果提供了源文件路径,则使用源文件内容覆盖 proposal.md
116
- if (sourceFilePath && fs.existsSync(sourceFilePath)) {
117
- proposalSource = sourceFilePath;
118
- Ec.waiting(`从文件 "${sourceFilePath}" 拷贝内容到 proposal.md`);
119
- await fsAsync.copyFile(sourceFilePath, proposalTarget);
120
- } else if (fs.existsSync(proposalSource)) {
121
- Ec.waiting(`拷贝文件: ${proposalTarget}`);
122
- await fsAsync.copyFile(proposalSource, proposalTarget);
123
- } else {
124
- // 如果模板文件不存在,则创建空文件
125
- Ec.waiting(`创建空文件: ${proposalTarget}`);
126
- await fsAsync.writeFile(proposalTarget, '');
127
- }
128
-
129
- // 拷贝 tasks.md
130
- const tasksSource = path.join(templateDir, 'tasks.md');
131
- const tasksTarget = path.join(targetDir, 'tasks.md');
132
- if (fs.existsSync(tasksSource)) {
133
- Ec.waiting(`拷贝文件: ${tasksTarget}`);
134
- await fsAsync.copyFile(tasksSource, tasksTarget);
135
- } else {
136
- // 如果模板文件不存在,则创建空文件
137
- Ec.waiting(`创建空文件: ${tasksTarget}`);
138
- await fsAsync.writeFile(tasksTarget, '');
139
- }
140
-
141
- // 创建 tasks 目录
142
- const tasksDir = path.join(targetDir, 'tasks');
143
- if (!fs.existsSync(tasksDir)) {
144
- Ec.waiting(`创建目录: ${tasksDir}`);
145
- await fsAsync.mkdir(tasksDir, { recursive: true });
146
- }
147
-
148
- // 拷贝 task-detail.md 到 tasks 目录
149
- const taskDetailSource = path.join(templateDir, 'tasks', 'task-detail.md');
150
- const taskDetailTarget = path.join(tasksDir, 'M01-T001-01.md'); // 示例任务文件名
151
- if (fs.existsSync(taskDetailSource)) {
152
- Ec.waiting(`拷贝文件: ${taskDetailTarget}`);
153
- await fsAsync.copyFile(taskDetailSource, taskDetailTarget);
154
- } else {
155
- // 如果模板文件不存在,则创建空文件
156
- Ec.waiting(`创建空文件: ${taskDetailTarget}`);
157
- await fsAsync.writeFile(taskDetailTarget, '');
158
- }
159
- } catch (error) {
160
- Ec.waiting(`拷贝模板文件失败: ${error.message}`);
161
- if (process.platform === 'win32') {
162
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
163
- }
164
- throw error;
165
- }
166
- };
167
-
168
- /**
169
- * 将内容复制到剪贴板(去除换行符)
170
- * @param {string} content 要复制的内容
171
- */
172
- const _copyToClipboard = async (content) => {
173
- try {
174
- // 去除换行符,将内容合并为一行
175
- const contentWithoutNewlines = content.replace(/\r?\n|\r/g, ' ');
176
-
177
- // 使用统一的剪贴板函数
178
- await outCopy(contentWithoutNewlines);
179
- Ec.waiting('✅ 提示词已复制到剪贴板');
180
- } catch (error) {
181
- Ec.waiting(`复制到剪贴板失败: ${error.message}`);
182
- // 提供备选方案
183
- Ec.waiting('提示词内容:');
184
- console.log(content);
185
- if (process.platform === 'win32') {
186
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
187
- }
188
- }
189
- };
190
-
191
- module.exports = async (options) => {
192
- // 参数提取
193
- const parsed = Ec.parseArgument(options);
194
-
195
- // 获取需求名称
196
- let requirementName = parsed.name || parsed.n;
197
-
198
- // 验证参数
199
- if (!requirementName) {
200
- Ec.error("❌ 请提供需求名称或需求文件路径 (-n, --name)");
201
- process.exit(1);
202
- }
203
-
204
- // 检查是否包含扩展名
205
- const hasExtension = path.extname(requirementName) !== '';
206
-
207
- // 如果包含扩展名,视为文件路径处理
208
- let sourceFilePath = null;
209
- if (hasExtension) {
210
- // 检查文件是否存在
211
- if (!fs.existsSync(requirementName)) {
212
- // 检查是否在当前目录下存在
213
- const fullPath = path.resolve(process.cwd(), requirementName);
214
- if (!fs.existsSync(fullPath)) {
215
- Ec.error(`❌ 文件 "${requirementName}" 不存在`);
216
- process.exit(1);
217
- }
218
- sourceFilePath = fullPath;
219
- } else {
220
- sourceFilePath = requirementName;
221
- }
222
-
223
- // 从文件中提取标题作为需求名称
224
- requirementName = await _extractTitleFromMarkdown(sourceFilePath);
225
- }
226
-
227
- // 检查需求名称是否包含非法字符(Windows 上特别检查)
228
- if (process.platform === 'win32') {
229
- const illegalChars = /[<>:"/\\|?*\x00-\x1F]/g;
230
- if (illegalChars.test(requirementName)) {
231
- Ec.error(`❌ 需求名称 "${requirementName}" 包含非法字符,请避免使用以下字符: < > : " / \\ | ? * 以及控制字符`);
232
- process.exit(1);
233
- }
234
- }
235
-
236
- // 检查需求名称是否包含点号(除了允许的独立需求)
237
- if (!hasExtension && requirementName.includes('.')) {
238
- Ec.error("❌ 独立需求名称不能包含点号(.),以防止与文件扩展名混淆");
239
- process.exit(1);
240
- }
241
-
242
- Ec.waiting(`准备添加新需求: ${requirementName}`);
243
-
244
- try {
245
- // 获取项目路径
246
- const projectDir = process.cwd();
247
- const changesDir = path.join(projectDir, 'specification', 'changes');
248
- const templateDir = path.join(__dirname, '../_template/LAIN/changes');
249
- const promptTemplatePath = path.join(__dirname, '../_template/PROMPT/add.md.ejs');
250
-
251
- // 检查需求是否已存在
252
- if (_isRequirementExists(changesDir, requirementName)) {
253
- Ec.error(`❌ 需求 "${requirementName}" 已存在`);
254
- process.exit(1);
255
- }
256
-
257
- // 确保 changes 目录存在
258
- if (!fs.existsSync(changesDir)) {
259
- Ec.waiting(`创建目录: ${changesDir}`);
260
- try {
261
- await fsAsync.mkdir(changesDir, { recursive: true });
262
- } catch (mkdirError) {
263
- Ec.error(`❌ 创建目录失败: ${mkdirError.message}`);
264
- if (process.platform === 'win32') {
265
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
266
- }
267
- process.exit(1);
268
- }
269
- }
270
-
271
- // 创建需求目录
272
- const requirementDir = path.join(changesDir, requirementName);
273
- Ec.waiting(`创建需求目录: ${requirementDir}`);
274
- try {
275
- await fsAsync.mkdir(requirementDir, { recursive: true });
276
- } catch (mkdirError) {
277
- Ec.error(`❌ 创建目录失败: ${mkdirError.message}`);
278
- if (process.platform === 'win32') {
279
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
280
- // 检查是否是由于特殊字符导致的问题
281
- if (mkdirError.message.includes('Invalid argument') || mkdirError.message.includes('EINVAL')) {
282
- Ec.waiting('💡 可能是由于需求名称包含非法字符,请尝试使用更简单的名称');
283
- }
284
- }
285
- process.exit(1);
286
- }
287
-
288
- // 拷贝模板文件
289
- await _copyTemplateFiles(templateDir, requirementDir, sourceFilePath);
290
-
291
- // 读取并处理提示词模板
292
- const templateContent = await _readTemplate(promptTemplatePath);
293
- const renderedContent = _renderTemplate(templateContent, { NAME: requirementName });
294
-
295
- // 将提示词复制到剪贴板
296
- await _copyToClipboard(renderedContent);
297
-
298
- Ec.info(`✅ 成功添加新需求 "${requirementName}"`);
299
- process.exit(0);
300
- } catch (error) {
301
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
302
- if (process.platform === 'win32') {
303
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
304
- }
305
- process.exit(1);
306
- }
307
- };
@@ -1,299 +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
- 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
- uriCn: agentInfo['uri-cn'], // 添加CN链接
49
- filePath: filePath
50
- });
51
- } catch (error) {
52
- Ec.waiting(`⚠️ 无法解析文件: ${file} - ${error.message}`);
53
- }
54
- });
55
- });
56
-
57
- return agents;
58
- };
59
-
60
- /**
61
- * 从 EJS 模板中提取内容
62
- * @param {string} templatePath 模板路径
63
- * @returns {Promise<string>} 提取的模板内容
64
- */
65
- const _extractTemplateContent = async (templatePath) => {
66
- try {
67
- const content = await fsAsync.readFile(templatePath, 'utf8');
68
- const lines = content.split('\n');
69
- let beginIndex = -1;
70
- let endIndex = -1;
71
-
72
- for (let i = 0; i < lines.length; i++) {
73
- if (lines[i].includes('<!-- BEGIN -->')) {
74
- beginIndex = i;
75
- } else if (lines[i].includes('<!-- END -->')) {
76
- endIndex = i;
77
- break;
78
- }
79
- }
80
-
81
- if (beginIndex !== -1 && endIndex !== -1) {
82
- // 提取 BEGIN 和 END 之间的内容(不包括 BEGIN 和 END 行)
83
- return lines.slice(beginIndex + 1, endIndex).join('\n');
84
- }
85
-
86
- return content;
87
- } catch (error) {
88
- throw new Error(`无法读取模板文件: ${error.message}`);
89
- }
90
- };
91
-
92
- /**
93
- * 将内容复制到剪贴板
94
- * @param {string} content 要复制的内容
95
- */
96
- const _copyToClipboard = async (content) => {
97
- const { outCopy } = require('../epic/momo.fn.out');
98
- try {
99
- // 先打印内容,按行打印并保留前缀
100
- Ec.waiting('📄 提示词内容:');
101
- Ec.waiting('----------------------------------------');
102
- const lines = content.split('\n');
103
- lines.forEach(line => {
104
- Ec.waiting(line);
105
- });
106
- Ec.waiting('----------------------------------------');
107
-
108
- // 再复制到剪贴板
109
- await outCopy(content);
110
- Ec.waiting('✅ 提示词已复制到剪贴板');
111
- } catch (error) {
112
- Ec.waiting(`复制到剪贴板失败: ${error.message}`);
113
- // 提供备选方案
114
- Ec.waiting('提示词内容:');
115
- const lines = content.split('\n');
116
- lines.forEach(line => {
117
- Ec.waiting(line);
118
- });
119
- }
120
- };
121
-
122
- module.exports = async (options) => {
123
- // 参数提取
124
- const parsed = Ec.parseArgument(options);
125
- const agentName = parsed.agent || parsed.a;
126
-
127
- try {
128
- // 获取所有 agents
129
- const agents = _getAgents();
130
-
131
- if (agents.length === 0) {
132
- Ec.error("❌ 未找到任何 agents");
133
- Ec.askClose();
134
- process.exit(1);
135
- }
136
-
137
- // 如果没有提供 agent 参数,显示可用的 agents 并让用户选择
138
- if (!agentName) {
139
- while (true) {
140
- Ec.waiting('可用的 Agents:');
141
-
142
- // 计算列宽以适应内容
143
- const typeColumnWidth = 12;
144
- const idColumnWidth = 20;
145
- const uriColumnWidth = 35;
146
- const uriCnColumnWidth = 35;
147
- const nameColumnWidth = 35;
148
-
149
- // 表头
150
- const header = "编号".padEnd(6) +
151
- "Type".padEnd(typeColumnWidth) +
152
- "ID".padEnd(idColumnWidth) +
153
- "URI".padEnd(uriColumnWidth) +
154
- "URI-CN".padEnd(uriCnColumnWidth) +
155
- "Name".padEnd(nameColumnWidth);
156
- Ec.waiting(header);
157
-
158
- // 分隔线
159
- const separator = "-".repeat(5) + " " +
160
- "-".repeat(typeColumnWidth - 1) + " " +
161
- "-".repeat(idColumnWidth - 1) + " " +
162
- "-".repeat(uriColumnWidth - 1) + " " +
163
- "-".repeat(uriCnColumnWidth - 1) + " " +
164
- "-".repeat(nameColumnWidth - 1);
165
- Ec.waiting(separator);
166
-
167
- // 数据行
168
- agents.forEach((agent, index) => {
169
- const name = `${agent.argName} (${agent.name})`;
170
- const row = `${(index + 1).toString().padEnd(6)}` +
171
- `${agent.type.padEnd(typeColumnWidth)}` +
172
- `${agent.id.padEnd(idColumnWidth).red.bold}` +
173
- `${(agent.uri || '').padEnd(uriColumnWidth)}` +
174
- `${(agent.uriCn || '').padEnd(uriCnColumnWidth)}` +
175
- name.padEnd(nameColumnWidth);
176
- Ec.waiting(row);
177
- });
178
-
179
- Ec.waiting(separator);
180
- Ec.waiting(`${agents.length + 1}. 退出`);
181
-
182
- // 获取用户选择
183
- const answer = await Ec.ask('请选择要使用的 Agent (输入编号): ');
184
- const selectedIndex = parseInt(answer) - 1;
185
-
186
- // 验证选择
187
- if (isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex > agents.length) {
188
- Ec.error("❌ 无效的选择");
189
- continue;
190
- }
191
-
192
- // 检查是否选择退出
193
- if (selectedIndex === agents.length) {
194
- Ec.info("已退出 Agent 选择");
195
- Ec.askClose();
196
- process.exit(0);
197
- }
198
-
199
- // 使用选择的 agent
200
- const selectedAgent = agents[selectedIndex];
201
- return await _processAgent(selectedAgent);
202
- }
203
- }
204
-
205
- // 查找指定的 agent
206
- const agent = agents.find(a => a.argName === agentName);
207
- if (!agent) {
208
- Ec.error(`❌ 未找到名为 "${agentName}" 的 Agent`);
209
-
210
- // 显示所有 agents(表格形式)
211
- Ec.waiting('可用的 Agents:');
212
-
213
- // 计算列宽以适应内容
214
- const typeColumnWidth = 12;
215
- const idColumnWidth = 20;
216
- const uriColumnWidth = 35;
217
- const uriCnColumnWidth = 35;
218
- const nameColumnWidth = 35;
219
-
220
- // 表头
221
- const header = "编号".padEnd(6) +
222
- "Type".padEnd(typeColumnWidth) +
223
- "ID".padEnd(idColumnWidth) +
224
- "URI".padEnd(uriColumnWidth) +
225
- "URI-CN".padEnd(uriCnColumnWidth) +
226
- "Name".padEnd(nameColumnWidth);
227
- Ec.waiting(header);
228
-
229
- // 分隔线
230
- const separator = "-".repeat(5) + " " +
231
- "-".repeat(typeColumnWidth - 1) + " " +
232
- "-".repeat(idColumnWidth - 1) + " " +
233
- "-".repeat(uriColumnWidth - 1) + " " +
234
- "-".repeat(uriCnColumnWidth - 1) + " " +
235
- "-".repeat(nameColumnWidth - 1);
236
- Ec.waiting(separator);
237
-
238
- // 数据行
239
- agents.forEach((agent, index) => {
240
- const name = `${agent.argName} (${agent.name})`;
241
- const row = `${(index + 1).toString().padEnd(6)}` +
242
- `${agent.type.padEnd(typeColumnWidth)}` +
243
- `${agent.id.padEnd(idColumnWidth).red.bold}` +
244
- `${(agent.uri || '').padEnd(uriColumnWidth)}` +
245
- `${(agent.uriCn || '').padEnd(uriCnColumnWidth)}` +
246
- name.padEnd(nameColumnWidth);
247
- Ec.waiting(row);
248
- });
249
-
250
- Ec.waiting(separator);
251
- Ec.waiting(`${agents.length + 1}. 退出`);
252
- Ec.askClose();
253
- process.exit(1);
254
- }
255
-
256
- // 处理选中的 agent
257
- await _processAgent(agent);
258
-
259
- } catch (error) {
260
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
261
- Ec.askClose();
262
- process.exit(1);
263
- }
264
- };
265
-
266
- /**
267
- * 处理选中的 agent
268
- * @param {Object} agent 选中的 agent 对象
269
- */
270
- const _processAgent = async (agent) => {
271
- try {
272
- // 构建模板路径
273
- const templatePath = path.resolve(__dirname, `../_template/PROMPT/${agent.type}/${agent.id}.ejs`);
274
-
275
- // 检查模板文件是否存在
276
- if (!fs.existsSync(templatePath)) {
277
- Ec.error(`❌ 未找到模板文件: ${templatePath}`);
278
- Ec.askClose();
279
- process.exit(1);
280
- }
281
-
282
- // 提取模板内容
283
- const content = await _extractTemplateContent(templatePath);
284
-
285
- // 复制到剪贴板
286
- await _copyToClipboard(content);
287
-
288
- // 显示警告提示
289
- Ec.waiting('');
290
- Ec.warn('⚠️ 为了获得最佳效果,请在您的 IDE 工具窗口中选择对应的 Agent 来配合使用此提示词');
291
-
292
- Ec.askClose();
293
- process.exit(0);
294
- } catch (error) {
295
- Ec.error(`❌ 处理 Agent 时发生错误: ${error.message}`);
296
- Ec.askClose();
297
- process.exit(1);
298
- }
299
- };