Repository navigation
Stage long agent launch lines where they are typed, so they arrive whole (step 2 of 7) - #23962
Conversation
19e020e to
1245810
Compare
The host's agent.launch typed any launch prompt into the shell as part of the launch command. A long or multi-line prompt then ran line by line in the shell, and an agent that never showed readiness or crashed at startup had nothing guarding where its text went. agent.launch now carries a prompt on the typed line only when the line stays one line, control-free and at most 512 bytes; otherwise the agent starts clean and the host pastes the prompt once the agent's own ready signal fires (bracketed paste plus its composer marker or a quiet render, read only after the shell's last hand-off, never while the pane's own shell is proven in front), with main's draft-paste bytes and an Enter 50 ms later. Orchestration worker starts wait on tui-idle as before. A replay-safe launch admits and claims its ledger row in one write, Qwen Code gets a second Enter, the desktop and phone share one launch-refusal classifier, and hosts advertise agent.launch.prompt-carry.v1. Split out of #23748, which moves the desktop source-control buttons onto this path.
f564d7a to
5867ca6
Compare
…h launch line, as main did #24257 moved every multi-line or over-512-byte prompt off the typed launch line and pasted it after readiness. The phone's AI buttons and review notes, whose multi-line prompts main typed whole into zsh, then reached Claude 0.5-3 s later and their RPC reply waited for the paste. The host now names the shell a local macOS or Linux line is typed into, the way the spawn picks it, and a multi-line prompt rides a zsh line when every line is at most 512 bytes and the whole line at most 8 KB. A real-zsh test types such a line through Orca's own ready barrier and startup write, including when a slow user config makes the write land early. Elsewhere the measured unsafe cases keep the paste: bash 3.2 runs multi-line lines piecemeal, fish drops an early multi-line write, and any shell loses a line over 1 KB written early.
…unch-host-prompt-delivery # Conflicts: # src/main/runtime/tui-idle-evidence.ts
…dows lane's gate scan The Windows lane registration check read `const ZSH_PATH = process.platform === 'win32'` (the head of a multi-line ternary) as a Windows-true flag, so `describe.skipIf(!ZSH_PATH)` looked like a Windows-only suite. The file is POSIX-only; the zsh lookup is now a function.
… module Main's protocol-version.ts sits at the 300-line cap, so the prompt-carry capability pushed it over. The four agent.launch capabilities and their doc move to agent-launch-runtime-capability.ts, re-exported by name and spread into RUNTIME_CAPABILITIES at the same position; the advertised lists and every export are unchanged.
…wn module `export *` from protocol-version left the four names undefined under the mobile recording loader, which resolves a relative import through a Proxy with no own keys, so 37 phone recordings lost agent.launchReplay. Importers now name agent-launch-runtime-capability directly; protocol-version only spreads its list.
…unch-host-prompt-delivery
… local caller id Both were inert in step 1 and existed only for step 2. agent.launch will become a public plugin API, so every wire field is permanent once shipped; a top-level viewMode reads as "choose terminal vs chat", which the host decides. Step 2 introduces placement and view intent under a placement object instead.
…unch-host-prompt-delivery # Conflicts: # src/main/ipc/desktop-renderer-runtime-capabilities.test.ts
…unch-host-prompt-delivery
…es' hold anchor Main (#24375) moved Codex's provisional-header check into codex.json's provisional_startup hold anchor and deleted codex-terminal-readiness.ts, so the launch readiness hold now asks showsHoldAnchor, as main's own settled check does.
…and census the zsh fixture Main (#24375) answers a name-only title from each agent's rule file ahead of the sustained-title lane, so gemini.json's name_title settled a launch readiness wait on the shell's auto-title while Gemini was still booting. A launch now asks quiet of every weak idle verdict, as that lane did. Main's readiness census requires a recorder for every runtime fixture; the zsh prompt recording is a non-agent control. Gemini's synthetic baseline is regenerated for this PR's stated change: a bare gemini title is no longer its rest mark, so name-only rows settle weak, and a fresh working or blocked status is no longer overridden.
A launch line that is long or has several lines could lose lines or wedge a shell that is still starting, because it was typed into the terminal before the shell could read it whole. The terminal host (local daemon, and the SSH relay) now writes such a line to a script file and types one short line that runs it, for every POSIX shell; a shell that cannot read Orca's quoting runs Orca's own agent lines through /bin/sh. If the script cannot be written, the terminal says so. The SSH background launch path no longer types the line from the renderer; the relay stages it like any other terminal. Bumps the terminal daemon protocol to 40 (main took 39); a v39 daemon keeps its sessions and gets no staged line. Restacked onto #24257 from the version reviewed on top of #23748; carries none of #23748's changes.
1245810 to
55fd9fe
Compare
fish and ksh run the commands of a sourced file in the shell's own process group, so a staged agent was not a job: Ctrl-Z was dropped (a typed line stops), and the shell-in-front check saw the shell's group in the foreground while the agent ran. fish now runs the script with `eval (string collect < '<path>')`, which runs it as if typed and leaves the shell's job-control mode alone. ksh and mksh run a long Orca-built line through `/bin/sh '<path>'`, a real job; a long command the user wrote is typed as before. The real-shell test now asserts the agent's process group is its own and is the terminal's foreground group. The staging rule also reuses hasControlByte and the 512-byte budget from startup-line-prompt-carry so the carry and staging limits cannot drift.
… is proven in front A launch pasted its prompt unless a shell was proven in the terminal's foreground, so any read that could not prove one let the prompt through. After an agent exited at startup, its shell turned bracketed paste on at the next prompt, readiness fired on it, and the prompt was typed into the shell: - macOS: a pane runs its shell under login, so the process-group fence's root was never the shell's group and never proved it; the cached foreground name could also still name the exited process. - Windows Git Bash and WSL: the shell-alone-in-its-job check never answers. Now one fresh read of the terminal's foreground decides: agent, shell or unknown. Only 'agent' lets a write through (paste, Enter, second Enter, reused panes too); 'shell' still drops a ready signal. A Windows host never proves the agent, so there the launch line carries the prompt at any size, as on main.
A host that cannot prove the launched agent holds its terminal (a Windows host, a local WSL pane on one, SSH to Windows) refuses a paste, so the one carry rule keeps such a prompt on the line, as main typed it; Claude and Codex still take a launch file for a long or shell-damaged prompt. launchHostProvesAgentInFront moves to its own module, since the typed-line shell naming beside it is gone with #24257's typed-line check.
…unch-host-prompt-delivery
…unch-host-prompt-delivery Main's #24601 added a config-driven readiness lane (composerReadyCaptures, census-checked: zcode, opencode, opencode2) in the same module this branch adds. The lane table is now the one source of truth for which agents wait on their composer marker alone; DSH and Grok follow main's table (tui-idle lane), and waitForWorkerAgentReady routes a fresh worker through this branch's worker-start wait. Main's extracted startup builders now carry this branch's prompt carry: buildRuntimeAgentTerminalStartupOptions plans through planExecutionHostStartupWithPromptCandidate (OpenCode model prep, then the typed-line carry decision), and resolveWorktreeCreateAgentStartup threads onStartupPromptCarry.
…h's capabilities moved out of protocol-version The mobile web bundle check failed at 124 assets against a ceiling of 123. Main already sat exactly on that ceiling: its sweep table read 69 scripts at 16 routes while the tree builds 73, the whole margin of 4. This branch imports the agent.launch capabilities from their own module, so protocol-version is no longer pulled into the root layout and four other routes. That moves which routes share which modules, and the Qoder capability module, imported by protocol-version and the AI-vault resume path, no longer shares an importer set with anything, so it gets a chunk of its own: 74 scripts. The fence says to re-derive the bound rather than raise it, so the sweep is re-measured on this head (every prefix of the sorted route list). The worst route now adds 10 scripts (session), not 9, which moves the pinned shell crossing from 32 to 30 routes; main re-measured on its own lands on the same crossing.
Brings #24257's merge of main (e02adc5) through #23962. Main's refactors met this branch's carry rule in the startup builders, so the rule now runs inside them: - Terminal create and agent-session create plan through planExecutionHostLaunchPrompt: main's OpenCode one-time model preparation, then planLaunchPrompt, with the model's launch config on whichever plan launches. A draft keeps main's refusal of a model preference. - The flag-prompt branch uses main's extracted builder (OpenCode run's positional message and prompt env) with this branch's launch-file directory grant; followupPrompt is gone there too. - Worktree create keeps main's resolveWorktreeCreateAgentStartup, now awaiting the async builder. - The relay strips OpenCode's startup-prompt env and probes its plugin before writing the launch file; the local spawn creates jcode's runtime dir before it. - Daemon protocol v41 (launch file) keeps main's fish codex-function constant at v39. - The new-tab launcher keeps main's structured-chat-first route with this branch's launch host. - Main's new prompted-plan tests (Qoder, Qoder CN, DSH, OpenCode startup prompt and model) plan through planLaunchPrompt; this branch's new launcher tests carry main's requestId. - The agent-session startup plan, and the work-item prompt delivery, moved into their own functions so the merged files stay under the line cap.
Brings #24257's merge of main (e02adc5) through #23962 and #24080. - Worker start: a structured session or a brief that rode the launch line still waits only on the setup gate; any other worker waits through main's waitForWorkerAgentReady, which routes a fresh launch through #24257's worker-start wait and a reused terminal to plain tui-idle. - startupPromptPaste is threaded through main's resolveWorktreeCreateAgentStartup and its extracted terminal startup builder. - Main's worker agent preflight (configured agent params, the OpenCode model probe) moved into local-worker-agent-launch.ts so local-worker-start stays under the line cap.
…unch-host-prompt-delivery Brings main to 40f9e7a, which fixes main's own locale tests; no conflicts.
…t-on-command-line
…nd Grok's start answers on its composer A paired-server worker start whose agent exited at startup typed its brief into the server's shell, which ran it: the idle wait can settle on a shell back at its prompt, and the brief was written with no foreground read. Both worker-start paths now check before each brief write, as a launch prompt is checked: on a host that can find the agent in front it must be there; on one that cannot (Windows) a shell proven in front still refuses, and anything else writes as before. A Grok worker start waited ~10 s more than main: its only rest signal is its bare name, which a launch holds to quiet output, and Grok animates its logo for ten seconds after its composer glyph. A worker start for an agent whose rest signal is its bare name and whose composer draws a marker (Grok, DSH, mimo-code) now also answers on that marker, whichever comes first.
…nto brennanb2025/launch-prompt-on-command-line
…nto brennanb2025/launch-prompt-argv-carry The foreground read keeps this branch's four-way verdict, on the shared launched-agent host the worker brief check also reads.
…unch-host-prompt-delivery Brings main to e2da3a1, which fixes main's own localization coverage audit; no conflicts.
…t-on-command-line
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
📒 Files selected for processing (3)
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughThe change adds shared startup-command staging and uses it in daemon, local PTY, and relay delivery paths. Staged scripts are removed during cleanup, and staging failures produce terminal notices while the original command is delivered. SSH background launches now request provider command delivery and shell-ready startup delivery instead of using renderer-side marker and fallback handling. The daemon protocol and local-build compatibility contract advance to version 41. Priority: ➖ Normal Merge Risk: 🟡 Moderate · up to An SSH launch using fish may lose its startup command if the shell is slow to become ready. Confirm delivery or add a readiness gate before merging. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to Launch delivery now stores eligible commands in private temporary files. Restrictive permissions limit exposure, but a partially failed write can leave command text behind without normal cleanup. Remote startup timing and mixed-version operation remain only partly established. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 2📝 Generate docstrings 💡
🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…/launch-prompt-argv-carry
…rompt-on-command-line Main landed its own daemon protocol v40 (#25291), so staging moves to v41 with 40 attachable (the version file, the local build contract and the pinned tests). Main's #23672 submits startup commands with CR and drops the submit option: the daemon and relay keep the staged line under the new signature, and the staging tests expect the sourcing line to end in CR. The renderer SSH startup delivery file stays deleted; main's only change there removed the submit option.
There was a problem hiding this comment.
Important
The origin/main merge left several of this PR's own staging tests asserting the old LF terminator, so seven tests are red. Main's #23672 made buildStartupCommandSubmission submit with CR; the merge updated the pre-existing tests but not this PR's newly-added ones in terminal-host-startup-staging.test.ts, local-pty-provider-shell-readiness.test.ts, and daemon-pty-startup-delivery.test.ts. I reproduced all seven failures locally.
Reviewed changes
- Merged
origin/main(853545d6d8): main took daemon protocol v40 (#25291), so this PR's staging moves to v41 with v40 attachable (version file, local-build contract JSON + TS, pinned tests). - Adopted main's CR startup-command submission (#23672): dropped the
submitoption from the daemon and relaybuildStartupCommandSubmissioncalls; the relay now typesmanaged.stagedStartupCommand?.command ?? startup.command. - Updated the pre-existing staging assertions to CR (
terminal-host.test.ts,pty-handler-startup-command-*.test.ts, the older cases ofdaemon-pty-startup-delivery.test.ts,startup-command-staging.node-pty.test.ts).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
|
|
||
| it('types a short launch line and reports it typed', async () => { | ||
| const { sub, result } = await create(`claude 'fix it'`) | ||
| expect(sub.write).toHaveBeenCalledWith(`claude 'fix it'\n`) |
There was a problem hiding this comment.
Main's #23672 now submits startup commands with \r, but this PR-added file still asserts ; sub.write receives claude 'fix it'\r, so this test and the expectations at lines 72, 79 and 116 all fail. Update the four expectations to \r (and the regex at line 79 to /^\. '.*orca-launch-[0-9a-f]+\.sh'\r$/).
| ) | ||
| expect(staged?.[1]).toContain(`\n${command}\n`) | ||
| await vi.advanceTimersByTimeAsync(200) | ||
| expect(mockProc.write).toHaveBeenCalledWith(`. '${staged?.[0]}'\n`) |
There was a problem hiding this comment.
Same stale LF terminator: after #23672 mockProc.write gets . '<script>'\r, so this and line 263 fail. Change both to \r.
| await waitFor(() => vi.mocked(lastSubprocess.write).mock.calls.length > 0) | ||
| const [script] = readdirSync(stagingDir) | ||
| expect(lastSubprocess.write).toHaveBeenCalledExactlyOnceWith( | ||
| `. '${join(stagingDir, script)}'\n` |
There was a problem hiding this comment.
This new assertion expects , but the merged buildStartupCommandSubmission emits \r, so the write is . '<script>'\r and the test fails. Change to \r (matching the CR you already applied to this file's earlier expectations).
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.
🟡 Minor · Preserve the no-output grace for SSH startup. · launch-agent-background-session.ts:180-185
src/renderer/src/lib/launch-agent-background-session.ts:180-185
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve the no-output grace for SSH startup.
When the relay supports shell-ready markers but the shell stays silent and the prompt probe does not identify readiness, it submits the command after 1.5 seconds. The previous path allowed 15 seconds for a silent shell because startup can still be running. Sending bracketed paste before readline is ready can cause the background agent launch to fail. Keep the 15-second grace while the shell is silent, then shorten it after output arrives.
ℹ️ Review info
⚙️ Run configuration
- Configuration used: Repository UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
bd7a169f-d2c9-45b0-9188-0cb332d33a0c
📒 Files selected for processing (12)
src/main/daemon/daemon-foreground-confirmation-protocol.test.tssrc/main/daemon/daemon-protocol-version.test.tssrc/main/daemon/daemon-protocol-version.tssrc/main/daemon/daemon-pty-startup-delivery.test.tssrc/main/daemon/terminal-host-session-create.tssrc/main/daemon/terminal-host.test.tssrc/relay/pty-handler-startup-command-staging.test.tssrc/relay/pty-handler.tssrc/renderer/src/lib/ssh-background-startup-delivery.tssrc/shared/local-build-compatibility-contract.jsonsrc/shared/local-build-compatibility-contract.tssrc/shared/startup-command-staging.node-pty.test.ts
💤 Files with no reviewable changes (1)
- src/renderer/src/lib/ssh-background-startup-delivery.ts
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.
| staging = stageStartupCommand({ | ||
| command: opts.command, | ||
| shellPath: subprocess.shellPath, | ||
| orcaBuiltLine: opts.launchAgent !== undefined | ||
| }) |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Stage before new Session(...), or discard the script when the session has already exited.
The exit closure at Line 167 reads staging before the assignment at Line 208 runs. If the shell exits before the listener is attached, the pre-listener exit replays synchronously and discards undefined. The code then writes the staged script, and session.write does nothing. No later step deletes the script, which contains the prompt.
After staging, check session.isAlive. If the session has exited, call discardStagedStartupCommand(staging).
…ch-prompt-argv-carry Conflicts resolved against #23962's head this branch had merged (83de487), so each keeps main's squashed #23962 plus this branch's change: - daemon protocol v42 (launch files), v41 (#23962's staged startup lines) now in PREVIOUS; build compatibility contract and pinned version tests follow. - agent-draft-readiness keeps main's OpenCode agent-row grace (#25101) and this branch's bracketed-paste-off revocation of the quiet window. - startup-line-prompt-carry.test.ts stays deleted; its rule lives in launch-prompt-carry. Semantic follow-ups from #23672 (CR submission, one-line PowerShell quoting): - windowsLaunchLineVerdict reads line breaks from the prompt too: PowerShell now quotes a multi-line prompt onto one physical line, which hid the measured multi-line rows (a 9 KB multi-line prompt read as exact) and the shim's line-break cut. - Typed launch lines end in CR; raw multi-line lines submit each break with CR; the PowerShell multi-line expectations use the one-line backtick form. - A duplicated pair of #23962 staging tests left by the auto-merge is removed. - agent-paste-draft: the two identical launch-paste tails share sendLaunchPaste; tui-agent-config writes devin on one line like jcode (main sat at the line cap).
… message carries (#24488) * fix(quick-commands): save agent prompts whole, bounded by what a chat message carries Agent quick-command prompts were silently cut to 6,000 characters on save: the editor accepted a long paste, settings normalization trimmed it, and reopening showed the shortened copy. The 6,000 was a Windows launch speed threshold, not a limit on prompts. - Storage no longer trims. A save is refused, never trimmed, when a prompt's chat text block is over 256 KiB of JSON (measured on its real escaped size, the measure the chat send schema applies) or the list is too large for one paired reply. Host and desktop store both check before writing. - The editor shows the size against the limit and blocks Save past it, and stays open with the text when the host refuses the save. - terminal.quick-commands.long-prompts.v1: hosts withhold prompts over 6,000 characters from clients that do not advertise it (older clients reject a whole list holding one); editors keep an older host's 6,000 cap. - The phone editor no longer drops pasted text past 6,000 via maxLength. Launch delivery of long prompts is left to the launch-prompt series (#24257, #23962, #24080); this branch's earlier paste-after-ready delivery duplicated it and is removed. * fix(quick-commands): drop a stale duplicate doc comment * fix(quick-commands): advertise long prompts to this build's own host too * fix(quick-commands): keep submitted editor immutable until save settles * test(quick-commands): keep storage and save lifecycle coverage focused * fix(quick-commands): keep portalled choices within pending form ownership * Preserve retained credentials when settings validation refuses a save --------- Co-authored-by: OrcaWin <alpha-eng@stably.ai>

The problem
When Orca starts an agent, it types the agent's launch line into a shell that is often still starting.
A long or multi-line launch line breaks there: lines go missing, the shell sits at a
quote>prompt, or the agent starts with half its text.Why: macOS keeps at most 1,024 bytes of a line typed into a terminal that is still starting, and a newline inside the line is read as Enter, so bash 3.2 runs each line of a multi-line prompt as its own command and fish drops an early multi-line write.
Today Orca avoids this only by keeping long or multi-line prompts off the launch line (#24257 pastes them once the agent is ready), so any launch line that still gets long or multi-line (a resume line, an SSH background launch, a terminal created with a long command, a multi-line zsh prompt up to 8 KB) is typed raw and can be cut or run in pieces.
Before and after, for the agent
What the agent receives does not change. The agent gets the same command and the same prompt text as before; nothing is added to or removed from the prompt. What changes is how that command reaches the shell, and only when the command is long or multi-line.
Before: Orca typed the whole launch command into the terminal, often while the shell was still starting. A multi-line prompt's newlines were read as Enter (bash 3.2 ran each line as its own shell command), and a line over ~1,024 bytes typed into a still-starting macOS terminal lost the rest. So the agent started with half its prompt, or never started and the shell sat at a
quote>prompt.After: Orca writes the exact same command into a private, self-deleting script (mode 0600) and types one short line that runs it, e.g.
. '/…/orca-launch-a1b2.sh'. The shell runs exactly the bytes Orca meant to type, so the agent starts with its full prompt.Unchanged: a launch command of 512 bytes or less with no newline or control character is typed exactly as today, so most launches look and behave the same.
What changes for you
A long or multi-line launch line on a macOS or Linux host (local, SSH, background) now reaches the agent whole, in bash, zsh, sh, dash, fish, ksh and mksh.
What you see in the terminal is one short line instead of the long one:
. '/…/orca-launch-<random>.sh'in bash, zsh, sh and dash,eval (string collect < '…')in fish, and/bin/sh '…'for Orca's own long agent lines in ksh and mksh. The agent runs as a normal foreground job, so Ctrl-Z and Ctrl-C behave as if the line had been typed.If Orca cannot write the launch script (disk full, unwritable temp dir), the terminal prints
[orca] Could not stage the launch command (...)and types the line as before, so you see why it may fail instead of a silentquote>prompt.In tcsh, nu and other shells whose quoting Orca does not speak, Orca's own agent launch line runs through
/bin/shwhen it is long, has a control character, or holds a character those shells do not read literally inside Orca's quoting (!, backslash,",$, backtick); a plain line is typed as before, and commands you wrote yourself are always typed exactly as before.Lines of 512 bytes or less with no control character are typed exactly as today.
Known limit: the shell's history holds the short line, and the script deletes itself when it runs, so pressing up-arrow and Enter does not relaunch the agent.
Scope
In scope: the places Orca types a startup line into a terminal on a macOS or Linux shell through the terminal daemon, the SSH relay or the in-process terminal provider, for local, SSH and background launches.
Not in scope:
The plan, and where this PR sits
This is step 2 of 7 of the agent launch plan:
agent.launch(supersedes feat(source-control): start the AI buttons' agents through agent.launch (step 2 of 2) #23748).How it works
. '<script>'in bash, zsh, sh and dash;eval (string collect < '<script>')in fish, because fish runs a sourced file without job control; and/bin/sh '<script>'for Orca's own long agent lines in ksh and mksh, because ksh runs a sourced file inside the shell's own process group. In tcsh, nu and other shells Orca's quoting does not cover, an Orca-built line also goes through/bin/shwhen it holds!, backslash,",$or a backtick, which those shells would not read literally.Why this approach
The decision is made where the bytes are written, by the host that owns the terminal, so one rule covers daemon, relay and in-process terminals instead of a check on every launch path.
A script the shell runs executes the exact bytes Orca quoted; no escaping trick survives every shell's line editor.
Alternatives considered: passing the agent line through an environment variable (Orca already does this for setup-sequenced startup, but for agent lines the value stays in the shell's environment, is inherited by every child, and needs shell-specific syntax to read) and making the agent the terminal's first process (it skips Orca's shell wrappers, setup sequencing and the "tab stays a shell" behaviour).
How this differs from the common pattern (comparison from the first architecture review of this change):
/bin/sh, and only when they need it; a user's command is never rewritten.How this differs from the previous version of this PR
The previous version sat on #23748 (desktop AI buttons); this version sits on #24257 and contains none of #23748's changes. The daemon protocol bump is 40 instead of 39, because main took 39.
Changed in this round's review:
eval, and ksh/mksh run Orca's long agent lines through/bin/sh; a new real-shell test checks that the agent gets its own process group in every shell./bin/sh, so the agent was sh's child; live on a loaded Mac, feat(agent-launch): keep long prompts off the launch line and paste them after readiness (step 1 of 7) #24257's paste guard then reported a pasted prompt as not delivered. A plain agent line is now typed directly there, so the agent is the shell's own job.agent.launch, and its check that finds an agent behind a wrapper such as/bin/sh).Size
23 files, +1,108/−688 against #24257's branch.
Testing
tc:node,tc:webandtc:clipass; oxlint andcheck:code-quality:changedare clean.Visual Proof
N/A: no UI changes; this only changes whether a long launch line arrives whole. Live QA evidence is in the status comment.
Notes
Author X handle: @BrennanKB5