mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 02:27:43 +00:00
fix(opencode): submit admitted native startup briefs without overwriting input (#24762)
* fix: wait for OpenCode worker composer before first dispatch Reuse captured composer readiness on local and paired execution hosts and revoke launching-shell paste anchors. Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> * feat(opencode): probe execution-host CLI capabilities * fix(opencode): select plugin default for execution host loader * fix(opencode): limit prompt prefill capability to verified release * feat(opencode): probe launch capabilities on the execution host * fix(opencode): select plugin loader for the launched host binary * fix(opencode): match WSL probe cwd and declared guest environment * fix(opencode): preserve launch environment deletion boundaries * wip(opencode): authorize native startup prompt intent at execution owner * fix(opencode): atomically replace status plugin entrypoints * fix(opencode): retain plugin permissions across restrictive umasks * test(opencode): resolve permission fixture from primary cwd * feat(opencode): install startup prompt plugin independently of status hooks * fix(opencode): wait for admitted startup intent and preserve failed-launch briefs * fix(opencode): unsubscribe hook settings during async host shutdown * STRICT launch CI contract correction * CAPS launch CI contract correction * INTENT launch CI contract correction * test: initialize Claude prompt state in output retention fixture * Wait for OpenCode location hydration in intent startup * Bind OpenCode startup readiness to the current location in intent startup * Retry interrupted OpenCode startup prompt claims --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Co-authored-by: Ahmed Nagy <ahmednagy25t@gmail.com> Co-authored-by: Orca startup hydration review <agents@stably.ai> Co-authored-by: Orca <dev@stably.ai>
This commit is contained in:
co-authored by
Brennan Benson
Ahmed Nagy
Orca startup hydration review
Orca
parent
58bd15fa3f
commit
e8310d5a4f
@@ -1,6 +1,12 @@
|
||||
import { createHash } from 'node:crypto'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { getOpenCodeCliCapabilities } from '../../shared/opencode-cli-version'
|
||||
import { prepareOpenCodePtyLaunch } from './opencode-pty-launch'
|
||||
import {
|
||||
OPENCODE_STARTUP_PROMPT_SHA256_ENV,
|
||||
OPENCODE_STARTUP_PROMPT_BODY_ENV,
|
||||
OPENCODE_STARTUP_PROMPT_SHELL_ENV
|
||||
} from '../../shared/opencode-startup-prompt'
|
||||
import {
|
||||
buildLocalPtySpawnEnvironment,
|
||||
enforceLocalPtySpawnEnvironmentOverrides
|
||||
@@ -28,20 +34,195 @@ const plan: LocalPtyLaunchPlan = {
|
||||
launchWslDistro: null
|
||||
}
|
||||
|
||||
const hookServer = vi.hoisted(() => {
|
||||
const server: { endpointFilePath: string | null } = { endpointFilePath: '/private/endpoint.env' }
|
||||
return server
|
||||
})
|
||||
vi.mock('../agent-hooks/server', () => ({ agentHookServer: hookServer }))
|
||||
const reserve = vi.hoisted(() => vi.fn(() => true))
|
||||
vi.mock('./opencode-startup-prompt-owner', () => ({ reserveOpenCodeStartupPrompt: reserve }))
|
||||
|
||||
async function prepare(options: Parameters<typeof prepareOpenCodePtyLaunch>[0]) {
|
||||
return (await prepareOpenCodePtyLaunch(options)).env
|
||||
}
|
||||
|
||||
const probe = vi.hoisted(() => vi.fn())
|
||||
const install = vi.hoisted(() => vi.fn())
|
||||
vi.mock('./opencode-startup-prompt-installer', () => ({
|
||||
installOpenCodeStartupPromptForLaunch: install
|
||||
}))
|
||||
vi.mock('./opencode-launch-capabilities', () => ({ probeOpenCodeLaunchCapabilities: probe }))
|
||||
|
||||
beforeEach(() => probe.mockReset())
|
||||
beforeEach(() => {
|
||||
probe.mockReset()
|
||||
reserve.mockReset().mockReturnValue(true)
|
||||
install.mockReset()
|
||||
hookServer.endpointFilePath = '/private/endpoint.env'
|
||||
})
|
||||
afterEach(() => vi.unstubAllEnvs())
|
||||
|
||||
describe('execution-host OpenCode launch preparation', () => {
|
||||
it('retains fresh owned source provenance through the final provider deletion pass', async () => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
install.mockImplementation((env) => {
|
||||
env.OPENCODE_CONFIG_DIR = '/private/owned-overlay'
|
||||
env.ORCA_OPENCODE_SOURCE_CONFIG_DIR = '/private/real-source'
|
||||
return true
|
||||
})
|
||||
const envToDelete = ['OPENCODE_CONFIG_DIR', 'ORCA_OPENCODE_SOURCE_CONFIG_DIR']
|
||||
const env = await prepare({
|
||||
command: 'opencode --prompt task',
|
||||
isFreshLaunch: true,
|
||||
envToDelete,
|
||||
env: {
|
||||
ORCA_AGENT_LAUNCH_TOKEN: 'admitted-launch',
|
||||
ORCA_OPENCODE_STARTUP_PROMPT_SHA256: createHash('sha256').update('task').digest('hex'),
|
||||
ORCA_OPENCODE_STARTUP_PROMPT_BODY: 'task',
|
||||
ORCA_OPENCODE_STARTUP_PROMPT_SHELL: 'posix'
|
||||
}
|
||||
})
|
||||
const finalEnv = await buildLocalPtySpawnEnvironment({
|
||||
id: 'source-proof',
|
||||
spawn: { cols: 80, rows: 24, env, envToDelete },
|
||||
getOptions: () => ({}),
|
||||
plan
|
||||
})
|
||||
enforceLocalPtySpawnEnvironmentOverrides({ cols: 80, rows: 24, env, envToDelete }, finalEnv)
|
||||
expect(finalEnv.OPENCODE_CONFIG_DIR).toBe('/private/owned-overlay')
|
||||
expect(finalEnv.ORCA_OPENCODE_SOURCE_CONFIG_DIR).toBe('/private/real-source')
|
||||
})
|
||||
it('removes only the automatic verified v2 prompt argument, retaining explicit run and manual flags', async () => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
const env = {
|
||||
ORCA_AGENT_LAUNCH_TOKEN: 'admitted-launch',
|
||||
[OPENCODE_STARTUP_PROMPT_SHA256_ENV]: createHash('sha256').update('task').digest('hex'),
|
||||
[OPENCODE_STARTUP_PROMPT_BODY_ENV]: 'task',
|
||||
[OPENCODE_STARTUP_PROMPT_SHELL_ENV]: 'posix'
|
||||
}
|
||||
const options = { env, envToDelete: [], isFreshLaunch: true }
|
||||
expect(
|
||||
(
|
||||
await prepareOpenCodePtyLaunch({
|
||||
...options,
|
||||
command: "opencode --standalone --prompt 'task'"
|
||||
})
|
||||
).command
|
||||
).toBe('opencode --standalone')
|
||||
expect(
|
||||
(await prepareOpenCodePtyLaunch({ ...options, command: "opencode run --prompt 'task'" }))
|
||||
.command
|
||||
).toBe("opencode run --prompt 'task'")
|
||||
expect(
|
||||
(await prepareOpenCodePtyLaunch({ ...options, env: {}, command: "opencode --prompt 'task'" }))
|
||||
.command
|
||||
).toBe("opencode --prompt 'task'")
|
||||
})
|
||||
it.each(['inherited', 'explicit', 'deleted'] as const)(
|
||||
'passes the %s config environment used by the execution-host version probe to the prompt installer',
|
||||
async (selection) => {
|
||||
vi.stubEnv('XDG_CONFIG_HOME', '/ambient/config')
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
await prepareOpenCodePtyLaunch({
|
||||
command: 'opencode --prompt task',
|
||||
envToDelete: selection === 'deleted' ? ['XDG_CONFIG_HOME'] : [],
|
||||
isFreshLaunch: true,
|
||||
env: {
|
||||
ORCA_AGENT_LAUNCH_TOKEN: 'admitted-launch',
|
||||
[OPENCODE_STARTUP_PROMPT_SHA256_ENV]: createHash('sha256').update('task').digest('hex'),
|
||||
[OPENCODE_STARTUP_PROMPT_BODY_ENV]: 'task',
|
||||
[OPENCODE_STARTUP_PROMPT_SHELL_ENV]: 'posix',
|
||||
...(selection === 'explicit' ? { XDG_CONFIG_HOME: '/selected/config' } : {})
|
||||
}
|
||||
})
|
||||
expect(install).toHaveBeenCalledTimes(1)
|
||||
const resolved = install.mock.calls[0][2]
|
||||
expect(resolved).toEqual(probe.mock.calls[0][0].env)
|
||||
expect(resolved.XDG_CONFIG_HOME).toBe(
|
||||
selection === 'deleted'
|
||||
? undefined
|
||||
: selection === 'explicit'
|
||||
? '/selected/config'
|
||||
: '/ambient/config'
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
it.each(['endpoint', 'installer', 'capacity', 'identity'])(
|
||||
'keeps the editable brief when automatic preparation lacks %s',
|
||||
async (failure) => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
if (failure === 'endpoint') {
|
||||
hookServer.endpointFilePath = null
|
||||
}
|
||||
if (failure === 'installer') {
|
||||
install.mockImplementation((env) => {
|
||||
delete env.ORCA_OPENCODE_STARTUP_PROMPT_NONCE
|
||||
})
|
||||
}
|
||||
if (failure === 'capacity') {
|
||||
reserve.mockReturnValue(false)
|
||||
}
|
||||
const original = "opencode --standalone --prompt 'task'"
|
||||
const result = await prepareOpenCodePtyLaunch({
|
||||
command: original,
|
||||
envToDelete: [],
|
||||
isFreshLaunch: true,
|
||||
env: {
|
||||
...(failure === 'identity' ? {} : { ORCA_AGENT_LAUNCH_TOKEN: 'admitted-launch' }),
|
||||
[OPENCODE_STARTUP_PROMPT_SHA256_ENV]: createHash('sha256').update('task').digest('hex'),
|
||||
[OPENCODE_STARTUP_PROMPT_BODY_ENV]: 'task',
|
||||
[OPENCODE_STARTUP_PROMPT_SHELL_ENV]: 'posix'
|
||||
}
|
||||
})
|
||||
expect(result.command).toBe(original)
|
||||
expect(result.env).not.toHaveProperty('ORCA_OPENCODE_STARTUP_PROMPT_NONCE')
|
||||
}
|
||||
)
|
||||
it.each(['1.1.23', '2.0.16', '2.0.17', 'unknown'])(
|
||||
'gates native intent against the executing %s capability',
|
||||
async (version) => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities(version))
|
||||
const envToDelete: string[] = []
|
||||
const fingerprint = createHash('sha256').update('task').digest('hex')
|
||||
const env = await prepare({
|
||||
command: 'opencode --prompt task',
|
||||
env: {
|
||||
ORCA_AGENT_LAUNCH_TOKEN: 'admitted-launch',
|
||||
[OPENCODE_STARTUP_PROMPT_SHA256_ENV]: fingerprint,
|
||||
[OPENCODE_STARTUP_PROMPT_BODY_ENV]: 'task',
|
||||
[OPENCODE_STARTUP_PROMPT_SHELL_ENV]: 'posix'
|
||||
},
|
||||
envToDelete,
|
||||
isFreshLaunch: true
|
||||
})
|
||||
expect(env?.[OPENCODE_STARTUP_PROMPT_SHA256_ENV]).toBe(
|
||||
version === '2.0.16' ? fingerprint : undefined
|
||||
)
|
||||
expect(envToDelete.includes(OPENCODE_STARTUP_PROMPT_SHA256_ENV)).toBe(version !== '2.0.16')
|
||||
}
|
||||
)
|
||||
|
||||
it('refuses remote automatic intent without execution-owned driving input', async () => {
|
||||
const fingerprint = 'b'.repeat(64)
|
||||
const envToDelete: string[] = []
|
||||
const env = await prepare({
|
||||
command: 'opencode --prompt task',
|
||||
connectionId: 'remote',
|
||||
isFreshLaunch: true,
|
||||
env: { [OPENCODE_STARTUP_PROMPT_SHA256_ENV]: fingerprint },
|
||||
envToDelete
|
||||
})
|
||||
expect(env?.[OPENCODE_STARTUP_PROMPT_SHA256_ENV]).toBeUndefined()
|
||||
expect(envToDelete).toContain(OPENCODE_STARTUP_PROMPT_SHA256_ENV)
|
||||
expect(probe).not.toHaveBeenCalled()
|
||||
})
|
||||
it('keeps deleted credentials and config absent from the probe and final provider environment', async () => {
|
||||
vi.stubEnv('ANTHROPIC_API_KEY', 'dummy-deleted-key')
|
||||
vi.stubEnv('OPENCODE_CONFIG_DIR', '/dummy/deleted-config')
|
||||
vi.stubEnv('ORCA_OPENCODE_PLUGIN_API', 'v1')
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities(null))
|
||||
const envToDelete = ['ANTHROPIC_API_KEY', 'OPENCODE_CONFIG_DIR']
|
||||
const env = await prepareOpenCodePtyLaunch({
|
||||
const env = await prepare({
|
||||
command: 'opencode',
|
||||
env: {},
|
||||
envToDelete,
|
||||
@@ -67,7 +248,7 @@ describe('execution-host OpenCode launch preparation', () => {
|
||||
vi.stubEnv('ORCA_OPENCODE_PLUGIN_API', 'v1')
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
const envToDelete = ['KEEP_DELETED', 'ORCA_OPENCODE_PLUGIN_API']
|
||||
const env = await prepareOpenCodePtyLaunch({
|
||||
const env = await prepare({
|
||||
command: 'opencode',
|
||||
env: {},
|
||||
envToDelete,
|
||||
@@ -94,7 +275,7 @@ describe('execution-host OpenCode launch preparation', () => {
|
||||
KEEP: '1',
|
||||
ORCA_OPENCODE_PLUGIN_API: 'stale'
|
||||
}
|
||||
const result = await prepareOpenCodePtyLaunch({
|
||||
const result = await prepare({
|
||||
command: 'opencode --prompt test',
|
||||
agent: 'opencode',
|
||||
env,
|
||||
@@ -117,7 +298,7 @@ describe('execution-host OpenCode launch preparation', () => {
|
||||
it('creates a launch environment for a known binary without caller env', async () => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('2.0.16'))
|
||||
expect(
|
||||
await prepareOpenCodePtyLaunch({
|
||||
await prepare({
|
||||
command: 'opencode',
|
||||
env: undefined,
|
||||
envToDelete: [],
|
||||
@@ -129,7 +310,7 @@ describe('execution-host OpenCode launch preparation', () => {
|
||||
it('forwards WSL plugin selection through WSLENV after a guest probe', async () => {
|
||||
probe.mockResolvedValue(getOpenCodeCliCapabilities('1.1.23'))
|
||||
const env = { KEEP: '1' }
|
||||
const result = await prepareOpenCodePtyLaunch({
|
||||
const result = await prepare({
|
||||
command: 'opencode',
|
||||
agent: 'opencode',
|
||||
env,
|
||||
@@ -148,9 +329,7 @@ describe('execution-host OpenCode launch preparation', () => {
|
||||
'never probes the client for an attach or SSH launch',
|
||||
async (route) => {
|
||||
const env = { ORCA_OPENCODE_PLUGIN_API: 'v1' }
|
||||
expect(
|
||||
await prepareOpenCodePtyLaunch({ command: 'opencode', env, envToDelete: [], ...route })
|
||||
).toEqual({})
|
||||
expect(await prepare({ command: 'opencode', env, envToDelete: [], ...route })).toEqual({})
|
||||
expect(probe).not.toHaveBeenCalled()
|
||||
expect(env).toEqual({ ORCA_OPENCODE_PLUGIN_API: 'v1' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user