@riddledc/riddle-proof 0.8.37 → 0.8.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -17377,6 +17377,210 @@ function extractRiddleProofProfileResult(input) {
17377
17377
  return void 0;
17378
17378
  }
17379
17379
 
17380
+ // src/pr-comment.ts
17381
+ var RIDDLE_PROOF_PR_COMMENT_MARKER = "<!-- riddle-proof:pr-comment:v1 -->";
17382
+ function asRecord(value) {
17383
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
17384
+ }
17385
+ function asArray(value) {
17386
+ return Array.isArray(value) ? value : [];
17387
+ }
17388
+ function stringValue3(value) {
17389
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
17390
+ }
17391
+ function numberValue2(value) {
17392
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
17393
+ }
17394
+ function booleanValue2(value) {
17395
+ return typeof value === "boolean" ? value : void 0;
17396
+ }
17397
+ function artifactKind(name, url) {
17398
+ const target = `${name} ${url}`.toLowerCase();
17399
+ if (/\.(png|jpe?g|gif|webp|avif|svg)(\?|#|$)/.test(target)) return "image";
17400
+ if (/\.(json|har|txt|md|html|log)(\?|#|$)/.test(target)) return "data";
17401
+ return "artifact";
17402
+ }
17403
+ function artifactDisplayName(value, fallback) {
17404
+ const raw = stringValue3(value);
17405
+ if (raw) return raw;
17406
+ return fallback;
17407
+ }
17408
+ function collectArtifacts(runResponse) {
17409
+ const proofResult = asRecord(runResponse.proofResult);
17410
+ const outputs = asArray(proofResult.outputs);
17411
+ const artifacts = [];
17412
+ const seen = /* @__PURE__ */ new Set();
17413
+ for (const [index, item] of outputs.entries()) {
17414
+ const artifact = asRecord(item);
17415
+ const url = stringValue3(artifact.url);
17416
+ if (!url || seen.has(url)) continue;
17417
+ seen.add(url);
17418
+ const name = artifactDisplayName(artifact.name, `artifact-${index + 1}`);
17419
+ artifacts.push({
17420
+ name,
17421
+ url,
17422
+ kind: artifactKind(name, url),
17423
+ size_bytes: numberValue2(artifact.size)
17424
+ });
17425
+ }
17426
+ return artifacts;
17427
+ }
17428
+ function pageSummaries(result) {
17429
+ const pages = [];
17430
+ for (const page of asArray(result.pages)) {
17431
+ const record = asRecord(page);
17432
+ const route = stringValue3(record.route) || stringValue3(record.url) || "page";
17433
+ const checks = asRecord(record.checks);
17434
+ let passed = 0;
17435
+ let failed = 0;
17436
+ for (const value of Object.values(checks)) {
17437
+ if (value === true) passed += 1;
17438
+ if (value === false) failed += 1;
17439
+ }
17440
+ pages.push({ route, passed, failed });
17441
+ }
17442
+ return pages;
17443
+ }
17444
+ function summarizeExplicitChecks(value) {
17445
+ let passed = 0;
17446
+ let failed = 0;
17447
+ const visit = (current, inChecks = false) => {
17448
+ if (current === true && inChecks) {
17449
+ passed += 1;
17450
+ return;
17451
+ }
17452
+ if (current === false && inChecks) {
17453
+ failed += 1;
17454
+ return;
17455
+ }
17456
+ if (Array.isArray(current)) {
17457
+ for (const item of current) visit(item, inChecks);
17458
+ return;
17459
+ }
17460
+ if (current && typeof current === "object") {
17461
+ for (const [key, item] of Object.entries(current)) {
17462
+ visit(item, inChecks || key === "checks");
17463
+ }
17464
+ }
17465
+ };
17466
+ visit(value);
17467
+ return { passed, failed };
17468
+ }
17469
+ function selectPrimaryImage(artifacts) {
17470
+ const images = artifacts.filter((artifact) => artifact.kind === "image");
17471
+ return images.find((artifact) => /after|proof|screenshot/i.test(artifact.name)) || images[0];
17472
+ }
17473
+ function summarizeRiddleProofPrComment(input) {
17474
+ const runResponse = asRecord(input.runResponse);
17475
+ const result = asRecord(input.result);
17476
+ const proofResult = asRecord(runResponse.proofResult);
17477
+ const preview = asRecord(runResponse.preview);
17478
+ const artifacts = collectArtifacts(runResponse);
17479
+ const pages = pageSummaries(result);
17480
+ const checkSource = { ...result };
17481
+ delete checkSource.ok;
17482
+ const nestedChecks = summarizeExplicitChecks(checkSource);
17483
+ const ok = booleanValue2(result.ok) ?? booleanValue2(runResponse.ok) ?? null;
17484
+ return {
17485
+ ok,
17486
+ status: stringValue3(proofResult.status),
17487
+ job_id: stringValue3(proofResult.job_id),
17488
+ duration_ms: numberValue2(proofResult.duration_ms),
17489
+ proof_url: stringValue3(runResponse.proofUrl),
17490
+ preview_id: stringValue3(preview.id),
17491
+ preview_url: stringValue3(preview.preview_url) || stringValue3(preview.url),
17492
+ preview_publish_recovered: booleanValue2(preview.publish_recovered),
17493
+ preview_publish_error: stringValue3(preview.publish_error),
17494
+ passed_checks: nestedChecks.passed,
17495
+ failed_checks: nestedChecks.failed,
17496
+ pages,
17497
+ artifacts,
17498
+ primary_image: selectPrimaryImage(artifacts)
17499
+ };
17500
+ }
17501
+ function formatDuration(ms) {
17502
+ if (typeof ms !== "number" || !Number.isFinite(ms)) return "";
17503
+ const seconds = Math.max(0, Math.round(ms / 1e3));
17504
+ const minutes = Math.floor(seconds / 60);
17505
+ const remainder = seconds % 60;
17506
+ return minutes > 0 ? `${minutes}m${String(remainder).padStart(2, "0")}s` : `${seconds}s`;
17507
+ }
17508
+ function markdownLink(label, url) {
17509
+ return `[${label.replace(/\]/g, "\\]")}](${url})`;
17510
+ }
17511
+ function resultLabel(summary) {
17512
+ if (summary.ok === true) return "passed";
17513
+ if (summary.ok === false) return "failed";
17514
+ return summary.status || "recorded";
17515
+ }
17516
+ function artifactRank(artifact) {
17517
+ const name = artifact.name.toLowerCase();
17518
+ if (name === "proof.json") return 0;
17519
+ if (name === "result.json") return 1;
17520
+ if (name.includes("proof") && name.endsWith(".json") && !name.includes("layout")) return 2;
17521
+ if (name === "console.json") return 3;
17522
+ if (artifact.kind === "data") return 10;
17523
+ if (artifact.kind === "image") return 20;
17524
+ return 30;
17525
+ }
17526
+ function buildRiddleProofPrCommentMarkdown(input) {
17527
+ const summary = summarizeRiddleProofPrComment(input);
17528
+ const title = input.title?.trim() || "Riddle Proof Evidence";
17529
+ const lines = [
17530
+ RIDDLE_PROOF_PR_COMMENT_MARKER,
17531
+ `## ${title}`,
17532
+ "",
17533
+ `**Result:** ${resultLabel(summary)}`
17534
+ ];
17535
+ if (input.goal?.trim()) lines.push(`**Goal:** ${input.goal.trim()}`);
17536
+ if (input.successCriteria?.trim()) lines.push(`**Success criteria:** ${input.successCriteria.trim()}`);
17537
+ if (summary.status) lines.push(`**Riddle job status:** ${summary.status}`);
17538
+ if (summary.job_id) lines.push(`**Riddle job:** \`${summary.job_id}\``);
17539
+ if (summary.duration_ms) lines.push(`**Duration:** ${formatDuration(summary.duration_ms)}`);
17540
+ if (summary.proof_url) lines.push(`**Proof URL:** ${markdownLink(summary.proof_url, summary.proof_url)}`);
17541
+ if (summary.preview_id || summary.preview_url) {
17542
+ const previewLabel = summary.preview_id ? `\`${summary.preview_id}\`` : "preview";
17543
+ lines.push(`**Preview:** ${summary.preview_url ? markdownLink(previewLabel, summary.preview_url) : previewLabel}`);
17544
+ }
17545
+ if (summary.preview_publish_recovered) {
17546
+ const detail = summary.preview_publish_error ? `: ${summary.preview_publish_error}` : "";
17547
+ lines.push(`**Preview publish recovery:** recovered after publish error${detail}`);
17548
+ }
17549
+ lines.push(`**Checks:** ${summary.passed_checks} passed / ${summary.failed_checks} failed`);
17550
+ lines.push("");
17551
+ if (summary.primary_image) {
17552
+ lines.push("### Screenshot");
17553
+ lines.push(`![${summary.primary_image.name}](${summary.primary_image.url})`);
17554
+ lines.push("");
17555
+ }
17556
+ if (summary.pages.length) {
17557
+ lines.push("### Page Checks");
17558
+ for (const page of summary.pages.slice(0, 12)) {
17559
+ lines.push(`- \`${page.route}\`: ${page.passed} passed / ${page.failed} failed`);
17560
+ }
17561
+ if (summary.pages.length > 12) lines.push(`- ${summary.pages.length - 12} more page(s) omitted`);
17562
+ lines.push("");
17563
+ }
17564
+ const linkedArtifacts = summary.artifacts.filter((artifact) => artifact.url !== summary.primary_image?.url).sort((left, right) => artifactRank(left) - artifactRank(right) || left.name.localeCompare(right.name)).slice(0, 20);
17565
+ if (linkedArtifacts.length) {
17566
+ lines.push("### Artifacts");
17567
+ for (const artifact of linkedArtifacts) {
17568
+ lines.push(`- ${markdownLink(artifact.name, artifact.url)}`);
17569
+ }
17570
+ if (summary.artifacts.length - (summary.primary_image ? 1 : 0) > linkedArtifacts.length) {
17571
+ lines.push(`- ${summary.artifacts.length - (summary.primary_image ? 1 : 0) - linkedArtifacts.length} more artifact(s) omitted`);
17572
+ }
17573
+ lines.push("");
17574
+ }
17575
+ if (input.source?.trim()) {
17576
+ lines.push(`_Source: ${input.source.trim()}_`);
17577
+ } else {
17578
+ lines.push("_Updated by `riddle-proof-loop pr-comment`._");
17579
+ }
17580
+ return `${lines.join("\n").trim()}
17581
+ `;
17582
+ }
17583
+
17380
17584
  // src/cli.ts
17381
17585
  var RIDDLE_PROFILE_BALANCE_PREFLIGHT_MIN_SECONDS_PER_JOB = 30;
17382
17586
  var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
@@ -17399,11 +17603,14 @@ var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
17399
17603
  "codexSandbox",
17400
17604
  "codexTimeoutMs",
17401
17605
  "command",
17606
+ "commentMode",
17402
17607
  "continueWithStage",
17403
17608
  "createdAt",
17404
17609
  "decision",
17405
17610
  "defaultReviewer",
17406
17611
  "defaultShipMode",
17612
+ "bodyFile",
17613
+ "dryRun",
17407
17614
  "exclude",
17408
17615
  "format",
17409
17616
  "framework",
@@ -17431,20 +17638,25 @@ var KNOWN_CLI_OPTIONS = /* @__PURE__ */ new Set([
17431
17638
  "pack",
17432
17639
  "packFile",
17433
17640
  "profile",
17641
+ "proofDir",
17642
+ "pr",
17434
17643
  "progressEveryMs",
17435
17644
  "quiet",
17436
17645
  "readinessPath",
17437
17646
  "readinessTimeout",
17438
17647
  "reasonsJson",
17648
+ "repo",
17439
17649
  "requestJson",
17440
17650
  "requiredJson",
17441
17651
  "responseJson",
17442
17652
  "resultFormat",
17653
+ "resultJson",
17443
17654
  "resultsDir",
17444
17655
  "riddleEngineModuleUrl",
17445
17656
  "riddleProofDir",
17446
17657
  "route",
17447
17658
  "runDir",
17659
+ "runResponse",
17448
17660
  "runner",
17449
17661
  "scriptFile",
17450
17662
  "sourceKind",
@@ -17481,6 +17693,7 @@ function usage() {
17481
17693
  " riddle-proof-loop run-profile aggregate --profile <file|json|-> --url <base-url> [--base-url <base-url>] --input-dir <dir>|--inputs <path[,path...]> [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
17482
17694
  " riddle-proof-loop run-profile recover --profile <file|json|-> --url <base-url> [--base-url <base-url>] --job <job-id> [--viewport-name <name[,name...]>] [--output <dir>|--output-dir <dir>] [--result-format json|compact-json|summary|none; default json]",
17483
17695
  " riddle-proof-loop regression-pack run [--pack oc-flow-regression|--pack-file <file>] [--local-core true|false; default true] [--hosted-riddle true|false; default false] [--format json|markdown|compact-json; default json] [--output <dir>|--output-dir <dir>]",
17696
+ " riddle-proof-loop pr-comment --proof-dir <dir>|--run-response <file> [--result-json <file>] --pr <number|url> [--repo owner/name] [--dry-run] [--body-file <file>] [--comment-mode update|append]",
17484
17697
  " riddle-proof-loop profile-body-assertions --artifact <file|url|-> --candidates-json <file|json|-> [--required-json <file|json|->] [--format json|body-contains]",
17485
17698
  " riddle-proof-loop profile-http-status-preflight --profile <file|json|-> --url <base-url> [--format json|summary]",
17486
17699
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label> [--framework spa|static] [--quiet]",
@@ -18289,6 +18502,81 @@ function riddlePreviewProgressLine(snapshot) {
18289
18502
  const messagePart = snapshot.message ? ` ${snapshot.message}` : "";
18290
18503
  return `[riddle-preview] ${snapshot.stage}${idPart}${statusPart}${attemptPart} elapsed=${formatPollDuration(snapshot.elapsed_ms)} label=${snapshot.label} framework=${snapshot.framework}${filePart}${totalPart}${archivePart}${previewPart}${recoveryPart}${messagePart}`;
18291
18504
  }
18505
+ function readJsonFileIfExists(filePath) {
18506
+ if (!filePath || !(0, import_node_fs6.existsSync)(filePath)) return void 0;
18507
+ return readJsonValue(filePath, filePath);
18508
+ }
18509
+ function defaultProofDirJsonPath(proofDir, filename) {
18510
+ return proofDir ? import_node_path6.default.join(proofDir, filename) : void 0;
18511
+ }
18512
+ function prNumberFromValue(value) {
18513
+ const text = value?.trim();
18514
+ if (!text) return "";
18515
+ const match = text.match(/\/pull\/(\d+)(?:\/|$)/) || text.match(/^#?(\d+)$/);
18516
+ return match ? match[1] : text;
18517
+ }
18518
+ function ghJson(args, input) {
18519
+ const result = (0, import_node_child_process5.spawnSync)("gh", args, {
18520
+ input: typeof input === "undefined" ? void 0 : `${JSON.stringify(input)}
18521
+ `,
18522
+ encoding: "utf-8",
18523
+ timeout: 9e4
18524
+ });
18525
+ if (result.error) throw result.error;
18526
+ if (result.status !== 0) {
18527
+ const detail = (result.stderr || result.stdout || "").trim();
18528
+ throw new Error(`gh ${args.join(" ")} failed${detail ? `: ${detail}` : ""}`);
18529
+ }
18530
+ const stdout = (result.stdout || "").trim();
18531
+ return stdout ? JSON.parse(stdout) : {};
18532
+ }
18533
+ function resolveGhRepoName(repoOption) {
18534
+ if (repoOption?.trim()) return repoOption.trim();
18535
+ const result = (0, import_node_child_process5.spawnSync)("gh", ["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"], {
18536
+ encoding: "utf-8",
18537
+ timeout: 3e4
18538
+ });
18539
+ if (result.error) throw result.error;
18540
+ if (result.status !== 0 || !result.stdout.trim()) {
18541
+ const detail = (result.stderr || result.stdout || "").trim();
18542
+ throw new Error(`Could not resolve GitHub repository. Pass --repo owner/name.${detail ? ` gh said: ${detail}` : ""}`);
18543
+ }
18544
+ return result.stdout.trim();
18545
+ }
18546
+ function findManagedPrComment(repo, prNumber) {
18547
+ const comments = ghJson(["api", `repos/${repo}/issues/${prNumber}/comments`, "--paginate"]);
18548
+ return comments.find((comment) => typeof comment.body === "string" && comment.body.includes(RIDDLE_PROOF_PR_COMMENT_MARKER));
18549
+ }
18550
+ function upsertPrComment(input) {
18551
+ const payload = { body: input.body };
18552
+ if (input.mode !== "append") {
18553
+ const existing = findManagedPrComment(input.repo, input.prNumber);
18554
+ if (existing?.id) {
18555
+ return {
18556
+ action: "updated",
18557
+ comment: ghJson([
18558
+ "api",
18559
+ `repos/${input.repo}/issues/comments/${existing.id}`,
18560
+ "-X",
18561
+ "PATCH",
18562
+ "--input",
18563
+ "-"
18564
+ ], payload)
18565
+ };
18566
+ }
18567
+ }
18568
+ return {
18569
+ action: "created",
18570
+ comment: ghJson([
18571
+ "api",
18572
+ `repos/${input.repo}/issues/${input.prNumber}/comments`,
18573
+ "-X",
18574
+ "POST",
18575
+ "--input",
18576
+ "-"
18577
+ ], payload)
18578
+ };
18579
+ }
18292
18580
  function readJsonValue(value, label) {
18293
18581
  if (!value) throw new Error(`${label} is required.`);
18294
18582
  const raw = value === "-" ? readStdin() : (0, import_node_fs6.existsSync)(value) ? (0, import_node_fs6.readFileSync)(value, "utf-8") : value;
@@ -21921,6 +22209,47 @@ async function main() {
21921
22209
  process.exitCode = result.ok ? 0 : 1;
21922
22210
  return;
21923
22211
  }
22212
+ if (command === "pr-comment") {
22213
+ const proofDir = optionString(options, "proofDir") || optionString(options, "outputDir") || positional[1];
22214
+ const runResponsePath = optionString(options, "runResponse") || defaultProofDirJsonPath(proofDir, "riddle-run-response.json");
22215
+ const resultJsonPath = optionString(options, "resultJson") || defaultProofDirJsonPath(proofDir, "result.json");
22216
+ const runResponse = readJsonFileIfExists(runResponsePath);
22217
+ const result = readJsonFileIfExists(resultJsonPath);
22218
+ if (!runResponse && !result) {
22219
+ throw new Error("pr-comment requires --proof-dir with riddle-run-response.json/result.json or explicit --run-response/--result-json.");
22220
+ }
22221
+ const body = buildRiddleProofPrCommentMarkdown({
22222
+ title: optionString(options, "title"),
22223
+ goal: optionString(options, "summary"),
22224
+ successCriteria: optionString(options, "successCriteria"),
22225
+ runResponse,
22226
+ result
22227
+ });
22228
+ const bodyFile = optionString(options, "bodyFile");
22229
+ if (bodyFile) (0, import_node_fs6.writeFileSync)(bodyFile, body);
22230
+ if (optionBoolean(options, "dryRun")) {
22231
+ process.stdout.write(body);
22232
+ return;
22233
+ }
22234
+ const prNumber = prNumberFromValue(optionString(options, "pr"));
22235
+ if (!prNumber) throw new Error("pr-comment requires --pr <number|url> unless --dry-run is used.");
22236
+ const commentMode = optionString(options, "commentMode") || "update";
22237
+ if (!["update", "append"].includes(commentMode)) throw new Error("--comment-mode must be update or append.");
22238
+ const repo = resolveGhRepoName(optionString(options, "repo"));
22239
+ const resultPayload = upsertPrComment({ repo, prNumber, body, mode: commentMode });
22240
+ const comment = resultPayload.comment;
22241
+ process.stdout.write(`${JSON.stringify({
22242
+ ok: true,
22243
+ action: resultPayload.action,
22244
+ repo,
22245
+ pr: prNumber,
22246
+ comment_url: cliString(comment.html_url) || null,
22247
+ summary: summarizeRiddleProofPrComment({ runResponse, result }),
22248
+ body_file: bodyFile || null
22249
+ }, null, 2)}
22250
+ `);
22251
+ return;
22252
+ }
21924
22253
  if (command === "profile-http-status-preflight") {
21925
22254
  const profile = normalizeProfileForCli(options);
21926
22255
  const result = await preflightRiddleProofProfileHttpStatusChecks(profile);
package/dist/cli.js CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-F4HKK2YH.js";
3
- import "./chunk-Z2LCVROU.js";
2
+ import "./chunk-U44KBAPH.js";
4
3
  import "./chunk-DI2XNGEZ.js";
4
+ import "./chunk-6KYXX4OE.js";
5
+ import "./chunk-Z2LCVROU.js";
5
6
  import "./chunk-ZREWMTFA.js";
6
7
  import "./chunk-ZQWVXQKJ.js";
7
8
  import "./chunk-RDPG554T.js";
package/dist/index.cjs CHANGED
@@ -3411,6 +3411,7 @@ __export(index_exports, {
3411
3411
  RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
3412
3412
  RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
3413
3413
  RIDDLE_PROOF_PROFILE_VERSION: () => RIDDLE_PROOF_PROFILE_VERSION,
3414
+ RIDDLE_PROOF_PR_COMMENT_MARKER: () => RIDDLE_PROOF_PR_COMMENT_MARKER,
3414
3415
  RIDDLE_PROOF_RUN_CARD_VERSION: () => RIDDLE_PROOF_RUN_CARD_VERSION,
3415
3416
  RIDDLE_PROOF_RUN_STATE_VERSION: () => RIDDLE_PROOF_RUN_STATE_VERSION,
3416
3417
  RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION: () => RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
@@ -3433,6 +3434,7 @@ __export(index_exports, {
3433
3434
  buildAuthorCheckpointPacket: () => buildAuthorCheckpointPacket,
3434
3435
  buildCheckpointPacketForEngineResult: () => buildCheckpointPacketForEngineResult,
3435
3436
  buildProofAssessmentCheckpointPacket: () => buildProofAssessmentCheckpointPacket,
3437
+ buildRiddleProofPrCommentMarkdown: () => buildRiddleProofPrCommentMarkdown,
3436
3438
  buildRiddleProofProfileScript: () => buildRiddleProofProfileScript,
3437
3439
  buildStageCheckpointPacket: () => buildStageCheckpointPacket,
3438
3440
  buildVisualProofSession: () => buildVisualProofSession,
@@ -3507,6 +3509,7 @@ __export(index_exports, {
3507
3509
  slugifyRiddleProofProfileName: () => slugifyRiddleProofProfileName,
3508
3510
  statePathsForRunState: () => statePathsForRunState,
3509
3511
  summarizeCaptureArtifacts: () => summarizeCaptureArtifacts,
3512
+ summarizeRiddleProofPrComment: () => summarizeRiddleProofPrComment,
3510
3513
  summarizeRiddleProofProfileResult: () => summarizeRiddleProofProfileResult,
3511
3514
  visualSessionFingerprint: () => visualSessionFingerprint,
3512
3515
  visualSessionFingerprintBasis: () => visualSessionFingerprintBasis
@@ -19566,6 +19569,210 @@ function createRiddleApiClient(config = {}) {
19566
19569
  pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
19567
19570
  };
19568
19571
  }
19572
+
19573
+ // src/pr-comment.ts
19574
+ var RIDDLE_PROOF_PR_COMMENT_MARKER = "<!-- riddle-proof:pr-comment:v1 -->";
19575
+ function asRecord(value) {
19576
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
19577
+ }
19578
+ function asArray(value) {
19579
+ return Array.isArray(value) ? value : [];
19580
+ }
19581
+ function stringValue6(value) {
19582
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
19583
+ }
19584
+ function numberValue4(value) {
19585
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
19586
+ }
19587
+ function booleanValue2(value) {
19588
+ return typeof value === "boolean" ? value : void 0;
19589
+ }
19590
+ function artifactKind(name, url) {
19591
+ const target = `${name} ${url}`.toLowerCase();
19592
+ if (/\.(png|jpe?g|gif|webp|avif|svg)(\?|#|$)/.test(target)) return "image";
19593
+ if (/\.(json|har|txt|md|html|log)(\?|#|$)/.test(target)) return "data";
19594
+ return "artifact";
19595
+ }
19596
+ function artifactDisplayName(value, fallback) {
19597
+ const raw = stringValue6(value);
19598
+ if (raw) return raw;
19599
+ return fallback;
19600
+ }
19601
+ function collectArtifacts(runResponse) {
19602
+ const proofResult = asRecord(runResponse.proofResult);
19603
+ const outputs = asArray(proofResult.outputs);
19604
+ const artifacts = [];
19605
+ const seen = /* @__PURE__ */ new Set();
19606
+ for (const [index, item] of outputs.entries()) {
19607
+ const artifact = asRecord(item);
19608
+ const url = stringValue6(artifact.url);
19609
+ if (!url || seen.has(url)) continue;
19610
+ seen.add(url);
19611
+ const name = artifactDisplayName(artifact.name, `artifact-${index + 1}`);
19612
+ artifacts.push({
19613
+ name,
19614
+ url,
19615
+ kind: artifactKind(name, url),
19616
+ size_bytes: numberValue4(artifact.size)
19617
+ });
19618
+ }
19619
+ return artifacts;
19620
+ }
19621
+ function pageSummaries(result) {
19622
+ const pages = [];
19623
+ for (const page of asArray(result.pages)) {
19624
+ const record = asRecord(page);
19625
+ const route = stringValue6(record.route) || stringValue6(record.url) || "page";
19626
+ const checks = asRecord(record.checks);
19627
+ let passed = 0;
19628
+ let failed = 0;
19629
+ for (const value of Object.values(checks)) {
19630
+ if (value === true) passed += 1;
19631
+ if (value === false) failed += 1;
19632
+ }
19633
+ pages.push({ route, passed, failed });
19634
+ }
19635
+ return pages;
19636
+ }
19637
+ function summarizeExplicitChecks(value) {
19638
+ let passed = 0;
19639
+ let failed = 0;
19640
+ const visit = (current, inChecks = false) => {
19641
+ if (current === true && inChecks) {
19642
+ passed += 1;
19643
+ return;
19644
+ }
19645
+ if (current === false && inChecks) {
19646
+ failed += 1;
19647
+ return;
19648
+ }
19649
+ if (Array.isArray(current)) {
19650
+ for (const item of current) visit(item, inChecks);
19651
+ return;
19652
+ }
19653
+ if (current && typeof current === "object") {
19654
+ for (const [key, item] of Object.entries(current)) {
19655
+ visit(item, inChecks || key === "checks");
19656
+ }
19657
+ }
19658
+ };
19659
+ visit(value);
19660
+ return { passed, failed };
19661
+ }
19662
+ function selectPrimaryImage(artifacts) {
19663
+ const images = artifacts.filter((artifact) => artifact.kind === "image");
19664
+ return images.find((artifact) => /after|proof|screenshot/i.test(artifact.name)) || images[0];
19665
+ }
19666
+ function summarizeRiddleProofPrComment(input) {
19667
+ const runResponse = asRecord(input.runResponse);
19668
+ const result = asRecord(input.result);
19669
+ const proofResult = asRecord(runResponse.proofResult);
19670
+ const preview = asRecord(runResponse.preview);
19671
+ const artifacts = collectArtifacts(runResponse);
19672
+ const pages = pageSummaries(result);
19673
+ const checkSource = { ...result };
19674
+ delete checkSource.ok;
19675
+ const nestedChecks = summarizeExplicitChecks(checkSource);
19676
+ const ok = booleanValue2(result.ok) ?? booleanValue2(runResponse.ok) ?? null;
19677
+ return {
19678
+ ok,
19679
+ status: stringValue6(proofResult.status),
19680
+ job_id: stringValue6(proofResult.job_id),
19681
+ duration_ms: numberValue4(proofResult.duration_ms),
19682
+ proof_url: stringValue6(runResponse.proofUrl),
19683
+ preview_id: stringValue6(preview.id),
19684
+ preview_url: stringValue6(preview.preview_url) || stringValue6(preview.url),
19685
+ preview_publish_recovered: booleanValue2(preview.publish_recovered),
19686
+ preview_publish_error: stringValue6(preview.publish_error),
19687
+ passed_checks: nestedChecks.passed,
19688
+ failed_checks: nestedChecks.failed,
19689
+ pages,
19690
+ artifacts,
19691
+ primary_image: selectPrimaryImage(artifacts)
19692
+ };
19693
+ }
19694
+ function formatDuration(ms) {
19695
+ if (typeof ms !== "number" || !Number.isFinite(ms)) return "";
19696
+ const seconds = Math.max(0, Math.round(ms / 1e3));
19697
+ const minutes = Math.floor(seconds / 60);
19698
+ const remainder = seconds % 60;
19699
+ return minutes > 0 ? `${minutes}m${String(remainder).padStart(2, "0")}s` : `${seconds}s`;
19700
+ }
19701
+ function markdownLink(label, url) {
19702
+ return `[${label.replace(/\]/g, "\\]")}](${url})`;
19703
+ }
19704
+ function resultLabel(summary) {
19705
+ if (summary.ok === true) return "passed";
19706
+ if (summary.ok === false) return "failed";
19707
+ return summary.status || "recorded";
19708
+ }
19709
+ function artifactRank(artifact) {
19710
+ const name = artifact.name.toLowerCase();
19711
+ if (name === "proof.json") return 0;
19712
+ if (name === "result.json") return 1;
19713
+ if (name.includes("proof") && name.endsWith(".json") && !name.includes("layout")) return 2;
19714
+ if (name === "console.json") return 3;
19715
+ if (artifact.kind === "data") return 10;
19716
+ if (artifact.kind === "image") return 20;
19717
+ return 30;
19718
+ }
19719
+ function buildRiddleProofPrCommentMarkdown(input) {
19720
+ const summary = summarizeRiddleProofPrComment(input);
19721
+ const title = input.title?.trim() || "Riddle Proof Evidence";
19722
+ const lines = [
19723
+ RIDDLE_PROOF_PR_COMMENT_MARKER,
19724
+ `## ${title}`,
19725
+ "",
19726
+ `**Result:** ${resultLabel(summary)}`
19727
+ ];
19728
+ if (input.goal?.trim()) lines.push(`**Goal:** ${input.goal.trim()}`);
19729
+ if (input.successCriteria?.trim()) lines.push(`**Success criteria:** ${input.successCriteria.trim()}`);
19730
+ if (summary.status) lines.push(`**Riddle job status:** ${summary.status}`);
19731
+ if (summary.job_id) lines.push(`**Riddle job:** \`${summary.job_id}\``);
19732
+ if (summary.duration_ms) lines.push(`**Duration:** ${formatDuration(summary.duration_ms)}`);
19733
+ if (summary.proof_url) lines.push(`**Proof URL:** ${markdownLink(summary.proof_url, summary.proof_url)}`);
19734
+ if (summary.preview_id || summary.preview_url) {
19735
+ const previewLabel = summary.preview_id ? `\`${summary.preview_id}\`` : "preview";
19736
+ lines.push(`**Preview:** ${summary.preview_url ? markdownLink(previewLabel, summary.preview_url) : previewLabel}`);
19737
+ }
19738
+ if (summary.preview_publish_recovered) {
19739
+ const detail = summary.preview_publish_error ? `: ${summary.preview_publish_error}` : "";
19740
+ lines.push(`**Preview publish recovery:** recovered after publish error${detail}`);
19741
+ }
19742
+ lines.push(`**Checks:** ${summary.passed_checks} passed / ${summary.failed_checks} failed`);
19743
+ lines.push("");
19744
+ if (summary.primary_image) {
19745
+ lines.push("### Screenshot");
19746
+ lines.push(`![${summary.primary_image.name}](${summary.primary_image.url})`);
19747
+ lines.push("");
19748
+ }
19749
+ if (summary.pages.length) {
19750
+ lines.push("### Page Checks");
19751
+ for (const page of summary.pages.slice(0, 12)) {
19752
+ lines.push(`- \`${page.route}\`: ${page.passed} passed / ${page.failed} failed`);
19753
+ }
19754
+ if (summary.pages.length > 12) lines.push(`- ${summary.pages.length - 12} more page(s) omitted`);
19755
+ lines.push("");
19756
+ }
19757
+ const linkedArtifacts = summary.artifacts.filter((artifact) => artifact.url !== summary.primary_image?.url).sort((left, right) => artifactRank(left) - artifactRank(right) || left.name.localeCompare(right.name)).slice(0, 20);
19758
+ if (linkedArtifacts.length) {
19759
+ lines.push("### Artifacts");
19760
+ for (const artifact of linkedArtifacts) {
19761
+ lines.push(`- ${markdownLink(artifact.name, artifact.url)}`);
19762
+ }
19763
+ if (summary.artifacts.length - (summary.primary_image ? 1 : 0) > linkedArtifacts.length) {
19764
+ lines.push(`- ${summary.artifacts.length - (summary.primary_image ? 1 : 0) - linkedArtifacts.length} more artifact(s) omitted`);
19765
+ }
19766
+ lines.push("");
19767
+ }
19768
+ if (input.source?.trim()) {
19769
+ lines.push(`_Source: ${input.source.trim()}_`);
19770
+ } else {
19771
+ lines.push("_Updated by `riddle-proof-loop pr-comment`._");
19772
+ }
19773
+ return `${lines.join("\n").trim()}
19774
+ `;
19775
+ }
19569
19776
  // Annotate the CommonJS export names for ESM import in node:
19570
19777
  0 && (module.exports = {
19571
19778
  BASIC_GAMEPLAY_ACTION_TYPES,
@@ -19590,6 +19797,7 @@ function createRiddleApiClient(config = {}) {
19590
19797
  RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
19591
19798
  RIDDLE_PROOF_PROFILE_STATUSES,
19592
19799
  RIDDLE_PROOF_PROFILE_VERSION,
19800
+ RIDDLE_PROOF_PR_COMMENT_MARKER,
19593
19801
  RIDDLE_PROOF_RUN_CARD_VERSION,
19594
19802
  RIDDLE_PROOF_RUN_STATE_VERSION,
19595
19803
  RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION,
@@ -19612,6 +19820,7 @@ function createRiddleApiClient(config = {}) {
19612
19820
  buildAuthorCheckpointPacket,
19613
19821
  buildCheckpointPacketForEngineResult,
19614
19822
  buildProofAssessmentCheckpointPacket,
19823
+ buildRiddleProofPrCommentMarkdown,
19615
19824
  buildRiddleProofProfileScript,
19616
19825
  buildStageCheckpointPacket,
19617
19826
  buildVisualProofSession,
@@ -19686,6 +19895,7 @@ function createRiddleApiClient(config = {}) {
19686
19895
  slugifyRiddleProofProfileName,
19687
19896
  statePathsForRunState,
19688
19897
  summarizeCaptureArtifacts,
19898
+ summarizeRiddleProofPrComment,
19689
19899
  summarizeRiddleProofProfileResult,
19690
19900
  visualSessionFingerprint,
19691
19901
  visualSessionFingerprintBasis
package/dist/index.d.cts CHANGED
@@ -12,3 +12,4 @@ export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION,
12
12
  export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.cjs';
13
13
  export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofArtifactBodyAssertionInput, RiddleProofArtifactBodyAssertionResult, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileHttpStatusBodyJsonAssertion, RiddleProofProfileHttpStatusBodyJsonAssertionResult, RiddleProofProfileHttpStatusPreflightCheckResult, RiddleProofProfileHttpStatusPreflightFetch, RiddleProofProfileHttpStatusPreflightFetchResponse, RiddleProofProfileHttpStatusPreflightOptions, RiddleProofProfileHttpStatusPreflightResult, RiddleProofProfileJsonValueType, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileReturnSummaryField, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, deriveRiddleProofArtifactBodyAssertions, extractRiddleProofProfileResult, normalizeRiddleProofProfile, preflightRiddleProofProfileHttpStatusChecks, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
14
14
  export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.cjs';
15
+ export { RIDDLE_PROOF_PR_COMMENT_MARKER, RiddleProofPrCommentArtifact, RiddleProofPrCommentArtifactKind, RiddleProofPrCommentInput, RiddleProofPrCommentPageSummary, RiddleProofPrCommentSummary, buildRiddleProofPrCommentMarkdown, summarizeRiddleProofPrComment } from './pr-comment.cjs';