momo-ai 1.0.19 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
  2. package/.claude/skills/algorithmic-art/SKILL.md +405 -0
  3. package/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
  4. package/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
  5. package/.claude/skills/r2mo-rad-lain/PROMPT.md +281 -0
  6. package/.claude/skills/r2mo-rad-lain/README.md +192 -0
  7. package/.claude/skills/r2mo-rad-lain/SKILL.md +412 -0
  8. package/.claude/skills/r2mo-rad-lain/examples/argument-parsing.js +154 -0
  9. package/.claude/skills/r2mo-rad-lain/examples/file-operations.js +182 -0
  10. package/.claude/skills/r2mo-rad-lain/file-utils-api.md +281 -0
  11. package/.claude/skills/r2mo-rad-lain/menu-api.md +187 -0
  12. package/.claude/skills/r2mo-rad-lain/scripts/file-utils.js +223 -0
  13. package/.claude/skills/r2mo-rad-lain/scripts/menu.js +289 -0
  14. package/.claude/skills/r2mo-rad-lain/scripts/yaml-parser.js +209 -0
  15. package/.claude/skills/r2mo-rad-lain/templates/command.json.template +13 -0
  16. package/.claude/skills/r2mo-rad-lain/templates/executor.js.template +32 -0
  17. package/.claude/skills/r2mo-rad-lain/templates/interactive-menu.js.template +221 -0
  18. package/.cursor/mcp.json +17 -0
  19. package/.obsidian/app.json +1 -0
  20. package/.obsidian/appearance.json +4 -0
  21. package/.obsidian/community-plugins.json +4 -0
  22. package/.obsidian/core-plugins.json +33 -0
  23. package/.obsidian/plugins/ai-agent/main.js +98495 -0
  24. package/.obsidian/plugins/ai-agent/manifest.json +11 -0
  25. package/.obsidian/plugins/ai-agent/styles.css +806 -0
  26. package/.obsidian/plugins/dataview/main.js +20876 -0
  27. package/.obsidian/plugins/dataview/manifest.json +11 -0
  28. package/.obsidian/plugins/dataview/styles.css +141 -0
  29. package/.obsidian/plugins/obsidian-excalidraw-plugin/main.js +10 -0
  30. package/.obsidian/plugins/obsidian-excalidraw-plugin/manifest.json +12 -0
  31. package/.obsidian/plugins/obsidian-excalidraw-plugin/styles.css +1 -0
  32. package/.obsidian/plugins/templater-obsidian/main.js +45 -0
  33. package/.obsidian/plugins/templater-obsidian/manifest.json +11 -0
  34. package/.obsidian/plugins/templater-obsidian/styles.css +226 -0
  35. package/.obsidian/plugins/terminal/main.js +200 -0
  36. package/.obsidian/plugins/terminal/manifest.json +14 -0
  37. package/.obsidian/plugins/terminal/styles.css +32 -0
  38. package/.obsidian/themes/AnuPpuccin/manifest.json +7 -0
  39. package/.obsidian/themes/AnuPpuccin/theme.css +9080 -0
  40. package/.obsidian/themes/Things/manifest.json +7 -0
  41. package/.obsidian/themes/Things/theme.css +1628 -0
  42. package/.obsidian/workspace.json +196 -0
  43. package/README.md +10 -123
  44. package/docs/images/logo.jpeg +0 -0
  45. package/install.sh +1 -0
  46. package/package.json +6 -2
  47. package/skills/r2mo-rad-lain/SKILL.md +101 -0
  48. package/src/_agent/trae/momo-datamodel.json +2 -1
  49. package/src/_agent/trae/momo-module-req.json +2 -1
  50. package/src/_agent/trae/momo-system-req.json +2 -1
  51. package/src/_agent/trae/momo-task.json +2 -1
  52. package/src/_agent/trae/momo-taskplan.json +2 -1
  53. package/src/_mcp/skills-server.mjs +70 -0
  54. package/src/_skill/repositories.json +16 -0
  55. package/src/_template/LAIN/.momo/advanced/refer.json +0 -4
  56. package/src/commander/help.json +5 -0
  57. package/src/commander/mcp.json +13 -0
  58. package/src/commander/open.json +8 -2
  59. package/src/commander/skills.json +20 -0
  60. package/src/executor/executeEnv.js +48 -38
  61. package/src/executor/executeHelp.js +77 -16
  62. package/src/executor/executeInit.js +203 -149
  63. package/src/executor/executeMcp.js +290 -0
  64. package/src/executor/executeOpen.js +144 -125
  65. package/src/executor/executeSkills.js +747 -0
  66. package/src/executor/index.js +5 -39
  67. package/src/momo.js +2 -1
  68. package/src/utils/momo-args.js +39 -0
  69. package/src/utils/momo-file-utils.js +75 -0
  70. package/src/utils/momo-menu.js +54 -0
  71. package/src/commander/actor.json +0 -12
  72. package/src/commander/actors.json +0 -6
  73. package/src/commander/add.json +0 -12
  74. package/src/commander/agent.json +0 -12
  75. package/src/commander/agentcfg.json +0 -5
  76. package/src/commander/archive.json +0 -12
  77. package/src/commander/commit.json +0 -12
  78. package/src/commander/console.json +0 -7
  79. package/src/commander/lain.json +0 -7
  80. package/src/commander/list.json +0 -7
  81. package/src/commander/plan.json +0 -12
  82. package/src/commander/project.json +0 -12
  83. package/src/commander/pull.json +0 -6
  84. package/src/commander/push.json +0 -6
  85. package/src/commander/repo.json +0 -18
  86. package/src/commander/run.json +0 -18
  87. package/src/commander/show.json +0 -12
  88. package/src/commander/tasks.json +0 -18
  89. package/src/commander/unlock.json +0 -6
  90. package/src/commander/validate.json +0 -12
  91. package/src/executor/executeActor.js +0 -133
  92. package/src/executor/executeActors.js +0 -58
  93. package/src/executor/executeAdd.js +0 -307
  94. package/src/executor/executeAgent.js +0 -224
  95. package/src/executor/executeAgentCfg.js +0 -195
  96. package/src/executor/executeArchive.js +0 -124
  97. package/src/executor/executeCommit.js +0 -202
  98. package/src/executor/executeConsole.js +0 -142
  99. package/src/executor/executeList.js +0 -133
  100. package/src/executor/executePlan.js +0 -164
  101. package/src/executor/executeProject.js +0 -312
  102. package/src/executor/executePull.js +0 -127
  103. package/src/executor/executePush.js +0 -243
  104. package/src/executor/executeRepo.js +0 -238
  105. package/src/executor/executeRun.js +0 -644
  106. package/src/executor/executeShow.js +0 -164
  107. package/src/executor/executeTasks.js +0 -384
  108. package/src/executor/executeUnlock.js +0 -110
  109. package/src/executor/executeValidate.js +0 -210
@@ -1,164 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const Ec = require('../epic');
4
-
5
- /**
6
- * 解析 Markdown 文件内容,提取标题结构
7
- * @param {string} content 文件内容
8
- * @returns {Array} 标题结构数组
9
- */
10
- const _parseMarkdownStructure = (content) => {
11
- const lines = content.split('\n');
12
- const structure = [];
13
- const stack = [];
14
-
15
- lines.forEach(line => {
16
- const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
17
- if (headingMatch) {
18
- const level = headingMatch[1].length;
19
- const title = headingMatch[2].trim();
20
-
21
- // 调整栈以匹配当前层级
22
- while (stack.length >= level) {
23
- stack.pop();
24
- }
25
-
26
- const item = { level, title, children: [] };
27
-
28
- if (stack.length > 0) {
29
- stack[stack.length - 1].children.push(item);
30
- } else {
31
- structure.push(item);
32
- }
33
-
34
- stack.push(item);
35
- }
36
- });
37
-
38
- return structure;
39
- };
40
-
41
- /**
42
- * 打印树型结构
43
- * @param {Array} items 结构项数组
44
- * @param {number} indent 缩进级别
45
- */
46
- const _printTree = (items, indent = 0) => {
47
- items.forEach(item => {
48
- const prefix = ' '.repeat(indent);
49
- Ec.waiting(`${prefix}├─ ${item.title}`);
50
-
51
- if (item.children && item.children.length > 0) {
52
- _printTree(item.children, indent + 1);
53
- }
54
- });
55
- };
56
-
57
- /**
58
- * 提取任务清单
59
- * @param {string} tasksFile 任务文件路径
60
- * @returns {Array} 任务列表
61
- */
62
- const _extractTaskList = (tasksFile) => {
63
- const tasks = [];
64
-
65
- try {
66
- if (!fs.existsSync(tasksFile)) {
67
- return tasks;
68
- }
69
-
70
- const content = fs.readFileSync(tasksFile, 'utf8');
71
- const lines = content.split('\n');
72
-
73
- // 使用与 executeList.js 相同的逻辑来匹配任务
74
- for (const line of lines) {
75
- // 匹配任务格式,例如: - [ ] [任务1简要描述](tasks/M01-T001-01.md)
76
- if (line.trim().startsWith('- [') && line.includes('] [') && line.includes('](') && line.includes('tasks/')) {
77
- // 提取任务描述部分,使用更兼容的正则表达式
78
- const titleMatch = line.match(/] $$(.*?)$$$(tasks\/)/);
79
- if (titleMatch) {
80
- // 获取标题和链接
81
- const fullMatch = line.match(/] $$(.*?)$$$(tasks\/[^)]+)$/);
82
- if (fullMatch) {
83
- tasks.push({
84
- title: fullMatch[1],
85
- link: fullMatch[2]
86
- });
87
- }
88
- } else {
89
- // 备用方案:简单提取方括号中的内容
90
- const simpleMatch = line.match(/\[([^\]]+)\]/g);
91
- if (simpleMatch && simpleMatch.length >= 2) {
92
- tasks.push({
93
- title: simpleMatch[1].substring(1, simpleMatch[1].length - 1),
94
- link: ''
95
- });
96
- }
97
- }
98
- }
99
- }
100
- } catch (error) {
101
- // 忽略错误,返回空任务列表
102
- }
103
-
104
- return tasks;
105
- };
106
-
107
- module.exports = (options) => {
108
- // 参数提取
109
- const parsed = Ec.parseArgument(options);
110
- const requirementName = parsed.name || parsed.n;
111
-
112
- // 验证参数
113
- if (!requirementName) {
114
- Ec.error("❌ 请提供需求名称 (-n, --name)");
115
- process.exit(1);
116
- }
117
-
118
- try {
119
- // 构建路径
120
- const projectDir = process.cwd();
121
- const changesDir = path.join(projectDir, 'specification', 'changes');
122
- const requirementDir = path.join(changesDir, requirementName);
123
-
124
- // 检查需求目录是否存在
125
- if (!fs.existsSync(requirementDir)) {
126
- Ec.error(`❌ 需求 "${requirementName}" 不存在`);
127
- process.exit(1);
128
- }
129
-
130
- // 读取 proposal.md 文件
131
- const proposalFile = path.join(requirementDir, 'proposal.md');
132
- if (!fs.existsSync(proposalFile)) {
133
- Ec.error(`❌ 需求 "${requirementName}" 中未找到 proposal.md 文件`);
134
- process.exit(1);
135
- }
136
-
137
- const content = fs.readFileSync(proposalFile, 'utf8');
138
-
139
- // 解析并显示结构
140
- Ec.waiting(`需求名称: ${requirementName}`);
141
- Ec.waiting('文档结构:');
142
- const structure = _parseMarkdownStructure(content);
143
- _printTree(structure);
144
-
145
- // 提取并显示任务清单
146
- const tasksFile = path.join(requirementDir, 'tasks.md');
147
- const tasks = _extractTaskList(tasksFile);
148
-
149
- Ec.waiting(`\n任务清单 (共${tasks.length}个任务):`);
150
- if (tasks.length > 0) {
151
- tasks.forEach((task, index) => {
152
- Ec.waiting(` ${index + 1}. ${task.title}`);
153
- });
154
- } else {
155
- Ec.waiting(' 无');
156
- }
157
-
158
- Ec.info('✅ 需求详情显示完成');
159
- process.exit(0);
160
- } catch (error) {
161
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
162
- process.exit(1);
163
- }
164
- };
@@ -1,384 +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
- throw error;
38
- }
39
- };
40
-
41
- /**
42
- * 渲染 EJS 模板
43
- * @param {string} template 模板内容
44
- * @param {Object} data 数据对象
45
- * @returns {string} 渲染后的内容
46
- */
47
- const _renderTemplate = (template, data) => {
48
- let result = template;
49
- for (const key in data) {
50
- if (data.hasOwnProperty(key)) {
51
- const regex = new RegExp(`<%=\\s*${key}\\s*%>`, 'g');
52
- result = result.replace(regex, data[key]);
53
- }
54
- }
55
- return result;
56
- };
57
-
58
- /**
59
- * 将内容复制到剪贴板
60
- * @param {string} content 要复制的内容
61
- */
62
- const _copyToClipboard = async (content) => {
63
- try {
64
- // 使用统一的剪贴板函数
65
- await outCopy(content);
66
- Ec.waiting('📄 任务检查提示词已拷贝到剪切板');
67
- } catch (error) {
68
- Ec.waiting(`⚠️ 无法拷贝到剪切板: ${error.message}`);
69
- // 备选方案:显示内容
70
- Ec.waiting('提示词内容:');
71
- console.log(content);
72
- if (process.platform === 'win32') {
73
- Ec.waiting('💡 Windows 用户提示: 请确保您在具有足够权限的命令行中运行此命令');
74
- }
75
- }
76
- };
77
-
78
- /**
79
- * 从 Markdown 文件中提取第一个标题
80
- * @param {string} filePath 文件路径
81
- * @returns {string} 第一个标题内容
82
- */
83
- const _extractTitleFromMarkdown = (filePath) => {
84
- try {
85
- if (!fs.existsSync(filePath)) {
86
- return path.basename(filePath, '.md');
87
- }
88
-
89
- const content = fs.readFileSync(filePath, 'utf8');
90
- const lines = content.split('\n');
91
-
92
- for (const line of lines) {
93
- // 匹配 # 开头的标题行
94
- const titleMatch = line.match(/^#\s+(.+)$/);
95
- if (titleMatch) {
96
- return titleMatch[1].trim();
97
- }
98
- }
99
-
100
- // 如果没有找到标题,使用文件名(不含扩展名)作为任务名称
101
- return path.basename(filePath, '.md');
102
- } catch (error) {
103
- return path.basename(filePath, '.md');
104
- }
105
- };
106
-
107
- /**
108
- * 检查任务状态
109
- * @param {string} taskName 任务名称
110
- * @param {string} tasksDir 任务目录
111
- * @returns {string} 任务状态
112
- */
113
- const _checkTaskStatus = (taskName, tasksDir) => {
114
- // 检查.lock文件(进行中)
115
- const lockFile = path.join(tasksDir, `${taskName}.lock`);
116
- if (fs.existsSync(lockFile)) {
117
- return '进行中';
118
- }
119
-
120
- // 检查.done文件(已完成)
121
- const doneFile = path.join(tasksDir, `${taskName}.done`);
122
- if (fs.existsSync(doneFile)) {
123
- return '已完成';
124
- }
125
-
126
- // 默认状态(未开始)
127
- return '未开始';
128
- };
129
-
130
- module.exports = async (options) => {
131
- // 参数提取
132
- const parsed = Ec.parseArgument(options);
133
- const taskName = parsed.task;
134
-
135
- try {
136
- // 获取 changes 目录路径
137
- const changesDir = path.resolve(process.cwd(), 'specification', 'changes');
138
-
139
- // 检查目录是否存在
140
- if (!fs.existsSync(changesDir)) {
141
- Ec.error("❌ 未找到 changes 目录,请先初始化项目");
142
- Ec.askClose();
143
- process.exit(1);
144
- }
145
-
146
- // 获取所有需求目录
147
- const requirements = fs.readdirSync(changesDir).filter(file =>
148
- fs.statSync(path.join(changesDir, file)).isDirectory()
149
- );
150
-
151
- if (requirements.length === 0) {
152
- Ec.waiting("🔍 未找到任何需求");
153
- Ec.askClose();
154
- process.exit(0);
155
- }
156
-
157
- // 如果指定了任务名称,只检查该任务的重复信息
158
- if (taskName) {
159
- const taskInstances = [];
160
-
161
- // 查找指定任务
162
- requirements.forEach(requirement => {
163
- const tasksDir = path.resolve(changesDir, requirement, 'tasks');
164
-
165
- // 检查 tasks 目录是否存在
166
- if (fs.existsSync(tasksDir) && fs.statSync(tasksDir).isDirectory()) {
167
- // 检查 .md 文件
168
- const taskFile = `${taskName}.md`;
169
- const taskPath = path.resolve(tasksDir, taskFile);
170
-
171
- // 检查任务文件是否存在
172
- if (fs.existsSync(taskPath)) {
173
- const relativePath = path.relative(process.cwd(), taskPath);
174
- taskInstances.push({
175
- name: taskName,
176
- path: relativePath,
177
- requirement: requirement
178
- });
179
- }
180
-
181
- // 检查 .done 文件(如果 .md 文件不存在)
182
- const doneFile = `${taskName}.done`;
183
- const donePath = path.resolve(tasksDir, doneFile);
184
-
185
- if (!fs.existsSync(taskPath) && fs.existsSync(donePath)) {
186
- const relativePath = path.relative(process.cwd(), donePath);
187
- taskInstances.push({
188
- name: taskName,
189
- path: relativePath,
190
- requirement: requirement
191
- });
192
- }
193
- }
194
- });
195
-
196
- if (taskInstances.length === 0) {
197
- Ec.waiting(`✅ 未找到任务 ${taskName}`);
198
- // 即使未找到任务也执行剪切板任务
199
- await _handleClipboardTask(taskName, [{ requirement: 'unknown' }]);
200
- Ec.info(`✅ 任务 ${taskName} 的检查完成`);
201
- Ec.askClose();
202
- process.exit(0);
203
- } else if (taskInstances.length === 1) {
204
- Ec.waiting(`✅ 任务 ${taskName} 无重复`);
205
- Ec.waiting(` - ${taskInstances[0].path}`);
206
- // 即使无重复也执行剪切板任务
207
- await _handleClipboardTask(taskName, taskInstances);
208
- Ec.info(`✅ 任务 ${taskName} 的检查完成`);
209
- Ec.askClose();
210
- process.exit(0);
211
- } else {
212
- Ec.waiting(`⚠️ 发现 ${taskInstances.length} 个重复任务 ${taskName}:`);
213
- taskInstances.forEach((task, index) => {
214
- Ec.waiting(` ${String(index + 1).padStart(3, '0')}. ${task.path}`);
215
- });
216
-
217
- // 执行剪切板任务
218
- await _handleClipboardTask(taskName, taskInstances);
219
- Ec.info(`✅ 任务 ${taskName} 的重复检查完成`);
220
- Ec.askClose();
221
- process.exit(0);
222
- }
223
- }
224
-
225
- // 未指定任务名称,列出所有任务
226
- const tasks = [];
227
-
228
- requirements.forEach(requirement => {
229
- const tasksDir = path.resolve(changesDir, requirement, 'tasks');
230
-
231
- // 检查 tasks 目录是否存在
232
- if (fs.existsSync(tasksDir) && fs.statSync(tasksDir).isDirectory()) {
233
- // 获取所有 .md 文件
234
- const mdFiles = fs.readdirSync(tasksDir).filter(file =>
235
- file.endsWith('.md')
236
- );
237
-
238
- // 获取所有 .done 文件
239
- const doneFiles = fs.readdirSync(tasksDir).filter(file =>
240
- file.endsWith('.done')
241
- );
242
-
243
- // 处理 .md 文件
244
- mdFiles.forEach(taskFile => {
245
- const name = path.basename(taskFile, '.md');
246
- const taskPath = path.relative(process.cwd(), path.resolve(tasksDir, taskFile));
247
- const title = _extractTitleFromMarkdown(path.resolve(tasksDir, taskFile));
248
- const status = _checkTaskStatus(name, tasksDir);
249
-
250
- // 为状态添加颜色代码
251
- let coloredStatus;
252
- switch (status) {
253
- case '进行中':
254
- coloredStatus = status.blue;
255
- break;
256
- case '已完成':
257
- coloredStatus = status.green;
258
- break;
259
- case '未开始':
260
- coloredStatus = status.red;
261
- break;
262
- default:
263
- coloredStatus = status;
264
- }
265
-
266
- tasks.push({
267
- name: name,
268
- title: title,
269
- path: taskPath,
270
- requirement: requirement,
271
- status: coloredStatus
272
- });
273
- });
274
-
275
- // 处理 .done 文件(但没有对应的 .md 文件)
276
- doneFiles.forEach(doneFile => {
277
- const name = path.basename(doneFile, '.done');
278
- // 检查是否已经有对应的 .md 文件在任务列表中
279
- const hasMdFile = mdFiles.some(mdFile =>
280
- path.basename(mdFile, '.md') === name
281
- );
282
-
283
- // 如果没有对应的 .md 文件,则添加到任务列表
284
- if (!hasMdFile) {
285
- const donePath = path.relative(process.cwd(), path.resolve(tasksDir, doneFile));
286
- // 尝试从 .done 文件中提取标题,如果失败则使用文件名
287
- let title = _extractTitleFromMarkdown(path.resolve(tasksDir, `${name}.md`));
288
- // 如果从 .md 文件提取失败,则尝试从 .done 文件提取
289
- if (title === name) {
290
- title = _extractTitleFromMarkdown(path.resolve(tasksDir, doneFile));
291
- }
292
- // 使用标准的状态检查函数
293
- const status = _checkTaskStatus(name, tasksDir);
294
- // 为状态添加颜色代码
295
- let coloredStatus;
296
- switch (status) {
297
- case '进行中':
298
- coloredStatus = status.blue;
299
- break;
300
- case '已完成':
301
- coloredStatus = status.green;
302
- break;
303
- case '未开始':
304
- coloredStatus = status.red;
305
- break;
306
- default:
307
- coloredStatus = status;
308
- }
309
-
310
- tasks.push({
311
- name: name,
312
- title: title,
313
- path: donePath,
314
- requirement: requirement,
315
- status: coloredStatus
316
- });
317
- }
318
- });
319
-
320
- }
321
- });
322
-
323
- // 按任务名称排序
324
- tasks.sort((a, b) => a.name.localeCompare(b.name));
325
-
326
- if (tasks.length === 0) {
327
- Ec.waiting("🔍 未找到任何任务");
328
- // 即使未找到任务也执行剪切板任务(使用默认值)
329
- await _handleClipboardTask('default', [{ requirement: 'unknown' }]);
330
- Ec.info("✅ 任务列表显示完成");
331
- Ec.askClose();
332
- process.exit(0);
333
- }
334
-
335
- // 列出所有任务(包含路径和状态,状态在前)
336
- Ec.waiting(`📊 共找到 ${tasks.length} 个任务:`);
337
- tasks.forEach((task, index) => {
338
- const paddedIndex = String(index + 1).padStart(3, '0');
339
- const coloredName = task.name.cyan;
340
- const coloredPath = task.path.yellow; // 使用黄色高亮路径
341
-
342
- Ec.waiting(`${paddedIndex}. ${coloredName} [${task.status}] | ${task.title} / ${coloredPath}`);
343
- });
344
-
345
- // 执行剪切板任务(使用第一个任务)
346
- await _handleClipboardTask(tasks[0].name, [tasks[0]]);
347
- Ec.info("✅ 任务列表显示完成");
348
- Ec.askClose();
349
- process.exit(0);
350
- } catch (error) {
351
- Ec.error(`❌ 执行过程中发生错误: ${error.message}`);
352
- Ec.askClose();
353
- process.exit(1);
354
- }
355
- };
356
-
357
- /**
358
- * 处理剪切板任务
359
- * @param {string} taskName 任务名称
360
- * @param {Array} taskInstances 任务实例列表
361
- */
362
- const _handleClipboardTask = async (taskName, taskInstances) => {
363
- // 读取模板文件并填充参数,然后拷贝到剪贴板
364
- const templatePath = path.resolve(__dirname, '../_template/PROMPT/tasks.md.ejs');
365
-
366
- if (fs.existsSync(templatePath)) {
367
- try {
368
- // 读取并处理提示词模板
369
- const templateContent = await _readTemplate(templatePath);
370
-
371
- const renderedContent = _renderTemplate(templateContent, {
372
- REQ: taskInstances[0].requirement,
373
- TASK: taskName
374
- });
375
-
376
- // 将提示词复制到剪贴板
377
- await _copyToClipboard(renderedContent);
378
- } catch (error) {
379
- Ec.waiting(`⚠️ 处理模板时出错: ${error.message}`);
380
- }
381
- } else {
382
- Ec.waiting(`⚠️ 未找到模板文件: ${templatePath}`);
383
- }
384
- };
@@ -1,110 +0,0 @@
1
- const Ec = require('../epic');
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- /**
6
- * 删除 specification 目录下的所有任务锁文件
7
- * @param {string} dir specification 目录路径
8
- * @returns {number} 删除的文件数量
9
- */
10
- const _unlockSpecification = (dir) => {
11
- let deletedCount = 0;
12
-
13
- if (!fs.existsSync(dir)) {
14
- return deletedCount;
15
- }
16
-
17
- // 递归查找 specification/changes/*/tasks/*.lock 文件
18
- const changesDir = path.join(dir, 'changes');
19
- if (fs.existsSync(changesDir) && fs.statSync(changesDir).isDirectory()) {
20
- const requirements = fs.readdirSync(changesDir).filter(file =>
21
- fs.statSync(path.join(changesDir, file)).isDirectory()
22
- );
23
-
24
- requirements.forEach(requirement => {
25
- const tasksDir = path.join(changesDir, requirement, 'tasks');
26
- if (fs.existsSync(tasksDir) && fs.statSync(tasksDir).isDirectory()) {
27
- const taskFiles = fs.readdirSync(tasksDir).filter(file =>
28
- file.endsWith('.lock')
29
- );
30
-
31
- taskFiles.forEach(taskFile => {
32
- const taskFilePath = path.join(tasksDir, taskFile);
33
- try {
34
- fs.unlinkSync(taskFilePath);
35
- Ec.waiting(`🔓 已解锁任务: ${path.relative(process.cwd(), taskFilePath)}`);
36
- deletedCount++;
37
- } catch (error) {
38
- Ec.waiting(`⚠️ 无法解锁任务: ${path.relative(process.cwd(), taskFilePath)} - ${error.message}`);
39
- }
40
- });
41
- }
42
- });
43
- }
44
-
45
- return deletedCount;
46
- };
47
-
48
- /**
49
- * 删除 source 目录下的工作空间锁文件
50
- * @param {string} dir source 目录路径
51
- * @returns {number} 删除的文件数量
52
- */
53
- const _unlockSource = (dir) => {
54
- let deletedCount = 0;
55
-
56
- if (!fs.existsSync(dir)) {
57
- return deletedCount;
58
- }
59
-
60
- // 只删除 source/*.lock 文件(工作空间锁文件)
61
- const lockFiles = fs.readdirSync(dir).filter(file =>
62
- file.endsWith('.lock')
63
- );
64
-
65
- lockFiles.forEach(lockFile => {
66
- const lockFilePath = path.join(dir, lockFile);
67
- try {
68
- fs.unlinkSync(lockFilePath);
69
- Ec.waiting(`🔓 已解锁工作空间: ${path.relative(process.cwd(), lockFilePath)}`);
70
- deletedCount++;
71
- } catch (error) {
72
- Ec.waiting(`⚠️ 无法解锁工作空间: ${path.relative(process.cwd(), lockFilePath)} - ${error.message}`);
73
- }
74
- });
75
-
76
- return deletedCount;
77
- };
78
-
79
- module.exports = (options) => {
80
- // 参数提取
81
- const parsed = Ec.parseArgument(options);
82
-
83
- try {
84
- Ec.waiting("🔍 正在查找并解锁所有.lock文件...");
85
-
86
- // 解锁specification目录下的任务锁文件
87
- const specificationDir = path.resolve(process.cwd(), 'specification');
88
- const specDeletedCount = _unlockSpecification(specificationDir);
89
-
90
- // 解锁source目录下的工作空间锁文件
91
- const sourceDir = path.resolve(process.cwd(), 'source');
92
- const sourceDeletedCount = _unlockSource(sourceDir);
93
-
94
- const totalDeletedCount = specDeletedCount + sourceDeletedCount;
95
-
96
- if (totalDeletedCount === 0) {
97
- Ec.waiting("✅ 未找到任何.lock文件,无需解锁");
98
- } else {
99
- Ec.waiting(`✅ 共解锁 ${totalDeletedCount} 个文件`);
100
- }
101
-
102
- Ec.info("🔓 解锁操作完成");
103
- Ec.askClose();
104
- process.exit(0);
105
- } catch (error) {
106
- Ec.error(`❌ 解锁过程中发生错误: ${error.message}`);
107
- Ec.askClose();
108
- process.exit(1);
109
- }
110
- };