fix(launch): type a plain Orca agent line as is in tcsh and nu

In tcsh and nu, every Orca-built agent line ran through `/bin/sh '<script>'`,
so the agent was a child of sh in sh's process group. When the prompt was
pasted after the agent was ready, the paste guard read sh in front and, on a
loaded Mac, reported the prompt not delivered (4/4 live runs in tcsh).

Now only a line that needs it goes through `/bin/sh`: one over 512 bytes, with
a control byte, or with a character those shells would not read literally
(`!`, backslash, `"`, `$`, backtick). A plain line such as
`claude '--dangerously-skip-permissions'` is typed as on main, so the agent is
the shell's own job.
This commit is contained in:
Brennan Benson
2026-10-02 04:01:46 -07:00
parent ef629543bd
commit b865c7d07e
2 changed files with 43 additions and 13 deletions
@@ -146,6 +146,38 @@ describe('stageStartupCommand', () => {
}
)
// Why: behind `/bin/sh` the agent is not the shell's own job, and a pasted prompt waits on that.
it.each([['/bin/tcsh'], ['/usr/bin/nu'], [undefined]])(
'types a short plain Orca-built line as is for a shell that cannot source it (%s)',
(shellPath) => {
const command = `claude '--dangerously-skip-permissions' '--model' 'claude-opus-5-5[1m]'`
expect(
stageStartupCommand({
command,
shellPath,
orcaBuiltLine: true,
platform: 'darwin',
directory
})
).toEqual({ command, delivery: 'typed' })
expect(readdirSync(directory)).toEqual([])
}
)
it.each([[`claude 'it'\\''s'`], ['claude "x"'], ["claude '$HOME'"], ["claude 'a`b'"]])(
'stages a short Orca-built line tcsh would not read literally: %s',
(command) => {
const staged = stageStartupCommand({
command,
shellPath: '/bin/tcsh',
orcaBuiltLine: true,
platform: 'darwin',
directory
})
expect(staged.command).toBe(`/bin/sh '${staged.scriptPath}'`)
}
)
it('types a short Orca-built line in a shell that reads its quoting literally', () => {
const command = `claude 'wow!! great'`
expect(
+11 -13
View File
@@ -32,9 +32,9 @@ export type StartupCommandStaging = {
failure?: string
}
// Why only these type a short line as is: Orca's portable quoting is verified literal in these. Any
// other shell (tcsh, nu, xonsh, pwsh...) runs an agent launch line Orca built through `/bin/sh`
// instead; a command the user wrote for that shell is typed as it always was.
// Why only these type any short line as is: Orca's portable quoting is verified literal in these. Any
// other shell (tcsh, nu, xonsh, pwsh...) runs an agent launch line Orca built through `/bin/sh` when
// it holds anything but plain characters; a command the user wrote for that shell is typed as it was.
const STAGING_SHELLS = new Set(['bash', 'zsh', 'sh', 'dash', 'fish', 'ksh', 'mksh'])
// Why not ksh: it runs a sourced file's commands in the shell's own process group, so Ctrl-Z could
@@ -63,17 +63,15 @@ export function shouldStageStartupCommand(args: {
return false
}
const shellName = stagingShellName(args.shellPath)
if (shellName === null) {
// Why every length: Orca's POSIX quoting is literal only in the shells above (tcsh doubles a
// quoted backslash and expands `!!`), so another shell only ever sees the script's inert path.
return args.orcaBuiltLine === true
}
const body = stripSubmitTerminator(args.command)
return (
(hasControlByte(body) ||
encoder.encode(body).byteLength > TYPED_STARTUP_LINE_PROMPT_BUDGET_BYTES) &&
(SOURCING_SHELLS.has(shellName) || args.orcaBuiltLine === true)
)
const needsStaging =
hasControlByte(body) || encoder.encode(body).byteLength > TYPED_STARTUP_LINE_PROMPT_BUDGET_BYTES
if (shellName === null) {
// Why these characters: tcsh doubles a quoted backslash and expands `!!`, and nu cannot read
// `'\''`. A plain line is typed so the agent is the shell's own job, where the paste guard finds it.
return args.orcaBuiltLine === true && (needsStaging || /[!\\"`$]/.test(body))
}
return needsStaging && (SOURCING_SHELLS.has(shellName) || args.orcaBuiltLine === true)
}
function stagedScriptLine(shellName: string | null, quotedPath: string): string {