@riddledc/openclaw-riddledc 0.9.4 → 0.9.6

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/CHECKSUMS.txt CHANGED
@@ -1,9 +1,9 @@
1
- c320ef98658b4d0bbe03485cb28105e299b85d0fb240c3a1e45f337c7011464e dist/chunk-SNGACMAL.js
2
- 64cc01e78e10d5cc8855cb849431b8c4b9c9da5c8cb1d2030cc1857f8db2e4f1 dist/core.cjs
3
- 9e6f2ccdbc993bea4445dbc20e131b442c01b298c19f87fe81846a22d6c92c48 dist/core.d.cts
4
- 9e6f2ccdbc993bea4445dbc20e131b442c01b298c19f87fe81846a22d6c92c48 dist/core.d.ts
5
- b42375f824ecc6089e065b28268c828b29ccef979c9d8ae53ffff4abe138c0b4 dist/core.js
6
- 2ecc1e44daec4535712881dd0fbc3af4afe98d58bf1a2336a1a377cb94e41eb5 dist/index.cjs
1
+ c6ac3162f44cefd3bdf39030780ca7e90812d2f9f72064f6f6946c3d4592b4f3 dist/chunk-ZNO6NNKO.js
2
+ e50d40eafee4081213bfe42ec6e77e9ef58c4f383c0c966df5512f28a8144a68 dist/core.cjs
3
+ d6e158722c91097e647d712652cc6bd26792aecf2ff6f990b0a5bf4dfa323aa2 dist/core.d.cts
4
+ d6e158722c91097e647d712652cc6bd26792aecf2ff6f990b0a5bf4dfa323aa2 dist/core.d.ts
5
+ 2ce75cbb7701f3a0cb1a0adcbe4c53e5062a540ef7cf7517b470908071c86d67 dist/core.js
6
+ 3d1abeb96c6539cf6e801b8632657a110a3f9767b4b6d51e1c8b419ef5fd94c2 dist/index.cjs
7
7
  94ce04f0e2d84bf64dd68f0500dfdd2f951287a3deccec87f197261961927f6f dist/index.d.cts
8
8
  94ce04f0e2d84bf64dd68f0500dfdd2f951287a3deccec87f197261961927f6f dist/index.d.ts
9
- 4b4cdbf998c5d79fb14c43d0137846696c15c48676914ab243d8d3a78cdb242e dist/index.js
9
+ 0effe0fdd362247d9186a419604b2696b6955f25b2ceda6ba3360742db46881f dist/index.js
@@ -151,6 +151,24 @@ function previewTimeoutResult(jobId, timeoutMs, lastStatusData, resultExtras = (
151
151
  if (lastStatusData?.error) result.server_error = lastStatusData.error;
152
152
  return result;
153
153
  }
154
+ function isCompletedPreviewStatus(status) {
155
+ const value = String(status ?? "").toLowerCase();
156
+ return value === "complete" || value === "completed";
157
+ }
158
+ function isTerminalPreviewStatus(status) {
159
+ const value = String(status ?? "").toLowerCase();
160
+ return [
161
+ "complete",
162
+ "completed",
163
+ "failed",
164
+ "completed_error",
165
+ "completed_timeout",
166
+ "timeout",
167
+ "timed_out",
168
+ "cancelled",
169
+ "canceled"
170
+ ].includes(value);
171
+ }
154
172
  async function writeArtifact(workspace, subdir, filename, content) {
155
173
  const dir = join(workspace, "riddle", subdir);
156
174
  await mkdir(dir, { recursive: true });
@@ -258,6 +276,7 @@ async function fetchArtifactsAndBuild(config, jobId, include) {
258
276
  const data = await res.json();
259
277
  const artifacts = data.artifacts || [];
260
278
  const result = {};
279
+ result.outputs = artifacts;
261
280
  if (data.status) result._artifactsStatus = data.status;
262
281
  if (data.timeout) result._timeout = data.timeout;
263
282
  if (data.error) result._error = data.error;
@@ -304,6 +323,20 @@ async function fetchArtifactsAndBuild(config, jobId, include) {
304
323
  } catch {
305
324
  }
306
325
  }
326
+ const visualDiffArtifact = artifacts.find((a) => a.name === "visual-diff.json");
327
+ if (include.includes("visual_diff") && visualDiffArtifact?.url) {
328
+ try {
329
+ const vRes = await fetch(visualDiffArtifact.url);
330
+ if (vRes.ok) {
331
+ result.visual_diff = await vRes.json();
332
+ }
333
+ } catch {
334
+ }
335
+ }
336
+ const visualDiffImages = artifacts.filter((a) => /^visual-diff.*\.(png|jpg|jpeg)$/i.test(a.name || ""));
337
+ if (visualDiffImages.length > 0) {
338
+ result.visual_diff_images = visualDiffImages;
339
+ }
307
340
  if (include.includes("har")) {
308
341
  const harArtifact = artifacts.find((a) => a.name === "network.har");
309
342
  if (harArtifact?.url) {
@@ -486,6 +519,62 @@ async function saveImageOutputs(workspace, jobId, outputs, label) {
486
519
  }
487
520
  }
488
521
  }
522
+ async function previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras = () => ({})) {
523
+ const status = statusData?.status ?? "unknown";
524
+ const terminal = isTerminalPreviewStatus(status);
525
+ const completed = isCompletedPreviewStatus(status);
526
+ const label = pathPrefix.slice(1);
527
+ const result = {
528
+ ok: terminal ? completed : true,
529
+ terminal,
530
+ job_id: jobId,
531
+ status,
532
+ phase: statusData?.phase ?? status,
533
+ phase_updated_at: statusData?.phase_updated_at,
534
+ phase_details: statusData?.phase_details,
535
+ outputs: statusData?.outputs || [],
536
+ compute_seconds: statusData?.compute_seconds,
537
+ egress_bytes: statusData?.egress_bytes,
538
+ ...resultExtras(statusData ?? {})
539
+ };
540
+ if (!terminal) {
541
+ result.message = `Job is still ${status}. Call the status tool again later to recover artifacts when it completes.`;
542
+ }
543
+ if (statusData?.error) result.error = statusData.error;
544
+ if (statusData?.script_error) result.script_error = statusData.script_error;
545
+ if (terminal && !completed && !result.error && !result.script_error) {
546
+ result.error = `Job ended with status ${status}`;
547
+ }
548
+ await saveImageOutputs(config.workspace, jobId, result.outputs, label);
549
+ result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
550
+ return result;
551
+ }
552
+ async function getPreviewJobStatus(config, pathPrefix, jobId, resultExtras = () => ({})) {
553
+ let cfg;
554
+ try {
555
+ cfg = requireConfig(config);
556
+ } catch (err) {
557
+ return { ok: false, error: err.message };
558
+ }
559
+ if (!jobId || typeof jobId !== "string") {
560
+ return { ok: false, error: "job_id must be a non-empty string" };
561
+ }
562
+ const endpoint = cfg.baseUrl.replace(/\/$/, "");
563
+ let statusRes;
564
+ try {
565
+ statusRes = await fetchWithRetry(`${endpoint}${pathPrefix}/${jobId}`, {
566
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
567
+ }, PREVIEW_REQUEST_TIMEOUT_MS, `${pathPrefix.slice(1)} status`, { attempts: 2 });
568
+ } catch (e) {
569
+ return { ok: false, job_id: jobId, error: `Status failed: ${describeError(e)}` };
570
+ }
571
+ if (!statusRes.ok) {
572
+ const err = await statusRes.text().catch(() => "");
573
+ return { ok: false, job_id: jobId, error: `Status failed: HTTP ${statusRes.status}${err ? ` ${err}` : ""}` };
574
+ }
575
+ const statusData = await statusRes.json();
576
+ return previewResultFromStatusData(cfg, pathPrefix, jobId, statusData, resultExtras);
577
+ }
489
578
  async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras) {
490
579
  const endpoint = config.baseUrl.replace(/\/$/, "");
491
580
  const pollStart = Date.now();
@@ -505,24 +594,8 @@ async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras
505
594
  }
506
595
  const statusData = await statusRes.json();
507
596
  lastStatusData = statusData;
508
- if (statusData.status === "complete" || statusData.status === "completed" || statusData.status === "failed") {
509
- const result = {
510
- ok: statusData.status === "complete" || statusData.status === "completed",
511
- job_id: jobId,
512
- status: statusData.status,
513
- phase: statusData.phase ?? statusData.status,
514
- phase_updated_at: statusData.phase_updated_at,
515
- phase_details: statusData.phase_details,
516
- outputs: statusData.outputs || [],
517
- compute_seconds: statusData.compute_seconds,
518
- egress_bytes: statusData.egress_bytes,
519
- ...resultExtras(statusData)
520
- };
521
- if (statusData.error) result.error = statusData.error;
522
- if (statusData.script_error) result.script_error = statusData.script_error;
523
- await saveImageOutputs(config.workspace, jobId, result.outputs, pathPrefix.slice(1));
524
- result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
525
- return result;
597
+ if (isTerminalPreviewStatus(statusData.status)) {
598
+ return previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras);
526
599
  }
527
600
  await sleep(pollIntervalMs);
528
601
  }
@@ -735,6 +808,9 @@ async function createServerPreview(config, params) {
735
808
  }
736
809
  return pollPreviewJob(cfg, "/v1/server-preview", created.job_id, ((params.timeout || 120) + 60) * 1e3, () => ({}));
737
810
  }
811
+ async function getServerPreviewStatus(config, jobId) {
812
+ return getPreviewJobStatus(config, "/v1/server-preview", jobId, () => ({}));
813
+ }
738
814
  async function createBuildPreview(config, params) {
739
815
  let cfg;
740
816
  try {
@@ -837,6 +913,14 @@ async function createBuildPreview(config, params) {
837
913
  ...statusData.audit ? { audit: statusData.audit } : {}
838
914
  }));
839
915
  }
916
+ async function getBuildPreviewStatus(config, jobId) {
917
+ return getPreviewJobStatus(config, "/v1/build-preview", jobId, (statusData) => ({
918
+ build_duration_ms: statusData.build_duration_ms,
919
+ ...statusData.build_log ? { build_log: statusData.build_log } : {},
920
+ ...statusData.container_log ? { container_log: statusData.container_log } : {},
921
+ ...statusData.audit ? { audit: statusData.audit } : {}
922
+ }));
923
+ }
840
924
 
841
925
  export {
842
926
  configFromOpenClawApi,
@@ -854,5 +938,7 @@ export {
854
938
  createStaticPreview,
855
939
  deleteStaticPreview,
856
940
  createServerPreview,
857
- createBuildPreview
941
+ getServerPreviewStatus,
942
+ createBuildPreview,
943
+ getBuildPreviewStatus
858
944
  };
package/dist/core.cjs CHANGED
@@ -31,6 +31,8 @@ __export(core_exports, {
31
31
  fetchArtifactsAndBuild: () => fetchArtifactsAndBuild,
32
32
  fetchWithRetry: () => fetchWithRetry,
33
33
  fetchWithTimeout: () => fetchWithTimeout,
34
+ getBuildPreviewStatus: () => getBuildPreviewStatus,
35
+ getServerPreviewStatus: () => getServerPreviewStatus,
34
36
  isAlreadyStartedResponse: () => isAlreadyStartedResponse,
35
37
  pollJobStatus: () => pollJobStatus,
36
38
  riddleApiFetch: () => riddleApiFetch,
@@ -190,6 +192,24 @@ function previewTimeoutResult(jobId, timeoutMs, lastStatusData, resultExtras = (
190
192
  if (lastStatusData?.error) result.server_error = lastStatusData.error;
191
193
  return result;
192
194
  }
195
+ function isCompletedPreviewStatus(status) {
196
+ const value = String(status ?? "").toLowerCase();
197
+ return value === "complete" || value === "completed";
198
+ }
199
+ function isTerminalPreviewStatus(status) {
200
+ const value = String(status ?? "").toLowerCase();
201
+ return [
202
+ "complete",
203
+ "completed",
204
+ "failed",
205
+ "completed_error",
206
+ "completed_timeout",
207
+ "timeout",
208
+ "timed_out",
209
+ "cancelled",
210
+ "canceled"
211
+ ].includes(value);
212
+ }
193
213
  async function writeArtifact(workspace, subdir, filename, content) {
194
214
  const dir = (0, import_node_path.join)(workspace, "riddle", subdir);
195
215
  await (0, import_promises.mkdir)(dir, { recursive: true });
@@ -297,6 +317,7 @@ async function fetchArtifactsAndBuild(config, jobId, include) {
297
317
  const data = await res.json();
298
318
  const artifacts = data.artifacts || [];
299
319
  const result = {};
320
+ result.outputs = artifacts;
300
321
  if (data.status) result._artifactsStatus = data.status;
301
322
  if (data.timeout) result._timeout = data.timeout;
302
323
  if (data.error) result._error = data.error;
@@ -343,6 +364,20 @@ async function fetchArtifactsAndBuild(config, jobId, include) {
343
364
  } catch {
344
365
  }
345
366
  }
367
+ const visualDiffArtifact = artifacts.find((a) => a.name === "visual-diff.json");
368
+ if (include.includes("visual_diff") && visualDiffArtifact?.url) {
369
+ try {
370
+ const vRes = await fetch(visualDiffArtifact.url);
371
+ if (vRes.ok) {
372
+ result.visual_diff = await vRes.json();
373
+ }
374
+ } catch {
375
+ }
376
+ }
377
+ const visualDiffImages = artifacts.filter((a) => /^visual-diff.*\.(png|jpg|jpeg)$/i.test(a.name || ""));
378
+ if (visualDiffImages.length > 0) {
379
+ result.visual_diff_images = visualDiffImages;
380
+ }
346
381
  if (include.includes("har")) {
347
382
  const harArtifact = artifacts.find((a) => a.name === "network.har");
348
383
  if (harArtifact?.url) {
@@ -525,6 +560,62 @@ async function saveImageOutputs(workspace, jobId, outputs, label) {
525
560
  }
526
561
  }
527
562
  }
563
+ async function previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras = () => ({})) {
564
+ const status = statusData?.status ?? "unknown";
565
+ const terminal = isTerminalPreviewStatus(status);
566
+ const completed = isCompletedPreviewStatus(status);
567
+ const label = pathPrefix.slice(1);
568
+ const result = {
569
+ ok: terminal ? completed : true,
570
+ terminal,
571
+ job_id: jobId,
572
+ status,
573
+ phase: statusData?.phase ?? status,
574
+ phase_updated_at: statusData?.phase_updated_at,
575
+ phase_details: statusData?.phase_details,
576
+ outputs: statusData?.outputs || [],
577
+ compute_seconds: statusData?.compute_seconds,
578
+ egress_bytes: statusData?.egress_bytes,
579
+ ...resultExtras(statusData ?? {})
580
+ };
581
+ if (!terminal) {
582
+ result.message = `Job is still ${status}. Call the status tool again later to recover artifacts when it completes.`;
583
+ }
584
+ if (statusData?.error) result.error = statusData.error;
585
+ if (statusData?.script_error) result.script_error = statusData.script_error;
586
+ if (terminal && !completed && !result.error && !result.script_error) {
587
+ result.error = `Job ended with status ${status}`;
588
+ }
589
+ await saveImageOutputs(config.workspace, jobId, result.outputs, label);
590
+ result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
591
+ return result;
592
+ }
593
+ async function getPreviewJobStatus(config, pathPrefix, jobId, resultExtras = () => ({})) {
594
+ let cfg;
595
+ try {
596
+ cfg = requireConfig(config);
597
+ } catch (err) {
598
+ return { ok: false, error: err.message };
599
+ }
600
+ if (!jobId || typeof jobId !== "string") {
601
+ return { ok: false, error: "job_id must be a non-empty string" };
602
+ }
603
+ const endpoint = cfg.baseUrl.replace(/\/$/, "");
604
+ let statusRes;
605
+ try {
606
+ statusRes = await fetchWithRetry(`${endpoint}${pathPrefix}/${jobId}`, {
607
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
608
+ }, PREVIEW_REQUEST_TIMEOUT_MS, `${pathPrefix.slice(1)} status`, { attempts: 2 });
609
+ } catch (e) {
610
+ return { ok: false, job_id: jobId, error: `Status failed: ${describeError(e)}` };
611
+ }
612
+ if (!statusRes.ok) {
613
+ const err = await statusRes.text().catch(() => "");
614
+ return { ok: false, job_id: jobId, error: `Status failed: HTTP ${statusRes.status}${err ? ` ${err}` : ""}` };
615
+ }
616
+ const statusData = await statusRes.json();
617
+ return previewResultFromStatusData(cfg, pathPrefix, jobId, statusData, resultExtras);
618
+ }
528
619
  async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras) {
529
620
  const endpoint = config.baseUrl.replace(/\/$/, "");
530
621
  const pollStart = Date.now();
@@ -544,24 +635,8 @@ async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras
544
635
  }
545
636
  const statusData = await statusRes.json();
546
637
  lastStatusData = statusData;
547
- if (statusData.status === "complete" || statusData.status === "completed" || statusData.status === "failed") {
548
- const result = {
549
- ok: statusData.status === "complete" || statusData.status === "completed",
550
- job_id: jobId,
551
- status: statusData.status,
552
- phase: statusData.phase ?? statusData.status,
553
- phase_updated_at: statusData.phase_updated_at,
554
- phase_details: statusData.phase_details,
555
- outputs: statusData.outputs || [],
556
- compute_seconds: statusData.compute_seconds,
557
- egress_bytes: statusData.egress_bytes,
558
- ...resultExtras(statusData)
559
- };
560
- if (statusData.error) result.error = statusData.error;
561
- if (statusData.script_error) result.script_error = statusData.script_error;
562
- await saveImageOutputs(config.workspace, jobId, result.outputs, pathPrefix.slice(1));
563
- result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
564
- return result;
638
+ if (isTerminalPreviewStatus(statusData.status)) {
639
+ return previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras);
565
640
  }
566
641
  await sleep(pollIntervalMs);
567
642
  }
@@ -774,6 +849,9 @@ async function createServerPreview(config, params) {
774
849
  }
775
850
  return pollPreviewJob(cfg, "/v1/server-preview", created.job_id, ((params.timeout || 120) + 60) * 1e3, () => ({}));
776
851
  }
852
+ async function getServerPreviewStatus(config, jobId) {
853
+ return getPreviewJobStatus(config, "/v1/server-preview", jobId, () => ({}));
854
+ }
777
855
  async function createBuildPreview(config, params) {
778
856
  let cfg;
779
857
  try {
@@ -876,6 +954,14 @@ async function createBuildPreview(config, params) {
876
954
  ...statusData.audit ? { audit: statusData.audit } : {}
877
955
  }));
878
956
  }
957
+ async function getBuildPreviewStatus(config, jobId) {
958
+ return getPreviewJobStatus(config, "/v1/build-preview", jobId, (statusData) => ({
959
+ build_duration_ms: statusData.build_duration_ms,
960
+ ...statusData.build_log ? { build_log: statusData.build_log } : {},
961
+ ...statusData.container_log ? { container_log: statusData.container_log } : {},
962
+ ...statusData.audit ? { audit: statusData.audit } : {}
963
+ }));
964
+ }
879
965
  // Annotate the CommonJS export names for ESM import in node:
880
966
  0 && (module.exports = {
881
967
  applySafetySpec,
@@ -889,6 +975,8 @@ async function createBuildPreview(config, params) {
889
975
  fetchArtifactsAndBuild,
890
976
  fetchWithRetry,
891
977
  fetchWithTimeout,
978
+ getBuildPreviewStatus,
979
+ getServerPreviewStatus,
892
980
  isAlreadyStartedResponse,
893
981
  pollJobStatus,
894
982
  riddleApiFetch,
package/dist/core.d.cts CHANGED
@@ -52,6 +52,8 @@ declare function createStaticPreview(config: RiddleCoreConfig, params: {
52
52
  }): Promise<PreviewResult>;
53
53
  declare function deleteStaticPreview(config: RiddleCoreConfig, id: string): Promise<PreviewResult>;
54
54
  declare function createServerPreview(config: RiddleCoreConfig, params: Record<string, any>): Promise<PreviewResult>;
55
+ declare function getServerPreviewStatus(config: RiddleCoreConfig, jobId: string): Promise<PreviewResult>;
55
56
  declare function createBuildPreview(config: RiddleCoreConfig, params: Record<string, any>): Promise<PreviewResult>;
57
+ declare function getBuildPreviewStatus(config: RiddleCoreConfig, jobId: string): Promise<PreviewResult>;
56
58
 
57
- export { type PreviewResult, type RiddleCoreConfig, type RiddlePayload, type RunResult, applySafetySpec, assertAllowedBaseUrl, configFromOpenClawApi, createBuildPreview, createServerPreview, createStaticPreview, deleteStaticPreview, describeError, fetchArtifactsAndBuild, fetchWithRetry, fetchWithTimeout, isAlreadyStartedResponse, pollJobStatus, riddleApiFetch, runWithDefaults, writeArtifactBinary };
59
+ export { type PreviewResult, type RiddleCoreConfig, type RiddlePayload, type RunResult, applySafetySpec, assertAllowedBaseUrl, configFromOpenClawApi, createBuildPreview, createServerPreview, createStaticPreview, deleteStaticPreview, describeError, fetchArtifactsAndBuild, fetchWithRetry, fetchWithTimeout, getBuildPreviewStatus, getServerPreviewStatus, isAlreadyStartedResponse, pollJobStatus, riddleApiFetch, runWithDefaults, writeArtifactBinary };
package/dist/core.d.ts CHANGED
@@ -52,6 +52,8 @@ declare function createStaticPreview(config: RiddleCoreConfig, params: {
52
52
  }): Promise<PreviewResult>;
53
53
  declare function deleteStaticPreview(config: RiddleCoreConfig, id: string): Promise<PreviewResult>;
54
54
  declare function createServerPreview(config: RiddleCoreConfig, params: Record<string, any>): Promise<PreviewResult>;
55
+ declare function getServerPreviewStatus(config: RiddleCoreConfig, jobId: string): Promise<PreviewResult>;
55
56
  declare function createBuildPreview(config: RiddleCoreConfig, params: Record<string, any>): Promise<PreviewResult>;
57
+ declare function getBuildPreviewStatus(config: RiddleCoreConfig, jobId: string): Promise<PreviewResult>;
56
58
 
57
- export { type PreviewResult, type RiddleCoreConfig, type RiddlePayload, type RunResult, applySafetySpec, assertAllowedBaseUrl, configFromOpenClawApi, createBuildPreview, createServerPreview, createStaticPreview, deleteStaticPreview, describeError, fetchArtifactsAndBuild, fetchWithRetry, fetchWithTimeout, isAlreadyStartedResponse, pollJobStatus, riddleApiFetch, runWithDefaults, writeArtifactBinary };
59
+ export { type PreviewResult, type RiddleCoreConfig, type RiddlePayload, type RunResult, applySafetySpec, assertAllowedBaseUrl, configFromOpenClawApi, createBuildPreview, createServerPreview, createStaticPreview, deleteStaticPreview, describeError, fetchArtifactsAndBuild, fetchWithRetry, fetchWithTimeout, getBuildPreviewStatus, getServerPreviewStatus, isAlreadyStartedResponse, pollJobStatus, riddleApiFetch, runWithDefaults, writeArtifactBinary };
package/dist/core.js CHANGED
@@ -10,12 +10,14 @@ import {
10
10
  fetchArtifactsAndBuild,
11
11
  fetchWithRetry,
12
12
  fetchWithTimeout,
13
+ getBuildPreviewStatus,
14
+ getServerPreviewStatus,
13
15
  isAlreadyStartedResponse,
14
16
  pollJobStatus,
15
17
  riddleApiFetch,
16
18
  runWithDefaults,
17
19
  writeArtifactBinary
18
- } from "./chunk-SNGACMAL.js";
20
+ } from "./chunk-ZNO6NNKO.js";
19
21
  export {
20
22
  applySafetySpec,
21
23
  assertAllowedBaseUrl,
@@ -28,6 +30,8 @@ export {
28
30
  fetchArtifactsAndBuild,
29
31
  fetchWithRetry,
30
32
  fetchWithTimeout,
33
+ getBuildPreviewStatus,
34
+ getServerPreviewStatus,
31
35
  isAlreadyStartedResponse,
32
36
  pollJobStatus,
33
37
  riddleApiFetch,
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ var execFile = (0, import_node_util.promisify)(import_node_child_process.execFil
38
38
  var INLINE_CAP = 50 * 1024;
39
39
  var PREVIEW_REQUEST_TIMEOUT_MS = 3e4;
40
40
  var PREVIEW_UPLOAD_TIMEOUT_MS = 5 * 6e4;
41
+ var PREVIEW_ARTIFACT_TIMEOUT_MS = 6e4;
41
42
  var PREVIEW_RETRY_ATTEMPTS = 3;
42
43
  var PREVIEW_RETRY_BASE_DELAY_MS = 750;
43
44
  function configFromOpenClawApi(api) {
@@ -132,6 +133,32 @@ async function fetchWithRetry(url, init, timeoutMs, label, opts = {}) {
132
133
  }
133
134
  throw new Error(`${label} failed after ${attempts} attempts: ${describeError(lastErr)}`);
134
135
  }
136
+ function isCompletedPreviewStatus(status) {
137
+ const value = String(status ?? "").toLowerCase();
138
+ return value === "complete" || value === "completed";
139
+ }
140
+ function isTerminalPreviewStatus(status) {
141
+ const value = String(status ?? "").toLowerCase();
142
+ return [
143
+ "complete",
144
+ "completed",
145
+ "failed",
146
+ "completed_error",
147
+ "completed_timeout",
148
+ "timeout",
149
+ "timed_out",
150
+ "cancelled",
151
+ "canceled"
152
+ ].includes(value);
153
+ }
154
+ async function writeArtifactBinary(workspace, subdir, filename, base64Content) {
155
+ const dir = (0, import_node_path.join)(workspace, "riddle", subdir);
156
+ await (0, import_promises.mkdir)(dir, { recursive: true });
157
+ const filePath = (0, import_node_path.join)(dir, filename);
158
+ const buf = Buffer.from(base64Content, "base64");
159
+ await (0, import_promises.writeFile)(filePath, buf);
160
+ return { path: filePath, sizeBytes: buf.byteLength };
161
+ }
135
162
  async function assertDirectory(dir) {
136
163
  if (!dir || typeof dir !== "string") throw new Error("directory must be an absolute path");
137
164
  try {
@@ -147,6 +174,79 @@ async function tarDirectory(dir, tarball, excludes, timeout) {
147
174
  await execFile("tar", ["czf", tarball, ...excludeArgs, "-C", dir, "."], { timeout });
148
175
  return (0, import_promises.readFile)(tarball);
149
176
  }
177
+ async function saveImageOutputs(workspace, jobId, outputs, label) {
178
+ for (const output of outputs) {
179
+ if (output.name && /\.(png|jpg|jpeg)$/i.test(output.name) && output.url) {
180
+ try {
181
+ const imgRes = await fetchWithTimeout(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS, `${label} artifact download`);
182
+ if (imgRes.ok) {
183
+ const buf = await imgRes.arrayBuffer();
184
+ const base64 = Buffer.from(buf).toString("base64");
185
+ const ref = await writeArtifactBinary(workspace, "screenshots", `${jobId}-${output.name}`, base64);
186
+ output.saved = ref.path;
187
+ output.sizeBytes = ref.sizeBytes;
188
+ }
189
+ } catch {
190
+ }
191
+ }
192
+ }
193
+ }
194
+ async function previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras = () => ({})) {
195
+ const status = statusData?.status ?? "unknown";
196
+ const terminal = isTerminalPreviewStatus(status);
197
+ const completed = isCompletedPreviewStatus(status);
198
+ const label = pathPrefix.slice(1);
199
+ const result = {
200
+ ok: terminal ? completed : true,
201
+ terminal,
202
+ job_id: jobId,
203
+ status,
204
+ phase: statusData?.phase ?? status,
205
+ phase_updated_at: statusData?.phase_updated_at,
206
+ phase_details: statusData?.phase_details,
207
+ outputs: statusData?.outputs || [],
208
+ compute_seconds: statusData?.compute_seconds,
209
+ egress_bytes: statusData?.egress_bytes,
210
+ ...resultExtras(statusData ?? {})
211
+ };
212
+ if (!terminal) {
213
+ result.message = `Job is still ${status}. Call the status tool again later to recover artifacts when it completes.`;
214
+ }
215
+ if (statusData?.error) result.error = statusData.error;
216
+ if (statusData?.script_error) result.script_error = statusData.script_error;
217
+ if (terminal && !completed && !result.error && !result.script_error) {
218
+ result.error = `Job ended with status ${status}`;
219
+ }
220
+ await saveImageOutputs(config.workspace, jobId, result.outputs, label);
221
+ result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
222
+ return result;
223
+ }
224
+ async function getPreviewJobStatus(config, pathPrefix, jobId, resultExtras = () => ({})) {
225
+ let cfg;
226
+ try {
227
+ cfg = requireConfig(config);
228
+ } catch (err) {
229
+ return { ok: false, error: err.message };
230
+ }
231
+ if (!jobId || typeof jobId !== "string") {
232
+ return { ok: false, error: "job_id must be a non-empty string" };
233
+ }
234
+ const endpoint = cfg.baseUrl.replace(/\/$/, "");
235
+ let statusRes;
236
+ try {
237
+ statusRes = await fetchWithRetry(`${endpoint}${pathPrefix}/${jobId}`, {
238
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
239
+ }, PREVIEW_REQUEST_TIMEOUT_MS, `${pathPrefix.slice(1)} status`, { attempts: 2 });
240
+ } catch (e) {
241
+ return { ok: false, job_id: jobId, error: `Status failed: ${describeError(e)}` };
242
+ }
243
+ if (!statusRes.ok) {
244
+ const err = await statusRes.text().catch(() => "");
245
+ return { ok: false, job_id: jobId, error: `Status failed: HTTP ${statusRes.status}${err ? ` ${err}` : ""}` };
246
+ }
247
+ const statusData = await statusRes.json();
248
+ return previewResultFromStatusData(cfg, pathPrefix, jobId, statusData, resultExtras);
249
+ }
150
250
  async function createStaticPreview(config, params) {
151
251
  let cfg;
152
252
  try {
@@ -240,13 +340,24 @@ async function deleteStaticPreview(config, id) {
240
340
  const data = await res.json();
241
341
  return { ok: true, deleted: true, files_removed: data.files_removed };
242
342
  }
343
+ async function getServerPreviewStatus(config, jobId) {
344
+ return getPreviewJobStatus(config, "/v1/server-preview", jobId, () => ({}));
345
+ }
346
+ async function getBuildPreviewStatus(config, jobId) {
347
+ return getPreviewJobStatus(config, "/v1/build-preview", jobId, (statusData) => ({
348
+ build_duration_ms: statusData.build_duration_ms,
349
+ ...statusData.build_log ? { build_log: statusData.build_log } : {},
350
+ ...statusData.container_log ? { container_log: statusData.container_log } : {},
351
+ ...statusData.audit ? { audit: statusData.audit } : {}
352
+ }));
353
+ }
243
354
 
244
355
  // src/index.ts
245
356
  var execFile2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
246
357
  var INLINE_CAP2 = 50 * 1024;
247
358
  var PREVIEW_REQUEST_TIMEOUT_MS2 = 3e4;
248
359
  var PREVIEW_UPLOAD_TIMEOUT_MS2 = 5 * 6e4;
249
- var PREVIEW_ARTIFACT_TIMEOUT_MS = 6e4;
360
+ var PREVIEW_ARTIFACT_TIMEOUT_MS2 = 6e4;
250
361
  var PREVIEW_RETRY_ATTEMPTS2 = 3;
251
362
  var PREVIEW_RETRY_BASE_DELAY_MS2 = 750;
252
363
  function getCfg(api) {
@@ -387,7 +498,7 @@ async function writeArtifact(workspace, subdir, filename, content) {
387
498
  await (0, import_promises2.writeFile)(filePath, buf);
388
499
  return { path: filePath, sizeBytes: buf.byteLength };
389
500
  }
390
- async function writeArtifactBinary(workspace, subdir, filename, base64Content) {
501
+ async function writeArtifactBinary2(workspace, subdir, filename, base64Content) {
391
502
  const dir = (0, import_node_path2.join)(workspace, "riddle", subdir);
392
503
  await (0, import_promises2.mkdir)(dir, { recursive: true });
393
504
  const filePath = (0, import_node_path2.join)(dir, filename);
@@ -405,7 +516,7 @@ async function applySafetySpec(result, opts) {
405
516
  base64Data = result.screenshot.data.replace(/^data:image\/\w+;base64,/, "");
406
517
  }
407
518
  if (base64Data) {
408
- const ref = await writeArtifactBinary(opts.workspace, "screenshots", `${jobId}.png`, base64Data);
519
+ const ref = await writeArtifactBinary2(opts.workspace, "screenshots", `${jobId}.png`, base64Data);
409
520
  const cdnUrl = typeof result.screenshot === "object" ? result.screenshot.url : void 0;
410
521
  result.screenshot = { saved: ref.path, sizeBytes: ref.sizeBytes, ...cdnUrl ? { url: cdnUrl } : {} };
411
522
  }
@@ -422,14 +533,14 @@ async function applySafetySpec(result, opts) {
422
533
  base64Data = ss.data.replace(/^data:image\/\w+;base64,/, "");
423
534
  }
424
535
  if (base64Data) {
425
- const ref = await writeArtifactBinary(opts.workspace, "screenshots", `${jobId}-${i}.png`, base64Data);
536
+ const ref = await writeArtifactBinary2(opts.workspace, "screenshots", `${jobId}-${i}.png`, base64Data);
426
537
  savedRefs.push({ saved: ref.path, sizeBytes: ref.sizeBytes, ...cdnUrl ? { url: cdnUrl } : {} });
427
538
  }
428
539
  }
429
540
  result.screenshots = savedRefs;
430
541
  }
431
542
  if (result.rawPngBase64 != null) {
432
- const ref = await writeArtifactBinary(opts.workspace, "screenshots", `${jobId}.png`, result.rawPngBase64);
543
+ const ref = await writeArtifactBinary2(opts.workspace, "screenshots", `${jobId}.png`, result.rawPngBase64);
433
544
  result.screenshot = { saved: ref.path, sizeBytes: ref.sizeBytes };
434
545
  delete result.rawPngBase64;
435
546
  }
@@ -1304,11 +1415,11 @@ function register(api) {
1304
1415
  for (const output of result.outputs) {
1305
1416
  if (output.name && /\.(png|jpg|jpeg)$/i.test(output.name) && output.url) {
1306
1417
  try {
1307
- const imgRes = await fetchWithTimeout2(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS, "server preview artifact download");
1418
+ const imgRes = await fetchWithTimeout2(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS2, "server preview artifact download");
1308
1419
  if (imgRes.ok) {
1309
1420
  const buf = await imgRes.arrayBuffer();
1310
1421
  const base64 = Buffer.from(buf).toString("base64");
1311
- const ref = await writeArtifactBinary(workspace, "screenshots", `${created.job_id}-${output.name}`, base64);
1422
+ const ref = await writeArtifactBinary2(workspace, "screenshots", `${created.job_id}-${output.name}`, base64);
1312
1423
  output.saved = ref.path;
1313
1424
  output.sizeBytes = ref.sizeBytes;
1314
1425
  }
@@ -1326,6 +1437,20 @@ function register(api) {
1326
1437
  },
1327
1438
  { optional: true }
1328
1439
  );
1440
+ api.registerTool(
1441
+ {
1442
+ name: "riddle_server_preview_status",
1443
+ description: "Check/recover a server-preview job by ID (sp_...). Use when riddle_server_preview printed a job_id but the local watcher was interrupted or timed out before artifacts were returned. Downloads screenshot outputs into the workspace when available.",
1444
+ parameters: import_typebox.Type.Object({
1445
+ job_id: import_typebox.Type.String({ description: "Server-preview job ID, for example sp_abc123" })
1446
+ }),
1447
+ async execute(_id, params) {
1448
+ const result = await getServerPreviewStatus(configFromOpenClawApi(api), params.job_id);
1449
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
1450
+ }
1451
+ },
1452
+ { optional: true }
1453
+ );
1329
1454
  api.registerTool(
1330
1455
  {
1331
1456
  name: "riddle_build_preview",
@@ -1510,11 +1635,11 @@ function register(api) {
1510
1635
  for (const output of result.outputs) {
1511
1636
  if (output.name && /\.(png|jpg|jpeg)$/i.test(output.name) && output.url) {
1512
1637
  try {
1513
- const imgRes = await fetchWithTimeout2(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS, "build preview artifact download");
1638
+ const imgRes = await fetchWithTimeout2(output.url, {}, PREVIEW_ARTIFACT_TIMEOUT_MS2, "build preview artifact download");
1514
1639
  if (imgRes.ok) {
1515
1640
  const buf = await imgRes.arrayBuffer();
1516
1641
  const base64 = Buffer.from(buf).toString("base64");
1517
- const ref = await writeArtifactBinary(workspace, "screenshots", `${created.job_id}-${output.name}`, base64);
1642
+ const ref = await writeArtifactBinary2(workspace, "screenshots", `${created.job_id}-${output.name}`, base64);
1518
1643
  output.saved = ref.path;
1519
1644
  output.sizeBytes = ref.sizeBytes;
1520
1645
  }
@@ -1537,6 +1662,20 @@ function register(api) {
1537
1662
  },
1538
1663
  { optional: true }
1539
1664
  );
1665
+ api.registerTool(
1666
+ {
1667
+ name: "riddle_build_preview_status",
1668
+ description: "Check/recover a build-preview job by ID (bp_...). Use when riddle_build_preview printed a job_id but the local watcher was interrupted or timed out before artifacts were returned. Downloads screenshot outputs and returns build/container logs when available.",
1669
+ parameters: import_typebox.Type.Object({
1670
+ job_id: import_typebox.Type.String({ description: "Build-preview job ID, for example bp_abc123" })
1671
+ }),
1672
+ async execute(_id, params) {
1673
+ const result = await getBuildPreviewStatus(configFromOpenClawApi(api), params.job_id);
1674
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
1675
+ }
1676
+ },
1677
+ { optional: true }
1678
+ );
1540
1679
  async function riddleApiFetch(api2, method, path, body) {
1541
1680
  const { apiKey, baseUrl } = getCfg(api2);
1542
1681
  if (!apiKey) throw new Error("Missing Riddle API key. Set RIDDLE_API_KEY or configure in plugin settings.");
@@ -1657,7 +1796,7 @@ function register(api) {
1657
1796
  if (imgRes.ok) {
1658
1797
  const buf = await imgRes.arrayBuffer();
1659
1798
  const base64 = Buffer.from(buf).toString("base64");
1660
- const ref = await writeArtifactBinary(workspace, "screenshots", `${data.job_id}-${output.name}`, base64);
1799
+ const ref = await writeArtifactBinary2(workspace, "screenshots", `${data.job_id}-${output.name}`, base64);
1661
1800
  output.saved = ref.path;
1662
1801
  output.sizeBytes = ref.sizeBytes;
1663
1802
  }
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  configFromOpenClawApi,
3
3
  createStaticPreview,
4
- deleteStaticPreview
5
- } from "./chunk-SNGACMAL.js";
4
+ deleteStaticPreview,
5
+ getBuildPreviewStatus,
6
+ getServerPreviewStatus
7
+ } from "./chunk-ZNO6NNKO.js";
6
8
 
7
9
  // src/index.ts
8
10
  import { Type } from "@sinclair/typebox";
@@ -1094,6 +1096,20 @@ function register(api) {
1094
1096
  },
1095
1097
  { optional: true }
1096
1098
  );
1099
+ api.registerTool(
1100
+ {
1101
+ name: "riddle_server_preview_status",
1102
+ description: "Check/recover a server-preview job by ID (sp_...). Use when riddle_server_preview printed a job_id but the local watcher was interrupted or timed out before artifacts were returned. Downloads screenshot outputs into the workspace when available.",
1103
+ parameters: Type.Object({
1104
+ job_id: Type.String({ description: "Server-preview job ID, for example sp_abc123" })
1105
+ }),
1106
+ async execute(_id, params) {
1107
+ const result = await getServerPreviewStatus(configFromOpenClawApi(api), params.job_id);
1108
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
1109
+ }
1110
+ },
1111
+ { optional: true }
1112
+ );
1097
1113
  api.registerTool(
1098
1114
  {
1099
1115
  name: "riddle_build_preview",
@@ -1305,6 +1321,20 @@ function register(api) {
1305
1321
  },
1306
1322
  { optional: true }
1307
1323
  );
1324
+ api.registerTool(
1325
+ {
1326
+ name: "riddle_build_preview_status",
1327
+ description: "Check/recover a build-preview job by ID (bp_...). Use when riddle_build_preview printed a job_id but the local watcher was interrupted or timed out before artifacts were returned. Downloads screenshot outputs and returns build/container logs when available.",
1328
+ parameters: Type.Object({
1329
+ job_id: Type.String({ description: "Build-preview job ID, for example bp_abc123" })
1330
+ }),
1331
+ async execute(_id, params) {
1332
+ const result = await getBuildPreviewStatus(configFromOpenClawApi(api), params.job_id);
1333
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
1334
+ }
1335
+ },
1336
+ { optional: true }
1337
+ );
1308
1338
  async function riddleApiFetch(api2, method, path, body) {
1309
1339
  const { apiKey, baseUrl } = getCfg(api2);
1310
1340
  if (!apiKey) throw new Error("Missing Riddle API key. Set RIDDLE_API_KEY or configure in plugin settings.");
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-riddledc",
3
3
  "name": "Riddle",
4
4
  "description": "Riddle (riddledc.com) hosted browser API tools for OpenClaw agents.",
5
- "version": "0.9.4",
5
+ "version": "0.9.6",
6
6
  "notes": "0.8.0: Added riddle_build_preview for Dockerfile-based builds with image caching.",
7
7
  "type": "plugin",
8
8
  "bundledSkills": [],
@@ -42,7 +42,9 @@
42
42
  "riddle_preview",
43
43
  "riddle_preview_delete",
44
44
  "riddle_server_preview",
45
+ "riddle_server_preview_status",
45
46
  "riddle_build_preview",
47
+ "riddle_build_preview_status",
46
48
  "riddle_session_create",
47
49
  "riddle_session_list",
48
50
  "riddle_session_run",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/openclaw-riddledc",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "OpenClaw integration package for RiddleDC (no secrets).",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",