Skip to content

Commit 1986a6e

Browse files
authored
refactor(cli): convert session subcommands to effectCmd (#25483)
1 parent dfe1325 commit 1986a6e

1 file changed

Lines changed: 49 additions & 53 deletions

File tree

packages/opencode/src/cli/cmd/session.ts

Lines changed: 49 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { Argv } from "yargs"
2+
import { Effect } from "effect"
23
import { cmd } from "./cmd"
4+
import { effectCmd, fail } from "../effect-cmd"
35
import { Session } from "@/session/session"
46
import { SessionID } from "../../session/schema"
5-
import { bootstrap } from "../bootstrap"
67
import { UI } from "../ui"
78
import { Locale } from "@/util/locale"
89
import { Flag } from "@opencode-ai/core/flag/flag"
@@ -11,7 +12,8 @@ import { Process } from "@/util/process"
1112
import { EOL } from "os"
1213
import path from "path"
1314
import { which } from "../../util/which"
14-
import { AppRuntime } from "@/effect/app-runtime"
15+
import { InstanceRef } from "@/effect/instance-ref"
16+
import { InstanceStore } from "@/project/instance-store"
1517

1618
function pagerCmd(): string[] {
1719
const lessOptions = ["-R", "-S"]
@@ -47,36 +49,35 @@ export const SessionCommand = cmd({
4749
async handler() {},
4850
})
4951

50-
export const SessionDeleteCommand = cmd({
52+
export const SessionDeleteCommand = effectCmd({
5153
command: "delete <sessionID>",
5254
describe: "delete a session",
53-
builder: (yargs: Argv) => {
54-
return yargs.positional("sessionID", {
55+
builder: (yargs) =>
56+
yargs.positional("sessionID", {
5557
describe: "session ID to delete",
5658
type: "string",
5759
demandOption: true,
58-
})
59-
},
60-
handler: async (args) => {
61-
await bootstrap(process.cwd(), async () => {
60+
}),
61+
handler: Effect.fn("Cli.session.delete")(function* (args) {
62+
const ctx = yield* InstanceRef
63+
if (!ctx) return
64+
const store = yield* InstanceStore.Service
65+
return yield* Effect.gen(function* () {
66+
const svc = yield* Session.Service
6267
const sessionID = SessionID.make(args.sessionID)
63-
try {
64-
await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID)))
65-
} catch {
66-
UI.error(`Session not found: ${args.sessionID}`)
67-
process.exit(1)
68-
}
69-
await AppRuntime.runPromise(Session.Service.use((svc) => svc.remove(sessionID)))
68+
// Match legacy try/catch — Session.get surfaces NotFoundError as a defect.
69+
yield* svc.get(sessionID).pipe(Effect.catchCause(() => fail(`Session not found: ${args.sessionID}`)))
70+
yield* svc.remove(sessionID)
7071
UI.println(UI.Style.TEXT_SUCCESS_BOLD + `Session ${args.sessionID} deleted` + UI.Style.TEXT_NORMAL)
71-
})
72-
},
72+
}).pipe(Effect.ensuring(store.dispose(ctx)))
73+
}),
7374
})
7475

75-
export const SessionListCommand = cmd({
76+
export const SessionListCommand = effectCmd({
7677
command: "list",
7778
describe: "list sessions",
78-
builder: (yargs: Argv) => {
79-
return yargs
79+
builder: (yargs) =>
80+
yargs
8081
.option("max-count", {
8182
alias: "n",
8283
describe: "limit to N most recent sessions",
@@ -87,47 +88,42 @@ export const SessionListCommand = cmd({
8788
type: "string",
8889
choices: ["table", "json"],
8990
default: "table",
90-
})
91-
},
92-
handler: async (args) => {
93-
await bootstrap(process.cwd(), async () => {
94-
const sessions = await AppRuntime.runPromise(
95-
Session.Service.use((svc) => svc.list({ roots: true, limit: args.maxCount })),
96-
)
97-
98-
if (sessions.length === 0) {
99-
return
100-
}
91+
}),
92+
handler: Effect.fn("Cli.session.list")(function* (args) {
93+
const ctx = yield* InstanceRef
94+
if (!ctx) return
95+
const store = yield* InstanceStore.Service
96+
return yield* Effect.gen(function* () {
97+
const sessions = yield* Session.Service.use((svc) => svc.list({ roots: true, limit: args.maxCount }))
10198

102-
let output: string
103-
if (args.format === "json") {
104-
output = formatSessionJSON(sessions)
105-
} else {
106-
output = formatSessionTable(sessions)
107-
}
99+
if (sessions.length === 0) return
100+
101+
const output = args.format === "json" ? formatSessionJSON(sessions) : formatSessionTable(sessions)
108102

109103
const shouldPaginate = process.stdout.isTTY && !args.maxCount && args.format === "table"
110104

111105
if (shouldPaginate) {
112-
const proc = Process.spawn(pagerCmd(), {
113-
stdin: "pipe",
114-
stdout: "inherit",
115-
stderr: "inherit",
106+
yield* Effect.promise(async () => {
107+
const proc = Process.spawn(pagerCmd(), {
108+
stdin: "pipe",
109+
stdout: "inherit",
110+
stderr: "inherit",
111+
})
112+
113+
if (!proc.stdin) {
114+
console.log(output)
115+
return
116+
}
117+
118+
proc.stdin.write(output)
119+
proc.stdin.end()
120+
await proc.exited
116121
})
117-
118-
if (!proc.stdin) {
119-
console.log(output)
120-
return
121-
}
122-
123-
proc.stdin.write(output)
124-
proc.stdin.end()
125-
await proc.exited
126122
} else {
127123
console.log(output)
128124
}
129-
})
130-
},
125+
}).pipe(Effect.ensuring(store.dispose(ctx)))
126+
}),
131127
})
132128

133129
function formatSessionTable(sessions: Session.Info[]): string {

0 commit comments

Comments
 (0)