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

refactor(cli): convert session subcommands to effectCmd (#25483)

Kit Langton 3 месяцев назад
Родитель
Сommit
1986a6e817
1 измененных файлов с 49 добавлено и 53 удалено
  1. 49 53
      packages/opencode/src/cli/cmd/session.ts

+ 49 - 53
packages/opencode/src/cli/cmd/session.ts

@@ -1,8 +1,9 @@
 import type { Argv } from "yargs"
+import { Effect } from "effect"
 import { cmd } from "./cmd"
+import { effectCmd, fail } from "../effect-cmd"
 import { Session } from "@/session/session"
 import { SessionID } from "../../session/schema"
-import { bootstrap } from "../bootstrap"
 import { UI } from "../ui"
 import { Locale } from "@/util/locale"
 import { Flag } from "@opencode-ai/core/flag/flag"
@@ -11,7 +12,8 @@ import { Process } from "@/util/process"
 import { EOL } from "os"
 import path from "path"
 import { which } from "../../util/which"
-import { AppRuntime } from "@/effect/app-runtime"
+import { InstanceRef } from "@/effect/instance-ref"
+import { InstanceStore } from "@/project/instance-store"
 
 function pagerCmd(): string[] {
   const lessOptions = ["-R", "-S"]
@@ -47,36 +49,35 @@ export const SessionCommand = cmd({
   async handler() {},
 })
 
-export const SessionDeleteCommand = cmd({
+export const SessionDeleteCommand = effectCmd({
   command: "delete <sessionID>",
   describe: "delete a session",
-  builder: (yargs: Argv) => {
-    return yargs.positional("sessionID", {
+  builder: (yargs) =>
+    yargs.positional("sessionID", {
       describe: "session ID to delete",
       type: "string",
       demandOption: true,
-    })
-  },
-  handler: async (args) => {
-    await bootstrap(process.cwd(), async () => {
+    }),
+  handler: Effect.fn("Cli.session.delete")(function* (args) {
+    const ctx = yield* InstanceRef
+    if (!ctx) return
+    const store = yield* InstanceStore.Service
+    return yield* Effect.gen(function* () {
+      const svc = yield* Session.Service
       const sessionID = SessionID.make(args.sessionID)
-      try {
-        await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID)))
-      } catch {
-        UI.error(`Session not found: ${args.sessionID}`)
-        process.exit(1)
-      }
-      await AppRuntime.runPromise(Session.Service.use((svc) => svc.remove(sessionID)))
+      // Match legacy try/catch — Session.get surfaces NotFoundError as a defect.
+      yield* svc.get(sessionID).pipe(Effect.catchCause(() => fail(`Session not found: ${args.sessionID}`)))
+      yield* svc.remove(sessionID)
       UI.println(UI.Style.TEXT_SUCCESS_BOLD + `Session ${args.sessionID} deleted` + UI.Style.TEXT_NORMAL)
-    })
-  },
+    }).pipe(Effect.ensuring(store.dispose(ctx)))
+  }),
 })
 
-export const SessionListCommand = cmd({
+export const SessionListCommand = effectCmd({
   command: "list",
   describe: "list sessions",
-  builder: (yargs: Argv) => {
-    return yargs
+  builder: (yargs) =>
+    yargs
       .option("max-count", {
         alias: "n",
         describe: "limit to N most recent sessions",
@@ -87,47 +88,42 @@ export const SessionListCommand = cmd({
         type: "string",
         choices: ["table", "json"],
         default: "table",
-      })
-  },
-  handler: async (args) => {
-    await bootstrap(process.cwd(), async () => {
-      const sessions = await AppRuntime.runPromise(
-        Session.Service.use((svc) => svc.list({ roots: true, limit: args.maxCount })),
-      )
-
-      if (sessions.length === 0) {
-        return
-      }
+      }),
+  handler: Effect.fn("Cli.session.list")(function* (args) {
+    const ctx = yield* InstanceRef
+    if (!ctx) return
+    const store = yield* InstanceStore.Service
+    return yield* Effect.gen(function* () {
+      const sessions = yield* Session.Service.use((svc) => svc.list({ roots: true, limit: args.maxCount }))
 
-      let output: string
-      if (args.format === "json") {
-        output = formatSessionJSON(sessions)
-      } else {
-        output = formatSessionTable(sessions)
-      }
+      if (sessions.length === 0) return
+
+      const output = args.format === "json" ? formatSessionJSON(sessions) : formatSessionTable(sessions)
 
       const shouldPaginate = process.stdout.isTTY && !args.maxCount && args.format === "table"
 
       if (shouldPaginate) {
-        const proc = Process.spawn(pagerCmd(), {
-          stdin: "pipe",
-          stdout: "inherit",
-          stderr: "inherit",
+        yield* Effect.promise(async () => {
+          const proc = Process.spawn(pagerCmd(), {
+            stdin: "pipe",
+            stdout: "inherit",
+            stderr: "inherit",
+          })
+
+          if (!proc.stdin) {
+            console.log(output)
+            return
+          }
+
+          proc.stdin.write(output)
+          proc.stdin.end()
+          await proc.exited
         })
-
-        if (!proc.stdin) {
-          console.log(output)
-          return
-        }
-
-        proc.stdin.write(output)
-        proc.stdin.end()
-        await proc.exited
       } else {
         console.log(output)
       }
-    })
-  },
+    }).pipe(Effect.ensuring(store.dispose(ctx)))
+  }),
 })
 
 function formatSessionTable(sessions: Session.Info[]): string {