From 8b56d1712f26901b109db300a84002f8d71b3ea5 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 30 Apr 2026 23:00:59 -0400 Subject: [PATCH] refactor(session): pass project to list (#25215) --- packages/opencode/src/cli/cmd/export.ts | 5 +- packages/opencode/src/cli/cmd/session.ts | 4 +- .../instance/httpapi/handlers/session.ts | 24 ++++----- .../src/server/routes/instance/session.ts | 28 ++++++----- packages/opencode/src/session/session.ts | 49 +++++++++++-------- .../opencode/test/server/session-list.test.ts | 33 ++++++++----- 6 files changed, 79 insertions(+), 64 deletions(-) diff --git a/packages/opencode/src/cli/cmd/export.ts b/packages/opencode/src/cli/cmd/export.ts index 4f19c3c4d5..62ba20e2ca 100644 --- a/packages/opencode/src/cli/cmd/export.ts +++ b/packages/opencode/src/cli/cmd/export.ts @@ -245,10 +245,7 @@ export const ExportCommand = cmd({ output: process.stderr, }) - const sessions = [] - for await (const session of Session.list()) { - sessions.push(session) - } + const sessions = await AppRuntime.runPromise(Session.Service.use((svc) => svc.list())) if (sessions.length === 0) { prompts.log.error("No sessions found", { diff --git a/packages/opencode/src/cli/cmd/session.ts b/packages/opencode/src/cli/cmd/session.ts index ae9f7c8844..52a3d7204e 100644 --- a/packages/opencode/src/cli/cmd/session.ts +++ b/packages/opencode/src/cli/cmd/session.ts @@ -91,7 +91,9 @@ export const SessionListCommand = cmd({ }, handler: async (args) => { await bootstrap(process.cwd(), async () => { - const sessions = [...Session.list({ roots: true, limit: args.maxCount })] + const sessions = await AppRuntime.runPromise( + Session.Service.use((svc) => svc.list({ roots: true, limit: args.maxCount })), + ) if (sessions.length === 0) { return diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index cd8b5e11c2..8cc969f483 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -5,7 +5,6 @@ import { Bus } from "@/bus" import { Command } from "@/command" import { Permission } from "@/permission" import { PermissionID } from "@/permission/schema" -import { Instance } from "@/project/instance" import { SessionShare } from "@/share/session" import { Session } from "@/session/session" import { SessionCompaction } from "@/session/compaction" @@ -64,20 +63,15 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", const scope = yield* Scope.Scope const list = Effect.fn("SessionHttpApi.list")(function* (ctx: { query: typeof ListQuery.Type }) { - const instance = yield* InstanceState.context - return Instance.restore(instance, () => - Array.from( - Session.list({ - directory: ctx.query.scope === "project" ? undefined : ctx.query.directory, - scope: ctx.query.scope, - path: ctx.query.path, - roots: ctx.query.roots, - start: ctx.query.start, - search: ctx.query.search, - limit: ctx.query.limit, - }), - ), - ) + return yield* session.list({ + directory: ctx.query.scope === "project" ? undefined : ctx.query.directory, + scope: ctx.query.scope, + path: ctx.query.path, + roots: ctx.query.roots, + start: ctx.query.start, + search: ctx.query.search, + limit: ctx.query.limit, + }) }) const status = Effect.fn("SessionHttpApi.status")(function* () { diff --git a/packages/opencode/src/server/routes/instance/session.ts b/packages/opencode/src/server/routes/instance/session.ts index 410d8bba0c..a16a92f927 100644 --- a/packages/opencode/src/server/routes/instance/session.ts +++ b/packages/opencode/src/server/routes/instance/session.ts @@ -78,18 +78,22 @@ export const SessionRoutes = lazy(() => ), async (c) => { const query = c.req.valid("query") - const sessions: Session.Info[] = [] - for await (const session of Session.list({ - directory: query.scope === "project" ? undefined : query.directory, - path: query.path, - roots: queryBoolean(query.roots), - start: query.start, - search: query.search, - limit: query.limit, - })) { - sessions.push(session) - } - return c.json(sessions) + return c.json( + await runRequest( + "SessionRoutes.list", + c, + Session.Service.use((svc) => + svc.list({ + directory: query.scope === "project" ? undefined : query.directory, + path: query.path, + roots: queryBoolean(query.roots), + start: query.start, + search: query.search, + limit: query.limit, + }), + ), + ), + ) }, ) .get( diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index 7e6016b87f..2ff7842bdb 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -26,7 +26,7 @@ import { ProjectTable } from "../project/project.sql" import { Storage } from "@/storage/storage" import * as Log from "@opencode-ai/core/util/log" import { MessageV2 } from "./message-v2" -import { Instance, type InstanceContext } from "../project/instance" +import type { InstanceContext } from "../project/instance" import { InstanceState } from "@/effect/instance-state" import { Snapshot } from "@/snapshot" import { ProjectID } from "../project/schema" @@ -234,6 +234,16 @@ export const MessagesInput = Schema.Struct({ sessionID: SessionID, limit: Schema.optional(NonNegativeInt), }).pipe(withStatics((s) => ({ zod: zod(s) }))) +export type ListInput = { + directory?: string + scope?: "project" + path?: string + workspaceID?: WorkspaceID + roots?: boolean + start?: number + search?: string + limit?: number +} const CreatedEventSchema = Schema.Struct({ sessionID: SessionID, @@ -390,6 +400,7 @@ export class BusyError extends Error { } export interface Interface { + readonly list: (input?: ListInput) => Effect.Effect readonly create: (input?: { parentID?: SessionID title?: string @@ -498,6 +509,11 @@ export const layer: Layer.Layer d @@ -731,6 +747,7 @@ export const layer: Layer.Layer db diff --git a/packages/opencode/test/server/session-list.test.ts b/packages/opencode/test/server/session-list.test.ts index cbdda6b426..e2f92c20f6 100644 --- a/packages/opencode/test/server/session-list.test.ts +++ b/packages/opencode/test/server/session-list.test.ts @@ -23,6 +23,9 @@ const svc = { create(input?: SessionNs.CreateInput) { return run(SessionNs.Service.use((svc) => svc.create(input))) }, + list(input?: SessionNs.ListInput) { + return run(SessionNs.Service.use((svc) => svc.list(input))) + }, } afterEach(async () => { @@ -55,7 +58,7 @@ describe("session.list", () => { fn: async () => svc.create({ title: "sibling" }), }) - const ids = [...svc.list()].map((s) => s.id) + const ids = (await svc.list()).map((s) => s.id) expect(ids).toContain(root.id) expect(ids).toContain(parent.id) expect(ids).toContain(current.id) @@ -88,7 +91,7 @@ describe("session.list", () => { fn: async () => svc.create({ title: "sibling" }), }) - const ids = [...svc.list({ directory: path.join(tmp.path, "packages", "opencode") })].map((s) => s.id) + const ids = (await svc.list({ directory: path.join(tmp.path, "packages", "opencode") })).map((s) => s.id) expect(ids).not.toContain(root.id) expect(ids).not.toContain(parent.id) expect(ids).toContain(current.id) @@ -123,9 +126,12 @@ describe("session.list", () => { fn: async () => svc.create({ title: "sibling" }), }) - const pathIDs = [ - ...svc.list({ directory: path.join(tmp.path, "packages", "app"), path: "packages/opencode/src" }), - ].map((s) => s.id) + const pathIDs = ( + await svc.list({ + directory: path.join(tmp.path, "packages", "app"), + path: "packages/opencode/src", + }) + ).map((s) => s.id) expect(pathIDs).not.toContain(parent.id) expect(pathIDs).toContain(current.id) expect(pathIDs).toContain(deeper.id) @@ -155,9 +161,12 @@ describe("session.list", () => { Database.use((db) => db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, current.id)).run()) Database.use((db) => db.update(SessionTable).set({ path: null }).where(eq(SessionTable.id, sibling.id)).run()) - const pathIDs = [ - ...svc.list({ directory: path.join(tmp.path, "packages", "opencode", "src"), path: "packages/opencode/src" }), - ].map((s) => s.id) + const pathIDs = ( + await svc.list({ + directory: path.join(tmp.path, "packages", "opencode", "src"), + path: "packages/opencode/src", + }) + ).map((s) => s.id) expect(pathIDs).toContain(current.id) expect(pathIDs).not.toContain(sibling.id) }, @@ -172,7 +181,7 @@ describe("session.list", () => { const root = await svc.create({ title: "root-session" }) const child = await svc.create({ title: "child-session", parentID: root.id }) - const sessions = [...svc.list({ roots: true })] + const sessions = await svc.list({ roots: true }) const ids = sessions.map((s) => s.id) expect(ids).toContain(root.id) @@ -189,7 +198,7 @@ describe("session.list", () => { await svc.create({ title: "new-session" }) const futureStart = Date.now() + 86400000 - const sessions = [...svc.list({ start: futureStart })] + const sessions = await svc.list({ start: futureStart }) expect(sessions.length).toBe(0) }, }) @@ -203,7 +212,7 @@ describe("session.list", () => { await svc.create({ title: "unique-search-term-abc" }) await svc.create({ title: "other-session-xyz" }) - const sessions = [...svc.list({ search: "unique-search" })] + const sessions = await svc.list({ search: "unique-search" }) const titles = sessions.map((s) => s.title) expect(titles).toContain("unique-search-term-abc") @@ -221,7 +230,7 @@ describe("session.list", () => { await svc.create({ title: "session-2" }) await svc.create({ title: "session-3" }) - const sessions = [...svc.list({ limit: 2 })] + const sessions = await svc.list({ limit: 2 }) expect(sessions.length).toBe(2) }, })