opensteer 0.9.5 → 0.9.6
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/dist/{chunk-ZRF7WMS3.js → chunk-3I3A5OLB.js} +3 -3
- package/dist/{chunk-ZRF7WMS3.js.map → chunk-3I3A5OLB.js.map} +1 -1
- package/dist/{chunk-GSCQQKZZ.js → chunk-3XBQRZZC.js} +221 -6
- package/dist/chunk-3XBQRZZC.js.map +1 -0
- package/dist/{chunk-7LQL5YUR.js → chunk-BVRIPCWA.js} +259 -277
- package/dist/chunk-BVRIPCWA.js.map +1 -0
- package/dist/chunk-L4NF74KI.js +458 -0
- package/dist/chunk-L4NF74KI.js.map +1 -0
- package/dist/cli/bin.cjs +760 -282
- package/dist/cli/bin.cjs.map +1 -1
- package/dist/cli/bin.js +225 -84
- package/dist/cli/bin.js.map +1 -1
- package/dist/index.cjs +527 -202
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +3 -3
- package/dist/local-view/serve-entry.cjs +5354 -4
- package/dist/local-view/serve-entry.cjs.map +1 -1
- package/dist/local-view/serve-entry.js +1 -1
- package/dist/opensteer-UGA6YBRN.js +6 -0
- package/dist/{opensteer-T2JENADR.js.map → opensteer-UGA6YBRN.js.map} +1 -1
- package/dist/{session-control-M3JD7ZKA.js → session-control-U3L5H2ZI.js} +3 -3
- package/dist/{session-control-M3JD7ZKA.js.map → session-control-U3L5H2ZI.js.map} +1 -1
- package/package.json +6 -6
- package/dist/chunk-7D45QUZ3.js +0 -332
- package/dist/chunk-7D45QUZ3.js.map +0 -1
- package/dist/chunk-7LQL5YUR.js.map +0 -1
- package/dist/chunk-GSCQQKZZ.js.map +0 -1
- package/dist/opensteer-T2JENADR.js +0 -6
package/dist/cli/bin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { runLocalViewService } from '../chunk-
|
|
3
|
-
import { createOpensteerSemanticRuntime, dispatchSemanticOperation, loadEnvironment, normalizeOpensteerProviderMode, resolveOpensteerRuntimeConfig, assertProviderSupportsEngine, resolveOpensteerProvider, requireCloudAppBaseUrl, CloudSessionProxy, FlowRecorderCollector, generateReplayScript, OpensteerCloudClient } from '../chunk-
|
|
4
|
-
import { OpensteerBrowserManager, stopLocalViewService, setLocalViewMode, ensureLocalViewServiceRunning, buildLocalViewSessionUrl, resolveOpensteerEngineName, resolveFilesystemWorkspacePath } from '../chunk-
|
|
2
|
+
import { runLocalViewService } from '../chunk-3I3A5OLB.js';
|
|
3
|
+
import { createOpensteerSemanticRuntime, dispatchSemanticOperation, isBrowserCoreError, loadEnvironment, normalizeOpensteerProviderMode, resolveOpensteerRuntimeConfig, assertProviderSupportsEngine, resolveOpensteerProvider, requireCloudAppBaseUrl, CloudSessionProxy, FlowRecorderCollector, generateReplayScript, OpensteerCloudClient } from '../chunk-BVRIPCWA.js';
|
|
4
|
+
import { isOpensteerProtocolError, OpensteerBrowserManager, stopLocalViewService, setLocalViewMode, ensureLocalViewServiceRunning, buildLocalViewSessionUrl, resolveOpensteerEngineName, resolveFilesystemWorkspacePath } from '../chunk-3XBQRZZC.js';
|
|
5
5
|
import { discoverLocalCdpBrowsers, inspectCdpEndpoint, readPersistedLocalBrowserSessionRecord, isProcessRunning, buildLocalViewSessionId, pathExists, readPersistedCloudSessionRecord } from '../chunk-T5P2QGZ3.js';
|
|
6
6
|
import process4 from 'process';
|
|
7
7
|
import { mkdir, writeFile } from 'fs/promises';
|
|
@@ -14,13 +14,115 @@ import { fileURLToPath } from 'url';
|
|
|
14
14
|
|
|
15
15
|
// package.json
|
|
16
16
|
var package_default = {
|
|
17
|
-
version: "0.9.
|
|
17
|
+
version: "0.9.6"};
|
|
18
18
|
|
|
19
19
|
// src/cli/env-loader.ts
|
|
20
20
|
async function loadCliEnvironment(cwd) {
|
|
21
21
|
loadEnvironment(cwd);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// src/cli/errors.ts
|
|
25
|
+
var CliError = class extends Error {
|
|
26
|
+
type;
|
|
27
|
+
usage;
|
|
28
|
+
constructor(type, message, usage) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.name = "CliError";
|
|
31
|
+
this.type = type;
|
|
32
|
+
this.usage = usage;
|
|
33
|
+
}
|
|
34
|
+
format() {
|
|
35
|
+
return this.usage === void 0 ? this.message : `${this.message}
|
|
36
|
+
Usage: ${this.usage}`;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
function isCliError(value) {
|
|
40
|
+
return value instanceof CliError;
|
|
41
|
+
}
|
|
42
|
+
function formatCliErrorOutput(error) {
|
|
43
|
+
if (isCliError(error)) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: error.format(),
|
|
47
|
+
type: error.type
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (isOpensteerProtocolError(error)) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
error: error.message,
|
|
54
|
+
code: error.code,
|
|
55
|
+
retriable: error.retriable
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (isBrowserCoreError(error)) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
error: error.message,
|
|
62
|
+
code: error.code,
|
|
63
|
+
retriable: error.retriable
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (error instanceof Error && "opensteerError" in error) {
|
|
67
|
+
const oe = error.opensteerError;
|
|
68
|
+
return {
|
|
69
|
+
success: false,
|
|
70
|
+
error: oe.message,
|
|
71
|
+
code: oe.code,
|
|
72
|
+
retriable: oe.retriable
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (error instanceof SyntaxError) {
|
|
76
|
+
return {
|
|
77
|
+
success: false,
|
|
78
|
+
error: error.message,
|
|
79
|
+
type: "invalid_value"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: error instanceof Error ? error.message : String(error)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function emitWarning(warning) {
|
|
88
|
+
process.stderr.write(`${JSON.stringify({ warning })}
|
|
89
|
+
`);
|
|
90
|
+
}
|
|
91
|
+
var CLI_USAGE_HINTS = {
|
|
92
|
+
"session.open": "opensteer open <url> [--workspace <id>]",
|
|
93
|
+
"page.goto": "opensteer goto <url>",
|
|
94
|
+
"page.evaluate": "opensteer evaluate <script>",
|
|
95
|
+
"page.add-init-script": "opensteer init-script <script>",
|
|
96
|
+
"dom.click": "opensteer click <element> --persist <key>",
|
|
97
|
+
"dom.hover": "opensteer hover <element> --persist <key>",
|
|
98
|
+
"dom.input": "opensteer input <element> <text> --persist <key>",
|
|
99
|
+
"dom.scroll": "opensteer scroll <direction> <amount> --persist <key>",
|
|
100
|
+
"dom.extract": "opensteer extract <template> --persist <key>",
|
|
101
|
+
"network.detail": "opensteer network detail <recordId>",
|
|
102
|
+
"session.fetch": "opensteer fetch <url>",
|
|
103
|
+
"captcha.solve": "opensteer captcha solve --provider <name> --api-key <key>",
|
|
104
|
+
"scripts.capture": "opensteer scripts capture",
|
|
105
|
+
"scripts.beautify": "opensteer scripts beautify <artifactId>",
|
|
106
|
+
"scripts.deobfuscate": "opensteer scripts deobfuscate <artifactId>",
|
|
107
|
+
"scripts.sandbox": "opensteer scripts sandbox <artifactId>",
|
|
108
|
+
"interaction.capture": "opensteer interaction capture",
|
|
109
|
+
"interaction.get": "opensteer interaction get <traceId>",
|
|
110
|
+
"interaction.replay": "opensteer interaction replay <traceId>",
|
|
111
|
+
"interaction.diff": "opensteer interaction diff <leftTraceId> <rightTraceId>",
|
|
112
|
+
"artifact.read": "opensteer artifact read <artifactId>",
|
|
113
|
+
"computer.click": "opensteer computer click <x> <y>",
|
|
114
|
+
"computer.type": "opensteer computer type <text>",
|
|
115
|
+
"computer.key": "opensteer computer key <key>",
|
|
116
|
+
"computer.scroll": "opensteer computer scroll <x> <y> --dx <n> --dy <n>",
|
|
117
|
+
"computer.move": "opensteer computer move <x> <y>",
|
|
118
|
+
"computer.drag": "opensteer computer drag <x1> <y1> <x2> <y2>",
|
|
119
|
+
"computer.screenshot": "opensteer computer screenshot",
|
|
120
|
+
exec: "opensteer exec <expression>",
|
|
121
|
+
record: "opensteer record --url <url> --workspace <id>",
|
|
122
|
+
"browser.inspect": "opensteer browser inspect <endpoint>",
|
|
123
|
+
"browser.clone": "opensteer browser clone --source-user-data-dir <path>"
|
|
124
|
+
};
|
|
125
|
+
|
|
24
126
|
// src/cli/help.ts
|
|
25
127
|
function getHelpText() {
|
|
26
128
|
return `Opensteer CLI
|
|
@@ -279,7 +381,7 @@ function parseCommandLine(argv) {
|
|
|
279
381
|
const key = token.slice(2, separator === -1 ? void 0 : separator);
|
|
280
382
|
const spec = CLI_OPTION_SPECS[key];
|
|
281
383
|
if (spec === void 0) {
|
|
282
|
-
throw new
|
|
384
|
+
throw new CliError("unknown_option", `Unknown option: --${key}.`);
|
|
283
385
|
}
|
|
284
386
|
if (separator !== -1) {
|
|
285
387
|
rawOptions.set(key, [...rawOptions.get(key) ?? [], token.slice(separator + 1)]);
|
|
@@ -308,7 +410,8 @@ function parseCommandLine(argv) {
|
|
|
308
410
|
continue;
|
|
309
411
|
}
|
|
310
412
|
if (next === void 0 || next.startsWith("--")) {
|
|
311
|
-
throw new
|
|
413
|
+
throw new CliError(
|
|
414
|
+
"missing_arguments",
|
|
312
415
|
`Option "--${key}" requires a value.${next?.startsWith("--") === true ? ` Use "--${key}=<value>" when the value begins with "--".` : ``}`
|
|
313
416
|
);
|
|
314
417
|
}
|
|
@@ -354,10 +457,14 @@ function parseCommandLine(argv) {
|
|
|
354
457
|
const autoLocalView = readOptionalBoolean(rawOptions, "auto");
|
|
355
458
|
const noAutoLocalView = readOptionalBoolean(rawOptions, "no-auto");
|
|
356
459
|
if (autoLocalView === true && noAutoLocalView === true) {
|
|
357
|
-
throw new
|
|
460
|
+
throw new CliError("invalid_option", 'Options "--auto" and "--no-auto" cannot be combined.');
|
|
358
461
|
}
|
|
359
462
|
if (command[0] !== "view" && (autoLocalView !== void 0 || noAutoLocalView !== void 0)) {
|
|
360
|
-
throw new
|
|
463
|
+
throw new CliError(
|
|
464
|
+
"invalid_option",
|
|
465
|
+
'Options "--auto" and "--no-auto" are only supported with "view".',
|
|
466
|
+
"opensteer view --auto"
|
|
467
|
+
);
|
|
361
468
|
}
|
|
362
469
|
const global = readOptionalBoolean(rawOptions, "global");
|
|
363
470
|
const yes = readOptionalBoolean(rawOptions, "yes");
|
|
@@ -413,7 +520,7 @@ function parseKeyValueList(values) {
|
|
|
413
520
|
values.map((entry) => {
|
|
414
521
|
const separator = entry.indexOf("=");
|
|
415
522
|
if (separator <= 0) {
|
|
416
|
-
throw new
|
|
523
|
+
throw new CliError("invalid_value", `Expected NAME=VALUE, received "${entry}".`);
|
|
417
524
|
}
|
|
418
525
|
return [entry.slice(0, separator), entry.slice(separator + 1)];
|
|
419
526
|
})
|
|
@@ -444,7 +551,7 @@ function readOptionalBoolean(options, name) {
|
|
|
444
551
|
if (value === "false") {
|
|
445
552
|
return false;
|
|
446
553
|
}
|
|
447
|
-
throw new
|
|
554
|
+
throw new CliError("invalid_value", `Option "--${name}" must be true or false.`);
|
|
448
555
|
}
|
|
449
556
|
function readOptionalNumber(options, name) {
|
|
450
557
|
const value = readSingle(options, name);
|
|
@@ -453,13 +560,20 @@ function readOptionalNumber(options, name) {
|
|
|
453
560
|
}
|
|
454
561
|
const parsed = Number(value);
|
|
455
562
|
if (!Number.isFinite(parsed)) {
|
|
456
|
-
throw new
|
|
563
|
+
throw new CliError("invalid_value", `Option "--${name}" must be a number.`);
|
|
457
564
|
}
|
|
458
565
|
return parsed;
|
|
459
566
|
}
|
|
460
567
|
function readJsonValue(options, name) {
|
|
461
568
|
const value = readSingle(options, name);
|
|
462
|
-
|
|
569
|
+
if (value === void 0) {
|
|
570
|
+
return void 0;
|
|
571
|
+
}
|
|
572
|
+
try {
|
|
573
|
+
return JSON.parse(value);
|
|
574
|
+
} catch {
|
|
575
|
+
throw new CliError("invalid_value", `Option "--${name}" contains invalid JSON.`);
|
|
576
|
+
}
|
|
463
577
|
}
|
|
464
578
|
function readJsonObject(options, name) {
|
|
465
579
|
const parsed = readJsonValue(options, name);
|
|
@@ -467,7 +581,7 @@ function readJsonObject(options, name) {
|
|
|
467
581
|
return void 0;
|
|
468
582
|
}
|
|
469
583
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
470
|
-
throw new
|
|
584
|
+
throw new CliError("invalid_value", `Option "--${name}" must be a JSON object.`);
|
|
471
585
|
}
|
|
472
586
|
return parsed;
|
|
473
587
|
}
|
|
@@ -477,7 +591,7 @@ function readJsonArray(options, name) {
|
|
|
477
591
|
return void 0;
|
|
478
592
|
}
|
|
479
593
|
if (!Array.isArray(parsed)) {
|
|
480
|
-
throw new
|
|
594
|
+
throw new CliError("invalid_value", `Option "--${name}" must be a JSON array.`);
|
|
481
595
|
}
|
|
482
596
|
return parsed;
|
|
483
597
|
}
|
|
@@ -497,7 +611,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
497
611
|
case "session.open": {
|
|
498
612
|
const url = parsed.rest[0];
|
|
499
613
|
if (url === void 0) {
|
|
500
|
-
throw new
|
|
614
|
+
throw new CliError("missing_arguments", "open requires a URL.", CLI_USAGE_HINTS[operation]);
|
|
501
615
|
}
|
|
502
616
|
return {
|
|
503
617
|
url,
|
|
@@ -530,7 +644,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
530
644
|
}
|
|
531
645
|
case "page.goto": {
|
|
532
646
|
if (parsed.rest[0] === void 0) {
|
|
533
|
-
throw new
|
|
647
|
+
throw new CliError("missing_arguments", "goto requires a URL.", CLI_USAGE_HINTS[operation]);
|
|
534
648
|
}
|
|
535
649
|
const captureNetwork = readSingle(parsed.rawOptions, "capture-network");
|
|
536
650
|
return {
|
|
@@ -542,14 +656,14 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
542
656
|
return parsed.rest[0] === void 0 ? {} : { mode: parsed.rest[0] };
|
|
543
657
|
case "page.evaluate":
|
|
544
658
|
if (parsed.rest[0] === void 0) {
|
|
545
|
-
throw new
|
|
659
|
+
throw new CliError("missing_arguments", "evaluate requires a script.", CLI_USAGE_HINTS[operation]);
|
|
546
660
|
}
|
|
547
661
|
return {
|
|
548
662
|
script: joinRest(parsed.rest, 0)
|
|
549
663
|
};
|
|
550
664
|
case "page.add-init-script":
|
|
551
665
|
if (parsed.rest[0] === void 0) {
|
|
552
|
-
throw new
|
|
666
|
+
throw new CliError("missing_arguments", "init-script requires a script.", CLI_USAGE_HINTS[operation]);
|
|
553
667
|
}
|
|
554
668
|
return {
|
|
555
669
|
script: joinRest(parsed.rest, 0)
|
|
@@ -565,7 +679,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
565
679
|
return buildElementTargetInput(parsed, "hover");
|
|
566
680
|
case "dom.input": {
|
|
567
681
|
if (parsed.rest[1] === void 0) {
|
|
568
|
-
throw new
|
|
682
|
+
throw new CliError("missing_arguments", "input requires an element number and text.", CLI_USAGE_HINTS[operation]);
|
|
569
683
|
}
|
|
570
684
|
const pressEnter = readOptionalBoolean(parsed.rawOptions, "press-enter");
|
|
571
685
|
return {
|
|
@@ -596,7 +710,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
596
710
|
}
|
|
597
711
|
case "dom.extract": {
|
|
598
712
|
if (parsed.rest[0] === void 0) {
|
|
599
|
-
throw new
|
|
713
|
+
throw new CliError("missing_arguments", "extract requires a template.", CLI_USAGE_HINTS[operation]);
|
|
600
714
|
}
|
|
601
715
|
const persist = readPersistKey(parsed, "extract");
|
|
602
716
|
return {
|
|
@@ -632,7 +746,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
632
746
|
}
|
|
633
747
|
case "network.detail": {
|
|
634
748
|
if (parsed.rest[0] === void 0) {
|
|
635
|
-
throw new
|
|
749
|
+
throw new CliError("missing_arguments", "network detail requires a record id.", CLI_USAGE_HINTS[operation]);
|
|
636
750
|
}
|
|
637
751
|
const probeFlag = readOptionalBoolean(parsed.rawOptions, "probe");
|
|
638
752
|
return {
|
|
@@ -643,7 +757,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
643
757
|
case "session.fetch": {
|
|
644
758
|
const url = parsed.rest[0];
|
|
645
759
|
if (url === void 0) {
|
|
646
|
-
throw new
|
|
760
|
+
throw new CliError("missing_arguments", "fetch requires a URL.", CLI_USAGE_HINTS[operation]);
|
|
647
761
|
}
|
|
648
762
|
const bodyJson = readJsonValue(parsed.rawOptions, "body");
|
|
649
763
|
const bodyText = readSingle(parsed.rawOptions, "body-text");
|
|
@@ -651,7 +765,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
651
765
|
const query = parseKeyValueList(parsed.rawOptions.get("query"));
|
|
652
766
|
const headers = parseKeyValueList(parsed.rawOptions.get("header"));
|
|
653
767
|
if (bodyJson !== void 0 && bodyText !== void 0) {
|
|
654
|
-
throw new
|
|
768
|
+
throw new CliError("invalid_option", 'Use either "--body" or "--body-text", not both.');
|
|
655
769
|
}
|
|
656
770
|
const transport = readSingle(parsed.rawOptions, "transport");
|
|
657
771
|
const cookies = readOptionalBoolean(parsed.rawOptions, "cookies");
|
|
@@ -682,7 +796,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
682
796
|
const siteKey = readSingle(parsed.rawOptions, "site-key");
|
|
683
797
|
const pageUrl = readSingle(parsed.rawOptions, "page-url");
|
|
684
798
|
if (provider === void 0 || apiKey === void 0) {
|
|
685
|
-
throw new
|
|
799
|
+
throw new CliError("missing_arguments", 'captcha solve requires "--provider" and "--api-key".', CLI_USAGE_HINTS[operation]);
|
|
686
800
|
}
|
|
687
801
|
return {
|
|
688
802
|
provider: readCaptchaProvider(provider),
|
|
@@ -712,7 +826,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
712
826
|
case "scripts.beautify":
|
|
713
827
|
case "scripts.deobfuscate": {
|
|
714
828
|
if (parsed.rest[0] === void 0) {
|
|
715
|
-
throw new
|
|
829
|
+
throw new CliError("missing_arguments", `${parsed.command.join(" ")} requires an artifact id.`, CLI_USAGE_HINTS[operation]);
|
|
716
830
|
}
|
|
717
831
|
const persist = readOptionalBoolean(parsed.rawOptions, "persist");
|
|
718
832
|
return {
|
|
@@ -722,7 +836,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
722
836
|
}
|
|
723
837
|
case "scripts.sandbox":
|
|
724
838
|
if (parsed.rest[0] === void 0) {
|
|
725
|
-
throw new
|
|
839
|
+
throw new CliError("missing_arguments", "scripts sandbox requires an artifact id.", CLI_USAGE_HINTS[operation]);
|
|
726
840
|
}
|
|
727
841
|
{
|
|
728
842
|
const fidelity = readSingle(parsed.rawOptions, "fidelity");
|
|
@@ -771,14 +885,14 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
771
885
|
case "interaction.get":
|
|
772
886
|
case "interaction.replay":
|
|
773
887
|
if (parsed.rest[0] === void 0) {
|
|
774
|
-
throw new
|
|
888
|
+
throw new CliError("missing_arguments", `${parsed.command.join(" ")} requires a trace id.`, CLI_USAGE_HINTS[operation]);
|
|
775
889
|
}
|
|
776
890
|
return {
|
|
777
891
|
traceId: parsed.rest[0]
|
|
778
892
|
};
|
|
779
893
|
case "interaction.diff":
|
|
780
894
|
if (parsed.rest[0] === void 0 || parsed.rest[1] === void 0) {
|
|
781
|
-
throw new
|
|
895
|
+
throw new CliError("missing_arguments", "interaction diff requires two trace ids.", CLI_USAGE_HINTS[operation]);
|
|
782
896
|
}
|
|
783
897
|
return {
|
|
784
898
|
leftTraceId: parsed.rest[0],
|
|
@@ -786,7 +900,7 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
786
900
|
};
|
|
787
901
|
case "artifact.read":
|
|
788
902
|
if (parsed.rest[0] === void 0) {
|
|
789
|
-
throw new
|
|
903
|
+
throw new CliError("missing_arguments", "artifact read requires an artifact id.", CLI_USAGE_HINTS[operation]);
|
|
790
904
|
}
|
|
791
905
|
return {
|
|
792
906
|
artifactId: parsed.rest[0]
|
|
@@ -794,7 +908,8 @@ async function buildOperationInput(operation, parsed, runtime) {
|
|
|
794
908
|
case "session.close":
|
|
795
909
|
return {};
|
|
796
910
|
default:
|
|
797
|
-
throw new
|
|
911
|
+
throw new CliError(
|
|
912
|
+
"unsupported_operation",
|
|
798
913
|
`${operation} does not have a direct CLI input shape. Use a supported command or the SDK.`
|
|
799
914
|
);
|
|
800
915
|
}
|
|
@@ -841,7 +956,7 @@ function buildComputerExecuteInput(parsed) {
|
|
|
841
956
|
}
|
|
842
957
|
case "type":
|
|
843
958
|
if (parsed.rest[0] === void 0) {
|
|
844
|
-
throw new
|
|
959
|
+
throw new CliError("missing_arguments", "computer type requires text.");
|
|
845
960
|
}
|
|
846
961
|
return {
|
|
847
962
|
action: {
|
|
@@ -852,7 +967,7 @@ function buildComputerExecuteInput(parsed) {
|
|
|
852
967
|
};
|
|
853
968
|
case "key": {
|
|
854
969
|
if (parsed.rest[0] === void 0) {
|
|
855
|
-
throw new
|
|
970
|
+
throw new CliError("missing_arguments", "computer key requires a key.");
|
|
856
971
|
}
|
|
857
972
|
const modifiers = readKeyModifiers(readSingle(parsed.rawOptions, "modifiers"));
|
|
858
973
|
return {
|
|
@@ -868,7 +983,7 @@ function buildComputerExecuteInput(parsed) {
|
|
|
868
983
|
const dx = readOptionalNumber(parsed.rawOptions, "dx");
|
|
869
984
|
const dy = readOptionalNumber(parsed.rawOptions, "dy");
|
|
870
985
|
if (dx === void 0 || dy === void 0) {
|
|
871
|
-
throw new
|
|
986
|
+
throw new CliError("missing_arguments", 'computer scroll requires "--dx" and "--dy".');
|
|
872
987
|
}
|
|
873
988
|
return {
|
|
874
989
|
action: {
|
|
@@ -923,49 +1038,50 @@ function buildComputerExecuteInput(parsed) {
|
|
|
923
1038
|
}
|
|
924
1039
|
};
|
|
925
1040
|
default:
|
|
926
|
-
throw new
|
|
1041
|
+
throw new CliError("unknown_command", `Unknown computer command: ${parsed.command.join(" ")}`);
|
|
927
1042
|
}
|
|
928
1043
|
}
|
|
929
1044
|
async function resolvePageRefByIndex(runtime, index) {
|
|
930
1045
|
const pages = (await runtime.listPages({})).pages;
|
|
931
1046
|
const page = pages[index - 1];
|
|
932
1047
|
if (page === void 0) {
|
|
933
|
-
throw new
|
|
1048
|
+
throw new CliError("invalid_value", `tab ${String(index)} does not exist.`);
|
|
934
1049
|
}
|
|
935
1050
|
return page.pageRef;
|
|
936
1051
|
}
|
|
937
1052
|
function readRequiredPositiveInteger(value, message) {
|
|
938
1053
|
const parsed = readRequiredNumber(value, message);
|
|
939
1054
|
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
940
|
-
throw new
|
|
1055
|
+
throw new CliError("missing_arguments", message);
|
|
941
1056
|
}
|
|
942
1057
|
return parsed;
|
|
943
1058
|
}
|
|
944
1059
|
function readRequiredNumber(value, message) {
|
|
945
1060
|
if (value === void 0) {
|
|
946
|
-
throw new
|
|
1061
|
+
throw new CliError("missing_arguments", message);
|
|
947
1062
|
}
|
|
948
1063
|
const parsed = Number(value);
|
|
949
1064
|
if (!Number.isFinite(parsed)) {
|
|
950
|
-
throw new
|
|
1065
|
+
throw new CliError("missing_arguments", message);
|
|
951
1066
|
}
|
|
952
1067
|
return parsed;
|
|
953
1068
|
}
|
|
954
1069
|
function readSingleDirection(value) {
|
|
955
1070
|
if (value === void 0 || !SCROLL_DIRECTIONS.has(value)) {
|
|
956
|
-
throw new
|
|
1071
|
+
throw new CliError("missing_arguments", "scroll requires a direction: up, down, left, or right.");
|
|
957
1072
|
}
|
|
958
1073
|
return value;
|
|
959
1074
|
}
|
|
960
1075
|
function readClickButton(value) {
|
|
961
1076
|
if (value === void 0 || !CLICK_BUTTONS.has(value)) {
|
|
962
|
-
throw new
|
|
1077
|
+
throw new CliError("invalid_value", 'Expected "--button" to be one of: left, middle, right.');
|
|
963
1078
|
}
|
|
964
1079
|
return value;
|
|
965
1080
|
}
|
|
966
1081
|
function readFetchTransport(value) {
|
|
967
1082
|
if (value === void 0 || !FETCH_TRANSPORTS.has(value)) {
|
|
968
|
-
throw new
|
|
1083
|
+
throw new CliError(
|
|
1084
|
+
"invalid_value",
|
|
969
1085
|
'Expected "--transport" to be one of: auto, direct, matched-tls, context, page.'
|
|
970
1086
|
);
|
|
971
1087
|
}
|
|
@@ -973,31 +1089,31 @@ function readFetchTransport(value) {
|
|
|
973
1089
|
}
|
|
974
1090
|
function readCaptchaProvider(value) {
|
|
975
1091
|
if (value === void 0 || !CAPTCHA_PROVIDERS.has(value)) {
|
|
976
|
-
throw new
|
|
1092
|
+
throw new CliError("invalid_value", 'Expected "--provider" to be one of: 2captcha, capsolver.');
|
|
977
1093
|
}
|
|
978
1094
|
return value;
|
|
979
1095
|
}
|
|
980
1096
|
function readCaptchaType(value) {
|
|
981
1097
|
if (value === void 0 || !CAPTCHA_TYPES.has(value)) {
|
|
982
|
-
throw new
|
|
1098
|
+
throw new CliError("invalid_value", 'Expected "--type" to be one of: recaptcha-v2, hcaptcha, turnstile.');
|
|
983
1099
|
}
|
|
984
1100
|
return value;
|
|
985
1101
|
}
|
|
986
1102
|
function readSandboxFidelity(value) {
|
|
987
1103
|
if (value === void 0 || !SANDBOX_FIDELITIES.has(value)) {
|
|
988
|
-
throw new
|
|
1104
|
+
throw new CliError("invalid_value", 'Expected "--fidelity" to be one of: minimal, standard, full.');
|
|
989
1105
|
}
|
|
990
1106
|
return value;
|
|
991
1107
|
}
|
|
992
1108
|
function readSandboxClockMode(value) {
|
|
993
1109
|
if (value === void 0 || !SANDBOX_CLOCK_MODES.has(value)) {
|
|
994
|
-
throw new
|
|
1110
|
+
throw new CliError("invalid_value", 'Expected "--clock" to be one of: real, manual.');
|
|
995
1111
|
}
|
|
996
1112
|
return value;
|
|
997
1113
|
}
|
|
998
1114
|
function readScreenshotFormat(value) {
|
|
999
1115
|
if (value === void 0 || !SCREENSHOT_FORMATS.has(value)) {
|
|
1000
|
-
throw new
|
|
1116
|
+
throw new CliError("invalid_value", 'Expected "--format" to be one of: png, jpeg, webp.');
|
|
1001
1117
|
}
|
|
1002
1118
|
return value;
|
|
1003
1119
|
}
|
|
@@ -1008,7 +1124,7 @@ function readKeyModifiers(value) {
|
|
|
1008
1124
|
}
|
|
1009
1125
|
for (const modifier of modifiers) {
|
|
1010
1126
|
if (!KEY_MODIFIERS.has(modifier)) {
|
|
1011
|
-
throw new
|
|
1127
|
+
throw new CliError("invalid_value", 'Expected "--modifiers" to contain only: Shift, Control, Alt, Meta.');
|
|
1012
1128
|
}
|
|
1013
1129
|
}
|
|
1014
1130
|
return [...new Set(modifiers)];
|
|
@@ -1016,17 +1132,22 @@ function readKeyModifiers(value) {
|
|
|
1016
1132
|
function readPersistKey(parsed, verb) {
|
|
1017
1133
|
const value = readSingle(parsed.rawOptions, "persist");
|
|
1018
1134
|
if (value === void 0) {
|
|
1019
|
-
throw new
|
|
1135
|
+
throw new CliError("missing_arguments", `${verb} requires "--persist <key>".`);
|
|
1020
1136
|
}
|
|
1021
1137
|
if (value === "true" || value === "false") {
|
|
1022
|
-
throw new
|
|
1138
|
+
throw new CliError("missing_arguments", `${verb} requires "--persist <key>".`);
|
|
1023
1139
|
}
|
|
1024
1140
|
return value;
|
|
1025
1141
|
}
|
|
1026
1142
|
function parseRequiredJsonObjectArgument(value, label) {
|
|
1027
|
-
|
|
1143
|
+
let parsed;
|
|
1144
|
+
try {
|
|
1145
|
+
parsed = JSON.parse(value);
|
|
1146
|
+
} catch {
|
|
1147
|
+
throw new CliError("invalid_value", `${label} contains invalid JSON.`);
|
|
1148
|
+
}
|
|
1028
1149
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1029
|
-
throw new
|
|
1150
|
+
throw new CliError("invalid_value", `${label} must be a JSON object.`);
|
|
1030
1151
|
}
|
|
1031
1152
|
return parsed;
|
|
1032
1153
|
}
|
|
@@ -2182,7 +2303,7 @@ async function handleViewCommand(parsed, options = {}) {
|
|
|
2182
2303
|
return;
|
|
2183
2304
|
}
|
|
2184
2305
|
if (subcommand !== void 0) {
|
|
2185
|
-
throw new
|
|
2306
|
+
throw new CliError("unknown_command", `Unknown view command: view ${subcommand}`);
|
|
2186
2307
|
}
|
|
2187
2308
|
if (parsed.options.localViewMode !== void 0) {
|
|
2188
2309
|
const preference = await setLocalViewMode(parsed.options.localViewMode);
|
|
@@ -2230,7 +2351,10 @@ async function resolveWorkspaceSessionId(input) {
|
|
|
2230
2351
|
}
|
|
2231
2352
|
function assertNoViewPreferenceFlag(parsed) {
|
|
2232
2353
|
if (parsed.options.localViewMode !== void 0) {
|
|
2233
|
-
throw new
|
|
2354
|
+
throw new CliError(
|
|
2355
|
+
"invalid_option",
|
|
2356
|
+
"View preference flags cannot be combined with this subcommand."
|
|
2357
|
+
);
|
|
2234
2358
|
}
|
|
2235
2359
|
}
|
|
2236
2360
|
function writeViewOutput(parsed, value) {
|
|
@@ -2315,10 +2439,10 @@ async function main() {
|
|
|
2315
2439
|
}
|
|
2316
2440
|
const operation = resolveOperation(parsed.command);
|
|
2317
2441
|
if (!operation) {
|
|
2318
|
-
throw new
|
|
2442
|
+
throw new CliError("unknown_command", `Unknown command: ${parsed.command.join(" ")}`);
|
|
2319
2443
|
}
|
|
2320
2444
|
if (parsed.options.workspace === void 0) {
|
|
2321
|
-
throw new
|
|
2445
|
+
throw new CliError("missing_workspace", 'Stateful commands require "--workspace <id>" or OPENSTEER_WORKSPACE.');
|
|
2322
2446
|
}
|
|
2323
2447
|
const { engineName, provider, runtimeProvider } = resolveCliRuntimeSelection(parsed);
|
|
2324
2448
|
if (operation === "session.close") {
|
|
@@ -2340,28 +2464,43 @@ async function main() {
|
|
|
2340
2464
|
let renderOperation = operation;
|
|
2341
2465
|
try {
|
|
2342
2466
|
const input = await buildOperationInput(operation, parsed, runtime);
|
|
2343
|
-
|
|
2467
|
+
const rawResult = await dispatchSemanticOperation(runtime, operation, input);
|
|
2344
2468
|
if (parsed.command[0] === "tab" && operation !== "page.list") {
|
|
2345
2469
|
renderOperation = "page.list";
|
|
2346
2470
|
result = await runtime.listPages({});
|
|
2471
|
+
} else {
|
|
2472
|
+
result = rawResult;
|
|
2473
|
+
}
|
|
2474
|
+
let warning;
|
|
2475
|
+
if (result !== null && typeof result === "object" && "warning" in result) {
|
|
2476
|
+
const { warning: w, ...rest } = result;
|
|
2477
|
+
if (typeof w === "string") {
|
|
2478
|
+
warning = w;
|
|
2479
|
+
result = rest;
|
|
2480
|
+
}
|
|
2347
2481
|
}
|
|
2348
2482
|
process4.stdout.write(renderOperationOutput(renderOperation, result, input));
|
|
2483
|
+
if (warning !== void 0) {
|
|
2484
|
+
emitWarning(warning);
|
|
2485
|
+
}
|
|
2349
2486
|
} finally {
|
|
2350
2487
|
await runtime.disconnect().catch(() => void 0);
|
|
2351
2488
|
}
|
|
2352
2489
|
}
|
|
2353
2490
|
async function handleExecCommand(parsed) {
|
|
2354
2491
|
if (parsed.options.workspace === void 0) {
|
|
2355
|
-
throw new
|
|
2492
|
+
throw new CliError("missing_workspace", 'exec requires "--workspace <id>" or OPENSTEER_WORKSPACE.');
|
|
2356
2493
|
}
|
|
2357
2494
|
const expression = parsed.rest.join(" ");
|
|
2358
2495
|
if (!expression) {
|
|
2359
|
-
throw new
|
|
2360
|
-
|
|
2496
|
+
throw new CliError(
|
|
2497
|
+
"missing_arguments",
|
|
2498
|
+
"exec requires an expression.",
|
|
2499
|
+
"opensteer exec <expression>"
|
|
2361
2500
|
);
|
|
2362
2501
|
}
|
|
2363
2502
|
const { engineName, runtimeProvider } = resolveCliRuntimeSelection(parsed);
|
|
2364
|
-
const { Opensteer } = await import('../opensteer-
|
|
2503
|
+
const { Opensteer } = await import('../opensteer-UGA6YBRN.js');
|
|
2365
2504
|
const opensteer = new Opensteer({
|
|
2366
2505
|
workspace: parsed.options.workspace,
|
|
2367
2506
|
rootDir: process4.cwd(),
|
|
@@ -2393,8 +2532,10 @@ async function handleBrowserCommand(parsed) {
|
|
|
2393
2532
|
if (subcommand === "inspect") {
|
|
2394
2533
|
const endpoint = parsed.options.attachEndpoint ?? parsed.rest[0];
|
|
2395
2534
|
if (!endpoint) {
|
|
2396
|
-
throw new
|
|
2397
|
-
|
|
2535
|
+
throw new CliError(
|
|
2536
|
+
"missing_arguments",
|
|
2537
|
+
'browser inspect requires "--attach-endpoint <url>" or a positional endpoint.',
|
|
2538
|
+
"opensteer browser inspect <endpoint>"
|
|
2398
2539
|
);
|
|
2399
2540
|
}
|
|
2400
2541
|
const result = await inspectCdpEndpoint({
|
|
@@ -2407,7 +2548,8 @@ async function handleBrowserCommand(parsed) {
|
|
|
2407
2548
|
return;
|
|
2408
2549
|
}
|
|
2409
2550
|
if (parsed.options.workspace === void 0) {
|
|
2410
|
-
throw new
|
|
2551
|
+
throw new CliError(
|
|
2552
|
+
"missing_workspace",
|
|
2411
2553
|
'Browser workspace commands require "--workspace <id>" or OPENSTEER_WORKSPACE.'
|
|
2412
2554
|
);
|
|
2413
2555
|
}
|
|
@@ -2430,7 +2572,11 @@ async function handleBrowserCommand(parsed) {
|
|
|
2430
2572
|
case "clone": {
|
|
2431
2573
|
const sourceUserDataDir = parsed.options.sourceUserDataDir;
|
|
2432
2574
|
if (!sourceUserDataDir) {
|
|
2433
|
-
throw new
|
|
2575
|
+
throw new CliError(
|
|
2576
|
+
"missing_arguments",
|
|
2577
|
+
'browser clone requires "--source-user-data-dir <path>".',
|
|
2578
|
+
"opensteer browser clone --source-user-data-dir <path>"
|
|
2579
|
+
);
|
|
2434
2580
|
}
|
|
2435
2581
|
const result = await manager.clonePersistentBrowser({
|
|
2436
2582
|
sourceUserDataDir,
|
|
@@ -2453,7 +2599,7 @@ async function handleBrowserCommand(parsed) {
|
|
|
2453
2599
|
return;
|
|
2454
2600
|
}
|
|
2455
2601
|
default:
|
|
2456
|
-
throw new
|
|
2602
|
+
throw new CliError("unknown_command", `Unknown browser command: ${parsed.command.join(" ")}`);
|
|
2457
2603
|
}
|
|
2458
2604
|
}
|
|
2459
2605
|
async function handleCloseCommand(parsed, engineName, providerMode, runtimeProvider) {
|
|
@@ -2486,23 +2632,27 @@ async function handleCloseCommand(parsed, engineName, providerMode, runtimeProvi
|
|
|
2486
2632
|
}
|
|
2487
2633
|
async function handleRecordCommandEntry(parsed) {
|
|
2488
2634
|
if (parsed.options.workspace === void 0) {
|
|
2489
|
-
throw new
|
|
2635
|
+
throw new CliError("missing_workspace", 'record requires "--workspace <id>" or OPENSTEER_WORKSPACE.');
|
|
2490
2636
|
}
|
|
2491
2637
|
const url = parsed.options.url ?? parsed.rest[0];
|
|
2492
2638
|
if (url === void 0) {
|
|
2493
|
-
throw new
|
|
2639
|
+
throw new CliError(
|
|
2640
|
+
"missing_arguments",
|
|
2641
|
+
'record requires "--url <value>" or a positional URL.',
|
|
2642
|
+
"opensteer record --url <url> --workspace <id>"
|
|
2643
|
+
);
|
|
2494
2644
|
}
|
|
2495
2645
|
const provider = resolveCliProvider(parsed);
|
|
2496
2646
|
assertCloudCliOptionsMatchProvider(parsed, provider.mode);
|
|
2497
2647
|
const engineName = resolveCliEngineName(parsed);
|
|
2498
2648
|
if (engineName !== "playwright") {
|
|
2499
|
-
throw new
|
|
2649
|
+
throw new CliError("config_conflict", "record requires engine=playwright.");
|
|
2500
2650
|
}
|
|
2501
2651
|
const rootDir = process4.cwd();
|
|
2502
2652
|
const recordBrowser = parsed.options.browser;
|
|
2503
2653
|
if (provider.mode === "cloud") {
|
|
2504
2654
|
if (typeof recordBrowser === "object") {
|
|
2505
|
-
throw new
|
|
2655
|
+
throw new CliError("config_conflict", 'record does not support browser.mode="attach".');
|
|
2506
2656
|
}
|
|
2507
2657
|
const runtimeProvider = buildCliRuntimeProvider(parsed, provider.mode);
|
|
2508
2658
|
const runtimeConfig = resolveOpensteerRuntimeConfig({
|
|
@@ -2522,10 +2672,10 @@ async function handleRecordCommandEntry(parsed) {
|
|
|
2522
2672
|
return;
|
|
2523
2673
|
}
|
|
2524
2674
|
if (parsed.options.launch?.headless === true) {
|
|
2525
|
-
throw new
|
|
2675
|
+
throw new CliError("config_conflict", 'record requires a headed browser. Remove "--headless true".');
|
|
2526
2676
|
}
|
|
2527
2677
|
if (typeof recordBrowser === "object") {
|
|
2528
|
-
throw new
|
|
2678
|
+
throw new CliError("config_conflict", 'record does not support browser.mode="attach".');
|
|
2529
2679
|
}
|
|
2530
2680
|
const launch = {
|
|
2531
2681
|
...parsed.options.launch ?? {},
|
|
@@ -2594,7 +2744,7 @@ function resolveCliBootstrapAction(argv) {
|
|
|
2594
2744
|
}
|
|
2595
2745
|
function buildCliBrowserProfile(parsed) {
|
|
2596
2746
|
if (parsed.options.cloudProfileReuseIfActive === true && parsed.options.cloudProfileId === void 0) {
|
|
2597
|
-
throw new
|
|
2747
|
+
throw new CliError("invalid_option", '"--cloud-profile-reuse-if-active" requires "--cloud-profile-id <id>".');
|
|
2598
2748
|
}
|
|
2599
2749
|
return parsed.options.cloudProfileId === void 0 ? void 0 : {
|
|
2600
2750
|
profileId: parsed.options.cloudProfileId,
|
|
@@ -2655,7 +2805,8 @@ function buildCliRuntimeProvider(parsed, providerMode) {
|
|
|
2655
2805
|
}
|
|
2656
2806
|
function assertCloudCliOptionsMatchProvider(parsed, providerMode) {
|
|
2657
2807
|
if (providerMode !== "cloud" && (parsed.options.cloudBaseUrl !== void 0 || parsed.options.cloudApiKey !== void 0 || parsed.options.cloudAppBaseUrl !== void 0 || parsed.options.cloudProfileId !== void 0 || parsed.options.cloudProfileReuseIfActive === true)) {
|
|
2658
|
-
throw new
|
|
2808
|
+
throw new CliError(
|
|
2809
|
+
"config_conflict",
|
|
2659
2810
|
'Cloud-specific options require provider=cloud. Set "--provider cloud" or OPENSTEER_PROVIDER=cloud.'
|
|
2660
2811
|
);
|
|
2661
2812
|
}
|
|
@@ -2689,17 +2840,7 @@ function printVersion() {
|
|
|
2689
2840
|
`);
|
|
2690
2841
|
}
|
|
2691
2842
|
main().catch((error) => {
|
|
2692
|
-
const payload = error
|
|
2693
|
-
error: {
|
|
2694
|
-
name: error.name,
|
|
2695
|
-
message: error.message
|
|
2696
|
-
}
|
|
2697
|
-
} : {
|
|
2698
|
-
error: {
|
|
2699
|
-
name: "Error",
|
|
2700
|
-
message: String(error)
|
|
2701
|
-
}
|
|
2702
|
-
};
|
|
2843
|
+
const payload = formatCliErrorOutput(error);
|
|
2703
2844
|
process4.stderr.write(`${JSON.stringify(payload)}
|
|
2704
2845
|
`);
|
|
2705
2846
|
process4.exitCode = 1;
|