opensteer 0.6.2 → 0.6.4
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/bin/opensteer.mjs +94 -8
- package/dist/{browser-profile-client-DK9qa_Dj.d.cts → browser-profile-client-D6PuRefA.d.cts} +1 -1
- package/dist/{browser-profile-client-CaL-mwqs.d.ts → browser-profile-client-OUHaODro.d.ts} +1 -1
- package/dist/{chunk-7RMY26CM.js → chunk-54KNQTOL.js} +172 -55
- package/dist/{chunk-WJI7TGBQ.js → chunk-6B6LOYU3.js} +1 -1
- package/dist/{chunk-F2VDVOJO.js → chunk-G6V2DJRN.js} +451 -609
- package/dist/chunk-K5CL76MG.js +81 -0
- package/dist/{chunk-WDRMHPWL.js → chunk-KPPOTU3D.js} +159 -180
- package/dist/cli/auth.cjs +186 -95
- package/dist/cli/auth.d.cts +1 -1
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +2 -2
- package/dist/cli/local-profile.cjs +197 -0
- package/dist/cli/local-profile.d.cts +18 -0
- package/dist/cli/local-profile.d.ts +18 -0
- package/dist/cli/local-profile.js +97 -0
- package/dist/cli/profile.cjs +1747 -1279
- package/dist/cli/profile.d.cts +2 -2
- package/dist/cli/profile.d.ts +2 -2
- package/dist/cli/profile.js +469 -7
- package/dist/cli/server.cjs +759 -257
- package/dist/cli/server.js +69 -16
- package/dist/index.cjs +688 -238
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +4 -3
- package/dist/{types-BxiRblC7.d.cts → types-BWItZPl_.d.cts} +31 -13
- package/dist/{types-BxiRblC7.d.ts → types-BWItZPl_.d.ts} +31 -13
- package/package.json +2 -2
- package/skills/opensteer/SKILL.md +34 -14
- package/skills/opensteer/references/cli-reference.md +1 -1
- package/skills/opensteer/references/examples.md +5 -3
- package/skills/opensteer/references/sdk-reference.md +16 -14
package/dist/index.cjs
CHANGED
|
@@ -515,7 +515,13 @@ module.exports = __toCommonJS(index_exports);
|
|
|
515
515
|
var import_crypto = require("crypto");
|
|
516
516
|
|
|
517
517
|
// src/browser/pool.ts
|
|
518
|
-
var
|
|
518
|
+
var import_node_child_process = require("child_process");
|
|
519
|
+
var import_node_fs = require("fs");
|
|
520
|
+
var import_promises = require("fs/promises");
|
|
521
|
+
var import_node_net = require("net");
|
|
522
|
+
var import_node_os = require("os");
|
|
523
|
+
var import_node_path = require("path");
|
|
524
|
+
var import_playwright = require("playwright");
|
|
519
525
|
|
|
520
526
|
// src/browser/cdp-proxy.ts
|
|
521
527
|
var import_ws = __toESM(require("ws"), 1);
|
|
@@ -854,209 +860,263 @@ function errorMessage(error) {
|
|
|
854
860
|
return error instanceof Error ? error.message : String(error);
|
|
855
861
|
}
|
|
856
862
|
|
|
857
|
-
// src/browser/chromium-profile.ts
|
|
858
|
-
var import_node_util = require("util");
|
|
859
|
-
var import_node_child_process2 = require("child_process");
|
|
860
|
-
var import_node_crypto = require("crypto");
|
|
861
|
-
var import_promises = require("fs/promises");
|
|
862
|
-
var import_node_fs = require("fs");
|
|
863
|
-
var import_node_path = require("path");
|
|
864
|
-
var import_node_os = require("os");
|
|
865
|
-
var import_playwright = require("playwright");
|
|
866
|
-
|
|
867
|
-
// src/auth/keychain-store.ts
|
|
868
|
-
var import_node_child_process = require("child_process");
|
|
869
|
-
|
|
870
863
|
// src/browser/chrome.ts
|
|
871
864
|
var import_os = require("os");
|
|
872
865
|
var import_path = require("path");
|
|
866
|
+
var import_fs = require("fs");
|
|
867
|
+
function detectChromePaths() {
|
|
868
|
+
const os = (0, import_os.platform)();
|
|
869
|
+
if (os === "darwin") {
|
|
870
|
+
const executable2 = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
871
|
+
return {
|
|
872
|
+
executable: (0, import_fs.existsSync)(executable2) ? executable2 : null,
|
|
873
|
+
defaultUserDataDir: (0, import_path.join)(
|
|
874
|
+
(0, import_os.homedir)(),
|
|
875
|
+
"Library",
|
|
876
|
+
"Application Support",
|
|
877
|
+
"Google",
|
|
878
|
+
"Chrome"
|
|
879
|
+
)
|
|
880
|
+
};
|
|
881
|
+
}
|
|
882
|
+
if (os === "win32") {
|
|
883
|
+
const executable2 = (0, import_path.join)(
|
|
884
|
+
process.env.PROGRAMFILES || "C:\\Program Files",
|
|
885
|
+
"Google",
|
|
886
|
+
"Chrome",
|
|
887
|
+
"Application",
|
|
888
|
+
"chrome.exe"
|
|
889
|
+
);
|
|
890
|
+
return {
|
|
891
|
+
executable: (0, import_fs.existsSync)(executable2) ? executable2 : null,
|
|
892
|
+
defaultUserDataDir: (0, import_path.join)(
|
|
893
|
+
process.env.LOCALAPPDATA || (0, import_path.join)((0, import_os.homedir)(), "AppData", "Local"),
|
|
894
|
+
"Google",
|
|
895
|
+
"Chrome",
|
|
896
|
+
"User Data"
|
|
897
|
+
)
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
const executable = "/usr/bin/google-chrome";
|
|
901
|
+
return {
|
|
902
|
+
executable: (0, import_fs.existsSync)(executable) ? executable : null,
|
|
903
|
+
defaultUserDataDir: (0, import_path.join)((0, import_os.homedir)(), ".config", "google-chrome")
|
|
904
|
+
};
|
|
905
|
+
}
|
|
873
906
|
function expandHome(p) {
|
|
874
907
|
if (p.startsWith("~/") || p === "~") {
|
|
875
908
|
return (0, import_path.join)((0, import_os.homedir)(), p.slice(1));
|
|
876
909
|
}
|
|
877
910
|
return p;
|
|
878
911
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
return (0, import_node_fs.statSync)(filePath).isDirectory();
|
|
885
|
-
} catch {
|
|
886
|
-
return false;
|
|
912
|
+
function listLocalChromeProfiles(userDataDir = detectChromePaths().defaultUserDataDir) {
|
|
913
|
+
const resolvedUserDataDir = expandHome(userDataDir);
|
|
914
|
+
const localStatePath = (0, import_path.join)(resolvedUserDataDir, "Local State");
|
|
915
|
+
if (!(0, import_fs.existsSync)(localStatePath)) {
|
|
916
|
+
return [];
|
|
887
917
|
}
|
|
888
|
-
}
|
|
889
|
-
function fileExists(filePath) {
|
|
890
918
|
try {
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
}
|
|
896
|
-
function resolveCookieDbPath(profileDir) {
|
|
897
|
-
const candidates = [(0, import_node_path.join)(profileDir, "Network", "Cookies"), (0, import_node_path.join)(profileDir, "Cookies")];
|
|
898
|
-
for (const candidate of candidates) {
|
|
899
|
-
if (fileExists(candidate)) {
|
|
900
|
-
return candidate;
|
|
919
|
+
const raw = JSON.parse((0, import_fs.readFileSync)(localStatePath, "utf-8"));
|
|
920
|
+
const infoCache = raw && typeof raw === "object" && !Array.isArray(raw) && raw.profile && typeof raw.profile === "object" && !Array.isArray(raw.profile) ? raw.profile.info_cache : void 0;
|
|
921
|
+
if (!infoCache || typeof infoCache !== "object") {
|
|
922
|
+
return [];
|
|
901
923
|
}
|
|
924
|
+
return Object.entries(infoCache).map(([directory, info]) => {
|
|
925
|
+
const record = info && typeof info === "object" && !Array.isArray(info) ? info : {};
|
|
926
|
+
const name = typeof record.name === "string" && record.name.trim() ? record.name.trim() : directory;
|
|
927
|
+
return {
|
|
928
|
+
directory,
|
|
929
|
+
name
|
|
930
|
+
};
|
|
931
|
+
}).filter((profile) => profile.directory.trim().length > 0).sort(
|
|
932
|
+
(left, right) => left.directory.localeCompare(right.directory)
|
|
933
|
+
);
|
|
934
|
+
} catch {
|
|
935
|
+
return [];
|
|
902
936
|
}
|
|
903
|
-
return null;
|
|
904
|
-
}
|
|
905
|
-
function resolvePersistentChromiumLaunchProfile(inputPath) {
|
|
906
|
-
const expandedPath = expandHome(inputPath.trim());
|
|
907
|
-
if (!expandedPath) {
|
|
908
|
-
return {
|
|
909
|
-
userDataDir: inputPath
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
if (fileExists(expandedPath) && (0, import_node_path.basename)(expandedPath) === "Cookies") {
|
|
913
|
-
const directParent = (0, import_node_path.dirname)(expandedPath);
|
|
914
|
-
const profileDir = (0, import_node_path.basename)(directParent) === "Network" ? (0, import_node_path.dirname)(directParent) : directParent;
|
|
915
|
-
return {
|
|
916
|
-
userDataDir: (0, import_node_path.dirname)(profileDir),
|
|
917
|
-
profileDirectory: (0, import_node_path.basename)(profileDir)
|
|
918
|
-
};
|
|
919
|
-
}
|
|
920
|
-
if (directoryExists(expandedPath) && resolveCookieDbPath(expandedPath) && fileExists((0, import_node_path.join)((0, import_node_path.dirname)(expandedPath), "Local State"))) {
|
|
921
|
-
return {
|
|
922
|
-
userDataDir: (0, import_node_path.dirname)(expandedPath),
|
|
923
|
-
profileDirectory: (0, import_node_path.basename)(expandedPath)
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
return {
|
|
927
|
-
userDataDir: expandedPath
|
|
928
|
-
};
|
|
929
937
|
}
|
|
930
938
|
|
|
931
939
|
// src/browser/pool.ts
|
|
932
940
|
var BrowserPool = class {
|
|
933
941
|
browser = null;
|
|
934
|
-
persistentContext = null;
|
|
935
942
|
cdpProxy = null;
|
|
943
|
+
launchedProcess = null;
|
|
944
|
+
tempUserDataDir = null;
|
|
936
945
|
defaults;
|
|
937
946
|
constructor(defaults = {}) {
|
|
938
947
|
this.defaults = defaults;
|
|
939
948
|
}
|
|
940
949
|
async launch(options = {}) {
|
|
941
|
-
if (this.browser || this.cdpProxy) {
|
|
950
|
+
if (this.browser || this.cdpProxy || this.launchedProcess || this.tempUserDataDir) {
|
|
942
951
|
await this.close();
|
|
943
952
|
}
|
|
944
|
-
const
|
|
945
|
-
const
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
|
|
953
|
+
const mode = options.mode ?? this.defaults.mode ?? "chromium";
|
|
954
|
+
const cdpUrl = options.cdpUrl ?? this.defaults.cdpUrl;
|
|
955
|
+
const userDataDir = options.userDataDir ?? this.defaults.userDataDir;
|
|
956
|
+
const profileDirectory = options.profileDirectory ?? this.defaults.profileDirectory;
|
|
957
|
+
const executablePath = options.executablePath ?? this.defaults.executablePath;
|
|
958
|
+
if (cdpUrl) {
|
|
959
|
+
if (mode === "real") {
|
|
960
|
+
throw new Error(
|
|
961
|
+
'cdpUrl cannot be combined with mode "real". Use one browser launch path at a time.'
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
if (userDataDir || profileDirectory) {
|
|
965
|
+
throw new Error(
|
|
966
|
+
"userDataDir/profileDirectory cannot be combined with cdpUrl."
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
if (options.context && Object.keys(options.context).length > 0) {
|
|
970
|
+
throw new Error(
|
|
971
|
+
"context launch options are not supported when attaching over CDP."
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
return this.connectToRunning(cdpUrl, options.timeout);
|
|
949
975
|
}
|
|
950
|
-
if (
|
|
951
|
-
|
|
976
|
+
if (mode !== "real" && (userDataDir || profileDirectory)) {
|
|
977
|
+
throw new Error(
|
|
978
|
+
'userDataDir/profileDirectory require mode "real".'
|
|
979
|
+
);
|
|
952
980
|
}
|
|
953
|
-
if (
|
|
954
|
-
|
|
981
|
+
if (mode === "real") {
|
|
982
|
+
if (options.context && Object.keys(options.context).length > 0) {
|
|
983
|
+
throw new Error(
|
|
984
|
+
"context launch options are not supported for real-browser mode."
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
return this.launchOwnedRealBrowser({
|
|
988
|
+
...options,
|
|
989
|
+
executablePath,
|
|
990
|
+
userDataDir,
|
|
991
|
+
profileDirectory
|
|
992
|
+
});
|
|
955
993
|
}
|
|
956
994
|
return this.launchSandbox(options);
|
|
957
995
|
}
|
|
958
996
|
async close() {
|
|
959
997
|
const browser = this.browser;
|
|
960
|
-
const
|
|
998
|
+
const cdpProxy = this.cdpProxy;
|
|
999
|
+
const launchedProcess = this.launchedProcess;
|
|
1000
|
+
const tempUserDataDir = this.tempUserDataDir;
|
|
961
1001
|
this.browser = null;
|
|
962
|
-
this.
|
|
1002
|
+
this.cdpProxy = null;
|
|
1003
|
+
this.launchedProcess = null;
|
|
1004
|
+
this.tempUserDataDir = null;
|
|
963
1005
|
try {
|
|
964
|
-
if (
|
|
965
|
-
await
|
|
966
|
-
} else if (browser) {
|
|
967
|
-
await browser.close();
|
|
1006
|
+
if (browser) {
|
|
1007
|
+
await browser.close().catch(() => void 0);
|
|
968
1008
|
}
|
|
969
1009
|
} finally {
|
|
970
|
-
|
|
971
|
-
|
|
1010
|
+
cdpProxy?.close();
|
|
1011
|
+
await killProcessTree(launchedProcess);
|
|
1012
|
+
if (tempUserDataDir) {
|
|
1013
|
+
await (0, import_promises.rm)(tempUserDataDir, {
|
|
1014
|
+
recursive: true,
|
|
1015
|
+
force: true
|
|
1016
|
+
}).catch(() => void 0);
|
|
1017
|
+
}
|
|
972
1018
|
}
|
|
973
1019
|
}
|
|
974
|
-
async connectToRunning(
|
|
975
|
-
this.cdpProxy?.close();
|
|
976
|
-
this.cdpProxy = null;
|
|
1020
|
+
async connectToRunning(cdpUrl, timeout) {
|
|
977
1021
|
let browser = null;
|
|
1022
|
+
let cdpProxy = null;
|
|
978
1023
|
try {
|
|
979
|
-
const { browserWsUrl, targets } = await discoverTargets(
|
|
1024
|
+
const { browserWsUrl, targets } = await discoverTargets(cdpUrl);
|
|
980
1025
|
if (targets.length === 0) {
|
|
981
1026
|
throw new Error(
|
|
982
1027
|
"No page targets found. Is the browser running with an open window?"
|
|
983
1028
|
);
|
|
984
1029
|
}
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
browser = await import_playwright2.chromium.connectOverCDP(proxyWsUrl, {
|
|
1030
|
+
cdpProxy = new CDPProxy(browserWsUrl, targets[0].id);
|
|
1031
|
+
const proxyWsUrl = await cdpProxy.start();
|
|
1032
|
+
browser = await import_playwright.chromium.connectOverCDP(proxyWsUrl, {
|
|
989
1033
|
timeout: timeout ?? 3e4
|
|
990
1034
|
});
|
|
991
1035
|
this.browser = browser;
|
|
992
|
-
this.
|
|
993
|
-
const
|
|
994
|
-
if (contexts.length === 0) {
|
|
995
|
-
throw new Error(
|
|
996
|
-
"Connection succeeded but no browser contexts found. Is the browser running with an open window?"
|
|
997
|
-
);
|
|
998
|
-
}
|
|
999
|
-
const context = contexts[0];
|
|
1000
|
-
const pages = context.pages();
|
|
1001
|
-
const page = pages.length > 0 ? pages[0] : await context.newPage();
|
|
1036
|
+
this.cdpProxy = cdpProxy;
|
|
1037
|
+
const { context, page } = await pickBrowserContextAndPage(browser);
|
|
1002
1038
|
return { browser, context, page, isExternal: true };
|
|
1003
1039
|
} catch (error) {
|
|
1004
1040
|
if (browser) {
|
|
1005
1041
|
await browser.close().catch(() => void 0);
|
|
1006
1042
|
}
|
|
1043
|
+
cdpProxy?.close();
|
|
1007
1044
|
this.browser = null;
|
|
1008
|
-
this.persistentContext = null;
|
|
1009
|
-
this.cdpProxy?.close();
|
|
1010
1045
|
this.cdpProxy = null;
|
|
1011
1046
|
throw error;
|
|
1012
1047
|
}
|
|
1013
1048
|
}
|
|
1014
|
-
async
|
|
1015
|
-
const
|
|
1016
|
-
const
|
|
1017
|
-
if (
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
launchProfile.userDataDir,
|
|
1022
|
-
{
|
|
1023
|
-
channel,
|
|
1024
|
-
headless: options.headless ?? this.defaults.headless,
|
|
1025
|
-
executablePath: options.executablePath ?? this.defaults.executablePath ?? void 0,
|
|
1026
|
-
slowMo: options.slowMo ?? this.defaults.slowMo ?? 0,
|
|
1027
|
-
timeout: options.timeout,
|
|
1028
|
-
...options.context || {},
|
|
1029
|
-
args
|
|
1030
|
-
}
|
|
1031
|
-
);
|
|
1032
|
-
const browser = context.browser();
|
|
1033
|
-
if (!browser) {
|
|
1034
|
-
await context.close().catch(() => void 0);
|
|
1035
|
-
throw new Error("Persistent browser launch did not expose a browser instance.");
|
|
1049
|
+
async launchOwnedRealBrowser(options) {
|
|
1050
|
+
const chromePaths = detectChromePaths();
|
|
1051
|
+
const executablePath = options.executablePath ?? chromePaths.executable ?? void 0;
|
|
1052
|
+
if (!executablePath) {
|
|
1053
|
+
throw new Error(
|
|
1054
|
+
"Chrome was not found. Set browser.executablePath or install Chrome in a supported location."
|
|
1055
|
+
);
|
|
1036
1056
|
}
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1057
|
+
const sourceUserDataDir = expandHome(
|
|
1058
|
+
options.userDataDir ?? chromePaths.defaultUserDataDir
|
|
1059
|
+
);
|
|
1060
|
+
const profileDirectory = options.profileDirectory ?? "Default";
|
|
1061
|
+
const tempUserDataDir = await cloneProfileToTempDir(
|
|
1062
|
+
sourceUserDataDir,
|
|
1063
|
+
profileDirectory
|
|
1064
|
+
);
|
|
1065
|
+
const debugPort = await reserveDebugPort();
|
|
1066
|
+
const headless = resolveLaunchHeadless(
|
|
1067
|
+
"real",
|
|
1068
|
+
options.headless,
|
|
1069
|
+
this.defaults.headless
|
|
1070
|
+
);
|
|
1071
|
+
const launchArgs = buildRealBrowserLaunchArgs({
|
|
1072
|
+
userDataDir: tempUserDataDir,
|
|
1073
|
+
profileDirectory,
|
|
1074
|
+
debugPort,
|
|
1075
|
+
headless
|
|
1050
1076
|
});
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1077
|
+
const processHandle = (0, import_node_child_process.spawn)(executablePath, launchArgs, {
|
|
1078
|
+
detached: process.platform !== "win32",
|
|
1079
|
+
stdio: "ignore"
|
|
1080
|
+
});
|
|
1081
|
+
processHandle.unref();
|
|
1082
|
+
let browser = null;
|
|
1083
|
+
try {
|
|
1084
|
+
const wsUrl = await resolveCdpWebSocketUrl(
|
|
1085
|
+
`http://127.0.0.1:${debugPort}`,
|
|
1086
|
+
options.timeout ?? 3e4
|
|
1087
|
+
);
|
|
1088
|
+
browser = await import_playwright.chromium.connectOverCDP(wsUrl, {
|
|
1089
|
+
timeout: options.timeout ?? 3e4
|
|
1090
|
+
});
|
|
1091
|
+
const { context, page } = await createOwnedBrowserContextAndPage(
|
|
1092
|
+
browser,
|
|
1093
|
+
{
|
|
1094
|
+
headless,
|
|
1095
|
+
initialUrl: options.initialUrl,
|
|
1096
|
+
timeoutMs: options.timeout ?? 3e4
|
|
1097
|
+
}
|
|
1098
|
+
);
|
|
1099
|
+
this.browser = browser;
|
|
1100
|
+
this.launchedProcess = processHandle;
|
|
1101
|
+
this.tempUserDataDir = tempUserDataDir;
|
|
1102
|
+
return { browser, context, page, isExternal: false };
|
|
1103
|
+
} catch (error) {
|
|
1104
|
+
await browser?.close().catch(() => void 0);
|
|
1105
|
+
await killProcessTree(processHandle);
|
|
1106
|
+
await (0, import_promises.rm)(tempUserDataDir, {
|
|
1107
|
+
recursive: true,
|
|
1108
|
+
force: true
|
|
1109
|
+
}).catch(() => void 0);
|
|
1110
|
+
throw error;
|
|
1111
|
+
}
|
|
1056
1112
|
}
|
|
1057
1113
|
async launchSandbox(options) {
|
|
1058
|
-
const browser = await
|
|
1059
|
-
headless:
|
|
1114
|
+
const browser = await import_playwright.chromium.launch({
|
|
1115
|
+
headless: resolveLaunchHeadless(
|
|
1116
|
+
"chromium",
|
|
1117
|
+
options.headless,
|
|
1118
|
+
this.defaults.headless
|
|
1119
|
+
),
|
|
1060
1120
|
executablePath: options.executablePath ?? this.defaults.executablePath ?? void 0,
|
|
1061
1121
|
slowMo: options.slowMo ?? this.defaults.slowMo ?? 0,
|
|
1062
1122
|
timeout: options.timeout
|
|
@@ -1064,13 +1124,271 @@ var BrowserPool = class {
|
|
|
1064
1124
|
const context = await browser.newContext(options.context || {});
|
|
1065
1125
|
const page = await context.newPage();
|
|
1066
1126
|
this.browser = browser;
|
|
1067
|
-
this.persistentContext = null;
|
|
1068
1127
|
return { browser, context, page, isExternal: false };
|
|
1069
1128
|
}
|
|
1070
1129
|
};
|
|
1130
|
+
async function pickBrowserContextAndPage(browser) {
|
|
1131
|
+
const context = getPrimaryBrowserContext(browser);
|
|
1132
|
+
const pages = context.pages();
|
|
1133
|
+
const page = pages.find((candidate) => isInspectablePageUrl2(candidate.url())) || pages[0] || await context.newPage();
|
|
1134
|
+
return { context, page };
|
|
1135
|
+
}
|
|
1136
|
+
function resolveLaunchHeadless(mode, requestedHeadless, defaultHeadless) {
|
|
1137
|
+
if (requestedHeadless !== void 0) {
|
|
1138
|
+
return requestedHeadless;
|
|
1139
|
+
}
|
|
1140
|
+
if (defaultHeadless !== void 0) {
|
|
1141
|
+
return defaultHeadless;
|
|
1142
|
+
}
|
|
1143
|
+
return mode === "real";
|
|
1144
|
+
}
|
|
1145
|
+
async function createOwnedBrowserContextAndPage(browser, options) {
|
|
1146
|
+
const context = getPrimaryBrowserContext(browser);
|
|
1147
|
+
const page = await createOwnedBrowserPage(browser, context, options);
|
|
1148
|
+
return { context, page };
|
|
1149
|
+
}
|
|
1150
|
+
async function createOwnedBrowserPage(browser, context, options) {
|
|
1151
|
+
const targetUrl = options.initialUrl ?? "about:blank";
|
|
1152
|
+
const existingPages = new Set(context.pages());
|
|
1153
|
+
const browserSession = await browser.newBrowserCDPSession();
|
|
1154
|
+
try {
|
|
1155
|
+
const { targetId } = await browserSession.send("Target.createTarget", {
|
|
1156
|
+
url: targetUrl,
|
|
1157
|
+
newWindow: !options.headless
|
|
1158
|
+
});
|
|
1159
|
+
await browserSession.send("Target.activateTarget", { targetId }).catch(() => void 0);
|
|
1160
|
+
const page = await waitForOwnedBrowserPage(context, {
|
|
1161
|
+
existingPages,
|
|
1162
|
+
targetUrl,
|
|
1163
|
+
timeoutMs: options.timeoutMs
|
|
1164
|
+
});
|
|
1165
|
+
if (targetUrl !== "about:blank") {
|
|
1166
|
+
await page.waitForLoadState("domcontentloaded", {
|
|
1167
|
+
timeout: options.timeoutMs
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
await closeDisposableStartupTargets(browserSession, targetId);
|
|
1171
|
+
return page;
|
|
1172
|
+
} finally {
|
|
1173
|
+
await browserSession.detach().catch(() => void 0);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
async function closeDisposableStartupTargets(browserSession, preservedTargetId) {
|
|
1177
|
+
const response = await browserSession.send("Target.getTargets").catch(() => null);
|
|
1178
|
+
if (!response) {
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
for (const targetInfo of response.targetInfos) {
|
|
1182
|
+
if (targetInfo.targetId === preservedTargetId || targetInfo.type !== "page" || !isDisposableStartupPageUrl(targetInfo.url)) {
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
await browserSession.send("Target.closeTarget", { targetId: targetInfo.targetId }).catch(() => void 0);
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
async function waitForOwnedBrowserPage(context, options) {
|
|
1189
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
1190
|
+
let fallbackPage = null;
|
|
1191
|
+
while (Date.now() < deadline) {
|
|
1192
|
+
for (const candidate of context.pages()) {
|
|
1193
|
+
if (options.existingPages.has(candidate)) {
|
|
1194
|
+
continue;
|
|
1195
|
+
}
|
|
1196
|
+
const url = candidate.url();
|
|
1197
|
+
if (!isInspectablePageUrl2(url)) {
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
fallbackPage ??= candidate;
|
|
1201
|
+
if (options.targetUrl === "about:blank") {
|
|
1202
|
+
return candidate;
|
|
1203
|
+
}
|
|
1204
|
+
if (pageLooselyMatchesUrl(url, options.targetUrl)) {
|
|
1205
|
+
return candidate;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
await sleep(100);
|
|
1209
|
+
}
|
|
1210
|
+
if (fallbackPage) {
|
|
1211
|
+
return fallbackPage;
|
|
1212
|
+
}
|
|
1213
|
+
throw new Error(
|
|
1214
|
+
`Chrome created a target for ${options.targetUrl}, but Playwright did not expose the page in time.`
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
function getPrimaryBrowserContext(browser) {
|
|
1218
|
+
const contexts = browser.contexts();
|
|
1219
|
+
if (contexts.length === 0) {
|
|
1220
|
+
throw new Error(
|
|
1221
|
+
"Connection succeeded but no browser contexts were exposed."
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
return contexts[0];
|
|
1225
|
+
}
|
|
1226
|
+
function isInspectablePageUrl2(url) {
|
|
1227
|
+
return url === "about:blank" || url.startsWith("http://") || url.startsWith("https://");
|
|
1228
|
+
}
|
|
1229
|
+
function isDisposableStartupPageUrl(url) {
|
|
1230
|
+
return url === "about:blank" || url === "chrome://newtab/" || url === "chrome://new-tab-page/";
|
|
1231
|
+
}
|
|
1232
|
+
function pageLooselyMatchesUrl(currentUrl, initialUrl) {
|
|
1233
|
+
try {
|
|
1234
|
+
const current = new URL(currentUrl);
|
|
1235
|
+
const requested = new URL(initialUrl);
|
|
1236
|
+
if (current.href === requested.href) {
|
|
1237
|
+
return true;
|
|
1238
|
+
}
|
|
1239
|
+
return current.hostname === requested.hostname && current.pathname === requested.pathname;
|
|
1240
|
+
} catch {
|
|
1241
|
+
return currentUrl === initialUrl;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
function normalizeDiscoveryUrl(cdpUrl) {
|
|
1245
|
+
let parsed;
|
|
1246
|
+
try {
|
|
1247
|
+
parsed = new URL(cdpUrl);
|
|
1248
|
+
} catch {
|
|
1249
|
+
throw new Error(
|
|
1250
|
+
`Invalid CDP URL "${cdpUrl}". Use an http(s) or ws(s) endpoint.`
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
if (parsed.protocol === "ws:" || parsed.protocol === "wss:") {
|
|
1254
|
+
return parsed;
|
|
1255
|
+
}
|
|
1256
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1257
|
+
throw new Error(
|
|
1258
|
+
`Unsupported CDP URL protocol "${parsed.protocol}". Use http(s) or ws(s).`
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
const normalized = new URL(parsed.toString());
|
|
1262
|
+
normalized.pathname = "/json/version";
|
|
1263
|
+
normalized.search = "";
|
|
1264
|
+
normalized.hash = "";
|
|
1265
|
+
return normalized;
|
|
1266
|
+
}
|
|
1267
|
+
async function resolveCdpWebSocketUrl(cdpUrl, timeoutMs) {
|
|
1268
|
+
if (cdpUrl.startsWith("ws://") || cdpUrl.startsWith("wss://")) {
|
|
1269
|
+
return cdpUrl;
|
|
1270
|
+
}
|
|
1271
|
+
const versionUrl = normalizeDiscoveryUrl(cdpUrl);
|
|
1272
|
+
const deadline = Date.now() + timeoutMs;
|
|
1273
|
+
let lastError = "CDP discovery did not respond.";
|
|
1274
|
+
while (Date.now() < deadline) {
|
|
1275
|
+
const remaining = Math.max(deadline - Date.now(), 1e3);
|
|
1276
|
+
try {
|
|
1277
|
+
const response = await fetch(versionUrl, {
|
|
1278
|
+
signal: AbortSignal.timeout(Math.min(remaining, 5e3))
|
|
1279
|
+
});
|
|
1280
|
+
if (!response.ok) {
|
|
1281
|
+
lastError = `${response.status} ${response.statusText}`;
|
|
1282
|
+
} else {
|
|
1283
|
+
const payload = await response.json();
|
|
1284
|
+
const wsUrl = payload && typeof payload === "object" && !Array.isArray(payload) && typeof payload.webSocketDebuggerUrl === "string" ? payload.webSocketDebuggerUrl : null;
|
|
1285
|
+
if (wsUrl && wsUrl.trim()) {
|
|
1286
|
+
return wsUrl;
|
|
1287
|
+
}
|
|
1288
|
+
lastError = "CDP discovery response did not include webSocketDebuggerUrl.";
|
|
1289
|
+
}
|
|
1290
|
+
} catch (error) {
|
|
1291
|
+
lastError = error instanceof Error ? error.message : "Unknown error";
|
|
1292
|
+
}
|
|
1293
|
+
await sleep(100);
|
|
1294
|
+
}
|
|
1295
|
+
throw new Error(
|
|
1296
|
+
`Failed to resolve a CDP websocket URL from ${versionUrl.toString()}: ${lastError}`
|
|
1297
|
+
);
|
|
1298
|
+
}
|
|
1299
|
+
async function reserveDebugPort() {
|
|
1300
|
+
return await new Promise((resolve, reject) => {
|
|
1301
|
+
const server = (0, import_node_net.createServer)();
|
|
1302
|
+
server.unref();
|
|
1303
|
+
server.on("error", reject);
|
|
1304
|
+
server.listen(0, "127.0.0.1", () => {
|
|
1305
|
+
const address = server.address();
|
|
1306
|
+
if (!address || typeof address === "string") {
|
|
1307
|
+
server.close();
|
|
1308
|
+
reject(new Error("Failed to reserve a local debug port."));
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
server.close((error) => {
|
|
1312
|
+
if (error) {
|
|
1313
|
+
reject(error);
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
resolve(address.port);
|
|
1317
|
+
});
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
async function cloneProfileToTempDir(userDataDir, profileDirectory) {
|
|
1322
|
+
const resolvedUserDataDir = expandHome(userDataDir);
|
|
1323
|
+
const tempUserDataDir = await (0, import_promises.mkdtemp)(
|
|
1324
|
+
(0, import_node_path.join)((0, import_node_os.tmpdir)(), "opensteer-real-browser-")
|
|
1325
|
+
);
|
|
1326
|
+
const sourceProfileDir = (0, import_node_path.join)(resolvedUserDataDir, profileDirectory);
|
|
1327
|
+
const targetProfileDir = (0, import_node_path.join)(tempUserDataDir, profileDirectory);
|
|
1328
|
+
if ((0, import_node_fs.existsSync)(sourceProfileDir)) {
|
|
1329
|
+
await (0, import_promises.cp)(sourceProfileDir, targetProfileDir, {
|
|
1330
|
+
recursive: true
|
|
1331
|
+
});
|
|
1332
|
+
} else {
|
|
1333
|
+
await (0, import_promises.mkdir)(targetProfileDir, {
|
|
1334
|
+
recursive: true
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
const localStatePath = (0, import_node_path.join)(resolvedUserDataDir, "Local State");
|
|
1338
|
+
if ((0, import_node_fs.existsSync)(localStatePath)) {
|
|
1339
|
+
await (0, import_promises.copyFile)(localStatePath, (0, import_node_path.join)(tempUserDataDir, "Local State"));
|
|
1340
|
+
}
|
|
1341
|
+
return tempUserDataDir;
|
|
1342
|
+
}
|
|
1343
|
+
function buildRealBrowserLaunchArgs(options) {
|
|
1344
|
+
const args = [
|
|
1345
|
+
`--user-data-dir=${options.userDataDir}`,
|
|
1346
|
+
`--profile-directory=${options.profileDirectory}`,
|
|
1347
|
+
`--remote-debugging-port=${options.debugPort}`,
|
|
1348
|
+
"--no-first-run",
|
|
1349
|
+
"--no-default-browser-check",
|
|
1350
|
+
"--disable-background-networking",
|
|
1351
|
+
"--disable-sync",
|
|
1352
|
+
"--disable-popup-blocking"
|
|
1353
|
+
];
|
|
1354
|
+
if (options.headless) {
|
|
1355
|
+
args.push("--headless=new");
|
|
1356
|
+
}
|
|
1357
|
+
return args;
|
|
1358
|
+
}
|
|
1359
|
+
async function killProcessTree(processHandle) {
|
|
1360
|
+
if (!processHandle || processHandle.pid == null || processHandle.exitCode !== null) {
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (process.platform === "win32") {
|
|
1364
|
+
await new Promise((resolve) => {
|
|
1365
|
+
const killer = (0, import_node_child_process.spawn)(
|
|
1366
|
+
"taskkill",
|
|
1367
|
+
["/pid", String(processHandle.pid), "/t", "/f"],
|
|
1368
|
+
{
|
|
1369
|
+
stdio: "ignore"
|
|
1370
|
+
}
|
|
1371
|
+
);
|
|
1372
|
+
killer.on("error", () => resolve());
|
|
1373
|
+
killer.on("exit", () => resolve());
|
|
1374
|
+
});
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
try {
|
|
1378
|
+
process.kill(-processHandle.pid, "SIGKILL");
|
|
1379
|
+
} catch {
|
|
1380
|
+
try {
|
|
1381
|
+
processHandle.kill("SIGKILL");
|
|
1382
|
+
} catch {
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
async function sleep(ms) {
|
|
1387
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1388
|
+
}
|
|
1071
1389
|
|
|
1072
1390
|
// src/config.ts
|
|
1073
|
-
var
|
|
1391
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
1074
1392
|
var import_path3 = __toESM(require("path"), 1);
|
|
1075
1393
|
var import_url = require("url");
|
|
1076
1394
|
var import_dotenv = require("dotenv");
|
|
@@ -1301,6 +1619,65 @@ function toJsonSafeValue(value, seen) {
|
|
|
1301
1619
|
return void 0;
|
|
1302
1620
|
}
|
|
1303
1621
|
|
|
1622
|
+
// src/cloud/credential-selection.ts
|
|
1623
|
+
function selectCloudCredential(options) {
|
|
1624
|
+
const apiKey = normalizeNonEmptyString(options.apiKey);
|
|
1625
|
+
const accessToken = normalizeNonEmptyString(options.accessToken);
|
|
1626
|
+
if (apiKey) {
|
|
1627
|
+
if (options.authScheme === "bearer") {
|
|
1628
|
+
return {
|
|
1629
|
+
apiKey,
|
|
1630
|
+
authScheme: "bearer",
|
|
1631
|
+
kind: "access-token",
|
|
1632
|
+
token: apiKey,
|
|
1633
|
+
compatibilityBearerApiKey: true
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
return {
|
|
1637
|
+
apiKey,
|
|
1638
|
+
authScheme: "api-key",
|
|
1639
|
+
kind: "api-key",
|
|
1640
|
+
token: apiKey
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
if (accessToken) {
|
|
1644
|
+
return {
|
|
1645
|
+
accessToken,
|
|
1646
|
+
authScheme: "bearer",
|
|
1647
|
+
kind: "access-token",
|
|
1648
|
+
token: accessToken
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
return null;
|
|
1652
|
+
}
|
|
1653
|
+
function selectCloudCredentialByPrecedence(layers, authScheme) {
|
|
1654
|
+
for (const layer of layers) {
|
|
1655
|
+
const hasApiKey = layer.hasApiKey ?? Object.prototype.hasOwnProperty.call(layer, "apiKey");
|
|
1656
|
+
const hasAccessToken = layer.hasAccessToken ?? Object.prototype.hasOwnProperty.call(layer, "accessToken");
|
|
1657
|
+
if (!hasApiKey && !hasAccessToken) {
|
|
1658
|
+
continue;
|
|
1659
|
+
}
|
|
1660
|
+
return {
|
|
1661
|
+
source: layer.source,
|
|
1662
|
+
apiKey: layer.apiKey,
|
|
1663
|
+
accessToken: layer.accessToken,
|
|
1664
|
+
hasApiKey,
|
|
1665
|
+
hasAccessToken,
|
|
1666
|
+
credential: selectCloudCredential({
|
|
1667
|
+
apiKey: layer.apiKey,
|
|
1668
|
+
accessToken: layer.accessToken,
|
|
1669
|
+
authScheme: layer.authScheme ?? authScheme
|
|
1670
|
+
})
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
return null;
|
|
1674
|
+
}
|
|
1675
|
+
function normalizeNonEmptyString(value) {
|
|
1676
|
+
if (typeof value !== "string") return void 0;
|
|
1677
|
+
const normalized = value.trim();
|
|
1678
|
+
return normalized.length ? normalized : void 0;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1304
1681
|
// src/storage/namespace.ts
|
|
1305
1682
|
var import_path2 = __toESM(require("path"), 1);
|
|
1306
1683
|
var DEFAULT_NAMESPACE = "default";
|
|
@@ -1339,9 +1716,10 @@ var DEFAULT_CONFIG = {
|
|
|
1339
1716
|
headless: false,
|
|
1340
1717
|
executablePath: void 0,
|
|
1341
1718
|
slowMo: 0,
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1719
|
+
mode: void 0,
|
|
1720
|
+
cdpUrl: void 0,
|
|
1721
|
+
userDataDir: void 0,
|
|
1722
|
+
profileDirectory: void 0
|
|
1345
1723
|
},
|
|
1346
1724
|
storage: {
|
|
1347
1725
|
rootDir: process.cwd()
|
|
@@ -1378,9 +1756,9 @@ function loadDotenvValues(rootDir, baseEnv, options = {}) {
|
|
|
1378
1756
|
const nodeEnv = baseEnv.NODE_ENV?.trim() || "";
|
|
1379
1757
|
for (const filename of dotenvFileOrder(nodeEnv)) {
|
|
1380
1758
|
const filePath = import_path3.default.join(baseDir, filename);
|
|
1381
|
-
if (!
|
|
1759
|
+
if (!import_fs2.default.existsSync(filePath)) continue;
|
|
1382
1760
|
try {
|
|
1383
|
-
const raw =
|
|
1761
|
+
const raw = import_fs2.default.readFileSync(filePath, "utf8");
|
|
1384
1762
|
const parsed = (0, import_dotenv.parse)(raw);
|
|
1385
1763
|
for (const [key, value] of Object.entries(parsed)) {
|
|
1386
1764
|
if (values[key] === void 0) {
|
|
@@ -1450,9 +1828,9 @@ function assertNoLegacyRuntimeConfig(source, config) {
|
|
|
1450
1828
|
}
|
|
1451
1829
|
function loadConfigFile(rootDir, options = {}) {
|
|
1452
1830
|
const configPath = import_path3.default.join(rootDir, ".opensteer", "config.json");
|
|
1453
|
-
if (!
|
|
1831
|
+
if (!import_fs2.default.existsSync(configPath)) return {};
|
|
1454
1832
|
try {
|
|
1455
|
-
const raw =
|
|
1833
|
+
const raw = import_fs2.default.readFileSync(configPath, "utf8");
|
|
1456
1834
|
return JSON.parse(raw);
|
|
1457
1835
|
} catch (error) {
|
|
1458
1836
|
const message = extractErrorMessage(
|
|
@@ -1625,11 +2003,6 @@ function normalizeCloudOptions(value) {
|
|
|
1625
2003
|
}
|
|
1626
2004
|
return value;
|
|
1627
2005
|
}
|
|
1628
|
-
function normalizeNonEmptyString(value) {
|
|
1629
|
-
if (typeof value !== "string") return void 0;
|
|
1630
|
-
const normalized = value.trim();
|
|
1631
|
-
return normalized.length ? normalized : void 0;
|
|
1632
|
-
}
|
|
1633
2006
|
function parseCloudEnabled(value, source) {
|
|
1634
2007
|
if (value == null) return void 0;
|
|
1635
2008
|
if (typeof value === "boolean") return value;
|
|
@@ -1638,6 +2011,18 @@ function parseCloudEnabled(value, source) {
|
|
|
1638
2011
|
`Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
|
|
1639
2012
|
);
|
|
1640
2013
|
}
|
|
2014
|
+
function resolveCloudCredentialFields(selectedLayer) {
|
|
2015
|
+
const credential = selectedLayer?.credential;
|
|
2016
|
+
if (!credential) return {};
|
|
2017
|
+
if (credential.kind === "api-key" || credential.compatibilityBearerApiKey === true && selectedLayer?.source !== "env") {
|
|
2018
|
+
return {
|
|
2019
|
+
apiKey: credential.token
|
|
2020
|
+
};
|
|
2021
|
+
}
|
|
2022
|
+
return {
|
|
2023
|
+
accessToken: credential.token
|
|
2024
|
+
};
|
|
2025
|
+
}
|
|
1641
2026
|
function resolveCloudSelection(config, env = process.env) {
|
|
1642
2027
|
const configCloud = parseCloudEnabled(config.cloud, "cloud");
|
|
1643
2028
|
if (configCloud !== void 0) {
|
|
@@ -1674,7 +2059,12 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1674
2059
|
});
|
|
1675
2060
|
assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
|
|
1676
2061
|
assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
|
|
2062
|
+
const fileCloudOptions = normalizeCloudOptions(fileConfig.cloud);
|
|
2063
|
+
const fileHasCloudApiKey = hasOwn(fileCloudOptions, "apiKey");
|
|
2064
|
+
const fileHasCloudAccessToken = hasOwn(fileCloudOptions, "accessToken");
|
|
1677
2065
|
const fileRootDir = typeof fileConfig.storage?.rootDir === "string" ? fileConfig.storage.rootDir : void 0;
|
|
2066
|
+
assertNoRemovedBrowserConfig(input.browser, "Opensteer constructor config");
|
|
2067
|
+
assertNoRemovedBrowserConfig(fileConfig.browser, ".opensteer/config.json");
|
|
1678
2068
|
const envRootDir = input.storage?.rootDir ?? fileRootDir ?? initialRootDir;
|
|
1679
2069
|
const env = resolveEnv(envRootDir, {
|
|
1680
2070
|
debug: debugHint,
|
|
@@ -1690,14 +2080,30 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1690
2080
|
"OPENSTEER_RUNTIME is no longer supported. Use OPENSTEER_MODE instead."
|
|
1691
2081
|
);
|
|
1692
2082
|
}
|
|
2083
|
+
if (env.OPENSTEER_CONNECT_URL != null) {
|
|
2084
|
+
throw new Error(
|
|
2085
|
+
"OPENSTEER_CONNECT_URL is no longer supported. Use OPENSTEER_CDP_URL instead."
|
|
2086
|
+
);
|
|
2087
|
+
}
|
|
2088
|
+
if (env.OPENSTEER_CHANNEL != null) {
|
|
2089
|
+
throw new Error(
|
|
2090
|
+
"OPENSTEER_CHANNEL is no longer supported. Use OPENSTEER_BROWSER plus OPENSTEER_BROWSER_PATH when needed."
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
if (env.OPENSTEER_PROFILE_DIR != null) {
|
|
2094
|
+
throw new Error(
|
|
2095
|
+
"OPENSTEER_PROFILE_DIR is no longer supported. Use OPENSTEER_USER_DATA_DIR and OPENSTEER_PROFILE_DIRECTORY instead."
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
1693
2098
|
const envConfig = {
|
|
1694
2099
|
browser: {
|
|
1695
2100
|
headless: parseBool(env.OPENSTEER_HEADLESS),
|
|
1696
2101
|
executablePath: env.OPENSTEER_BROWSER_PATH || void 0,
|
|
1697
2102
|
slowMo: parseNumber(env.OPENSTEER_SLOW_MO),
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
2103
|
+
mode: env.OPENSTEER_BROWSER === "real" || env.OPENSTEER_BROWSER === "chromium" ? env.OPENSTEER_BROWSER : void 0,
|
|
2104
|
+
cdpUrl: env.OPENSTEER_CDP_URL || void 0,
|
|
2105
|
+
userDataDir: env.OPENSTEER_USER_DATA_DIR || void 0,
|
|
2106
|
+
profileDirectory: env.OPENSTEER_PROFILE_DIRECTORY || void 0
|
|
1701
2107
|
},
|
|
1702
2108
|
cursor: {
|
|
1703
2109
|
enabled: parseBool(env.OPENSTEER_CURSOR)
|
|
@@ -1708,17 +2114,38 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1708
2114
|
const mergedWithFile = mergeDeep(runtimeDefaults, fileConfig);
|
|
1709
2115
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1710
2116
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
2117
|
+
const browserHeadlessExplicit = input.browser?.headless !== void 0 || fileConfig.browser?.headless !== void 0 || envConfig.browser?.headless !== void 0;
|
|
2118
|
+
if (!browserHeadlessExplicit && resolved.browser?.mode === "real") {
|
|
2119
|
+
resolved.browser = {
|
|
2120
|
+
...resolved.browser,
|
|
2121
|
+
headless: true
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
function assertNoRemovedBrowserConfig(value, source) {
|
|
2125
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2126
|
+
return;
|
|
2127
|
+
}
|
|
2128
|
+
const record = value;
|
|
2129
|
+
if (record.connectUrl !== void 0) {
|
|
2130
|
+
throw new Error(
|
|
2131
|
+
`${source}.browser.connectUrl is no longer supported. Use browser.cdpUrl instead.`
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
if (record.channel !== void 0) {
|
|
2135
|
+
throw new Error(
|
|
2136
|
+
`${source}.browser.channel is no longer supported. Use browser.mode plus browser.executablePath instead.`
|
|
2137
|
+
);
|
|
2138
|
+
}
|
|
2139
|
+
if (record.profileDir !== void 0) {
|
|
2140
|
+
throw new Error(
|
|
2141
|
+
`${source}.browser.profileDir is no longer supported. Use browser.userDataDir and browser.profileDirectory instead.`
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
1711
2145
|
const envApiKey = resolveOpensteerApiKey(env);
|
|
1712
2146
|
const envAccessTokenRaw = resolveOpensteerAccessToken(env);
|
|
1713
2147
|
const envBaseUrl = resolveOpensteerBaseUrl(env);
|
|
1714
2148
|
const envAuthScheme = resolveOpensteerAuthScheme(env);
|
|
1715
|
-
if (envApiKey && envAccessTokenRaw) {
|
|
1716
|
-
throw new Error(
|
|
1717
|
-
"OPENSTEER_API_KEY and OPENSTEER_ACCESS_TOKEN are mutually exclusive. Set only one."
|
|
1718
|
-
);
|
|
1719
|
-
}
|
|
1720
|
-
const envAccessToken = envAccessTokenRaw || (envAuthScheme === "bearer" ? envApiKey : void 0);
|
|
1721
|
-
const envApiCredential = envAuthScheme === "bearer" && !envAccessTokenRaw ? void 0 : envApiKey;
|
|
1722
2149
|
const envCloudProfileId = resolveOpensteerCloudProfileId(env);
|
|
1723
2150
|
const envCloudProfileReuseIfActive = resolveOpensteerCloudProfileReuseIfActive(env);
|
|
1724
2151
|
const envCloudAnnounce = parseCloudAnnounce(
|
|
@@ -1747,11 +2174,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1747
2174
|
const inputHasCloudBaseUrl = Boolean(
|
|
1748
2175
|
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "baseUrl")
|
|
1749
2176
|
);
|
|
1750
|
-
if (normalizeNonEmptyString(inputCloudOptions?.apiKey) && normalizeNonEmptyString(inputCloudOptions?.accessToken)) {
|
|
1751
|
-
throw new Error(
|
|
1752
|
-
"cloud.apiKey and cloud.accessToken are mutually exclusive. Set only one."
|
|
1753
|
-
);
|
|
1754
|
-
}
|
|
1755
2177
|
const cloudSelection = resolveCloudSelection({
|
|
1756
2178
|
cloud: resolved.cloud
|
|
1757
2179
|
}, env);
|
|
@@ -1762,11 +2184,6 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1762
2184
|
accessToken: resolvedCloudAccessTokenRaw,
|
|
1763
2185
|
...resolvedCloudRest
|
|
1764
2186
|
} = resolvedCloud;
|
|
1765
|
-
if (normalizeNonEmptyString(resolvedCloudApiKeyRaw) && normalizeNonEmptyString(resolvedCloudAccessTokenRaw)) {
|
|
1766
|
-
throw new Error(
|
|
1767
|
-
"Cloud config cannot include both apiKey and accessToken at the same time."
|
|
1768
|
-
);
|
|
1769
|
-
}
|
|
1770
2187
|
const resolvedCloudBrowserProfile = normalizeCloudBrowserProfileOptions(
|
|
1771
2188
|
resolvedCloud.browserProfile,
|
|
1772
2189
|
"resolved.cloud.browserProfile"
|
|
@@ -1778,25 +2195,40 @@ function resolveConfigWithEnv(input = {}, options = {}) {
|
|
|
1778
2195
|
const browserProfile = inputCloudBrowserProfile ?? envCloudBrowserProfile ?? resolvedCloudBrowserProfile;
|
|
1779
2196
|
let authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
|
|
1780
2197
|
const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
|
|
1781
|
-
const
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
2198
|
+
const selectedCredentialLayer = selectCloudCredentialByPrecedence(
|
|
2199
|
+
[
|
|
2200
|
+
{
|
|
2201
|
+
source: "input",
|
|
2202
|
+
apiKey: inputCloudOptions?.apiKey,
|
|
2203
|
+
accessToken: inputCloudOptions?.accessToken,
|
|
2204
|
+
hasApiKey: inputHasCloudApiKey,
|
|
2205
|
+
hasAccessToken: inputHasCloudAccessToken
|
|
2206
|
+
},
|
|
2207
|
+
{
|
|
2208
|
+
source: "env",
|
|
2209
|
+
apiKey: envApiKey,
|
|
2210
|
+
accessToken: envAccessTokenRaw,
|
|
2211
|
+
hasApiKey: envApiKey !== void 0,
|
|
2212
|
+
hasAccessToken: envAccessTokenRaw !== void 0
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
source: "file",
|
|
2216
|
+
apiKey: fileCloudOptions?.apiKey,
|
|
2217
|
+
accessToken: fileCloudOptions?.accessToken,
|
|
2218
|
+
hasApiKey: fileHasCloudApiKey,
|
|
2219
|
+
hasAccessToken: fileHasCloudAccessToken
|
|
2220
|
+
}
|
|
2221
|
+
],
|
|
2222
|
+
authScheme
|
|
2223
|
+
);
|
|
2224
|
+
const { apiKey, accessToken } = resolveCloudCredentialFields(selectedCredentialLayer);
|
|
1793
2225
|
if (accessToken) {
|
|
1794
2226
|
authScheme = "bearer";
|
|
1795
2227
|
}
|
|
1796
2228
|
resolved.cloud = {
|
|
1797
2229
|
...resolvedCloudRest,
|
|
1798
|
-
...
|
|
1799
|
-
...
|
|
2230
|
+
...apiKey ? { apiKey } : selectedCredentialLayer?.hasApiKey && !accessToken ? { apiKey: selectedCredentialLayer.apiKey } : {},
|
|
2231
|
+
...accessToken ? { accessToken } : selectedCredentialLayer?.hasAccessToken && !apiKey ? { accessToken: selectedCredentialLayer.accessToken } : {},
|
|
1800
2232
|
authScheme,
|
|
1801
2233
|
announce,
|
|
1802
2234
|
...browserProfile ? { browserProfile } : {}
|
|
@@ -2225,7 +2657,7 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
2225
2657
|
TRANSIENT_CONTEXT_RETRY_DELAY_MS,
|
|
2226
2658
|
Math.max(0, deadline - Date.now())
|
|
2227
2659
|
);
|
|
2228
|
-
await
|
|
2660
|
+
await sleep2(retryDelay);
|
|
2229
2661
|
}
|
|
2230
2662
|
}
|
|
2231
2663
|
}
|
|
@@ -2258,7 +2690,7 @@ var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
|
2258
2690
|
() => ({ kind: "resolved" }),
|
|
2259
2691
|
(error) => ({ kind: "rejected", error })
|
|
2260
2692
|
);
|
|
2261
|
-
const timeoutPromise =
|
|
2693
|
+
const timeoutPromise = sleep2(
|
|
2262
2694
|
timeout + FRAME_EVALUATE_GRACE_MS
|
|
2263
2695
|
).then(() => ({ kind: "timeout" }));
|
|
2264
2696
|
const result = await Promise.race([
|
|
@@ -2400,14 +2832,14 @@ function isIgnorableFrameError(error) {
|
|
|
2400
2832
|
const message = error.message;
|
|
2401
2833
|
return message.includes("Frame was detached") || message.includes("Target page, context or browser has been closed") || isTransientExecutionContextError(error) || message.includes("No frame for given id found");
|
|
2402
2834
|
}
|
|
2403
|
-
function
|
|
2835
|
+
function sleep2(ms) {
|
|
2404
2836
|
return new Promise((resolve) => {
|
|
2405
2837
|
setTimeout(resolve, ms);
|
|
2406
2838
|
});
|
|
2407
2839
|
}
|
|
2408
2840
|
|
|
2409
2841
|
// src/storage/local.ts
|
|
2410
|
-
var
|
|
2842
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
2411
2843
|
var import_path4 = __toESM(require("path"), 1);
|
|
2412
2844
|
|
|
2413
2845
|
// src/storage/registry.ts
|
|
@@ -2451,14 +2883,14 @@ var LocalSelectorStorage = class {
|
|
|
2451
2883
|
return import_path4.default.join(this.getNamespaceDir(), this.getSelectorFileName(id));
|
|
2452
2884
|
}
|
|
2453
2885
|
ensureDirs() {
|
|
2454
|
-
|
|
2886
|
+
import_fs3.default.mkdirSync(this.getNamespaceDir(), { recursive: true });
|
|
2455
2887
|
}
|
|
2456
2888
|
loadRegistry() {
|
|
2457
2889
|
this.ensureDirs();
|
|
2458
2890
|
const file = this.getRegistryPath();
|
|
2459
|
-
if (!
|
|
2891
|
+
if (!import_fs3.default.existsSync(file)) return createEmptyRegistry(this.namespace);
|
|
2460
2892
|
try {
|
|
2461
|
-
const raw =
|
|
2893
|
+
const raw = import_fs3.default.readFileSync(file, "utf8");
|
|
2462
2894
|
return JSON.parse(raw);
|
|
2463
2895
|
} catch (error) {
|
|
2464
2896
|
const message = extractErrorMessage(
|
|
@@ -2475,16 +2907,16 @@ var LocalSelectorStorage = class {
|
|
|
2475
2907
|
}
|
|
2476
2908
|
saveRegistry(registry) {
|
|
2477
2909
|
this.ensureDirs();
|
|
2478
|
-
|
|
2910
|
+
import_fs3.default.writeFileSync(
|
|
2479
2911
|
this.getRegistryPath(),
|
|
2480
2912
|
JSON.stringify(registry, null, 2)
|
|
2481
2913
|
);
|
|
2482
2914
|
}
|
|
2483
2915
|
readSelector(id) {
|
|
2484
2916
|
const file = this.getSelectorPath(id);
|
|
2485
|
-
if (!
|
|
2917
|
+
if (!import_fs3.default.existsSync(file)) return null;
|
|
2486
2918
|
try {
|
|
2487
|
-
const raw =
|
|
2919
|
+
const raw = import_fs3.default.readFileSync(file, "utf8");
|
|
2488
2920
|
return JSON.parse(raw);
|
|
2489
2921
|
} catch (error) {
|
|
2490
2922
|
const message = extractErrorMessage(
|
|
@@ -2501,15 +2933,15 @@ var LocalSelectorStorage = class {
|
|
|
2501
2933
|
}
|
|
2502
2934
|
writeSelector(payload) {
|
|
2503
2935
|
this.ensureDirs();
|
|
2504
|
-
|
|
2936
|
+
import_fs3.default.writeFileSync(
|
|
2505
2937
|
this.getSelectorPath(payload.id),
|
|
2506
2938
|
JSON.stringify(payload, null, 2)
|
|
2507
2939
|
);
|
|
2508
2940
|
}
|
|
2509
2941
|
clearNamespace() {
|
|
2510
2942
|
const dir = this.getNamespaceDir();
|
|
2511
|
-
if (!
|
|
2512
|
-
|
|
2943
|
+
if (!import_fs3.default.existsSync(dir)) return;
|
|
2944
|
+
import_fs3.default.rmSync(dir, { recursive: true, force: true });
|
|
2513
2945
|
}
|
|
2514
2946
|
};
|
|
2515
2947
|
|
|
@@ -6963,7 +7395,7 @@ var AdaptiveNetworkTracker = class {
|
|
|
6963
7395
|
this.idleSince = 0;
|
|
6964
7396
|
}
|
|
6965
7397
|
const remaining = Math.max(1, options.deadline - now);
|
|
6966
|
-
await
|
|
7398
|
+
await sleep3(Math.min(NETWORK_POLL_MS, remaining));
|
|
6967
7399
|
}
|
|
6968
7400
|
}
|
|
6969
7401
|
handleRequestStarted = (request) => {
|
|
@@ -7008,7 +7440,7 @@ var AdaptiveNetworkTracker = class {
|
|
|
7008
7440
|
return false;
|
|
7009
7441
|
}
|
|
7010
7442
|
};
|
|
7011
|
-
async function
|
|
7443
|
+
async function sleep3(ms) {
|
|
7012
7444
|
await new Promise((resolve) => {
|
|
7013
7445
|
setTimeout(resolve, ms);
|
|
7014
7446
|
});
|
|
@@ -8485,15 +8917,15 @@ function withTokenQuery(wsUrl, token) {
|
|
|
8485
8917
|
}
|
|
8486
8918
|
|
|
8487
8919
|
// src/cloud/local-cache-sync.ts
|
|
8488
|
-
var
|
|
8920
|
+
var import_fs4 = __toESM(require("fs"), 1);
|
|
8489
8921
|
var import_path5 = __toESM(require("path"), 1);
|
|
8490
8922
|
function collectLocalSelectorCacheEntries(storage, options = {}) {
|
|
8491
8923
|
const debug = options.debug === true;
|
|
8492
8924
|
const namespace = storage.getNamespace();
|
|
8493
8925
|
const namespaceDir = storage.getNamespaceDir();
|
|
8494
|
-
if (!
|
|
8926
|
+
if (!import_fs4.default.existsSync(namespaceDir)) return [];
|
|
8495
8927
|
const entries = [];
|
|
8496
|
-
const fileNames =
|
|
8928
|
+
const fileNames = import_fs4.default.readdirSync(namespaceDir);
|
|
8497
8929
|
for (const fileName of fileNames) {
|
|
8498
8930
|
if (fileName === "index.json" || !fileName.endsWith(".json")) continue;
|
|
8499
8931
|
const filePath = import_path5.default.join(namespaceDir, fileName);
|
|
@@ -8524,7 +8956,7 @@ function collectLocalSelectorCacheEntries(storage, options = {}) {
|
|
|
8524
8956
|
}
|
|
8525
8957
|
function readSelectorFile(filePath, debug) {
|
|
8526
8958
|
try {
|
|
8527
|
-
const raw =
|
|
8959
|
+
const raw = import_fs4.default.readFileSync(filePath, "utf8");
|
|
8528
8960
|
return JSON.parse(raw);
|
|
8529
8961
|
} catch (error) {
|
|
8530
8962
|
const message = extractErrorMessage(
|
|
@@ -8619,13 +9051,13 @@ function dedupeNewest(entries) {
|
|
|
8619
9051
|
}
|
|
8620
9052
|
|
|
8621
9053
|
// src/cloud/cdp-client.ts
|
|
8622
|
-
var
|
|
9054
|
+
var import_playwright2 = require("playwright");
|
|
8623
9055
|
var CloudCdpClient = class {
|
|
8624
9056
|
async connect(args) {
|
|
8625
9057
|
const endpoint = withTokenQuery2(args.wsUrl, args.token);
|
|
8626
9058
|
let browser;
|
|
8627
9059
|
try {
|
|
8628
|
-
browser = await
|
|
9060
|
+
browser = await import_playwright2.chromium.connectOverCDP(endpoint);
|
|
8629
9061
|
} catch (error) {
|
|
8630
9062
|
const message = error instanceof Error ? error.message : "Failed to connect to cloud CDP endpoint.";
|
|
8631
9063
|
throw new OpensteerCloudError("CLOUD_TRANSPORT_ERROR", message);
|
|
@@ -10418,7 +10850,7 @@ async function executeAgentAction(page, action) {
|
|
|
10418
10850
|
}
|
|
10419
10851
|
case "wait": {
|
|
10420
10852
|
const ms = numberOr(action.timeMs, action.time_ms, 1e3);
|
|
10421
|
-
await
|
|
10853
|
+
await sleep4(ms);
|
|
10422
10854
|
return;
|
|
10423
10855
|
}
|
|
10424
10856
|
case "goto": {
|
|
@@ -10583,7 +11015,7 @@ async function pressKeyCombo(page, combo) {
|
|
|
10583
11015
|
}
|
|
10584
11016
|
}
|
|
10585
11017
|
}
|
|
10586
|
-
function
|
|
11018
|
+
function sleep4(ms) {
|
|
10587
11019
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
10588
11020
|
}
|
|
10589
11021
|
|
|
@@ -10614,7 +11046,7 @@ var OpensteerCuaAgentHandler = class {
|
|
|
10614
11046
|
if (isMutatingAgentAction(action)) {
|
|
10615
11047
|
this.onMutatingAction?.(action);
|
|
10616
11048
|
}
|
|
10617
|
-
await
|
|
11049
|
+
await sleep5(this.config.waitBetweenActionsMs);
|
|
10618
11050
|
});
|
|
10619
11051
|
try {
|
|
10620
11052
|
const result = await this.client.execute({
|
|
@@ -10676,7 +11108,7 @@ var OpensteerCuaAgentHandler = class {
|
|
|
10676
11108
|
await this.cursorController.preview({ x, y }, "agent");
|
|
10677
11109
|
}
|
|
10678
11110
|
};
|
|
10679
|
-
function
|
|
11111
|
+
function sleep5(ms) {
|
|
10680
11112
|
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
10681
11113
|
}
|
|
10682
11114
|
|
|
@@ -11112,7 +11544,7 @@ var CursorController = class {
|
|
|
11112
11544
|
for (const step of motion.points) {
|
|
11113
11545
|
await this.renderer.move(step, this.style);
|
|
11114
11546
|
if (motion.stepDelayMs > 0) {
|
|
11115
|
-
await
|
|
11547
|
+
await sleep6(motion.stepDelayMs);
|
|
11116
11548
|
}
|
|
11117
11549
|
}
|
|
11118
11550
|
if (shouldPulse(intent)) {
|
|
@@ -11270,7 +11702,7 @@ function clamp2(value, min, max) {
|
|
|
11270
11702
|
function shouldPulse(intent) {
|
|
11271
11703
|
return intent === "click" || intent === "dblclick" || intent === "rightclick" || intent === "agent";
|
|
11272
11704
|
}
|
|
11273
|
-
function
|
|
11705
|
+
function sleep6(ms) {
|
|
11274
11706
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11275
11707
|
}
|
|
11276
11708
|
|
|
@@ -11321,30 +11753,20 @@ var Opensteer = class _Opensteer {
|
|
|
11321
11753
|
this.pool = new BrowserPool(resolved.browser || {});
|
|
11322
11754
|
if (cloudSelection.cloud) {
|
|
11323
11755
|
const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
|
|
11324
|
-
const
|
|
11325
|
-
|
|
11326
|
-
|
|
11327
|
-
|
|
11328
|
-
|
|
11329
|
-
);
|
|
11330
|
-
}
|
|
11331
|
-
let credential = "";
|
|
11332
|
-
let authScheme = cloudConfig?.authScheme ?? "api-key";
|
|
11333
|
-
if (accessToken) {
|
|
11334
|
-
credential = accessToken;
|
|
11335
|
-
authScheme = "bearer";
|
|
11336
|
-
} else if (apiKey) {
|
|
11337
|
-
credential = apiKey;
|
|
11338
|
-
}
|
|
11756
|
+
const credential = selectCloudCredential({
|
|
11757
|
+
apiKey: cloudConfig?.apiKey,
|
|
11758
|
+
accessToken: cloudConfig?.accessToken,
|
|
11759
|
+
authScheme: cloudConfig?.authScheme
|
|
11760
|
+
});
|
|
11339
11761
|
if (!credential) {
|
|
11340
11762
|
throw new Error(
|
|
11341
11763
|
"Cloud mode requires credentials via cloud.apiKey/cloud.accessToken or OPENSTEER_API_KEY/OPENSTEER_ACCESS_TOKEN."
|
|
11342
11764
|
);
|
|
11343
11765
|
}
|
|
11344
11766
|
this.cloud = createCloudRuntimeState(
|
|
11345
|
-
credential,
|
|
11767
|
+
credential.token,
|
|
11346
11768
|
cloudConfig?.baseUrl,
|
|
11347
|
-
authScheme
|
|
11769
|
+
credential.authScheme
|
|
11348
11770
|
);
|
|
11349
11771
|
} else {
|
|
11350
11772
|
this.cloud = null;
|
|
@@ -11665,9 +12087,11 @@ var Opensteer = class _Opensteer {
|
|
|
11665
12087
|
}
|
|
11666
12088
|
const session = await this.pool.launch({
|
|
11667
12089
|
...options,
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
|
|
12090
|
+
mode: options.mode ?? this.config.browser?.mode,
|
|
12091
|
+
cdpUrl: options.cdpUrl ?? this.config.browser?.cdpUrl,
|
|
12092
|
+
userDataDir: options.userDataDir ?? this.config.browser?.userDataDir,
|
|
12093
|
+
profileDirectory: options.profileDirectory ?? this.config.browser?.profileDirectory,
|
|
12094
|
+
executablePath: options.executablePath ?? this.config.browser?.executablePath
|
|
11671
12095
|
});
|
|
11672
12096
|
this.browser = session.browser;
|
|
11673
12097
|
this.contextRef = session.context;
|
|
@@ -11698,6 +12122,32 @@ var Opensteer = class _Opensteer {
|
|
|
11698
12122
|
instance.snapshotCache = null;
|
|
11699
12123
|
return instance;
|
|
11700
12124
|
}
|
|
12125
|
+
static listLocalProfiles(userDataDir) {
|
|
12126
|
+
return listLocalChromeProfiles(userDataDir);
|
|
12127
|
+
}
|
|
12128
|
+
static fromSystemChrome(browser = {}, config = {}) {
|
|
12129
|
+
const chromePaths = detectChromePaths();
|
|
12130
|
+
const executablePath = browser.executablePath ?? config.browser?.executablePath ?? chromePaths.executable ?? void 0;
|
|
12131
|
+
if (!executablePath) {
|
|
12132
|
+
throw new Error(
|
|
12133
|
+
"Chrome was not found. Pass executablePath explicitly or install Chrome in a supported location."
|
|
12134
|
+
);
|
|
12135
|
+
}
|
|
12136
|
+
const userDataDir = browser.userDataDir ?? config.browser?.userDataDir ?? chromePaths.defaultUserDataDir;
|
|
12137
|
+
const autoDetectedProfiles = listLocalChromeProfiles(userDataDir);
|
|
12138
|
+
const profileDirectory = browser.profileDirectory ?? config.browser?.profileDirectory ?? autoDetectedProfiles[0]?.directory ?? "Default";
|
|
12139
|
+
return new _Opensteer({
|
|
12140
|
+
...config,
|
|
12141
|
+
browser: {
|
|
12142
|
+
...config.browser || {},
|
|
12143
|
+
mode: "real",
|
|
12144
|
+
headless: browser.headless ?? config.browser?.headless ?? true,
|
|
12145
|
+
executablePath,
|
|
12146
|
+
userDataDir,
|
|
12147
|
+
profileDirectory
|
|
12148
|
+
}
|
|
12149
|
+
});
|
|
12150
|
+
}
|
|
11701
12151
|
async close() {
|
|
11702
12152
|
this.snapshotCache = null;
|
|
11703
12153
|
if (this.cloud) {
|
|
@@ -14188,7 +14638,7 @@ var CdpOverlayCursorRenderer = class {
|
|
|
14188
14638
|
outlineColor: toProtocolRgba(pulseOutline)
|
|
14189
14639
|
});
|
|
14190
14640
|
});
|
|
14191
|
-
await
|
|
14641
|
+
await sleep7(PULSE_DELAY_MS);
|
|
14192
14642
|
await this.move(point, style);
|
|
14193
14643
|
}
|
|
14194
14644
|
async clear() {
|
|
@@ -14312,7 +14762,7 @@ function clampAlpha(value) {
|
|
|
14312
14762
|
function roundPointValue(value) {
|
|
14313
14763
|
return Math.round(value * 100) / 100;
|
|
14314
14764
|
}
|
|
14315
|
-
function
|
|
14765
|
+
function sleep7(ms) {
|
|
14316
14766
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
14317
14767
|
}
|
|
14318
14768
|
// Annotate the CommonJS export names for ESM import in node:
|