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 };', diff --git a/openclaw/src/index.ts b/openclaw/src/index.ts index d9413a1..8cea5fc 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.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); +} + +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 = typeof pkg.version === "string" ? pkg.version : null; + if (latest && isNewer(latest, current)) { + logger.info?.(`⬆️ Hivemind update available: ${current} → ${latest}. Run: openclaw plugins update hivemind`); + } + } catch {} +} // --- Auth state --- let authPending = false; @@ -173,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; @@ -306,14 +365,20 @@ 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 + checkForUpdate(logger).catch(() => {}); + logger.info?.("Hivemind plugin registered"); } catch (err) { pluginApi.logger?.error?.(`Hivemind register failed: ${err instanceof Error ? err.message : String(err)}`);