Skip to content
Closed
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
3 changes: 2 additions & 1 deletion packages/opencode/src/project/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { NodeFileSystem, NodePath } from "@effect/platform-node"
import { makeRuntime } from "@/effect/run-service"
import { AppFileSystem } from "@/filesystem"
import * as CrossSpawnSpawner from "@/effect/cross-spawn-spawner"
import { Filesystem } from "@/util/filesystem"

export namespace Project {
const log = Log.create({ service: "project" })
Expand Down Expand Up @@ -315,7 +316,7 @@ export namespace Project {
d
.update(SessionTable)
.set({ project_id: data.id })
.where(and(eq(SessionTable.project_id, ProjectID.global), eq(SessionTable.directory, data.worktree)))
.where(and(eq(SessionTable.project_id, ProjectID.global), eq(SessionTable.directory, Filesystem.normalizePathSeparators(data.worktree))))
.run(),
)
}
Expand Down
7 changes: 4 additions & 3 deletions packages/opencode/src/session/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { ProjectTable } from "../project/project.sql"
import { Storage } from "@/storage/storage"
import { Log } from "../util/log"
import { updateSchema } from "../util/update-schema"
import { Filesystem } from "@/util/filesystem"
import { MessageV2 } from "./message-v2"
import { Instance } from "../project/instance"
import { SessionPrompt } from "./prompt"
Expand Down Expand Up @@ -400,7 +401,7 @@ export namespace Session {
slug: Slug.create(),
version: Installation.VERSION,
projectID: Instance.project.id,
directory: input.directory,
directory: Filesystem.normalizePathSeparators(input.directory),
workspaceID: input.workspaceID,
parentID: input.parentID,
title: input.title ?? createDefaultTitle(!!input.parentID),
Expand Down Expand Up @@ -768,7 +769,7 @@ export namespace Session {
conditions.push(eq(SessionTable.workspace_id, input.workspaceID))
}
if (input?.directory) {
conditions.push(eq(SessionTable.directory, input.directory))
conditions.push(eq(SessionTable.directory, Filesystem.normalizePathSeparators(input.directory)))
}
if (input?.roots) {
conditions.push(isNull(SessionTable.parent_id))
Expand Down Expand Up @@ -808,7 +809,7 @@ export namespace Session {
const conditions: SQL[] = []

if (input?.directory) {
conditions.push(eq(SessionTable.directory, input.directory))
conditions.push(eq(SessionTable.directory, Filesystem.normalizePathSeparators(input.directory)))
}
if (input?.roots) {
conditions.push(isNull(SessionTable.parent_id))
Expand Down
17 changes: 17 additions & 0 deletions packages/opencode/src/util/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,23 @@ export namespace Filesystem {
}
}

/**
* Normalize path separators to forward slashes for consistent database queries.
* This fixes Windows path compatibility issues where paths might use backslashes
* in some cases and forward slashes in others, and ensures consistent drive letter casing.
*/
export function normalizePathSeparators(p: string): string {
// Convert backslashes to forward slashes
let normalized = p.replace(/\\/g, "/")

// Normalize Windows drive letters to uppercase (e.g., c:/ -> C:/)
if (/^[a-z]:\//.test(normalized)) {
normalized = normalized[0].toUpperCase() + normalized.slice(1)
}

return normalized
}

// We cannot rely on path.resolve() here because git.exe may come from Git Bash, Cygwin, or MSYS2, so we need to translate these paths at the boundary.
// Also resolves symlinks so that callers using the result as a cache key
// always get the same canonical path for a given physical directory.
Expand Down
Loading