fix(native): recover macOS command deadlines (#6059)

* fix(native): recover macOS command deadlines

Promote native_command_timeout_ms (default 60000), native_ui_deadline_ms
(default 180000), and pwntools_timeout_ms (default 30000) as validated
per-call settings. Keep cpuSeconds, byte allowances, LLDB grace, and plist
probes fixed, and say those caps have no runtime override.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(native): report the deadline that actually expired

Pass the selected native command timeout through xcrun resolution, thread
the pwntools deadline into pwndbg failures, and state the selected UI
deadline apart from the fixed wait-step cap. SIGXFSZ and EFBIG recovery
names the file-size allowance.

Co-authored-by: morluto <morluto@users.noreply.github.com>

* fix(native): honor the selected deadline on helper stages

The UI helper compile and capture subprocesses used fixed 60s and 30s
exec timeouts, so a longer native_ui_deadline_ms still failed as a generic
provider error. Preparation timeouts reported the 60000 ms default instead
of the selected native_command_timeout_ms.

Memory resource-constraint recovery names memory again, and the Darwin
plist CLI expectation matches the byte-counted input allowance.

Co-authored-by: morluto <morluto@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: morluto <morluto@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-10-22 02:59:27 +08:00
1 parent 67a6477f01
commit ae09e3fe70
55 files changed
+1365 -169

No files matched your search

+45 -3
View File
@@ -3,8 +3,13 @@ import {
AnalysisCancelledError,
AnalysisTimeoutError,
} from "../domain/analysisErrorCore.js";
import {
DEFAULT_NATIVE_UI_DEADLINE_MS,
nativeDeadlineRecovery,
} from "../domain/native/nativeDeadlines.js";
export const NATIVE_UI_DEADLINE_MS = 180_000;
/** Omitted `native_ui_deadline_ms`. */
export const NATIVE_UI_DEADLINE_MS = DEFAULT_NATIVE_UI_DEADLINE_MS;
type Interruption =
| { readonly kind: "caller"; readonly reason: unknown }
@@ -17,6 +22,7 @@ export class NativeUiInterruptionControl {
#interruption: Interruption | undefined;
#caller: AbortSignal | undefined;
#deadline: AbortSignal;
#deadlineMs: number;
#onCallerAbort = (): void => {
this.#interrupt("caller", this.#caller?.reason);
};
@@ -24,9 +30,19 @@ export class NativeUiInterruptionControl {
this.#interrupt("deadline", this.#deadline.reason);
};
constructor(caller: AbortSignal | undefined, deadline: AbortSignal) {
/** Selected `native_ui_deadline_ms`, including the omitted default. */
get deadlineMs(): number {
return this.#deadlineMs;
}
constructor(
caller: AbortSignal | undefined,
deadline: AbortSignal,
deadlineMs = NATIVE_UI_DEADLINE_MS,
) {
this.#caller = caller;
this.#deadline = deadline;
this.#deadlineMs = deadlineMs;
this.signal = this.#controller.signal;
// Match AbortSignal.any's iterable priority when both are already aborted.
@@ -40,6 +56,22 @@ export class NativeUiInterruptionControl {
}
}
/**
* A helper subprocess reached the selected deadline before the abort signal
* settled. Caller cancellation already recorded on this control stays primary.
*/
deadlineFailure(
operation: string,
partialObservation?: AnalysisPartialObservation,
): AnalysisTimeoutError | AnalysisCancelledError {
if (this.#interruption === undefined)
this.#interrupt("deadline", this.#deadline.reason);
const error = this.error(operation, partialObservation);
if (error === undefined)
throw new Error("UI deadline failure requires an interruption.");
return error;
}
error(
operation: string,
partialObservation?: AnalysisPartialObservation,
@@ -47,9 +79,19 @@ export class NativeUiInterruptionControl {
const interruption = this.#interruption;
if (interruption === undefined) return undefined;
return interruption.kind === "deadline"
? new AnalysisTimeoutError(operation, NATIVE_UI_DEADLINE_MS, {
? new AnalysisTimeoutError(operation, this.#deadlineMs, {
cause: interruption.reason,
partialObservation,
...nativeDeadlineRecovery({
timeoutMs: this.#deadlineMs,
setting: "native_ui_deadline_ms",
cliFlag: "--native-ui-deadline-ms",
defaultMs: NATIVE_UI_DEADLINE_MS,
phase: "native UI observation deadline",
detail: " A partial observation may already be retained.",
unchanged:
"The 67108864-byte scenario output allowance and the 180000 ms cap on one wait step have no runtime override.",
}),
})
: new AnalysisCancelledError(operation, {
cause: interruption.reason,