refactor(cli): convert run command to effectCmd (#25519)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import type { CommandModule } from "yargs"
|
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>>) {
|
export function cmd<T, U>(input: CommandModule<T, WithDoubleDash<U>>) {
|
||||||
return input
|
return input
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Argv } from "yargs"
|
import type { Argv } from "yargs"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { pathToFileURL } from "url"
|
import { pathToFileURL } from "url"
|
||||||
|
import { Effect } from "effect"
|
||||||
import { UI } from "../ui"
|
import { UI } from "../ui"
|
||||||
import { cmd } from "./cmd"
|
import { effectCmd } from "../effect-cmd"
|
||||||
import { Flag } from "@opencode-ai/core/flag/flag"
|
import { Flag } from "@opencode-ai/core/flag/flag"
|
||||||
import { bootstrap } from "../bootstrap"
|
|
||||||
import { EOL } from "os"
|
import { EOL } from "os"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import { createOpencodeClient, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
|
import { createOpencodeClient, type OpencodeClient, type ToolPart } from "@opencode-ai/sdk/v2"
|
||||||
@@ -203,11 +203,17 @@ function normalizePath(input?: string) {
|
|||||||
return input
|
return input
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RunCommand = cmd({
|
export const RunCommand = effectCmd({
|
||||||
command: "run [message..]",
|
command: "run [message..]",
|
||||||
describe: "run opencode with a message",
|
describe: "run opencode with a message",
|
||||||
builder: (yargs: Argv) => {
|
// --attach connects to a remote server (no local instance needed); the
|
||||||
return yargs
|
// 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", {
|
.positional("message", {
|
||||||
describe: "message to send",
|
describe: "message to send",
|
||||||
type: "string",
|
type: "string",
|
||||||
@@ -291,9 +297,9 @@ export const RunCommand = cmd({
|
|||||||
type: "boolean",
|
type: "boolean",
|
||||||
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
|
describe: "auto-approve permissions that are not explicitly denied (dangerous!)",
|
||||||
default: false,
|
default: false,
|
||||||
})
|
}),
|
||||||
},
|
handler: Effect.fn("Cli.run")(function* (args) {
|
||||||
handler: async (args) => {
|
yield* Effect.promise(async () => {
|
||||||
let message = [...args.message, ...(args["--"] || [])]
|
let message = [...args.message, ...(args["--"] || [])]
|
||||||
.map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg))
|
.map((arg) => (arg.includes(" ") ? `"${arg.replace(/"/g, '\\"')}"` : arg))
|
||||||
.join(" ")
|
.join(" ")
|
||||||
@@ -661,13 +667,12 @@ export const RunCommand = cmd({
|
|||||||
return await execute(sdk)
|
return await execute(sdk)
|
||||||
}
|
}
|
||||||
|
|
||||||
await bootstrap(process.cwd(), async () => {
|
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
const fetchFn = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
const request = new Request(input, init)
|
||||||
const request = new Request(input, init)
|
return Server.Default().app.fetch(request)
|
||||||
return Server.Default().app.fetch(request)
|
}) as typeof globalThis.fetch
|
||||||
}) as typeof globalThis.fetch
|
const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn })
|
||||||
const sdk = createOpencodeClient({ baseUrl: "http://opencode.internal", fetch: fetchFn })
|
await execute(sdk)
|
||||||
await execute(sdk)
|
|
||||||
})
|
})
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Effect, Schema } from "effect"
|
|||||||
import { AppRuntime, type AppServices } from "@/effect/app-runtime"
|
import { AppRuntime, type AppServices } from "@/effect/app-runtime"
|
||||||
import { InstanceStore } from "@/project/instance-store"
|
import { InstanceStore } from "@/project/instance-store"
|
||||||
import { InstanceRef } from "@/effect/instance-ref"
|
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
|
* User-visible command failure. Throw via `fail("...")` from an effectCmd handler
|
||||||
@@ -47,7 +47,7 @@ interface EffectCmdOpts<Args, A> {
|
|||||||
instance?: boolean | ((args: Args) => boolean)
|
instance?: boolean | ((args: Args) => boolean)
|
||||||
/** Defaults to process.cwd(). Override for commands that take a directory positional. */
|
/** Defaults to process.cwd(). Override for commands that take a directory positional. */
|
||||||
directory?: (args: Args) => string
|
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,
|
builder: opts.builder as never,
|
||||||
async handler(rawArgs) {
|
async handler(rawArgs) {
|
||||||
// yargs typing wraps Args in ArgumentsCamelCase<WithDoubleDash<...>>; cast at the boundary.
|
// 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
|
const useInstance = typeof opts.instance === "function" ? opts.instance(args) : opts.instance !== false
|
||||||
if (!useInstance) {
|
if (!useInstance) {
|
||||||
await AppRuntime.runPromise(opts.handler(args))
|
await AppRuntime.runPromise(opts.handler(args))
|
||||||
|
|||||||
Reference in New Issue
Block a user