@riddledc/openclaw-riddledc 0.9.4 → 0.9.5

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
+ 0756013923a5d79711ea1b22571589cce1dfc49d85b37de79eb2f9194b11c01e dist/chunk-UTJTPSHW.js
2
+ 628d17715e71385c1c21752d1c90dd956a0552b549444100cc62990ee0ca519d dist/core.cjs
3
+ d6e158722c91097e647d712652cc6bd26792aecf2ff6f990b0a5bf4dfa323aa2 dist/core.d.cts
4
+ d6e158722c91097e647d712652cc6bd26792aecf2ff6f990b0a5bf4dfa323aa2 dist/core.d.ts
5
+ 7d719fd0ea00019cb51bd4b2a02bf2e4104cae2350c91abe6d4cafb8702b4eb2 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
+ a3554f1a5ef8b62cb94c1c2bfdff682bbe64e935af412afccb06b3075c22b52e 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 });
@@ -486,6 +504,62 @@ async function saveImageOutputs(workspace, jobId, outputs, label) {
486
504
  }
487
505
  }
488
506
  }
507
+ async function previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras = () => ({})) {
508
+ const status = statusData?.status ?? "unknown";
509
+ const terminal = isTerminalPreviewStatus(status);
510
+ const completed = isCompletedPreviewStatus(status);
511
+ const label = pathPrefix.slice(1);
512
+ const result = {
513
+ ok: terminal ? completed : true,
514
+ terminal,
515
+ job_id: jobId,
516
+ status,
517
+ phase: statusData?.phase ?? status,
518
+ phase_updated_at: statusData?.phase_updated_at,
519
+ phase_details: statusData?.phase_details,
520
+ outputs: statusData?.outputs || [],
521
+ compute_seconds: statusData?.compute_seconds,
522
+ egress_bytes: statusData?.egress_bytes,
523
+ ...resultExtras(statusData ?? {})
524
+ };
525
+ if (!terminal) {
526
+ result.message = `Job is still ${status}. Call the status tool again later to recover artifacts when it completes.`;
527
+ }
528
+ if (statusData?.error) result.error = statusData.error;
529
+ if (statusData?.script_error) result.script_error = statusData.script_error;
530
+ if (terminal && !completed && !result.error && !result.script_error) {
531
+ result.error = `Job ended with status ${status}`;
532
+ }
533
+ await saveImageOutputs(config.workspace, jobId, result.outputs, label);
534
+ result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
535
+ return result;
536
+ }
537
+ async function getPreviewJobStatus(config, pathPrefix, jobId, resultExtras = () => ({})) {
538
+ let cfg;
539
+ try {
540
+ cfg = requireConfig(config);
541
+ } catch (err) {
542
+ return { ok: false, error: err.message };
543
+ }
544
+ if (!jobId || typeof jobId !== "string") {
545
+ return { ok: false, error: "job_id must be a non-empty string" };
546
+ }
547
+ const endpoint = cfg.baseUrl.replace(/\/$/, "");
548
+ let statusRes;
549
+ try {
550
+ statusRes = await fetchWithRetry(`${endpoint}${pathPrefix}/${jobId}`, {
551
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
552
+ }, PREVIEW_REQUEST_TIMEOUT_MS, `${pathPrefix.slice(1)} status`, { attempts: 2 });
553
+ } catch (e) {
554
+ return { ok: false, job_id: jobId, error: `Status failed: ${describeError(e)}` };
555
+ }
556
+ if (!statusRes.ok) {
557
+ const err = await statusRes.text().catch(() => "");
558
+ return { ok: false, job_id: jobId, error: `Status failed: HTTP ${statusRes.status}${err ? ` ${err}` : ""}` };
559
+ }
560
+ const statusData = await statusRes.json();
561
+ return previewResultFromStatusData(cfg, pathPrefix, jobId, statusData, resultExtras);
562
+ }
489
563
  async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras) {
490
564
  const endpoint = config.baseUrl.replace(/\/$/, "");
491
565
  const pollStart = Date.now();
@@ -505,24 +579,8 @@ async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras
505
579
  }
506
580
  const statusData = await statusRes.json();
507
581
  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;
582
+ if (isTerminalPreviewStatus(statusData.status)) {
583
+ return previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras);
526
584
  }
527
585
  await sleep(pollIntervalMs);
528
586
  }
@@ -735,6 +793,9 @@ async function createServerPreview(config, params) {
735
793
  }
736
794
  return pollPreviewJob(cfg, "/v1/server-preview", created.job_id, ((params.timeout || 120) + 60) * 1e3, () => ({}));
737
795
  }
796
+ async function getServerPreviewStatus(config, jobId) {
797
+ return getPreviewJobStatus(config, "/v1/server-preview", jobId, () => ({}));
798
+ }
738
799
  async function createBuildPreview(config, params) {
739
800
  let cfg;
740
801
  try {
@@ -837,6 +898,14 @@ async function createBuildPreview(config, params) {
837
898
  ...statusData.audit ? { audit: statusData.audit } : {}
838
899
  }));
839
900
  }
901
+ async function getBuildPreviewStatus(config, jobId) {
902
+ return getPreviewJobStatus(config, "/v1/build-preview", jobId, (statusData) => ({
903
+ build_duration_ms: statusData.build_duration_ms,
904
+ ...statusData.build_log ? { build_log: statusData.build_log } : {},
905
+ ...statusData.container_log ? { container_log: statusData.container_log } : {},
906
+ ...statusData.audit ? { audit: statusData.audit } : {}
907
+ }));
908
+ }
840
909
 
841
910
  export {
842
911
  configFromOpenClawApi,
@@ -854,5 +923,7 @@ export {
854
923
  createStaticPreview,
855
924
  deleteStaticPreview,
856
925
  createServerPreview,
857
- createBuildPreview
926
+ getServerPreviewStatus,
927
+ createBuildPreview,
928
+ getBuildPreviewStatus
858
929
  };
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 });
@@ -525,6 +545,62 @@ async function saveImageOutputs(workspace, jobId, outputs, label) {
525
545
  }
526
546
  }
527
547
  }
548
+ async function previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras = () => ({})) {
549
+ const status = statusData?.status ?? "unknown";
550
+ const terminal = isTerminalPreviewStatus(status);
551
+ const completed = isCompletedPreviewStatus(status);
552
+ const label = pathPrefix.slice(1);
553
+ const result = {
554
+ ok: terminal ? completed : true,
555
+ terminal,
556
+ job_id: jobId,
557
+ status,
558
+ phase: statusData?.phase ?? status,
559
+ phase_updated_at: statusData?.phase_updated_at,
560
+ phase_details: statusData?.phase_details,
561
+ outputs: statusData?.outputs || [],
562
+ compute_seconds: statusData?.compute_seconds,
563
+ egress_bytes: statusData?.egress_bytes,
564
+ ...resultExtras(statusData ?? {})
565
+ };
566
+ if (!terminal) {
567
+ result.message = `Job is still ${status}. Call the status tool again later to recover artifacts when it completes.`;
568
+ }
569
+ if (statusData?.error) result.error = statusData.error;
570
+ if (statusData?.script_error) result.script_error = statusData.script_error;
571
+ if (terminal && !completed && !result.error && !result.script_error) {
572
+ result.error = `Job ended with status ${status}`;
573
+ }
574
+ await saveImageOutputs(config.workspace, jobId, result.outputs, label);
575
+ result.screenshots = result.outputs.filter((o) => /\.(png|jpg|jpeg)$/i.test(o.name));
576
+ return result;
577
+ }
578
+ async function getPreviewJobStatus(config, pathPrefix, jobId, resultExtras = () => ({})) {
579
+ let cfg;
580
+ try {
581
+ cfg = requireConfig(config);
582
+ } catch (err) {
583
+ return { ok: false, error: err.message };
584
+ }
585
+ if (!jobId || typeof jobId !== "string") {
586
+ return { ok: false, error: "job_id must be a non-empty string" };
587
+ }
588
+ const endpoint = cfg.baseUrl.replace(/\/$/, "");
589
+ let statusRes;
590
+ try {
591
+ statusRes = await fetchWithRetry(`${endpoint}${pathPrefix}/${jobId}`, {
592
+ headers: { Authorization: `Bearer ${cfg.apiKey}` }
593
+ }, PREVIEW_REQUEST_TIMEOUT_MS, `${pathPrefix.slice(1)} status`, { attempts: 2 });
594
+ } catch (e) {
595
+ return { ok: false, job_id: jobId, error: `Status failed: ${describeError(e)}` };
596
+ }
597
+ if (!statusRes.ok) {
598
+ const err = await statusRes.text().catch(() => "");
599
+ return { ok: false, job_id: jobId, error: `Status failed: HTTP ${statusRes.status}${err ? ` ${err}` : ""}` };
600
+ }
601
+ const statusData = await statusRes.json();
602
+ return previewResultFromStatusData(cfg, pathPrefix, jobId, statusData, resultExtras);
603
+ }
528
604
  async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras) {
529
605
  const endpoint = config.baseUrl.replace(/\/$/, "");
530
606
  const pollStart = Date.now();
@@ -544,24 +620,8 @@ async function pollPreviewJob(config, pathPrefix, jobId, timeoutMs, resultExtras
544
620
  }
545
621
  const statusData = await statusRes.json();
546
622
  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;
623
+ if (isTerminalPreviewStatus(statusData.status)) {
624
+ return previewResultFromStatusData(config, pathPrefix, jobId, statusData, resultExtras);
565
625
  }
566
626
  await sleep(pollIntervalMs);
567
627
  }
@@ -774,6 +834,9 @@ async function createServerPreview(config, params) {
774
834
  }
775
835
  return pollPreviewJob(cfg, "/v1/server-preview", created.job_id, ((params.timeout || 120) + 60) * 1e3, () => ({}));
776
836
  }
837
+ async function getServerPreviewStatus(config, jobId) {
838
+ return getPreviewJobStatus(config, "/v1/server-preview", jobId, () => ({}));
839
+ }
777
840
  async function createBuildPreview(config, params) {
778
841
  let cfg;
779
842
  try {
@@ -876,6 +939,14 @@ async function createBuildPreview(config, params) {
876
939
  ...statusData.audit ? { audit: statusData.audit } : {}
877
940
  }));
878
941
  }
942
+ async function getBuildPreviewStatus(config, jobId) {
943
+ return getPreviewJobStatus(config, "/v1/build-preview", jobId, (statusData) => ({
944
+ build_duration_ms: statusData.build_duration_ms,
945
+ ...statusData.build_log ? { build_log: statusData.build_log } : {},
946
+ ...statusData.container_log ? { container_log: statusData.container_log } : {},
947
+ ...statusData.audit ? { audit: statusData.audit } : {}
948
+ }));
949
+ }
879
950
  // Annotate the CommonJS export names for ESM import in node:
880
951
  0 && (module.exports = {
881
952
  applySafetySpec,
@@ -889,6 +960,8 @@ async function createBuildPreview(config, params) {
889
960
  fetchArtifactsAndBuild,
890
961
  fetchWithRetry,
891
962
  fetchWithTimeout,
963
+ getBuildPreviewStatus,
964
+ getServerPreviewStatus,
892
965
  isAlreadyStartedResponse,
893
966
  pollJobStatus,
894
967
  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-UTJTPSHW.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-UTJTPSHW.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.5",
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.5",
4
4
  "description": "OpenClaw integration package for RiddleDC (no secrets).",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",