142 lines
4.5 KiB
TypeScript
142 lines
4.5 KiB
TypeScript
import type {
|
|
MemberLaunchState,
|
|
MemberSpawnStatus,
|
|
TeamAgentRuntimeDiagnosticSeverity,
|
|
TeamAgentRuntimeLivenessKind,
|
|
} from '@shared/types';
|
|
|
|
export interface ProvisionedButNotAliveLaunchEntry {
|
|
launchState?: MemberLaunchState;
|
|
status?: MemberSpawnStatus;
|
|
hardFailure?: boolean;
|
|
hardFailureReason?: string;
|
|
error?: string;
|
|
runtimeDiagnostic?: string;
|
|
runtimeDiagnosticSeverity?: TeamAgentRuntimeDiagnosticSeverity;
|
|
bootstrapConfirmed?: boolean;
|
|
livenessKind?: TeamAgentRuntimeLivenessKind;
|
|
}
|
|
|
|
export function stripProcessTableUnavailableDiagnosticSuffix(reason: string): string | null {
|
|
const match = /^(.*?);\s*process table (?:is )?unavailable$/i.exec(reason.trim());
|
|
const baseReason = match?.[1]?.trim();
|
|
return baseReason && baseReason.length > 0 ? baseReason : null;
|
|
}
|
|
|
|
export function isProvisionedButNotAliveFailureReason(reason?: string): boolean {
|
|
return isCliProvisionedButNotAliveFailureReason(reason);
|
|
}
|
|
|
|
export function isCliProvisionedButNotAliveFailureReason(reason?: string): boolean {
|
|
const text = reason?.trim();
|
|
if (!text) {
|
|
return false;
|
|
}
|
|
const normalizedText = stripProcessTableUnavailableDiagnosticSuffix(text) ?? text;
|
|
return /^CLI process exited \(code (?:unknown|-?\d+|\?)\)\s+[-\u2013\u2014]\s+team provisioned but not alive$/i.test(
|
|
normalizedText
|
|
);
|
|
}
|
|
|
|
export function mentionsProcessTableUnavailable(value: string | undefined): boolean {
|
|
return /\bprocess table\b.*\bunavailable\b/i.test(value ?? '');
|
|
}
|
|
|
|
export function hasBootstrapConfirmationProofForLaunchFailure(
|
|
entry: ProvisionedButNotAliveLaunchEntry | undefined
|
|
): boolean {
|
|
return (
|
|
entry?.bootstrapConfirmed === true ||
|
|
entry?.launchState === 'confirmed_alive' ||
|
|
entry?.livenessKind === 'confirmed_bootstrap'
|
|
);
|
|
}
|
|
|
|
export function isProvisionedButNotAliveLaunchFailure(
|
|
entry: ProvisionedButNotAliveLaunchEntry | undefined
|
|
): boolean {
|
|
if (!entry) {
|
|
return false;
|
|
}
|
|
const hardFailureReason = entry.hardFailureReason?.trim();
|
|
const failureReasonMatches = hardFailureReason
|
|
? isProvisionedButNotAliveFailureReason(hardFailureReason)
|
|
: isProvisionedButNotAliveFailureReason(entry.error ?? entry.runtimeDiagnostic);
|
|
if (!failureReasonMatches) {
|
|
return false;
|
|
}
|
|
return (
|
|
entry.launchState === 'failed_to_start' ||
|
|
entry.status === 'error' ||
|
|
entry.hardFailure === true
|
|
);
|
|
}
|
|
|
|
export function isBootstrapConfirmedProvisionedButNotAliveFailure(
|
|
entry: ProvisionedButNotAliveLaunchEntry | undefined
|
|
): boolean {
|
|
return (
|
|
isProvisionedButNotAliveLaunchFailure(entry) &&
|
|
hasBootstrapConfirmationProofForLaunchFailure(entry)
|
|
);
|
|
}
|
|
|
|
export function hasUnsafeProvisionedButNotAliveRuntimeEvidence(
|
|
entry: ProvisionedButNotAliveLaunchEntry | undefined
|
|
): boolean {
|
|
if (!entry) {
|
|
return false;
|
|
}
|
|
if (entry.runtimeDiagnosticSeverity === 'error') {
|
|
return true;
|
|
}
|
|
if (
|
|
entry.livenessKind === 'not_found' ||
|
|
entry.livenessKind === 'shell_only' ||
|
|
entry.livenessKind === 'permission_blocked' ||
|
|
entry.livenessKind === 'runtime_process_candidate'
|
|
) {
|
|
return true;
|
|
}
|
|
const hasProcessTableUnavailableMarker =
|
|
mentionsProcessTableUnavailable(entry.runtimeDiagnostic) ||
|
|
mentionsProcessTableUnavailable(entry.hardFailureReason) ||
|
|
mentionsProcessTableUnavailable(entry.error);
|
|
if (!entry.livenessKind) {
|
|
return !hasProcessTableUnavailableMarker;
|
|
}
|
|
if (entry.livenessKind !== 'registered_only' && entry.livenessKind !== 'stale_metadata') {
|
|
return false;
|
|
}
|
|
return !hasProcessTableUnavailableMarker;
|
|
}
|
|
|
|
export function hasUnsafeProvisionedButNotAliveRuntimeEvidenceWithSpawnContext(
|
|
spawnEntry: ProvisionedButNotAliveLaunchEntry | undefined,
|
|
runtimeEntry: ProvisionedButNotAliveLaunchEntry | undefined
|
|
): boolean {
|
|
if (hasUnsafeProvisionedButNotAliveRuntimeEvidence(spawnEntry)) {
|
|
return true;
|
|
}
|
|
if (!runtimeEntry) {
|
|
return false;
|
|
}
|
|
|
|
const runtimeDiagnostic = runtimeEntry.runtimeDiagnostic?.trim();
|
|
if (
|
|
!runtimeDiagnostic &&
|
|
(runtimeEntry.livenessKind == null ||
|
|
runtimeEntry.livenessKind === 'registered_only' ||
|
|
runtimeEntry.livenessKind === 'stale_metadata')
|
|
) {
|
|
return hasUnsafeProvisionedButNotAliveRuntimeEvidence({
|
|
runtimeDiagnostic: spawnEntry?.runtimeDiagnostic,
|
|
hardFailureReason: spawnEntry?.hardFailureReason,
|
|
error: spawnEntry?.error,
|
|
runtimeDiagnosticSeverity: runtimeEntry.runtimeDiagnosticSeverity,
|
|
livenessKind: runtimeEntry.livenessKind,
|
|
});
|
|
}
|
|
|
|
return hasUnsafeProvisionedButNotAliveRuntimeEvidence(runtimeEntry);
|
|
}
|