From 892c9af366ccfa16dbd8cf0c59080e0ccb8574d3 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Sun, 7 Jun 2026 12:45:32 +0800 Subject: [PATCH] fix: CaseRun blocker visibility in status + cloud-api hwpod_node_not_connected error --- internal/cloud/server.ts | 2 +- tools/src/hwlab-caserun-lib.ts | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/internal/cloud/server.ts b/internal/cloud/server.ts index f9181e10..e271137c 100644 --- a/internal/cloud/server.ts +++ b/internal/cloud/server.ts @@ -754,7 +754,7 @@ async function forwardHwpodNodeOpsPlan(targetUrl, plan, requestMeta, options) { }); } if (target.ok && target.nodeId && target.nodeId !== plan.nodeId) { - return directHwpodNodeBlocked(plan, "hwpod_node_id_mismatch", `configured hwpod-node URL is ${target.nodeId}, but plan targets ${plan.nodeId}`, { + return directHwpodNodeBlocked(plan, "hwpod_node_not_connected", `${plan.nodeId} is not connected via WebSocket and HWLAB_HWPOD_NODE_OPS_URL points to ${target.nodeId}`, { requestedNodeId: plan.nodeId, targetNodeId: target.nodeId, targetUrl: redactNodeOpsUrl(targetUrl), diff --git a/tools/src/hwlab-caserun-lib.ts b/tools/src/hwlab-caserun-lib.ts index 60a2fe13..c5b9fdd1 100644 --- a/tools/src/hwlab-caserun-lib.ts +++ b/tools/src/hwlab-caserun-lib.ts @@ -374,7 +374,9 @@ async function runCaseRunWorker(context: CaseContext) { return payload; } catch (error) { const run = await readRunFromDir(runDir).catch(() => loadControlRunSkeleton(workerContext, caseId, runId, runDir)); - await writeRunControl(workerContext, run, { status: "failed", stage: "failed", completedAt: context.now(), exitCode: 1, error: errorSummary(error) }); + const summary = errorSummary(error); + const blocker = extractPrepareBlocker(summary); + await writeRunControl(workerContext, run, { status: "failed", stage: "failed", completedAt: context.now(), exitCode: 1, error: summary, ...(blocker ? { blocker } : {}) }); throw error; } } @@ -412,6 +414,7 @@ export async function statusCaseRun(context: CaseContext) { agent: run.agent ? agentSummary(run.agent) : null, traceLookup: run.agent ? agentTraceLookupForRun(run) : null, agentDiff: run.agentDiff ? diffSummary(run.agentDiff) : null, + blocker: control.blocker ?? null, evidencePath: text(run.evidencePath ?? control.resultPath) || null, nextPollCommand: `hwlab-cli case run status ${run.runId} --state-dir ${stateRoot(context)}`, resultCommand: `hwlab-cli case run result ${run.runId} --state-dir ${stateRoot(context)}`, @@ -2437,6 +2440,18 @@ function errorSummary(error: unknown) { return { code: typeof (error as any)?.code === "string" ? (error as any).code : "caserun_worker_failed", message: error instanceof Error ? error.message : String(error), details: (error as any)?.details ?? null }; } +function extractPrepareBlocker(summary: ReturnType) { + const results = (summary.details as any)?.body?.body?.results ?? (summary.details as any)?.body?.results ?? []; + if (!Array.isArray(results) || results.length === 0) return null; + for (const r of results) { + const blocker = (r as any)?.blocker; + if (blocker && typeof blocker.code === "string") { + return { code: blocker.code, summary: blocker.summary ?? "", layer: blocker.layer ?? null }; + } + } + return null; +} + function commandVisibility(command: string[]) { return command.map((item) => item.includes("/") || item.includes("\\") ? path.basename(item) || item : item); }