refactor(launch-file): drop the unused sensitive flag

The worker brief was its only producer, and #24081 now routes the brief through
the carry rule as ordinary text, so every launch file was minted with
sensitive: false. The flag, its wire field, its parse check and the skip in the
pane prompt cache are removed; nothing that crossed the wire was released.
This commit is contained in:
Brennan Benson
2026-10-02 04:41:18 -07:00
parent 5c5f3f62b0
commit 6bdfb960da
22 changed files with 47 additions and 81 deletions
@@ -120,7 +120,7 @@ export async function maybeAutoRenameBranchOnFirstWork(
const hookPrompt = event.prompt?.trim()
// Why the pointer: a launch that carried its prompt in a file names only that file here, which
// would name the branch after "read the task file". Its real prompt, when main kept it, names it
// instead; otherwise (a worker brief) a later prompt of the user's own can.
// instead; otherwise (no longer kept, as after a restart) a later prompt of the user's own can.
const shown = hookPrompt
? (deps.showLaunchPrompt?.(event.paneKey, hookPrompt) ?? hookPrompt).trim()
: undefined
@@ -8,14 +8,13 @@ const promptByPane = new Map<string, string>()
/**
* Keeps a launch file's prompt for the pane it launched: the agent's hook reports only the pointer
* to the file, and Orca shows the prompt instead (`launchPromptShownForPane`). A sensitive file (a
* worker brief with its capability) is never kept.
* to the file, and Orca shows the prompt instead (`launchPromptShownForPane`).
*/
export function rememberLaunchFilePrompt(
paneKey: string,
launchFile: LaunchFile | undefined
): void {
if (!launchFile || launchFile.sensitive) {
if (!launchFile) {
return
}
promptByPane.delete(paneKey)
@@ -11,7 +11,7 @@ describe('a status row whose agent reports its launch file’s pointer', () => {
// Why: the agent's own hook sees only the pointer sentence; every Orca reader of the row (status
// row, dashboard, phone) must see the prompt the user wrote.
it('shows the prompt the file carries', () => {
rememberLaunchFilePrompt(LAUNCHED, carryInLaunchFile('fix the flaky test', false).launchFile)
rememberLaunchFilePrompt(LAUNCHED, carryInLaunchFile('fix the flaky test').launchFile)
const server = new AgentHookServer()
server.ingestTerminalStatus({
paneKey: LAUNCHED,
@@ -23,17 +23,4 @@ describe('a status row whose agent reports its launch file’s pointer', () => {
expect.objectContaining({ paneKey: LAUNCHED, prompt: 'fix the flaky test' })
])
})
it('leaves a sensitive file’s pointer, whose content is never kept', () => {
const pane = makePaneKey('tab-sensitive', '66666666-6666-4666-8666-666666666666')
rememberLaunchFilePrompt(pane, carryInLaunchFile('token dcap_secret', true).launchFile)
const server = new AgentHookServer()
server.ingestTerminalStatus({
paneKey: pane,
tabId: 'tab-sensitive',
worktreeId: 'wt-1',
payload: { state: 'working', prompt: POINTER }
})
expect(server.getStatusSnapshot()).toEqual([expect.objectContaining({ prompt: POINTER })])
})
})
@@ -43,7 +43,7 @@ describe('a launch file sent to a terminal daemon', () => {
tokenPath,
protocolVersion: LAUNCH_FILE_DAEMON_PROTOCOL_VERSION - 1
})
const { prompt, launchFile } = carryInLaunchFile('the whole task', false)
const { prompt, launchFile } = carryInLaunchFile('the whole task')
try {
await legacy
.spawn({
@@ -66,7 +66,7 @@ describe('a launch file sent to a terminal daemon', () => {
it('is sent to the current daemon, which writes it', async () => {
const request = vi.spyOn(DaemonClient.prototype, 'request')
const { prompt, launchFile } = carryInLaunchFile('the whole task', false)
const { prompt, launchFile } = carryInLaunchFile('the whole task')
await adapter.spawn({
cols: 80,
rows: 24,
@@ -141,7 +141,7 @@ describe('DaemonPtyAdapter startup delivery', () => {
vi.stubEnv('TMPDIR', stagingDir)
nextShellPath = '/bin/zsh'
try {
const { prompt, launchFile } = carryInLaunchFile('secret brief', true)
const { prompt, launchFile } = carryInLaunchFile('secret brief')
await adapter.spawn({
cols: 80,
rows: 24,
@@ -33,7 +33,7 @@ describe('a daemon WSL session with a launch file', () => {
})
function create(wslLaunchDirectory: WslLaunchDirectory | undefined) {
const { prompt, launchFile } = carryInLaunchFile('secret brief', true)
const { prompt, launchFile } = carryInLaunchFile('secret brief')
return host.createOrAttach({
sessionId: 'wsl-session',
cols: 80,
@@ -8,8 +8,7 @@ import type { PtySpawnIpcArgs, PtySpawnIpcDeps } from './spawn-types'
const LAUNCH_FILE = {
placeholder: `orca-launch-file-${'a'.repeat(32)}`,
content: 'the whole task',
sensitive: false
content: 'the whole task'
}
async function spawnOptionsFor(
@@ -61,22 +60,12 @@ describe('renderer pty spawn: launch file', () => {
})
// Why: the agent's hook reports only the pointer; Orca shows the prompt it points at instead.
it('shows the prompt a launch file carries for its pane, never a sensitive one', async () => {
it('shows the prompt a launch file carries for its pane', async () => {
await spawnOptionsFor(
{ cols: 80, rows: 24, command, launchFile: LAUNCH_FILE },
command,
'tab-a:leaf-a'
)
await spawnOptionsFor(
{
cols: 80,
rows: 24,
command,
launchFile: { ...LAUNCH_FILE, content: 'dcap brief', sensitive: true }
},
command,
'tab-b:leaf-b'
)
const pointer = buildLaunchFilePointer('/tmp/orca-launch-file-a1/task-context.md')
expect(launchPromptShownForPane('tab-a:leaf-a', pointer)).toBe('the whole task')
expect(launchPromptShownForPane('tab-b:leaf-b', pointer)).toBe(pointer)
@@ -273,7 +273,7 @@ describe('LocalPtyProvider', () => {
vi.useFakeTimers()
try {
process.env.SHELL = '/bin/sh'
const { prompt, launchFile } = carryInLaunchFile('secret brief', true)
const { prompt, launchFile } = carryInLaunchFile('secret brief')
await provider.spawn({ cols: 80, rows: 24, command: `claude '${prompt}'`, launchFile })
@@ -149,7 +149,7 @@ describe('SshPlainShellPtyProvider', () => {
'(no_runtime)'
)
// Why: nothing here writes a launch file, so its line would name a file that is not there.
const { prompt, launchFile } = carryInLaunchFile('the whole task', false)
const { prompt, launchFile } = carryInLaunchFile('the whole task')
await expect(
provider.spawn({ cols: 80, rows: 24, command: `claude '${prompt}'`, launchFile })
).rejects.toThrow('needs the Orca remote server')
@@ -48,7 +48,7 @@ describe('resolveWslLaunchDirectory', () => {
})
// Why: files written over the UNC share take 9P's default mode, so only the directory's mode
// keeps a worker brief from the distro's other users.
// keeps a launch file's prompt from the distro's other users.
it('makes the cache directory private to the distro user before anything is written there', async () => {
runWslProcess.mockResolvedValue(answers('/home/ada\n/bin/bash\n'))
await resolveWslLaunchDirectory('Kali')
@@ -71,7 +71,7 @@ async function probeWslLaunchDirectory(distro: string): Promise<WslLaunchDirecto
...RESOLVE_WSL_LOGIN_SHELL,
`_orca_root="$HOME"/${quotePosixShell(ORCA_CACHE_RELATIVE)}`,
// Why chmod in the distro: files written over the UNC share take 9P's default mode, so the
// 0700 directory is what keeps a worker brief from other distro users.
// 0700 directory is what keeps a launch file's prompt from other distro users.
'mkdir -p "$_orca_root" && chmod 700 "$_orca_root" || exit 1',
`printf '%s\\n%s\\n' "$HOME" "$_orca_wsl_shell"`
].join('\n')
@@ -84,14 +84,14 @@ describe('a terminal create that is handed a launch prompt', () => {
await runtime.createTerminal('id:wt-1', { startupAgent: 'claude', startupPrompt: prompt })
const launchFile = spawn.mock.calls[0]?.[0]?.launchFile
expect(launchFile).toMatchObject({ content: prompt, sensitive: false, quoting: 'posix' })
expect(launchFile).toMatchObject({ content: prompt, quoting: 'posix' })
expect(spawnedCommand(spawn)).toContain(launchFile.placeholder)
expect(spawnedCommand(spawn)).not.toContain('xxxx')
})
it('tells the host how the line quoted a launch file its caller wrote', async () => {
const { runtime, spawn } = runtimeWithAgentLaunch()
const { prompt, launchFile } = carryInLaunchFile('worker brief', true)
const { prompt, launchFile } = carryInLaunchFile('worker brief')
await runtime.createTerminal('id:wt-1', {
startupAgent: 'claude',
@@ -114,7 +114,7 @@ describePosix('relay startup command staging', () => {
})
it('writes a launch file before typing the line that names it, and removes it on exit', async () => {
const { prompt, launchFile } = carryInLaunchFile('secret brief', true)
const { prompt, launchFile } = carryInLaunchFile('secret brief')
await dispatcher.callRequest('pty.spawn', {
command: `claude '${prompt}'`,
commandDelivery: 'provider',
@@ -857,7 +857,7 @@ describe('launchAgentInNewTab', () => {
const queued = mockQueueTabStartupCommand.mock.calls[0]?.[1]
// Handed back to copy if the host refuses to write the file.
expect(queued?.launchPrompt).toBe(prompt)
expect(queued?.launchFile).toMatchObject({ content: prompt, sensitive: false })
expect(queued?.launchFile).toMatchObject({ content: prompt })
expect(queued?.command).toContain(queued?.launchFile?.placeholder)
expect(queued?.command).not.toContain('xxxx')
})
@@ -12,7 +12,7 @@ import {
import type { TuiAgent } from './tui-agent'
function planWithLaunchFile(agent: TuiAgent, shell: 'posix' | 'cmd' | 'powershell' = 'posix') {
const { prompt, launchFile } = carryInLaunchFile('the brief', true)
const { prompt, launchFile } = carryInLaunchFile('the brief')
const plan = planLaunchForTest({
agent,
prompt,
+15 -16
View File
@@ -36,30 +36,29 @@ afterEach(() => {
describe('carryInLaunchFile', () => {
it('moves a prompt into a launch file and names it by a pointer', () => {
const prompt = 'b'.repeat(20_000)
const carried = carryInLaunchFile(prompt, false)
expect(carried.launchFile).toMatchObject({ content: prompt, sensitive: false })
const carried = carryInLaunchFile(prompt)
expect(carried.launchFile).toMatchObject({ content: prompt })
expect(carried.prompt).toBe(buildLaunchFilePointer(carried.launchFile.placeholder))
})
it('keeps a sensitive prompt off the pointer', () => {
const carried = carryInLaunchFile('token dcap_secret', true)
expect(carried.prompt).not.toContain('dcap_secret')
expect(carried.launchFile).toMatchObject({ content: 'token dcap_secret', sensitive: true })
it('keeps the prompt off the pointer', () => {
const carried = carryInLaunchFile('fix the flaky test')
expect(carried.prompt).not.toContain('flaky')
})
it('mints a fresh placeholder each time', () => {
const first = carryInLaunchFile('x', true).launchFile.placeholder
const second = carryInLaunchFile('x', true).launchFile.placeholder
const first = carryInLaunchFile('x').launchFile.placeholder
const second = carryInLaunchFile('x').launchFile.placeholder
expect(first).not.toBe(second)
})
})
describe('parseLaunchFile', () => {
it('accepts what carryInLaunchFile mints and rejects anything else', () => {
const { launchFile } = carryInLaunchFile('x', true)
const { launchFile } = carryInLaunchFile('x')
expect(parseLaunchFile(launchFile)).toEqual(launchFile)
expect(parseLaunchFile({ ...launchFile, placeholder: 'HOME' })).toBeUndefined()
expect(parseLaunchFile({ ...launchFile, sensitive: 'yes' })).toBeUndefined()
expect(parseLaunchFile({ ...launchFile, content: 7 })).toBeUndefined()
expect(parseLaunchFile({ ...launchFile, quoting: 'cmd' })).toEqual({
...launchFile,
quoting: 'cmd'
@@ -71,7 +70,7 @@ describe('parseLaunchFile', () => {
describe('writeLaunchFile', () => {
it('writes a 0600 file in a private 0700 directory and puts its path in the line and env', () => {
const { prompt, launchFile } = carryInLaunchFile('c'.repeat(20_000), false)
const { prompt, launchFile } = carryInLaunchFile('c'.repeat(20_000))
const written = writeLaunchFile({
launchFile: launchFile!,
command: `claude '${prompt}'`,
@@ -92,7 +91,7 @@ describe('writeLaunchFile', () => {
it("refuses an apostrophe in the path when the line's quoting is unknown, leaving nothing behind", () => {
const quoted = join(baseDirectory, "it's")
mkdirSync(quoted)
const { launchFile } = carryInLaunchFile('x', true)
const { launchFile } = carryInLaunchFile('x')
expect(() => writeLaunchFile({ launchFile: launchFile!, baseDirectory: quoted })).toThrow(
LaunchFileUnavailableError
)
@@ -100,7 +99,7 @@ describe('writeLaunchFile', () => {
})
it('refuses when the temp directory cannot be written', () => {
const { launchFile } = carryInLaunchFile('x', true)
const { launchFile } = carryInLaunchFile('x')
expect(() =>
writeLaunchFile({ launchFile: launchFile!, baseDirectory: join(baseDirectory, 'missing') })
).toThrow(
@@ -109,7 +108,7 @@ describe('writeLaunchFile', () => {
})
it('removes the whole directory', () => {
const { launchFile } = carryInLaunchFile('x', true)
const { launchFile } = carryInLaunchFile('x')
const written = writeLaunchFile({ launchFile: launchFile!, baseDirectory })
removeLaunchFile(written)
expect(existsSync(written.directory)).toBe(false)
@@ -168,7 +167,7 @@ describePosix('a launch line naming a file under an unusual home directory', ()
async (user) => {
const home = join(baseDirectory, user)
mkdirSync(home)
const { prompt, launchFile } = carryInLaunchFile('brief', true)
const { prompt, launchFile } = carryInLaunchFile('brief')
const written = writeLaunchFile({
launchFile: { ...launchFile!, quoting: 'posix' },
command: `printf '%s' ${quoteStartupArg(prompt, 'posix')}`,
@@ -234,7 +233,7 @@ describe('sweepStaleLaunchFiles', () => {
})
it('names the owning process in each folder it writes', () => {
const { launchFile } = carryInLaunchFile('x', true)
const { launchFile } = carryInLaunchFile('x')
const written = writeLaunchFile({
launchFile: { ...launchFile, quoting: 'posix' },
baseDirectory
+2 -2
View File
@@ -63,7 +63,7 @@ describe('where a launch prompt rides', () => {
if (planned?.carry !== 'launch-file') {
throw new Error(`expected a launch file, got ${planned?.carry}`)
}
expect(planned.launchFile).toMatchObject({ content: prompt, sensitive: false })
expect(planned.launchFile).toMatchObject({ content: prompt })
expect(planned.plan.launchCommand).toContain(planned.launchFile.placeholder)
expect(planned.plan.launchCommand).not.toContain('yyyy')
}
@@ -95,7 +95,7 @@ describe('where a launch prompt rides', () => {
})
it('names a launch file its caller wrote, quoted for the line', () => {
const { prompt, launchFile } = carryInLaunchFile('worker brief', true)
const { prompt, launchFile } = carryInLaunchFile('worker brief')
const planned = plan('claude', prompt, { launchFile })
expect(planned).toMatchObject({
carry: 'launch-file',
+1 -1
View File
@@ -163,7 +163,7 @@ export function carryLaunchPrompt<A extends CarriedPlanArgs, P extends { launchC
if (!args.host.takesLaunchFile || !agentReadsLaunchFile(args.agent)) {
return lineOrPaste()
}
const pointer = carryInLaunchFile(text, false)
const pointer = carryInLaunchFile(text)
const plan = buildLine({ ...args, prompt: pointer.prompt, launchFile: pointer.launchFile })
return (
plan && { carry: 'launch-file', plan, launchFile: withQuoting(pointer.launchFile, shell) }
+7 -15
View File
@@ -1,7 +1,6 @@
/**
* A launch prompt too long for a command line, or carrying a secret, rides in a
* file the execution host writes; the command line carries only a sentence
* pointing at it.
* A launch prompt its command line cannot carry rides in a file the execution host writes; the
* command line carries only a sentence pointing at it.
*/
import type { AgentStartupShell } from './tui-agent-startup-shell'
@@ -15,8 +14,6 @@ export type LaunchFile = {
/** Stands in for the file's path in the command and env until the host substitutes it. */
placeholder: string
content: string
/** Set by the caller that minted a secret in `content`; keeps it out of argv and shell history. */
sensitive: boolean
/** How the launch line quoted the placeholder, set where the line is built; the host writes the
* path inside that quoting. Absent, the host accepts only a path every quoting carries as is. */
quoting?: AgentStartupShell
@@ -50,15 +47,12 @@ export function isLaunchFilePointer(prompt: string): boolean {
)
}
export function carryInLaunchFile(
content: string,
sensitive: boolean
): { prompt: string; launchFile: LaunchFile } {
export function carryInLaunchFile(content: string): { prompt: string; launchFile: LaunchFile } {
const bytes = crypto.getRandomValues(new Uint8Array(16))
const placeholder = `orca-launch-file-${Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')}`
return {
prompt: buildLaunchFilePointer(placeholder),
launchFile: { placeholder, content, sensitive }
launchFile: { placeholder, content }
}
}
@@ -68,24 +62,22 @@ export function parseLaunchFile(value: unknown): LaunchFile | undefined {
typeof value !== 'object' ||
value === null ||
!('placeholder' in value) ||
!('content' in value) ||
!('sensitive' in value)
!('content' in value)
) {
return undefined
}
const { placeholder, content, sensitive } = value
const { placeholder, content } = value
const quoting = 'quoting' in value ? value.quoting : undefined
const knownQuoting = LAUNCH_LINE_QUOTINGS.find((candidate) => candidate === quoting)
if (
typeof placeholder !== 'string' ||
!PLACEHOLDER_PATTERN.test(placeholder) ||
typeof content !== 'string' ||
typeof sensitive !== 'boolean' ||
(quoting !== undefined && knownQuoting === undefined)
) {
return undefined
}
return { placeholder, content, sensitive, ...(knownQuoting ? { quoting: knownQuoting } : {}) }
return { placeholder, content, ...(knownQuoting ? { quoting: knownQuoting } : {}) }
}
export const LAUNCH_FILE_UNAVAILABLE_CODE = 'launch_file_unavailable'
@@ -198,7 +198,7 @@ describeShells('a launch file named on a real command line', () => {
for (const shell of SHELLS) {
it(`hands ${shell.name}'s agent a pointer to the full prompt`, async () => {
const prompt = `${HOSTILE}\n${'z'.repeat(20_000)}\n`
const planned = carryInLaunchFile(prompt, false)
const planned = carryInLaunchFile(prompt)
let written: WrittenLaunchFile | undefined
const run = await launchInRealShell(shell, planned.prompt, (command) => {
written = writeLaunchFile({
+1 -1
View File
@@ -118,7 +118,7 @@ describe('tui agent startup plans', () => {
expect(plan?.launchCommand).not.toMatch(/[\r\n]/)
expect(plan?.launchCommand).not.toContain('PWNED')
expect(plan?.launchFile).toMatchObject({ content: prompt, sensitive: false })
expect(plan?.launchFile).toMatchObject({ content: prompt })
expect(plan?.launchCommand).toContain(plan?.launchFile?.placeholder)
}
)
+1 -1
View File
@@ -21,7 +21,7 @@ afterEach(() => {
})
function launchFile(content = 'fix the build'): LaunchFile {
const planned = carryInLaunchFile(content, true)
const planned = carryInLaunchFile(content)
return { ...planned.launchFile!, quoting: 'posix' }
}