fix(web-probe): stabilize browser transport sampling (#717)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-23 05:14:03 +08:00
committed by GitHub
parent ffbc70105f
commit 4a471dc9dd
4 changed files with 66 additions and 15 deletions
+23 -6
View File
@@ -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");