Files
oh-my-opencode/src/hooks/auto-update-checker/hook/background-update-check.ts
T
acamq 094bcc8ef2 fix(auto-update): sync cache package.json to opencode.json intent
When users switch opencode.json from pinned version to tag (e.g., 3.10.0 -> @latest),
the cache package.json still contains the pinned version. This causes bun install
to reinstall the old version instead of resolving the new tag.

This adds syncCachePackageJsonToIntent() which updates the cache package.json
to match the user's declared intent in opencode.json before running bun install.

Also fixes mock.module in test files to include all exported constants,
preventing module pollution across parallel tests.
2026-03-10 16:15:15 -06:00

90 lines
3.2 KiB
TypeScript

import type { PluginInput } from "@opencode-ai/plugin"
import { runBunInstall } from "../../../cli/config-manager"
import { log } from "../../../shared/logger"
import { invalidatePackage } from "../cache"
import { PACKAGE_NAME } from "../constants"
import { extractChannel } from "../version-channel"
import { findPluginEntry, getCachedVersion, getLatestVersion, revertPinnedVersion, syncCachePackageJsonToIntent } from "../checker"
import { showAutoUpdatedToast, showUpdateAvailableToast } from "./update-toasts"
function getPinnedVersionToastMessage(latestVersion: string): string {
return `Update available: ${latestVersion} (version pinned, update manually)`
}
async function runBunInstallSafe(): Promise<boolean> {
try {
return await runBunInstall()
} catch (err) {
const errorMessage = err instanceof Error ? err.message : String(err)
log("[auto-update-checker] bun install error:", errorMessage)
return false
}
}
export async function runBackgroundUpdateCheck(
ctx: PluginInput,
autoUpdate: boolean,
getToastMessage: (isUpdate: boolean, latestVersion?: string) => string
): Promise<void> {
const pluginInfo = findPluginEntry(ctx.directory)
if (!pluginInfo) {
log("[auto-update-checker] Plugin not found in config")
return
}
const cachedVersion = getCachedVersion()
const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion
if (!currentVersion) {
log("[auto-update-checker] No version found (cached or pinned)")
return
}
const channel = extractChannel(pluginInfo.pinnedVersion ?? currentVersion)
const latestVersion = await getLatestVersion(channel)
if (!latestVersion) {
log("[auto-update-checker] Failed to fetch latest version for channel:", channel)
return
}
if (currentVersion === latestVersion) {
log("[auto-update-checker] Already on latest version for channel:", channel)
return
}
log(`[auto-update-checker] Update available (${channel}): ${currentVersion}${latestVersion}`)
if (!autoUpdate) {
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage)
log("[auto-update-checker] Auto-update disabled, notification only")
return
}
if (pluginInfo.isPinned) {
await showUpdateAvailableToast(ctx, latestVersion, () => getPinnedVersionToastMessage(latestVersion))
log(`[auto-update-checker] User-pinned version detected (${pluginInfo.entry}), skipping auto-update. Notification only.`)
return
}
// Sync cache package.json to match opencode.json intent before updating
// This handles the case where user switched from pinned version to tag (e.g., 3.10.0 -> @latest)
syncCachePackageJsonToIntent(pluginInfo)
invalidatePackage(PACKAGE_NAME)
const installSuccess = await runBunInstallSafe()
if (installSuccess) {
await showAutoUpdatedToast(ctx, currentVersion, latestVersion)
log(`[auto-update-checker] Update installed: ${currentVersion}${latestVersion}`)
return
}
if (pluginInfo.isPinned) {
revertPinnedVersion(pluginInfo.configPath, latestVersion, pluginInfo.entry)
log("[auto-update-checker] Config reverted due to install failure")
}
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage)
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)")
}