Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion esbuild.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };',
Expand Down
62 changes: 62 additions & 0 deletions openclaw/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -314,6 +373,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)}`);
Expand Down
Loading