@@ -0,0 +1,506 @@
// 重构前 index.ts 只读参考:commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f, blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58;可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。
import { spawnSync } from "node:child_process" ;
import type { JsonValue } from "./types" ;
export type RuntimePreflightAgentPort = "codex" | "opencode" ;
export interface RuntimePreflightOptions {
includeRemote? : boolean ;
includePushDryRun? : boolean ;
pushDryRunRef? : string ;
issueNumber? : number ;
}
export interface RuntimeCommandProbe {
command : string ;
args : string [ ] ;
ok : boolean ;
exitCode : number | null ;
signal : string | null ;
error : string | null ;
stdout : string ;
stderr : string ;
}
export interface RuntimePreflightPortStatus {
agentPort : RuntimePreflightAgentPort ;
ok : boolean ;
path : string ;
commandPath : string | null ;
version : string | null ;
appServerDryRun? : RuntimeCommandProbe ;
probes : {
commandV : RuntimeCommandProbe ;
version : RuntimeCommandProbe ;
} ;
errors : string [ ] ;
checkedAt : string ;
}
export interface RuntimePreflightReport {
ok : boolean ;
checkedAt : string ;
cwd : string ;
pid : number ;
node : {
platform : NodeJS.Platform ;
arch : string ;
version : string ;
} ;
path : string ;
ports : Record < RuntimePreflightAgentPort , RuntimePreflightPortStatus > ;
pullRequestDelivery : PullRequestDeliveryPreflight ;
}
export interface PullRequestDeliveryPreflight {
ok : boolean ;
checkedAt : string ;
tools : Record < string , RuntimeToolStatus > ;
credentials : {
ghTokenPresent : boolean ;
githubTokenPresent : boolean ;
ghHostPresent : boolean ;
githubApiUrlPresent : boolean ;
ghRepoPresent : boolean ;
sshAuthSockPresent : boolean ;
gitAskpassPresent : boolean ;
ghHostsConfigPresent : boolean ;
gitCredentialsPresent : boolean ;
} ;
githubContext : {
host : string ;
apiBaseUrl : string ;
repo : string | null ;
issueProbeNumber : number ;
} ;
egress : {
proxy : {
httpProxy : string | null ;
httpsProxy : string | null ;
allProxy : string | null ;
noProxy : string | null ;
selectedProxyHost : string | null ;
selectedProxyPort : string | null ;
selectedProxyHostProbe : RuntimeCommandProbe | null ;
selectedProxyHostResolvable : boolean | null ;
} ;
githubDefault : RuntimeCommandProbe ;
githubDirect : RuntimeCommandProbe ;
apiDefault : RuntimeCommandProbe ;
apiDirect : RuntimeCommandProbe ;
issueApi : RuntimeCommandProbe | null ;
} ;
git : {
insideWorktree : boolean ;
branch : string | null ;
head : string | null ;
originMaster : string | null ;
remoteOrigin : string | null ;
userName : string | null ;
userEmail : string | null ;
home : string | null ;
homeWritable : boolean ;
knownHostsPresent : boolean ;
privateKeyPresent : boolean ;
} ;
remote ? : {
gitLsRemote : RuntimeCommandProbe ;
gitHttpsLsRemote : RuntimeCommandProbe | null ;
githubSshAuth : RuntimeCommandProbe ;
githubSshAuthenticated : boolean ;
ghAuthStatus : RuntimeCommandProbe | null ;
ghRepoView : RuntimeCommandProbe | null ;
ghIssueView : RuntimeCommandProbe | null ;
ghPrReadOnly : RuntimeCommandProbe | null ;
} ;
pushDryRun? : RuntimeCommandProbe ;
limitations : string [ ] ;
risks : string [ ] ;
}
export interface RuntimeToolStatus {
name : string ;
ok : boolean ;
path : string | null ;
version : string | null ;
probe : RuntimeCommandProbe ;
}
function redactSensitive ( value : string ) : string {
return value
. replace ( / g h [ p o u s r ] _ [ A - Z a - z 0 - 9 _ ] { 2 0 , } / g u , " * * * " )
. replace ( / g i t h u b _ p a t _ [ A - Z a - z 0 - 9 _ ] + / g u , " * * * " )
. replace ( / ( h t t p s ? : \ / \ / ) ( [ ^ / \ s : @ ] + ) : ( [ ^ / \ s @ ] + ) @ / g i u , " $ 1 * * * : * * * @ " )
. replace ( / ( h t t p s ? : \ / \ / ) ( [ ^ / \ s @ ] + ) @ / g i u , " $ 1 * * * @ " )
. replace ( / ( [ ? & ] ( ? : a c c e s s _ t o k e n | t o k e n ) = ) [ ^ & \ s ] + / g i u , " $ 1 * * * " ) ;
}
function compactOutput ( value : string , maxChars = 4000 ) : string {
const text = redactSensitive ( value ) . replace ( / \ u 0 0 1 b \ [ [ 0 - 9 ; ] * m / g u , " " ) . t r i m ( ) ;
return text . length <= maxChars ? text : ` ${ text . slice ( 0 , maxChars ) } ... ` ;
}
function commandProbe ( command : string , args : string [ ] , options : { timeoutMs? : number } = { } ) : RuntimeCommandProbe {
const run = spawnSync ( command , args , {
encoding : "utf8" ,
timeout : options.timeoutMs ? ? 5000 ,
maxBuffer : 256 * 1024 ,
env : process.env ,
shell : false ,
} ) ;
const error = run . error instanceof Error ? run.error.message : null ;
const timedOut = run . error instanceof Error && run . error . message . includes ( "ETIMEDOUT" ) ;
return {
command ,
args ,
ok : error === null && ! timedOut && run . status === 0 ,
exitCode : run.status ,
signal : run.signal ,
error ,
stdout : compactOutput ( typeof run . stdout === "string" ? run . stdout : "" ) ,
stderr : compactOutput ( typeof run . stderr === "string" ? run . stderr : "" ) ,
} ;
}
function shellProbe ( script : string , timeoutMs = 5000 ) : RuntimeCommandProbe {
return commandProbe ( "sh" , [ "-lc" , script ] , { timeoutMs } ) ;
}
function skippedProbe ( name : string ) : RuntimeCommandProbe {
return {
command : "preflight" ,
args : [ name ] ,
ok : true ,
exitCode : 0 ,
signal : null ,
error : null ,
stdout : "skipped; pass remote=1 to run this probe" ,
stderr : "" ,
} ;
}
function firstLine ( value : string ) : string | null {
const line = value . split ( / \ r ? \ n / u ) . m a p ( ( i t e m ) = > i t e m . t r i m ( ) ) . f i n d ( ( i t e m ) = > i t e m . l e n g t h > 0 ) ;
return line ? ? null ;
}
function errorSummary ( probe : RuntimeCommandProbe ) : string | null {
if ( probe . ok ) return null ;
const detail = firstLine ( [ probe . error ? ? "" , probe . stderr , probe . stdout ] . filter ( Boolean ) . join ( "\n" ) ) ;
return ` ${ probe . command } ${ probe . args . join ( " " ) } failed ${ detail === null ? "" : ` : ${ detail } ` } ` ;
}
function commandPath ( command : string ) : string | null {
const probe = shellProbe ( ` command -v ${ shellQuote ( command ) } ` , 2000 ) ;
return probe . ok ? firstLine ( probe . stdout ) : null ;
}
function shellQuote ( value : string ) : string {
return ` ' ${ value . replace ( / ' / g u , " ' \ \ ' ' " ) } ' ` ;
}
function toolStatus ( name : string , versionArgs : string [ ] = [ "--version" ] ) : RuntimeToolStatus {
const path = commandPath ( name ) ;
const probe = path === null ? shellProbe ( ` command -v ${ shellQuote ( name ) } ` , 2000 ) : commandProbe ( name , versionArgs , { timeoutMs : 5000 } ) ;
return {
name ,
ok : path !== null ,
path ,
version : path === null ? null : firstLine ( probe . stdout ) ? ? firstLine ( probe . stderr ) ,
probe ,
} ;
}
function gitValue ( args : string [ ] ) : string | null {
const probe = commandProbe ( "git" , args , { timeoutMs : 5000 } ) ;
return probe . ok ? firstLine ( probe . stdout ) : null ;
}
function homeWritable ( ) : boolean {
const home = process . env . HOME ;
if ( home === undefined || home . trim ( ) . length === 0 ) return false ;
return shellProbe ( ` test -w ${ shellQuote ( home ) } ` , 2000 ) . ok ;
}
function boolEnv ( name : string ) : boolean {
const value = process . env [ name ] ;
return value !== undefined && value . trim ( ) . length > 0 ;
}
function fileExistsProbe ( path : string ) : boolean {
return shellProbe ( ` test -s ${ shellQuote ( path ) } ` , 2000 ) . ok ;
}
function parseGitHubRepo ( remote : string | null ) : string | null {
const envRepo = process . env . GH_REPO ? . trim ( ) ;
if ( envRepo !== undefined && / ^ [ A - Z a - z 0 - 9 _ . - ] + \ / [ A - Z a - z 0 - 9 _ . - ] + $ / u . t e s t ( e n v R e p o ) ) r e t u r n e n v R e p o ;
if ( remote === null ) return null ;
const sshMatch = remote . match ( / ^ g i t @ g i t h u b \ . c o m : ( [ ^ / ] + \ / [ ^ / ] + ? ) ( ? : \ . g i t ) ? $ / u ) ;
if ( sshMatch !== null ) return sshMatch [ 1 ] ? ? null ;
const httpsMatch = remote . match ( / ^ h t t p s : \ / \ / g i t h u b \ . c o m \ / ( [ ^ / ] + \ / [ ^ / ] + ? ) ( ? : \ . g i t ) ? ( ? : \ / ) ? $ / u ) ;
if ( httpsMatch !== null ) return httpsMatch [ 1 ] ? ? null ;
return null ;
}
function envUrl ( name : string ) : URL | null {
const raw = process . env [ name ] ? . trim ( ) ;
if ( raw === undefined || raw . length === 0 ) return null ;
try {
return new URL ( raw ) ;
} catch {
return null ;
}
}
function proxySummary ( ) : PullRequestDeliveryPreflight [ "egress" ] [ "proxy" ] {
const httpProxy = process . env . HTTP_PROXY || process . env . http_proxy || null ;
const httpsProxy = process . env . HTTPS_PROXY || process . env . https_proxy || null ;
const allProxy = process . env . ALL_PROXY || process . env . all_proxy || null ;
const noProxy = process . env . NO_PROXY || process . env . no_proxy || null ;
const selected = envUrl ( "HTTPS_PROXY" ) ? ? envUrl ( "https_proxy" ) ? ? envUrl ( "HTTP_PROXY" ) ? ? envUrl ( "http_proxy" ) ? ? envUrl ( "ALL_PROXY" ) ? ? envUrl ( "all_proxy" ) ;
const selectedProxyHost = selected ? . hostname ? ? null ;
const selectedProxyPort = selected === null ? null : selected . port || ( selected . protocol === "https:" ? "443" : "80" ) ;
const selectedProxyHostProbe = selectedProxyHost === null ? null : commandProbe ( "getent" , [ "ahosts" , selectedProxyHost ] , { timeoutMs : 5000 } ) ;
return {
httpProxy : httpProxy === null ? null : compactOutput ( httpProxy , 1000 ) ,
httpsProxy : httpsProxy === null ? null : compactOutput ( httpsProxy , 1000 ) ,
allProxy : allProxy === null ? null : compactOutput ( allProxy , 1000 ) ,
noProxy : noProxy === null ? null : compactOutput ( noProxy , 1000 ) ,
selectedProxyHost ,
selectedProxyPort ,
selectedProxyHostProbe ,
selectedProxyHostResolvable : selectedProxyHostProbe === null ? null : selectedProxyHostProbe . ok ,
} ;
}
function authCurlProbe ( url : string ) : RuntimeCommandProbe {
const script = [
"set -eu" ,
"status_file=/tmp/unidesk-github-api-probe.status" ,
"body_file=/tmp/unidesk-github-api-probe.json" ,
"rm -f \"$status_file\" \"$body_file\"" ,
"if [ -n \"${GH_TOKEN:-}\" ]; then" ,
` curl -sS -o " $ body_file" -w 'http_status=%{http_code} \\ n' -H "Authorization: Bearer \ ${ GH_TOKEN } " ${ shellQuote ( url ) } > " $ status_file" ` ,
"elif [ -n \"${GITHUB_TOKEN:-}\" ]; then" ,
` curl -sS -o " $ body_file" -w 'http_status=%{http_code} \\ n' -H "Authorization: Bearer \ ${ GITHUB_TOKEN } " ${ shellQuote ( url ) } > " $ status_file" ` ,
"else" ,
` curl -sS -o " $ body_file" -w 'http_status=%{http_code} \\ n' ${ shellQuote ( url ) } > " $ status_file" ` ,
"fi" ,
"cat \"$status_file\"" ,
"status=$(sed -n 's/^http_status=//p' \"$status_file\" | tail -1)" ,
"rm -f /tmp/unidesk-github-api-probe.json" ,
"rm -f \"$status_file\"" ,
"case \"$status\" in 2*) exit 0 ;; *) exit 1 ;; esac" ,
] . join ( "\n" ) ;
return shellProbe ( script , 15 _000 ) ;
}
function issueApiUrl ( apiBaseUrl : string , repo : string | null , issueNumber : number ) : string | null {
if ( repo === null ) return null ;
return ` ${ apiBaseUrl . replace ( / \ / + $ / u , " " ) } / r e p o s / $ { r e p o } / i s s u e s / $ { i s s u e N u m b e r } ` ;
}
function ghRepoArgs ( repo : string | null ) : string [ ] {
return repo === null ? [ "repo" , "view" , "--json" , "nameWithOwner,visibility,isPrivate" ] : [ "repo" , "view" , repo , "--json" , "nameWithOwner,visibility,isPrivate" ] ;
}
function httpsGitUrl ( repo : string | null , host : string ) : string | null {
return repo === null ? null : ` https:// ${ host } / ${ repo } .git ` ;
}
function collectPullRequestDeliveryPreflight ( options : RuntimePreflightOptions , checkedAt : string ) : PullRequestDeliveryPreflight {
const tools = {
git : toolStatus ( "git" , [ "--version" ] ) ,
gh : toolStatus ( "gh" , [ "--version" ] ) ,
hub : toolStatus ( "hub" , [ "version" ] ) ,
jq : toolStatus ( "jq" , [ "--version" ] ) ,
ssh : toolStatus ( "ssh" , [ "-V" ] ) ,
curl : toolStatus ( "curl" , [ "--version" ] ) ,
} ;
const insideProbe = commandProbe ( "git" , [ "rev-parse" , "--is-inside-work-tree" ] , { timeoutMs : 5000 } ) ;
const insideWorktree = insideProbe . ok && firstLine ( insideProbe . stdout ) === "true" ;
const home = process . env . HOME ? ? null ;
const remoteOrigin = gitValue ( [ "remote" , "get-url" , "origin" ] ) ;
const githubHost = process . env . GH_HOST ? . trim ( ) || "github.com" ;
const githubApiBaseUrl = ( process . env . GITHUB_API_URL ? . trim ( ) || "https://api.github.com" ) . replace ( / \ / + $ / u , " " ) ;
const githubRepo = parseGitHubRepo ( remoteOrigin ) ;
const issueProbeNumberRaw = Number ( options . issueNumber ? ? process . env . CODE_QUEUE_PR_PREFLIGHT_ISSUE_NUMBER ? ? 20 ) ;
const issueProbeNumber = Number . isInteger ( issueProbeNumberRaw ) && issueProbeNumberRaw > 0 ? issueProbeNumberRaw : 20 ;
const privateKeyProbe = shellProbe ( "test -d \"$HOME/.ssh\" && find \"$HOME/.ssh\" -maxdepth 1 -type f \\( -name 'id_*' ! -name '*.pub' -o -name '*.pem' \\) -print -quit" , 2000 ) ;
const knownHostsProbe = shellProbe ( "test -s \"$HOME/.ssh/known_hosts\"" , 2000 ) ;
const gitInfo = {
insideWorktree ,
branch : gitValue ( [ "branch" , "--show-current" ] ) ,
head : gitValue ( [ "rev-parse" , "--short" , "HEAD" ] ) ,
originMaster : gitValue ( [ "rev-parse" , "--short" , "origin/master" ] ) ,
remoteOrigin : remoteOrigin === null ? null : compactOutput ( remoteOrigin , 800 ) ,
userName : gitValue ( [ "config" , "--get" , "user.name" ] ) ,
userEmail : gitValue ( [ "config" , "--get" , "user.email" ] ) ,
home ,
homeWritable : homeWritable ( ) ,
knownHostsPresent : knownHostsProbe.ok ,
privateKeyPresent : privateKeyProbe.ok && privateKeyProbe . stdout . trim ( ) . length > 0 ,
} ;
const credentials = {
ghTokenPresent : boolEnv ( "GH_TOKEN" ) ,
githubTokenPresent : boolEnv ( "GITHUB_TOKEN" ) ,
ghHostPresent : boolEnv ( "GH_HOST" ) ,
githubApiUrlPresent : boolEnv ( "GITHUB_API_URL" ) ,
ghRepoPresent : boolEnv ( "GH_REPO" ) ,
sshAuthSockPresent : boolEnv ( "SSH_AUTH_SOCK" ) ,
gitAskpassPresent : boolEnv ( "GIT_ASKPASS" ) ,
ghHostsConfigPresent : fileExistsProbe ( ` ${ home ? ? "/root" } /.config/gh/hosts.yml ` ) ,
gitCredentialsPresent : fileExistsProbe ( ` ${ home ? ? "/root" } /.git-credentials ` ) ,
} ;
const egressProxy = proxySummary ( ) ;
const issueUrl = issueApiUrl ( githubApiBaseUrl , githubRepo , issueProbeNumber ) ;
const egress = {
proxy : egressProxy ,
githubDefault : options.includeRemote === true ? commandProbe ( "curl" , [ "-IsS" , "--max-time" , "10" , ` https:// ${ githubHost } ` ] , { timeoutMs : 15_000 } ) : skippedProbe ( "github-default-network" ) ,
githubDirect : options.includeRemote === true ? commandProbe ( "curl" , [ "--noproxy" , "*" , "-IsS" , "--max-time" , "10" , ` https:// ${ githubHost } ` ] , { timeoutMs : 15_000 } ) : skippedProbe ( "github-direct-network" ) ,
apiDefault : options.includeRemote === true ? commandProbe ( "curl" , [ "-IsS" , "--max-time" , "10" , githubApiBaseUrl ] , { timeoutMs : 15_000 } ) : skippedProbe ( "github-api-default-network" ) ,
apiDirect : options.includeRemote === true ? commandProbe ( "curl" , [ "--noproxy" , "*" , "-IsS" , "--max-time" , "10" , githubApiBaseUrl ] , { timeoutMs : 15_000 } ) : skippedProbe ( "github-api-direct-network" ) ,
issueApi : options.includeRemote === true && issueUrl !== null ? authCurlProbe ( issueUrl ) : null ,
} ;
const githubSshAuthProbe = options . includeRemote === true
? commandProbe ( "ssh" , [ "-o" , "BatchMode=yes" , "-o" , "StrictHostKeyChecking=accept-new" , "-T" , ` git@ ${ githubHost } ` ] , { timeoutMs : 20_000 } )
: null ;
const githubSshAuthenticated = githubSshAuthProbe !== null
&& ( githubSshAuthProbe . ok || / s u c c e s s f u l l y a u t h e n t i c a t e d / i u . t e s t ( ` $ { g i t h u b S s h A u t h P r o b e . s t d o u t } \ n $ { g i t h u b S s h A u t h P r o b e . s t d e r r } ` ) ) ;
const ghRepoView = options . includeRemote === true && tools . gh . ok
? commandProbe ( "gh" , ghRepoArgs ( githubRepo ) , { timeoutMs : 15_000 } )
: null ;
const ghIssueView = options . includeRemote === true && tools . gh . ok && githubRepo !== null
? commandProbe ( "gh" , [ "issue" , "view" , String ( issueProbeNumber ) , "--repo" , githubRepo , "--json" , "number,title,state" ] , { timeoutMs : 15_000 } )
: null ;
const ghPrReadOnly = options . includeRemote === true && tools . gh . ok && githubRepo !== null
? commandProbe ( "gh" , [ "pr" , "list" , "--repo" , githubRepo , "--limit" , "1" , "--json" , "number,title,state,headRefName,baseRefName" ] , { timeoutMs : 15_000 } )
: null ;
const gitHttpsUrl = httpsGitUrl ( githubRepo , githubHost ) ;
const remote = options . includeRemote === true ? {
gitLsRemote : commandProbe ( "git" , [ "ls-remote" , "--heads" , "origin" , "master" ] , { timeoutMs : 20_000 } ) ,
gitHttpsLsRemote : gitHttpsUrl === null ? null : commandProbe ( "git" , [ "-c" , "credential.helper=" , "ls-remote" , "--heads" , gitHttpsUrl , "master" ] , { timeoutMs : 20_000 } ) ,
githubSshAuth : githubSshAuthProbe ? ? shellProbe ( "exit 1" , 1000 ) ,
githubSshAuthenticated ,
ghAuthStatus : tools.gh.ok ? commandProbe ( "gh" , [ "auth" , "status" , "-h" , githubHost ] , { timeoutMs : 10_000 } ) : null ,
ghRepoView ,
ghIssueView ,
ghPrReadOnly ,
} : undefined ;
const pushDryRunRef = options . pushDryRunRef ? . trim ( ) || "refs/heads/probe/code-queue-pr-capability-dryrun" ;
const pushDryRun = options . includePushDryRun === true
? commandProbe ( "git" , [ "push" , "--dry-run" , "origin" , ` HEAD: ${ pushDryRunRef } ` ] , { timeoutMs : 30_000 } )
: undefined ;
const limitations : string [ ] = [ ] ;
const risks : string [ ] = [ ] ;
if ( ! tools . git . ok ) limitations . push ( "missing git CLI" ) ;
if ( ! tools . jq . ok ) limitations . push ( "missing jq CLI" ) ;
if ( ! tools . gh . ok && ! tools . hub . ok ) limitations . push ( "missing PR CLI: install gh or hub" ) ;
if ( ! credentials . ghTokenPresent && ! credentials . githubTokenPresent ) limitations . push ( "GH_TOKEN/GITHUB_TOKEN is not present; gh cannot create PRs unless another gh credential store is mounted" ) ;
if ( ! credentials . ghHostsConfigPresent && ! credentials . gitCredentialsPresent && ! credentials . ghTokenPresent && ! credentials . githubTokenPresent ) limitations . push ( "no gh hosts config, git credentials file, GH_TOKEN, or GITHUB_TOKEN is visible for GitHub API/issue/PR access" ) ;
if ( ! gitInfo . insideWorktree ) limitations . push ( "current directory is not a Git worktree" ) ;
if ( gitInfo . remoteOrigin === null ) limitations . push ( "git remote origin is not configured" ) ;
if ( githubRepo === null ) limitations . push ( "cannot infer GitHub owner/repo from GH_REPO or git remote origin" ) ;
if ( ! gitInfo . homeWritable ) limitations . push ( "HOME is not writable" ) ;
if ( ! gitInfo . knownHostsPresent ) risks . push ( "GitHub known_hosts is not pre-seeded; first SSH use may need accept-new behavior" ) ;
if ( ! gitInfo . privateKeyPresent && ! credentials . sshAuthSockPresent && ! credentials . ghTokenPresent && ! credentials . githubTokenPresent ) limitations . push ( "no SSH key, SSH agent, or GitHub token credential is visible" ) ;
if ( egress . proxy . selectedProxyHost !== null && egress . proxy . selectedProxyHostResolvable === false ) limitations . push ( ` configured GitHub egress proxy host is not resolvable: ${ egress . proxy . selectedProxyHost } ` ) ;
if ( options . includeRemote === true && ! egress . githubDefault . ok ) limitations . push ( "GitHub HTTPS probe failed with the default environment/proxy" ) ;
if ( options . includeRemote === true && ! egress . apiDefault . ok ) limitations . push ( "GitHub API probe failed with the default environment/proxy" ) ;
if ( options . includeRemote === true && egress . issueApi !== null && ! egress . issueApi . ok ) limitations . push ( ` GitHub issue API probe for # ${ issueProbeNumber } failed; private repo access likely lacks token or egress ` ) ;
if ( remote !== undefined ) {
if ( ! remote . gitLsRemote . ok ) limitations . push ( "git ls-remote origin master failed" ) ;
if ( remote . gitHttpsLsRemote !== null && ! remote . gitHttpsLsRemote . ok ) limitations . push ( "anonymous HTTPS git ls-remote failed; HTTPS Git access likely needs token credentials" ) ;
if ( ! remote . githubSshAuthenticated ) limitations . push ( "GitHub SSH auth probe did not authenticate" ) ;
if ( remote . ghAuthStatus !== null && ! remote . ghAuthStatus . ok ) limitations . push ( "gh auth status failed" ) ;
if ( tools . gh . ok && remote . ghRepoView !== null && ! remote . ghRepoView . ok ) limitations . push ( "gh repo view failed" ) ;
if ( tools . gh . ok && remote . ghIssueView !== null && ! remote . ghIssueView . ok ) limitations . push ( ` gh issue view # ${ issueProbeNumber } failed ` ) ;
if ( tools . gh . ok && remote . ghPrReadOnly !== null && ! remote . ghPrReadOnly . ok ) limitations . push ( "gh pr read-only probe failed" ) ;
}
if ( pushDryRun !== undefined && ! pushDryRun . ok ) limitations . push ( "git push --dry-run failed for probe branch" ) ;
const prCliReady = tools . gh . ok || tools . hub . ok ;
const tokenOrGhStore = credentials . ghTokenPresent || credentials . githubTokenPresent || credentials . ghHostsConfigPresent || ( remote ? . ghAuthStatus ? . ok === true ) ;
const remoteReady = remote === undefined || ( egress . githubDefault . ok && egress . apiDefault . ok && remote . gitLsRemote . ok && remote . githubSshAuthenticated ) ;
const pushReady = pushDryRun === undefined || pushDryRun . ok ;
return {
ok : tools.git.ok && tools . jq . ok && prCliReady && tokenOrGhStore && gitInfo . insideWorktree && gitInfo . remoteOrigin !== null && gitInfo . homeWritable && remoteReady && pushReady ,
checkedAt ,
tools ,
credentials ,
githubContext : {
host : githubHost ,
apiBaseUrl : githubApiBaseUrl ,
repo : githubRepo ,
issueProbeNumber ,
} ,
egress ,
git : gitInfo ,
remote ,
pushDryRun ,
limitations ,
risks ,
} ;
}
function codexStatus ( path : string , checkedAt : string ) : RuntimePreflightPortStatus {
const commandV = shellProbe ( "command -v codex" ) ;
const version = commandProbe ( "codex" , [ "--version" ] ) ;
const appServerDryRun = commandProbe ( "codex" , [ "app-server" , "--help" ] ) ;
const errors = [ commandV , version , appServerDryRun ] . map ( errorSummary ) . filter ( ( value ) : value is string = > value !== null ) ;
return {
agentPort : "codex" ,
ok : errors.length === 0 ,
path ,
commandPath : firstLine ( commandV . stdout ) ,
version : firstLine ( version . stdout ) ? ? firstLine ( version . stderr ) ,
appServerDryRun ,
probes : { commandV , version } ,
errors ,
checkedAt ,
} ;
}
function opencodeStatus ( path : string , checkedAt : string ) : RuntimePreflightPortStatus {
const commandV = shellProbe ( "command -v opencode" ) ;
const version = commandProbe ( "opencode" , [ "--version" ] ) ;
const errors = [ commandV , version ] . map ( errorSummary ) . filter ( ( value ) : value is string = > value !== null ) ;
return {
agentPort : "opencode" ,
ok : errors.length === 0 ,
path ,
commandPath : firstLine ( commandV . stdout ) ,
version : firstLine ( version . stdout ) ? ? firstLine ( version . stderr ) ,
probes : { commandV , version } ,
errors ,
checkedAt ,
} ;
}
export function collectRuntimePreflight ( options : RuntimePreflightOptions = { } ) : RuntimePreflightReport {
const checkedAt = new Date ( ) . toISOString ( ) ;
const path = process . env . PATH ? ? "" ;
const ports = {
codex : codexStatus ( path , checkedAt ) ,
opencode : opencodeStatus ( path , checkedAt ) ,
} ;
const pullRequestDelivery = collectPullRequestDeliveryPreflight ( options , checkedAt ) ;
return {
ok : ports.codex.ok && ports . opencode . ok && pullRequestDelivery . ok ,
checkedAt ,
cwd : process.cwd ( ) ,
pid : process.pid ,
node : {
platform : process.platform ,
arch : process.arch ,
version : process.version ,
} ,
path ,
ports ,
pullRequestDelivery ,
} ;
}
export function runtimePreflightJson ( report : RuntimePreflightReport ) : JsonValue {
return report as unknown as JsonValue ;
}