mirror of
https://github.com/stablyai/orca.git
synced 2026-10-07 16:02:29 +00:00
* 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 * STRICT launch CI contract correction * CAPS launch CI contract correction * test: initialize Claude prompt state in output retention fixture --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
100 lines
3.4 KiB
TypeScript
100 lines
3.4 KiB
TypeScript
import { parseWslUncPath, toLinuxPath } from '../../shared/wsl-paths'
|
|
import {
|
|
getFirstCommandToken,
|
|
getCommandTokenPathBasename
|
|
} from '../../shared/command-token-scanner'
|
|
import {
|
|
getOpenCodeCliCapabilities,
|
|
type OpenCodeCliCapabilities
|
|
} from '../../shared/opencode-cli-version'
|
|
import type { TuiAgent } from '../../shared/tui-agent'
|
|
import { resolveCommandOnLocalPath } from '../ipc/command-path-resolver'
|
|
import { runWslProcess } from '../wsl/wsl-runner'
|
|
import { probeOpenCodeCliVersion } from './opencode-cli-version'
|
|
|
|
export function getOpenCodeLaunchExecutable(
|
|
command: string | undefined,
|
|
agent?: TuiAgent
|
|
): string | null {
|
|
const executable = getFirstCommandToken(command ?? '')
|
|
const name = getCommandTokenPathBasename(executable)
|
|
.toLowerCase()
|
|
.replace(/\.(?:exe|cmd|sh)$/, '')
|
|
return agent === 'opencode' ||
|
|
agent === 'opencode2' ||
|
|
(!agent && (name === 'opencode' || name === 'opencode2'))
|
|
? executable || null
|
|
: null
|
|
}
|
|
|
|
export async function probeOpenCodeLaunchCapabilities(options: {
|
|
command: string | undefined
|
|
agent?: TuiAgent
|
|
env: NodeJS.ProcessEnv
|
|
cwd?: string
|
|
wsl?: { distro?: string }
|
|
hostIdentity?: string
|
|
resolveExecutable?: (executable: string) => Promise<string | null>
|
|
}): Promise<OpenCodeCliCapabilities | null> {
|
|
const executable = getOpenCodeLaunchExecutable(options.command, options.agent)
|
|
if (!executable) {
|
|
return null
|
|
}
|
|
if (options.wsl) {
|
|
// An empty carrier prevents the runner from restoring deleted ambient imports.
|
|
const guestEnv: Record<string, string> = { WSLENV: '' }
|
|
const wslEnv = options.env.WSLENV?.split(':')
|
|
.filter((token) => options.env[token.split('/')[0]] !== undefined)
|
|
.join(':')
|
|
if (wslEnv) {
|
|
guestEnv.WSLENV = wslEnv
|
|
for (const token of wslEnv.split(':')) {
|
|
const [key, flags = ''] = token.split('/')
|
|
if (!key || flags.includes('w') || ['PATH', 'HOME', 'TMP', 'TEMP'].includes(key)) {
|
|
continue
|
|
}
|
|
const value = options.env[key]
|
|
if (value !== undefined) {
|
|
guestEnv[key] = value
|
|
}
|
|
}
|
|
}
|
|
const wslPath = options.cwd ? parseWslUncPath(options.cwd) : null
|
|
const cwd = options.cwd ? (wslPath?.linuxPath ?? toLinuxPath(options.cwd)) : undefined
|
|
if (cwd !== undefined && !cwd.startsWith('/')) {
|
|
return getOpenCodeCliCapabilities(null)
|
|
}
|
|
const distro = wslPath?.distro ?? options.wsl.distro
|
|
return probeOpenCodeCliVersion({
|
|
executablePath: executable,
|
|
env: guestEnv,
|
|
cwd,
|
|
hostIdentity: `${options.hostIdentity ?? 'local'}:wsl:${distro ?? 'default'}`,
|
|
execute: async () => {
|
|
const result = await runWslProcess({
|
|
distro,
|
|
loginPath: 'preferred',
|
|
cwd,
|
|
program: executable,
|
|
args: ['--version'],
|
|
env: guestEnv,
|
|
timeoutMs: 5_000,
|
|
maxOutputBytes: 4_096
|
|
})
|
|
return result.environmentResolved ? result : { ...result, code: null }
|
|
}
|
|
})
|
|
}
|
|
const executablePath = options.resolveExecutable
|
|
? await options.resolveExecutable(executable)
|
|
: await resolveCommandOnLocalPath(executable, { env: options.env, cwd: options.cwd })
|
|
return executablePath
|
|
? probeOpenCodeCliVersion({
|
|
executablePath,
|
|
env: options.env,
|
|
cwd: options.cwd,
|
|
hostIdentity: options.hostIdentity
|
|
})
|
|
: getOpenCodeCliCapabilities(null)
|
|
}
|