mirror of
https://github.com/stablyai/orca.git
synced 2026-11-15 18:37:24 +00:00
* fix(serve): keep `orca serve` running while it probes the login shell
`orca serve` started from an interactive terminal stopped itself ("[1]+
Stopped") before printing its pairing link. orcad inherits the terminal
and probes the login shell with `$SHELL -ilc`; an interactive bash 5 or
zsh takes the terminal's foreground job, so orcad's next terminal access
raised SIGTTOU/SIGTTIN. Give both shell probes (login environment and
PATH) a POSIX session of their own so they never hold a controlling
terminal. Windows keeps attached spawns, where `detached` would open a
console.
Refs #38347
* fix(serve): end a detached shell probe with its owner and on timeout
A probe in its own session no longer receives the terminal's Ctrl+C or
hangup, so a hung rc could outlive `orca serve`. Kill the probe's process
group by its own pid when it times out and when its owner exits while it
still runs; orcad and Electron turn INT/TERM into an exit, so a Ctrl+C
reaches it that way. No signal listeners: one would replace Electron's
graceful signal quit. The timeout now also ends what the rc started, not
just the shell.
Refs #38347
51 lines
2.2 KiB
TypeScript
51 lines
2.2 KiB
TypeScript
import { delimiter, win32 as pathWin32 } from 'node:path'
|
|
import { resolveWindowsShellStartupFamily } from '../../shared/windows-terminal-shell'
|
|
|
|
export const SHELL_PATH_DELIMITER = '__ORCA_SHELL_PATH__'
|
|
|
|
/** Own session on POSIX so an `-i` probe can't take the launching terminal's foreground; Windows `detached` opens a console. */
|
|
export function shellProbeDetached(): boolean {
|
|
return process.platform !== 'win32'
|
|
}
|
|
|
|
/** Build the login PATH probe in the selected shell's native syntax. */
|
|
export function shellPathProbe(shell: string): {
|
|
args: string[]
|
|
pathDelimiter: string
|
|
detached: boolean
|
|
} {
|
|
return { ...shellPathProbeCommand(shell), detached: shellProbeDetached() }
|
|
}
|
|
|
|
function shellPathProbeCommand(shell: string): { args: string[]; pathDelimiter: string } {
|
|
if (process.platform !== 'win32') {
|
|
if (pathWin32.basename(shell).toLowerCase() === 'nu') {
|
|
// Nushell stores PATH as a list; POSIX quoting would print a literal.
|
|
const command = [
|
|
`print -n '${SHELL_PATH_DELIMITER}';`,
|
|
'print -n ($env.PATH | str join (char esep));',
|
|
`print -n '${SHELL_PATH_DELIMITER}'`
|
|
].join(' ')
|
|
// Retain interactive login flags for $nu.is-interactive rc behavior.
|
|
return { args: ['-ilc', command], pathDelimiter: delimiter }
|
|
}
|
|
const command =
|
|
`printf '%s' '${SHELL_PATH_DELIMITER}'; printf '%s' "$PATH"; ` +
|
|
`printf '%s' '${SHELL_PATH_DELIMITER}'`
|
|
return { args: ['-ilc', command], pathDelimiter: delimiter }
|
|
}
|
|
if (resolveWindowsShellStartupFamily(shell) === 'posix') {
|
|
// Native children cannot resolve Git Bash /c/... PATH entries.
|
|
const command =
|
|
`printf '%s' '${SHELL_PATH_DELIMITER}'; cygpath -wp "$PATH"; ` +
|
|
`printf '%s' '${SHELL_PATH_DELIMITER}'`
|
|
return { args: ['-ilc', command], pathDelimiter: ';' }
|
|
}
|
|
const command =
|
|
`[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false); ` +
|
|
`[Console]::Write('${SHELL_PATH_DELIMITER}'); [Console]::Write($env:Path); ` +
|
|
`[Console]::Write('${SHELL_PATH_DELIMITER}')`
|
|
// Load profiles to capture user configuration; do not pass NoProfile.
|
|
return { args: ['-NoLogo', '-Command', command], pathDelimiter: ';' }
|
|
}
|