Files
pikasTech-unidesk/scripts/src/hwlab-node-web-observe-wrapper-render.ts
T
2026-06-25 21:45:24 +08:00

61 lines
2.8 KiB
TypeScript

// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-25-p0-web-probe-sentinel.
// Responsibility: Bounded CLI rendering for the observe wrapper contract.
export function renderWebObserveWrapperContract(value: Record<string, unknown>): string[] {
const wrapper = nullableRecord(value.wrapper);
if (wrapper === null) return [];
const cli = record(wrapper.cli);
const artifacts = record(wrapper.artifacts);
const invariants = record(wrapper.invariants);
return [
"Wrapper contract:",
webObserveTable(["SPEC", "MODE", "VERB", "RUNNER", "ANALYZER", "STATE_DIR"], [[
webObserveShort(webObserveText(wrapper.specRef), 56),
wrapper.mode,
wrapper.action,
invariants.reusesExistingObserveRunner === true && invariants.createsSecondPlaywrightRunner === false ? "existing" : "blocked",
invariants.reusesExistingObserveAnalyzer === true && invariants.createsSecondAnalyzer === false ? "existing" : "blocked",
webObserveShort(webObserveText(artifacts.stateDir), 88),
]]),
` cli: ${webObserveShort(webObserveText(cli.commandShape), 140)}`,
"",
];
}
function webObserveTable(headers: string[], rows: unknown[][]): string {
const stringRows = rows.map((row) => headers.map((_, index) => webObserveCell(row[index])));
const widths = headers.map((header, index) => Math.max(header.length, ...stringRows.map((row) => row[index]?.length ?? 0)));
const renderRow = (row: string[]) => row.map((cell, index) => cell.padEnd(widths[index] ?? cell.length)).join(" ").trimEnd();
return [renderRow(headers), ...stringRows.map(renderRow)].join("\n");
}
function webObserveCell(value: unknown, maxLength = 96): string {
if (value === null || value === undefined) return "-";
const text = typeof value === "string" ? value : String(value);
const compact = text.replace(/\s+/gu, " ").trim();
if (compact.length === 0) return "-";
if (compact.length <= maxLength) return compact;
return `${compact.slice(0, Math.max(1, maxLength - 1))}...`;
}
function webObserveText(value: unknown): string {
if (value === null || value === undefined || value === "") return "-";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
return JSON.stringify(value);
}
function webObserveShort(value: string, maxLength: number): string {
if (value.length <= maxLength) return value;
if (maxLength <= 1) return value.slice(0, maxLength);
return `${value.slice(0, maxLength - 1)}~`;
}
function record(value: unknown): Record<string, unknown> {
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : {};
}
function nullableRecord(value: unknown): Record<string, unknown> | null {
return value && typeof value === "object" && !Array.isArray(value) ? value as Record<string, unknown> : null;
}