diff --git a/claude-code/bundle/session-start-setup.js b/claude-code/bundle/session-start-setup.js index c0f05cc..3d1d476 100755 --- a/claude-code/bundle/session-start-setup.js +++ b/claude-code/bundle/session-start-setup.js @@ -2,9 +2,9 @@ // dist/src/hooks/session-start-setup.js import { fileURLToPath } from "node:url"; -import { dirname as dirname2, join as join7 } from "node:path"; +import { dirname as dirname3, join as join8 } from "node:path"; import { execSync as execSync2 } from "node:child_process"; -import { homedir as homedir4 } from "node:os"; +import { homedir as homedir5 } from "node:os"; // dist/src/commands/auth.js import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs"; @@ -451,17 +451,6 @@ function getInstalledVersion(bundleDir, pluginManifestDir) { } return null; } -async function getLatestVersion(timeoutMs = 3e3) { - try { - const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(timeoutMs) }); - if (!res.ok) - return null; - const pkg = await res.json(); - return pkg.version ?? null; - } catch { - return null; - } -} function isNewer(latest, current) { const parse = (v) => v.split(".").map(Number); const [la, lb, lc] = parse(latest); @@ -469,16 +458,75 @@ function isNewer(latest, current) { return la > ca || la === ca && lb > cb || la === ca && lb === cb && lc > cc; } +// dist/src/hooks/version-check.js +import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs"; +import { dirname as dirname2, join as join6 } from "node:path"; +import { homedir as homedir4 } from "node:os"; +var DEFAULT_VERSION_CACHE_PATH = join6(homedir4(), ".deeplake", ".version-check.json"); +var DEFAULT_VERSION_CACHE_TTL_MS = 60 * 60 * 1e3; +function readVersionCache(cachePath = DEFAULT_VERSION_CACHE_PATH) { + if (!existsSync4(cachePath)) + return null; + try { + const parsed = JSON.parse(readFileSync5(cachePath, "utf-8")); + if (parsed && typeof parsed.checkedAt === "number" && typeof parsed.url === "string" && (typeof parsed.latest === "string" || parsed.latest === null)) { + return parsed; + } + } catch { + } + return null; +} +function writeVersionCache(entry, cachePath = DEFAULT_VERSION_CACHE_PATH) { + mkdirSync3(dirname2(cachePath), { recursive: true }); + writeFileSync3(cachePath, JSON.stringify(entry)); +} +function readFreshCachedLatestVersion(url, ttlMs = DEFAULT_VERSION_CACHE_TTL_MS, cachePath = DEFAULT_VERSION_CACHE_PATH, nowMs = Date.now()) { + const cached = readVersionCache(cachePath); + if (!cached || cached.url !== url) + return void 0; + if (nowMs - cached.checkedAt > ttlMs) + return void 0; + return cached.latest; +} +async function getLatestVersionCached(opts) { + const ttlMs = opts.ttlMs ?? DEFAULT_VERSION_CACHE_TTL_MS; + const cachePath = opts.cachePath ?? DEFAULT_VERSION_CACHE_PATH; + const nowMs = opts.nowMs ?? Date.now(); + const fetchImpl = opts.fetchImpl ?? fetch; + const fresh = readFreshCachedLatestVersion(opts.url, ttlMs, cachePath, nowMs); + if (fresh !== void 0) + return fresh; + const stale = readVersionCache(cachePath); + try { + const res = await fetchImpl(opts.url, { signal: AbortSignal.timeout(opts.timeoutMs) }); + const latest = res.ok ? (await res.json()).version ?? null : stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } catch { + const latest = stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } +} + // dist/src/utils/wiki-log.js -import { mkdirSync as mkdirSync3, appendFileSync as appendFileSync2 } from "node:fs"; -import { join as join6 } from "node:path"; +import { mkdirSync as mkdirSync4, appendFileSync as appendFileSync2 } from "node:fs"; +import { join as join7 } from "node:path"; function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { - const path = join6(hooksDir, filename); + const path = join7(hooksDir, filename); return { path, log(msg) { try { - mkdirSync3(hooksDir, { recursive: true }); + mkdirSync4(hooksDir, { recursive: true }); appendFileSync2(path, `[${utcTimestamp()}] ${msg} `); } catch { @@ -489,8 +537,8 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { // dist/src/hooks/session-start-setup.js var log3 = (msg) => log("session-setup", msg); -var __bundleDir = dirname2(fileURLToPath(import.meta.url)); -var { log: wikiLog } = makeWikiLogger(join7(homedir4(), ".claude", "hooks")); +var __bundleDir = dirname3(fileURLToPath(import.meta.url)); +var { log: wikiLog } = makeWikiLogger(join8(homedir5(), ".claude", "hooks")); async function main() { if (process.env.HIVEMIND_WIKI_WORKER === "1") return; @@ -527,7 +575,7 @@ async function main() { try { const current = getInstalledVersion(__bundleDir, ".claude-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3e3 }); if (latest && isNewer(latest, current)) { if (autoupdate) { log3(`autoupdate: updating ${current} \u2192 ${latest}`); diff --git a/claude-code/bundle/session-start.js b/claude-code/bundle/session-start.js index 1f815ee..c222aa4 100755 --- a/claude-code/bundle/session-start.js +++ b/claude-code/bundle/session-start.js @@ -2,10 +2,10 @@ // dist/src/hooks/session-start.js import { fileURLToPath } from "node:url"; -import { dirname as dirname2, join as join7 } from "node:path"; +import { dirname as dirname3, join as join8 } from "node:path"; import { readdirSync, rmSync } from "node:fs"; import { execSync as execSync2 } from "node:child_process"; -import { homedir as homedir4 } from "node:os"; +import { homedir as homedir5 } from "node:os"; // dist/src/commands/auth.js import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs"; @@ -452,17 +452,6 @@ function getInstalledVersion(bundleDir, pluginManifestDir) { } return null; } -async function getLatestVersion(timeoutMs = 3e3) { - try { - const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(timeoutMs) }); - if (!res.ok) - return null; - const pkg = await res.json(); - return pkg.version ?? null; - } catch { - return null; - } -} function isNewer(latest, current) { const parse = (v) => v.split(".").map(Number); const [la, lb, lc] = parse(latest); @@ -470,16 +459,75 @@ function isNewer(latest, current) { return la > ca || la === ca && lb > cb || la === ca && lb === cb && lc > cc; } +// dist/src/hooks/version-check.js +import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs"; +import { dirname as dirname2, join as join6 } from "node:path"; +import { homedir as homedir4 } from "node:os"; +var DEFAULT_VERSION_CACHE_PATH = join6(homedir4(), ".deeplake", ".version-check.json"); +var DEFAULT_VERSION_CACHE_TTL_MS = 60 * 60 * 1e3; +function readVersionCache(cachePath = DEFAULT_VERSION_CACHE_PATH) { + if (!existsSync4(cachePath)) + return null; + try { + const parsed = JSON.parse(readFileSync5(cachePath, "utf-8")); + if (parsed && typeof parsed.checkedAt === "number" && typeof parsed.url === "string" && (typeof parsed.latest === "string" || parsed.latest === null)) { + return parsed; + } + } catch { + } + return null; +} +function writeVersionCache(entry, cachePath = DEFAULT_VERSION_CACHE_PATH) { + mkdirSync3(dirname2(cachePath), { recursive: true }); + writeFileSync3(cachePath, JSON.stringify(entry)); +} +function readFreshCachedLatestVersion(url, ttlMs = DEFAULT_VERSION_CACHE_TTL_MS, cachePath = DEFAULT_VERSION_CACHE_PATH, nowMs = Date.now()) { + const cached = readVersionCache(cachePath); + if (!cached || cached.url !== url) + return void 0; + if (nowMs - cached.checkedAt > ttlMs) + return void 0; + return cached.latest; +} +async function getLatestVersionCached(opts) { + const ttlMs = opts.ttlMs ?? DEFAULT_VERSION_CACHE_TTL_MS; + const cachePath = opts.cachePath ?? DEFAULT_VERSION_CACHE_PATH; + const nowMs = opts.nowMs ?? Date.now(); + const fetchImpl = opts.fetchImpl ?? fetch; + const fresh = readFreshCachedLatestVersion(opts.url, ttlMs, cachePath, nowMs); + if (fresh !== void 0) + return fresh; + const stale = readVersionCache(cachePath); + try { + const res = await fetchImpl(opts.url, { signal: AbortSignal.timeout(opts.timeoutMs) }); + const latest = res.ok ? (await res.json()).version ?? null : stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } catch { + const latest = stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } +} + // dist/src/utils/wiki-log.js -import { mkdirSync as mkdirSync3, appendFileSync as appendFileSync2 } from "node:fs"; -import { join as join6 } from "node:path"; +import { mkdirSync as mkdirSync4, appendFileSync as appendFileSync2 } from "node:fs"; +import { join as join7 } from "node:path"; function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { - const path = join6(hooksDir, filename); + const path = join7(hooksDir, filename); return { path, log(msg) { try { - mkdirSync3(hooksDir, { recursive: true }); + mkdirSync4(hooksDir, { recursive: true }); appendFileSync2(path, `[${utcTimestamp()}] ${msg} `); } catch { @@ -490,8 +538,8 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { // dist/src/hooks/session-start.js var log3 = (msg) => log("session-start", msg); -var __bundleDir = dirname2(fileURLToPath(import.meta.url)); -var AUTH_CMD = join7(__bundleDir, "commands", "auth-login.js"); +var __bundleDir = dirname3(fileURLToPath(import.meta.url)); +var AUTH_CMD = join8(__bundleDir, "commands", "auth-login.js"); var context = `DEEPLAKE MEMORY: You have TWO memory sources. ALWAYS check BOTH when the user asks you to recall, remember, or look up ANY information: 1. Your built-in memory (~/.claude/) \u2014 personal per-project notes @@ -522,8 +570,8 @@ IMPORTANT: Only use bash commands (cat, ls, grep, echo, jq, head, tail, etc.) to LIMITS: Do NOT spawn subagents to read deeplake memory. If a file returns empty after 2 attempts, skip it and move on. Report what you found rather than exhaustively retrying. Debugging: Set HIVEMIND_DEBUG=1 to enable verbose logging to ~/.deeplake/hook-debug.log`; -var HOME = homedir4(); -var { log: wikiLog } = makeWikiLogger(join7(HOME, ".claude", "hooks")); +var HOME = homedir5(); +var { log: wikiLog } = makeWikiLogger(join8(HOME, ".claude", "hooks")); async function createPlaceholder(api, table, sessionId, cwd, userName, orgName, workspaceId) { const summaryPath = `/summaries/${userName}/${sessionId}.md`; const existing = await api.query(`SELECT path FROM "${table}" WHERE path = '${sqlStr(summaryPath)}' LIMIT 1`); @@ -592,7 +640,7 @@ async function main() { try { const current = getInstalledVersion(__bundleDir, ".claude-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3e3 }); if (latest && isNewer(latest, current)) { if (autoupdate) { log3(`autoupdate: updating ${current} \u2192 ${latest}`); @@ -601,11 +649,11 @@ async function main() { const cmd = scopes.map((s) => `claude plugin update hivemind@hivemind --scope ${s} 2>/dev/null || true`).join("; "); execSync2(cmd, { stdio: "ignore", timeout: 6e4 }); try { - const cacheParent = join7(homedir4(), ".claude", "plugins", "cache", "hivemind", "hivemind"); + const cacheParent = join8(homedir5(), ".claude", "plugins", "cache", "hivemind", "hivemind"); const entries = readdirSync(cacheParent, { withFileTypes: true }); for (const e of entries) { if (e.isDirectory() && e.name !== latest) { - rmSync(join7(cacheParent, e.name), { recursive: true, force: true }); + rmSync(join8(cacheParent, e.name), { recursive: true, force: true }); log3(`cache cleanup: removed old version ${e.name}`); } } diff --git a/claude-code/tests/codex-session-start-setup-hook.test.ts b/claude-code/tests/codex-session-start-setup-hook.test.ts index 3c05a71..7ac310f 100644 --- a/claude-code/tests/codex-session-start-setup-hook.test.ts +++ b/claude-code/tests/codex-session-start-setup-hook.test.ts @@ -1,4 +1,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; /** * Source-level tests for src/hooks/codex/session-start-setup.ts. The @@ -67,7 +70,11 @@ const validConfig = { sessionsTableName: "sessions", }; +let cacheTmp: string; + beforeEach(() => { + cacheTmp = mkdtempSync(join(tmpdir(), "codex-session-start-setup-test-")); + process.env.HIVEMIND_VERSION_CACHE_PATH = join(cacheTmp, "cache.json"); stdinMock.mockReset().mockResolvedValue({ session_id: "sid-1", cwd: "/workspaces/proj", hook_event_name: "SessionStart", model: "gpt-5", @@ -92,6 +99,8 @@ afterEach(() => { vi.restoreAllMocks(); // @ts-expect-error global.fetch = originalFetch; + delete process.env.HIVEMIND_VERSION_CACHE_PATH; + try { rmSync(cacheTmp, { recursive: true, force: true }); } catch { /* ignore */ } }); describe("codex session-start-setup hook — guards", () => { diff --git a/claude-code/tests/session-start-hook.test.ts b/claude-code/tests/session-start-hook.test.ts index 27b15c8..6321544 100644 --- a/claude-code/tests/session-start-hook.test.ts +++ b/claude-code/tests/session-start-hook.test.ts @@ -99,6 +99,7 @@ let cacheTmp: string; beforeEach(() => { cacheTmp = mkdtempSync(join(tmpdir(), "session-start-test-")); + process.env.HIVEMIND_VERSION_CACHE_PATH = join(cacheTmp, "cache.json"); stdinMock.mockReset().mockResolvedValue({ session_id: "sid-1", cwd: "/workspaces/proj" }); loadCredsMock.mockReset().mockReturnValue({ token: "tok", orgId: "o", orgName: "acme", userName: "alice", workspaceId: "default", @@ -122,6 +123,7 @@ afterEach(() => { vi.restoreAllMocks(); // @ts-expect-error global.fetch = originalFetch; + delete process.env.HIVEMIND_VERSION_CACHE_PATH; try { rmSync(cacheTmp, { recursive: true, force: true }); } catch { /* ignore */ } }); diff --git a/claude-code/tests/session-start-setup-hook.test.ts b/claude-code/tests/session-start-setup-hook.test.ts index e3c9ca6..1288355 100644 --- a/claude-code/tests/session-start-setup-hook.test.ts +++ b/claude-code/tests/session-start-setup-hook.test.ts @@ -1,4 +1,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; /** * Source-level tests for src/hooks/session-start-setup.ts. This hook @@ -63,7 +66,11 @@ const validConfig = { sessionsTableName: "sessions", }; +let cacheTmp: string; + beforeEach(() => { + cacheTmp = mkdtempSync(join(tmpdir(), "session-start-setup-test-")); + process.env.HIVEMIND_VERSION_CACHE_PATH = join(cacheTmp, "cache.json"); stdinMock.mockReset().mockResolvedValue({ session_id: "sid-1", cwd: "/x" }); loadCredsMock.mockReset().mockReturnValue({ token: "tok", orgId: "o", orgName: "acme", userName: "alice", @@ -84,6 +91,8 @@ afterEach(() => { vi.restoreAllMocks(); // @ts-expect-error global.fetch = originalFetch; + delete process.env.HIVEMIND_VERSION_CACHE_PATH; + try { rmSync(cacheTmp, { recursive: true, force: true }); } catch { /* ignore */ } }); describe("session-start-setup hook — guards", () => { diff --git a/codex/bundle/session-start-setup.js b/codex/bundle/session-start-setup.js index 21609fa..924885e 100755 --- a/codex/bundle/session-start-setup.js +++ b/codex/bundle/session-start-setup.js @@ -2,9 +2,9 @@ // dist/src/hooks/codex/session-start-setup.js import { fileURLToPath } from "node:url"; -import { dirname as dirname2, join as join7 } from "node:path"; +import { dirname as dirname3, join as join8 } from "node:path"; import { execSync as execSync2 } from "node:child_process"; -import { homedir as homedir4 } from "node:os"; +import { homedir as homedir5 } from "node:os"; // dist/src/commands/auth.js import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from "node:fs"; @@ -451,17 +451,6 @@ function getInstalledVersion(bundleDir, pluginManifestDir) { } return null; } -async function getLatestVersion(timeoutMs = 3e3) { - try { - const res = await fetch(GITHUB_RAW_PKG, { signal: AbortSignal.timeout(timeoutMs) }); - if (!res.ok) - return null; - const pkg = await res.json(); - return pkg.version ?? null; - } catch { - return null; - } -} function isNewer(latest, current) { const parse = (v) => v.split(".").map(Number); const [la, lb, lc] = parse(latest); @@ -469,16 +458,75 @@ function isNewer(latest, current) { return la > ca || la === ca && lb > cb || la === ca && lb === cb && lc > cc; } +// dist/src/hooks/version-check.js +import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs"; +import { dirname as dirname2, join as join6 } from "node:path"; +import { homedir as homedir4 } from "node:os"; +var DEFAULT_VERSION_CACHE_PATH = join6(homedir4(), ".deeplake", ".version-check.json"); +var DEFAULT_VERSION_CACHE_TTL_MS = 60 * 60 * 1e3; +function readVersionCache(cachePath = DEFAULT_VERSION_CACHE_PATH) { + if (!existsSync4(cachePath)) + return null; + try { + const parsed = JSON.parse(readFileSync5(cachePath, "utf-8")); + if (parsed && typeof parsed.checkedAt === "number" && typeof parsed.url === "string" && (typeof parsed.latest === "string" || parsed.latest === null)) { + return parsed; + } + } catch { + } + return null; +} +function writeVersionCache(entry, cachePath = DEFAULT_VERSION_CACHE_PATH) { + mkdirSync3(dirname2(cachePath), { recursive: true }); + writeFileSync3(cachePath, JSON.stringify(entry)); +} +function readFreshCachedLatestVersion(url, ttlMs = DEFAULT_VERSION_CACHE_TTL_MS, cachePath = DEFAULT_VERSION_CACHE_PATH, nowMs = Date.now()) { + const cached = readVersionCache(cachePath); + if (!cached || cached.url !== url) + return void 0; + if (nowMs - cached.checkedAt > ttlMs) + return void 0; + return cached.latest; +} +async function getLatestVersionCached(opts) { + const ttlMs = opts.ttlMs ?? DEFAULT_VERSION_CACHE_TTL_MS; + const cachePath = opts.cachePath ?? DEFAULT_VERSION_CACHE_PATH; + const nowMs = opts.nowMs ?? Date.now(); + const fetchImpl = opts.fetchImpl ?? fetch; + const fresh = readFreshCachedLatestVersion(opts.url, ttlMs, cachePath, nowMs); + if (fresh !== void 0) + return fresh; + const stale = readVersionCache(cachePath); + try { + const res = await fetchImpl(opts.url, { signal: AbortSignal.timeout(opts.timeoutMs) }); + const latest = res.ok ? (await res.json()).version ?? null : stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } catch { + const latest = stale?.latest ?? null; + writeVersionCache({ + checkedAt: nowMs, + latest, + url: opts.url + }, cachePath); + return latest; + } +} + // dist/src/utils/wiki-log.js -import { mkdirSync as mkdirSync3, appendFileSync as appendFileSync2 } from "node:fs"; -import { join as join6 } from "node:path"; +import { mkdirSync as mkdirSync4, appendFileSync as appendFileSync2 } from "node:fs"; +import { join as join7 } from "node:path"; function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { - const path = join6(hooksDir, filename); + const path = join7(hooksDir, filename); return { path, log(msg) { try { - mkdirSync3(hooksDir, { recursive: true }); + mkdirSync4(hooksDir, { recursive: true }); appendFileSync2(path, `[${utcTimestamp()}] ${msg} `); } catch { @@ -489,8 +537,8 @@ function makeWikiLogger(hooksDir, filename = "deeplake-wiki.log") { // dist/src/hooks/codex/session-start-setup.js var log3 = (msg) => log("codex-session-setup", msg); -var __bundleDir = dirname2(fileURLToPath(import.meta.url)); -var { log: wikiLog } = makeWikiLogger(join7(homedir4(), ".codex", "hooks")); +var __bundleDir = dirname3(fileURLToPath(import.meta.url)); +var { log: wikiLog } = makeWikiLogger(join8(homedir5(), ".codex", "hooks")); async function createPlaceholder(api, table, sessionId, cwd, userName, orgName, workspaceId) { const summaryPath = `/summaries/${userName}/${sessionId}.md`; const existing = await api.query(`SELECT path FROM "${table}" WHERE path = '${sqlStr(summaryPath)}' LIMIT 1`); @@ -553,7 +601,7 @@ async function main() { try { const current = getInstalledVersion(__bundleDir, ".codex-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3e3 }); if (latest && isNewer(latest, current)) { if (autoupdate) { log3(`autoupdate: updating ${current} \u2192 ${latest}`); diff --git a/src/hooks/codex/session-start-setup.ts b/src/hooks/codex/session-start-setup.ts index 8dfb984..c1bbd64 100644 --- a/src/hooks/codex/session-start-setup.ts +++ b/src/hooks/codex/session-start-setup.ts @@ -16,7 +16,8 @@ import { DeeplakeApi } from "../../deeplake-api.js"; import { sqlStr } from "../../utils/sql.js"; import { readStdin } from "../../utils/stdin.js"; import { log as _log } from "../../utils/debug.js"; -import { getInstalledVersion, getLatestVersion, isNewer } from "../../utils/version-check.js"; +import { getInstalledVersion, GITHUB_RAW_PKG, isNewer } from "../../utils/version-check.js"; +import { getLatestVersionCached } from "../version-check.js"; import { makeWikiLogger } from "../../utils/wiki-log.js"; const log = (msg: string) => _log("codex-session-setup", msg); @@ -108,7 +109,7 @@ async function main(): Promise { try { const current = getInstalledVersion(__bundleDir, ".codex-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3000, cachePath: process.env.HIVEMIND_VERSION_CACHE_PATH || undefined }); if (latest && isNewer(latest, current)) { if (autoupdate) { log(`autoupdate: updating ${current} → ${latest}`); diff --git a/src/hooks/session-start-setup.ts b/src/hooks/session-start-setup.ts index f78ceb0..10ef5bc 100644 --- a/src/hooks/session-start-setup.ts +++ b/src/hooks/session-start-setup.ts @@ -15,7 +15,8 @@ import { loadConfig } from "../config.js"; import { DeeplakeApi } from "../deeplake-api.js"; import { readStdin } from "../utils/stdin.js"; import { log as _log } from "../utils/debug.js"; -import { getInstalledVersion, getLatestVersion, isNewer } from "../utils/version-check.js"; +import { getInstalledVersion, GITHUB_RAW_PKG, isNewer } from "../utils/version-check.js"; +import { getLatestVersionCached } from "./version-check.js"; import { makeWikiLogger } from "../utils/wiki-log.js"; const log = (msg: string) => _log("session-setup", msg); @@ -64,7 +65,7 @@ async function main(): Promise { try { const current = getInstalledVersion(__bundleDir, ".claude-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3000, cachePath: process.env.HIVEMIND_VERSION_CACHE_PATH || undefined }); if (latest && isNewer(latest, current)) { if (autoupdate) { log(`autoupdate: updating ${current} → ${latest}`); diff --git a/src/hooks/session-start.ts b/src/hooks/session-start.ts index 60e402b..8bc5567 100644 --- a/src/hooks/session-start.ts +++ b/src/hooks/session-start.ts @@ -17,7 +17,8 @@ import { DeeplakeApi } from "../deeplake-api.js"; import { sqlStr } from "../utils/sql.js"; import { readStdin } from "../utils/stdin.js"; import { log as _log } from "../utils/debug.js"; -import { getInstalledVersion, getLatestVersion, isNewer } from "../utils/version-check.js"; +import { getInstalledVersion, GITHUB_RAW_PKG, isNewer } from "../utils/version-check.js"; +import { getLatestVersionCached } from "./version-check.js"; import { makeWikiLogger } from "../utils/wiki-log.js"; const log = (msg: string) => _log("session-start", msg); @@ -154,7 +155,7 @@ async function main(): Promise { try { const current = getInstalledVersion(__bundleDir, ".claude-plugin"); if (current) { - const latest = await getLatestVersion(); + const latest = await getLatestVersionCached({ url: GITHUB_RAW_PKG, timeoutMs: 3000, cachePath: process.env.HIVEMIND_VERSION_CACHE_PATH || undefined }); if (latest && isNewer(latest, current)) { if (autoupdate) { log(`autoupdate: updating ${current} → ${latest}`); diff --git a/src/utils/version-check.ts b/src/utils/version-check.ts index e8e14cb..3c5a729 100644 --- a/src/utils/version-check.ts +++ b/src/utils/version-check.ts @@ -10,7 +10,7 @@ import { readFileSync } from "node:fs"; import { dirname, join } from "node:path"; -const GITHUB_RAW_PKG = "https://raw.githubusercontent.com/activeloopai/hivemind/main/package.json"; +export const GITHUB_RAW_PKG = "https://raw.githubusercontent.com/activeloopai/hivemind/main/package.json"; /** * Read the installed plugin version.