From 06473c264e96e6c5bd5a9d760bd3fbbc2c9795f4 Mon Sep 17 00:00:00 2001 From: OpeOginni Date: Wed, 4 Mar 2026 17:43:05 +0100 Subject: [PATCH 1/2] refactor(cli): implement canonical path resolution in TUI and worker commands --- packages/opencode/src/cli/cmd/tui/thread.ts | 2 +- packages/opencode/src/cli/cmd/tui/worker.ts | 3 ++- packages/opencode/src/project/instance.ts | 11 ++++++----- packages/opencode/src/util/filesystem.ts | 15 ++++++++++++++- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index f53cc392552..d58b1bafe64 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -112,7 +112,7 @@ export const TuiThreadCommand = cmd({ // Resolve relative paths against PWD to preserve behavior when using --cwd flag const root = process.env.PWD ?? process.cwd() - const cwd = args.project ? path.resolve(root, args.project) : process.cwd() + const cwd = Filesystem.canonical(args.project ? path.resolve(root, args.project) : process.cwd()) const file = await target() try { process.chdir(cwd) diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index e63f10ba80c..4354868c9b8 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -10,6 +10,7 @@ import { GlobalBus } from "@/bus/global" import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2" import type { BunWebSocketData } from "hono/bun" import { Flag } from "@/flag/flag" +import { Filesystem } from "@/util/filesystem" await Log.init({ print: process.argv.includes("--print-logs"), @@ -94,7 +95,7 @@ const startEventStream = (directory: string) => { }) } -startEventStream(process.cwd()) +startEventStream(Filesystem.canonical(process.cwd())) export const rpc = { async fetch(input: { url: string; method: string; headers: Record; body?: string }) { diff --git a/packages/opencode/src/project/instance.ts b/packages/opencode/src/project/instance.ts index 98031f18d3f..f784cd99220 100644 --- a/packages/opencode/src/project/instance.ts +++ b/packages/opencode/src/project/instance.ts @@ -20,13 +20,14 @@ const disposal = { export const Instance = { async provide(input: { directory: string; init?: () => Promise; fn: () => R }): Promise { - let existing = cache.get(input.directory) + const directory = Filesystem.canonical(input.directory) + let existing = cache.get(directory) if (!existing) { - Log.Default.info("creating instance", { directory: input.directory }) + Log.Default.info("creating instance", { directory }) existing = iife(async () => { - const { project, sandbox } = await Project.fromDirectory(input.directory) + const { project, sandbox } = await Project.fromDirectory(directory) const ctx = { - directory: input.directory, + directory, worktree: sandbox, project, } @@ -35,7 +36,7 @@ export const Instance = { }) return ctx }) - cache.set(input.directory, existing) + cache.set(directory, existing) } const ctx = await existing return context.provide(ctx, async () => { diff --git a/packages/opencode/src/util/filesystem.ts b/packages/opencode/src/util/filesystem.ts index a87aaeb9866..160f473e7b6 100644 --- a/packages/opencode/src/util/filesystem.ts +++ b/packages/opencode/src/util/filesystem.ts @@ -2,7 +2,7 @@ import { chmod, mkdir, readFile, writeFile } from "fs/promises" import { createWriteStream, existsSync, statSync } from "fs" import { lookup } from "mime-types" import { realpathSync } from "fs" -import { dirname, join, relative } from "path" +import { dirname, join, normalize, relative, resolve } from "path" import { Readable } from "stream" import { pipeline } from "stream/promises" import { Glob } from "./glob" @@ -113,6 +113,19 @@ export namespace Filesystem { } } + export function canonical(p: string): string { + const abs = normalize(resolve(p)) + const real = (() => { + try { + return normalize(realpathSync.native(abs)) + } catch { + return abs + } + })() + if (process.platform === "win32") return real.toLowerCase() + return real + } + export function windowsPath(p: string): string { if (process.platform !== "win32") return p return ( From 368035600c58f4746347111051178c02219da3c1 Mon Sep 17 00:00:00 2001 From: OpeOginni Date: Wed, 4 Mar 2026 18:15:37 +0100 Subject: [PATCH 2/2] refactor(cli): simplify path resolution in TUI and worker commands --- packages/opencode/src/cli/cmd/tui/thread.ts | 2 +- packages/opencode/src/cli/cmd/tui/worker.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index d58b1bafe64..f53cc392552 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -112,7 +112,7 @@ export const TuiThreadCommand = cmd({ // Resolve relative paths against PWD to preserve behavior when using --cwd flag const root = process.env.PWD ?? process.cwd() - const cwd = Filesystem.canonical(args.project ? path.resolve(root, args.project) : process.cwd()) + const cwd = args.project ? path.resolve(root, args.project) : process.cwd() const file = await target() try { process.chdir(cwd) diff --git a/packages/opencode/src/cli/cmd/tui/worker.ts b/packages/opencode/src/cli/cmd/tui/worker.ts index 4354868c9b8..e63f10ba80c 100644 --- a/packages/opencode/src/cli/cmd/tui/worker.ts +++ b/packages/opencode/src/cli/cmd/tui/worker.ts @@ -10,7 +10,6 @@ import { GlobalBus } from "@/bus/global" import { createOpencodeClient, type Event } from "@opencode-ai/sdk/v2" import type { BunWebSocketData } from "hono/bun" import { Flag } from "@/flag/flag" -import { Filesystem } from "@/util/filesystem" await Log.init({ print: process.argv.includes("--print-logs"), @@ -95,7 +94,7 @@ const startEventStream = (directory: string) => { }) } -startEventStream(Filesystem.canonical(process.cwd())) +startEventStream(process.cwd()) export const rpc = { async fetch(input: { url: string; method: string; headers: Record; body?: string }) {