File tree Expand file tree Collapse file tree 3 files changed +18
-5
lines changed
Expand file tree Collapse file tree 3 files changed +18
-5
lines changed Original file line number Diff line number Diff line change @@ -376,7 +376,8 @@ export abstract class LocalBaseRuntime implements Runtime {
376376 } ) ;
377377
378378 try {
379- using proc = execAsync ( spawnCommand ) ;
379+ // Use bash shell explicitly - spawnCommand uses POSIX commands (nohup, setsid)
380+ using proc = execAsync ( spawnCommand , { shell : getBashPath ( ) } ) ;
380381 const result = await proc . result ;
381382
382383 const pid = parseInt ( result . stdout . trim ( ) , 10 ) ;
Original file line number Diff line number Diff line change @@ -12,6 +12,7 @@ import type {
1212import { listLocalBranches } from "@/node/git" ;
1313import { checkInitHookExists } from "./initHook" ;
1414import { execAsync } from "@/node/utils/disposableExec" ;
15+ import { getBashPath } from "@/node/utils/main/bashPath" ;
1516import { getProjectName } from "@/node/utils/runtime/helpers" ;
1617import { getErrorMessage } from "@/common/utils/errors" ;
1718import { expandTilde } from "./tildeExpansion" ;
@@ -283,8 +284,8 @@ export class WorktreeRuntime extends LocalBaseRuntime {
283284 // Ignore prune errors - we'll still try rm -rf
284285 }
285286
286- // Force delete the directory
287- using rmProc = execAsync ( `rm -rf "${ deletedPath } "` ) ;
287+ // Force delete the directory (use bash shell for rm -rf on Windows)
288+ using rmProc = execAsync ( `rm -rf "${ deletedPath } "` , { shell : getBashPath ( ) } ) ;
288289 await rmProc . result ;
289290
290291 return { success : true , deletedPath } ;
Original file line number Diff line number Diff line change @@ -113,16 +113,27 @@ class DisposableExec implements Disposable {
113113 }
114114}
115115
116+ /**
117+ * Options for execAsync.
118+ */
119+ export interface ExecAsyncOptions {
120+ /** Shell to use for command execution. If not specified, uses system default (cmd.exe on Windows). */
121+ shell ?: string ;
122+ }
123+
116124/**
117125 * Execute command with automatic cleanup via `using` declaration.
118126 * Prevents zombie processes by ensuring child is reaped even on error.
119127 *
120128 * @example
121129 * using proc = execAsync("git status");
122130 * const { stdout } = await proc.result;
131+ *
132+ * // With explicit shell (needed for POSIX commands on Windows)
133+ * using proc = execAsync("nohup bash -c ...", { shell: getBashPath() });
123134 */
124- export function execAsync ( command : string ) : DisposableExec {
125- const child = exec ( command ) ;
135+ export function execAsync ( command : string , options ?: ExecAsyncOptions ) : DisposableExec {
136+ const child = exec ( command , { shell : options ?. shell } ) ;
126137 const promise = new Promise < { stdout : string ; stderr : string } > ( ( resolve , reject ) => {
127138 let stdout = "" ;
128139 let stderr = "" ;
You can’t perform that action at this time.
0 commit comments