@mingxy/cerebro 1.10.6 → 1.10.8
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/cerebro.example.jsonc +71 -0
- package/dist/client.d.ts +2 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +14 -15
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +30 -11
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +101 -46
- package/dist/config.js.map +1 -1
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +86 -47
- package/dist/hooks.js.map +1 -1
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +4 -4
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +42 -23
- package/dist/logger.js.map +1 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +1 -1
- package/dist/tools.js.map +1 -1
- package/package.json +47 -47
- package/src/client.ts +13 -14
- package/src/config.ts +207 -104
- package/src/hooks.ts +69 -42
- package/src/index.ts +13 -13
- package/src/logger.ts +65 -65
- package/src/tools.ts +3 -3
- package/omem.example.jsonc +0 -22
package/src/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { join, dirname } from "node:path";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
6
|
+
import { CerebroClient } from "./client.js";
|
|
7
7
|
import { autoRecallHook, compactingHook, keywordDetectionHook, sessionIdleHook } from "./hooks.js";
|
|
8
8
|
import { getUserTag, getProjectTag } from "./tags.js";
|
|
9
9
|
import { buildTools } from "./tools.js";
|
|
@@ -74,24 +74,24 @@ const OmemPlugin: Plugin = async (input) => {
|
|
|
74
74
|
let overrides: Record<string, unknown> = {};
|
|
75
75
|
try {
|
|
76
76
|
const ocCfg = JSON.parse(readFileSync(join(directory, "opencode.json"), "utf-8"));
|
|
77
|
-
const pc = ocCfg?.plugin_config?.["@mingxy/
|
|
77
|
+
const pc = ocCfg?.plugin_config?.["@mingxy/cerebro"];
|
|
78
78
|
if (pc) overrides = pc;
|
|
79
79
|
} catch {}
|
|
80
80
|
|
|
81
81
|
const config = loadPluginConfig(overrides as any);
|
|
82
82
|
|
|
83
|
-
const
|
|
83
|
+
const cerebroClient = new CerebroClient(config.connection.apiUrl, config.connection.apiKey, config);
|
|
84
84
|
|
|
85
85
|
// 启动时检测连接状态
|
|
86
86
|
try {
|
|
87
|
-
await
|
|
87
|
+
await cerebroClient.getStats();
|
|
88
88
|
showToast(tui, "🧠 Cerebro · Connected", `Version v${pluginVersion}`, "success", 6000);
|
|
89
|
-
logInfo(`Connected to ${config.apiUrl}`);
|
|
89
|
+
logInfo(`Connected to ${config.connection.apiUrl}`);
|
|
90
90
|
} catch (err) {
|
|
91
91
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
92
92
|
logError(`Connection failed: ${errMsg}`);
|
|
93
|
-
if (errMsg.includes("[
|
|
94
|
-
const cleanMsg = errMsg.replace(/^\[
|
|
93
|
+
if (errMsg.includes("[cerebro]")) {
|
|
94
|
+
const cleanMsg = errMsg.replace(/^\[cerebro\]\s*/, "");
|
|
95
95
|
showToast(
|
|
96
96
|
tui,
|
|
97
97
|
`🧠 Cerebro v${pluginVersion} · Server Error`,
|
|
@@ -103,7 +103,7 @@ const OmemPlugin: Plugin = async (input) => {
|
|
|
103
103
|
showToast(
|
|
104
104
|
tui,
|
|
105
105
|
`🧠 Cerebro v${pluginVersion} · Connection Failed`,
|
|
106
|
-
`Unable to reach ${config.apiUrl}`,
|
|
106
|
+
`Unable to reach ${config.connection.apiUrl}`,
|
|
107
107
|
"error",
|
|
108
108
|
8000
|
|
109
109
|
);
|
|
@@ -117,7 +117,7 @@ const OmemPlugin: Plugin = async (input) => {
|
|
|
117
117
|
|
|
118
118
|
let currentSessionId: string | undefined;
|
|
119
119
|
|
|
120
|
-
const recallHook = autoRecallHook(
|
|
120
|
+
const recallHook = autoRecallHook(cerebroClient, containerTags, tui, config);
|
|
121
121
|
|
|
122
122
|
return {
|
|
123
123
|
config: async (cfg: any) => {
|
|
@@ -131,10 +131,10 @@ const OmemPlugin: Plugin = async (input) => {
|
|
|
131
131
|
if (input.sessionID) currentSessionId = input.sessionID;
|
|
132
132
|
return recallHook(input, output);
|
|
133
133
|
},
|
|
134
|
-
"chat.message": keywordDetectionHook(
|
|
135
|
-
"experimental.session.compacting": compactingHook(
|
|
136
|
-
tool: buildTools(
|
|
137
|
-
event: sessionIdleHook(
|
|
134
|
+
"chat.message": keywordDetectionHook(cerebroClient, containerTags, config.ingest.autoCaptureThreshold, tui, config.ingest.ingestMode, config, agentId),
|
|
135
|
+
"experimental.session.compacting": compactingHook(cerebroClient, containerTags, tui, config.ingest.ingestMode, isAutoStoreEnabled, () => currentSessionId, client, config, agentId),
|
|
136
|
+
tool: buildTools(cerebroClient, containerTags, { agentId, getSessionId: () => currentSessionId }),
|
|
137
|
+
event: sessionIdleHook(cerebroClient, containerTags, tui, client, config.ingest.ingestMode, config.ingest.autoCaptureThreshold, () => currentSessionId, isAutoStoreEnabled, agentId, config),
|
|
138
138
|
"shell.env": async (_input: any, output: any) => {
|
|
139
139
|
if (directory) {
|
|
140
140
|
output.env.OMEM_PROJECT_DIR = directory;
|
package/src/logger.ts
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
import { appendFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { loadPluginConfig } from "./config.js";
|
|
4
|
-
|
|
5
|
-
const LEVEL_MAP: Record<string, number> = {
|
|
6
|
-
DEBUG: 0,
|
|
7
|
-
INFO: 1,
|
|
8
|
-
WARN: 2,
|
|
9
|
-
ERROR: 3,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const cfg = loadPluginConfig();
|
|
13
|
-
const MIN_LEVEL = LEVEL_MAP[cfg.logLevel] ?? LEVEL_MAP.INFO;
|
|
14
|
-
const LOG_DIR = cfg.logDir;
|
|
15
|
-
const LOG_FILE = join(LOG_DIR, "plugin.log");
|
|
16
|
-
const LOG_ENABLED = cfg.logEnabled;
|
|
17
|
-
|
|
18
|
-
let lastLogTime = Date.now();
|
|
19
|
-
|
|
20
|
-
function ensureLogDir(): void {
|
|
21
|
-
if (!existsSync(LOG_DIR)) {
|
|
22
|
-
try {
|
|
23
|
-
mkdirSync(LOG_DIR, { recursive: true });
|
|
24
|
-
} catch {}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeLog(level: string, message: string, fields?: Record<string, unknown>): void {
|
|
29
|
-
if (!LOG_ENABLED) return;
|
|
30
|
-
const lvl = LEVEL_MAP[level] ?? 0;
|
|
31
|
-
if (lvl < MIN_LEVEL) return;
|
|
32
|
-
ensureLogDir();
|
|
33
|
-
const now = new Date();
|
|
34
|
-
const nowMs = now.getTime();
|
|
35
|
-
const delta = ((nowMs - lastLogTime) / 1000).toFixed(2);
|
|
36
|
-
lastLogTime = nowMs;
|
|
37
|
-
const ts = now.toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
|
|
38
|
-
const parts = [`${level.padEnd(5)} ${ts} +${delta}s service=cerebro`];
|
|
39
|
-
if (fields) {
|
|
40
|
-
for (const [k, v] of Object.entries(fields)) {
|
|
41
|
-
const val = typeof v === "string" ? v : JSON.stringify(v);
|
|
42
|
-
parts.push(`${k}=${val}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
parts.push(message);
|
|
46
|
-
try {
|
|
47
|
-
appendFileSync(LOG_FILE, parts.join(" ") + "\n");
|
|
48
|
-
} catch {}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function logInfo(message: string, fields?: Record<string, unknown>): void {
|
|
52
|
-
writeLog("INFO", message, fields);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function logWarn(message: string, fields?: Record<string, unknown>): void {
|
|
56
|
-
writeLog("WARN", message, fields);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function logError(message: string, fields?: Record<string, unknown>): void {
|
|
60
|
-
writeLog("ERROR", message, fields);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function logDebug(message: string, fields?: Record<string, unknown>): void {
|
|
64
|
-
writeLog("DEBUG", message, fields);
|
|
65
|
-
}
|
|
1
|
+
import { appendFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { loadPluginConfig } from "./config.js";
|
|
4
|
+
|
|
5
|
+
const LEVEL_MAP: Record<string, number> = {
|
|
6
|
+
DEBUG: 0,
|
|
7
|
+
INFO: 1,
|
|
8
|
+
WARN: 2,
|
|
9
|
+
ERROR: 3,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const cfg = loadPluginConfig();
|
|
13
|
+
const MIN_LEVEL = LEVEL_MAP[cfg.logging.logLevel] ?? LEVEL_MAP.INFO;
|
|
14
|
+
const LOG_DIR = cfg.logging.logDir;
|
|
15
|
+
const LOG_FILE = join(LOG_DIR, "plugin.log");
|
|
16
|
+
const LOG_ENABLED = cfg.logging.logEnabled;
|
|
17
|
+
|
|
18
|
+
let lastLogTime = Date.now();
|
|
19
|
+
|
|
20
|
+
function ensureLogDir(): void {
|
|
21
|
+
if (!existsSync(LOG_DIR)) {
|
|
22
|
+
try {
|
|
23
|
+
mkdirSync(LOG_DIR, { recursive: true });
|
|
24
|
+
} catch {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function writeLog(level: string, message: string, fields?: Record<string, unknown>): void {
|
|
29
|
+
if (!LOG_ENABLED) return;
|
|
30
|
+
const lvl = LEVEL_MAP[level] ?? 0;
|
|
31
|
+
if (lvl < MIN_LEVEL) return;
|
|
32
|
+
ensureLogDir();
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const nowMs = now.getTime();
|
|
35
|
+
const delta = ((nowMs - lastLogTime) / 1000).toFixed(2);
|
|
36
|
+
lastLogTime = nowMs;
|
|
37
|
+
const ts = now.toISOString().replace("T", " ").replace(/\.\d+Z$/, "");
|
|
38
|
+
const parts = [`${level.padEnd(5)} ${ts} +${delta}s service=cerebro`];
|
|
39
|
+
if (fields) {
|
|
40
|
+
for (const [k, v] of Object.entries(fields)) {
|
|
41
|
+
const val = typeof v === "string" ? v : JSON.stringify(v);
|
|
42
|
+
parts.push(`${k}=${val}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
parts.push(message);
|
|
46
|
+
try {
|
|
47
|
+
appendFileSync(LOG_FILE, parts.join(" ") + "\n");
|
|
48
|
+
} catch {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function logInfo(message: string, fields?: Record<string, unknown>): void {
|
|
52
|
+
writeLog("INFO", message, fields);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function logWarn(message: string, fields?: Record<string, unknown>): void {
|
|
56
|
+
writeLog("WARN", message, fields);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function logError(message: string, fields?: Record<string, unknown>): void {
|
|
60
|
+
writeLog("ERROR", message, fields);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function logDebug(message: string, fields?: Record<string, unknown>): void {
|
|
64
|
+
writeLog("DEBUG", message, fields);
|
|
65
|
+
}
|
package/src/tools.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin";
|
|
2
|
-
import type {
|
|
2
|
+
import type { CerebroClient } from "./client.js";
|
|
3
3
|
import { isAutoStoreEnabled, setAutoStoreEnabled } from "./index.js";
|
|
4
4
|
|
|
5
5
|
function extractMemoryIds(result: unknown): string[] {
|
|
@@ -26,7 +26,7 @@ export interface ToolContext {
|
|
|
26
26
|
getSessionId: () => string | undefined;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export function buildTools(client:
|
|
29
|
+
export function buildTools(client: CerebroClient, containerTags: string[], context: ToolContext) {
|
|
30
30
|
return {
|
|
31
31
|
memory_store: tool({
|
|
32
32
|
description:
|
|
@@ -95,7 +95,7 @@ export function buildTools(client: OmemClient, containerTags: string[], context:
|
|
|
95
95
|
args.visibility,
|
|
96
96
|
args.category,
|
|
97
97
|
);
|
|
98
|
-
if (!result) return JSON.stringify({ ok: false, error: "The
|
|
98
|
+
if (!result) return JSON.stringify({ ok: false, error: "The Cerebro server may be unavailable." });
|
|
99
99
|
return JSON.stringify({ ok: true, id: result.id, tags: result.tags });
|
|
100
100
|
},
|
|
101
101
|
}),
|
package/omem.example.jsonc
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"apiUrl": "https://www.mengxy.cc",
|
|
3
|
-
"apiKey": "your-tenant-id",
|
|
4
|
-
|
|
5
|
-
"requestTimeoutMs": 15000,
|
|
6
|
-
|
|
7
|
-
"maxQueryLength": 200,
|
|
8
|
-
"maxContentChars": 30000,
|
|
9
|
-
"maxContentLength": 500,
|
|
10
|
-
|
|
11
|
-
"autoCaptureThreshold": 5,
|
|
12
|
-
"ingestMode": "smart",
|
|
13
|
-
|
|
14
|
-
"similarityThreshold": 0.4,
|
|
15
|
-
"maxRecallResults": 10,
|
|
16
|
-
|
|
17
|
-
"toastDelayMs": 7000,
|
|
18
|
-
|
|
19
|
-
"logEnabled": true,
|
|
20
|
-
"logLevel": "INFO",
|
|
21
|
-
"logDir": "~/.config/cerebro"
|
|
22
|
-
}
|