This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user