fix(windows): mark PowerShell startup command boundaries with OSC 133 C/D (#18182)

A startup command embedded in the PowerShell -EncodedCommand payload runs
before the first prompt, and the prompt wrapper suppresses 133;D until it
has printed once. An agent launched this way exited with no
command-finished boundary, so its pane was never retired.

Emit 133;C before the embedded startup command and prime the prompt latch
so the first prompt reports 133;D with the exit code. Stdin-typed startup
commands keep readline's own marks. The encoded-command budget grows by
the mark's size so real commands keep the prior limit.

Co-authored-by: Neil <4138956+nwparker@users.noreply.github.com>
This commit is contained in:
hwantage
2026-10-26 05:14:19 -07:00
committed by GitHub
co-authored by Neil
parent 90493a9879
commit 1187abdbc2
4 changed files with 20 additions and 7 deletions
+5
View File
@@ -93,6 +93,11 @@ export function getPowerShellOsc133Bootstrap(): string {
return POWERSHELL_OSC133_BOOTSTRAP_PAYLOAD
}
// Startup commands run before the first prompt, which suppresses 133;D; mark them like typed commands.
export function getPowerShellOsc133StartupCommandMark(): string {
return 'if (Test-Path variable:global:__OrcaOsc133State) { [Console]::Write("$([char]27)]133;C$([char]7)"); $Global:__OrcaOsc133State.HasSeenPrompt = $true }'
}
export function isPowerShellExecutableName(shellName: string): boolean {
const normalized = shellName.toLowerCase()
return (
@@ -9,6 +9,7 @@ import { resolveWindowsShellLaunchArgs } from './windows-shell-args'
import { getShellReadyWrapperRoot } from './local-pty-shell-ready-wrapper-root'
const CODEX_LAUNCH_PREFLIGHT = 'C:\\Program Files\\Orca\\orca.exe'
const POWERSHELL_STARTUP_COMMAND_C_MARK = '[Console]::Write("$([char]27)]133;C$([char]7)")'
const CMD_CODEX_LAUNCH_PREFLIGHT =
'if defined ORCA_CODEX_LAUNCH_PREFLIGHT call %ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE%%ORCA_CODEX_LAUNCH_PREFLIGHT%%ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE% agent hooks prepare-codex > nul 2>&1'
@@ -200,6 +201,10 @@ describe('resolveWindowsShellLaunchArgs', () => {
expect(command).toContain('function Global:prompt')
expect(command).toContain(expectedPowerShellRestoreCwdCommand("'C:\\Users\\alice'"))
expect(command.trimEnd().endsWith("& 'codex' '--no-alt-screen'")).toBe(true)
// Without the mark, the first prompt after the agent exits withholds 133;D (#18180).
expect(command).toContain(
`${POWERSHELL_STARTUP_COMMAND_C_MARK}; $Global:__OrcaOsc133State.HasSeenPrompt = $true }\n& 'codex' '--no-alt-screen'`
)
})
it('preserves complex PowerShell startup command text through EncodedCommand', () => {
@@ -230,9 +235,10 @@ describe('resolveWindowsShellLaunchArgs', () => {
expect(result.startupCommandDeliveredInShellArgs).toBeUndefined()
expect(result.shellArgs).toEqual(['-NoLogo', '-NoExit', '-EncodedCommand', expect.any(String)])
expect(decodePowerShellCommand(result)).toContain(
expectedPowerShellRestoreCwdCommand("'C:\\Users\\alice'")
)
const command = decodePowerShellCommand(result)
expect(command).toContain(expectedPowerShellRestoreCwdCommand("'C:\\Users\\alice'"))
// Stdin-typed commands get readline's 133;C; an early latch would emit a false 133;D.
expect(command).not.toContain(POWERSHELL_STARTUP_COMMAND_C_MARK)
})
it('handles pwsh.exe (PowerShell Core) the same as Windows PowerShell', () => {
+5 -3
View File
@@ -10,14 +10,16 @@ import { getBashWrapperLaunchArgs } from './local-pty-shell-ready'
import { ensureShellReadyWrappersAt } from './local-pty-shell-ready-wrapper-generation'
import {
encodePowerShellCommand,
getPowerShellOsc133Bootstrap
getPowerShellOsc133Bootstrap,
getPowerShellOsc133StartupCommandMark
} from '../powershell-osc133-bootstrap'
import { quoteStartupArg } from '../../shared/tui-agent-startup-shell'
/** cmd.exe's own documented ceiling; callers that go through sshd budget below it. */
export const CMD_EXE_COMMAND_LINE_MAX_CHARS = 8191
const STARTUP_COMMAND_TEXT_MAX_CHARS = 6000
const POWERSHELL_ENCODED_COMMAND_ARG_MAX_CHARS = 28_000
// Includes ~400 encoded chars for the startup command mark so real commands keep the prior budget.
const POWERSHELL_ENCODED_COMMAND_ARG_MAX_CHARS = 28_400
const CMD_UTF8_SETUP_COMMAND = 'chcp 65001 > nul'
export const ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE_ENV = 'ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE'
const CMD_CODEX_LAUNCH_PREFLIGHT = `if defined ORCA_CODEX_LAUNCH_PREFLIGHT call %${ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE_ENV}%%ORCA_CODEX_LAUNCH_PREFLIGHT%%${ORCA_CODEX_LAUNCH_PREFLIGHT_CMD_QUOTE_ENV}% agent hooks prepare-codex > nul 2>&1`
@@ -88,7 +90,7 @@ function getPowerShellEncodedCommand(
return { encodedCommand: encodePowerShellCommand(bootstrap) }
}
const command = `${bootstrap}\n${startupCommand}`
const command = `${bootstrap}\n${getPowerShellOsc133StartupCommandMark()}\n${startupCommand}`
const encodedCommand = encodePowerShellCommand(command)
// UTF-16/base64 expands payloads; leave margin under CreateProcess 32,767-character limit.
if (encodedCommand.length > POWERSHELL_ENCODED_COMMAND_ARG_MAX_CHARS) {
+1 -1
View File
@@ -52,7 +52,7 @@ export function observeTerminalCommandPaint(
record.commandPaint.observe(data, normalizedText)
}
/** Without markers (older fish, relay zsh, unwrapped shells, Windows command args), any output is the only paint evidence. */
/** Without markers (older fish, relay zsh, unwrapped shells, cmd.exe /K startup args), any output is the only paint evidence. */
export function hasTerminalCommandPainted(record: TerminalCommandPaintRecord): boolean {
return record.commandPaint?.hasPainted() ?? true
}