@memtensor/memos-cloud-openclaw-plugin 0.1.8-beta.2 → 0.1.8-beta.4

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.
@@ -2,7 +2,7 @@
2
2
  "id": "memos-cloud-openclaw-plugin",
3
3
  "name": "MemOS Cloud OpenClaw Plugin",
4
4
  "description": "MemOS Cloud recall + add memory via lifecycle hooks",
5
- "version": "0.1.8-beta.2",
5
+ "version": "0.1.8-beta.4",
6
6
  "kind": "lifecycle",
7
7
  "main": "./index.js",
8
8
  "configSchema": {
package/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  USER_QUERY_MARKER,
8
8
  searchMemory,
9
9
  } from "./lib/memos-cloud-api.js";
10
- import { checkUpdate } from "./lib/check-update.js";
10
+ import { startUpdateChecker } from "./lib/check-update.js";
11
11
  let lastCaptureTime = 0;
12
12
  const conversationCounters = new Map();
13
13
  const API_KEY_HELP_URL = "https://memos-dashboard.openmem.net/cn/apikeys/";
@@ -206,8 +206,8 @@ export default {
206
206
  const cfg = buildConfig(api.pluginConfig);
207
207
  const log = api.logger ?? console;
208
208
 
209
- // Call update check asynchronously. The interval control is inside checkUpdate
210
- checkUpdate(log);
209
+ // Start 12-hour background update interval
210
+ startUpdateChecker(log);
211
211
 
212
212
  if (!cfg.envFileStatus?.found) {
213
213
  const searchPaths = cfg.envFileStatus?.searchPaths?.join(", ") ?? ENV_FILE_SEARCH_HINTS.join(", ");
@@ -233,7 +233,6 @@ export default {
233
233
  }
234
234
 
235
235
  api.on("before_agent_start", async (event, ctx) => {
236
- checkUpdate(log);
237
236
  if (!cfg.recallEnabled) return;
238
237
  if (!event?.prompt || event.prompt.length < 3) return;
239
238
  if (!cfg.apiKey) {
@@ -1,14 +1,15 @@
1
1
  import https from "https";
2
2
  import fs from "fs";
3
- import { exec } from "child_process";
4
3
  import path from "path";
5
4
  import { fileURLToPath } from "url";
5
+ import { exec } from "child_process";
6
+ import os from "os";
6
7
 
7
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
9
 
9
- let lastCheckTime = 0;
10
- const CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
10
+ const CHECK_INTERVAL = 1 * 60 * 1000; // 1 minute
11
11
  const PLUGIN_NAME = "@memtensor/memos-cloud-openclaw-plugin";
12
+ const CHECK_FILE = path.join(os.tmpdir(), "memos_openclaw_update_check.json");
12
13
 
13
14
  const ANSI = {
14
15
  RESET: "\x1b[0m",
@@ -101,78 +102,111 @@ function compareVersions(v1, v2) {
101
102
  return 0;
102
103
  }
103
104
 
104
- export async function checkUpdate(log) {
105
- // Prevent infinite loop: do not check for updates if the current process
106
- // is already running an openclaw CLI command like `openclaw plugins update ...`
107
- const isUpdateCommand = process.argv.includes("plugins") && process.argv.includes("update");
108
- if (isUpdateCommand) {
105
+ export function startUpdateChecker(log) {
106
+ // Only start the interval if we are in the gateway
107
+ const isGateway = process.argv.includes("gateway");
108
+ if (!isGateway) {
109
109
  return;
110
110
  }
111
111
 
112
- const now = Date.now();
113
- if (now - lastCheckTime < CHECK_INTERVAL) {
114
- return;
115
- }
116
-
117
- lastCheckTime = now;
118
-
119
- const currentVersion = getPackageVersion();
120
- if (!currentVersion) {
121
- return;
122
- }
123
-
124
- try {
125
- const latestVersion = await getLatestVersion(log);
112
+ const runCheck = async () => {
113
+ log.info?.(`${ANSI.CYAN}[memos-cloud] Starting update check sequence...${ANSI.RESET}`);
126
114
 
127
- // Normal version check
128
- if (compareVersions(latestVersion, currentVersion) <= 0) {
115
+ // TRULY PREVENT LOOPS: The instant we start a check, record the time BEFORE any network or processing happens.
116
+ // This absolutely guarantees that even if the network hangs, NPM crashes, or openclaw update causes an immediate hot reload,
117
+ // the system has already advanced the 12-hour/1-min clock and will NOT re-enter this function on boot.
118
+ try {
119
+ fs.writeFileSync(CHECK_FILE, JSON.stringify({ time: Date.now() }));
120
+ } catch (e) {
121
+ log.warn?.(`${ANSI.RED}[memos-cloud] Failed to write initial timestamp file: ${e.message}${ANSI.RESET}`);
122
+ }
123
+
124
+ const currentVersion = getPackageVersion();
125
+ if (!currentVersion) {
126
+ log.warn?.(`${ANSI.RED}[memos-cloud] Could not read current version from package.json${ANSI.RESET}`);
129
127
  return;
130
128
  }
131
129
 
132
- log.info?.(`${ANSI.YELLOW}[memos-cloud] Update available: ${currentVersion} -> ${latestVersion}. Updating in background...${ANSI.RESET}`);
133
-
134
-
135
- let dotCount = 0;
136
- const progressInterval = setInterval(() => {
137
- dotCount++;
138
- const dots = ".".repeat(dotCount % 4);
139
- log.info?.(`${ANSI.YELLOW}[memos-cloud] Update in progress for memos-cloud-openclaw-plugin${dots}${ANSI.RESET}`);
140
- }, 5000); // Log every 5 seconds to show it's still alive
141
-
142
- const cliName = (() => {
143
- // Check the full path of the entry script (e.g., .../moltbot/bin/index.js) or the executable
144
- const scriptPath = process.argv[1] ? process.argv[1].toLowerCase() : "";
145
- const execPath = process.execPath ? process.execPath.toLowerCase() : "";
146
-
147
- if (scriptPath.includes("moltbot") || execPath.includes("moltbot")) return "moltbot";
148
- if (scriptPath.includes("clawdbot") || execPath.includes("clawdbot")) return "clawdbot";
149
- return "openclaw";
150
- })();
151
-
152
- exec(`${cliName} plugins update memos-cloud-openclaw-plugin`, (error, stdout, stderr) => {
153
- clearInterval(progressInterval);
154
-
155
- const outText = (stdout || "").trim();
156
- const errText = (stderr || "").trim();
157
-
158
- if (outText) log.info?.(`${ANSI.CYAN}[${cliName}-cli]${ANSI.RESET}\n${outText}`);
159
- if (errText) log.warn?.(`${ANSI.RED}[${cliName}-cli]${ANSI.RESET}\n${errText}`);
160
-
161
- // Wait for a brief moment to let file system sync if needed
162
- setTimeout(() => {
163
- const postUpdateVersion = getPackageVersion();
164
- const actuallyUpdated = (postUpdateVersion === latestVersion) && (postUpdateVersion !== currentVersion);
165
-
166
- if (error || !actuallyUpdated) {
167
- const reason = error ? "Command exited with error" : "Version did not change after update command";
168
- log.warn?.(`${ANSI.RED}[memos-cloud] Auto-update failed (${reason}). Please refer to the CLI logs above, or run manually: ${cliName} plugins update memos-cloud-openclaw-plugin${ANSI.RESET}`);
169
- } else {
170
- log.info?.(`${ANSI.GREEN}[memos-cloud] Successfully updated to version ${latestVersion}. Please restart the gateway to apply changes.${ANSI.RESET}`);
171
- }
172
- }, 1000); // Small 1-second buffer for file systems
173
- });
130
+ try {
131
+ log.info?.(`${ANSI.CYAN}[memos-cloud] Fetching latest version for ${PLUGIN_NAME} from registry...${ANSI.RESET}`);
132
+ const latestVersion = await getLatestVersion(log);
133
+
134
+ // Normal version check
135
+ if (compareVersions(latestVersion, currentVersion) <= 0) {
136
+ log.info?.(`${ANSI.GREEN}[memos-cloud] No update needed. Current: ${currentVersion}, Latest: ${latestVersion}${ANSI.RESET}`);
137
+ return;
138
+ }
139
+
140
+ log.info?.(`${ANSI.YELLOW}[memos-cloud] Update available: ${currentVersion} -> ${latestVersion}. Updating in background...${ANSI.RESET}`);
141
+
142
+ let dotCount = 0;
143
+ const progressInterval = setInterval(() => {
144
+ dotCount++;
145
+ const dots = ".".repeat(dotCount % 4);
146
+ log.info?.(`${ANSI.YELLOW}[memos-cloud] Update in progress for memos-cloud-openclaw-plugin${dots}${ANSI.RESET}`);
147
+ }, 5000); // Log every 5 seconds to show it's still alive
148
+
149
+ const cliName = (() => {
150
+ // Check the full path of the entry script (e.g., .../moltbot/bin/index.js) or the executable
151
+ const scriptPath = process.argv[1] ? process.argv[1].toLowerCase() : "";
152
+ const execPath = process.execPath ? process.execPath.toLowerCase() : "";
153
+
154
+ if (scriptPath.includes("moltbot") || execPath.includes("moltbot")) return "moltbot";
155
+ if (scriptPath.includes("clawdbot") || execPath.includes("clawdbot")) return "clawdbot";
156
+ return "openclaw";
157
+ })();
158
+
159
+ exec(`${cliName} plugins update memos-cloud-openclaw-plugin`, (error, stdout, stderr) => {
160
+ clearInterval(progressInterval);
161
+
162
+ const outText = (stdout || "").trim();
163
+ const errText = (stderr || "").trim();
164
+
165
+ if (outText) log.info?.(`${ANSI.CYAN}[${cliName}-cli]${ANSI.RESET}\n${outText}`);
166
+ if (errText) log.warn?.(`${ANSI.RED}[${cliName}-cli]${ANSI.RESET}\n${errText}`);
167
+
168
+ // Wait for a brief moment to let file system sync if needed
169
+ setTimeout(() => {
170
+ const postUpdateVersion = getPackageVersion();
171
+ const actuallyUpdated = (postUpdateVersion === latestVersion) && (postUpdateVersion !== currentVersion);
172
+
173
+ if (error || !actuallyUpdated) {
174
+ const reason = error ? "Command exited with error" : "Version did not change after update command";
175
+ log.warn?.(`${ANSI.RED}[memos-cloud] Auto-update failed (${reason}). Please refer to the CLI logs above, or run manually: ${cliName} plugins update memos-cloud-openclaw-plugin${ANSI.RESET}`);
176
+ } else {
177
+ log.info?.(`${ANSI.GREEN}[memos-cloud] Successfully updated to version ${latestVersion}. Please restart the gateway to apply changes.${ANSI.RESET}`);
178
+ }
179
+ }, 1000); // Small 1-second buffer for file systems
180
+ });
174
181
 
175
- } catch (error) {
176
- // Silently handle errors
182
+ } catch (error) {
183
+ log.warn?.(`${ANSI.RED}[memos-cloud] Update check failed entirely: ${error.message}${ANSI.RESET}`);
184
+ }
185
+ };
186
+
187
+ // Check when we last ran
188
+ let lastCheckTime = 0;
189
+ try {
190
+ if (fs.existsSync(CHECK_FILE)) {
191
+ const data = JSON.parse(fs.readFileSync(CHECK_FILE, "utf-8"));
192
+ lastCheckTime = data.time || 0;
193
+ }
194
+ } catch (e) {}
195
+
196
+ const now = Date.now();
197
+ const timeSinceLastCheck = now - lastCheckTime;
198
+
199
+ // If the interval has passed, run it IMMEDIATELY without delay.
200
+ // The immediate file-write at the top of runCheck() will prevent loop scenarios.
201
+ if (timeSinceLastCheck >= CHECK_INTERVAL) {
202
+ runCheck();
203
+ setInterval(runCheck, CHECK_INTERVAL);
204
+ } else {
205
+ // If it hasn't been the full interval yet, wait the remaining time, then trigger interval
206
+ const timeUntilNextCheck = CHECK_INTERVAL - timeSinceLastCheck;
207
+ setTimeout(() => {
208
+ runCheck();
209
+ setInterval(runCheck, CHECK_INTERVAL);
210
+ }, timeUntilNextCheck);
177
211
  }
178
212
  }
@@ -2,7 +2,7 @@
2
2
  "id": "memos-cloud-openclaw-plugin",
3
3
  "name": "MemOS Cloud OpenClaw Plugin",
4
4
  "description": "MemOS Cloud recall + add memory via lifecycle hooks",
5
- "version": "0.1.8-beta.2",
5
+ "version": "0.1.8-beta.4",
6
6
  "kind": "lifecycle",
7
7
  "main": "./index.js",
8
8
  "configSchema": {
@@ -2,7 +2,7 @@
2
2
  "id": "memos-cloud-openclaw-plugin",
3
3
  "name": "MemOS Cloud OpenClaw Plugin",
4
4
  "description": "MemOS Cloud recall + add memory via lifecycle hooks",
5
- "version": "0.1.8-beta.2",
5
+ "version": "0.1.8-beta.4",
6
6
  "kind": "lifecycle",
7
7
  "main": "./index.js",
8
8
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memtensor/memos-cloud-openclaw-plugin",
3
- "version": "0.1.8-beta.2",
3
+ "version": "0.1.8-beta.4",
4
4
  "description": "OpenClaw lifecycle plugin for MemOS Cloud (add + recall memory)",
5
5
  "scripts": {
6
6
  "sync-version": "node scripts/sync-version.js",