diff --git a/packages/opencode/src/cli/cmd/agent.ts b/packages/opencode/src/cli/cmd/agent.ts index 4011269495..e2565c6272 100644 --- a/packages/opencode/src/cli/cmd/agent.ts +++ b/packages/opencode/src/cli/cmd/agent.ts @@ -9,8 +9,7 @@ import path from "path" import fs from "fs/promises" import { Filesystem } from "@/util/filesystem" import matter from "gray-matter" -import { Instance } from "../../project/instance" -import { WithInstance } from "../../project/with-instance" +import { InstanceRef } from "@/effect/instance-ref" import { EOL } from "os" import type { Argv } from "yargs" import { Effect } from "effect" @@ -35,7 +34,7 @@ const AVAILABLE_PERMISSIONS = [ "skill", ] -const AgentCreateCommand = cmd({ +const AgentCreateCommand = effectCmd({ command: "create", describe: "create a new agent", builder: (yargs: Argv) => @@ -63,10 +62,11 @@ const AgentCreateCommand = cmd({ alias: ["m"], describe: "model to use in the format of provider/model", }), - async handler(args) { - await WithInstance.provide({ - directory: process.cwd(), - async fn() { + handler: Effect.fn("Cli.agent.create")(function* (args) { + const maybeCtx = yield* InstanceRef + if (!maybeCtx) return yield* Effect.die("InstanceRef not provided") + const ctx = maybeCtx + yield* Effect.promise(async () => { const cliPath = args.path const cliDescription = args.description const cliMode = args.mode as AgentMode | undefined @@ -79,7 +79,7 @@ const AgentCreateCommand = cmd({ prompts.intro("Create agent") } - const project = Instance.project + const project = ctx.project // Determine scope/path let targetPath: string @@ -94,7 +94,7 @@ const AgentCreateCommand = cmd({ { label: "Current project", value: "project" as const, - hint: Instance.worktree, + hint: ctx.worktree, }, { label: "Global", @@ -107,7 +107,7 @@ const AgentCreateCommand = cmd({ scope = scopeResult } targetPath = path.join( - scope === "global" ? Global.Path.config : path.join(Instance.worktree, ".opencode"), + scope === "global" ? Global.Path.config : path.join(ctx.worktree, ".opencode"), "agent", ) } @@ -230,9 +230,8 @@ const AgentCreateCommand = cmd({ prompts.log.success(`Agent created: ${filePath}`) prompts.outro("Done") } - }, }) - }, + }), }) const AgentListCommand = effectCmd({ diff --git a/packages/opencode/src/cli/cmd/mcp.ts b/packages/opencode/src/cli/cmd/mcp.ts index a2a956c3b6..d1e8b33be7 100644 --- a/packages/opencode/src/cli/cmd/mcp.ts +++ b/packages/opencode/src/cli/cmd/mcp.ts @@ -11,8 +11,7 @@ import { McpAuth } from "../../mcp/auth" import { McpOAuthProvider } from "../../mcp/oauth-provider" import { Config } from "@/config/config" import { ConfigMCP } from "../../config/mcp" -import { Instance } from "../../project/instance" -import { WithInstance } from "../../project/with-instance" +import { InstanceRef } from "@/effect/instance-ref" import { Installation } from "../../installation" import { InstallationVersion } from "@opencode-ai/core/installation/version" import path from "path" @@ -433,21 +432,22 @@ async function addMcpToConfig(name: string, mcpConfig: ConfigMCP.Info, configPat return configPath } -export const McpAddCommand = cmd({ +export const McpAddCommand = effectCmd({ command: "add", describe: "add an MCP server", - async handler() { - await WithInstance.provide({ - directory: process.cwd(), - async fn() { + handler: Effect.fn("Cli.mcp.add")(function* () { + const maybeCtx = yield* InstanceRef + if (!maybeCtx) return yield* Effect.die("InstanceRef not provided") + const ctx = maybeCtx + yield* Effect.promise(async () => { UI.empty() prompts.intro("Add MCP server") - const project = Instance.project + const project = ctx.project // Resolve config paths eagerly for hints const [projectConfigPath, globalConfigPath] = await Promise.all([ - resolveConfigPath(Instance.worktree), + resolveConfigPath(ctx.worktree), resolveConfigPath(Global.Path.config, true), ]) @@ -592,12 +592,11 @@ export const McpAddCommand = cmd({ } prompts.outro("MCP server added successfully") - }, }) - }, + }), }) -export const McpDebugCommand = cmd({ +export const McpDebugCommand = effectCmd({ command: "debug ", describe: "debug OAuth connection for an MCP server", builder: (yargs) => @@ -606,10 +605,8 @@ export const McpDebugCommand = cmd({ type: "string", demandOption: true, }), - async handler(args) { - await WithInstance.provide({ - directory: process.cwd(), - async fn() { + handler: Effect.fn("Cli.mcp.debug")(function* (args) { + yield* Effect.promise(async () => { UI.empty() prompts.intro("MCP OAuth Debug") @@ -781,7 +778,6 @@ export const McpDebugCommand = cmd({ } prompts.outro("Debug complete") - }, }) - }, + }), }) diff --git a/packages/opencode/src/cli/cmd/providers.ts b/packages/opencode/src/cli/cmd/providers.ts index ca64526182..93541114b4 100644 --- a/packages/opencode/src/cli/cmd/providers.ts +++ b/packages/opencode/src/cli/cmd/providers.ts @@ -1,6 +1,7 @@ import { Auth } from "../../auth" import { AppRuntime } from "../../effect/app-runtime" import { cmd } from "./cmd" +import { effectCmd } from "../effect-cmd" import * as prompts from "@clack/prompts" import { UI } from "../ui" import { ModelsDev } from "@/provider/models" @@ -13,7 +14,6 @@ import os from "os" import { Config } from "@/config/config" import { Global } from "@opencode-ai/core/global" import { Plugin } from "../../plugin" -import { WithInstance } from "../../project/with-instance" import type { Hooks } from "@opencode-ai/plugin" import { Process } from "@/util/process" import { text } from "node:stream/consumers" @@ -232,11 +232,14 @@ export const ProvidersCommand = cmd({ async handler() {}, }) -export const ProvidersListCommand = cmd({ +export const ProvidersListCommand = effectCmd({ command: "list", aliases: ["ls"], describe: "list providers and credentials", - async handler(_args) { + // Lists global credentials + provider env vars; no project instance needed. + instance: false, + handler: Effect.fn("Cli.providers.list")(function* (_args) { + yield* Effect.promise(async () => { UI.empty() const authPath = path.join(Global.Path.data, "auth.json") const homedir = os.homedir() @@ -280,10 +283,11 @@ export const ProvidersListCommand = cmd({ prompts.outro(`${activeEnvVars.length} environment variable` + (activeEnvVars.length === 1 ? "" : "s")) } - }, + }) + }), }) -export const ProvidersLoginCommand = cmd({ +export const ProvidersLoginCommand = effectCmd({ command: "login [url]", describe: "log in to a provider", builder: (yargs) => @@ -302,10 +306,8 @@ export const ProvidersLoginCommand = cmd({ describe: "login method label (skips method selection)", type: "string", }), - async handler(args) { - await WithInstance.provide({ - directory: process.cwd(), - async fn() { + handler: Effect.fn("Cli.providers.login")(function* (args) { + yield* Effect.promise(async () => { UI.empty() prompts.intro("Add credential") if (args.url) { @@ -487,15 +489,17 @@ export const ProvidersLoginCommand = cmd({ }) prompts.outro("Done") - }, }) - }, + }), }) -export const ProvidersLogoutCommand = cmd({ +export const ProvidersLogoutCommand = effectCmd({ command: "logout", describe: "log out from a configured provider", - async handler(_args) { + // Removes a global auth credential; no project instance needed. + instance: false, + handler: Effect.fn("Cli.providers.logout")(function* (_args) { + yield* Effect.promise(async () => { UI.empty() const credentials: Array<[string, Auth.Info]> = await AppRuntime.runPromise( Effect.gen(function* () { @@ -525,5 +529,6 @@ export const ProvidersLogoutCommand = cmd({ }), ) prompts.outro("Logout successful") - }, + }) + }), })