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

refactor(cli): convert export command to effectCmd (#25471)

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

+ 57 - 64
packages/opencode/src/cli/cmd/export.ts

@@ -1,13 +1,13 @@
-import type { Argv } from "yargs"
 import { Session } from "@/session/session"
 import { MessageV2 } from "../../session/message-v2"
 import { SessionID } from "../../session/schema"
-import { cmd } from "./cmd"
-import { bootstrap } from "../bootstrap"
+import { effectCmd, fail } from "../effect-cmd"
 import { UI } from "../ui"
 import * as prompts from "@clack/prompts"
 import { EOL } from "os"
-import { AppRuntime } from "@/effect/app-runtime"
+import { Effect } from "effect"
+import { InstanceRef } from "@/effect/instance-ref"
+import { InstanceStore } from "@/project/instance-store"
 
 function redact(kind: string, id: string, value: string) {
   return value.trim() ? `[redacted:${kind}:${id}]` : value
@@ -220,11 +220,11 @@ function sanitize(data: { info: Session.Info; messages: MessageV2.WithParts[] })
   }
 }
 
-export const ExportCommand = cmd({
+export const ExportCommand = effectCmd({
   command: "export [sessionID]",
   describe: "export session data as JSON",
-  builder: (yargs: Argv) => {
-    return yargs
+  builder: (yargs) =>
+    yargs
       .positional("sessionID", {
         describe: "session id to export",
         type: "string",
@@ -232,72 +232,65 @@ export const ExportCommand = cmd({
       .option("sanitize", {
         describe: "redact sensitive transcript and file data",
         type: "boolean",
-      })
-  },
-  handler: async (args) => {
-    await bootstrap(process.cwd(), async () => {
-      let sessionID = args.sessionID ? SessionID.make(args.sessionID) : undefined
-      process.stderr.write(`Exporting session: ${sessionID ?? "latest"}\n`)
+      }),
+  handler: Effect.fn("Cli.export")(function* (args) {
+    const ctx = yield* InstanceRef
+    if (!ctx) return
+    const store = yield* InstanceStore.Service
+    return yield* run(args).pipe(Effect.ensuring(store.dispose(ctx)))
+  }),
+})
 
-      if (!sessionID) {
-        UI.empty()
-        prompts.intro("Export session", {
-          output: process.stderr,
-        })
+const run = Effect.fn("Cli.export.body")(function* (args: { sessionID?: string; sanitize?: boolean }) {
+  const svc = yield* Session.Service
+  let sessionID = args.sessionID ? SessionID.make(args.sessionID) : undefined
+  process.stderr.write(`Exporting session: ${sessionID ?? "latest"}\n`)
 
-        const sessions = await AppRuntime.runPromise(Session.Service.use((svc) => svc.list()))
+  if (!sessionID) {
+    UI.empty()
+    prompts.intro("Export session", { output: process.stderr })
 
-        if (sessions.length === 0) {
-          prompts.log.error("No sessions found", {
-            output: process.stderr,
-          })
-          prompts.outro("Done", {
-            output: process.stderr,
-          })
-          return
-        }
+    const sessions = yield* svc.list()
+
+    if (sessions.length === 0) {
+      prompts.log.error("No sessions found", { output: process.stderr })
+      prompts.outro("Done", { output: process.stderr })
+      return
+    }
 
-        sessions.sort((a, b) => b.time.updated - a.time.updated)
+    sessions.sort((a, b) => b.time.updated - a.time.updated)
 
-        const selectedSession = await prompts.autocomplete({
-          message: "Select session to export",
-          maxItems: 10,
-          options: sessions.map((session) => ({
-            label: session.title,
-            value: session.id,
-            hint: `${new Date(session.time.updated).toLocaleString()} • ${session.id.slice(-8)}`,
-          })),
-          output: process.stderr,
-        })
+    const selectedSession = yield* Effect.promise(() =>
+      prompts.autocomplete({
+        message: "Select session to export",
+        maxItems: 10,
+        options: sessions.map((session) => ({
+          label: session.title,
+          value: session.id,
+          hint: `${new Date(session.time.updated).toLocaleString()} • ${session.id.slice(-8)}`,
+        })),
+        output: process.stderr,
+      }),
+    )
 
-        if (prompts.isCancel(selectedSession)) {
-          throw new UI.CancelledError()
-        }
+    if (prompts.isCancel(selectedSession)) {
+      return yield* Effect.die(new UI.CancelledError())
+    }
 
-        sessionID = selectedSession
+    sessionID = selectedSession
 
-        prompts.outro("Exporting session...", {
-          output: process.stderr,
-        })
-      }
+    prompts.outro("Exporting session...", { output: process.stderr })
+  }
 
-      try {
-        const sessionInfo = await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID!)))
-        const messages = await AppRuntime.runPromise(
-          Session.Service.use((svc) => svc.messages({ sessionID: sessionInfo.id })),
-        )
+  // Match legacy try/catch — catches both typed failures and defects
+  // (Session.Service.get throws NotFoundError as a defect, not a typed E).
+  return yield* Effect.gen(function* () {
+    const sessionInfo = yield* svc.get(sessionID!)
+    const messages = yield* svc.messages({ sessionID: sessionInfo.id })
 
-        const exportData = {
-          info: sessionInfo,
-          messages,
-        }
+    const exportData = { info: sessionInfo, messages }
 
-        process.stdout.write(JSON.stringify(args.sanitize ? sanitize(exportData) : exportData, null, 2))
-        process.stdout.write(EOL)
-      } catch {
-        UI.error(`Session not found: ${sessionID!}`)
-        process.exit(1)
-      }
-    })
-  },
+    process.stdout.write(JSON.stringify(args.sanitize ? sanitize(exportData) : exportData, null, 2))
+    process.stdout.write(EOL)
+  }).pipe(Effect.catchCause(() => fail(`Session not found: ${sessionID!}`)))
 })