Skip to content

[Bug]: "Open in PowerShell" passes the project path as a command on Windows #40045

Closed as not planned

Description

@RogarLeo

Description

[Bug]: "Open in PowerShell" passes the project path as a command on Windows

Describe the bug

On Windows, selecting Open in PowerShell from the project picker or session header fails instead of opening a PowerShell window in the selected project directory.

The error is similar to:

Error invoking remote method 'open-path': Error: Command failed:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe C:\path\to\project

C:\path\to\project : The term 'C:\path\to\project' is not recognized
as the name of a cmdlet, function, script file, or operable program.

CategoryInfo          : ObjectNotFound
FullyQualifiedErrorId : CommandNotFoundException

Steps to reproduce

  1. Open OpenCode Desktop on Windows.
  2. Open a project, for example C:\path\to\project.
  3. Select Open in PowerShell from the project or session menu.
  4. Observe that OpenCode reports a CommandNotFoundException instead of opening PowerShell.

Expected behavior

A new PowerShell window should open with its working directory set to the selected project directory.

Environment

  • OpenCode Desktop: 1.18.10, Windows x64
  • Operating system: Windows 11 x64
  • PowerShell: Windows PowerShell 5.1

Related history

This is the same issue as #15111, which was fixed by #15112 for the Tauri-based desktop build (packages/desktop/src-tauri, a Rust open_in_powershell command using CREATE_NEW_CONSOLE). The Electron-based desktop build shipped in 1.18.10 still runs the generic open-path handler below and remains affected.

Root cause

The open-path IPC handler in packages/desktop/src/main/ipc.ts uses the following generic non-macOS behavior:

const [cmd, args] =
  process.platform === "darwin"
    ? (["open", ["-a", app, path]] as const)
    : ([app, [path]] as const)

execFile(cmd, args, ...)

On Windows, selecting PowerShell therefore executes the equivalent of:

powershell.exe C:\path\to\project

PowerShell interprets the positional path argument as a command or script to execute. It does not interpret it as the desired working directory, resulting in CommandNotFoundException.

Suggested direction

PowerShell should use a dedicated Windows launch path rather than the generic application + directory argument behavior.

The implementation should:

  • launch PowerShell in a separate interactive console window;
  • set the selected project as its working directory;
  • support both powershell.exe and pwsh.exe where applicable;
  • avoid interpolating an unescaped project path through multiple command parsers;
  • surface an error when the Windows launcher process itself cannot be created.

Using cmd.exe /c start may be a practical way to create the console window, but the implementation should account for both CMD and PowerShell quoting rules.

A minimal Electron-side fix that works in practice:

diff --git a/packages/desktop/src/main/ipc.ts b/packages/desktop/src/main/ipc.ts
index 1103401c49..27c7d06fd0 100644
--- a/packages/desktop/src/main/ipc.ts
+++ b/packages/desktop/src/main/ipc.ts
@@ -1,4 +1,4 @@
-import { execFile } from "node:child_process"
+import { execFile, spawn } from "node:child_process"
 import { stat } from "node:fs/promises"
 import { basename } from "node:path"
 import { app, BrowserWindow, Notification, clipboard, dialog, ipcMain, shell } from "electron"
@@ -179,6 +179,12 @@ export function registerIpcHandlers(deps: Deps) {
 
   ipcMain.handle("open-path", async (_event: IpcMainInvokeEvent, path: string, app?: string) => {
     if (!app) return shell.openPath(path)
+
+    if (process.platform === "win32") {
+      await openWindowsApp(app, path)
+      return
+    }
+
     await new Promise<void>((resolve, reject) => {
       const [cmd, args] =
         process.platform === "darwin" ? (["open", ["-a", app, path]] as const) : ([app, [path]] as const)
@@ -265,6 +271,26 @@ export function sendMenuCommand(win: BrowserWindow, id: string) {
   win.webContents.send("menu-command", id)
 }
 
+async function openWindowsApp(appPath: string, targetPath: string) {
+  const executable = basename(appPath).toLowerCase()
+  const isPowerShell = ["powershell", "powershell.exe", "pwsh", "pwsh.exe"].includes(executable)
+  const launch = isPowerShell
+    ? {
+        cmd: "cmd.exe",
+        args: ["/d", "/c", "start", "", appPath, "-NoExit", "-Command", `Set-Location -LiteralPath '${targetPath.replace(/'/g, "''")}'`],
+      }
+    : { cmd: appPath, args: [targetPath] }
+
+  await new Promise<void>((resolve, reject) => {
+    const child = spawn(launch.cmd, launch.args, { stdio: "ignore", windowsHide: false })
+    child.once("error", reject)
+    child.once("spawn", () => {
+      child.unref()
+      resolve()
+    })
+  })
+}
+
 export function sendDeepLinks(win: BrowserWindow, urls: string[]) {
   win.webContents.send("deep-link", urls)
 }

Notes on the approach:

  • In the tested Electron/Node runtime, spawn(..., { detached: true }) maps to DETACHED_PROCESS — the child gets no visible console window, so PowerShell never becomes visible.
  • spawn(powershell.exe, ...) without detached inherits no console from the Electron (GUI) parent and the conhost window comes up with a "blocked" icon.
  • cmd.exe /d /c start "" powershell.exe ... is the standard Windows way to spawn a console app in its own new console window (/d disables AutoRun scripts).
  • The targetPath.replace(/'/g, "''") escapes single quotes for PowerShell's -Command.
  • Since the path passes through cmd.exe inside -Command, a path containing a pair of % characters (e.g. C:\Projects\%TEMP%\demo) can be expanded by CMD as an environment variable. A more robust implementation could avoid CMD parsing of the path entirely by passing the script as a Base64 -EncodedCommand argument.
  • Non-PowerShell GUI applications on Windows retain the existing behavior of receiving the target path as an argument.

Suggested test cases

The launcher should be verified with project paths containing:

C:\Projects\simple
C:\Projects\path with spaces
C:\Projects\owner's project
C:\Projects\中文项目
C:\Projects\100% complete
C:\Projects\research & development
C:\Projects\%TEMP%\demo

It should also be tested with:

  • a full powershell.exe path;
  • a bare powershell command;
  • PowerShell 7 pwsh.exe;
  • failure to create the Windows launcher process;
  • an invalid or deleted project directory.

Plugins

No response

OpenCode version

1.18.10

Steps to reproduce

  1. Open OpenCode Desktop on Windows.
  2. Open a project, for example C:\path\to\project.
  3. Select Open in PowerShell from the project picker or session header.
  4. Observe that OpenCode reports a CommandNotFoundException instead of opening a PowerShell window in the selected project directory.

Screenshot and/or share link

No response

Operating System

Windows 11 x64

Terminal

Windows PowerShell 5.1

Activity

  1. github-actions commented on Aug 1, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of an existing issue. Please check:

    The two issues describe identical root cause, error messages, and affect the same version (1.18.10).

  2. hokonoko commented on Sep 2, 2026

    @hokonoko

    Opened a PR for this: #46712 — implements your suggested direction with cmd.exe /d /c start plus a UTF-16LE Base64 -EncodedCommand (so the path bypasses both CMD and PowerShell parsers, avoiding the %VAR% expansion concern you raised). Verified on Windows 11 with paths containing spaces, single quotes, % chars, and non-ASCII characters.

  3. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions