Fixes potential plugin resolution issues when switching between projects by wrapping plugin loading in Instance.provide(). This ensures each plugin resolves dependencies relative to its correct project directory instead of inheriting context from whatever instance happened to be active. Also reorganizes config loading code into focused modules (command.ts, managed.ts, plugin.ts) to make the codebase easier to maintain and test.
72 lines
2.0 KiB
TypeScript
72 lines
2.0 KiB
TypeScript
import { existsSync } from "fs"
|
|
import os from "os"
|
|
import path from "path"
|
|
import { type Info, parseConfig } from "./config"
|
|
import { Log, Process } from "../util"
|
|
|
|
const log = Log.create({ service: "config" })
|
|
|
|
const MANAGED_PLIST_DOMAIN = "ai.opencode.managed"
|
|
|
|
// Keys injected by macOS/MDM into the managed plist that are not OpenCode config
|
|
const PLIST_META = new Set([
|
|
"PayloadDisplayName",
|
|
"PayloadIdentifier",
|
|
"PayloadType",
|
|
"PayloadUUID",
|
|
"PayloadVersion",
|
|
"_manualProfile",
|
|
])
|
|
|
|
function systemManagedConfigDir(): string {
|
|
switch (process.platform) {
|
|
case "darwin":
|
|
return "/Library/Application Support/opencode"
|
|
case "win32":
|
|
return path.join(process.env.ProgramData || "C:\\ProgramData", "opencode")
|
|
default:
|
|
return "/etc/opencode"
|
|
}
|
|
}
|
|
|
|
function managedConfigDir() {
|
|
return process.env.OPENCODE_TEST_MANAGED_CONFIG_DIR || systemManagedConfigDir()
|
|
}
|
|
|
|
function parseManagedPlist(json: string, source: string): Info {
|
|
const raw = JSON.parse(json)
|
|
for (const key of Object.keys(raw)) {
|
|
if (PLIST_META.has(key)) delete raw[key]
|
|
}
|
|
return parseConfig(JSON.stringify(raw), source)
|
|
}
|
|
|
|
async function readManagedPreferences(): Promise<Info> {
|
|
if (process.platform !== "darwin") return {}
|
|
|
|
const user = os.userInfo().username
|
|
const paths = [
|
|
path.join("/Library/Managed Preferences", user, `${MANAGED_PLIST_DOMAIN}.plist`),
|
|
path.join("/Library/Managed Preferences", `${MANAGED_PLIST_DOMAIN}.plist`),
|
|
]
|
|
|
|
for (const plist of paths) {
|
|
if (!existsSync(plist)) continue
|
|
log.info("reading macOS managed preferences", { path: plist })
|
|
const result = await Process.run(["plutil", "-convert", "json", "-o", "-", plist], { nothrow: true })
|
|
if (result.code !== 0) {
|
|
log.warn("failed to convert managed preferences plist", { path: plist })
|
|
continue
|
|
}
|
|
return parseManagedPlist(result.stdout.toString(), `mobileconfig:${plist}`)
|
|
}
|
|
|
|
return {}
|
|
}
|
|
|
|
export const ConfigManaged = {
|
|
managedConfigDir,
|
|
parseManagedPlist,
|
|
readManagedPreferences,
|
|
}
|