Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com> Co-authored-by: Kit Langton <kit.langton@gmail.com> Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com> Co-authored-by: Affan Ali <93028901+affanali2k3@users.noreply.github.com> Co-authored-by: affanali2k3 <affanalikhanxx@gmail.com> Co-authored-by: Frank <frank@anoma.ly> Co-authored-by: opencode-agent[bot] <219766164+opencode-agent[bot]@users.noreply.github.com> Co-authored-by: 𝓛𝓲𝓽𝓽𝓵𝓮 𝓕𝓻𝓪𝓷𝓴 <little-frank@opencord.local> Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Co-authored-by: Jay V <air@live.ca> Co-authored-by: Dax Raad <d@ironbay.co> Co-authored-by: Aarav Sareen <96787824+arvsrn@users.noreply.github.com> Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com> Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com> Co-authored-by: Ben Guthrie <benjee.012@gmail.com> Co-authored-by: Dax <mail@thdxr.com> Co-authored-by: Filip <34747899+neriousy@users.noreply.github.com> Co-authored-by: Max Anderson <max.a.anderson95@gmail.com> Co-authored-by: Brendan Allan <git@brendonovich.dev> Co-authored-by: Jack <jack@anoma.ly> Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com> Co-authored-by: Dustin Deus <deusdustin@gmail.com> Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box> Co-authored-by: Aiden Cline <aidenpcline@gmail.com> Co-authored-by: usrnk1 <7547651+usrnk1@users.noreply.github.com> Co-authored-by: Jay <53023+jayair@users.noreply.github.com> Co-authored-by: runvip <164729189+runvip@users.noreply.github.com> Co-authored-by: opencode <opencode@sst.dev> Co-authored-by: Julian Coy <julian@ex-machina.co> Co-authored-by: Vladimir Glafirov <vglafirov@gitlab.com>
108 lines
4.2 KiB
TypeScript
108 lines
4.2 KiB
TypeScript
import { describe, expect } from "bun:test"
|
|
import { LayerNode } from "@opencode-ai/core/effect/layer-node"
|
|
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
|
import { Deferred, Effect, Layer } from "effect"
|
|
import { Project } from "@/project/project"
|
|
import { Session as SessionNs } from "@/session/session"
|
|
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
|
import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture"
|
|
import { testEffect } from "../lib/effect"
|
|
|
|
const it = testEffect(
|
|
LayerNode.compile(LayerNode.group([SessionNs.node, SessionProjector.node, Project.node, CrossSpawnSpawner.node])),
|
|
)
|
|
|
|
const withSession = (input?: Parameters<SessionNs.Interface["create"]>[0]) =>
|
|
Effect.acquireRelease(SessionNs.use.create(input), (created) =>
|
|
SessionNs.Service.use((session) => session.remove(created.id).pipe(Effect.ignore)),
|
|
)
|
|
|
|
describe("session.listGlobal", () => {
|
|
it.instance(
|
|
"lists sessions across projects with project metadata",
|
|
() =>
|
|
Effect.gen(function* () {
|
|
const first = yield* TestInstance
|
|
const second = yield* tmpdirScoped({ git: true })
|
|
|
|
const firstSession = yield* withSession({ title: "first-session" })
|
|
const secondSession = yield* withSession({ title: "second-session" }).pipe(provideInstance(second))
|
|
|
|
const sessions = yield* SessionNs.Service.use((session) => session.listGlobal({ limit: 200 }))
|
|
const ids = sessions.map((session) => session.id)
|
|
|
|
expect(ids).toContain(firstSession.id)
|
|
expect(ids).toContain(secondSession.id)
|
|
|
|
const firstProject = yield* Project.use.get(firstSession.projectID)
|
|
const secondProject = yield* Project.use.get(secondSession.projectID)
|
|
|
|
const firstItem = sessions.find((session) => session.id === firstSession.id)
|
|
const secondItem = sessions.find((session) => session.id === secondSession.id)
|
|
|
|
expect(firstItem?.project?.id).toBe(firstProject?.id)
|
|
expect(firstItem?.project?.worktree).toBe(firstProject?.worktree)
|
|
expect(secondItem?.project?.id).toBe(secondProject?.id)
|
|
expect(secondItem?.project?.worktree).toBe(secondProject?.worktree)
|
|
expect(first.directory).not.toBe(second)
|
|
}),
|
|
{ git: true },
|
|
)
|
|
|
|
it.instance(
|
|
"excludes archived sessions by default",
|
|
() =>
|
|
Effect.gen(function* () {
|
|
const archived = yield* withSession({ title: "archived-session" })
|
|
|
|
yield* SessionNs.Service.use((session) => session.setArchived({ sessionID: archived.id, time: Date.now() }))
|
|
|
|
const sessions = yield* SessionNs.Service.use((session) => session.listGlobal({ limit: 200 }))
|
|
const ids = sessions.map((session) => session.id)
|
|
|
|
expect(ids).not.toContain(archived.id)
|
|
|
|
const allSessions = yield* SessionNs.Service.use((session) =>
|
|
session.listGlobal({ limit: 200, archived: true }),
|
|
)
|
|
const allIds = allSessions.map((session) => session.id)
|
|
|
|
expect(allIds).toContain(archived.id)
|
|
}),
|
|
{ git: true },
|
|
)
|
|
|
|
it.instance(
|
|
"supports cursor pagination",
|
|
() =>
|
|
Effect.gen(function* () {
|
|
const test = yield* TestInstance
|
|
|
|
const first = yield* withSession({ title: "page-one" })
|
|
const ready = yield* Deferred.make<void>()
|
|
yield* Deferred.succeed(ready, undefined).pipe(Effect.delay("5 millis"), Effect.forkScoped)
|
|
yield* Deferred.await(ready).pipe(
|
|
Effect.timeoutOrElse({
|
|
duration: "1 second",
|
|
orElse: () => Effect.fail(new Error("timed out waiting between session creates")),
|
|
}),
|
|
)
|
|
const second = yield* withSession({ title: "page-two" })
|
|
|
|
const page = yield* SessionNs.Service.use((session) =>
|
|
session.listGlobal({ directory: test.directory, limit: 1 }),
|
|
)
|
|
expect(page.length).toBe(1)
|
|
expect(page[0].id).toBe(second.id)
|
|
|
|
const next = yield* SessionNs.Service.use((session) =>
|
|
session.listGlobal({ directory: test.directory, limit: 10, cursor: page[0].time.updated }),
|
|
)
|
|
const ids = next.map((session) => session.id)
|
|
|
|
expect(ids).toContain(first.id)
|
|
expect(ids).not.toContain(second.id)
|
|
}),
|
|
{ git: true },
|
|
)
|
|
})
|