fix(doctor): detect plugin version via require.resolve fallback
The doctor command reported "unknown" for the plugin version whenever the
package was installed somewhere outside the config dir or XDG cache dir
(for example, when running via `bunx oh-my-openagent`, which keeps the
plugin in its own ephemeral cache). The existing scan only checked
`node_modules/<package>/package.json` under those two well-known
directories, so it silently returned a null `loadedVersion`.
Add a `require.resolve("<pkg>/package.json")` fallback that uses Node's
own module resolution to locate whichever copy of the plugin is actually
loaded. The fallback only runs when neither candidate path exists, so
existing behavior is preserved for the common case.
Closes #3822
This commit is contained in:
@@ -129,6 +129,46 @@ describe("system loaded version", () => {
|
||||
expect(loadedVersion.loadedVersion).toBe("5.6.7")
|
||||
})
|
||||
|
||||
it("falls back to require.resolve when neither config nor cache directory has an install", () => {
|
||||
//#given
|
||||
const configDir = createTemporaryDirectory("omo-config-")
|
||||
const cacheHome = createTemporaryDirectory("omo-cache-")
|
||||
|
||||
process.env.OPENCODE_CONFIG_DIR = configDir
|
||||
process.env.XDG_CACHE_HOME = cacheHome
|
||||
|
||||
//#when
|
||||
const loadedVersion = getLoadedPluginVersion()
|
||||
|
||||
//#then
|
||||
expect(loadedVersion.loadedVersion).not.toBeNull()
|
||||
expect(loadedVersion.loadedVersion).toMatch(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/)
|
||||
expect(loadedVersion.installedPackagePath).toContain("package.json")
|
||||
})
|
||||
|
||||
it("prefers candidate install path over require.resolve fallback when candidate exists", () => {
|
||||
//#given
|
||||
const configDir = createTemporaryDirectory("omo-config-")
|
||||
const cacheHome = createTemporaryDirectory("omo-cache-")
|
||||
|
||||
process.env.OPENCODE_CONFIG_DIR = configDir
|
||||
process.env.XDG_CACHE_HOME = cacheHome
|
||||
|
||||
writeJson(join(configDir, "package.json"), {
|
||||
dependencies: { [PACKAGE_NAME]: "7.7.7" },
|
||||
})
|
||||
writeJson(join(configDir, "node_modules", PACKAGE_NAME, "package.json"), {
|
||||
version: "7.7.7",
|
||||
})
|
||||
|
||||
//#when
|
||||
const loadedVersion = getLoadedPluginVersion()
|
||||
|
||||
//#then
|
||||
expect(loadedVersion.installedPackagePath).toBe(join(configDir, "node_modules", PACKAGE_NAME, "package.json"))
|
||||
expect(loadedVersion.loadedVersion).toBe("7.7.7")
|
||||
})
|
||||
|
||||
it("resolves symlinked config directories before selecting install path", () => {
|
||||
//#given
|
||||
const realConfigDir = createTemporaryDirectory("omo-real-config-")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { existsSync, readFileSync } from "node:fs"
|
||||
import { createRequire } from "node:module"
|
||||
import { homedir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
import { resolveSymlink } from "../../../shared/file-utils"
|
||||
@@ -86,6 +87,25 @@ function getExpectedVersion(cachePackage: PackageJsonShape | null, packageName:
|
||||
?? normalizeVersion(cachePackage?.dependencies?.[PACKAGE_NAME])
|
||||
}
|
||||
|
||||
function resolveInstalledPackageJsonPath(): { packageName: string; packageJsonPath: string } | null {
|
||||
try {
|
||||
const require = createRequire(import.meta.url)
|
||||
for (const packageName of ACCEPTED_PACKAGE_NAMES) {
|
||||
try {
|
||||
const packageJsonPath = require.resolve(`${packageName}/package.json`)
|
||||
if (existsSync(packageJsonPath)) {
|
||||
return { packageName, packageJsonPath }
|
||||
}
|
||||
} catch {
|
||||
continue
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function getLoadedPluginVersion(): LoadedVersionInfo {
|
||||
const configPaths = getOpenCodeConfigPaths({ binary: "opencode" })
|
||||
const configDir = resolveExistingDir(configPaths.configDir)
|
||||
@@ -108,12 +128,17 @@ export function getLoadedPluginVersion(): LoadedVersionInfo {
|
||||
|
||||
const { cacheDir: selectedDir, cachePackagePath } = selectedCandidate
|
||||
const selectedPackage = selectInstalledPackage(selectedCandidate)
|
||||
const installedPackagePath = selectedPackage.installedPackagePath
|
||||
const candidateInstalledPath = selectedPackage.installedPackagePath
|
||||
const candidateExists = existsSync(candidateInstalledPath)
|
||||
|
||||
const resolvedFallback = candidateExists ? null : resolveInstalledPackageJsonPath()
|
||||
const installedPackagePath = resolvedFallback?.packageJsonPath ?? candidateInstalledPath
|
||||
const resolvedPackageName = resolvedFallback?.packageName ?? selectedPackage.packageName
|
||||
|
||||
const cachePackage = readPackageJson(cachePackagePath)
|
||||
const installedPackage = readPackageJson(installedPackagePath)
|
||||
|
||||
const expectedVersion = getExpectedVersion(cachePackage, selectedPackage.packageName)
|
||||
const expectedVersion = getExpectedVersion(cachePackage, resolvedPackageName)
|
||||
const loadedVersion = normalizeVersion(installedPackage?.version)
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user