momo-ai 1.0.80 → 1.0.81

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "1.0.0",
3
- "lastScanned": 1774749434107,
3
+ "lastScanned": 1774929664565,
4
4
  "projectRoot": "/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain",
5
5
  "techStack": {
6
6
  "languages": [
@@ -50,21 +50,21 @@
50
50
  "path": "docs",
51
51
  "purpose": "Documentation",
52
52
  "fileCount": 0,
53
- "lastAccessed": 1774749434071,
53
+ "lastAccessed": 1774929664518,
54
54
  "keyFiles": []
55
55
  },
56
56
  "skills": {
57
57
  "path": "skills",
58
58
  "purpose": null,
59
59
  "fileCount": 0,
60
- "lastAccessed": 1774749434072,
60
+ "lastAccessed": 1774929664542,
61
61
  "keyFiles": []
62
62
  },
63
63
  "src": {
64
64
  "path": "src",
65
65
  "purpose": "Source code",
66
66
  "fileCount": 2,
67
- "lastAccessed": 1774749434082,
67
+ "lastAccessed": 1774929664551,
68
68
  "keyFiles": [
69
69
  "lain.js",
70
70
  "momo.js"
@@ -74,81 +74,39 @@
74
74
  "hotPaths": [
75
75
  {
76
76
  "path": "src/executor/executeDocs.js",
77
- "accessCount": 8,
78
- "lastAccessed": 1774751265141,
77
+ "accessCount": 40,
78
+ "lastAccessed": 1774936174792,
79
79
  "type": "file"
80
80
  },
81
81
  {
82
82
  "path": "",
83
83
  "accessCount": 3,
84
- "lastAccessed": 1774751128555,
84
+ "lastAccessed": 1774936806834,
85
85
  "type": "directory"
86
86
  },
87
- {
88
- "path": "src/utils/momo-file-utils.js",
89
- "accessCount": 2,
90
- "lastAccessed": 1774751242643,
91
- "type": "file"
92
- },
93
87
  {
94
88
  "path": "src/commander/docs.json",
95
89
  "accessCount": 1,
96
- "lastAccessed": 1774749598781,
97
- "type": "file"
98
- },
99
- {
100
- "path": "src/_template/LAIN/.obsidian/core-plugins.json",
101
- "accessCount": 1,
102
- "lastAccessed": 1774751051853,
103
- "type": "file"
104
- },
105
- {
106
- "path": "src/_template/.obsidian/core-plugins.json",
107
- "accessCount": 1,
108
- "lastAccessed": 1774751051877,
109
- "type": "file"
110
- },
111
- {
112
- "path": "src/_template/.obsidian",
113
- "accessCount": 1,
114
- "lastAccessed": 1774751051999,
115
- "type": "directory"
116
- },
117
- {
118
- "path": "src/_template/LAIN/.obsidian",
119
- "accessCount": 1,
120
- "lastAccessed": 1774751052069,
121
- "type": "directory"
122
- },
123
- {
124
- "path": "src/_template/.obsidian/community-plugins.json",
125
- "accessCount": 1,
126
- "lastAccessed": 1774751086361,
90
+ "lastAccessed": 1774930199134,
127
91
  "type": "file"
128
92
  },
129
93
  {
130
- "path": "src/_template/LAIN/.obsidian/community-plugins.json",
94
+ "path": "src/momo.js",
131
95
  "accessCount": 1,
132
- "lastAccessed": 1774751086413,
96
+ "lastAccessed": 1774934085428,
133
97
  "type": "file"
134
98
  },
135
99
  {
136
- "path": "src/_template/.obsidian/plugins/terminal/data.json",
100
+ "path": "src/utils/momo-file-utils.js",
137
101
  "accessCount": 1,
138
- "lastAccessed": 1774751086460,
102
+ "lastAccessed": 1774935787741,
139
103
  "type": "file"
140
104
  },
141
105
  {
142
- "path": "src",
106
+ "path": "src/utils",
143
107
  "accessCount": 1,
144
- "lastAccessed": 1774751128496,
108
+ "lastAccessed": 1774935890599,
145
109
  "type": "directory"
146
- },
147
- {
148
- "path": "src/utils/momo-args.js",
149
- "accessCount": 1,
150
- "lastAccessed": 1774751349801,
151
- "type": "file"
152
110
  }
153
111
  ],
154
112
  "userDirectives": []
@@ -0,0 +1,8 @@
1
+ {
2
+ "session_id": "24968ee6-c99b-47be-a904-68fcce1b08ba",
3
+ "ended_at": "2026-03-30T07:17:31.410Z",
4
+ "reason": "other",
5
+ "agents_spawned": 0,
6
+ "agents_completed": 0,
7
+ "modes_used": []
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "session_id": "d7901fcc-6318-4bc6-ba68-81722b1a4231",
3
+ "ended_at": "2026-03-29T03:41:06.062Z",
4
+ "reason": "other",
5
+ "agents_spawned": 0,
6
+ "agents_completed": 0,
7
+ "modes_used": []
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "session_id": "e12400d6-5242-491c-b32a-21db817a0d61",
3
+ "ended_at": "2026-03-30T06:30:50.982Z",
4
+ "reason": "other",
5
+ "agents_spawned": 0,
6
+ "agents_completed": 0,
7
+ "modes_used": []
8
+ }
@@ -0,0 +1,18 @@
1
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:using-superpowers"}
2
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"r2mo-rad-lain"}
3
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:systematic-debugging"}
4
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"everything-claude-code:documentation-lookup"}
5
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
6
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
7
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:p7"}
8
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:p7"}
9
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:verification-before-completion"}
10
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
11
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
12
+ {"t":0,"agent":"a299be7","agent_type":"everything-claude-code:typescript-reviewer","event":"agent_start","parent_mode":"none"}
13
+ {"t":0,"agent":"afff8f9","agent_type":"everything-claude-code:code-reviewer","event":"agent_start","parent_mode":"none"}
14
+ {"t":0,"agent":"afff8f9","agent_type":"everything-claude-code:code-reviewer","event":"agent_stop","success":true,"duration_ms":26039}
15
+ {"t":0,"agent":"a299be7","agent_type":"everything-claude-code:typescript-reviewer","event":"agent_stop","success":true,"duration_ms":102170}
16
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
17
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"commit"}
18
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"commit"}
@@ -1,6 +1,6 @@
1
1
  {
2
- "timestamp": "2026-03-29T01:59:39.454Z",
2
+ "timestamp": "2026-03-31T04:04:05.113Z",
3
3
  "backgroundTasks": [],
4
- "sessionStartTimestamp": "2026-03-29T01:59:02.995Z",
5
- "sessionId": "d7901fcc-6318-4bc6-ba68-81722b1a4231"
4
+ "sessionStartTimestamp": "2026-03-31T04:03:44.223Z",
5
+ "sessionId": "5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5"
6
6
  }
@@ -1 +1 @@
1
- {"session_id":"d7901fcc-6318-4bc6-ba68-81722b1a4231","transcript_path":"/Users/lang/.claude/projects/-Users-lang-zero-cloud-app-zero-r2mo-matrix-r2mo-lain/d7901fcc-6318-4bc6-ba68-81722b1a4231.jsonl","cwd":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","model":{"id":"claude-opus-4-6[1m]","display_name":"Opus 4.6 (1M context)"},"workspace":{"current_dir":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","project_dir":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","added_dirs":[]},"version":"2.1.86","output_style":{"name":"default"},"cost":{"total_cost_usd":14.797680850000003,"total_duration_ms":4656786,"total_api_duration_ms":3081069,"total_lines_added":143,"total_lines_removed":6},"context_window":{"total_input_tokens":2770259,"total_output_tokens":15347,"context_window_size":1000000,"current_usage":{"input_tokens":105356,"output_tokens":87,"cache_creation_input_tokens":0,"cache_read_input_tokens":0},"used_percentage":11,"remaining_percentage":89},"exceeds_200k_tokens":false}
1
+ {"session_id":"5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5","transcript_path":"/Users/lang/.claude/projects/-Users-lang-zero-cloud-app-zero-r2mo-matrix-r2mo-lain/5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5.jsonl","cwd":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","model":{"id":"claude-opus-4-6[1m]","display_name":"Opus 4.6 (1M context)"},"workspace":{"current_dir":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","project_dir":"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain","added_dirs":[]},"version":"2.1.87","output_style":{"name":"default"},"cost":{"total_cost_usd":54.5241126,"total_duration_ms":7223369,"total_api_duration_ms":4819083,"total_lines_added":334,"total_lines_removed":357},"context_window":{"total_input_tokens":8433472,"total_output_tokens":53391,"context_window_size":1000000,"current_usage":{"input_tokens":218155,"output_tokens":89,"cache_creation_input_tokens":0,"cache_read_input_tokens":0},"used_percentage":22,"remaining_percentage":78},"exceeds_200k_tokens":true}
@@ -1,3 +1,3 @@
1
1
  {
2
- "lastSentAt": "2026-03-29T03:02:25.980Z"
2
+ "lastSentAt": "2026-03-31T06:00:57.605Z"
3
3
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "tool_name": "Read",
3
- "tool_input_preview": "{\"file_path\":\"/Users/lang/.claude/projects/-Users-lang-zero-cloud-app-zero-r2mo-matrix/r2mo-lain/memory/MEMORY.md\"}",
4
- "error": "File does not exist. Note: your current working directory is /Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain.",
5
- "timestamp": "2026-03-29T02:34:12.376Z",
2
+ "tool_name": "Bash",
3
+ "tool_input_preview": "{\"command\":\"cd \\\"/Users/lang/zero-cloud/app-zero/r2mo-matrix/r2mo-lain\\\" && bash ./publish.sh\",\"timeout\":600000,\"description\":\"Run publish script\"}",
4
+ "error": "Exit code 1\n\u001b[31m❌ 错误: 请提供 Git 提交注释。\u001b[0m\n用法: ./publish.sh \"你的提交注释\"",
5
+ "timestamp": "2026-03-31T06:00:09.540Z",
6
6
  "retry_count": 1
7
7
  }
@@ -0,0 +1,79 @@
1
+ {
2
+ "updatedAt": "2026-03-31T05:44:18.340Z",
3
+ "missions": [
4
+ {
5
+ "id": "session:5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5:none",
6
+ "source": "session",
7
+ "name": "none",
8
+ "objective": "Session mission",
9
+ "createdAt": "2026-03-31T05:42:36.170Z",
10
+ "updatedAt": "2026-03-31T05:44:18.340Z",
11
+ "status": "done",
12
+ "workerCount": 2,
13
+ "taskCounts": {
14
+ "total": 2,
15
+ "pending": 0,
16
+ "blocked": 0,
17
+ "inProgress": 0,
18
+ "completed": 2,
19
+ "failed": 0
20
+ },
21
+ "agents": [
22
+ {
23
+ "name": "everything-claude-code:typescript-reviewer:a299be7",
24
+ "role": "everything-claude-code:typescript-reviewer",
25
+ "ownership": "a299be7cc4b858917",
26
+ "status": "done",
27
+ "currentStep": null,
28
+ "latestUpdate": "completed",
29
+ "completedSummary": null,
30
+ "updatedAt": "2026-03-31T05:44:18.340Z"
31
+ },
32
+ {
33
+ "name": "everything-claude-code:code-reviewer:afff8f9",
34
+ "role": "everything-claude-code:code-reviewer",
35
+ "ownership": "afff8f900d18e2fc9",
36
+ "status": "done",
37
+ "currentStep": null,
38
+ "latestUpdate": "completed",
39
+ "completedSummary": null,
40
+ "updatedAt": "2026-03-31T05:43:02.231Z"
41
+ }
42
+ ],
43
+ "timeline": [
44
+ {
45
+ "id": "session-start:a299be7cc4b858917:2026-03-31T05:42:36.170Z",
46
+ "at": "2026-03-31T05:42:36.170Z",
47
+ "kind": "update",
48
+ "agent": "everything-claude-code:typescript-reviewer:a299be7",
49
+ "detail": "started everything-claude-code:typescript-reviewer:a299be7",
50
+ "sourceKey": "session-start:a299be7cc4b858917"
51
+ },
52
+ {
53
+ "id": "session-start:afff8f900d18e2fc9:2026-03-31T05:42:36.192Z",
54
+ "at": "2026-03-31T05:42:36.192Z",
55
+ "kind": "update",
56
+ "agent": "everything-claude-code:code-reviewer:afff8f9",
57
+ "detail": "started everything-claude-code:code-reviewer:afff8f9",
58
+ "sourceKey": "session-start:afff8f900d18e2fc9"
59
+ },
60
+ {
61
+ "id": "session-stop:afff8f900d18e2fc9:2026-03-31T05:43:02.231Z",
62
+ "at": "2026-03-31T05:43:02.231Z",
63
+ "kind": "completion",
64
+ "agent": "everything-claude-code:code-reviewer:afff8f9",
65
+ "detail": "completed",
66
+ "sourceKey": "session-stop:afff8f900d18e2fc9"
67
+ },
68
+ {
69
+ "id": "session-stop:a299be7cc4b858917:2026-03-31T05:44:18.340Z",
70
+ "at": "2026-03-31T05:44:18.340Z",
71
+ "kind": "completion",
72
+ "agent": "everything-claude-code:typescript-reviewer:a299be7",
73
+ "detail": "completed",
74
+ "sourceKey": "session-stop:a299be7cc4b858917"
75
+ }
76
+ ]
77
+ }
78
+ ]
79
+ }
@@ -1,7 +1,26 @@
1
1
  {
2
- "agents": [],
3
- "total_spawned": 0,
4
- "total_completed": 0,
2
+ "agents": [
3
+ {
4
+ "agent_id": "a299be7cc4b858917",
5
+ "agent_type": "everything-claude-code:typescript-reviewer",
6
+ "started_at": "2026-03-31T05:42:36.170Z",
7
+ "parent_mode": "none",
8
+ "status": "completed",
9
+ "completed_at": "2026-03-31T05:44:18.340Z",
10
+ "duration_ms": 102170
11
+ },
12
+ {
13
+ "agent_id": "afff8f900d18e2fc9",
14
+ "agent_type": "everything-claude-code:code-reviewer",
15
+ "started_at": "2026-03-31T05:42:36.192Z",
16
+ "parent_mode": "none",
17
+ "status": "completed",
18
+ "completed_at": "2026-03-31T05:43:02.231Z",
19
+ "duration_ms": 26039
20
+ }
21
+ ],
22
+ "total_spawned": 1,
23
+ "total_completed": 2,
5
24
  "total_failed": 0,
6
- "last_updated": "2026-03-29T02:39:25.000Z"
25
+ "last_updated": "2026-03-31T05:44:18.443Z"
7
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "momo-ai",
3
- "version": "1.0.80",
3
+ "version": "1.0.81",
4
4
  "description": "Rachel Momo ( OpenSpec )",
5
5
  "main": "src/momo.js",
6
6
  "bin": {
@@ -21,32 +21,43 @@ const outString = (paths, content, sync = false) => __FX.fxContinue(!!content, (
21
21
 
22
22
  const outCopy = (data) => new Promise(function (resolve, reject) {
23
23
  const platform = os.platform();
24
- let cmd = '';
25
- let args = [];
26
-
24
+
27
25
  if (platform === 'win32') {
28
- cmd = 'clip';
26
+ // 避免 stdin/控制台代码页导致的中文乱码:
27
+ // 1) Node 侧将文本转为 UTF-8 Base64
28
+ // 2) PowerShell 侧按 UTF-8 还原后写入剪贴板
29
+ const b64 = Buffer.from(String(data), 'utf8').toString('base64');
30
+ const command = `$text = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${b64}')); Set-Clipboard -Value $text`;
31
+ const proc = require('child_process').spawn(
32
+ 'powershell.exe',
33
+ ['-NoProfile', '-NonInteractive', '-Command', command],
34
+ { env: { ...process.env } }
35
+ );
36
+ proc.on('error', function (err) { reject(err); });
37
+ proc.on('close', function (code) {
38
+ if (code === 0) resolve();
39
+ else reject(new Error(`剪贴板进程退出码: ${code}`));
40
+ });
29
41
  } else if (platform === 'darwin') {
30
- cmd = 'pbcopy';
42
+ const proc = require('child_process').spawn('pbcopy', []);
43
+ proc.on('error', function (err) { reject(err); });
44
+ proc.on('close', function (code) {
45
+ if (code === 0) resolve();
46
+ else reject(new Error(`剪贴板进程退出码: ${code}`));
47
+ });
48
+ proc.stdin.write(data);
49
+ proc.stdin.end();
31
50
  } else {
32
- // 对于Linux和其他Unix-like系统,尝试使用xclip
33
- cmd = 'xclip';
34
- args = ['-selection', 'clipboard'];
51
+ // Linux: 尝试 xclip
52
+ const proc = require('child_process').spawn('xclip', ['-selection', 'clipboard']);
53
+ proc.on('error', function (err) { reject(err); });
54
+ proc.on('close', function (code) {
55
+ if (code === 0) resolve();
56
+ else reject(new Error(`剪贴板进程退出码: ${code}`));
57
+ });
58
+ proc.stdin.write(data);
59
+ proc.stdin.end();
35
60
  }
36
-
37
- const proc = require('child_process').spawn(cmd, args);
38
- proc.on('error', function (err) {
39
- reject(err);
40
- });
41
- proc.on('close', function (code) {
42
- if (code === 0) {
43
- resolve();
44
- } else {
45
- reject(new Error(`剪贴板进程退出码: ${code}`));
46
- }
47
- });
48
- proc.stdin.write(data);
49
- proc.stdin.end();
50
61
  });
51
62
  module.exports = {
52
63
  outCopy,
@@ -197,135 +197,142 @@ const _registerVaultToObsidian = async (vaultPath) => {
197
197
  }
198
198
  };
199
199
 
200
+ /**
201
+ * 检查指定 vault 是否已注册到 Obsidian 配置
202
+ * @param {string} vaultPath vault 路径
203
+ * @returns {Promise<{registered: boolean, vaultId: string|null}>}
204
+ */
205
+ const _checkVaultRegistration = async (vaultPath) => {
206
+ const platform = os.platform();
207
+ let configPath;
208
+
209
+ if (platform === 'darwin') {
210
+ configPath = path.join(os.homedir(), 'Library/Application Support/obsidian/obsidian.json');
211
+ } else if (platform === 'win32') {
212
+ configPath = path.join(process.env.APPDATA || '', 'obsidian', 'obsidian.json');
213
+ } else {
214
+ const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
215
+ configPath = path.join(xdgConfig, 'obsidian', 'obsidian.json');
216
+ }
217
+
218
+ try {
219
+ if (!fs.existsSync(configPath)) {
220
+ return { registered: false, vaultId: null };
221
+ }
222
+
223
+ const content = await fsAsync.readFile(configPath, 'utf8');
224
+ const config = JSON.parse(content);
225
+
226
+ const entry = Object.entries(config.vaults || {}).find(
227
+ ([, vault]) => vault.path === vaultPath
228
+ );
229
+
230
+ if (entry) {
231
+ return { registered: true, vaultId: entry[0] };
232
+ }
233
+ return { registered: false, vaultId: null };
234
+ } catch {
235
+ return { registered: false, vaultId: null };
236
+ }
237
+ };
238
+
200
239
  /**
201
240
  * 使用 Obsidian 打开目录
202
- * 直接调用 Obsidian 可执行文件,传递目录路径作为参数
241
+ * 支持双模式:URI scheme(vault 已注册时)或路径启动
203
242
  * @param {string} targetDir 目标目录绝对路径
204
- * @param {string} vaultId vault ID,用于 URL scheme
243
+ * @param {string|null} vaultId Obsidian 分配的 vault ID
205
244
  * @returns {Promise<void>}
206
245
  */
207
246
  const _openWithObsidian = async (targetDir, vaultId = null) => {
208
247
  const platform = os.platform();
209
248
 
210
249
  if (platform === 'darwin') {
211
- // macOS: 优先使用 vault ID 的 URL scheme,更可靠
212
250
  if (vaultId) {
251
+ // vault 已注册:使用 URI scheme 打开/切换
213
252
  const obsidianUri = `obsidian://open?vault=${vaultId}`;
214
-
215
253
  return new Promise((resolve, reject) => {
216
- const child = spawn('open', [obsidianUri], {
217
- stdio: 'ignore'
218
- });
219
-
220
- child.on('error', (error) => {
221
- reject(new Error(`启动 Obsidian 失败: ${error.message}`));
222
- });
223
-
254
+ const child = spawn('open', [obsidianUri], { stdio: 'ignore' });
255
+ child.on('error', (error) => reject(new Error(`打开 Obsidian 失败: ${error.message}`)));
224
256
  child.on('close', (code) => {
225
- if (code === 0) {
226
- // Obsidian 时间加载
227
- setTimeout(() => resolve(), 1000);
228
- } else {
229
- reject(new Error(`启动 Obsidian 失败,退出码: ${code}`));
230
- }
257
+ if (code === 0) setTimeout(() => resolve(), 1500);
258
+ else reject(new Error(`打开 Obsidian 失败,退出码: ${code}`));
231
259
  });
232
260
  });
233
- } else {
234
- // 回退到直接调用可执行文件
235
- const obsidianBinary = '/Applications/Obsidian.app/Contents/MacOS/Obsidian';
236
-
237
- if (!fs.existsSync(obsidianBinary)) {
238
- throw new Error('找不到 Obsidian 可执行文件');
239
- }
240
-
261
+ }
262
+ // vault 未注册:直接按路径启动
263
+ return new Promise((resolve, reject) => {
264
+ const child = spawn('open', ['-a', 'Obsidian', targetDir], { stdio: 'ignore' });
265
+ child.on('error', (error) => reject(new Error(`启动 Obsidian 失败: ${error.message}`)));
266
+ child.on('close', (code) => {
267
+ if (code === 0) setTimeout(() => resolve(), 2000);
268
+ else reject(new Error(`启动 Obsidian 失败,退出码: ${code}`));
269
+ });
270
+ });
271
+ } else if (platform === 'win32') {
272
+ if (vaultId) {
273
+ const obsidianUri = `obsidian://open?vault=${vaultId}`;
241
274
  return new Promise((resolve, reject) => {
242
- const child = spawn(obsidianBinary, [targetDir], {
243
- detached: true,
244
- stdio: 'ignore'
245
- });
246
-
247
- child.on('error', (error) => {
248
- reject(new Error(`启动 Obsidian 失败: ${error.message}`));
275
+ const child = spawn('cmd', ['/c', 'start', '', obsidianUri], { stdio: 'ignore' });
276
+ child.on('error', (error) => reject(new Error(`打开 Obsidian 失败: ${error.message}`)));
277
+ child.on('close', (code) => {
278
+ if (code === 0) setTimeout(() => resolve(), 1500);
279
+ else reject(new Error(`打开 Obsidian 失败,退出码: ${code}`));
249
280
  });
250
-
251
- child.unref();
252
- setTimeout(() => resolve(), 500);
253
281
  });
254
282
  }
255
- } else if (platform === 'win32') {
256
- // Windows: 查找 Obsidian.exe 并直接打开目录
257
283
  const localAppData = process.env.LOCALAPPDATA || '';
258
284
  const programFiles = process.env.PROGRAMFILES || 'C:\\Program Files';
259
285
  const possiblePaths = [
260
286
  path.join(localAppData, 'Obsidian', 'Obsidian.exe'),
261
287
  path.join(programFiles, 'Obsidian', 'Obsidian.exe')
262
288
  ];
263
-
289
+
264
290
  const obsidianExe = possiblePaths.find(p => fs.existsSync(p));
265
- if (!obsidianExe) {
266
- throw new Error('找不到 Obsidian 可执行文件');
267
- }
268
-
291
+ if (!obsidianExe) throw new Error('找不到 Obsidian 可执行文件');
292
+
269
293
  return new Promise((resolve, reject) => {
270
- const child = spawn(obsidianExe, [targetDir], {
271
- detached: true,
272
- stdio: 'ignore'
273
- });
274
-
275
- child.on('error', (error) => {
276
- reject(new Error(`启动 Obsidian 失败: ${error.message}`));
277
- });
278
-
294
+ const child = spawn(obsidianExe, [targetDir], { detached: true, stdio: 'ignore' });
295
+ child.on('error', (error) => reject(new Error(`启动 Obsidian 失败: ${error.message}`)));
279
296
  child.unref();
280
-
281
- setTimeout(() => {
282
- resolve();
283
- }, 500);
297
+ setTimeout(() => resolve(), 2000);
284
298
  });
285
299
  } else {
286
- // Linux: 尝试直接启动 obsidian 命令
300
+ if (vaultId) {
301
+ const obsidianUri = `obsidian://open?vault=${vaultId}`;
302
+ return new Promise((resolve, reject) => {
303
+ const child = spawn('xdg-open', [obsidianUri], { stdio: 'ignore' });
304
+ child.on('error', (error) => reject(new Error(`打开 Obsidian 失败: ${error.message}`)));
305
+ child.on('close', (code) => {
306
+ if (code === 0) setTimeout(() => resolve(), 1500);
307
+ else reject(new Error(`打开 Obsidian 失败,退出码: ${code}`));
308
+ });
309
+ });
310
+ }
287
311
  const snapPath = '/snap/bin/obsidian';
288
312
  const flatpakPath = 'flatpak run md.obsidian.Obsidian';
289
313
  let obsidianCmd = 'obsidian';
290
314
  let args = [targetDir];
291
315
  let useShell = false;
292
-
293
- // 检查 snap 安装
316
+
294
317
  if (fs.existsSync(snapPath)) {
295
318
  obsidianCmd = snapPath;
296
319
  } else {
297
- // 尝试 flatpak
298
320
  try {
299
321
  execSync('flatpak list | grep -i obsidian', { stdio: 'pipe' });
300
322
  obsidianCmd = flatpakPath;
301
323
  useShell = true;
302
- args = [targetDir];
303
324
  } catch {
304
325
  // 使用默认命令
305
326
  }
306
327
  }
307
-
328
+
308
329
  return new Promise((resolve, reject) => {
309
- const spawnOptions = {
310
- detached: true,
311
- stdio: 'ignore'
312
- };
313
-
314
- if (useShell) {
315
- spawnOptions.shell = true;
316
- }
317
-
330
+ const spawnOptions = { detached: true, stdio: 'ignore' };
331
+ if (useShell) spawnOptions.shell = true;
318
332
  const child = spawn(obsidianCmd, args, spawnOptions);
319
-
320
- child.on('error', (error) => {
321
- reject(new Error(`启动 Obsidian 失败: ${error.message}`));
322
- });
323
-
333
+ child.on('error', (error) => reject(new Error(`启动 Obsidian 失败: ${error.message}`)));
324
334
  child.unref();
325
-
326
- setTimeout(() => {
327
- resolve();
328
- }, 500);
335
+ setTimeout(() => resolve(), 2000);
329
336
  });
330
337
  }
331
338
  };
@@ -474,7 +481,7 @@ const _updateGitignore = async (targetDir) => {
474
481
  }
475
482
  };
476
483
 
477
- module.exports = async (options) => {
484
+ module.exports = async (_options) => {
478
485
  try {
479
486
  // 1. 解析 -d 参数,获取目标目录
480
487
  const dirArg = parseOptional('dir', 'd');
@@ -547,25 +554,13 @@ module.exports = async (options) => {
547
554
  const isObsidianRunning = await _isObsidianProcessRunning();
548
555
 
549
556
  if (isVaultRunning) {
550
- // vault 已在运行,主动激活到前台,避免“已打开但窗口不可见”
551
- Ec.waiting('检测到 vault 已打开,正在激活 Obsidian 窗口...');
552
- try {
553
- const existingVaultId = await _registerVaultToObsidian(targetDir);
554
- await _openWithObsidian(targetDir, existingVaultId);
555
- console.log('');
556
- Ec.info(`✅ 已激活 Obsidian 窗口`);
557
- Ec.info(`💡 路径: ${targetDir.cyan}`);
558
- console.log('');
559
- process.exit(0);
560
- } catch (error) {
561
- console.log('');
562
- Ec.warn(`⚠ 激活窗口失败: ${error.message}`);
563
- Ec.warn('将继续尝试重新打开该 vault...');
564
- console.log('');
565
- }
557
+ Ec.info('✓ 当前 vault 已在运行,继续拉起目标仓库...');
566
558
  }
567
559
 
568
- // 8. 注册 vault Obsidian 配置
560
+ // 8. 检查 vault 是否已在 Obsidian 注册
561
+ const { registered, vaultId: registeredVaultId } = await _checkVaultRegistration(targetDir);
562
+
563
+ // 9. 注册 vault 到 Obsidian 配置
569
564
  Ec.waiting('正在注册 vault 到 Obsidian...');
570
565
  const vaultId = await _registerVaultToObsidian(targetDir);
571
566
  if (vaultId) {
@@ -574,41 +569,23 @@ module.exports = async (options) => {
574
569
  Ec.warn('⚠ Vault 注册失败,将尝试直接打开');
575
570
  }
576
571
 
577
- // 9. 使用 Obsidian 打开目录
578
- if (isObsidianRunning && vaultId) {
579
- // Obsidian 正在运行,使用 URL scheme 切换到该 vault(不会创建新窗口)
580
- Ec.waiting(`正在切换到 vault: ${targetDir.cyan}...`);
581
- try {
582
- await _openWithObsidian(targetDir, vaultId);
583
- console.log('');
584
- Ec.info(`✅ 已切换到该 vault`);
585
- Ec.info(`💡 提示: 使用现有 Obsidian 窗口打开`);
586
- console.log('');
587
- } catch (error) {
588
- console.log('');
589
- Ec.error(`❌ 切换失败: ${error.message}`);
590
- console.log('');
591
- Ec.warn('您可以手动在 Obsidian 中切换到该 vault');
592
- console.log('');
593
- }
594
- } else {
595
- // Obsidian 未运行,启动新实例
596
- Ec.waiting(`正在启动 Obsidian 并打开: ${targetDir.cyan}...`);
597
- try {
598
- await _openWithObsidian(targetDir, vaultId);
599
- console.log('');
600
- Ec.info(`✅ 已成功启动 Obsidian`);
601
- if (vaultId) {
602
- Ec.info(`💡 提示: 该 vault 现在会出现在 Obsidian 的本地仓库列表中`);
603
- }
604
- console.log('');
605
- } catch (error) {
606
- console.log('');
607
- Ec.error(`❌ 启动失败: ${error.message}`);
608
- console.log('');
609
- Ec.warn('您可以手动使用 Obsidian 打开该目录');
610
- console.log('');
572
+ // 10. 使用 Obsidian 打开目录
573
+ Ec.waiting(`正在打开 vault: ${targetDir.cyan}...`);
574
+ try {
575
+ const activeVaultId = registered ? registeredVaultId : null;
576
+ await _openWithObsidian(targetDir, activeVaultId);
577
+ console.log('');
578
+ Ec.info(`✅ 已成功打开 vault`);
579
+ if (!isObsidianRunning && vaultId) {
580
+ Ec.info('💡 提示: vault 现在会出现在 Obsidian 的本地仓库列表中');
611
581
  }
582
+ console.log('');
583
+ } catch (error) {
584
+ console.log('');
585
+ Ec.error(`❌ 打开失败: ${error.message}`);
586
+ console.log('');
587
+ Ec.warn('您可以手动使用 Obsidian 打开该目录');
588
+ console.log('');
612
589
  }
613
590
 
614
591
  // 短暂延迟后退出,确保进程完成
@@ -1,6 +0,0 @@
1
- {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}
2
- {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:brainstorming"}
3
- {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:test-driven-development"}
4
- {"t":0,"agent":"system","event":"skill_invoked","skill_name":"claude-mem:mem-search"}
5
- {"t":0,"agent":"a21654c","agent_type":"unknown","event":"agent_stop","success":true}
6
- {"t":0,"agent":"system","event":"skill_invoked","skill_name":"pua:pua"}