Files
maestro/src/engine/tools/console-run-lib.ts
T
oss-sync 03be80f036
CI / build-and-test (push) Has been cancelled
sync: update from private repo (6c4d482)
2026-06-08 01:01:47 +00:00

46 lines
2.0 KiB
TypeScript

import { randomBytes } from 'node:crypto';
const MARKER_PREFIX = '__MAESTRO_DONE_';
export function makeNonce(): string {
return randomBytes(16).toString('hex');
}
export function makeMarkerCommand(command: string, nonce: string): { text: string; marker: string } {
const marker = `${MARKER_PREFIX}${nonce}:`;
// `$?` after `command;` reflects the command's exit code.
return { text: `${command}; echo "${marker}$?__"\n`, marker };
}
export function parseMarker(text: string, nonce: string): { found: boolean; exitCode: number | null } {
const re = new RegExp(`${MARKER_PREFIX}${nonce}:(\\d+)__`);
const m = re.exec(text);
if (!m) return { found: false, exitCode: null };
return { found: true, exitCode: Number(m[1]) };
}
// Best-effort: drop the echoed command line and the marker line(s). PTY echo /
// prompt noise may remain — perfect formatting is a non-goal.
export function extractOutput(raw: string, command: string, nonce: string): string {
const markerRe = new RegExp(`${MARKER_PREFIX}${nonce}:.*?__`);
return raw
.split('\n')
.filter((line) => !markerRe.test(line))
.filter((line) => line.trim() !== `${command}; echo "${MARKER_PREFIX}${nonce}:$?__"`)
.join('\n');
}
const WAITING_RE = /(password:|\[y\/n\]|\(yes\/no\)\??|continue\?|press .*key|passphrase:)\s*$/i;
export function detectWaitingForInput(screenTail: string): boolean {
const lastLines = screenTail.split('\n').slice(-3).join('\n').trim();
return WAITING_RE.test(lastLines);
}
export interface InterruptLiveness { idleMs: number; msSinceAiInput: number; sessionAgeMs: number; }
const GUARD_IDLE_MS = 3000, GUARD_RECENT_INPUT_MS = 5000, GUARD_SESSION_AGE_MS = 5000;
export function shouldGuardInterrupt(l: InterruptLiveness, confirmInterrupt: boolean): boolean {
if (confirmInterrupt) return false;
const alive = l.idleMs < GUARD_IDLE_MS || l.msSinceAiInput < GUARD_RECENT_INPUT_MS || l.sessionAgeMs < GUARD_SESSION_AGE_MS;
return alive; // true => block the interrupt
}