88 lines
2.4 KiB
TypeScript
88 lines
2.4 KiB
TypeScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import {
|
|
ARTIFACT_EVIDENCE_KINDS,
|
|
DB_EVIDENCE_ACTIONS,
|
|
DEPLOY_EVIDENCE_ACTIONS,
|
|
GITHUB_EVIDENCE_ACTIONS,
|
|
HOST_EVIDENCE_ACTIONS,
|
|
type HostEvidenceAction,
|
|
} from 'ejclaw-runners-shared';
|
|
|
|
export {
|
|
ARTIFACT_EVIDENCE_KINDS,
|
|
DB_EVIDENCE_ACTIONS,
|
|
DEPLOY_EVIDENCE_ACTIONS,
|
|
GITHUB_EVIDENCE_ACTIONS,
|
|
HOST_EVIDENCE_ACTIONS,
|
|
type HostEvidenceAction,
|
|
};
|
|
|
|
export interface HostEvidenceResponse {
|
|
requestId: string;
|
|
ok: boolean;
|
|
action: HostEvidenceAction;
|
|
command: string;
|
|
stdout: string;
|
|
stderr: string;
|
|
exitCode: number;
|
|
error?: string;
|
|
}
|
|
|
|
const DEFAULT_LOG_TAIL_LINES = 20;
|
|
const MAX_LOG_TAIL_LINES = 200;
|
|
|
|
export function normalizeHostEvidenceTailLines(value?: number): number {
|
|
if (!Number.isFinite(value)) {
|
|
return DEFAULT_LOG_TAIL_LINES;
|
|
}
|
|
const normalized = Math.trunc(value as number);
|
|
return Math.min(Math.max(normalized, 1), MAX_LOG_TAIL_LINES);
|
|
}
|
|
|
|
export function resolveHostEvidenceResponsesDir(hostIpcDir: string): string {
|
|
return path.join(hostIpcDir, 'host-evidence-responses');
|
|
}
|
|
|
|
export async function waitForHostEvidenceResponse(
|
|
responseDir: string,
|
|
requestId: string,
|
|
options?: {
|
|
timeoutMs?: number;
|
|
pollMs?: number;
|
|
},
|
|
): Promise<HostEvidenceResponse> {
|
|
const timeoutMs = options?.timeoutMs ?? 7_000;
|
|
const pollMs = options?.pollMs ?? 100;
|
|
const responsePath = path.join(responseDir, `${requestId}.json`);
|
|
const deadline = Date.now() + timeoutMs;
|
|
|
|
while (Date.now() <= deadline) {
|
|
if (fs.existsSync(responsePath)) {
|
|
const response = JSON.parse(
|
|
fs.readFileSync(responsePath, 'utf-8'),
|
|
) as HostEvidenceResponse;
|
|
fs.unlinkSync(responsePath);
|
|
return response;
|
|
}
|
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
}
|
|
|
|
throw new Error(`Timed out waiting for host evidence response: ${requestId}`);
|
|
}
|
|
|
|
export function formatHostEvidenceResponse(
|
|
response: HostEvidenceResponse,
|
|
): string {
|
|
const parts = [
|
|
`Host evidence action: ${response.action}`,
|
|
`Exit code: ${response.exitCode}`,
|
|
response.command ? `$ ${response.command}` : null,
|
|
response.stdout ? response.stdout.trimEnd() : null,
|
|
response.stderr ? `[stderr]\n${response.stderr.trimEnd()}` : null,
|
|
response.error ? `[error] ${response.error}` : null,
|
|
].filter((value): value is string => Boolean(value));
|
|
|
|
return parts.join('\n');
|
|
}
|