#!/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; type LaneName = "baseline" | "candidate"; type LaneStatus = "blocked" | "fail" | "pass"; 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 }; outcome: LaneStatus; 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, ) { 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, required: laneStatus(lane) === "pass", 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): LaneStatus { return lane.status === "pass" || lane.status === "blocked" ? lane.status : "fail"; } function requireLaneAttestation(lane: LoadedLane, expectedLane: LaneName, expectedSha: string) { const attestation = lane.summary.sutAttestation; if (attestation?.lane === expectedLane && attestation.sha === expectedSha) { return; } if ( lane.status === "fail" && lane.summary.status === "infra-error" && attestation == null && Object.keys(lane.summary.artifacts ?? {}).length === 0 && lane.summary.report === undefined ) { return; } throw new Error(`SUT attestation mismatch for ${expectedLane}.`); } function laneArtifactEntries(statuses: Record): 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`, required: statuses[lane] === "pass", 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 outcome = baselineStatus === "fail" || candidateStatus === "fail" ? "fail" : baselineStatus === "blocked" || candidateStatus === "blocked" ? "blocked" : "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", }, outcome, pass: outcome === "pass", }, artifacts: laneArtifactEntries({ baseline: baselineStatus, candidate: candidateStatus }), }; } 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); } }