@memtensor/memos-local-openclaw-plugin 1.0.6-beta.3 → 1.0.6-beta.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.
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +62 -24
- package/dist/viewer/server.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/scripts/native-binding.cjs +32 -0
- package/scripts/postinstall.cjs +13 -16
- package/src/viewer/server.ts +51 -8
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "MemOS Local Memory",
|
|
4
4
|
"description": "Full-write local conversation memory with hybrid search (RRF + MMR + recency), task summarization, skill evolution, and team sharing (Hub-Client). Provides memory_search, memory_get, task_summary, skill_search, task_share, network_skill_pull, network_team_info, memory_viewer for layered retrieval and team collaboration.",
|
|
5
5
|
"kind": "memory",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "1.0.6-beta.5",
|
|
7
7
|
"skills": [
|
|
8
8
|
"skill/memos-memory-guide"
|
|
9
9
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memtensor/memos-local-openclaw-plugin",
|
|
3
|
-
"version": "1.0.6-beta.
|
|
3
|
+
"version": "1.0.6-beta.5",
|
|
4
4
|
"description": "MemOS Local memory plugin for OpenClaw — full-write, hybrid-recall, progressive retrieval",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"dist",
|
|
12
12
|
"skill",
|
|
13
13
|
"prebuilds",
|
|
14
|
+
"scripts/native-binding.cjs",
|
|
14
15
|
"scripts/postinstall.cjs",
|
|
15
16
|
"openclaw.plugin.json",
|
|
16
17
|
"telemetry.credentials.json",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
function errorMessage(error) {
|
|
4
|
+
if (error && typeof error.message === "string") return error.message;
|
|
5
|
+
return String(error || "Unknown native binding error");
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function defaultLoadBinding(bindingPath) {
|
|
9
|
+
process.dlopen({ exports: {} }, bindingPath);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function validateNativeBinding(bindingPath, loadBinding = defaultLoadBinding) {
|
|
13
|
+
if (!bindingPath) {
|
|
14
|
+
return { ok: false, reason: "missing", message: "Native binding path not found" };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
loadBinding(bindingPath);
|
|
19
|
+
return { ok: true, reason: "ok", message: "" };
|
|
20
|
+
} catch (error) {
|
|
21
|
+
const message = errorMessage(error);
|
|
22
|
+
if (/NODE_MODULE_VERSION/.test(message)) {
|
|
23
|
+
return { ok: false, reason: "node-module-version", message };
|
|
24
|
+
}
|
|
25
|
+
return { ok: false, reason: "load-error", message };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
defaultLoadBinding,
|
|
31
|
+
validateNativeBinding,
|
|
32
|
+
};
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
const { spawnSync } = require("child_process");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs");
|
|
7
|
+
const { validateNativeBinding } = require("./native-binding.cjs");
|
|
7
8
|
|
|
8
9
|
const RESET = "\x1b[0m";
|
|
9
10
|
const GREEN = "\x1b[32m";
|
|
@@ -377,35 +378,31 @@ function findSqliteBinding() {
|
|
|
377
378
|
|
|
378
379
|
function sqliteBindingsExist() {
|
|
379
380
|
const found = findSqliteBinding();
|
|
380
|
-
if (found)
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
if (!found) return false;
|
|
382
|
+
log(`Native binding found: ${DIM}${found}${RESET}`);
|
|
383
|
+
const status = validateNativeBinding(found);
|
|
384
|
+
if (status.ok) return true;
|
|
385
|
+
if (status.reason === "node-module-version") {
|
|
386
|
+
warn("Native binding exists but was compiled for a different Node.js version.");
|
|
387
|
+
} else {
|
|
388
|
+
warn("Native binding exists but failed to load.");
|
|
383
389
|
}
|
|
390
|
+
warn(`${DIM}${status.message}${RESET}`);
|
|
384
391
|
return false;
|
|
385
392
|
}
|
|
386
393
|
|
|
387
394
|
if (sqliteBindingsExist()) {
|
|
388
395
|
ok("better-sqlite3 is ready.");
|
|
389
396
|
} else {
|
|
390
|
-
warn("better-sqlite3 native bindings
|
|
397
|
+
warn("better-sqlite3 native bindings are missing or not loadable.");
|
|
391
398
|
log(`Searched in: ${DIM}${sqliteModulePath}/build/${RESET}`);
|
|
392
399
|
log("Running: npm rebuild better-sqlite3 (may take 30-60s)...");
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
const startMs = Date.now();
|
|
396
|
-
|
|
397
|
-
const result = spawnSync(npmCmd, ["rebuild", "better-sqlite3"], {
|
|
398
|
-
cwd: pluginDir,
|
|
399
|
-
stdio: "pipe",
|
|
400
|
-
shell: false,
|
|
401
|
-
timeout: 180_000,
|
|
402
|
-
});
|
|
403
400
|
|
|
404
401
|
const startMs = Date.now();
|
|
405
|
-
const result = spawnSync(
|
|
402
|
+
const result = spawnSync(npmCmd, ["rebuild", "better-sqlite3"], {
|
|
406
403
|
cwd: pluginDir,
|
|
407
404
|
stdio: "pipe",
|
|
408
|
-
shell:
|
|
405
|
+
shell: false,
|
|
409
406
|
timeout: 180_000,
|
|
410
407
|
});
|
|
411
408
|
const elapsed = ((Date.now() - startMs) / 1000).toFixed(1);
|
package/src/viewer/server.ts
CHANGED
|
@@ -3356,6 +3356,32 @@ export class ViewerServer {
|
|
|
3356
3356
|
const shortName = pluginName?.replace(/^@[\w-]+\//, "") ?? "memos-local-openclaw-plugin";
|
|
3357
3357
|
const extDir = path.join(os.homedir(), ".openclaw", "extensions", shortName);
|
|
3358
3358
|
const tmpDir = path.join(os.tmpdir(), `openclaw-update-${Date.now()}`);
|
|
3359
|
+
const backupDir = path.join(path.dirname(extDir), `${shortName}.backup-${Date.now()}`);
|
|
3360
|
+
let backupReady = false;
|
|
3361
|
+
|
|
3362
|
+
const cleanupTmpDir = () => {
|
|
3363
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
3364
|
+
};
|
|
3365
|
+
const rollbackInstall = () => {
|
|
3366
|
+
try { fs.rmSync(extDir, { recursive: true, force: true }); } catch {}
|
|
3367
|
+
if (!backupReady) return;
|
|
3368
|
+
try {
|
|
3369
|
+
fs.renameSync(backupDir, extDir);
|
|
3370
|
+
backupReady = false;
|
|
3371
|
+
this.log.info(`update-install: restored previous version from ${backupDir}`);
|
|
3372
|
+
} catch (restoreErr: any) {
|
|
3373
|
+
this.log.warn(`update-install: failed to restore previous version: ${restoreErr?.message ?? restoreErr}`);
|
|
3374
|
+
}
|
|
3375
|
+
};
|
|
3376
|
+
const discardBackup = () => {
|
|
3377
|
+
if (!backupReady) return;
|
|
3378
|
+
try {
|
|
3379
|
+
fs.rmSync(backupDir, { recursive: true, force: true });
|
|
3380
|
+
backupReady = false;
|
|
3381
|
+
} catch (cleanupErr: any) {
|
|
3382
|
+
this.log.warn(`update-install: failed to remove backup dir ${backupDir}: ${cleanupErr?.message ?? cleanupErr}`);
|
|
3383
|
+
}
|
|
3384
|
+
};
|
|
3359
3385
|
|
|
3360
3386
|
// Download via npm pack, extract, and replace extension dir.
|
|
3361
3387
|
// Does NOT touch openclaw.json → no config watcher SIGUSR1.
|
|
@@ -3365,7 +3391,7 @@ export class ViewerServer {
|
|
|
3365
3391
|
if (packErr) {
|
|
3366
3392
|
this.log.warn(`update-install: npm pack failed: ${packErr.message}`);
|
|
3367
3393
|
this.jsonResponse(res, { ok: false, error: `Download failed: ${packErr.message}` });
|
|
3368
|
-
|
|
3394
|
+
cleanupTmpDir();
|
|
3369
3395
|
return;
|
|
3370
3396
|
}
|
|
3371
3397
|
const tgzFile = packOut.trim().split("\n").pop()!;
|
|
@@ -3378,7 +3404,7 @@ export class ViewerServer {
|
|
|
3378
3404
|
if (tarErr) {
|
|
3379
3405
|
this.log.warn(`update-install: tar extract failed: ${tarErr.message}`);
|
|
3380
3406
|
this.jsonResponse(res, { ok: false, error: `Extract failed: ${tarErr.message}` });
|
|
3381
|
-
|
|
3407
|
+
cleanupTmpDir();
|
|
3382
3408
|
return;
|
|
3383
3409
|
}
|
|
3384
3410
|
|
|
@@ -3386,23 +3412,36 @@ export class ViewerServer {
|
|
|
3386
3412
|
const srcDir = path.join(extractDir, "package");
|
|
3387
3413
|
if (!fs.existsSync(srcDir)) {
|
|
3388
3414
|
this.jsonResponse(res, { ok: false, error: "Extracted package has no 'package' dir" });
|
|
3389
|
-
|
|
3415
|
+
cleanupTmpDir();
|
|
3390
3416
|
return;
|
|
3391
3417
|
}
|
|
3392
3418
|
|
|
3393
3419
|
// Replace extension directory
|
|
3394
3420
|
this.log.info(`update-install: replacing ${extDir}...`);
|
|
3395
|
-
try {
|
|
3396
|
-
|
|
3397
|
-
|
|
3421
|
+
try {
|
|
3422
|
+
fs.mkdirSync(path.dirname(extDir), { recursive: true });
|
|
3423
|
+
try { fs.rmSync(backupDir, { recursive: true, force: true }); } catch {}
|
|
3424
|
+
if (fs.existsSync(extDir)) {
|
|
3425
|
+
fs.renameSync(extDir, backupDir);
|
|
3426
|
+
backupReady = true;
|
|
3427
|
+
}
|
|
3428
|
+
fs.renameSync(srcDir, extDir);
|
|
3429
|
+
} catch (replaceErr: any) {
|
|
3430
|
+
this.log.warn(`update-install: replace failed: ${replaceErr?.message ?? replaceErr}`);
|
|
3431
|
+
cleanupTmpDir();
|
|
3432
|
+
rollbackInstall();
|
|
3433
|
+
this.jsonResponse(res, { ok: false, error: `Replace failed: ${replaceErr?.message ?? replaceErr}` });
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3398
3436
|
|
|
3399
3437
|
// Install dependencies
|
|
3400
3438
|
this.log.info(`update-install: installing dependencies...`);
|
|
3401
3439
|
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
3402
3440
|
execFile(npmCmd, ["install", "--omit=dev", "--ignore-scripts"], { cwd: extDir, timeout: 120_000 }, (npmErr, npmOut, npmStderr) => {
|
|
3403
3441
|
if (npmErr) {
|
|
3404
|
-
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
3405
3442
|
this.log.warn(`update-install: npm install failed: ${npmErr.message}`);
|
|
3443
|
+
cleanupTmpDir();
|
|
3444
|
+
rollbackInstall();
|
|
3406
3445
|
this.jsonResponse(res, { ok: false, error: `Dependency install failed: ${npmStderr || npmErr.message}` });
|
|
3407
3446
|
return;
|
|
3408
3447
|
}
|
|
@@ -3416,12 +3455,15 @@ export class ViewerServer {
|
|
|
3416
3455
|
|
|
3417
3456
|
this.log.info(`update-install: running postinstall...`);
|
|
3418
3457
|
execFile(process.execPath, ["scripts/postinstall.cjs"], { cwd: extDir, timeout: 180_000 }, (postErr, postOut, postStderr) => {
|
|
3419
|
-
|
|
3458
|
+
cleanupTmpDir();
|
|
3420
3459
|
|
|
3421
3460
|
if (postErr) {
|
|
3422
3461
|
this.log.warn(`update-install: postinstall failed: ${postErr.message}`);
|
|
3423
3462
|
const postStderrStr = String(postStderr || "").trim();
|
|
3424
3463
|
if (postStderrStr) this.log.warn(`update-install: postinstall stderr: ${postStderrStr.slice(0, 500)}`);
|
|
3464
|
+
rollbackInstall();
|
|
3465
|
+
this.jsonResponse(res, { ok: false, error: `Postinstall failed: ${postStderrStr || postErr.message}` });
|
|
3466
|
+
return;
|
|
3425
3467
|
}
|
|
3426
3468
|
|
|
3427
3469
|
// Read new version
|
|
@@ -3431,6 +3473,7 @@ export class ViewerServer {
|
|
|
3431
3473
|
newVersion = newPkg.version ?? newVersion;
|
|
3432
3474
|
} catch {}
|
|
3433
3475
|
|
|
3476
|
+
discardBackup();
|
|
3434
3477
|
this.log.info(`update-install: success! Updated to ${newVersion}`);
|
|
3435
3478
|
this.jsonResponse(res, { ok: true, version: newVersion });
|
|
3436
3479
|
|