← Files Codex Browser RecorderARCHIVED FILE
skills/record-browser/scripts/recording-outcome.mjs
10 KB · Sep 30, 2026 · 23:13 UTC
const CAPTURE_RESULT_FIELDS = [
"backpressureDrops",
"cursorChildFrameEventsCaptured",
"elapsedMs",
"encoderExitCode",
"framesAcknowledged",
"framesDropped",
"framesReceived",
"invalidFrames",
"lastFrameTimestamp",
"maxObservedOutputBytes",
"outputSamples",
"terminationReason",
"truncations",
"visibilityChanges",
"visibilityState",
];
const VIDEO_VALIDATION_FAILURE_CODES = new Set([
"audio_stream_present",
"codec_invalid",
"container_invalid",
"dimensions_out_of_bounds",
"duration_invalid",
"duration_mismatch",
"ffprobe_failed",
"invalid_configuration",
"output_missing",
"output_too_small",
"pixel_format_invalid",
"video_stream_count_invalid",
"video_stream_missing",
]);
const CAPTURE_FAILURE_CODES = new Set([
"cdp_unavailable",
"cursor_recording_failed",
"encoder_failed",
"encoder_finalize_failed",
"encoder_shutdown_timeout",
"event_stream_invalid",
"frame_ack_failed",
"frame_stream_stalled",
"frame_stream_unavailable",
"frame_too_large",
"integration_failed",
"invalid_configuration",
"invalid_frame",
"origin_not_allowed",
"origin_changed_during_recording",
"origin_verification_failed",
"output_monitor_failed",
"recording_cancelled",
"recording_duration_limit",
"recording_output_limit",
]);
const MESSAGE_GROUPS = [
{
codes: ["cursor_recording_failed"],
summary: "Cursor or click feedback was missing",
remediation:
"Make each pointer action clear, then record the flow again",
},
{
codes: [
"invalid_target",
"target_credentials_present",
"target_scheme_not_allowed",
"invalid_duration",
],
summary: "This recording request is not supported",
remediation:
"Use an HTTPS page (or localhost) without URL credentials, and choose 5 to 60 seconds",
},
{
codes: [
"browser_plugin_unavailable",
"cdp_unavailable",
"plugin_module_unavailable",
],
summary: "Browser Recorder could not connect to the Codex In-app Browser",
remediation:
"Make sure the Codex In-app Browser is available and full CDP access is enabled in Codex settings, then try again",
},
{
codes: ["browser_visibility_unavailable"],
summary:
"The Codex In-app Browser could not enter the approved visibility mode",
remediation:
"Keep Codex open and make sure the Codex In-app Browser visibility can be controlled, then try again",
},
{
codes: ["unsupported_platform"],
summary: "Browser Recorder currently works only on macOS",
remediation: "Use the Codex desktop app on a Mac",
},
{
codes: ["ffmpeg_missing", "ffprobe_missing"],
summary: "FFmpeg is not installed or is not available to Codex",
remediation:
"Install FFmpeg (Homebrew: brew install ffmpeg), then run the setup check again",
},
{
codes: [
"ffmpeg_h264_unavailable",
"ffmpeg_mp4_unavailable",
"ffprobe_unusable",
],
summary: "This FFmpeg installation cannot create the required video",
remediation:
"Install a complete FFmpeg build with H.264 and MP4 support, then run the setup check again",
},
{
codes: ["output_directory_not_writable"],
summary: "The selected folder cannot be used for recordings",
remediation:
"Choose a writable local folder or allow folder access in macOS, then try again",
},
{
codes: ["cancelled", "recording_cancelled"],
summary: "Recording was cancelled",
remediation:
"Start again when you are ready and approve the requested scope",
},
{
codes: ["setup_cancelled"],
summary: "Setup check was cancelled",
remediation: "Run the setup check again when you are ready",
},
{
codes: ["setup_timeout"],
summary: "Setup check timed out while testing the Codex In-app Browser",
remediation:
"Keep Codex open, confirm the Codex In-app Browser is available, and run the setup check again",
},
{
codes: ["browser_tab_cleanup_failed"],
summary: "The setup diagnostic tab could not be cleaned up",
remediation:
"Close the fresh setup diagnostic tab manually, then run the setup check again",
},
{
codes: [
"origin_not_allowed",
"origin_verification_failed",
"origin_changed_during_recording",
],
summary: "Recording stopped because the tab opened another website",
remediation:
"Start a new recording and keep the tab on the approved site",
},
{
codes: [
"event_stream_invalid",
"frame_ack_failed",
"frame_stream_stalled",
"frame_stream_unavailable",
"frame_too_large",
"invalid_frame",
],
summary: "The Codex In-app Browser stopped sending video frames",
remediation:
"Confirm full CDP access is enabled in Codex settings, then try again",
},
{
codes: [
"output_monitor_failed",
"recording_duration_limit",
"recording_output_limit",
],
summary: "Recording stopped at a safety limit",
remediation:
"Use a shorter or less visually intensive flow and try again",
},
{
codes: [
"encoder_failed",
"encoder_finalize_failed",
"encoder_shutdown_timeout",
],
summary: "FFmpeg could not finish the video",
remediation:
"Run preflight and verify local FFmpeg H.264 MP4 support before retrying",
},
{
codes: [
"audio_stream_present",
"codec_invalid",
"container_invalid",
"dimensions_out_of_bounds",
"duration_invalid",
"duration_mismatch",
"ffprobe_failed",
"output_missing",
"output_too_small",
"pixel_format_invalid",
"video_stream_count_invalid",
"video_stream_missing",
],
summary: "The video could not be verified, so it was not saved",
remediation:
"Run preflight, verify local H.264 MP4 support, and record the flow again",
},
{
codes: ["saved_recording_unavailable"],
summary: "The selected folder cannot be used for recordings",
remediation:
"Choose a writable local folder, approve macOS file access if requested, and retry",
},
{
codes: ["saved_recording_persistence_failed"],
summary: "The recording was captured but could not be saved",
remediation:
"Use the temporary recovery folder shown in the result, or choose another writable folder and try again",
},
{
codes: ["artifact_persistence_failed", "cleanup_failed"],
summary: "Temporary recording files could not be cleaned up",
remediation:
"Check temporary storage permissions and free space, then retry",
},
{
codes: [
"capture_failed",
"integration_failed",
"invalid_configuration",
"recording_already_active",
"recording_not_started",
"recording_failed",
],
summary: "The recording could not be completed",
remediation: "Run the setup check, then try one recording at a time",
},
];
const USER_MESSAGES = new Map(
MESSAGE_GROUPS.flatMap(({ codes, remediation, summary }) =>
codes.map((code) => [code, Object.freeze({ remediation, summary })]),
),
);
export const RECORDING_FAILURE_CODES = Object.freeze(
[...USER_MESSAGES.keys()].toSorted(),
);
const RECORDING_CLEANUP_DETAILS = new WeakMap();
export function getRecordingCleanupDetails(error) {
const details = RECORDING_CLEANUP_DETAILS.get(error);
return details === undefined ? null : { ...details };
}
export function describeRecordingFailure(code) {
return USER_MESSAGES.get(code) ?? USER_MESSAGES.get("recording_failed");
}
export function sanitizeRecordingFailure(
error,
{
artifactCleanupIncomplete = false,
browserTabCleanupIncomplete = false,
cleanupDirectory,
cleanupFile,
resourceCleanupIncomplete = false,
} = {},
) {
const code = USER_MESSAGES.has(error?.code)
? error.code
: "recording_failed";
const { remediation, summary } = describeRecordingFailure(code);
const publicError = Object.assign(new Error(summary), {
code,
remediation,
summary,
});
const inherited = RECORDING_CLEANUP_DETAILS.get(error) ?? {};
const details = {
...inherited,
...(artifactCleanupIncomplete === true
? { artifactCleanupIncomplete: true }
: {}),
...(browserTabCleanupIncomplete === true
? { browserTabCleanupIncomplete: true }
: {}),
...(resourceCleanupIncomplete === true
? { resourceCleanupIncomplete: true }
: {}),
...(typeof cleanupDirectory === "string" && cleanupDirectory.length > 0
? {
cleanupIncomplete: true,
directory: cleanupDirectory,
}
: {}),
...(typeof cleanupFile === "string" && cleanupFile.length > 0
? {
cleanupFile,
cleanupIncomplete: true,
}
: {}),
};
if (Object.keys(details).length > 0) {
RECORDING_CLEANUP_DETAILS.set(publicError, Object.freeze(details));
}
return publicError;
}
export function sanitizeCaptureResult(capture) {
return Object.fromEntries(
CAPTURE_RESULT_FIELDS.map((field) => [field, capture[field] ?? null]),
);
}
export function sanitizeCaptureStatus(capture) {
return {
...sanitizeCaptureResult(capture),
cursorEventsCaptured: capture.cursorEventsCaptured ?? null,
cursorFramesObserved: capture.cursorFramesObserved ?? null,
cursorLastEventEpochMs: capture.cursorLastEventEpochMs ?? null,
};
}
export function captureFailureCode(error) {
if (error == null) return null;
return CAPTURE_FAILURE_CODES.has(error.code)
? error.code
: "capture_failed";
}
export function isVideoValidationFailure(error) {
return VIDEO_VALIDATION_FAILURE_CODES.has(error?.code);
}
export function createRecordingOutcome({
capture,
failureCode,
outputFile,
validation,
}) {
const { summary, remediation } =
failureCode === null
? {
summary: "Recording completed successfully",
remediation: "No action is required",
}
: describeRecordingFailure(failureCode);
return {
capture: sanitizeCaptureResult(capture),
failureCode,
media: validation,
outputFile,
recorderContractVersion: 1,
remediation,
schemaVersion: 3,
status: failureCode === null ? "passed" : "failed",
summary,
};
}
SHA-256: db83285b08994d9a237666f7ff59e7ea937738845dc5ad88fa923cfd03e6f758