@riddledc/openclaw-riddledc 0.9.2 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ configFromOpenClawApi,
3
+ createStaticPreview,
4
+ deleteStaticPreview
5
+ } from "./chunk-SNGACMAL.js";
6
+
1
7
  // src/index.ts
2
8
  import { Type } from "@sinclair/typebox";
3
9
  import { writeFile, mkdir, readFile, stat, rm } from "fs/promises";
@@ -126,6 +132,21 @@ async function fetchWithRetry(url, init, timeoutMs, label, opts = {}) {
126
132
  function isAlreadyStartedResponse(status, body) {
127
133
  return status === 409 && /already in status:\s*(queued|running|complete|completed)/i.test(body);
128
134
  }
135
+ function previewTimeoutToolResult(jobId, timeoutMs, lastStatusData, extras = {}) {
136
+ const lastStatus = lastStatusData?.status ?? "unknown";
137
+ const result = {
138
+ ok: false,
139
+ job_id: jobId,
140
+ status: lastStatus,
141
+ outputs: lastStatusData?.outputs || [],
142
+ compute_seconds: lastStatusData?.compute_seconds,
143
+ egress_bytes: lastStatusData?.egress_bytes,
144
+ error: `Job did not complete within ${timeoutMs / 1e3}s; last status was ${lastStatus}`,
145
+ ...extras
146
+ };
147
+ if (lastStatusData?.error) result.server_error = lastStatusData.error;
148
+ return result;
149
+ }
129
150
  async function writeArtifact(workspace, subdir, filename, content) {
130
151
  const dir = join(workspace, "riddle", subdir);
131
152
  await mkdir(dir, { recursive: true });
@@ -860,85 +881,8 @@ function register(api) {
860
881
  framework: Type.Optional(Type.String({ description: "Framework hint: 'spa' (default) or 'static'" }))
861
882
  }),
862
883
  async execute(_id, params) {
863
- const { apiKey, baseUrl } = getCfg(api);
864
- if (!apiKey) {
865
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: "Missing Riddle API key." }, null, 2) }] };
866
- }
867
- assertAllowedBaseUrl(baseUrl);
868
- const dir = params.directory;
869
- if (!dir || typeof dir !== "string") throw new Error("directory must be an absolute path");
870
- try {
871
- const st = await stat(dir);
872
- if (!st.isDirectory()) throw new Error(`Not a directory: ${dir}`);
873
- } catch (e) {
874
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Cannot access directory: ${e.message}` }, null, 2) }] };
875
- }
876
- const endpoint = baseUrl.replace(/\/$/, "");
877
- let createRes;
878
- try {
879
- createRes = await fetchWithRetry(`${endpoint}/v1/preview`, {
880
- method: "POST",
881
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
882
- body: JSON.stringify({ framework: params.framework || "spa" })
883
- }, PREVIEW_REQUEST_TIMEOUT_MS, "preview create");
884
- } catch (e) {
885
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: ${describeError(e)}` }, null, 2) }] };
886
- }
887
- if (!createRes.ok) {
888
- const err = await createRes.text();
889
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Create failed: HTTP ${createRes.status} ${err}` }, null, 2) }] };
890
- }
891
- const created = await createRes.json();
892
- const tarball = `/tmp/riddle-preview-${created.id}.tar.gz`;
893
- try {
894
- await execFile("tar", ["czf", tarball, "-C", dir, "."], { timeout: 6e4 });
895
- const tarData = await readFile(tarball);
896
- let uploadRes;
897
- try {
898
- uploadRes = await fetchWithRetry(created.upload_url, {
899
- method: "PUT",
900
- headers: { "Content-Type": "application/gzip" },
901
- body: tarData
902
- }, PREVIEW_UPLOAD_TIMEOUT_MS, "preview upload");
903
- } catch (e) {
904
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Upload failed: ${describeError(e)}` }, null, 2) }] };
905
- }
906
- if (!uploadRes.ok) {
907
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Upload failed: HTTP ${uploadRes.status}` }, null, 2) }] };
908
- }
909
- } finally {
910
- try {
911
- await rm(tarball, { force: true });
912
- } catch {
913
- }
914
- }
915
- let publishRes;
916
- try {
917
- publishRes = await fetchWithTimeout(`${endpoint}/v1/preview/${created.id}/publish`, {
918
- method: "POST",
919
- headers: { Authorization: `Bearer ${apiKey}` }
920
- }, PREVIEW_REQUEST_TIMEOUT_MS, "preview publish");
921
- } catch (e) {
922
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Publish failed: ${describeError(e)}` }, null, 2) }] };
923
- }
924
- if (!publishRes.ok) {
925
- const err = await publishRes.text();
926
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, id: created.id, error: `Publish failed: HTTP ${publishRes.status} ${err}` }, null, 2) }] };
927
- }
928
- const published = await publishRes.json();
929
- return {
930
- content: [{
931
- type: "text",
932
- text: JSON.stringify({
933
- ok: true,
934
- id: published.id,
935
- preview_url: published.preview_url,
936
- file_count: published.file_count,
937
- total_bytes: published.total_bytes,
938
- expires_at: created.expires_at
939
- }, null, 2)
940
- }]
941
- };
884
+ const result = await createStaticPreview(configFromOpenClawApi(api), params);
885
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
942
886
  }
943
887
  },
944
888
  { optional: true }
@@ -951,26 +895,8 @@ function register(api) {
951
895
  id: Type.String({ description: "Preview ID (e.g. pv_a1b2c3d4)" })
952
896
  }),
953
897
  async execute(_id, params) {
954
- const { apiKey, baseUrl } = getCfg(api);
955
- if (!apiKey) {
956
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: "Missing Riddle API key." }, null, 2) }] };
957
- }
958
- assertAllowedBaseUrl(baseUrl);
959
- let res;
960
- try {
961
- res = await fetchWithTimeout(`${baseUrl.replace(/\/$/, "")}/v1/preview/${params.id}`, {
962
- method: "DELETE",
963
- headers: { Authorization: `Bearer ${apiKey}` }
964
- }, PREVIEW_REQUEST_TIMEOUT_MS, "preview delete");
965
- } catch (e) {
966
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Delete failed: ${describeError(e)}` }, null, 2) }] };
967
- }
968
- if (!res.ok) {
969
- const err = await res.text();
970
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, error: `Delete failed: HTTP ${res.status} ${err}` }, null, 2) }] };
971
- }
972
- const data = await res.json();
973
- return { content: [{ type: "text", text: JSON.stringify({ ok: true, deleted: true, files_removed: data.files_removed }, null, 2) }] };
898
+ const result = await deleteStaticPreview(configFromOpenClawApi(api), params.id);
899
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
974
900
  }
975
901
  },
976
902
  { optional: true }
@@ -1117,6 +1043,7 @@ function register(api) {
1117
1043
  const timeoutMs = ((params.timeout || 120) + 60) * 1e3;
1118
1044
  const pollStart = Date.now();
1119
1045
  const POLL_INTERVAL = 3e3;
1046
+ let lastStatusData = null;
1120
1047
  while (Date.now() - pollStart < timeoutMs) {
1121
1048
  let statusRes;
1122
1049
  try {
@@ -1130,6 +1057,7 @@ function register(api) {
1130
1057
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: HTTP ${statusRes.status}` }, null, 2) }] };
1131
1058
  }
1132
1059
  const statusData = await statusRes.json();
1060
+ lastStatusData = statusData;
1133
1061
  if (statusData.status === "complete" || statusData.status === "completed" || statusData.status === "failed") {
1134
1062
  const result = {
1135
1063
  ok: statusData.status === "complete" || statusData.status === "completed",
@@ -1161,7 +1089,7 @@ function register(api) {
1161
1089
  }
1162
1090
  await new Promise((r) => setTimeout(r, POLL_INTERVAL));
1163
1091
  }
1164
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Job did not complete within ${timeoutMs / 1e3}s` }, null, 2) }] };
1092
+ return { content: [{ type: "text", text: JSON.stringify(previewTimeoutToolResult(created.job_id, timeoutMs, lastStatusData), null, 2) }] };
1165
1093
  }
1166
1094
  },
1167
1095
  { optional: true }
@@ -1317,6 +1245,7 @@ function register(api) {
1317
1245
  const timeoutMs = ((params.timeout || 180) + 120) * 1e3;
1318
1246
  const pollStart = Date.now();
1319
1247
  const POLL_INTERVAL = 3e3;
1248
+ let lastStatusData = null;
1320
1249
  while (Date.now() - pollStart < timeoutMs) {
1321
1250
  let statusRes;
1322
1251
  try {
@@ -1330,6 +1259,7 @@ function register(api) {
1330
1259
  return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Poll failed: HTTP ${statusRes.status}` }, null, 2) }] };
1331
1260
  }
1332
1261
  const statusData = await statusRes.json();
1262
+ lastStatusData = statusData;
1333
1263
  if (statusData.status === "complete" || statusData.status === "completed" || statusData.status === "failed") {
1334
1264
  const result = {
1335
1265
  ok: statusData.status === "complete" || statusData.status === "completed",
@@ -1365,7 +1295,12 @@ function register(api) {
1365
1295
  }
1366
1296
  await new Promise((r) => setTimeout(r, POLL_INTERVAL));
1367
1297
  }
1368
- return { content: [{ type: "text", text: JSON.stringify({ ok: false, job_id: created.job_id, error: `Job did not complete within ${timeoutMs / 1e3}s` }, null, 2) }] };
1298
+ return { content: [{ type: "text", text: JSON.stringify(previewTimeoutToolResult(created.job_id, timeoutMs, lastStatusData, {
1299
+ build_duration_ms: lastStatusData?.build_duration_ms,
1300
+ ...lastStatusData?.build_log ? { build_log: lastStatusData.build_log } : {},
1301
+ ...lastStatusData?.container_log ? { container_log: lastStatusData.container_log } : {},
1302
+ ...lastStatusData?.audit ? { audit: lastStatusData.audit } : {}
1303
+ }), null, 2) }] };
1369
1304
  }
1370
1305
  },
1371
1306
  { optional: true }
@@ -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.2",
5
+ "version": "0.9.4",
6
6
  "notes": "0.8.0: Added riddle_build_preview for Dockerfile-based builds with image caching.",
7
7
  "type": "plugin",
8
8
  "bundledSkills": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/openclaw-riddledc",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "OpenClaw integration package for RiddleDC (no secrets).",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",
@@ -18,6 +18,11 @@
18
18
  "types": "./dist/index.d.ts",
19
19
  "import": "./dist/index.js",
20
20
  "require": "./dist/index.cjs"
21
+ },
22
+ "./core": {
23
+ "types": "./dist/core.d.ts",
24
+ "import": "./dist/core.js",
25
+ "require": "./dist/core.cjs"
21
26
  }
22
27
  },
23
28
  "files": [
@@ -45,7 +50,7 @@
45
50
  "typescript": "^5.4.5"
46
51
  },
47
52
  "scripts": {
48
- "build": "npm run sync:openclaw-plugin-version && tsup src/index.ts --format cjs,esm --dts --out-dir dist",
53
+ "build": "npm run sync:openclaw-plugin-version && tsup src/index.ts src/core.ts --format cjs,esm --dts --out-dir dist",
49
54
  "clean": "rm -rf dist",
50
55
  "lint": "echo 'lint: (not configured)'",
51
56
  "test": "echo 'test: (not configured)'",