opensteer 0.4.9 → 0.4.11
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/CHANGELOG.md +5 -0
- package/README.md +70 -141
- package/bin/opensteer.mjs +1 -1
- package/dist/{chunk-U6YJI5GO.js → chunk-C3NM6XZH.js} +43 -34
- package/dist/cli/server.cjs +43 -34
- package/dist/cli/server.js +1 -1
- package/dist/index.cjs +43 -34
- package/dist/index.d.cts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -1
- package/package.json +73 -80
package/CHANGELOG.md
CHANGED
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
timeout/stale-target cases more accurately.
|
|
37
37
|
- Cloud action failures now accept optional structured failure details and map
|
|
38
38
|
them to `OpensteerActionError` when available.
|
|
39
|
+
- Docs: refreshed README and getting-started guidance to match current SDK/CLI
|
|
40
|
+
behavior and env vars.
|
|
41
|
+
- Docs: added CLI reference and docs index.
|
|
42
|
+
- OSS community docs: expanded `CONTRIBUTING.md` and added `SECURITY.md` +
|
|
43
|
+
`SUPPORT.md`.
|
|
39
44
|
|
|
40
45
|
## 0.1.0
|
|
41
46
|
|
package/README.md
CHANGED
|
@@ -1,186 +1,115 @@
|
|
|
1
1
|
# Opensteer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Open-source browser automation SDK for coding agents and deterministic replay.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`extractFromPlan`, `uploadFile`), observation (`snapshot`, `state`,
|
|
8
|
-
`screenshot`), navigation (`goto`), and convenience methods for tabs, cookies,
|
|
9
|
-
keyboard, element info, and wait.
|
|
5
|
+
Opensteer combines descriptor-aware actions, resilient selector persistence,
|
|
6
|
+
clean HTML snapshots, and first-class local or cloud runtime support.
|
|
10
7
|
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node.js `>=20`
|
|
11
|
+
- A browser environment supported by Playwright
|
|
12
|
+
- API key for your selected model provider if you use LLM resolve/extract
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
17
|
# npm
|
|
18
|
-
npm install opensteer
|
|
18
|
+
npm install opensteer
|
|
19
19
|
# pnpm
|
|
20
|
-
pnpm add opensteer
|
|
20
|
+
pnpm add opensteer
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
OpenSteer CLI now separates runtime routing from selector caching:
|
|
26
|
-
|
|
27
|
-
- Runtime routing: `--session` or `OPENSTEER_SESSION`
|
|
28
|
-
- Selector cache namespace: `--name` or `OPENSTEER_NAME` (used on `open`)
|
|
29
|
-
|
|
30
|
-
If neither `--session` nor `OPENSTEER_SESSION` is set:
|
|
31
|
-
|
|
32
|
-
- In an interactive terminal, OpenSteer creates/reuses a terminal-scoped default session.
|
|
33
|
-
- In non-interactive environments (agents/CI), it fails fast unless you set
|
|
34
|
-
`OPENSTEER_SESSION` or `OPENSTEER_CLIENT_ID`.
|
|
35
|
-
|
|
36
|
-
Example:
|
|
23
|
+
If your environment skips Playwright browser downloads, run:
|
|
37
24
|
|
|
38
25
|
```bash
|
|
39
|
-
|
|
40
|
-
opensteer open https://example.com --name product-scraper
|
|
41
|
-
opensteer snapshot
|
|
42
|
-
opensteer click 3
|
|
43
|
-
opensteer status
|
|
26
|
+
npx playwright install chromium
|
|
44
27
|
```
|
|
45
28
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
## Quickstart
|
|
29
|
+
## Quickstart (SDK)
|
|
49
30
|
|
|
50
31
|
```ts
|
|
51
32
|
import { Opensteer } from "opensteer";
|
|
52
33
|
|
|
53
|
-
const opensteer = new Opensteer({ name: "my-scraper" });
|
|
34
|
+
const opensteer = new Opensteer({ name: "my-scraper" });
|
|
54
35
|
await opensteer.launch({ headless: false });
|
|
55
36
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await opensteer.input({ description: "email", text: "user@example.com" });
|
|
61
|
-
await opensteer.page.keyboard.press("Enter");
|
|
62
|
-
|
|
63
|
-
await opensteer.close();
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Core Model
|
|
67
|
-
|
|
68
|
-
- `opensteer.page`: raw Playwright `Page`
|
|
69
|
-
- `opensteer.context`: raw Playwright `BrowserContext`
|
|
70
|
-
- Opensteer methods: descriptor-aware operations that can persist selectors
|
|
71
|
-
- Selector storage: `.opensteer/selectors/<namespace>`
|
|
72
|
-
|
|
73
|
-
## Resolution Chain
|
|
74
|
-
|
|
75
|
-
For actions like `click`/`input`/`hover`/`select`/`scroll`:
|
|
76
|
-
|
|
77
|
-
1. Use persisted path for `description` (if present)
|
|
78
|
-
2. Use `element` counter from snapshot
|
|
79
|
-
3. Use explicit CSS `selector`
|
|
80
|
-
4. Use built-in LLM resolution (`description` required)
|
|
81
|
-
5. Throw
|
|
82
|
-
|
|
83
|
-
When steps 2-4 resolve and `description` is provided, the path is persisted.
|
|
84
|
-
|
|
85
|
-
## Smart Post-Action Wait
|
|
86
|
-
|
|
87
|
-
Mutating actions (`click`, `input`, `select`, `scroll`, etc.) include a
|
|
88
|
-
best-effort post-action wait so delayed visual updates are usually settled
|
|
89
|
-
before the method resolves.
|
|
90
|
-
|
|
91
|
-
You can disable or tune this per call:
|
|
92
|
-
|
|
93
|
-
```ts
|
|
94
|
-
await opensteer.click({ description: "Save button", wait: false });
|
|
37
|
+
try {
|
|
38
|
+
await opensteer.goto("https://example.com");
|
|
39
|
+
const html = await opensteer.snapshot();
|
|
40
|
+
console.log(html.slice(0, 500));
|
|
95
41
|
|
|
96
|
-
await opensteer.click({
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
42
|
+
await opensteer.click({ description: "main call to action", element: 3 });
|
|
43
|
+
} finally {
|
|
44
|
+
await opensteer.close();
|
|
45
|
+
}
|
|
100
46
|
```
|
|
101
47
|
|
|
102
|
-
##
|
|
103
|
-
|
|
104
|
-
Descriptor-aware interaction methods (`click`, `dblclick`, `rightclick`,
|
|
105
|
-
`hover`, `input`, `select`, `scroll`, `uploadFile`) throw
|
|
106
|
-
`OpensteerActionError` when an interaction cannot be completed.
|
|
107
|
-
|
|
108
|
-
The error includes structured failure metadata for agent/tooling decisions:
|
|
48
|
+
## Quickstart (CLI)
|
|
109
49
|
|
|
110
|
-
|
|
111
|
-
- `error.failure.message`
|
|
112
|
-
- `error.failure.retryable`
|
|
113
|
-
- `error.failure.classificationSource`
|
|
114
|
-
- `error.failure.details` (for blocker and observation details when available)
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
import { Opensteer, OpensteerActionError } from "opensteer";
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
await opensteer.click({ description: "Save button" });
|
|
121
|
-
} catch (err) {
|
|
122
|
-
if (err instanceof OpensteerActionError) {
|
|
123
|
-
console.error(err.failure.code); // e.g. BLOCKED_BY_INTERCEPTOR
|
|
124
|
-
console.error(err.failure.message);
|
|
125
|
-
console.error(err.failure.classificationSource);
|
|
126
|
-
}
|
|
127
|
-
throw err;
|
|
128
|
-
}
|
|
129
|
-
```
|
|
50
|
+
Opensteer CLI separates runtime routing from selector namespace routing.
|
|
130
51
|
|
|
131
|
-
|
|
52
|
+
- Runtime routing: `--session` or `OPENSTEER_SESSION`
|
|
53
|
+
- Selector namespace: `--name` or `OPENSTEER_NAME` (used by `open`)
|
|
132
54
|
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
55
|
+
```bash
|
|
56
|
+
opensteer open https://example.com --session agent-a --name product-scraper
|
|
57
|
+
opensteer snapshot --session agent-a
|
|
58
|
+
opensteer click 3 --session agent-a
|
|
59
|
+
opensteer status --session agent-a
|
|
60
|
+
opensteer close --session agent-a
|
|
139
61
|
```
|
|
140
62
|
|
|
141
|
-
|
|
63
|
+
In non-interactive environments, set `OPENSTEER_SESSION` or
|
|
64
|
+
`OPENSTEER_CLIENT_ID` explicitly.
|
|
142
65
|
|
|
143
|
-
|
|
66
|
+
## Resolution and Replay Model
|
|
144
67
|
|
|
145
|
-
|
|
146
|
-
stable descriptions for replay.
|
|
68
|
+
For descriptor-aware actions (`click`, `input`, `hover`, `select`, `scroll`):
|
|
147
69
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
70
|
+
1. Reuse persisted path for `description`
|
|
71
|
+
2. Use `element` counter from snapshot
|
|
72
|
+
3. Use explicit CSS `selector`
|
|
73
|
+
4. Use built-in LLM resolution (`description` required)
|
|
74
|
+
5. Throw actionable error
|
|
152
75
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
name: "run-mode",
|
|
156
|
-
model: "gpt-5-mini",
|
|
157
|
-
});
|
|
158
|
-
```
|
|
76
|
+
When steps 2-4 succeed and `description` is present, Opensteer persists the
|
|
77
|
+
path for deterministic replay in `.opensteer/selectors/<namespace>`.
|
|
159
78
|
|
|
160
|
-
## Mode
|
|
79
|
+
## Cloud Mode
|
|
161
80
|
|
|
162
81
|
Opensteer defaults to local mode.
|
|
163
82
|
|
|
164
|
-
- `OPENSTEER_MODE=local`
|
|
165
|
-
- `
|
|
166
|
-
- `
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
- Existing `process.env` values are never overwritten by `.env` values.
|
|
171
|
-
- Set `OPENSTEER_DISABLE_DOTENV_AUTOLOAD=true` to disable auto-loading.
|
|
83
|
+
- `OPENSTEER_MODE=local|cloud`
|
|
84
|
+
- `OPENSTEER_API_KEY` or `cloud.apiKey` required in cloud mode
|
|
85
|
+
- `OPENSTEER_BASE_URL` or `cloud.baseUrl` to override the default cloud host
|
|
86
|
+
- `OPENSTEER_AUTH_SCHEME` or `cloud.authScheme` for auth header mode
|
|
87
|
+
(`api-key` or `bearer`)
|
|
88
|
+
- `cloud: true` or a `cloud` options object overrides `OPENSTEER_MODE`
|
|
172
89
|
|
|
173
|
-
|
|
90
|
+
`.env` files are auto-loaded from `storage.rootDir` (default `process.cwd()`)
|
|
91
|
+
in this order: `.env.<NODE_ENV>.local`, `.env.local` (except in test),
|
|
92
|
+
`.env.<NODE_ENV>`, `.env`. Existing `process.env` values are not overwritten.
|
|
93
|
+
Set `OPENSTEER_DISABLE_DOTENV_AUTOLOAD=true` to disable.
|
|
174
94
|
|
|
175
95
|
## Docs
|
|
176
96
|
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
180
|
-
-
|
|
181
|
-
-
|
|
182
|
-
-
|
|
97
|
+
- [Getting Started](docs/getting-started.md)
|
|
98
|
+
- [API Reference](docs/api-reference.md)
|
|
99
|
+
- [CLI Reference](docs/cli-reference.md)
|
|
100
|
+
- [Cloud Integration](docs/cloud-integration.md)
|
|
101
|
+
- [Selectors and Storage](docs/selectors.md)
|
|
102
|
+
- [HTML Cleaning and Snapshot Modes](docs/html-cleaning.md)
|
|
103
|
+
- [Live Web Validation Suite](docs/live-web-tests.md)
|
|
104
|
+
|
|
105
|
+
## Community
|
|
106
|
+
|
|
107
|
+
- [Contributing Guide](CONTRIBUTING.md)
|
|
108
|
+
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
|
109
|
+
- [Security Policy](SECURITY.md)
|
|
110
|
+
- [Support](SUPPORT.md)
|
|
111
|
+
- [Changelog](CHANGELOG.md)
|
|
183
112
|
|
|
184
113
|
## License
|
|
185
114
|
|
|
186
|
-
MIT
|
|
115
|
+
[MIT](LICENSE)
|
package/bin/opensteer.mjs
CHANGED
|
@@ -781,7 +781,7 @@ Environment:
|
|
|
781
781
|
OPENSTEER_MODE Runtime routing: "local" (default) or "cloud"
|
|
782
782
|
OPENSTEER_API_KEY Required when cloud mode is selected
|
|
783
783
|
OPENSTEER_BASE_URL Override cloud control-plane base URL
|
|
784
|
-
|
|
784
|
+
OPENSTEER_AUTH_SCHEME Cloud auth scheme: api-key (default) or bearer
|
|
785
785
|
OPENSTEER_REMOTE_ANNOUNCE Cloud session announcement policy: always (default), off, tty
|
|
786
786
|
`)
|
|
787
787
|
}
|
|
@@ -38,6 +38,7 @@ function sanitizeNamespaceSegment(segment) {
|
|
|
38
38
|
var DEFAULT_TIMEOUT = 3e4;
|
|
39
39
|
var DEFAULT_SETTLE_MS = 750;
|
|
40
40
|
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
41
|
+
var TRANSIENT_CONTEXT_RETRY_DELAY_MS = 25;
|
|
41
42
|
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
42
43
|
var StealthWaitUnavailableError = class extends Error {
|
|
43
44
|
constructor(cause) {
|
|
@@ -341,9 +342,12 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
341
342
|
const frameRecords = await this.getFrameRecords();
|
|
342
343
|
const mainFrame = frameRecords[0];
|
|
343
344
|
if (!mainFrame) return;
|
|
344
|
-
await this.waitForFrameVisualStability(
|
|
345
|
-
|
|
346
|
-
|
|
345
|
+
await this.waitForFrameVisualStability(
|
|
346
|
+
mainFrame.frameId,
|
|
347
|
+
timeout,
|
|
348
|
+
settleMs,
|
|
349
|
+
true
|
|
350
|
+
);
|
|
347
351
|
}
|
|
348
352
|
async collectVisibleFrameIds() {
|
|
349
353
|
const frameRecords = await this.getFrameRecords();
|
|
@@ -372,16 +376,15 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
372
376
|
}
|
|
373
377
|
return visibleFrameIds;
|
|
374
378
|
}
|
|
375
|
-
async waitForFrameVisualStability(frameId, timeout, settleMs,
|
|
379
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs, retryTransientContextErrors = true) {
|
|
376
380
|
if (timeout <= 0) return;
|
|
377
381
|
const script = buildStabilityScript(timeout, settleMs);
|
|
378
|
-
const retryTransientContextErrors = options.retryTransientContextErrors ?? true;
|
|
379
382
|
if (!retryTransientContextErrors) {
|
|
380
383
|
let contextId = await this.ensureFrameContextId(frameId);
|
|
381
384
|
try {
|
|
382
385
|
await this.evaluateWithGuard(contextId, script, timeout);
|
|
383
386
|
} catch (error) {
|
|
384
|
-
if (!
|
|
387
|
+
if (!isMissingExecutionContextError(error)) {
|
|
385
388
|
throw error;
|
|
386
389
|
}
|
|
387
390
|
this.contextsByFrame.delete(frameId);
|
|
@@ -405,6 +408,11 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
405
408
|
throw error;
|
|
406
409
|
}
|
|
407
410
|
this.contextsByFrame.delete(frameId);
|
|
411
|
+
const retryDelay = Math.min(
|
|
412
|
+
TRANSIENT_CONTEXT_RETRY_DELAY_MS,
|
|
413
|
+
Math.max(0, deadline - Date.now())
|
|
414
|
+
);
|
|
415
|
+
await sleep(retryDelay);
|
|
408
416
|
}
|
|
409
417
|
}
|
|
410
418
|
}
|
|
@@ -526,9 +534,7 @@ async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
|
526
534
|
frameId,
|
|
527
535
|
remaining,
|
|
528
536
|
settleMs,
|
|
529
|
-
|
|
530
|
-
retryTransientContextErrors: false
|
|
531
|
-
}
|
|
537
|
+
false
|
|
532
538
|
);
|
|
533
539
|
} catch (error) {
|
|
534
540
|
if (isIgnorableFrameError(error)) return;
|
|
@@ -571,7 +577,7 @@ function isTransientExecutionContextError(error) {
|
|
|
571
577
|
const message = error.message;
|
|
572
578
|
return message.includes("Execution context was destroyed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
573
579
|
}
|
|
574
|
-
function
|
|
580
|
+
function isMissingExecutionContextError(error) {
|
|
575
581
|
if (!(error instanceof Error)) return false;
|
|
576
582
|
const message = error.message;
|
|
577
583
|
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
@@ -6208,6 +6214,11 @@ function resolveOpensteerApiKey(env) {
|
|
|
6208
6214
|
if (!value) return void 0;
|
|
6209
6215
|
return value;
|
|
6210
6216
|
}
|
|
6217
|
+
function resolveOpensteerBaseUrl(env) {
|
|
6218
|
+
const value = env.OPENSTEER_BASE_URL?.trim();
|
|
6219
|
+
if (!value) return void 0;
|
|
6220
|
+
return value;
|
|
6221
|
+
}
|
|
6211
6222
|
function resolveOpensteerAuthScheme(env) {
|
|
6212
6223
|
return parseAuthScheme(env.OPENSTEER_AUTH_SCHEME, "OPENSTEER_AUTH_SCHEME");
|
|
6213
6224
|
}
|
|
@@ -6286,6 +6297,7 @@ function resolveConfig(input = {}) {
|
|
|
6286
6297
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
6287
6298
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
6288
6299
|
const envApiKey = resolveOpensteerApiKey(env);
|
|
6300
|
+
const envBaseUrl = resolveOpensteerBaseUrl(env);
|
|
6289
6301
|
const envAuthScheme = resolveOpensteerAuthScheme(env);
|
|
6290
6302
|
const envCloudAnnounce = parseCloudAnnounce(
|
|
6291
6303
|
env.OPENSTEER_REMOTE_ANNOUNCE,
|
|
@@ -6303,6 +6315,9 @@ function resolveConfig(input = {}) {
|
|
|
6303
6315
|
const inputHasCloudApiKey = Boolean(
|
|
6304
6316
|
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "apiKey")
|
|
6305
6317
|
);
|
|
6318
|
+
const inputHasCloudBaseUrl = Boolean(
|
|
6319
|
+
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
|
|
6320
|
+
);
|
|
6306
6321
|
const cloudSelection = resolveCloudSelection({
|
|
6307
6322
|
cloud: resolved.cloud
|
|
6308
6323
|
}, env);
|
|
@@ -6322,6 +6337,12 @@ function resolveConfig(input = {}) {
|
|
|
6322
6337
|
apiKey: envApiKey
|
|
6323
6338
|
};
|
|
6324
6339
|
}
|
|
6340
|
+
if (envBaseUrl && cloudSelection.cloud && !inputHasCloudBaseUrl) {
|
|
6341
|
+
resolved.cloud = {
|
|
6342
|
+
...normalizeCloudOptions(resolved.cloud) ?? {},
|
|
6343
|
+
baseUrl: envBaseUrl
|
|
6344
|
+
};
|
|
6345
|
+
}
|
|
6325
6346
|
return resolved;
|
|
6326
6347
|
}
|
|
6327
6348
|
function resolveNamespace(config, rootDir) {
|
|
@@ -7716,12 +7737,16 @@ function clonePersistedExtractNode(node) {
|
|
|
7716
7737
|
|
|
7717
7738
|
// src/cloud/runtime.ts
|
|
7718
7739
|
var DEFAULT_CLOUD_BASE_URL = "https://remote.opensteer.com";
|
|
7719
|
-
|
|
7720
|
-
|
|
7740
|
+
function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authScheme = "api-key") {
|
|
7741
|
+
const normalizedBaseUrl = normalizeCloudBaseUrl(baseUrl);
|
|
7721
7742
|
return {
|
|
7722
|
-
sessionClient: new CloudSessionClient(
|
|
7743
|
+
sessionClient: new CloudSessionClient(
|
|
7744
|
+
normalizedBaseUrl,
|
|
7745
|
+
key,
|
|
7746
|
+
authScheme
|
|
7747
|
+
),
|
|
7723
7748
|
cdpClient: new CloudCdpClient(),
|
|
7724
|
-
|
|
7749
|
+
baseUrl: normalizedBaseUrl,
|
|
7725
7750
|
actionClient: null,
|
|
7726
7751
|
sessionId: null,
|
|
7727
7752
|
localRunId: null,
|
|
@@ -7731,15 +7756,9 @@ function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authSchem
|
|
|
7731
7756
|
function resolveCloudBaseUrl() {
|
|
7732
7757
|
const value = process.env.OPENSTEER_BASE_URL?.trim();
|
|
7733
7758
|
if (!value) return DEFAULT_CLOUD_BASE_URL;
|
|
7734
|
-
return value
|
|
7735
|
-
}
|
|
7736
|
-
function resolveCloudAppUrl() {
|
|
7737
|
-
const value = process.env.OPENSTEER_APP_URL?.trim();
|
|
7738
|
-
if (!value) return DEFAULT_CLOUD_APP_URL;
|
|
7739
|
-
return normalizeCloudAppUrl(value);
|
|
7759
|
+
return normalizeCloudBaseUrl(value);
|
|
7740
7760
|
}
|
|
7741
|
-
function
|
|
7742
|
-
if (!value) return null;
|
|
7761
|
+
function normalizeCloudBaseUrl(value) {
|
|
7743
7762
|
return value.replace(/\/+$/, "");
|
|
7744
7763
|
}
|
|
7745
7764
|
function readCloudActionDescription(payload) {
|
|
@@ -7797,8 +7816,7 @@ var Opensteer = class _Opensteer {
|
|
|
7797
7816
|
this.cloud = createCloudRuntimeState(
|
|
7798
7817
|
apiKey,
|
|
7799
7818
|
cloudConfig?.baseUrl,
|
|
7800
|
-
cloudConfig?.authScheme
|
|
7801
|
-
cloudConfig?.appUrl
|
|
7819
|
+
cloudConfig?.authScheme
|
|
7802
7820
|
);
|
|
7803
7821
|
} else {
|
|
7804
7822
|
this.cloud = null;
|
|
@@ -7990,10 +8008,7 @@ var Opensteer = class _Opensteer {
|
|
|
7990
8008
|
this.snapshotCache = null;
|
|
7991
8009
|
this.cloud.actionClient = actionClient;
|
|
7992
8010
|
this.cloud.sessionId = sessionId;
|
|
7993
|
-
this.cloud.cloudSessionUrl =
|
|
7994
|
-
this.cloud.appUrl,
|
|
7995
|
-
session2.cloudSession.sessionId
|
|
7996
|
-
);
|
|
8011
|
+
this.cloud.cloudSessionUrl = session2.cloudSessionUrl;
|
|
7997
8012
|
this.announceCloudSession({
|
|
7998
8013
|
sessionId: session2.sessionId,
|
|
7999
8014
|
workspaceId: session2.cloudSession.workspaceId,
|
|
@@ -10050,12 +10065,6 @@ function buildLocalRunId(namespace) {
|
|
|
10050
10065
|
const normalized = namespace.trim() || "default";
|
|
10051
10066
|
return `${normalized}-${Date.now().toString(36)}-${randomUUID2().slice(0, 8)}`;
|
|
10052
10067
|
}
|
|
10053
|
-
function buildCloudSessionUrl(appUrl, sessionId) {
|
|
10054
|
-
if (!appUrl) {
|
|
10055
|
-
return null;
|
|
10056
|
-
}
|
|
10057
|
-
return `${appUrl}/browser/${encodeURIComponent(sessionId)}`;
|
|
10058
|
-
}
|
|
10059
10068
|
|
|
10060
10069
|
export {
|
|
10061
10070
|
normalizeNamespace,
|
package/dist/cli/server.cjs
CHANGED
|
@@ -1036,6 +1036,11 @@ function resolveOpensteerApiKey(env) {
|
|
|
1036
1036
|
if (!value) return void 0;
|
|
1037
1037
|
return value;
|
|
1038
1038
|
}
|
|
1039
|
+
function resolveOpensteerBaseUrl(env) {
|
|
1040
|
+
const value = env.OPENSTEER_BASE_URL?.trim();
|
|
1041
|
+
if (!value) return void 0;
|
|
1042
|
+
return value;
|
|
1043
|
+
}
|
|
1039
1044
|
function resolveOpensteerAuthScheme(env) {
|
|
1040
1045
|
return parseAuthScheme(env.OPENSTEER_AUTH_SCHEME, "OPENSTEER_AUTH_SCHEME");
|
|
1041
1046
|
}
|
|
@@ -1114,6 +1119,7 @@ function resolveConfig(input = {}) {
|
|
|
1114
1119
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1115
1120
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
1116
1121
|
const envApiKey = resolveOpensteerApiKey(env);
|
|
1122
|
+
const envBaseUrl = resolveOpensteerBaseUrl(env);
|
|
1117
1123
|
const envAuthScheme = resolveOpensteerAuthScheme(env);
|
|
1118
1124
|
const envCloudAnnounce = parseCloudAnnounce(
|
|
1119
1125
|
env.OPENSTEER_REMOTE_ANNOUNCE,
|
|
@@ -1131,6 +1137,9 @@ function resolveConfig(input = {}) {
|
|
|
1131
1137
|
const inputHasCloudApiKey = Boolean(
|
|
1132
1138
|
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "apiKey")
|
|
1133
1139
|
);
|
|
1140
|
+
const inputHasCloudBaseUrl = Boolean(
|
|
1141
|
+
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
|
|
1142
|
+
);
|
|
1134
1143
|
const cloudSelection = resolveCloudSelection({
|
|
1135
1144
|
cloud: resolved.cloud
|
|
1136
1145
|
}, env);
|
|
@@ -1150,6 +1159,12 @@ function resolveConfig(input = {}) {
|
|
|
1150
1159
|
apiKey: envApiKey
|
|
1151
1160
|
};
|
|
1152
1161
|
}
|
|
1162
|
+
if (envBaseUrl && cloudSelection.cloud && !inputHasCloudBaseUrl) {
|
|
1163
|
+
resolved.cloud = {
|
|
1164
|
+
...normalizeCloudOptions(resolved.cloud) ?? {},
|
|
1165
|
+
baseUrl: envBaseUrl
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1153
1168
|
return resolved;
|
|
1154
1169
|
}
|
|
1155
1170
|
function resolveNamespace(config, rootDir) {
|
|
@@ -1190,6 +1205,7 @@ function getCallerFilePath() {
|
|
|
1190
1205
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1191
1206
|
var DEFAULT_SETTLE_MS = 750;
|
|
1192
1207
|
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
1208
|
+
var TRANSIENT_CONTEXT_RETRY_DELAY_MS = 25;
|
|
1193
1209
|
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
1194
1210
|
var StealthWaitUnavailableError = class extends Error {
|
|
1195
1211
|
constructor(cause) {
|
|
@@ -1493,9 +1509,12 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1493
1509
|
const frameRecords = await this.getFrameRecords();
|
|
1494
1510
|
const mainFrame = frameRecords[0];
|
|
1495
1511
|
if (!mainFrame) return;
|
|
1496
|
-
await this.waitForFrameVisualStability(
|
|
1497
|
-
|
|
1498
|
-
|
|
1512
|
+
await this.waitForFrameVisualStability(
|
|
1513
|
+
mainFrame.frameId,
|
|
1514
|
+
timeout,
|
|
1515
|
+
settleMs,
|
|
1516
|
+
true
|
|
1517
|
+
);
|
|
1499
1518
|
}
|
|
1500
1519
|
async collectVisibleFrameIds() {
|
|
1501
1520
|
const frameRecords = await this.getFrameRecords();
|
|
@@ -1524,16 +1543,15 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1524
1543
|
}
|
|
1525
1544
|
return visibleFrameIds;
|
|
1526
1545
|
}
|
|
1527
|
-
async waitForFrameVisualStability(frameId, timeout, settleMs,
|
|
1546
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs, retryTransientContextErrors = true) {
|
|
1528
1547
|
if (timeout <= 0) return;
|
|
1529
1548
|
const script = buildStabilityScript(timeout, settleMs);
|
|
1530
|
-
const retryTransientContextErrors = options.retryTransientContextErrors ?? true;
|
|
1531
1549
|
if (!retryTransientContextErrors) {
|
|
1532
1550
|
let contextId = await this.ensureFrameContextId(frameId);
|
|
1533
1551
|
try {
|
|
1534
1552
|
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1535
1553
|
} catch (error) {
|
|
1536
|
-
if (!
|
|
1554
|
+
if (!isMissingExecutionContextError(error)) {
|
|
1537
1555
|
throw error;
|
|
1538
1556
|
}
|
|
1539
1557
|
this.contextsByFrame.delete(frameId);
|
|
@@ -1557,6 +1575,11 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1557
1575
|
throw error;
|
|
1558
1576
|
}
|
|
1559
1577
|
this.contextsByFrame.delete(frameId);
|
|
1578
|
+
const retryDelay = Math.min(
|
|
1579
|
+
TRANSIENT_CONTEXT_RETRY_DELAY_MS,
|
|
1580
|
+
Math.max(0, deadline - Date.now())
|
|
1581
|
+
);
|
|
1582
|
+
await sleep(retryDelay);
|
|
1560
1583
|
}
|
|
1561
1584
|
}
|
|
1562
1585
|
}
|
|
@@ -1678,9 +1701,7 @@ async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
|
1678
1701
|
frameId,
|
|
1679
1702
|
remaining,
|
|
1680
1703
|
settleMs,
|
|
1681
|
-
|
|
1682
|
-
retryTransientContextErrors: false
|
|
1683
|
-
}
|
|
1704
|
+
false
|
|
1684
1705
|
);
|
|
1685
1706
|
} catch (error) {
|
|
1686
1707
|
if (isIgnorableFrameError(error)) return;
|
|
@@ -1723,7 +1744,7 @@ function isTransientExecutionContextError(error) {
|
|
|
1723
1744
|
const message = error.message;
|
|
1724
1745
|
return message.includes("Execution context was destroyed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
1725
1746
|
}
|
|
1726
|
-
function
|
|
1747
|
+
function isMissingExecutionContextError(error) {
|
|
1727
1748
|
if (!(error instanceof Error)) return false;
|
|
1728
1749
|
const message = error.message;
|
|
1729
1750
|
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
@@ -8050,12 +8071,16 @@ function toCloudErrorCode(code) {
|
|
|
8050
8071
|
|
|
8051
8072
|
// src/cloud/runtime.ts
|
|
8052
8073
|
var DEFAULT_CLOUD_BASE_URL = "https://remote.opensteer.com";
|
|
8053
|
-
|
|
8054
|
-
|
|
8074
|
+
function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authScheme = "api-key") {
|
|
8075
|
+
const normalizedBaseUrl = normalizeCloudBaseUrl(baseUrl);
|
|
8055
8076
|
return {
|
|
8056
|
-
sessionClient: new CloudSessionClient(
|
|
8077
|
+
sessionClient: new CloudSessionClient(
|
|
8078
|
+
normalizedBaseUrl,
|
|
8079
|
+
key,
|
|
8080
|
+
authScheme
|
|
8081
|
+
),
|
|
8057
8082
|
cdpClient: new CloudCdpClient(),
|
|
8058
|
-
|
|
8083
|
+
baseUrl: normalizedBaseUrl,
|
|
8059
8084
|
actionClient: null,
|
|
8060
8085
|
sessionId: null,
|
|
8061
8086
|
localRunId: null,
|
|
@@ -8065,15 +8090,9 @@ function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authSchem
|
|
|
8065
8090
|
function resolveCloudBaseUrl() {
|
|
8066
8091
|
const value = process.env.OPENSTEER_BASE_URL?.trim();
|
|
8067
8092
|
if (!value) return DEFAULT_CLOUD_BASE_URL;
|
|
8068
|
-
return value
|
|
8069
|
-
}
|
|
8070
|
-
function resolveCloudAppUrl() {
|
|
8071
|
-
const value = process.env.OPENSTEER_APP_URL?.trim();
|
|
8072
|
-
if (!value) return DEFAULT_CLOUD_APP_URL;
|
|
8073
|
-
return normalizeCloudAppUrl(value);
|
|
8093
|
+
return normalizeCloudBaseUrl(value);
|
|
8074
8094
|
}
|
|
8075
|
-
function
|
|
8076
|
-
if (!value) return null;
|
|
8095
|
+
function normalizeCloudBaseUrl(value) {
|
|
8077
8096
|
return value.replace(/\/+$/, "");
|
|
8078
8097
|
}
|
|
8079
8098
|
function readCloudActionDescription(payload) {
|
|
@@ -8131,8 +8150,7 @@ var Opensteer = class _Opensteer {
|
|
|
8131
8150
|
this.cloud = createCloudRuntimeState(
|
|
8132
8151
|
apiKey,
|
|
8133
8152
|
cloudConfig?.baseUrl,
|
|
8134
|
-
cloudConfig?.authScheme
|
|
8135
|
-
cloudConfig?.appUrl
|
|
8153
|
+
cloudConfig?.authScheme
|
|
8136
8154
|
);
|
|
8137
8155
|
} else {
|
|
8138
8156
|
this.cloud = null;
|
|
@@ -8324,10 +8342,7 @@ var Opensteer = class _Opensteer {
|
|
|
8324
8342
|
this.snapshotCache = null;
|
|
8325
8343
|
this.cloud.actionClient = actionClient;
|
|
8326
8344
|
this.cloud.sessionId = sessionId;
|
|
8327
|
-
this.cloud.cloudSessionUrl =
|
|
8328
|
-
this.cloud.appUrl,
|
|
8329
|
-
session3.cloudSession.sessionId
|
|
8330
|
-
);
|
|
8345
|
+
this.cloud.cloudSessionUrl = session3.cloudSessionUrl;
|
|
8331
8346
|
this.announceCloudSession({
|
|
8332
8347
|
sessionId: session3.sessionId,
|
|
8333
8348
|
workspaceId: session3.cloudSession.workspaceId,
|
|
@@ -10384,12 +10399,6 @@ function buildLocalRunId(namespace) {
|
|
|
10384
10399
|
const normalized = namespace.trim() || "default";
|
|
10385
10400
|
return `${normalized}-${Date.now().toString(36)}-${(0, import_crypto2.randomUUID)().slice(0, 8)}`;
|
|
10386
10401
|
}
|
|
10387
|
-
function buildCloudSessionUrl(appUrl, sessionId) {
|
|
10388
|
-
if (!appUrl) {
|
|
10389
|
-
return null;
|
|
10390
|
-
}
|
|
10391
|
-
return `${appUrl}/browser/${encodeURIComponent(sessionId)}`;
|
|
10392
|
-
}
|
|
10393
10402
|
|
|
10394
10403
|
// src/cli/paths.ts
|
|
10395
10404
|
var import_os2 = require("os");
|
package/dist/cli/server.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1111,6 +1111,11 @@ function resolveOpensteerApiKey(env) {
|
|
|
1111
1111
|
if (!value) return void 0;
|
|
1112
1112
|
return value;
|
|
1113
1113
|
}
|
|
1114
|
+
function resolveOpensteerBaseUrl(env) {
|
|
1115
|
+
const value = env.OPENSTEER_BASE_URL?.trim();
|
|
1116
|
+
if (!value) return void 0;
|
|
1117
|
+
return value;
|
|
1118
|
+
}
|
|
1114
1119
|
function resolveOpensteerAuthScheme(env) {
|
|
1115
1120
|
return parseAuthScheme(env.OPENSTEER_AUTH_SCHEME, "OPENSTEER_AUTH_SCHEME");
|
|
1116
1121
|
}
|
|
@@ -1189,6 +1194,7 @@ function resolveConfig(input = {}) {
|
|
|
1189
1194
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1190
1195
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
1191
1196
|
const envApiKey = resolveOpensteerApiKey(env);
|
|
1197
|
+
const envBaseUrl = resolveOpensteerBaseUrl(env);
|
|
1192
1198
|
const envAuthScheme = resolveOpensteerAuthScheme(env);
|
|
1193
1199
|
const envCloudAnnounce = parseCloudAnnounce(
|
|
1194
1200
|
env.OPENSTEER_REMOTE_ANNOUNCE,
|
|
@@ -1206,6 +1212,9 @@ function resolveConfig(input = {}) {
|
|
|
1206
1212
|
const inputHasCloudApiKey = Boolean(
|
|
1207
1213
|
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "apiKey")
|
|
1208
1214
|
);
|
|
1215
|
+
const inputHasCloudBaseUrl = Boolean(
|
|
1216
|
+
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
|
|
1217
|
+
);
|
|
1209
1218
|
const cloudSelection = resolveCloudSelection({
|
|
1210
1219
|
cloud: resolved.cloud
|
|
1211
1220
|
}, env);
|
|
@@ -1225,6 +1234,12 @@ function resolveConfig(input = {}) {
|
|
|
1225
1234
|
apiKey: envApiKey
|
|
1226
1235
|
};
|
|
1227
1236
|
}
|
|
1237
|
+
if (envBaseUrl && cloudSelection.cloud && !inputHasCloudBaseUrl) {
|
|
1238
|
+
resolved.cloud = {
|
|
1239
|
+
...normalizeCloudOptions(resolved.cloud) ?? {},
|
|
1240
|
+
baseUrl: envBaseUrl
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1228
1243
|
return resolved;
|
|
1229
1244
|
}
|
|
1230
1245
|
function resolveNamespace(config, rootDir) {
|
|
@@ -1265,6 +1280,7 @@ function getCallerFilePath() {
|
|
|
1265
1280
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1266
1281
|
var DEFAULT_SETTLE_MS = 750;
|
|
1267
1282
|
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
1283
|
+
var TRANSIENT_CONTEXT_RETRY_DELAY_MS = 25;
|
|
1268
1284
|
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
1269
1285
|
var StealthWaitUnavailableError = class extends Error {
|
|
1270
1286
|
constructor(cause) {
|
|
@@ -1568,9 +1584,12 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1568
1584
|
const frameRecords = await this.getFrameRecords();
|
|
1569
1585
|
const mainFrame = frameRecords[0];
|
|
1570
1586
|
if (!mainFrame) return;
|
|
1571
|
-
await this.waitForFrameVisualStability(
|
|
1572
|
-
|
|
1573
|
-
|
|
1587
|
+
await this.waitForFrameVisualStability(
|
|
1588
|
+
mainFrame.frameId,
|
|
1589
|
+
timeout,
|
|
1590
|
+
settleMs,
|
|
1591
|
+
true
|
|
1592
|
+
);
|
|
1574
1593
|
}
|
|
1575
1594
|
async collectVisibleFrameIds() {
|
|
1576
1595
|
const frameRecords = await this.getFrameRecords();
|
|
@@ -1599,16 +1618,15 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1599
1618
|
}
|
|
1600
1619
|
return visibleFrameIds;
|
|
1601
1620
|
}
|
|
1602
|
-
async waitForFrameVisualStability(frameId, timeout, settleMs,
|
|
1621
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs, retryTransientContextErrors = true) {
|
|
1603
1622
|
if (timeout <= 0) return;
|
|
1604
1623
|
const script = buildStabilityScript(timeout, settleMs);
|
|
1605
|
-
const retryTransientContextErrors = options.retryTransientContextErrors ?? true;
|
|
1606
1624
|
if (!retryTransientContextErrors) {
|
|
1607
1625
|
let contextId = await this.ensureFrameContextId(frameId);
|
|
1608
1626
|
try {
|
|
1609
1627
|
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1610
1628
|
} catch (error) {
|
|
1611
|
-
if (!
|
|
1629
|
+
if (!isMissingExecutionContextError(error)) {
|
|
1612
1630
|
throw error;
|
|
1613
1631
|
}
|
|
1614
1632
|
this.contextsByFrame.delete(frameId);
|
|
@@ -1632,6 +1650,11 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
1632
1650
|
throw error;
|
|
1633
1651
|
}
|
|
1634
1652
|
this.contextsByFrame.delete(frameId);
|
|
1653
|
+
const retryDelay = Math.min(
|
|
1654
|
+
TRANSIENT_CONTEXT_RETRY_DELAY_MS,
|
|
1655
|
+
Math.max(0, deadline - Date.now())
|
|
1656
|
+
);
|
|
1657
|
+
await sleep(retryDelay);
|
|
1635
1658
|
}
|
|
1636
1659
|
}
|
|
1637
1660
|
}
|
|
@@ -1753,9 +1776,7 @@ async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
|
1753
1776
|
frameId,
|
|
1754
1777
|
remaining,
|
|
1755
1778
|
settleMs,
|
|
1756
|
-
|
|
1757
|
-
retryTransientContextErrors: false
|
|
1758
|
-
}
|
|
1779
|
+
false
|
|
1759
1780
|
);
|
|
1760
1781
|
} catch (error) {
|
|
1761
1782
|
if (isIgnorableFrameError(error)) return;
|
|
@@ -1798,7 +1819,7 @@ function isTransientExecutionContextError(error) {
|
|
|
1798
1819
|
const message = error.message;
|
|
1799
1820
|
return message.includes("Execution context was destroyed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
1800
1821
|
}
|
|
1801
|
-
function
|
|
1822
|
+
function isMissingExecutionContextError(error) {
|
|
1802
1823
|
if (!(error instanceof Error)) return false;
|
|
1803
1824
|
const message = error.message;
|
|
1804
1825
|
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
@@ -8135,12 +8156,16 @@ function toCloudErrorCode(code) {
|
|
|
8135
8156
|
|
|
8136
8157
|
// src/cloud/runtime.ts
|
|
8137
8158
|
var DEFAULT_CLOUD_BASE_URL = "https://remote.opensteer.com";
|
|
8138
|
-
|
|
8139
|
-
|
|
8159
|
+
function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authScheme = "api-key") {
|
|
8160
|
+
const normalizedBaseUrl = normalizeCloudBaseUrl(baseUrl);
|
|
8140
8161
|
return {
|
|
8141
|
-
sessionClient: new CloudSessionClient(
|
|
8162
|
+
sessionClient: new CloudSessionClient(
|
|
8163
|
+
normalizedBaseUrl,
|
|
8164
|
+
key,
|
|
8165
|
+
authScheme
|
|
8166
|
+
),
|
|
8142
8167
|
cdpClient: new CloudCdpClient(),
|
|
8143
|
-
|
|
8168
|
+
baseUrl: normalizedBaseUrl,
|
|
8144
8169
|
actionClient: null,
|
|
8145
8170
|
sessionId: null,
|
|
8146
8171
|
localRunId: null,
|
|
@@ -8150,15 +8175,9 @@ function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authSchem
|
|
|
8150
8175
|
function resolveCloudBaseUrl() {
|
|
8151
8176
|
const value = process.env.OPENSTEER_BASE_URL?.trim();
|
|
8152
8177
|
if (!value) return DEFAULT_CLOUD_BASE_URL;
|
|
8153
|
-
return value
|
|
8154
|
-
}
|
|
8155
|
-
function resolveCloudAppUrl() {
|
|
8156
|
-
const value = process.env.OPENSTEER_APP_URL?.trim();
|
|
8157
|
-
if (!value) return DEFAULT_CLOUD_APP_URL;
|
|
8158
|
-
return normalizeCloudAppUrl(value);
|
|
8178
|
+
return normalizeCloudBaseUrl(value);
|
|
8159
8179
|
}
|
|
8160
|
-
function
|
|
8161
|
-
if (!value) return null;
|
|
8180
|
+
function normalizeCloudBaseUrl(value) {
|
|
8162
8181
|
return value.replace(/\/+$/, "");
|
|
8163
8182
|
}
|
|
8164
8183
|
function readCloudActionDescription(payload) {
|
|
@@ -8216,8 +8235,7 @@ var Opensteer = class _Opensteer {
|
|
|
8216
8235
|
this.cloud = createCloudRuntimeState(
|
|
8217
8236
|
apiKey,
|
|
8218
8237
|
cloudConfig?.baseUrl,
|
|
8219
|
-
cloudConfig?.authScheme
|
|
8220
|
-
cloudConfig?.appUrl
|
|
8238
|
+
cloudConfig?.authScheme
|
|
8221
8239
|
);
|
|
8222
8240
|
} else {
|
|
8223
8241
|
this.cloud = null;
|
|
@@ -8409,10 +8427,7 @@ var Opensteer = class _Opensteer {
|
|
|
8409
8427
|
this.snapshotCache = null;
|
|
8410
8428
|
this.cloud.actionClient = actionClient;
|
|
8411
8429
|
this.cloud.sessionId = sessionId;
|
|
8412
|
-
this.cloud.cloudSessionUrl =
|
|
8413
|
-
this.cloud.appUrl,
|
|
8414
|
-
session2.cloudSession.sessionId
|
|
8415
|
-
);
|
|
8430
|
+
this.cloud.cloudSessionUrl = session2.cloudSessionUrl;
|
|
8416
8431
|
this.announceCloudSession({
|
|
8417
8432
|
sessionId: session2.sessionId,
|
|
8418
8433
|
workspaceId: session2.cloudSession.workspaceId,
|
|
@@ -10469,12 +10484,6 @@ function buildLocalRunId(namespace) {
|
|
|
10469
10484
|
const normalized = namespace.trim() || "default";
|
|
10470
10485
|
return `${normalized}-${Date.now().toString(36)}-${(0, import_crypto2.randomUUID)().slice(0, 8)}`;
|
|
10471
10486
|
}
|
|
10472
|
-
function buildCloudSessionUrl(appUrl, sessionId) {
|
|
10473
|
-
if (!appUrl) {
|
|
10474
|
-
return null;
|
|
10475
|
-
}
|
|
10476
|
-
return `${appUrl}/browser/${encodeURIComponent(sessionId)}`;
|
|
10477
|
-
}
|
|
10478
10487
|
|
|
10479
10488
|
// src/ai/index.ts
|
|
10480
10489
|
init_resolver();
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,82 +1,75 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"require": "./dist/index.cjs"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"files": [
|
|
22
|
-
"dist",
|
|
23
|
-
"bin",
|
|
24
|
-
"README.md",
|
|
25
|
-
"LICENSE",
|
|
26
|
-
"CHANGELOG.md"
|
|
27
|
-
],
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsup src/index.ts src/cli/server.ts --dts --format esm,cjs --clean --external ai --external zod --external @ai-sdk/openai --external @ai-sdk/anthropic --external @ai-sdk/google --external @ai-sdk/xai --external @ai-sdk/groq",
|
|
30
|
-
"prepublishOnly": "pnpm run build",
|
|
31
|
-
"test": "vitest run",
|
|
32
|
-
"test:live-web": "vitest run --config vitest.live-web.config.ts",
|
|
33
|
-
"test:unit": "vitest run tests/html tests/element-path tests/config.test.ts tests/storage",
|
|
34
|
-
"test:actions": "vitest run tests/actions",
|
|
35
|
-
"test:integration": "vitest run tests/integration",
|
|
36
|
-
"test:ai": "vitest run tests/ai tests/e2e/ai-resolve.test.ts tests/e2e/ai-extract-products.test.ts",
|
|
37
|
-
"test:e2e": "vitest run tests/e2e",
|
|
38
|
-
"test:app:dev": "pnpm --dir tests/test-app run dev",
|
|
39
|
-
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"@ai-sdk/anthropic": "^3.0.46",
|
|
43
|
-
"@ai-sdk/google": "^3.0.30",
|
|
44
|
-
"@ai-sdk/groq": "^3.0.24",
|
|
45
|
-
"@ai-sdk/openai": "^3.0.26",
|
|
46
|
-
"@ai-sdk/xai": "^3.0.57",
|
|
47
|
-
"ai": "^6.0.77",
|
|
48
|
-
"cheerio": "^1.0.0-rc.12",
|
|
49
|
-
"dotenv": "^17.2.4",
|
|
50
|
-
"playwright": "^1.50.0",
|
|
51
|
-
"ws": "^8.18.0",
|
|
52
|
-
"zod": "^4.3.6"
|
|
53
|
-
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@types/node": "^22.10.0",
|
|
56
|
-
"@types/ws": "^8.5.13",
|
|
57
|
-
"domhandler": "^5.0.3",
|
|
58
|
-
"tsup": "^8.0.1",
|
|
59
|
-
"typescript": "^5.6.3",
|
|
60
|
-
"vite": "^7.3.1",
|
|
61
|
-
"vitest": "^2.1.8"
|
|
62
|
-
},
|
|
63
|
-
"pnpm": {
|
|
64
|
-
"onlyBuiltDependencies": [
|
|
65
|
-
"esbuild"
|
|
66
|
-
]
|
|
67
|
-
},
|
|
68
|
-
"engines": {
|
|
69
|
-
"node": ">=20"
|
|
70
|
-
},
|
|
71
|
-
"keywords": [
|
|
72
|
-
"browser-automation",
|
|
73
|
-
"selectors",
|
|
74
|
-
"playwright",
|
|
75
|
-
"llm",
|
|
76
|
-
"agents"
|
|
77
|
-
],
|
|
78
|
-
"repository": {
|
|
79
|
-
"type": "git",
|
|
80
|
-
"url": "https://github.com/opensteer-ai/opensteer"
|
|
2
|
+
"name": "opensteer",
|
|
3
|
+
"version": "0.4.11",
|
|
4
|
+
"description": "Open-source browser automation SDK with robust selectors and deterministic replay.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"opensteer": "./bin/opensteer.mjs"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.cjs",
|
|
11
|
+
"module": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js",
|
|
17
|
+
"require": "./dist/index.cjs"
|
|
81
18
|
}
|
|
82
|
-
}
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"bin",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"CHANGELOG.md"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@ai-sdk/anthropic": "^3.0.46",
|
|
29
|
+
"@ai-sdk/google": "^3.0.30",
|
|
30
|
+
"@ai-sdk/groq": "^3.0.24",
|
|
31
|
+
"@ai-sdk/openai": "^3.0.26",
|
|
32
|
+
"@ai-sdk/xai": "^3.0.57",
|
|
33
|
+
"ai": "^6.0.77",
|
|
34
|
+
"cheerio": "^1.0.0-rc.12",
|
|
35
|
+
"dotenv": "^17.2.4",
|
|
36
|
+
"playwright": "^1.50.0",
|
|
37
|
+
"ws": "^8.18.0",
|
|
38
|
+
"zod": "^4.3.6"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.10.0",
|
|
42
|
+
"@types/ws": "^8.5.13",
|
|
43
|
+
"domhandler": "^5.0.3",
|
|
44
|
+
"tsup": "^8.0.1",
|
|
45
|
+
"typescript": "^5.6.3",
|
|
46
|
+
"vite": "^7.3.1",
|
|
47
|
+
"vitest": "^2.1.8"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"browser-automation",
|
|
54
|
+
"selectors",
|
|
55
|
+
"playwright",
|
|
56
|
+
"llm",
|
|
57
|
+
"agents"
|
|
58
|
+
],
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "https://github.com/opensteer-ai/opensteer"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsup src/index.ts src/cli/server.ts --dts --format esm,cjs --clean --external ai --external zod --external @ai-sdk/openai --external @ai-sdk/anthropic --external @ai-sdk/google --external @ai-sdk/xai --external @ai-sdk/groq",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"test:live-web": "vitest run --config vitest.live-web.config.ts",
|
|
67
|
+
"test:unit": "vitest run tests/html tests/element-path tests/config.test.ts tests/storage",
|
|
68
|
+
"test:actions": "vitest run tests/actions",
|
|
69
|
+
"test:integration": "vitest run tests/integration",
|
|
70
|
+
"test:ai": "vitest run tests/ai tests/e2e/ai-resolve.test.ts tests/e2e/ai-extract-products.test.ts",
|
|
71
|
+
"test:e2e": "vitest run tests/e2e",
|
|
72
|
+
"test:app:dev": "pnpm --dir tests/test-app run dev",
|
|
73
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
74
|
+
}
|
|
75
|
+
}
|