Просмотр исходного кода

refactor(cli): convert agent / providers / mcp to effectCmd (#25525)

Kit Langton 3 месяцев назад
Родитель
Сommit
0e13279545

+ 11 - 12
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({

+ 14 - 18
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 <name>",
   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")
-      },
     })
-  },
+  }),
 })

+ 19 - 14
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")
-  },
+    })
+  }),
 })