diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts
index 81a9a903ce4c..eb9a8069b17d 100644
--- a/packages/core/src/session.ts
+++ b/packages/core/src/session.ts
@@ -366,9 +366,15 @@ const layer = Layer.effect(
if (recorded) return recorded
const parent = input.parentID ? yield* store.get(input.parentID) : undefined
if (input.parentID && parent === undefined) return yield* new NotFoundError({ sessionID: input.parentID })
- const location = parent?.location ?? input.location
- if (location === undefined)
+ const requestedLocation = parent?.location ?? input.location
+ if (requestedLocation === undefined)
return yield* Effect.die(new Error("Session.create requires either location or an existing parentID"))
+ const location = parent
+ ? parent.location
+ : Location.Ref.make({
+ ...requestedLocation,
+ directory: AbsolutePath.make(yield* fs.resolve(requestedLocation.directory)),
+ })
const project = yield* projects.resolve(location.directory)
yield* persistProject(project)
const projected = yield* bus
@@ -474,7 +480,8 @@ const layer = Layer.effect(
const order = direction === "previous" ? (requestedOrder === "asc" ? "desc" : "asc") : requestedOrder
const sortColumn = SessionTable.time_updated
const conditions: SQL[] = []
- if ("directory" in input) conditions.push(eq(SessionTable.directory, input.directory))
+ if ("directory" in input)
+ conditions.push(eq(SessionTable.directory, AbsolutePath.make(yield* fs.resolve(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 ("project" in input && input.subpath !== undefined) conditions.push(eq(SessionTable.path, input.subpath))
@@ -775,7 +782,7 @@ const layer = Layer.effect(
const value = input.directory.trim()
const expanded =
value === "~" ? global.home : value.startsWith("~/") ? path.join(global.home, value.slice(2)) : value
- const directory = AbsolutePath.make(path.resolve(current.location.directory, expanded))
+ const directory = AbsolutePath.make(yield* fs.resolve(path.resolve(current.location.directory, expanded)))
const info = yield* fs.stat(directory).pipe(Effect.orElseSucceed(() => undefined))
if (!info) return yield* new DestinationNotFoundError({ directory })
if (info.type !== "Directory") return yield* new DestinationNotDirectoryError({ directory })
diff --git a/packages/core/test/session-create.test.ts b/packages/core/test/session-create.test.ts
index 69de3a547e45..9d1c23d56588 100644
--- a/packages/core/test/session-create.test.ts
+++ b/packages/core/test/session-create.test.ts
@@ -83,6 +83,27 @@ function withTmp(f: (directory: string) => Effect.Effect) {
}
describe("Session.create", () => {
+ liveIt.live("uses on-disk macOS casing for creation and directory listing", () =>
+ withTmp((directory) =>
+ Effect.gen(function* () {
+ if (process.platform !== "darwin") return
+ const session = yield* Session.Service
+ const actual = path.join(directory, "Academic", "Project")
+ yield* Effect.promise(() => fs.mkdir(actual, { recursive: true }))
+ const requested = path.join(directory, "academic", "project")
+ if (!(yield* Effect.promise(() => fs.access(requested).then(() => true, () => false)))) return
+
+ const created = yield* session.create({
+ location: Location.Ref.make({ directory: AbsolutePath.make(requested) }),
+ })
+
+ expect(created.location.directory).toBe(AbsolutePath.make(actual))
+ expect((yield* session.list({ directory: AbsolutePath.make(requested) })).data).toEqual([created])
+ expect((yield* session.list({ directory: AbsolutePath.make(actual) })).data).toEqual([created])
+ }),
+ ),
+ )
+
liveIt.live("follows the directory's project identity established after creation", () =>
withTmp((directory) =>
Effect.gen(function* () {
diff --git a/packages/util/src/fs-util.ts b/packages/util/src/fs-util.ts
index b82a5d8e66ce..afcaf431b809 100644
--- a/packages/util/src/fs-util.ts
+++ b/packages/util/src/fs-util.ts
@@ -103,6 +103,7 @@ export namespace FSUtil {
const resolve = Effect.fn("FileSystem.resolve")(function* (input: string) {
const resolved = path.resolve(windowsPath(input))
return yield* fs.realPath(resolved).pipe(
+ Effect.map((real) => (process.platform === "darwin" ? realpathSync.native(resolved) : real)),
Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(resolved)),
Effect.orDie,
)