opensteer 0.8.13 → 0.8.15
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 +147 -273
- package/dist/{chunk-BW2BH7HA.js → chunk-DFQCK2U6.js} +8377 -15604
- package/dist/chunk-DFQCK2U6.js.map +1 -0
- package/dist/cli/bin.cjs +10620 -16671
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.js +2121 -949
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.cjs +7881 -15156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +271 -686
- package/dist/index.d.ts +271 -686
- package/dist/index.js +145 -192
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/skills/opensteer/SKILL.md +317 -51
- package/skills/opensteer/references/cli-reference.md +69 -212
- package/skills/opensteer/references/request-workflow.md +95 -342
- package/skills/opensteer/references/sdk-reference.md +83 -339
- package/dist/chunk-BW2BH7HA.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,340 +1,214 @@
|
|
|
1
|
-
# Opensteer
|
|
1
|
+
# Opensteer
|
|
2
2
|
|
|
3
|
-
`opensteer` is
|
|
3
|
+
`opensteer` is a browser-backed toolkit for agents exploring websites.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- a thin JSON-first CLI
|
|
7
|
-
- a local per-session service so CLI commands can share one live browser session
|
|
8
|
-
- browser-native observation and instrumentation primitives
|
|
9
|
-
- deterministic replay through request plans, recipes, and saved evidence
|
|
10
|
-
- HTML-first snapshots, DOM action replay, computer-use actions, descriptor persistence, traces,
|
|
11
|
-
and artifacts
|
|
5
|
+
It focuses on the parts normal code cannot do reliably on its own:
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
- capture real browser traffic from real browser actions
|
|
8
|
+
- inspect captured requests without dumping huge raw payloads
|
|
9
|
+
- replay requests with browser-grade transports
|
|
10
|
+
- read browser cookies, storage, and page state
|
|
11
|
+
- turn discoveries into plain TypeScript with `session.fetch()`
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
- `Observe / Instrument`: capture network, capture scripts, add init scripts, route requests, replace scripts
|
|
17
|
-
- `Replay / Execute`: `direct-http`, `context-http`, `page-http`, reverse workflows, request plans, and recipes
|
|
13
|
+
The goal is discovery first, code second. The artifact should usually be working code, not a custom registry abstraction.
|
|
18
14
|
|
|
19
15
|
## Install
|
|
20
16
|
|
|
21
|
-
CLI:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx --yes opensteer@latest skills install
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
SDK:
|
|
28
|
-
|
|
29
17
|
```bash
|
|
30
18
|
pnpm add opensteer
|
|
31
19
|
pnpm exec playwright install chromium
|
|
32
20
|
|
|
33
21
|
# npm
|
|
34
22
|
npm install opensteer
|
|
35
|
-
|
|
36
|
-
# Optional ABP backend for `--engine abp`
|
|
37
|
-
pnpm add @opensteer/engine-abp
|
|
23
|
+
npx playwright install chromium
|
|
38
24
|
```
|
|
39
25
|
|
|
40
|
-
|
|
41
|
-
through the upstream `skills` CLI. Use
|
|
42
|
-
`npx --yes opensteer@latest skills install --agent claude-code` when you want to target
|
|
43
|
-
Claude Code explicitly.
|
|
26
|
+
The package uses the Playwright-backed local engine by default.
|
|
44
27
|
|
|
45
|
-
|
|
46
|
-
`@opensteer/engine-abp` only when you need the ABP backend.
|
|
28
|
+
## CLI Quickstart
|
|
47
29
|
|
|
48
|
-
|
|
49
|
-
|
|
30
|
+
```bash
|
|
31
|
+
opensteer open https://example.com --workspace demo
|
|
32
|
+
opensteer goto https://example.com/search --workspace demo --capture-network search
|
|
33
|
+
opensteer network query --workspace demo --capture search
|
|
34
|
+
opensteer network detail rec_123 --workspace demo
|
|
35
|
+
opensteer replay rec_123 --workspace demo
|
|
36
|
+
opensteer cookies example.com --workspace demo
|
|
37
|
+
opensteer storage example.com --workspace demo
|
|
38
|
+
opensteer state example.com --workspace demo
|
|
39
|
+
opensteer close --workspace demo
|
|
40
|
+
```
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
For DOM exploration:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
opensteer snapshot action --workspace demo
|
|
46
|
+
opensteer input 5 laptop --workspace demo --persist "search input" --capture-network search
|
|
47
|
+
opensteer click 7 --workspace demo --persist "search button" --capture-network search
|
|
48
|
+
opensteer snapshot extraction --workspace demo
|
|
49
|
+
opensteer extract '{"title":{"element":3}}' --workspace demo --persist "page summary"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## SDK Quickstart
|
|
52
53
|
|
|
53
54
|
```ts
|
|
54
55
|
import { Opensteer } from "opensteer";
|
|
55
56
|
|
|
56
57
|
const opensteer = new Opensteer({
|
|
57
|
-
|
|
58
|
+
workspace: "demo",
|
|
58
59
|
rootDir: process.cwd(),
|
|
59
|
-
browser: { headless: true },
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
headless: true,
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
const snapshot = await opensteer.snapshot("action");
|
|
70
|
-
const firstButton = snapshot.counters.find((counter) => counter.tagName === "BUTTON");
|
|
71
|
-
if (firstButton) {
|
|
72
|
-
await opensteer.click({
|
|
73
|
-
element: firstButton.element,
|
|
74
|
-
description: "primary button",
|
|
75
|
-
});
|
|
76
|
-
}
|
|
62
|
+
await opensteer.open("https://example.com");
|
|
63
|
+
await opensteer.goto("https://example.com/search", {
|
|
64
|
+
captureNetwork: "search",
|
|
65
|
+
});
|
|
77
66
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
title: { selector: "title" },
|
|
83
|
-
},
|
|
84
|
-
});
|
|
67
|
+
const records = await opensteer.network.query({
|
|
68
|
+
capture: "search",
|
|
69
|
+
json: true,
|
|
70
|
+
});
|
|
85
71
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
const detail = await opensteer.network.detail(records.records[0]!.recordId);
|
|
73
|
+
const replay = await opensteer.network.replay(records.records[0]!.recordId);
|
|
74
|
+
|
|
75
|
+
console.log(detail.summary.url);
|
|
76
|
+
console.log(replay.transport);
|
|
91
77
|
```
|
|
92
78
|
|
|
93
|
-
|
|
79
|
+
## `session.fetch()`
|
|
80
|
+
|
|
81
|
+
After discovery, write ordinary TypeScript using `fetch()` on the session.
|
|
94
82
|
|
|
95
83
|
```ts
|
|
96
84
|
import { Opensteer } from "opensteer";
|
|
97
85
|
|
|
98
86
|
const opensteer = new Opensteer({
|
|
99
|
-
|
|
87
|
+
workspace: "target",
|
|
100
88
|
rootDir: process.cwd(),
|
|
101
|
-
browser: { headless: true },
|
|
102
89
|
});
|
|
103
90
|
|
|
104
|
-
|
|
105
|
-
await opensteer.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const response = await opensteer.rawRequest({
|
|
111
|
-
transport: "context-http",
|
|
112
|
-
url: "https://example.com/api/items",
|
|
113
|
-
method: "POST",
|
|
114
|
-
body: {
|
|
115
|
-
json: { token },
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
console.log(response.data);
|
|
120
|
-
} finally {
|
|
121
|
-
await opensteer.close();
|
|
91
|
+
async function ensureTargetSession() {
|
|
92
|
+
const cookies = await opensteer.cookies(".target.com");
|
|
93
|
+
if (cookies.has("visitorId")) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
await opensteer.goto("https://target.com");
|
|
122
97
|
}
|
|
123
|
-
```
|
|
124
98
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
99
|
+
export async function searchTarget(keyword: string, count = 24) {
|
|
100
|
+
await ensureTargetSession();
|
|
101
|
+
|
|
102
|
+
const response = await opensteer.fetch(
|
|
103
|
+
"https://redsky.target.com/redsky_aggregations/v1/web/plp_search_v2",
|
|
104
|
+
{
|
|
105
|
+
query: {
|
|
106
|
+
keyword,
|
|
107
|
+
count,
|
|
108
|
+
offset: 0,
|
|
109
|
+
channel: "WEB",
|
|
110
|
+
platform: "desktop",
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
);
|
|
134
114
|
|
|
135
|
-
|
|
136
|
-
const state = await opensteer.open();
|
|
137
|
-
console.log(state.url);
|
|
138
|
-
} finally {
|
|
139
|
-
await opensteer.disconnect();
|
|
115
|
+
return response.json();
|
|
140
116
|
}
|
|
141
117
|
```
|
|
142
118
|
|
|
143
|
-
|
|
119
|
+
Transport is selected automatically by default. Force it only when discovery showed a specific requirement:
|
|
144
120
|
|
|
145
121
|
```ts
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
cloud: {
|
|
150
|
-
apiKey: process.env.OPENSTEER_API_KEY!,
|
|
151
|
-
browserProfile: {
|
|
152
|
-
profileId: "bp_123",
|
|
153
|
-
reuseIfActive: true,
|
|
154
|
-
},
|
|
155
|
-
},
|
|
122
|
+
const response = await opensteer.fetch("https://api.example.com/search", {
|
|
123
|
+
query: { keyword: "laptop" },
|
|
124
|
+
transport: "matched-tls",
|
|
156
125
|
});
|
|
157
126
|
```
|
|
158
127
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
import { OpensteerCloudClient } from "opensteer";
|
|
163
|
-
|
|
164
|
-
const client = new OpensteerCloudClient({
|
|
165
|
-
apiKey: process.env.OPENSTEER_API_KEY!,
|
|
166
|
-
baseUrl: process.env.OPENSTEER_BASE_URL ?? "https://api.opensteer.dev",
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
await client.syncBrowserProfileCookies({
|
|
170
|
-
profileId: "bp_123",
|
|
171
|
-
attachEndpoint: "9222",
|
|
172
|
-
domains: ["github.com"],
|
|
173
|
-
});
|
|
174
|
-
```
|
|
128
|
+
## Browser State
|
|
175
129
|
|
|
176
|
-
|
|
130
|
+
Opensteer exposes the browser state agents need for request tracing:
|
|
177
131
|
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
--source-profile-directory Default
|
|
184
|
-
opensteer open https://example.com --name docs-example --browser snapshot-authenticated \
|
|
185
|
-
--source-user-data-dir "~/Library/Application Support/Google/Chrome" \
|
|
186
|
-
--source-profile-directory "Profile 1"
|
|
187
|
-
opensteer browser discover
|
|
188
|
-
opensteer browser inspect --endpoint 9222
|
|
189
|
-
opensteer local-profile list
|
|
190
|
-
opensteer local-profile inspect --user-data-dir "~/Library/Application Support/Opensteer Chrome"
|
|
191
|
-
opensteer local-profile unlock --user-data-dir "~/Library/Application Support/Opensteer Chrome"
|
|
192
|
-
opensteer profile sync \
|
|
193
|
-
--profile-id bp_123 \
|
|
194
|
-
--attach-endpoint 9222 \
|
|
195
|
-
--domain github.com
|
|
196
|
-
opensteer open https://example.com --name docs-example --engine abp
|
|
197
|
-
opensteer snapshot action --name docs-example
|
|
198
|
-
opensteer click 3 --name docs-example --description "primary button"
|
|
199
|
-
opensteer extract --name docs-example --description "page summary" \
|
|
200
|
-
--schema '{"url":{"source":"current_url"},"title":{"selector":"title"}}'
|
|
201
|
-
opensteer computer '{"type":"screenshot"}' --name docs-example
|
|
202
|
-
opensteer close --name docs-example
|
|
132
|
+
```ts
|
|
133
|
+
const cookies = await opensteer.cookies("example.com");
|
|
134
|
+
const localStorage = await opensteer.storage("example.com", "local");
|
|
135
|
+
const sessionStorage = await opensteer.storage("example.com", "session");
|
|
136
|
+
const state = await opensteer.state("example.com");
|
|
203
137
|
```
|
|
204
138
|
|
|
205
|
-
|
|
206
|
-
`--press-enter`. Unknown flags and flags used on the wrong command fail fast instead of being
|
|
207
|
-
silently ignored.
|
|
208
|
-
|
|
209
|
-
Action and data commands print JSON to stdout. Help commands print human-readable usage text.
|
|
210
|
-
Browser state does not live in the CLI process. It lives
|
|
211
|
-
in the local session service recorded under `.opensteer/runtime/sessions/<name>/service.json`.
|
|
212
|
-
`opensteer computer` prints compact screenshot metadata and points at the persisted image through
|
|
213
|
-
`screenshot.path` for local shells and `screenshot.payload.uri` for the canonical file-backed
|
|
214
|
-
location.
|
|
215
|
-
|
|
216
|
-
Use `--engine <playwright|abp>` on `open` to choose the backend for a new session. You can also
|
|
217
|
-
set `OPENSTEER_ENGINE=abp` to change the default engine for `open` in the current shell. Engine
|
|
218
|
-
selection is fixed when the session service starts, so `OPENSTEER_ENGINE` and `--engine` only
|
|
219
|
-
affect `open`, not commands like `snapshot` or `click` that attach to an existing session.
|
|
220
|
-
When using `--engine abp`, Opensteer accepts the ABP launch options it can actually honor:
|
|
221
|
-
`--headless`, `--executable-path`, and equivalent `--browser-json` fields for `headless`, `args`,
|
|
222
|
-
and `executablePath`. Unsupported shared browser/context options fail fast instead of being
|
|
223
|
-
ignored.
|
|
224
|
-
|
|
225
|
-
Use `opensteer local-profile inspect` to diagnose whether a live Chromium profile is safe to reuse
|
|
226
|
-
as a snapshot source or whether it should be attached via CDP instead. `opensteer local-profile unlock`
|
|
227
|
-
remains limited to explicit `stale_lock` recovery; Opensteer does not mutate or take ownership of
|
|
228
|
-
real user-data-dirs as part of `open`.
|
|
229
|
-
|
|
230
|
-
## Connect To Real Browser
|
|
231
|
-
|
|
232
|
-
- `managed` launches a fresh isolated Chrome/Chromium process with a temporary `user-data-dir`.
|
|
233
|
-
- `snapshot-session` copies a source profile into a temporary owned browser directory without full authenticated OS-integrated state. Use it when persisted cookies/storage are enough.
|
|
234
|
-
- `snapshot-authenticated` copies a source profile into a temporary owned browser directory and preserves the authenticated browser state needed for harder replay cases.
|
|
235
|
-
- `attach-live` connects to an already-running Chrome/Chromium instance. Pass `endpoint` for an explicit CDP target, or omit it to auto-discover a locally attachable browser.
|
|
236
|
-
|
|
237
|
-
When you are launching a browser yourself for `attach-live`, prefer a dedicated profile directory:
|
|
139
|
+
`cookies()` returns a lightweight cookie jar:
|
|
238
140
|
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
141
|
+
```ts
|
|
142
|
+
cookies.has("session");
|
|
143
|
+
cookies.get("session");
|
|
144
|
+
cookies.getAll();
|
|
145
|
+
cookies.serialize();
|
|
243
146
|
```
|
|
244
147
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
## Transport Guide
|
|
248
|
-
|
|
249
|
-
- `direct-http`: use when the request is replayable without a browser
|
|
250
|
-
- `context-http`: use when browser cookies or browser session state are required
|
|
251
|
-
- `page-http`: use when request execution must happen inside the live page JavaScript world
|
|
148
|
+
## DOM Automation
|
|
252
149
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
150
|
+
```ts
|
|
151
|
+
await opensteer.click({ persist: "search button", captureNetwork: "search" });
|
|
152
|
+
await opensteer.input({
|
|
153
|
+
persist: "search input",
|
|
154
|
+
text: "laptop",
|
|
155
|
+
pressEnter: true,
|
|
156
|
+
captureNetwork: "search",
|
|
157
|
+
});
|
|
259
158
|
|
|
260
|
-
|
|
261
|
-
|
|
159
|
+
const data = await opensteer.extract({
|
|
160
|
+
persist: "page summary",
|
|
161
|
+
schema: {
|
|
162
|
+
title: { selector: "title" },
|
|
163
|
+
url: { source: "current_url" },
|
|
164
|
+
},
|
|
165
|
+
});
|
|
262
166
|
```
|
|
263
167
|
|
|
264
|
-
|
|
168
|
+
Use `snapshot("action")` or `snapshot("extraction")` during exploration. The snapshot result is the filtered HTML string, not a huge raw DOM object.
|
|
265
169
|
|
|
266
|
-
|
|
267
|
-
.opensteer/
|
|
268
|
-
artifacts/
|
|
269
|
-
traces/
|
|
270
|
-
registry/
|
|
271
|
-
runtime/
|
|
272
|
-
sessions/
|
|
273
|
-
```
|
|
170
|
+
## Public SDK Surface
|
|
274
171
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
- `
|
|
278
|
-
- `discoverLocalCdpBrowsers({ timeoutMs? })`
|
|
279
|
-
- `inspectCdpEndpoint({ endpoint, headers?, timeoutMs? })`
|
|
280
|
-
- `inspectLocalBrowserProfile({ userDataDir? })`
|
|
281
|
-
- `unlockLocalBrowserProfile({ userDataDir })`
|
|
282
|
-
- `open(url | { url?, name?, browser?, context? })`
|
|
283
|
-
- `goto(url | { url, captureNetwork? })`
|
|
284
|
-
- `evaluate(script | { script, pageRef?, args? })`
|
|
285
|
-
- `evaluateJson({ script, pageRef?, args? })`
|
|
286
|
-
- `waitForNetwork({ ...filters, pageRef?, includeBodies?, timeoutMs? })`
|
|
287
|
-
- `waitForResponse({ ...filters, pageRef?, includeBodies?, timeoutMs? })`
|
|
172
|
+
- `new Opensteer({ workspace?, rootDir?, browser?, provider? })`
|
|
173
|
+
- `open(url | input?)`
|
|
174
|
+
- `info()`
|
|
288
175
|
- `listPages()`
|
|
289
|
-
- `newPage(
|
|
290
|
-
- `activatePage(
|
|
291
|
-
- `closePage(
|
|
292
|
-
- `
|
|
176
|
+
- `newPage()`
|
|
177
|
+
- `activatePage()`
|
|
178
|
+
- `closePage()`
|
|
179
|
+
- `goto(url, { captureNetwork? })`
|
|
180
|
+
- `evaluate(script | input)`
|
|
181
|
+
- `evaluateJson(input)`
|
|
182
|
+
- `addInitScript(input)`
|
|
293
183
|
- `snapshot("action" | "extraction")`
|
|
294
|
-
- `click({ element | selector |
|
|
295
|
-
- `hover({ element | selector |
|
|
296
|
-
- `input({ element | selector |
|
|
297
|
-
- `scroll({ element | selector |
|
|
298
|
-
- `extract({
|
|
299
|
-
- `
|
|
300
|
-
- `
|
|
301
|
-
- `
|
|
302
|
-
- `
|
|
303
|
-
- `
|
|
304
|
-
- `
|
|
305
|
-
- `
|
|
306
|
-
- `
|
|
307
|
-
- `
|
|
308
|
-
- `
|
|
309
|
-
- `
|
|
310
|
-
- `
|
|
311
|
-
- `
|
|
312
|
-
- `
|
|
313
|
-
- `
|
|
314
|
-
- `
|
|
315
|
-
- `
|
|
316
|
-
- `computerExecute({ action, screenshot?, captureNetwork? })`
|
|
317
|
-
- `disconnect()`
|
|
184
|
+
- `click({ element? | selector? | persist?, captureNetwork? })`
|
|
185
|
+
- `hover({ element? | selector? | persist?, captureNetwork? })`
|
|
186
|
+
- `input({ text, element? | selector? | persist?, captureNetwork? })`
|
|
187
|
+
- `scroll({ direction, amount, element? | selector? | persist?, captureNetwork? })`
|
|
188
|
+
- `extract({ schema } | { persist, schema? })`
|
|
189
|
+
- `network.query(input?)`
|
|
190
|
+
- `network.detail(recordId)`
|
|
191
|
+
- `network.replay(recordId, overrides?)`
|
|
192
|
+
- `waitForNetwork(input?)`
|
|
193
|
+
- `waitForResponse(input?)`
|
|
194
|
+
- `waitForPage(input?)`
|
|
195
|
+
- `cookies(domain?)`
|
|
196
|
+
- `storage(domain?, "local" | "session")`
|
|
197
|
+
- `state(domain?)`
|
|
198
|
+
- `fetch(url, options?)`
|
|
199
|
+
- `computerExecute(input)`
|
|
200
|
+
- `route(input)`
|
|
201
|
+
- `interceptScript(input)`
|
|
202
|
+
- `browser.status()`
|
|
203
|
+
- `browser.clone(input)`
|
|
204
|
+
- `browser.reset()`
|
|
205
|
+
- `browser.delete()`
|
|
318
206
|
- `close()`
|
|
207
|
+
- `disconnect()`
|
|
319
208
|
|
|
320
|
-
|
|
321
|
-
`selector` resolves a CSS selector directly and, when not explicitly scoped, searches the current
|
|
322
|
-
page before falling back to child frames.
|
|
323
|
-
|
|
324
|
-
Use `disconnect()` for attached sessions when you want to release the SDK handle but keep the
|
|
325
|
-
underlying session alive. Use `close()` when you want to destructively end the session.
|
|
326
|
-
|
|
327
|
-
Profile inspection is independent from session ownership. `inspectLocalBrowserProfile()` returns a
|
|
328
|
-
structured status union (`available`, `unsupported_default_user_data_dir`, `opensteer_owned`,
|
|
329
|
-
`browser_owned`, `stale_lock`) that launch, CLI, and SDK all consume. Failed owned launches throw
|
|
330
|
-
`OpensteerLocalProfileUnavailableError` with the inspection attached for programmatic handling.
|
|
331
|
-
|
|
332
|
-
The reverse-engineering workflow is: perform a browser action, inspect traffic with
|
|
333
|
-
`queryNetwork()`, optionally instrument with `addInitScript()`, `route()`, or
|
|
334
|
-
`captureScripts()`, experiment with `rawRequest()`, promote a record with
|
|
335
|
-
`inferRequestPlan()`, passing `transport` when you have already proven a portable
|
|
336
|
-
request path, then replay with `request()`.
|
|
209
|
+
## Design Notes
|
|
337
210
|
|
|
338
|
-
`
|
|
339
|
-
|
|
340
|
-
|
|
211
|
+
- `network query` is intentionally summary-oriented. Use `network detail` for deep inspection.
|
|
212
|
+
- `replay` is transport-aware and should usually replace manual probe logic.
|
|
213
|
+
- `browser status` intentionally does not leak the raw browser websocket endpoint.
|
|
214
|
+
- The package also exports advanced cloud and browser-management utilities, but the core agent workflow is the local discovery-first SDK and CLI shown above.
|