opensteer 0.9.0 → 0.9.2
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 +0 -3
- package/dist/chunk-2TIVULZY.js +4103 -0
- package/dist/chunk-2TIVULZY.js.map +1 -0
- package/dist/chunk-BMPUL66S.js +1170 -0
- package/dist/chunk-BMPUL66S.js.map +1 -0
- package/dist/chunk-FIMNKEG5.js +1800 -0
- package/dist/chunk-FIMNKEG5.js.map +1 -0
- package/dist/{chunk-656MQUSM.js → chunk-HD6KVZ42.js} +6080 -12739
- package/dist/chunk-HD6KVZ42.js.map +1 -0
- package/dist/{chunk-OIKLSFXA.js → chunk-KPYLS2KQ.js} +5 -35
- package/dist/chunk-KPYLS2KQ.js.map +1 -0
- package/dist/cli/bin.cjs +7436 -6861
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.js +124 -7
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.cjs +1048 -2584
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -757
- package/dist/index.d.ts +60 -757
- package/dist/index.js +4 -2
- package/dist/local-view/public/assets/app.css +770 -0
- package/dist/local-view/public/assets/app.js +2053 -0
- package/dist/local-view/public/index.html +235 -0
- package/dist/local-view/serve-entry.cjs +7203 -0
- package/dist/local-view/serve-entry.cjs.map +1 -0
- package/dist/local-view/serve-entry.d.cts +1 -0
- package/dist/local-view/serve-entry.d.ts +1 -0
- package/dist/local-view/serve-entry.js +23 -0
- package/dist/local-view/serve-entry.js.map +1 -0
- package/dist/opensteer-MIQ43CY4.js +6 -0
- package/dist/{opensteer-LKX3233A.js.map → opensteer-MIQ43CY4.js.map} +1 -1
- package/dist/session-control-IFE3IPS3.js +39 -0
- package/dist/session-control-IFE3IPS3.js.map +1 -0
- package/package.json +8 -8
- package/skills/README.md +3 -0
- package/skills/opensteer/SKILL.md +230 -49
- package/dist/chunk-656MQUSM.js.map +0 -1
- package/dist/chunk-OIKLSFXA.js.map +0 -1
- package/dist/opensteer-LKX3233A.js +0 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runLocalViewService } from '../chunk-FIMNKEG5.js';
|
|
3
|
+
import '../chunk-BMPUL66S.js';
|
|
4
|
+
|
|
5
|
+
// src/local-view/serve-entry.ts
|
|
6
|
+
runLocalViewService().catch((error) => {
|
|
7
|
+
const payload = error instanceof Error ? {
|
|
8
|
+
error: {
|
|
9
|
+
name: error.name,
|
|
10
|
+
message: error.message
|
|
11
|
+
}
|
|
12
|
+
} : {
|
|
13
|
+
error: {
|
|
14
|
+
name: "Error",
|
|
15
|
+
message: String(error)
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
process.stderr.write(`${JSON.stringify(payload)}
|
|
19
|
+
`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=serve-entry.js.map
|
|
23
|
+
//# sourceMappingURL=serve-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/local-view/serve-entry.ts"],"names":[],"mappings":";;;;;AAIA,mBAAA,EAAoB,CAAE,KAAA,CAAM,CAAC,KAAA,KAAU;AACrC,EAAA,MAAM,OAAA,GACJ,iBAAiB,KAAA,GACb;AAAA,IACE,KAAA,EAAO;AAAA,MACL,MAAM,KAAA,CAAM,IAAA;AAAA,MACZ,SAAS,KAAA,CAAM;AAAA;AACjB,GACF,GACA;AAAA,IACE,KAAA,EAAO;AAAA,MACL,IAAA,EAAM,OAAA;AAAA,MACN,OAAA,EAAS,OAAO,KAAK;AAAA;AACvB,GACF;AACN,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,OAAO,CAAC;AAAA,CAAI,CAAA;AACnD,EAAA,OAAA,CAAQ,QAAA,GAAW,CAAA;AACrB,CAAC,CAAA","file":"serve-entry.js","sourcesContent":["#!/usr/bin/env node\n\nimport { runLocalViewService } from \"./serve.js\";\n\nrunLocalViewService().catch((error) => {\n const payload =\n error instanceof Error\n ? {\n error: {\n name: error.name,\n message: error.message,\n },\n }\n : {\n error: {\n name: \"Error\",\n message: String(error),\n },\n };\n process.stderr.write(`${JSON.stringify(payload)}\\n`);\n process.exitCode = 1;\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"opensteer-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"opensteer-MIQ43CY4.js"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { OpensteerBrowserManager } from './chunk-2TIVULZY.js';
|
|
2
|
+
import { readLocalViewSessionManifest, readPersistedLocalBrowserSessionRecord, deleteLocalViewSessionManifest } from './chunk-BMPUL66S.js';
|
|
3
|
+
|
|
4
|
+
// src/local-view/session-control.ts
|
|
5
|
+
var LocalViewSessionCloseError = class extends Error {
|
|
6
|
+
constructor(message, statusCode) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.name = "LocalViewSessionCloseError";
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
async function closeLocalViewSessionBrowser(sessionId) {
|
|
13
|
+
const manifest = await readLocalViewSessionManifest(sessionId);
|
|
14
|
+
if (!manifest) {
|
|
15
|
+
throw new LocalViewSessionCloseError("Session not found.", 404);
|
|
16
|
+
}
|
|
17
|
+
if (manifest.ownership !== "owned") {
|
|
18
|
+
throw new LocalViewSessionCloseError(
|
|
19
|
+
"Only Opensteer-owned local browsers can be closed from the local view.",
|
|
20
|
+
409
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
const record = await readPersistedLocalBrowserSessionRecord(manifest.rootPath);
|
|
24
|
+
if (!record || record.pid !== manifest.pid || record.startedAt !== manifest.startedAt || record.engine !== manifest.engine) {
|
|
25
|
+
await deleteLocalViewSessionManifest(sessionId).catch(() => void 0);
|
|
26
|
+
throw new LocalViewSessionCloseError("Session not found.", 404);
|
|
27
|
+
}
|
|
28
|
+
const manager = new OpensteerBrowserManager({
|
|
29
|
+
rootPath: manifest.rootPath,
|
|
30
|
+
...manifest.workspace === void 0 ? {} : { workspace: manifest.workspace },
|
|
31
|
+
engineName: record.engine,
|
|
32
|
+
browser: "persistent"
|
|
33
|
+
});
|
|
34
|
+
await manager.close();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { LocalViewSessionCloseError, closeLocalViewSessionBrowser };
|
|
38
|
+
//# sourceMappingURL=session-control-IFE3IPS3.js.map
|
|
39
|
+
//# sourceMappingURL=session-control-IFE3IPS3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/local-view/session-control.ts"],"names":[],"mappings":";;;;AAOO,IAAM,0BAAA,GAAN,cAAyC,KAAA,CAAM;AAAA,EACpD,WAAA,CACE,SACS,UAAA,EACT;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAFJ,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AAGT,IAAA,IAAA,CAAK,IAAA,GAAO,4BAAA;AAAA,EACd;AACF;AAEA,eAAsB,6BAA6B,SAAA,EAAkC;AACnF,EAAA,MAAM,QAAA,GAAW,MAAM,4BAAA,CAA6B,SAAS,CAAA;AAC7D,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,MAAM,IAAI,0BAAA,CAA2B,oBAAA,EAAsB,GAAG,CAAA;AAAA,EAChE;AAEA,EAAA,IAAI,QAAA,CAAS,cAAc,OAAA,EAAS;AAClC,IAAA,MAAM,IAAI,0BAAA;AAAA,MACR,wEAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,MAAM,sCAAA,CAAuC,QAAA,CAAS,QAAQ,CAAA;AAC7E,EAAA,IACE,CAAC,MAAA,IACD,MAAA,CAAO,GAAA,KAAQ,QAAA,CAAS,GAAA,IACxB,MAAA,CAAO,SAAA,KAAc,QAAA,CAAS,SAAA,IAC9B,MAAA,CAAO,MAAA,KAAW,SAAS,MAAA,EAC3B;AACA,IAAA,MAAM,8BAAA,CAA+B,SAAS,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AACrE,IAAA,MAAM,IAAI,0BAAA,CAA2B,oBAAA,EAAsB,GAAG,CAAA;AAAA,EAChE;AAEA,EAAA,MAAM,OAAA,GAAU,IAAI,uBAAA,CAAwB;AAAA,IAC1C,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,GAAI,SAAS,SAAA,KAAc,MAAA,GAAY,EAAC,GAAI,EAAE,SAAA,EAAW,QAAA,CAAS,SAAA,EAAU;AAAA,IAC5E,YAAY,MAAA,CAAO,MAAA;AAAA,IACnB,OAAA,EAAS;AAAA,GACV,CAAA;AACD,EAAA,MAAM,QAAQ,KAAA,EAAM;AACtB","file":"session-control-IFE3IPS3.js","sourcesContent":["import { readPersistedLocalBrowserSessionRecord } from \"../live-session.js\";\nimport { OpensteerBrowserManager } from \"../browser-manager.js\";\nimport {\n deleteLocalViewSessionManifest,\n readLocalViewSessionManifest,\n} from \"./session-manifest.js\";\n\nexport class LocalViewSessionCloseError extends Error {\n constructor(\n message: string,\n readonly statusCode: 404 | 409,\n ) {\n super(message);\n this.name = \"LocalViewSessionCloseError\";\n }\n}\n\nexport async function closeLocalViewSessionBrowser(sessionId: string): Promise<void> {\n const manifest = await readLocalViewSessionManifest(sessionId);\n if (!manifest) {\n throw new LocalViewSessionCloseError(\"Session not found.\", 404);\n }\n\n if (manifest.ownership !== \"owned\") {\n throw new LocalViewSessionCloseError(\n \"Only Opensteer-owned local browsers can be closed from the local view.\",\n 409,\n );\n }\n\n const record = await readPersistedLocalBrowserSessionRecord(manifest.rootPath);\n if (\n !record ||\n record.pid !== manifest.pid ||\n record.startedAt !== manifest.startedAt ||\n record.engine !== manifest.engine\n ) {\n await deleteLocalViewSessionManifest(sessionId).catch(() => undefined);\n throw new LocalViewSessionCloseError(\"Session not found.\", 404);\n }\n\n const manager = new OpensteerBrowserManager({\n rootPath: manifest.rootPath,\n ...(manifest.workspace === undefined ? {} : { workspace: manifest.workspace }),\n engineName: record.engine,\n browser: \"persistent\",\n });\n await manager.close();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opensteer",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Opensteer browser automation, replay, and reverse-engineering toolkit.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
"sharp": "^0.34.5",
|
|
57
57
|
"skills": "^1.4.6",
|
|
58
58
|
"ws": "^8.18.0",
|
|
59
|
-
"@opensteer/
|
|
60
|
-
"@opensteer/
|
|
59
|
+
"@opensteer/engine-playwright": "0.8.8",
|
|
60
|
+
"@opensteer/runtime-core": "0.2.2"
|
|
61
61
|
},
|
|
62
62
|
"optionalDependencies": {
|
|
63
63
|
"webcrack": "^2.15.1"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@opensteer/engine-abp": "0.8.
|
|
66
|
+
"@opensteer/engine-abp": "0.8.9"
|
|
67
67
|
},
|
|
68
68
|
"peerDependenciesMeta": {
|
|
69
69
|
"@opensteer/engine-abp": {
|
|
@@ -71,12 +71,12 @@
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@opensteer/browser-core": "0.7.
|
|
75
|
-
"@opensteer/
|
|
76
|
-
"@opensteer/
|
|
74
|
+
"@opensteer/browser-core": "0.7.9",
|
|
75
|
+
"@opensteer/protocol": "0.8.2",
|
|
76
|
+
"@opensteer/engine-abp": "0.8.9"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
|
-
"build": "tsup && node ../../scripts/sync-package-skills.mjs",
|
|
79
|
+
"build": "tsup && node ../../scripts/copy-opensteer-local-view-assets.mjs && node ../../scripts/sync-package-skills.mjs",
|
|
80
80
|
"clean": "rimraf dist skills",
|
|
81
81
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
82
82
|
}
|
package/skills/README.md
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
First-party Opensteer skills published from this repository. Install them through the upstream [`skills`](https://skills.sh) CLI into Codex, Cursor, Claude Code, and other compatible agents.
|
|
4
4
|
|
|
5
|
+
From an Opensteer checkout, the installer prefers the local `skills/` directory so
|
|
6
|
+
Codex, Cursor, and Claude Code see the current repo `SKILL.md` immediately.
|
|
7
|
+
|
|
5
8
|
## Install
|
|
6
9
|
|
|
7
10
|
```bash
|
|
@@ -6,31 +6,34 @@ argument-hint: "[goal]"
|
|
|
6
6
|
|
|
7
7
|
# Opensteer
|
|
8
8
|
|
|
9
|
-
Use
|
|
9
|
+
Opensteer gives AI agents a real Chromium browser — local or cloud. Use it when normal code is not enough because the task depends on a live browser session.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- inspect browser state like cookies or storage
|
|
13
|
-
- capture real network traffic from real browser actions
|
|
14
|
-
- replay requests through the browser session
|
|
15
|
-
- turn the discovery into plain TypeScript
|
|
11
|
+
Default workflow:
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
1. CLI to explore the site and discover behavior.
|
|
14
|
+
2. Save stable targets with `persist`.
|
|
15
|
+
3. SDK to write the final reusable TypeScript.
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
2. Figure out the page or API behavior.
|
|
21
|
-
3. Save stable targets with `persist` when useful.
|
|
22
|
-
4. Write the final reusable code with the SDK.
|
|
17
|
+
Do not stop at manual exploration if the user needs automation.
|
|
23
18
|
|
|
24
|
-
|
|
19
|
+
## Setup
|
|
20
|
+
|
|
21
|
+
Install the Opensteer skill so the coding agent can use it:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
opensteer skills install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This registers the skill with the agent's tool system. Only needed once per environment.
|
|
25
28
|
|
|
26
29
|
## When To Use
|
|
27
30
|
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
31
|
+
- Real browser session needed (clicks, forms, DOM extraction, navigation).
|
|
32
|
+
- Cookies, localStorage, sessionStorage, or auth state involved.
|
|
33
|
+
- Reverse-engineering a site API from real browser traffic.
|
|
34
|
+
- Browser-backed `fetch()` instead of plain Node HTTP.
|
|
35
|
+
- Coordinate-based interaction (canvas, WebGL, hard-to-target UI).
|
|
36
|
+
- Need to reuse a real user's logged-in browser profile.
|
|
34
37
|
|
|
35
38
|
If the user wants to manually drive a browser and record the flow, use the `recorder` skill instead.
|
|
36
39
|
|
|
@@ -39,20 +42,27 @@ If the user wants to manually drive a browser and record the flow, use the `reco
|
|
|
39
42
|
1. Always use a workspace for stateful commands: `--workspace <id>` or `OPENSTEER_WORKSPACE`.
|
|
40
43
|
2. In this repo, prefer `pnpm run opensteer:local -- <command>` instead of bare `opensteer ...`.
|
|
41
44
|
3. Re-snapshot after navigation or big UI changes before reusing element numbers.
|
|
42
|
-
4.
|
|
45
|
+
4. CLI to discover, SDK for the final implementation.
|
|
43
46
|
5. Use `persist` for stable reusable targets and extraction payloads.
|
|
44
47
|
6. Use `exec` for SDK code and API experiments. Use `evaluate` only for page-context JavaScript.
|
|
45
48
|
7. If `fetch()` fails with auth errors, inspect `state()`, `cookies()`, and `storage()` before changing transport.
|
|
46
|
-
8. Keep
|
|
47
|
-
9. Close the browser when
|
|
49
|
+
8. Keep output simple. Prefer ordinary TypeScript with `Opensteer`, no extra abstraction.
|
|
50
|
+
9. Close the browser when done. Do not leave headed browsers running. Use `opensteer browser delete --workspace <id>` or SDK cleanup when the session does not need to stay open.
|
|
48
51
|
|
|
49
52
|
## Choose A Path
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
```
|
|
55
|
+
What does the task need?
|
|
56
|
+
├─ Click, type, navigate, extract visible data → DOM path
|
|
57
|
+
├─ Find or replay a site API → Network path
|
|
58
|
+
├─ Analyze, deobfuscate, or sandbox page JavaScript → Scripts analysis
|
|
59
|
+
├─ Canvas, WebGL, or hard-to-target UI → Computer-use
|
|
60
|
+
├─ Work with multiple tabs or popups → Tab management
|
|
61
|
+
├─ Set up browser profile, clone, or attach → Browser sessions
|
|
62
|
+
├─ Run browser in the cloud → Cloud mode
|
|
63
|
+
├─ Watch what a headless browser is doing → Local view
|
|
64
|
+
└─ Unsure → start by capturing network traffic
|
|
65
|
+
```
|
|
56
66
|
|
|
57
67
|
## DOM Path
|
|
58
68
|
|
|
@@ -106,8 +116,6 @@ Use `network detail --probe` to learn which transport works.
|
|
|
106
116
|
|
|
107
117
|
### Session state checks
|
|
108
118
|
|
|
109
|
-
Use these when auth or browser state matters:
|
|
110
|
-
|
|
111
119
|
```bash
|
|
112
120
|
opensteer state example.com --workspace demo
|
|
113
121
|
```
|
|
@@ -151,6 +159,54 @@ export async function search(keyword: string) {
|
|
|
151
159
|
|
|
152
160
|
Use ordinary `fetch()` syntax. Only set `transport` explicitly if probing showed you need it.
|
|
153
161
|
|
|
162
|
+
## Scripts Analysis
|
|
163
|
+
|
|
164
|
+
Use this when you need to understand what JavaScript a page is running — reverse-engineering obfuscated code, finding hidden API calls, or testing script behavior in isolation.
|
|
165
|
+
|
|
166
|
+
### Capture scripts from the page
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
opensteer scripts capture --workspace demo
|
|
170
|
+
opensteer scripts capture --workspace demo --url-filter "api" --external --dynamic
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Flags: `--inline`, `--external`, `--dynamic`, `--workers` to filter by source type. `--persist` to save as an artifact. `--url-filter <pattern>` to match script URLs.
|
|
174
|
+
|
|
175
|
+
### Beautify and deobfuscate
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Format minified code
|
|
179
|
+
opensteer scripts beautify <artifactId> --workspace demo --persist
|
|
180
|
+
|
|
181
|
+
# Deobfuscate packed/obfuscated code
|
|
182
|
+
opensteer scripts deobfuscate <artifactId> --workspace demo --persist
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Sandbox execution
|
|
186
|
+
|
|
187
|
+
Run captured JavaScript in isolation with controlled inputs:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
opensteer scripts sandbox <artifactId> --workspace demo \
|
|
191
|
+
--fidelity standard \
|
|
192
|
+
--timeout 5000 \
|
|
193
|
+
--cookies '{"session":"abc123"}' \
|
|
194
|
+
--globals '{"window.API_KEY":"test"}' \
|
|
195
|
+
--ajax-routes '[{"url":"*/api/*","response":{"data":[]}}]'
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Fidelity levels: `minimal` (fast, no DOM), `standard` (basic DOM), `full` (complete browser emulation).
|
|
199
|
+
|
|
200
|
+
### Typical workflow
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
opensteer scripts capture --workspace demo --persist --external
|
|
204
|
+
opensteer artifact read art_abc123 --workspace demo # inspect raw
|
|
205
|
+
opensteer scripts beautify art_abc123 --workspace demo --persist
|
|
206
|
+
opensteer scripts deobfuscate art_def456 --workspace demo --persist
|
|
207
|
+
opensteer scripts sandbox art_ghi789 --workspace demo
|
|
208
|
+
```
|
|
209
|
+
|
|
154
210
|
## Computer-Use
|
|
155
211
|
|
|
156
212
|
Use this only when DOM targeting is not enough.
|
|
@@ -170,54 +226,179 @@ await opensteer.computerExecute({
|
|
|
170
226
|
|
|
171
227
|
After coordinate-based actions, switch back to normal extraction or request analysis as soon as possible.
|
|
172
228
|
|
|
173
|
-
##
|
|
229
|
+
## Tab Management
|
|
230
|
+
|
|
231
|
+
Use when handling OAuth popups, multi-page flows, or any task that opens new tabs.
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
opensteer tab list --workspace demo # List all open tabs
|
|
235
|
+
opensteer tab new https://example.com --workspace demo # Open new tab
|
|
236
|
+
opensteer tab 2 --workspace demo # Switch to tab 2
|
|
237
|
+
opensteer tab close 3 --workspace demo # Close tab 3
|
|
238
|
+
opensteer tab close --workspace demo # Close current tab
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
const tabs = await opensteer.listPages();
|
|
243
|
+
await opensteer.newPage("https://example.com");
|
|
244
|
+
await opensteer.activatePage(2);
|
|
245
|
+
await opensteer.closePage(3);
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Re-snapshot after switching tabs — element numbers are per-page.
|
|
249
|
+
|
|
250
|
+
## Browser Sessions
|
|
251
|
+
|
|
252
|
+
Each workspace has one browser. Three modes:
|
|
253
|
+
|
|
254
|
+
| Mode | What it does | Data persists? |
|
|
255
|
+
| ------------------------ | ----------------------------------------------- | --------------------------------------------------------------------- |
|
|
256
|
+
| **Persistent** (default) | Browser tied to workspace, survives restarts | Yes — cookies, localStorage, logins, history, extensions all retained |
|
|
257
|
+
| **Temporary** | Headless browser in `/tmp`, cleaned up on close | No |
|
|
258
|
+
| **Attach** | Connects to an already-running browser via CDP | Depends on that browser |
|
|
259
|
+
|
|
260
|
+
### Headless vs headed
|
|
174
261
|
|
|
175
|
-
|
|
262
|
+
Browsers launch headless by default. Use `--headless false` to see the browser window:
|
|
176
263
|
|
|
177
264
|
```bash
|
|
265
|
+
opensteer open https://example.com --workspace demo --headless false
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Use headed mode for debugging or when the user wants to watch. For hands-free automation, keep headless and use `opensteer view` if a human needs to observe.
|
|
269
|
+
|
|
270
|
+
### Persistent sessions
|
|
271
|
+
|
|
272
|
+
When you `opensteer open` with a workspace, the browser's full Chrome user-data directory lives at `~/.opensteer/workspaces/<id>/browser/user-data/`. Everything Chrome normally persists (cookies, localStorage, IndexedDB, history, extensions) survives between runs.
|
|
273
|
+
|
|
274
|
+
Re-running `opensteer open --workspace demo` reconnects to the existing browser if it's still alive, or launches a fresh one with the same profile if it died.
|
|
275
|
+
|
|
276
|
+
### Profile cloning
|
|
277
|
+
|
|
278
|
+
Clone a real user's Chrome profile to start a workspace with their logins already active:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Discover available local browsers and profiles
|
|
178
282
|
opensteer browser discover
|
|
179
|
-
|
|
283
|
+
|
|
284
|
+
# Clone a profile into a workspace
|
|
180
285
|
opensteer browser clone --workspace demo \
|
|
181
286
|
--source-user-data-dir "$HOME/Library/Application Support/Google/Chrome" \
|
|
182
287
|
--source-profile-directory Default
|
|
183
|
-
opensteer browser status --workspace demo
|
|
184
|
-
opensteer browser reset --workspace demo
|
|
185
|
-
opensteer browser delete --workspace demo
|
|
186
288
|
```
|
|
187
289
|
|
|
188
|
-
|
|
290
|
+
This copies cookies, localStorage, extensions, and settings from the source browser. Caches and lock files are skipped. The source browser does not need to be closed — cloning while running is safe.
|
|
291
|
+
|
|
292
|
+
### Attach to an existing browser
|
|
189
293
|
|
|
190
294
|
```bash
|
|
191
295
|
opensteer open https://example.com --workspace demo --attach-endpoint http://localhost:9222
|
|
192
296
|
```
|
|
193
297
|
|
|
194
|
-
|
|
298
|
+
### Workspace lifecycle
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
opensteer browser status --workspace demo # Check if browser is running
|
|
302
|
+
opensteer browser reset --workspace demo # Wipe browser data, keep workspace
|
|
303
|
+
opensteer browser delete --workspace demo # Delete workspace entirely
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Cloud Mode
|
|
195
307
|
|
|
196
|
-
|
|
197
|
-
- Common env vars are `OPENSTEER_BASE_URL`, `OPENSTEER_API_KEY`, and `OPENSTEER_CLOUD_APP_BASE_URL`.
|
|
308
|
+
Run the browser on Opensteer's cloud infrastructure instead of locally. Use cloud mode when you need browsers that run 24/7, or when the local machine should not run Chromium.
|
|
198
309
|
|
|
199
|
-
|
|
310
|
+
### Setup
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
export OPENSTEER_API_KEY=osk_your_key_here # Required
|
|
314
|
+
export OPENSTEER_PROVIDER=cloud # Or use --provider cloud per command
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Usage
|
|
318
|
+
|
|
319
|
+
All CLI commands work the same with `--provider cloud`:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
opensteer open https://example.com --workspace demo --provider cloud
|
|
323
|
+
opensteer snapshot action --workspace demo
|
|
324
|
+
opensteer click 5 --workspace demo
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Export local browser profile to cloud
|
|
328
|
+
|
|
329
|
+
Sync a local browser's cookies to a cloud browser profile so the cloud session starts logged in:
|
|
200
330
|
|
|
201
|
-
|
|
331
|
+
```bash
|
|
332
|
+
# Reads cookies from local Chrome, decrypts them, uploads to cloud
|
|
333
|
+
opensteer browser clone --workspace demo \
|
|
334
|
+
--source-user-data-dir "$HOME/Library/Application Support/Google/Chrome" \
|
|
335
|
+
--source-profile-directory Default \
|
|
336
|
+
--provider cloud
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
The cookies are extracted from the local SQLite database, decrypted, packaged into a portable format, and uploaded. The cloud browser then starts with those cookies applied.
|
|
340
|
+
|
|
341
|
+
## Local View
|
|
342
|
+
|
|
343
|
+
When Opensteer runs headless, a human cannot see what the browser is doing. Local view streams live screenshots from headless sessions to a browser-based viewer.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
opensteer view # Start viewer service, print URL
|
|
347
|
+
opensteer view stop # Stop the viewer service
|
|
348
|
+
opensteer view --auto # Auto-start viewer on every browser launch
|
|
349
|
+
opensteer view --no-auto # Only start viewer when manually requested
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The viewer is a local web UI that shows:
|
|
353
|
+
|
|
354
|
+
- Live JPEG stream of the active browser tab
|
|
355
|
+
- Tab bar with switching
|
|
356
|
+
- Navigation controls (back, forward, reload, URL bar)
|
|
357
|
+
|
|
358
|
+
Local view is a passive observer — it connects to the browser's existing CDP endpoint. Starting or stopping it has zero impact on running browser sessions.
|
|
359
|
+
|
|
360
|
+
## Interaction Capture & Replay
|
|
361
|
+
|
|
362
|
+
Record a trace of browser interactions (clicks, typing, network, DOM changes) and replay them deterministically. Useful for building repeatable test flows or comparing behavior across runs.
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
opensteer interaction capture --workspace demo --key "login-flow" --duration 30000
|
|
366
|
+
opensteer interaction get <traceId> --workspace demo
|
|
367
|
+
opensteer interaction replay <traceId> --workspace demo
|
|
368
|
+
opensteer interaction diff <traceA> <traceB> --workspace demo
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Artifacts
|
|
372
|
+
|
|
373
|
+
Commands that use `--persist` save artifacts to the workspace. Read them back with:
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
opensteer artifact read <artifactId> --workspace demo
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Artifacts are created by `extract --persist`, `scripts capture --persist`, `scripts beautify --persist`, and other persist-enabled commands.
|
|
380
|
+
|
|
381
|
+
## Useful SDK Surface
|
|
202
382
|
|
|
203
|
-
- `open(url)`
|
|
204
|
-
- `goto(url, { captureNetwork? })`
|
|
383
|
+
- `open(url)`, `goto(url, { captureNetwork? })`, `close()`
|
|
205
384
|
- `snapshot("action" | "extraction")`
|
|
206
385
|
- `click()`, `hover()`, `input()`, `scroll()`
|
|
207
386
|
- `extract()`
|
|
208
|
-
- `
|
|
209
|
-
- `network.detail()`
|
|
210
|
-
- `
|
|
387
|
+
- `listPages()`, `newPage()`, `activatePage()`, `closePage()`
|
|
388
|
+
- `network.query()`, `network.detail()`
|
|
389
|
+
- `waitForPage()`
|
|
211
390
|
- `cookies()`, `storage()`, `state()`
|
|
212
391
|
- `fetch()`
|
|
392
|
+
- `evaluate()`, `addInitScript()`
|
|
393
|
+
- `route()` — intercept and modify network requests
|
|
213
394
|
- `computerExecute()`
|
|
214
|
-
- `addInitScript()`
|
|
215
395
|
- `browser.status()`, `browser.clone()`, `browser.reset()`, `browser.delete()`
|
|
216
396
|
|
|
217
397
|
## Guardrails
|
|
218
398
|
|
|
219
|
-
- Snapshot before using element numbers.
|
|
220
|
-
-
|
|
221
|
-
- Do not use `evaluate` for API work.
|
|
399
|
+
- Snapshot before using element numbers. Snapshot again after UI changes.
|
|
400
|
+
- Do not use `evaluate` for API work — use `exec` or `fetch`.
|
|
222
401
|
- Do not keep the result as a manual-only workflow if the user needs reusable automation.
|
|
223
402
|
- Prefer a small final script over a large framework.
|
|
403
|
+
- Close browsers when done. Do not leave headed browser windows open.
|
|
404
|
+
- When cloning profiles, verify the source path exists with `opensteer browser discover` first.
|