From 9c272c36255605e30ba6959d976ee249398421c9 Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 14 Apr 2026 14:40:37 -0700 Subject: [PATCH 1/6] Add version check to OpenClaw plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check GitHub for newer versions on plugin registration. Since child_process is stubbed in the OpenClaw bundle, auto-update isn't possible — log a notice with the update command instead. --- openclaw/src/index.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index d9413a1..0769079 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -38,6 +38,43 @@ interface PluginAPI { } const DEFAULT_API_URL = "https://api.deeplake.ai"; +const GITHUB_RAW_PKG = "https://raw.githubusercontent.com/activeloopai/hivemind/main/openclaw/package.json"; + +function getInstalledVersion(): string | null { + try { + // dist/index.js → package.json is one level up + const dir = new URL(".", import.meta.url).pathname; + const candidates = [join(dir, "..", "package.json"), join(dir, "package.json")]; + for (const c of candidates) { + try { + const pkg = JSON.parse(readFileSync(c, "utf-8")); + if (pkg.name === "hivemind" && pkg.version) return pkg.version; + } catch {} + } + } catch {} + return null; +} + +function isNewer(latest: string, current: string): boolean { + const parse = (v: string) => v.split(".").map(Number); + const [la, lb, lc] = parse(latest); + const [ca, cb, cc] = parse(current); + return la > ca || (la === ca && lb > cb) || (la === ca && lb === cb && lc > cc); +} + +async function checkForUpdate(logger: PluginLogger): Promise { + try { + const current = getInstalledVersion(); + if (!current) return; + const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(3000) }); + if (!res.ok) return; + const pkg = await res.json(); + const latest = pkg.version; + if (latest && isNewer(latest, current)) { + logger.info?.(`⬆️ Hivemind update available: ${current} → ${latest}. Run: openclaw plugins update hivemind`); + } + } catch {} +} // --- Auth state --- let authPending = false; @@ -314,6 +351,9 @@ export default definePluginEntry({ }); } + // Non-blocking version check + checkForUpdate(logger).catch(() => {}); + logger.info?.("Hivemind plugin registered"); } catch (err) { pluginApi.logger?.error?.(`Hivemind register failed: ${err instanceof Error ? err.message : String(err)}`); From 1d1a12fceb08821b42963beb50b377b1e217f1e5 Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 14 Apr 2026 15:46:53 -0700 Subject: [PATCH 2/6] Address review: npm registry, pre-release parse, version type guard - Use npm registry instead of GitHub raw to avoid false update notices for unreleased versions on main - Strip pre-release suffix before version comparison - Add string type guard on pkg.version from registry response --- openclaw/src/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index 0769079..1ef89d0 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -38,7 +38,7 @@ interface PluginAPI { } const DEFAULT_API_URL = "https://api.deeplake.ai"; -const GITHUB_RAW_PKG = "https://raw.githubusercontent.com/activeloopai/hivemind/main/openclaw/package.json"; +const GITHUB_RAW_PKG = "https://registry.npmjs.org/hivemind/latest"; function getInstalledVersion(): string | null { try { @@ -56,7 +56,7 @@ function getInstalledVersion(): string | null { } function isNewer(latest: string, current: string): boolean { - const parse = (v: string) => v.split(".").map(Number); + const parse = (v: string) => v.replace(/-.*$/, "").split(".").map(Number); const [la, lb, lc] = parse(latest); const [ca, cb, cc] = parse(current); return la > ca || (la === ca && lb > cb) || (la === ca && lb === cb && lc > cc); @@ -69,7 +69,7 @@ async function checkForUpdate(logger: PluginLogger): Promise { const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(3000) }); if (!res.ok) return; const pkg = await res.json(); - const latest = pkg.version; + const latest = typeof pkg.version === "string" ? pkg.version : null; if (latest && isNewer(latest, current)) { logger.info?.(`⬆️ Hivemind update available: ${current} → ${latest}. Run: openclaw plugins update hivemind`); } From 530ce32b684d4bca4575ed3d321b284f3c7ffb15 Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 14 Apr 2026 16:18:39 -0700 Subject: [PATCH 3/6] Add unlinkSync to OpenClaw fs-wrap plugin auth.ts imports unlinkSync from node:fs but the OpenClaw esbuild fs-wrap didn't export it, breaking the build. --- esbuild.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 6b5b5b2..e905c6f 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -114,7 +114,7 @@ await build({ contents: [ 'import { createRequire } from "node:module";', 'const _f = createRequire(import.meta.url)("fs");', - 'export const { existsSync, writeFileSync, mkdirSync, appendFileSync } = _f;', + 'export const { existsSync, writeFileSync, mkdirSync, appendFileSync, unlinkSync } = _f;', 'const _k = ["rea","dFile","Sync"].join("");', 'export const rfs = _f[_k];', 'export { rfs as readFileSync };', From 941500b5986fc2a0292e0ea8a600eafd066d09a7 Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 14 Apr 2026 16:27:53 -0700 Subject: [PATCH 4/6] Revert to GitHub raw for version check npm registry has a different package named hivemind (0.1.2). The OpenClaw plugin is published on ClawHub, not npm. GitHub raw is the correct source for the latest version. --- openclaw/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index 1ef89d0..fa27a74 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -38,7 +38,7 @@ interface PluginAPI { } const DEFAULT_API_URL = "https://api.deeplake.ai"; -const GITHUB_RAW_PKG = "https://registry.npmjs.org/hivemind/latest"; +const GITHUB_RAW_PKG = "https://raw.githubusercontent.com/activeloopai/hivemind/main/openclaw/package.json"; function getInstalledVersion(): string | null { try { From 9453884e7f24747cce3e45868440382a722ccf31 Mon Sep 17 00:00:00 2001 From: kaghni Date: Tue, 14 Apr 2026 16:29:09 -0700 Subject: [PATCH 5/6] Add /hivemind_update command for manual update check Checks GitHub for newer version and tells the user what command to run. Cannot auto-update since child_process is stubbed in the OpenClaw bundle. --- openclaw/src/index.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index fa27a74..254fa26 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -210,6 +210,28 @@ export default definePluginEntry({ return { text: `🔐 Sign in to activate Hivemind memory:\n\n${url}\n\nAfter signing in, send another message.` }; }, }); + + pluginApi.registerCommand({ + name: "hivemind_update", + description: "Check for Hivemind updates and show how to upgrade", + handler: async () => { + const current = getInstalledVersion(); + if (!current) return { text: "Could not determine installed version." }; + try { + const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(3000) }); + if (!res.ok) return { text: `Current version: ${current}. Could not check for updates.` }; + const pkg = await res.json(); + const latest = typeof pkg.version === "string" ? pkg.version : null; + if (!latest) return { text: `Current version: ${current}. Could not parse latest version.` }; + if (isNewer(latest, current)) { + return { text: `⬆️ Update available: ${current} → ${latest}\n\nRun in your terminal:\n\`openclaw plugins update hivemind\`` }; + } + return { text: `✅ Hivemind v${current} is up to date.` }; + } catch { + return { text: `Current version: ${current}. Could not check for updates.` }; + } + }, + }); } const config = (pluginApi.pluginConfig ?? {}) as PluginConfig; From 8b61392d3e2ff745cccd2ca63edd1d4512493261 Mon Sep 17 00:00:00 2001 From: kaghni Date: Wed, 15 Apr 2026 12:05:47 -0700 Subject: [PATCH 6/6] Prompt user to run /hivemind_login after install if not authenticated --- openclaw/src/index.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index 254fa26..8cea5fc 100644 --- a/openclaw/src/index.ts +++ b/openclaw/src/index.ts @@ -365,12 +365,15 @@ export default definePluginEntry({ }); } - // Pre-fetch auth URL during registration + // Prompt login if not authenticated const creds = loadCredentials(); - if (!creds?.token && !authPending) { - requestAuth().catch(err => { - logger.error(`Pre-auth failed: ${err instanceof Error ? err.message : String(err)}`); - }); + if (!creds?.token) { + logger.info?.("Hivemind installed. Run /hivemind_login to authenticate and activate shared memory."); + if (!authPending) { + requestAuth().catch(err => { + logger.error(`Pre-auth failed: ${err instanceof Error ? err.message : String(err)}`); + }); + } } // Non-blocking version check