Files
openclaw/scripts/mantis/build-telegram-desktop-proof-evidence.mts
Peter Steinberger c70aee247e refactor(scripts): migrate JavaScript tools to TypeScript (#121005)
* refactor(scripts): migrate JavaScript tools to TypeScript

* fix(ci): keep changed-scope preflight zero-install

* fix(ci): preserve zero-install script owners

* fix(ci): complete script migration follow-through

* fix(release): keep stable closeout zero-install

* fix(scripts): preserve standalone execution boundaries

* fix(scripts): repair standalone loader boundaries

* fix(scripts): normalize gateway observation ids

* fix(scripts): keep Docker packager standalone

* test(scripts): preserve rebase cleanup helpers

* test(sessions): use tracked temp directory
2026-08-09 07:21:35 -07:00

358 lines
9.7 KiB
TypeScript

#!/usr/bin/env node
// Builds an HTML/manifest evidence bundle from Telegram Desktop proof artifacts.
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
type CliArgs = Record<string, string>;
type LaneName = "baseline" | "candidate";
type SessionSummary = {
artifacts?: Partial<
Record<
"previewGifCropped" | "previewGif" | "screenshot" | "trimmedVideoCropped" | "trimmedVideo",
string
>
>;
report?: string;
status?: string;
sutAttestation?: { lane?: string; sha?: string };
};
type LoadedLane = {
outputDir: string;
repoRoot: string;
status: string;
summary: SessionSummary;
summaryPath: string;
};
type EvidenceArtifact = {
alt?: string;
inline?: boolean;
kind: string;
label: string;
lane: LaneName;
path: string;
required?: boolean;
targetPath: string;
width?: number;
};
type TelegramDesktopProofManifest = {
schemaVersion: number;
id: string;
title: string;
summary: string;
scenario: string;
comparison: {
baseline: { expected: string; status: string; ref?: string; sha?: string };
candidate: { expected: string; status: string; fixed: boolean; ref?: string; sha?: string };
pass: boolean;
};
artifacts: EvidenceArtifact[];
};
const LANES = [
{
altPrefix: "Baseline",
label: "Main",
lane: "baseline",
},
{
altPrefix: "Candidate",
label: "This PR",
lane: "candidate",
},
] satisfies ReadonlyArray<{
altPrefix: string;
label: string;
lane: LaneName;
}>;
function parseArgs(argv: string[]): CliArgs {
const args: CliArgs = {};
for (let index = 0; index < argv.length; index += 1) {
const key = argv[index];
if (!key?.startsWith("--")) {
throw new Error(`Unexpected argument: ${key}`);
}
const name = key.slice(2).replaceAll("-", "_");
const value = argv[index + 1];
if (!value || value.startsWith("--")) {
throw new Error(`Missing value for ${key}`);
}
args[name] = value;
index += 1;
}
return args;
}
function requireArg(args: CliArgs, name: string): string {
const value = args[name];
if (!value) {
throw new Error(`Missing --${name.replaceAll("_", "-")}.`);
}
return value;
}
function readJson(filePath: string): SessionSummary {
return JSON.parse(readFileSync(filePath, "utf8"));
}
function copyArtifact({
outputDir,
required = true,
source,
targetPath,
}: {
outputDir: string;
required?: boolean;
source?: string;
targetPath: string;
}) {
if (!source || !existsSync(source)) {
if (required) {
throw new Error(`Missing required artifact: ${source}`);
}
return false;
}
const target = path.join(outputDir, targetPath);
mkdirSync(path.dirname(target), { recursive: true });
copyFileSync(source, target);
return true;
}
function resolveSummaryArtifact(
lane: LoadedLane,
key: keyof NonNullable<SessionSummary["artifacts"]>,
) {
const value = lane.summary.artifacts?.[key];
return typeof value === "string" ? path.resolve(lane.repoRoot, value) : undefined;
}
function loadLane({
outputDir,
repoRoot,
status,
}: {
outputDir: string;
repoRoot: string;
status?: string;
}): LoadedLane {
const summaryPath = path.join(outputDir, "telegram-user-crabbox-session-summary.json");
const summary = readJson(summaryPath);
return {
outputDir,
repoRoot,
status: status || summary.status || "unknown",
summary,
summaryPath,
};
}
function copyLaneArtifacts({
lane,
laneName,
outputDir,
}: {
lane: LoadedLane;
laneName: LaneName;
outputDir: string;
}) {
const prefix = laneName;
const gif =
resolveSummaryArtifact(lane, "previewGifCropped") ?? resolveSummaryArtifact(lane, "previewGif");
copyArtifact({
outputDir,
source: gif,
targetPath: `${prefix}/telegram-desktop-proof.gif`,
});
copyArtifact({
outputDir,
required: false,
source:
resolveSummaryArtifact(lane, "trimmedVideoCropped") ??
resolveSummaryArtifact(lane, "trimmedVideo"),
targetPath: `${prefix}/telegram-desktop-proof.mp4`,
});
copyArtifact({
outputDir,
required: false,
source: resolveSummaryArtifact(lane, "screenshot"),
targetPath: `${prefix}/telegram-desktop-proof.png`,
});
copyArtifact({
outputDir,
source: lane.summaryPath,
targetPath: `${prefix}/summary.json`,
});
copyArtifact({
outputDir,
required: false,
source:
typeof lane.summary.report === "string"
? path.resolve(lane.repoRoot, lane.summary.report)
: undefined,
targetPath: `${prefix}/report.md`,
});
}
function laneStatus(lane: LoadedLane) {
return lane.status === "pass" ? "pass" : "fail";
}
function requireLaneAttestation(lane: LoadedLane, expectedLane: LaneName, expectedSha: string) {
const attestation = lane.summary.sutAttestation;
if (attestation?.lane !== expectedLane || attestation?.sha !== expectedSha) {
throw new Error(`SUT attestation mismatch for ${expectedLane}.`);
}
}
function laneArtifactEntries(): EvidenceArtifact[] {
return LANES.flatMap(({ altPrefix, label, lane }) => [
{
alt: `${altPrefix} native Telegram Desktop proof GIF`,
inline: true,
kind: "motionPreview",
label,
lane,
path: `${lane}/telegram-desktop-proof.gif`,
targetPath: `${lane}/telegram-desktop-proof.gif`,
width: 420,
},
{
kind: "motionClip",
label: `${label} MP4`,
lane,
path: `${lane}/telegram-desktop-proof.mp4`,
required: false,
targetPath: `${lane}/telegram-desktop-proof.mp4`,
},
{
alt: `${altPrefix} native Telegram Desktop screenshot`,
inline: false,
kind: "desktopScreenshot",
label: `${label} screenshot`,
lane,
path: `${lane}/telegram-desktop-proof.png`,
required: false,
targetPath: `${lane}/telegram-desktop-proof.png`,
},
{
kind: "metadata",
label: `${label} session summary`,
lane,
path: `${lane}/summary.json`,
targetPath: `${lane}/summary.json`,
},
{
kind: "report",
label: `${label} session report`,
lane,
path: `${lane}/report.md`,
required: false,
targetPath: `${lane}/report.md`,
},
]);
}
/**
* Builds the manifest for paired baseline/candidate Telegram Desktop proof artifacts.
*/
function buildTelegramDesktopProofManifest({
baseline,
baselineRef,
baselineSha,
candidate,
candidateRef,
candidateSha,
scenarioLabel,
}: {
baseline: LoadedLane;
baselineRef?: string;
baselineSha?: string;
candidate: LoadedLane;
candidateRef?: string;
candidateSha?: string;
scenarioLabel?: string;
}): TelegramDesktopProofManifest {
const baselineStatus = laneStatus(baseline);
const candidateStatus = laneStatus(candidate);
const pass = baselineStatus === "pass" && candidateStatus === "pass";
return {
schemaVersion: 1,
id: "telegram-desktop-proof",
title: "Mantis Telegram Desktop Proof",
summary:
"Mantis captured native Telegram Desktop before/after GIF evidence with Convex-leased Telegram credentials.",
scenario: scenarioLabel || "telegram-desktop-proof",
comparison: {
baseline: {
...(baselineSha ? { sha: baselineSha } : {}),
...(baselineRef ? { ref: baselineRef } : {}),
expected: "baseline visual proof captured",
status: baselineStatus,
},
candidate: {
...(candidateSha ? { sha: candidateSha } : {}),
...(candidateRef ? { ref: candidateRef } : {}),
expected: "candidate visual proof captured",
status: candidateStatus,
fixed: candidateStatus === "pass",
},
pass,
},
artifacts: laneArtifactEntries(),
};
}
export function writeTelegramDesktopProofEvidence(rawArgs: string[] = process.argv.slice(2)): {
manifest: TelegramDesktopProofManifest;
manifestPath: string;
} {
const args = parseArgs(rawArgs);
const baselineOutputDir = requireArg(args, "baseline_output_dir");
const baselineRepoRoot = requireArg(args, "baseline_repo_root");
const baselineSha = requireArg(args, "baseline_sha");
const candidateOutputDir = requireArg(args, "candidate_output_dir");
const candidateRepoRoot = requireArg(args, "candidate_repo_root");
const candidateSha = requireArg(args, "candidate_sha");
const evidenceOutputDir = requireArg(args, "output_dir");
const outputDir = path.resolve(evidenceOutputDir);
mkdirSync(outputDir, { recursive: true });
const baseline = loadLane({
outputDir: path.resolve(baselineOutputDir),
repoRoot: path.resolve(baselineRepoRoot),
status: args.baseline_status,
});
const candidate = loadLane({
outputDir: path.resolve(candidateOutputDir),
repoRoot: path.resolve(candidateRepoRoot),
status: args.candidate_status,
});
requireLaneAttestation(baseline, "baseline", baselineSha);
requireLaneAttestation(candidate, "candidate", candidateSha);
copyLaneArtifacts({ lane: baseline, laneName: "baseline", outputDir });
copyLaneArtifacts({ lane: candidate, laneName: "candidate", outputDir });
const manifest = buildTelegramDesktopProofManifest({
baseline,
baselineRef: args.baseline_ref,
baselineSha,
candidate,
candidateRef: args.candidate_ref,
candidateSha,
scenarioLabel: args.scenario_label,
});
const manifestPath = path.join(outputDir, "mantis-evidence.json");
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
return { manifest, manifestPath };
}
const executedPath = process.argv[1] ? path.resolve(process.argv[1]) : "";
if (executedPath === fileURLToPath(import.meta.url)) {
try {
writeTelegramDesktopProofEvidence();
} catch (error) {
console.error(error instanceof Error ? error.message : String(error));
process.exit(1);
}
}