memory-braid 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ On the target machine:
20
20
  1. Install from npm:
21
21
 
22
22
  ```bash
23
- openclaw plugins install memory-braid@0.3.4
23
+ openclaw plugins install memory-braid@0.3.5
24
24
  ```
25
25
 
26
26
  2. Rebuild native dependencies inside the installed extension:
@@ -71,6 +71,7 @@ openclaw gateway restart
71
71
  If you install from npm and see native module errors like:
72
72
 
73
73
  - `Could not locate the bindings file` (sqlite3)
74
+ - `.../node_modules/jiti/.../node_sqlite3.node` in the stack/error text
74
75
  - `Cannot find module ... sharp-*.node`
75
76
 
76
77
  run:
@@ -81,6 +82,14 @@ npm rebuild sqlite3 sharp
81
82
  openclaw gateway restart
82
83
  ```
83
84
 
85
+ Note:
86
+ - The `jiti/.../node_sqlite3.node` error is still a sqlite native artifact/runtime loading issue.
87
+ - `memory-braid` now preloads sqlite via native `require` to avoid that path, but you still need `npm rebuild sqlite3 sharp` after `--ignore-scripts` installs.
88
+ - When this happens, startup logs now include `memory_braid.mem0.error` with:
89
+ - `sqliteBindingsError: true`
90
+ - `fixCommand` (copy/paste command for that machine)
91
+ - `pluginDir` (resolved extension directory when available)
92
+
84
93
  ## Quick start: hybrid capture + multilingual NER
85
94
 
86
95
  Add this under `plugins.entries["memory-braid"].config` in your OpenClaw config:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-braid",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "OpenClaw memory plugin that augments local memory with Mem0, bootstrap import, reconcile, and capture.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -1,4 +1,5 @@
1
1
  import fs from "node:fs/promises";
2
+ import { createRequire } from "node:module";
2
3
  import os from "node:os";
3
4
  import path from "node:path";
4
5
  import { normalizeForHash } from "./chunking.js";
@@ -46,6 +47,13 @@ type OssClientLike = {
46
47
 
47
48
  type OssMemoryCtor = new (config?: Record<string, unknown>) => OssClientLike;
48
49
 
50
+ type LoadedOssModule = {
51
+ moduleValue: unknown;
52
+ loader: "require" | "import";
53
+ mem0Path?: string;
54
+ sqlite3Path?: string;
55
+ };
56
+
49
57
  function extractCloudText(memory: CloudRecord): string {
50
58
  const byData = memory.data?.memory;
51
59
  if (typeof byData === "string" && byData.trim()) {
@@ -137,6 +145,34 @@ function resolveCtorFromCandidate(candidate: unknown, depth = 0): OssMemoryCtor
137
145
  );
138
146
  }
139
147
 
148
+ function asErrorMessage(error: unknown): string {
149
+ if (error instanceof Error) {
150
+ return error.message;
151
+ }
152
+ return String(error);
153
+ }
154
+
155
+ function isSqliteBindingsError(error: unknown): boolean {
156
+ const message = asErrorMessage(error);
157
+ return /Could not locate the bindings file/i.test(message) || /node_sqlite3\.node/i.test(message);
158
+ }
159
+
160
+ function createLocalRequire(): NodeJS.Require {
161
+ return createRequire(import.meta.url);
162
+ }
163
+
164
+ function tryResolve(requireFn: NodeJS.Require, id: string): string | undefined {
165
+ try {
166
+ return requireFn.resolve(id);
167
+ } catch {
168
+ return undefined;
169
+ }
170
+ }
171
+
172
+ function tryRequire(requireFn: NodeJS.Require, id: string): unknown {
173
+ return requireFn(id);
174
+ }
175
+
140
176
  export function resolveOssMemoryCtor(moduleValue: unknown): OssMemoryCtor | undefined {
141
177
  return (
142
178
  resolveCtorFromCandidate(moduleValue) ??
@@ -300,11 +336,13 @@ export class Mem0Adapter {
300
336
  private ossClient: OssClientLike | null = null;
301
337
  private readonly cfg: MemoryBraidConfig;
302
338
  private readonly log: MemoryBraidLogger;
339
+ private readonly pluginDir?: string;
303
340
  private stateDir?: string;
304
341
 
305
342
  constructor(cfg: MemoryBraidConfig, log: MemoryBraidLogger, options?: Mem0AdapterOptions) {
306
343
  this.cfg = cfg;
307
344
  this.log = log;
345
+ this.pluginDir = this.resolvePluginDir();
308
346
  this.stateDir = options?.stateDir;
309
347
  }
310
348
 
@@ -362,7 +400,7 @@ export class Mem0Adapter {
362
400
  }
363
401
 
364
402
  try {
365
- const mod = await import("mem0ai/oss");
403
+ const { moduleValue: mod, loader, mem0Path, sqlite3Path } = await this.loadOssModule();
366
404
  const Memory = resolveOssMemoryCtor(mod);
367
405
  if (!Memory) {
368
406
  const exportKeys = Object.keys(asRecord(mod));
@@ -384,20 +422,104 @@ export class Mem0Adapter {
384
422
  this.log.debug("memory_braid.mem0.response", {
385
423
  action: "init",
386
424
  mode: "oss",
425
+ loader,
426
+ mem0Path,
427
+ sqlite3Path,
387
428
  hasCustomConfig,
388
429
  sqliteDbPaths: collectSqliteDbPaths(configToUse),
389
430
  }, true);
390
431
  return this.ossClient;
391
432
  } catch (err) {
433
+ const sqliteBindingsError = isSqliteBindingsError(err);
392
434
  this.log.error("memory_braid.mem0.error", {
393
435
  reason: "init_failed",
394
436
  mode: "oss",
437
+ sqliteBindingsError,
438
+ ...(sqliteBindingsError ? this.nativeRebuildHint() : {}),
395
439
  error: err instanceof Error ? err.message : String(err),
396
440
  });
397
441
  return null;
398
442
  }
399
443
  }
400
444
 
445
+ private async loadOssModule(): Promise<LoadedOssModule> {
446
+ const requireFromHere = createLocalRequire();
447
+ const sqlite3Path = tryResolve(requireFromHere, "sqlite3");
448
+ if (sqlite3Path) {
449
+ try {
450
+ tryRequire(requireFromHere, sqlite3Path);
451
+ } catch (error) {
452
+ this.log.warn("memory_braid.mem0.error", {
453
+ reason: "sqlite3_preload_failed",
454
+ mode: "oss",
455
+ ...this.nativeRebuildHint(),
456
+ sqlite3Path,
457
+ error: asErrorMessage(error),
458
+ });
459
+ }
460
+ }
461
+
462
+ const mem0Path = tryResolve(requireFromHere, "mem0ai/oss");
463
+ if (mem0Path) {
464
+ try {
465
+ const required = tryRequire(requireFromHere, mem0Path);
466
+ return {
467
+ moduleValue: required,
468
+ loader: "require",
469
+ mem0Path,
470
+ sqlite3Path,
471
+ };
472
+ } catch (error) {
473
+ const sqliteBindingsError = isSqliteBindingsError(error);
474
+ this.log.warn("memory_braid.mem0.error", {
475
+ reason: "oss_require_failed",
476
+ mode: "oss",
477
+ mem0Path,
478
+ sqlite3Path,
479
+ sqliteBindingsError,
480
+ ...(sqliteBindingsError ? this.nativeRebuildHint() : {}),
481
+ error: asErrorMessage(error),
482
+ });
483
+ }
484
+ }
485
+
486
+ const imported = await import("mem0ai/oss");
487
+ return {
488
+ moduleValue: imported,
489
+ loader: "import",
490
+ mem0Path,
491
+ sqlite3Path,
492
+ };
493
+ }
494
+
495
+ private resolvePluginDir(): string | undefined {
496
+ const requireFromHere = createLocalRequire();
497
+ const packageJsonPath = tryResolve(requireFromHere, "../package.json");
498
+ if (!packageJsonPath) {
499
+ return undefined;
500
+ }
501
+ return path.dirname(packageJsonPath);
502
+ }
503
+
504
+ private nativeRebuildHint(): {
505
+ pluginDir?: string;
506
+ fixCommand: string;
507
+ why: string;
508
+ } {
509
+ if (this.pluginDir) {
510
+ return {
511
+ pluginDir: this.pluginDir,
512
+ fixCommand: `cd "${this.pluginDir}" && npm rebuild sqlite3 sharp && openclaw gateway restart`,
513
+ why: "OpenClaw plugin installs use --ignore-scripts, so sqlite3/sharp native artifacts may be missing after install/update.",
514
+ };
515
+ }
516
+
517
+ return {
518
+ fixCommand: "cd ~/.openclaw/extensions/memory-braid && npm rebuild sqlite3 sharp && openclaw gateway restart",
519
+ why: "OpenClaw plugin installs use --ignore-scripts, so sqlite3/sharp native artifacts may be missing after install/update.",
520
+ };
521
+ }
522
+
401
523
  async ensureClient(): Promise<{ mode: "cloud" | "oss"; client: CloudClientLike | OssClientLike } | null> {
402
524
  if (this.cfg.mem0.mode === "oss") {
403
525
  const client = await this.ensureOssClient();