@poprobertdaniel/openclaw-memory 0.1.1 → 0.1.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.
Files changed (44) hide show
  1. package/README.md +22 -10
  2. package/dist/{chunk-NHFPLDZK.js → chunk-5SZWJKD5.js} +3 -3
  3. package/dist/{chunk-CRPEAZ44.cjs → chunk-HPGHPKK3.cjs} +3 -2
  4. package/dist/chunk-HPGHPKK3.cjs.map +1 -0
  5. package/dist/{chunk-JNWCMHOB.js → chunk-ITGUJZUL.js} +2 -2
  6. package/dist/{chunk-JNWCMHOB.js.map → chunk-ITGUJZUL.js.map} +1 -1
  7. package/dist/{chunk-VXULEX3A.cjs → chunk-L2KRIMDA.cjs} +9 -9
  8. package/dist/{chunk-VXULEX3A.cjs.map → chunk-L2KRIMDA.cjs.map} +1 -1
  9. package/dist/{chunk-ZY2C2CJQ.cjs → chunk-LA5OP5VI.cjs} +2 -2
  10. package/dist/{chunk-ZY2C2CJQ.cjs.map → chunk-LA5OP5VI.cjs.map} +1 -1
  11. package/dist/{chunk-NMUPGLJW.cjs → chunk-MQEBVCH5.cjs} +25 -19
  12. package/dist/chunk-MQEBVCH5.cjs.map +1 -0
  13. package/dist/{chunk-JSQBXYDM.js → chunk-RZPYOMPO.js} +3 -2
  14. package/dist/chunk-RZPYOMPO.js.map +1 -0
  15. package/dist/{chunk-RFLG2CCR.js → chunk-VB5GGBGB.js} +14 -8
  16. package/dist/chunk-VB5GGBGB.js.map +1 -0
  17. package/dist/cli/index.cjs +25 -25
  18. package/dist/cli/index.cjs.map +1 -1
  19. package/dist/cli/index.js +7 -7
  20. package/dist/cli/index.js.map +1 -1
  21. package/dist/index.cjs +5 -5
  22. package/dist/index.d.cts +14 -2
  23. package/dist/index.d.ts +14 -2
  24. package/dist/index.js +4 -4
  25. package/dist/memory-service-4ZPYUN4L.js +9 -0
  26. package/dist/memory-service-LURM3FBB.cjs +9 -0
  27. package/dist/{memory-service-6WDMF6KX.cjs.map → memory-service-LURM3FBB.cjs.map} +1 -1
  28. package/dist/{server-BTbRv-yX.d.ts → server-D-3OqU-T.d.cts} +12 -0
  29. package/dist/{server-BTbRv-yX.d.cts → server-D-3OqU-T.d.ts} +12 -0
  30. package/dist/server.cjs +4 -4
  31. package/dist/server.d.cts +1 -1
  32. package/dist/server.d.ts +1 -1
  33. package/dist/server.js +3 -3
  34. package/package.json +2 -2
  35. package/templates/.env.example +1 -1
  36. package/templates/openclaw-memory.config.ts +2 -2
  37. package/dist/chunk-CRPEAZ44.cjs.map +0 -1
  38. package/dist/chunk-JSQBXYDM.js.map +0 -1
  39. package/dist/chunk-NMUPGLJW.cjs.map +0 -1
  40. package/dist/chunk-RFLG2CCR.js.map +0 -1
  41. package/dist/memory-service-6WDMF6KX.cjs +0 -9
  42. package/dist/memory-service-GKEG6J2D.js +0 -9
  43. /package/dist/{chunk-NHFPLDZK.js.map → chunk-5SZWJKD5.js.map} +0 -0
  44. /package/dist/{memory-service-GKEG6J2D.js.map → memory-service-4ZPYUN4L.js.map} +0 -0
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
 
7
- var _chunkZY2C2CJQcjs = require('../chunk-ZY2C2CJQ.cjs');
7
+ var _chunkLA5OP5VIcjs = require('../chunk-LA5OP5VI.cjs');
8
8
 
9
9
  // src/cli/index.ts
10
10
  var _commander = require('commander');
@@ -39,7 +39,7 @@ function bullet(label, value, status) {
39
39
  console.log(` ${dot} ${_picocolors2.default.bold(label)} ${value}`);
40
40
  }
41
41
  function getServerPid() {
42
- const pidPath = _chunkZY2C2CJQcjs.getPidFilePath.call(void 0, );
42
+ const pidPath = _chunkLA5OP5VIcjs.getPidFilePath.call(void 0, );
43
43
  if (!_fs2.default.existsSync(pidPath)) return null;
44
44
  try {
45
45
  const pid = parseInt(_fs2.default.readFileSync(pidPath, "utf-8").trim(), 10);
@@ -113,8 +113,8 @@ function initCommand() {
113
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
114
  header("Setup Wizard");
115
115
  const tier = opts.tier || "lite";
116
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
117
- const sqlitePath = _chunkZY2C2CJQcjs.getDefaultSqlitePath.call(void 0, );
116
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
117
+ const sqlitePath = _chunkLA5OP5VIcjs.getDefaultSqlitePath.call(void 0, );
118
118
  _fs2.default.mkdirSync(dataDir, { recursive: true });
119
119
  info(`Data directory: ${dataDir}`);
120
120
  let qdrantAvailable = false;
@@ -184,7 +184,7 @@ function initCommand() {
184
184
  }
185
185
  function generateConfig(tier, sqlitePath) {
186
186
  const lines = [
187
- `import { defineConfig } from 'openclaw-memory';`,
187
+ `import { defineConfig } from '@poprobertdaniel/openclaw-memory';`,
188
188
  ``,
189
189
  `export default defineConfig({`,
190
190
  ` tier: '${tier}',`,
@@ -208,7 +208,7 @@ function generateConfig(tier, sqlitePath) {
208
208
  lines.push(` },`);
209
209
  lines.push(` extraction: {`);
210
210
  lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);
211
- lines.push(` model: 'gpt-4o-mini',`);
211
+ lines.push(` model: 'gpt-5-nano',`);
212
212
  lines.push(` enabled: true,`);
213
213
  lines.push(` },`);
214
214
  }
@@ -251,7 +251,7 @@ function generateEnvExample(tier) {
251
251
  lines.push(`# EMBEDDING_BASE_URL=https://api.openai.com/v1`);
252
252
  lines.push(``);
253
253
  lines.push(`# Entity extraction`);
254
- lines.push(`# EXTRACTION_MODEL=gpt-4o-mini`);
254
+ lines.push(`# EXTRACTION_MODEL=gpt-5-nano`);
255
255
  lines.push(``);
256
256
  }
257
257
  if (tier === "full") {
@@ -290,12 +290,12 @@ async function startForeground(opts) {
290
290
  const port = opts.port ? parseInt(opts.port, 10) : config.port;
291
291
  app.listen(port);
292
292
  console.log(`[server] Listening on http://0.0.0.0:${port}`);
293
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
293
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
294
294
  _fs2.default.mkdirSync(dataDir, { recursive: true });
295
- _fs2.default.writeFileSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ), String(process.pid), "utf-8");
295
+ _fs2.default.writeFileSync(_chunkLA5OP5VIcjs.getPidFilePath.call(void 0, ), String(process.pid), "utf-8");
296
296
  const cleanup = () => {
297
297
  try {
298
- _fs2.default.unlinkSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ));
298
+ _fs2.default.unlinkSync(_chunkLA5OP5VIcjs.getPidFilePath.call(void 0, ));
299
299
  } catch (e6) {
300
300
  }
301
301
  process.exit(0);
@@ -305,7 +305,7 @@ async function startForeground(opts) {
305
305
  }
306
306
  async function startBackground(opts) {
307
307
  header("Starting Server (background)");
308
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
308
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
309
309
  _fs2.default.mkdirSync(dataDir, { recursive: true });
310
310
  const args = ["run", "src/server.ts"];
311
311
  const env = { ...process.env };
@@ -324,9 +324,9 @@ async function startBackground(opts) {
324
324
  });
325
325
  child.unref();
326
326
  if (child.pid) {
327
- _fs2.default.writeFileSync(_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, ), String(child.pid), "utf-8");
327
+ _fs2.default.writeFileSync(_chunkLA5OP5VIcjs.getPidFilePath.call(void 0, ), String(child.pid), "utf-8");
328
328
  success(`Server started in background (PID: ${child.pid})`);
329
- info(`PID file: ${_chunkZY2C2CJQcjs.getPidFilePath.call(void 0, )}`);
329
+ info(`PID file: ${_chunkLA5OP5VIcjs.getPidFilePath.call(void 0, )}`);
330
330
  info(`Stop with: openclaw-memory stop`);
331
331
  } else {
332
332
  error("Failed to start server");
@@ -340,7 +340,7 @@ async function startBackground(opts) {
340
340
  function stopCommand() {
341
341
  return new (0, _commander.Command)("stop").description("Stop the running server").action(async () => {
342
342
  header("Stopping Server");
343
- const pidPath = _chunkZY2C2CJQcjs.getPidFilePath.call(void 0, );
343
+ const pidPath = _chunkLA5OP5VIcjs.getPidFilePath.call(void 0, );
344
344
  if (!_fs2.default.existsSync(pidPath)) {
345
345
  warn("No PID file found \u2014 server may not be running");
346
346
  return;
@@ -393,7 +393,7 @@ function statusCommand() {
393
393
  header("Status");
394
394
  let config;
395
395
  try {
396
- config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
396
+ config = await _chunkLA5OP5VIcjs.loadConfig.call(void 0, opts.config);
397
397
  } catch (e10) {
398
398
  config = null;
399
399
  }
@@ -503,7 +503,7 @@ function storeCommand() {
503
503
  console.error("Error: content is required (pass as argument or pipe via stdin)");
504
504
  process.exit(1);
505
505
  }
506
- const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, opts.config);
506
+ const config = await _chunkLA5OP5VIcjs.loadConfig.call(void 0, opts.config);
507
507
  const baseUrl = getBaseUrl(config.port);
508
508
  const serverUp = await isServerRunning(baseUrl);
509
509
  const body = {
@@ -519,7 +519,7 @@ function storeCommand() {
519
519
  const result = await apiPost(baseUrl, "/api/memories", body, config.auth.token);
520
520
  output(result, opts.format);
521
521
  } else {
522
- const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
522
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-LURM3FBB.cjs")));
523
523
  const service = new MemoryService();
524
524
  await service.init();
525
525
  try {
@@ -545,7 +545,7 @@ function storeCommand() {
545
545
  function searchCommand() {
546
546
  const cmd = new (0, _commander.Command)("search").description("Search memories");
547
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);
548
+ const config = await _chunkLA5OP5VIcjs.loadConfig.call(void 0, opts.config);
549
549
  const baseUrl = getBaseUrl(config.port);
550
550
  const serverUp = await isServerRunning(baseUrl);
551
551
  const body = {
@@ -562,7 +562,7 @@ function searchCommand() {
562
562
  if (serverUp) {
563
563
  result = await apiPost(baseUrl, "/api/search", body, config.auth.token);
564
564
  } else {
565
- const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
565
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-LURM3FBB.cjs")));
566
566
  const service = new MemoryService();
567
567
  await service.init();
568
568
  try {
@@ -602,7 +602,7 @@ function searchCommand() {
602
602
 
603
603
  function migrateCommand() {
604
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);
605
+ const config = await _chunkLA5OP5VIcjs.loadConfig.call(void 0, opts.config);
606
606
  const baseUrl = getBaseUrl(config.port);
607
607
  const serverUp = await isServerRunning(baseUrl);
608
608
  const paths = opts.paths.split(",").map((p) => p.trim());
@@ -618,7 +618,7 @@ function migrateCommand() {
618
618
  if (serverUp) {
619
619
  result = await apiPost(baseUrl, "/api/admin/migrate-markdown", body, config.auth.token);
620
620
  } else {
621
- const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-6WDMF6KX.cjs")));
621
+ const { MemoryService } = await Promise.resolve().then(() => _interopRequireWildcard(require("../memory-service-LURM3FBB.cjs")));
622
622
  const service = new MemoryService();
623
623
  await service.init();
624
624
  try {
@@ -662,7 +662,7 @@ function infraCommand() {
662
662
  let tier = opts.tier;
663
663
  if (!tier) {
664
664
  try {
665
- const config = await _chunkZY2C2CJQcjs.loadConfig.call(void 0, );
665
+ const config = await _chunkLA5OP5VIcjs.loadConfig.call(void 0, );
666
666
  tier = config.tier;
667
667
  } catch (e13) {
668
668
  tier = "standard";
@@ -679,7 +679,7 @@ function infraCommand() {
679
679
  error("Expected in ./docker/ or ./templates/ directory");
680
680
  process.exit(1);
681
681
  }
682
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
682
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
683
683
  _fs2.default.mkdirSync(dataDir, { recursive: true });
684
684
  const targetPath = _path2.default.join(dataDir, "docker-compose.yml");
685
685
  _fs2.default.copyFileSync(templatePath, targetPath);
@@ -698,7 +698,7 @@ function infraCommand() {
698
698
  });
699
699
  infra.command("down").description("Stop Docker containers").action(async () => {
700
700
  header("Infrastructure Down");
701
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
701
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
702
702
  const composePath = _path2.default.join(dataDir, "docker-compose.yml");
703
703
  if (!_fs2.default.existsSync(composePath)) {
704
704
  warn("No docker-compose.yml found in data directory");
@@ -717,7 +717,7 @@ function infraCommand() {
717
717
  });
718
718
  infra.command("status").description("Show Docker container status").action(async () => {
719
719
  header("Infrastructure Status");
720
- const dataDir = _chunkZY2C2CJQcjs.getDataDir.call(void 0, );
720
+ const dataDir = _chunkLA5OP5VIcjs.getDataDir.call(void 0, );
721
721
  const composePath = _path2.default.join(dataDir, "docker-compose.yml");
722
722
  if (!_fs2.default.existsSync(composePath)) {
723
723
  info("No docker-compose.yml found \u2014 infrastructure not set up");
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/robertpop/work/personal/openclaw-memory/dist/cli/index.cjs","../../src/cli/index.ts","../../src/cli/commands/init.ts","../../src/cli/utils.ts","../../src/cli/commands/start.ts","../../src/cli/commands/stop.ts","../../src/cli/commands/status.ts","../../src/cli/commands/store.ts","../../src/cli/commands/search.ts","../../src/cli/commands/migrate.ts","../../src/cli/commands/infra.ts"],"names":[],"mappings":"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","file":"/Users/robertpop/work/personal/openclaw-memory/dist/cli/index.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { startCommand } from \"./commands/start.js\";\nimport { stopCommand } from \"./commands/stop.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { storeCommand } from \"./commands/store.js\";\nimport { searchCommand } from \"./commands/search.js\";\nimport { migrateCommand } from \"./commands/migrate.js\";\nimport { infraCommand } from \"./commands/infra.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"openclaw-memory\")\n .description(\"Triple-layer memory system for AI agents — SQLite + Qdrant + Postgres/AGE\")\n .version(\"0.1.0\");\n\n// Register commands\nprogram.addCommand(initCommand());\nprogram.addCommand(startCommand());\nprogram.addCommand(stopCommand());\nprogram.addCommand(statusCommand());\nprogram.addCommand(storeCommand());\nprogram.addCommand(searchCommand());\nprogram.addCommand(migrateCommand());\nprogram.addCommand(infraCommand());\n\nprogram.parse();\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { header, success, info, warn, error as logError } from \"../utils.js\";\nimport { getDataDir, getDefaultSqlitePath } from \"../../config/index.js\";\n\nexport function initCommand(): Command {\n return new Command(\"init\")\n .description(\"Interactive setup wizard\")\n .option(\"--tier <tier>\", \"Tier: lite, standard, or full\")\n .option(\"--non-interactive\", \"Skip prompts, use defaults + flags\")\n .action(async (opts) => {\n header(\"Setup Wizard\");\n\n // For non-interactive mode, generate config from flags/defaults\n const tier = opts.tier || \"lite\";\n const dataDir = getDataDir();\n const sqlitePath = getDefaultSqlitePath();\n\n // Ensure data directory exists\n fs.mkdirSync(dataDir, { recursive: true });\n info(`Data directory: ${dataDir}`);\n\n // Auto-detect available services\n let qdrantAvailable = false;\n let ageAvailable = false;\n\n if (tier !== \"lite\") {\n info(\"Checking Qdrant connectivity...\");\n try {\n const res = await fetch(\"http://localhost:6333/collections\", {\n signal: AbortSignal.timeout(2000),\n });\n qdrantAvailable = res.ok;\n } catch { /* not available */ }\n\n if (qdrantAvailable) {\n success(\"Qdrant is reachable at http://localhost:6333\");\n } else {\n warn(\"Qdrant not reachable at http://localhost:6333\");\n }\n }\n\n if (tier === \"full\") {\n info(\"Checking PostgreSQL/AGE connectivity...\");\n try {\n // Simple TCP check\n const net = await import(\"node:net\");\n ageAvailable = await new Promise<boolean>((resolve) => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.connect(5432, \"localhost\", () => {\n socket.destroy();\n resolve(true);\n });\n socket.on(\"error\", () => resolve(false));\n socket.on(\"timeout\", () => { socket.destroy(); resolve(false); });\n });\n } catch { /* not available */ }\n\n if (ageAvailable) {\n success(\"PostgreSQL is reachable at localhost:5432\");\n } else {\n warn(\"PostgreSQL not reachable at localhost:5432\");\n }\n }\n\n // Determine effective tier\n let effectiveTier = tier;\n if (tier === \"full\" && !ageAvailable) {\n effectiveTier = qdrantAvailable ? \"standard\" : \"lite\";\n warn(`Downgrading to ${effectiveTier} tier (missing dependencies)`);\n } else if (tier === \"standard\" && !qdrantAvailable) {\n effectiveTier = \"lite\";\n warn(\"Downgrading to lite tier (Qdrant not available)\");\n }\n\n // Generate config file\n const configContent = generateConfig(effectiveTier, sqlitePath);\n const configPath = path.join(process.cwd(), \"openclaw-memory.config.ts\");\n\n fs.writeFileSync(configPath, configContent, \"utf-8\");\n success(`Config written to ${configPath}`);\n\n // Generate .env.example\n const envExample = generateEnvExample(effectiveTier);\n const envPath = path.join(process.cwd(), \".env.example\");\n fs.writeFileSync(envPath, envExample, \"utf-8\");\n success(`Environment template written to ${envPath}`);\n\n console.log();\n info(\"Next steps:\");\n console.log(\" openclaw-memory start # Start the server\");\n console.log(\" openclaw-memory status # Check all layers\");\n console.log();\n });\n}\n\nfunction generateConfig(tier: string, sqlitePath: string): string {\n const lines = [\n `import { defineConfig } from 'openclaw-memory';`,\n ``,\n `export default defineConfig({`,\n ` tier: '${tier}',`,\n ` port: 7777,`,\n ` auth: {`,\n ` token: process.env.MEMORY_AUTH_TOKEN || 'change-me',`,\n ` },`,\n ` sqlite: {`,\n ` path: '${sqlitePath}',`,\n ` },`,\n ];\n\n if (tier === \"standard\" || tier === \"full\") {\n lines.push(` qdrant: {`);\n lines.push(` url: process.env.QDRANT_URL || 'http://localhost:6333',`);\n lines.push(` collection: 'openclaw_memories',`);\n lines.push(` },`);\n lines.push(` embedding: {`);\n lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);\n lines.push(` model: 'text-embedding-3-small',`);\n lines.push(` dimensions: 1536,`);\n lines.push(` },`);\n lines.push(` extraction: {`);\n lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);\n lines.push(` model: 'gpt-4o-mini',`);\n lines.push(` enabled: true,`);\n lines.push(` },`);\n }\n\n if (tier === \"full\") {\n lines.push(` age: {`);\n lines.push(` host: process.env.PGHOST || 'localhost',`);\n lines.push(` port: parseInt(process.env.PGPORT || '5432', 10),`);\n lines.push(` user: process.env.PGUSER || 'openclaw',`);\n lines.push(` password: process.env.PGPASSWORD || '',`);\n lines.push(` database: process.env.PGDATABASE || 'agent_memory',`);\n lines.push(` graph: 'agent_memory',`);\n lines.push(` },`);\n }\n\n lines.push(`});`);\n lines.push(``);\n\n return lines.join(\"\\n\");\n}\n\nfunction generateEnvExample(tier: string): string {\n const lines = [\n `# openclaw-memory environment variables`,\n ``,\n `# Server`,\n `# OPENCLAW_MEMORY_PORT=7777`,\n `# OPENCLAW_MEMORY_HOST=0.0.0.0`,\n ``,\n `# Authentication`,\n `MEMORY_AUTH_TOKEN=change-me-to-a-secure-token`,\n ``,\n `# SQLite (always required)`,\n `# SQLITE_PATH=~/.openclaw-memory/memory.sqlite`,\n ``,\n ];\n\n if (tier === \"standard\" || tier === \"full\") {\n lines.push(`# Qdrant (Standard/Full tier)`);\n lines.push(`QDRANT_URL=http://localhost:6333`);\n lines.push(``);\n lines.push(`# Embedding provider`);\n lines.push(`OPENAI_API_KEY=sk-your-key-here`);\n lines.push(`# EMBEDDING_MODEL=text-embedding-3-small`);\n lines.push(`# EMBEDDING_BASE_URL=https://api.openai.com/v1`);\n lines.push(``);\n lines.push(`# Entity extraction`);\n lines.push(`# EXTRACTION_MODEL=gpt-4o-mini`);\n lines.push(``);\n }\n\n if (tier === \"full\") {\n lines.push(`# PostgreSQL + Apache AGE (Full tier)`);\n lines.push(`PGHOST=localhost`);\n lines.push(`PGPORT=5432`);\n lines.push(`PGUSER=openclaw`);\n lines.push(`PGPASSWORD=your-password`);\n lines.push(`PGDATABASE=agent_memory`);\n lines.push(`# AGE_GRAPH=agent_memory`);\n lines.push(``);\n }\n\n return lines.join(\"\\n\");\n}\n","import pc from \"picocolors\";\nimport fs from \"node:fs\";\nimport { getPidFilePath } from \"../config/index.js\";\n\n// ── CLI Utilities ───────────────────────────────────────────────────────\n\nexport function log(msg: string): void {\n console.log(msg);\n}\n\nexport function info(msg: string): void {\n console.log(pc.blue(\"ℹ\") + \" \" + msg);\n}\n\nexport function success(msg: string): void {\n console.log(pc.green(\"✓\") + \" \" + msg);\n}\n\nexport function warn(msg: string): void {\n console.log(pc.yellow(\"⚠\") + \" \" + msg);\n}\n\nexport function error(msg: string): void {\n console.error(pc.red(\"✗\") + \" \" + msg);\n}\n\nexport function header(title: string): void {\n console.log();\n console.log(pc.bold(` 🧠 OpenClaw Memory — ${title}`));\n console.log();\n}\n\nexport function bullet(label: string, value: string, status?: \"ok\" | \"error\" | \"disabled\" | \"degraded\"): void {\n const dot = status === \"ok\" ? pc.green(\"●\")\n : status === \"error\" ? pc.red(\"●\")\n : status === \"degraded\" ? pc.yellow(\"●\")\n : status === \"disabled\" ? pc.dim(\"○\")\n : \" \";\n console.log(` ${dot} ${pc.bold(label)} ${value}`);\n}\n\n// ── Server Detection ────────────────────────────────────────────────────\n\nexport function getServerPid(): number | null {\n const pidPath = getPidFilePath();\n if (!fs.existsSync(pidPath)) return null;\n\n try {\n const pid = parseInt(fs.readFileSync(pidPath, \"utf-8\").trim(), 10);\n if (isNaN(pid)) return null;\n\n // Check if process is alive\n try {\n process.kill(pid, 0);\n return pid;\n } catch {\n // Process not running, clean up stale PID file\n fs.unlinkSync(pidPath);\n return null;\n }\n } catch {\n return null;\n }\n}\n\nexport async function isServerRunning(baseUrl: string = \"http://localhost:7777\"): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl}/api/health`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport function getBaseUrl(port?: number): string {\n return `http://localhost:${port || 7777}`;\n}\n\n// ── HTTP Client ─────────────────────────────────────────────────────────\n\nexport async function apiGet(baseUrl: string, path: string, token?: string): Promise<unknown> {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, { headers });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\nexport async function apiPost(baseUrl: string, path: string, body: unknown, token?: string): Promise<unknown> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\nexport async function apiDelete(baseUrl: string, path: string, token?: string): Promise<unknown> {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, {\n method: \"DELETE\",\n headers,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\n// ── Output Formatting ───────────────────────────────────────────────────\n\nexport function output(data: unknown, format: \"json\" | \"text\" = \"json\"): void {\n if (format === \"text\") {\n console.log(JSON.stringify(data, null, 2));\n } else {\n console.log(JSON.stringify(data));\n }\n}\n\n// ── Stdin Reading ───────────────────────────────────────────────────────\n\nexport async function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return \"\";\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf-8\").trim();\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { spawn } from \"node:child_process\";\nimport { header, success, info, error as logError } from \"../utils.js\";\nimport { getPidFilePath, getDataDir } from \"../../config/index.js\";\n\nexport function startCommand(): Command {\n return new Command(\"start\")\n .description(\"Start the HTTP server\")\n .option(\"-p, --port <port>\", \"Server port\")\n .option(\"--bg\", \"Run in background (daemon mode)\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n if (opts.bg) {\n await startBackground(opts);\n } else {\n await startForeground(opts);\n }\n });\n}\n\nasync function startForeground(opts: { port?: string; config?: string }): Promise<void> {\n // Set port if specified\n if (opts.port) {\n process.env.OPENCLAW_MEMORY_PORT = opts.port;\n process.env.PORT = opts.port;\n }\n\n // Import and run server directly\n const { createServer } = await import(\"../../server.js\");\n const { app, config } = await createServer(opts.config);\n\n const port = opts.port ? parseInt(opts.port, 10) : config.port;\n app.listen(port);\n\n console.log(`[server] Listening on http://0.0.0.0:${port}`);\n\n // Write PID file for status/stop commands\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n fs.writeFileSync(getPidFilePath(), String(process.pid), \"utf-8\");\n\n const cleanup = () => {\n try { fs.unlinkSync(getPidFilePath()); } catch {}\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n}\n\nasync function startBackground(opts: { port?: string; config?: string }): Promise<void> {\n header(\"Starting Server (background)\");\n\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n\n // Build the command to run\n const args = [\"run\", \"src/server.ts\"];\n const env = { ...process.env };\n\n if (opts.port) {\n env.OPENCLAW_MEMORY_PORT = opts.port;\n env.PORT = opts.port;\n }\n\n // Detect runtime\n const runtime = typeof Bun !== \"undefined\" ? \"bun\" : \"node\";\n const execPath = runtime === \"bun\" ? \"bun\" : process.execPath;\n const execArgs = runtime === \"bun\" ? args : [\"--import\", \"tsx\", ...args];\n\n const child = spawn(execPath, execArgs, {\n env,\n detached: true,\n stdio: \"ignore\",\n cwd: process.cwd(),\n });\n\n child.unref();\n\n if (child.pid) {\n fs.writeFileSync(getPidFilePath(), String(child.pid), \"utf-8\");\n success(`Server started in background (PID: ${child.pid})`);\n info(`PID file: ${getPidFilePath()}`);\n info(`Stop with: openclaw-memory stop`);\n } else {\n logError(\"Failed to start server\");\n process.exit(1);\n }\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { header, success, warn, error as logError } from \"../utils.js\";\nimport { getPidFilePath } from \"../../config/index.js\";\n\nexport function stopCommand(): Command {\n return new Command(\"stop\")\n .description(\"Stop the running server\")\n .action(async () => {\n header(\"Stopping Server\");\n\n const pidPath = getPidFilePath();\n if (!fs.existsSync(pidPath)) {\n warn(\"No PID file found — server may not be running\");\n return;\n }\n\n const pidStr = fs.readFileSync(pidPath, \"utf-8\").trim();\n const pid = parseInt(pidStr, 10);\n\n if (isNaN(pid)) {\n logError(`Invalid PID in ${pidPath}: ${pidStr}`);\n return;\n }\n\n try {\n // Send SIGTERM for graceful shutdown\n process.kill(pid, \"SIGTERM\");\n success(`Sent SIGTERM to PID ${pid}`);\n\n // Wait up to 3 seconds for graceful shutdown\n let alive = true;\n for (let i = 0; i < 30; i++) {\n await new Promise((r) => setTimeout(r, 100));\n try {\n process.kill(pid, 0);\n } catch {\n alive = false;\n break;\n }\n }\n\n if (alive) {\n warn(\"Process still running after 3s, sending SIGKILL...\");\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {}\n }\n\n success(\"Server stopped\");\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"ESRCH\") {\n warn(`Process ${pid} not found — may have already stopped`);\n } else {\n logError(`Failed to stop process ${pid}: ${err}`);\n }\n }\n\n // Clean up PID file\n try {\n fs.unlinkSync(pidPath);\n } catch {}\n });\n}\n","import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { header, bullet, info, getServerPid, isServerRunning, getBaseUrl, apiGet } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function statusCommand(): Command {\n return new Command(\"status\")\n .description(\"Show server and layer health status\")\n .option(\"-p, --port <port>\", \"Server port to check\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n header(\"Status\");\n\n let config;\n try {\n config = await loadConfig(opts.config);\n } catch {\n config = null;\n }\n\n const port = opts.port ? parseInt(opts.port, 10) : config?.port || 7777;\n const baseUrl = getBaseUrl(port);\n const pid = getServerPid();\n const running = await isServerRunning(baseUrl);\n\n // Server status\n if (running && pid) {\n bullet(\"Server\", `Running (PID ${pid}, port ${port})`, \"ok\");\n } else if (running) {\n bullet(\"Server\", `Running (port ${port})`, \"ok\");\n } else if (pid) {\n bullet(\"Server\", `PID file exists (${pid}) but not responding`, \"error\");\n } else {\n bullet(\"Server\", \"Not running\", \"disabled\");\n }\n\n if (config) {\n bullet(\"Tier\", config.tier, undefined);\n }\n\n console.log();\n\n // If server is running, get health from API\n if (running) {\n try {\n const health = await apiGet(baseUrl, \"/api/health\", config?.auth?.token) as Record<string, unknown>;\n\n info(\"Layers:\");\n const sqliteStatus = health.sqlite === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L1 SQLite\", String(health.sqlite), sqliteStatus);\n\n if (health.qdrant !== \"disabled\") {\n const qdrantStatus = health.qdrant === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L2 Qdrant\", String(health.qdrant), qdrantStatus);\n } else {\n bullet(\"L2 Qdrant\", \"disabled\", \"disabled\");\n }\n\n if (health.age !== \"disabled\") {\n const ageStatus = health.age === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L3 AGE\", String(health.age), ageStatus);\n } else {\n bullet(\"L3 AGE\", \"disabled\", \"disabled\");\n }\n\n if (health.uptime !== undefined) {\n const uptime = formatUptime(Number(health.uptime));\n console.log();\n info(`Uptime: ${uptime}`);\n }\n } catch (error) {\n info(\"Could not fetch health status from server\");\n }\n } else {\n // Server not running — try direct layer checks\n if (config) {\n info(\"Server not running. Checking layers directly...\");\n console.log();\n\n // SQLite — always available\n bullet(\"L1 SQLite\", config.sqlite.path, \"ok\");\n\n // Qdrant\n if (config.qdrant) {\n try {\n const res = await fetch(`${config.qdrant.url}/collections`, {\n signal: AbortSignal.timeout(2000),\n });\n bullet(\"L2 Qdrant\", config.qdrant.url, res.ok ? \"ok\" : \"error\");\n } catch {\n bullet(\"L2 Qdrant\", `${config.qdrant.url} (unreachable)`, \"error\");\n }\n } else {\n bullet(\"L2 Qdrant\", \"not configured\", \"disabled\");\n }\n\n // AGE\n if (config.age) {\n try {\n const net = await import(\"node:net\");\n const reachable = await new Promise<boolean>((resolve) => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.connect(config!.age!.port, config!.age!.host, () => {\n socket.destroy();\n resolve(true);\n });\n socket.on(\"error\", () => resolve(false));\n socket.on(\"timeout\", () => { socket.destroy(); resolve(false); });\n });\n bullet(\"L3 AGE\", `${config.age.host}:${config.age.port}`, reachable ? \"ok\" : \"error\");\n } catch {\n bullet(\"L3 AGE\", \"unreachable\", \"error\");\n }\n } else {\n bullet(\"L3 AGE\", \"not configured\", \"disabled\");\n }\n }\n }\n\n console.log();\n });\n}\n\nfunction formatUptime(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = seconds % 60;\n if (h > 0) return `${h}h ${m}m`;\n if (m > 0) return `${m}m ${s}s`;\n return `${s}s`;\n}\n","import { Command } from \"commander\";\nimport { output, readStdin, apiPost, isServerRunning, getBaseUrl } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function storeCommand(): Command {\n return new Command(\"store\")\n .description(\"Store a new memory\")\n .argument(\"[content]\", \"Memory content (or pipe via stdin)\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .requiredOption(\"--scope <scope>\", \"Memory scope (user, agent, global, project, session)\")\n .option(\"--subject <id>\", \"Subject ID\")\n .option(\"--tags <tags>\", \"Comma-separated tags\")\n .option(\"--source <source>\", \"Memory source\", \"explicit\")\n .option(\"--no-extract\", \"Skip entity extraction\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (contentArg, opts) => {\n const content = contentArg || await readStdin();\n if (!content) {\n console.error(\"Error: content is required (pass as argument or pipe via stdin)\");\n process.exit(1);\n }\n\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const body = {\n agent_id: opts.agent,\n scope: opts.scope,\n subject_id: opts.subject || null,\n content,\n tags: opts.tags ? opts.tags.split(\",\").map((t: string) => t.trim()) : [],\n source: opts.source,\n extract_entities: opts.extract !== false,\n };\n\n if (serverUp) {\n // Use HTTP API\n const result = await apiPost(baseUrl, \"/api/memories\", body, config.auth.token);\n output(result, opts.format);\n } else {\n // Direct mode — instantiate MemoryService in-process\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n\n try {\n const result = await service.store({\n agentId: opts.agent,\n scope: opts.scope,\n subjectId: opts.subject || null,\n content,\n tags: body.tags,\n source: opts.source,\n extractEntities: opts.extract !== false,\n });\n output(result, opts.format);\n } finally {\n await service.close();\n }\n }\n });\n}\n","import { Command } from \"commander\";\nimport { output, apiPost, isServerRunning, getBaseUrl } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function searchCommand(): Command {\n const cmd = new Command(\"search\")\n .description(\"Search memories\");\n\n // Default search (smart auto-select)\n cmd\n .argument(\"<query>\", \"Search query\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .option(\"--limit <n>\", \"Max results\", \"10\")\n .option(\"--strategy <s>\", \"Search strategy (auto, semantic, fulltext, graph, all)\", \"auto\")\n .option(\"--scopes <scopes>\", \"Comma-separated scopes\")\n .option(\"--subject <id>\", \"Subject ID filter\")\n .option(\"--cross-agent\", \"Search across all agents\")\n .option(\"--no-graph\", \"Exclude graph results\")\n .option(\"--recall\", \"Format output for LLM context injection\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (query, opts) => {\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const body = {\n agent_id: opts.agent,\n query,\n limit: parseInt(opts.limit, 10),\n strategy: opts.strategy,\n scopes: opts.scopes ? opts.scopes.split(\",\") : undefined,\n subject_id: opts.subject || null,\n cross_agent: opts.crossAgent || false,\n include_graph: opts.graph !== false,\n };\n\n let result: unknown;\n if (serverUp) {\n result = await apiPost(baseUrl, \"/api/search\", body, config.auth.token);\n } else {\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n try {\n result = await service.search({\n agentId: opts.agent,\n query,\n limit: parseInt(opts.limit, 10),\n strategy: opts.strategy,\n scopes: opts.scopes ? opts.scopes.split(\",\") : undefined,\n subjectId: opts.subject || null,\n crossAgent: opts.crossAgent || false,\n includeGraph: opts.graph !== false,\n });\n } finally {\n await service.close();\n }\n }\n\n // Recall mode — format for LLM\n if (opts.recall) {\n const data = result as { results?: Array<{ memory: { content: string; scope: string; created_at: string } }> };\n if (data.results && data.results.length > 0) {\n console.log(\"## Relevant Memories\");\n for (const r of data.results) {\n const date = new Date(r.memory.created_at).toLocaleDateString();\n console.log(`- ${r.memory.content} (${r.memory.scope}, ${date})`);\n }\n } else {\n console.log(\"No relevant memories found.\");\n }\n } else {\n output(result, opts.format);\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { output, apiPost, isServerRunning, getBaseUrl, success, info, header } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function migrateCommand(): Command {\n return new Command(\"migrate\")\n .description(\"Import memories from markdown files\")\n .requiredOption(\"--paths <paths>\", \"Comma-separated file paths\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .option(\"--dry-run\", \"Preview without writing\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const paths = opts.paths.split(\",\").map((p: string) => p.trim());\n\n if (opts.dryRun) {\n header(\"Migration (dry run)\");\n }\n\n const body = {\n markdown_paths: paths,\n agent_id: opts.agent,\n dry_run: opts.dryRun || false,\n };\n\n let result: unknown;\n if (serverUp) {\n result = await apiPost(baseUrl, \"/api/admin/migrate-markdown\", body, config.auth.token);\n } else {\n // Direct mode\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n try {\n const migrated = await service.migrateMarkdown(paths, opts.agent);\n result = migrated;\n } finally {\n await service.close();\n }\n }\n\n if (opts.format === \"text\") {\n const data = result as { migrated?: number; skipped?: number; errors?: string[] };\n if (data.migrated !== undefined) {\n success(`Migrated ${data.migrated} memories`);\n }\n if (data.skipped) {\n info(`Skipped ${data.skipped} sections`);\n }\n if (data.errors && data.errors.length > 0) {\n for (const err of data.errors) {\n console.error(` ✗ ${err}`);\n }\n }\n } else {\n output(result, opts.format);\n }\n });\n}\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { header, success, info, warn, error as logError } from \"../utils.js\";\nimport { getDataDir, loadConfig } from \"../../config/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function infraCommand(): Command {\n const infra = new Command(\"infra\")\n .description(\"Manage Docker infrastructure\");\n\n infra\n .command(\"up\")\n .description(\"Start Docker containers for the configured tier\")\n .option(\"--tier <tier>\", \"Override tier (standard, full)\")\n .action(async (opts) => {\n header(\"Infrastructure Up\");\n\n let tier = opts.tier;\n if (!tier) {\n try {\n const config = await loadConfig();\n tier = config.tier;\n } catch {\n tier = \"standard\";\n }\n }\n\n if (tier === \"lite\") {\n info(\"Lite tier uses only SQLite — no Docker infrastructure needed.\");\n return;\n }\n\n const templateFile = tier === \"full\" ? \"full.yml\" : \"standard.yml\";\n const templatePath = findTemplate(templateFile);\n\n if (!templatePath) {\n logError(`Template not found: ${templateFile}`);\n logError(\"Expected in ./docker/ or ./templates/ directory\");\n process.exit(1);\n }\n\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n\n const targetPath = path.join(dataDir, \"docker-compose.yml\");\n fs.copyFileSync(templatePath, targetPath);\n info(`Using template: ${templatePath}`);\n\n try {\n execSync(`docker compose -f ${targetPath} up -d`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n success(\"Docker containers started\");\n } catch (error) {\n logError(\"Failed to start Docker containers\");\n logError(\"Make sure Docker is installed and running\");\n process.exit(1);\n }\n });\n\n infra\n .command(\"down\")\n .description(\"Stop Docker containers\")\n .action(async () => {\n header(\"Infrastructure Down\");\n\n const dataDir = getDataDir();\n const composePath = path.join(dataDir, \"docker-compose.yml\");\n\n if (!fs.existsSync(composePath)) {\n warn(\"No docker-compose.yml found in data directory\");\n return;\n }\n\n try {\n execSync(`docker compose -f ${composePath} down`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n success(\"Docker containers stopped\");\n } catch (error) {\n logError(\"Failed to stop Docker containers\");\n process.exit(1);\n }\n });\n\n infra\n .command(\"status\")\n .description(\"Show Docker container status\")\n .action(async () => {\n header(\"Infrastructure Status\");\n\n const dataDir = getDataDir();\n const composePath = path.join(dataDir, \"docker-compose.yml\");\n\n if (!fs.existsSync(composePath)) {\n info(\"No docker-compose.yml found — infrastructure not set up\");\n info(\"Run: openclaw-memory infra up\");\n return;\n }\n\n try {\n execSync(`docker compose -f ${composePath} ps`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n } catch {\n logError(\"Failed to get container status\");\n }\n });\n\n return infra;\n}\n\nfunction findTemplate(filename: string): string | null {\n const searchPaths = [\n path.join(process.cwd(), \"docker\", filename),\n path.join(process.cwd(), \"templates\", filename),\n // Look in the package's installed location\n path.join(__dirname, \"../../docker\", filename),\n path.join(__dirname, \"../../templates\", filename),\n ];\n\n for (const p of searchPaths) {\n if (fs.existsSync(p)) return p;\n }\n\n return null;\n}\n"]}
1
+ {"version":3,"sources":["/Users/robertpop/work/personal/openclaw-memory/dist/cli/index.cjs","../../src/cli/index.ts","../../src/cli/commands/init.ts","../../src/cli/utils.ts","../../src/cli/commands/start.ts","../../src/cli/commands/stop.ts","../../src/cli/commands/status.ts","../../src/cli/commands/store.ts","../../src/cli/commands/search.ts","../../src/cli/commands/migrate.ts","../../src/cli/commands/infra.ts"],"names":[],"mappings":"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","file":"/Users/robertpop/work/personal/openclaw-memory/dist/cli/index.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { initCommand } from \"./commands/init.js\";\nimport { startCommand } from \"./commands/start.js\";\nimport { stopCommand } from \"./commands/stop.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { storeCommand } from \"./commands/store.js\";\nimport { searchCommand } from \"./commands/search.js\";\nimport { migrateCommand } from \"./commands/migrate.js\";\nimport { infraCommand } from \"./commands/infra.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"openclaw-memory\")\n .description(\"Triple-layer memory system for AI agents — SQLite + Qdrant + Postgres/AGE\")\n .version(\"0.1.0\");\n\n// Register commands\nprogram.addCommand(initCommand());\nprogram.addCommand(startCommand());\nprogram.addCommand(stopCommand());\nprogram.addCommand(statusCommand());\nprogram.addCommand(storeCommand());\nprogram.addCommand(searchCommand());\nprogram.addCommand(migrateCommand());\nprogram.addCommand(infraCommand());\n\nprogram.parse();\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { header, success, info, warn, error as logError } from \"../utils.js\";\nimport { getDataDir, getDefaultSqlitePath } from \"../../config/index.js\";\n\nexport function initCommand(): Command {\n return new Command(\"init\")\n .description(\"Interactive setup wizard\")\n .option(\"--tier <tier>\", \"Tier: lite, standard, or full\")\n .option(\"--non-interactive\", \"Skip prompts, use defaults + flags\")\n .action(async (opts) => {\n header(\"Setup Wizard\");\n\n // For non-interactive mode, generate config from flags/defaults\n const tier = opts.tier || \"lite\";\n const dataDir = getDataDir();\n const sqlitePath = getDefaultSqlitePath();\n\n // Ensure data directory exists\n fs.mkdirSync(dataDir, { recursive: true });\n info(`Data directory: ${dataDir}`);\n\n // Auto-detect available services\n let qdrantAvailable = false;\n let ageAvailable = false;\n\n if (tier !== \"lite\") {\n info(\"Checking Qdrant connectivity...\");\n try {\n const res = await fetch(\"http://localhost:6333/collections\", {\n signal: AbortSignal.timeout(2000),\n });\n qdrantAvailable = res.ok;\n } catch { /* not available */ }\n\n if (qdrantAvailable) {\n success(\"Qdrant is reachable at http://localhost:6333\");\n } else {\n warn(\"Qdrant not reachable at http://localhost:6333\");\n }\n }\n\n if (tier === \"full\") {\n info(\"Checking PostgreSQL/AGE connectivity...\");\n try {\n // Simple TCP check\n const net = await import(\"node:net\");\n ageAvailable = await new Promise<boolean>((resolve) => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.connect(5432, \"localhost\", () => {\n socket.destroy();\n resolve(true);\n });\n socket.on(\"error\", () => resolve(false));\n socket.on(\"timeout\", () => { socket.destroy(); resolve(false); });\n });\n } catch { /* not available */ }\n\n if (ageAvailable) {\n success(\"PostgreSQL is reachable at localhost:5432\");\n } else {\n warn(\"PostgreSQL not reachable at localhost:5432\");\n }\n }\n\n // Determine effective tier\n let effectiveTier = tier;\n if (tier === \"full\" && !ageAvailable) {\n effectiveTier = qdrantAvailable ? \"standard\" : \"lite\";\n warn(`Downgrading to ${effectiveTier} tier (missing dependencies)`);\n } else if (tier === \"standard\" && !qdrantAvailable) {\n effectiveTier = \"lite\";\n warn(\"Downgrading to lite tier (Qdrant not available)\");\n }\n\n // Generate config file\n const configContent = generateConfig(effectiveTier, sqlitePath);\n const configPath = path.join(process.cwd(), \"openclaw-memory.config.ts\");\n\n fs.writeFileSync(configPath, configContent, \"utf-8\");\n success(`Config written to ${configPath}`);\n\n // Generate .env.example\n const envExample = generateEnvExample(effectiveTier);\n const envPath = path.join(process.cwd(), \".env.example\");\n fs.writeFileSync(envPath, envExample, \"utf-8\");\n success(`Environment template written to ${envPath}`);\n\n console.log();\n info(\"Next steps:\");\n console.log(\" openclaw-memory start # Start the server\");\n console.log(\" openclaw-memory status # Check all layers\");\n console.log();\n });\n}\n\nfunction generateConfig(tier: string, sqlitePath: string): string {\n const lines = [\n `import { defineConfig } from '@poprobertdaniel/openclaw-memory';`,\n ``,\n `export default defineConfig({`,\n ` tier: '${tier}',`,\n ` port: 7777,`,\n ` auth: {`,\n ` token: process.env.MEMORY_AUTH_TOKEN || 'change-me',`,\n ` },`,\n ` sqlite: {`,\n ` path: '${sqlitePath}',`,\n ` },`,\n ];\n\n if (tier === \"standard\" || tier === \"full\") {\n lines.push(` qdrant: {`);\n lines.push(` url: process.env.QDRANT_URL || 'http://localhost:6333',`);\n lines.push(` collection: 'openclaw_memories',`);\n lines.push(` },`);\n lines.push(` embedding: {`);\n lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);\n lines.push(` model: 'text-embedding-3-small',`);\n lines.push(` dimensions: 1536,`);\n lines.push(` },`);\n lines.push(` extraction: {`);\n lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);\n lines.push(` model: 'gpt-5-nano',`);\n lines.push(` enabled: true,`);\n lines.push(` },`);\n }\n\n if (tier === \"full\") {\n lines.push(` age: {`);\n lines.push(` host: process.env.PGHOST || 'localhost',`);\n lines.push(` port: parseInt(process.env.PGPORT || '5432', 10),`);\n lines.push(` user: process.env.PGUSER || 'openclaw',`);\n lines.push(` password: process.env.PGPASSWORD || '',`);\n lines.push(` database: process.env.PGDATABASE || 'agent_memory',`);\n lines.push(` graph: 'agent_memory',`);\n lines.push(` },`);\n }\n\n lines.push(`});`);\n lines.push(``);\n\n return lines.join(\"\\n\");\n}\n\nfunction generateEnvExample(tier: string): string {\n const lines = [\n `# openclaw-memory environment variables`,\n ``,\n `# Server`,\n `# OPENCLAW_MEMORY_PORT=7777`,\n `# OPENCLAW_MEMORY_HOST=0.0.0.0`,\n ``,\n `# Authentication`,\n `MEMORY_AUTH_TOKEN=change-me-to-a-secure-token`,\n ``,\n `# SQLite (always required)`,\n `# SQLITE_PATH=~/.openclaw-memory/memory.sqlite`,\n ``,\n ];\n\n if (tier === \"standard\" || tier === \"full\") {\n lines.push(`# Qdrant (Standard/Full tier)`);\n lines.push(`QDRANT_URL=http://localhost:6333`);\n lines.push(``);\n lines.push(`# Embedding provider`);\n lines.push(`OPENAI_API_KEY=sk-your-key-here`);\n lines.push(`# EMBEDDING_MODEL=text-embedding-3-small`);\n lines.push(`# EMBEDDING_BASE_URL=https://api.openai.com/v1`);\n lines.push(``);\n lines.push(`# Entity extraction`);\n lines.push(`# EXTRACTION_MODEL=gpt-5-nano`);\n lines.push(``);\n }\n\n if (tier === \"full\") {\n lines.push(`# PostgreSQL + Apache AGE (Full tier)`);\n lines.push(`PGHOST=localhost`);\n lines.push(`PGPORT=5432`);\n lines.push(`PGUSER=openclaw`);\n lines.push(`PGPASSWORD=your-password`);\n lines.push(`PGDATABASE=agent_memory`);\n lines.push(`# AGE_GRAPH=agent_memory`);\n lines.push(``);\n }\n\n return lines.join(\"\\n\");\n}\n","import pc from \"picocolors\";\nimport fs from \"node:fs\";\nimport { getPidFilePath } from \"../config/index.js\";\n\n// ── CLI Utilities ───────────────────────────────────────────────────────\n\nexport function log(msg: string): void {\n console.log(msg);\n}\n\nexport function info(msg: string): void {\n console.log(pc.blue(\"ℹ\") + \" \" + msg);\n}\n\nexport function success(msg: string): void {\n console.log(pc.green(\"✓\") + \" \" + msg);\n}\n\nexport function warn(msg: string): void {\n console.log(pc.yellow(\"⚠\") + \" \" + msg);\n}\n\nexport function error(msg: string): void {\n console.error(pc.red(\"✗\") + \" \" + msg);\n}\n\nexport function header(title: string): void {\n console.log();\n console.log(pc.bold(` 🧠 OpenClaw Memory — ${title}`));\n console.log();\n}\n\nexport function bullet(label: string, value: string, status?: \"ok\" | \"error\" | \"disabled\" | \"degraded\"): void {\n const dot = status === \"ok\" ? pc.green(\"●\")\n : status === \"error\" ? pc.red(\"●\")\n : status === \"degraded\" ? pc.yellow(\"●\")\n : status === \"disabled\" ? pc.dim(\"○\")\n : \" \";\n console.log(` ${dot} ${pc.bold(label)} ${value}`);\n}\n\n// ── Server Detection ────────────────────────────────────────────────────\n\nexport function getServerPid(): number | null {\n const pidPath = getPidFilePath();\n if (!fs.existsSync(pidPath)) return null;\n\n try {\n const pid = parseInt(fs.readFileSync(pidPath, \"utf-8\").trim(), 10);\n if (isNaN(pid)) return null;\n\n // Check if process is alive\n try {\n process.kill(pid, 0);\n return pid;\n } catch {\n // Process not running, clean up stale PID file\n fs.unlinkSync(pidPath);\n return null;\n }\n } catch {\n return null;\n }\n}\n\nexport async function isServerRunning(baseUrl: string = \"http://localhost:7777\"): Promise<boolean> {\n try {\n const res = await fetch(`${baseUrl}/api/health`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport function getBaseUrl(port?: number): string {\n return `http://localhost:${port || 7777}`;\n}\n\n// ── HTTP Client ─────────────────────────────────────────────────────────\n\nexport async function apiGet(baseUrl: string, path: string, token?: string): Promise<unknown> {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, { headers });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\nexport async function apiPost(baseUrl: string, path: string, body: unknown, token?: string): Promise<unknown> {\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" };\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\nexport async function apiDelete(baseUrl: string, path: string, token?: string): Promise<unknown> {\n const headers: Record<string, string> = {};\n if (token) headers.Authorization = `Bearer ${token}`;\n\n const res = await fetch(`${baseUrl}${path}`, {\n method: \"DELETE\",\n headers,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`HTTP ${res.status}: ${text}`);\n }\n return res.json();\n}\n\n// ── Output Formatting ───────────────────────────────────────────────────\n\nexport function output(data: unknown, format: \"json\" | \"text\" = \"json\"): void {\n if (format === \"text\") {\n console.log(JSON.stringify(data, null, 2));\n } else {\n console.log(JSON.stringify(data));\n }\n}\n\n// ── Stdin Reading ───────────────────────────────────────────────────────\n\nexport async function readStdin(): Promise<string> {\n if (process.stdin.isTTY) return \"\";\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf-8\").trim();\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { spawn } from \"node:child_process\";\nimport { header, success, info, error as logError } from \"../utils.js\";\nimport { getPidFilePath, getDataDir } from \"../../config/index.js\";\n\nexport function startCommand(): Command {\n return new Command(\"start\")\n .description(\"Start the HTTP server\")\n .option(\"-p, --port <port>\", \"Server port\")\n .option(\"--bg\", \"Run in background (daemon mode)\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n if (opts.bg) {\n await startBackground(opts);\n } else {\n await startForeground(opts);\n }\n });\n}\n\nasync function startForeground(opts: { port?: string; config?: string }): Promise<void> {\n // Set port if specified\n if (opts.port) {\n process.env.OPENCLAW_MEMORY_PORT = opts.port;\n process.env.PORT = opts.port;\n }\n\n // Import and run server directly\n const { createServer } = await import(\"../../server.js\");\n const { app, config } = await createServer(opts.config);\n\n const port = opts.port ? parseInt(opts.port, 10) : config.port;\n app.listen(port);\n\n console.log(`[server] Listening on http://0.0.0.0:${port}`);\n\n // Write PID file for status/stop commands\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n fs.writeFileSync(getPidFilePath(), String(process.pid), \"utf-8\");\n\n const cleanup = () => {\n try { fs.unlinkSync(getPidFilePath()); } catch {}\n process.exit(0);\n };\n\n process.on(\"SIGINT\", cleanup);\n process.on(\"SIGTERM\", cleanup);\n}\n\nasync function startBackground(opts: { port?: string; config?: string }): Promise<void> {\n header(\"Starting Server (background)\");\n\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n\n // Build the command to run\n const args = [\"run\", \"src/server.ts\"];\n const env = { ...process.env };\n\n if (opts.port) {\n env.OPENCLAW_MEMORY_PORT = opts.port;\n env.PORT = opts.port;\n }\n\n // Detect runtime\n const runtime = typeof Bun !== \"undefined\" ? \"bun\" : \"node\";\n const execPath = runtime === \"bun\" ? \"bun\" : process.execPath;\n const execArgs = runtime === \"bun\" ? args : [\"--import\", \"tsx\", ...args];\n\n const child = spawn(execPath, execArgs, {\n env,\n detached: true,\n stdio: \"ignore\",\n cwd: process.cwd(),\n });\n\n child.unref();\n\n if (child.pid) {\n fs.writeFileSync(getPidFilePath(), String(child.pid), \"utf-8\");\n success(`Server started in background (PID: ${child.pid})`);\n info(`PID file: ${getPidFilePath()}`);\n info(`Stop with: openclaw-memory stop`);\n } else {\n logError(\"Failed to start server\");\n process.exit(1);\n }\n}\n","import { Command } from \"commander\";\nimport fs from \"node:fs\";\nimport { header, success, warn, error as logError } from \"../utils.js\";\nimport { getPidFilePath } from \"../../config/index.js\";\n\nexport function stopCommand(): Command {\n return new Command(\"stop\")\n .description(\"Stop the running server\")\n .action(async () => {\n header(\"Stopping Server\");\n\n const pidPath = getPidFilePath();\n if (!fs.existsSync(pidPath)) {\n warn(\"No PID file found — server may not be running\");\n return;\n }\n\n const pidStr = fs.readFileSync(pidPath, \"utf-8\").trim();\n const pid = parseInt(pidStr, 10);\n\n if (isNaN(pid)) {\n logError(`Invalid PID in ${pidPath}: ${pidStr}`);\n return;\n }\n\n try {\n // Send SIGTERM for graceful shutdown\n process.kill(pid, \"SIGTERM\");\n success(`Sent SIGTERM to PID ${pid}`);\n\n // Wait up to 3 seconds for graceful shutdown\n let alive = true;\n for (let i = 0; i < 30; i++) {\n await new Promise((r) => setTimeout(r, 100));\n try {\n process.kill(pid, 0);\n } catch {\n alive = false;\n break;\n }\n }\n\n if (alive) {\n warn(\"Process still running after 3s, sending SIGKILL...\");\n try {\n process.kill(pid, \"SIGKILL\");\n } catch {}\n }\n\n success(\"Server stopped\");\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code === \"ESRCH\") {\n warn(`Process ${pid} not found — may have already stopped`);\n } else {\n logError(`Failed to stop process ${pid}: ${err}`);\n }\n }\n\n // Clean up PID file\n try {\n fs.unlinkSync(pidPath);\n } catch {}\n });\n}\n","import { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { header, bullet, info, getServerPid, isServerRunning, getBaseUrl, apiGet } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function statusCommand(): Command {\n return new Command(\"status\")\n .description(\"Show server and layer health status\")\n .option(\"-p, --port <port>\", \"Server port to check\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n header(\"Status\");\n\n let config;\n try {\n config = await loadConfig(opts.config);\n } catch {\n config = null;\n }\n\n const port = opts.port ? parseInt(opts.port, 10) : config?.port || 7777;\n const baseUrl = getBaseUrl(port);\n const pid = getServerPid();\n const running = await isServerRunning(baseUrl);\n\n // Server status\n if (running && pid) {\n bullet(\"Server\", `Running (PID ${pid}, port ${port})`, \"ok\");\n } else if (running) {\n bullet(\"Server\", `Running (port ${port})`, \"ok\");\n } else if (pid) {\n bullet(\"Server\", `PID file exists (${pid}) but not responding`, \"error\");\n } else {\n bullet(\"Server\", \"Not running\", \"disabled\");\n }\n\n if (config) {\n bullet(\"Tier\", config.tier, undefined);\n }\n\n console.log();\n\n // If server is running, get health from API\n if (running) {\n try {\n const health = await apiGet(baseUrl, \"/api/health\", config?.auth?.token) as Record<string, unknown>;\n\n info(\"Layers:\");\n const sqliteStatus = health.sqlite === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L1 SQLite\", String(health.sqlite), sqliteStatus);\n\n if (health.qdrant !== \"disabled\") {\n const qdrantStatus = health.qdrant === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L2 Qdrant\", String(health.qdrant), qdrantStatus);\n } else {\n bullet(\"L2 Qdrant\", \"disabled\", \"disabled\");\n }\n\n if (health.age !== \"disabled\") {\n const ageStatus = health.age === \"ok\" ? \"ok\" as const : \"error\" as const;\n bullet(\"L3 AGE\", String(health.age), ageStatus);\n } else {\n bullet(\"L3 AGE\", \"disabled\", \"disabled\");\n }\n\n if (health.uptime !== undefined) {\n const uptime = formatUptime(Number(health.uptime));\n console.log();\n info(`Uptime: ${uptime}`);\n }\n } catch (error) {\n info(\"Could not fetch health status from server\");\n }\n } else {\n // Server not running — try direct layer checks\n if (config) {\n info(\"Server not running. Checking layers directly...\");\n console.log();\n\n // SQLite — always available\n bullet(\"L1 SQLite\", config.sqlite.path, \"ok\");\n\n // Qdrant\n if (config.qdrant) {\n try {\n const res = await fetch(`${config.qdrant.url}/collections`, {\n signal: AbortSignal.timeout(2000),\n });\n bullet(\"L2 Qdrant\", config.qdrant.url, res.ok ? \"ok\" : \"error\");\n } catch {\n bullet(\"L2 Qdrant\", `${config.qdrant.url} (unreachable)`, \"error\");\n }\n } else {\n bullet(\"L2 Qdrant\", \"not configured\", \"disabled\");\n }\n\n // AGE\n if (config.age) {\n try {\n const net = await import(\"node:net\");\n const reachable = await new Promise<boolean>((resolve) => {\n const socket = new net.Socket();\n socket.setTimeout(2000);\n socket.connect(config!.age!.port, config!.age!.host, () => {\n socket.destroy();\n resolve(true);\n });\n socket.on(\"error\", () => resolve(false));\n socket.on(\"timeout\", () => { socket.destroy(); resolve(false); });\n });\n bullet(\"L3 AGE\", `${config.age.host}:${config.age.port}`, reachable ? \"ok\" : \"error\");\n } catch {\n bullet(\"L3 AGE\", \"unreachable\", \"error\");\n }\n } else {\n bullet(\"L3 AGE\", \"not configured\", \"disabled\");\n }\n }\n }\n\n console.log();\n });\n}\n\nfunction formatUptime(seconds: number): string {\n const h = Math.floor(seconds / 3600);\n const m = Math.floor((seconds % 3600) / 60);\n const s = seconds % 60;\n if (h > 0) return `${h}h ${m}m`;\n if (m > 0) return `${m}m ${s}s`;\n return `${s}s`;\n}\n","import { Command } from \"commander\";\nimport { output, readStdin, apiPost, isServerRunning, getBaseUrl } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function storeCommand(): Command {\n return new Command(\"store\")\n .description(\"Store a new memory\")\n .argument(\"[content]\", \"Memory content (or pipe via stdin)\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .requiredOption(\"--scope <scope>\", \"Memory scope (user, agent, global, project, session)\")\n .option(\"--subject <id>\", \"Subject ID\")\n .option(\"--tags <tags>\", \"Comma-separated tags\")\n .option(\"--source <source>\", \"Memory source\", \"explicit\")\n .option(\"--no-extract\", \"Skip entity extraction\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (contentArg, opts) => {\n const content = contentArg || await readStdin();\n if (!content) {\n console.error(\"Error: content is required (pass as argument or pipe via stdin)\");\n process.exit(1);\n }\n\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const body = {\n agent_id: opts.agent,\n scope: opts.scope,\n subject_id: opts.subject || null,\n content,\n tags: opts.tags ? opts.tags.split(\",\").map((t: string) => t.trim()) : [],\n source: opts.source,\n extract_entities: opts.extract !== false,\n };\n\n if (serverUp) {\n // Use HTTP API\n const result = await apiPost(baseUrl, \"/api/memories\", body, config.auth.token);\n output(result, opts.format);\n } else {\n // Direct mode — instantiate MemoryService in-process\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n\n try {\n const result = await service.store({\n agentId: opts.agent,\n scope: opts.scope,\n subjectId: opts.subject || null,\n content,\n tags: body.tags,\n source: opts.source,\n extractEntities: opts.extract !== false,\n });\n output(result, opts.format);\n } finally {\n await service.close();\n }\n }\n });\n}\n","import { Command } from \"commander\";\nimport { output, apiPost, isServerRunning, getBaseUrl } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function searchCommand(): Command {\n const cmd = new Command(\"search\")\n .description(\"Search memories\");\n\n // Default search (smart auto-select)\n cmd\n .argument(\"<query>\", \"Search query\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .option(\"--limit <n>\", \"Max results\", \"10\")\n .option(\"--strategy <s>\", \"Search strategy (auto, semantic, fulltext, graph, all)\", \"auto\")\n .option(\"--scopes <scopes>\", \"Comma-separated scopes\")\n .option(\"--subject <id>\", \"Subject ID filter\")\n .option(\"--cross-agent\", \"Search across all agents\")\n .option(\"--no-graph\", \"Exclude graph results\")\n .option(\"--recall\", \"Format output for LLM context injection\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (query, opts) => {\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const body = {\n agent_id: opts.agent,\n query,\n limit: parseInt(opts.limit, 10),\n strategy: opts.strategy,\n scopes: opts.scopes ? opts.scopes.split(\",\") : undefined,\n subject_id: opts.subject || null,\n cross_agent: opts.crossAgent || false,\n include_graph: opts.graph !== false,\n };\n\n let result: unknown;\n if (serverUp) {\n result = await apiPost(baseUrl, \"/api/search\", body, config.auth.token);\n } else {\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n try {\n result = await service.search({\n agentId: opts.agent,\n query,\n limit: parseInt(opts.limit, 10),\n strategy: opts.strategy,\n scopes: opts.scopes ? opts.scopes.split(\",\") : undefined,\n subjectId: opts.subject || null,\n crossAgent: opts.crossAgent || false,\n includeGraph: opts.graph !== false,\n });\n } finally {\n await service.close();\n }\n }\n\n // Recall mode — format for LLM\n if (opts.recall) {\n const data = result as { results?: Array<{ memory: { content: string; scope: string; created_at: string } }> };\n if (data.results && data.results.length > 0) {\n console.log(\"## Relevant Memories\");\n for (const r of data.results) {\n const date = new Date(r.memory.created_at).toLocaleDateString();\n console.log(`- ${r.memory.content} (${r.memory.scope}, ${date})`);\n }\n } else {\n console.log(\"No relevant memories found.\");\n }\n } else {\n output(result, opts.format);\n }\n });\n\n return cmd;\n}\n","import { Command } from \"commander\";\nimport { output, apiPost, isServerRunning, getBaseUrl, success, info, header } from \"../utils.js\";\nimport { loadConfig } from \"../../config/index.js\";\n\nexport function migrateCommand(): Command {\n return new Command(\"migrate\")\n .description(\"Import memories from markdown files\")\n .requiredOption(\"--paths <paths>\", \"Comma-separated file paths\")\n .requiredOption(\"--agent <id>\", \"Agent ID\")\n .option(\"--dry-run\", \"Preview without writing\")\n .option(\"--format <fmt>\", \"Output format (json, text)\", \"json\")\n .option(\"--config <path>\", \"Path to config file\")\n .action(async (opts) => {\n const config = await loadConfig(opts.config);\n const baseUrl = getBaseUrl(config.port);\n const serverUp = await isServerRunning(baseUrl);\n\n const paths = opts.paths.split(\",\").map((p: string) => p.trim());\n\n if (opts.dryRun) {\n header(\"Migration (dry run)\");\n }\n\n const body = {\n markdown_paths: paths,\n agent_id: opts.agent,\n dry_run: opts.dryRun || false,\n };\n\n let result: unknown;\n if (serverUp) {\n result = await apiPost(baseUrl, \"/api/admin/migrate-markdown\", body, config.auth.token);\n } else {\n // Direct mode\n const { MemoryService } = await import(\"../../core/memory-service.js\");\n const service = new MemoryService();\n await service.init();\n try {\n const migrated = await service.migrateMarkdown(paths, opts.agent);\n result = migrated;\n } finally {\n await service.close();\n }\n }\n\n if (opts.format === \"text\") {\n const data = result as { migrated?: number; skipped?: number; errors?: string[] };\n if (data.migrated !== undefined) {\n success(`Migrated ${data.migrated} memories`);\n }\n if (data.skipped) {\n info(`Skipped ${data.skipped} sections`);\n }\n if (data.errors && data.errors.length > 0) {\n for (const err of data.errors) {\n console.error(` ✗ ${err}`);\n }\n }\n } else {\n output(result, opts.format);\n }\n });\n}\n","import { Command } from \"commander\";\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { header, success, info, warn, error as logError } from \"../utils.js\";\nimport { getDataDir, loadConfig } from \"../../config/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function infraCommand(): Command {\n const infra = new Command(\"infra\")\n .description(\"Manage Docker infrastructure\");\n\n infra\n .command(\"up\")\n .description(\"Start Docker containers for the configured tier\")\n .option(\"--tier <tier>\", \"Override tier (standard, full)\")\n .action(async (opts) => {\n header(\"Infrastructure Up\");\n\n let tier = opts.tier;\n if (!tier) {\n try {\n const config = await loadConfig();\n tier = config.tier;\n } catch {\n tier = \"standard\";\n }\n }\n\n if (tier === \"lite\") {\n info(\"Lite tier uses only SQLite — no Docker infrastructure needed.\");\n return;\n }\n\n const templateFile = tier === \"full\" ? \"full.yml\" : \"standard.yml\";\n const templatePath = findTemplate(templateFile);\n\n if (!templatePath) {\n logError(`Template not found: ${templateFile}`);\n logError(\"Expected in ./docker/ or ./templates/ directory\");\n process.exit(1);\n }\n\n const dataDir = getDataDir();\n fs.mkdirSync(dataDir, { recursive: true });\n\n const targetPath = path.join(dataDir, \"docker-compose.yml\");\n fs.copyFileSync(templatePath, targetPath);\n info(`Using template: ${templatePath}`);\n\n try {\n execSync(`docker compose -f ${targetPath} up -d`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n success(\"Docker containers started\");\n } catch (error) {\n logError(\"Failed to start Docker containers\");\n logError(\"Make sure Docker is installed and running\");\n process.exit(1);\n }\n });\n\n infra\n .command(\"down\")\n .description(\"Stop Docker containers\")\n .action(async () => {\n header(\"Infrastructure Down\");\n\n const dataDir = getDataDir();\n const composePath = path.join(dataDir, \"docker-compose.yml\");\n\n if (!fs.existsSync(composePath)) {\n warn(\"No docker-compose.yml found in data directory\");\n return;\n }\n\n try {\n execSync(`docker compose -f ${composePath} down`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n success(\"Docker containers stopped\");\n } catch (error) {\n logError(\"Failed to stop Docker containers\");\n process.exit(1);\n }\n });\n\n infra\n .command(\"status\")\n .description(\"Show Docker container status\")\n .action(async () => {\n header(\"Infrastructure Status\");\n\n const dataDir = getDataDir();\n const composePath = path.join(dataDir, \"docker-compose.yml\");\n\n if (!fs.existsSync(composePath)) {\n info(\"No docker-compose.yml found — infrastructure not set up\");\n info(\"Run: openclaw-memory infra up\");\n return;\n }\n\n try {\n execSync(`docker compose -f ${composePath} ps`, {\n stdio: \"inherit\",\n cwd: dataDir,\n });\n } catch {\n logError(\"Failed to get container status\");\n }\n });\n\n return infra;\n}\n\nfunction findTemplate(filename: string): string | null {\n const searchPaths = [\n path.join(process.cwd(), \"docker\", filename),\n path.join(process.cwd(), \"templates\", filename),\n // Look in the package's installed location\n path.join(__dirname, \"../../docker\", filename),\n path.join(__dirname, \"../../templates\", filename),\n ];\n\n for (const p of searchPaths) {\n if (fs.existsSync(p)) return p;\n }\n\n return null;\n}\n"]}
package/dist/cli/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  getDefaultSqlitePath,
5
5
  getPidFilePath,
6
6
  loadConfig
7
- } from "../chunk-JNWCMHOB.js";
7
+ } from "../chunk-ITGUJZUL.js";
8
8
 
9
9
  // src/cli/index.ts
10
10
  import { Command as Command9 } from "commander";
@@ -184,7 +184,7 @@ function initCommand() {
184
184
  }
185
185
  function generateConfig(tier, sqlitePath) {
186
186
  const lines = [
187
- `import { defineConfig } from 'openclaw-memory';`,
187
+ `import { defineConfig } from '@poprobertdaniel/openclaw-memory';`,
188
188
  ``,
189
189
  `export default defineConfig({`,
190
190
  ` tier: '${tier}',`,
@@ -208,7 +208,7 @@ function generateConfig(tier, sqlitePath) {
208
208
  lines.push(` },`);
209
209
  lines.push(` extraction: {`);
210
210
  lines.push(` apiKey: process.env.OPENAI_API_KEY || '',`);
211
- lines.push(` model: 'gpt-4o-mini',`);
211
+ lines.push(` model: 'gpt-5-nano',`);
212
212
  lines.push(` enabled: true,`);
213
213
  lines.push(` },`);
214
214
  }
@@ -251,7 +251,7 @@ function generateEnvExample(tier) {
251
251
  lines.push(`# EMBEDDING_BASE_URL=https://api.openai.com/v1`);
252
252
  lines.push(``);
253
253
  lines.push(`# Entity extraction`);
254
- lines.push(`# EXTRACTION_MODEL=gpt-4o-mini`);
254
+ lines.push(`# EXTRACTION_MODEL=gpt-5-nano`);
255
255
  lines.push(``);
256
256
  }
257
257
  if (tier === "full") {
@@ -519,7 +519,7 @@ function storeCommand() {
519
519
  const result = await apiPost(baseUrl, "/api/memories", body, config.auth.token);
520
520
  output(result, opts.format);
521
521
  } else {
522
- const { MemoryService } = await import("../memory-service-GKEG6J2D.js");
522
+ const { MemoryService } = await import("../memory-service-4ZPYUN4L.js");
523
523
  const service = new MemoryService();
524
524
  await service.init();
525
525
  try {
@@ -562,7 +562,7 @@ function searchCommand() {
562
562
  if (serverUp) {
563
563
  result = await apiPost(baseUrl, "/api/search", body, config.auth.token);
564
564
  } else {
565
- const { MemoryService } = await import("../memory-service-GKEG6J2D.js");
565
+ const { MemoryService } = await import("../memory-service-4ZPYUN4L.js");
566
566
  const service = new MemoryService();
567
567
  await service.init();
568
568
  try {
@@ -618,7 +618,7 @@ function migrateCommand() {
618
618
  if (serverUp) {
619
619
  result = await apiPost(baseUrl, "/api/admin/migrate-markdown", body, config.auth.token);
620
620
  } else {
621
- const { MemoryService } = await import("../memory-service-GKEG6J2D.js");
621
+ const { MemoryService } = await import("../memory-service-4ZPYUN4L.js");
622
622
  const service = new MemoryService();
623
623
  await service.init();
624
624
  try {