fd874ceef5
Co-authored-by: Codex <codex@noreply.local>
61 lines
2.8 KiB
TypeScript
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;
|
|
}
|