momo-ai 1.0.71 → 1.0.73
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/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "momo-ai",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.73",
|
|
4
4
|
"description": "Rachel Momo ( OpenSpec )",
|
|
5
5
|
"main": "src/momo.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"momo": "
|
|
8
|
-
"lain": "
|
|
7
|
+
"momo": "src/momo.js",
|
|
8
|
+
"lain": "src/lain.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"test": "src/index.test.js"
|
package/src/commander/docs.json
CHANGED
package/src/commander/task.json
CHANGED
|
@@ -7,6 +7,20 @@ const Ec = require('../epic');
|
|
|
7
7
|
const { parseOptional } = require('../utils/momo-args');
|
|
8
8
|
const { copyDir } = require('../utils/momo-file-utils');
|
|
9
9
|
|
|
10
|
+
const _getObsidianConfigPath = () => {
|
|
11
|
+
const platform = os.platform();
|
|
12
|
+
|
|
13
|
+
if (platform === 'darwin') {
|
|
14
|
+
return path.join(os.homedir(), 'Library/Application Support/obsidian/obsidian.json');
|
|
15
|
+
}
|
|
16
|
+
if (platform === 'win32') {
|
|
17
|
+
return path.join(process.env.APPDATA || '', 'obsidian', 'obsidian.json');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
21
|
+
return path.join(xdgConfig, 'obsidian', 'obsidian.json');
|
|
22
|
+
};
|
|
23
|
+
|
|
10
24
|
/**
|
|
11
25
|
* 检查 Obsidian 是否已安装
|
|
12
26
|
* @returns {Promise<boolean>}
|
|
@@ -54,17 +68,7 @@ const _isObsidianInstalled = async () => {
|
|
|
54
68
|
* @returns {Promise<boolean>}
|
|
55
69
|
*/
|
|
56
70
|
const _isVaultRunning = async (vaultPath) => {
|
|
57
|
-
const
|
|
58
|
-
let configPath;
|
|
59
|
-
|
|
60
|
-
if (platform === 'darwin') {
|
|
61
|
-
configPath = path.join(os.homedir(), 'Library/Application Support/obsidian/obsidian.json');
|
|
62
|
-
} else if (platform === 'win32') {
|
|
63
|
-
configPath = path.join(process.env.APPDATA || '', 'obsidian', 'obsidian.json');
|
|
64
|
-
} else {
|
|
65
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
66
|
-
configPath = path.join(xdgConfig, 'obsidian', 'obsidian.json');
|
|
67
|
-
}
|
|
71
|
+
const configPath = _getObsidianConfigPath();
|
|
68
72
|
|
|
69
73
|
try {
|
|
70
74
|
if (!fs.existsSync(configPath)) {
|
|
@@ -92,17 +96,7 @@ const _isVaultRunning = async (vaultPath) => {
|
|
|
92
96
|
* @returns {Promise<void>}
|
|
93
97
|
*/
|
|
94
98
|
const _closeVault = async (vaultPath) => {
|
|
95
|
-
const
|
|
96
|
-
let configPath;
|
|
97
|
-
|
|
98
|
-
if (platform === 'darwin') {
|
|
99
|
-
configPath = path.join(os.homedir(), 'Library/Application Support/obsidian/obsidian.json');
|
|
100
|
-
} else if (platform === 'win32') {
|
|
101
|
-
configPath = path.join(process.env.APPDATA || '', 'obsidian', 'obsidian.json');
|
|
102
|
-
} else {
|
|
103
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
104
|
-
configPath = path.join(xdgConfig, 'obsidian', 'obsidian.json');
|
|
105
|
-
}
|
|
99
|
+
const configPath = _getObsidianConfigPath();
|
|
106
100
|
|
|
107
101
|
try {
|
|
108
102
|
if (!fs.existsSync(configPath)) {
|
|
@@ -150,18 +144,7 @@ const _generateVaultId = () => {
|
|
|
150
144
|
* @returns {Promise<string|null>} 返回 vault ID,失败返回 null
|
|
151
145
|
*/
|
|
152
146
|
const _registerVaultToObsidian = async (vaultPath) => {
|
|
153
|
-
const
|
|
154
|
-
let configPath;
|
|
155
|
-
|
|
156
|
-
if (platform === 'darwin') {
|
|
157
|
-
configPath = path.join(os.homedir(), 'Library/Application Support/obsidian/obsidian.json');
|
|
158
|
-
} else if (platform === 'win32') {
|
|
159
|
-
configPath = path.join(process.env.APPDATA || '', 'obsidian', 'obsidian.json');
|
|
160
|
-
} else {
|
|
161
|
-
// Linux
|
|
162
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
163
|
-
configPath = path.join(xdgConfig, 'obsidian', 'obsidian.json');
|
|
164
|
-
}
|
|
147
|
+
const configPath = _getObsidianConfigPath();
|
|
165
148
|
|
|
166
149
|
try {
|
|
167
150
|
let config = { vaults: {}, frame: 'custom' };
|
|
@@ -208,6 +191,79 @@ const _registerVaultToObsidian = async (vaultPath) => {
|
|
|
208
191
|
}
|
|
209
192
|
};
|
|
210
193
|
|
|
194
|
+
const _removeVaultRegistration = async (vaultPath) => {
|
|
195
|
+
const configPath = _getObsidianConfigPath();
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
if (!fs.existsSync(configPath)) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const content = await fsAsync.readFile(configPath, 'utf8');
|
|
203
|
+
const config = JSON.parse(content);
|
|
204
|
+
let updated = false;
|
|
205
|
+
|
|
206
|
+
for (const [id, vault] of Object.entries(config.vaults || {})) {
|
|
207
|
+
if (vault.path === vaultPath) {
|
|
208
|
+
delete config.vaults[id];
|
|
209
|
+
updated = true;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!updated) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
await fsAsync.writeFile(configPath, JSON.stringify(config), 'utf8');
|
|
218
|
+
return true;
|
|
219
|
+
} catch (error) {
|
|
220
|
+
Ec.warn(`⚠ 清理 vault 注册失败: ${error.message}`);
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const _removeLocalObsidianConfig = async (targetDir) => {
|
|
226
|
+
const obsidianConfigPath = path.join(targetDir, '.obsidian');
|
|
227
|
+
|
|
228
|
+
try {
|
|
229
|
+
if (!fs.existsSync(obsidianConfigPath)) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
await fsAsync.rm(obsidianConfigPath, { recursive: true, force: true });
|
|
234
|
+
return true;
|
|
235
|
+
} catch (error) {
|
|
236
|
+
Ec.warn(`⚠ 清理本地 .obsidian 失败: ${error.message}`);
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const _resetVaultConfig = async (targetDir) => {
|
|
242
|
+
Ec.waiting(`正在清理 Obsidian 配置: ${targetDir.cyan}...`);
|
|
243
|
+
|
|
244
|
+
const isVaultRunning = await _isVaultRunning(targetDir);
|
|
245
|
+
if (isVaultRunning) {
|
|
246
|
+
await _closeVault(targetDir);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const removedVault = await _removeVaultRegistration(targetDir);
|
|
250
|
+
const removedConfig = await _removeLocalObsidianConfig(targetDir);
|
|
251
|
+
|
|
252
|
+
if (removedVault) {
|
|
253
|
+
Ec.info('✓ 已移除 Obsidian 中的 vault 注册');
|
|
254
|
+
} else {
|
|
255
|
+
Ec.info('✓ 未发现需要移除的 vault 注册');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (removedConfig) {
|
|
259
|
+
Ec.info('✓ 已删除目标目录下的 .obsidian 配置');
|
|
260
|
+
} else {
|
|
261
|
+
Ec.info('✓ 目标目录下不存在 .obsidian 配置');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
Ec.info('✅ Obsidian 配置清理完成');
|
|
265
|
+
};
|
|
266
|
+
|
|
211
267
|
/**
|
|
212
268
|
* 使用 Obsidian 打开目录
|
|
213
269
|
* 直接调用 Obsidian 可执行文件,传递目录路径作为参数
|
|
@@ -429,11 +485,21 @@ const _updateGitignore = async (targetDir) => {
|
|
|
429
485
|
|
|
430
486
|
module.exports = async (options) => {
|
|
431
487
|
try {
|
|
432
|
-
// 1. 解析 -d 参数,获取目标目录
|
|
488
|
+
// 1. 解析 -d/-r 参数,获取目标目录
|
|
433
489
|
const dirArg = parseOptional('dir', 'd');
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
490
|
+
const removeArg = parseOptional('remove', 'r');
|
|
491
|
+
|
|
492
|
+
if (dirArg.hasFlag && removeArg.hasFlag) {
|
|
493
|
+
Ec.error('❌ 参数 -d/--dir 与 -r/--remove 不能同时使用');
|
|
494
|
+
process.exit(1);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
let targetDir = process.cwd();
|
|
498
|
+
if (removeArg.hasFlag) {
|
|
499
|
+
targetDir = removeArg.value ? path.resolve(removeArg.value) : process.cwd();
|
|
500
|
+
} else if (dirArg.hasFlag) {
|
|
501
|
+
targetDir = dirArg.value ? path.resolve(dirArg.value) : process.cwd();
|
|
502
|
+
}
|
|
437
503
|
|
|
438
504
|
Ec.info(`📁 目标目录: ${targetDir.cyan}`);
|
|
439
505
|
Ec.info(`💻 操作系统: ${_getOsName().cyan}`);
|
|
@@ -451,6 +517,12 @@ module.exports = async (options) => {
|
|
|
451
517
|
process.exit(1);
|
|
452
518
|
}
|
|
453
519
|
|
|
520
|
+
if (removeArg.hasFlag) {
|
|
521
|
+
await _resetVaultConfig(targetDir);
|
|
522
|
+
console.log('');
|
|
523
|
+
process.exit(0);
|
|
524
|
+
}
|
|
525
|
+
|
|
454
526
|
// 4. 检查 .obsidian 配置是否存在,不存在则自动初始化
|
|
455
527
|
const obsidianConfigPath = path.join(targetDir, '.obsidian');
|
|
456
528
|
if (!fs.existsSync(obsidianConfigPath)) {
|
|
@@ -70,7 +70,7 @@ const _listTaskFiles = async (taskDir) => {
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
/** 提示词模板:阅读后为所选 md 的相对路径(统一模板) */
|
|
73
|
-
const _promptForTask = (relativePath) => `执行任务:读取当前工作目录下 ${relativePath} 的正文(frontmatter 之后),按其中要求完成任务,若开启了 Team 模式则考虑使用 Team 模式执行,最多创建的 Worker(不包括Team Leader)最多
|
|
73
|
+
const _promptForTask = (relativePath) => `执行任务:读取当前工作目录下 ${relativePath} 的正文(frontmatter 之后),按其中要求完成任务,若开启了 Team 模式则考虑使用 Team 模式执行,最多创建的 Worker(不包括Team Leader)最多10个,自动评估和创建,执行完成后 Team Leader 回写 ${relativePath} 追加 Changes 记录。`;
|
|
74
74
|
|
|
75
75
|
|
|
76
76
|
module.exports = async () => {
|
|
@@ -5,7 +5,7 @@ const Ec = require('../epic');
|
|
|
5
5
|
const TASK_DIR = '.r2mo/task';
|
|
6
6
|
const THREAD_FILE = 'thread';
|
|
7
7
|
const UNDO_DIR = 'undo';
|
|
8
|
-
const DEFAULT_SLOTS =
|
|
8
|
+
const DEFAULT_SLOTS = 10;
|
|
9
9
|
|
|
10
10
|
const TASK_FILE_RE = /^task-(\d+)\.md$/;
|
|
11
11
|
|
|
@@ -120,7 +120,7 @@ const _yamlFrontmatter = (attrs) => {
|
|
|
120
120
|
/** 生成针对某槽位 task 文件的提示词(统一模板) */
|
|
121
121
|
const _taskPromptForSlot = (filename) => {
|
|
122
122
|
const relativePath = `.r2mo/task/${filename}`;
|
|
123
|
-
return `执行任务:读取当前工作目录下 ${relativePath} 的正文(frontmatter 之后),按其中要求完成任务,若开启了 Team 模式则考虑使用 Team 模式执行,最多创建的 Worker(不包括Team Leader)最多
|
|
123
|
+
return `执行任务:读取当前工作目录下 ${relativePath} 的正文(frontmatter 之后),按其中要求完成任务,若开启了 Team 模式则考虑使用 Team 模式执行,最多创建的 Worker(不包括Team Leader)最多10个,自动评估和创建,执行完成后 Team Leader 回写 ${relativePath} 追加 Changes 记录。`;
|
|
124
124
|
};
|
|
125
125
|
|
|
126
126
|
module.exports = (options) => {
|