2025-12-13 01:18:39 +09:00
|
|
|
import type { PluginInput } from "@opencode-ai/plugin"
|
2025-12-14 17:48:41 +09:00
|
|
|
import { checkForUpdate, getCachedVersion, getLocalDevVersion } from "./checker"
|
2025-12-14 17:16:52 +09:00
|
|
|
import { invalidatePackage } from "./cache"
|
2025-12-13 01:18:39 +09:00
|
|
|
import { PACKAGE_NAME } from "./constants"
|
|
|
|
|
import { log } from "../../shared/logger"
|
2025-12-19 02:03:31 +09:00
|
|
|
import { getUserConfigPath } from "../../shared/config-path"
|
|
|
|
|
import { getConfigLoadErrors, clearConfigLoadErrors } from "../../index"
|
2025-12-14 17:16:52 +09:00
|
|
|
import type { AutoUpdateCheckerOptions } from "./types"
|
2025-12-13 01:18:39 +09:00
|
|
|
|
2025-12-14 17:16:52 +09:00
|
|
|
export function createAutoUpdateCheckerHook(ctx: PluginInput, options: AutoUpdateCheckerOptions = {}) {
|
|
|
|
|
const { showStartupToast = true } = options
|
2025-12-13 01:18:39 +09:00
|
|
|
let hasChecked = false
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
event: async ({ event }: { event: { type: string; properties?: unknown } }) => {
|
|
|
|
|
if (event.type !== "session.created") return
|
|
|
|
|
if (hasChecked) return
|
|
|
|
|
|
|
|
|
|
const props = event.properties as { info?: { parentID?: string } } | undefined
|
|
|
|
|
if (props?.info?.parentID) return
|
|
|
|
|
|
|
|
|
|
hasChecked = true
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const result = await checkForUpdate(ctx.directory)
|
|
|
|
|
|
|
|
|
|
if (result.isLocalDev) {
|
|
|
|
|
log("[auto-update-checker] Skipped: local development mode")
|
2025-12-14 17:16:52 +09:00
|
|
|
if (showStartupToast) {
|
2025-12-14 17:48:41 +09:00
|
|
|
const version = getLocalDevVersion(ctx.directory) ?? getCachedVersion()
|
|
|
|
|
await showVersionToast(ctx, version)
|
2025-12-14 17:16:52 +09:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result.isPinned) {
|
|
|
|
|
log(`[auto-update-checker] Skipped: version pinned to ${result.currentVersion}`)
|
|
|
|
|
if (showStartupToast) {
|
|
|
|
|
await showVersionToast(ctx, result.currentVersion)
|
|
|
|
|
}
|
2025-12-13 01:18:39 +09:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result.needsUpdate) {
|
|
|
|
|
log("[auto-update-checker] No update needed")
|
2025-12-14 17:16:52 +09:00
|
|
|
if (showStartupToast) {
|
|
|
|
|
await showVersionToast(ctx, result.currentVersion)
|
|
|
|
|
}
|
2025-12-13 01:18:39 +09:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-14 17:16:52 +09:00
|
|
|
invalidatePackage(PACKAGE_NAME)
|
2025-12-13 01:18:39 +09:00
|
|
|
|
|
|
|
|
await ctx.client.tui
|
|
|
|
|
.showToast({
|
|
|
|
|
body: {
|
2025-12-14 17:16:52 +09:00
|
|
|
title: `OhMyOpenCode ${result.latestVersion}`,
|
|
|
|
|
message: `OpenCode is now on Steroids. oMoMoMoMo...\nv${result.latestVersion} available. Restart OpenCode to apply.`,
|
2025-12-13 01:18:39 +09:00
|
|
|
variant: "info" as const,
|
|
|
|
|
duration: 8000,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {})
|
|
|
|
|
|
|
|
|
|
log(`[auto-update-checker] Update notification sent: v${result.currentVersion} → v${result.latestVersion}`)
|
|
|
|
|
} catch (err) {
|
|
|
|
|
log("[auto-update-checker] Error during update check:", err)
|
|
|
|
|
}
|
2025-12-19 02:03:31 +09:00
|
|
|
|
|
|
|
|
await showConfigErrorsIfAny(ctx)
|
2025-12-13 01:18:39 +09:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-19 02:03:31 +09:00
|
|
|
async function showConfigErrorsIfAny(ctx: PluginInput): Promise<void> {
|
|
|
|
|
const errors = getConfigLoadErrors()
|
|
|
|
|
if (errors.length === 0) return
|
|
|
|
|
|
|
|
|
|
const errorMessages = errors.map(e => `${e.path}: ${e.error}`).join("\n")
|
|
|
|
|
await ctx.client.tui
|
|
|
|
|
.showToast({
|
|
|
|
|
body: {
|
|
|
|
|
title: "Config Load Error",
|
|
|
|
|
message: `Failed to load config:\n${errorMessages}`,
|
|
|
|
|
variant: "error" as const,
|
|
|
|
|
duration: 10000,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {})
|
|
|
|
|
|
|
|
|
|
log(`[auto-update-checker] Config load errors shown: ${errors.length} error(s)`)
|
|
|
|
|
clearConfigLoadErrors()
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-14 17:16:52 +09:00
|
|
|
async function showVersionToast(ctx: PluginInput, version: string | null): Promise<void> {
|
|
|
|
|
const displayVersion = version ?? "unknown"
|
2025-12-19 02:03:31 +09:00
|
|
|
const configPath = getUserConfigPath()
|
2025-12-14 17:16:52 +09:00
|
|
|
await ctx.client.tui
|
|
|
|
|
.showToast({
|
|
|
|
|
body: {
|
|
|
|
|
title: `OhMyOpenCode ${displayVersion}`,
|
2025-12-19 02:03:31 +09:00
|
|
|
message: `OpenCode is now on Steroids. oMoMoMoMo...\nConfig: ${configPath}`,
|
2025-12-14 17:16:52 +09:00
|
|
|
variant: "info" as const,
|
|
|
|
|
duration: 5000,
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {})
|
|
|
|
|
log(`[auto-update-checker] Startup toast shown: v${displayVersion}`)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type { UpdateCheckResult, AutoUpdateCheckerOptions } from "./types"
|
2025-12-13 01:18:39 +09:00
|
|
|
export { checkForUpdate } from "./checker"
|
2025-12-14 17:16:52 +09:00
|
|
|
export { invalidatePackage, invalidateCache } from "./cache"
|