openmemory-plus 1.2.3 → 1.3.2
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/dist/index.js +501 -139
- package/package.json +1 -1
- package/templates/shared/_omp/commands/memory.md +3 -83
- package/templates/shared/_omp/workflows/memory/steps/clean.md +92 -0
- package/templates/shared/_omp/workflows/memory/steps/decay.md +82 -0
- package/templates/shared/_omp/workflows/memory/steps/graph.md +88 -0
- package/templates/shared/_omp/workflows/memory/steps/search.md +68 -0
- package/templates/shared/_omp/workflows/memory/steps/status.md +63 -0
- package/templates/shared/_omp/workflows/memory/steps/store.md +81 -0
- package/templates/shared/_omp/workflows/memory/steps/sync.md +76 -0
- package/templates/shared/_omp/workflows/memory/workflow.md +147 -0
- package/templates/augment/AGENTS.md +0 -85
- package/templates/claude/CLAUDE.md +0 -65
- package/templates/common/AGENTS.md +0 -51
- package/templates/cursor/.cursorrules +0 -81
- package/templates/gemini/gemini.md +0 -84
- package/templates/shared/_omp/commands/memory-actions/clean.md +0 -54
- package/templates/shared/_omp/commands/memory-actions/decay.md +0 -64
- package/templates/shared/_omp/commands/memory-actions/graph.md +0 -75
- package/templates/shared/_omp/commands/memory-actions/search.md +0 -38
- package/templates/shared/_omp/commands/memory-actions/status.md +0 -35
- package/templates/shared/_omp/commands/memory-actions/store.md +0 -45
- package/templates/shared/_omp/commands/memory-actions/sync.md +0 -50
package/dist/index.js
CHANGED
|
@@ -2,22 +2,152 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
6
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
7
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5
8
|
|
|
6
9
|
// src/commands/install.ts
|
|
7
10
|
import chalk from "chalk";
|
|
8
11
|
import ora from "ora";
|
|
9
12
|
import inquirer from "inquirer";
|
|
10
|
-
import {
|
|
11
|
-
import { promisify as promisify2 } from "util";
|
|
13
|
+
import { spawn as spawn2 } from "child_process";
|
|
12
14
|
import { existsSync, mkdirSync, copyFileSync, writeFileSync, readdirSync, readFileSync } from "fs";
|
|
13
15
|
import { join, dirname } from "path";
|
|
14
16
|
import { fileURLToPath } from "url";
|
|
15
17
|
|
|
16
18
|
// src/lib/detector.ts
|
|
17
|
-
import { exec } from "child_process";
|
|
18
|
-
import { promisify } from "util";
|
|
19
|
+
import { exec as exec2 } from "child_process";
|
|
20
|
+
import { promisify as promisify2 } from "util";
|
|
19
21
|
import which from "which";
|
|
22
|
+
|
|
23
|
+
// src/lib/platform.ts
|
|
24
|
+
import { exec, spawn } from "child_process";
|
|
25
|
+
import { promisify } from "util";
|
|
20
26
|
var execAsync = promisify(exec);
|
|
27
|
+
function getPlatform() {
|
|
28
|
+
const p = process.platform;
|
|
29
|
+
if (p === "darwin" || p === "linux" || p === "win32") {
|
|
30
|
+
return p;
|
|
31
|
+
}
|
|
32
|
+
return "unknown";
|
|
33
|
+
}
|
|
34
|
+
function isTTY() {
|
|
35
|
+
return process.stdout.isTTY === true && process.stdin.isTTY === true;
|
|
36
|
+
}
|
|
37
|
+
function isCI() {
|
|
38
|
+
return !!(process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.GITHUB_ACTIONS || process.env.GITLAB_CI || process.env.JENKINS_URL || process.env.TRAVIS);
|
|
39
|
+
}
|
|
40
|
+
function getOllamaInstallCommand() {
|
|
41
|
+
const platform = getPlatform();
|
|
42
|
+
switch (platform) {
|
|
43
|
+
case "darwin":
|
|
44
|
+
return { command: "brew", args: ["install", "ollama"] };
|
|
45
|
+
case "linux":
|
|
46
|
+
return {
|
|
47
|
+
command: "sh",
|
|
48
|
+
args: ["-c", "curl -fsSL https://ollama.com/install.sh | sh"],
|
|
49
|
+
manual: "curl -fsSL https://ollama.com/install.sh | sh"
|
|
50
|
+
};
|
|
51
|
+
case "win32":
|
|
52
|
+
return {
|
|
53
|
+
command: "winget",
|
|
54
|
+
args: ["install", "Ollama.Ollama"],
|
|
55
|
+
manual: "https://ollama.com/download/windows"
|
|
56
|
+
};
|
|
57
|
+
default:
|
|
58
|
+
return { command: "", args: [], manual: "https://ollama.com/download" };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function getOpenUrlCommand() {
|
|
62
|
+
const platform = getPlatform();
|
|
63
|
+
switch (platform) {
|
|
64
|
+
case "darwin":
|
|
65
|
+
return "open";
|
|
66
|
+
case "linux":
|
|
67
|
+
return "xdg-open";
|
|
68
|
+
case "win32":
|
|
69
|
+
return "start";
|
|
70
|
+
default:
|
|
71
|
+
return "open";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function safeExec(command, args, options) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const proc = spawn(command, args, {
|
|
77
|
+
...options,
|
|
78
|
+
shell: false
|
|
79
|
+
});
|
|
80
|
+
let stdout = "";
|
|
81
|
+
let stderr = "";
|
|
82
|
+
const timeoutMs = options?.timeout ?? 6e4;
|
|
83
|
+
const timer = setTimeout(() => {
|
|
84
|
+
proc.kill("SIGTERM");
|
|
85
|
+
reject(new Error(`Command timed out after ${timeoutMs}ms`));
|
|
86
|
+
}, timeoutMs);
|
|
87
|
+
proc.stdout?.on("data", (data) => {
|
|
88
|
+
stdout += data.toString();
|
|
89
|
+
});
|
|
90
|
+
proc.stderr?.on("data", (data) => {
|
|
91
|
+
stderr += data.toString();
|
|
92
|
+
});
|
|
93
|
+
proc.on("close", (code) => {
|
|
94
|
+
clearTimeout(timer);
|
|
95
|
+
resolve({ stdout, stderr, code: code ?? 0 });
|
|
96
|
+
});
|
|
97
|
+
proc.on("error", (err) => {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
reject(err);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async function waitForService(url, maxAttempts = 30, intervalMs = 1e3) {
|
|
104
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
105
|
+
try {
|
|
106
|
+
const controller = new AbortController();
|
|
107
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
108
|
+
const response = await fetch(url, { signal: controller.signal });
|
|
109
|
+
clearTimeout(timeoutId);
|
|
110
|
+
if (response.ok || response.status < 500) {
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
async function isPortInUse(port) {
|
|
120
|
+
const platform = getPlatform();
|
|
121
|
+
if (platform === "win32") {
|
|
122
|
+
try {
|
|
123
|
+
const { code, stdout } = await safeExec("netstat", ["-ano"], { timeout: 5e3 });
|
|
124
|
+
if (code === 0 && stdout.includes(`:${port}`)) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
try {
|
|
131
|
+
const { code } = await safeExec("lsof", ["-i", `:${port}`, "-t"], { timeout: 5e3 });
|
|
132
|
+
if (code === 0) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const controller = new AbortController();
|
|
140
|
+
const timeoutId = setTimeout(() => controller.abort(), 2e3);
|
|
141
|
+
await fetch(`http://localhost:${port}`, { signal: controller.signal });
|
|
142
|
+
clearTimeout(timeoutId);
|
|
143
|
+
return true;
|
|
144
|
+
} catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/lib/detector.ts
|
|
150
|
+
var execAsync2 = promisify2(exec2);
|
|
21
151
|
async function checkCommand(cmd) {
|
|
22
152
|
try {
|
|
23
153
|
return await which(cmd);
|
|
@@ -25,9 +155,10 @@ async function checkCommand(cmd) {
|
|
|
25
155
|
return null;
|
|
26
156
|
}
|
|
27
157
|
}
|
|
28
|
-
async function getVersion(cmd,
|
|
158
|
+
async function getVersion(cmd, versionArgs) {
|
|
29
159
|
try {
|
|
30
|
-
const { stdout } = await
|
|
160
|
+
const { stdout, code } = await safeExec(cmd, versionArgs);
|
|
161
|
+
if (code !== 0) return null;
|
|
31
162
|
return stdout.trim().split("\n")[0];
|
|
32
163
|
} catch {
|
|
33
164
|
return null;
|
|
@@ -38,10 +169,13 @@ async function checkDocker() {
|
|
|
38
169
|
if (!path) {
|
|
39
170
|
return { name: "Docker", installed: false, error: "\u672A\u5B89\u88C5" };
|
|
40
171
|
}
|
|
41
|
-
const version = await getVersion("docker", "--version");
|
|
172
|
+
const version = await getVersion("docker", ["--version"]);
|
|
42
173
|
try {
|
|
43
|
-
await
|
|
44
|
-
|
|
174
|
+
const { code } = await safeExec("docker", ["info"]);
|
|
175
|
+
if (code === 0) {
|
|
176
|
+
return { name: "Docker", installed: true, version: version || void 0, running: true };
|
|
177
|
+
}
|
|
178
|
+
return { name: "Docker", installed: true, version: version || void 0, running: false, error: "Docker \u5B88\u62A4\u8FDB\u7A0B\u672A\u8FD0\u884C" };
|
|
45
179
|
} catch {
|
|
46
180
|
return { name: "Docker", installed: true, version: version || void 0, running: false, error: "Docker \u5B88\u62A4\u8FDB\u7A0B\u672A\u8FD0\u884C" };
|
|
47
181
|
}
|
|
@@ -51,43 +185,58 @@ async function checkOllama() {
|
|
|
51
185
|
if (!path) {
|
|
52
186
|
return { name: "Ollama", installed: false, error: "\u672A\u5B89\u88C5" };
|
|
53
187
|
}
|
|
54
|
-
const version = await getVersion("ollama", "--version");
|
|
188
|
+
const version = await getVersion("ollama", ["--version"]);
|
|
55
189
|
try {
|
|
56
|
-
await
|
|
57
|
-
|
|
190
|
+
const response = await fetch("http://localhost:11434/api/tags");
|
|
191
|
+
if (response.ok) {
|
|
192
|
+
return { name: "Ollama", installed: true, version: version || void 0, running: true };
|
|
193
|
+
}
|
|
194
|
+
return { name: "Ollama", installed: true, version: version || void 0, running: false, error: "Ollama \u670D\u52A1\u672A\u8FD0\u884C" };
|
|
58
195
|
} catch {
|
|
59
196
|
return { name: "Ollama", installed: true, version: version || void 0, running: false, error: "Ollama \u670D\u52A1\u672A\u8FD0\u884C" };
|
|
60
197
|
}
|
|
61
198
|
}
|
|
62
199
|
async function checkQdrant() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const data = JSON.parse(stdout);
|
|
66
|
-
return { name: "Qdrant", installed: true, running: true, version: "container" };
|
|
67
|
-
} catch {
|
|
200
|
+
const portInUse = await isPortInUse(6333);
|
|
201
|
+
if (portInUse) {
|
|
68
202
|
try {
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
return { name: "Qdrant", installed: true, running:
|
|
203
|
+
const response = await fetch("http://localhost:6333/collections");
|
|
204
|
+
if (response.ok) {
|
|
205
|
+
return { name: "Qdrant", installed: true, running: true, version: "container" };
|
|
72
206
|
}
|
|
73
207
|
} catch {
|
|
208
|
+
return { name: "Qdrant", installed: false, running: false, error: "\u7AEF\u53E3 6333 \u88AB\u5176\u4ED6\u670D\u52A1\u5360\u7528" };
|
|
74
209
|
}
|
|
75
|
-
return { name: "Qdrant", installed: false, error: "\u5BB9\u5668\u672A\u521B\u5EFA" };
|
|
76
210
|
}
|
|
211
|
+
try {
|
|
212
|
+
const { stdout, code } = await safeExec("docker", ["ps", "-a", "--filter", "name=^qdrant$", "--format", "{{.Status}}"]);
|
|
213
|
+
if (code === 0 && stdout.trim()) {
|
|
214
|
+
return { name: "Qdrant", installed: true, running: false, error: "\u5BB9\u5668\u5B58\u5728\u4F46\u672A\u8FD0\u884C" };
|
|
215
|
+
}
|
|
216
|
+
} catch {
|
|
217
|
+
}
|
|
218
|
+
return { name: "Qdrant", installed: false, error: "\u5BB9\u5668\u672A\u521B\u5EFA" };
|
|
77
219
|
}
|
|
78
220
|
async function checkOpenMemory() {
|
|
79
221
|
try {
|
|
80
|
-
await
|
|
81
|
-
|
|
222
|
+
const response = await fetch("http://localhost:8765/health");
|
|
223
|
+
if (response.ok) {
|
|
224
|
+
return { name: "OpenMemory MCP", installed: true, running: true };
|
|
225
|
+
}
|
|
82
226
|
} catch {
|
|
83
|
-
return { name: "OpenMemory MCP", installed: false, running: false, error: "\u670D\u52A1\u672A\u8FD0\u884C" };
|
|
84
227
|
}
|
|
228
|
+
return { name: "OpenMemory MCP", installed: false, running: false, error: "\u6309\u9700\u542F\u52A8 (\u53EF\u9009)" };
|
|
85
229
|
}
|
|
86
230
|
async function checkBgeM3() {
|
|
87
231
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
232
|
+
const response = await fetch("http://localhost:11434/api/tags");
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
return { name: "BGE-M3", installed: false, error: "Ollama \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u68C0\u6D4B" };
|
|
235
|
+
}
|
|
236
|
+
const data = await response.json();
|
|
237
|
+
const hasModel = data.models?.some(
|
|
238
|
+
(m) => m.name === "bge-m3" || m.name === "bge-m3:latest" || m.name.startsWith("bge-m3:")
|
|
239
|
+
);
|
|
91
240
|
if (hasModel) {
|
|
92
241
|
return { name: "BGE-M3", installed: true, running: true };
|
|
93
242
|
}
|
|
@@ -111,13 +260,12 @@ function isSystemReady(status) {
|
|
|
111
260
|
}
|
|
112
261
|
|
|
113
262
|
// src/commands/install.ts
|
|
114
|
-
var execAsync2 = promisify2(exec2);
|
|
115
263
|
var IDE_CONFIGS = {
|
|
116
|
-
augment: {
|
|
117
|
-
claude: {
|
|
118
|
-
cursor: {
|
|
119
|
-
gemini: {
|
|
120
|
-
common: {
|
|
264
|
+
augment: { commandsDir: ".augment/commands", skillsDir: ".augment/skills" },
|
|
265
|
+
claude: { commandsDir: ".claude/commands", skillsDir: ".claude/skills" },
|
|
266
|
+
cursor: { commandsDir: ".cursor/commands", skillsDir: ".cursor/skills" },
|
|
267
|
+
gemini: { commandsDir: ".gemini/commands", skillsDir: ".gemini/skills" },
|
|
268
|
+
common: { commandsDir: ".agents/commands", skillsDir: ".agents/skills" }
|
|
121
269
|
};
|
|
122
270
|
var BANNER = `
|
|
123
271
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
@@ -129,82 +277,193 @@ var BANNER = `
|
|
|
129
277
|
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
130
278
|
`;
|
|
131
279
|
async function openUrl(url) {
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
280
|
+
const cmd = getOpenUrlCommand();
|
|
281
|
+
try {
|
|
282
|
+
await safeExec(cmd, [url]);
|
|
283
|
+
} catch {
|
|
284
|
+
console.log(chalk.gray(` \u8BF7\u624B\u52A8\u6253\u5F00: ${url}`));
|
|
285
|
+
}
|
|
135
286
|
}
|
|
136
287
|
async function installOllama() {
|
|
137
|
-
const
|
|
288
|
+
const platform = getPlatform();
|
|
289
|
+
const installCmd = getOllamaInstallCommand();
|
|
290
|
+
if (!installCmd.command) {
|
|
291
|
+
console.log(chalk.yellow(` \u4E0D\u652F\u6301\u7684\u5E73\u53F0: ${platform}`));
|
|
292
|
+
console.log(chalk.yellow(` \u8BF7\u624B\u52A8\u5B89\u88C5: ${installCmd.manual}`));
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const spinner = ora(`\u5B89\u88C5 Ollama (${platform})...`).start();
|
|
138
296
|
try {
|
|
139
|
-
await
|
|
297
|
+
const { code, stderr } = await safeExec(installCmd.command, installCmd.args);
|
|
298
|
+
if (code !== 0) {
|
|
299
|
+
throw new Error(stderr || "Installation failed");
|
|
300
|
+
}
|
|
140
301
|
spinner.succeed("Ollama \u5B89\u88C5\u6210\u529F");
|
|
141
302
|
return true;
|
|
142
|
-
} catch {
|
|
303
|
+
} catch (e) {
|
|
143
304
|
spinner.fail("Ollama \u5B89\u88C5\u5931\u8D25");
|
|
144
|
-
console.log(chalk.yellow(
|
|
305
|
+
console.log(chalk.yellow(` \u8BF7\u624B\u52A8\u5B89\u88C5: ${installCmd.manual || "https://ollama.com/download"}`));
|
|
306
|
+
if (e.message) {
|
|
307
|
+
console.log(chalk.gray(` \u9519\u8BEF: ${e.message}`));
|
|
308
|
+
}
|
|
145
309
|
return false;
|
|
146
310
|
}
|
|
147
311
|
}
|
|
148
312
|
async function startOllama() {
|
|
149
313
|
const spinner = ora("\u542F\u52A8 Ollama \u670D\u52A1...").start();
|
|
150
314
|
try {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
315
|
+
const proc = spawn2("ollama", ["serve"], {
|
|
316
|
+
detached: true,
|
|
317
|
+
stdio: "ignore"
|
|
318
|
+
});
|
|
319
|
+
proc.unref();
|
|
320
|
+
spinner.text = "\u7B49\u5F85 Ollama \u670D\u52A1\u5C31\u7EEA...";
|
|
321
|
+
const ready = await waitForService("http://localhost:11434/api/tags", 30, 1e3);
|
|
322
|
+
if (ready) {
|
|
323
|
+
spinner.succeed("Ollama \u670D\u52A1\u5DF2\u542F\u52A8");
|
|
324
|
+
return true;
|
|
325
|
+
} else {
|
|
326
|
+
spinner.fail("Ollama \u542F\u52A8\u8D85\u65F6");
|
|
327
|
+
console.log(chalk.yellow(" \u8BF7\u624B\u52A8\u8FD0\u884C: ollama serve"));
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
} catch (e) {
|
|
156
331
|
spinner.fail("Ollama \u542F\u52A8\u5931\u8D25");
|
|
332
|
+
console.log(chalk.gray(` \u9519\u8BEF: ${e.message || "\u672A\u77E5\u9519\u8BEF"}`));
|
|
157
333
|
return false;
|
|
158
334
|
}
|
|
159
335
|
}
|
|
160
336
|
async function pullBgeM3() {
|
|
161
|
-
const spinner = ora("\u4E0B\u8F7D BGE-M3 \u6A21\u578B (\u53EF\u80FD\u9700\u8981\
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
337
|
+
const spinner = ora("\u4E0B\u8F7D BGE-M3 \u6A21\u578B (\u7EA6 1.2GB\uFF0C\u53EF\u80FD\u9700\u8981 5-10 \u5206\u949F)...").start();
|
|
338
|
+
return new Promise((resolve) => {
|
|
339
|
+
const proc = spawn2("ollama", ["pull", "bge-m3"], {
|
|
340
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
341
|
+
});
|
|
342
|
+
let lastProgress = "";
|
|
343
|
+
proc.stdout?.on("data", (data) => {
|
|
344
|
+
const line = data.toString().trim();
|
|
345
|
+
if (line && line !== lastProgress) {
|
|
346
|
+
lastProgress = line;
|
|
347
|
+
spinner.text = `\u4E0B\u8F7D BGE-M3: ${line}`;
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
proc.stderr?.on("data", (data) => {
|
|
351
|
+
const line = data.toString().trim();
|
|
352
|
+
if (line) {
|
|
353
|
+
spinner.text = `\u4E0B\u8F7D BGE-M3: ${line}`;
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
let killed = false;
|
|
357
|
+
const timeout = setTimeout(() => {
|
|
358
|
+
killed = true;
|
|
359
|
+
proc.kill("SIGTERM");
|
|
360
|
+
setTimeout(() => {
|
|
361
|
+
if (!proc.killed) {
|
|
362
|
+
proc.kill("SIGKILL");
|
|
363
|
+
}
|
|
364
|
+
}, 5e3);
|
|
365
|
+
spinner.fail("BGE-M3 \u4E0B\u8F7D\u8D85\u65F6 (30\u5206\u949F)");
|
|
366
|
+
console.log(chalk.yellow(" \u8BF7\u624B\u52A8\u8FD0\u884C: ollama pull bge-m3"));
|
|
367
|
+
resolve(false);
|
|
368
|
+
}, 30 * 60 * 1e3);
|
|
369
|
+
proc.on("close", (code) => {
|
|
370
|
+
clearTimeout(timeout);
|
|
371
|
+
if (code === 0) {
|
|
372
|
+
spinner.succeed("BGE-M3 \u6A21\u578B\u5DF2\u4E0B\u8F7D");
|
|
373
|
+
resolve(true);
|
|
374
|
+
} else {
|
|
375
|
+
spinner.fail("BGE-M3 \u4E0B\u8F7D\u5931\u8D25");
|
|
376
|
+
console.log(chalk.yellow(" \u8BF7\u624B\u52A8\u8FD0\u884C: ollama pull bge-m3"));
|
|
377
|
+
resolve(false);
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
proc.on("error", (err) => {
|
|
381
|
+
clearTimeout(timeout);
|
|
382
|
+
spinner.fail("BGE-M3 \u4E0B\u8F7D\u5931\u8D25");
|
|
383
|
+
console.log(chalk.gray(` \u9519\u8BEF: ${err.message}`));
|
|
384
|
+
resolve(false);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
170
387
|
}
|
|
171
388
|
async function startQdrant() {
|
|
172
389
|
const spinner = ora("\u542F\u52A8 Qdrant \u5BB9\u5668...").start();
|
|
390
|
+
const portInUse = await isPortInUse(6333);
|
|
391
|
+
if (portInUse) {
|
|
392
|
+
try {
|
|
393
|
+
const response = await fetch("http://localhost:6333/collections");
|
|
394
|
+
if (response.ok) {
|
|
395
|
+
spinner.succeed("Qdrant \u5DF2\u5728\u8FD0\u884C");
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
} catch {
|
|
399
|
+
}
|
|
400
|
+
spinner.fail("\u7AEF\u53E3 6333 \u5DF2\u88AB\u5176\u4ED6\u670D\u52A1\u5360\u7528");
|
|
401
|
+
console.log(chalk.yellow(" \u8BF7\u91CA\u653E\u7AEF\u53E3 6333 \u6216\u4F7F\u7528\u5176\u4ED6\u7AEF\u53E3"));
|
|
402
|
+
return false;
|
|
403
|
+
}
|
|
173
404
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (e.message?.includes("already in use") || e.message?.includes("Conflict")) {
|
|
179
|
-
try {
|
|
180
|
-
await execAsync2("docker start qdrant");
|
|
405
|
+
const { code } = await safeExec("docker", ["start", "qdrant"]);
|
|
406
|
+
if (code === 0) {
|
|
407
|
+
const ready = await waitForService("http://localhost:6333/collections", 30, 1e3);
|
|
408
|
+
if (ready) {
|
|
181
409
|
spinner.succeed("Qdrant \u5BB9\u5668\u5DF2\u542F\u52A8");
|
|
182
410
|
return true;
|
|
183
|
-
} catch {
|
|
184
411
|
}
|
|
185
412
|
}
|
|
413
|
+
} catch {
|
|
414
|
+
}
|
|
415
|
+
try {
|
|
416
|
+
const { code, stderr } = await safeExec("docker", [
|
|
417
|
+
"run",
|
|
418
|
+
"-d",
|
|
419
|
+
"--name",
|
|
420
|
+
"qdrant",
|
|
421
|
+
"-p",
|
|
422
|
+
"6333:6333",
|
|
423
|
+
"-p",
|
|
424
|
+
"6334:6334",
|
|
425
|
+
"qdrant/qdrant"
|
|
426
|
+
]);
|
|
427
|
+
if (code !== 0) {
|
|
428
|
+
throw new Error(stderr || "Failed to create container");
|
|
429
|
+
}
|
|
430
|
+
const ready = await waitForService("http://localhost:6333/collections", 30, 1e3);
|
|
431
|
+
if (ready) {
|
|
432
|
+
spinner.succeed("Qdrant \u5BB9\u5668\u5DF2\u542F\u52A8");
|
|
433
|
+
return true;
|
|
434
|
+
} else {
|
|
435
|
+
spinner.fail("Qdrant \u542F\u52A8\u8D85\u65F6");
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
} catch (e) {
|
|
186
439
|
spinner.fail("Qdrant \u542F\u52A8\u5931\u8D25");
|
|
440
|
+
console.log(chalk.gray(` \u9519\u8BEF: ${e.message || "\u672A\u77E5\u9519\u8BEF"}`));
|
|
441
|
+
console.log(chalk.yellow(" \u8BF7\u786E\u4FDD Docker \u6B63\u5728\u8FD0\u884C"));
|
|
187
442
|
return false;
|
|
188
443
|
}
|
|
189
444
|
}
|
|
190
445
|
function getTemplatesDir() {
|
|
191
|
-
const
|
|
446
|
+
const __dirname2 = dirname(fileURLToPath(import.meta.url));
|
|
192
447
|
const possiblePaths = [
|
|
193
|
-
join(
|
|
194
|
-
join(
|
|
195
|
-
join(
|
|
448
|
+
join(__dirname2, "..", "templates"),
|
|
449
|
+
join(__dirname2, "..", "..", "templates"),
|
|
450
|
+
join(__dirname2, "..", "..", "..", "templates")
|
|
196
451
|
];
|
|
197
452
|
for (const p of possiblePaths) {
|
|
198
453
|
if (existsSync(join(p, "shared"))) {
|
|
199
454
|
return p;
|
|
200
455
|
}
|
|
201
456
|
}
|
|
202
|
-
|
|
457
|
+
throw new Error(
|
|
458
|
+
`\u6A21\u677F\u76EE\u5F55\u672A\u627E\u5230\u3002\u5DF2\u68C0\u67E5\u8DEF\u5F84:
|
|
459
|
+
${possiblePaths.map((p) => ` - ${p}`).join("\n")}
|
|
460
|
+
\u8BF7\u786E\u4FDD openmemory-plus \u5305\u5B89\u88C5\u5B8C\u6574\u3002`
|
|
461
|
+
);
|
|
203
462
|
}
|
|
204
|
-
function copyDir(src, dest) {
|
|
463
|
+
function copyDir(src, dest, errors = []) {
|
|
205
464
|
if (!existsSync(src)) {
|
|
206
|
-
|
|
207
|
-
return;
|
|
465
|
+
errors.push(`\u6E90\u76EE\u5F55\u4E0D\u5B58\u5728: ${src}`);
|
|
466
|
+
return errors;
|
|
208
467
|
}
|
|
209
468
|
mkdirSync(dest, { recursive: true });
|
|
210
469
|
for (const file of readdirSync(src, { withFileTypes: true })) {
|
|
@@ -212,14 +471,15 @@ function copyDir(src, dest) {
|
|
|
212
471
|
const destPath = join(dest, file.name);
|
|
213
472
|
try {
|
|
214
473
|
if (file.isDirectory()) {
|
|
215
|
-
copyDir(srcPath, destPath);
|
|
474
|
+
copyDir(srcPath, destPath, errors);
|
|
216
475
|
} else {
|
|
217
476
|
copyFileSync(srcPath, destPath);
|
|
218
477
|
}
|
|
219
478
|
} catch (err) {
|
|
220
|
-
|
|
479
|
+
errors.push(`\u590D\u5236\u5931\u8D25 ${srcPath}: ${err.message || "\u672A\u77E5\u9519\u8BEF"}`);
|
|
221
480
|
}
|
|
222
481
|
}
|
|
482
|
+
return errors;
|
|
223
483
|
}
|
|
224
484
|
function generateProjectYaml(projectName) {
|
|
225
485
|
return `# OpenMemory Plus Project Configuration
|
|
@@ -261,14 +521,16 @@ function processTemplate(content, projectName) {
|
|
|
261
521
|
}
|
|
262
522
|
function showMcpConfig(ide) {
|
|
263
523
|
console.log(chalk.bold("\n\u{1F4CB} MCP \u914D\u7F6E (\u590D\u5236\u5230 IDE \u914D\u7F6E\u6587\u4EF6):"));
|
|
524
|
+
console.log(chalk.gray("\n\u{1F4A1} \u4F7F\u7528\u672C\u5730 Ollama + BGE-M3\uFF0C\u65E0\u9700 OpenAI API Key\n"));
|
|
264
525
|
const mcpConfig = {
|
|
265
526
|
openmemory: {
|
|
266
527
|
command: "npx",
|
|
267
528
|
args: ["-y", "openmemory-mcp"],
|
|
268
529
|
env: {
|
|
269
|
-
|
|
530
|
+
// Fix Issue #7: Remove misleading OPENAI_API_KEY
|
|
270
531
|
MEM0_EMBEDDING_MODEL: "bge-m3",
|
|
271
532
|
MEM0_EMBEDDING_PROVIDER: "ollama",
|
|
533
|
+
OLLAMA_HOST: "http://localhost:11434",
|
|
272
534
|
QDRANT_HOST: "localhost",
|
|
273
535
|
QDRANT_PORT: "6333"
|
|
274
536
|
}
|
|
@@ -284,17 +546,26 @@ function showMcpConfig(ide) {
|
|
|
284
546
|
gemini: "~/.config/gemini/mcp.json",
|
|
285
547
|
common: "\u53C2\u8003\u5404 IDE \u7684 MCP \u914D\u7F6E\u6587\u6863"
|
|
286
548
|
};
|
|
287
|
-
console.log(chalk.gray(`\u914D\u7F6E\u6587\u4EF6\u4F4D\u7F6E: ${configPaths[ide] || configPaths.common}
|
|
288
|
-
|
|
549
|
+
console.log(chalk.gray(`\u914D\u7F6E\u6587\u4EF6\u4F4D\u7F6E: ${configPaths[ide] || configPaths.common}`));
|
|
550
|
+
console.log(chalk.gray("\n\u{1F4D6} \u8BE6\u7EC6\u914D\u7F6E\u8BF4\u660E: https://github.com/mem0ai/mem0/tree/main/openmemory\n"));
|
|
289
551
|
}
|
|
290
552
|
async function phase1_checkAndInstallDeps(options) {
|
|
291
553
|
console.log(chalk.bold.cyan("\n\u2501\u2501\u2501 \u7B2C 1 \u6B65: \u68C0\u6D4B\u7CFB\u7EDF\u4F9D\u8D56 \u2501\u2501\u2501\n"));
|
|
554
|
+
const inCI = isCI();
|
|
555
|
+
const hasTTY = isTTY();
|
|
556
|
+
if (inCI) {
|
|
557
|
+
console.log(chalk.gray("\u68C0\u6D4B\u5230 CI/CD \u73AF\u5883\uFF0C\u4F7F\u7528\u975E\u4EA4\u4E92\u6A21\u5F0F\n"));
|
|
558
|
+
}
|
|
292
559
|
const spinner = ora("\u68C0\u6D4B\u7CFB\u7EDF\u72B6\u6001...").start();
|
|
293
560
|
const status = await checkAllDependencies();
|
|
294
561
|
spinner.stop();
|
|
295
562
|
console.log(chalk.bold("\u5F53\u524D\u72B6\u6001:"));
|
|
296
|
-
console.log(
|
|
297
|
-
|
|
563
|
+
console.log(
|
|
564
|
+
` \u{1F433} Docker: ${status.docker.installed ? status.docker.running ? chalk.green("\u2713 \u8FD0\u884C\u4E2D") : chalk.yellow("\u26A0 \u5DF2\u5B89\u88C5\u672A\u8FD0\u884C") : chalk.red("\u2717 \u672A\u5B89\u88C5")}`
|
|
565
|
+
);
|
|
566
|
+
console.log(
|
|
567
|
+
` \u{1F999} Ollama: ${status.ollama.installed ? status.ollama.running ? chalk.green("\u2713 \u8FD0\u884C\u4E2D") : chalk.yellow("\u26A0 \u5DF2\u5B89\u88C5\u672A\u8FD0\u884C") : chalk.red("\u2717 \u672A\u5B89\u88C5")}`
|
|
568
|
+
);
|
|
298
569
|
console.log(` \u{1F4E6} Qdrant: ${status.qdrant.running ? chalk.green("\u2713 \u8FD0\u884C\u4E2D") : chalk.red("\u2717 \u672A\u8FD0\u884C")}`);
|
|
299
570
|
console.log(` \u{1F524} BGE-M3: ${status.bgeM3.installed ? chalk.green("\u2713 \u5DF2\u5B89\u88C5") : chalk.red("\u2717 \u672A\u5B89\u88C5")}`);
|
|
300
571
|
console.log("");
|
|
@@ -306,13 +577,20 @@ async function phase1_checkAndInstallDeps(options) {
|
|
|
306
577
|
console.log(chalk.yellow("\u26A0\uFE0F \u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5 (--skip-deps)\n"));
|
|
307
578
|
return true;
|
|
308
579
|
}
|
|
580
|
+
if (inCI || !hasTTY) {
|
|
581
|
+
console.log(chalk.yellow("\u26A0\uFE0F \u975E\u4EA4\u4E92\u73AF\u5883\uFF0C\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5"));
|
|
582
|
+
console.log(chalk.gray(" \u8BF7\u5728\u4EA4\u4E92\u5F0F\u7EC8\u7AEF\u4E2D\u8FD0\u884C\uFF0C\u6216\u4F7F\u7528 --skip-deps \u8DF3\u8FC7\n"));
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
309
585
|
if (!options.yes) {
|
|
310
|
-
const { confirm } = await inquirer.prompt([
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
586
|
+
const { confirm } = await inquirer.prompt([
|
|
587
|
+
{
|
|
588
|
+
type: "confirm",
|
|
589
|
+
name: "confirm",
|
|
590
|
+
message: "\u9700\u8981\u5B89\u88C5/\u542F\u52A8\u7F3A\u5931\u7684\u4F9D\u8D56\uFF0C\u662F\u5426\u7EE7\u7EED?",
|
|
591
|
+
default: true
|
|
592
|
+
}
|
|
593
|
+
]);
|
|
316
594
|
if (!confirm) {
|
|
317
595
|
console.log(chalk.yellow("\n\u5DF2\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5\uFF0C\u7EE7\u7EED\u9879\u76EE\u914D\u7F6E...\n"));
|
|
318
596
|
return true;
|
|
@@ -321,13 +599,15 @@ async function phase1_checkAndInstallDeps(options) {
|
|
|
321
599
|
if (!status.docker.installed) {
|
|
322
600
|
console.log(chalk.yellow("\n\u{1F4E6} Docker \u9700\u8981\u624B\u52A8\u5B89\u88C5"));
|
|
323
601
|
console.log(chalk.gray(" \u8BF7\u8BBF\u95EE https://docker.com/download \u4E0B\u8F7D\u5B89\u88C5"));
|
|
324
|
-
if (!options.yes) {
|
|
325
|
-
const { openDocker } = await inquirer.prompt([
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
602
|
+
if (!options.yes && hasTTY) {
|
|
603
|
+
const { openDocker } = await inquirer.prompt([
|
|
604
|
+
{
|
|
605
|
+
type: "confirm",
|
|
606
|
+
name: "openDocker",
|
|
607
|
+
message: "\u662F\u5426\u6253\u5F00 Docker \u4E0B\u8F7D\u9875\u9762?",
|
|
608
|
+
default: true
|
|
609
|
+
}
|
|
610
|
+
]);
|
|
331
611
|
if (openDocker) await openUrl("https://docker.com/download");
|
|
332
612
|
await inquirer.prompt([{ type: "input", name: "wait", message: "\u5B89\u88C5\u5B8C\u6210\u540E\u6309 Enter \u7EE7\u7EED..." }]);
|
|
333
613
|
}
|
|
@@ -349,43 +629,102 @@ async function phase1_checkAndInstallDeps(options) {
|
|
|
349
629
|
}
|
|
350
630
|
async function phase2_initProject(options) {
|
|
351
631
|
console.log(chalk.bold.cyan("\n\u2501\u2501\u2501 \u7B2C 2 \u6B65: \u914D\u7F6E\u9879\u76EE \u2501\u2501\u2501\n"));
|
|
352
|
-
let ide = options.ide?.toLowerCase();
|
|
353
|
-
if (!ide || !IDE_CONFIGS[ide]) {
|
|
354
|
-
const { selectedIde } = await inquirer.prompt([{
|
|
355
|
-
type: "list",
|
|
356
|
-
name: "selectedIde",
|
|
357
|
-
message: "\u9009\u62E9 IDE \u7C7B\u578B:",
|
|
358
|
-
choices: [
|
|
359
|
-
{ name: "Augment", value: "augment" },
|
|
360
|
-
{ name: "Claude Code", value: "claude" },
|
|
361
|
-
{ name: "Cursor", value: "cursor" },
|
|
362
|
-
{ name: "Gemini", value: "gemini" },
|
|
363
|
-
{ name: "\u901A\u7528 (AGENTS.md)", value: "common" }
|
|
364
|
-
],
|
|
365
|
-
default: "augment"
|
|
366
|
-
}]);
|
|
367
|
-
ide = selectedIde;
|
|
368
|
-
}
|
|
369
632
|
const cwd = process.cwd();
|
|
633
|
+
const ompDir = join(cwd, "_omp");
|
|
634
|
+
let shouldForce = options.force ?? false;
|
|
635
|
+
if (existsSync(ompDir) && !shouldForce) {
|
|
636
|
+
console.log(chalk.yellow("\u26A0\uFE0F \u68C0\u6D4B\u5230\u5DF2\u5B58\u5728\u7684 _omp/ \u76EE\u5F55"));
|
|
637
|
+
if (!isTTY() || isCI()) {
|
|
638
|
+
console.log(chalk.gray(" \u4F7F\u7528 --force \u5F3A\u5236\u8986\u76D6\uFF0C\u6216\u624B\u52A8\u5220\u9664 _omp/ \u76EE\u5F55"));
|
|
639
|
+
console.log(chalk.yellow("\n\u8DF3\u8FC7\u9879\u76EE\u914D\u7F6E\uFF0C\u4FDD\u7559\u73B0\u6709\u914D\u7F6E\n"));
|
|
640
|
+
return options.ide?.toLowerCase() || "augment";
|
|
641
|
+
}
|
|
642
|
+
if (!options.yes) {
|
|
643
|
+
const { action } = await inquirer.prompt([
|
|
644
|
+
{
|
|
645
|
+
type: "list",
|
|
646
|
+
name: "action",
|
|
647
|
+
message: "\u5982\u4F55\u5904\u7406\u73B0\u6709\u914D\u7F6E?",
|
|
648
|
+
choices: [
|
|
649
|
+
{ name: "\u4FDD\u7559\u73B0\u6709\u914D\u7F6E (\u8DF3\u8FC7)", value: "skip" },
|
|
650
|
+
{ name: "\u8986\u76D6\u73B0\u6709\u914D\u7F6E", value: "overwrite" },
|
|
651
|
+
{ name: "\u4EC5\u66F4\u65B0 commands \u548C skills", value: "update" }
|
|
652
|
+
],
|
|
653
|
+
default: "skip"
|
|
654
|
+
}
|
|
655
|
+
]);
|
|
656
|
+
if (action === "skip") {
|
|
657
|
+
console.log(chalk.yellow("\n\u4FDD\u7559\u73B0\u6709\u914D\u7F6E\n"));
|
|
658
|
+
return options.ide?.toLowerCase() || "augment";
|
|
659
|
+
}
|
|
660
|
+
if (action === "update") {
|
|
661
|
+
shouldForce = false;
|
|
662
|
+
} else {
|
|
663
|
+
shouldForce = true;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
let selectedIdes = [];
|
|
668
|
+
if (options.ide) {
|
|
669
|
+
const requestedIdes = options.ide.toLowerCase().split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
670
|
+
const validIdes = requestedIdes.filter((s) => IDE_CONFIGS[s]);
|
|
671
|
+
const invalidIdes = requestedIdes.filter((s) => !IDE_CONFIGS[s]);
|
|
672
|
+
if (invalidIdes.length > 0) {
|
|
673
|
+
console.log(chalk.yellow(` \u26A0 \u672A\u77E5\u7684 IDE: ${invalidIdes.join(", ")}`));
|
|
674
|
+
console.log(chalk.gray(` \u6709\u6548\u9009\u9879: ${Object.keys(IDE_CONFIGS).join(", ")}`));
|
|
675
|
+
}
|
|
676
|
+
selectedIdes = validIdes;
|
|
677
|
+
}
|
|
678
|
+
if (selectedIdes.length === 0) {
|
|
679
|
+
if (!isTTY() || isCI()) {
|
|
680
|
+
selectedIdes = ["augment"];
|
|
681
|
+
console.log(chalk.gray(` \u4F7F\u7528\u9ED8\u8BA4 IDE: augment`));
|
|
682
|
+
} else {
|
|
683
|
+
const { ides } = await inquirer.prompt([
|
|
684
|
+
{
|
|
685
|
+
type: "checkbox",
|
|
686
|
+
name: "ides",
|
|
687
|
+
message: "\u9009\u62E9 IDE \u7C7B\u578B (\u7A7A\u683C\u9009\u62E9\uFF0C\u56DE\u8F66\u786E\u8BA4):",
|
|
688
|
+
choices: [
|
|
689
|
+
{ name: "Augment", value: "augment", checked: true },
|
|
690
|
+
{ name: "Claude Code", value: "claude" },
|
|
691
|
+
{ name: "Cursor", value: "cursor" },
|
|
692
|
+
{ name: "Gemini", value: "gemini" },
|
|
693
|
+
{ name: "\u901A\u7528 (AGENTS.md)", value: "common" }
|
|
694
|
+
]
|
|
695
|
+
}
|
|
696
|
+
]);
|
|
697
|
+
selectedIdes = ides.length > 0 ? ides : ["augment"];
|
|
698
|
+
}
|
|
699
|
+
}
|
|
370
700
|
const defaultName = cwd.split("/").pop() || "my-project";
|
|
371
701
|
let projectName = defaultName;
|
|
372
|
-
if (!options.yes) {
|
|
373
|
-
const { name } = await inquirer.prompt([
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
702
|
+
if (!options.yes && isTTY() && !isCI()) {
|
|
703
|
+
const { name } = await inquirer.prompt([
|
|
704
|
+
{
|
|
705
|
+
type: "input",
|
|
706
|
+
name: "name",
|
|
707
|
+
message: "\u9879\u76EE\u540D\u79F0:",
|
|
708
|
+
default: defaultName
|
|
709
|
+
}
|
|
710
|
+
]);
|
|
379
711
|
projectName = name;
|
|
380
712
|
}
|
|
381
|
-
const config = IDE_CONFIGS[ide];
|
|
382
713
|
console.log(chalk.bold("\n\u{1F4C1} \u521B\u5EFA\u914D\u7F6E\u6587\u4EF6...\n"));
|
|
383
|
-
|
|
714
|
+
let templatesDir;
|
|
715
|
+
try {
|
|
716
|
+
templatesDir = getTemplatesDir();
|
|
717
|
+
} catch (e) {
|
|
718
|
+
console.error(chalk.red("\u274C " + e.message));
|
|
719
|
+
process.exit(1);
|
|
720
|
+
}
|
|
384
721
|
const ompTemplates = join(templatesDir, "shared", "_omp");
|
|
385
|
-
const ideTemplates = join(templatesDir, ide === "common" ? "common" : ide);
|
|
386
|
-
const ompDir = join(cwd, "_omp");
|
|
387
722
|
mkdirSync(ompDir, { recursive: true });
|
|
388
|
-
copyDir(ompTemplates, ompDir);
|
|
723
|
+
const copyErrors = copyDir(ompTemplates, ompDir);
|
|
724
|
+
if (copyErrors.length > 0) {
|
|
725
|
+
console.log(chalk.yellow(" \u26A0 \u90E8\u5206\u6587\u4EF6\u590D\u5236\u5931\u8D25:"));
|
|
726
|
+
copyErrors.forEach((err) => console.log(chalk.gray(` - ${err}`)));
|
|
727
|
+
}
|
|
389
728
|
console.log(chalk.green(" \u2713 \u521B\u5EFA _omp/ (\u6838\u5FC3\u76EE\u5F55)"));
|
|
390
729
|
const ompMemoryDir = join(ompDir, ".memory");
|
|
391
730
|
mkdirSync(ompMemoryDir, { recursive: true });
|
|
@@ -393,31 +732,38 @@ async function phase2_initProject(options) {
|
|
|
393
732
|
const memoryFiles = readdirSync(ompMemoryDir);
|
|
394
733
|
for (const file of memoryFiles) {
|
|
395
734
|
const filePath = join(ompMemoryDir, file);
|
|
396
|
-
|
|
397
|
-
|
|
735
|
+
try {
|
|
736
|
+
const content = readFileSync(filePath, "utf-8");
|
|
737
|
+
writeFileSync(filePath, processTemplate(content, projectName));
|
|
738
|
+
} catch (e) {
|
|
739
|
+
console.log(chalk.yellow(` \u26A0 \u5904\u7406\u6A21\u677F\u5931\u8D25: ${file} - ${e.message}`));
|
|
740
|
+
}
|
|
398
741
|
}
|
|
399
742
|
}
|
|
400
743
|
const projectYaml = join(ompMemoryDir, "project.yaml");
|
|
401
744
|
writeFileSync(projectYaml, generateProjectYaml(projectName));
|
|
402
745
|
console.log(chalk.green(" \u2713 \u521B\u5EFA _omp/.memory/project.yaml"));
|
|
403
746
|
const commandsCount = existsSync(join(ompDir, "commands")) ? readdirSync(join(ompDir, "commands")).filter((f) => f.endsWith(".md")).length : 0;
|
|
404
|
-
const
|
|
405
|
-
console.log(chalk.green(` \u2713 \u521B\u5EFA _omp/commands/ (${commandsCount} \u547D\u4EE4
|
|
747
|
+
const workflowStepsCount = existsSync(join(ompDir, "workflows", "memory", "steps")) ? readdirSync(join(ompDir, "workflows", "memory", "steps")).length : 0;
|
|
748
|
+
console.log(chalk.green(` \u2713 \u521B\u5EFA _omp/commands/ (${commandsCount} \u547D\u4EE4)`));
|
|
749
|
+
console.log(chalk.green(` \u2713 \u521B\u5EFA _omp/workflows/ (${workflowStepsCount} \u6B65\u9AA4)`));
|
|
406
750
|
console.log(chalk.green(" \u2713 \u521B\u5EFA _omp/skills/ (memory-extraction)"));
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
751
|
+
for (const ide of selectedIdes) {
|
|
752
|
+
const config = IDE_CONFIGS[ide];
|
|
753
|
+
if (!config) continue;
|
|
754
|
+
const ideCommandsDir = join(cwd, config.commandsDir);
|
|
755
|
+
mkdirSync(ideCommandsDir, { recursive: true });
|
|
756
|
+
copyDir(join(ompDir, "commands"), ideCommandsDir);
|
|
757
|
+
const ideSkillsDir = join(cwd, config.skillsDir);
|
|
758
|
+
mkdirSync(ideSkillsDir, { recursive: true });
|
|
759
|
+
copyDir(join(ompDir, "skills"), ideSkillsDir);
|
|
760
|
+
console.log(chalk.green(` \u2713 \u914D\u7F6E ${ide} (${config.commandsDir}/)`));
|
|
761
|
+
}
|
|
762
|
+
if (selectedIdes.length > 1) {
|
|
763
|
+
console.log(chalk.green(`
|
|
764
|
+
\u2713 \u5DF2\u4E3A ${selectedIdes.length} \u4E2A IDE \u914D\u7F6E\u5B8C\u6210: ${selectedIdes.join(", ")}`));
|
|
765
|
+
}
|
|
766
|
+
return selectedIdes[0];
|
|
421
767
|
}
|
|
422
768
|
function phase3_showCompletion(ide, showMcp) {
|
|
423
769
|
console.log(chalk.bold.cyan("\n\u2501\u2501\u2501 \u5B89\u88C5\u5B8C\u6210 \u2501\u2501\u2501\n"));
|
|
@@ -631,9 +977,25 @@ async function doctorCommand(options) {
|
|
|
631
977
|
}
|
|
632
978
|
|
|
633
979
|
// src/index.ts
|
|
980
|
+
var __dirname = dirname2(fileURLToPath2(import.meta.url));
|
|
981
|
+
function getVersion2() {
|
|
982
|
+
const possiblePaths = [
|
|
983
|
+
join2(__dirname, "..", "package.json"),
|
|
984
|
+
join2(__dirname, "..", "..", "package.json")
|
|
985
|
+
];
|
|
986
|
+
for (const p of possiblePaths) {
|
|
987
|
+
try {
|
|
988
|
+
const pkg = JSON.parse(readFileSync2(p, "utf-8"));
|
|
989
|
+
return pkg.version || "0.0.0";
|
|
990
|
+
} catch {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
return "0.0.0";
|
|
995
|
+
}
|
|
634
996
|
var program = new Command();
|
|
635
|
-
program.name("openmemory-plus").description("\u{1F9E0} Agent Memory Management - \u8BA9\u4EFB\u4F55 AI Agent \u83B7\u5F97\u6301\u4E45\u8BB0\u5FC6\u80FD\u529B").version(
|
|
636
|
-
program.command("install", { isDefault: true }).description("\u4E00\u952E\u5B89\u88C5\u548C\u914D\u7F6E OpenMemory Plus (\u63A8\u8350)").option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4\u63D0\u793A").option("-i, --ide <type>", "IDE \u7C7B\u578B: augment, claude, cursor, gemini, common").option("--skip-deps", "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5\uFF0C\u4EC5\u914D\u7F6E\u9879\u76EE").option("--show-mcp", "\u663E\u793A MCP \u914D\u7F6E").action(installCommand);
|
|
997
|
+
program.name("openmemory-plus").description("\u{1F9E0} Agent Memory Management - \u8BA9\u4EFB\u4F55 AI Agent \u83B7\u5F97\u6301\u4E45\u8BB0\u5FC6\u80FD\u529B").version(getVersion2());
|
|
998
|
+
program.command("install", { isDefault: true }).description("\u4E00\u952E\u5B89\u88C5\u548C\u914D\u7F6E OpenMemory Plus (\u63A8\u8350)").option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4\u63D0\u793A").option("-i, --ide <type>", "IDE \u7C7B\u578B: augment, claude, cursor, gemini, common").option("--skip-deps", "\u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5\uFF0C\u4EC5\u914D\u7F6E\u9879\u76EE").option("--show-mcp", "\u663E\u793A MCP \u914D\u7F6E").option("-f, --force", "\u5F3A\u5236\u8986\u76D6\u5DF2\u5B58\u5728\u7684\u914D\u7F6E\u6587\u4EF6").action(installCommand);
|
|
637
999
|
program.command("status").description("\u68C0\u67E5\u7CFB\u7EDF\u72B6\u6001").action(statusCommand);
|
|
638
1000
|
program.command("doctor").description("\u8BCA\u65AD\u5E76\u4FEE\u590D\u95EE\u9898").option("--fix", "\u81EA\u52A8\u4FEE\u590D\u95EE\u9898").action(doctorCommand);
|
|
639
1001
|
program.parse();
|