oh-memos-mcp 1.0.0

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.
Files changed (41) hide show
  1. package/.env.example +27 -0
  2. package/README.md +71 -0
  3. package/dist/api-client.d.ts +22 -0
  4. package/dist/api-client.js +127 -0
  5. package/dist/config.d.ts +30 -0
  6. package/dist/config.js +163 -0
  7. package/dist/cube-manager.d.ts +16 -0
  8. package/dist/cube-manager.js +357 -0
  9. package/dist/formatters.d.ts +16 -0
  10. package/dist/formatters.js +174 -0
  11. package/dist/handlers/admin.d.ts +13 -0
  12. package/dist/handlers/admin.js +331 -0
  13. package/dist/handlers/calendar.d.ts +8 -0
  14. package/dist/handlers/calendar.js +281 -0
  15. package/dist/handlers/graph.d.ts +11 -0
  16. package/dist/handlers/graph.js +502 -0
  17. package/dist/handlers/index.d.ts +7 -0
  18. package/dist/handlers/index.js +71 -0
  19. package/dist/handlers/memory.d.ts +12 -0
  20. package/dist/handlers/memory.js +270 -0
  21. package/dist/handlers/search.d.ts +11 -0
  22. package/dist/handlers/search.js +334 -0
  23. package/dist/handlers/utils.d.ts +22 -0
  24. package/dist/handlers/utils.js +75 -0
  25. package/dist/index.d.ts +13 -0
  26. package/dist/index.js +18 -0
  27. package/dist/keyword-enhancer.d.ts +18 -0
  28. package/dist/keyword-enhancer.js +335 -0
  29. package/dist/memory-analysis.d.ts +7 -0
  30. package/dist/memory-analysis.js +45 -0
  31. package/dist/models.d.ts +21 -0
  32. package/dist/models.js +101 -0
  33. package/dist/query-processing.d.ts +20 -0
  34. package/dist/query-processing.js +265 -0
  35. package/dist/server.d.ts +5 -0
  36. package/dist/server.js +114 -0
  37. package/dist/tools-registry.d.ts +303 -0
  38. package/dist/tools-registry.js +369 -0
  39. package/dist/types.d.ts +118 -0
  40. package/dist/types.js +5 -0
  41. package/package.json +53 -0
@@ -0,0 +1,357 @@
1
+ /**
2
+ * MemOS MCP Server Cube Management Module
3
+ *
4
+ * Handles cube discovery, config, and registration.
5
+ */
6
+ import * as fs from "fs";
7
+ import * as path from "path";
8
+ import { MEMOS_URL, MEMOS_USER, MEMOS_DEFAULT_CUBE, MEMOS_CUBES_DIR, MEMOS_TIMEOUT_STARTUP, REGISTRATION_RETRY_INTERVAL, registeredCubes, lastRegistrationAttempt, logger, isDefaultCubeFromEnv, } from "./config.js";
9
+ import { detectCubeFromPath } from "./keyword-enhancer.js";
10
+ import { fetchWithTimeout } from "./api-client.js";
11
+ // ============================================================================
12
+ // Windows/WSL Path Conversion
13
+ // ============================================================================
14
+ /**
15
+ * Convert Windows path to WSL/Linux path for local file access.
16
+ * e.g. "G:\\test\\MemOS\\data" → "/mnt/g/test/MemOS/data"
17
+ */
18
+ function toLocalPath(p) {
19
+ // Already a Unix path
20
+ if (p.startsWith("/"))
21
+ return p;
22
+ // Windows absolute path: "G:\..." or "G:/..."
23
+ const winMatch = p.match(/^([A-Za-z]):[/\\](.*)/);
24
+ if (winMatch) {
25
+ const drive = winMatch[1].toLowerCase();
26
+ const rest = winMatch[2].replace(/\\/g, "/");
27
+ return `/mnt/${drive}/${rest}`;
28
+ }
29
+ return p;
30
+ }
31
+ // ============================================================================
32
+ // Cube Discovery
33
+ // ============================================================================
34
+ export function getCubesBaseDir() {
35
+ const cubesDir = MEMOS_CUBES_DIR;
36
+ if (cubesDir.endsWith(MEMOS_DEFAULT_CUBE)) {
37
+ return path.dirname(cubesDir);
38
+ }
39
+ return cubesDir;
40
+ }
41
+ export function getLocalCubesBaseDir() {
42
+ return toLocalPath(getCubesBaseDir());
43
+ }
44
+ export function listAvailableCubes() {
45
+ const available = [];
46
+ const cubesDirLocal = getLocalCubesBaseDir();
47
+ if (!fs.existsSync(cubesDirLocal) || !fs.statSync(cubesDirLocal).isDirectory()) {
48
+ logger.warning(`Cubes directory does not exist: ${cubesDirLocal}`);
49
+ return available;
50
+ }
51
+ try {
52
+ const items = fs.readdirSync(cubesDirLocal);
53
+ for (const item of items) {
54
+ const itemPath = path.join(cubesDirLocal, item);
55
+ const configPath = path.join(itemPath, "config.json");
56
+ if (fs.existsSync(itemPath) &&
57
+ fs.statSync(itemPath).isDirectory() &&
58
+ fs.existsSync(configPath)) {
59
+ available.push({ id: item, path: itemPath });
60
+ }
61
+ }
62
+ }
63
+ catch (err) {
64
+ logger.warning(`Error scanning cubes directory: ${err}`);
65
+ }
66
+ return available;
67
+ }
68
+ export function getCubePath(cubeId) {
69
+ const localBase = getLocalCubesBaseDir();
70
+ let cubePath;
71
+ if (cubeId === MEMOS_DEFAULT_CUBE) {
72
+ const cubesDirLocal = toLocalPath(MEMOS_CUBES_DIR);
73
+ if (cubesDirLocal.endsWith(MEMOS_DEFAULT_CUBE)) {
74
+ cubePath = cubesDirLocal;
75
+ }
76
+ else {
77
+ cubePath = path.join(cubesDirLocal, MEMOS_DEFAULT_CUBE);
78
+ }
79
+ }
80
+ else {
81
+ cubePath = path.join(localBase, cubeId);
82
+ }
83
+ const configPath = path.join(cubePath, "config.json");
84
+ if (fs.existsSync(cubePath) && fs.statSync(cubePath).isDirectory() && fs.existsSync(configPath)) {
85
+ return cubePath;
86
+ }
87
+ return null;
88
+ }
89
+ /**
90
+ * Get the original (possibly Windows) path for the cube, for API registration.
91
+ * The API runs on Windows, so it needs the Windows path.
92
+ */
93
+ function getCubeApiPath(cubeId) {
94
+ const localPath = getCubePath(cubeId);
95
+ if (!localPath)
96
+ return null;
97
+ // Convert back to Windows path if MEMOS_CUBES_DIR is a Windows path
98
+ const cubesDir = MEMOS_CUBES_DIR;
99
+ const isWindowsPath = /^[A-Za-z]:/.test(cubesDir);
100
+ if (isWindowsPath) {
101
+ // Local path is /mnt/g/... → G:\...
102
+ const match = localPath.match(/^\/mnt\/([a-z])\/(.*)/);
103
+ if (match) {
104
+ const drive = match[1].toUpperCase();
105
+ const rest = match[2].replace(/\//g, "\\");
106
+ return `${drive}:\\${rest}`;
107
+ }
108
+ }
109
+ return localPath;
110
+ }
111
+ // ============================================================================
112
+ // Cube Configuration
113
+ // ============================================================================
114
+ function cloneConfig(config) {
115
+ return JSON.parse(JSON.stringify(config));
116
+ }
117
+ function updateConfigForCube(config, cubeId) {
118
+ config.user_id = MEMOS_USER;
119
+ config.cube_id = cubeId;
120
+ config.config_filename = "config.json";
121
+ const textMem = config.text_mem;
122
+ if (typeof textMem === "object" && textMem !== null) {
123
+ const textCfg = textMem.config;
124
+ if (typeof textCfg === "object" && textCfg !== null) {
125
+ const tc = textCfg;
126
+ if ("cube_id" in tc)
127
+ tc.cube_id = cubeId;
128
+ const graphDb = tc.graph_db;
129
+ if (typeof graphDb === "object" && graphDb !== null) {
130
+ const graphCfg = graphDb.config;
131
+ if (typeof graphCfg === "object" && graphCfg !== null) {
132
+ const gc = graphCfg;
133
+ const useMultiDb = gc.use_multi_db;
134
+ if (useMultiDb === false || "user_name" in gc) {
135
+ gc.user_name = cubeId;
136
+ }
137
+ const vecCfg = typeof gc.vec_config === "object" && gc.vec_config !== null
138
+ ? gc.vec_config.config
139
+ : null;
140
+ if (vecCfg && typeof vecCfg === "object" && "collection_name" in vecCfg) {
141
+ vecCfg.collection_name = `${cubeId}_graph`;
142
+ }
143
+ }
144
+ }
145
+ const vectorDb = tc.vector_db;
146
+ if (typeof vectorDb === "object" && vectorDb !== null) {
147
+ const vectorCfg = vectorDb.config;
148
+ if (typeof vectorCfg === "object" && vectorCfg !== null && "collection_name" in vectorCfg) {
149
+ vectorCfg.collection_name = `${cubeId}_collection`;
150
+ }
151
+ }
152
+ }
153
+ }
154
+ return config;
155
+ }
156
+ function buildCubeConfig(cubeId) {
157
+ const templatePath = getCubePath(MEMOS_DEFAULT_CUBE);
158
+ if (templatePath !== null) {
159
+ const configPath = path.join(templatePath, "config.json");
160
+ try {
161
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
162
+ const cloned = cloneConfig(config);
163
+ return updateConfigForCube(cloned, cubeId);
164
+ }
165
+ catch (err) {
166
+ logger.warning(`Failed to read template cube config: ${err}`);
167
+ }
168
+ }
169
+ // Minimal fallback config (will likely fail API registration without proper fields)
170
+ return {
171
+ user_id: MEMOS_USER,
172
+ cube_id: cubeId,
173
+ config_filename: "config.json",
174
+ text_mem: {},
175
+ act_mem: {},
176
+ para_mem: {},
177
+ };
178
+ }
179
+ export function validateAndFixCubeConfig(cubeId, configPath) {
180
+ try {
181
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
182
+ let modified = false;
183
+ if (config.cube_id !== cubeId) {
184
+ config.cube_id = cubeId;
185
+ modified = true;
186
+ }
187
+ const textMem = config.text_mem;
188
+ if (typeof textMem === "object" && textMem !== null) {
189
+ const textCfg = textMem.config;
190
+ if (typeof textCfg === "object" && textCfg !== null) {
191
+ const tc = textCfg;
192
+ if (tc.cube_id !== cubeId) {
193
+ tc.cube_id = cubeId;
194
+ modified = true;
195
+ }
196
+ const graphDb = tc.graph_db;
197
+ if (typeof graphDb === "object" && graphDb !== null) {
198
+ const graphCfg = graphDb.config;
199
+ if (typeof graphCfg === "object" && graphCfg !== null) {
200
+ const gc = graphCfg;
201
+ if (gc.user_name && gc.user_name !== cubeId) {
202
+ gc.user_name = cubeId;
203
+ modified = true;
204
+ }
205
+ const vecCfg = typeof gc.vec_config === "object" && gc.vec_config !== null
206
+ ? gc.vec_config.config
207
+ : null;
208
+ if (vecCfg && typeof vecCfg === "object" && "collection_name" in vecCfg) {
209
+ const expected = `${cubeId}_graph`;
210
+ if (vecCfg.collection_name !== expected) {
211
+ vecCfg.collection_name = expected;
212
+ modified = true;
213
+ }
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ if (modified) {
220
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
221
+ }
222
+ return [modified, null];
223
+ }
224
+ catch (err) {
225
+ return [false, `Failed to validate cube config: ${err}`];
226
+ }
227
+ }
228
+ export function ensureCubeDirectory(cubeId) {
229
+ const localBase = getLocalCubesBaseDir();
230
+ try {
231
+ fs.mkdirSync(localBase, { recursive: true });
232
+ const cubeDir = path.join(localBase, cubeId);
233
+ const configPath = path.join(cubeDir, "config.json");
234
+ if (fs.existsSync(cubeDir) && fs.existsSync(configPath)) {
235
+ validateAndFixCubeConfig(cubeId, configPath);
236
+ return [cubeDir, null];
237
+ }
238
+ fs.mkdirSync(cubeDir, { recursive: true });
239
+ const config = buildCubeConfig(cubeId);
240
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
241
+ return [cubeDir, null];
242
+ }
243
+ catch (err) {
244
+ return [null, `Failed to create cube '${cubeId}': ${err}`];
245
+ }
246
+ }
247
+ // ============================================================================
248
+ // Cube Registration
249
+ // ============================================================================
250
+ export async function verifyCubeLoaded(cubeId) {
251
+ try {
252
+ const response = await fetchWithTimeout(`${MEMOS_URL}/memories?user_id=${encodeURIComponent(MEMOS_USER)}&mem_cube_id=${encodeURIComponent(cubeId)}`, { method: "GET", timeoutMs: 5 });
253
+ if (response.ok) {
254
+ const data = await response.json();
255
+ return data.code === 200;
256
+ }
257
+ }
258
+ catch {
259
+ // ignore
260
+ }
261
+ return false;
262
+ }
263
+ export async function ensureCubeRegistered(cubeId, force = false) {
264
+ const now = Date.now() / 1000;
265
+ if (!force && registeredCubes.has(cubeId))
266
+ return [true, null];
267
+ if (!force) {
268
+ const lastAttempt = lastRegistrationAttempt.get(cubeId) ?? 0;
269
+ if (now - lastAttempt < REGISTRATION_RETRY_INTERVAL && registeredCubes.has(cubeId)) {
270
+ return [true, null];
271
+ }
272
+ }
273
+ lastRegistrationAttempt.set(cubeId, now);
274
+ try {
275
+ // Check if already loaded
276
+ if (await verifyCubeLoaded(cubeId)) {
277
+ registeredCubes.add(cubeId);
278
+ logger.debug(`Cube '${cubeId}' already loaded`);
279
+ return [true, null];
280
+ }
281
+ // Get or create cube path
282
+ let cubePath = getCubeApiPath(cubeId);
283
+ if (!cubePath) {
284
+ // Try to auto-create
285
+ logger.debug(`Cube '${cubeId}' not found, attempting auto-creation...`);
286
+ const templatePath = getCubePath(MEMOS_DEFAULT_CUBE);
287
+ if (!templatePath) {
288
+ const available = listAvailableCubes();
289
+ const availableIds = available.map((c) => c.id);
290
+ if (availableIds.length > 0) {
291
+ return [false, `Cube '${cubeId}' not found. Available cubes: ${availableIds.join(", ")}`];
292
+ }
293
+ return [false, `Cube '${cubeId}' not found and no cubes available.`];
294
+ }
295
+ const [newDir, createErr] = ensureCubeDirectory(cubeId);
296
+ if (!newDir) {
297
+ return [false, `Failed to auto-create cube '${cubeId}': ${createErr}`];
298
+ }
299
+ cubePath = getCubeApiPath(cubeId);
300
+ if (!cubePath) {
301
+ return [false, `Failed to get path for cube '${cubeId}' after creation`];
302
+ }
303
+ }
304
+ // Register with API
305
+ const response = await fetchWithTimeout(`${MEMOS_URL}/mem_cubes`, {
306
+ method: "POST",
307
+ headers: { "Content-Type": "application/json" },
308
+ body: JSON.stringify({
309
+ user_id: MEMOS_USER,
310
+ mem_cube_name_or_path: cubePath,
311
+ mem_cube_id: cubeId,
312
+ }),
313
+ timeoutMs: MEMOS_TIMEOUT_STARTUP,
314
+ });
315
+ if (response.ok) {
316
+ const data = await response.json();
317
+ if (data.code === 200) {
318
+ registeredCubes.add(cubeId);
319
+ logger.debug(`Auto-registered cube: ${cubeId}`);
320
+ return [true, null];
321
+ }
322
+ const msg = String(data.message ?? "Unknown error");
323
+ if (msg.toLowerCase().includes("already")) {
324
+ registeredCubes.add(cubeId);
325
+ return [true, null];
326
+ }
327
+ const available = listAvailableCubes();
328
+ const availableIds = available.map((c) => c.id);
329
+ return [false, `Failed to register cube '${cubeId}': ${msg}. Available: ${availableIds.join(", ") || "none"}`];
330
+ }
331
+ }
332
+ catch (err) {
333
+ const msg = String(err);
334
+ if (msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("ECONNRESET")) {
335
+ return [false, `Cannot connect to MemOS API at ${MEMOS_URL}. Is the server running?`];
336
+ }
337
+ return [false, `Failed to register cube '${cubeId}': ${err}`];
338
+ }
339
+ return [false, `Unknown error registering cube '${cubeId}'`];
340
+ }
341
+ // ============================================================================
342
+ // Default Cube ID
343
+ // ============================================================================
344
+ export function getDefaultCubeId() {
345
+ if (isDefaultCubeFromEnv()) {
346
+ if (getCubePath(MEMOS_DEFAULT_CUBE) !== null) {
347
+ return MEMOS_DEFAULT_CUBE;
348
+ }
349
+ }
350
+ try {
351
+ return detectCubeFromPath(process.cwd());
352
+ }
353
+ catch {
354
+ return MEMOS_DEFAULT_CUBE;
355
+ }
356
+ }
357
+ //# sourceMappingURL=cube-manager.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * MemOS MCP Server Formatters
3
+ *
4
+ * Formats memory search results and knowledge graphs for display.
5
+ */
6
+ import type { SearchData, MemoryNode, GraphEdge } from "./types.js";
7
+ export declare function formatMemoriesForDisplay(data: SearchData): string;
8
+ export interface GraphCubeData {
9
+ cube_id?: string;
10
+ memories?: Array<{
11
+ nodes?: MemoryNode[];
12
+ edges?: GraphEdge[];
13
+ }>;
14
+ }
15
+ export declare function formatGraphForDisplay(data: GraphCubeData[]): string;
16
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1,174 @@
1
+ /**
2
+ * MemOS MCP Server Formatters
3
+ *
4
+ * Formats memory search results and knowledge graphs for display.
5
+ */
6
+ // ============================================================================
7
+ // Memory Display Formatter
8
+ // ============================================================================
9
+ export function formatMemoriesForDisplay(data) {
10
+ const results = [];
11
+ const textMems = data.text_mem ?? [];
12
+ for (const cubeData of textMems) {
13
+ const cubeId = cubeData.cube_id ?? "unknown";
14
+ const memoriesData = cubeData.memories;
15
+ let memories = [];
16
+ if (memoriesData && !Array.isArray(memoriesData) && memoriesData.nodes) {
17
+ memories = memoriesData.nodes;
18
+ }
19
+ else if (Array.isArray(memoriesData)) {
20
+ memories = memoriesData;
21
+ }
22
+ if (memories.length === 0)
23
+ continue;
24
+ results.push(`## 📦 Cube: ${cubeId}`);
25
+ results.push("");
26
+ // Group by type
27
+ const grouped = {};
28
+ for (const mem of memories) {
29
+ const memText = mem.memory ?? "";
30
+ const typeMatch = memText.match(/^\[([A-Z_]+)\]/);
31
+ const memType = typeMatch ? typeMatch[1] : "PROGRESS";
32
+ if (!grouped[memType])
33
+ grouped[memType] = [];
34
+ grouped[memType].push(mem);
35
+ }
36
+ // Display by type
37
+ for (const [memType, items] of Object.entries(grouped)) {
38
+ results.push(`### 🏷️ Type: ${memType}`);
39
+ results.push("");
40
+ for (let i = 0; i < items.length; i++) {
41
+ const mem = items[i];
42
+ const memText = mem.memory ?? "";
43
+ const memId = mem.id ?? "";
44
+ // Remove [TYPE] prefix
45
+ const displayText = memText.replace(/^\[[A-Z_]+\]\s*/, "");
46
+ const firstLine = displayText.split("\n")[0].slice(0, 100);
47
+ if (displayText.split("\n").length > 1 || displayText.length > 100) {
48
+ results.push(`#### ${i + 1}. ${firstLine}`);
49
+ }
50
+ else {
51
+ results.push(`#### ${i + 1}. ${displayText}`);
52
+ }
53
+ results.push(`ID: \`${memId}\``);
54
+ results.push("");
55
+ // Detect code blocks
56
+ const hasCodeIndicator = displayText.split("\n").some((line) => /^(import |def |class |export |const |let |var )/.test(line.trim()));
57
+ if (!displayText.includes("```") && hasCodeIndicator) {
58
+ results.push("```python");
59
+ results.push(displayText);
60
+ results.push("```");
61
+ }
62
+ else {
63
+ results.push(displayText);
64
+ }
65
+ results.push("");
66
+ results.push("---");
67
+ results.push("");
68
+ }
69
+ }
70
+ }
71
+ if (results.length === 0) {
72
+ return "No memories found matching your query.";
73
+ }
74
+ return results.join("\n");
75
+ }
76
+ export function formatGraphForDisplay(data) {
77
+ const results = [];
78
+ for (const cubeData of data) {
79
+ const cubeId = cubeData.cube_id ?? "unknown";
80
+ const memoriesList = cubeData.memories ?? [];
81
+ if (memoriesList.length === 0)
82
+ continue;
83
+ results.push(`## 🧠 Knowledge Graph: ${cubeId}`);
84
+ results.push("");
85
+ for (const memData of memoriesList) {
86
+ const nodes = memData.nodes ?? [];
87
+ const edges = memData.edges ?? [];
88
+ // Build node lookup
89
+ const nodeLookup = {};
90
+ for (const node of nodes) {
91
+ const nodeId = node.id ?? "";
92
+ const nodeMemory = node.memory ?? "";
93
+ const cleanText = nodeMemory.replace(/\n/g, " ").replace(/"/g, "'").replace(/\[/g, "(").replace(/\]/g, ")");
94
+ nodeLookup[nodeId] = cleanText.length > 50 ? cleanText.slice(0, 50) + "..." : cleanText;
95
+ }
96
+ // Display nodes
97
+ if (nodes.length > 0) {
98
+ results.push("### 📝 Memory Nodes");
99
+ results.push("");
100
+ for (let i = 0; i < Math.min(nodes.length, 10); i++) {
101
+ const node = nodes[i];
102
+ const memory = node.memory ?? "";
103
+ const firstLine = memory.split("\n")[0].slice(0, 100);
104
+ const nodeId = node.id ?? "";
105
+ results.push(`${i + 1}. **${firstLine}**`);
106
+ results.push(` ID: \`${nodeId}\``);
107
+ results.push("");
108
+ }
109
+ }
110
+ // Display relationships with Mermaid
111
+ if (edges.length > 0) {
112
+ results.push("### 📊 Relationship Diagram (Mermaid)");
113
+ results.push("");
114
+ results.push("```mermaid");
115
+ results.push("graph TD");
116
+ results.push(" classDef cause fill:#f96,stroke:#333,stroke-width:2px;");
117
+ results.push(" classDef relate fill:#bbf,stroke:#333,stroke-width:1px;");
118
+ results.push(" classDef conflict fill:#f66,stroke:#333,stroke-width:2px,stroke-dasharray: 5 5;");
119
+ const addedEdges = new Set();
120
+ for (const edge of edges) {
121
+ const sourceId = edge.source ?? "";
122
+ const targetId = edge.target ?? "";
123
+ const relType = edge.type ?? "UNKNOWN";
124
+ if (relType === "PARENT")
125
+ continue;
126
+ const edgeKey = `${sourceId}-${targetId}-${relType}`;
127
+ if (addedEdges.has(edgeKey))
128
+ continue;
129
+ addedEdges.add(edgeKey);
130
+ const sourceText = nodeLookup[sourceId] ?? sourceId.slice(0, 8);
131
+ const targetText = nodeLookup[targetId] ?? targetId.slice(0, 8);
132
+ const sId = `node_${sourceId.slice(0, 8)}`;
133
+ const tId = `node_${targetId.slice(0, 8)}`;
134
+ if (relType === "CAUSE") {
135
+ results.push(` ${sId}["${sourceText}"] -- CAUSE --> ${tId}["${targetText}"]:::cause`);
136
+ }
137
+ else if (relType === "RELATE") {
138
+ results.push(` ${sId}["${sourceText}"] -. RELATE .- ${tId}["${targetText}"]:::relate`);
139
+ }
140
+ else if (relType === "CONFLICT") {
141
+ results.push(` ${sId}["${sourceText}"] == CONFLICT == ${tId}["${targetText}"]:::conflict`);
142
+ }
143
+ else if (relType === "CONDITION") {
144
+ results.push(` ${sId}["${sourceText}"] -- CONDITION --> ${tId}["${targetText}"]`);
145
+ }
146
+ else {
147
+ results.push(` ${sId}["${sourceText}"] -- ${relType} --> ${tId}["${targetText}"]`);
148
+ }
149
+ }
150
+ results.push("```");
151
+ results.push("");
152
+ // Textual fallback
153
+ results.push("### 🔗 Textual Relationships");
154
+ results.push("");
155
+ results.push("```");
156
+ for (const edge of edges) {
157
+ if (edge.type === "PARENT")
158
+ continue;
159
+ const sText = (nodeLookup[edge.source ?? ""] ?? "???").slice(0, 40);
160
+ const tText = (nodeLookup[edge.target ?? ""] ?? "???").slice(0, 40);
161
+ results.push(`[${sText}] --${edge.type}--> [${tText}]`);
162
+ }
163
+ results.push("```");
164
+ results.push("");
165
+ }
166
+ }
167
+ results.push("---");
168
+ }
169
+ if (results.length === 0) {
170
+ return "No memories or relationships found.";
171
+ }
172
+ return results.join("\n");
173
+ }
174
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Admin Handlers
3
+ *
4
+ * memos_list_cubes, memos_register_cube, memos_create_user,
5
+ * memos_validate_cubes, memos_delete
6
+ */
7
+ import type { TextContent } from "../types.js";
8
+ export declare function handleMemosListCubes(arguments_: Record<string, unknown>): Promise<TextContent[]>;
9
+ export declare function handleMemosRegisterCube(arguments_: Record<string, unknown>): Promise<TextContent[]>;
10
+ export declare function handleMemosCreateUser(arguments_: Record<string, unknown>): Promise<TextContent[]>;
11
+ export declare function handleMemosValidateCubes(arguments_: Record<string, unknown>): Promise<TextContent[]>;
12
+ export declare function handleMemosDelete(arguments_: Record<string, unknown>): Promise<TextContent[]>;
13
+ //# sourceMappingURL=admin.d.ts.map