mirror of
https://github.com/stablyai/orca.git
synced 2026-10-24 00:04:01 +00:00
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:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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' }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user