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.71",
3
+ "version": "1.0.73",
4
4
  "description": "Rachel Momo ( OpenSpec )",
5
5
  "main": "src/momo.js",
6
6
  "bin": {
7
- "momo": "./src/momo.js",
8
- "lain": "./src/lain.js"
7
+ "momo": "src/momo.js",
8
+ "lain": "src/lain.js"
9
9
  },
10
10
  "scripts": {
11
11
  "test": "src/index.test.js"
@@ -8,6 +8,12 @@
8
8
  "alias": "d",
9
9
  "description": "目标目录(默认当前目录)",
10
10
  "type": "string"
11
+ },
12
+ {
13
+ "name": "remove",
14
+ "alias": "r",
15
+ "description": "清理指定目录的 Obsidian 配置(与 -d 互斥)",
16
+ "type": "string"
11
17
  }
12
18
  ]
13
19
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "executor": "executeTask",
3
- "description": "在 .r2mo/task/ 下使用五槽位 task-001~005 创建任务(满则选替换),备份后写入对应提示词到剪贴板",
3
+ "description": "在 .r2mo/task/ 下使用十槽位 task-001~010 创建任务(满则选替换),备份后写入对应提示词到剪贴板",
4
4
  "command": "task",
5
5
  "options": []
6
6
  }
@@ -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 platform = os.platform();
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 platform = os.platform();
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 platform = os.platform();
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 targetDir = dirArg.hasFlag && dirArg.value
435
- ? path.resolve(dirArg.value)
436
- : process.cwd();
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)最多5个,自动评估和创建,执行完成后 Team Leader 回写 ${relativePath} 追加 Changes 记录。`;
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 = 5;
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)最多5个,自动评估和创建,执行完成后 Team Leader 回写 ${relativePath} 追加 Changes 记录。`;
123
+ return `执行任务:读取当前工作目录下 ${relativePath} 的正文(frontmatter 之后),按其中要求完成任务,若开启了 Team 模式则考虑使用 Team 模式执行,最多创建的 Worker(不包括Team Leader)最多10个,自动评估和创建,执行完成后 Team Leader 回写 ${relativePath} 追加 Changes 记录。`;
124
124
  };
125
125
 
126
126
  module.exports = (options) => {