Merge pull request #2247 from code-yeongyu/fix/pr-1977-doctor-paths

fix(doctor): quote cache paths and respect release channel tags
This commit is contained in:
YeonGyu-Kim
2026-03-03 00:48:00 +09:00
committed by GitHub
4 changed files with 130 additions and 3 deletions

View File

@@ -0,0 +1,18 @@
import { describe, expect, it } from "bun:test"
import { getSuggestedInstallTag } from "./system-loaded-version"
describe("system loaded version", () => {
describe("getSuggestedInstallTag", () => {
it("returns prerelease channel when current version is prerelease", () => {
//#given
const currentVersion = "3.2.0-beta.4"
//#when
const installTag = getSuggestedInstallTag(currentVersion)
//#then
expect(installTag).toBe("beta")
})
})
})

View File

@@ -77,3 +77,7 @@ export async function getLatestPluginVersion(currentVersion: string | null): Pro
const channel = extractChannel(currentVersion)
return getLatestVersion(channel)
}
export function getSuggestedInstallTag(currentVersion: string | null): string {
return extractChannel(currentVersion)
}

View File

@@ -0,0 +1,104 @@
import { beforeEach, describe, expect, it, mock } from "bun:test"
const mockFindOpenCodeBinary = mock(async () => ({ path: "/usr/local/bin/opencode" }))
const mockGetOpenCodeVersion = mock(async () => "1.0.200")
const mockCompareVersions = mock(() => true)
const mockGetPluginInfo = mock(() => ({
registered: true,
entry: "oh-my-opencode",
isPinned: false,
pinnedVersion: null,
configPath: null,
isLocalDev: false,
}))
const mockGetLoadedPluginVersion = mock(() => ({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0",
loadedVersion: "3.1.0",
}))
const mockGetLatestPluginVersion = mock(async () => null)
mock.module("./system-binary", () => ({
findOpenCodeBinary: mockFindOpenCodeBinary,
getOpenCodeVersion: mockGetOpenCodeVersion,
compareVersions: mockCompareVersions,
}))
mock.module("./system-plugin", () => ({
getPluginInfo: mockGetPluginInfo,
}))
mock.module("./system-loaded-version", () => ({
getLoadedPluginVersion: mockGetLoadedPluginVersion,
getLatestPluginVersion: mockGetLatestPluginVersion,
}))
const { checkSystem } = await import("./system?test")
describe("system check", () => {
beforeEach(() => {
mockFindOpenCodeBinary.mockReset()
mockGetOpenCodeVersion.mockReset()
mockCompareVersions.mockReset()
mockGetPluginInfo.mockReset()
mockGetLoadedPluginVersion.mockReset()
mockGetLatestPluginVersion.mockReset()
mockFindOpenCodeBinary.mockResolvedValue({ path: "/usr/local/bin/opencode" })
mockGetOpenCodeVersion.mockResolvedValue("1.0.200")
mockCompareVersions.mockReturnValue(true)
mockGetPluginInfo.mockReturnValue({
registered: true,
entry: "oh-my-opencode",
isPinned: false,
pinnedVersion: null,
configPath: null,
isLocalDev: false,
})
mockGetLoadedPluginVersion.mockReturnValue({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0",
loadedVersion: "3.1.0",
})
mockGetLatestPluginVersion.mockResolvedValue(null)
})
describe("#given cache directory contains spaces", () => {
it("uses a quoted cache directory in mismatch fix command", async () => {
//#when
const result = await checkSystem()
//#then
const mismatchIssue = result.issues.find((issue) => issue.title === "Loaded plugin version mismatch")
expect(mismatchIssue?.fix).toBe('Reinstall: cd "/Users/test/Library/Caches/opencode with spaces" && bun install')
})
it("uses the loaded version channel for update fix command", async () => {
//#given
mockGetLoadedPluginVersion.mockReturnValue({
cacheDir: "/Users/test/Library/Caches/opencode with spaces",
cachePackagePath: "/tmp/package.json",
installedPackagePath: "/tmp/node_modules/oh-my-opencode/package.json",
expectedVersion: "3.0.0-canary.1",
loadedVersion: "3.0.0-canary.1",
})
mockGetLatestPluginVersion.mockResolvedValue("3.0.0-canary.2")
mockCompareVersions.mockImplementation((leftVersion: string, rightVersion: string) => {
return !(leftVersion === "3.0.0-canary.1" && rightVersion === "3.0.0-canary.2")
})
//#when
const result = await checkSystem()
//#then
const outdatedIssue = result.issues.find((issue) => issue.title === "Loaded plugin is outdated")
expect(outdatedIssue?.fix).toBe(
'Update: cd "/Users/test/Library/Caches/opencode with spaces" && bun add oh-my-opencode@canary'
)
})
})
})

View File

@@ -4,7 +4,7 @@ import { MIN_OPENCODE_VERSION, CHECK_IDS, CHECK_NAMES } from "../constants"
import type { CheckResult, DoctorIssue, SystemInfo } from "../types"
import { findOpenCodeBinary, getOpenCodeVersion, compareVersions } from "./system-binary"
import { getPluginInfo } from "./system-plugin"
import { getLatestPluginVersion, getLoadedPluginVersion } from "./system-loaded-version"
import { getLatestPluginVersion, getLoadedPluginVersion, getSuggestedInstallTag } from "./system-loaded-version"
import { parseJsonc } from "../../../shared"
function isConfigValid(configPath: string | null): boolean {
@@ -54,6 +54,7 @@ export async function checkSystem(): Promise<CheckResult> {
const [systemInfo, pluginInfo] = await Promise.all([gatherSystemInfo(), Promise.resolve(getPluginInfo())])
const loadedInfo = getLoadedPluginVersion()
const latestVersion = await getLatestPluginVersion(systemInfo.loadedVersion)
const installTag = getSuggestedInstallTag(systemInfo.loadedVersion)
const issues: DoctorIssue[] = []
if (!systemInfo.opencodePath) {
@@ -93,7 +94,7 @@ export async function checkSystem(): Promise<CheckResult> {
issues.push({
title: "Loaded plugin version mismatch",
description: `Cache expects ${loadedInfo.expectedVersion} but loaded ${loadedInfo.loadedVersion}.`,
fix: `Reinstall: cd ${loadedInfo.cacheDir} && bun install`,
fix: `Reinstall: cd "${loadedInfo.cacheDir}" && bun install`,
severity: "warning",
affects: ["plugin loading"],
})
@@ -107,7 +108,7 @@ export async function checkSystem(): Promise<CheckResult> {
issues.push({
title: "Loaded plugin is outdated",
description: `Loaded ${systemInfo.loadedVersion}, latest ${latestVersion}.`,
fix: `Update: cd ${loadedInfo.cacheDir} && bun add oh-my-opencode@latest`,
fix: `Update: cd "${loadedInfo.cacheDir}" && bun add oh-my-opencode@${installTag}`,
severity: "warning",
affects: ["plugin features"],
})