()
| 182 | } |
| 183 | |
| 184 | function ensureWindowsCliOnPath(): Promise<'updated' | 'already-present'> { |
| 185 | return new Promise((resolve, reject) => { |
| 186 | const cliWrapper = getPackagedCliWrapperPath(); |
| 187 | if (!cliWrapper) { |
| 188 | reject(new Error('CLI wrapper not found in app resources.')); |
| 189 | return; |
| 190 | } |
| 191 | |
| 192 | const cliDir = dirname(cliWrapper); |
| 193 | const helperPath = join(cliDir, 'update-user-path.ps1'); |
| 194 | if (!existsSync(helperPath)) { |
| 195 | reject(new Error(`PATH helper not found at ${helperPath}`)); |
| 196 | return; |
| 197 | } |
| 198 | |
| 199 | const child = spawn( |
| 200 | getWindowsPowerShellPath(), |
| 201 | [ |
| 202 | '-NoProfile', |
| 203 | '-NonInteractive', |
| 204 | '-ExecutionPolicy', |
| 205 | 'Bypass', |
| 206 | '-File', |
| 207 | helperPath, |
| 208 | '-Action', |
| 209 | 'add', |
| 210 | '-CliDir', |
| 211 | cliDir, |
| 212 | ], |
| 213 | { |
| 214 | env: process.env, |
| 215 | stdio: ['ignore', 'pipe', 'pipe'], |
| 216 | windowsHide: true, |
| 217 | }, |
| 218 | ); |
| 219 | |
| 220 | let stdout = ''; |
| 221 | let stderr = ''; |
| 222 | |
| 223 | child.stdout.on('data', (chunk) => { |
| 224 | stdout += chunk.toString(); |
| 225 | }); |
| 226 | |
| 227 | child.stderr.on('data', (chunk) => { |
| 228 | stderr += chunk.toString(); |
| 229 | }); |
| 230 | |
| 231 | child.on('error', reject); |
| 232 | child.on('close', (code) => { |
| 233 | if (code !== 0) { |
| 234 | reject(new Error(stderr.trim() || `PowerShell exited with code ${code}`)); |
| 235 | return; |
| 236 | } |
| 237 | |
| 238 | const status = stdout.trim(); |
| 239 | if (status === 'updated' || status === 'already-present') { |
| 240 | resolve(status); |
| 241 | return; |
no test coverage detected