Merge pull request #453 from nwparker/cloud/rst-flags-keep-permission

fix(cloud): RST-FLAGS Restart keeps the permission flag when default args are substituted (P1)
This commit is contained in:
Neil
2026-11-11 07:55:37 -08:00
committed by GitHub
3 changed files with 77 additions and 5 deletions
@@ -39,12 +39,22 @@ import {
} from '@/lib/orca-cloud/cloud-agent-restart-attempt'
import { selectReadyAccountRestartPtyIds } from './pane-account-restart-readiness'
import { runReadyPaneAccountRestarts } from './use-ready-pane-account-restarts'
import { resolveTuiAgentLaunchRawArgs } from '../../../../../shared/agent-launch/choices/tui-agent-launch-defaults'
const TAB = 'tab-1'
const LEAF = '11111111-1111-4111-8111-111111111111'
const PTY = 'env-1@@pty-1'
const PANE_KEY = makePaneKey(TAB, LEAF)
/** The terminal a resume ensure placed in the pane's leaf. */
/** RA-11d defaults as a fresh launch would project them now (configured args + permission choice). */
function projectedDefaults(): string {
return resolveTuiAgentLaunchRawArgs(
'claude',
useAppStore.getState().settings,
undefined,
'posix'
).trim()
}
const RESUMED = { handle: 'term_resumed', disposition: 'created' as const }
function seed(state: AgentStatusEntry['state']): void {
@@ -458,10 +468,12 @@ describe('RA-11 Restart on a paired (remote) pane', () => {
await vi.waitFor(() => expect(freshIfResumeFoundNothing).toHaveBeenCalledTimes(1))
expect(resumeRemotePane).toHaveBeenCalledWith(
expect.objectContaining({
launchConfig: { agentArgs: '--model opus --effort high', agentEnv: {} }
launchConfig: { agentArgs: projectedDefaults(), agentEnv: {} }
})
)
expect(buildFreshCommand).toHaveBeenCalledWith('claude', LEAF, '--model opus --effort high')
expect(buildFreshCommand).toHaveBeenCalledWith('claude', LEAF, projectedDefaults())
// RST-FLAGS: the substituted defaults keep the launch profile's permission flag.
expect(projectedDefaults()).toContain('--model opus --effort high')
})
function runWithRecorded(launchConfig: { agentArgs: string; agentEnv: Record<string, string> }) {
@@ -510,10 +522,10 @@ describe('RA-11 Restart on a paired (remote) pane', () => {
await vi.waitFor(() => expect(freshIfResumeFoundNothing).toHaveBeenCalledTimes(1))
expect(resumeRemotePane).toHaveBeenCalledWith(
expect.objectContaining({
launchConfig: { agentArgs: '--model opus --effort high', agentEnv: { ORCA_X: '1' } }
launchConfig: { agentArgs: projectedDefaults(), agentEnv: { ORCA_X: '1' } }
})
)
expect(buildFreshCommand).toHaveBeenCalledWith('claude', LEAF, '--model opus --effort high')
expect(buildFreshCommand).toHaveBeenCalledWith('claude', LEAF, projectedDefaults())
})
it('RA-11d: recorded launch args win over the defaults', async () => {
@@ -0,0 +1,48 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it } from 'vitest'
import { getDefaultSettings } from '../../../../shared/constants'
import { useAppStore } from '@/store'
import { defaultLaunchConfig } from './cloud-restart-launch-command'
function withSettings(patch: Record<string, unknown>): void {
const base = getDefaultSettings('/home/dev')
useAppStore.setState({ settings: { ...base, ...patch } })
}
describe('defaultLaunchConfig (RA-11d, RST-FLAGS)', () => {
afterEach(() => {
useAppStore.setState({ settings: getDefaultSettings('/home/dev') })
})
it('no default args set: nothing is sent, so the host projects its own launch profile', () => {
withSettings({})
expect(defaultLaunchConfig('claude')).toBeUndefined()
})
it('default args are projected like a fresh launch: the bypass permission is kept', () => {
withSettings({
agentDefaultArgs: {
...getDefaultSettings('/home/dev').agentDefaultArgs,
claude: '--model opus --effort high'
},
agentPermissionDefault: 'full-access'
})
const args = defaultLaunchConfig('claude')?.agentArgs ?? ''
expect(args).toContain('--dangerously-skip-permissions')
expect(args).toContain('--model opus')
expect(args).toContain('--effort high')
})
it('with permissions set to ask, no bypass flag is added', () => {
withSettings({
agentDefaultArgs: {
...getDefaultSettings('/home/dev').agentDefaultArgs,
claude: '--model opus --effort high'
},
agentPermissionDefault: 'ask'
})
const args = defaultLaunchConfig('claude')?.agentArgs ?? ''
expect(args).not.toContain('--dangerously-skip-permissions')
expect(args).toContain('--model opus')
})
})
@@ -2,13 +2,25 @@
// command can't be built.
import { useAppStore } from '@/store'
import { ORCA_CLOUD_SESSION_ENV_REFRESH } from './cloud-restart-session-env'
import { resolveTuiAgentLaunchRawArgs } from '../../../../shared/agent-launch/choices/tui-agent-launch-defaults'
import type { SleepingAgentLaunchConfig } from '../../../../shared/agent-session/lifecycle/agent-session-resume'
import type { AccountRestartAgent } from '@/store/terminals/terminal-contracts'
/**
* RA-11d: the launch args a pane with nothing recorded restarts with, when the person set default args. They
* go through the same launch-profile projection a fresh launch uses (configured Arguments plus the permission
* choice), so a Restart keeps e.g. `--dangerously-skip-permissions`; the host takes explicit agentArgs
* verbatim and only projects its own profile when none are sent (RST-FLAGS). No default args set: undefined,
* and the host's own projection applies as before. The host is a Linux sandbox, so posix quoting.
*/
export function defaultLaunchConfig(
agent: AccountRestartAgent
): SleepingAgentLaunchConfig | undefined {
const agentArgs = useAppStore.getState().settings?.agentDefaultArgs?.[agent]?.trim()
const settings = useAppStore.getState().settings
if (!settings?.agentDefaultArgs?.[agent]?.trim()) {
return undefined
}
const agentArgs = resolveTuiAgentLaunchRawArgs(agent, settings, undefined, 'posix').trim()
return agentArgs ? { agentArgs, agentEnv: {} } : undefined
}