( runtime: Runtime, script: string, options: SpawnOptions )
| 115 | * @param options Spawn options |
| 116 | */ |
| 117 | export async function spawnProcess( |
| 118 | runtime: Runtime, |
| 119 | script: string, |
| 120 | options: SpawnOptions |
| 121 | ): Promise<SpawnResult> { |
| 122 | log.debug(`BackgroundProcessExecutor.spawnProcess: Spawning in ${options.cwd}`); |
| 123 | |
| 124 | // Get temp directory from runtime (absolute path, runtime-agnostic) |
| 125 | const tempDir = await runtime.tempDir(); |
| 126 | const bgOutputDir = `${tempDir}/${BG_OUTPUT_SUBDIR}`; |
| 127 | |
| 128 | // Use shell-safe quoting for paths (handles spaces, special chars) |
| 129 | const quotePath = quotePathForShell; |
| 130 | |
| 131 | // Verify working directory exists |
| 132 | const cwdCheck = await execBuffered(runtime, `cd ${quotePath(options.cwd)}`, { |
| 133 | cwd: FALLBACK_CWD, |
| 134 | timeout: 10, |
| 135 | }); |
| 136 | if (cwdCheck.exitCode !== 0) { |
| 137 | return { success: false, error: `Working directory does not exist: ${options.cwd}` }; |
| 138 | } |
| 139 | |
| 140 | // Compute output paths (unified output.log instead of separate stdout/stderr) |
| 141 | const { outputDir, outputPath, exitCodePath } = computeOutputPaths( |
| 142 | bgOutputDir, |
| 143 | options.workspaceId, |
| 144 | options.processId |
| 145 | ); |
| 146 | |
| 147 | // Create output directory and empty file |
| 148 | try { |
| 149 | await runtime.ensureDir(outputDir); |
| 150 | await writeFileString(runtime, outputPath, ""); |
| 151 | } catch (error) { |
| 152 | return { |
| 153 | success: false, |
| 154 | error: `Failed to create output directory: ${errorMsg(error)}`, |
| 155 | }; |
| 156 | } |
| 157 | |
| 158 | // Build wrapper script (same for all runtimes now that paths are absolute) |
| 159 | // Note: buildWrapperScript handles quoting internally via shellQuote |
| 160 | const wrapperScript = buildWrapperScript({ |
| 161 | exitCodePath, |
| 162 | cwd: options.cwd, |
| 163 | env: { ...options.env, ...NON_INTERACTIVE_ENV_VARS }, |
| 164 | script, |
| 165 | }); |
| 166 | |
| 167 | const spawnCommand = buildSpawnCommand({ |
| 168 | wrapperScript, |
| 169 | outputPath, |
| 170 | quotePath, |
| 171 | }); |
| 172 | |
| 173 | try { |
| 174 | // No timeout - the spawn command backgrounds the process and returns immediately |
no test coverage detected