fix(cli): restore plugin list diagnostics (#37540)
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
This commit is contained in:
co-authored by
Aiden Cline
parent
4bc8faa01c
commit
f2a4011371
@@ -114,6 +114,10 @@ export const Commands = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCO
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
Spec.make("plugin", {
|
||||||
|
description: "Manage plugins",
|
||||||
|
commands: [Spec.make("list", { description: "List active plugins" })],
|
||||||
|
}),
|
||||||
Spec.make("migrate", { description: "Migrate v1 data to v2" }),
|
Spec.make("migrate", { description: "Migrate v1 data to v2" }),
|
||||||
Spec.make("mini", {
|
Spec.make("mini", {
|
||||||
description: "Start the minimal interactive interface",
|
description: "Start the minimal interactive interface",
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { EOL } from "node:os"
|
||||||
|
import { Effect } from "effect"
|
||||||
|
import { OpenCode } from "@opencode-ai/client"
|
||||||
|
import { Service } from "@opencode-ai/client/effect/service"
|
||||||
|
import { Commands } from "../../commands"
|
||||||
|
import { Runtime } from "../../../framework/runtime"
|
||||||
|
import { ServiceConfig } from "../../../services/service-config"
|
||||||
|
|
||||||
|
export default Runtime.handler(
|
||||||
|
Commands.commands.plugin.commands.list,
|
||||||
|
Effect.fn("cli.plugin.list")(function* () {
|
||||||
|
const options = yield* ServiceConfig.options()
|
||||||
|
const found = yield* Service.discover(options)
|
||||||
|
const endpoint = found ?? (yield* Service.ensure(options))
|
||||||
|
const client = OpenCode.make({ baseUrl: endpoint.url, headers: Service.headers(endpoint) })
|
||||||
|
const response = yield* Effect.promise(() => client.plugin.list({ location: { directory: process.cwd() } }))
|
||||||
|
const plugins = response.data.toSorted((a, b) => a.id.localeCompare(b.id))
|
||||||
|
if (plugins.length === 0) {
|
||||||
|
process.stdout.write("No plugins loaded" + EOL)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
process.stdout.write(plugins.map((plugin) => plugin.id).join(EOL) + EOL)
|
||||||
|
}),
|
||||||
|
)
|
||||||
@@ -32,6 +32,9 @@ const Handlers = Runtime.handlers(Commands, {
|
|||||||
auth: () => import("./commands/handlers/mcp/auth"),
|
auth: () => import("./commands/handlers/mcp/auth"),
|
||||||
logout: () => import("./commands/handlers/mcp/logout"),
|
logout: () => import("./commands/handlers/mcp/logout"),
|
||||||
},
|
},
|
||||||
|
plugin: {
|
||||||
|
list: () => import("./commands/handlers/plugin/list"),
|
||||||
|
},
|
||||||
migrate: () => import("./commands/handlers/migrate"),
|
migrate: () => import("./commands/handlers/migrate"),
|
||||||
mini: () => import("./commands/handlers/mini"),
|
mini: () => import("./commands/handlers/mini"),
|
||||||
run: () => import("./commands/handlers/run"),
|
run: () => import("./commands/handlers/run"),
|
||||||
|
|||||||
@@ -142,7 +142,11 @@ const resolve = Effect.fn("PluginSupervisor.resolve")(function* (
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugin = yield* load(operation).pipe(Effect.catchCause(() => Effect.succeed(undefined)))
|
const plugin = yield* load(operation).pipe(
|
||||||
|
Effect.catchCause((cause) =>
|
||||||
|
Effect.logWarning("failed to load plugin", { target: operation.target, cause }).pipe(Effect.as(undefined)),
|
||||||
|
),
|
||||||
|
)
|
||||||
if (!plugin) continue
|
if (!plugin) continue
|
||||||
const previous = packages.get(operation.target)
|
const previous = packages.get(operation.target)
|
||||||
if (previous) enabled.delete(previous.id)
|
if (previous) enabled.delete(previous.id)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { PluginSupervisor } from "@opencode-ai/core/plugin/supervisor"
|
|||||||
import { ModelV2 } from "@opencode-ai/core/model"
|
import { ModelV2 } from "@opencode-ai/core/model"
|
||||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||||
import { Effect } from "effect"
|
import { Effect, Logger } from "effect"
|
||||||
import { Database } from "../../src/database/database"
|
import { Database } from "../../src/database/database"
|
||||||
import { tmpdir } from "../fixture/tmpdir"
|
import { tmpdir } from "../fixture/tmpdir"
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
@@ -111,8 +111,15 @@ describe("PluginSupervisor config", () => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("ignores invalid packages and continues loading", () =>
|
it.live("logs invalid packages and continues loading", () => {
|
||||||
withLocation(
|
const output: string[] = []
|
||||||
|
const logger = Logger.map(Logger.formatStructured, (entry) => {
|
||||||
|
if (!Array.isArray(entry.message) || entry.message[0] !== "failed to load plugin") return
|
||||||
|
const details = entry.message[1]
|
||||||
|
if (typeof details !== "object" || details === null || !("target" in details)) return
|
||||||
|
if (typeof details.target === "string") output.push(details.target)
|
||||||
|
})
|
||||||
|
return withLocation(
|
||||||
{
|
{
|
||||||
plugins: [
|
plugins: [
|
||||||
"-*",
|
"-*",
|
||||||
@@ -130,9 +137,13 @@ describe("PluginSupervisor config", () => {
|
|||||||
expect(yield* agents.get(AgentV2.ID.make("configured"))).toMatchObject({
|
expect(yield* agents.get(AgentV2.ID.make("configured"))).toMatchObject({
|
||||||
description: "Loaded after invalid plugins",
|
description: "Loaded after invalid plugins",
|
||||||
})
|
})
|
||||||
|
expect(output).toEqual([
|
||||||
|
path.join(import.meta.dir, "../plugin/fixtures/missing-plugin.ts"),
|
||||||
|
path.join(import.meta.dir, "../plugin/fixtures/invalid-plugin.ts"),
|
||||||
|
])
|
||||||
}),
|
}),
|
||||||
),
|
).pipe(Effect.provide(Logger.layer([logger])))
|
||||||
)
|
})
|
||||||
|
|
||||||
it.live("loads auto-discovered plugin files", () =>
|
it.live("loads auto-discovered plugin files", () =>
|
||||||
withLocation(
|
withLocation(
|
||||||
|
|||||||
Reference in New Issue
Block a user