@riddledc/openclaw-riddledc 0.3.3 → 0.4.0
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 +4 -0
- package/README.md +75 -17
- package/SECURITY.md +131 -0
- package/dist/index.cjs +64 -8
- package/dist/index.js +64 -8
- package/openclaw.plugin.json +43 -2
- package/package.json +8 -4
package/CHECKSUMS.txt
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
008b101829a770aab04361a6432304b6fe7edf4173fed1185339d6f53969b418 dist/index.cjs
|
|
2
|
+
94ce04f0e2d84bf64dd68f0500dfdd2f951287a3deccec87f197261961927f6f dist/index.d.cts
|
|
3
|
+
94ce04f0e2d84bf64dd68f0500dfdd2f951287a3deccec87f197261961927f6f dist/index.d.ts
|
|
4
|
+
52e59ee4fd2c37fd503c9e52add79ef76e5959fdef1d0c5e191b132eba4027db dist/index.js
|
package/README.md
CHANGED
|
@@ -1,34 +1,92 @@
|
|
|
1
1
|
# @riddledc/openclaw-riddledc
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@riddledc/openclaw-riddledc)
|
|
4
|
+
[](https://github.com/riddledc/integrations/actions)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
OpenClaw plugin for [Riddle](https://riddledc.com) - hosted browser automation API. Take screenshots, run Playwright scripts, and automate web interactions from your OpenClaw agent.
|
|
4
8
|
|
|
5
9
|
## Install
|
|
6
10
|
|
|
7
|
-
```
|
|
11
|
+
```bash
|
|
12
|
+
# 1. Install the plugin
|
|
8
13
|
openclaw plugins install @riddledc/openclaw-riddledc
|
|
9
|
-
|
|
14
|
+
|
|
15
|
+
# 2. Add to allowlist and enable
|
|
16
|
+
openclaw config set plugins.allow --json '["discord","telegram","memory-core","openclaw-riddledc"]'
|
|
17
|
+
openclaw config set tools.alsoAllow --json '["openclaw-riddledc"]'
|
|
18
|
+
|
|
19
|
+
# 3. Set your API key
|
|
20
|
+
openclaw config set plugins.entries.openclaw-riddledc.config.apiKey "YOUR_RIDDLE_API_KEY"
|
|
21
|
+
|
|
22
|
+
# 4. Restart gateway
|
|
23
|
+
openclaw gateway restart
|
|
24
|
+
# Or if using systemd: systemctl restart openclaw-gateway
|
|
10
25
|
```
|
|
11
26
|
|
|
12
|
-
|
|
27
|
+
Get your API key at [riddledc.com](https://riddledc.com).
|
|
13
28
|
|
|
14
|
-
|
|
29
|
+
## Tools
|
|
15
30
|
|
|
16
|
-
|
|
31
|
+
| Tool | Description |
|
|
32
|
+
|------|-------------|
|
|
33
|
+
| `riddle_screenshot` | Take a screenshot of a single URL |
|
|
34
|
+
| `riddle_screenshots` | Take screenshots of multiple URLs in one job |
|
|
35
|
+
| `riddle_steps` | Run a workflow using steps (goto/click/fill/etc.) |
|
|
36
|
+
| `riddle_script` | Run full Playwright code |
|
|
37
|
+
| `riddle_run` | Low-level pass-through to the Riddle API |
|
|
17
38
|
|
|
18
|
-
|
|
39
|
+
All tools return screenshots + console logs by default. Pass `include: ["har"]` to also capture network traffic.
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
- `apiKey` (or `RIDDLE_API_KEY` env var)
|
|
22
|
-
- `baseUrl` (defaults to `https://api.riddledc.com`)
|
|
41
|
+
## How It Works
|
|
23
42
|
|
|
24
|
-
|
|
43
|
+
Screenshots are automatically saved to `~/.openclaw/workspace/riddle/screenshots/` and the tool returns a file reference instead of inline base64. This keeps agent context small and prevents token overflow.
|
|
44
|
+
|
|
45
|
+
Example response:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"ok": true,
|
|
49
|
+
"job_id": "job_abc123",
|
|
50
|
+
"screenshot": { "saved": "riddle/screenshots/job_abc123.png", "sizeBytes": 45000 },
|
|
51
|
+
"console": []
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
25
56
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- `riddle_script`
|
|
57
|
+
| Option | Description |
|
|
58
|
+
|--------|-------------|
|
|
59
|
+
| `apiKey` | Your Riddle API key (or set `RIDDLE_API_KEY` env var) |
|
|
60
|
+
| `baseUrl` | API endpoint (defaults to `https://api.riddledc.com`) |
|
|
31
61
|
|
|
32
62
|
## Security
|
|
33
63
|
|
|
34
|
-
|
|
64
|
+
- **Capability manifest**: See `openclaw.plugin.json` for declared permissions
|
|
65
|
+
- **Network**: Only communicates with `api.riddledc.com` (hardcoded allowlist)
|
|
66
|
+
- **Context**: No access to conversation history, other tools, or user profile
|
|
67
|
+
- **Filesystem**: Only writes to `~/.openclaw/workspace/riddle/`
|
|
68
|
+
- **Secrets**: Only requires `RIDDLE_API_KEY` (use env var, not config file)
|
|
69
|
+
|
|
70
|
+
For defense in depth, run your agent with sandboxing:
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
agents:
|
|
74
|
+
defaults:
|
|
75
|
+
sandbox: true
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
See [SECURITY.md](./SECURITY.md) for full threat model, data flow diagram, and capability details.
|
|
79
|
+
|
|
80
|
+
## Reproducible Builds
|
|
81
|
+
|
|
82
|
+
To verify a build matches the published package:
|
|
83
|
+
|
|
84
|
+
1. Clone the repo at the tagged version
|
|
85
|
+
2. Run: `pnpm install && pnpm build`
|
|
86
|
+
3. Compare checksums: `shasum -a 256 dist/*`
|
|
87
|
+
|
|
88
|
+
Expected checksums are in `CHECKSUMS.txt`.
|
|
89
|
+
|
|
90
|
+
## License
|
|
91
|
+
|
|
92
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Security Model
|
|
2
|
+
|
|
3
|
+
## Plugin vs Skill: What This Is
|
|
4
|
+
|
|
5
|
+
This is a **plugin** (code), not a **skill** (prompt). Understanding the difference matters for trust:
|
|
6
|
+
|
|
7
|
+
| Type | What it is | Trust implications |
|
|
8
|
+
|------|------------|-------------------|
|
|
9
|
+
| **Plugin** | Node.js code that runs in-process with OpenClaw | Has full process privileges; can access env vars, filesystem, network |
|
|
10
|
+
| **Skill** | Markdown/prompt instructions that guide the LLM | No direct system access; influences agent via tool invocation |
|
|
11
|
+
|
|
12
|
+
**This package is a plugin.** It runs as code inside the OpenClaw process. That means:
|
|
13
|
+
|
|
14
|
+
- It *could* read any env var, file, or make any network call (plugins are trusted code)
|
|
15
|
+
- We *choose* to constrain ourselves via hardcoded allowlists and explicit capability limits
|
|
16
|
+
- You should audit the source or trust the npm provenance
|
|
17
|
+
|
|
18
|
+
**This plugin does NOT bundle any skills.** It only provides tools. No prompt instructions are injected into your agent's context.
|
|
19
|
+
|
|
20
|
+
## Data Flow
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
┌─────────────────┐ HTTPS only ┌──────────────────┐
|
|
24
|
+
│ OpenClaw Agent │ ──────────────────► │ api.riddledc.com │
|
|
25
|
+
│ │ POST /v1/run │ │
|
|
26
|
+
│ - RIDDLE_API_KEY │ - Runs browser │
|
|
27
|
+
│ - User prompts │ ◄────────────────── │ - Returns data │
|
|
28
|
+
└─────────────────┘ JSON response └──────────────────┘
|
|
29
|
+
│
|
|
30
|
+
▼
|
|
31
|
+
┌─────────────────┐
|
|
32
|
+
│ Local Workspace │
|
|
33
|
+
│ ~/.openclaw/ │
|
|
34
|
+
│ workspace/riddle│ Screenshots saved
|
|
35
|
+
│ /screenshots/ │ as files (not inline)
|
|
36
|
+
└─────────────────┘
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## What This Plugin CAN Do
|
|
40
|
+
|
|
41
|
+
- Send requests to api.riddledc.com (hardcoded, cannot be changed)
|
|
42
|
+
- Read your RIDDLE_API_KEY from config or environment
|
|
43
|
+
- Write screenshot/HAR files to your workspace directory
|
|
44
|
+
- Execute Playwright scripts on Riddle's remote browser
|
|
45
|
+
|
|
46
|
+
## What This Plugin CANNOT Do
|
|
47
|
+
|
|
48
|
+
- Send your API key to any other domain (blocked by `assertAllowedBaseUrl`)
|
|
49
|
+
- Access your filesystem outside the workspace directory
|
|
50
|
+
- Make network requests to arbitrary URLs from your machine
|
|
51
|
+
- Run code locally (all execution happens on Riddle's servers)
|
|
52
|
+
|
|
53
|
+
## Agent Context Access
|
|
54
|
+
|
|
55
|
+
This plugin has **no access** to:
|
|
56
|
+
|
|
57
|
+
| Context | Access |
|
|
58
|
+
|---------|--------|
|
|
59
|
+
| Conversation history | ❌ None |
|
|
60
|
+
| Other tools' outputs | ❌ None |
|
|
61
|
+
| User profile / preferences | ❌ None |
|
|
62
|
+
| Other plugins' data | ❌ None |
|
|
63
|
+
| System environment (except RIDDLE_API_KEY) | ❌ None |
|
|
64
|
+
|
|
65
|
+
The plugin only sees data explicitly passed to its tools by the agent. It does not hook into message events, read logs, or access the agent's memory/context.
|
|
66
|
+
|
|
67
|
+
## Capability Manifest
|
|
68
|
+
|
|
69
|
+
This plugin declares its capabilities in `openclaw.plugin.json`. Key constraints:
|
|
70
|
+
|
|
71
|
+
- **Network egress**: Only `api.riddledc.com` (hardcoded, enforced at runtime)
|
|
72
|
+
- **Filesystem**: Write only to `~/.openclaw/workspace/riddle/`
|
|
73
|
+
- **Tools**: Provides 5 tools; invokes no other agent tools
|
|
74
|
+
- **Secrets**: Only `RIDDLE_API_KEY` required
|
|
75
|
+
|
|
76
|
+
## Security Controls
|
|
77
|
+
|
|
78
|
+
### 1. Hardcoded Domain Allowlist
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
function assertAllowedBaseUrl(baseUrl: string) {
|
|
82
|
+
const url = new URL(baseUrl);
|
|
83
|
+
if (url.protocol !== "https:")
|
|
84
|
+
throw new Error(`Riddle baseUrl must be https`);
|
|
85
|
+
if (url.hostname !== "api.riddledc.com")
|
|
86
|
+
throw new Error(`Refusing to use non-official Riddle host`);
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This runs on EVERY request. Even if config is manipulated, keys never leave riddledc.com.
|
|
91
|
+
|
|
92
|
+
### 2. No Inline Base64
|
|
93
|
+
|
|
94
|
+
Screenshots are saved to disk, not returned inline. This prevents:
|
|
95
|
+
|
|
96
|
+
- Context overflow attacks
|
|
97
|
+
- Memory exhaustion
|
|
98
|
+
- Accidental key leakage in logs
|
|
99
|
+
|
|
100
|
+
### 3. Minimal Permissions
|
|
101
|
+
|
|
102
|
+
Only requires one secret: `RIDDLE_API_KEY`. No OAuth, no cookies, no session state.
|
|
103
|
+
|
|
104
|
+
## Threat Model
|
|
105
|
+
|
|
106
|
+
| Threat | Mitigation |
|
|
107
|
+
|--------|------------|
|
|
108
|
+
| API key exfiltration to attacker server | Hardcoded domain check blocks all non-riddledc.com requests |
|
|
109
|
+
| Malicious config injection | Domain check runs at request time, not config time |
|
|
110
|
+
| Supply chain attack (npm) | npm provenance + checksums + reproducible builds |
|
|
111
|
+
| Build tampering | CHECKSUMS.txt with SHA256 hashes |
|
|
112
|
+
| Local file access | Plugin only writes to designated workspace subdirectory |
|
|
113
|
+
| Context/conversation leakage | Plugin has no access to agent context (see above) |
|
|
114
|
+
| Prompt injection via tool output | Screenshots saved as file refs, not inline content |
|
|
115
|
+
|
|
116
|
+
## Recommended: Run in Sandbox
|
|
117
|
+
|
|
118
|
+
For defense in depth, consider running your agent with sandboxing enabled:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
# In your OpenClaw config
|
|
122
|
+
agents:
|
|
123
|
+
defaults:
|
|
124
|
+
sandbox: true
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This runs tools like `exec` in a Docker container, limiting blast radius if any plugin or skill misbehaves. While this plugin doesn't require sandboxing (it only calls a remote API), sandboxing protects against other plugins or prompt injection attacks.
|
|
128
|
+
|
|
129
|
+
## Reporting Security Issues
|
|
130
|
+
|
|
131
|
+
Email: security@riddledc.com
|
package/dist/index.cjs
CHANGED
|
@@ -221,10 +221,20 @@ function register(api) {
|
|
|
221
221
|
api.registerTool(
|
|
222
222
|
{
|
|
223
223
|
name: "riddle_screenshot",
|
|
224
|
-
description: 'Riddle: take a screenshot of a single URL. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
224
|
+
description: 'Riddle: take a screenshot of a single URL. Supports authenticated screenshots via cookies/localStorage. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
225
225
|
parameters: import_typebox.Type.Object({
|
|
226
226
|
url: import_typebox.Type.String(),
|
|
227
227
|
timeout_sec: import_typebox.Type.Optional(import_typebox.Type.Number()),
|
|
228
|
+
cookies: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.Object({
|
|
229
|
+
name: import_typebox.Type.String(),
|
|
230
|
+
value: import_typebox.Type.String(),
|
|
231
|
+
domain: import_typebox.Type.String(),
|
|
232
|
+
path: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
233
|
+
secure: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
234
|
+
httpOnly: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
235
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
236
|
+
localStorage: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
237
|
+
headers: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "HTTP headers to send with requests" })),
|
|
228
238
|
options: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.Any())),
|
|
229
239
|
include: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.String())),
|
|
230
240
|
harInline: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
@@ -233,7 +243,11 @@ function register(api) {
|
|
|
233
243
|
if (!params.url || typeof params.url !== "string") throw new Error("url must be a string");
|
|
234
244
|
const payload = { url: params.url };
|
|
235
245
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
236
|
-
|
|
246
|
+
const opts = { ...params.options || {} };
|
|
247
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
248
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
249
|
+
if (params.headers) opts.headers = params.headers;
|
|
250
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
237
251
|
if (params.include) payload.include = params.include;
|
|
238
252
|
if (params.harInline) payload.harInline = params.harInline;
|
|
239
253
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console"] });
|
|
@@ -245,10 +259,20 @@ function register(api) {
|
|
|
245
259
|
api.registerTool(
|
|
246
260
|
{
|
|
247
261
|
name: "riddle_screenshots",
|
|
248
|
-
description: 'Riddle: take screenshots for multiple URLs in one job. Returns screenshots + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
262
|
+
description: 'Riddle: take screenshots for multiple URLs in one job. Supports authenticated sessions via cookies/localStorage (shared across all URLs). Returns screenshots + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
249
263
|
parameters: import_typebox.Type.Object({
|
|
250
264
|
urls: import_typebox.Type.Array(import_typebox.Type.String()),
|
|
251
265
|
timeout_sec: import_typebox.Type.Optional(import_typebox.Type.Number()),
|
|
266
|
+
cookies: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.Object({
|
|
267
|
+
name: import_typebox.Type.String(),
|
|
268
|
+
value: import_typebox.Type.String(),
|
|
269
|
+
domain: import_typebox.Type.String(),
|
|
270
|
+
path: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
271
|
+
secure: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
272
|
+
httpOnly: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
273
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
274
|
+
localStorage: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
275
|
+
headers: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "HTTP headers to send with requests" })),
|
|
252
276
|
options: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.Any())),
|
|
253
277
|
include: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.String())),
|
|
254
278
|
harInline: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
@@ -259,7 +283,11 @@ function register(api) {
|
|
|
259
283
|
}
|
|
260
284
|
const payload = { urls: params.urls };
|
|
261
285
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
262
|
-
|
|
286
|
+
const opts = { ...params.options || {} };
|
|
287
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
288
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
289
|
+
if (params.headers) opts.headers = params.headers;
|
|
290
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
263
291
|
if (params.include) payload.include = params.include;
|
|
264
292
|
if (params.harInline) payload.harInline = params.harInline;
|
|
265
293
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console"] });
|
|
@@ -271,10 +299,20 @@ function register(api) {
|
|
|
271
299
|
api.registerTool(
|
|
272
300
|
{
|
|
273
301
|
name: "riddle_steps",
|
|
274
|
-
description: 'Riddle: run a workflow in steps mode (goto/click/fill/etc.). Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
302
|
+
description: 'Riddle: run a workflow in steps mode (goto/click/fill/etc.). Supports authenticated sessions via cookies/localStorage. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
275
303
|
parameters: import_typebox.Type.Object({
|
|
276
304
|
steps: import_typebox.Type.Array(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.Any())),
|
|
277
305
|
timeout_sec: import_typebox.Type.Optional(import_typebox.Type.Number()),
|
|
306
|
+
cookies: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.Object({
|
|
307
|
+
name: import_typebox.Type.String(),
|
|
308
|
+
value: import_typebox.Type.String(),
|
|
309
|
+
domain: import_typebox.Type.String(),
|
|
310
|
+
path: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
311
|
+
secure: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
312
|
+
httpOnly: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
313
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
314
|
+
localStorage: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
315
|
+
headers: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "HTTP headers to send with requests" })),
|
|
278
316
|
options: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.Any())),
|
|
279
317
|
include: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.String())),
|
|
280
318
|
harInline: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
@@ -285,7 +323,11 @@ function register(api) {
|
|
|
285
323
|
const payload = { steps: params.steps };
|
|
286
324
|
if (typeof params.sync === "boolean") payload.sync = params.sync;
|
|
287
325
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
288
|
-
|
|
326
|
+
const opts = { ...params.options || {} };
|
|
327
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
328
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
329
|
+
if (params.headers) opts.headers = params.headers;
|
|
330
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
289
331
|
if (params.include) payload.include = params.include;
|
|
290
332
|
if (params.harInline) payload.harInline = params.harInline;
|
|
291
333
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console", "result"] });
|
|
@@ -297,10 +339,20 @@ function register(api) {
|
|
|
297
339
|
api.registerTool(
|
|
298
340
|
{
|
|
299
341
|
name: "riddle_script",
|
|
300
|
-
description: 'Riddle: run full Playwright code (script mode). Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
342
|
+
description: 'Riddle: run full Playwright code (script mode). Supports authenticated sessions via cookies/localStorage. In scripts, use `await injectLocalStorage()` after navigating to the origin to apply localStorage values. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
301
343
|
parameters: import_typebox.Type.Object({
|
|
302
344
|
script: import_typebox.Type.String(),
|
|
303
345
|
timeout_sec: import_typebox.Type.Optional(import_typebox.Type.Number()),
|
|
346
|
+
cookies: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.Object({
|
|
347
|
+
name: import_typebox.Type.String(),
|
|
348
|
+
value: import_typebox.Type.String(),
|
|
349
|
+
domain: import_typebox.Type.String(),
|
|
350
|
+
path: import_typebox.Type.Optional(import_typebox.Type.String()),
|
|
351
|
+
secure: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
352
|
+
httpOnly: import_typebox.Type.Optional(import_typebox.Type.Boolean())
|
|
353
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
354
|
+
localStorage: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "localStorage key-value pairs; use injectLocalStorage() in script after goto to apply" })),
|
|
355
|
+
headers: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.String(), { description: "HTTP headers to send with requests" })),
|
|
304
356
|
options: import_typebox.Type.Optional(import_typebox.Type.Record(import_typebox.Type.String(), import_typebox.Type.Any())),
|
|
305
357
|
include: import_typebox.Type.Optional(import_typebox.Type.Array(import_typebox.Type.String())),
|
|
306
358
|
harInline: import_typebox.Type.Optional(import_typebox.Type.Boolean()),
|
|
@@ -311,7 +363,11 @@ function register(api) {
|
|
|
311
363
|
const payload = { script: params.script };
|
|
312
364
|
if (typeof params.sync === "boolean") payload.sync = params.sync;
|
|
313
365
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
314
|
-
|
|
366
|
+
const opts = { ...params.options || {} };
|
|
367
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
368
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
369
|
+
if (params.headers) opts.headers = params.headers;
|
|
370
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
315
371
|
if (params.include) payload.include = params.include;
|
|
316
372
|
if (params.harInline) payload.harInline = params.harInline;
|
|
317
373
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console", "result"] });
|
package/dist/index.js
CHANGED
|
@@ -197,10 +197,20 @@ function register(api) {
|
|
|
197
197
|
api.registerTool(
|
|
198
198
|
{
|
|
199
199
|
name: "riddle_screenshot",
|
|
200
|
-
description: 'Riddle: take a screenshot of a single URL. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
200
|
+
description: 'Riddle: take a screenshot of a single URL. Supports authenticated screenshots via cookies/localStorage. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
201
201
|
parameters: Type.Object({
|
|
202
202
|
url: Type.String(),
|
|
203
203
|
timeout_sec: Type.Optional(Type.Number()),
|
|
204
|
+
cookies: Type.Optional(Type.Array(Type.Object({
|
|
205
|
+
name: Type.String(),
|
|
206
|
+
value: Type.String(),
|
|
207
|
+
domain: Type.String(),
|
|
208
|
+
path: Type.Optional(Type.String()),
|
|
209
|
+
secure: Type.Optional(Type.Boolean()),
|
|
210
|
+
httpOnly: Type.Optional(Type.Boolean())
|
|
211
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
212
|
+
localStorage: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
213
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "HTTP headers to send with requests" })),
|
|
204
214
|
options: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
205
215
|
include: Type.Optional(Type.Array(Type.String())),
|
|
206
216
|
harInline: Type.Optional(Type.Boolean())
|
|
@@ -209,7 +219,11 @@ function register(api) {
|
|
|
209
219
|
if (!params.url || typeof params.url !== "string") throw new Error("url must be a string");
|
|
210
220
|
const payload = { url: params.url };
|
|
211
221
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
212
|
-
|
|
222
|
+
const opts = { ...params.options || {} };
|
|
223
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
224
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
225
|
+
if (params.headers) opts.headers = params.headers;
|
|
226
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
213
227
|
if (params.include) payload.include = params.include;
|
|
214
228
|
if (params.harInline) payload.harInline = params.harInline;
|
|
215
229
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console"] });
|
|
@@ -221,10 +235,20 @@ function register(api) {
|
|
|
221
235
|
api.registerTool(
|
|
222
236
|
{
|
|
223
237
|
name: "riddle_screenshots",
|
|
224
|
-
description: 'Riddle: take screenshots for multiple URLs in one job. Returns screenshots + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
238
|
+
description: 'Riddle: take screenshots for multiple URLs in one job. Supports authenticated sessions via cookies/localStorage (shared across all URLs). Returns screenshots + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
225
239
|
parameters: Type.Object({
|
|
226
240
|
urls: Type.Array(Type.String()),
|
|
227
241
|
timeout_sec: Type.Optional(Type.Number()),
|
|
242
|
+
cookies: Type.Optional(Type.Array(Type.Object({
|
|
243
|
+
name: Type.String(),
|
|
244
|
+
value: Type.String(),
|
|
245
|
+
domain: Type.String(),
|
|
246
|
+
path: Type.Optional(Type.String()),
|
|
247
|
+
secure: Type.Optional(Type.Boolean()),
|
|
248
|
+
httpOnly: Type.Optional(Type.Boolean())
|
|
249
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
250
|
+
localStorage: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
251
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "HTTP headers to send with requests" })),
|
|
228
252
|
options: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
229
253
|
include: Type.Optional(Type.Array(Type.String())),
|
|
230
254
|
harInline: Type.Optional(Type.Boolean())
|
|
@@ -235,7 +259,11 @@ function register(api) {
|
|
|
235
259
|
}
|
|
236
260
|
const payload = { urls: params.urls };
|
|
237
261
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
238
|
-
|
|
262
|
+
const opts = { ...params.options || {} };
|
|
263
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
264
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
265
|
+
if (params.headers) opts.headers = params.headers;
|
|
266
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
239
267
|
if (params.include) payload.include = params.include;
|
|
240
268
|
if (params.harInline) payload.harInline = params.harInline;
|
|
241
269
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console"] });
|
|
@@ -247,10 +275,20 @@ function register(api) {
|
|
|
247
275
|
api.registerTool(
|
|
248
276
|
{
|
|
249
277
|
name: "riddle_steps",
|
|
250
|
-
description: 'Riddle: run a workflow in steps mode (goto/click/fill/etc.). Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
278
|
+
description: 'Riddle: run a workflow in steps mode (goto/click/fill/etc.). Supports authenticated sessions via cookies/localStorage. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
251
279
|
parameters: Type.Object({
|
|
252
280
|
steps: Type.Array(Type.Record(Type.String(), Type.Any())),
|
|
253
281
|
timeout_sec: Type.Optional(Type.Number()),
|
|
282
|
+
cookies: Type.Optional(Type.Array(Type.Object({
|
|
283
|
+
name: Type.String(),
|
|
284
|
+
value: Type.String(),
|
|
285
|
+
domain: Type.String(),
|
|
286
|
+
path: Type.Optional(Type.String()),
|
|
287
|
+
secure: Type.Optional(Type.Boolean()),
|
|
288
|
+
httpOnly: Type.Optional(Type.Boolean())
|
|
289
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
290
|
+
localStorage: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "localStorage key-value pairs to inject (e.g., JWT tokens)" })),
|
|
291
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "HTTP headers to send with requests" })),
|
|
254
292
|
options: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
255
293
|
include: Type.Optional(Type.Array(Type.String())),
|
|
256
294
|
harInline: Type.Optional(Type.Boolean()),
|
|
@@ -261,7 +299,11 @@ function register(api) {
|
|
|
261
299
|
const payload = { steps: params.steps };
|
|
262
300
|
if (typeof params.sync === "boolean") payload.sync = params.sync;
|
|
263
301
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
264
|
-
|
|
302
|
+
const opts = { ...params.options || {} };
|
|
303
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
304
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
305
|
+
if (params.headers) opts.headers = params.headers;
|
|
306
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
265
307
|
if (params.include) payload.include = params.include;
|
|
266
308
|
if (params.harInline) payload.harInline = params.harInline;
|
|
267
309
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console", "result"] });
|
|
@@ -273,10 +315,20 @@ function register(api) {
|
|
|
273
315
|
api.registerTool(
|
|
274
316
|
{
|
|
275
317
|
name: "riddle_script",
|
|
276
|
-
description: 'Riddle: run full Playwright code (script mode). Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
318
|
+
description: 'Riddle: run full Playwright code (script mode). Supports authenticated sessions via cookies/localStorage. In scripts, use `await injectLocalStorage()` after navigating to the origin to apply localStorage values. Returns screenshot + console by default; pass include:["har"] to opt in to HAR capture.',
|
|
277
319
|
parameters: Type.Object({
|
|
278
320
|
script: Type.String(),
|
|
279
321
|
timeout_sec: Type.Optional(Type.Number()),
|
|
322
|
+
cookies: Type.Optional(Type.Array(Type.Object({
|
|
323
|
+
name: Type.String(),
|
|
324
|
+
value: Type.String(),
|
|
325
|
+
domain: Type.String(),
|
|
326
|
+
path: Type.Optional(Type.String()),
|
|
327
|
+
secure: Type.Optional(Type.Boolean()),
|
|
328
|
+
httpOnly: Type.Optional(Type.Boolean())
|
|
329
|
+
}), { description: "Cookies to inject for authenticated sessions" })),
|
|
330
|
+
localStorage: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "localStorage key-value pairs; use injectLocalStorage() in script after goto to apply" })),
|
|
331
|
+
headers: Type.Optional(Type.Record(Type.String(), Type.String(), { description: "HTTP headers to send with requests" })),
|
|
280
332
|
options: Type.Optional(Type.Record(Type.String(), Type.Any())),
|
|
281
333
|
include: Type.Optional(Type.Array(Type.String())),
|
|
282
334
|
harInline: Type.Optional(Type.Boolean()),
|
|
@@ -287,7 +339,11 @@ function register(api) {
|
|
|
287
339
|
const payload = { script: params.script };
|
|
288
340
|
if (typeof params.sync === "boolean") payload.sync = params.sync;
|
|
289
341
|
if (params.timeout_sec) payload.timeout_sec = params.timeout_sec;
|
|
290
|
-
|
|
342
|
+
const opts = { ...params.options || {} };
|
|
343
|
+
if (params.cookies) opts.cookies = params.cookies;
|
|
344
|
+
if (params.localStorage) opts.localStorage = params.localStorage;
|
|
345
|
+
if (params.headers) opts.headers = params.headers;
|
|
346
|
+
if (Object.keys(opts).length > 0) payload.options = opts;
|
|
291
347
|
if (params.include) payload.include = params.include;
|
|
292
348
|
if (params.harInline) payload.harInline = params.harInline;
|
|
293
349
|
const result = await runWithDefaults(api, payload, { include: ["screenshot", "console", "result"] });
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,8 +2,49 @@
|
|
|
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.
|
|
6
|
-
"notes": "0.3.
|
|
5
|
+
"version": "0.4.0",
|
|
6
|
+
"notes": "0.3.4: Added capability manifest, npm provenance, checksums, SECURITY.md.",
|
|
7
|
+
"type": "plugin",
|
|
8
|
+
"bundledSkills": [],
|
|
9
|
+
"capabilities": {
|
|
10
|
+
"network": {
|
|
11
|
+
"egress": [
|
|
12
|
+
"api.riddledc.com"
|
|
13
|
+
],
|
|
14
|
+
"enforced": true,
|
|
15
|
+
"note": "Hardcoded allowlist in assertAllowedBaseUrl() - cannot be overridden by config"
|
|
16
|
+
},
|
|
17
|
+
"filesystem": {
|
|
18
|
+
"write": [
|
|
19
|
+
"~/.openclaw/workspace/riddle/"
|
|
20
|
+
],
|
|
21
|
+
"read": []
|
|
22
|
+
},
|
|
23
|
+
"agentContext": {
|
|
24
|
+
"conversationHistory": false,
|
|
25
|
+
"otherToolOutputs": false,
|
|
26
|
+
"userProfile": false,
|
|
27
|
+
"note": "Plugin only sees data explicitly passed to its tools"
|
|
28
|
+
},
|
|
29
|
+
"tools": {
|
|
30
|
+
"provides": [
|
|
31
|
+
"riddle_screenshot",
|
|
32
|
+
"riddle_screenshots",
|
|
33
|
+
"riddle_steps",
|
|
34
|
+
"riddle_script",
|
|
35
|
+
"riddle_run"
|
|
36
|
+
],
|
|
37
|
+
"invokes": [],
|
|
38
|
+
"note": "Provides tools for agent use; does not invoke other agent tools"
|
|
39
|
+
},
|
|
40
|
+
"secrets": {
|
|
41
|
+
"required": [
|
|
42
|
+
"RIDDLE_API_KEY"
|
|
43
|
+
],
|
|
44
|
+
"optional": [],
|
|
45
|
+
"note": "Key only sent to api.riddledc.com (enforced)"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
7
48
|
"configSchema": {
|
|
8
49
|
"type": "object",
|
|
9
50
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riddledc/openclaw-riddledc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "OpenClaw integration package for RiddleDC (no secrets).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "RiddleDC",
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
|
-
"openclaw.plugin.json"
|
|
25
|
+
"openclaw.plugin.json",
|
|
26
|
+
"CHECKSUMS.txt",
|
|
27
|
+
"SECURITY.md",
|
|
28
|
+
"LICENSE"
|
|
26
29
|
],
|
|
27
30
|
"sideEffects": false,
|
|
28
31
|
"engines": {
|
|
@@ -42,10 +45,11 @@
|
|
|
42
45
|
"typescript": "^5.4.5"
|
|
43
46
|
},
|
|
44
47
|
"scripts": {
|
|
45
|
-
"build": "tsup src/index.ts --format cjs,esm --dts --out-dir dist",
|
|
48
|
+
"build": "npm run sync:openclaw-plugin-version && tsup src/index.ts --format cjs,esm --dts --out-dir dist",
|
|
46
49
|
"clean": "rm -rf dist",
|
|
47
50
|
"lint": "echo 'lint: (not configured)'",
|
|
48
51
|
"test": "echo 'test: (not configured)'",
|
|
49
|
-
"sync:openclaw-plugin-version": "node scripts/sync-openclaw-plugin-version.mjs"
|
|
52
|
+
"sync:openclaw-plugin-version": "node scripts/sync-openclaw-plugin-version.mjs",
|
|
53
|
+
"checksums": "node scripts/generate-checksums.mjs"
|
|
50
54
|
}
|
|
51
55
|
}
|