mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 16:02:24 +00:00
* fix(omp): answer startup Kitty queries before renderer handoff Forward actual renderer capability through local and remote spawn. Preserve source ranges and following keyboard mode pushes, and retain independent ConPTY color authority. Refs #17081. Secondary review: #17082. Co-authored-by: stevelliu <stevelliu@tencent.com> * test(omp): cover fragmented keyboard modes and ConPTY handoff * fix: preserve keyboard startup intent without terminal colors * fix: negotiate keyboard support for host-authoritative agent launches * fix: keep terminal creation within line budget * fix(omp): negotiate keyboard support for paired web launches * test: remove obsolete message type import after main integration * fix: validate paired launch results and retry incomplete SSH test snapshots * fix(omp): negotiate keyboard support for background paired launches --------- Co-authored-by: stevelliu <stevelliu@tencent.com>
199 lines
6.0 KiB
TypeScript
199 lines
6.0 KiB
TypeScript
import {
|
|
execDockerSshRelayTargetCommand,
|
|
shellQuote,
|
|
type DockerSshRelayTarget
|
|
} from './docker-ssh-relay-target'
|
|
|
|
export type DockerSshRelayProcessSnapshot = {
|
|
relayPid: number
|
|
watcherPids: number[]
|
|
relayDir: string
|
|
}
|
|
|
|
export type DockerSshRelayArtifactState = {
|
|
installComplete: boolean
|
|
relayWatcher: boolean
|
|
}
|
|
|
|
type RelayProcessRow = {
|
|
type: 'relay' | 'watcher'
|
|
pid: number
|
|
parentPid: number
|
|
cwd: string
|
|
}
|
|
|
|
const LIST_RELAY_PROCESSES_COMMAND = `
|
|
for proc in /proc/[0-9]*; do
|
|
[ -r "$proc/cmdline" ] || continue
|
|
argv=()
|
|
mapfile -d '' -t argv < "$proc/cmdline" 2>/dev/null || continue
|
|
entry="\${argv[1]:-}"
|
|
base="\${entry##*/}"
|
|
type=
|
|
if [ "$base" = relay-watcher.js ]; then
|
|
type=watcher
|
|
elif [ "$base" = relay.js ]; then
|
|
for arg in "\${argv[@]:2}"; do
|
|
if [ "$arg" = --detached ]; then type=relay; break; fi
|
|
done
|
|
fi
|
|
[ -n "$type" ] || continue
|
|
pid="\${proc##*/}"
|
|
ppid="$(awk '/^PPid:/{print $2}' "$proc/status" 2>/dev/null)"
|
|
cwd="$(readlink "$proc/cwd" 2>/dev/null)"
|
|
printf '%s\\t%s\\t%s\\t%s\\n' "$type" "$pid" "$ppid" "$cwd"
|
|
done
|
|
`
|
|
|
|
function parseRelayProcessRows(output: string): RelayProcessRow[] {
|
|
if (!output) {
|
|
return []
|
|
}
|
|
return output.split('\n').map((line) => {
|
|
const [type, rawPid, rawParentPid, cwd] = line.split('\t')
|
|
// Why: Number('') is 0, so empty pid/ppid (e.g. vanished /proc status) must
|
|
// throw so callers retry the observation instead of accepting parentPid: 0.
|
|
const pid = Number(rawPid)
|
|
const parentPid = Number(rawParentPid)
|
|
if (
|
|
(type !== 'relay' && type !== 'watcher') ||
|
|
rawPid === undefined ||
|
|
rawPid === '' ||
|
|
rawParentPid === undefined ||
|
|
rawParentPid === '' ||
|
|
!Number.isInteger(pid) ||
|
|
!Number.isInteger(parentPid) ||
|
|
!cwd
|
|
) {
|
|
throw new Error(`Unexpected Docker SSH relay process row: ${line}`)
|
|
}
|
|
return { type, pid, parentPid, cwd }
|
|
})
|
|
}
|
|
|
|
export function readDockerSshRelayProcessSnapshot(
|
|
target: DockerSshRelayTarget
|
|
): DockerSshRelayProcessSnapshot | null {
|
|
const groups = readDockerSshRelayProcessSnapshots(target)
|
|
if (groups.length > 1) {
|
|
throw new Error(`Expected one Docker SSH relay process group, found ${groups.length}`)
|
|
}
|
|
return groups[0] ?? null
|
|
}
|
|
|
|
export function readDockerSshRelayProcessSnapshots(
|
|
target: DockerSshRelayTarget
|
|
): DockerSshRelayProcessSnapshot[] {
|
|
const rows = parseRelayProcessRows(
|
|
execDockerSshRelayTargetCommand(target, LIST_RELAY_PROCESSES_COMMAND)
|
|
)
|
|
const relays = rows.filter((row) => row.type === 'relay')
|
|
const groups = relays.flatMap((relay) => {
|
|
const watcherPids = rows
|
|
.filter((row) => row.type === 'watcher' && row.parentPid === relay.pid)
|
|
.map((row) => row.pid)
|
|
.sort((left, right) => left - right)
|
|
return watcherPids.length > 0 ? [{ relayPid: relay.pid, watcherPids, relayDir: relay.cwd }] : []
|
|
})
|
|
return groups.sort((left, right) => left.relayPid - right.relayPid)
|
|
}
|
|
|
|
export function signalDockerSshRelayWatchers(
|
|
target: DockerSshRelayTarget,
|
|
snapshot: DockerSshRelayProcessSnapshot
|
|
): void {
|
|
const { relayPid, watcherPids } = snapshot
|
|
if (!Number.isInteger(relayPid) || watcherPids.some((pid) => !Number.isInteger(pid))) {
|
|
throw new Error('Docker SSH relay process IDs must be integers')
|
|
}
|
|
execDockerSshRelayTargetCommand(
|
|
target,
|
|
[
|
|
`relay_proc=/proc/${relayPid}`,
|
|
'[ -r "$relay_proc/cmdline" ]',
|
|
'relay_argv=()',
|
|
'mapfile -d \'\' -t relay_argv < "$relay_proc/cmdline"',
|
|
'[ "${relay_argv[1]##*/}" = relay.js ]',
|
|
'[[ " ${relay_argv[*]:2} " = *" --detached "* ]]',
|
|
...watcherPids.flatMap((watcherPid) => [
|
|
`proc=/proc/${watcherPid}`,
|
|
'[ -r "$proc/cmdline" ]',
|
|
'argv=()',
|
|
'mapfile -d \'\' -t argv < "$proc/cmdline"',
|
|
'[ "${argv[1]##*/}" = relay-watcher.js ]',
|
|
`ppid="$(awk '/^PPid:/{print $2}' "$proc/status")"`,
|
|
`[ "$ppid" = ${relayPid} ]`,
|
|
`kill -SEGV ${watcherPid}`
|
|
])
|
|
].join(' && ')
|
|
)
|
|
}
|
|
|
|
export function terminateDockerSshRelay(
|
|
target: DockerSshRelayTarget,
|
|
snapshot: DockerSshRelayProcessSnapshot
|
|
): void {
|
|
const { relayPid } = snapshot
|
|
if (!Number.isInteger(relayPid)) {
|
|
throw new Error('Docker SSH relay process ID must be an integer')
|
|
}
|
|
execDockerSshRelayTargetCommand(
|
|
target,
|
|
[
|
|
`proc=/proc/${relayPid}`,
|
|
'[ -r "$proc/cmdline" ]',
|
|
'argv=()',
|
|
'mapfile -d \'\' -t argv < "$proc/cmdline"',
|
|
'[ "${argv[1]##*/}" = relay.js ]',
|
|
'[[ " ${argv[*]:2} " = *" --detached "* ]]',
|
|
`kill -TERM ${relayPid}`
|
|
].join(' && ')
|
|
)
|
|
}
|
|
|
|
export function isDockerSshRelayPidRunning(
|
|
target: DockerSshRelayTarget,
|
|
relayPid: number
|
|
): boolean {
|
|
if (!Number.isInteger(relayPid)) {
|
|
return false
|
|
}
|
|
const result = execDockerSshRelayTargetCommand(
|
|
target,
|
|
`proc=/proc/${relayPid}; ` +
|
|
'if [ -r "$proc/cmdline" ]; then ' +
|
|
'argv=(); mapfile -d \'\' -t argv < "$proc/cmdline"; ' +
|
|
'if [ "${argv[1]##*/}" = relay.js ] && ' +
|
|
'[[ " ${argv[*]:2} " = *" --detached "* ]]; then echo ALIVE; else echo DEAD; fi; ' +
|
|
'else echo DEAD; fi'
|
|
)
|
|
return result === 'ALIVE'
|
|
}
|
|
|
|
export function readDockerSshRelayArtifactState(
|
|
target: DockerSshRelayTarget,
|
|
relayDir: string
|
|
): DockerSshRelayArtifactState {
|
|
const quotedDir = shellQuote(relayDir)
|
|
const output = execDockerSshRelayTargetCommand(
|
|
target,
|
|
`test -f ${quotedDir}/.install-complete && marker=yes || marker=no; ` +
|
|
`test -f ${quotedDir}/relay-watcher.js && watcher=yes || watcher=no; ` +
|
|
'printf "%s %s" "$marker" "$watcher"'
|
|
)
|
|
const [marker, watcher] = output.split(' ')
|
|
return { installComplete: marker === 'yes', relayWatcher: watcher === 'yes' }
|
|
}
|
|
|
|
export function removeDockerSshRelayWatcherArtifact(
|
|
target: DockerSshRelayTarget,
|
|
relayDir: string
|
|
): void {
|
|
const quotedDir = shellQuote(relayDir)
|
|
execDockerSshRelayTargetCommand(
|
|
target,
|
|
`test -f ${quotedDir}/.install-complete && rm -f ${quotedDir}/relay-watcher.js && ` +
|
|
`test -f ${quotedDir}/.install-complete && test ! -e ${quotedDir}/relay-watcher.js`
|
|
)
|
|
}
|