Files
orca/src/main/opencode/opencode-pty-launch.ts
T
e8310d5a4f 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>
2026-10-04 01:41:01 -07:00

140 lines
5.1 KiB
TypeScript

import { addWslEnvKeys } from '../../shared/wsl-env'
import type { TuiAgent } from '../../shared/tui-agent'
import { randomUUID, createHash } from 'node:crypto'
import { agentHookServer } from '../agent-hooks/server'
import { tokenizeStartupCommand } from '../../shared/tui-agent-startup-shell'
import { isOpenCodeRunCommand } from '../../shared/opencode-headless-command'
import {
OPENCODE_STARTUP_PROMPT_SHA256_ENV,
OPENCODE_STARTUP_PROMPT_NONCE_ENV,
OPENCODE_STARTUP_PROMPT_ENDPOINT_ENV,
OPENCODE_STARTUP_PROMPT_BODY_ENV,
OPENCODE_STARTUP_PROMPT_SHELL_ENV
} from '../../shared/opencode-startup-prompt'
const intentKeys = [
OPENCODE_STARTUP_PROMPT_SHA256_ENV,
OPENCODE_STARTUP_PROMPT_NONCE_ENV,
OPENCODE_STARTUP_PROMPT_ENDPOINT_ENV,
OPENCODE_STARTUP_PROMPT_BODY_ENV,
OPENCODE_STARTUP_PROMPT_SHELL_ENV
]
import { deleteRequestedEnvKeys } from '../ipc/pty/host-env/path'
import { probeOpenCodeLaunchCapabilities } from './opencode-launch-capabilities'
import { reserveOpenCodeStartupPrompt } from './opencode-startup-prompt-owner'
import { installOpenCodeStartupPromptForLaunch } from './opencode-startup-prompt-installer'
export async function prepareOpenCodePtyLaunch(options: {
command: string | undefined
agent?: TuiAgent
env: Record<string, string> | undefined
envToDelete: string[]
cwd?: string
connectionId?: string | null
isFreshLaunch: boolean
wsl?: { distro?: string }
}): Promise<{ env: Record<string, string> | undefined; command: string | undefined }> {
let command = options.command
const env = options.env ? { ...options.env } : undefined
const requestedPrompt = env?.[OPENCODE_STARTUP_PROMPT_SHA256_ENV]
const body = env?.[OPENCODE_STARTUP_PROMPT_BODY_ENV]
const shell = env?.[OPENCODE_STARTUP_PROMPT_SHELL_ENV]
if (env) {
delete env.ORCA_OPENCODE_PLUGIN_API
for (const key of intentKeys) {
delete env[key]
}
}
// Providers merge their own ambient environment after this preparation.
if (!options.envToDelete.includes('ORCA_OPENCODE_PLUGIN_API')) {
options.envToDelete.push('ORCA_OPENCODE_PLUGIN_API')
}
for (const key of intentKeys) {
if (!options.envToDelete.includes(key)) {
options.envToDelete.push(key)
}
}
if (options.connectionId || !options.isFreshLaunch) {
return { env, command }
}
const probeEnv: Record<string, string> = {}
for (const [key, value] of Object.entries({ ...process.env, ...env })) {
if (value !== undefined) {
probeEnv[key] = value
}
}
deleteRequestedEnvKeys(probeEnv, options.envToDelete)
const capabilities = await probeOpenCodeLaunchCapabilities({
...options,
env: probeEnv
})
if (!capabilities || capabilities.pluginApi === 'unknown') {
return { env, command }
}
const launchEnv: Record<string, string> = {
...env,
ORCA_OPENCODE_PLUGIN_API: capabilities.pluginApi
}
options.envToDelete.splice(options.envToDelete.indexOf('ORCA_OPENCODE_PLUGIN_API'), 1)
if (
capabilities.promptMode === 'prefill' &&
!options.wsl &&
launchEnv.ORCA_AGENT_LAUNCH_TOKEN &&
requestedPrompt &&
body &&
command &&
(shell === 'posix' || shell === 'powershell' || shell === 'cmd') &&
createHash('sha256').update(body).digest('hex') === requestedPrompt
) {
const parsed = tokenizeStartupCommand(command, shell)
const last = parsed.ok ? parsed.tokens.length - 1 : -1
if (
parsed.ok &&
!isOpenCodeRunCommand(parsed.tokens, shell) &&
parsed.tokens.filter((token) => token === '--prompt').length === 1 &&
parsed.tokens[last - 1] === '--prompt' &&
parsed.tokens[last] === body &&
!parsed.spans[last].divergesFromShell &&
!parsed.spans[last - 1].divergesFromShell
) {
const endpoint = agentHookServer.endpointFilePath
if (endpoint) {
launchEnv[OPENCODE_STARTUP_PROMPT_SHA256_ENV] = requestedPrompt
launchEnv[OPENCODE_STARTUP_PROMPT_BODY_ENV] = body
launchEnv[OPENCODE_STARTUP_PROMPT_NONCE_ENV] = randomUUID()
launchEnv[OPENCODE_STARTUP_PROMPT_ENDPOINT_ENV] = endpoint
if (installOpenCodeStartupPromptForLaunch(launchEnv, false, probeEnv)) {
for (const key of [
'OPENCODE_CONFIG_DIR',
'ORCA_OPENCODE_CONFIG_DIR',
'ORCA_OPENCODE_SOURCE_CONFIG_DIR'
]) {
const deletion = options.envToDelete.indexOf(key)
if (launchEnv[key] && deletion !== -1) {
options.envToDelete.splice(deletion, 1)
}
}
}
const nonce = launchEnv[OPENCODE_STARTUP_PROMPT_NONCE_ENV]
if (nonce && reserveOpenCodeStartupPrompt(nonce, requestedPrompt)) {
command = command.slice(0, parsed.spans[last - 1].start).trimEnd()
} else {
for (const key of intentKeys) {
delete launchEnv[key]
}
}
for (const key of intentKeys) {
if (launchEnv[key]) {
options.envToDelete.splice(options.envToDelete.indexOf(key), 1)
}
}
}
}
}
if (options.wsl) {
addWslEnvKeys(launchEnv, ['ORCA_OPENCODE_PLUGIN_API'])
}
return { env: launchEnv, command }
}