@poprobertdaniel/openclaw-memory 0.1.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 (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +410 -0
  3. package/dist/chunk-CRPEAZ44.cjs +1881 -0
  4. package/dist/chunk-CRPEAZ44.cjs.map +1 -0
  5. package/dist/chunk-JNWCMHOB.js +309 -0
  6. package/dist/chunk-JNWCMHOB.js.map +1 -0
  7. package/dist/chunk-JSQBXYDM.js +1881 -0
  8. package/dist/chunk-JSQBXYDM.js.map +1 -0
  9. package/dist/chunk-NHFPLDZK.js +236 -0
  10. package/dist/chunk-NHFPLDZK.js.map +1 -0
  11. package/dist/chunk-NMUPGLJW.cjs +752 -0
  12. package/dist/chunk-NMUPGLJW.cjs.map +1 -0
  13. package/dist/chunk-RFLG2CCR.js +752 -0
  14. package/dist/chunk-RFLG2CCR.js.map +1 -0
  15. package/dist/chunk-VXULEX3A.cjs +236 -0
  16. package/dist/chunk-VXULEX3A.cjs.map +1 -0
  17. package/dist/chunk-ZY2C2CJQ.cjs +309 -0
  18. package/dist/chunk-ZY2C2CJQ.cjs.map +1 -0
  19. package/dist/cli/index.cjs +764 -0
  20. package/dist/cli/index.cjs.map +1 -0
  21. package/dist/cli/index.d.cts +1 -0
  22. package/dist/cli/index.d.ts +1 -0
  23. package/dist/cli/index.js +764 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/index.cjs +48 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +790 -0
  28. package/dist/index.d.ts +790 -0
  29. package/dist/index.js +48 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/memory-service-6WDMF6KX.cjs +9 -0
  32. package/dist/memory-service-6WDMF6KX.cjs.map +1 -0
  33. package/dist/memory-service-GKEG6J2D.js +9 -0
  34. package/dist/memory-service-GKEG6J2D.js.map +1 -0
  35. package/dist/server-BTbRv-yX.d.cts +1199 -0
  36. package/dist/server-BTbRv-yX.d.ts +1199 -0
  37. package/dist/server.cjs +9 -0
  38. package/dist/server.cjs.map +1 -0
  39. package/dist/server.d.cts +2 -0
  40. package/dist/server.d.ts +2 -0
  41. package/dist/server.js +9 -0
  42. package/dist/server.js.map +1 -0
  43. package/docker/full.yml +45 -0
  44. package/docker/standard.yml +26 -0
  45. package/package.json +109 -0
  46. package/skill/SKILL.md +139 -0
  47. package/templates/.env.example +42 -0
  48. package/templates/docker-compose.full.yml +45 -0
  49. package/templates/docker-compose.standard.yml +26 -0
  50. package/templates/openclaw-memory.config.ts +49 -0
@@ -0,0 +1,764 @@
1
+ #!/usr/bin/env node
2
+ "use strict"; function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3
+
4
+
5
+
6
+
7
+ var _chunkZY2C2CJQcjs = require('../chunk-ZY2C2CJQ.cjs');
8
+
9
+ // src/cli/index.ts
10
+ var _commander = require('commander');
11
+
12
+ // src/cli/commands/init.ts
13
+
14
+ var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);
15
+ var _path = require('path'); var _path2 = _interopRequireDefault(_path);
16
+
17
+ // src/cli/utils.ts
18
+ var _picocolors = require('picocolors'); var _picocolors2 = _interopRequireDefault(_picocolors);
19
+
20
+ function info(msg) {
21
+ console.log(_picocolors2.default.blue("\u2139") + " " + msg);
22
+ }
23
+ function success(msg) {
24
+ console.log(_picocolors2.default.green("\u2713") + " " + msg);
25
+ }
26
+ function warn(msg) {
27
+ console.log(_picocolors2.default.yellow("\u26A0") + " " + msg);
28
+ }
29
+ function error(msg) {
30
+ console.error(_picocolors2.default.red("\u2717") + " " + msg);
31
+ }
32
+ function header(title) {
33
+ console.log();
34
+ console.log(_picocolors2.default.bold(` \u{1F9E0} OpenClaw Memory \u2014 ${title}`));
35
+ console.log();
36
+ }
37
+ function bullet(label, value, status) {
38
+ const dot = status === "ok" ? _picocolors2.default.green("\u25CF") : status === "error" ? _picocolors2.default.red("\u25CF") : status === "degraded" ? _picocolors2.default.yellow("\u25CF") : status === "disabled" ? _picocolors2.default.dim("\u25CB") : " ";
39
+ console.log(` ${dot} ${_picocolors2.default.bold(label)} ${value}`);
40
+ }
41
+ function getServerPid() {
42
+ const pidPath = _chunkZY2C2CJQcjs.getPidFilePath.call(void 0, );
43
+ if (!_fs2.default.existsSync(pidPath)) return null;
44
+ try {
45
+ const pid = parseInt(_fs2.default.readFileSync(pidPath, "utf-8").trim(), 10);
46
+ if (isNaN(pid)) return null;
47
+ try {
48
+ process.kill(pid, 0);
49
+ return pid;
50
+ } catch (e) {
51
+ _fs2.default.unlinkSync(pidPath);
52
+ return null;
53
+ }
54
+ } catch (e2) {
55
+ return null;
56
+ }
57
+ }
58
+ async function isServerRunning(baseUrl = "http://localhost:7777") {
59
+ try {
60
+ const res = await fetch(`${baseUrl}/api/health`, {
61
+ signal: AbortSignal.timeout(2e3)
62
+ });
63
+ return res.ok;
64
+ } catch (e3) {
65
+ return false;
66
+ }
67
+ }
68
+ function getBaseUrl(port) {
69
+ return `http://localhost:${port || 7777}`;
70
+ }
71
+ async function apiGet(baseUrl, path3, token) {
72
+ const headers = {};
73
+ if (token) headers.Authorization = `Bearer ${token}`;
74
+ const res = await fetch(`${baseUrl}${path3}`, { headers });
75
+ if (!res.ok) {
76
+ const text = await res.text();
77
+ throw new Error(`HTTP ${res.status}: ${text}`);
78
+ }
79
+ return res.json();
80
+ }
81
+ async function apiPost(baseUrl, path3, body, token) {
82
+ const headers = { "Content-Type": "application/json" };
83
+ if (token) headers.Authorization = `Bearer ${token}`;
84
+ const res = await fetch(`${baseUrl}${path3}`, {
85
+ method: "POST",
86
+ headers,
87
+ body: JSON.stringify(body)
88
+ });
89
+ if (!res.ok) {
90
+ const text = await res.text();
91
+ throw new Error(`HTTP ${res.status}: ${text}`);
92
+ }
93
+ return res.json();
94
+ }
95
+ function output(data, format = "json") {
96
+ if (format === "text") {
97
+ console.log(JSON.stringify(data, null, 2));
98
+ } else {
99
+ console.log(JSON.stringify(data));
100
+ }
101
+ }
102
+ async function readStdin() {
103
+ if (process.stdin.isTTY) return "";
104
+ const chunks = [];
105
+ for await (const chunk of process.stdin) {
106
+ chunks.push(Buffer.from(chunk));
107
+ }
108
+ return Buffer.concat(chunks).toString("utf-8").trim();
109
+ }
110
+
111
+ // src/cli/commands/init.ts
112
+ function initCommand() {
113
+ return new (0, _commander.Command)("init").description("Interactive setup wizard").option("--tier <tier>", "Tier: lite, standard, or full").option("--non-interactive", "Skip prompts, use defaults + flags").action(async (opts) => {
114
+ header("Setup Wizard");
115
+ const tier = opts.tier || "lite";
116
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
117
+ const sqlitePath = _chunkZY2C2CJQcjs.getDefaultSqlitePath.call(void 0, );
118
+ _fs2.default.mkdirSync(dataDir, { recursive: true });
119
+ info(`Data directory: ${dataDir}`);
120
+ let qdrantAvailable = false;
121
+ let ageAvailable = false;
122
+ if (tier !== "lite") {
123
+ info("Checking Qdrant connectivity...");
124
+ try {
125
+ const res = await fetch("http://localhost:6333/collections", {
126
+ signal: AbortSignal.timeout(2e3)
127
+ });
128
+ qdrantAvailable = res.ok;
129
+ } catch (e4) {
130
+ }
131
+ if (qdrantAvailable) {
132
+ success("Qdrant is reachable at http://localhost:6333");
133
+ } else {
134
+ warn("Qdrant not reachable at http://localhost:6333");
135
+ }
136
+ }
137
+ if (tier === "full") {
138
+ info("Checking PostgreSQL/AGE connectivity...");
139
+ try {
140
+ const net = await Promise.resolve().then(() => _interopRequireWildcard(require("net")));
141
+ ageAvailable = await new Promise((resolve) => {
142
+ const socket = new net.Socket();
143
+ socket.setTimeout(2e3);
144
+ socket.connect(5432, "localhost", () => {
145
+ socket.destroy();
146
+ resolve(true);
147
+ });
148
+ socket.on("error", () => resolve(false));
149
+ socket.on("timeout", () => {
150
+ socket.destroy();
151
+ resolve(false);
152
+ });
153
+ });
154
+ } catch (e5) {
155
+ }
156
+ if (ageAvailable) {
157
+ success("PostgreSQL is reachable at localhost:5432");
158
+ } else {
159
+ warn("PostgreSQL not reachable at localhost:5432");
160
+ }
161
+ }
162
+ let effectiveTier = tier;
163
+ if (tier === "full" && !ageAvailable) {
164
+ effectiveTier = qdrantAvailable ? "standard" : "lite";
165
+ warn(`Downgrading to ${effectiveTier} tier (missing dependencies)`);
166
+ } else if (tier === "standard" && !qdrantAvailable) {
167
+ effectiveTier = "lite";
168
+ warn("Downgrading to lite tier (Qdrant not available)");
169
+ }
170
+ const configContent = generateConfig(effectiveTier, sqlitePath);
171
+ const configPath = _path2.default.join(process.cwd(), "openclaw-memory.config.ts");
172
+ _fs2.default.writeFileSync(configPath, configContent, "utf-8");
173
+ success(`Config written to ${configPath}`);
174
+ const envExample = generateEnvExample(effectiveTier);
175
+ const envPath = _path2.default.join(process.cwd(), ".env.example");
176
+ _fs2.default.writeFileSync(envPath, envExample, "utf-8");
177
+ success(`Environment template written to ${envPath}`);
178
+ console.log();
179
+ info("Next steps:");
180
+ console.log(" openclaw-memory start # Start the server");
181
+ console.log(" openclaw-memory status # Check all layers");
182
+ console.log();
183
+ });
184
+ }
185
+ function generateConfig(tier, sqlitePath) {
186
+ const lines = [
187
+ `import { defineConfig } from 'openclaw-memory';`,
188
+ ``,
189
+ `export default defineConfig({`,
190
+ ` tier: '${tier}',`,
191
+ ` port: 7777,`,
192
+ ` auth: {`,
193
+ ` token: process.env.MEMORY_AUTH_TOKEN || 'change-me',`,
194
+ ` },`,
195
+ ` sqlite: {`,
196
+ ` path: '${sqlitePath}',`,
197
+ ` },`
198
+ ];
199
+ if (tier === "standard" || tier === "full") {
200
+ lines.push(` qdrant: {`);
201
+ lines.push(` url: process.env.QDRANT_URL || 'http://localhost:6333',`);
202
+ lines.push(` collection: 'openclaw_memories',`);
203
+ lines.push(` },`);
204
+ lines.push(` embedding: {`);
205
+ lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);
206
+ lines.push(` model: 'text-embedding-3-small',`);
207
+ lines.push(` dimensions: 1536,`);
208
+ lines.push(` },`);
209
+ lines.push(` extraction: {`);
210
+ lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);
211
+ lines.push(` model: 'gpt-4o-mini',`);
212
+ lines.push(` enabled: true,`);
213
+ lines.push(` },`);
214
+ }
215
+ if (tier === "full") {
216
+ lines.push(` age: {`);
217
+ lines.push(` host: process.env.PGHOST || 'localhost',`);
218
+ lines.push(` port: parseInt(process.env.PGPORT || '5432', 10),`);
219
+ lines.push(` user: process.env.PGUSER || 'openclaw',`);
220
+ lines.push(` password: process.env.PGPASSWORD || '',`);
221
+ lines.push(` database: process.env.PGDATABASE || 'agent_memory',`);
222
+ lines.push(` graph: 'agent_memory',`);
223
+ lines.push(` },`);
224
+ }
225
+ lines.push(`});`);
226
+ lines.push(``);
227
+ return lines.join("\n");
228
+ }
229
+ function generateEnvExample(tier) {
230
+ const lines = [
231
+ `# openclaw-memory environment variables`,
232
+ ``,
233
+ `# Server`,
234
+ `# OPENCLAW_MEMORY_PORT=7777`,
235
+ `# OPENCLAW_MEMORY_HOST=0.0.0.0`,
236
+ ``,
237
+ `# Authentication`,
238
+ `MEMORY_AUTH_TOKEN=change-me-to-a-secure-token`,
239
+ ``,
240
+ `# SQLite (always required)`,
241
+ `# SQLITE_PATH=~/.openclaw-memory/memory.sqlite`,
242
+ ``
243
+ ];
244
+ if (tier === "standard" || tier === "full") {
245
+ lines.push(`# Qdrant (Standard/Full tier)`);
246
+ lines.push(`QDRANT_URL=http://localhost:6333`);
247
+ lines.push(``);
248
+ lines.push(`# Embedding provider`);
249
+ lines.push(`OPENAI_API_KEY=sk-your-key-here`);
250
+ lines.push(`# EMBEDDING_MODEL=text-embedding-3-small`);
251
+ lines.push(`# EMBEDDING_BASE_URL=https://api.openai.com/v1`);
252
+ lines.push(``);
253
+ lines.push(`# Entity extraction`);
254
+ lines.push(`# EXTRACTION_MODEL=gpt-4o-mini`);
255
+ lines.push(``);
256
+ }
257
+ if (tier === "full") {
258
+ lines.push(`# PostgreSQL + Apache AGE (Full tier)`);
259
+ lines.push(`PGHOST=localhost`);
260
+ lines.push(`PGPORT=5432`);
261
+ lines.push(`PGUSER=openclaw`);
262
+ lines.push(`PGPASSWORD=your-password`);
263
+ lines.push(`PGDATABASE=agent_memory`);
264
+ lines.push(`# AGE_GRAPH=agent_memory`);
265
+ lines.push(``);
266
+ }
267
+ return lines.join("\n");
268
+ }
269
+
270
+ // src/cli/commands/start.ts
271
+
272
+
273
+ var _child_process = require('child_process');
274
+ function startCommand() {
275
+ return new (0, _commander.Command)("start").description("Start the HTTP server").option("-p, --port <port>", "Server port").option("--bg", "Run in background (daemon mode)").option("--config <path>", "Path to config file").action(async (opts) => {
276
+ if (opts.bg) {
277
+ await startBackground(opts);
278
+ } else {
279
+ await startForeground(opts);
280
+ }
281
+ });
282
+ }
283
+ async function startForeground(opts) {
284
+ if (opts.port) {
285
+ process.env.OPENCLAW_MEMORY_PORT = opts.port;
286
+ process.env.PORT = opts.port;
287
+ }
288
+ const { createServer } = await Promise.resolve().then(() => _interopRequireWildcard(require("../server.cjs")));
289
+ const { app, config } = await createServer(opts.config);
290
+ const port = opts.port ? parseInt(opts.port, 10) : config.port;
291
+ app.listen(port);
292
+ console.log(`[server] Listening on http://0.0.0.0:${port}`);
293
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
294
+ _fs2.default.mkdirSync(dataDir, { recursive: true });
295
+ _fs2.default.writeFileSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ), String(process.pid), "utf-8");
296
+ const cleanup = () => {
297
+ try {
298
+ _fs2.default.unlinkSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ));
299
+ } catch (e6) {
300
+ }
301
+ process.exit(0);
302
+ };
303
+ process.on("SIGINT", cleanup);
304
+ process.on("SIGTERM", cleanup);
305
+ }
306
+ async function startBackground(opts) {
307
+ header("Starting Server (background)");
308
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
309
+ _fs2.default.mkdirSync(dataDir, { recursive: true });
310
+ const args = ["run", "src/server.ts"];
311
+ const env = { ...process.env };
312
+ if (opts.port) {
313
+ env.OPENCLAW_MEMORY_PORT = opts.port;
314
+ env.PORT = opts.port;
315
+ }
316
+ const runtime = typeof Bun !== "undefined" ? "bun" : "node";
317
+ const execPath = runtime === "bun" ? "bun" : process.execPath;
318
+ const execArgs = runtime === "bun" ? args : ["--import", "tsx", ...args];
319
+ const child = _child_process.spawn.call(void 0, execPath, execArgs, {
320
+ env,
321
+ detached: true,
322
+ stdio: "ignore",
323
+ cwd: process.cwd()
324
+ });
325
+ child.unref();
326
+ if (child.pid) {
327
+ _fs2.default.writeFileSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ), String(child.pid), "utf-8");
328
+ success(`Server started in background (PID: ${child.pid})`);
329
+ info(`PID file: ${_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, )}`);
330
+ info(`Stop with: openclaw-memory stop`);
331
+ } else {
332
+ error("Failed to start server");
333
+ process.exit(1);
334
+ }
335
+ }
336
+
337
+ // src/cli/commands/stop.ts
338
+
339
+
340
+ function stopCommand() {
341
+ return new (0, _commander.Command)("stop").description("Stop the running server").action(async () => {
342
+ header("Stopping Server");
343
+ const pidPath = _chunkZY2C2CJQcjs.getPidFilePath.call(void 0, );
344
+ if (!_fs2.default.existsSync(pidPath)) {
345
+ warn("No PID file found \u2014 server may not be running");
346
+ return;
347
+ }
348
+ const pidStr = _fs2.default.readFileSync(pidPath, "utf-8").trim();
349
+ const pid = parseInt(pidStr, 10);
350
+ if (isNaN(pid)) {
351
+ error(`Invalid PID in ${pidPath}: ${pidStr}`);
352
+ return;
353
+ }
354
+ try {
355
+ process.kill(pid, "SIGTERM");
356
+ success(`Sent SIGTERM to PID ${pid}`);
357
+ let alive = true;
358
+ for (let i = 0; i < 30; i++) {
359
+ await new Promise((r) => setTimeout(r, 100));
360
+ try {
361
+ process.kill(pid, 0);
362
+ } catch (e7) {
363
+ alive = false;
364
+ break;
365
+ }
366
+ }
367
+ if (alive) {
368
+ warn("Process still running after 3s, sending SIGKILL...");
369
+ try {
370
+ process.kill(pid, "SIGKILL");
371
+ } catch (e8) {
372
+ }
373
+ }
374
+ success("Server stopped");
375
+ } catch (err) {
376
+ if (err.code === "ESRCH") {
377
+ warn(`Process ${pid} not found \u2014 may have already stopped`);
378
+ } else {
379
+ error(`Failed to stop process ${pid}: ${err}`);
380
+ }
381
+ }
382
+ try {
383
+ _fs2.default.unlinkSync(pidPath);
384
+ } catch (e9) {
385
+ }
386
+ });
387
+ }
388
+
389
+ // src/cli/commands/status.ts
390
+
391
+ function statusCommand() {
392
+ return new (0, _commander.Command)("status").description("Show server and layer health status").option("-p, --port <port>", "Server port to check").option("--config <path>", "Path to config file").action(async (opts) => {
393
+ header("Status");
394
+ let config;
395
+ try {
396
+ config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
397
+ } catch (e10) {
398
+ config = null;
399
+ }
400
+ const port = opts.port ? parseInt(opts.port, 10) : _optionalChain([config, 'optionalAccess', _ => _.port]) || 7777;
401
+ const baseUrl = getBaseUrl(port);
402
+ const pid = getServerPid();
403
+ const running = await isServerRunning(baseUrl);
404
+ if (running && pid) {
405
+ bullet("Server", `Running (PID ${pid}, port ${port})`, "ok");
406
+ } else if (running) {
407
+ bullet("Server", `Running (port ${port})`, "ok");
408
+ } else if (pid) {
409
+ bullet("Server", `PID file exists (${pid}) but not responding`, "error");
410
+ } else {
411
+ bullet("Server", "Not running", "disabled");
412
+ }
413
+ if (config) {
414
+ bullet("Tier", config.tier, void 0);
415
+ }
416
+ console.log();
417
+ if (running) {
418
+ try {
419
+ const health = await apiGet(baseUrl, "/api/health", _optionalChain([config, 'optionalAccess', _2 => _2.auth, 'optionalAccess', _3 => _3.token]));
420
+ info("Layers:");
421
+ const sqliteStatus = health.sqlite === "ok" ? "ok" : "error";
422
+ bullet("L1 SQLite", String(health.sqlite), sqliteStatus);
423
+ if (health.qdrant !== "disabled") {
424
+ const qdrantStatus = health.qdrant === "ok" ? "ok" : "error";
425
+ bullet("L2 Qdrant", String(health.qdrant), qdrantStatus);
426
+ } else {
427
+ bullet("L2 Qdrant", "disabled", "disabled");
428
+ }
429
+ if (health.age !== "disabled") {
430
+ const ageStatus = health.age === "ok" ? "ok" : "error";
431
+ bullet("L3 AGE", String(health.age), ageStatus);
432
+ } else {
433
+ bullet("L3 AGE", "disabled", "disabled");
434
+ }
435
+ if (health.uptime !== void 0) {
436
+ const uptime = formatUptime(Number(health.uptime));
437
+ console.log();
438
+ info(`Uptime: ${uptime}`);
439
+ }
440
+ } catch (error2) {
441
+ info("Could not fetch health status from server");
442
+ }
443
+ } else {
444
+ if (config) {
445
+ info("Server not running. Checking layers directly...");
446
+ console.log();
447
+ bullet("L1 SQLite", config.sqlite.path, "ok");
448
+ if (config.qdrant) {
449
+ try {
450
+ const res = await fetch(`${config.qdrant.url}/collections`, {
451
+ signal: AbortSignal.timeout(2e3)
452
+ });
453
+ bullet("L2 Qdrant", config.qdrant.url, res.ok ? "ok" : "error");
454
+ } catch (e11) {
455
+ bullet("L2 Qdrant", `${config.qdrant.url} (unreachable)`, "error");
456
+ }
457
+ } else {
458
+ bullet("L2 Qdrant", "not configured", "disabled");
459
+ }
460
+ if (config.age) {
461
+ try {
462
+ const net = await Promise.resolve().then(() => _interopRequireWildcard(require("net")));
463
+ const reachable = await new Promise((resolve) => {
464
+ const socket = new net.Socket();
465
+ socket.setTimeout(2e3);
466
+ socket.connect(config.age.port, config.age.host, () => {
467
+ socket.destroy();
468
+ resolve(true);
469
+ });
470
+ socket.on("error", () => resolve(false));
471
+ socket.on("timeout", () => {
472
+ socket.destroy();
473
+ resolve(false);
474
+ });
475
+ });
476
+ bullet("L3 AGE", `${config.age.host}:${config.age.port}`, reachable ? "ok" : "error");
477
+ } catch (e12) {
478
+ bullet("L3 AGE", "unreachable", "error");
479
+ }
480
+ } else {
481
+ bullet("L3 AGE", "not configured", "disabled");
482
+ }
483
+ }
484
+ }
485
+ console.log();
486
+ });
487
+ }
488
+ function formatUptime(seconds) {
489
+ const h = Math.floor(seconds / 3600);
490
+ const m = Math.floor(seconds % 3600 / 60);
491
+ const s = seconds % 60;
492
+ if (h > 0) return `${h}h ${m}m`;
493
+ if (m > 0) return `${m}m ${s}s`;
494
+ return `${s}s`;
495
+ }
496
+
497
+ // src/cli/commands/store.ts
498
+
499
+ function storeCommand() {
500
+ return new (0, _commander.Command)("store").description("Store a new memory").argument("[content]", "Memory content (or pipe via stdin)").requiredOption("--agent <id>", "Agent ID").requiredOption("--scope <scope>", "Memory scope (user, agent, global, project, session)").option("--subject <id>", "Subject ID").option("--tags <tags>", "Comma-separated tags").option("--source <source>", "Memory source", "explicit").option("--no-extract", "Skip entity extraction").option("--format <fmt>", "Output format (json, text)", "json").option("--config <path>", "Path to config file").action(async (contentArg, opts) => {
501
+ const content = contentArg || await readStdin();
502
+ if (!content) {
503
+ console.error("Error: content is required (pass as argument or pipe via stdin)");
504
+ process.exit(1);
505
+ }
506
+ const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
507
+ const baseUrl = getBaseUrl(config.port);
508
+ const serverUp = await isServerRunning(baseUrl);
509
+ const body = {
510
+ agent_id: opts.agent,
511
+ scope: opts.scope,
512
+ subject_id: opts.subject || null,
513
+ content,
514
+ tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : [],
515
+ source: opts.source,
516
+ extract_entities: opts.extract !== false
517
+ };
518
+ if (serverUp) {
519
+ const result = await apiPost(baseUrl, "/api/memories", body, config.auth.token);
520
+ output(result, opts.format);
521
+ } else {
522
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
523
+ const service = new MemoryService();
524
+ await service.init();
525
+ try {
526
+ const result = await service.store({
527
+ agentId: opts.agent,
528
+ scope: opts.scope,
529
+ subjectId: opts.subject || null,
530
+ content,
531
+ tags: body.tags,
532
+ source: opts.source,
533
+ extractEntities: opts.extract !== false
534
+ });
535
+ output(result, opts.format);
536
+ } finally {
537
+ await service.close();
538
+ }
539
+ }
540
+ });
541
+ }
542
+
543
+ // src/cli/commands/search.ts
544
+
545
+ function searchCommand() {
546
+ const cmd = new (0, _commander.Command)("search").description("Search memories");
547
+ cmd.argument("<query>", "Search query").requiredOption("--agent <id>", "Agent ID").option("--limit <n>", "Max results", "10").option("--strategy <s>", "Search strategy (auto, semantic, fulltext, graph, all)", "auto").option("--scopes <scopes>", "Comma-separated scopes").option("--subject <id>", "Subject ID filter").option("--cross-agent", "Search across all agents").option("--no-graph", "Exclude graph results").option("--recall", "Format output for LLM context injection").option("--format <fmt>", "Output format (json, text)", "json").option("--config <path>", "Path to config file").action(async (query, opts) => {
548
+ const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
549
+ const baseUrl = getBaseUrl(config.port);
550
+ const serverUp = await isServerRunning(baseUrl);
551
+ const body = {
552
+ agent_id: opts.agent,
553
+ query,
554
+ limit: parseInt(opts.limit, 10),
555
+ strategy: opts.strategy,
556
+ scopes: opts.scopes ? opts.scopes.split(",") : void 0,
557
+ subject_id: opts.subject || null,
558
+ cross_agent: opts.crossAgent || false,
559
+ include_graph: opts.graph !== false
560
+ };
561
+ let result;
562
+ if (serverUp) {
563
+ result = await apiPost(baseUrl, "/api/search", body, config.auth.token);
564
+ } else {
565
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
566
+ const service = new MemoryService();
567
+ await service.init();
568
+ try {
569
+ result = await service.search({
570
+ agentId: opts.agent,
571
+ query,
572
+ limit: parseInt(opts.limit, 10),
573
+ strategy: opts.strategy,
574
+ scopes: opts.scopes ? opts.scopes.split(",") : void 0,
575
+ subjectId: opts.subject || null,
576
+ crossAgent: opts.crossAgent || false,
577
+ includeGraph: opts.graph !== false
578
+ });
579
+ } finally {
580
+ await service.close();
581
+ }
582
+ }
583
+ if (opts.recall) {
584
+ const data = result;
585
+ if (data.results && data.results.length > 0) {
586
+ console.log("## Relevant Memories");
587
+ for (const r of data.results) {
588
+ const date = new Date(r.memory.created_at).toLocaleDateString();
589
+ console.log(`- ${r.memory.content} (${r.memory.scope}, ${date})`);
590
+ }
591
+ } else {
592
+ console.log("No relevant memories found.");
593
+ }
594
+ } else {
595
+ output(result, opts.format);
596
+ }
597
+ });
598
+ return cmd;
599
+ }
600
+
601
+ // src/cli/commands/migrate.ts
602
+
603
+ function migrateCommand() {
604
+ return new (0, _commander.Command)("migrate").description("Import memories from markdown files").requiredOption("--paths <paths>", "Comma-separated file paths").requiredOption("--agent <id>", "Agent ID").option("--dry-run", "Preview without writing").option("--format <fmt>", "Output format (json, text)", "json").option("--config <path>", "Path to config file").action(async (opts) => {
605
+ const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
606
+ const baseUrl = getBaseUrl(config.port);
607
+ const serverUp = await isServerRunning(baseUrl);
608
+ const paths = opts.paths.split(",").map((p) => p.trim());
609
+ if (opts.dryRun) {
610
+ header("Migration (dry run)");
611
+ }
612
+ const body = {
613
+ markdown_paths: paths,
614
+ agent_id: opts.agent,
615
+ dry_run: opts.dryRun || false
616
+ };
617
+ let result;
618
+ if (serverUp) {
619
+ result = await apiPost(baseUrl, "/api/admin/migrate-markdown", body, config.auth.token);
620
+ } else {
621
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
622
+ const service = new MemoryService();
623
+ await service.init();
624
+ try {
625
+ const migrated = await service.migrateMarkdown(paths, opts.agent);
626
+ result = migrated;
627
+ } finally {
628
+ await service.close();
629
+ }
630
+ }
631
+ if (opts.format === "text") {
632
+ const data = result;
633
+ if (data.migrated !== void 0) {
634
+ success(`Migrated ${data.migrated} memories`);
635
+ }
636
+ if (data.skipped) {
637
+ info(`Skipped ${data.skipped} sections`);
638
+ }
639
+ if (data.errors && data.errors.length > 0) {
640
+ for (const err of data.errors) {
641
+ console.error(` \u2717 ${err}`);
642
+ }
643
+ }
644
+ } else {
645
+ output(result, opts.format);
646
+ }
647
+ });
648
+ }
649
+
650
+ // src/cli/commands/infra.ts
651
+
652
+
653
+
654
+
655
+ var _url = require('url');
656
+ var __filename = _url.fileURLToPath.call(void 0, import.meta.url);
657
+ var __dirname = _path2.default.dirname(__filename);
658
+ function infraCommand() {
659
+ const infra = new (0, _commander.Command)("infra").description("Manage Docker infrastructure");
660
+ infra.command("up").description("Start Docker containers for the configured tier").option("--tier <tier>", "Override tier (standard, full)").action(async (opts) => {
661
+ header("Infrastructure Up");
662
+ let tier = opts.tier;
663
+ if (!tier) {
664
+ try {
665
+ const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, );
666
+ tier = config.tier;
667
+ } catch (e13) {
668
+ tier = "standard";
669
+ }
670
+ }
671
+ if (tier === "lite") {
672
+ info("Lite tier uses only SQLite \u2014 no Docker infrastructure needed.");
673
+ return;
674
+ }
675
+ const templateFile = tier === "full" ? "full.yml" : "standard.yml";
676
+ const templatePath = findTemplate(templateFile);
677
+ if (!templatePath) {
678
+ error(`Template not found: ${templateFile}`);
679
+ error("Expected in ./docker/ or ./templates/ directory");
680
+ process.exit(1);
681
+ }
682
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
683
+ _fs2.default.mkdirSync(dataDir, { recursive: true });
684
+ const targetPath = _path2.default.join(dataDir, "docker-compose.yml");
685
+ _fs2.default.copyFileSync(templatePath, targetPath);
686
+ info(`Using template: ${templatePath}`);
687
+ try {
688
+ _child_process.execSync.call(void 0, `docker compose -f ${targetPath} up -d`, {
689
+ stdio: "inherit",
690
+ cwd: dataDir
691
+ });
692
+ success("Docker containers started");
693
+ } catch (error2) {
694
+ error("Failed to start Docker containers");
695
+ error("Make sure Docker is installed and running");
696
+ process.exit(1);
697
+ }
698
+ });
699
+ infra.command("down").description("Stop Docker containers").action(async () => {
700
+ header("Infrastructure Down");
701
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
702
+ const composePath = _path2.default.join(dataDir, "docker-compose.yml");
703
+ if (!_fs2.default.existsSync(composePath)) {
704
+ warn("No docker-compose.yml found in data directory");
705
+ return;
706
+ }
707
+ try {
708
+ _child_process.execSync.call(void 0, `docker compose -f ${composePath} down`, {
709
+ stdio: "inherit",
710
+ cwd: dataDir
711
+ });
712
+ success("Docker containers stopped");
713
+ } catch (error2) {
714
+ error("Failed to stop Docker containers");
715
+ process.exit(1);
716
+ }
717
+ });
718
+ infra.command("status").description("Show Docker container status").action(async () => {
719
+ header("Infrastructure Status");
720
+ const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
721
+ const composePath = _path2.default.join(dataDir, "docker-compose.yml");
722
+ if (!_fs2.default.existsSync(composePath)) {
723
+ info("No docker-compose.yml found \u2014 infrastructure not set up");
724
+ info("Run: openclaw-memory infra up");
725
+ return;
726
+ }
727
+ try {
728
+ _child_process.execSync.call(void 0, `docker compose -f ${composePath} ps`, {
729
+ stdio: "inherit",
730
+ cwd: dataDir
731
+ });
732
+ } catch (e14) {
733
+ error("Failed to get container status");
734
+ }
735
+ });
736
+ return infra;
737
+ }
738
+ function findTemplate(filename) {
739
+ const searchPaths = [
740
+ _path2.default.join(process.cwd(), "docker", filename),
741
+ _path2.default.join(process.cwd(), "templates", filename),
742
+ // Look in the package's installed location
743
+ _path2.default.join(__dirname, "../../docker", filename),
744
+ _path2.default.join(__dirname, "../../templates", filename)
745
+ ];
746
+ for (const p of searchPaths) {
747
+ if (_fs2.default.existsSync(p)) return p;
748
+ }
749
+ return null;
750
+ }
751
+
752
+ // src/cli/index.ts
753
+ var program = new (0, _commander.Command)();
754
+ program.name("openclaw-memory").description("Triple-layer memory system for AI agents \u2014 SQLite + Qdrant + Postgres/AGE").version("0.1.0");
755
+ program.addCommand(initCommand());
756
+ program.addCommand(startCommand());
757
+ program.addCommand(stopCommand());
758
+ program.addCommand(statusCommand());
759
+ program.addCommand(storeCommand());
760
+ program.addCommand(searchCommand());
761
+ program.addCommand(migrateCommand());
762
+ program.addCommand(infraCommand());
763
+ program.parse();
764
+ //# sourceMappingURL=index.cjs.map