fix: add bounded web-probe observe timeline drilldown (#937)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-26 10:20:28 +08:00
committed by GitHub
parent effd3656d4
commit 8abf188ee2
7 changed files with 247 additions and 5 deletions
+33 -1
View File
@@ -189,6 +189,8 @@ export function parseNodeWebProbeObserveOptions(
"--sample-seq",
"--timestamp",
"--turn",
"--command-id",
"--window-ms",
"--compact-raw",
"--archive-prefix",
"--tail-samples",
@@ -237,6 +239,11 @@ export function parseNodeWebProbeObserveOptions(
const collectTurnRaw = optionValue(args, "--turn") ?? null;
const collectTurn = collectTurnRaw === null ? null : Number(collectTurnRaw);
if (collectTurn !== null && (!Number.isInteger(collectTurn) || collectTurn < 1)) throw new Error("unsafe web-probe observe --turn: expected positive integer");
const collectCommandId = optionValue(args, "--command-id") ?? null;
if (collectCommandId !== null && (!/^[A-Za-z0-9_.:-]+$/u.test(collectCommandId) || collectCommandId.length > 120)) throw new Error("unsafe web-probe observe --command-id: expected 1-120 safe command id chars");
const collectWindowMsRaw = optionValue(args, "--window-ms") ?? null;
const collectWindowMs = collectWindowMsRaw === null ? null : Number(collectWindowMsRaw);
if (collectWindowMs !== null && (!Number.isInteger(collectWindowMs) || collectWindowMs < 1000 || collectWindowMs > 86_400_000)) throw new Error("unsafe web-probe observe --window-ms: expected integer 1000-86400000");
const analyzeArchivePrefix = optionValue(args, "--archive-prefix") ?? null;
if (analyzeArchivePrefix !== null && !isSafeWebObserveArchivePrefix(analyzeArchivePrefix)) throw new Error(`unsafe web-probe observe --archive-prefix: ${analyzeArchivePrefix}`);
const analyzeTailSamplesRaw = optionValue(args, "--tail-samples") ?? null;
@@ -308,6 +315,8 @@ export function parseNodeWebProbeObserveOptions(
collectSampleSeq,
collectTimestamp,
collectTurn,
collectCommandId,
collectWindowMs,
analyzeArchivePrefix,
analyzeTailSamples,
full: args.includes("--full"),
@@ -1159,6 +1168,8 @@ export function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOption
sampleSeq: options.collectSampleSeq,
timestamp: options.collectTimestamp,
turn: options.collectTurn,
commandId: options.collectCommandId,
windowMs: options.collectWindowMs,
});
const script = [
"set -eu",
@@ -1179,6 +1190,8 @@ export function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOption
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
@@ -1217,14 +1230,33 @@ function compactObserveCollectForRaw(collect: Record<string, unknown> | null): R
valuesRedacted: true,
};
}) : undefined;
const timelineRows = Array.isArray(collect.timelineRows) ? collect.timelineRows.slice(0, 12).map((item) => {
const row = observeRecord(item);
return {
ts: row.ts ?? null,
seq: row.seq ?? null,
kind: row.kind ?? null,
phase: row.phase ?? null,
type: row.type ?? null,
commandId: row.commandId ?? null,
sessionId: row.sessionId ?? null,
traceId: row.traceId ?? null,
summary: row.summary ?? null,
valuesRedacted: true,
};
}) : undefined;
return {
ok: collect.ok !== false,
command: collect.command,
view: collect.view,
stateDir: collect.stateDir,
turnCount: collect.turnCount,
anchor: observeRecord(collect.anchor),
window: observeRecord(collect.window),
counts: observeRecord(collect.counts),
...(rows === undefined ? {} : { rows }),
renderedText: typeof collect.renderedText === "string" ? collect.renderedText : undefined,
...(timelineRows === undefined ? {} : { timelineRows }),
renderedText: collect.view === "timeline" ? undefined : typeof collect.renderedText === "string" ? collect.renderedText : undefined,
sourceFiles: Array.isArray(collect.sourceFiles) ? collect.sourceFiles : undefined,
blocker: collect.blocker,
sampleSeq: collect.sampleSeq,