fix: bound web probe collect file output (#686)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-22 22:49:25 +08:00
committed by GitHub
parent 30613bb515
commit 6a58a06bd1
+55 -8
View File
@@ -7753,13 +7753,15 @@ function runNodeWebProbeObserveCollect(options: NodeWebProbeObserveOptions, spec
const result = runTransWorkspaceStdinScript(options.node, spec.workspace, script, options.commandTimeoutSeconds);
const collect = parseJsonObject(result.stdout);
return withWebObserveCollectRendered({
ok: result.exitCode === 0 && collect?.ok !== false,
status: result.exitCode === 0 ? "collected" : "blocked",
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,
requestedFile: options.collectFile,
degradedReason: collect === null ? "collect-json-parse-failed" : null,
collect,
result: collect === null ? compactCommandResultWithStdoutTail(result) : compactCommandResult(result),
valuesRedacted: true,
@@ -7776,10 +7778,10 @@ function withWebObserveCollectRendered(value: Record<string, unknown>): Rendered
}
function renderWebObserveCollectTable(value: Record<string, unknown>): string {
const collect = record(value.collect);
const collect = nullableRecord(value.collect);
const result = record(value.result);
const file = record(collect.file);
const files = Array.isArray(collect.files) ? collect.files.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 20) : [];
const file = record(collect?.file);
const files = Array.isArray(collect?.files) ? collect.files.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(0, 20) : [];
const jsonlTail = Array.isArray(file.jsonlTail) ? file.jsonlTail.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(-8) : [];
const jsonSummary = record(file.jsonSummary);
const jsonRunnerErrors = Array.isArray(jsonSummary.runnerErrors) ? jsonSummary.runnerErrors.map(record).filter((item): item is Record<string, unknown> => item !== null).slice(-8) : [];
@@ -7791,11 +7793,29 @@ function renderWebObserveCollectTable(value: Record<string, unknown>): string {
webObserveText(value.id),
webObserveText(value.node),
webObserveText(value.lane),
webObserveText(collect.mode ?? "files"),
webObserveShort(webObserveText(collect.stateDir), 88),
webObserveText(collect?.mode ?? "files"),
webObserveShort(webObserveText(collect?.stateDir), 88),
]]),
"",
];
if (collect === null) {
lines.push(
"Collect command:",
webObserveTable(["REQUESTED", "REASON", "EXIT", "TIMED_OUT", "STDOUT_BYTES", "STDOUT_TAIL", "STDERR"], [[
webObserveShort(webObserveText(value.requestedFile), 64),
webObserveShort(webObserveText(value.degradedReason), 40),
webObserveText(result.exitCode),
webObserveText(result.timedOut),
webObserveText(result.stdoutBytes),
webObserveShort(webObserveText(result.stdoutTail), 160),
webObserveShort(webObserveText(result.stderr), 160),
]]),
"",
"Disclosure:",
" collect stdout was not valid JSON; fix the collect command or rerun with a narrower --file after the root cause is visible.",
);
return lines.join("\n");
}
if (collect.mode === "file") {
lines.push(
"File:",
@@ -9214,6 +9234,33 @@ const fs=require('fs'),path=require('path'),crypto=require('crypto');
const dir=process.argv[1]; const selected=process.argv[2]||''; const maxFiles=${maxFiles}; const maxReadBytes=64*1024;
const shaFile=(file)=>'sha256:'+crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
const safeRel=(value)=>Boolean(value)&&!path.isAbsolute(value)&&!value.includes('..')&&!value.includes('\\\\')&&value.split('/').every((part)=>part&&part!=='.'&&part!=='..');
const short=(value,max=180)=>value===undefined||value===null?undefined:String(value).replace(/\\s+/g,' ').slice(0,max);
const slimJsonl=(value)=>{
if(!value||typeof value!=='object'||Array.isArray(value)) return {value:short(value)};
const readiness=value.readiness&&typeof value.readiness==='object'?value.readiness:null;
const snapshot=value.snapshot&&typeof value.snapshot==='object'?value.snapshot:null;
const error=value.error&&typeof value.error==='object'?value.error:null;
return {
ts:short(value.ts||value.timestamp||value.at,32),
seq:value.seq,
type:short(value.type,48),
phase:short(value.phase,32),
commandId:short(value.commandId,40),
commandType:short(value.commandType||value.command?.type,40),
pageRole:short(value.pageRole,20),
path:short(value.path||value.routePath||snapshot?.path,80),
routeSessionId:short(value.routeSessionId||snapshot?.routeSessionId,48),
activeSessionId:short(value.activeSessionId||snapshot?.activeSessionId,48),
messageCount:value.messageCount??snapshot?.messageCount,
traceEventCount:value.traceEventCount??snapshot?.traceEventCount,
method:short(value.method,12),
status:value.status,
url:short(value.url,120),
failure:short(value.failure||value.failureText||value.errorText,120),
readiness:readiness?{ok:readiness.ok,reason:short(readiness.reason,80),path:short(readiness.path,80),domReady:readiness.domReady,workbenchShellVisible:readiness.workbenchShellVisible,sessionCreateVisible:readiness.sessionCreateVisible,commandInputVisible:readiness.commandInputVisible}:undefined,
message:short(value.message||error?.message||value.text,180)
};
};
if(selected){
if(!safeRel(selected)){console.log(JSON.stringify({ok:false,command:'web-probe-observe collect',stateDir:dir,mode:'file',reason:'unsafe-file',file:selected,valuesRedacted:true},null,2)); process.exit(2);}
const file=path.join(dir,selected); const relative=path.relative(dir,file);
@@ -9223,7 +9270,7 @@ if(selected){
const lines=text.split(/\\r?\\n/).filter(Boolean); const isJsonl=selected.endsWith('.jsonl');
let jsonSummary=null;
if(selected.endsWith('.json')&&!truncated){try{const parsed=JSON.parse(text); jsonSummary={topLevelKeys:parsed&&typeof parsed==='object'&&!Array.isArray(parsed)?Object.keys(parsed).slice(0,40):[],counts:parsed&&parsed.counts||null,runnerErrors:Array.isArray(parsed&&parsed.runnerErrors)?parsed.runnerErrors.slice(-8):[],findings:Array.isArray(parsed&&parsed.findings)?parsed.findings.slice(0,8):[]}}catch(error){jsonSummary={parseError:String(error&&error.message||error).slice(0,160)}}}
const jsonlTail=isJsonl?lines.slice(-20).map((line,index)=>{try{return JSON.parse(line)}catch(error){return {parseError:true,index,lineTail:line.slice(-500),error:String(error&&error.message||error).slice(0,160)}}}):null;
const jsonlTail=isJsonl?lines.slice(-20).map((line,index)=>{try{return slimJsonl(JSON.parse(line))}catch(error){return {parseError:true,index,lineTail:line.slice(-240),error:String(error&&error.message||error).slice(0,160)}}}):null;
console.log(JSON.stringify({ok:true,command:'web-probe-observe collect',stateDir:dir,mode:'file',file:{path:file,relative,byteCount:st.size,sha256:shaFile(file),truncated,content:isJsonl||jsonSummary?undefined:text,jsonlTail,jsonSummary,lineCount:lines.length},valuesRedacted:true},null,2));
process.exit(0);
}