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.
- package/.omc/project-memory.json +14 -56
- package/.omc/sessions/24968ee6-c99b-47be-a904-68fcce1b08ba.json +8 -0
- package/.omc/sessions/d7901fcc-6318-4bc6-ba68-81722b1a4231.json +8 -0
- package/.omc/sessions/e12400d6-5242-491c-b32a-21db817a0d61.json +8 -0
- package/.omc/state/agent-replay-5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5.jsonl +18 -0
- package/.omc/state/hud-state.json +3 -3
- package/.omc/state/hud-stdin-cache.json +1 -1
- package/.omc/state/idle-notif-cooldown.json +1 -1
- package/.omc/state/last-tool-error.json +4 -4
- package/.omc/state/mission-state.json +79 -0
- package/.omc/state/subagent-tracking.json +23 -4
- package/package.json +1 -1
- package/src/epic/momo.fn.out.js +33 -22
- package/src/executor/executeDocs.js +109 -132
- package/.omc/state/agent-replay-d7901fcc-6318-4bc6-ba68-81722b1a4231.jsonl +0 -6
package/.omc/project-memory.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0.0",
|
|
3
|
-
"lastScanned":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
78
|
-
"lastAccessed":
|
|
77
|
+
"accessCount": 40,
|
|
78
|
+
"lastAccessed": 1774936174792,
|
|
79
79
|
"type": "file"
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"path": "",
|
|
83
83
|
"accessCount": 3,
|
|
84
|
-
"lastAccessed":
|
|
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":
|
|
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/
|
|
94
|
+
"path": "src/momo.js",
|
|
131
95
|
"accessCount": 1,
|
|
132
|
-
"lastAccessed":
|
|
96
|
+
"lastAccessed": 1774934085428,
|
|
133
97
|
"type": "file"
|
|
134
98
|
},
|
|
135
99
|
{
|
|
136
|
-
"path": "src/
|
|
100
|
+
"path": "src/utils/momo-file-utils.js",
|
|
137
101
|
"accessCount": 1,
|
|
138
|
-
"lastAccessed":
|
|
102
|
+
"lastAccessed": 1774935787741,
|
|
139
103
|
"type": "file"
|
|
140
104
|
},
|
|
141
105
|
{
|
|
142
|
-
"path": "src",
|
|
106
|
+
"path": "src/utils",
|
|
143
107
|
"accessCount": 1,
|
|
144
|
-
"lastAccessed":
|
|
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,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-
|
|
2
|
+
"timestamp": "2026-03-31T04:04:05.113Z",
|
|
3
3
|
"backgroundTasks": [],
|
|
4
|
-
"sessionStartTimestamp": "2026-03-
|
|
5
|
-
"sessionId": "
|
|
4
|
+
"sessionStartTimestamp": "2026-03-31T04:03:44.223Z",
|
|
5
|
+
"sessionId": "5d9bfa71-77e1-47e9-b3af-8ff9e2d70ce5"
|
|
6
6
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"session_id":"
|
|
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,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"tool_name": "
|
|
3
|
-
"tool_input_preview": "{\"
|
|
4
|
-
"error": "
|
|
5
|
-
"timestamp": "2026-03-
|
|
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
|
-
|
|
4
|
-
|
|
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-
|
|
25
|
+
"last_updated": "2026-03-31T05:44:18.443Z"
|
|
7
26
|
}
|
package/package.json
CHANGED
package/src/epic/momo.fn.out.js
CHANGED
|
@@ -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
|
-
|
|
25
|
-
let args = [];
|
|
26
|
-
|
|
24
|
+
|
|
27
25
|
if (platform === 'win32') {
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
*
|
|
241
|
+
* 支持双模式:URI scheme(vault 已注册时)或路径启动
|
|
203
242
|
* @param {string} targetDir 目标目录绝对路径
|
|
204
|
-
* @param {string} vaultId vault ID
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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(
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
|
|
267
|
-
}
|
|
268
|
-
|
|
291
|
+
if (!obsidianExe) throw new Error('找不到 Obsidian 可执行文件');
|
|
292
|
+
|
|
269
293
|
return new Promise((resolve, reject) => {
|
|
270
|
-
const child = spawn(obsidianExe, [targetDir], {
|
|
271
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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.
|
|
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
|
-
//
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
Ec.info(
|
|
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"}
|