Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions packages/opencode/src/session/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { like } from "drizzle-orm"
import { inArray } from "drizzle-orm"
import { lt } from "drizzle-orm"
import { or } from "drizzle-orm"
import { sql } from "drizzle-orm"
import { SyncEvent } from "../sync"
import type { SQL } from "drizzle-orm"
import { PartTable, SessionTable } from "./session.sql"
Expand Down Expand Up @@ -49,6 +50,22 @@ function createDefaultTitle(isChild = false) {
return (isChild ? childTitlePrefix : parentTitlePrefix) + new Date().toISOString()
}

function isWindowsDirectory(directory: string) {
return directory.length > 1 && (directory[1] === ":" || directory.startsWith("\\\\"))
}

function normalizeDirectory(directory: string) {
if (isWindowsDirectory(directory)) {
return directory.replaceAll("\\", "/")
}
return directory
}

function directoryMatches(directory: string) {
if (!isWindowsDirectory(directory)) return eq(SessionTable.directory, directory)
return sql`replace(${SessionTable.directory}, ${"\\"}, ${"/"}) = ${normalizeDirectory(directory)}`
}

export function isDefaultTitle(title: string) {
return new RegExp(
`^(${parentTitlePrefix}|${childTitlePrefix})\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$`,
Expand Down Expand Up @@ -536,7 +553,7 @@ export const layer: Layer.Layer<
slug: Slug.create(),
version: InstallationVersion,
projectID: ctx.project.id,
directory: input.directory,
directory: normalizeDirectory(input.directory),
path: input.path,
workspaceID: input.workspaceID,
parentID: input.parentID,
Expand Down Expand Up @@ -904,13 +921,13 @@ function* listByProject(

conditions.push(
input.directory
? or(...conds, and(isNull(SessionTable.path), eq(SessionTable.directory, input.directory))!)!
? or(...conds, and(isNull(SessionTable.path), directoryMatches(input.directory))!)!
: or(...conds)!,
)
}
} else if (input.scope !== "project" && !input.experimentalWorkspaces) {
if (input.directory) {
conditions.push(eq(SessionTable.directory, input.directory))
conditions.push(directoryMatches(input.directory))
}
}
if (input.roots) {
Expand Down Expand Up @@ -951,7 +968,7 @@ export function* listGlobal(input?: {
const conditions: SQL[] = []

if (input?.directory) {
conditions.push(eq(SessionTable.directory, input.directory))
conditions.push(directoryMatches(input.directory))
}
if (input?.roots) {
conditions.push(isNull(SessionTable.parent_id))
Expand Down
29 changes: 29 additions & 0 deletions packages/opencode/test/server/global-session-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
import * as Log from "@opencode-ai/core/util/log"
import { provideInstance, TestInstance, tmpdirScoped } from "../fixture/fixture"
import { testEffect } from "../lib/effect"
import { Database } from "@/storage/db"
import { SessionTable } from "@/session/session.sql"
import { eq } from "drizzle-orm"

void Log.init({ print: false })

Expand Down Expand Up @@ -101,4 +104,30 @@ describe("session.listGlobal", () => {
}),
{ git: true },
)

it.instance(
"matches Windows directories across separator styles",
() =>
Effect.gen(function* () {
const created = yield* withSession({ title: "windows-global-directory" })
const storedDirectory = String.raw`C:\Users\demo\project`
const requestedDirectory = "C:/Users/demo/project"

yield* Effect.sync(() =>
Database.use((db) =>
db
.update(SessionTable)
.set({ directory: storedDirectory, path: null })
.where(eq(SessionTable.id, created.id))
.run(),
),
)

const sessions = yield* Effect.sync(() => [...SessionNs.listGlobal({ directory: requestedDirectory })])
const ids = sessions.map((session) => session.id)

expect(ids).toContain(created.id)
}),
{ git: true },
)
})
27 changes: 27 additions & 0 deletions packages/opencode/test/server/session-list.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,33 @@ describe("session.list", () => {
{ git: true },
)

it.instance(
"matches Windows directories across separator styles",
() =>
Effect.gen(function* () {
const created = yield* withSession({ title: "windows-directory" })
const storedDirectory = String.raw`C:\Users\demo\project`
const requestedDirectory = "C:/Users/demo/project"

yield* Effect.sync(() =>
Database.use((db) =>
db
.update(SessionTable)
.set({ directory: storedDirectory, path: null })
.where(eq(SessionTable.id, created.id))
.run(),
),
)

const ids = (yield* SessionNs.Service.use((session) => session.list({ directory: requestedDirectory }))).map(
(session) => session.id,
)

expect(ids).toContain(created.id)
}),
{ git: true },
)

it.instance(
"filters by path and ignores directory when path is provided",
() =>
Expand Down
Loading