refactor: unwrap TuiPluginRuntime namespace + self-reexport (#22980)

This commit is contained in:
Kit Langton
2026-04-17 01:02:07 +00:00
committed by GitHub
parent 5022895e2b
commit 94878d76f8
@@ -918,113 +918,113 @@ async function installPluginBySpec(
} }
} }
export namespace TuiPluginRuntime { let dir = ""
let dir = "" let loaded: Promise<void> | undefined
let loaded: Promise<void> | undefined let runtime: RuntimeState | undefined
let runtime: RuntimeState | undefined export const Slot = View
export const Slot = View
export async function init(input: { api: HostPluginApi; config: TuiConfig.Info }) { export async function init(input: { api: HostPluginApi; config: TuiConfig.Info }) {
const cwd = process.cwd() const cwd = process.cwd()
if (loaded) { if (loaded) {
if (dir !== cwd) { if (dir !== cwd) {
throw new Error(`TuiPluginRuntime.init() called with a different working directory. expected=${dir} got=${cwd}`) throw new Error(`TuiPluginRuntime.init() called with a different working directory. expected=${dir} got=${cwd}`)
}
return loaded
} }
dir = cwd
loaded = load(input)
return loaded return loaded
} }
export function list() { dir = cwd
if (!runtime) return [] loaded = load(input)
return listPluginStatus(runtime) return loaded
} }
export async function activatePlugin(id: string) { export function list() {
return activatePluginById(runtime, id, true) if (!runtime) return []
} return listPluginStatus(runtime)
}
export async function deactivatePlugin(id: string) { export async function activatePlugin(id: string) {
return deactivatePluginById(runtime, id, true) return activatePluginById(runtime, id, true)
} }
export async function addPlugin(spec: string) { export async function deactivatePlugin(id: string) {
return addPluginBySpec(runtime, spec) return deactivatePluginById(runtime, id, true)
} }
export async function installPlugin(spec: string, options?: { global?: boolean }) { export async function addPlugin(spec: string) {
return installPluginBySpec(runtime, spec, options?.global) return addPluginBySpec(runtime, spec)
} }
export async function dispose() { export async function installPlugin(spec: string, options?: { global?: boolean }) {
const task = loaded return installPluginBySpec(runtime, spec, options?.global)
loaded = undefined }
dir = ""
if (task) await task
const state = runtime
runtime = undefined
if (!state) return
const queue = [...state.plugins].reverse()
for (const plugin of queue) {
await deactivatePluginEntry(state, plugin, false)
}
}
async function load(input: { api: Api; config: TuiConfig.Info }) { export async function dispose() {
const { api, config } = input const task = loaded
const cwd = process.cwd() loaded = undefined
const slots = setupSlots(api) dir = ""
const next: RuntimeState = { if (task) await task
directory: cwd, const state = runtime
api, runtime = undefined
slots, if (!state) return
plugins: [], const queue = [...state.plugins].reverse()
plugins_by_id: new Map(), for (const plugin of queue) {
pending: new Map(), await deactivatePluginEntry(state, plugin, false)
}
runtime = next
try {
await Instance.provide({
directory: cwd,
fn: async () => {
const records = Flag.OPENCODE_PURE ? [] : (config.plugin_origins ?? [])
if (Flag.OPENCODE_PURE && config.plugin_origins?.length) {
log.info("skipping external tui plugins in pure mode", { count: config.plugin_origins.length })
}
for (const item of INTERNAL_TUI_PLUGINS) {
log.info("loading internal tui plugin", { id: item.id })
const entry = loadInternalPlugin(item)
const meta = createMeta(entry.source, entry.spec, entry.target, undefined, entry.id)
addPluginEntry(next, {
id: entry.id,
load: entry,
meta,
themes: {},
plugin: entry.module.tui,
enabled: true,
})
}
const ready = await resolveExternalPlugins(records, () => TuiConfig.waitForDependencies())
await addExternalPluginEntries(next, ready)
applyInitialPluginEnabledState(next, config)
for (const plugin of next.plugins) {
if (!plugin.enabled) continue
// Keep plugin execution sequential for deterministic side effects:
// command registration order affects keybind/command precedence,
// route registration is last-wins when ids collide,
// and hook chains rely on stable plugin ordering.
await activatePluginEntry(next, plugin, false)
}
},
})
} catch (error) {
fail("failed to load tui plugins", { directory: cwd, error })
}
} }
} }
async function load(input: { api: Api; config: TuiConfig.Info }) {
const { api, config } = input
const cwd = process.cwd()
const slots = setupSlots(api)
const next: RuntimeState = {
directory: cwd,
api,
slots,
plugins: [],
plugins_by_id: new Map(),
pending: new Map(),
}
runtime = next
try {
await Instance.provide({
directory: cwd,
fn: async () => {
const records = Flag.OPENCODE_PURE ? [] : (config.plugin_origins ?? [])
if (Flag.OPENCODE_PURE && config.plugin_origins?.length) {
log.info("skipping external tui plugins in pure mode", { count: config.plugin_origins.length })
}
for (const item of INTERNAL_TUI_PLUGINS) {
log.info("loading internal tui plugin", { id: item.id })
const entry = loadInternalPlugin(item)
const meta = createMeta(entry.source, entry.spec, entry.target, undefined, entry.id)
addPluginEntry(next, {
id: entry.id,
load: entry,
meta,
themes: {},
plugin: entry.module.tui,
enabled: true,
})
}
const ready = await resolveExternalPlugins(records, () => TuiConfig.waitForDependencies())
await addExternalPluginEntries(next, ready)
applyInitialPluginEnabledState(next, config)
for (const plugin of next.plugins) {
if (!plugin.enabled) continue
// Keep plugin execution sequential for deterministic side effects:
// command registration order affects keybind/command precedence,
// route registration is last-wins when ids collide,
// and hook chains rely on stable plugin ordering.
await activatePluginEntry(next, plugin, false)
}
},
})
} catch (error) {
fail("failed to load tui plugins", { directory: cwd, error })
}
}
export * as TuiPluginRuntime from "./runtime"