fix(auto-update-checker): defer npm registry check until first idle
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -1,10 +1,23 @@
|
|||||||
import type { PluginInput } from "@opencode-ai/plugin"
|
import type { PluginInput } from "@opencode-ai/plugin"
|
||||||
import { describe, expect, mock, test } from "bun:test"
|
import { describe, expect, mock, test } from "bun:test"
|
||||||
|
|
||||||
const latestVersionMock = mock.fn(async () => "3.0.1")
|
let latestVersionCallCount = 0
|
||||||
const scheduleDeferredIdleCheckMock = mock.fn((runCheck: () => void) => {
|
let scheduleDeferredIdleCheckCallCount = 0
|
||||||
|
const flushMicrotasks = async (count: number): Promise<void> => {
|
||||||
|
for (let index = 0; index < count; index += 1) {
|
||||||
|
await Promise.resolve()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const latestVersionMock = async () => {
|
||||||
|
latestVersionCallCount += 1
|
||||||
|
return "3.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduleDeferredIdleCheckMock = (runCheck: () => void) => {
|
||||||
|
scheduleDeferredIdleCheckCallCount += 1
|
||||||
scheduledCheck = runCheck
|
scheduledCheck = runCheck
|
||||||
})
|
}
|
||||||
|
|
||||||
let scheduledCheck: (() => void) | null = null
|
let scheduledCheck: (() => void) | null = null
|
||||||
|
|
||||||
@@ -51,8 +64,8 @@ const createHook = async () => {
|
|||||||
describe("auto-update-checker hook", () => {
|
describe("auto-update-checker hook", () => {
|
||||||
test("defers update check until first session idle", async () => {
|
test("defers update check until first session idle", async () => {
|
||||||
// given
|
// given
|
||||||
latestVersionMock.mockClear()
|
latestVersionCallCount = 0
|
||||||
scheduleDeferredIdleCheckMock.mockClear()
|
scheduleDeferredIdleCheckCallCount = 0
|
||||||
scheduledCheck = null
|
scheduledCheck = null
|
||||||
const hook = await createHook()
|
const hook = await createHook()
|
||||||
|
|
||||||
@@ -60,28 +73,28 @@ describe("auto-update-checker hook", () => {
|
|||||||
hook.event({ event: { type: "session.created" } })
|
hook.event({ event: { type: "session.created" } })
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(0)
|
expect(scheduleDeferredIdleCheckCallCount).toBe(0)
|
||||||
expect(latestVersionMock).toHaveBeenCalledTimes(0)
|
expect(latestVersionCallCount).toBe(0)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
hook.event({ event: { type: "session.idle" } })
|
hook.event({ event: { type: "session.idle" } })
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1)
|
expect(scheduleDeferredIdleCheckCallCount).toBe(1)
|
||||||
expect(latestVersionMock).toHaveBeenCalledTimes(0)
|
expect(latestVersionCallCount).toBe(0)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
scheduledCheck?.()
|
await scheduledCheck?.()
|
||||||
|
await flushMicrotasks(8)
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(latestVersionMock).toHaveBeenCalledTimes(1)
|
expect(latestVersionCallCount).toBe(1)
|
||||||
|
|
||||||
// when
|
// when
|
||||||
hook.event({ event: { type: "session.idle" } })
|
hook.event({ event: { type: "session.idle" } })
|
||||||
scheduledCheck?.()
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(scheduleDeferredIdleCheckMock).toHaveBeenCalledTimes(1)
|
expect(scheduleDeferredIdleCheckCallCount).toBe(1)
|
||||||
expect(latestVersionMock).toHaveBeenCalledTimes(1)
|
expect(latestVersionCallCount).toBe(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { log } from "../../shared/logger"
|
|||||||
import type { AutoUpdateCheckerOptions } from "./types"
|
import type { AutoUpdateCheckerOptions } from "./types"
|
||||||
import { getCachedVersion, getLocalDevVersion } from "./checker"
|
import { getCachedVersion, getLocalDevVersion } from "./checker"
|
||||||
import { runBackgroundUpdateCheck } from "./hook/background-update-check"
|
import { runBackgroundUpdateCheck } from "./hook/background-update-check"
|
||||||
|
import { scheduleDeferredIdleCheck } from "./hook/deferred-idle-check"
|
||||||
import { showConfigErrorsIfAny } from "./hook/config-errors-toast"
|
import { showConfigErrorsIfAny } from "./hook/config-errors-toast"
|
||||||
import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status"
|
import { updateAndShowConnectedProvidersCacheStatus } from "./hook/connected-providers-status"
|
||||||
import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status"
|
import { refreshModelCapabilitiesOnStartup } from "./hook/model-capabilities-status"
|
||||||
@@ -60,44 +61,45 @@ export function createAutoUpdateCheckerHook(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let hasChecked = false
|
let hasChecked = false
|
||||||
|
let hasScheduled = false
|
||||||
|
|
||||||
return {
|
return {
|
||||||
event: ({ event }: { event: { type: string; properties?: unknown } }) => {
|
event: ({ event }: { event: { type: string; properties?: unknown } }) => {
|
||||||
if (event.type !== "session.created") return
|
if (event.type !== "session.idle") return
|
||||||
if (isCliRunMode) return
|
if (isCliRunMode) return
|
||||||
if (hasChecked) return
|
if (hasChecked || hasScheduled) return
|
||||||
|
|
||||||
const props = event.properties as { info?: { parentID?: string } } | undefined
|
hasScheduled = true
|
||||||
if (props?.info?.parentID) return
|
|
||||||
|
|
||||||
|
scheduleDeferredIdleCheck(() => {
|
||||||
hasChecked = true
|
hasChecked = true
|
||||||
|
void (async () => {
|
||||||
|
const cachedVersion = deps.getCachedVersion()
|
||||||
|
const localDevVersion = deps.getLocalDevVersion(ctx.directory)
|
||||||
|
const displayVersion = localDevVersion ?? cachedVersion
|
||||||
|
|
||||||
setTimeout(async () => {
|
await deps.showConfigErrorsIfAny(ctx)
|
||||||
const cachedVersion = deps.getCachedVersion()
|
await deps.updateAndShowConnectedProvidersCacheStatus(ctx)
|
||||||
const localDevVersion = deps.getLocalDevVersion(ctx.directory)
|
await deps.refreshModelCapabilitiesOnStartup(modelCapabilities)
|
||||||
const displayVersion = localDevVersion ?? cachedVersion
|
await deps.showModelCacheWarningIfNeeded(ctx)
|
||||||
|
|
||||||
await deps.showConfigErrorsIfAny(ctx)
|
if (localDevVersion) {
|
||||||
await deps.updateAndShowConnectedProvidersCacheStatus(ctx)
|
if (showStartupToast) {
|
||||||
await deps.refreshModelCapabilitiesOnStartup(modelCapabilities)
|
deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {})
|
||||||
await deps.showModelCacheWarningIfNeeded(ctx)
|
}
|
||||||
|
deps.log("[auto-update-checker] Local development mode")
|
||||||
if (localDevVersion) {
|
return
|
||||||
if (showStartupToast) {
|
|
||||||
deps.showLocalDevToast(ctx, displayVersion, isSisyphusEnabled).catch(() => {})
|
|
||||||
}
|
}
|
||||||
deps.log("[auto-update-checker] Local development mode")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showStartupToast) {
|
if (showStartupToast) {
|
||||||
deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {})
|
deps.showVersionToast(ctx, displayVersion, getToastMessage(false)).catch(() => {})
|
||||||
}
|
}
|
||||||
|
|
||||||
deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => {
|
deps.runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage).catch((err) => {
|
||||||
deps.log("[auto-update-checker] Background update check failed:", err)
|
deps.log("[auto-update-checker] Background update check failed:", err)
|
||||||
})
|
})
|
||||||
}, 0)
|
})()
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export function scheduleDeferredIdleCheck(runCheck: () => void): void {
|
||||||
|
const timeout = setTimeout(runCheck, 5000)
|
||||||
|
timeout.unref?.()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user