From 31cfab00686a484d0cda8e429c6b12fc490b5ad3 Mon Sep 17 00:00:00 2001 From: Lyon <88232613+pikasTech@users.noreply.github.com> Date: Mon, 22 Jun 2026 15:16:29 +0800 Subject: [PATCH] fix: render node control plane summary (#661) Co-authored-by: Codex --- scripts/src/hwlab-node-impl.ts | 99 +++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/scripts/src/hwlab-node-impl.ts b/scripts/src/hwlab-node-impl.ts index 591f9125..b90c0431 100644 --- a/scripts/src/hwlab-node-impl.ts +++ b/scripts/src/hwlab-node-impl.ts @@ -371,10 +371,14 @@ async function runNodeDelegatedDomain(config: Config, domain: DelegatedNodeDomai return nodeRuntimeBaseImageCommand(scoped); } if (domain === "control-plane" && scoped.action === "plan") { - return nodeRuntimeControlPlanePlan(scoped); + const result = nodeRuntimeControlPlanePlan(scoped); + return nodeScopedFullOutput(scoped) ? result : withNodeRuntimeControlPlanePlanRendered(result, scoped); } if (domain === "control-plane" && scoped.node !== defaultSpec.nodeId) { - if (scoped.action === "status") return nodeRuntimeControlPlaneStatus(scoped); + if (scoped.action === "status") { + const result = nodeRuntimeControlPlaneStatus(scoped); + return nodeScopedFullOutput(scoped) ? result : withNodeRuntimeControlPlaneStatusRendered(result, scoped); + } if (scoped.action === "apply" || scoped.action === "trigger-current" || scoped.action === "refresh" || scoped.action === "sync" || scoped.action === "runtime-migration" || scoped.action === "cleanup-runs") { if (scoped.confirm && !scoped.dryRun && !scoped.wait) return startNodeDelegatedJob(scoped); return nodeRuntimeControlPlaneRun(scoped); @@ -2936,6 +2940,97 @@ function withNodeRuntimeTriggerRendered(result: Record, scoped: return { ...result, renderedText, contentType: "text/plain" }; } +function withNodeRuntimeControlPlanePlanRendered(result: Record, scoped: ReturnType): RenderedCliResult { + const checks = record(result.checks); + const next = record(result.next); + const renderedText = [ + "hwlab nodes control-plane plan", + "", + webObserveTable( + ["NODE", "LANE", "STATUS", "MODE", "NAMESPACE", "EXT_PG", "PUBLIC"], + [[ + scoped.node, + scoped.lane, + result.ok === true ? "ok" : "failed", + webObserveText(result.mode), + webObserveText(checks.runtimeNamespace), + webObserveText(checks.externalPostgresDeclared), + webObserveText(checks.publicExposureDeclared), + ]], + ), + "", + webObserveTable( + ["CHECK", "VALUE"], + [ + ["node-scoped-target", webObserveText(checks.nodeScopedTargetConfigured)], + ["local-postgres-absent", webObserveText(checks.localPostgresExpectedAbsent)], + ["secret-values-printed", webObserveText(checks.secretValuesPrinted)], + ], + ), + "", + "NEXT", + ` ${next.status ?? `bun scripts/cli.ts hwlab nodes control-plane status --node ${scoped.node} --lane ${scoped.lane}`}`, + "", + "Disclosure:", + " default view is a bounded control-plane plan summary; use --full or --raw for the complete JSON payload.", + ].join("\n"); + return { ...result, renderedText, contentType: "text/plain" }; +} + +function withNodeRuntimeControlPlaneStatusRendered(result: Record, scoped: ReturnType): RenderedCliResult { + const pipelineRun = record(result.pipelineRun); + const argo = record(result.argo); + const runtime = record(result.runtime); + const publicProbe = record(result.publicProbe); + const gitMirror = record(result.gitMirror); + const next = record(result.next); + const diagnostic = record(publicProbe.diagnostic); + const status = result.ok === true ? "ok" : result.ok === false ? "failed" : "-"; + const renderedText = [ + "hwlab nodes control-plane status", + "", + webObserveTable( + ["NODE", "LANE", "STATUS", "REASON", "SOURCE", "PIPELINERUN"], + [[ + scoped.node, + scoped.lane, + status, + webObserveShort(webObserveText(result.degradedReason), 40), + shortValue(result.sourceCommit), + webObserveShort(webObserveText(pipelineRun.name), 36), + ]], + ), + "", + webObserveTable( + ["STAGE", "STATUS", "DETAIL"], + [ + ["pipeline", pipelineRun.ready === true ? "ok" : pipelineRun.exists === true ? webObserveText(pipelineRun.status) : "missing", webObserveShort(webObserveText(pipelineRun.reason ?? pipelineRun.message), 80)], + ["argo", argo.ready === true ? "ok" : "failed", `${webObserveText(argo.syncStatus)}/${webObserveText(argo.health)} rev=${shortValue(argo.syncRevision)}`], + ["runtime", runtime.ready === true ? "ok" : "failed", `workloads=${webObserveText(runtime.workloadReady)} pg=${webObserveText(runtime.externalPostgresReady)}`], + ["public", publicProbe.ready === true ? "ok" : "failed", webObserveShort(webObserveText(diagnostic.kind ?? diagnostic.message), 80)], + ["git-mirror", gitMirror.ready === true ? "ok" : "failed", `pending=${webObserveText(gitMirror.pendingFlush)} inSync=${webObserveText(gitMirror.githubInSync)}`], + ], + ), + "", + webObserveTable( + ["LOCAL_SOURCE", "GITHUB_SOURCE", "LOCAL_GITOPS", "GITHUB_GITOPS"], + [[ + shortValue(gitMirror.localSource), + shortValue(gitMirror.githubSource), + shortValue(gitMirror.localGitops), + shortValue(gitMirror.githubGitops), + ]], + ), + "", + "NEXT", + ` ${result.nextAction ?? next.full ?? `bun scripts/cli.ts hwlab nodes control-plane status --node ${scoped.node} --lane ${scoped.lane} --full`}`, + "", + "Disclosure:", + " default view is a bounded control-plane status summary; use --full or --raw for the complete JSON payload.", + ].join("\n"); + return { ...result, renderedText, contentType: "text/plain" }; +} + function nodeRuntimeGitMirrorStatus(scoped: ReturnType): Record { const spec = scoped.spec; const mirror = nodeRuntimeGitMirrorTarget(spec);