@memoryrelay/plugin-memoryrelay-ai 0.8.5 → 0.8.7

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/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * OpenClaw Memory Plugin - MemoryRelay
3
- * Version: 0.8.5 (OpenClaw Security Compliance)
3
+ * Version: 0.8.7 (OpenClaw Security Compliance)
4
4
  *
5
5
  * Long-term memory with vector search using MemoryRelay API.
6
6
  * Provides auto-recall and auto-capture via lifecycle hooks.
@@ -9,7 +9,7 @@
9
9
  * API: https://api.memoryrelay.net
10
10
  * Docs: https://memoryrelay.ai
11
11
  *
12
- * ENHANCEMENTS (v0.8.5):
12
+ * ENHANCEMENTS (v0.8.7):
13
13
  * - Removed fs.writeFile from export command (stdout only now)
14
14
  * - No filesystem operations - passes OpenClaw security validation
15
15
  * - Export usage: openclaw memoryrelay export > memories.json
@@ -863,7 +863,7 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
863
863
  const verboseEnabled = cfg?.verbose || false;
864
864
  const maxLogEntries = cfg?.maxLogEntries || 100;
865
865
 
866
- // Note: logFile is deprecated in v0.8.5 (removed for OpenClaw security compliance)
866
+ // Note: logFile is deprecated in v0.8.7 (removed for OpenClaw security compliance)
867
867
  // All debug logs are in-memory only. Use gateway methods to access logs.
868
868
 
869
869
  let debugLogger: DebugLogger | undefined;
@@ -3,7 +3,7 @@
3
3
  "kind": "memory",
4
4
  "name": "MemoryRelay AI",
5
5
  "description": "AI memory service with sessions, decisions, patterns & projects (api.memoryrelay.net)",
6
- "version": "0.8.5",
6
+ "version": "0.8.7",
7
7
  "uiHints": {
8
8
  "apiKey": {
9
9
  "label": "MemoryRelay API Key",
@@ -113,7 +113,7 @@
113
113
  },
114
114
  "logFile": {
115
115
  "type": "string",
116
- "description": "DEPRECATED (v0.8.5): File logging removed for OpenClaw security compliance. This option is ignored. Use gateway methods to access in-memory logs (coming in v0.9.0)."
116
+ "description": "DEPRECATED (v0.8.7): File logging removed for OpenClaw security compliance. This option is ignored. Use gateway methods to access in-memory logs (coming in v0.9.0)."
117
117
  },
118
118
  "maxLogEntries": {
119
119
  "type": "number",
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@memoryrelay/plugin-memoryrelay-ai",
3
- "version": "0.8.5",
3
+ "version": "0.8.7",
4
4
  "description": "OpenClaw memory plugin for MemoryRelay API - sessions, decisions, patterns, projects & semantic search",
5
5
  "type": "module",
6
6
  "main": "index.ts",
7
7
  "scripts": {
8
8
  "test": "vitest run",
9
9
  "test:watch": "vitest",
10
- "test:coverage": "vitest run --coverage",
11
- "postinstall": "node -e \"console.log('\\n⚠️ CONFIGURATION REQUIRED\\n\\nAdd config after installation:\\n\\ncat ~/.openclaw/openclaw.json | jq \\'.plugins.entries.\\\"plugin-memoryrelay-ai\\\".config = {\\\"apiKey\\\": \\\"YOUR_KEY\\\", \\\"agentId\\\": \\\"YOUR_AGENT\\\"}\\' > /tmp/config.json && mv /tmp/config.json ~/.openclaw/openclaw.json\\n\\nOr use environment variables:\\nexport MEMORYRELAY_API_KEY=\\\"mem_prod_...\\\"\\nexport MEMORYRELAY_AGENT_ID=\\\"your-agent\\\"\\n\\nThen restart: openclaw gateway restart\\n\\nGet your API key from: https://memoryrelay.ai\\n')\""
10
+ "test:coverage": "vitest run --coverage"
12
11
  },
13
12
  "keywords": [
14
13
  "openclaw",
@@ -51,7 +50,8 @@
51
50
  },
52
51
  "files": [
53
52
  "index.ts",
54
- "src/",
53
+ "src/*.ts",
54
+ "!src/*.test.ts",
55
55
  "bin/",
56
56
  "openclaw.plugin.json",
57
57
  "README.md",
@@ -1,233 +0,0 @@
1
- /**
2
- * DebugLogger Tests (Corrected)
3
- *
4
- * Tests matching actual implementation
5
- */
6
-
7
- import { describe, test, expect, beforeEach, vi } from "vitest";
8
- import { DebugLogger, type LogEntry } from "./debug-logger";
9
- import * as fs from "fs";
10
-
11
- vi.mock("fs");
12
-
13
- describe("DebugLogger", () => {
14
- let logger: DebugLogger;
15
-
16
- beforeEach(() => {
17
- vi.clearAllMocks();
18
- logger = new DebugLogger({
19
- enabled: true,
20
- verbose: false,
21
- maxEntries: 5,
22
- });
23
- });
24
-
25
- test("logs are stored when enabled", () => {
26
- logger.log({
27
- timestamp: new Date().toISOString(),
28
- tool: "memory_store",
29
- method: "POST",
30
- path: "/v1/memories",
31
- duration: 142,
32
- status: "success",
33
- });
34
-
35
- const logs = logger.getAllLogs();
36
- expect(logs).toHaveLength(1);
37
- });
38
-
39
- test("logs are not stored when disabled", () => {
40
- const disabledLogger = new DebugLogger({
41
- enabled: false,
42
- verbose: false,
43
- maxEntries: 5,
44
- });
45
-
46
- disabledLogger.log({
47
- timestamp: new Date().toISOString(),
48
- tool: "memory_store",
49
- method: "POST",
50
- path: "/v1/memories",
51
- duration: 142,
52
- status: "success",
53
- });
54
-
55
- const logs = disabledLogger.getAllLogs();
56
- expect(logs).toHaveLength(0);
57
- });
58
-
59
- test("respects circular buffer limit (FIFO)", () => {
60
- for (let i = 0; i < 10; i++) {
61
- logger.log({
62
- timestamp: new Date(Date.now() + i).toISOString(),
63
- tool: `tool_${i}`,
64
- method: "GET",
65
- path: `/test/${i}`,
66
- duration: 100,
67
- status: "success",
68
- });
69
- }
70
-
71
- const logs = logger.getAllLogs();
72
- expect(logs).toHaveLength(5); // maxEntries = 5
73
- expect(logs[0].tool).toBe("tool_5"); // Oldest kept
74
- expect(logs[4].tool).toBe("tool_9"); // Newest
75
- });
76
-
77
- test("getRecentLogs returns last N entries", () => {
78
- for (let i = 0; i < 3; i++) {
79
- logger.log({
80
- timestamp: new Date(Date.now() + i).toISOString(),
81
- tool: `tool_${i}`,
82
- method: "GET",
83
- path: `/test/${i}`,
84
- duration: 100,
85
- status: "success",
86
- });
87
- }
88
-
89
- const logs = logger.getRecentLogs(2);
90
- expect(logs).toHaveLength(2);
91
- expect(logs[0].tool).toBe("tool_1"); // Second-to-last
92
- expect(logs[1].tool).toBe("tool_2"); // Last
93
- });
94
-
95
- test("getToolLogs filters by tool name", () => {
96
- logger.log({
97
- timestamp: new Date().toISOString(),
98
- tool: "memory_store",
99
- method: "POST",
100
- path: "/v1/memories",
101
- duration: 142,
102
- status: "success",
103
- });
104
- logger.log({
105
- timestamp: new Date().toISOString(),
106
- tool: "memory_recall",
107
- method: "POST",
108
- path: "/v1/memories/search",
109
- duration: 78,
110
- status: "success",
111
- });
112
- logger.log({
113
- timestamp: new Date().toISOString(),
114
- tool: "memory_store",
115
- method: "POST",
116
- path: "/v1/memories",
117
- duration: 156,
118
- status: "error",
119
- error: "500",
120
- });
121
-
122
- const logs = logger.getToolLogs("memory_store", 10);
123
- expect(logs).toHaveLength(2);
124
- expect(logs.every(l => l.tool === "memory_store")).toBe(true);
125
- });
126
-
127
- test("getErrorLogs filters by error status", () => {
128
- logger.log({
129
- timestamp: new Date().toISOString(),
130
- tool: "memory_store",
131
- method: "POST",
132
- path: "/v1/memories",
133
- duration: 142,
134
- status: "success",
135
- });
136
- logger.log({
137
- timestamp: new Date().toISOString(),
138
- tool: "memory_recall",
139
- method: "POST",
140
- path: "/v1/memories/search",
141
- duration: 78,
142
- status: "error",
143
- error: "404",
144
- });
145
-
146
- const logs = logger.getErrorLogs(10);
147
- expect(logs).toHaveLength(1);
148
- expect(logs[0].status).toBe("error");
149
- });
150
-
151
- test("getStats calculates correctly", () => {
152
- logger.log({
153
- timestamp: new Date().toISOString(),
154
- tool: "memory_store",
155
- method: "POST",
156
- path: "/v1/memories",
157
- duration: 100,
158
- status: "success",
159
- });
160
- logger.log({
161
- timestamp: new Date().toISOString(),
162
- tool: "memory_recall",
163
- method: "POST",
164
- path: "/v1/memories/search",
165
- duration: 200,
166
- status: "success",
167
- });
168
- logger.log({
169
- timestamp: new Date().toISOString(),
170
- tool: "memory_store",
171
- method: "POST",
172
- path: "/v1/memories",
173
- duration: 150,
174
- status: "error",
175
- error: "500",
176
- });
177
-
178
- const stats = logger.getStats();
179
- expect(stats.total).toBe(3);
180
- expect(stats.successful).toBe(2);
181
- expect(stats.failed).toBe(1);
182
- expect(stats.avgDuration).toBe(150); // (100+200+150)/3 = 150
183
- });
184
-
185
- test("clear() empties logs", () => {
186
- logger.log({
187
- timestamp: new Date().toISOString(),
188
- tool: "memory_store",
189
- method: "POST",
190
- path: "/v1/memories",
191
- duration: 142,
192
- status: "success",
193
- });
194
-
195
- logger.clear();
196
- const logs = logger.getAllLogs();
197
- expect(logs).toHaveLength(0);
198
- });
199
-
200
- test("formatEntry creates human-readable output", () => {
201
- const entry: LogEntry = {
202
- timestamp: new Date().toISOString(),
203
- tool: "memory_store",
204
- method: "POST",
205
- path: "/v1/memories",
206
- duration: 142,
207
- status: "success",
208
- };
209
-
210
- const formatted = DebugLogger.formatEntry(entry);
211
- expect(formatted).toContain("memory_store");
212
- expect(formatted).toContain("142ms");
213
- expect(formatted).toContain("✓");
214
- });
215
-
216
- test("formatEntry shows error", () => {
217
- const entry: LogEntry = {
218
- timestamp: new Date().toISOString(),
219
- tool: "memory_store",
220
- method: "POST",
221
- path: "/v1/memories",
222
- duration: 156,
223
- status: "error",
224
- error: "500 Internal Server Error",
225
- };
226
-
227
- const formatted = DebugLogger.formatEntry(entry);
228
- expect(formatted).toContain("memory_store");
229
- expect(formatted).toContain("156ms");
230
- expect(formatted).toContain("✗");
231
- expect(formatted).toContain("500 Internal Server Error");
232
- });
233
- });
@@ -1,230 +0,0 @@
1
- /**
2
- * StatusReporter Tests (Simplified)
3
- *
4
- * Tests matching actual implementation
5
- */
6
-
7
- import { describe, test, expect, beforeEach } from "vitest";
8
- import { StatusReporter, type ConnectionStatus, type PluginConfig, type MemoryStats } from "./status-reporter";
9
- import { DebugLogger } from "./debug-logger";
10
-
11
- describe("StatusReporter", () => {
12
- let reporter: StatusReporter;
13
- let debugLogger: DebugLogger;
14
- let mockConnection: ConnectionStatus;
15
- let mockConfig: PluginConfig;
16
- let mockStats: MemoryStats;
17
-
18
- beforeEach(() => {
19
- debugLogger = new DebugLogger({
20
- enabled: true,
21
- verbose: false,
22
- maxEntries: 100,
23
- });
24
- reporter = new StatusReporter(debugLogger);
25
-
26
- mockConnection = {
27
- status: "connected",
28
- endpoint: "https://api.memoryrelay.net",
29
- lastCheck: new Date().toISOString(),
30
- responseTime: 45,
31
- };
32
-
33
- mockConfig = {
34
- agentId: "test-agent",
35
- autoRecall: true,
36
- autoCapture: false,
37
- recallLimit: 5,
38
- recallThreshold: 0.3,
39
- excludeChannels: [],
40
- };
41
-
42
- mockStats = {
43
- total_memories: 100,
44
- };
45
- });
46
-
47
- test("records and clears tool failures", () => {
48
- reporter.recordFailure("memory_store", "500 Error");
49
- let issues = reporter.getIssues();
50
- expect(issues).toHaveLength(1);
51
- expect(issues[0].tool).toBe("memory_store");
52
-
53
- reporter.recordSuccess("memory_store");
54
- issues = reporter.getIssues();
55
- expect(issues).toHaveLength(0);
56
- });
57
-
58
- test("buildReport creates status report", () => {
59
- const toolGroups = {
60
- "Core Memory": ["memory_store", "memory_recall"],
61
- "Projects": ["project_list"],
62
- };
63
-
64
- const report = reporter.buildReport(
65
- mockConnection,
66
- mockConfig,
67
- mockStats,
68
- toolGroups,
69
- );
70
-
71
- expect(report.connection).toEqual(mockConnection);
72
- expect(report.config).toEqual(mockConfig);
73
- expect(report.stats).toEqual(mockStats);
74
- expect(report.tools["Core Memory"]).toBeDefined();
75
- expect(report.tools["Projects"]).toBeDefined();
76
- });
77
-
78
- test("buildReport includes tool status from debug logs", () => {
79
- debugLogger.log({
80
- timestamp: new Date().toISOString(),
81
- tool: "memory_store",
82
- method: "POST",
83
- path: "/v1/memories",
84
- duration: 142,
85
- status: "success",
86
- });
87
-
88
- const toolGroups = {
89
- "Core Memory": ["memory_store"],
90
- };
91
-
92
- const report = reporter.buildReport(
93
- mockConnection,
94
- mockConfig,
95
- mockStats,
96
- toolGroups,
97
- );
98
-
99
- const memoryTools = report.tools["Core Memory"];
100
- expect(memoryTools.available).toBe(1);
101
- expect(memoryTools.failed).toBe(0);
102
- expect(memoryTools.tools[0].status).toBe("working");
103
- });
104
-
105
- test("buildReport shows failed tools", () => {
106
- debugLogger.log({
107
- timestamp: new Date().toISOString(),
108
- tool: "memory_store",
109
- method: "POST",
110
- path: "/v1/memories",
111
- duration: 156,
112
- status: "error",
113
- error: "500 Internal Server Error",
114
- });
115
-
116
- const toolGroups = {
117
- "Core Memory": ["memory_store"],
118
- };
119
-
120
- const report = reporter.buildReport(
121
- mockConnection,
122
- mockConfig,
123
- mockStats,
124
- toolGroups,
125
- );
126
-
127
- const memoryTools = report.tools["Core Memory"];
128
- expect(memoryTools.available).toBe(0);
129
- expect(memoryTools.failed).toBe(1);
130
- expect(memoryTools.tools[0].status).toBe("error");
131
- expect(memoryTools.tools[0].error).toBe("500 Internal Server Error");
132
- });
133
-
134
- test("buildReport includes recent calls", () => {
135
- debugLogger.log({
136
- timestamp: new Date().toISOString(),
137
- tool: "memory_store",
138
- method: "POST",
139
- path: "/v1/memories",
140
- duration: 142,
141
- status: "success",
142
- });
143
-
144
- const toolGroups = {
145
- "Core Memory": ["memory_store"],
146
- };
147
-
148
- const report = reporter.buildReport(
149
- mockConnection,
150
- mockConfig,
151
- mockStats,
152
- toolGroups,
153
- );
154
-
155
- expect(report.recentCalls).toHaveLength(1);
156
- expect(report.recentCalls[0].tool).toBe("memory_store");
157
- });
158
-
159
- test("formatReport creates human-readable output", () => {
160
- const toolGroups = {
161
- "Core Memory": ["memory_store", "memory_recall"],
162
- };
163
-
164
- const report = reporter.buildReport(
165
- mockConnection,
166
- mockConfig,
167
- mockStats,
168
- toolGroups,
169
- );
170
-
171
- const formatted = StatusReporter.formatReport(report);
172
- expect(formatted).toContain("MemoryRelay Plugin Status");
173
- expect(formatted).toContain("connected");
174
- expect(formatted).toContain("Core Memory");
175
- });
176
-
177
- test("formatCompact creates brief output", () => {
178
- const toolGroups = {
179
- "Core Memory": ["memory_store"],
180
- };
181
-
182
- const report = reporter.buildReport(
183
- mockConnection,
184
- mockConfig,
185
- mockStats,
186
- toolGroups,
187
- );
188
-
189
- const compact = StatusReporter.formatCompact(report);
190
- expect(compact).toContain("connected");
191
- expect(compact.length).toBeLessThan(200); // Should be brief
192
- });
193
-
194
- test("handles disconnected status", () => {
195
- mockConnection.status = "disconnected";
196
-
197
- const toolGroups = {
198
- "Core Memory": ["memory_store"],
199
- };
200
-
201
- const report = reporter.buildReport(
202
- mockConnection,
203
- mockConfig,
204
- mockStats,
205
- toolGroups,
206
- );
207
-
208
- expect(report.connection.status).toBe("disconnected");
209
- const formatted = StatusReporter.formatReport(report);
210
- expect(formatted).toContain("disconnected");
211
- });
212
-
213
- test("includes issues in report", () => {
214
- reporter.recordFailure("memory_batch_store", "500 Error");
215
-
216
- const toolGroups = {
217
- "Core Memory": ["memory_batch_store"],
218
- };
219
-
220
- const report = reporter.buildReport(
221
- mockConnection,
222
- mockConfig,
223
- mockStats,
224
- toolGroups,
225
- );
226
-
227
- expect(report.issues).toHaveLength(1);
228
- expect(report.issues[0].tool).toBe("memory_batch_store");
229
- });
230
- });