fix: Windows auto-update path detection and install function support (#404)
* fix: Windows auto-update path detection and add install function support - Fix Windows path inconsistency: check ~/.config first, then %APPDATA% - Add actual update installation via runBunInstall when autoUpdate=true - Check both Windows config locations for comprehensive detection Closes #402 * fix: address review feedback on error logging and message clarity - Update misleading log message to clarify fallback behavior - Serialize error object before logging to prevent {} serialization --------- Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
This commit is contained in:
@@ -9,7 +9,10 @@ import {
|
||||
INSTALLED_PACKAGE_JSON,
|
||||
USER_OPENCODE_CONFIG,
|
||||
USER_OPENCODE_CONFIG_JSONC,
|
||||
USER_CONFIG_DIR,
|
||||
getWindowsAppdataDir,
|
||||
} from "./constants"
|
||||
import * as os from "node:os"
|
||||
import { log } from "../../shared/logger"
|
||||
|
||||
export function isLocalDevMode(directory: string): boolean {
|
||||
@@ -23,12 +26,32 @@ function stripJsonComments(json: string): string {
|
||||
}
|
||||
|
||||
function getConfigPaths(directory: string): string[] {
|
||||
return [
|
||||
const paths = [
|
||||
path.join(directory, ".opencode", "opencode.json"),
|
||||
path.join(directory, ".opencode", "opencode.jsonc"),
|
||||
USER_OPENCODE_CONFIG,
|
||||
USER_OPENCODE_CONFIG_JSONC,
|
||||
]
|
||||
|
||||
if (process.platform === "win32") {
|
||||
const crossPlatformDir = path.join(os.homedir(), ".config")
|
||||
const appdataDir = getWindowsAppdataDir()
|
||||
|
||||
if (appdataDir) {
|
||||
const alternateDir = USER_CONFIG_DIR === crossPlatformDir ? appdataDir : crossPlatformDir
|
||||
const alternateConfig = path.join(alternateDir, "opencode", "opencode.json")
|
||||
const alternateConfigJsonc = path.join(alternateDir, "opencode", "opencode.jsonc")
|
||||
|
||||
if (!paths.includes(alternateConfig)) {
|
||||
paths.push(alternateConfig)
|
||||
}
|
||||
if (!paths.includes(alternateConfigJsonc)) {
|
||||
paths.push(alternateConfigJsonc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
export function getLocalDevPath(directory: string): string | null {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as path from "node:path"
|
||||
import * as os from "node:os"
|
||||
import * as fs from "node:fs"
|
||||
|
||||
export const PACKAGE_NAME = "oh-my-opencode"
|
||||
export const NPM_REGISTRY_URL = `https://registry.npmjs.org/-/package/${PACKAGE_NAME}/dist-tags`
|
||||
@@ -28,14 +29,36 @@ export const INSTALLED_PACKAGE_JSON = path.join(
|
||||
|
||||
/**
|
||||
* OpenCode config file locations (priority order)
|
||||
* On Windows, checks ~/.config first (cross-platform), then %APPDATA% (fallback)
|
||||
* This matches shared/config-path.ts behavior for consistency
|
||||
*/
|
||||
function getUserConfigDir(): string {
|
||||
if (process.platform === "win32") {
|
||||
return process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming")
|
||||
const crossPlatformDir = path.join(os.homedir(), ".config")
|
||||
const appdataDir = process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming")
|
||||
|
||||
// Check cross-platform path first (~/.config)
|
||||
const crossPlatformConfig = path.join(crossPlatformDir, "opencode", "opencode.json")
|
||||
const crossPlatformConfigJsonc = path.join(crossPlatformDir, "opencode", "opencode.jsonc")
|
||||
|
||||
if (fs.existsSync(crossPlatformConfig) || fs.existsSync(crossPlatformConfigJsonc)) {
|
||||
return crossPlatformDir
|
||||
}
|
||||
|
||||
// Fall back to %APPDATA%
|
||||
return appdataDir
|
||||
}
|
||||
return process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config")
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Windows-specific APPDATA directory (for fallback checks)
|
||||
*/
|
||||
export function getWindowsAppdataDir(): string | null {
|
||||
if (process.platform !== "win32") return null
|
||||
return process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming")
|
||||
}
|
||||
|
||||
export const USER_CONFIG_DIR = getUserConfigDir()
|
||||
export const USER_OPENCODE_CONFIG = path.join(USER_CONFIG_DIR, "opencode", "opencode.json")
|
||||
export const USER_OPENCODE_CONFIG_JSONC = path.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc")
|
||||
|
||||
@@ -4,6 +4,7 @@ import { invalidatePackage } from "./cache"
|
||||
import { PACKAGE_NAME } from "./constants"
|
||||
import { log } from "../../shared/logger"
|
||||
import { getConfigLoadErrors, clearConfigLoadErrors } from "../../shared/config-errors"
|
||||
import { runBunInstall } from "../../cli/config-manager"
|
||||
import type { AutoUpdateCheckerOptions } from "./types"
|
||||
|
||||
const SISYPHUS_SPINNER = ["·", "•", "●", "○", "◌", "◦", " "]
|
||||
@@ -100,16 +101,34 @@ async function runBackgroundUpdateCheck(
|
||||
|
||||
if (pluginInfo.isPinned) {
|
||||
const updated = updatePinnedVersion(pluginInfo.configPath, pluginInfo.entry, latestVersion)
|
||||
if (updated) {
|
||||
invalidatePackage(PACKAGE_NAME)
|
||||
await showAutoUpdatedToast(ctx, currentVersion, latestVersion)
|
||||
log(`[auto-update-checker] Config updated: ${pluginInfo.entry} → ${PACKAGE_NAME}@${latestVersion}`)
|
||||
} else {
|
||||
if (!updated) {
|
||||
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage)
|
||||
log("[auto-update-checker] Failed to update pinned version in config")
|
||||
return
|
||||
}
|
||||
log(`[auto-update-checker] Config updated: ${pluginInfo.entry} → ${PACKAGE_NAME}@${latestVersion}`)
|
||||
}
|
||||
|
||||
invalidatePackage(PACKAGE_NAME)
|
||||
|
||||
const installSuccess = await runBunInstallSafe()
|
||||
|
||||
if (installSuccess) {
|
||||
await showAutoUpdatedToast(ctx, currentVersion, latestVersion)
|
||||
log(`[auto-update-checker] Update installed: ${currentVersion} → ${latestVersion}`)
|
||||
} else {
|
||||
invalidatePackage(PACKAGE_NAME)
|
||||
await showUpdateAvailableToast(ctx, latestVersion, getToastMessage)
|
||||
log("[auto-update-checker] bun install failed; update not installed (falling back to notification-only)")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user