@riddledc/riddle-proof 0.8.77 → 0.8.78

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.
Files changed (56) hide show
  1. package/README.md +65 -3
  2. package/dist/advanced/index.d.cts +1 -1
  3. package/dist/advanced/index.d.ts +1 -1
  4. package/dist/advanced/proof-run-engine.d.cts +1 -1
  5. package/dist/advanced/proof-run-engine.d.ts +1 -1
  6. package/dist/change-proof.cjs +744 -85
  7. package/dist/change-proof.d.cts +100 -8
  8. package/dist/change-proof.d.ts +100 -8
  9. package/dist/change-proof.js +15 -1
  10. package/dist/{chunk-B2DP2LET.js → chunk-5IFZSUPF.js} +52 -13
  11. package/dist/chunk-6VFS2JFR.js +886 -0
  12. package/dist/{chunk-IY4W6STC.js → chunk-7N6X54WG.js} +116 -17
  13. package/dist/{chunk-GG2D3MFZ.js → chunk-FCSJZBC5.js} +26 -1
  14. package/dist/{chunk-H25IDX76.js → chunk-HSGZV2NK.js} +206 -35
  15. package/dist/chunk-MEVVL4TI.js +258 -0
  16. package/dist/{chunk-UE4I7RTI.js → chunk-RQPCKRKT.js} +1 -1
  17. package/dist/cli/index.js +7 -6
  18. package/dist/cli.cjs +2009 -1058
  19. package/dist/cli.js +7 -6
  20. package/dist/index.cjs +932 -122
  21. package/dist/index.d.cts +4 -3
  22. package/dist/index.d.ts +4 -3
  23. package/dist/index.js +42 -14
  24. package/dist/pr-comment.cjs +416 -17
  25. package/dist/pr-comment.d.cts +6 -1
  26. package/dist/pr-comment.d.ts +6 -1
  27. package/dist/pr-comment.js +6 -1
  28. package/dist/profile/index.cjs +26 -1
  29. package/dist/profile/index.js +1 -1
  30. package/dist/profile-suggestions.js +2 -2
  31. package/dist/profile.cjs +26 -1
  32. package/dist/profile.d.cts +7 -0
  33. package/dist/profile.d.ts +7 -0
  34. package/dist/profile.js +1 -1
  35. package/dist/{proof-run-engine-MiKZt9oY.d.ts → proof-run-engine-CsQshTUX.d.ts} +3 -3
  36. package/dist/{proof-run-engine-Baiv6l3A.d.cts → proof-run-engine-DmUqh7Cw.d.cts} +3 -3
  37. package/dist/proof-run-engine.d.cts +1 -1
  38. package/dist/proof-run-engine.d.ts +1 -1
  39. package/dist/receipts.cjs +286 -0
  40. package/dist/receipts.d.cts +115 -0
  41. package/dist/receipts.d.ts +115 -0
  42. package/dist/receipts.js +15 -0
  43. package/dist/riddle-client.cjs +98 -13
  44. package/dist/riddle-client.d.cts +18 -5
  45. package/dist/riddle-client.d.ts +18 -5
  46. package/dist/riddle-client.js +4 -1
  47. package/dist/runtime/index.cjs +98 -13
  48. package/dist/runtime/index.d.cts +5 -1
  49. package/dist/runtime/index.d.ts +5 -1
  50. package/dist/runtime/index.js +4 -1
  51. package/dist/runtime/riddle-client.cjs +98 -13
  52. package/dist/runtime/riddle-client.d.cts +5 -1
  53. package/dist/runtime/riddle-client.d.ts +5 -1
  54. package/dist/runtime/riddle-client.js +4 -1
  55. package/package.json +7 -2
  56. package/dist/chunk-BILL3UC2.js +0 -488
@@ -38,6 +38,7 @@ __export(runtime_exports, {
38
38
  createRiddleApiClient: () => createRiddleApiClient,
39
39
  deployRiddlePreview: () => deployRiddlePreview,
40
40
  deployRiddleStaticPreview: () => deployRiddleStaticPreview,
41
+ detectRiddlePreviewSource: () => detectRiddlePreviewSource,
41
42
  getRiddleBalance: () => getRiddleBalance,
42
43
  isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
43
44
  parseRiddleViewport: () => parseRiddleViewport,
@@ -55,6 +56,55 @@ var import_node_child_process = require("child_process");
55
56
  var import_node_fs = require("fs");
56
57
  var import_node_os = require("os");
57
58
  var import_node_path = __toESM(require("path"), 1);
59
+
60
+ // src/receipts.ts
61
+ var RIDDLE_PREVIEW_RECEIPT_VERSION = "riddle.preview-receipt.v1";
62
+ function isRecord(value) {
63
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
64
+ }
65
+ function requiredString(record, key, context) {
66
+ const value = record[key];
67
+ if (typeof value !== "string" || !value.trim()) {
68
+ throw new Error(`${context}.${key} must be a non-empty string.`);
69
+ }
70
+ return value.trim();
71
+ }
72
+ function normalizedSourceIdentity(value) {
73
+ if (!isRecord(value)) return {};
74
+ return {
75
+ git_revision: typeof value.git_revision === "string" && value.git_revision.trim() ? value.git_revision.trim() : void 0,
76
+ repository: typeof value.repository === "string" && value.repository.trim() ? value.repository.trim() : void 0,
77
+ dirty: typeof value.dirty === "boolean" ? value.dirty : void 0,
78
+ label: typeof value.label === "string" && value.label.trim() ? value.label.trim() : void 0
79
+ };
80
+ }
81
+ function parseRiddlePreviewReceipt(value) {
82
+ if (!isRecord(value)) throw new Error("Preview receipt must be an object.");
83
+ if (value.version !== RIDDLE_PREVIEW_RECEIPT_VERSION) {
84
+ throw new Error(`Unsupported Preview receipt version ${String(value.version || "missing")}.`);
85
+ }
86
+ if (!isRecord(value.source)) throw new Error("Preview receipt source must be an object.");
87
+ const expiresAt = requiredString(value, "expires_at", "preview receipt");
88
+ const publishedAt = requiredString(value, "published_at", "preview receipt");
89
+ const contentDigest = requiredString(value, "content_digest", "preview receipt");
90
+ if (!contentDigest.startsWith("sha256:") || contentDigest.length <= "sha256:".length) {
91
+ throw new Error("preview receipt.content_digest must be a sha256 digest.");
92
+ }
93
+ if (!Number.isFinite(Date.parse(expiresAt)) || !Number.isFinite(Date.parse(publishedAt))) {
94
+ throw new Error("Preview receipt timestamps must be valid ISO date strings.");
95
+ }
96
+ return {
97
+ version: RIDDLE_PREVIEW_RECEIPT_VERSION,
98
+ preview_id: requiredString(value, "preview_id", "preview receipt"),
99
+ url: requiredString(value, "url", "preview receipt"),
100
+ expires_at: expiresAt,
101
+ content_digest: contentDigest,
102
+ source: normalizedSourceIdentity(value.source),
103
+ published_at: publishedAt
104
+ };
105
+ }
106
+
107
+ // src/riddle-client.ts
58
108
  var DEFAULT_RIDDLE_API_BASE_URL = "https://api.riddledc.com";
59
109
  var DEFAULT_RIDDLE_API_KEY_FILE = "/tmp/riddle-api-key";
60
110
  var RIDDLE_UNSUBMITTED_WAKE_HINT = "hosted worker may still be waking or waiting for a lease";
@@ -116,6 +166,7 @@ async function getRiddleBalance(config = {}) {
116
166
  }
117
167
  function previewDeployResultFromRecord(input) {
118
168
  const { record, id, label, framework, expiresAt, publishRecovered, publishError } = input;
169
+ const receipt = record.receipt && typeof record.receipt === "object" ? parseRiddlePreviewReceipt(record.receipt) : void 0;
119
170
  return {
120
171
  ok: true,
121
172
  id: String(record.id || record.preview_id || id),
@@ -124,13 +175,32 @@ function previewDeployResultFromRecord(input) {
124
175
  preview_url: String(record.preview_url || ""),
125
176
  file_count: typeof record.file_count === "number" ? record.file_count : void 0,
126
177
  total_bytes: typeof record.total_bytes === "number" ? record.total_bytes : void 0,
127
- expires_at: expiresAt,
178
+ expires_at: receipt?.expires_at || expiresAt,
179
+ receipt,
128
180
  publish_recovered: publishRecovered || void 0,
129
181
  publish_error: publishError,
130
182
  warnings: input.warnings?.length ? input.warnings : void 0,
131
183
  raw: record
132
184
  };
133
185
  }
186
+ function gitOutput(directory, args) {
187
+ try {
188
+ return (0, import_node_child_process.execFileSync)("git", ["-C", directory, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
189
+ } catch {
190
+ return "";
191
+ }
192
+ }
193
+ function detectRiddlePreviewSource(directory) {
194
+ const gitRevision = gitOutput(directory, ["rev-parse", "HEAD"]);
195
+ if (!gitRevision) return {};
196
+ const repository = gitOutput(directory, ["config", "--get", "remote.origin.url"]);
197
+ const status = gitOutput(directory, ["status", "--porcelain", "--untracked-files=normal"]);
198
+ return {
199
+ git_revision: gitRevision,
200
+ repository: repository || void 0,
201
+ dirty: Boolean(status)
202
+ };
203
+ }
134
204
  function canRecoverPreviewPublish(error) {
135
205
  return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
136
206
  }
@@ -213,12 +283,13 @@ async function waitForPublishedPreview(config, input) {
213
283
  }
214
284
  throw input.publishError;
215
285
  }
216
- async function deployRiddlePreview(config, directory, label, framework = "static") {
286
+ async function deployRiddlePreview(config, directory, label, framework = "static", options = {}) {
217
287
  if (!directory?.trim()) throw new Error("directory is required");
218
288
  if (!label?.trim()) throw new Error("label is required");
219
289
  if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
220
290
  const startedAt = Date.now();
221
291
  const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
292
+ const source = options.source || detectRiddlePreviewSource(directory);
222
293
  const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
223
294
  await emitProgress({ stage: "validating", message: "checking preview input directory" });
224
295
  const localSummary = summarizePreviewDirectory(directory);
@@ -230,7 +301,7 @@ async function deployRiddlePreview(config, directory, label, framework = "static
230
301
  });
231
302
  const created = await riddleRequestJson(config, "/v1/preview", {
232
303
  method: "POST",
233
- body: JSON.stringify({ framework, label })
304
+ body: JSON.stringify({ framework, label, source })
234
305
  });
235
306
  const id = String(created.id || "");
236
307
  const uploadUrl = String(created.upload_url || "");
@@ -372,8 +443,8 @@ function collectRiddlePreviewDeployWarnings(directory, framework = "static") {
372
443
  return [];
373
444
  }
374
445
  }
375
- async function deployRiddleStaticPreview(config, directory, label) {
376
- return deployRiddlePreview(config, directory, label, "static");
446
+ async function deployRiddleStaticPreview(config, directory, label, options = {}) {
447
+ return deployRiddlePreview(config, directory, label, "static", options);
377
448
  }
378
449
  function createTarball(directory, label, exclude = []) {
379
450
  const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-upload-"));
@@ -495,21 +566,31 @@ function parseTimestampMs(value) {
495
566
  }
496
567
  function buildPollSnapshot(jobId, job, input) {
497
568
  const status = job?.status ? String(job.status) : null;
569
+ const phase = job?.phase ? String(job.phase) : null;
498
570
  const terminal = isTerminalRiddleJobStatus(status);
499
571
  const createdAt = stringField(job, "created_at");
500
572
  const submittedAt = stringField(job, "submitted_at");
501
573
  const completedAt = stringField(job, "completed_at");
502
574
  const createdMs = parseTimestampMs(createdAt);
503
575
  const submittedMs = parseTimestampMs(submittedAt);
576
+ const rawExecution = job?.execution && typeof job.execution === "object" && !Array.isArray(job.execution) ? job.execution : null;
577
+ const enqueuedAt = rawExecution ? stringField(rawExecution, "enqueued_at") : null;
578
+ const enqueuedMs = parseTimestampMs(enqueuedAt);
579
+ const queueStartedMs = enqueuedMs ?? createdMs;
580
+ const claimedAt = rawExecution ? stringField(rawExecution, "claimed_at") : null;
581
+ const claimedMs = parseTimestampMs(claimedAt);
504
582
  let queueElapsedMs = null;
505
- if (createdMs !== null && submittedMs !== null) {
506
- queueElapsedMs = Math.max(0, submittedMs - createdMs);
507
- } else if (createdMs !== null && !submittedAt && !terminal) {
508
- queueElapsedMs = Math.max(0, input.observedAt - createdMs);
583
+ if (queueStartedMs !== null && claimedMs !== null) {
584
+ queueElapsedMs = Math.max(0, claimedMs - queueStartedMs);
585
+ } else if (queueStartedMs !== null && submittedMs !== null) {
586
+ queueElapsedMs = Math.max(0, submittedMs - queueStartedMs);
587
+ } else if (queueStartedMs !== null && !submittedAt && !terminal) {
588
+ queueElapsedMs = Math.max(0, input.observedAt - queueStartedMs);
509
589
  }
510
590
  return {
511
591
  job_id: jobId,
512
592
  status,
593
+ phase,
513
594
  terminal,
514
595
  attempt: input.attempt,
515
596
  attempts: input.attempts,
@@ -519,7 +600,9 @@ function buildPollSnapshot(jobId, job, input) {
519
600
  completed_at: completedAt,
520
601
  queue_elapsed_ms: queueElapsedMs,
521
602
  pre_submission_elapsed_ms: Math.max(0, Math.floor(input.preSubmissionElapsedMs ?? 0)),
522
- running_without_submission: Boolean(status && !terminal && !submittedAt)
603
+ running_without_submission: Boolean(status && !terminal && !submittedAt),
604
+ active_execution: Boolean(status === "running" && phase && phase !== "queued"),
605
+ execution: rawExecution ? rawExecution : void 0
523
606
  };
524
607
  }
525
608
  function pollMessage(snapshot, timedOut) {
@@ -528,7 +611,7 @@ function pollMessage(snapshot, timedOut) {
528
611
  const wakeHint = snapshot.running_without_submission && !snapshot.created_at && !snapshot.submitted_at ? ` ${RIDDLE_UNSUBMITTED_WAKE_HINT}.` : "";
529
612
  const queue = snapshot.queue_elapsed_ms !== null ? ` queue_elapsed_ms=${snapshot.queue_elapsed_ms}` : "";
530
613
  const preSubmit = snapshot.pre_submission_elapsed_ms > 0 ? ` pre_submission_elapsed_ms=${snapshot.pre_submission_elapsed_ms}` : "";
531
- return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
614
+ return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} phase=${snapshot.phase || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
532
615
  }
533
616
  async function pollRiddleJob(config, jobId, options = {}) {
534
617
  if (!jobId?.trim()) throw new Error("jobId is required");
@@ -562,6 +645,7 @@ async function pollRiddleJob(config, jobId, options = {}) {
562
645
  };
563
646
  const progressKey = [
564
647
  lastSnapshot.status || "unknown",
648
+ lastSnapshot.phase || "unknown",
565
649
  lastSnapshot.terminal ? "terminal" : "nonterminal",
566
650
  lastSnapshot.submitted_at ? "submitted" : "unsubmitted"
567
651
  ].join(":");
@@ -628,8 +712,8 @@ function createRiddleApiClient(config = {}) {
628
712
  apiKeySource: () => resolveRiddleApiKeySource(config),
629
713
  requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
630
714
  getBalance: () => getRiddleBalance(config),
631
- deployPreview: (directory, label, framework = "static") => deployRiddlePreview(config, directory, label, framework),
632
- deployStaticPreview: (directory, label) => deployRiddleStaticPreview(config, directory, label),
715
+ deployPreview: (directory, label, framework = "static", options) => deployRiddlePreview(config, directory, label, framework, options),
716
+ deployStaticPreview: (directory, label, options) => deployRiddleStaticPreview(config, directory, label, options),
633
717
  runScript: (input) => runRiddleScript(config, input),
634
718
  runServerPreview: (input) => runRiddleServerPreview(config, input),
635
719
  pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
@@ -645,6 +729,7 @@ function createRiddleApiClient(config = {}) {
645
729
  createRiddleApiClient,
646
730
  deployRiddlePreview,
647
731
  deployRiddleStaticPreview,
732
+ detectRiddlePreviewSource,
648
733
  getRiddleBalance,
649
734
  isTerminalRiddleJobStatus,
650
735
  parseRiddleViewport,
@@ -1 +1,5 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, 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';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployOptions, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, detectRiddlePreviewSource, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.cjs';
2
+ import '../receipts.cjs';
3
+ import '../profile.cjs';
4
+ import '../types.cjs';
5
+ import '../public-state.cjs';
@@ -1 +1,5 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, 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.js';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployOptions, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, detectRiddlePreviewSource, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.js';
2
+ import '../receipts.js';
3
+ import '../profile.js';
4
+ import '../types.js';
5
+ import '../public-state.js';
@@ -7,6 +7,7 @@ import {
7
7
  createRiddleApiClient,
8
8
  deployRiddlePreview,
9
9
  deployRiddleStaticPreview,
10
+ detectRiddlePreviewSource,
10
11
  getRiddleBalance,
11
12
  isTerminalRiddleJobStatus,
12
13
  parseRiddleViewport,
@@ -16,7 +17,8 @@ import {
16
17
  riddleRequestJson,
17
18
  runRiddleScript,
18
19
  runRiddleServerPreview
19
- } from "../chunk-B2DP2LET.js";
20
+ } from "../chunk-5IFZSUPF.js";
21
+ import "../chunk-MEVVL4TI.js";
20
22
  import "../chunk-MLKGABMK.js";
21
23
  export {
22
24
  DEFAULT_RIDDLE_API_BASE_URL,
@@ -27,6 +29,7 @@ export {
27
29
  createRiddleApiClient,
28
30
  deployRiddlePreview,
29
31
  deployRiddleStaticPreview,
32
+ detectRiddlePreviewSource,
30
33
  getRiddleBalance,
31
34
  isTerminalRiddleJobStatus,
32
35
  parseRiddleViewport,
@@ -38,6 +38,7 @@ __export(riddle_client_exports, {
38
38
  createRiddleApiClient: () => createRiddleApiClient,
39
39
  deployRiddlePreview: () => deployRiddlePreview,
40
40
  deployRiddleStaticPreview: () => deployRiddleStaticPreview,
41
+ detectRiddlePreviewSource: () => detectRiddlePreviewSource,
41
42
  getRiddleBalance: () => getRiddleBalance,
42
43
  isTerminalRiddleJobStatus: () => isTerminalRiddleJobStatus,
43
44
  parseRiddleViewport: () => parseRiddleViewport,
@@ -55,6 +56,55 @@ var import_node_child_process = require("child_process");
55
56
  var import_node_fs = require("fs");
56
57
  var import_node_os = require("os");
57
58
  var import_node_path = __toESM(require("path"), 1);
59
+
60
+ // src/receipts.ts
61
+ var RIDDLE_PREVIEW_RECEIPT_VERSION = "riddle.preview-receipt.v1";
62
+ function isRecord(value) {
63
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
64
+ }
65
+ function requiredString(record, key, context) {
66
+ const value = record[key];
67
+ if (typeof value !== "string" || !value.trim()) {
68
+ throw new Error(`${context}.${key} must be a non-empty string.`);
69
+ }
70
+ return value.trim();
71
+ }
72
+ function normalizedSourceIdentity(value) {
73
+ if (!isRecord(value)) return {};
74
+ return {
75
+ git_revision: typeof value.git_revision === "string" && value.git_revision.trim() ? value.git_revision.trim() : void 0,
76
+ repository: typeof value.repository === "string" && value.repository.trim() ? value.repository.trim() : void 0,
77
+ dirty: typeof value.dirty === "boolean" ? value.dirty : void 0,
78
+ label: typeof value.label === "string" && value.label.trim() ? value.label.trim() : void 0
79
+ };
80
+ }
81
+ function parseRiddlePreviewReceipt(value) {
82
+ if (!isRecord(value)) throw new Error("Preview receipt must be an object.");
83
+ if (value.version !== RIDDLE_PREVIEW_RECEIPT_VERSION) {
84
+ throw new Error(`Unsupported Preview receipt version ${String(value.version || "missing")}.`);
85
+ }
86
+ if (!isRecord(value.source)) throw new Error("Preview receipt source must be an object.");
87
+ const expiresAt = requiredString(value, "expires_at", "preview receipt");
88
+ const publishedAt = requiredString(value, "published_at", "preview receipt");
89
+ const contentDigest = requiredString(value, "content_digest", "preview receipt");
90
+ if (!contentDigest.startsWith("sha256:") || contentDigest.length <= "sha256:".length) {
91
+ throw new Error("preview receipt.content_digest must be a sha256 digest.");
92
+ }
93
+ if (!Number.isFinite(Date.parse(expiresAt)) || !Number.isFinite(Date.parse(publishedAt))) {
94
+ throw new Error("Preview receipt timestamps must be valid ISO date strings.");
95
+ }
96
+ return {
97
+ version: RIDDLE_PREVIEW_RECEIPT_VERSION,
98
+ preview_id: requiredString(value, "preview_id", "preview receipt"),
99
+ url: requiredString(value, "url", "preview receipt"),
100
+ expires_at: expiresAt,
101
+ content_digest: contentDigest,
102
+ source: normalizedSourceIdentity(value.source),
103
+ published_at: publishedAt
104
+ };
105
+ }
106
+
107
+ // src/riddle-client.ts
58
108
  var DEFAULT_RIDDLE_API_BASE_URL = "https://api.riddledc.com";
59
109
  var DEFAULT_RIDDLE_API_KEY_FILE = "/tmp/riddle-api-key";
60
110
  var RIDDLE_UNSUBMITTED_WAKE_HINT = "hosted worker may still be waking or waiting for a lease";
@@ -116,6 +166,7 @@ async function getRiddleBalance(config = {}) {
116
166
  }
117
167
  function previewDeployResultFromRecord(input) {
118
168
  const { record, id, label, framework, expiresAt, publishRecovered, publishError } = input;
169
+ const receipt = record.receipt && typeof record.receipt === "object" ? parseRiddlePreviewReceipt(record.receipt) : void 0;
119
170
  return {
120
171
  ok: true,
121
172
  id: String(record.id || record.preview_id || id),
@@ -124,13 +175,32 @@ function previewDeployResultFromRecord(input) {
124
175
  preview_url: String(record.preview_url || ""),
125
176
  file_count: typeof record.file_count === "number" ? record.file_count : void 0,
126
177
  total_bytes: typeof record.total_bytes === "number" ? record.total_bytes : void 0,
127
- expires_at: expiresAt,
178
+ expires_at: receipt?.expires_at || expiresAt,
179
+ receipt,
128
180
  publish_recovered: publishRecovered || void 0,
129
181
  publish_error: publishError,
130
182
  warnings: input.warnings?.length ? input.warnings : void 0,
131
183
  raw: record
132
184
  };
133
185
  }
186
+ function gitOutput(directory, args) {
187
+ try {
188
+ return (0, import_node_child_process.execFileSync)("git", ["-C", directory, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
189
+ } catch {
190
+ return "";
191
+ }
192
+ }
193
+ function detectRiddlePreviewSource(directory) {
194
+ const gitRevision = gitOutput(directory, ["rev-parse", "HEAD"]);
195
+ if (!gitRevision) return {};
196
+ const repository = gitOutput(directory, ["config", "--get", "remote.origin.url"]);
197
+ const status = gitOutput(directory, ["status", "--porcelain", "--untracked-files=normal"]);
198
+ return {
199
+ git_revision: gitRevision,
200
+ repository: repository || void 0,
201
+ dirty: Boolean(status)
202
+ };
203
+ }
134
204
  function canRecoverPreviewPublish(error) {
135
205
  return error instanceof RiddleApiError && PREVIEW_PUBLISH_RECOVERY_STATUSES.has(error.status);
136
206
  }
@@ -213,12 +283,13 @@ async function waitForPublishedPreview(config, input) {
213
283
  }
214
284
  throw input.publishError;
215
285
  }
216
- async function deployRiddlePreview(config, directory, label, framework = "static") {
286
+ async function deployRiddlePreview(config, directory, label, framework = "static", options = {}) {
217
287
  if (!directory?.trim()) throw new Error("directory is required");
218
288
  if (!label?.trim()) throw new Error("label is required");
219
289
  if (framework !== "spa" && framework !== "static") throw new Error("framework must be spa or static");
220
290
  const startedAt = Date.now();
221
291
  const warnings = collectRiddlePreviewDeployWarnings(directory, framework);
292
+ const source = options.source || detectRiddlePreviewSource(directory);
222
293
  const emitProgress = previewProgressEmitter(config, { label, framework, directory, startedAt, warnings });
223
294
  await emitProgress({ stage: "validating", message: "checking preview input directory" });
224
295
  const localSummary = summarizePreviewDirectory(directory);
@@ -230,7 +301,7 @@ async function deployRiddlePreview(config, directory, label, framework = "static
230
301
  });
231
302
  const created = await riddleRequestJson(config, "/v1/preview", {
232
303
  method: "POST",
233
- body: JSON.stringify({ framework, label })
304
+ body: JSON.stringify({ framework, label, source })
234
305
  });
235
306
  const id = String(created.id || "");
236
307
  const uploadUrl = String(created.upload_url || "");
@@ -372,8 +443,8 @@ function collectRiddlePreviewDeployWarnings(directory, framework = "static") {
372
443
  return [];
373
444
  }
374
445
  }
375
- async function deployRiddleStaticPreview(config, directory, label) {
376
- return deployRiddlePreview(config, directory, label, "static");
446
+ async function deployRiddleStaticPreview(config, directory, label, options = {}) {
447
+ return deployRiddlePreview(config, directory, label, "static", options);
377
448
  }
378
449
  function createTarball(directory, label, exclude = []) {
379
450
  const scratch = (0, import_node_fs.mkdtempSync)(import_node_path.default.join((0, import_node_os.tmpdir)(), "riddle-upload-"));
@@ -495,21 +566,31 @@ function parseTimestampMs(value) {
495
566
  }
496
567
  function buildPollSnapshot(jobId, job, input) {
497
568
  const status = job?.status ? String(job.status) : null;
569
+ const phase = job?.phase ? String(job.phase) : null;
498
570
  const terminal = isTerminalRiddleJobStatus(status);
499
571
  const createdAt = stringField(job, "created_at");
500
572
  const submittedAt = stringField(job, "submitted_at");
501
573
  const completedAt = stringField(job, "completed_at");
502
574
  const createdMs = parseTimestampMs(createdAt);
503
575
  const submittedMs = parseTimestampMs(submittedAt);
576
+ const rawExecution = job?.execution && typeof job.execution === "object" && !Array.isArray(job.execution) ? job.execution : null;
577
+ const enqueuedAt = rawExecution ? stringField(rawExecution, "enqueued_at") : null;
578
+ const enqueuedMs = parseTimestampMs(enqueuedAt);
579
+ const queueStartedMs = enqueuedMs ?? createdMs;
580
+ const claimedAt = rawExecution ? stringField(rawExecution, "claimed_at") : null;
581
+ const claimedMs = parseTimestampMs(claimedAt);
504
582
  let queueElapsedMs = null;
505
- if (createdMs !== null && submittedMs !== null) {
506
- queueElapsedMs = Math.max(0, submittedMs - createdMs);
507
- } else if (createdMs !== null && !submittedAt && !terminal) {
508
- queueElapsedMs = Math.max(0, input.observedAt - createdMs);
583
+ if (queueStartedMs !== null && claimedMs !== null) {
584
+ queueElapsedMs = Math.max(0, claimedMs - queueStartedMs);
585
+ } else if (queueStartedMs !== null && submittedMs !== null) {
586
+ queueElapsedMs = Math.max(0, submittedMs - queueStartedMs);
587
+ } else if (queueStartedMs !== null && !submittedAt && !terminal) {
588
+ queueElapsedMs = Math.max(0, input.observedAt - queueStartedMs);
509
589
  }
510
590
  return {
511
591
  job_id: jobId,
512
592
  status,
593
+ phase,
513
594
  terminal,
514
595
  attempt: input.attempt,
515
596
  attempts: input.attempts,
@@ -519,7 +600,9 @@ function buildPollSnapshot(jobId, job, input) {
519
600
  completed_at: completedAt,
520
601
  queue_elapsed_ms: queueElapsedMs,
521
602
  pre_submission_elapsed_ms: Math.max(0, Math.floor(input.preSubmissionElapsedMs ?? 0)),
522
- running_without_submission: Boolean(status && !terminal && !submittedAt)
603
+ running_without_submission: Boolean(status && !terminal && !submittedAt),
604
+ active_execution: Boolean(status === "running" && phase && phase !== "queued"),
605
+ execution: rawExecution ? rawExecution : void 0
523
606
  };
524
607
  }
525
608
  function pollMessage(snapshot, timedOut) {
@@ -528,7 +611,7 @@ function pollMessage(snapshot, timedOut) {
528
611
  const wakeHint = snapshot.running_without_submission && !snapshot.created_at && !snapshot.submitted_at ? ` ${RIDDLE_UNSUBMITTED_WAKE_HINT}.` : "";
529
612
  const queue = snapshot.queue_elapsed_ms !== null ? ` queue_elapsed_ms=${snapshot.queue_elapsed_ms}` : "";
530
613
  const preSubmit = snapshot.pre_submission_elapsed_ms > 0 ? ` pre_submission_elapsed_ms=${snapshot.pre_submission_elapsed_ms}` : "";
531
- return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
614
+ return `Riddle job ${snapshot.job_id} did not reach a terminal status after ${snapshot.attempt} poll attempts; status=${snapshot.status || "unknown"} phase=${snapshot.phase || "unknown"} submitted_at=${submitted}.${wakeHint}${queue}${preSubmit}`;
532
615
  }
533
616
  async function pollRiddleJob(config, jobId, options = {}) {
534
617
  if (!jobId?.trim()) throw new Error("jobId is required");
@@ -562,6 +645,7 @@ async function pollRiddleJob(config, jobId, options = {}) {
562
645
  };
563
646
  const progressKey = [
564
647
  lastSnapshot.status || "unknown",
648
+ lastSnapshot.phase || "unknown",
565
649
  lastSnapshot.terminal ? "terminal" : "nonterminal",
566
650
  lastSnapshot.submitted_at ? "submitted" : "unsubmitted"
567
651
  ].join(":");
@@ -628,8 +712,8 @@ function createRiddleApiClient(config = {}) {
628
712
  apiKeySource: () => resolveRiddleApiKeySource(config),
629
713
  requestJson: (pathname, init) => riddleRequestJson(config, pathname, init),
630
714
  getBalance: () => getRiddleBalance(config),
631
- deployPreview: (directory, label, framework = "static") => deployRiddlePreview(config, directory, label, framework),
632
- deployStaticPreview: (directory, label) => deployRiddleStaticPreview(config, directory, label),
715
+ deployPreview: (directory, label, framework = "static", options) => deployRiddlePreview(config, directory, label, framework, options),
716
+ deployStaticPreview: (directory, label, options) => deployRiddleStaticPreview(config, directory, label, options),
633
717
  runScript: (input) => runRiddleScript(config, input),
634
718
  runServerPreview: (input) => runRiddleServerPreview(config, input),
635
719
  pollJob: (jobId, options) => pollRiddleJob(config, jobId, options)
@@ -645,6 +729,7 @@ function createRiddleApiClient(config = {}) {
645
729
  createRiddleApiClient,
646
730
  deployRiddlePreview,
647
731
  deployRiddleStaticPreview,
732
+ detectRiddlePreviewSource,
648
733
  getRiddleBalance,
649
734
  isTerminalRiddleJobStatus,
650
735
  parseRiddleViewport,
@@ -1 +1,5 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, 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';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployOptions, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, detectRiddlePreviewSource, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.cjs';
2
+ import '../receipts.cjs';
3
+ import '../profile.cjs';
4
+ import '../types.cjs';
5
+ import '../public-state.cjs';
@@ -1 +1,5 @@
1
- export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, 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.js';
1
+ export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RIDDLE_UNSUBMITTED_WAKE_HINT, RiddleApiError, RiddleApiKeySource, RiddleBalanceResult, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployOptions, RiddlePreviewDeployProgressSnapshot, RiddlePreviewDeployResult, RiddlePreviewDeployStage, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, collectRiddlePreviewDeployWarnings, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, detectRiddlePreviewSource, getRiddleBalance, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, resolveRiddleApiKeySource, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from '../riddle-client.js';
2
+ import '../receipts.js';
3
+ import '../profile.js';
4
+ import '../types.js';
5
+ import '../public-state.js';
@@ -7,6 +7,7 @@ import {
7
7
  createRiddleApiClient,
8
8
  deployRiddlePreview,
9
9
  deployRiddleStaticPreview,
10
+ detectRiddlePreviewSource,
10
11
  getRiddleBalance,
11
12
  isTerminalRiddleJobStatus,
12
13
  parseRiddleViewport,
@@ -16,7 +17,8 @@ import {
16
17
  riddleRequestJson,
17
18
  runRiddleScript,
18
19
  runRiddleServerPreview
19
- } from "../chunk-B2DP2LET.js";
20
+ } from "../chunk-5IFZSUPF.js";
21
+ import "../chunk-MEVVL4TI.js";
20
22
  import "../chunk-MLKGABMK.js";
21
23
  export {
22
24
  DEFAULT_RIDDLE_API_BASE_URL,
@@ -27,6 +29,7 @@ export {
27
29
  createRiddleApiClient,
28
30
  deployRiddlePreview,
29
31
  deployRiddleStaticPreview,
32
+ detectRiddlePreviewSource,
30
33
  getRiddleBalance,
31
34
  isTerminalRiddleJobStatus,
32
35
  parseRiddleViewport,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.8.77",
3
+ "version": "0.8.78",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -134,6 +134,11 @@
134
134
  "import": "./dist/profile-suggestions.js",
135
135
  "require": "./dist/profile-suggestions.cjs"
136
136
  },
137
+ "./receipts": {
138
+ "types": "./dist/receipts.d.ts",
139
+ "import": "./dist/receipts.js",
140
+ "require": "./dist/receipts.cjs"
141
+ },
137
142
  "./change-proof": {
138
143
  "types": "./dist/change-proof.d.ts",
139
144
  "import": "./dist/change-proof.js",
@@ -249,7 +254,7 @@
249
254
  "typescript": "^5.4.5"
250
255
  },
251
256
  "scripts": {
252
- "build": "npm --workspace @riddledc/riddle-proof-app-contract run build --if-present && tsup src/index.ts src/types.ts src/result.ts src/state.ts src/checkpoint.ts src/run-card.ts src/public-state.ts src/runner.ts src/engine-harness.ts src/codex-exec-agent.ts src/local-agent.ts src/cli.ts src/cli/index.ts src/diagnostics.ts src/proof-session.ts src/playability.ts src/basic-gameplay.ts src/profile.ts src/profile/index.ts src/profile-suggestions.ts src/change-proof.ts src/pr-comment.ts src/openclaw.ts src/proof-run-core.ts src/proof-run-engine.ts src/riddle-client.ts src/runtime/riddle-client.ts src/spec/index.ts src/spec/types.ts src/spec/result.ts src/spec/state.ts src/spec/checkpoint.ts src/spec/run-card.ts src/spec/public-state.ts src/runtime/index.ts src/app-contract/index.ts src/advanced/index.ts src/advanced/runner.ts src/advanced/engine-harness.ts src/advanced/proof-run-core.ts src/advanced/proof-run-engine.ts src/adapters/openclaw.ts src/adapters/local-agent.ts src/adapters/codex-exec-agent.ts src/adapters/codex.ts --format cjs,esm --dts --out-dir dist --clean",
257
+ "build": "npm --workspace @riddledc/riddle-proof-app-contract run build --if-present && tsup src/index.ts src/types.ts src/result.ts src/state.ts src/checkpoint.ts src/run-card.ts src/public-state.ts src/runner.ts src/engine-harness.ts src/codex-exec-agent.ts src/local-agent.ts src/cli.ts src/cli/index.ts src/diagnostics.ts src/proof-session.ts src/playability.ts src/basic-gameplay.ts src/profile.ts src/profile/index.ts src/profile-suggestions.ts src/receipts.ts src/change-proof.ts src/pr-comment.ts src/openclaw.ts src/proof-run-core.ts src/proof-run-engine.ts src/riddle-client.ts src/runtime/riddle-client.ts src/spec/index.ts src/spec/types.ts src/spec/result.ts src/spec/state.ts src/spec/checkpoint.ts src/spec/run-card.ts src/spec/public-state.ts src/runtime/index.ts src/app-contract/index.ts src/advanced/index.ts src/advanced/runner.ts src/advanced/engine-harness.ts src/advanced/proof-run-core.ts src/advanced/proof-run-engine.ts src/adapters/openclaw.ts src/adapters/local-agent.ts src/adapters/codex-exec-agent.ts src/adapters/codex.ts --format cjs,esm --dts --out-dir dist --clean",
253
258
  "clean": "rm -rf dist",
254
259
  "lint": "echo 'lint: (not configured)'",
255
260
  "test": "npm run build && node test.js && node proof-run.test.js && node formal-conformance.test.js && node trust-boundary.test.js && node regression-packs.test.js && node story-matrix.test.js && python3 runtime/tests/trust_boundary_regression.py && python3 runtime/tests/ship_artifact_publication.py && (python3 runtime/tests/recon_verify_smoke.py >/tmp/riddle-proof-recon-verify-smoke.json || (tail -120 /tmp/riddle-proof-recon-verify-smoke.json; exit 1))"