Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions packages/opencode/src/cli/cmd/plug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Spin = {

export type PlugDeps = {
spinner: () => Spin
tty: boolean
log: {
error: (msg: string) => void
info: (msg: string) => void
Expand Down Expand Up @@ -46,6 +47,7 @@ export type PlugCtx = {

const defaultPlugDeps: PlugDeps = {
spinner: () => spinner(),
tty: process.stdout.isTTY,
log: {
error: (msg) => log.error(msg),
info: (msg) => log.info(msg),
Expand All @@ -67,13 +69,26 @@ function cause(err: unknown) {
return (err as { cause?: unknown }).cause
}

function progress(dep: PlugDeps) {
if (dep.tty) return dep.spinner()
return {
start(msg: string) {
dep.log.info(msg)
},
stop(msg: string, code?: number) {
if (!code) return
dep.log.error(msg)
},
}
}

export function createPlugTask(input: PlugInput, dep: PlugDeps = defaultPlugDeps) {
const mod = input.mod
const force = Boolean(input.force)
const global = Boolean(input.global)

return async (ctx: PlugCtx) => {
const install = dep.spinner()
const install = progress(dep)
install.start("Installing plugin package...")
const target = await installPlugin(mod, dep)
if (!target.ok) {
Expand Down Expand Up @@ -101,7 +116,7 @@ export function createPlugTask(input: PlugInput, dep: PlugDeps = defaultPlugDeps
}
install.stop("Plugin package ready")

const inspect = dep.spinner()
const inspect = progress(dep)
inspect.start("Reading plugin manifest...")
const manifest = await readPluginManifest(target.target)
if (!manifest.ok) {
Expand Down Expand Up @@ -129,7 +144,7 @@ export function createPlugTask(input: PlugInput, dep: PlugDeps = defaultPlugDeps
`Detected ${manifest.targets.map((item) => item.kind).join(" + ")} target${manifest.targets.length === 1 ? "" : "s"}`,
)

const patch = dep.spinner()
const patch = progress(dep)
patch.start("Updating plugin config...")
const out = await patchPluginConfig(
{
Expand Down
32 changes: 28 additions & 4 deletions packages/opencode/test/plugin/install.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ import { Filesystem } from "@/util/filesystem"
import { createPlugTask, type PlugCtx, type PlugDeps } from "../../src/cli/cmd/plug"
import { tmpdir } from "../fixture/fixture"

function deps(global: string, target: string | Error): PlugDeps {
function deps(global: string, target: string | Error, options?: { tty?: boolean; logs?: string[] }): PlugDeps {
return {
spinner: () => ({
start() {},
stop() {},
}),
tty: options?.tty ?? true,
log: {
error() {},
info() {},
success() {},
error: (msg) => options?.logs?.push(`error:${msg}`),
info: (msg) => options?.logs?.push(`info:${msg}`),
success: (msg) => options?.logs?.push(`success:${msg}`),
},
resolve: async () => {
if (target instanceof Error) throw target
Expand Down Expand Up @@ -109,6 +110,29 @@ async function read(file: string) {
}

describe("plugin.install.task", () => {
test("logs plain progress messages when stdout is not a tty", async () => {
await using tmp = await tmpdir()
const target = await plugin(tmp.path, ["server"])
const logs: string[] = []
const run = createPlugTask(
{
mod: "acme@1.2.3",
},
deps(path.join(tmp.path, "global"), target, { tty: false, logs }),
)

const ok = await run(ctx(tmp.path))
expect(ok).toBe(true)
expect(logs).toEqual([
"info:Installing plugin package...",
"info:Reading plugin manifest...",
"info:Updating plugin config...",
`info:Added to ${path.join(tmp.path, ".opencode", "opencode.jsonc")}`,
"success:Installed acme@1.2.3",
`info:Scope: local (${path.join(tmp.path, ".opencode")})`,
])
})

test("writes both server and tui config entries", async () => {
await using tmp = await tmpdir()
const target = await plugin(tmp.path, ["server", "tui"])
Expand Down
Loading