MCPcopy Index your code
hub / github.com/codeaashu/claude-code / createPowerShellProvider

Function createPowerShellProvider

src/utils/shell/powershellProvider.ts:27–123  ·  view source on GitHub ↗
(shellPath: string)

Source from the content-addressed store, hash-verified

25}
26
27export function createPowerShellProvider(shellPath: string): ShellProvider {
28 let currentSandboxTmpDir: string | undefined
29
30 return {
31 type: 'powershell' as ShellProvider['type'],
32 shellPath,
33 detached: false,
34
35 async buildExecCommand(
36 command: string,
37 opts: {
38 id: number | string
39 sandboxTmpDir?: string
40 useSandbox: boolean
41 },
42 ): Promise<{ commandString: string; cwdFilePath: string }> {
43 // Stash sandboxTmpDir for getEnvironmentOverrides (mirrors bashProvider)
44 currentSandboxTmpDir = opts.useSandbox ? opts.sandboxTmpDir : undefined
45
46 // When sandboxed, tmpdir() is not writable — the sandbox only allows
47 // writes to sandboxTmpDir. Put the cwd tracking file there so the
48 // inner pwsh can actually write it. Only applies on Linux/macOS/WSL2;
49 // on Windows native, sandbox is never enabled so this branch is dead.
50 const cwdFilePath =
51 opts.useSandbox && opts.sandboxTmpDir
52 ? posixJoin(opts.sandboxTmpDir, `claude-pwd-ps-${opts.id}`)
53 : join(tmpdir(), `claude-pwd-ps-${opts.id}`)
54 const escapedCwdFilePath = cwdFilePath.replace(/'/g, "''")
55 // Exit-code capture: prefer $LASTEXITCODE when a native exe ran.
56 // On PS 5.1, a native command that writes to stderr while the stream
57 // is PS-redirected (e.g. `git push 2>&1`) sets $? = $false even when
58 // the exe returned exit 0 — so `if (!$?)` reports a false positive.
59 // $LASTEXITCODE is $null only when no native exe has run in the
60 // session; in that case fall back to $? for cmdlet-only pipelines.
61 // Tradeoff: `native-ok; cmdlet-fail` now returns 0 (was 1). Reverse
62 // is also true: `native-fail; cmdlet-ok` now returns the native
63 // exit code (was 0 — old logic only looked at $? which the trailing
64 // cmdlet set true). Both rarer than the git/npm/curl stderr case.
65 const cwdTracking = `\n; $_ec = if ($null -ne $LASTEXITCODE) { $LASTEXITCODE } elseif ($?) { 0 } else { 1 }\n; (Get-Location).Path | Out-File -FilePath '${escapedCwdFilePath}' -Encoding utf8 -NoNewline\n; exit $_ec`
66 const psCommand = command + cwdTracking
67
68 // Sandbox wraps the returned commandString as `<binShell> -c '<cmd>'` —
69 // hardcoded `-c`, no way to inject -NoProfile -NonInteractive. So for
70 // the sandbox path, build a command that itself invokes pwsh with the
71 // full flag set. Shell.ts passes /bin/sh as the sandbox binShell,
72 // producing: bwrap ... sh -c 'pwsh -NoProfile ... -EncodedCommand ...'.
73 // The non-sandbox path returns the bare PS command; getSpawnArgs() adds
74 // the flags via buildPowerShellArgs().
75 //
76 // -EncodedCommand (base64 UTF-16LE), not -Command: the sandbox runtime
77 // applies its OWN shellquote.quote() on top of whatever we build. Any
78 // string containing ' triggers double-quote mode which escapes ! as \! —
79 // POSIX sh preserves that literally, pwsh parse error. Base64 is
80 // [A-Za-z0-9+/=] — no chars that any quoting layer can corrupt.
81 // Review 2964609818.
82 //
83 // shellPath is POSIX-single-quoted so a space-containing install path
84 // (e.g. /opt/my tools/pwsh) survives the inner `/bin/sh -c` word-split.

Callers 1

Shell.tsFile · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected