@riddledc/riddle-proof 0.5.55 → 0.5.57

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.
@@ -21,14 +21,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var basic_gameplay_exports = {};
22
22
  __export(basic_gameplay_exports, {
23
23
  RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
24
+ RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
24
25
  RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION: () => RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
25
26
  assessBasicGameplayEvidence: () => assessBasicGameplayEvidence,
26
27
  assessBasicGameplayRoute: () => assessBasicGameplayRoute,
28
+ createBasicGameplayCatchSummary: () => createBasicGameplayCatchSummary,
27
29
  extractBasicGameplayEvidence: () => extractBasicGameplayEvidence
28
30
  });
29
31
  module.exports = __toCommonJS(basic_gameplay_exports);
30
32
  var RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION = "riddle-proof.basic-gameplay.v1";
31
33
  var RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION = "riddle-proof.basic-gameplay.assessment.v1";
34
+ var RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION = "riddle-proof.basic-gameplay.catch.v1";
32
35
  var BASIC_GAMEPLAY_CONTAINER_KEYS = [
33
36
  "basic_gameplay",
34
37
  "basicGameplay",
@@ -138,6 +141,37 @@ function assessBasicGameplayRoute(route, options = {}) {
138
141
  }
139
142
  };
140
143
  }
144
+ function createBasicGameplayCatchSummary(input, options = {}) {
145
+ const before = summarizeAssessment(assessBasicGameplayEvidence(input.before, options));
146
+ const after = input.after === void 0 ? void 0 : summarizeAssessment(assessBasicGameplayEvidence(input.after, options));
147
+ const fixed = Boolean(after && before.notable_codes.length > 0 && after.passed && after.notable_codes.length === 0);
148
+ const title = input.title || [
149
+ input.site || "Basic gameplay",
150
+ input.route ? `${input.route} proof catch` : "proof catch"
151
+ ].join(" ");
152
+ const beforeCodes = before.notable_codes.length ? before.notable_codes.join(", ") : "no failing or warning codes";
153
+ const afterCodes = after ? after.notable_codes.length ? after.notable_codes.join(", ") : "no failing or warning codes" : "not verified";
154
+ const summaryLines = [
155
+ `Before: ${before.checked_routes} checked, ${before.passing_routes} passing, codes: ${beforeCodes}.`,
156
+ after ? `After: ${after.checked_routes} checked, ${after.passing_routes} passing, codes: ${afterCodes}.` : "After: not provided."
157
+ ];
158
+ if (input.fix?.summary) summaryLines.push(`Fix: ${input.fix.summary}`);
159
+ if (input.artifacts?.length) summaryLines.push(`Artifacts: ${input.artifacts.length} attached.`);
160
+ return {
161
+ version: RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
162
+ title,
163
+ site: input.site,
164
+ route: input.route,
165
+ detected_at: input.detected_at || (/* @__PURE__ */ new Date()).toISOString(),
166
+ before,
167
+ after,
168
+ fixed,
169
+ fix: input.fix,
170
+ artifacts: input.artifacts || [],
171
+ summary_lines: summaryLines,
172
+ marketing_summary: fixed ? `${title}: Riddle Proof caught ${beforeCodes}; after the fix, ${afterCodes}.` : `${title}: Riddle Proof caught ${beforeCodes}; after evidence is ${after ? "not yet clean" : "not yet attached"}.`
173
+ };
174
+ }
141
175
  function extractBasicGameplayEvidence(...sources) {
142
176
  const seen = /* @__PURE__ */ new Set();
143
177
  for (const source of sources) {
@@ -146,6 +180,21 @@ function extractBasicGameplayEvidence(...sources) {
146
180
  }
147
181
  return null;
148
182
  }
183
+ function summarizeAssessment(assessment) {
184
+ return {
185
+ evidence_present: assessment.evidence_present,
186
+ passed: assessment.passed,
187
+ checked_routes: assessment.checked_routes,
188
+ passing_routes: assessment.passing_routes,
189
+ failing_routes: assessment.failing_routes,
190
+ failure_counts: assessment.failure_counts,
191
+ warning_counts: assessment.warning_counts,
192
+ notable_codes: [
193
+ ...Object.keys(assessment.failure_counts),
194
+ ...Object.keys(assessment.warning_counts)
195
+ ].sort()
196
+ };
197
+ }
149
198
  function findBasicGameplayEvidence(value, seen, depth = 0) {
150
199
  if (depth > 6 || value === null || value === void 0) return null;
151
200
  if (typeof value === "string") {
@@ -248,8 +297,10 @@ function parseJson(value) {
248
297
  // Annotate the CommonJS export names for ESM import in node:
249
298
  0 && (module.exports = {
250
299
  RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
300
+ RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
251
301
  RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
252
302
  assessBasicGameplayEvidence,
253
303
  assessBasicGameplayRoute,
304
+ createBasicGameplayCatchSummary,
254
305
  extractBasicGameplayEvidence
255
306
  });
@@ -1,5 +1,6 @@
1
1
  declare const RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION = "riddle-proof.basic-gameplay.v1";
2
2
  declare const RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION = "riddle-proof.basic-gameplay.assessment.v1";
3
+ declare const RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION = "riddle-proof.basic-gameplay.catch.v1";
3
4
  type BasicGameplayFailureCode = "route_http_error" | "fatal_page_error" | "route_blank_or_thin" | "no_game_surface" | "mobile_horizontal_overflow" | "primary_control_missing" | "primary_control_inert";
4
5
  type BasicGameplayWarningCode = "canvas_inert" | "some_actions_failed" | "missing_reset_path" | "critical_console_error";
5
6
  interface BasicGameplayCanvasState {
@@ -110,8 +111,59 @@ interface RiddleProofBasicGameplayAssessment {
110
111
  warning_counts: Record<string, number>;
111
112
  route_results: RiddleProofBasicGameplayRouteAssessment[];
112
113
  }
114
+ interface BasicGameplayProofArtifact {
115
+ name: string;
116
+ role?: string;
117
+ kind?: string;
118
+ url?: string;
119
+ path?: string;
120
+ sha256?: string;
121
+ [key: string]: unknown;
122
+ }
123
+ interface BasicGameplayFixReference {
124
+ repo?: string;
125
+ commit?: string;
126
+ pr_url?: string;
127
+ summary?: string;
128
+ [key: string]: unknown;
129
+ }
130
+ interface CreateBasicGameplayCatchSummaryInput {
131
+ title?: string;
132
+ site?: string;
133
+ route?: string;
134
+ detected_at?: string;
135
+ before: unknown;
136
+ after?: unknown;
137
+ fix?: BasicGameplayFixReference;
138
+ artifacts?: BasicGameplayProofArtifact[];
139
+ }
140
+ interface BasicGameplayAssessmentSummary {
141
+ evidence_present: boolean;
142
+ passed: boolean;
143
+ checked_routes: number;
144
+ passing_routes: number;
145
+ failing_routes: RiddleProofBasicGameplayAssessment["failing_routes"];
146
+ failure_counts: Record<string, number>;
147
+ warning_counts: Record<string, number>;
148
+ notable_codes: string[];
149
+ }
150
+ interface RiddleProofBasicGameplayCatchSummary {
151
+ version: typeof RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION;
152
+ title: string;
153
+ site?: string;
154
+ route?: string;
155
+ detected_at: string;
156
+ before: BasicGameplayAssessmentSummary;
157
+ after?: BasicGameplayAssessmentSummary;
158
+ fixed: boolean;
159
+ fix?: BasicGameplayFixReference;
160
+ artifacts: BasicGameplayProofArtifact[];
161
+ summary_lines: string[];
162
+ marketing_summary: string;
163
+ }
113
164
  declare function assessBasicGameplayEvidence(evidence: unknown, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayAssessment;
114
165
  declare function assessBasicGameplayRoute(route: RiddleProofBasicGameplayRouteEvidence, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayRouteAssessment;
166
+ declare function createBasicGameplayCatchSummary(input: CreateBasicGameplayCatchSummaryInput, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayCatchSummary;
115
167
  declare function extractBasicGameplayEvidence(...sources: unknown[]): RiddleProofBasicGameplayEvidence | null;
116
168
 
117
- export { type AssessBasicGameplayOptions, type BasicGameplayActionResult, type BasicGameplayCanvasState, type BasicGameplayChangeSummary, type BasicGameplayFailureCode, type BasicGameplayMobileEvidence, type BasicGameplaySnapshot, type BasicGameplayWarningCode, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, type RiddleProofBasicGameplayAssessment, type RiddleProofBasicGameplayEvidence, type RiddleProofBasicGameplayRouteAssessment, type RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayRoute, extractBasicGameplayEvidence };
169
+ export { type AssessBasicGameplayOptions, type BasicGameplayActionResult, type BasicGameplayAssessmentSummary, type BasicGameplayCanvasState, type BasicGameplayChangeSummary, type BasicGameplayFailureCode, type BasicGameplayFixReference, type BasicGameplayMobileEvidence, type BasicGameplayProofArtifact, type BasicGameplaySnapshot, type BasicGameplayWarningCode, type CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, type RiddleProofBasicGameplayAssessment, type RiddleProofBasicGameplayCatchSummary, type RiddleProofBasicGameplayEvidence, type RiddleProofBasicGameplayRouteAssessment, type RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayRoute, createBasicGameplayCatchSummary, extractBasicGameplayEvidence };
@@ -1,5 +1,6 @@
1
1
  declare const RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION = "riddle-proof.basic-gameplay.v1";
2
2
  declare const RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION = "riddle-proof.basic-gameplay.assessment.v1";
3
+ declare const RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION = "riddle-proof.basic-gameplay.catch.v1";
3
4
  type BasicGameplayFailureCode = "route_http_error" | "fatal_page_error" | "route_blank_or_thin" | "no_game_surface" | "mobile_horizontal_overflow" | "primary_control_missing" | "primary_control_inert";
4
5
  type BasicGameplayWarningCode = "canvas_inert" | "some_actions_failed" | "missing_reset_path" | "critical_console_error";
5
6
  interface BasicGameplayCanvasState {
@@ -110,8 +111,59 @@ interface RiddleProofBasicGameplayAssessment {
110
111
  warning_counts: Record<string, number>;
111
112
  route_results: RiddleProofBasicGameplayRouteAssessment[];
112
113
  }
114
+ interface BasicGameplayProofArtifact {
115
+ name: string;
116
+ role?: string;
117
+ kind?: string;
118
+ url?: string;
119
+ path?: string;
120
+ sha256?: string;
121
+ [key: string]: unknown;
122
+ }
123
+ interface BasicGameplayFixReference {
124
+ repo?: string;
125
+ commit?: string;
126
+ pr_url?: string;
127
+ summary?: string;
128
+ [key: string]: unknown;
129
+ }
130
+ interface CreateBasicGameplayCatchSummaryInput {
131
+ title?: string;
132
+ site?: string;
133
+ route?: string;
134
+ detected_at?: string;
135
+ before: unknown;
136
+ after?: unknown;
137
+ fix?: BasicGameplayFixReference;
138
+ artifacts?: BasicGameplayProofArtifact[];
139
+ }
140
+ interface BasicGameplayAssessmentSummary {
141
+ evidence_present: boolean;
142
+ passed: boolean;
143
+ checked_routes: number;
144
+ passing_routes: number;
145
+ failing_routes: RiddleProofBasicGameplayAssessment["failing_routes"];
146
+ failure_counts: Record<string, number>;
147
+ warning_counts: Record<string, number>;
148
+ notable_codes: string[];
149
+ }
150
+ interface RiddleProofBasicGameplayCatchSummary {
151
+ version: typeof RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION;
152
+ title: string;
153
+ site?: string;
154
+ route?: string;
155
+ detected_at: string;
156
+ before: BasicGameplayAssessmentSummary;
157
+ after?: BasicGameplayAssessmentSummary;
158
+ fixed: boolean;
159
+ fix?: BasicGameplayFixReference;
160
+ artifacts: BasicGameplayProofArtifact[];
161
+ summary_lines: string[];
162
+ marketing_summary: string;
163
+ }
113
164
  declare function assessBasicGameplayEvidence(evidence: unknown, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayAssessment;
114
165
  declare function assessBasicGameplayRoute(route: RiddleProofBasicGameplayRouteEvidence, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayRouteAssessment;
166
+ declare function createBasicGameplayCatchSummary(input: CreateBasicGameplayCatchSummaryInput, options?: AssessBasicGameplayOptions): RiddleProofBasicGameplayCatchSummary;
115
167
  declare function extractBasicGameplayEvidence(...sources: unknown[]): RiddleProofBasicGameplayEvidence | null;
116
168
 
117
- export { type AssessBasicGameplayOptions, type BasicGameplayActionResult, type BasicGameplayCanvasState, type BasicGameplayChangeSummary, type BasicGameplayFailureCode, type BasicGameplayMobileEvidence, type BasicGameplaySnapshot, type BasicGameplayWarningCode, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, type RiddleProofBasicGameplayAssessment, type RiddleProofBasicGameplayEvidence, type RiddleProofBasicGameplayRouteAssessment, type RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayRoute, extractBasicGameplayEvidence };
169
+ export { type AssessBasicGameplayOptions, type BasicGameplayActionResult, type BasicGameplayAssessmentSummary, type BasicGameplayCanvasState, type BasicGameplayChangeSummary, type BasicGameplayFailureCode, type BasicGameplayFixReference, type BasicGameplayMobileEvidence, type BasicGameplayProofArtifact, type BasicGameplaySnapshot, type BasicGameplayWarningCode, type CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, type RiddleProofBasicGameplayAssessment, type RiddleProofBasicGameplayCatchSummary, type RiddleProofBasicGameplayEvidence, type RiddleProofBasicGameplayRouteAssessment, type RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayRoute, createBasicGameplayCatchSummary, extractBasicGameplayEvidence };
@@ -1,14 +1,18 @@
1
1
  import {
2
2
  RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
3
+ RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
3
4
  RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
4
5
  assessBasicGameplayEvidence,
5
6
  assessBasicGameplayRoute,
7
+ createBasicGameplayCatchSummary,
6
8
  extractBasicGameplayEvidence
7
- } from "./chunk-RNGJX62B.js";
9
+ } from "./chunk-53DJMNQ6.js";
8
10
  export {
9
11
  RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
12
+ RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
10
13
  RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
11
14
  assessBasicGameplayEvidence,
12
15
  assessBasicGameplayRoute,
16
+ createBasicGameplayCatchSummary,
13
17
  extractBasicGameplayEvidence
14
18
  };
@@ -87,12 +87,94 @@ async function deployRiddleStaticPreview(config, directory, label) {
87
87
  raw: published
88
88
  };
89
89
  }
90
+ function createTarball(directory, label, exclude = []) {
91
+ const scratch = mkdtempSync(path.join(tmpdir(), "riddle-upload-"));
92
+ const tarball = path.join(scratch, `${label}.tar.gz`);
93
+ const excludeArgs = exclude.flatMap((item) => ["--exclude", item]);
94
+ try {
95
+ execFileSync("tar", ["czf", tarball, ...excludeArgs, "-C", directory, "."], { stdio: "pipe" });
96
+ return { scratch, tarball };
97
+ } catch (error) {
98
+ rmSync(scratch, { recursive: true, force: true });
99
+ throw error;
100
+ }
101
+ }
90
102
  function parseRiddleViewport(value) {
91
103
  if (!value) return void 0;
92
104
  const match = /^(\d+)x(\d+)$/.exec(value.trim());
93
105
  if (!match) throw new Error("viewport must look like 1280x720");
94
106
  return { width: Number(match[1]), height: Number(match[2]) };
95
107
  }
108
+ function scriptErrorFrom(job) {
109
+ const nested = job?.proof_of_execution && typeof job.proof_of_execution === "object" && !Array.isArray(job.proof_of_execution) ? job.proof_of_execution : null;
110
+ return typeof job?.script_error === "string" && job.script_error.trim() ? job.script_error : typeof nested?.script_error === "string" && nested.script_error.trim() ? nested.script_error : null;
111
+ }
112
+ async function runRiddleServerPreview(config, input) {
113
+ if (!input.directory?.trim()) throw new Error("directory is required");
114
+ if (!input.script?.trim()) throw new Error("script is required");
115
+ const port = input.port || 3e3;
116
+ const routePath = input.path || "/";
117
+ const timeoutSec = input.timeoutSec || 180;
118
+ const created = await riddleRequestJson(config, "/v1/server-preview", {
119
+ method: "POST",
120
+ body: JSON.stringify({
121
+ image: input.image || "node:22-slim",
122
+ command: input.command || "node scripts/riddleSpaPreviewServer.mjs build 3000",
123
+ port,
124
+ path: routePath,
125
+ readiness_path: input.readinessPath || routePath,
126
+ readiness_timeout: input.readinessTimeoutSec || 90,
127
+ wait_until: input.waitUntil || "domcontentloaded",
128
+ wait_for_selector: input.waitForSelector || "body",
129
+ navigation_timeout: input.navigationTimeoutSec || 60,
130
+ viewport: input.viewport,
131
+ timeout: timeoutSec,
132
+ script: input.script
133
+ })
134
+ });
135
+ const jobId = String(created.job_id || "");
136
+ const uploadUrl = String(created.upload_url || "");
137
+ if (!jobId || !uploadUrl) {
138
+ throw new Error(`Riddle server preview create response was missing job_id or upload_url.`);
139
+ }
140
+ const { scratch, tarball } = createTarball(input.directory, jobId, [
141
+ ".git",
142
+ "node_modules",
143
+ "test-results",
144
+ ...input.exclude || []
145
+ ]);
146
+ try {
147
+ const upload = await fetchFor(config)(uploadUrl, {
148
+ method: "PUT",
149
+ headers: { "Content-Type": "application/gzip" },
150
+ body: readFileSync(tarball)
151
+ });
152
+ if (!upload.ok) throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
153
+ } finally {
154
+ rmSync(scratch, { recursive: true, force: true });
155
+ }
156
+ await riddleRequestJson(config, `/v1/server-preview/${jobId}/start`, {
157
+ method: "POST"
158
+ });
159
+ let job = null;
160
+ const attempts = input.pollAttempts || Math.ceil((timeoutSec + 90) / 2);
161
+ const intervalMs = input.pollIntervalMs || 2e3;
162
+ for (let index = 0; index < attempts; index += 1) {
163
+ job = await riddleRequestJson(config, `/v1/server-preview/${jobId}`);
164
+ if (isTerminalRiddleJobStatus(job.status)) break;
165
+ if (index + 1 < attempts) await new Promise((resolve) => setTimeout(resolve, intervalMs));
166
+ }
167
+ const status = job?.status ? String(job.status) : null;
168
+ const scriptError = scriptErrorFrom(job);
169
+ return {
170
+ ok: (status === "completed" || status === "complete") && !scriptError,
171
+ job_id: jobId,
172
+ status,
173
+ terminal: isTerminalRiddleJobStatus(status),
174
+ script_error: scriptError,
175
+ job
176
+ };
177
+ }
96
178
  async function runRiddleScript(config, input) {
97
179
  if (!input.url?.trim()) throw new Error("url is required");
98
180
  if (!input.script?.trim()) throw new Error("script is required");
@@ -144,6 +226,7 @@ function createRiddleApiClient(config = {}) {
144
226
  requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
145
227
  deployStaticPreview: (directory, label) => deployRiddleStaticPreview(config, directory, label),
146
228
  runScript: (input) => runRiddleScript(config, input),
229
+ runServerPreview: (input) => runRiddleServerPreview(config, input),
147
230
  pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
148
231
  };
149
232
  }
@@ -156,6 +239,7 @@ export {
156
239
  riddleRequestJson,
157
240
  deployRiddleStaticPreview,
158
241
  parseRiddleViewport,
242
+ runRiddleServerPreview,
159
243
  runRiddleScript,
160
244
  isTerminalRiddleJobStatus,
161
245
  pollRiddleJob,
@@ -1,6 +1,7 @@
1
1
  // src/basic-gameplay.ts
2
2
  var RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION = "riddle-proof.basic-gameplay.v1";
3
3
  var RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION = "riddle-proof.basic-gameplay.assessment.v1";
4
+ var RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION = "riddle-proof.basic-gameplay.catch.v1";
4
5
  var BASIC_GAMEPLAY_CONTAINER_KEYS = [
5
6
  "basic_gameplay",
6
7
  "basicGameplay",
@@ -110,6 +111,37 @@ function assessBasicGameplayRoute(route, options = {}) {
110
111
  }
111
112
  };
112
113
  }
114
+ function createBasicGameplayCatchSummary(input, options = {}) {
115
+ const before = summarizeAssessment(assessBasicGameplayEvidence(input.before, options));
116
+ const after = input.after === void 0 ? void 0 : summarizeAssessment(assessBasicGameplayEvidence(input.after, options));
117
+ const fixed = Boolean(after && before.notable_codes.length > 0 && after.passed && after.notable_codes.length === 0);
118
+ const title = input.title || [
119
+ input.site || "Basic gameplay",
120
+ input.route ? `${input.route} proof catch` : "proof catch"
121
+ ].join(" ");
122
+ const beforeCodes = before.notable_codes.length ? before.notable_codes.join(", ") : "no failing or warning codes";
123
+ const afterCodes = after ? after.notable_codes.length ? after.notable_codes.join(", ") : "no failing or warning codes" : "not verified";
124
+ const summaryLines = [
125
+ `Before: ${before.checked_routes} checked, ${before.passing_routes} passing, codes: ${beforeCodes}.`,
126
+ after ? `After: ${after.checked_routes} checked, ${after.passing_routes} passing, codes: ${afterCodes}.` : "After: not provided."
127
+ ];
128
+ if (input.fix?.summary) summaryLines.push(`Fix: ${input.fix.summary}`);
129
+ if (input.artifacts?.length) summaryLines.push(`Artifacts: ${input.artifacts.length} attached.`);
130
+ return {
131
+ version: RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
132
+ title,
133
+ site: input.site,
134
+ route: input.route,
135
+ detected_at: input.detected_at || (/* @__PURE__ */ new Date()).toISOString(),
136
+ before,
137
+ after,
138
+ fixed,
139
+ fix: input.fix,
140
+ artifacts: input.artifacts || [],
141
+ summary_lines: summaryLines,
142
+ marketing_summary: fixed ? `${title}: Riddle Proof caught ${beforeCodes}; after the fix, ${afterCodes}.` : `${title}: Riddle Proof caught ${beforeCodes}; after evidence is ${after ? "not yet clean" : "not yet attached"}.`
143
+ };
144
+ }
113
145
  function extractBasicGameplayEvidence(...sources) {
114
146
  const seen = /* @__PURE__ */ new Set();
115
147
  for (const source of sources) {
@@ -118,6 +150,21 @@ function extractBasicGameplayEvidence(...sources) {
118
150
  }
119
151
  return null;
120
152
  }
153
+ function summarizeAssessment(assessment) {
154
+ return {
155
+ evidence_present: assessment.evidence_present,
156
+ passed: assessment.passed,
157
+ checked_routes: assessment.checked_routes,
158
+ passing_routes: assessment.passing_routes,
159
+ failing_routes: assessment.failing_routes,
160
+ failure_counts: assessment.failure_counts,
161
+ warning_counts: assessment.warning_counts,
162
+ notable_codes: [
163
+ ...Object.keys(assessment.failure_counts),
164
+ ...Object.keys(assessment.warning_counts)
165
+ ].sort()
166
+ };
167
+ }
121
168
  function findBasicGameplayEvidence(value, seen, depth = 0) {
122
169
  if (depth > 6 || value === null || value === void 0) return null;
123
170
  if (typeof value === "string") {
@@ -221,7 +268,9 @@ function parseJson(value) {
221
268
  export {
222
269
  RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION,
223
270
  RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION,
271
+ RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION,
224
272
  assessBasicGameplayEvidence,
225
273
  assessBasicGameplayRoute,
274
+ createBasicGameplayCatchSummary,
226
275
  extractBasicGameplayEvidence
227
276
  };
package/dist/cli.cjs CHANGED
@@ -6487,12 +6487,94 @@ async function deployRiddleStaticPreview(config, directory, label) {
6487
6487
  raw: published
6488
6488
  };
6489
6489
  }
6490
+ function createTarball(directory, label, exclude = []) {
6491
+ const scratch = (0, import_node_fs5.mkdtempSync)(import_node_path5.default.join((0, import_node_os2.tmpdir)(), "riddle-upload-"));
6492
+ const tarball = import_node_path5.default.join(scratch, `${label}.tar.gz`);
6493
+ const excludeArgs = exclude.flatMap((item) => ["--exclude", item]);
6494
+ try {
6495
+ (0, import_node_child_process4.execFileSync)("tar", ["czf", tarball, ...excludeArgs, "-C", directory, "."], { stdio: "pipe" });
6496
+ return { scratch, tarball };
6497
+ } catch (error) {
6498
+ (0, import_node_fs5.rmSync)(scratch, { recursive: true, force: true });
6499
+ throw error;
6500
+ }
6501
+ }
6490
6502
  function parseRiddleViewport(value) {
6491
6503
  if (!value) return void 0;
6492
6504
  const match = /^(\d+)x(\d+)$/.exec(value.trim());
6493
6505
  if (!match) throw new Error("viewport must look like 1280x720");
6494
6506
  return { width: Number(match[1]), height: Number(match[2]) };
6495
6507
  }
6508
+ function scriptErrorFrom(job) {
6509
+ const nested = job?.proof_of_execution && typeof job.proof_of_execution === "object" && !Array.isArray(job.proof_of_execution) ? job.proof_of_execution : null;
6510
+ return typeof job?.script_error === "string" && job.script_error.trim() ? job.script_error : typeof nested?.script_error === "string" && nested.script_error.trim() ? nested.script_error : null;
6511
+ }
6512
+ async function runRiddleServerPreview(config, input) {
6513
+ if (!input.directory?.trim()) throw new Error("directory is required");
6514
+ if (!input.script?.trim()) throw new Error("script is required");
6515
+ const port = input.port || 3e3;
6516
+ const routePath = input.path || "/";
6517
+ const timeoutSec = input.timeoutSec || 180;
6518
+ const created = await riddleRequestJson(config, "/v1/server-preview", {
6519
+ method: "POST",
6520
+ body: JSON.stringify({
6521
+ image: input.image || "node:22-slim",
6522
+ command: input.command || "node scripts/riddleSpaPreviewServer.mjs build 3000",
6523
+ port,
6524
+ path: routePath,
6525
+ readiness_path: input.readinessPath || routePath,
6526
+ readiness_timeout: input.readinessTimeoutSec || 90,
6527
+ wait_until: input.waitUntil || "domcontentloaded",
6528
+ wait_for_selector: input.waitForSelector || "body",
6529
+ navigation_timeout: input.navigationTimeoutSec || 60,
6530
+ viewport: input.viewport,
6531
+ timeout: timeoutSec,
6532
+ script: input.script
6533
+ })
6534
+ });
6535
+ const jobId = String(created.job_id || "");
6536
+ const uploadUrl = String(created.upload_url || "");
6537
+ if (!jobId || !uploadUrl) {
6538
+ throw new Error(`Riddle server preview create response was missing job_id or upload_url.`);
6539
+ }
6540
+ const { scratch, tarball } = createTarball(input.directory, jobId, [
6541
+ ".git",
6542
+ "node_modules",
6543
+ "test-results",
6544
+ ...input.exclude || []
6545
+ ]);
6546
+ try {
6547
+ const upload = await fetchFor(config)(uploadUrl, {
6548
+ method: "PUT",
6549
+ headers: { "Content-Type": "application/gzip" },
6550
+ body: (0, import_node_fs5.readFileSync)(tarball)
6551
+ });
6552
+ if (!upload.ok) throw new RiddleApiError(uploadUrl, upload.status, await upload.text());
6553
+ } finally {
6554
+ (0, import_node_fs5.rmSync)(scratch, { recursive: true, force: true });
6555
+ }
6556
+ await riddleRequestJson(config, `/v1/server-preview/${jobId}/start`, {
6557
+ method: "POST"
6558
+ });
6559
+ let job = null;
6560
+ const attempts = input.pollAttempts || Math.ceil((timeoutSec + 90) / 2);
6561
+ const intervalMs = input.pollIntervalMs || 2e3;
6562
+ for (let index = 0; index < attempts; index += 1) {
6563
+ job = await riddleRequestJson(config, `/v1/server-preview/${jobId}`);
6564
+ if (isTerminalRiddleJobStatus(job.status)) break;
6565
+ if (index + 1 < attempts) await new Promise((resolve) => setTimeout(resolve, intervalMs));
6566
+ }
6567
+ const status = job?.status ? String(job.status) : null;
6568
+ const scriptError = scriptErrorFrom(job);
6569
+ return {
6570
+ ok: (status === "completed" || status === "complete") && !scriptError,
6571
+ job_id: jobId,
6572
+ status,
6573
+ terminal: isTerminalRiddleJobStatus(status),
6574
+ script_error: scriptError,
6575
+ job
6576
+ };
6577
+ }
6496
6578
  async function runRiddleScript(config, input) {
6497
6579
  if (!input.url?.trim()) throw new Error("url is required");
6498
6580
  if (!input.script?.trim()) throw new Error("script is required");
@@ -6544,6 +6626,7 @@ function createRiddleApiClient(config = {}) {
6544
6626
  requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
6545
6627
  deployStaticPreview: (directory, label) => deployRiddleStaticPreview(config, directory, label),
6546
6628
  runScript: (input) => runRiddleScript(config, input),
6629
+ runServerPreview: (input) => runRiddleServerPreview(config, input),
6547
6630
  pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
6548
6631
  };
6549
6632
  }
@@ -6558,6 +6641,7 @@ function usage() {
6558
6641
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
6559
6642
  " riddle-proof-loop status --state-path <path>",
6560
6643
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label>",
6644
+ " riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
6561
6645
  " riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720]",
6562
6646
  " riddle-proof-loop riddle-poll <job-id> [--wait]",
6563
6647
  " riddle-proof-loop doctor local [--codex-command <path>]",
@@ -6801,6 +6885,32 @@ async function main() {
6801
6885
  `);
6802
6886
  return;
6803
6887
  }
6888
+ if (command === "riddle-server-preview") {
6889
+ const directory = positional[1];
6890
+ const scriptFile = optionString(options, "scriptFile");
6891
+ if (!directory || !scriptFile) throw new Error("riddle-server-preview requires <directory> and --script-file.");
6892
+ const result = await createRiddleApiClient(riddleClientConfig(options)).runServerPreview({
6893
+ directory,
6894
+ script: (0, import_node_fs6.readFileSync)(scriptFile, "utf-8"),
6895
+ image: optionString(options, "image"),
6896
+ command: optionString(options, "command"),
6897
+ port: optionString(options, "port") ? Number(optionString(options, "port")) : void 0,
6898
+ path: optionString(options, "path"),
6899
+ readinessPath: optionString(options, "readinessPath"),
6900
+ readinessTimeoutSec: optionString(options, "readinessTimeout") ? Number(optionString(options, "readinessTimeout")) : void 0,
6901
+ waitForSelector: optionString(options, "waitForSelector"),
6902
+ navigationTimeoutSec: optionString(options, "navigationTimeout") ? Number(optionString(options, "navigationTimeout")) : void 0,
6903
+ viewport: parseRiddleViewport(optionString(options, "viewport")),
6904
+ timeoutSec: optionString(options, "timeout") ? Number(optionString(options, "timeout")) : void 0,
6905
+ pollAttempts: optionString(options, "pollAttempts") ? Number(optionString(options, "pollAttempts")) : void 0,
6906
+ pollIntervalMs: optionString(options, "pollIntervalMs") ? Number(optionString(options, "pollIntervalMs")) : void 0,
6907
+ exclude: optionString(options, "exclude")?.split(",").map((item) => item.trim()).filter(Boolean)
6908
+ });
6909
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
6910
+ `);
6911
+ process.exitCode = result.ok ? 0 : 1;
6912
+ return;
6913
+ }
6804
6914
  if (command === "riddle-run-script") {
6805
6915
  const url = optionString(options, "url");
6806
6916
  const scriptFile = optionString(options, "scriptFile");
package/dist/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  createRiddleApiClient,
4
4
  parseRiddleViewport
5
- } from "./chunk-UR6ADV4Y.js";
5
+ } from "./chunk-3CVGVQTQ.js";
6
6
  import {
7
7
  createDisabledRiddleProofAgentAdapter,
8
8
  readRiddleProofRunStatus,
@@ -32,6 +32,7 @@ function usage() {
32
32
  " riddle-proof-loop respond --state-path <path> --decision <decision> --summary <text> [--payload-json <file|json|->]",
33
33
  " riddle-proof-loop status --state-path <path>",
34
34
  " riddle-proof-loop riddle-preview-deploy <build-dir> <label>",
35
+ " riddle-proof-loop riddle-server-preview <directory> --script-file <file> [--path /route] [--wait-for-selector selector]",
35
36
  " riddle-proof-loop riddle-run-script --url <url> --script-file <file> [--viewport 1280x720]",
36
37
  " riddle-proof-loop riddle-poll <job-id> [--wait]",
37
38
  " riddle-proof-loop doctor local [--codex-command <path>]",
@@ -275,6 +276,32 @@ async function main() {
275
276
  `);
276
277
  return;
277
278
  }
279
+ if (command === "riddle-server-preview") {
280
+ const directory = positional[1];
281
+ const scriptFile = optionString(options, "scriptFile");
282
+ if (!directory || !scriptFile) throw new Error("riddle-server-preview requires <directory> and --script-file.");
283
+ const result = await createRiddleApiClient(riddleClientConfig(options)).runServerPreview({
284
+ directory,
285
+ script: readFileSync(scriptFile, "utf-8"),
286
+ image: optionString(options, "image"),
287
+ command: optionString(options, "command"),
288
+ port: optionString(options, "port") ? Number(optionString(options, "port")) : void 0,
289
+ path: optionString(options, "path"),
290
+ readinessPath: optionString(options, "readinessPath"),
291
+ readinessTimeoutSec: optionString(options, "readinessTimeout") ? Number(optionString(options, "readinessTimeout")) : void 0,
292
+ waitForSelector: optionString(options, "waitForSelector"),
293
+ navigationTimeoutSec: optionString(options, "navigationTimeout") ? Number(optionString(options, "navigationTimeout")) : void 0,
294
+ viewport: parseRiddleViewport(optionString(options, "viewport")),
295
+ timeoutSec: optionString(options, "timeout") ? Number(optionString(options, "timeout")) : void 0,
296
+ pollAttempts: optionString(options, "pollAttempts") ? Number(optionString(options, "pollAttempts")) : void 0,
297
+ pollIntervalMs: optionString(options, "pollIntervalMs") ? Number(optionString(options, "pollIntervalMs")) : void 0,
298
+ exclude: optionString(options, "exclude")?.split(",").map((item) => item.trim()).filter(Boolean)
299
+ });
300
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
301
+ `);
302
+ process.exitCode = result.ok ? 0 : 1;
303
+ return;
304
+ }
278
305
  if (command === "riddle-run-script") {
279
306
  const url = optionString(options, "url");
280
307
  const scriptFile = optionString(options, "scriptFile");