Compare commits

...

3 Commits

Author SHA1 Message Date
Kit Langton 2d550aac46 chore(core): merge dev into session subpath fix 2026-06-22 13:19:06 -04:00
Kit Langton b74ff631c6 fix(core): treat session subpaths literally 2026-06-22 12:52:56 -04:00
Kit Langton da1f73873f fix(core): scope session lists to subpaths 2026-06-22 12:40:06 -04:00
2 changed files with 60 additions and 2 deletions
+8 -1
View File
@@ -2,7 +2,7 @@ export * as SessionV2 from "./session"
export * from "./session/schema"
import { DateTime, Effect, Layer, Schema, Context, Stream } from "effect"
import { and, asc, desc, eq, gt, like, lt, or, type SQL } from "drizzle-orm"
import { and, asc, desc, eq, gt, gte, like, lt, or, type SQL } from "drizzle-orm"
import { ProjectV2 } from "./project"
import { WorkspaceV2 } from "./workspace"
import { ModelV2 } from "./model"
@@ -248,6 +248,13 @@ export const layer = Layer.effect(
if ("directory" in input) conditions.push(eq(SessionTable.directory, input.directory))
if (input.workspaceID) conditions.push(eq(SessionTable.workspace_id, input.workspaceID))
if ("project" in input) conditions.push(eq(SessionTable.project_id, input.project))
if ("subpath" in input && input.subpath)
conditions.push(
or(
eq(SessionTable.path, input.subpath),
and(gte(SessionTable.path, `${input.subpath}/`), lt(SessionTable.path, `${input.subpath}0`)),
)!,
)
if (input.search) conditions.push(like(SessionTable.title, `%${input.search}%`))
if (input.anchor) {
conditions.push(
+52 -1
View File
@@ -11,7 +11,7 @@ import { ModelV2 } from "@opencode-ai/core/model"
import { ProjectV2 } from "@opencode-ai/core/project"
import { ProjectTable } from "@opencode-ai/core/project/sql"
import { ProviderV2 } from "@opencode-ai/core/provider"
import { AbsolutePath } from "@opencode-ai/core/schema"
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
import { SessionV2 } from "@opencode-ai/core/session"
import { SessionV1 } from "@opencode-ai/core/v1/session"
import { Prompt } from "@opencode-ai/core/session/prompt"
@@ -426,3 +426,54 @@ describe("SessionV2.create", () => {
}),
)
})
describe("SessionV2.list", () => {
it.effect("limits project sessions to the requested subpath", () =>
Effect.gen(function* () {
const session = yield* SessionV2.Service
const { db } = yield* Database.Service
const core = yield* session.create({ location })
const nested = yield* session.create({ location })
const web = yield* session.create({ location })
yield* Effect.all([
db.update(SessionTable).set({ path: "packages/core" }).where(eq(SessionTable.id, core.id)).run(),
db.update(SessionTable).set({ path: "packages/core/test" }).where(eq(SessionTable.id, nested.id)).run(),
db.update(SessionTable).set({ path: "packages/web" }).where(eq(SessionTable.id, web.id)).run(),
]).pipe(Effect.orDie)
const listed = yield* session.list({
project: ProjectV2.ID.global,
subpath: RelativePath.make("packages/core"),
})
expect(new Set(listed.map((item) => item.id))).toEqual(new Set([core.id, nested.id]))
}),
)
it.effect("treats wildcard characters in subpaths literally", () =>
Effect.gen(function* () {
const session = yield* SessionV2.Service
const { db } = yield* Database.Service
const exact = yield* session.create({ location })
const nested = yield* session.create({ location })
const sibling = yield* session.create({ location })
yield* Effect.all([
db.update(SessionTable).set({ path: "packages/core_test" }).where(eq(SessionTable.id, exact.id)).run(),
db.update(SessionTable).set({ path: "packages/core_test/unit" }).where(eq(SessionTable.id, nested.id)).run(),
db.update(SessionTable).set({ path: "packages/coreXtest/unit" }).where(eq(SessionTable.id, sibling.id)).run(),
]).pipe(Effect.orDie)
const listed = yield* session.list({
project: ProjectV2.ID.global,
subpath: RelativePath.make("packages/core_test"),
})
const ids = listed.map((item) => item.id)
expect(ids).toContain(exact.id)
expect(ids).toContain(nested.id)
expect(ids).not.toContain(sibling.id)
}),
)
})