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/dist/cli/bin.js
CHANGED
|
@@ -1,290 +1,1644 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { assertProviderSupportsEngine, createOpensteerSemanticRuntime,
|
|
3
|
-
import
|
|
2
|
+
import { assertProviderSupportsEngine, createOpensteerSemanticRuntime, dispatchSemanticOperation, loadEnvironment, normalizeOpensteerProviderMode, discoverLocalCdpBrowsers, inspectCdpEndpoint, OpensteerBrowserManager, resolveOpensteerRuntimeConfig, resolveOpensteerEngineName, resolveOpensteerProvider, resolveFilesystemWorkspacePath, requireCloudAppBaseUrl, CloudSessionProxy, FlowRecorderCollector, generateReplayScript, pathExists, readPersistedLocalBrowserSessionRecord, readPersistedCloudSessionRecord, OpensteerCloudClient, isProcessRunning } from '../chunk-DFQCK2U6.js';
|
|
3
|
+
import process4 from 'process';
|
|
4
|
+
import { mkdir, writeFile } from 'fs/promises';
|
|
5
|
+
import path2 from 'path';
|
|
4
6
|
import { spawn } from 'child_process';
|
|
7
|
+
import os from 'os';
|
|
5
8
|
import { existsSync } from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
9
|
import { createRequire } from 'module';
|
|
8
10
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
10
|
-
import os from 'os';
|
|
11
11
|
|
|
12
12
|
// package.json
|
|
13
13
|
var package_default = {
|
|
14
|
-
version: "0.8.
|
|
14
|
+
version: "0.8.14"};
|
|
15
15
|
|
|
16
16
|
// src/cli/env-loader.ts
|
|
17
17
|
async function loadCliEnvironment(cwd) {
|
|
18
18
|
loadEnvironment(cwd);
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
20
|
+
|
|
21
|
+
// src/cli/help.ts
|
|
22
|
+
function getHelpText() {
|
|
23
|
+
return `Opensteer CLI
|
|
24
|
+
|
|
25
|
+
Session:
|
|
26
|
+
open <url> [--workspace <id>] [--headless] [--provider local|cloud]
|
|
27
|
+
close
|
|
28
|
+
status
|
|
29
|
+
|
|
30
|
+
Navigation:
|
|
31
|
+
goto <url> [--capture-network <label>]
|
|
32
|
+
|
|
33
|
+
DOM:
|
|
34
|
+
snapshot [action|extraction]
|
|
35
|
+
click <element> [--button left|middle|right] [--persist <key>] [--capture-network <label>]
|
|
36
|
+
hover <element> [--persist <key>] [--capture-network <label>]
|
|
37
|
+
input <element> <text> [--press-enter] [--persist <key>] [--capture-network <label>]
|
|
38
|
+
scroll <direction> <amount> [--element <n>] [--persist <key>] [--capture-network <label>]
|
|
39
|
+
extract <schema> [--persist <key>]
|
|
40
|
+
evaluate <script>
|
|
41
|
+
init-script <script>
|
|
42
|
+
|
|
43
|
+
Tabs:
|
|
44
|
+
tab list
|
|
45
|
+
tab new [url]
|
|
46
|
+
tab <n>
|
|
47
|
+
tab close [n]
|
|
48
|
+
|
|
49
|
+
Network:
|
|
50
|
+
network query [--capture <label>] [--url <pattern>] [--hostname <host>] [--path <path>] [--method <m>] [--status <code>] [--type <resourceType>] [--json] [--before <id>] [--after <id>] [--limit <n>]
|
|
51
|
+
--json filters to JSON and GraphQL responses only
|
|
52
|
+
network detail <recordId>
|
|
53
|
+
replay <recordId> [--query key=value ...] [--header key=value ...] [--body <json>] [--variables <json>]
|
|
54
|
+
fetch <url> [--method <m>] [--header key=value ...] [--query key=value ...] [--body <json>] [--body-text <text>] [--transport auto|direct|matched-tls|page] [--cookies] [--follow-redirects]
|
|
55
|
+
|
|
56
|
+
Browser State:
|
|
57
|
+
cookies [domain]
|
|
58
|
+
storage [domain]
|
|
59
|
+
state [domain]
|
|
60
|
+
|
|
61
|
+
Computer:
|
|
62
|
+
computer click <x> <y> [--button left|right|middle] [--count <n>] [--modifiers Shift,Control,Alt,Meta] [--capture-network <label>]
|
|
63
|
+
computer type <text> [--capture-network <label>]
|
|
64
|
+
computer key <key> [--modifiers Shift,Control,Alt,Meta] [--capture-network <label>]
|
|
65
|
+
computer scroll <x> <y> --dx <n> --dy <n> [--capture-network <label>]
|
|
66
|
+
computer move <x> <y> [--capture-network <label>]
|
|
67
|
+
computer drag <x1> <y1> <x2> <y2> [--steps <n>] [--capture-network <label>]
|
|
68
|
+
computer screenshot [--format png|jpeg|webp]
|
|
69
|
+
computer wait <ms>
|
|
70
|
+
|
|
71
|
+
Advanced:
|
|
72
|
+
captcha solve --provider 2captcha|capsolver --api-key <key> [--type recaptcha-v2|hcaptcha|turnstile] [--site-key <key>] [--page-url <url>] [--timeout <ms>]
|
|
73
|
+
scripts capture [--url-filter <pattern>] [--persist] [--inline] [--external] [--dynamic] [--workers]
|
|
74
|
+
scripts beautify <artifactId> [--persist]
|
|
75
|
+
scripts deobfuscate <artifactId> [--persist]
|
|
76
|
+
scripts sandbox <artifactId> [--fidelity minimal|standard|full] [--timeout <ms>] [--clock real|manual] [--cookies <json>] [--globals <json>] [--ajax-routes <json>]
|
|
77
|
+
interaction capture [--key <name>] [--duration <ms>] [--script <js>] [--include-storage] [--include-session-storage] [--include-indexed-db] [--global-names <list>] [--case-id <id>] [--notes <text>] [--tags <list>]
|
|
78
|
+
interaction get <traceId>
|
|
79
|
+
interaction replay <traceId>
|
|
80
|
+
interaction diff <leftTraceId> <rightTraceId>
|
|
81
|
+
artifact read <artifactId>
|
|
82
|
+
|
|
83
|
+
Options:
|
|
84
|
+
--workspace <id> Required for stateful commands (or set OPENSTEER_WORKSPACE)
|
|
85
|
+
--capture-network <l> Record network traffic during an action
|
|
86
|
+
--help, --version
|
|
87
|
+
`;
|
|
60
88
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
|
|
90
|
+
// src/cli/commands.ts
|
|
91
|
+
var OPERATION_ALIASES = /* @__PURE__ */ new Map([
|
|
92
|
+
["open", "session.open"],
|
|
93
|
+
["close", "session.close"],
|
|
94
|
+
["goto", "page.goto"],
|
|
95
|
+
["snapshot", "page.snapshot"],
|
|
96
|
+
["evaluate", "page.evaluate"],
|
|
97
|
+
["init-script", "page.add-init-script"],
|
|
98
|
+
["click", "dom.click"],
|
|
99
|
+
["hover", "dom.hover"],
|
|
100
|
+
["input", "dom.input"],
|
|
101
|
+
["scroll", "dom.scroll"],
|
|
102
|
+
["extract", "dom.extract"],
|
|
103
|
+
["tab", "page.activate"],
|
|
104
|
+
["tab list", "page.list"],
|
|
105
|
+
["tab new", "page.new"],
|
|
106
|
+
["tab close", "page.close"],
|
|
107
|
+
["network query", "network.query"],
|
|
108
|
+
["network detail", "network.detail"],
|
|
109
|
+
["replay", "network.replay"],
|
|
110
|
+
["fetch", "session.fetch"],
|
|
111
|
+
["cookies", "session.cookies"],
|
|
112
|
+
["storage", "session.storage"],
|
|
113
|
+
["state", "session.state"],
|
|
114
|
+
["computer click", "computer.execute"],
|
|
115
|
+
["computer type", "computer.execute"],
|
|
116
|
+
["computer key", "computer.execute"],
|
|
117
|
+
["computer scroll", "computer.execute"],
|
|
118
|
+
["computer move", "computer.execute"],
|
|
119
|
+
["computer drag", "computer.execute"],
|
|
120
|
+
["computer screenshot", "computer.execute"],
|
|
121
|
+
["computer wait", "computer.execute"],
|
|
122
|
+
["captcha solve", "captcha.solve"],
|
|
123
|
+
["scripts capture", "scripts.capture"],
|
|
124
|
+
["scripts beautify", "scripts.beautify"],
|
|
125
|
+
["scripts deobfuscate", "scripts.deobfuscate"],
|
|
126
|
+
["scripts sandbox", "scripts.sandbox"],
|
|
127
|
+
["interaction capture", "interaction.capture"],
|
|
128
|
+
["interaction get", "interaction.get"],
|
|
129
|
+
["interaction diff", "interaction.diff"],
|
|
130
|
+
["interaction replay", "interaction.replay"],
|
|
131
|
+
["artifact read", "artifact.read"]
|
|
132
|
+
]);
|
|
133
|
+
function resolveOperation(command) {
|
|
134
|
+
for (let length = Math.min(3, command.length); length >= 1; length -= 1) {
|
|
135
|
+
const key = command.slice(0, length).join(" ");
|
|
136
|
+
const operation = OPERATION_ALIASES.get(key);
|
|
137
|
+
if (operation) {
|
|
138
|
+
return operation;
|
|
68
139
|
}
|
|
69
|
-
ancestor = path.resolve(ancestor, "..");
|
|
70
140
|
}
|
|
71
|
-
|
|
141
|
+
return void 0;
|
|
72
142
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
method: "HEAD",
|
|
77
|
-
signal: AbortSignal.timeout(3e3),
|
|
78
|
-
redirect: "manual"
|
|
79
|
-
});
|
|
80
|
-
return response.status < 500;
|
|
81
|
-
} catch {
|
|
82
|
-
return false;
|
|
143
|
+
function resolveCommandLength(tokens) {
|
|
144
|
+
if (tokens.length === 0) {
|
|
145
|
+
return 0;
|
|
83
146
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const deps = {
|
|
87
|
-
resolveSkillsCliPath: resolveOpensteerSkillsCliPath,
|
|
88
|
-
resolveLocalSkillSourcePath: resolveOpensteerLocalSkillSourcePath,
|
|
89
|
-
checkGitHubReachable: checkOpensteerGitHubReachable,
|
|
90
|
-
spawnInvocation: spawnOpensteerSkillsInvocation,
|
|
91
|
-
...overrideDeps
|
|
92
|
-
};
|
|
93
|
-
const useGitHub = await deps.checkGitHubReachable();
|
|
94
|
-
const skillSourcePath = useGitHub ? OPENSTEER_GITHUB_SOURCE : deps.resolveLocalSkillSourcePath();
|
|
95
|
-
const invocation = createOpensteerSkillsInvocation({
|
|
96
|
-
options,
|
|
97
|
-
skillsCliPath: deps.resolveSkillsCliPath(),
|
|
98
|
-
skillSourcePath
|
|
99
|
-
});
|
|
100
|
-
return deps.spawnInvocation(invocation);
|
|
101
|
-
}
|
|
102
|
-
async function spawnOpensteerSkillsInvocation(invocation) {
|
|
103
|
-
return await new Promise((resolvePromise, rejectPromise) => {
|
|
104
|
-
const child = spawn(process.execPath, [invocation.cliPath, ...invocation.cliArgs], {
|
|
105
|
-
cwd: process.cwd(),
|
|
106
|
-
env: process.env,
|
|
107
|
-
stdio: "inherit"
|
|
108
|
-
});
|
|
109
|
-
child.once("error", (error) => {
|
|
110
|
-
rejectPromise(error);
|
|
111
|
-
});
|
|
112
|
-
child.once("exit", (code) => {
|
|
113
|
-
resolvePromise(typeof code === "number" ? code : 1);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
function resolveSelectedSkills(options) {
|
|
118
|
-
if (options.skills !== void 0 && options.skills.length > 0) {
|
|
119
|
-
return options.skills;
|
|
147
|
+
if (tokens[0] === "browser") {
|
|
148
|
+
return Math.min(tokens.length, 2);
|
|
120
149
|
}
|
|
121
|
-
if (
|
|
122
|
-
return
|
|
150
|
+
if (tokens[0] === "skills") {
|
|
151
|
+
return Math.min(tokens.length, 2);
|
|
123
152
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
async function collectOpensteerStatus(input) {
|
|
127
|
-
const output = {
|
|
128
|
-
provider: {
|
|
129
|
-
current: input.provider.mode,
|
|
130
|
-
source: mapProviderSource(input.provider.source),
|
|
131
|
-
...input.cloudConfig === void 0 ? {} : { cloudBaseUrl: input.cloudConfig.baseUrl }
|
|
132
|
-
},
|
|
133
|
-
...input.workspace === void 0 ? {} : { workspace: input.workspace }
|
|
134
|
-
};
|
|
135
|
-
if (input.workspace === void 0) {
|
|
136
|
-
return output;
|
|
153
|
+
if (tokens[0] === "status" || tokens[0] === "record") {
|
|
154
|
+
return 1;
|
|
137
155
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
142
|
-
const localRecord = await readWorkspaceLocalRecord(rootPath);
|
|
143
|
-
const cloudRecord = await readWorkspaceCloudRecord(rootPath);
|
|
144
|
-
return {
|
|
145
|
-
...output,
|
|
146
|
-
rootPath,
|
|
147
|
-
lanes: {
|
|
148
|
-
local: describeLocalLane(localRecord, input.provider.mode === "local"),
|
|
149
|
-
cloud: await describeCloudLane({
|
|
150
|
-
record: cloudRecord,
|
|
151
|
-
current: input.provider.mode === "cloud",
|
|
152
|
-
cloudConfig: input.cloudConfig
|
|
153
|
-
})
|
|
156
|
+
for (let length = Math.min(3, tokens.length); length >= 1; length -= 1) {
|
|
157
|
+
if (OPERATION_ALIASES.has(tokens.slice(0, length).join(" "))) {
|
|
158
|
+
return length;
|
|
154
159
|
}
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function renderOpensteerStatus(status) {
|
|
158
|
-
const lines = [
|
|
159
|
-
"Provider resolution",
|
|
160
|
-
` current: ${status.provider.current}`,
|
|
161
|
-
` source: ${status.provider.source}`
|
|
162
|
-
];
|
|
163
|
-
if (status.provider.cloudBaseUrl !== void 0) {
|
|
164
|
-
lines.push(` control api: ${status.provider.cloudBaseUrl}`);
|
|
165
|
-
}
|
|
166
|
-
if (status.workspace !== void 0) {
|
|
167
|
-
lines.push(` workspace: ${status.workspace}`);
|
|
168
|
-
}
|
|
169
|
-
if (status.lanes === void 0) {
|
|
170
|
-
return `${lines.join("\n")}
|
|
171
|
-
`;
|
|
172
|
-
}
|
|
173
|
-
lines.push("", "Live sessions");
|
|
174
|
-
for (const lane of [status.lanes.local, status.lanes.cloud]) {
|
|
175
|
-
lines.push(
|
|
176
|
-
formatLaneRow({
|
|
177
|
-
marker: lane.current ? "*" : " ",
|
|
178
|
-
provider: lane.provider,
|
|
179
|
-
status: lane.status,
|
|
180
|
-
summary: lane.summary ?? "none",
|
|
181
|
-
detail: lane.detail
|
|
182
|
-
})
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
return `${lines.join("\n")}
|
|
186
|
-
`;
|
|
187
|
-
}
|
|
188
|
-
async function readWorkspaceLocalRecord(rootPath) {
|
|
189
|
-
if (!await pathExists(rootPath)) {
|
|
190
|
-
return void 0;
|
|
191
160
|
}
|
|
192
|
-
return
|
|
161
|
+
return Math.min(tokens.length, 1);
|
|
193
162
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
163
|
+
|
|
164
|
+
// src/cli/parse.ts
|
|
165
|
+
var CLI_OPTION_SPECS = {
|
|
166
|
+
workspace: { kind: "value" },
|
|
167
|
+
url: { kind: "value" },
|
|
168
|
+
output: { kind: "value" },
|
|
169
|
+
engine: { kind: "value" },
|
|
170
|
+
provider: { kind: "value" },
|
|
171
|
+
"cloud-base-url": { kind: "value" },
|
|
172
|
+
"cloud-api-key": { kind: "value" },
|
|
173
|
+
"cloud-app-base-url": { kind: "value" },
|
|
174
|
+
"cloud-profile-id": { kind: "value" },
|
|
175
|
+
"cloud-profile-reuse-if-active": { kind: "boolean" },
|
|
176
|
+
json: { kind: "boolean" },
|
|
177
|
+
agent: { kind: "value", multiple: true },
|
|
178
|
+
skill: { kind: "value", multiple: true },
|
|
179
|
+
global: { kind: "boolean" },
|
|
180
|
+
yes: { kind: "boolean" },
|
|
181
|
+
copy: { kind: "boolean" },
|
|
182
|
+
all: { kind: "boolean" },
|
|
183
|
+
list: { kind: "boolean" },
|
|
184
|
+
"attach-endpoint": { kind: "value" },
|
|
185
|
+
"attach-header": { kind: "value", multiple: true },
|
|
186
|
+
"fresh-tab": { kind: "boolean" },
|
|
187
|
+
headless: { kind: "boolean" },
|
|
188
|
+
"executable-path": { kind: "value" },
|
|
189
|
+
arg: { kind: "value", multiple: true },
|
|
190
|
+
"timeout-ms": { kind: "value" },
|
|
191
|
+
context: { kind: "value" },
|
|
192
|
+
"source-user-data-dir": { kind: "value" },
|
|
193
|
+
"source-profile-directory": { kind: "value" },
|
|
194
|
+
element: { kind: "value" },
|
|
195
|
+
persist: { kind: "optional-value" },
|
|
196
|
+
button: { kind: "value" },
|
|
197
|
+
count: { kind: "value" },
|
|
198
|
+
modifiers: { kind: "value" },
|
|
199
|
+
"press-enter": { kind: "boolean" },
|
|
200
|
+
"capture-network": { kind: "value" },
|
|
201
|
+
capture: { kind: "value" },
|
|
202
|
+
hostname: { kind: "value" },
|
|
203
|
+
path: { kind: "value" },
|
|
204
|
+
method: { kind: "value" },
|
|
205
|
+
status: { kind: "value" },
|
|
206
|
+
type: { kind: "value" },
|
|
207
|
+
before: { kind: "value" },
|
|
208
|
+
after: { kind: "value" },
|
|
209
|
+
limit: { kind: "value" },
|
|
210
|
+
query: { kind: "value", multiple: true },
|
|
211
|
+
header: { kind: "value", multiple: true },
|
|
212
|
+
body: { kind: "value" },
|
|
213
|
+
"body-text": { kind: "value" },
|
|
214
|
+
variables: { kind: "value" },
|
|
215
|
+
dx: { kind: "value" },
|
|
216
|
+
dy: { kind: "value" },
|
|
217
|
+
steps: { kind: "value" },
|
|
218
|
+
format: { kind: "value" },
|
|
219
|
+
transport: { kind: "value" },
|
|
220
|
+
cookies: { kind: "optional-value" },
|
|
221
|
+
"follow-redirects": { kind: "boolean" },
|
|
222
|
+
"api-key": { kind: "value" },
|
|
223
|
+
"site-key": { kind: "value" },
|
|
224
|
+
"page-url": { kind: "value" },
|
|
225
|
+
timeout: { kind: "value" },
|
|
226
|
+
"url-filter": { kind: "value" },
|
|
227
|
+
inline: { kind: "boolean" },
|
|
228
|
+
external: { kind: "boolean" },
|
|
229
|
+
dynamic: { kind: "boolean" },
|
|
230
|
+
workers: { kind: "boolean" },
|
|
231
|
+
fidelity: { kind: "value" },
|
|
232
|
+
clock: { kind: "value" },
|
|
233
|
+
globals: { kind: "value" },
|
|
234
|
+
"ajax-routes": { kind: "value" },
|
|
235
|
+
key: { kind: "value" },
|
|
236
|
+
duration: { kind: "value" },
|
|
237
|
+
script: { kind: "value" },
|
|
238
|
+
"include-storage": { kind: "boolean" },
|
|
239
|
+
"include-session-storage": { kind: "boolean" },
|
|
240
|
+
"include-indexed-db": { kind: "boolean" },
|
|
241
|
+
"global-names": { kind: "value" },
|
|
242
|
+
"case-id": { kind: "value" },
|
|
243
|
+
notes: { kind: "value" },
|
|
244
|
+
tags: { kind: "value" }
|
|
245
|
+
};
|
|
246
|
+
function parseCommandLine(argv) {
|
|
247
|
+
const leadingTokens = [];
|
|
248
|
+
let index = 0;
|
|
249
|
+
while (index < argv.length && !argv[index].startsWith("--")) {
|
|
250
|
+
leadingTokens.push(argv[index]);
|
|
251
|
+
index += 1;
|
|
197
252
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
253
|
+
const commandLength = resolveCommandLength(leadingTokens);
|
|
254
|
+
const command = leadingTokens.slice(0, commandLength);
|
|
255
|
+
const rest = leadingTokens.slice(commandLength);
|
|
256
|
+
const rawOptions = /* @__PURE__ */ new Map();
|
|
257
|
+
while (index < argv.length) {
|
|
258
|
+
const token = argv[index];
|
|
259
|
+
if (token === "--") {
|
|
260
|
+
rest.push(...argv.slice(index + 1));
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
if (!token.startsWith("--")) {
|
|
264
|
+
rest.push(token);
|
|
265
|
+
index += 1;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const separator = token.indexOf("=");
|
|
269
|
+
const key = token.slice(2, separator === -1 ? void 0 : separator);
|
|
270
|
+
const spec = CLI_OPTION_SPECS[key];
|
|
271
|
+
if (spec === void 0) {
|
|
272
|
+
throw new Error(`Unknown option: --${key}.`);
|
|
273
|
+
}
|
|
274
|
+
if (separator !== -1) {
|
|
275
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], token.slice(separator + 1)]);
|
|
276
|
+
index += 1;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const next = argv[index + 1];
|
|
280
|
+
if (spec.kind === "boolean") {
|
|
281
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
282
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], "true"]);
|
|
283
|
+
index += 1;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], next]);
|
|
287
|
+
index += 2;
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (spec.kind === "optional-value") {
|
|
291
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
292
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], "true"]);
|
|
293
|
+
index += 1;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], next]);
|
|
297
|
+
index += 2;
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (next === void 0 || next.startsWith("--")) {
|
|
301
|
+
throw new Error(
|
|
302
|
+
`Option "--${key}" requires a value.${next?.startsWith("--") === true ? ` Use "--${key}=<value>" when the value begins with "--".` : ``}`
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
rawOptions.set(key, [...rawOptions.get(key) ?? [], next]);
|
|
306
|
+
index += 2;
|
|
307
|
+
}
|
|
308
|
+
const workspace = readSingle(rawOptions, "workspace") ?? process4.env.OPENSTEER_WORKSPACE;
|
|
309
|
+
const requestedEngineName = readSingle(rawOptions, "engine");
|
|
310
|
+
const attachEndpoint = readSingle(rawOptions, "attach-endpoint");
|
|
311
|
+
const attachHeaders = parseKeyValueList(rawOptions.get("attach-header"));
|
|
312
|
+
const freshTab = readOptionalBoolean(rawOptions, "fresh-tab");
|
|
313
|
+
const headless = readOptionalBoolean(rawOptions, "headless");
|
|
314
|
+
const executablePath = readSingle(rawOptions, "executable-path");
|
|
315
|
+
const launchArgs = rawOptions.get("arg");
|
|
316
|
+
const timeoutMs = readOptionalNumber(rawOptions, "timeout-ms");
|
|
317
|
+
const browser = attachEndpoint === void 0 ? void 0 : {
|
|
318
|
+
mode: "attach",
|
|
319
|
+
endpoint: attachEndpoint,
|
|
320
|
+
...attachHeaders === void 0 ? {} : { headers: attachHeaders },
|
|
321
|
+
...freshTab === void 0 ? {} : { freshTab }
|
|
322
|
+
};
|
|
323
|
+
const launch = {
|
|
324
|
+
...headless === void 0 ? {} : { headless },
|
|
325
|
+
...executablePath === void 0 ? {} : { executablePath },
|
|
326
|
+
...launchArgs === void 0 ? {} : { args: launchArgs },
|
|
327
|
+
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
328
|
+
};
|
|
329
|
+
const providerValue = shouldParseRuntimeProvider(command) ? readSingle(rawOptions, "provider") : void 0;
|
|
330
|
+
const provider = providerValue === void 0 ? void 0 : normalizeOpensteerProviderMode(providerValue, "--provider");
|
|
331
|
+
const url = readSingle(rawOptions, "url");
|
|
332
|
+
const output = readSingle(rawOptions, "output");
|
|
333
|
+
const cloudBaseUrl = readSingle(rawOptions, "cloud-base-url");
|
|
334
|
+
const cloudApiKey = readSingle(rawOptions, "cloud-api-key");
|
|
335
|
+
const cloudAppBaseUrl = readSingle(rawOptions, "cloud-app-base-url");
|
|
336
|
+
const cloudProfileId = readSingle(rawOptions, "cloud-profile-id");
|
|
337
|
+
const cloudProfileReuseIfActive = readOptionalBoolean(rawOptions, "cloud-profile-reuse-if-active");
|
|
338
|
+
const json = readOptionalBoolean(rawOptions, "json");
|
|
339
|
+
const agents = rawOptions.get("agent");
|
|
340
|
+
const skills = rawOptions.get("skill");
|
|
341
|
+
const global = readOptionalBoolean(rawOptions, "global");
|
|
342
|
+
const yes = readOptionalBoolean(rawOptions, "yes");
|
|
343
|
+
const copy = readOptionalBoolean(rawOptions, "copy");
|
|
344
|
+
const all = readOptionalBoolean(rawOptions, "all");
|
|
345
|
+
const list = readOptionalBoolean(rawOptions, "list");
|
|
346
|
+
const context = readJsonObject(rawOptions, "context");
|
|
347
|
+
const sourceUserDataDir = readSingle(rawOptions, "source-user-data-dir");
|
|
348
|
+
const sourceProfileDirectory = readSingle(rawOptions, "source-profile-directory");
|
|
349
|
+
const options = {
|
|
350
|
+
...workspace === void 0 ? {} : { workspace },
|
|
351
|
+
...url === void 0 ? {} : { url },
|
|
352
|
+
...output === void 0 ? {} : { output },
|
|
353
|
+
...requestedEngineName === void 0 ? {} : { requestedEngineName },
|
|
354
|
+
...provider === void 0 ? {} : { provider },
|
|
355
|
+
...cloudBaseUrl === void 0 ? {} : { cloudBaseUrl },
|
|
356
|
+
...cloudApiKey === void 0 ? {} : { cloudApiKey },
|
|
357
|
+
...cloudAppBaseUrl === void 0 ? {} : { cloudAppBaseUrl },
|
|
358
|
+
...cloudProfileId === void 0 ? {} : { cloudProfileId },
|
|
359
|
+
...cloudProfileReuseIfActive === void 0 ? {} : { cloudProfileReuseIfActive },
|
|
360
|
+
...json === void 0 ? {} : { json },
|
|
361
|
+
...agents === void 0 ? {} : { agents },
|
|
362
|
+
...skills === void 0 ? {} : { skills },
|
|
363
|
+
...global === void 0 ? {} : { global },
|
|
364
|
+
...yes === void 0 ? {} : { yes },
|
|
365
|
+
...copy === void 0 ? {} : { copy },
|
|
366
|
+
...all === void 0 ? {} : { all },
|
|
367
|
+
...list === void 0 ? {} : { list },
|
|
368
|
+
...browser === void 0 ? {} : { browser },
|
|
369
|
+
...Object.keys(launch).length === 0 ? {} : { launch },
|
|
370
|
+
...context === void 0 ? {} : { context },
|
|
371
|
+
...attachEndpoint === void 0 ? {} : { attachEndpoint },
|
|
372
|
+
...attachHeaders === void 0 ? {} : { attachHeaders },
|
|
373
|
+
...sourceUserDataDir === void 0 ? {} : { sourceUserDataDir },
|
|
374
|
+
...sourceProfileDirectory === void 0 ? {} : { sourceProfileDirectory }
|
|
375
|
+
};
|
|
376
|
+
return {
|
|
377
|
+
command,
|
|
378
|
+
rest,
|
|
379
|
+
rawOptions,
|
|
380
|
+
options
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function shouldParseRuntimeProvider(command) {
|
|
384
|
+
return !(command[0] === "captcha" && command[1] === "solve");
|
|
385
|
+
}
|
|
386
|
+
function parseKeyValueList(values) {
|
|
387
|
+
if (values === void 0 || values.length === 0) {
|
|
388
|
+
return void 0;
|
|
389
|
+
}
|
|
390
|
+
return Object.fromEntries(
|
|
391
|
+
values.map((entry) => {
|
|
392
|
+
const separator = entry.indexOf("=");
|
|
393
|
+
if (separator <= 0) {
|
|
394
|
+
throw new Error(`Expected NAME=VALUE, received "${entry}".`);
|
|
395
|
+
}
|
|
396
|
+
return [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
397
|
+
})
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
function parseCommaSeparatedList(value) {
|
|
401
|
+
if (value === void 0) {
|
|
402
|
+
return void 0;
|
|
403
|
+
}
|
|
404
|
+
const values = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
405
|
+
return values.length === 0 ? void 0 : values;
|
|
406
|
+
}
|
|
407
|
+
function readSingle(options, name) {
|
|
408
|
+
const values = options.get(name);
|
|
409
|
+
if (values === void 0 || values.length === 0) {
|
|
410
|
+
return void 0;
|
|
411
|
+
}
|
|
412
|
+
return values[values.length - 1];
|
|
413
|
+
}
|
|
414
|
+
function readOptionalBoolean(options, name) {
|
|
415
|
+
const value = readSingle(options, name);
|
|
416
|
+
if (value === void 0) {
|
|
417
|
+
return void 0;
|
|
418
|
+
}
|
|
419
|
+
if (value === "true") {
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
if (value === "false") {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
throw new Error(`Option "--${name}" must be true or false.`);
|
|
426
|
+
}
|
|
427
|
+
function readOptionalNumber(options, name) {
|
|
428
|
+
const value = readSingle(options, name);
|
|
429
|
+
if (value === void 0) {
|
|
430
|
+
return void 0;
|
|
431
|
+
}
|
|
432
|
+
const parsed = Number(value);
|
|
433
|
+
if (!Number.isFinite(parsed)) {
|
|
434
|
+
throw new Error(`Option "--${name}" must be a number.`);
|
|
435
|
+
}
|
|
436
|
+
return parsed;
|
|
437
|
+
}
|
|
438
|
+
function readJsonValue(options, name) {
|
|
439
|
+
const value = readSingle(options, name);
|
|
440
|
+
return value === void 0 ? void 0 : JSON.parse(value);
|
|
441
|
+
}
|
|
442
|
+
function readJsonObject(options, name) {
|
|
443
|
+
const parsed = readJsonValue(options, name);
|
|
444
|
+
if (parsed === void 0) {
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
448
|
+
throw new Error(`Option "--${name}" must be a JSON object.`);
|
|
449
|
+
}
|
|
450
|
+
return parsed;
|
|
451
|
+
}
|
|
452
|
+
function readJsonArray(options, name) {
|
|
453
|
+
const parsed = readJsonValue(options, name);
|
|
454
|
+
if (parsed === void 0) {
|
|
455
|
+
return void 0;
|
|
456
|
+
}
|
|
457
|
+
if (!Array.isArray(parsed)) {
|
|
458
|
+
throw new Error(`Option "--${name}" must be a JSON array.`);
|
|
459
|
+
}
|
|
460
|
+
return parsed;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/cli/operation-input.ts
|
|
464
|
+
var CLICK_BUTTONS = /* @__PURE__ */ new Set(["left", "middle", "right"]);
|
|
465
|
+
var FETCH_TRANSPORTS = /* @__PURE__ */ new Set(["auto", "direct", "matched-tls", "page"]);
|
|
466
|
+
var CAPTCHA_PROVIDERS = /* @__PURE__ */ new Set(["2captcha", "capsolver"]);
|
|
467
|
+
var CAPTCHA_TYPES = /* @__PURE__ */ new Set(["recaptcha-v2", "hcaptcha", "turnstile"]);
|
|
468
|
+
var SANDBOX_FIDELITIES = /* @__PURE__ */ new Set(["minimal", "standard", "full"]);
|
|
469
|
+
var SANDBOX_CLOCK_MODES = /* @__PURE__ */ new Set(["real", "manual"]);
|
|
470
|
+
var SCREENSHOT_FORMATS = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
|
|
471
|
+
var KEY_MODIFIERS = /* @__PURE__ */ new Set(["Shift", "Control", "Alt", "Meta"]);
|
|
472
|
+
var SCROLL_DIRECTIONS = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
|
|
473
|
+
async function buildOperationInput(operation, parsed, runtime) {
|
|
474
|
+
switch (operation) {
|
|
475
|
+
case "session.open": {
|
|
476
|
+
const url = parsed.rest[0];
|
|
477
|
+
if (url === void 0) {
|
|
478
|
+
throw new Error("open requires a URL.");
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
url,
|
|
482
|
+
...parsed.options.workspace === void 0 ? {} : { workspace: parsed.options.workspace },
|
|
483
|
+
...parsed.options.browser === void 0 ? {} : { browser: parsed.options.browser },
|
|
484
|
+
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
485
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
case "page.list":
|
|
489
|
+
return {};
|
|
490
|
+
case "page.new":
|
|
491
|
+
return parsed.rest[0] === void 0 ? {} : { url: parsed.rest[0] };
|
|
492
|
+
case "page.activate": {
|
|
493
|
+
const index = readRequiredPositiveInteger(parsed.rest[0], "tab requires an index.");
|
|
494
|
+
return {
|
|
495
|
+
pageRef: await resolvePageRefByIndex(runtime, index)
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
case "page.close": {
|
|
499
|
+
if (parsed.rest[0] === void 0) {
|
|
500
|
+
return {};
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
pageRef: await resolvePageRefByIndex(
|
|
504
|
+
runtime,
|
|
505
|
+
readRequiredPositiveInteger(parsed.rest[0], "tab close requires an index.")
|
|
506
|
+
)
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
case "page.goto": {
|
|
510
|
+
if (parsed.rest[0] === void 0) {
|
|
511
|
+
throw new Error("goto requires a URL.");
|
|
512
|
+
}
|
|
513
|
+
const captureNetwork = readSingle(parsed.rawOptions, "capture-network");
|
|
514
|
+
return {
|
|
515
|
+
url: parsed.rest[0],
|
|
516
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
case "page.snapshot":
|
|
520
|
+
return parsed.rest[0] === void 0 ? {} : { mode: parsed.rest[0] };
|
|
521
|
+
case "page.evaluate":
|
|
522
|
+
if (parsed.rest[0] === void 0) {
|
|
523
|
+
throw new Error("evaluate requires a script.");
|
|
524
|
+
}
|
|
525
|
+
return {
|
|
526
|
+
script: joinRest(parsed.rest, 0)
|
|
527
|
+
};
|
|
528
|
+
case "page.add-init-script":
|
|
529
|
+
if (parsed.rest[0] === void 0) {
|
|
530
|
+
throw new Error("init-script requires a script.");
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
script: joinRest(parsed.rest, 0)
|
|
534
|
+
};
|
|
535
|
+
case "dom.click": {
|
|
536
|
+
const button = readSingle(parsed.rawOptions, "button");
|
|
537
|
+
return {
|
|
538
|
+
...buildElementTargetInput(parsed, "click"),
|
|
539
|
+
...button === void 0 ? {} : { button: readClickButton(button) }
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
case "dom.hover":
|
|
543
|
+
return buildElementTargetInput(parsed, "hover");
|
|
544
|
+
case "dom.input": {
|
|
545
|
+
if (parsed.rest[1] === void 0) {
|
|
546
|
+
throw new Error("input requires an element number and text.");
|
|
547
|
+
}
|
|
548
|
+
const pressEnter = readOptionalBoolean(parsed.rawOptions, "press-enter");
|
|
549
|
+
return {
|
|
550
|
+
...buildElementTargetInput(parsed, "input"),
|
|
551
|
+
text: joinRest(parsed.rest, 1),
|
|
552
|
+
...pressEnter === void 0 ? {} : { pressEnter }
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
case "dom.scroll": {
|
|
556
|
+
const direction = readSingleDirection(parsed.rest[0]);
|
|
557
|
+
const amount = readRequiredPositiveInteger(parsed.rest[1], "scroll requires an amount.");
|
|
558
|
+
const element = readOptionalNumber(parsed.rawOptions, "element");
|
|
559
|
+
const persist = readPersistKey(parsed, "scroll");
|
|
560
|
+
const captureNetwork = readSingle(parsed.rawOptions, "capture-network");
|
|
561
|
+
return {
|
|
562
|
+
target: element === void 0 ? {
|
|
563
|
+
kind: "selector",
|
|
564
|
+
selector: "html"
|
|
565
|
+
} : {
|
|
566
|
+
kind: "element",
|
|
567
|
+
element
|
|
568
|
+
},
|
|
569
|
+
direction,
|
|
570
|
+
amount,
|
|
571
|
+
...persist === void 0 ? {} : { persist },
|
|
572
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
case "dom.extract": {
|
|
576
|
+
if (parsed.rest[0] === void 0) {
|
|
577
|
+
throw new Error("extract requires a schema.");
|
|
578
|
+
}
|
|
579
|
+
const persist = readExtractPersistKey(parsed);
|
|
580
|
+
return {
|
|
581
|
+
schema: parseRequiredJsonObjectArgument(joinRest(parsed.rest, 0), "extract schema"),
|
|
582
|
+
...persist === void 0 ? {} : { persist }
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
case "network.query": {
|
|
586
|
+
const capture = readSingle(parsed.rawOptions, "capture");
|
|
587
|
+
const url = readSingle(parsed.rawOptions, "url");
|
|
588
|
+
const hostname = readSingle(parsed.rawOptions, "hostname");
|
|
589
|
+
const path4 = readSingle(parsed.rawOptions, "path");
|
|
590
|
+
const method = readSingle(parsed.rawOptions, "method");
|
|
591
|
+
const status = readOptionalNumber(parsed.rawOptions, "status");
|
|
592
|
+
const resourceType = readSingle(parsed.rawOptions, "type");
|
|
593
|
+
const json = readOptionalBoolean(parsed.rawOptions, "json");
|
|
594
|
+
const before = readSingle(parsed.rawOptions, "before");
|
|
595
|
+
const after = readSingle(parsed.rawOptions, "after");
|
|
596
|
+
const limit = readOptionalNumber(parsed.rawOptions, "limit");
|
|
597
|
+
return {
|
|
598
|
+
...capture === void 0 ? {} : { capture },
|
|
599
|
+
...url === void 0 ? {} : { url },
|
|
600
|
+
...hostname === void 0 ? {} : { hostname },
|
|
601
|
+
...path4 === void 0 ? {} : { path: path4 },
|
|
602
|
+
...method === void 0 ? {} : { method },
|
|
603
|
+
...status === void 0 ? {} : { status },
|
|
604
|
+
...resourceType === void 0 ? {} : { resourceType },
|
|
605
|
+
...json === true ? { json: true } : {},
|
|
606
|
+
...before === void 0 ? {} : { before },
|
|
607
|
+
...after === void 0 ? {} : { after },
|
|
608
|
+
...limit === void 0 ? {} : { limit }
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
case "network.detail":
|
|
612
|
+
if (parsed.rest[0] === void 0) {
|
|
613
|
+
throw new Error("network detail requires a record id.");
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
recordId: parsed.rest[0]
|
|
617
|
+
};
|
|
618
|
+
case "network.replay": {
|
|
619
|
+
if (parsed.rest[0] === void 0) {
|
|
620
|
+
throw new Error("replay requires a record id.");
|
|
621
|
+
}
|
|
622
|
+
const query = parseKeyValueList(parsed.rawOptions.get("query"));
|
|
623
|
+
const headers = parseKeyValueList(parsed.rawOptions.get("header"));
|
|
624
|
+
const bodyJson = readJsonValue(parsed.rawOptions, "body");
|
|
625
|
+
const variables = readJsonObject(parsed.rawOptions, "variables");
|
|
626
|
+
return {
|
|
627
|
+
recordId: parsed.rest[0],
|
|
628
|
+
...query === void 0 ? {} : { query },
|
|
629
|
+
...headers === void 0 ? {} : { headers },
|
|
630
|
+
...bodyJson === void 0 ? {} : { body: { json: bodyJson } },
|
|
631
|
+
...variables === void 0 ? {} : { variables }
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
case "session.fetch": {
|
|
635
|
+
const url = parsed.rest[0];
|
|
636
|
+
if (url === void 0) {
|
|
637
|
+
throw new Error("fetch requires a URL.");
|
|
638
|
+
}
|
|
639
|
+
const bodyJson = readJsonValue(parsed.rawOptions, "body");
|
|
640
|
+
const bodyText = readSingle(parsed.rawOptions, "body-text");
|
|
641
|
+
const method = readSingle(parsed.rawOptions, "method");
|
|
642
|
+
const query = parseKeyValueList(parsed.rawOptions.get("query"));
|
|
643
|
+
const headers = parseKeyValueList(parsed.rawOptions.get("header"));
|
|
644
|
+
if (bodyJson !== void 0 && bodyText !== void 0) {
|
|
645
|
+
throw new Error('Use either "--body" or "--body-text", not both.');
|
|
646
|
+
}
|
|
647
|
+
const transport = readSingle(parsed.rawOptions, "transport");
|
|
648
|
+
const cookies = readOptionalBoolean(parsed.rawOptions, "cookies");
|
|
649
|
+
const followRedirects = readOptionalBoolean(parsed.rawOptions, "follow-redirects");
|
|
650
|
+
return {
|
|
651
|
+
url,
|
|
652
|
+
...method === void 0 ? {} : { method },
|
|
653
|
+
...query === void 0 ? {} : { query },
|
|
654
|
+
...headers === void 0 ? {} : { headers },
|
|
655
|
+
...bodyJson === void 0 ? {} : { body: { json: bodyJson } },
|
|
656
|
+
...bodyText === void 0 ? {} : { body: { text: bodyText } },
|
|
657
|
+
...transport === void 0 ? {} : { transport: readFetchTransport(transport) },
|
|
658
|
+
...cookies === void 0 ? {} : { cookies },
|
|
659
|
+
...followRedirects === void 0 ? {} : { followRedirects }
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
case "session.cookies":
|
|
663
|
+
case "session.storage":
|
|
664
|
+
case "session.state":
|
|
665
|
+
return parsed.rest[0] === void 0 ? {} : { domain: parsed.rest[0] };
|
|
666
|
+
case "computer.execute":
|
|
667
|
+
return buildComputerExecuteInput(parsed);
|
|
668
|
+
case "captcha.solve": {
|
|
669
|
+
const provider = readSingle(parsed.rawOptions, "provider");
|
|
670
|
+
const apiKey = readSingle(parsed.rawOptions, "api-key");
|
|
671
|
+
const timeoutMs = readOptionalNumber(parsed.rawOptions, "timeout") ?? readOptionalNumber(parsed.rawOptions, "timeout-ms");
|
|
672
|
+
const type = readSingle(parsed.rawOptions, "type");
|
|
673
|
+
const siteKey = readSingle(parsed.rawOptions, "site-key");
|
|
674
|
+
const pageUrl = readSingle(parsed.rawOptions, "page-url");
|
|
675
|
+
if (provider === void 0 || apiKey === void 0) {
|
|
676
|
+
throw new Error('captcha solve requires "--provider" and "--api-key".');
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
provider: readCaptchaProvider(provider),
|
|
680
|
+
apiKey,
|
|
681
|
+
...timeoutMs === void 0 ? {} : { timeoutMs },
|
|
682
|
+
...type === void 0 ? {} : { type: readCaptchaType(type) },
|
|
683
|
+
...siteKey === void 0 ? {} : { siteKey },
|
|
684
|
+
...pageUrl === void 0 ? {} : { pageUrl }
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
case "scripts.capture": {
|
|
688
|
+
const urlFilter = readSingle(parsed.rawOptions, "url-filter");
|
|
689
|
+
const persist = readOptionalBoolean(parsed.rawOptions, "persist");
|
|
690
|
+
const includeInline = readOptionalBoolean(parsed.rawOptions, "inline");
|
|
691
|
+
const includeExternal = readOptionalBoolean(parsed.rawOptions, "external");
|
|
692
|
+
const includeDynamic = readOptionalBoolean(parsed.rawOptions, "dynamic");
|
|
693
|
+
const includeWorkers = readOptionalBoolean(parsed.rawOptions, "workers");
|
|
694
|
+
return {
|
|
695
|
+
...urlFilter === void 0 ? {} : { urlFilter },
|
|
696
|
+
...persist === void 0 ? {} : { persist },
|
|
697
|
+
...includeInline === void 0 ? {} : { includeInline },
|
|
698
|
+
...includeExternal === void 0 ? {} : { includeExternal },
|
|
699
|
+
...includeDynamic === void 0 ? {} : { includeDynamic },
|
|
700
|
+
...includeWorkers === void 0 ? {} : { includeWorkers }
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
case "scripts.beautify":
|
|
704
|
+
case "scripts.deobfuscate": {
|
|
705
|
+
if (parsed.rest[0] === void 0) {
|
|
706
|
+
throw new Error(`${parsed.command.join(" ")} requires an artifact id.`);
|
|
707
|
+
}
|
|
708
|
+
const persist = readOptionalBoolean(parsed.rawOptions, "persist");
|
|
709
|
+
return {
|
|
710
|
+
artifactId: parsed.rest[0],
|
|
711
|
+
...persist === void 0 ? {} : { persist }
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
case "scripts.sandbox":
|
|
715
|
+
if (parsed.rest[0] === void 0) {
|
|
716
|
+
throw new Error("scripts sandbox requires an artifact id.");
|
|
717
|
+
}
|
|
718
|
+
{
|
|
719
|
+
const fidelity = readSingle(parsed.rawOptions, "fidelity");
|
|
720
|
+
const timeoutMs = readOptionalNumber(parsed.rawOptions, "timeout") ?? readOptionalNumber(parsed.rawOptions, "timeout-ms");
|
|
721
|
+
const clock = readSingle(parsed.rawOptions, "clock");
|
|
722
|
+
const cookies = readJsonObject(parsed.rawOptions, "cookies");
|
|
723
|
+
const globals = readJsonObject(parsed.rawOptions, "globals");
|
|
724
|
+
const ajaxRoutes = readJsonArray(parsed.rawOptions, "ajax-routes");
|
|
725
|
+
return {
|
|
726
|
+
artifactId: parsed.rest[0],
|
|
727
|
+
...fidelity === void 0 ? {} : { fidelity: readSandboxFidelity(fidelity) },
|
|
728
|
+
...timeoutMs === void 0 ? {} : { timeoutMs },
|
|
729
|
+
...clock === void 0 ? {} : { clockMode: readSandboxClockMode(clock) },
|
|
730
|
+
...cookies === void 0 ? {} : { cookies },
|
|
731
|
+
...globals === void 0 ? {} : { globals },
|
|
732
|
+
...ajaxRoutes === void 0 ? {} : { ajaxRoutes }
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
case "interaction.capture": {
|
|
736
|
+
const key = readSingle(parsed.rawOptions, "key");
|
|
737
|
+
const durationMs = readOptionalNumber(parsed.rawOptions, "duration");
|
|
738
|
+
const script = readSingle(parsed.rawOptions, "script");
|
|
739
|
+
const includeStorage = readOptionalBoolean(parsed.rawOptions, "include-storage");
|
|
740
|
+
const includeSessionStorage = readOptionalBoolean(
|
|
741
|
+
parsed.rawOptions,
|
|
742
|
+
"include-session-storage"
|
|
743
|
+
);
|
|
744
|
+
const includeIndexedDb = readOptionalBoolean(parsed.rawOptions, "include-indexed-db");
|
|
745
|
+
const globalNames = parseCommaSeparatedList(readSingle(parsed.rawOptions, "global-names"));
|
|
746
|
+
const caseId = readSingle(parsed.rawOptions, "case-id");
|
|
747
|
+
const notes = readSingle(parsed.rawOptions, "notes");
|
|
748
|
+
const tags = parseCommaSeparatedList(readSingle(parsed.rawOptions, "tags"));
|
|
749
|
+
return {
|
|
750
|
+
...key === void 0 ? {} : { key },
|
|
751
|
+
...durationMs === void 0 ? {} : { durationMs },
|
|
752
|
+
...script === void 0 ? {} : { script },
|
|
753
|
+
...includeStorage === void 0 ? {} : { includeStorage },
|
|
754
|
+
...includeSessionStorage === void 0 ? {} : { includeSessionStorage },
|
|
755
|
+
...includeIndexedDb === void 0 ? {} : { includeIndexedDb },
|
|
756
|
+
...globalNames === void 0 ? {} : { globalNames },
|
|
757
|
+
...caseId === void 0 ? {} : { caseId },
|
|
758
|
+
...notes === void 0 ? {} : { notes },
|
|
759
|
+
...tags === void 0 ? {} : { tags }
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
case "interaction.get":
|
|
763
|
+
case "interaction.replay":
|
|
764
|
+
if (parsed.rest[0] === void 0) {
|
|
765
|
+
throw new Error(`${parsed.command.join(" ")} requires a trace id.`);
|
|
766
|
+
}
|
|
767
|
+
return {
|
|
768
|
+
traceId: parsed.rest[0]
|
|
769
|
+
};
|
|
770
|
+
case "interaction.diff":
|
|
771
|
+
if (parsed.rest[0] === void 0 || parsed.rest[1] === void 0) {
|
|
772
|
+
throw new Error("interaction diff requires two trace ids.");
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
leftTraceId: parsed.rest[0],
|
|
776
|
+
rightTraceId: parsed.rest[1]
|
|
777
|
+
};
|
|
778
|
+
case "artifact.read":
|
|
779
|
+
if (parsed.rest[0] === void 0) {
|
|
780
|
+
throw new Error("artifact read requires an artifact id.");
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
artifactId: parsed.rest[0]
|
|
784
|
+
};
|
|
785
|
+
case "session.close":
|
|
786
|
+
return {};
|
|
787
|
+
default:
|
|
788
|
+
throw new Error(
|
|
789
|
+
`${operation} does not have a direct CLI input shape. Use a supported command or the SDK.`
|
|
790
|
+
);
|
|
208
791
|
}
|
|
209
|
-
|
|
792
|
+
}
|
|
793
|
+
function buildElementTargetInput(parsed, verb) {
|
|
794
|
+
const element = readRequiredPositiveInteger(
|
|
795
|
+
parsed.rest[0],
|
|
796
|
+
`${verb} requires an element number.`
|
|
797
|
+
);
|
|
798
|
+
const persist = readPersistKey(parsed, verb);
|
|
799
|
+
const captureNetwork = readSingle(parsed.rawOptions, "capture-network");
|
|
210
800
|
return {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
engine: record.engine,
|
|
218
|
-
...browser === void 0 ? {} : { browser }
|
|
801
|
+
target: {
|
|
802
|
+
kind: "element",
|
|
803
|
+
element
|
|
804
|
+
},
|
|
805
|
+
...persist === void 0 ? {} : { persist },
|
|
806
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
219
807
|
};
|
|
220
808
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
809
|
+
function buildComputerExecuteInput(parsed) {
|
|
810
|
+
const subcommand = parsed.command[1];
|
|
811
|
+
const screenshotFormat = readSingle(parsed.rawOptions, "format");
|
|
812
|
+
const screenshot = screenshotFormat === void 0 ? void 0 : {
|
|
813
|
+
format: readScreenshotFormat(screenshotFormat)
|
|
814
|
+
};
|
|
815
|
+
const captureNetwork = readSingle(parsed.rawOptions, "capture-network");
|
|
816
|
+
switch (subcommand) {
|
|
817
|
+
case "click": {
|
|
818
|
+
const button = readSingle(parsed.rawOptions, "button");
|
|
819
|
+
const clickCount = readOptionalNumber(parsed.rawOptions, "count");
|
|
820
|
+
const modifiers = readKeyModifiers(readSingle(parsed.rawOptions, "modifiers"));
|
|
821
|
+
return {
|
|
822
|
+
action: {
|
|
823
|
+
type: "click",
|
|
824
|
+
x: readRequiredNumber(parsed.rest[0], "computer click requires x."),
|
|
825
|
+
y: readRequiredNumber(parsed.rest[1], "computer click requires y."),
|
|
826
|
+
...button === void 0 ? {} : { button: readClickButton(button) },
|
|
827
|
+
...clickCount === void 0 ? {} : { clickCount },
|
|
828
|
+
...modifiers === void 0 ? {} : { modifiers }
|
|
829
|
+
},
|
|
830
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
case "type":
|
|
834
|
+
if (parsed.rest[0] === void 0) {
|
|
835
|
+
throw new Error("computer type requires text.");
|
|
836
|
+
}
|
|
837
|
+
return {
|
|
838
|
+
action: {
|
|
839
|
+
type: "type",
|
|
840
|
+
text: joinRest(parsed.rest, 0)
|
|
841
|
+
},
|
|
842
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
843
|
+
};
|
|
844
|
+
case "key": {
|
|
845
|
+
if (parsed.rest[0] === void 0) {
|
|
846
|
+
throw new Error("computer key requires a key.");
|
|
847
|
+
}
|
|
848
|
+
const modifiers = readKeyModifiers(readSingle(parsed.rawOptions, "modifiers"));
|
|
849
|
+
return {
|
|
850
|
+
action: {
|
|
851
|
+
type: "key",
|
|
852
|
+
key: parsed.rest[0],
|
|
853
|
+
...modifiers === void 0 ? {} : { modifiers }
|
|
854
|
+
},
|
|
855
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
case "scroll": {
|
|
859
|
+
const dx = readOptionalNumber(parsed.rawOptions, "dx");
|
|
860
|
+
const dy = readOptionalNumber(parsed.rawOptions, "dy");
|
|
861
|
+
if (dx === void 0 || dy === void 0) {
|
|
862
|
+
throw new Error('computer scroll requires "--dx" and "--dy".');
|
|
863
|
+
}
|
|
864
|
+
return {
|
|
865
|
+
action: {
|
|
866
|
+
type: "scroll",
|
|
867
|
+
x: readRequiredNumber(parsed.rest[0], "computer scroll requires x."),
|
|
868
|
+
y: readRequiredNumber(parsed.rest[1], "computer scroll requires y."),
|
|
869
|
+
deltaX: dx,
|
|
870
|
+
deltaY: dy
|
|
871
|
+
},
|
|
872
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
case "move":
|
|
876
|
+
return {
|
|
877
|
+
action: {
|
|
878
|
+
type: "move",
|
|
879
|
+
x: readRequiredNumber(parsed.rest[0], "computer move requires x."),
|
|
880
|
+
y: readRequiredNumber(parsed.rest[1], "computer move requires y.")
|
|
881
|
+
},
|
|
882
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
883
|
+
};
|
|
884
|
+
case "drag": {
|
|
885
|
+
const steps = readOptionalNumber(parsed.rawOptions, "steps");
|
|
886
|
+
return {
|
|
887
|
+
action: {
|
|
888
|
+
type: "drag",
|
|
889
|
+
start: {
|
|
890
|
+
x: readRequiredNumber(parsed.rest[0], "computer drag requires start x."),
|
|
891
|
+
y: readRequiredNumber(parsed.rest[1], "computer drag requires start y.")
|
|
892
|
+
},
|
|
893
|
+
end: {
|
|
894
|
+
x: readRequiredNumber(parsed.rest[2], "computer drag requires end x."),
|
|
895
|
+
y: readRequiredNumber(parsed.rest[3], "computer drag requires end y.")
|
|
896
|
+
},
|
|
897
|
+
...steps === void 0 ? {} : { steps }
|
|
898
|
+
},
|
|
899
|
+
...captureNetwork === void 0 ? {} : { captureNetwork }
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
case "screenshot":
|
|
903
|
+
return {
|
|
904
|
+
action: {
|
|
905
|
+
type: "screenshot"
|
|
906
|
+
},
|
|
907
|
+
...screenshot === void 0 ? {} : { screenshot }
|
|
908
|
+
};
|
|
909
|
+
case "wait":
|
|
910
|
+
return {
|
|
911
|
+
action: {
|
|
912
|
+
type: "wait",
|
|
913
|
+
durationMs: readRequiredPositiveInteger(parsed.rest[0], "computer wait requires ms.")
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
default:
|
|
917
|
+
throw new Error(`Unknown computer command: ${parsed.command.join(" ")}`);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
async function resolvePageRefByIndex(runtime, index) {
|
|
921
|
+
const pages = (await runtime.listPages({})).pages;
|
|
922
|
+
const page = pages[index - 1];
|
|
923
|
+
if (page === void 0) {
|
|
924
|
+
throw new Error(`tab ${String(index)} does not exist.`);
|
|
925
|
+
}
|
|
926
|
+
return page.pageRef;
|
|
927
|
+
}
|
|
928
|
+
function readRequiredPositiveInteger(value, message) {
|
|
929
|
+
const parsed = readRequiredNumber(value, message);
|
|
930
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
931
|
+
throw new Error(message);
|
|
932
|
+
}
|
|
933
|
+
return parsed;
|
|
934
|
+
}
|
|
935
|
+
function readRequiredNumber(value, message) {
|
|
936
|
+
if (value === void 0) {
|
|
937
|
+
throw new Error(message);
|
|
938
|
+
}
|
|
939
|
+
const parsed = Number(value);
|
|
940
|
+
if (!Number.isFinite(parsed)) {
|
|
941
|
+
throw new Error(message);
|
|
942
|
+
}
|
|
943
|
+
return parsed;
|
|
944
|
+
}
|
|
945
|
+
function readSingleDirection(value) {
|
|
946
|
+
if (value === void 0 || !SCROLL_DIRECTIONS.has(value)) {
|
|
947
|
+
throw new Error("scroll requires a direction: up, down, left, or right.");
|
|
948
|
+
}
|
|
949
|
+
return value;
|
|
950
|
+
}
|
|
951
|
+
function readClickButton(value) {
|
|
952
|
+
if (value === void 0 || !CLICK_BUTTONS.has(value)) {
|
|
953
|
+
throw new Error('Expected "--button" to be one of: left, middle, right.');
|
|
954
|
+
}
|
|
955
|
+
return value;
|
|
956
|
+
}
|
|
957
|
+
function readFetchTransport(value) {
|
|
958
|
+
if (value === void 0 || !FETCH_TRANSPORTS.has(value)) {
|
|
959
|
+
throw new Error('Expected "--transport" to be one of: auto, direct, matched-tls, page.');
|
|
960
|
+
}
|
|
961
|
+
return value;
|
|
962
|
+
}
|
|
963
|
+
function readCaptchaProvider(value) {
|
|
964
|
+
if (value === void 0 || !CAPTCHA_PROVIDERS.has(value)) {
|
|
965
|
+
throw new Error('Expected "--provider" to be one of: 2captcha, capsolver.');
|
|
966
|
+
}
|
|
967
|
+
return value;
|
|
968
|
+
}
|
|
969
|
+
function readCaptchaType(value) {
|
|
970
|
+
if (value === void 0 || !CAPTCHA_TYPES.has(value)) {
|
|
971
|
+
throw new Error(
|
|
972
|
+
'Expected "--type" to be one of: recaptcha-v2, hcaptcha, turnstile.'
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
return value;
|
|
976
|
+
}
|
|
977
|
+
function readSandboxFidelity(value) {
|
|
978
|
+
if (value === void 0 || !SANDBOX_FIDELITIES.has(value)) {
|
|
979
|
+
throw new Error('Expected "--fidelity" to be one of: minimal, standard, full.');
|
|
980
|
+
}
|
|
981
|
+
return value;
|
|
982
|
+
}
|
|
983
|
+
function readSandboxClockMode(value) {
|
|
984
|
+
if (value === void 0 || !SANDBOX_CLOCK_MODES.has(value)) {
|
|
985
|
+
throw new Error('Expected "--clock" to be one of: real, manual.');
|
|
986
|
+
}
|
|
987
|
+
return value;
|
|
988
|
+
}
|
|
989
|
+
function readScreenshotFormat(value) {
|
|
990
|
+
if (value === void 0 || !SCREENSHOT_FORMATS.has(value)) {
|
|
991
|
+
throw new Error('Expected "--format" to be one of: png, jpeg, webp.');
|
|
992
|
+
}
|
|
993
|
+
return value;
|
|
994
|
+
}
|
|
995
|
+
function readKeyModifiers(value) {
|
|
996
|
+
const modifiers = parseCommaSeparatedList(value);
|
|
997
|
+
if (modifiers === void 0) {
|
|
998
|
+
return void 0;
|
|
999
|
+
}
|
|
1000
|
+
for (const modifier of modifiers) {
|
|
1001
|
+
if (!KEY_MODIFIERS.has(modifier)) {
|
|
1002
|
+
throw new Error('Expected "--modifiers" to contain only: Shift, Control, Alt, Meta.');
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
return [...new Set(modifiers)];
|
|
1006
|
+
}
|
|
1007
|
+
function readPersistKey(parsed, verb) {
|
|
1008
|
+
const value = readSingle(parsed.rawOptions, "persist");
|
|
1009
|
+
if (value === void 0) {
|
|
1010
|
+
return void 0;
|
|
1011
|
+
}
|
|
1012
|
+
if (value === "true" || value === "false") {
|
|
1013
|
+
throw new Error(`${verb} requires "--persist <key>" when using --persist.`);
|
|
1014
|
+
}
|
|
1015
|
+
if (verb === "scroll" && readOptionalNumber(parsed.rawOptions, "element") === void 0) {
|
|
1016
|
+
throw new Error('scroll requires "--element <n>" when using "--persist <key>".');
|
|
1017
|
+
}
|
|
1018
|
+
return value;
|
|
1019
|
+
}
|
|
1020
|
+
function readExtractPersistKey(parsed) {
|
|
1021
|
+
const value = readSingle(parsed.rawOptions, "persist");
|
|
1022
|
+
if (value === void 0) {
|
|
1023
|
+
return void 0;
|
|
1024
|
+
}
|
|
1025
|
+
if (value === "true" || value === "false") {
|
|
1026
|
+
throw new Error('extract requires "--persist <key>" when using --persist.');
|
|
1027
|
+
}
|
|
1028
|
+
return value;
|
|
1029
|
+
}
|
|
1030
|
+
function parseRequiredJsonObjectArgument(value, label) {
|
|
1031
|
+
const parsed = JSON.parse(value);
|
|
1032
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1033
|
+
throw new Error(`${label} must be a JSON object.`);
|
|
1034
|
+
}
|
|
1035
|
+
return parsed;
|
|
1036
|
+
}
|
|
1037
|
+
function joinRest(rest, startIndex) {
|
|
1038
|
+
return rest.slice(startIndex).join(" ");
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// src/cli/output.ts
|
|
1042
|
+
function renderOperationOutput(operation, result, input) {
|
|
1043
|
+
switch (operation) {
|
|
1044
|
+
case "session.open":
|
|
1045
|
+
case "page.goto":
|
|
1046
|
+
return renderJson(formatNavigationOutput(result));
|
|
1047
|
+
case "page.snapshot":
|
|
1048
|
+
return formatSnapshotOutput(result);
|
|
1049
|
+
case "dom.click":
|
|
1050
|
+
case "dom.hover":
|
|
1051
|
+
case "dom.input":
|
|
1052
|
+
case "dom.scroll":
|
|
1053
|
+
return renderJson(formatActionOutput(result, input));
|
|
1054
|
+
case "dom.extract":
|
|
1055
|
+
return renderJson(formatExtractOutput(result));
|
|
1056
|
+
case "page.list":
|
|
1057
|
+
case "page.new":
|
|
1058
|
+
case "page.activate":
|
|
1059
|
+
case "page.close":
|
|
1060
|
+
return formatTabOutput(result);
|
|
1061
|
+
case "network.query":
|
|
1062
|
+
return formatNetworkQueryOutput(result, input);
|
|
1063
|
+
case "network.detail":
|
|
1064
|
+
return formatNetworkDetailOutput(result);
|
|
1065
|
+
case "network.replay":
|
|
1066
|
+
case "session.fetch":
|
|
1067
|
+
return renderJson(formatTransportOutput(result, operation));
|
|
1068
|
+
case "session.cookies":
|
|
1069
|
+
return formatCookiesOutput(result);
|
|
1070
|
+
case "session.storage":
|
|
1071
|
+
return formatStorageOutput(result);
|
|
1072
|
+
case "session.state":
|
|
1073
|
+
return formatStateOutput(result);
|
|
1074
|
+
case "computer.execute":
|
|
1075
|
+
return renderJson(formatComputerOutput(result));
|
|
1076
|
+
case "scripts.capture":
|
|
1077
|
+
return formatScriptsCaptureOutput(result);
|
|
1078
|
+
case "scripts.beautify":
|
|
1079
|
+
return formatScriptTransformOutput(result, "scripts.beautify");
|
|
1080
|
+
case "scripts.deobfuscate":
|
|
1081
|
+
return formatScriptTransformOutput(result, "scripts.deobfuscate");
|
|
1082
|
+
case "scripts.sandbox":
|
|
1083
|
+
return renderJson(formatScriptSandboxOutput(result));
|
|
1084
|
+
case "captcha.solve":
|
|
1085
|
+
return renderJson(formatCaptchaSolveOutput(result));
|
|
1086
|
+
case "interaction.capture":
|
|
1087
|
+
case "interaction.get":
|
|
1088
|
+
return renderJson(formatInteractionTraceOutput(result));
|
|
1089
|
+
case "interaction.diff":
|
|
1090
|
+
return renderJson(formatInteractionDiffOutput(result));
|
|
1091
|
+
case "interaction.replay":
|
|
1092
|
+
return renderJson(formatInteractionReplayOutput(result));
|
|
1093
|
+
default:
|
|
1094
|
+
return renderJson(result);
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
function formatNavigationOutput(result) {
|
|
1098
|
+
return {
|
|
1099
|
+
...readStringField(result, "url") === void 0 ? {} : { url: readStringField(result, "url") },
|
|
1100
|
+
...readStringField(result, "title") === void 0 ? {} : { title: readStringField(result, "title") }
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
function formatSnapshotOutput(result) {
|
|
1104
|
+
if (result !== null && typeof result === "object" && typeof result.html === "string") {
|
|
1105
|
+
return `${result.html}
|
|
1106
|
+
`;
|
|
1107
|
+
}
|
|
1108
|
+
return renderJson(result);
|
|
1109
|
+
}
|
|
1110
|
+
function formatActionOutput(result, input) {
|
|
1111
|
+
const target = readObjectField(result, "target");
|
|
1112
|
+
const output = {
|
|
1113
|
+
...readStringField(target, "tagName") === void 0 ? {} : { tagName: readStringField(target, "tagName") },
|
|
1114
|
+
...readStringField(target, "pathHint") === void 0 ? {} : { pathHint: readStringField(target, "pathHint") }
|
|
1115
|
+
};
|
|
1116
|
+
const point = readObjectField(result, "point");
|
|
1117
|
+
if (point !== void 0) {
|
|
1118
|
+
output.point = {
|
|
1119
|
+
...readNumberField(point, "x") === void 0 ? {} : { x: readNumberField(point, "x") },
|
|
1120
|
+
...readNumberField(point, "y") === void 0 ? {} : { y: readNumberField(point, "y") }
|
|
228
1121
|
};
|
|
229
1122
|
}
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
1123
|
+
const persist = readStringField(target, "persist");
|
|
1124
|
+
if (persist !== void 0) {
|
|
1125
|
+
output.persist = persist;
|
|
1126
|
+
}
|
|
1127
|
+
const text = readStringField(input, "text");
|
|
1128
|
+
if (text !== void 0) {
|
|
1129
|
+
output.text = text;
|
|
1130
|
+
}
|
|
1131
|
+
const direction = readStringField(input, "direction");
|
|
1132
|
+
if (direction !== void 0) {
|
|
1133
|
+
output.direction = direction;
|
|
1134
|
+
}
|
|
1135
|
+
const amount = readNumberField(input, "amount");
|
|
1136
|
+
if (amount !== void 0) {
|
|
1137
|
+
output.amount = amount;
|
|
1138
|
+
}
|
|
1139
|
+
return output;
|
|
1140
|
+
}
|
|
1141
|
+
function formatExtractOutput(result) {
|
|
1142
|
+
const data = readUnknownField(result, "data");
|
|
1143
|
+
return data === void 0 ? result : data;
|
|
1144
|
+
}
|
|
1145
|
+
function formatTabOutput(result) {
|
|
1146
|
+
const pages = readArrayField(result, "pages");
|
|
1147
|
+
const activePageRef = readStringField(result, "activePageRef");
|
|
1148
|
+
const lines = [`[tabs] ${pages.length} tab${pages.length === 1 ? "" : "s"}`];
|
|
1149
|
+
pages.forEach((page, index) => {
|
|
1150
|
+
const marker = readStringField(page, "pageRef") === activePageRef ? "*" : " ";
|
|
1151
|
+
lines.push(
|
|
1152
|
+
`${marker} ${String(index + 1).padStart(2, " ")} ${truncateInline(readStringField(page, "title") ?? "(untitled)", 48)} ${readStringField(page, "url") ?? ""}`
|
|
1153
|
+
);
|
|
1154
|
+
});
|
|
1155
|
+
return `${lines.join("\n")}
|
|
1156
|
+
`;
|
|
1157
|
+
}
|
|
1158
|
+
function formatNetworkQueryOutput(result, input) {
|
|
1159
|
+
const records = readArrayField(result, "records");
|
|
1160
|
+
const capture = summarizeCapture(records);
|
|
1161
|
+
const jsonOnly = readBooleanField(input, "json") === true;
|
|
1162
|
+
const lines = [
|
|
1163
|
+
`[network.query] ${records.length} record${records.length === 1 ? "" : "s"}${capture === void 0 ? "" : ` from capture "${capture}"`}${jsonOnly ? " (JSON/GraphQL only)" : ""}`
|
|
1164
|
+
];
|
|
1165
|
+
for (const record of records) {
|
|
1166
|
+
const graphql = readObjectField(record, "graphql");
|
|
1167
|
+
const operationName = readStringField(graphql, "operationName");
|
|
1168
|
+
lines.push(
|
|
1169
|
+
`${readStringField(record, "recordId") ?? "rec:unknown"} ${readStringField(record, "method") ?? "GET"} ${readStatus(record)} ${readStringField(record, "resourceType") ?? "unknown"} ${readStringField(record, "url") ?? ""}${operationName === void 0 ? "" : ` [query: ${operationName}]`}`
|
|
1170
|
+
);
|
|
1171
|
+
const request = readObjectField(record, "request");
|
|
1172
|
+
const response = readObjectField(record, "response");
|
|
1173
|
+
const websocket = readObjectField(record, "websocket");
|
|
1174
|
+
if (request !== void 0) {
|
|
1175
|
+
lines.push(` request: ${formatBodySummary(request)}`);
|
|
1176
|
+
}
|
|
1177
|
+
if (response !== void 0) {
|
|
1178
|
+
lines.push(` response: ${formatBodySummary(response)}`);
|
|
1179
|
+
}
|
|
1180
|
+
const subprotocol = readStringField(websocket, "subprotocol");
|
|
1181
|
+
if (subprotocol !== void 0) {
|
|
1182
|
+
lines.push(` subprotocol: ${subprotocol}`);
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
return `${lines.join("\n")}
|
|
1186
|
+
`;
|
|
1187
|
+
}
|
|
1188
|
+
function formatNetworkDetailOutput(result) {
|
|
1189
|
+
if (result === null || typeof result !== "object") {
|
|
1190
|
+
return renderJson(result);
|
|
1191
|
+
}
|
|
1192
|
+
const lines = [`[network.detail] ${readStringField(result, "recordId") ?? "unknown"}`, ""];
|
|
1193
|
+
const summary = readObjectField(result, "summary");
|
|
1194
|
+
if (summary !== void 0) {
|
|
1195
|
+
lines.push(
|
|
1196
|
+
`${readStringField(summary, "method") ?? "GET"} ${readStatus(summary)} ${readStringField(summary, "url") ?? ""}`
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
const graphql = readObjectField(result, "graphql");
|
|
1200
|
+
if (graphql !== void 0) {
|
|
1201
|
+
const operationType = readStringField(graphql, "operationType");
|
|
1202
|
+
const operationName = readStringField(graphql, "operationName");
|
|
1203
|
+
lines.push(
|
|
1204
|
+
`${["GraphQL:", operationType, operationName].filter((value) => value !== void 0).join(" ")}`
|
|
1205
|
+
);
|
|
1206
|
+
const variables = readUnknownField(graphql, "variables");
|
|
1207
|
+
if (variables !== void 0) {
|
|
1208
|
+
lines.push("Variables:");
|
|
1209
|
+
lines.push(indentLines(stringifyValue(variables)));
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
const requestHeaders = readArrayField(result, "requestHeaders");
|
|
1213
|
+
if (requestHeaders.length > 0) {
|
|
1214
|
+
lines.push("", "Request headers:");
|
|
1215
|
+
lines.push(...requestHeaders.map((header) => formatHeaderLine(header)));
|
|
1216
|
+
}
|
|
1217
|
+
const responseHeaders = readArrayField(result, "responseHeaders");
|
|
1218
|
+
if (responseHeaders.length > 0) {
|
|
1219
|
+
lines.push("", "Response headers:");
|
|
1220
|
+
lines.push(...responseHeaders.map((header) => formatHeaderLine(header)));
|
|
1221
|
+
}
|
|
1222
|
+
const cookiesSent = readArrayField(result, "cookiesSent");
|
|
1223
|
+
if (cookiesSent.length > 0) {
|
|
1224
|
+
lines.push("", "Cookies sent:");
|
|
1225
|
+
lines.push(
|
|
1226
|
+
...cookiesSent.map((cookie) => {
|
|
1227
|
+
const name = readStringField(cookie, "name") ?? "cookie";
|
|
1228
|
+
const value = readStringField(cookie, "value") ?? "";
|
|
1229
|
+
return ` ${name}: ${truncateInline(value, 80)}`;
|
|
1230
|
+
})
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
const requestBody = readObjectField(result, "requestBody");
|
|
1234
|
+
if (requestBody !== void 0) {
|
|
1235
|
+
lines.push("", formatBodyPreview("Request body", requestBody));
|
|
1236
|
+
}
|
|
1237
|
+
const responseBody = readObjectField(result, "responseBody");
|
|
1238
|
+
if (responseBody !== void 0) {
|
|
1239
|
+
lines.push("", formatBodyPreview("Response body", responseBody));
|
|
1240
|
+
}
|
|
1241
|
+
const redirectChain = readArrayField(result, "redirectChain");
|
|
1242
|
+
if (redirectChain.length > 0) {
|
|
1243
|
+
lines.push("", `Redirect chain (${redirectChain.length} hop${redirectChain.length === 1 ? "" : "s"}):`);
|
|
1244
|
+
redirectChain.forEach((hop, index) => {
|
|
1245
|
+
const location = readStringField(hop, "location");
|
|
1246
|
+
lines.push(
|
|
1247
|
+
` ${index + 1}. ${readStringField(hop, "method") ?? "GET"} ${readStatus(hop)} ${readStringField(hop, "url") ?? ""}${location === void 0 ? "" : ` -> Location: ${location}`}`
|
|
1248
|
+
);
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
const notes = readArrayField(result, "notes").map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => entry !== void 0);
|
|
1252
|
+
if (notes.length > 0) {
|
|
1253
|
+
lines.push("", ...notes.map((note) => `Note: ${note}`));
|
|
1254
|
+
}
|
|
1255
|
+
return `${lines.join("\n")}
|
|
1256
|
+
`;
|
|
1257
|
+
}
|
|
1258
|
+
function formatTransportOutput(result, operation) {
|
|
1259
|
+
if (result === null || typeof result !== "object") {
|
|
1260
|
+
return { result };
|
|
1261
|
+
}
|
|
1262
|
+
const response = readObjectField(result, "response");
|
|
1263
|
+
const attempts = readArrayField(result, "attempts").map((attempt) => ({
|
|
1264
|
+
...readStringField(attempt, "transport") === void 0 ? {} : { transport: readStringField(attempt, "transport") },
|
|
1265
|
+
...readNumberField(attempt, "status") === void 0 ? {} : { status: readNumberField(attempt, "status") },
|
|
1266
|
+
...readStringField(attempt, "note") === void 0 ? {} : { note: readStringField(attempt, "note") },
|
|
1267
|
+
...readStringField(attempt, "error") === void 0 ? {} : { error: readStringField(attempt, "error") }
|
|
1268
|
+
}));
|
|
1269
|
+
const contentType = response === void 0 ? void 0 : findHeaderValue(readArrayField(response, "headers"), "content-type") ?? readStringField(readObjectField(response, "body"), "mimeType");
|
|
1270
|
+
const body = readObjectField(response, "body");
|
|
1271
|
+
const bodySize = body === void 0 ? void 0 : readNumberField(body, "originalByteLength") ?? readNumberField(body, "capturedByteLength");
|
|
1272
|
+
const output = {
|
|
1273
|
+
...operation === "network.replay" && readStringField(result, "recordId") !== void 0 ? { recordId: readStringField(result, "recordId") } : {},
|
|
1274
|
+
...readStringField(result, "transport") === void 0 ? {} : { transport: readStringField(result, "transport") },
|
|
1275
|
+
...response === void 0 ? {} : { status: readNumberField(response, "status") },
|
|
1276
|
+
...contentType === void 0 ? {} : { contentType },
|
|
1277
|
+
...bodySize === void 0 ? {} : { bodySize }
|
|
1278
|
+
};
|
|
1279
|
+
const note = readStringField(result, "note");
|
|
1280
|
+
if (note !== void 0) {
|
|
1281
|
+
output.note = note;
|
|
1282
|
+
}
|
|
1283
|
+
const data = readUnknownField(result, "data");
|
|
1284
|
+
if (data !== void 0) {
|
|
1285
|
+
output.data = truncateDataShape(data);
|
|
1286
|
+
}
|
|
1287
|
+
if (attempts.length > 0) {
|
|
1288
|
+
output.attempts = attempts;
|
|
1289
|
+
}
|
|
1290
|
+
if (JSON.stringify(output).length > 4096 && data !== void 0) {
|
|
1291
|
+
output.data = `... truncated, ${JSON.stringify(data).length.toLocaleString("en-US")} chars total`;
|
|
1292
|
+
}
|
|
1293
|
+
return output;
|
|
1294
|
+
}
|
|
1295
|
+
function formatCookiesOutput(result) {
|
|
1296
|
+
if (result === null || typeof result !== "object") {
|
|
1297
|
+
return renderJson(result);
|
|
1298
|
+
}
|
|
1299
|
+
const cookies = readArrayField(result, "cookies");
|
|
1300
|
+
const domain = readStringField(result, "domain");
|
|
1301
|
+
const lines = [`[cookies] ${cookies.length} cookie${cookies.length === 1 ? "" : "s"}${domain === void 0 ? "" : ` for ${domain}`}`];
|
|
1302
|
+
for (const cookie of cookies) {
|
|
1303
|
+
const flags = [
|
|
1304
|
+
readBooleanField(cookie, "session") === true ? "session" : void 0,
|
|
1305
|
+
readBooleanField(cookie, "httpOnly") === true ? "httpOnly" : void 0,
|
|
1306
|
+
readBooleanField(cookie, "secure") === true ? "secure" : void 0,
|
|
1307
|
+
readStringField(cookie, "expiresAt")
|
|
1308
|
+
].filter((value) => value !== void 0);
|
|
1309
|
+
lines.push(
|
|
1310
|
+
` ${padRight(readStringField(cookie, "name") ?? "cookie", 20)} ${truncateInline(readStringField(cookie, "value") ?? "", 48)}${flags.length === 0 ? "" : ` ${flags.join(" ")}`}`
|
|
1311
|
+
);
|
|
1312
|
+
}
|
|
1313
|
+
return `${lines.join("\n")}
|
|
1314
|
+
`;
|
|
1315
|
+
}
|
|
1316
|
+
function formatStorageOutput(result) {
|
|
1317
|
+
if (result === null || typeof result !== "object") {
|
|
1318
|
+
return renderJson(result);
|
|
1319
|
+
}
|
|
1320
|
+
const domains = readArrayField(result, "domains");
|
|
1321
|
+
const lines = [];
|
|
1322
|
+
for (const domain of domains) {
|
|
1323
|
+
const domainName = readStringField(domain, "domain") ?? "unknown";
|
|
1324
|
+
const localStorage = readArrayField(domain, "localStorage");
|
|
1325
|
+
const sessionStorage = readArrayField(domain, "sessionStorage");
|
|
1326
|
+
lines.push(`[storage] localStorage for ${domainName} (${localStorage.length} key${localStorage.length === 1 ? "" : "s"})`, "");
|
|
1327
|
+
lines.push(...localStorage.map((entry) => formatStorageEntry(entry)));
|
|
1328
|
+
lines.push("", `[storage] sessionStorage for ${domainName} (${sessionStorage.length} key${sessionStorage.length === 1 ? "" : "s"})`, "");
|
|
1329
|
+
lines.push(...sessionStorage.map((entry) => formatStorageEntry(entry)), "");
|
|
1330
|
+
}
|
|
1331
|
+
return `${lines.join("\n").trimEnd()}
|
|
1332
|
+
`;
|
|
1333
|
+
}
|
|
1334
|
+
function formatStateOutput(result) {
|
|
1335
|
+
if (result === null || typeof result !== "object") {
|
|
1336
|
+
return renderJson(result);
|
|
1337
|
+
}
|
|
1338
|
+
const domains = readArrayField(result, "domains");
|
|
1339
|
+
const lines = [];
|
|
1340
|
+
for (const domain of domains) {
|
|
1341
|
+
const name = readStringField(domain, "domain") ?? "unknown";
|
|
1342
|
+
lines.push(`[state] ${name}`, "");
|
|
1343
|
+
const cookies = readArrayField(domain, "cookies");
|
|
1344
|
+
lines.push(`Cookies (${cookies.length}):`);
|
|
1345
|
+
lines.push(
|
|
1346
|
+
...cookies.map(
|
|
1347
|
+
(cookie) => ` ${padRight(readStringField(cookie, "name") ?? "cookie", 16)} ${truncateInline(readStringField(cookie, "value") ?? "", 36)}`
|
|
1348
|
+
)
|
|
1349
|
+
);
|
|
1350
|
+
const hiddenFields = readArrayField(domain, "hiddenFields");
|
|
1351
|
+
lines.push("", `Hidden fields (${hiddenFields.length}):`);
|
|
1352
|
+
lines.push(
|
|
1353
|
+
...hiddenFields.map(
|
|
1354
|
+
(field) => ` ${readStringField(field, "path") ?? "input"} = ${JSON.stringify(readStringField(field, "value") ?? "")}`
|
|
1355
|
+
)
|
|
1356
|
+
);
|
|
1357
|
+
const localStorage = readArrayField(domain, "localStorage");
|
|
1358
|
+
lines.push("", `localStorage (${localStorage.length} key${localStorage.length === 1 ? "" : "s"}):`);
|
|
1359
|
+
lines.push(...localStorage.map((entry) => formatStorageEntry(entry)));
|
|
1360
|
+
const sessionStorage = readArrayField(domain, "sessionStorage");
|
|
1361
|
+
lines.push("", `sessionStorage (${sessionStorage.length} key${sessionStorage.length === 1 ? "" : "s"}):`);
|
|
1362
|
+
lines.push(...sessionStorage.map((entry) => formatStorageEntry(entry)));
|
|
1363
|
+
const globals = readObjectField(domain, "globals");
|
|
1364
|
+
if (globals !== void 0) {
|
|
1365
|
+
lines.push("", "Globals:");
|
|
1366
|
+
for (const [key, value] of Object.entries(globals)) {
|
|
1367
|
+
lines.push(` ${key} = ${truncateInline(stringifyScalarLike(value), 80)}`);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
lines.push("");
|
|
1371
|
+
}
|
|
1372
|
+
return `${lines.join("\n").trimEnd()}
|
|
1373
|
+
`;
|
|
1374
|
+
}
|
|
1375
|
+
function formatComputerOutput(result) {
|
|
1376
|
+
const action = readObjectField(result, "action");
|
|
1377
|
+
const screenshot = readObjectField(result, "screenshot");
|
|
1378
|
+
const payload = readObjectField(screenshot, "payload");
|
|
1379
|
+
const timing = readObjectField(result, "timing");
|
|
1380
|
+
return {
|
|
1381
|
+
...action === void 0 ? {} : { action },
|
|
1382
|
+
...payload === void 0 ? {} : {
|
|
1383
|
+
screenshot: {
|
|
1384
|
+
...readStringField(payload, "uri") === void 0 ? {} : { uri: readStringField(payload, "uri") },
|
|
1385
|
+
...readStringField(screenshot, "format") === void 0 ? {} : { format: readStringField(screenshot, "format") },
|
|
1386
|
+
...readObjectField(screenshot, "size") === void 0 ? {} : { size: readObjectField(screenshot, "size") }
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
...timing === void 0 ? {} : { timingMs: timing }
|
|
1390
|
+
};
|
|
1391
|
+
}
|
|
1392
|
+
function formatScriptsCaptureOutput(result) {
|
|
1393
|
+
if (result === null || typeof result !== "object") {
|
|
1394
|
+
return renderJson(result);
|
|
1395
|
+
}
|
|
1396
|
+
const scripts = readArrayField(result, "scripts");
|
|
1397
|
+
const lines = [`[scripts.capture] ${scripts.length} script${scripts.length === 1 ? "" : "s"}`];
|
|
1398
|
+
for (const script of scripts) {
|
|
1399
|
+
const source = readStringField(script, "source") ?? "unknown";
|
|
1400
|
+
const url = readStringField(script, "url") ?? "<inline>";
|
|
1401
|
+
const artifactId = readStringField(script, "artifactId");
|
|
1402
|
+
const content = readStringField(script, "content") ?? "";
|
|
1403
|
+
lines.push(
|
|
1404
|
+
`${artifactId === void 0 ? "-" : artifactId} ${source.padEnd(8, " ")} ${truncateInline(url, 120)} (${content.length.toLocaleString("en-US")} chars)`
|
|
1405
|
+
);
|
|
1406
|
+
}
|
|
1407
|
+
return `${lines.join("\n")}
|
|
1408
|
+
`;
|
|
1409
|
+
}
|
|
1410
|
+
function formatScriptTransformOutput(result, label) {
|
|
1411
|
+
if (result === null || typeof result !== "object") {
|
|
1412
|
+
return renderJson(result);
|
|
1413
|
+
}
|
|
1414
|
+
const lines = [
|
|
1415
|
+
`[${label}] ${formatBytes(readNumberField(result, "bytesBefore"))} -> ${formatBytes(readNumberField(result, "bytesAfter"))}`
|
|
1416
|
+
];
|
|
1417
|
+
const artifactId = readStringField(result, "artifactId");
|
|
1418
|
+
if (artifactId !== void 0) {
|
|
1419
|
+
lines.push(`artifact: ${artifactId}`);
|
|
1420
|
+
}
|
|
1421
|
+
const transforms = readArrayField(result, "transforms").map((value) => typeof value === "string" ? value : void 0).filter((value) => value !== void 0);
|
|
1422
|
+
if (transforms.length > 0) {
|
|
1423
|
+
lines.push(`transforms: ${transforms.join(", ")}`);
|
|
1424
|
+
}
|
|
1425
|
+
const content = readStringField(result, "content");
|
|
1426
|
+
if (content !== void 0) {
|
|
1427
|
+
lines.push("", content);
|
|
1428
|
+
}
|
|
1429
|
+
return `${lines.join("\n")}
|
|
1430
|
+
`;
|
|
1431
|
+
}
|
|
1432
|
+
function formatInteractionTraceOutput(result) {
|
|
1433
|
+
const trace = readObjectField(result, "trace");
|
|
1434
|
+
if (trace === void 0) {
|
|
1435
|
+
return { result };
|
|
1436
|
+
}
|
|
1437
|
+
const payload = readObjectField(trace, "payload");
|
|
1438
|
+
return {
|
|
1439
|
+
...readStringField(trace, "id") === void 0 ? {} : { id: readStringField(trace, "id") },
|
|
1440
|
+
...readStringField(trace, "key") === void 0 ? {} : { key: readStringField(trace, "key") },
|
|
1441
|
+
...readStringField(trace, "version") === void 0 ? {} : { version: readStringField(trace, "version") },
|
|
1442
|
+
...readStringField(payload, "mode") === void 0 ? {} : { mode: readStringField(payload, "mode") },
|
|
1443
|
+
...readStringField(payload, "url") === void 0 ? {} : { url: readStringField(payload, "url") },
|
|
1444
|
+
...readArrayField(payload, "events").length === 0 ? {} : { eventCount: readArrayField(payload, "events").length },
|
|
1445
|
+
...readArrayField(payload, "networkRecordIds").length === 0 ? {} : { networkRecordIds: readArrayField(payload, "networkRecordIds") }
|
|
1446
|
+
};
|
|
1447
|
+
}
|
|
1448
|
+
function formatScriptSandboxOutput(result) {
|
|
1449
|
+
if (result === null || typeof result !== "object") {
|
|
1450
|
+
return { result };
|
|
1451
|
+
}
|
|
1452
|
+
const capturedAjax = readArrayField(result, "capturedAjax").map((entry) => ({
|
|
1453
|
+
...readStringField(entry, "method") === void 0 ? {} : { method: readStringField(entry, "method") },
|
|
1454
|
+
...readStringField(entry, "url") === void 0 ? {} : { url: readStringField(entry, "url") },
|
|
1455
|
+
...readNumberField(entry, "timestamp") === void 0 ? {} : { timestamp: readNumberField(entry, "timestamp") }
|
|
1456
|
+
}));
|
|
1457
|
+
const errors = readArrayField(result, "errors").map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => entry !== void 0);
|
|
1458
|
+
return {
|
|
1459
|
+
...readNumberField(result, "durationMs") === void 0 ? {} : { durationMs: readNumberField(result, "durationMs") },
|
|
1460
|
+
...capturedAjax.length === 0 ? {} : { capturedAjax },
|
|
1461
|
+
...errors.length === 0 ? {} : { errors },
|
|
1462
|
+
...readUnknownField(result, "result") === void 0 ? {} : { result: truncateDataShape(readUnknownField(result, "result")) }
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
function formatCaptchaSolveOutput(result) {
|
|
1466
|
+
const captcha = readObjectField(result, "captcha");
|
|
1467
|
+
return {
|
|
1468
|
+
...readStringField(result, "provider") === void 0 ? {} : { provider: readStringField(result, "provider") },
|
|
1469
|
+
...captcha === void 0 ? {} : {
|
|
1470
|
+
captcha: {
|
|
1471
|
+
...readStringField(captcha, "type") === void 0 ? {} : { type: readStringField(captcha, "type") },
|
|
1472
|
+
...readStringField(captcha, "siteKey") === void 0 ? {} : { siteKey: readStringField(captcha, "siteKey") },
|
|
1473
|
+
...readStringField(captcha, "pageUrl") === void 0 ? {} : { pageUrl: readStringField(captcha, "pageUrl") }
|
|
1474
|
+
}
|
|
1475
|
+
},
|
|
1476
|
+
...readStringField(result, "token") === void 0 ? {} : { token: readStringField(result, "token") },
|
|
1477
|
+
...readBooleanField(result, "injected") === void 0 ? {} : { injected: readBooleanField(result, "injected") }
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
function formatInteractionDiffOutput(result) {
|
|
1481
|
+
return {
|
|
1482
|
+
...readObjectField(result, "summary") === void 0 ? {} : { summary: readObjectField(result, "summary") },
|
|
1483
|
+
...readArrayField(result, "eventSequenceMismatches").length === 0 ? {} : { eventSequenceMismatches: readArrayField(result, "eventSequenceMismatches") },
|
|
1484
|
+
...readArrayField(result, "eventPropertyMismatches").length === 0 ? {} : { eventPropertyMismatches: readArrayField(result, "eventPropertyMismatches") },
|
|
1485
|
+
...readArrayField(result, "stateMismatches").length === 0 ? {} : { stateMismatches: readArrayField(result, "stateMismatches") },
|
|
1486
|
+
...readArrayField(result, "downstreamRequestMismatches").length === 0 ? {} : { downstreamRequestMismatches: readArrayField(result, "downstreamRequestMismatches") }
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
function formatInteractionReplayOutput(result) {
|
|
1490
|
+
return {
|
|
1491
|
+
...readStringField(result, "traceId") === void 0 ? {} : { traceId: readStringField(result, "traceId") },
|
|
1492
|
+
...readNumberField(result, "replayedEventCount") === void 0 ? {} : { replayedEventCount: readNumberField(result, "replayedEventCount") },
|
|
1493
|
+
...readBooleanField(result, "success") === void 0 ? {} : { success: readBooleanField(result, "success") },
|
|
1494
|
+
...readStringField(result, "error") === void 0 ? {} : { error: readStringField(result, "error") }
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
function formatBodySummary(body) {
|
|
1498
|
+
if (body === null || typeof body !== "object") {
|
|
1499
|
+
return "unknown";
|
|
1500
|
+
}
|
|
1501
|
+
if (readBooleanField(body, "streaming") === true) {
|
|
1502
|
+
return `streaming (${readStringField(body, "contentType") ?? "unknown"})`;
|
|
1503
|
+
}
|
|
1504
|
+
return `${formatBytes(readNumberField(body, "bytes"))} (${readStringField(body, "contentType") ?? "unknown"})`;
|
|
1505
|
+
}
|
|
1506
|
+
function formatBodyPreview(label, preview) {
|
|
1507
|
+
const header = `${label} (${formatBytes(readNumberField(preview, "bytes"))}${readStringField(preview, "contentType") === void 0 ? "" : `, ${readStringField(preview, "contentType")}`}${readBooleanField(preview, "truncated") === true ? ", truncated" : ""}):`;
|
|
1508
|
+
const data = readUnknownField(preview, "data");
|
|
1509
|
+
if (data === void 0) {
|
|
1510
|
+
return header;
|
|
1511
|
+
}
|
|
1512
|
+
return `${header}
|
|
1513
|
+
${indentLines(stringifyValue(data))}`;
|
|
1514
|
+
}
|
|
1515
|
+
function formatStorageEntry(entry) {
|
|
1516
|
+
return ` ${padRight(readStringField(entry, "key") ?? "key", 18)} ${truncateInline(readStringField(entry, "value") ?? "", 80)}`;
|
|
1517
|
+
}
|
|
1518
|
+
function formatHeaderLine(header) {
|
|
1519
|
+
return ` ${readStringField(header, "name") ?? "header"}: ${readStringField(header, "value") ?? ""}`;
|
|
1520
|
+
}
|
|
1521
|
+
function truncateDataShape(value, depth = 0) {
|
|
1522
|
+
if (value === null || typeof value === "number" || typeof value === "boolean" || value === void 0) {
|
|
1523
|
+
return value;
|
|
1524
|
+
}
|
|
1525
|
+
if (typeof value === "string") {
|
|
1526
|
+
return value.length <= 200 ? value : `${value.slice(0, 200)}...${value.length} chars total`;
|
|
1527
|
+
}
|
|
1528
|
+
if (Array.isArray(value)) {
|
|
1529
|
+
if (depth >= 4) {
|
|
1530
|
+
return `... ${value.length} items`;
|
|
239
1531
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
1532
|
+
if (value.length > 3) {
|
|
1533
|
+
return [
|
|
1534
|
+
`... ${value.length} items, first 2 shown`,
|
|
1535
|
+
truncateDataShape(value[0], depth + 1),
|
|
1536
|
+
truncateDataShape(value[1], depth + 1)
|
|
1537
|
+
];
|
|
1538
|
+
}
|
|
1539
|
+
return value.map((entry) => truncateDataShape(entry, depth + 1));
|
|
243
1540
|
}
|
|
244
|
-
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return {
|
|
249
|
-
...base,
|
|
250
|
-
status: "closed",
|
|
251
|
-
...session.region ?? session.runtimeRegion ? { region: session.region ?? session.runtimeRegion } : {}
|
|
252
|
-
};
|
|
1541
|
+
if (typeof value === "object") {
|
|
1542
|
+
const entries = Object.entries(value);
|
|
1543
|
+
if (depth >= 4) {
|
|
1544
|
+
return `... ${entries.length} keys`;
|
|
253
1545
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
1546
|
+
return Object.fromEntries(
|
|
1547
|
+
entries.map(([key, entry]) => [key, truncateDataShape(entry, depth + 1)])
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
return String(value);
|
|
1551
|
+
}
|
|
1552
|
+
function readArrayField(value, key) {
|
|
1553
|
+
if (value === null || typeof value !== "object") {
|
|
1554
|
+
return [];
|
|
1555
|
+
}
|
|
1556
|
+
const field = value[key];
|
|
1557
|
+
return Array.isArray(field) ? field : [];
|
|
1558
|
+
}
|
|
1559
|
+
function readObjectField(value, key) {
|
|
1560
|
+
if (value === null || typeof value !== "object") {
|
|
1561
|
+
return void 0;
|
|
1562
|
+
}
|
|
1563
|
+
const field = value[key];
|
|
1564
|
+
return field !== null && typeof field === "object" && !Array.isArray(field) ? field : void 0;
|
|
1565
|
+
}
|
|
1566
|
+
function readUnknownField(value, key) {
|
|
1567
|
+
if (value === null || typeof value !== "object") {
|
|
1568
|
+
return void 0;
|
|
1569
|
+
}
|
|
1570
|
+
return value[key];
|
|
1571
|
+
}
|
|
1572
|
+
function readStringField(value, key) {
|
|
1573
|
+
if (value === null || typeof value !== "object") {
|
|
1574
|
+
return void 0;
|
|
1575
|
+
}
|
|
1576
|
+
const field = value[key];
|
|
1577
|
+
return typeof field === "string" ? field : void 0;
|
|
1578
|
+
}
|
|
1579
|
+
function readNumberField(value, key) {
|
|
1580
|
+
if (value === null || typeof value !== "object") {
|
|
1581
|
+
return void 0;
|
|
1582
|
+
}
|
|
1583
|
+
const field = value[key];
|
|
1584
|
+
return typeof field === "number" ? field : void 0;
|
|
1585
|
+
}
|
|
1586
|
+
function readBooleanField(value, key) {
|
|
1587
|
+
if (value === null || typeof value !== "object") {
|
|
1588
|
+
return void 0;
|
|
1589
|
+
}
|
|
1590
|
+
const field = value[key];
|
|
1591
|
+
return typeof field === "boolean" ? field : void 0;
|
|
1592
|
+
}
|
|
1593
|
+
function readStatus(value) {
|
|
1594
|
+
const status = readNumberField(value, "status");
|
|
1595
|
+
return status === void 0 ? "-" : String(status);
|
|
1596
|
+
}
|
|
1597
|
+
function findHeaderValue(headers, name) {
|
|
1598
|
+
const normalized = name.toLowerCase();
|
|
1599
|
+
for (const header of headers) {
|
|
1600
|
+
if (readStringField(header, "name")?.toLowerCase() === normalized) {
|
|
1601
|
+
return readStringField(header, "value");
|
|
259
1602
|
}
|
|
260
|
-
return {
|
|
261
|
-
...base,
|
|
262
|
-
...session.region ?? session.runtimeRegion ? { region: session.region ?? session.runtimeRegion } : {}
|
|
263
|
-
};
|
|
264
|
-
} catch {
|
|
265
|
-
return {
|
|
266
|
-
...base,
|
|
267
|
-
status: "stale"
|
|
268
|
-
};
|
|
269
1603
|
}
|
|
1604
|
+
return void 0;
|
|
270
1605
|
}
|
|
271
|
-
function
|
|
272
|
-
if (
|
|
273
|
-
return "
|
|
1606
|
+
function formatBytes(bytes) {
|
|
1607
|
+
if (bytes === void 0) {
|
|
1608
|
+
return "unknown";
|
|
274
1609
|
}
|
|
275
|
-
return
|
|
1610
|
+
return `${bytes.toLocaleString("en-US")} bytes`;
|
|
276
1611
|
}
|
|
277
|
-
function
|
|
278
|
-
const
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
return
|
|
1612
|
+
function summarizeCapture(records) {
|
|
1613
|
+
const captures = new Set(
|
|
1614
|
+
records.map((record) => readStringField(record, "capture")).filter((capture) => capture !== void 0)
|
|
1615
|
+
);
|
|
1616
|
+
return captures.size === 1 ? [...captures][0] : void 0;
|
|
1617
|
+
}
|
|
1618
|
+
function padRight(value, width) {
|
|
1619
|
+
return value.length >= width ? value : `${value}${" ".repeat(width - value.length)}`;
|
|
1620
|
+
}
|
|
1621
|
+
function truncateInline(value, limit) {
|
|
1622
|
+
return value.length <= limit ? value : `${value.slice(0, Math.max(0, limit - 18))}...${value.length} chars`;
|
|
1623
|
+
}
|
|
1624
|
+
function stringifyValue(value) {
|
|
1625
|
+
return typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
1626
|
+
}
|
|
1627
|
+
function stringifyScalarLike(value) {
|
|
1628
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
1629
|
+
}
|
|
1630
|
+
function indentLines(value) {
|
|
1631
|
+
return value.split("\n").map((line) => ` ${line}`).join("\n");
|
|
1632
|
+
}
|
|
1633
|
+
function renderJson(value) {
|
|
1634
|
+
return `${JSON.stringify(value, null, 2)}
|
|
1635
|
+
`;
|
|
282
1636
|
}
|
|
283
1637
|
async function openBrowserUrl(url) {
|
|
284
1638
|
const command = resolveOpenBrowserCommand(url);
|
|
285
1639
|
await new Promise((resolve, reject) => {
|
|
286
1640
|
const child = spawn(command.executable, command.args, {
|
|
287
|
-
detached:
|
|
1641
|
+
detached: process4.platform !== "win32",
|
|
288
1642
|
stdio: "ignore"
|
|
289
1643
|
});
|
|
290
1644
|
child.once("error", reject);
|
|
@@ -295,15 +1649,15 @@ async function openBrowserUrl(url) {
|
|
|
295
1649
|
});
|
|
296
1650
|
}
|
|
297
1651
|
function resolveOpenBrowserCommand(url) {
|
|
298
|
-
if (
|
|
1652
|
+
if (process4.platform === "darwin") {
|
|
299
1653
|
return {
|
|
300
1654
|
executable: "open",
|
|
301
1655
|
args: [url]
|
|
302
1656
|
};
|
|
303
1657
|
}
|
|
304
|
-
if (
|
|
1658
|
+
if (process4.platform === "win32" || isWsl()) {
|
|
305
1659
|
return {
|
|
306
|
-
executable:
|
|
1660
|
+
executable: process4.platform === "win32" ? "cmd" : "cmd.exe",
|
|
307
1661
|
args: ["/c", "start", "", url]
|
|
308
1662
|
};
|
|
309
1663
|
}
|
|
@@ -313,7 +1667,7 @@ function resolveOpenBrowserCommand(url) {
|
|
|
313
1667
|
};
|
|
314
1668
|
}
|
|
315
1669
|
function isWsl() {
|
|
316
|
-
return
|
|
1670
|
+
return process4.platform === "linux" && (process4.env.WSL_DISTRO_NAME !== void 0 || os.release().toLowerCase().includes("microsoft"));
|
|
317
1671
|
}
|
|
318
1672
|
|
|
319
1673
|
// src/cli/record.ts
|
|
@@ -351,7 +1705,7 @@ async function runOpensteerRecordCommand(input) {
|
|
|
351
1705
|
workspace: input.workspace,
|
|
352
1706
|
startUrl: opened.url
|
|
353
1707
|
});
|
|
354
|
-
await mkdir(
|
|
1708
|
+
await mkdir(path2.dirname(outputPath), { recursive: true });
|
|
355
1709
|
await writeFile(outputPath, script, "utf8");
|
|
356
1710
|
if (input.closeSession !== void 0) {
|
|
357
1711
|
await input.closeSession();
|
|
@@ -417,7 +1771,7 @@ async function runOpensteerCloudRecordCommand(input) {
|
|
|
417
1771
|
if (completed.result === void 0) {
|
|
418
1772
|
throw new Error("Cloud recording completed without a replay script.");
|
|
419
1773
|
}
|
|
420
|
-
await mkdir(
|
|
1774
|
+
await mkdir(path2.dirname(outputPath), { recursive: true });
|
|
421
1775
|
await writeFile(outputPath, completed.result.script, "utf8");
|
|
422
1776
|
await runtime.close();
|
|
423
1777
|
closed = true;
|
|
@@ -433,166 +1787,385 @@ async function runOpensteerCloudRecordCommand(input) {
|
|
|
433
1787
|
}
|
|
434
1788
|
}
|
|
435
1789
|
}
|
|
436
|
-
function resolveRecordOutputPath(input) {
|
|
437
|
-
if (input.outputPath !== void 0) {
|
|
438
|
-
return
|
|
1790
|
+
function resolveRecordOutputPath(input) {
|
|
1791
|
+
if (input.outputPath !== void 0) {
|
|
1792
|
+
return path2.resolve(input.rootDir, input.outputPath);
|
|
1793
|
+
}
|
|
1794
|
+
return path2.join(
|
|
1795
|
+
resolveFilesystemWorkspacePath({
|
|
1796
|
+
rootDir: input.rootDir,
|
|
1797
|
+
workspace: input.workspace
|
|
1798
|
+
}),
|
|
1799
|
+
"recorded-flow.ts"
|
|
1800
|
+
);
|
|
1801
|
+
}
|
|
1802
|
+
function createRecorderRuntimeAdapter(runtime) {
|
|
1803
|
+
return {
|
|
1804
|
+
addInitScript: (input) => runtime.addInitScript(input),
|
|
1805
|
+
evaluate: async (input) => {
|
|
1806
|
+
const output = await runtime.evaluate({
|
|
1807
|
+
script: input.script,
|
|
1808
|
+
...input.pageRef === void 0 ? {} : { pageRef: input.pageRef }
|
|
1809
|
+
});
|
|
1810
|
+
return output.value;
|
|
1811
|
+
},
|
|
1812
|
+
listPages: async () => {
|
|
1813
|
+
const output = await runtime.listPages();
|
|
1814
|
+
return {
|
|
1815
|
+
pages: output.pages.map((page) => ({
|
|
1816
|
+
pageRef: page.pageRef,
|
|
1817
|
+
url: page.url,
|
|
1818
|
+
...page.openerPageRef === void 0 ? {} : { openerPageRef: page.openerPageRef }
|
|
1819
|
+
}))
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
function buildCloudRecordingSessionUrl(appBaseUrl, sessionId) {
|
|
1825
|
+
return `${appBaseUrl}/browsers/${encodeURIComponent(sessionId)}`;
|
|
1826
|
+
}
|
|
1827
|
+
async function tryOpenCloudRecordingSessionUrl(input) {
|
|
1828
|
+
try {
|
|
1829
|
+
await input.openUrl(input.sessionUrl);
|
|
1830
|
+
} catch {
|
|
1831
|
+
input.stderr.write(
|
|
1832
|
+
`Could not automatically open the cloud browser session. Open it manually: ${input.sessionUrl}
|
|
1833
|
+
`
|
|
1834
|
+
);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
async function resolveCloudRecordingSessionId(runtime) {
|
|
1838
|
+
const info = await runtime.info();
|
|
1839
|
+
if (typeof info.sessionId !== "string" || info.sessionId.length === 0) {
|
|
1840
|
+
throw new Error("Cloud recording could not resolve the created session id.");
|
|
1841
|
+
}
|
|
1842
|
+
return info.sessionId;
|
|
1843
|
+
}
|
|
1844
|
+
async function waitForCloudRecordingCompletion(input) {
|
|
1845
|
+
const pollIntervalMs = input.pollIntervalMs ?? 1e3;
|
|
1846
|
+
for (; ; ) {
|
|
1847
|
+
const state = await input.client.getSessionRecording(input.sessionId);
|
|
1848
|
+
if (state.status === "completed") {
|
|
1849
|
+
return state;
|
|
1850
|
+
}
|
|
1851
|
+
if (state.status === "failed") {
|
|
1852
|
+
throw new Error(state.error ?? "Cloud recording failed.");
|
|
1853
|
+
}
|
|
1854
|
+
await input.sleep(pollIntervalMs);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
function formatRecordedAction(action) {
|
|
1858
|
+
const time = new Date(action.timestamp).toISOString().slice(11, 19);
|
|
1859
|
+
switch (action.kind) {
|
|
1860
|
+
case "click":
|
|
1861
|
+
return `[${time}] click ${action.pageId} -> ${action.selector ?? "<unknown>"}`;
|
|
1862
|
+
case "dblclick":
|
|
1863
|
+
return `[${time}] dblclick ${action.pageId} -> ${action.selector ?? "<unknown>"}`;
|
|
1864
|
+
case "type":
|
|
1865
|
+
return `[${time}] type ${action.pageId} -> ${action.selector ?? "<unknown>"} -> ${JSON.stringify(action.detail.text)}`;
|
|
1866
|
+
case "keypress":
|
|
1867
|
+
return `[${time}] keypress ${action.pageId} -> ${action.detail.key}`;
|
|
1868
|
+
case "scroll":
|
|
1869
|
+
return `[${time}] scroll ${action.pageId} -> (${String(action.detail.deltaX)}, ${String(action.detail.deltaY)})`;
|
|
1870
|
+
case "select-option":
|
|
1871
|
+
return `[${time}] select ${action.pageId} -> ${action.selector ?? "<unknown>"} -> ${JSON.stringify(action.detail.value)}`;
|
|
1872
|
+
case "navigate":
|
|
1873
|
+
return `[${time}] navigate ${action.pageId} -> ${action.detail.url}`;
|
|
1874
|
+
case "new-tab":
|
|
1875
|
+
return `[${time}] new-tab ${action.pageId} -> ${action.detail.initialUrl}`;
|
|
1876
|
+
case "close-tab":
|
|
1877
|
+
return `[${time}] close-tab ${action.pageId}`;
|
|
1878
|
+
case "switch-tab":
|
|
1879
|
+
return `[${time}] switch-tab -> ${action.detail.toPageId}`;
|
|
1880
|
+
case "go-back":
|
|
1881
|
+
return `[${time}] go-back ${action.pageId}`;
|
|
1882
|
+
case "go-forward":
|
|
1883
|
+
return `[${time}] go-forward ${action.pageId}`;
|
|
1884
|
+
case "reload":
|
|
1885
|
+
return `[${time}] reload ${action.pageId}`;
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function delay(ms) {
|
|
1889
|
+
return new Promise((resolve) => {
|
|
1890
|
+
setTimeout(resolve, ms);
|
|
1891
|
+
});
|
|
1892
|
+
}
|
|
1893
|
+
var OPENSTEER_GITHUB_SOURCE = "steerlabs/opensteer";
|
|
1894
|
+
function createOpensteerSkillsInvocation(input) {
|
|
1895
|
+
const cliArgs = ["add", input.skillSourcePath];
|
|
1896
|
+
if (input.options.all === true) {
|
|
1897
|
+
cliArgs.push("--all");
|
|
1898
|
+
} else {
|
|
1899
|
+
const selectedSkills = resolveSelectedSkills(input.options);
|
|
1900
|
+
for (const skill of selectedSkills) {
|
|
1901
|
+
cliArgs.push("--skill", skill);
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
for (const agent of input.options.agents ?? []) {
|
|
1905
|
+
cliArgs.push("--agent", agent);
|
|
1906
|
+
}
|
|
1907
|
+
if (input.options.global === true) {
|
|
1908
|
+
cliArgs.push("--global");
|
|
1909
|
+
}
|
|
1910
|
+
if (input.options.yes === true) {
|
|
1911
|
+
cliArgs.push("--yes");
|
|
1912
|
+
}
|
|
1913
|
+
if (input.options.copy === true) {
|
|
1914
|
+
cliArgs.push("--copy");
|
|
1915
|
+
}
|
|
1916
|
+
if (input.options.list === true) {
|
|
1917
|
+
cliArgs.push("--list");
|
|
1918
|
+
}
|
|
1919
|
+
return {
|
|
1920
|
+
cliPath: input.skillsCliPath,
|
|
1921
|
+
cliArgs
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
function resolveOpensteerSkillsCliPath() {
|
|
1925
|
+
const require2 = createRequire(import.meta.url);
|
|
1926
|
+
const skillsPackagePath = require2.resolve("skills/package.json");
|
|
1927
|
+
const skillsPackageDir = path2.dirname(skillsPackagePath);
|
|
1928
|
+
const cliPath = path2.join(skillsPackageDir, "bin", "cli.mjs");
|
|
1929
|
+
if (!existsSync(cliPath)) {
|
|
1930
|
+
throw new Error(`skills CLI entrypoint was not found at "${cliPath}".`);
|
|
1931
|
+
}
|
|
1932
|
+
return cliPath;
|
|
1933
|
+
}
|
|
1934
|
+
function resolveOpensteerLocalSkillSourcePath() {
|
|
1935
|
+
let ancestor = path2.dirname(fileURLToPath(import.meta.url));
|
|
1936
|
+
for (let index = 0; index < 6; index += 1) {
|
|
1937
|
+
const candidate = path2.join(ancestor, "skills");
|
|
1938
|
+
const skillManifest = path2.join(candidate, "opensteer", "SKILL.md");
|
|
1939
|
+
if (existsSync(skillManifest)) {
|
|
1940
|
+
return candidate;
|
|
1941
|
+
}
|
|
1942
|
+
ancestor = path2.resolve(ancestor, "..");
|
|
1943
|
+
}
|
|
1944
|
+
throw new Error("Unable to find the packaged Opensteer skill source directory.");
|
|
1945
|
+
}
|
|
1946
|
+
async function checkOpensteerGitHubReachable() {
|
|
1947
|
+
try {
|
|
1948
|
+
const response = await fetch(`https://github.com/${OPENSTEER_GITHUB_SOURCE}`, {
|
|
1949
|
+
method: "HEAD",
|
|
1950
|
+
signal: AbortSignal.timeout(3e3),
|
|
1951
|
+
redirect: "manual"
|
|
1952
|
+
});
|
|
1953
|
+
return response.status < 500;
|
|
1954
|
+
} catch {
|
|
1955
|
+
return false;
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
async function runOpensteerSkillsInstaller(options = {}, overrideDeps = {}) {
|
|
1959
|
+
const deps = {
|
|
1960
|
+
resolveSkillsCliPath: resolveOpensteerSkillsCliPath,
|
|
1961
|
+
resolveLocalSkillSourcePath: resolveOpensteerLocalSkillSourcePath,
|
|
1962
|
+
checkGitHubReachable: checkOpensteerGitHubReachable,
|
|
1963
|
+
spawnInvocation: spawnOpensteerSkillsInvocation,
|
|
1964
|
+
...overrideDeps
|
|
1965
|
+
};
|
|
1966
|
+
const useGitHub = await deps.checkGitHubReachable();
|
|
1967
|
+
const skillSourcePath = useGitHub ? OPENSTEER_GITHUB_SOURCE : deps.resolveLocalSkillSourcePath();
|
|
1968
|
+
const invocation = createOpensteerSkillsInvocation({
|
|
1969
|
+
options,
|
|
1970
|
+
skillsCliPath: deps.resolveSkillsCliPath(),
|
|
1971
|
+
skillSourcePath
|
|
1972
|
+
});
|
|
1973
|
+
return deps.spawnInvocation(invocation);
|
|
1974
|
+
}
|
|
1975
|
+
async function spawnOpensteerSkillsInvocation(invocation) {
|
|
1976
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
1977
|
+
const child = spawn(process.execPath, [invocation.cliPath, ...invocation.cliArgs], {
|
|
1978
|
+
cwd: process.cwd(),
|
|
1979
|
+
env: process.env,
|
|
1980
|
+
stdio: "inherit"
|
|
1981
|
+
});
|
|
1982
|
+
child.once("error", (error) => {
|
|
1983
|
+
rejectPromise(error);
|
|
1984
|
+
});
|
|
1985
|
+
child.once("exit", (code) => {
|
|
1986
|
+
resolvePromise(typeof code === "number" ? code : 1);
|
|
1987
|
+
});
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
function resolveSelectedSkills(options) {
|
|
1991
|
+
if (options.skills !== void 0 && options.skills.length > 0) {
|
|
1992
|
+
return options.skills;
|
|
439
1993
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}),
|
|
445
|
-
"recorded-flow.ts"
|
|
446
|
-
);
|
|
1994
|
+
if (options.list === true) {
|
|
1995
|
+
return [];
|
|
1996
|
+
}
|
|
1997
|
+
return ["opensteer"];
|
|
447
1998
|
}
|
|
448
|
-
function
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
...input.pageRef === void 0 ? {} : { pageRef: input.pageRef }
|
|
455
|
-
});
|
|
456
|
-
return output.value;
|
|
1999
|
+
async function collectOpensteerStatus(input) {
|
|
2000
|
+
const output = {
|
|
2001
|
+
provider: {
|
|
2002
|
+
current: input.provider.mode,
|
|
2003
|
+
source: mapProviderSource(input.provider.source),
|
|
2004
|
+
...input.cloudConfig === void 0 ? {} : { cloudBaseUrl: input.cloudConfig.baseUrl }
|
|
457
2005
|
},
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
2006
|
+
...input.workspace === void 0 ? {} : { workspace: input.workspace }
|
|
2007
|
+
};
|
|
2008
|
+
if (input.workspace === void 0) {
|
|
2009
|
+
return output;
|
|
2010
|
+
}
|
|
2011
|
+
const rootPath = resolveFilesystemWorkspacePath({
|
|
2012
|
+
rootDir: input.rootDir,
|
|
2013
|
+
workspace: input.workspace
|
|
2014
|
+
});
|
|
2015
|
+
const localRecord = await readWorkspaceLocalRecord(rootPath);
|
|
2016
|
+
const cloudRecord = await readWorkspaceCloudRecord(rootPath);
|
|
2017
|
+
return {
|
|
2018
|
+
...output,
|
|
2019
|
+
rootPath,
|
|
2020
|
+
lanes: {
|
|
2021
|
+
local: describeLocalLane(localRecord, input.provider.mode === "local"),
|
|
2022
|
+
cloud: await describeCloudLane({
|
|
2023
|
+
record: cloudRecord,
|
|
2024
|
+
current: input.provider.mode === "cloud",
|
|
2025
|
+
cloudConfig: input.cloudConfig
|
|
2026
|
+
})
|
|
467
2027
|
}
|
|
468
2028
|
};
|
|
469
2029
|
}
|
|
470
|
-
function
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
2030
|
+
function renderOpensteerStatus(status) {
|
|
2031
|
+
const lines = [
|
|
2032
|
+
"Provider resolution",
|
|
2033
|
+
` current: ${status.provider.current}`,
|
|
2034
|
+
` source: ${status.provider.source}`
|
|
2035
|
+
];
|
|
2036
|
+
if (status.provider.cloudBaseUrl !== void 0) {
|
|
2037
|
+
lines.push(` control api: ${status.provider.cloudBaseUrl}`);
|
|
2038
|
+
}
|
|
2039
|
+
if (status.workspace !== void 0) {
|
|
2040
|
+
lines.push(` workspace: ${status.workspace}`);
|
|
2041
|
+
}
|
|
2042
|
+
if (status.lanes === void 0) {
|
|
2043
|
+
return `${lines.join("\n")}
|
|
2044
|
+
`;
|
|
2045
|
+
}
|
|
2046
|
+
lines.push("", "Live sessions");
|
|
2047
|
+
for (const lane of [status.lanes.local, status.lanes.cloud]) {
|
|
2048
|
+
lines.push(
|
|
2049
|
+
formatLaneRow({
|
|
2050
|
+
marker: lane.current ? "*" : " ",
|
|
2051
|
+
provider: lane.provider,
|
|
2052
|
+
status: lane.status,
|
|
2053
|
+
summary: lane.summary ?? "none",
|
|
2054
|
+
detail: lane.detail
|
|
2055
|
+
})
|
|
480
2056
|
);
|
|
481
2057
|
}
|
|
2058
|
+
return `${lines.join("\n")}
|
|
2059
|
+
`;
|
|
482
2060
|
}
|
|
483
|
-
async function
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
throw new Error("Cloud recording could not resolve the created session id.");
|
|
2061
|
+
async function readWorkspaceLocalRecord(rootPath) {
|
|
2062
|
+
if (!await pathExists(rootPath)) {
|
|
2063
|
+
return void 0;
|
|
487
2064
|
}
|
|
488
|
-
return
|
|
2065
|
+
return readPersistedLocalBrowserSessionRecord(rootPath);
|
|
489
2066
|
}
|
|
490
|
-
async function
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
const state = await input.client.getSessionRecording(input.sessionId);
|
|
494
|
-
if (state.status === "completed") {
|
|
495
|
-
return state;
|
|
496
|
-
}
|
|
497
|
-
if (state.status === "failed") {
|
|
498
|
-
throw new Error(state.error ?? "Cloud recording failed.");
|
|
499
|
-
}
|
|
500
|
-
await input.sleep(pollIntervalMs);
|
|
2067
|
+
async function readWorkspaceCloudRecord(rootPath) {
|
|
2068
|
+
if (!await pathExists(rootPath)) {
|
|
2069
|
+
return void 0;
|
|
501
2070
|
}
|
|
2071
|
+
return readPersistedCloudSessionRecord(rootPath);
|
|
502
2072
|
}
|
|
503
|
-
function
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
return `[${time}] type ${action.pageId} -> ${action.selector ?? "<unknown>"} -> ${JSON.stringify(action.detail.text)}`;
|
|
512
|
-
case "keypress":
|
|
513
|
-
return `[${time}] keypress ${action.pageId} -> ${action.detail.key}`;
|
|
514
|
-
case "scroll":
|
|
515
|
-
return `[${time}] scroll ${action.pageId} -> (${String(action.detail.deltaX)}, ${String(action.detail.deltaY)})`;
|
|
516
|
-
case "select-option":
|
|
517
|
-
return `[${time}] select ${action.pageId} -> ${action.selector ?? "<unknown>"} -> ${JSON.stringify(action.detail.value)}`;
|
|
518
|
-
case "navigate":
|
|
519
|
-
return `[${time}] navigate ${action.pageId} -> ${action.detail.url}`;
|
|
520
|
-
case "new-tab":
|
|
521
|
-
return `[${time}] new-tab ${action.pageId} -> ${action.detail.initialUrl}`;
|
|
522
|
-
case "close-tab":
|
|
523
|
-
return `[${time}] close-tab ${action.pageId}`;
|
|
524
|
-
case "switch-tab":
|
|
525
|
-
return `[${time}] switch-tab -> ${action.detail.toPageId}`;
|
|
526
|
-
case "go-back":
|
|
527
|
-
return `[${time}] go-back ${action.pageId}`;
|
|
528
|
-
case "go-forward":
|
|
529
|
-
return `[${time}] go-forward ${action.pageId}`;
|
|
530
|
-
case "reload":
|
|
531
|
-
return `[${time}] reload ${action.pageId}`;
|
|
2073
|
+
function describeLocalLane(record, current) {
|
|
2074
|
+
if (record === void 0 || !isProcessRunning(record.pid)) {
|
|
2075
|
+
return {
|
|
2076
|
+
provider: "local",
|
|
2077
|
+
status: "idle",
|
|
2078
|
+
current,
|
|
2079
|
+
summary: "none"
|
|
2080
|
+
};
|
|
532
2081
|
}
|
|
2082
|
+
const browser = record.executablePath ? path2.basename(record.executablePath).replace(/\.[A-Za-z0-9]+$/u, "") : void 0;
|
|
2083
|
+
return {
|
|
2084
|
+
provider: "local",
|
|
2085
|
+
status: "active",
|
|
2086
|
+
current,
|
|
2087
|
+
summary: `PID ${String(record.pid)}`,
|
|
2088
|
+
detail: browser ?? record.engine,
|
|
2089
|
+
pid: record.pid,
|
|
2090
|
+
engine: record.engine,
|
|
2091
|
+
...browser === void 0 ? {} : { browser }
|
|
2092
|
+
};
|
|
533
2093
|
}
|
|
534
|
-
function
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
2094
|
+
async function describeCloudLane(input) {
|
|
2095
|
+
if (input.record === void 0) {
|
|
2096
|
+
return {
|
|
2097
|
+
provider: "cloud",
|
|
2098
|
+
status: "idle",
|
|
2099
|
+
current: input.current,
|
|
2100
|
+
summary: "none"
|
|
2101
|
+
};
|
|
2102
|
+
}
|
|
2103
|
+
const base = {
|
|
2104
|
+
provider: "cloud",
|
|
2105
|
+
status: "connected",
|
|
2106
|
+
current: input.current,
|
|
2107
|
+
summary: input.record.sessionId,
|
|
2108
|
+
sessionId: input.record.sessionId,
|
|
2109
|
+
...input.cloudConfig === void 0 ? {} : {
|
|
2110
|
+
detail: input.cloudConfig.baseUrl,
|
|
2111
|
+
baseUrl: input.cloudConfig.baseUrl
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
if (input.cloudConfig === void 0) {
|
|
2115
|
+
return base;
|
|
2116
|
+
}
|
|
2117
|
+
try {
|
|
2118
|
+
const client = new OpensteerCloudClient(input.cloudConfig);
|
|
2119
|
+
const session = await client.getSession(input.record.sessionId);
|
|
2120
|
+
if (session.status === "closed") {
|
|
2121
|
+
return {
|
|
2122
|
+
...base,
|
|
2123
|
+
status: "closed",
|
|
2124
|
+
...session.region ?? session.runtimeRegion ? { region: session.region ?? session.runtimeRegion } : {}
|
|
2125
|
+
};
|
|
2126
|
+
}
|
|
2127
|
+
if (session.status === "failed") {
|
|
2128
|
+
return {
|
|
2129
|
+
...base,
|
|
2130
|
+
status: "stale"
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
2133
|
+
return {
|
|
2134
|
+
...base,
|
|
2135
|
+
...session.region ?? session.runtimeRegion ? { region: session.region ?? session.runtimeRegion } : {}
|
|
2136
|
+
};
|
|
2137
|
+
} catch {
|
|
2138
|
+
return {
|
|
2139
|
+
...base,
|
|
2140
|
+
status: "stale"
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
538
2143
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
[
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
["reverse package get", "reverse.package.get"],
|
|
563
|
-
["reverse package list", "reverse.package.list"],
|
|
564
|
-
["reverse package patch", "reverse.package.patch"],
|
|
565
|
-
["interaction capture", "interaction.capture"],
|
|
566
|
-
["interaction get", "interaction.get"],
|
|
567
|
-
["interaction diff", "interaction.diff"],
|
|
568
|
-
["interaction replay", "interaction.replay"],
|
|
569
|
-
["artifact read", "artifact.read"],
|
|
570
|
-
["scripts capture", "scripts.capture"],
|
|
571
|
-
["scripts beautify", "scripts.beautify"],
|
|
572
|
-
["scripts deobfuscate", "scripts.deobfuscate"],
|
|
573
|
-
["scripts sandbox", "scripts.sandbox"],
|
|
574
|
-
["captcha solve", "captcha.solve"],
|
|
575
|
-
["inspect cookies", "inspect.cookies"],
|
|
576
|
-
["inspect storage", "inspect.storage"],
|
|
577
|
-
["request raw", "request.raw"],
|
|
578
|
-
["request-plan infer", "request-plan.infer"],
|
|
579
|
-
["request-plan write", "request-plan.write"],
|
|
580
|
-
["request-plan get", "request-plan.get"],
|
|
581
|
-
["request-plan list", "request-plan.list"],
|
|
582
|
-
["recipe write", "recipe.write"],
|
|
583
|
-
["recipe get", "recipe.get"],
|
|
584
|
-
["recipe list", "recipe.list"],
|
|
585
|
-
["recipe run", "recipe.run"],
|
|
586
|
-
["auth-recipe write", "auth-recipe.write"],
|
|
587
|
-
["auth-recipe get", "auth-recipe.get"],
|
|
588
|
-
["auth-recipe list", "auth-recipe.list"],
|
|
589
|
-
["auth-recipe run", "auth-recipe.run"],
|
|
590
|
-
["request execute", "request.execute"],
|
|
591
|
-
["computer execute", "computer.execute"],
|
|
592
|
-
["close", "session.close"]
|
|
593
|
-
]);
|
|
2144
|
+
function mapProviderSource(source) {
|
|
2145
|
+
if (source === "explicit") {
|
|
2146
|
+
return "flag";
|
|
2147
|
+
}
|
|
2148
|
+
return source;
|
|
2149
|
+
}
|
|
2150
|
+
function formatLaneRow(input) {
|
|
2151
|
+
const provider = input.provider.padEnd(7, " ");
|
|
2152
|
+
const status = input.status.padEnd(9, " ");
|
|
2153
|
+
const summary = input.summary.padEnd(16, " ");
|
|
2154
|
+
return `${input.marker} ${provider} ${status} ${summary}${input.detail ?? ""}`.trimEnd();
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
// src/cli/bin.ts
|
|
2158
|
+
var emitProcessWarning = process4.emitWarning.bind(process4);
|
|
2159
|
+
process4.emitWarning = ((warning, ...args) => {
|
|
2160
|
+
const name = warning instanceof Error ? warning.name : typeof args[0] === "string" ? args[0] : void 0;
|
|
2161
|
+
const message = warning instanceof Error ? warning.message : warning;
|
|
2162
|
+
if (name === "ExperimentalWarning" && typeof message === "string" && message.includes("SQLite is an experimental feature")) {
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
return emitProcessWarning(warning, ...args);
|
|
2166
|
+
});
|
|
594
2167
|
async function main() {
|
|
595
|
-
const argv =
|
|
2168
|
+
const argv = process4.argv.slice(2);
|
|
596
2169
|
const bootstrapAction = resolveCliBootstrapAction(argv);
|
|
597
2170
|
if (bootstrapAction === "version") {
|
|
598
2171
|
printVersion();
|
|
@@ -602,7 +2175,7 @@ async function main() {
|
|
|
602
2175
|
printHelp();
|
|
603
2176
|
return;
|
|
604
2177
|
}
|
|
605
|
-
await loadCliEnvironment(
|
|
2178
|
+
await loadCliEnvironment(process4.cwd());
|
|
606
2179
|
const parsed = parseCommandLine(argv);
|
|
607
2180
|
if (parsed.command[0] === "browser") {
|
|
608
2181
|
await handleBrowserCommand(parsed);
|
|
@@ -619,7 +2192,7 @@ async function main() {
|
|
|
619
2192
|
list: parsed.options.list === true
|
|
620
2193
|
});
|
|
621
2194
|
if (exitCode !== 0) {
|
|
622
|
-
|
|
2195
|
+
process4.exitCode = exitCode;
|
|
623
2196
|
}
|
|
624
2197
|
return;
|
|
625
2198
|
}
|
|
@@ -631,12 +2204,14 @@ async function main() {
|
|
|
631
2204
|
await handleRecordCommandEntry(parsed);
|
|
632
2205
|
return;
|
|
633
2206
|
}
|
|
634
|
-
const operation =
|
|
2207
|
+
const operation = resolveOperation(parsed.command);
|
|
635
2208
|
if (!operation) {
|
|
636
2209
|
throw new Error(`Unknown command: ${parsed.command.join(" ")}`);
|
|
637
2210
|
}
|
|
638
2211
|
if (parsed.options.workspace === void 0) {
|
|
639
|
-
throw new Error(
|
|
2212
|
+
throw new Error(
|
|
2213
|
+
'Stateful commands require "--workspace <id>" or OPENSTEER_WORKSPACE.'
|
|
2214
|
+
);
|
|
640
2215
|
}
|
|
641
2216
|
const engineName = resolveCliEngineName(parsed);
|
|
642
2217
|
const provider = resolveCliProvider(parsed);
|
|
@@ -644,34 +2219,7 @@ async function main() {
|
|
|
644
2219
|
assertCloudCliOptionsMatchProvider(parsed, provider.mode);
|
|
645
2220
|
const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
|
|
646
2221
|
if (operation === "session.close") {
|
|
647
|
-
|
|
648
|
-
const runtime2 = createOpensteerSemanticRuntime({
|
|
649
|
-
...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
|
|
650
|
-
engine: engineName,
|
|
651
|
-
runtimeOptions: {
|
|
652
|
-
workspace: parsed.options.workspace,
|
|
653
|
-
rootDir: process3.cwd(),
|
|
654
|
-
browser: "persistent",
|
|
655
|
-
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
656
|
-
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
657
|
-
}
|
|
658
|
-
});
|
|
659
|
-
const result2 = await runtime2.close();
|
|
660
|
-
process3.stdout.write(`${JSON.stringify(result2, null, 2)}
|
|
661
|
-
`);
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
const manager = new OpensteerBrowserManager({
|
|
665
|
-
rootDir: process3.cwd(),
|
|
666
|
-
workspace: parsed.options.workspace,
|
|
667
|
-
engineName,
|
|
668
|
-
browser: "persistent",
|
|
669
|
-
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
670
|
-
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
671
|
-
});
|
|
672
|
-
await manager.close();
|
|
673
|
-
process3.stdout.write(`${JSON.stringify({ closed: true }, null, 2)}
|
|
674
|
-
`);
|
|
2222
|
+
await handleCloseCommand(parsed, engineName, provider.mode, runtimeProvider);
|
|
675
2223
|
return;
|
|
676
2224
|
}
|
|
677
2225
|
const runtime = createOpensteerSemanticRuntime({
|
|
@@ -679,27 +2227,25 @@ async function main() {
|
|
|
679
2227
|
engine: engineName,
|
|
680
2228
|
runtimeOptions: {
|
|
681
2229
|
workspace: parsed.options.workspace,
|
|
682
|
-
rootDir:
|
|
2230
|
+
rootDir: process4.cwd(),
|
|
683
2231
|
...parsed.options.browser === void 0 ? {} : { browser: parsed.options.browser },
|
|
684
2232
|
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
685
2233
|
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
686
2234
|
}
|
|
687
2235
|
});
|
|
688
2236
|
let result;
|
|
2237
|
+
let renderOperation = operation;
|
|
689
2238
|
try {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
);
|
|
2239
|
+
const input = await buildOperationInput(operation, parsed, runtime);
|
|
2240
|
+
result = await dispatchSemanticOperation(runtime, operation, input);
|
|
2241
|
+
if (parsed.command[0] === "tab" && operation !== "page.list") {
|
|
2242
|
+
renderOperation = "page.list";
|
|
2243
|
+
result = await runtime.listPages({});
|
|
2244
|
+
}
|
|
2245
|
+
process4.stdout.write(renderOperationOutput(renderOperation, result, input));
|
|
698
2246
|
} finally {
|
|
699
2247
|
await runtime.disconnect().catch(() => void 0);
|
|
700
2248
|
}
|
|
701
|
-
process3.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
702
|
-
`);
|
|
703
2249
|
}
|
|
704
2250
|
async function handleBrowserCommand(parsed) {
|
|
705
2251
|
const subcommand = parsed.command[1];
|
|
@@ -707,7 +2253,7 @@ async function handleBrowserCommand(parsed) {
|
|
|
707
2253
|
const result = await discoverLocalCdpBrowsers({
|
|
708
2254
|
...parsed.options.launch?.timeoutMs === void 0 ? {} : { timeoutMs: parsed.options.launch.timeoutMs }
|
|
709
2255
|
});
|
|
710
|
-
|
|
2256
|
+
process4.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
711
2257
|
`);
|
|
712
2258
|
return;
|
|
713
2259
|
}
|
|
@@ -723,16 +2269,18 @@ async function handleBrowserCommand(parsed) {
|
|
|
723
2269
|
...parsed.options.attachHeaders === void 0 ? {} : { headers: parsed.options.attachHeaders },
|
|
724
2270
|
...parsed.options.launch?.timeoutMs === void 0 ? {} : { timeoutMs: parsed.options.launch.timeoutMs }
|
|
725
2271
|
});
|
|
726
|
-
|
|
2272
|
+
process4.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
727
2273
|
`);
|
|
728
2274
|
return;
|
|
729
2275
|
}
|
|
730
2276
|
if (parsed.options.workspace === void 0) {
|
|
731
|
-
throw new Error(
|
|
2277
|
+
throw new Error(
|
|
2278
|
+
'Browser workspace commands require "--workspace <id>" or OPENSTEER_WORKSPACE.'
|
|
2279
|
+
);
|
|
732
2280
|
}
|
|
733
2281
|
const engineName = resolveCliEngineName(parsed);
|
|
734
2282
|
const manager = new OpensteerBrowserManager({
|
|
735
|
-
rootDir:
|
|
2283
|
+
rootDir: process4.cwd(),
|
|
736
2284
|
workspace: parsed.options.workspace,
|
|
737
2285
|
engineName,
|
|
738
2286
|
browser: "persistent",
|
|
@@ -742,7 +2290,7 @@ async function handleBrowserCommand(parsed) {
|
|
|
742
2290
|
switch (subcommand) {
|
|
743
2291
|
case "status": {
|
|
744
2292
|
const result = await manager.status();
|
|
745
|
-
|
|
2293
|
+
process4.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
746
2294
|
`);
|
|
747
2295
|
return;
|
|
748
2296
|
}
|
|
@@ -755,393 +2303,147 @@ async function handleBrowserCommand(parsed) {
|
|
|
755
2303
|
sourceUserDataDir,
|
|
756
2304
|
...parsed.options.sourceProfileDirectory === void 0 ? {} : { sourceProfileDirectory: parsed.options.sourceProfileDirectory }
|
|
757
2305
|
});
|
|
758
|
-
|
|
2306
|
+
process4.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
759
2307
|
`);
|
|
760
2308
|
return;
|
|
761
2309
|
}
|
|
762
2310
|
case "reset": {
|
|
763
2311
|
await manager.reset();
|
|
764
|
-
|
|
2312
|
+
process4.stdout.write(`${JSON.stringify({ reset: true }, null, 2)}
|
|
765
2313
|
`);
|
|
766
2314
|
return;
|
|
767
2315
|
}
|
|
768
2316
|
case "delete": {
|
|
769
2317
|
await manager.delete();
|
|
770
|
-
|
|
2318
|
+
process4.stdout.write(`${JSON.stringify({ deleted: true }, null, 2)}
|
|
771
2319
|
`);
|
|
772
2320
|
return;
|
|
773
2321
|
}
|
|
774
2322
|
default:
|
|
775
|
-
throw new Error(`Unknown browser command: ${parsed.command.join(" ")}`);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
async function
|
|
779
|
-
if (
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
const browserManager = new OpensteerBrowserManager({
|
|
826
|
-
rootDir,
|
|
827
|
-
workspace: parsed.options.workspace,
|
|
828
|
-
engineName,
|
|
829
|
-
browser: "persistent",
|
|
830
|
-
launch,
|
|
831
|
-
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
832
|
-
});
|
|
833
|
-
const runtime = createOpensteerSemanticRuntime({
|
|
834
|
-
provider: {
|
|
835
|
-
mode: "local"
|
|
836
|
-
},
|
|
837
|
-
engine: engineName,
|
|
838
|
-
runtimeOptions: {
|
|
839
|
-
rootPath: browserManager.rootPath,
|
|
840
|
-
cleanupRootOnClose: browserManager.cleanupRootOnDisconnect,
|
|
841
|
-
workspace: parsed.options.workspace,
|
|
842
|
-
browser: "persistent",
|
|
843
|
-
launch,
|
|
844
|
-
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
await runOpensteerRecordCommand({
|
|
848
|
-
runtime,
|
|
849
|
-
closeSession: () => closeOwnedLocalBrowserSession(runtime, browserManager),
|
|
850
|
-
workspace: parsed.options.workspace,
|
|
851
|
-
url,
|
|
852
|
-
rootDir,
|
|
853
|
-
...parsed.options.output === void 0 ? {} : { outputPath: parsed.options.output }
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
async function closeOwnedLocalBrowserSession(runtime, browserManager) {
|
|
857
|
-
let closeError;
|
|
858
|
-
try {
|
|
859
|
-
await runtime.close();
|
|
860
|
-
} catch (error) {
|
|
861
|
-
closeError = error;
|
|
862
|
-
}
|
|
863
|
-
try {
|
|
864
|
-
await browserManager.close();
|
|
865
|
-
} catch (error) {
|
|
866
|
-
closeError ??= error;
|
|
867
|
-
}
|
|
868
|
-
if (closeError !== void 0) {
|
|
869
|
-
throw closeError;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
function buildOperationInput(operation, parsed) {
|
|
873
|
-
if (parsed.options.inputJson !== void 0) {
|
|
874
|
-
return parsed.options.inputJson;
|
|
875
|
-
}
|
|
876
|
-
switch (operation) {
|
|
877
|
-
case "session.open":
|
|
878
|
-
return {
|
|
879
|
-
...parsed.rest[0] === void 0 ? {} : { url: parsed.rest[0] },
|
|
880
|
-
...parsed.options.workspace === void 0 ? {} : { workspace: parsed.options.workspace },
|
|
881
|
-
...parsed.options.browser === void 0 ? {} : { browser: parsed.options.browser },
|
|
882
|
-
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
883
|
-
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
884
|
-
};
|
|
885
|
-
case "page.goto":
|
|
886
|
-
if (parsed.rest[0] === void 0) {
|
|
887
|
-
throw new Error("goto requires a URL.");
|
|
888
|
-
}
|
|
889
|
-
return {
|
|
890
|
-
url: parsed.rest[0]
|
|
891
|
-
};
|
|
892
|
-
case "page.snapshot":
|
|
893
|
-
return parsed.rest[0] === void 0 ? {} : { mode: parsed.rest[0] };
|
|
894
|
-
case "dom.click":
|
|
895
|
-
case "dom.hover":
|
|
896
|
-
return normalizeTargetInput(parsed, {});
|
|
897
|
-
case "dom.input":
|
|
898
|
-
if (parsed.options.text === void 0) {
|
|
899
|
-
throw new Error('input requires "--text <value>".');
|
|
900
|
-
}
|
|
901
|
-
return {
|
|
902
|
-
...normalizeTargetInput(parsed, {}),
|
|
903
|
-
text: parsed.options.text,
|
|
904
|
-
...parsed.options.pressEnter === void 0 ? {} : { pressEnter: parsed.options.pressEnter }
|
|
905
|
-
};
|
|
906
|
-
case "dom.scroll":
|
|
907
|
-
if (parsed.options.direction === void 0 || parsed.options.amount === void 0) {
|
|
908
|
-
throw new Error('scroll requires "--direction" and "--amount".');
|
|
909
|
-
}
|
|
910
|
-
return {
|
|
911
|
-
...normalizeTargetInput(parsed, {}),
|
|
912
|
-
direction: parsed.options.direction,
|
|
913
|
-
amount: parsed.options.amount
|
|
914
|
-
};
|
|
915
|
-
case "dom.extract":
|
|
916
|
-
if (parsed.options.description === void 0) {
|
|
917
|
-
throw new Error('extract requires "--description <text>".');
|
|
918
|
-
}
|
|
919
|
-
return {
|
|
920
|
-
description: parsed.options.description,
|
|
921
|
-
...parsed.options.schemaJson === void 0 ? {} : { schema: parsed.options.schemaJson }
|
|
922
|
-
};
|
|
923
|
-
case "session.close":
|
|
924
|
-
return {};
|
|
925
|
-
default:
|
|
926
|
-
return {};
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
function normalizeTargetInput(parsed, input) {
|
|
930
|
-
const hasElement = parsed.options.element !== void 0;
|
|
931
|
-
const hasSelector = parsed.options.selector !== void 0;
|
|
932
|
-
const hasDescription = parsed.options.description !== void 0;
|
|
933
|
-
const selected = Number(hasElement) + Number(hasSelector) + Number(hasDescription);
|
|
934
|
-
if (selected !== 1) {
|
|
935
|
-
throw new Error('Specify exactly one of "--element", "--selector", or "--description".');
|
|
936
|
-
}
|
|
937
|
-
return {
|
|
938
|
-
...input,
|
|
939
|
-
target: hasElement ? { kind: "element", element: parsed.options.element } : hasSelector ? { kind: "selector", selector: parsed.options.selector } : { kind: "description", description: parsed.options.description }
|
|
940
|
-
};
|
|
941
|
-
}
|
|
942
|
-
function resolveOperation(command) {
|
|
943
|
-
for (let length = Math.min(3, command.length); length >= 1; length -= 1) {
|
|
944
|
-
const key = command.slice(0, length).join(" ");
|
|
945
|
-
const operation = OPERATION_ALIASES.get(key);
|
|
946
|
-
if (operation) {
|
|
947
|
-
return operation;
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
return void 0;
|
|
951
|
-
}
|
|
952
|
-
var CLI_OPTION_SPECS = {
|
|
953
|
-
workspace: { kind: "value" },
|
|
954
|
-
url: { kind: "value" },
|
|
955
|
-
output: { kind: "value" },
|
|
956
|
-
engine: { kind: "value" },
|
|
957
|
-
provider: { kind: "value" },
|
|
958
|
-
"cloud-base-url": { kind: "value" },
|
|
959
|
-
"cloud-api-key": { kind: "value" },
|
|
960
|
-
"cloud-app-base-url": { kind: "value" },
|
|
961
|
-
"cloud-profile-id": { kind: "value" },
|
|
962
|
-
"cloud-profile-reuse-if-active": { kind: "boolean" },
|
|
963
|
-
json: { kind: "boolean" },
|
|
964
|
-
agent: { kind: "value", multiple: true },
|
|
965
|
-
skill: { kind: "value", multiple: true },
|
|
966
|
-
global: { kind: "boolean" },
|
|
967
|
-
yes: { kind: "boolean" },
|
|
968
|
-
copy: { kind: "boolean" },
|
|
969
|
-
all: { kind: "boolean" },
|
|
970
|
-
list: { kind: "boolean" },
|
|
971
|
-
browser: { kind: "value" },
|
|
972
|
-
"attach-endpoint": { kind: "value" },
|
|
973
|
-
"attach-header": { kind: "value", multiple: true },
|
|
974
|
-
"fresh-tab": { kind: "boolean" },
|
|
975
|
-
headless: { kind: "boolean" },
|
|
976
|
-
"executable-path": { kind: "value" },
|
|
977
|
-
arg: { kind: "value", multiple: true },
|
|
978
|
-
"timeout-ms": { kind: "value" },
|
|
979
|
-
"context-json": { kind: "value" },
|
|
980
|
-
"input-json": { kind: "value" },
|
|
981
|
-
"schema-json": { kind: "value" },
|
|
982
|
-
"source-user-data-dir": { kind: "value" },
|
|
983
|
-
"source-profile-directory": { kind: "value" },
|
|
984
|
-
selector: { kind: "value" },
|
|
985
|
-
description: { kind: "value" },
|
|
986
|
-
element: { kind: "value" },
|
|
987
|
-
text: { kind: "value" },
|
|
988
|
-
"press-enter": { kind: "boolean" },
|
|
989
|
-
direction: { kind: "value" },
|
|
990
|
-
amount: { kind: "value" }
|
|
991
|
-
};
|
|
992
|
-
function parseCommandLine(argv) {
|
|
993
|
-
const leadingTokens = [];
|
|
994
|
-
let index = 0;
|
|
995
|
-
while (index < argv.length && !argv[index].startsWith("--")) {
|
|
996
|
-
leadingTokens.push(argv[index]);
|
|
997
|
-
index += 1;
|
|
998
|
-
}
|
|
999
|
-
const commandLength = resolveCommandLength(leadingTokens);
|
|
1000
|
-
const commandTokens = leadingTokens.slice(0, commandLength);
|
|
1001
|
-
const rest = leadingTokens.slice(commandLength);
|
|
1002
|
-
const rawOptions = /* @__PURE__ */ new Map();
|
|
1003
|
-
while (index < argv.length) {
|
|
1004
|
-
const token = argv[index];
|
|
1005
|
-
if (token === "--") {
|
|
1006
|
-
rest.push(...argv.slice(index + 1));
|
|
1007
|
-
break;
|
|
1008
|
-
}
|
|
1009
|
-
if (!token.startsWith("--")) {
|
|
1010
|
-
rest.push(token);
|
|
1011
|
-
index += 1;
|
|
1012
|
-
continue;
|
|
1013
|
-
}
|
|
1014
|
-
const separator = token.indexOf("=");
|
|
1015
|
-
const key = token.slice(2, separator === -1 ? void 0 : separator);
|
|
1016
|
-
const spec = CLI_OPTION_SPECS[key];
|
|
1017
|
-
if (spec === void 0) {
|
|
1018
|
-
throw new Error(`Unknown option: --${key}.`);
|
|
1019
|
-
}
|
|
1020
|
-
if (separator !== -1) {
|
|
1021
|
-
const value = token.slice(separator + 1);
|
|
1022
|
-
rawOptions.set(key, [...rawOptions.get(key) ?? [], value]);
|
|
1023
|
-
index += 1;
|
|
1024
|
-
continue;
|
|
1025
|
-
}
|
|
1026
|
-
const next = argv[index + 1];
|
|
1027
|
-
if (spec.kind === "boolean") {
|
|
1028
|
-
if (next === void 0 || next.startsWith("--")) {
|
|
1029
|
-
rawOptions.set(key, [...rawOptions.get(key) ?? [], "true"]);
|
|
1030
|
-
index += 1;
|
|
1031
|
-
continue;
|
|
1032
|
-
}
|
|
1033
|
-
rawOptions.set(key, [...rawOptions.get(key) ?? [], next]);
|
|
1034
|
-
index += 2;
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
|
-
if (next === void 0 || next.startsWith("--")) {
|
|
1038
|
-
throw new Error(
|
|
1039
|
-
`Option "--${key}" requires a value.${next?.startsWith("--") === true ? ` Use "--${key}=<value>" when the value begins with "--".` : ``}`
|
|
1040
|
-
);
|
|
2323
|
+
throw new Error(`Unknown browser command: ${parsed.command.join(" ")}`);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
async function handleCloseCommand(parsed, engineName, providerMode, runtimeProvider) {
|
|
2327
|
+
if (providerMode === "cloud") {
|
|
2328
|
+
const runtime = createOpensteerSemanticRuntime({
|
|
2329
|
+
...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
|
|
2330
|
+
engine: engineName,
|
|
2331
|
+
runtimeOptions: {
|
|
2332
|
+
workspace: parsed.options.workspace,
|
|
2333
|
+
rootDir: process4.cwd(),
|
|
2334
|
+
browser: "persistent",
|
|
2335
|
+
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
2336
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
2337
|
+
}
|
|
2338
|
+
});
|
|
2339
|
+
const result = await runtime.close();
|
|
2340
|
+
process4.stdout.write(renderOperationOutput("session.close", result));
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
const manager = new OpensteerBrowserManager({
|
|
2344
|
+
rootDir: process4.cwd(),
|
|
2345
|
+
workspace: parsed.options.workspace,
|
|
2346
|
+
engineName,
|
|
2347
|
+
browser: "persistent",
|
|
2348
|
+
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
2349
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
2350
|
+
});
|
|
2351
|
+
await manager.close();
|
|
2352
|
+
process4.stdout.write(renderOperationOutput("session.close", { closed: true }));
|
|
2353
|
+
}
|
|
2354
|
+
async function handleRecordCommandEntry(parsed) {
|
|
2355
|
+
if (parsed.options.workspace === void 0) {
|
|
2356
|
+
throw new Error('record requires "--workspace <id>" or OPENSTEER_WORKSPACE.');
|
|
2357
|
+
}
|
|
2358
|
+
const url = parsed.options.url ?? parsed.rest[0];
|
|
2359
|
+
if (url === void 0) {
|
|
2360
|
+
throw new Error('record requires "--url <value>" or a positional URL.');
|
|
2361
|
+
}
|
|
2362
|
+
const provider = resolveCliProvider(parsed);
|
|
2363
|
+
assertCloudCliOptionsMatchProvider(parsed, provider.mode);
|
|
2364
|
+
const engineName = resolveCliEngineName(parsed);
|
|
2365
|
+
if (engineName !== "playwright") {
|
|
2366
|
+
throw new Error("record requires engine=playwright.");
|
|
2367
|
+
}
|
|
2368
|
+
const rootDir = process4.cwd();
|
|
2369
|
+
const recordBrowser = parsed.options.browser;
|
|
2370
|
+
if (provider.mode === "cloud") {
|
|
2371
|
+
if (typeof recordBrowser === "object") {
|
|
2372
|
+
throw new Error('record does not support browser.mode="attach".');
|
|
1041
2373
|
}
|
|
1042
|
-
|
|
1043
|
-
|
|
2374
|
+
const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
|
|
2375
|
+
const runtimeConfig = resolveOpensteerRuntimeConfig({
|
|
2376
|
+
...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
|
|
2377
|
+
environment: process4.env
|
|
2378
|
+
});
|
|
2379
|
+
await runOpensteerCloudRecordCommand({
|
|
2380
|
+
cloudConfig: runtimeConfig.cloud,
|
|
2381
|
+
workspace: parsed.options.workspace,
|
|
2382
|
+
url,
|
|
2383
|
+
rootDir,
|
|
2384
|
+
...recordBrowser === void 0 ? {} : { browser: recordBrowser },
|
|
2385
|
+
...parsed.options.launch === void 0 ? {} : { launch: parsed.options.launch },
|
|
2386
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context },
|
|
2387
|
+
...parsed.options.output === void 0 ? {} : { outputPath: parsed.options.output }
|
|
2388
|
+
});
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
if (parsed.options.launch?.headless === true) {
|
|
2392
|
+
throw new Error('record requires a headed browser. Remove "--headless true".');
|
|
2393
|
+
}
|
|
2394
|
+
if (typeof recordBrowser === "object") {
|
|
2395
|
+
throw new Error('record does not support browser.mode="attach".');
|
|
1044
2396
|
}
|
|
1045
|
-
const browserKind = readSingle(rawOptions, "browser");
|
|
1046
|
-
const requestedEngineName = readSingle(rawOptions, "engine");
|
|
1047
|
-
const attachEndpoint = readSingle(rawOptions, "attach-endpoint");
|
|
1048
|
-
const attachHeaders = parseKeyValueList(rawOptions.get("attach-header"));
|
|
1049
|
-
const freshTab = readOptionalBoolean(rawOptions, "fresh-tab");
|
|
1050
|
-
const headless = readOptionalBoolean(rawOptions, "headless");
|
|
1051
|
-
const executablePath = readSingle(rawOptions, "executable-path");
|
|
1052
|
-
const launchArgs = rawOptions.get("arg");
|
|
1053
|
-
const timeoutMs = readOptionalNumber(rawOptions, "timeout-ms");
|
|
1054
|
-
const browser = browserKind === void 0 ? attachEndpoint === void 0 ? void 0 : {
|
|
1055
|
-
mode: "attach",
|
|
1056
|
-
endpoint: attachEndpoint,
|
|
1057
|
-
...attachHeaders === void 0 ? {} : { headers: attachHeaders },
|
|
1058
|
-
...freshTab === void 0 ? {} : { freshTab }
|
|
1059
|
-
} : browserKind === "temporary" || browserKind === "persistent" ? browserKind : {
|
|
1060
|
-
mode: "attach",
|
|
1061
|
-
...attachEndpoint === void 0 ? {} : { endpoint: attachEndpoint },
|
|
1062
|
-
...attachHeaders === void 0 ? {} : { headers: attachHeaders },
|
|
1063
|
-
...freshTab === void 0 ? {} : { freshTab }
|
|
1064
|
-
};
|
|
1065
2397
|
const launch = {
|
|
1066
|
-
...
|
|
1067
|
-
|
|
1068
|
-
...launchArgs === void 0 ? {} : { args: launchArgs },
|
|
1069
|
-
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
1070
|
-
};
|
|
1071
|
-
const workspace = readSingle(rawOptions, "workspace");
|
|
1072
|
-
const url = readSingle(rawOptions, "url");
|
|
1073
|
-
const output = readSingle(rawOptions, "output");
|
|
1074
|
-
const sourceUserDataDir = readSingle(rawOptions, "source-user-data-dir");
|
|
1075
|
-
const sourceProfileDirectory = readSingle(rawOptions, "source-profile-directory");
|
|
1076
|
-
const selector = readSingle(rawOptions, "selector");
|
|
1077
|
-
const description = readSingle(rawOptions, "description");
|
|
1078
|
-
const element = readOptionalNumber(rawOptions, "element");
|
|
1079
|
-
const text = readSingle(rawOptions, "text");
|
|
1080
|
-
const pressEnter = readOptionalBoolean(rawOptions, "press-enter");
|
|
1081
|
-
const direction = readSingle(rawOptions, "direction");
|
|
1082
|
-
const amount = readOptionalNumber(rawOptions, "amount");
|
|
1083
|
-
const contextJson = readJsonObject(rawOptions, "context-json");
|
|
1084
|
-
const inputJson = readJsonObject(rawOptions, "input-json");
|
|
1085
|
-
const schemaJson = readJsonObject(rawOptions, "schema-json");
|
|
1086
|
-
const providerValue = readSingle(rawOptions, "provider");
|
|
1087
|
-
const provider = providerValue === void 0 ? void 0 : normalizeOpensteerProviderMode(providerValue, "--provider");
|
|
1088
|
-
const cloudBaseUrl = readSingle(rawOptions, "cloud-base-url");
|
|
1089
|
-
const cloudApiKey = readSingle(rawOptions, "cloud-api-key");
|
|
1090
|
-
const cloudAppBaseUrl = readSingle(rawOptions, "cloud-app-base-url");
|
|
1091
|
-
const cloudProfileId = readSingle(rawOptions, "cloud-profile-id");
|
|
1092
|
-
const cloudProfileReuseIfActive = readOptionalBoolean(
|
|
1093
|
-
rawOptions,
|
|
1094
|
-
"cloud-profile-reuse-if-active"
|
|
1095
|
-
);
|
|
1096
|
-
const json = readOptionalBoolean(rawOptions, "json");
|
|
1097
|
-
const agents = rawOptions.get("agent");
|
|
1098
|
-
const skills = rawOptions.get("skill");
|
|
1099
|
-
const global = readOptionalBoolean(rawOptions, "global");
|
|
1100
|
-
const yes = readOptionalBoolean(rawOptions, "yes");
|
|
1101
|
-
const copy = readOptionalBoolean(rawOptions, "copy");
|
|
1102
|
-
const all = readOptionalBoolean(rawOptions, "all");
|
|
1103
|
-
const list = readOptionalBoolean(rawOptions, "list");
|
|
1104
|
-
const options = {
|
|
1105
|
-
...workspace === void 0 ? {} : { workspace },
|
|
1106
|
-
...url === void 0 ? {} : { url },
|
|
1107
|
-
...output === void 0 ? {} : { output },
|
|
1108
|
-
...requestedEngineName === void 0 ? {} : { requestedEngineName },
|
|
1109
|
-
...provider === void 0 ? {} : { provider },
|
|
1110
|
-
...cloudBaseUrl === void 0 ? {} : { cloudBaseUrl },
|
|
1111
|
-
...cloudApiKey === void 0 ? {} : { cloudApiKey },
|
|
1112
|
-
...cloudAppBaseUrl === void 0 ? {} : { cloudAppBaseUrl },
|
|
1113
|
-
...cloudProfileId === void 0 ? {} : { cloudProfileId },
|
|
1114
|
-
...cloudProfileReuseIfActive === void 0 ? {} : { cloudProfileReuseIfActive },
|
|
1115
|
-
...json === void 0 ? {} : { json },
|
|
1116
|
-
...agents === void 0 ? {} : { agents },
|
|
1117
|
-
...skills === void 0 ? {} : { skills },
|
|
1118
|
-
...global === void 0 ? {} : { global },
|
|
1119
|
-
...yes === void 0 ? {} : { yes },
|
|
1120
|
-
...copy === void 0 ? {} : { copy },
|
|
1121
|
-
...all === void 0 ? {} : { all },
|
|
1122
|
-
...list === void 0 ? {} : { list },
|
|
1123
|
-
...browser === void 0 ? {} : { browser },
|
|
1124
|
-
...Object.keys(launch).length === 0 ? {} : { launch },
|
|
1125
|
-
...contextJson === void 0 ? {} : { context: contextJson },
|
|
1126
|
-
...inputJson === void 0 ? {} : { inputJson },
|
|
1127
|
-
...schemaJson === void 0 ? {} : { schemaJson },
|
|
1128
|
-
...attachEndpoint === void 0 ? {} : { attachEndpoint },
|
|
1129
|
-
...attachHeaders === void 0 ? {} : { attachHeaders },
|
|
1130
|
-
...sourceUserDataDir === void 0 ? {} : { sourceUserDataDir },
|
|
1131
|
-
...sourceProfileDirectory === void 0 ? {} : { sourceProfileDirectory },
|
|
1132
|
-
...selector === void 0 ? {} : { selector },
|
|
1133
|
-
...description === void 0 ? {} : { description },
|
|
1134
|
-
...element === void 0 ? {} : { element },
|
|
1135
|
-
...text === void 0 ? {} : { text },
|
|
1136
|
-
...pressEnter === void 0 ? {} : { pressEnter },
|
|
1137
|
-
...direction === void 0 ? {} : { direction },
|
|
1138
|
-
...amount === void 0 ? {} : { amount }
|
|
1139
|
-
};
|
|
1140
|
-
return {
|
|
1141
|
-
command: commandTokens,
|
|
1142
|
-
rest,
|
|
1143
|
-
options
|
|
2398
|
+
...parsed.options.launch ?? {},
|
|
2399
|
+
headless: false
|
|
1144
2400
|
};
|
|
2401
|
+
const browserManager = new OpensteerBrowserManager({
|
|
2402
|
+
rootDir,
|
|
2403
|
+
workspace: parsed.options.workspace,
|
|
2404
|
+
engineName,
|
|
2405
|
+
browser: "persistent",
|
|
2406
|
+
launch,
|
|
2407
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
2408
|
+
});
|
|
2409
|
+
const runtime = createOpensteerSemanticRuntime({
|
|
2410
|
+
provider: {
|
|
2411
|
+
mode: "local"
|
|
2412
|
+
},
|
|
2413
|
+
engine: engineName,
|
|
2414
|
+
runtimeOptions: {
|
|
2415
|
+
rootPath: browserManager.rootPath,
|
|
2416
|
+
cleanupRootOnClose: browserManager.cleanupRootOnDisconnect,
|
|
2417
|
+
workspace: parsed.options.workspace,
|
|
2418
|
+
browser: "persistent",
|
|
2419
|
+
launch,
|
|
2420
|
+
...parsed.options.context === void 0 ? {} : { context: parsed.options.context }
|
|
2421
|
+
}
|
|
2422
|
+
});
|
|
2423
|
+
await runOpensteerRecordCommand({
|
|
2424
|
+
runtime,
|
|
2425
|
+
closeSession: () => closeOwnedLocalBrowserSession(runtime, browserManager),
|
|
2426
|
+
workspace: parsed.options.workspace,
|
|
2427
|
+
url,
|
|
2428
|
+
rootDir,
|
|
2429
|
+
...parsed.options.output === void 0 ? {} : { outputPath: parsed.options.output }
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
async function closeOwnedLocalBrowserSession(runtime, browserManager) {
|
|
2433
|
+
let closeError;
|
|
2434
|
+
try {
|
|
2435
|
+
await runtime.close();
|
|
2436
|
+
} catch (error) {
|
|
2437
|
+
closeError = error;
|
|
2438
|
+
}
|
|
2439
|
+
try {
|
|
2440
|
+
await browserManager.close();
|
|
2441
|
+
} catch (error) {
|
|
2442
|
+
closeError ??= error;
|
|
2443
|
+
}
|
|
2444
|
+
if (closeError !== void 0) {
|
|
2445
|
+
throw closeError;
|
|
2446
|
+
}
|
|
1145
2447
|
}
|
|
1146
2448
|
function resolveCliBootstrapAction(argv) {
|
|
1147
2449
|
if (argv.length === 0) {
|
|
@@ -1178,14 +2480,14 @@ function buildCliExplicitProvider(parsed) {
|
|
|
1178
2480
|
function resolveCliEngineName(parsed) {
|
|
1179
2481
|
return resolveOpensteerEngineName({
|
|
1180
2482
|
...parsed.options.requestedEngineName === void 0 ? {} : { requested: parsed.options.requestedEngineName },
|
|
1181
|
-
...
|
|
2483
|
+
...process4.env.OPENSTEER_ENGINE === void 0 ? {} : { environment: process4.env.OPENSTEER_ENGINE }
|
|
1182
2484
|
});
|
|
1183
2485
|
}
|
|
1184
2486
|
function resolveCliProvider(parsed) {
|
|
1185
2487
|
const explicitProvider = buildCliExplicitProvider(parsed);
|
|
1186
2488
|
return resolveOpensteerProvider({
|
|
1187
2489
|
...explicitProvider === void 0 ? {} : { provider: explicitProvider },
|
|
1188
|
-
...
|
|
2490
|
+
...process4.env.OPENSTEER_PROVIDER === void 0 ? {} : { environmentProvider: process4.env.OPENSTEER_PROVIDER }
|
|
1189
2491
|
});
|
|
1190
2492
|
}
|
|
1191
2493
|
function buildCliRuntimeProvider(parsed, providerMode) {
|
|
@@ -1219,156 +2521,26 @@ async function handleStatusCommand(parsed) {
|
|
|
1219
2521
|
const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
|
|
1220
2522
|
const runtimeConfig = resolveOpensteerRuntimeConfig({
|
|
1221
2523
|
...runtimeProvider === void 0 ? {} : { provider: runtimeProvider },
|
|
1222
|
-
environment:
|
|
2524
|
+
environment: process4.env
|
|
1223
2525
|
});
|
|
1224
2526
|
const status = await collectOpensteerStatus({
|
|
1225
|
-
rootDir:
|
|
2527
|
+
rootDir: process4.cwd(),
|
|
1226
2528
|
...parsed.options.workspace === void 0 ? {} : { workspace: parsed.options.workspace },
|
|
1227
2529
|
provider,
|
|
1228
2530
|
...runtimeConfig.cloud === void 0 ? {} : { cloudConfig: runtimeConfig.cloud }
|
|
1229
2531
|
});
|
|
1230
2532
|
if (parsed.options.json === true) {
|
|
1231
|
-
|
|
2533
|
+
process4.stdout.write(`${JSON.stringify(status, null, 2)}
|
|
1232
2534
|
`);
|
|
1233
2535
|
return;
|
|
1234
2536
|
}
|
|
1235
|
-
|
|
1236
|
-
}
|
|
1237
|
-
function parseKeyValueList(values) {
|
|
1238
|
-
if (values === void 0 || values.length === 0) {
|
|
1239
|
-
return void 0;
|
|
1240
|
-
}
|
|
1241
|
-
return Object.fromEntries(
|
|
1242
|
-
values.map((entry) => {
|
|
1243
|
-
const separator = entry.indexOf("=");
|
|
1244
|
-
if (separator <= 0) {
|
|
1245
|
-
throw new Error(`Expected NAME=VALUE, received "${entry}".`);
|
|
1246
|
-
}
|
|
1247
|
-
return [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
1248
|
-
})
|
|
1249
|
-
);
|
|
1250
|
-
}
|
|
1251
|
-
function readSingle(options, name) {
|
|
1252
|
-
const values = options.get(name);
|
|
1253
|
-
if (values === void 0 || values.length === 0) {
|
|
1254
|
-
return void 0;
|
|
1255
|
-
}
|
|
1256
|
-
return values[values.length - 1];
|
|
1257
|
-
}
|
|
1258
|
-
function readOptionalBoolean(options, name) {
|
|
1259
|
-
const value = readSingle(options, name);
|
|
1260
|
-
if (value === void 0) {
|
|
1261
|
-
return void 0;
|
|
1262
|
-
}
|
|
1263
|
-
if (value === "true") {
|
|
1264
|
-
return true;
|
|
1265
|
-
}
|
|
1266
|
-
if (value === "false") {
|
|
1267
|
-
return false;
|
|
1268
|
-
}
|
|
1269
|
-
throw new Error(`Option "--${name}" must be true or false.`);
|
|
1270
|
-
}
|
|
1271
|
-
function readOptionalNumber(options, name) {
|
|
1272
|
-
const value = readSingle(options, name);
|
|
1273
|
-
if (value === void 0) {
|
|
1274
|
-
return void 0;
|
|
1275
|
-
}
|
|
1276
|
-
const parsed = Number(value);
|
|
1277
|
-
if (!Number.isFinite(parsed)) {
|
|
1278
|
-
throw new Error(`Option "--${name}" must be a number.`);
|
|
1279
|
-
}
|
|
1280
|
-
return parsed;
|
|
1281
|
-
}
|
|
1282
|
-
function readJsonObject(options, name) {
|
|
1283
|
-
const value = readSingle(options, name);
|
|
1284
|
-
if (value === void 0) {
|
|
1285
|
-
return void 0;
|
|
1286
|
-
}
|
|
1287
|
-
const parsed = JSON.parse(value);
|
|
1288
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1289
|
-
throw new Error(`Option "--${name}" must be a JSON object.`);
|
|
1290
|
-
}
|
|
1291
|
-
return parsed;
|
|
1292
|
-
}
|
|
1293
|
-
function resolveCommandLength(tokens) {
|
|
1294
|
-
if (tokens.length === 0) {
|
|
1295
|
-
return 0;
|
|
1296
|
-
}
|
|
1297
|
-
if (tokens[0] === "browser") {
|
|
1298
|
-
return Math.min(tokens.length, 2);
|
|
1299
|
-
}
|
|
1300
|
-
if (tokens[0] === "skills") {
|
|
1301
|
-
return Math.min(tokens.length, 2);
|
|
1302
|
-
}
|
|
1303
|
-
if (tokens[0] === "run") {
|
|
1304
|
-
return 1;
|
|
1305
|
-
}
|
|
1306
|
-
if (tokens[0] === "status") {
|
|
1307
|
-
return 1;
|
|
1308
|
-
}
|
|
1309
|
-
if (tokens[0] === "record") {
|
|
1310
|
-
return 1;
|
|
1311
|
-
}
|
|
1312
|
-
for (let length = Math.min(3, tokens.length); length >= 1; length -= 1) {
|
|
1313
|
-
if (OPERATION_ALIASES.has(tokens.slice(0, length).join(" "))) {
|
|
1314
|
-
return length;
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
return Math.min(tokens.length, 1);
|
|
2537
|
+
process4.stdout.write(renderOpensteerStatus(status));
|
|
1318
2538
|
}
|
|
1319
2539
|
function printHelp() {
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
Usage:
|
|
1323
|
-
opensteer open <url> --workspace <id> [--browser persistent|temporary|attach]
|
|
1324
|
-
opensteer goto <url> --workspace <id>
|
|
1325
|
-
opensteer snapshot [action|extraction] --workspace <id>
|
|
1326
|
-
opensteer click --workspace <id> (--element <n> | --selector <css> | --description <text>)
|
|
1327
|
-
opensteer input --workspace <id> --text <value> (--element <n> | --selector <css> | --description <text>)
|
|
1328
|
-
opensteer extract --workspace <id> --description <text> [--schema-json <json>]
|
|
1329
|
-
opensteer record --workspace <id> --url <url> [--output <path>]
|
|
1330
|
-
opensteer close --workspace <id>
|
|
1331
|
-
opensteer status [--workspace <id>] [--json]
|
|
1332
|
-
|
|
1333
|
-
opensteer browser status --workspace <id>
|
|
1334
|
-
opensteer browser clone --workspace <id> --source-user-data-dir <path> [--source-profile-directory <name>]
|
|
1335
|
-
opensteer browser reset --workspace <id>
|
|
1336
|
-
opensteer browser delete --workspace <id>
|
|
1337
|
-
opensteer browser discover
|
|
1338
|
-
opensteer browser inspect --attach-endpoint <url>
|
|
1339
|
-
opensteer skills install [--skill <name>] [--agent <name>] [--global] [--yes]
|
|
1340
|
-
|
|
1341
|
-
opensteer run <semantic-operation> --workspace <id> --input-json <json>
|
|
1342
|
-
|
|
1343
|
-
Common options:
|
|
1344
|
-
--help
|
|
1345
|
-
--version
|
|
1346
|
-
--workspace <id>
|
|
1347
|
-
--url <url>
|
|
1348
|
-
--output <path>
|
|
1349
|
-
--provider local|cloud
|
|
1350
|
-
--cloud-base-url <url>
|
|
1351
|
-
--cloud-api-key <key>
|
|
1352
|
-
--cloud-app-base-url <url>
|
|
1353
|
-
--cloud-profile-id <id>
|
|
1354
|
-
--cloud-profile-reuse-if-active <true|false>
|
|
1355
|
-
--json <true|false>
|
|
1356
|
-
--engine playwright|abp
|
|
1357
|
-
--browser temporary|persistent|attach
|
|
1358
|
-
--attach-endpoint <url>
|
|
1359
|
-
--fresh-tab <true|false>
|
|
1360
|
-
--headless <true|false>
|
|
1361
|
-
--executable-path <path>
|
|
1362
|
-
--arg <value> repeatable
|
|
1363
|
-
--timeout-ms <ms>
|
|
1364
|
-
--context-json <json>
|
|
1365
|
-
--input-json <json>
|
|
1366
|
-
--skill <name> repeatable
|
|
1367
|
-
--agent <name> repeatable
|
|
1368
|
-
`);
|
|
2540
|
+
process4.stdout.write(getHelpText());
|
|
1369
2541
|
}
|
|
1370
2542
|
function printVersion() {
|
|
1371
|
-
|
|
2543
|
+
process4.stdout.write(`${package_default.version}
|
|
1372
2544
|
`);
|
|
1373
2545
|
}
|
|
1374
2546
|
main().catch((error) => {
|
|
@@ -1383,9 +2555,9 @@ main().catch((error) => {
|
|
|
1383
2555
|
message: String(error)
|
|
1384
2556
|
}
|
|
1385
2557
|
};
|
|
1386
|
-
|
|
2558
|
+
process4.stderr.write(`${JSON.stringify(payload)}
|
|
1387
2559
|
`);
|
|
1388
|
-
|
|
2560
|
+
process4.exitCode = 1;
|
|
1389
2561
|
});
|
|
1390
2562
|
//# sourceMappingURL=bin.js.map
|
|
1391
2563
|
//# sourceMappingURL=bin.js.map
|