Files
orca/src/main/shell-wrapper-file-writer.ts
T
OrcaWinandOrca Worker 58d1ff3b6a Provide the Orca CLI automatically in managed WSL terminals (#22761)
* Provide the Orca CLI automatically in managed WSL terminals

* Simplify managed WSL CLI provisioning

Never block a shell on CLI availability, keep the shared WSL login-shell
builder unchanged, provision from PTY env assembly only, drop the error
variable and command probing, and reuse the existing WSLENV helper.

* Scope the managed WSL CLI to WSL terminals

Provision only for WSL panes and publish the directory through
addOrcaWslInteropEnv, so daemon terminals keep inherited WSLENV entries and
non-WSL builds never see the variable. Write the bridge with a UTF-8 BOM so
Windows PowerShell 5.1 keeps non-ASCII user-data paths, give the dev bridge the
dev launcher's app-launch env, and drop the unused skill-setup wiring and
runtime capability.

* Tighten the managed WSL CLI bridge and setup

Launch the bridge child exactly like the registered bridge (no hidden
window or output relay; verified through WSL with Node and Electron), give
the dev bridge the dev launcher's NODE_OPTIONS stash, clear the guest-only
directory before starting Windows processes, collapse setup into one
function, warn once, and guard WSL env routing with tests.

* Harden managed WSL CLI quoting and inheritance

PowerShell also ends single-quoted strings at typographic quotes, so a
user-data path such as O'Brien with a curly apostrophe broke the managed
bridge. Fix the shared quotePowerShellLiteral and reuse it. Drop an inherited
ORCA_WSL_CLI_DIR on the daemon path, remove the unreachable PATH dedupe, and
cover failed setup with a stale caller value.

* Cover the managed WSL CLI in zsh and on POSIX CI

Add a live zsh case that reaches a real prompt, a POSIX test that runs the
PATH restore snippet in bash and zsh under set -u, and a null result for
unwritable user data. Say what a failed write actually costs, and document
per-spawn write logging and older-daemon behaviour.

* Keep system bashrc out of the PATH restore test

CI runners make bash -c read /etc/bash.bashrc, which fails under set -u.

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-09-25 21:55:21 -07:00

46 lines
1.7 KiB
TypeScript

/**
* Writes a generated shell wrapper tree atomically, and says whether it worked.
*
* Why the boolean matters: the launch config points ZDOTDIR at the wrapper dir.
* If a write failed — read-only FS, full disk, EACCES — the old code still
* pointed ZDOTDIR at that dir, so zsh found no .zshrc there and the user
* silently lost their entire configuration. Callers use the result to fall back
* to an unwrapped shell instead.
*/
import { chmodSync, mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs'
import { dirname } from 'node:path'
export type ShellWrapperFile = readonly [path: string, content: string]
export function writeShellWrapperFiles(
files: readonly ShellWrapperFile[],
logPrefix: string,
consequence = 'Shell will launch unwrapped'
): boolean {
try {
for (const [path, content] of files) {
mkdirSync(dirname(path), { recursive: true })
// Why temp+rename: a shell reading the wrapper concurrently sees either
// the old file or the new one, never a truncated prefix of the new one.
const temporaryPath = `${path}.orca-tmp-${process.pid}`
try {
writeFileSync(temporaryPath, content, 'utf8')
chmodSync(temporaryPath, 0o644)
renameSync(temporaryPath, path)
} catch (error) {
rmSync(temporaryPath, { force: true })
throw error
}
}
return true
} catch (error) {
const errorMessage =
error instanceof Error
? `${error.message} (${(error as NodeJS.ErrnoException).code || 'unknown'})`
: String(error)
console.error(`${logPrefix} Failed to write shell wrapper files: ${errorMessage}`)
console.error(`${logPrefix} ${consequence}`)
return false
}
}