fix(installer): add upgrade path safety checks
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,12 +1,14 @@
|
||||
import { readFileSync, writeFileSync } from "node:fs"
|
||||
import type { ConfigMergeResult } from "../types"
|
||||
import { PLUGIN_NAME, LEGACY_PLUGIN_NAME } from "../../shared"
|
||||
import { backupConfigFile } from "./backup-config"
|
||||
import { getConfigDir } from "./config-context"
|
||||
import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists"
|
||||
import { formatErrorWithSuggestion } from "./format-error-with-suggestion"
|
||||
import { detectConfigFormat } from "./opencode-config-format"
|
||||
import { parseOpenCodeConfigFileWithError, type OpenCodeConfig } from "./parse-opencode-config-file"
|
||||
import { getPluginNameWithVersion } from "./plugin-name-with-version"
|
||||
import { checkVersionCompatibility, extractVersionFromPluginEntry } from "./version-compatibility"
|
||||
|
||||
export async function addPluginToOpenCodeConfig(currentVersion: string): Promise<ConfigMergeResult> {
|
||||
try {
|
||||
@@ -52,6 +54,29 @@ export async function addPluginToOpenCodeConfig(currentVersion: string): Promise
|
||||
&& !(plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`))
|
||||
)
|
||||
|
||||
const existingEntry = canonicalEntries[0] ?? legacyEntries[0]
|
||||
if (existingEntry) {
|
||||
const installedVersion = extractVersionFromPluginEntry(existingEntry)
|
||||
const compatibility = checkVersionCompatibility(installedVersion, currentVersion)
|
||||
|
||||
if (!compatibility.canUpgrade) {
|
||||
return {
|
||||
success: false,
|
||||
configPath: path,
|
||||
error: compatibility.reason ?? "Version compatibility check failed",
|
||||
}
|
||||
}
|
||||
|
||||
const backupResult = backupConfigFile(path)
|
||||
if (!backupResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
configPath: path,
|
||||
error: `Failed to create backup: ${backupResult.error}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedPlugins = [...otherPlugins]
|
||||
|
||||
if (canonicalEntries.length > 0) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { DetectedConfig } from "../types"
|
||||
import { getOmoConfigPath } from "./config-context"
|
||||
import { detectConfigFormat } from "./opencode-config-format"
|
||||
import { parseOpenCodeConfigFileWithError } from "./parse-opencode-config-file"
|
||||
import { extractVersionFromPluginEntry } from "./version-compatibility"
|
||||
|
||||
function detectProvidersFromOmoConfig(): {
|
||||
hasOpenAI: boolean
|
||||
@@ -60,9 +61,14 @@ function isOurPlugin(plugin: string): boolean {
|
||||
plugin === LEGACY_PLUGIN_NAME || plugin.startsWith(`${LEGACY_PLUGIN_NAME}@`)
|
||||
}
|
||||
|
||||
function findOurPluginEntry(plugins: string[]): string | null {
|
||||
return plugins.find(isOurPlugin) ?? null
|
||||
}
|
||||
|
||||
export function detectCurrentConfig(): DetectedConfig {
|
||||
const result: DetectedConfig = {
|
||||
isInstalled: false,
|
||||
installedVersion: null,
|
||||
hasClaude: true,
|
||||
isMax20: true,
|
||||
hasOpenAI: true,
|
||||
@@ -86,7 +92,12 @@ export function detectCurrentConfig(): DetectedConfig {
|
||||
|
||||
const openCodeConfig = parseResult.config
|
||||
const plugins = openCodeConfig.plugin ?? []
|
||||
result.isInstalled = plugins.some(isOurPlugin)
|
||||
const ourPluginEntry = findOurPluginEntry(plugins)
|
||||
result.isInstalled = !!ourPluginEntry
|
||||
|
||||
if (ourPluginEntry) {
|
||||
result.installedVersion = extractVersionFromPluginEntry(ourPluginEntry)
|
||||
}
|
||||
|
||||
if (!result.isInstalled) {
|
||||
return result
|
||||
|
||||
@@ -18,6 +18,7 @@ const installConfig: InstallConfig = {
|
||||
hasOpencodeZen: false,
|
||||
hasZaiCodingPlan: false,
|
||||
hasKimiForCoding: false,
|
||||
hasOpencodeGo: false,
|
||||
}
|
||||
|
||||
function getRecord(value: unknown): Record<string, unknown> {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs"
|
||||
import { parseJsonc } from "../../shared"
|
||||
import type { ConfigMergeResult, InstallConfig } from "../types"
|
||||
import { backupConfigFile } from "./backup-config"
|
||||
import { getConfigDir, getOmoConfigPath } from "./config-context"
|
||||
import { deepMergeRecord } from "./deep-merge-record"
|
||||
import { ensureConfigDirectoryExists } from "./ensure-config-directory-exists"
|
||||
@@ -28,6 +29,15 @@ export function writeOmoConfig(installConfig: InstallConfig): ConfigMergeResult
|
||||
const newConfig = generateOmoConfig(installConfig)
|
||||
|
||||
if (existsSync(omoConfigPath)) {
|
||||
const backupResult = backupConfigFile(omoConfigPath)
|
||||
if (!backupResult.success) {
|
||||
return {
|
||||
success: false,
|
||||
configPath: omoConfigPath,
|
||||
error: `Failed to create backup: ${backupResult.error}`,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const stat = statSync(omoConfigPath)
|
||||
const content = readFileSync(omoConfigPath, "utf-8")
|
||||
|
||||
Reference in New Issue
Block a user