fix(web-probe): stabilize browser transport sampling (#717)
Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
@@ -20,6 +20,7 @@ import type { RenderedCliResult } from "./output";
|
||||
type SecretAction = "status" | "ensure" | "cleanup-owned-postgres" | "cleanup-obsolete";
|
||||
type SecretPreset = "openfga" | "master-server-admin-api-key" | "bootstrap-admin" | "code-agent-provider" | "cloud-api-db" | "owned-postgres-cleanup" | "obsolete-secret-cleanup";
|
||||
type NodeRuntimeRenderLocation = "node-host" | "local";
|
||||
type WebProbeBrowserProxyMode = "auto" | "direct";
|
||||
|
||||
interface NodeWebProbeRunOptions {
|
||||
action: "run";
|
||||
@@ -48,6 +49,7 @@ interface NodeWebProbeScriptOptions {
|
||||
url: string;
|
||||
timeoutMs: number;
|
||||
viewport: string;
|
||||
browserProxyMode: WebProbeBrowserProxyMode;
|
||||
commandTimeoutSeconds: number;
|
||||
scriptText: string;
|
||||
scriptSource: {
|
||||
@@ -70,6 +72,7 @@ interface NodeWebProbeObserveOptions {
|
||||
url: string;
|
||||
targetPath: string;
|
||||
viewport: string;
|
||||
browserProxyMode: WebProbeBrowserProxyMode;
|
||||
sampleIntervalMs: number;
|
||||
screenshotIntervalMs: number;
|
||||
observerRefreshIntervalMs: number;
|
||||
@@ -6774,6 +6777,7 @@ function parseNodeWebProbeOptions(args: string[]): NodeWebProbeOptions {
|
||||
"--url",
|
||||
"--timeout-ms",
|
||||
"--viewport",
|
||||
"--browser-proxy-mode",
|
||||
"--script-file",
|
||||
"--command-timeout-seconds",
|
||||
]), new Set([]));
|
||||
@@ -6792,6 +6796,7 @@ function parseNodeWebProbeOptions(args: string[]): NodeWebProbeOptions {
|
||||
url: optionValue(args, "--url") ?? spec.publicWebUrl,
|
||||
timeoutMs,
|
||||
viewport: optionValue(args, "--viewport") ?? "1440x900",
|
||||
browserProxyMode: parseWebProbeBrowserProxyMode(optionValue(args, "--browser-proxy-mode")),
|
||||
commandTimeoutSeconds,
|
||||
scriptText,
|
||||
scriptSource: {
|
||||
@@ -6899,6 +6904,7 @@ function parseNodeWebProbeObserveOptions(
|
||||
"--url",
|
||||
"--target-path",
|
||||
"--viewport",
|
||||
"--browser-proxy-mode",
|
||||
"--sample-interval-ms",
|
||||
"--screenshot-interval-ms",
|
||||
"--observer-refresh-interval-ms",
|
||||
@@ -6940,6 +6946,7 @@ function parseNodeWebProbeObserveOptions(
|
||||
url: optionValue(args, "--url") ?? spec.publicWebUrl,
|
||||
targetPath: optionValue(args, "--target-path") ?? "/workbench",
|
||||
viewport: optionValue(args, "--viewport") ?? "1440x900",
|
||||
browserProxyMode: parseWebProbeBrowserProxyMode(optionValue(args, "--browser-proxy-mode")),
|
||||
sampleIntervalMs: positiveIntegerOption(args, "--sample-interval-ms", 5000, 600000),
|
||||
screenshotIntervalMs: positiveIntegerOption(args, "--screenshot-interval-ms", 300000, 86_400_000),
|
||||
observerRefreshIntervalMs: positiveIntegerOption(args, "--observer-refresh-interval-ms", 180000, 86_400_000),
|
||||
@@ -6979,6 +6986,12 @@ function parseNodeWebProbeObserveCommandType(value: string): NodeWebProbeObserve
|
||||
throw new Error(`web-probe observe command --type must be login, preflight, goto, newSession, sendPrompt, selectProvider, clickSession, screenshot, mark, or stop; got ${value}`);
|
||||
}
|
||||
|
||||
function parseWebProbeBrowserProxyMode(value: string | undefined): WebProbeBrowserProxyMode {
|
||||
if (value === undefined || value === "auto") return "auto";
|
||||
if (value === "direct") return "direct";
|
||||
throw new Error(`web-probe --browser-proxy-mode must be auto or direct, got ${value}`);
|
||||
}
|
||||
|
||||
function nodeWebProbeAutoCommandTimeoutSeconds(input: {
|
||||
timeoutMs: number;
|
||||
waitAfterSubmitMs: number;
|
||||
@@ -7421,6 +7434,7 @@ function runNodeWebProbeObserveStart(
|
||||
`UNIDESK_WEB_OBSERVE_OBSERVER_REFRESH_INTERVAL_MS=${shellQuote(String(options.observerRefreshIntervalMs))}`,
|
||||
`UNIDESK_WEB_OBSERVE_MAX_SAMPLES=${shellQuote(String(options.maxSamples))}`,
|
||||
`UNIDESK_WEB_OBSERVE_VIEWPORT=${shellQuote(options.viewport)}`,
|
||||
`UNIDESK_WEB_OBSERVE_BROWSER_PROXY_MODE=${shellQuote(options.browserProxyMode)}`,
|
||||
].join(" ");
|
||||
const script = [
|
||||
"set -eu",
|
||||
@@ -9505,23 +9519,24 @@ function runNodeWebProbeScript(
|
||||
const webProbeProxy = nodeWebProbeHostProxyEnv(spec);
|
||||
const script = nodeWebProbeScriptRemoteShell(options, secretSpec, material.password ?? "", webProbeProxy);
|
||||
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
|
||||
const commandTimedOut = result.timedOut || result.exitCode === 124;
|
||||
const stdoutReport = parseJsonObject(result.stdout);
|
||||
const runPaths = webProbeScriptRunPathsFromStderr(result.stderr);
|
||||
const recoveredReport = stdoutReport === null ? readNodeWebProbeScriptReport(options, spec, runPaths.reportPath) : null;
|
||||
const recoveredArtifacts = stdoutReport === null || result.timedOut ? readNodeWebProbeScriptArtifacts(options, spec, runPaths.runDir) : null;
|
||||
const recoveredArtifacts = stdoutReport === null || commandTimedOut ? readNodeWebProbeScriptArtifacts(options, spec, runPaths.runDir) : null;
|
||||
const parsedReport = stdoutReport ?? recoveredReport?.report ?? null;
|
||||
const report = compactWebProbeScriptResult(parsedReport);
|
||||
const passed = result.exitCode === 0 && report?.ok === true;
|
||||
const summary = nullableRecord(report?.summary);
|
||||
const stdoutBytes = Buffer.byteLength(result.stdout, "utf8");
|
||||
const outputFailureKind = parsedReport === null
|
||||
? result.timedOut
|
||||
? commandTimedOut
|
||||
? "web-probe-command-timeout"
|
||||
: stdoutBytes > 64 * 1024
|
||||
? "web-probe-output-too-large"
|
||||
: "web-probe-report-parse-failed"
|
||||
: null;
|
||||
const degradedReason = result.timedOut
|
||||
const degradedReason = commandTimedOut
|
||||
? "web-probe-command-timeout"
|
||||
: typeof summary?.degradedReason === "string"
|
||||
? summary.degradedReason
|
||||
@@ -9529,10 +9544,10 @@ function runNodeWebProbeScript(
|
||||
? report.failureKind
|
||||
: outputFailureKind
|
||||
? outputFailureKind
|
||||
: result.timedOut
|
||||
: commandTimedOut
|
||||
? "web-probe-command-timeout"
|
||||
: null;
|
||||
const failureKind = result.timedOut
|
||||
const failureKind = commandTimedOut
|
||||
? "web-probe-command-timeout"
|
||||
: typeof summary?.failureKind === "string"
|
||||
? summary.failureKind
|
||||
@@ -9541,7 +9556,7 @@ function runNodeWebProbeScript(
|
||||
: outputFailureKind;
|
||||
const effectiveSummary = summary !== null ? {
|
||||
...summary,
|
||||
transportTimedOut: result.timedOut,
|
||||
transportTimedOut: commandTimedOut,
|
||||
recoveredFrom: stdoutReport !== null ? "stdout" : recoveredReport?.source ?? null,
|
||||
} : (outputFailureKind === null ? null : {
|
||||
ok: false,
|
||||
@@ -9564,6 +9579,7 @@ function runNodeWebProbeScript(
|
||||
screenshots: recoveredArtifacts?.screenshots ?? [],
|
||||
artifacts: recoveredArtifacts?.artifacts ?? null,
|
||||
stdoutBytes,
|
||||
exitCode: result.exitCode,
|
||||
stderrTail: result.stderr.trim().slice(-2000),
|
||||
valuesRedacted: true,
|
||||
});
|
||||
@@ -9631,6 +9647,7 @@ function nodeWebProbeScriptRemoteShell(options: NodeWebProbeScriptOptions, secre
|
||||
"UNIDESK_WEB_PROBE_USER_SCRIPT=\"$user_script\"",
|
||||
`UNIDESK_WEB_PROBE_TIMEOUT_MS=${shellQuote(String(options.timeoutMs))}`,
|
||||
`UNIDESK_WEB_PROBE_VIEWPORT=${shellQuote(options.viewport)}`,
|
||||
`UNIDESK_WEB_PROBE_BROWSER_PROXY_MODE=${shellQuote(options.browserProxyMode)}`,
|
||||
"node \"$runner\"",
|
||||
].join(" "),
|
||||
].join("\n");
|
||||
|
||||
Reference in New Issue
Block a user