refactor(cli): convert run command to effectCmd (#25519)

This commit is contained in:
Kit Langton 2026-05-02 22:35:20 -04:00 committed by GitHub
parent 2829943ad1
commit 7409dcc6bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 25 additions and 20 deletions

View file

@ -1,6 +1,6 @@
import type { CommandModule } from "yargs"
type WithDoubleDash<T> = T & { "--"?: string[] }
export type WithDoubleDash<T> = T & { "--"?: string[] }
export function cmd<T, U>(input: CommandModule<T, WithDoubleDash<U>>) {
return input

View file

@ -1,10 +1,10 @@
import type { Argv } from "yargs"
import path from "path"
import { pathToFileURL } from "url"
import { Effect } from "effect"
import { UI } from "../ui"
import { cmd } from "./cmd"
import { effectCmd } from "../effect-cmd"
import { Flag } from "@opencode-ai/core/flag/flag"
import { bootstrap } from "../bootstrap"
import { EOL } from "os"
import { Filesystem } from "@/util/filesystem"
import { createOpencodeClient, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
@ -203,11 +203,17 @@ function normalizePath(input?: string) {
return input
}
export const RunCommand = cmd({
export const RunCommand = effectCmd({
command: "run [message..]",
describe: "run opencode with a message",
builder: (yargs: Argv) => {
return yargs
// --attach connects to a remote server (no local instance needed); the
// default path runs an in-process server and needs the project instance.
instance: (args) => !args.attach,
// For --dir without --attach, load instance for the resolved target dir.
// The handler also chdirs (preserving the legacy order: chdir → file resolution).
directory: (args) => (args.dir && !args.attach ? path.resolve(process.cwd(), args.dir) : process.cwd()),
builder: (yargs: Argv) =>
yargs
.positional("message", {
describe: "message to send",
type: "string",
@ -291,9 +297,9 @@ export const RunCommand = cmd({
type: "boolean",
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
default: false,
})
},
handler: async (args) => {
}),
handler: Effect.fn("Cli.run")(function* (args) {
yield* Effect.promise(async () => {
let message = [...args.message, ...(args["--"] || [])]
.map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg))
.join(" ")
@ -661,13 +667,12 @@ export const RunCommand = cmd({
return await execute(sdk)
}
await bootstrap(process.cwd(), async () => {
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init)
return Server.Default().app.fetch(request)
}) as typeof globalThis.fetch
const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn })
await execute(sdk)
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init)
return Server.Default().app.fetch(request)
}) as typeof globalThis.fetch
const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn })
await execute(sdk)
})
},
}),
})

View file

@ -3,7 +3,7 @@ import { Effect, Schema } from "effect"
import { AppRuntime, type AppServices } from "@/effect/app-runtime"
import { InstanceStore } from "@/project/instance-store"
import { InstanceRef } from "@/effect/instance-ref"
import { cmd } from "./cmd/cmd"
import { cmd, type WithDoubleDash } from "./cmd/cmd"
/**
* User-visible command failure. Throw via `fail("...")` from an effectCmd handler
@ -47,7 +47,7 @@ interface EffectCmdOpts<Args, A> {
instance?: boolean | ((args: Args) => boolean)
/** Defaults to process.cwd(). Override for commands that take a directory positional. */
directory?: (args: Args) => string
handler: (args: Args) => Effect.Effect<A, CliError, AppServices | InstanceStore.Service>
handler: (args: WithDoubleDash<Args>) => Effect.Effect<A, CliError, AppServices | InstanceStore.Service>
}
/**
@ -75,7 +75,7 @@ export const effectCmd = <Args, A>(opts: EffectCmdOpts<Args, A>) =>
builder: opts.builder as never,
async handler(rawArgs) {
// yargs typing wraps Args in ArgumentsCamelCase<WithDoubleDash<...>>; cast at the boundary.
const args = rawArgs as unknown as Args
const args = rawArgs as unknown as WithDoubleDash<Args>
const useInstance = typeof opts.instance === "function" ? opts.instance(args) : opts.instance !== false
if (!useInstance) {
await AppRuntime.runPromise(opts.handler(args))