opensteer 0.8.14 → 0.8.16
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/README.md +1 -1
- package/dist/{chunk-BRUJHMWO.js → chunk-KBO7DDPF.js} +233 -299
- package/dist/chunk-KBO7DDPF.js.map +1 -0
- package/dist/chunk-KCINASQC.js +3 -0
- package/dist/chunk-KCINASQC.js.map +1 -0
- package/dist/chunk-Y3ULLNOS.js +359 -0
- package/dist/chunk-Y3ULLNOS.js.map +1 -0
- package/dist/cli/bin.cjs +25883 -23428
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.js +133 -103
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.cjs +152 -205
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -39
- package/dist/index.d.ts +34 -39
- package/dist/index.js +3 -345
- package/dist/index.js.map +1 -1
- package/dist/opensteer-3Q3LR5XM.js +4 -0
- package/dist/opensteer-3Q3LR5XM.js.map +1 -0
- package/package.json +5 -5
- package/skills/opensteer/SKILL.md +76 -77
- package/dist/chunk-BRUJHMWO.js.map +0 -1
- package/skills/opensteer/references/cli-reference.md +0 -117
- package/skills/opensteer/references/request-workflow.md +0 -153
- package/skills/opensteer/references/sdk-reference.md +0 -158
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: opensteer
|
|
3
|
-
description: "Handles Opensteer browser automation, structured DOM extraction, and browser-backed API reverse engineering. Use when the user mentions Opensteer, browser automation, real Chromium sessions, DOM extraction, network capture,
|
|
3
|
+
description: "Handles Opensteer browser automation, structured DOM extraction, and browser-backed API reverse engineering. Use when the user mentions Opensteer, browser automation, real Chromium sessions, DOM extraction, network capture, reverse-engineering a site API, or browser-grade fetch."
|
|
4
4
|
argument-hint: "[goal]"
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ argument-hint: "[goal]"
|
|
|
9
9
|
Opensteer gives agents a real Chromium browser for two jobs normal code cannot do:
|
|
10
10
|
|
|
11
11
|
1. **DOM automation** — interact with pages and extract structured data via snapshot-based element targeting.
|
|
12
|
-
2. **API reverse engineering** — capture real browser traffic, identify APIs, test transport portability, and write
|
|
12
|
+
2. **API reverse engineering** — capture real browser traffic, identify APIs, test transport portability, and write reusable code.
|
|
13
13
|
|
|
14
14
|
The workflow is always: **explore with CLI, then write reusable code with SDK.**
|
|
15
15
|
|
|
@@ -56,7 +56,7 @@ opensteer hover 3 --workspace demo --persist "menu trigger"
|
|
|
56
56
|
opensteer scroll down 400 --workspace demo
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
`--persist <
|
|
59
|
+
`--persist <key>` saves the element's structural DOM path for deterministic SDK replay. Element number is always required on CLI — persist is save-only, not a targeting mode.
|
|
60
60
|
|
|
61
61
|
### Step 3: Extract
|
|
62
62
|
|
|
@@ -85,7 +85,7 @@ const opensteer = new Opensteer({ workspace: "demo", rootDir: process.cwd() });
|
|
|
85
85
|
try {
|
|
86
86
|
await opensteer.open("https://example.com");
|
|
87
87
|
|
|
88
|
-
// Replay by persist
|
|
88
|
+
// Replay by persist key — no element numbers or snapshots needed
|
|
89
89
|
await opensteer.input({ persist: "search input", text: "laptop", pressEnter: true });
|
|
90
90
|
await opensteer.click({ persist: "search button" });
|
|
91
91
|
|
|
@@ -122,40 +122,51 @@ opensteer network query --workspace demo --capture search --hostname api.example
|
|
|
122
122
|
|
|
123
123
|
`--json` filters to JSON and GraphQL responses only. Other filters: `--url`, `--path`, `--method`, `--status`, `--type`, `--before`, `--after`, `--limit`.
|
|
124
124
|
|
|
125
|
-
### Step 3: Inspect
|
|
125
|
+
### Step 3: Inspect and probe transport
|
|
126
126
|
|
|
127
127
|
```bash
|
|
128
128
|
opensteer network detail rec_123 --workspace demo
|
|
129
|
+
opensteer network detail rec_123 --probe --workspace demo
|
|
129
130
|
```
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
The first command shows: URL, method, request headers, cookies sent, request/response body preview, GraphQL metadata, redirect chain.
|
|
132
133
|
|
|
133
|
-
|
|
134
|
+
Add `--probe` to also test which transport works for this API:
|
|
135
|
+
|
|
136
|
+
| Transport | Meaning | SDK usage |
|
|
137
|
+
| ------------- | ------------------------------ | ----------------------------------------------- |
|
|
138
|
+
| `direct-http` | Plain HTTP works | `this.fetch(url)` (default) |
|
|
139
|
+
| `matched-tls` | Needs TLS fingerprint matching | `this.fetch(url, { transport: "matched-tls" })` |
|
|
140
|
+
| `page-http` | Needs a live browser page | `this.fetch(url, { transport: "page" })` |
|
|
141
|
+
|
|
142
|
+
### Step 4: Check browser state (if 401/403)
|
|
134
143
|
|
|
135
144
|
```bash
|
|
136
|
-
opensteer
|
|
137
|
-
opensteer replay rec_123 --workspace demo --query keyword=headphones --query count=10
|
|
145
|
+
opensteer state example.com --workspace demo
|
|
138
146
|
```
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
Look for session cookies, CSRF tokens, or storage-backed auth that the request depends on.
|
|
141
149
|
|
|
142
|
-
|
|
143
|
-
|---|---|---|
|
|
144
|
-
| `direct-http` | Plain HTTP works | `opensteer.fetch(url)` (default) |
|
|
145
|
-
| `matched-tls` | Needs TLS fingerprint matching | `opensteer.fetch(url, { transport: "matched-tls" })` |
|
|
146
|
-
| `page-http` | Needs a live browser page | `opensteer.fetch(url, { transport: "page" })` |
|
|
150
|
+
### Step 5: Test and write code with exec
|
|
147
151
|
|
|
148
|
-
|
|
152
|
+
Use `exec` to test the API call with the SDK. The code you write here is the same code that goes in your final script:
|
|
149
153
|
|
|
150
154
|
```bash
|
|
151
|
-
opensteer
|
|
152
|
-
|
|
153
|
-
|
|
155
|
+
opensteer exec "
|
|
156
|
+
const r = await this.fetch('https://api.example.com/search', {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
headers: { 'content-type': 'application/json' },
|
|
159
|
+
body: JSON.stringify({ keyword: 'laptop', count: 24 }),
|
|
160
|
+
});
|
|
161
|
+
return { status: r.status, data: await r.json() };
|
|
162
|
+
" --workspace demo
|
|
154
163
|
```
|
|
155
164
|
|
|
156
|
-
|
|
165
|
+
`exec` runs JavaScript with the Opensteer SDK bound as `this`. It supports `await` and has access to `this.fetch()`, `this.cookies()`, `this.evaluate()`, and all other SDK methods.
|
|
166
|
+
|
|
167
|
+
IMPORTANT: Use `exec` instead of `evaluate` for API calls. `evaluate` runs inside the browser page where anti-bot scripts can detect and block programmatic requests. `exec` runs through the framework's transport stack which automatically finds the least detectable path.
|
|
157
168
|
|
|
158
|
-
### Step 6: Write SDK
|
|
169
|
+
### Step 6: Write the final SDK script
|
|
159
170
|
|
|
160
171
|
```bash
|
|
161
172
|
opensteer close --workspace demo
|
|
@@ -165,31 +176,17 @@ opensteer close --workspace demo
|
|
|
165
176
|
import { Opensteer } from "opensteer";
|
|
166
177
|
const opensteer = new Opensteer({ workspace: "demo", rootDir: process.cwd() });
|
|
167
178
|
|
|
168
|
-
async function ensureSession() {
|
|
169
|
-
const cookies = await opensteer.cookies("example.com");
|
|
170
|
-
if (cookies.has("session")) return;
|
|
171
|
-
await opensteer.goto("https://example.com");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
179
|
export async function search(keyword: string) {
|
|
175
|
-
await ensureSession();
|
|
176
180
|
const response = await opensteer.fetch("https://api.example.com/search", {
|
|
177
|
-
|
|
181
|
+
method: "POST",
|
|
182
|
+
headers: { "content-type": "application/json" },
|
|
183
|
+
body: JSON.stringify({ keyword, count: 24 }),
|
|
178
184
|
});
|
|
179
185
|
return response.json();
|
|
180
186
|
}
|
|
181
187
|
```
|
|
182
188
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
```ts
|
|
186
|
-
const response = await opensteer.fetch("https://api.example.com/search", {
|
|
187
|
-
query: { keyword: "laptop" },
|
|
188
|
-
transport: "matched-tls",
|
|
189
|
-
});
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
IMPORTANT: `opensteer.fetch()` does not require opening a browser page. It works directly with the session's cookies and transport stack. Only call `opensteer.open()` or `opensteer.goto()` if you need to establish session cookies first.
|
|
189
|
+
`opensteer.fetch()` accepts standard Web Fetch API syntax (`body` as string, `headers` as `Record<string, string>`). It auto-selects the best transport and includes browser cookies by default.
|
|
193
190
|
|
|
194
191
|
---
|
|
195
192
|
|
|
@@ -244,6 +241,14 @@ opensteer tab close 2 --workspace demo
|
|
|
244
241
|
|
|
245
242
|
## Run JavaScript
|
|
246
243
|
|
|
244
|
+
Use `exec` for API calls and SDK operations (runs in Node.js, avoids bot detection):
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
opensteer exec "await this.fetch('https://api.example.com/data').then(r => r.json())" --workspace demo
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Use `evaluate` only for DOM inspection (runs inside the browser page):
|
|
251
|
+
|
|
247
252
|
```bash
|
|
248
253
|
opensteer evaluate "document.title" --workspace demo
|
|
249
254
|
```
|
|
@@ -264,28 +269,26 @@ opensteer computer screenshot --workspace demo
|
|
|
264
269
|
|
|
265
270
|
## CLI Quick Reference
|
|
266
271
|
|
|
267
|
-
| Command
|
|
268
|
-
|
|
269
|
-
| `open <url>`
|
|
270
|
-
| `close`
|
|
271
|
-
| `status`
|
|
272
|
-
| `goto <url>`
|
|
273
|
-
| `snapshot [mode]`
|
|
274
|
-
| `click <element>`
|
|
275
|
-
| `hover <element>`
|
|
276
|
-
| `input <element> <text>`
|
|
277
|
-
| `scroll <dir> <amount>`
|
|
278
|
-
| `extract <schema>`
|
|
279
|
-
| `evaluate <script>`
|
|
280
|
-
| `network query`
|
|
281
|
-
| `network detail <id>`
|
|
282
|
-
| `
|
|
283
|
-
| `
|
|
284
|
-
| `
|
|
285
|
-
| `
|
|
286
|
-
| `
|
|
287
|
-
| `tab list / new / <n> / close` | varies | — |
|
|
288
|
-
| `computer click/type/key/scroll/move/drag/screenshot/wait` | varies | `--capture-network` |
|
|
272
|
+
| Command | Positional args | Key flags |
|
|
273
|
+
| ---------------------------------------------------------- | -------------------- | ----------------------------------------------------------------------- |
|
|
274
|
+
| `open <url>` | url | `--headless`, `--provider`, `--attach-endpoint`, `--attach-header` |
|
|
275
|
+
| `close` | — | — |
|
|
276
|
+
| `status` | — | — |
|
|
277
|
+
| `goto <url>` | url | `--capture-network` |
|
|
278
|
+
| `snapshot [mode]` | action \| extraction | — |
|
|
279
|
+
| `click <element>` | element number | `--persist`, `--capture-network`, `--button` |
|
|
280
|
+
| `hover <element>` | element number | `--persist`, `--capture-network` |
|
|
281
|
+
| `input <element> <text>` | element, text | `--persist`, `--press-enter`, `--capture-network` |
|
|
282
|
+
| `scroll <dir> <amount>` | direction, amount | `--element`, `--persist`, `--capture-network` |
|
|
283
|
+
| `extract <schema>` | JSON schema | `--persist` |
|
|
284
|
+
| `evaluate <script>` | JS expression | — |
|
|
285
|
+
| `network query` | — | `--capture`, `--url`, `--hostname`, `--json`, `--limit`, +6 filters |
|
|
286
|
+
| `network detail <id>` | recordId | `--probe` |
|
|
287
|
+
| `fetch <url>` | url | `--method`, `--header`, `--query`, `--body`, `--transport`, `--cookies` |
|
|
288
|
+
| `state [domain]` | domain (optional) | — |
|
|
289
|
+
| `exec <expression>` | JS expression | — |
|
|
290
|
+
| `tab list / new / <n> / close` | varies | — |
|
|
291
|
+
| `computer click/type/key/scroll/move/drag/screenshot/wait` | varies | `--capture-network` |
|
|
289
292
|
|
|
290
293
|
## SDK Quick Reference
|
|
291
294
|
|
|
@@ -312,20 +315,16 @@ await opensteer.extract({ persist: "name", schema: { ... } }); // inline schem
|
|
|
312
315
|
// Network discovery
|
|
313
316
|
const records = await opensteer.network.query({ capture: "label", limit: 20 });
|
|
314
317
|
const detail = await opensteer.network.detail(recordId);
|
|
315
|
-
const replay = await opensteer.network.replay(recordId, { query: { k: "v" } });
|
|
316
318
|
|
|
317
|
-
// Fetch —
|
|
319
|
+
// Fetch — standard Web Fetch API syntax, auto-selects transport
|
|
318
320
|
const response = await opensteer.fetch(url, {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
body?: { ... },
|
|
323
|
-
transport?: "auto" | "direct" | "matched-tls" | "page",
|
|
321
|
+
method: "POST",
|
|
322
|
+
headers: { "content-type": "application/json" },
|
|
323
|
+
body: JSON.stringify({ keyword: "laptop" }),
|
|
324
324
|
});
|
|
325
325
|
|
|
326
326
|
// Browser state
|
|
327
327
|
const cookies = await opensteer.cookies("domain.com"); // .has(), .get(), .serialize()
|
|
328
|
-
const storage = await opensteer.storage("domain.com", "local");
|
|
329
328
|
const state = await opensteer.state("domain.com");
|
|
330
329
|
|
|
331
330
|
// Snapshots
|
|
@@ -337,11 +336,11 @@ const html = await opensteer.snapshot("extraction");
|
|
|
337
336
|
|
|
338
337
|
## Common Issues
|
|
339
338
|
|
|
340
|
-
| Symptom
|
|
341
|
-
|
|
342
|
-
| Element numbers wrong after navigation
|
|
343
|
-
| `
|
|
344
|
-
|
|
|
345
|
-
|
|
|
346
|
-
|
|
|
347
|
-
| `
|
|
339
|
+
| Symptom | Fix |
|
|
340
|
+
| -------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
341
|
+
| Element numbers wrong after navigation | Re-snapshot before using element numbers |
|
|
342
|
+
| `fetch()` returns 401/403 | Check `state` — request depends on session cookies or tokens |
|
|
343
|
+
| Direct HTTP blocked, browser transport works | Site uses TLS fingerprinting — use `transport: "matched-tls"` |
|
|
344
|
+
| Extract returns empty data | Element numbers changed — re-snapshot and rebuild the schema |
|
|
345
|
+
| `fetch()` fails with no session | Call `opensteer.goto(url)` first to establish cookies, then `fetch()` |
|
|
346
|
+
| Using `evaluate` for API calls | Use `exec` instead — `evaluate` runs inside the page where anti-bot scripts can intercept requests |
|