memoclaw 1.8.3 → 1.8.5

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 (2) hide show
  1. package/dist/cli.mjs +138 -14
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -30108,7 +30108,7 @@ var jsYaml = {
30108
30108
  import * as fs from "fs";
30109
30109
  import * as path from "path";
30110
30110
  import * as os from "os";
30111
- var VERSION = "1.9.0";
30111
+ var VERSION = "1.8.5";
30112
30112
  var CONFIG_DIR = path.join(os.homedir(), ".memoclaw");
30113
30113
  var CONFIG_FILE_JSON = path.join(CONFIG_DIR, "config.json");
30114
30114
  var CONFIG_FILE_YAML = path.join(CONFIG_DIR, "config");
@@ -30245,6 +30245,9 @@ function success(msg) {
30245
30245
  return;
30246
30246
  outputWrite(`${c.green}✓${c.reset} ${msg}`);
30247
30247
  }
30248
+ function warn(msg) {
30249
+ outputError(`${c.yellow}⚠${c.reset} ${msg}`);
30250
+ }
30248
30251
  function info(msg) {
30249
30252
  if (outputQuiet)
30250
30253
  return;
@@ -30306,10 +30309,13 @@ async function request(method, path2, body = null) {
30306
30309
  options.body = JSON.stringify(body);
30307
30310
  const walletAuth = await getWalletAuthHeader();
30308
30311
  headers["x-wallet-auth"] = walletAuth;
30312
+ const controller = new AbortController;
30313
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
30309
30314
  let res;
30310
30315
  try {
30311
- res = await fetch(url, { ...options, headers });
30316
+ res = await fetch(url, { ...options, headers, signal: controller.signal });
30312
30317
  } catch (e) {
30318
+ clearTimeout(timeoutId);
30313
30319
  if (e.code === "ECONNREFUSED" || e.cause?.code === "ECONNREFUSED") {
30314
30320
  throw new Error(`Cannot connect to ${API_URL} — is the server running?`);
30315
30321
  }
@@ -30317,10 +30323,11 @@ async function request(method, path2, body = null) {
30317
30323
  throw new Error(`DNS lookup failed for ${API_URL} — check your internet connection`);
30318
30324
  }
30319
30325
  if (e.name === "AbortError") {
30320
- throw new Error(`Request timed out`);
30326
+ throw new Error(`Request timed out after ${TIMEOUT_MS / 1000}s`);
30321
30327
  }
30322
30328
  throw new Error(`Network error: ${e.message}`);
30323
30329
  }
30330
+ clearTimeout(timeoutId);
30324
30331
  const freeTierRemaining = res.headers.get("x-free-tier-remaining");
30325
30332
  if (freeTierRemaining !== null && process.env.DEBUG) {
30326
30333
  console.error(`${c.dim}Free tier remaining: ${freeTierRemaining}${c.reset}`);
@@ -30863,9 +30870,9 @@ async function cmdExport(opts) {
30863
30870
  count: allMemories.length,
30864
30871
  memories: allMemories
30865
30872
  };
30866
- console.log(JSON.stringify(exportData, null, 2));
30873
+ outputWrite(JSON.stringify(exportData, null, 2));
30867
30874
  if (!outputQuiet) {
30868
- console.error(`${c.green}✓${c.reset} Exported ${allMemories.length} memories`);
30875
+ outputError(`${c.green}✓${c.reset} Exported ${allMemories.length} memories`);
30869
30876
  }
30870
30877
  }
30871
30878
  async function cmdImport(opts) {
@@ -30883,7 +30890,7 @@ async function cmdImport(opts) {
30883
30890
  const memories = data.memories || data;
30884
30891
  if (!Array.isArray(memories))
30885
30892
  throw new Error("Invalid format: expected { memories: [...] } or [...]");
30886
- const concurrency = opts.concurrency ? parseInt(opts.concurrency) : 1;
30893
+ const concurrency = opts.concurrency ? parseInt(opts.concurrency) : 5;
30887
30894
  const batchSize = Math.min(concurrency, memories.length);
30888
30895
  let imported = 0;
30889
30896
  let failed = 0;
@@ -31054,17 +31061,35 @@ async function cmdPurge(opts) {
31054
31061
  if (opts.namespace)
31055
31062
  params.set("namespace", opts.namespace);
31056
31063
  let deleted = 0;
31064
+ let failedInRow = 0;
31065
+ const MAX_CONSECUTIVE_FAILURES = 3;
31057
31066
  while (true) {
31058
31067
  params.set("offset", "0");
31059
31068
  const result = await request("GET", `/v1/memories?${params}`);
31060
31069
  const memories = result.memories || result.data || [];
31061
31070
  if (memories.length === 0)
31062
31071
  break;
31072
+ let batchDeleted = 0;
31063
31073
  for (const mem of memories) {
31064
- await request("DELETE", `/v1/memories/${mem.id}`);
31065
- deleted++;
31066
- if (!outputQuiet)
31067
- process.stderr.write(`\r ${progressBar(deleted, result.total || deleted)}`);
31074
+ try {
31075
+ await request("DELETE", `/v1/memories/${mem.id}`);
31076
+ deleted++;
31077
+ batchDeleted++;
31078
+ failedInRow = 0;
31079
+ if (!outputQuiet)
31080
+ process.stderr.write(`\r ${progressBar(deleted, result.total || deleted)}`);
31081
+ } catch (e) {
31082
+ if (process.env.DEBUG)
31083
+ console.error(`
31084
+ Failed to delete ${mem.id}: ${e.message}`);
31085
+ }
31086
+ }
31087
+ if (batchDeleted === 0) {
31088
+ failedInRow++;
31089
+ if (failedInRow >= MAX_CONSECUTIVE_FAILURES) {
31090
+ warn(`Aborting: ${MAX_CONSECUTIVE_FAILURES} consecutive batches failed to delete any memories`);
31091
+ break;
31092
+ }
31068
31093
  }
31069
31094
  }
31070
31095
  if (!outputQuiet)
@@ -31136,13 +31161,42 @@ async function cmdMigrate(targetPath, opts) {
31136
31161
  }
31137
31162
  const mdFiles = [];
31138
31163
  const stat = fs.statSync(resolvedPath);
31164
+ const IGNORED_DIRS = new Set([
31165
+ "node_modules",
31166
+ ".git",
31167
+ ".next",
31168
+ ".nuxt",
31169
+ "dist",
31170
+ "build",
31171
+ ".output",
31172
+ "__pycache__",
31173
+ ".venv",
31174
+ "venv",
31175
+ "env",
31176
+ ".env",
31177
+ ".tox",
31178
+ ".cache",
31179
+ ".tmp",
31180
+ "tmp",
31181
+ "coverage",
31182
+ ".nyc_output",
31183
+ "vendor",
31184
+ "target",
31185
+ ".gradle",
31186
+ ".mvn",
31187
+ "skills",
31188
+ ".openclaw",
31189
+ ".clawd"
31190
+ ]);
31139
31191
  if (stat.isDirectory()) {
31140
31192
  const walk2 = (dir) => {
31141
31193
  const entries = fs.readdirSync(dir, { withFileTypes: true });
31142
31194
  for (const entry of entries) {
31143
31195
  const full = path.join(dir, entry.name);
31144
31196
  if (entry.isDirectory()) {
31145
- walk2(full);
31197
+ if (!IGNORED_DIRS.has(entry.name)) {
31198
+ walk2(full);
31199
+ }
31146
31200
  } else if (entry.name.endsWith(".md")) {
31147
31201
  mdFiles.push({ filepath: full, filename: path.relative(resolvedPath, full) });
31148
31202
  }
@@ -31160,7 +31214,7 @@ async function cmdMigrate(targetPath, opts) {
31160
31214
  if (!outputQuiet) {
31161
31215
  console.log(`${c.blue}ℹ${c.reset} Found ${c.bold}${mdFiles.length}${c.reset} markdown file${mdFiles.length !== 1 ? "s" : ""}`);
31162
31216
  }
31163
- const BATCH_SIZE = 50;
31217
+ const BATCH_SIZE = 5;
31164
31218
  let totalCreated = 0;
31165
31219
  let totalDeduplicated = 0;
31166
31220
  let totalErrors = 0;
@@ -31230,16 +31284,59 @@ async function cmdCompletions(shell) {
31230
31284
  "graph",
31231
31285
  "purge",
31232
31286
  "count",
31233
- "namespace"
31287
+ "namespace",
31288
+ "help"
31289
+ ];
31290
+ const globalFlags = [
31291
+ "--help",
31292
+ "--version",
31293
+ "--json",
31294
+ "--quiet",
31295
+ "--namespace",
31296
+ "--limit",
31297
+ "--offset",
31298
+ "--tags",
31299
+ "--format",
31300
+ "--pretty",
31301
+ "--watch",
31302
+ "--raw",
31303
+ "--force",
31304
+ "--output",
31305
+ "--truncate",
31306
+ "--no-truncate",
31307
+ "--columns",
31308
+ "--sort-by",
31309
+ "--reverse",
31310
+ "--wide",
31311
+ "--concurrency",
31312
+ "--yes",
31313
+ "--timeout",
31314
+ "--field",
31315
+ "--dry-run"
31234
31316
  ];
31235
31317
  if (shell === "bash") {
31236
31318
  console.log(`# Add to ~/.bashrc:
31237
31319
  # eval "$(memoclaw completions bash)"
31238
31320
  _memoclaw() {
31239
31321
  local cur="\${COMP_WORDS[COMP_CWORD]}"
31322
+ local prev="\${COMP_WORDS[COMP_CWORD-1]}"
31240
31323
  local cmds="${commands.join(" ")}"
31324
+ local flags="${globalFlags.join(" ")}"
31325
+
31241
31326
  if [ "$COMP_CWORD" -eq 1 ]; then
31242
31327
  COMPREPLY=( $(compgen -W "$cmds" -- "$cur") )
31328
+ elif [[ "$cur" == -* ]]; then
31329
+ COMPREPLY=( $(compgen -W "$flags" -- "$cur") )
31330
+ elif [[ "$prev" == "--format" || "$prev" == "-f" ]]; then
31331
+ COMPREPLY=( $(compgen -W "json table csv yaml" -- "$cur") )
31332
+ elif [[ "\${COMP_WORDS[1]}" == "relations" && "$COMP_CWORD" -eq 2 ]]; then
31333
+ COMPREPLY=( $(compgen -W "list create delete" -- "$cur") )
31334
+ elif [[ "\${COMP_WORDS[1]}" == "config" && "$COMP_CWORD" -eq 2 ]]; then
31335
+ COMPREPLY=( $(compgen -W "show check init path" -- "$cur") )
31336
+ elif [[ "\${COMP_WORDS[1]}" == "namespace" && "$COMP_CWORD" -eq 2 ]]; then
31337
+ COMPREPLY=( $(compgen -W "list stats" -- "$cur") )
31338
+ elif [[ "\${COMP_WORDS[1]}" == "completions" && "$COMP_CWORD" -eq 2 ]]; then
31339
+ COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") )
31243
31340
  fi
31244
31341
  }
31245
31342
  complete -F _memoclaw memoclaw`);
@@ -31248,12 +31345,38 @@ complete -F _memoclaw memoclaw`);
31248
31345
  # eval "$(memoclaw completions zsh)"
31249
31346
  _memoclaw() {
31250
31347
  local -a commands=(${commands.map((c2) => `'${c2}'`).join(" ")})
31251
- _describe 'command' commands
31348
+ local -a flags=(${globalFlags.map((f) => `'${f}'`).join(" ")})
31349
+
31350
+ if (( CURRENT == 2 )); then
31351
+ _describe 'command' commands
31352
+ else
31353
+ case \${words[2]} in
31354
+ relations) _values 'subcommand' list create delete ;;
31355
+ config) _values 'subcommand' show check init path ;;
31356
+ namespace) _values 'subcommand' list stats ;;
31357
+ completions) _values 'shell' bash zsh fish ;;
31358
+ *)
31359
+ if [[ "$PREFIX" == -* ]]; then
31360
+ _describe 'flag' flags
31361
+ fi
31362
+ ;;
31363
+ esac
31364
+ fi
31252
31365
  }
31253
31366
  compdef _memoclaw memoclaw`);
31254
31367
  } else if (shell === "fish") {
31255
31368
  console.log(`# Add to ~/.config/fish/completions/memoclaw.fish:
31256
31369
  ${commands.map((cmd) => `complete -c memoclaw -n '__fish_use_subcommand' -a '${cmd}'`).join(`
31370
+ `)}
31371
+
31372
+ # Subcommands
31373
+ complete -c memoclaw -n '__fish_seen_subcommand_from relations' -a 'list create delete'
31374
+ complete -c memoclaw -n '__fish_seen_subcommand_from config' -a 'show check init path'
31375
+ complete -c memoclaw -n '__fish_seen_subcommand_from namespace' -a 'list stats'
31376
+ complete -c memoclaw -n '__fish_seen_subcommand_from completions' -a 'bash zsh fish'
31377
+
31378
+ # Global flags
31379
+ ${globalFlags.map((f) => `complete -c memoclaw -l '${f.replace(/^--/, "")}'`).join(`
31257
31380
  `)}`);
31258
31381
  } else {
31259
31382
  throw new Error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
@@ -31640,6 +31763,7 @@ ${c.bold}Commands:${c.reset}
31640
31763
  ${c.cyan}purge${c.reset} Delete ALL memories (requires --force or confirm)
31641
31764
  ${c.cyan}namespace${c.reset} [list|stats] Manage and view namespaces
31642
31765
  ${c.cyan}count${c.reset} Quick memory count
31766
+ ${c.cyan}help${c.reset} [command] Show help for a command
31643
31767
 
31644
31768
  ${c.bold}Global Options:${c.reset}
31645
31769
  -h, --help Show help (use with command for details)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoclaw",
3
- "version": "1.8.3",
3
+ "version": "1.8.5",
4
4
  "description": "MemoClaw CLI - Memory-as-a-Service for AI agents. 1000 free calls, then x402 micropayments.",
5
5
  "type": "module",
6
6
  "bin": {