fix(cli): recover web observe collect JSON dumps
This commit is contained in:
@@ -317,6 +317,8 @@ function renderWebObserveCollectTable(value: Record<string, unknown>): string {
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (collect === null) {
|
if (collect === null) {
|
||||||
|
const stdoutRecovery = record(value.stdoutRecovery) ?? record(result.stdoutRecovery);
|
||||||
|
const artifact = record(stdoutRecovery?.artifact);
|
||||||
lines.push(
|
lines.push(
|
||||||
"Collect command:",
|
"Collect command:",
|
||||||
webObserveTable(["REQUESTED", "REASON", "EXIT", "TIMED_OUT", "STDOUT_BYTES", "STDOUT_TAIL", "STDERR"], [[
|
webObserveTable(["REQUESTED", "REASON", "EXIT", "TIMED_OUT", "STDOUT_BYTES", "STDOUT_TAIL", "STDERR"], [[
|
||||||
@@ -329,8 +331,19 @@ function renderWebObserveCollectTable(value: Record<string, unknown>): string {
|
|||||||
webObserveShort(webObserveText(result.stderr), 160),
|
webObserveShort(webObserveText(result.stderr), 160),
|
||||||
]]),
|
]]),
|
||||||
"",
|
"",
|
||||||
|
"Stdout recovery:",
|
||||||
|
webObserveTable(["REQUESTED_TYPE", "STDOUT_KIND", "SOURCE", "FALLBACK_REASON", "DUMP_PATH", "ARTIFACT_PATH", "NEXT"], [[
|
||||||
|
webObserveShort(webObserveText(stdoutRecovery?.requestedStdoutType), 42),
|
||||||
|
webObserveShort(webObserveText(stdoutRecovery?.stdoutKind), 28),
|
||||||
|
webObserveShort(webObserveText(stdoutRecovery?.source), 20),
|
||||||
|
webObserveShort(webObserveText(stdoutRecovery?.fallbackReason), 40),
|
||||||
|
webObserveShort(webObserveText(stdoutRecovery?.dumpPath), 72),
|
||||||
|
webObserveShort(webObserveText(artifact?.path ?? artifact?.requestedPath), 72),
|
||||||
|
webObserveShort(webObserveText(artifact?.nextCommand), 96),
|
||||||
|
]]),
|
||||||
|
"",
|
||||||
"Disclosure:",
|
"Disclosure:",
|
||||||
" collect stdout was not valid JSON; fix the collect command or rerun with a narrower --file after the root cause is visible.",
|
" collect stdout could not be recovered as a valid collect contract; inspect dumpPath or artifact path when present, otherwise rerun with a narrower --file.",
|
||||||
);
|
);
|
||||||
return lines.join("\n");
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
import { mkdirSync, writeFileSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import type { CommandResult } from "../command";
|
||||||
|
import type { NodeWebProbeObserveOptions } from "./entry";
|
||||||
|
import { buildNodeWebProbeObserveCollectPayload } from "./web-probe-observe-collect";
|
||||||
|
|
||||||
|
describe("web-probe observe collect child JSON recovery", () => {
|
||||||
|
test("recovers collect JSON from trans stdout dump", () => {
|
||||||
|
const dir = join(tmpdir(), `unidesk-collect-recovery-${Date.now()}-${process.pid}`);
|
||||||
|
mkdirSync(dir, { recursive: true });
|
||||||
|
const dumpPath = join(dir, "stdout.json");
|
||||||
|
writeFileSync(dumpPath, JSON.stringify({
|
||||||
|
ok: true,
|
||||||
|
command: "web-probe-observe collect",
|
||||||
|
view: "performance-summary",
|
||||||
|
stateDir: "/remote/state",
|
||||||
|
renderedText: "WEB PERFORMANCE SUMMARY\npayloads=2 events=3 groups=1",
|
||||||
|
valuesRedacted: true,
|
||||||
|
}));
|
||||||
|
const summary = {
|
||||||
|
stdout: {
|
||||||
|
stream: "stdout",
|
||||||
|
truncated: true,
|
||||||
|
dumpPath,
|
||||||
|
valuesRedacted: true,
|
||||||
|
},
|
||||||
|
valuesRedacted: true,
|
||||||
|
};
|
||||||
|
const payload = buildNodeWebProbeObserveCollectPayload(collectOptions(), { workspace: "/workspace" }, {
|
||||||
|
command: ["trans", "JD01:/workspace", "sh"],
|
||||||
|
cwd: "/repo",
|
||||||
|
exitCode: 0,
|
||||||
|
stdout: "tail only WEB PERFORMANCE SUMMARY",
|
||||||
|
stderr: `UNIDESK_SSH_TRUNCATION_SUMMARY ${JSON.stringify(summary)}\n`,
|
||||||
|
signal: null,
|
||||||
|
timedOut: false,
|
||||||
|
} satisfies CommandResult);
|
||||||
|
expect(payload.ok).toBe(true);
|
||||||
|
expect(payload.status).toBe("collected");
|
||||||
|
const collect = payload.collect as Record<string, unknown>;
|
||||||
|
expect(collect.view).toBe("performance-summary");
|
||||||
|
expect(collect.renderedText).toContain("payloads=2");
|
||||||
|
const recovery = payload.stdoutRecovery as Record<string, unknown>;
|
||||||
|
expect(recovery.stdoutKind).toBe("ssh-truncation-summary");
|
||||||
|
expect(recovery.dumpPath).toBe(dumpPath);
|
||||||
|
expect(recovery.source).toBe("dump");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function collectOptions(): NodeWebProbeObserveOptions {
|
||||||
|
return {
|
||||||
|
action: "observe",
|
||||||
|
observeAction: "collect",
|
||||||
|
id: "webobs-test",
|
||||||
|
node: "JD01",
|
||||||
|
lane: "v03",
|
||||||
|
url: "https://example.test",
|
||||||
|
targetPath: "/",
|
||||||
|
viewport: "1920x1080",
|
||||||
|
browserProxyMode: "auto",
|
||||||
|
sampleIntervalMs: 1000,
|
||||||
|
screenshotIntervalMs: 0,
|
||||||
|
observerRefreshIntervalMs: 1000,
|
||||||
|
maxSamples: 10,
|
||||||
|
maxRunSeconds: 60,
|
||||||
|
commandTimeoutSeconds: 30,
|
||||||
|
waitMs: 0,
|
||||||
|
tailLines: 20,
|
||||||
|
maxFiles: 100,
|
||||||
|
gcKeepHours: 24,
|
||||||
|
gcLimit: 10,
|
||||||
|
confirm: false,
|
||||||
|
dryRun: false,
|
||||||
|
collectView: "performance-summary",
|
||||||
|
collectFile: null,
|
||||||
|
collectFinding: null,
|
||||||
|
collectGrep: null,
|
||||||
|
collectTraceId: null,
|
||||||
|
collectSampleSeq: null,
|
||||||
|
collectTimestamp: null,
|
||||||
|
collectTurn: null,
|
||||||
|
collectCommandId: null,
|
||||||
|
collectWindowMs: null,
|
||||||
|
analyzeArchivePrefix: null,
|
||||||
|
analyzeTailSamples: null,
|
||||||
|
full: false,
|
||||||
|
raw: false,
|
||||||
|
compactRaw: false,
|
||||||
|
stateDir: null,
|
||||||
|
jobId: null,
|
||||||
|
force: false,
|
||||||
|
commandType: null,
|
||||||
|
commandText: null,
|
||||||
|
commandPath: null,
|
||||||
|
commandLabel: null,
|
||||||
|
commandSessionId: null,
|
||||||
|
commandProvider: null,
|
||||||
|
commandAfterRound: null,
|
||||||
|
commandSeverity: null,
|
||||||
|
commandAlternateSessionStrategy: null,
|
||||||
|
commandExpectedSentinelRange: null,
|
||||||
|
commandExpectedActionWaitMs: null,
|
||||||
|
commandDurationMs: null,
|
||||||
|
commandRequireComposerReady: false,
|
||||||
|
commandWaitProjectManagementReady: false,
|
||||||
|
commandFindingId: null,
|
||||||
|
commandBlocking: null,
|
||||||
|
commandAccountId: null,
|
||||||
|
commandFromAccountId: null,
|
||||||
|
commandToAccountId: null,
|
||||||
|
commandSourceId: null,
|
||||||
|
commandFileRef: null,
|
||||||
|
commandFilename: null,
|
||||||
|
commandTaskRef: null,
|
||||||
|
commandTaskId: null,
|
||||||
|
commandField: null,
|
||||||
|
commandLink: null,
|
||||||
|
commandTitle: null,
|
||||||
|
commandBody: null,
|
||||||
|
commandStatus: null,
|
||||||
|
commandHwpodId: null,
|
||||||
|
commandNodeId: null,
|
||||||
|
commandWorkspaceRoot: null,
|
||||||
|
commandRoot: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// SPEC: PJ2026-01040111 长程观测 draft-2026-06-20-p0-passive-web-probe-observer.
|
||||||
|
// Responsibility: web-probe observe collect action and child JSON recovery.
|
||||||
|
import type { CommandResult } from "../command";
|
||||||
|
import { resolveCliChildJsonCommandResult } from "../cli-child-json-recovery";
|
||||||
|
import { nodeWebObserveCollectViewNodeScript } from "../hwlab-node-web-observe-collect";
|
||||||
|
import { withWebObserveCollectRendered } from "../hwlab-node-web-observe-render";
|
||||||
|
import { buildWebObserveWrapperForObserveOptions } from "../hwlab-node-web-observe-wrapper";
|
||||||
|
import type { HwlabRuntimeLaneSpec } from "../hwlab-node-lanes";
|
||||||
|
import type { RenderedCliResult } from "../output";
|
||||||
|
import type { NodeWebProbeObserveOptions } from "./entry";
|
||||||
|
import { runTransWorkspaceStdinScript } from "./public-exposure";
|
||||||
|
import { compactCommandResult, compactCommandResultWithStdoutTail } from "./utils";
|
||||||
|
import { webObserveCommandLabel, webObserveIdFromOptions, nodeWebObserveResolveStateDirShell } from "./web-observe-render";
|
||||||
|
import { nodeWebObserveCollectNodeScript } from "./web-observe-scripts";
|
||||||
|
import { compactObserveCollectForRaw } from "./web-observe-collect-compact";
|
||||||
|
|
||||||
|
export function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> | RenderedCliResult {
|
||||||
|
const collectScript = options.collectView === "files"
|
||||||
|
? nodeWebObserveCollectNodeScript(options.maxFiles, options.collectFile, options.collectFinding, options.collectGrep)
|
||||||
|
: nodeWebObserveCollectViewNodeScript({
|
||||||
|
maxFiles: options.maxFiles,
|
||||||
|
view: options.collectView,
|
||||||
|
traceId: options.collectTraceId,
|
||||||
|
sampleSeq: options.collectSampleSeq,
|
||||||
|
timestamp: options.collectTimestamp,
|
||||||
|
turn: options.collectTurn,
|
||||||
|
commandId: options.collectCommandId,
|
||||||
|
windowMs: options.collectWindowMs,
|
||||||
|
});
|
||||||
|
const script = [
|
||||||
|
"set -eu",
|
||||||
|
nodeWebObserveResolveStateDirShell(options),
|
||||||
|
collectScript,
|
||||||
|
].join("\n");
|
||||||
|
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
|
||||||
|
const payload = buildNodeWebProbeObserveCollectPayload(options, spec, result);
|
||||||
|
return options.raw ? payload : withWebObserveCollectRendered(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildNodeWebProbeObserveCollectPayload(
|
||||||
|
options: NodeWebProbeObserveOptions,
|
||||||
|
spec: Pick<HwlabRuntimeLaneSpec, "workspace">,
|
||||||
|
result: CommandResult,
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const stdoutResolution = resolveCliChildJsonCommandResult({
|
||||||
|
result,
|
||||||
|
requestedStdoutType: "web-probe-observe-collect",
|
||||||
|
acceptParsed: isWebObserveCollectJsonContract,
|
||||||
|
});
|
||||||
|
const collect = stdoutResolution.parsed;
|
||||||
|
const compactRaw = options.raw && options.compactRaw;
|
||||||
|
const degradedReason = collect === null
|
||||||
|
? collectDegradedReason(stdoutResolution.diagnostics)
|
||||||
|
: null;
|
||||||
|
return {
|
||||||
|
ok: result.exitCode === 0 && collect !== null && collect.ok !== false,
|
||||||
|
status: result.exitCode === 0 && collect !== null ? "collected" : "blocked",
|
||||||
|
command: webObserveCommandLabel("collect", options),
|
||||||
|
id: webObserveIdFromOptions(options),
|
||||||
|
node: options.node,
|
||||||
|
lane: options.lane,
|
||||||
|
workspace: spec.workspace,
|
||||||
|
view: options.collectView,
|
||||||
|
requestedFile: options.collectFile,
|
||||||
|
requestedGrep: options.collectGrep,
|
||||||
|
requestedCommandId: options.collectCommandId,
|
||||||
|
requestedWindowMs: options.collectWindowMs,
|
||||||
|
degradedReason,
|
||||||
|
stdoutRecovery: stdoutResolution.diagnostics,
|
||||||
|
collect: compactRaw ? compactObserveCollectForRaw(collect) : collect,
|
||||||
|
wrapper: compactRaw
|
||||||
|
? { mode: "wrapper-only", action: "collect", node: options.node, lane: options.lane, id: webObserveIdFromOptions(options), stateDir: options.stateDir, valuesRedacted: true }
|
||||||
|
: buildWebObserveWrapperForObserveOptions("collect", options, spec.workspace),
|
||||||
|
result: compactRaw
|
||||||
|
? { exitCode: result.exitCode, timedOut: result.timedOut, stdoutBytes: Buffer.byteLength(result.stdout), stderrBytes: Buffer.byteLength(result.stderr), stdoutRecovery: stdoutResolution.diagnostics }
|
||||||
|
: collect === null
|
||||||
|
? { ...compactCommandResultWithStdoutTail(result), stdoutRecovery: stdoutResolution.diagnostics }
|
||||||
|
: compactCommandResult(result),
|
||||||
|
valuesRedacted: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWebObserveCollectJsonContract(value: Record<string, unknown>): boolean {
|
||||||
|
const command = stringOrNull(value.command);
|
||||||
|
const view = stringOrNull(value.view);
|
||||||
|
const stateDir = stringOrNull(value.stateDir);
|
||||||
|
if (value.ok === false) {
|
||||||
|
return command === "web-probe-observe collect"
|
||||||
|
|| view !== null
|
||||||
|
|| stringOrNull(value.reason) !== null
|
||||||
|
|| stringOrNull(value.error) !== null;
|
||||||
|
}
|
||||||
|
return command === "web-probe-observe collect"
|
||||||
|
&& view !== null
|
||||||
|
&& stateDir !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectDegradedReason(diagnostics: Record<string, unknown>): string {
|
||||||
|
const fallbackReason = stringOrNull(diagnostics.fallbackReason);
|
||||||
|
if (fallbackReason === "stdout-json-contract-invalid") return "collect-stdout-json-contract-invalid";
|
||||||
|
if (fallbackReason === "stdout-trans-truncated" || fallbackReason === "stdout-ssh-truncated") return "collect-stdout-dump-unavailable";
|
||||||
|
if (fallbackReason === "stdout-dump-wrapper-unreadable") return "collect-stdout-dump-unreadable";
|
||||||
|
if (fallbackReason === "stdout-empty") return "collect-stdout-empty";
|
||||||
|
return "collect-stdout-json-unavailable";
|
||||||
|
}
|
||||||
|
|
||||||
|
function stringOrNull(value: unknown): string | null {
|
||||||
|
return typeof value === "string" && value.length > 0 ? value : null;
|
||||||
|
}
|
||||||
@@ -19,8 +19,8 @@ import { hwlabRuntimeLaneConfigPath, hwlabRuntimeLaneIds, hwlabRuntimeLaneSpec,
|
|||||||
import { nodeWebProbeScriptRunnerSource } from "../hwlab-node-web-probe-runner-source";
|
import { nodeWebProbeScriptRunnerSource } from "../hwlab-node-web-probe-runner-source";
|
||||||
import { nodeWebObserveAnalyzerSource } from "../hwlab-node-web-observe-analyzer-source";
|
import { nodeWebObserveAnalyzerSource } from "../hwlab-node-web-observe-analyzer-source";
|
||||||
import { nodeWebObserveRunnerSource } from "../hwlab-node-web-observe-runner-source";
|
import { nodeWebObserveRunnerSource } from "../hwlab-node-web-observe-runner-source";
|
||||||
import { nodeWebObserveCollectViewNodeScript, parseNodeWebProbeObserveCollectView, type NodeWebProbeObserveCollectView } from "../hwlab-node-web-observe-collect";
|
import { parseNodeWebProbeObserveCollectView, type NodeWebProbeObserveCollectView } from "../hwlab-node-web-observe-collect";
|
||||||
import { withWebObserveCollectRendered, withWebObserveCommandRendered, withWebObserveStatusRendered } from "../hwlab-node-web-observe-render";
|
import { withWebObserveCommandRendered, withWebObserveStatusRendered } from "../hwlab-node-web-observe-render";
|
||||||
import { buildWebObserveWrapperForObserveOptions, webObserveWrapperStateDirFromStatus } from "../hwlab-node-web-observe-wrapper";
|
import { buildWebObserveWrapperForObserveOptions, webObserveWrapperStateDirFromStatus } from "../hwlab-node-web-observe-wrapper";
|
||||||
import { renderWebObserveWrapperContract } from "../hwlab-node-web-observe-wrapper-render";
|
import { renderWebObserveWrapperContract } from "../hwlab-node-web-observe-wrapper-render";
|
||||||
import { runWebProbeSentinelCommand, type WebProbeSentinelDashboardAction, type WebProbeSentinelOptions, type WebProbeSentinelReportView } from "../hwlab-node-web-sentinel-cicd";
|
import { runWebProbeSentinelCommand, type WebProbeSentinelDashboardAction, type WebProbeSentinelOptions, type WebProbeSentinelReportView } from "../hwlab-node-web-sentinel-cicd";
|
||||||
@@ -35,9 +35,9 @@ import type { BootstrapAdminPasswordMaterial, NodeWebProbeObserveCommandType, No
|
|||||||
import { runTransWorkspaceStdinScript, runtimeSecretSpec } from "./public-exposure";
|
import { runTransWorkspaceStdinScript, runtimeSecretSpec } from "./public-exposure";
|
||||||
import { transPath } from "./runtime-common";
|
import { transPath } from "./runtime-common";
|
||||||
import { assertLane, assertNodeId, compactCommandResult, compactCommandResultRedacted, compactCommandResultWithStdoutTail, nullableRecord, optionValue, parseJsonObject, positiveIntegerOption, record, requiredOption, shellQuote } from "./utils";
|
import { assertLane, assertNodeId, compactCommandResult, compactCommandResultRedacted, compactCommandResultWithStdoutTail, nullableRecord, optionValue, parseJsonObject, positiveIntegerOption, record, requiredOption, shellQuote } from "./utils";
|
||||||
|
import { runNodeWebProbeObserveCollect } from "./web-probe-observe-collect";
|
||||||
import { nodeWebObserveResolveStateDirShell, recoverWebObserveAnalyzeTurnDetails, renderWebObserveStartResult, renderWebProbeRunResult, upsertWebObserveIndexEntry, webObserveCommandLabel, webObserveIdFromOptions, webObserveIdFromStatus, webObserveIndexEntryFromOptions, webObserveNextCommands, withWebObserveAnalyzeRendered, withWebObserveShortcuts } from "./web-observe-render";
|
import { nodeWebObserveResolveStateDirShell, recoverWebObserveAnalyzeTurnDetails, renderWebObserveStartResult, renderWebProbeRunResult, upsertWebObserveIndexEntry, webObserveCommandLabel, webObserveIdFromOptions, webObserveIdFromStatus, webObserveIndexEntryFromOptions, webObserveNextCommands, withWebObserveAnalyzeRendered, withWebObserveShortcuts } from "./web-observe-render";
|
||||||
import { commandSummaryForOutput, isSafeWebObserveArchivePrefix, isSafeWebObserveCollectFile, isSafeWebObserveFindingId, isSafeWebObserveJobId, isSafeWebObserveStateDir, isSafeWebObserveTraceId, nodeWebObserveCollectNodeScript, nodeWebObserveForceStopNodeScript, nodeWebObserveStatusNodeScript, nodeWebObserveWaitCommandShell, runNodeWebProbeScript, safeWebObserveSegment, safeWebObserveTargetSegment } from "./web-observe-scripts";
|
import { commandSummaryForOutput, isSafeWebObserveArchivePrefix, isSafeWebObserveCollectFile, isSafeWebObserveFindingId, isSafeWebObserveJobId, isSafeWebObserveStateDir, isSafeWebObserveTraceId, nodeWebObserveForceStopNodeScript, nodeWebObserveStatusNodeScript, nodeWebObserveWaitCommandShell, runNodeWebProbeScript, safeWebObserveSegment, safeWebObserveTargetSegment } from "./web-observe-scripts";
|
||||||
import { compactObserveCollectForRaw } from "./web-observe-collect-compact";
|
|
||||||
import { displayRepoPath, readBootstrapAdminPasswordMaterial, sleepSync } from "./web-probe";
|
import { displayRepoPath, readBootstrapAdminPasswordMaterial, sleepSync } from "./web-probe";
|
||||||
|
|
||||||
export function parseNodeWebProbeSentinelOptions(args: string[]): NodeWebProbeSentinelOptions {
|
export function parseNodeWebProbeSentinelOptions(args: string[]): NodeWebProbeSentinelOptions {
|
||||||
@@ -2022,51 +2022,6 @@ export function runNodeWebProbeObserveForceStop(
|
|||||||
return options.raw ? payloadResult : withWebObserveCommandRendered(payloadResult);
|
return options.raw ? payloadResult : withWebObserveCommandRendered(payloadResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> | RenderedCliResult {
|
|
||||||
const collectScript = options.collectView === "files"
|
|
||||||
? nodeWebObserveCollectNodeScript(options.maxFiles, options.collectFile, options.collectFinding, options.collectGrep)
|
|
||||||
: nodeWebObserveCollectViewNodeScript({
|
|
||||||
maxFiles: options.maxFiles,
|
|
||||||
view: options.collectView,
|
|
||||||
traceId: options.collectTraceId,
|
|
||||||
sampleSeq: options.collectSampleSeq,
|
|
||||||
timestamp: options.collectTimestamp,
|
|
||||||
turn: options.collectTurn,
|
|
||||||
commandId: options.collectCommandId,
|
|
||||||
windowMs: options.collectWindowMs,
|
|
||||||
});
|
|
||||||
const script = [
|
|
||||||
"set -eu",
|
|
||||||
nodeWebObserveResolveStateDirShell(options),
|
|
||||||
collectScript,
|
|
||||||
].join("\n");
|
|
||||||
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
|
|
||||||
const collect = parseJsonObject(result.stdout);
|
|
||||||
const compactRaw = options.raw && options.compactRaw;
|
|
||||||
const payload = {
|
|
||||||
ok: result.exitCode === 0 && collect !== null && collect.ok !== false,
|
|
||||||
status: result.exitCode === 0 && collect !== null ? "collected" : "blocked",
|
|
||||||
command: webObserveCommandLabel("collect", options),
|
|
||||||
id: webObserveIdFromOptions(options),
|
|
||||||
node: options.node,
|
|
||||||
lane: options.lane,
|
|
||||||
workspace: spec.workspace,
|
|
||||||
view: options.collectView,
|
|
||||||
requestedFile: options.collectFile,
|
|
||||||
requestedGrep: options.collectGrep,
|
|
||||||
requestedCommandId: options.collectCommandId,
|
|
||||||
requestedWindowMs: options.collectWindowMs,
|
|
||||||
degradedReason: collect === null ? "collect-json-parse-failed" : null,
|
|
||||||
collect: compactRaw ? compactObserveCollectForRaw(collect) : collect,
|
|
||||||
wrapper: compactRaw
|
|
||||||
? { mode: "wrapper-only", action: "collect", node: options.node, lane: options.lane, id: webObserveIdFromOptions(options), stateDir: options.stateDir, valuesRedacted: true }
|
|
||||||
: buildWebObserveWrapperForObserveOptions("collect", options, spec.workspace),
|
|
||||||
result: compactRaw ? { exitCode: result.exitCode, timedOut: result.timedOut, stdoutBytes: Buffer.byteLength(result.stdout), stderrBytes: Buffer.byteLength(result.stderr) } : collect === null ? compactCommandResultWithStdoutTail(result) : compactCommandResult(result),
|
|
||||||
valuesRedacted: true,
|
|
||||||
};
|
|
||||||
return options.raw ? payload : withWebObserveCollectRendered(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> | RenderedCliResult {
|
export function runNodeWebProbeObserveAnalyze(options: NodeWebProbeObserveOptions, spec: HwlabRuntimeLaneSpec): Record<string, unknown> | RenderedCliResult {
|
||||||
const analyzerB64 = Buffer.from(nodeWebObserveAnalyzerSource(), "utf8").toString("base64");
|
const analyzerB64 = Buffer.from(nodeWebObserveAnalyzerSource(), "utf8").toString("base64");
|
||||||
const alertThresholds = nodeWebProbeAlertThresholds(spec);
|
const alertThresholds = nodeWebProbeAlertThresholds(spec);
|
||||||
|
|||||||
Reference in New Issue
Block a user