opensteer 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { assertExecutionModeSupportsEngine, createOpensteerSemanticRuntime, OpensteerBrowserManager, dispatchSemanticOperation, resolveOpensteerEngineName, discoverLocalCdpBrowsers, inspectCdpEndpoint, resolveFilesystemWorkspacePath, hasPersistedCloudSession, resolveOpensteerExecutionMode } from '../chunk-2UMBR4XO.js';
2
+ import { assertExecutionModeSupportsEngine, createOpensteerSemanticRuntime, OpensteerBrowserManager, dispatchSemanticOperation, resolveOpensteerEngineName, discoverLocalCdpBrowsers, inspectCdpEndpoint, resolveFilesystemWorkspacePath, hasPersistedCloudSession, resolveOpensteerExecutionMode } from '../chunk-X3G6QSCF.js';
3
3
  import process2 from 'process';
4
4
  import { spawn } from 'child_process';
5
5
  import { existsSync } from 'fs';
package/dist/index.cjs CHANGED
@@ -11316,6 +11316,38 @@ async function clearChromeSingletonEntries(userDataDir) {
11316
11316
  )
11317
11317
  );
11318
11318
  }
11319
+ async function sanitizeChromeProfile(userDataDir) {
11320
+ if (!fs.existsSync(userDataDir)) {
11321
+ return;
11322
+ }
11323
+ const entries = await promises.readdir(userDataDir).catch(() => []);
11324
+ const profileDirs = entries.filter(
11325
+ (entry) => entry === "Default" || /^Profile \d+$/i.test(entry)
11326
+ );
11327
+ await Promise.all(profileDirs.map((dir) => sanitizeProfilePreferences(userDataDir, dir)));
11328
+ }
11329
+ async function sanitizeProfilePreferences(userDataDir, profileDir) {
11330
+ const prefsPath = path6.join(userDataDir, profileDir, "Preferences");
11331
+ if (!fs.existsSync(prefsPath)) {
11332
+ return;
11333
+ }
11334
+ try {
11335
+ const raw = await promises.readFile(prefsPath, "utf8");
11336
+ const prefs = JSON.parse(raw);
11337
+ const profile = prefs.profile ?? {};
11338
+ if (profile.exit_type === "Normal" && profile.exited_cleanly === true) {
11339
+ return;
11340
+ }
11341
+ profile.exit_type = "Normal";
11342
+ profile.exited_cleanly = true;
11343
+ prefs.profile = profile;
11344
+ await promises.writeFile(prefsPath, JSON.stringify(prefs), "utf8");
11345
+ await promises.rm(path6.join(userDataDir, profileDir, "Secure Preferences"), { force: true }).catch(
11346
+ () => void 0
11347
+ );
11348
+ } catch {
11349
+ }
11350
+ }
11319
11351
  var PROCESS_LIST_MAX_BUFFER_BYTES2 = 16 * 1024 * 1024;
11320
11352
  var PS_COMMAND_ENV2 = { ...process.env, LC_ALL: "C" };
11321
11353
  var WINDOWS_PROGRAM_FILES = process.env.PROGRAMFILES ?? "C:\\Program Files";
@@ -12145,6 +12177,7 @@ async function createBrowserProfileSnapshot(input) {
12145
12177
  ...profileDirectory === void 0 ? {} : { selectedProfileDirectory: profileDirectory }
12146
12178
  });
12147
12179
  await clearChromeSingletonEntries(targetUserDataDir);
12180
+ await sanitizeChromeProfile(targetUserDataDir);
12148
12181
  }
12149
12182
  async function copyRootLevelEntries(input) {
12150
12183
  const entries = await promises.readdir(input.sourceUserDataDir).catch(() => []);
@@ -12208,68 +12241,88 @@ function generateStealthInitScript(profile) {
12208
12241
  const encodedProfile = JSON.stringify(profile);
12209
12242
  return `(() => {
12210
12243
  const profile = ${encodedProfile};
12211
- const define = (target, key, value) => {
12212
- Object.defineProperty(target, key, {
12244
+
12245
+ // --- navigator.webdriver safety net ---
12246
+ // --disable-blink-features=AutomationControlled handles this at the flag level
12247
+ // and CDP handles it at the protocol level, but some Chrome builds still leak
12248
+ // webdriver=true when --remote-debugging-port is active.
12249
+ if (navigator.webdriver === true) {
12250
+ Object.defineProperty(Navigator.prototype, 'webdriver', {
12213
12251
  configurable: true,
12214
- get: typeof value === "function" ? value : () => value,
12252
+ get: function() { return false; },
12215
12253
  });
12216
- };
12217
- define(Navigator.prototype, 'webdriver', false);
12218
- define(Navigator.prototype, 'platform', profile.platform === 'macos' ? 'MacIntel' : profile.platform === 'windows' ? 'Win32' : 'Linux x86_64');
12219
- define(Navigator.prototype, 'userAgent', profile.userAgent);
12220
- define(Navigator.prototype, 'language', profile.locale);
12221
- define(Navigator.prototype, 'languages', [profile.locale, 'en']);
12222
- define(Navigator.prototype, 'maxTouchPoints', profile.maxTouchPoints);
12223
- define(window, 'devicePixelRatio', profile.devicePixelRatio);
12224
- define(window.screen, 'width', profile.screenResolution.width);
12225
- define(window.screen, 'height', profile.screenResolution.height);
12226
- define(window.screen, 'availWidth', profile.screenResolution.width);
12227
- define(window.screen, 'availHeight', profile.screenResolution.height - 40);
12228
- if (document.fonts && typeof document.fonts.check === 'function') {
12229
- const originalCheck = document.fonts.check.bind(document.fonts);
12230
- document.fonts.check = function(font, text) {
12231
- const family = String(font).match(/["']([^"']+)["']/)?.[1] || String(font).split(/s+/).at(-1);
12232
- if (family && profile.fonts.includes(family)) {
12233
- return true;
12234
- }
12235
- return originalCheck(font, text);
12236
- };
12237
12254
  }
12238
- const seedNoise = (seed, input) => {
12239
- const value = Math.sin(seed + input * 12.9898) * 43758.5453;
12255
+
12256
+ // --- CDP Runtime.enable leak defense ---
12257
+ var _wrap = function(name) {
12258
+ var orig = console[name];
12259
+ if (typeof orig !== 'function') return;
12260
+ console[name] = new Proxy(orig, {
12261
+ apply: function(target, thisArg, args) {
12262
+ for (var i = 0; i < args.length; i++) {
12263
+ if (args[i] instanceof Error) {
12264
+ var d = Object.getOwnPropertyDescriptor(args[i], 'stack');
12265
+ if (d && typeof d.get === 'function') return undefined;
12266
+ }
12267
+ }
12268
+ return Reflect.apply(target, thisArg, args);
12269
+ },
12270
+ });
12271
+ };
12272
+ ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12273
+
12274
+ // --- Canvas fingerprint noise ---
12275
+ var seedNoise = function(seed, input) {
12276
+ var value = Math.sin(seed + input * 12.9898) * 43758.5453;
12240
12277
  return value - Math.floor(value);
12241
12278
  };
12242
12279
  if (HTMLCanvasElement.prototype.toDataURL) {
12243
- const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
12244
- HTMLCanvasElement.prototype.toDataURL = function(...args) {
12245
- const context = this.getContext('2d');
12280
+ var originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
12281
+ HTMLCanvasElement.prototype.toDataURL = function() {
12282
+ var context = this.getContext('2d');
12246
12283
  if (context) {
12247
- const x = Math.min(1, Math.max(0, this.width - 1));
12248
- const y = Math.min(1, Math.max(0, this.height - 1));
12249
- const imageData = context.getImageData(x, y, 1, 1);
12284
+ var x = Math.min(1, Math.max(0, this.width - 1));
12285
+ var y = Math.min(1, Math.max(0, this.height - 1));
12286
+ var imageData = context.getImageData(x, y, 1, 1);
12250
12287
  imageData.data[0] = Math.max(0, Math.min(255, imageData.data[0] + Math.floor(seedNoise(profile.canvasNoiseSeed, 1) * 2)));
12251
12288
  context.putImageData(imageData, x, y);
12252
12289
  }
12253
- return originalToDataURL.apply(this, args);
12290
+ return originalToDataURL.apply(this, arguments);
12254
12291
  };
12255
12292
  }
12293
+
12294
+ // --- WebGL vendor/renderer spoofing ---
12256
12295
  if (typeof WebGLRenderingContext !== 'undefined') {
12257
- const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
12296
+ var originalGetParameter = WebGLRenderingContext.prototype.getParameter;
12258
12297
  WebGLRenderingContext.prototype.getParameter = function(parameter) {
12259
12298
  if (parameter === 37445) return profile.webglVendor;
12260
12299
  if (parameter === 37446) return profile.webglRenderer;
12261
12300
  return originalGetParameter.call(this, parameter);
12262
12301
  };
12263
12302
  }
12303
+
12304
+ // --- AudioBuffer fingerprint noise ---
12264
12305
  if (typeof AudioBuffer !== 'undefined' && typeof AnalyserNode !== 'undefined') {
12265
- const originalGetFloatFrequencyData = AnalyserNode.prototype.getFloatFrequencyData;
12306
+ var originalGetFloatFrequencyData = AnalyserNode.prototype.getFloatFrequencyData;
12266
12307
  AnalyserNode.prototype.getFloatFrequencyData = function(array) {
12267
12308
  originalGetFloatFrequencyData.call(this, array);
12268
- for (let index = 0; index < array.length; index += 16) {
12309
+ for (var index = 0; index < array.length; index += 16) {
12269
12310
  array[index] += (seedNoise(profile.audioNoiseSeed, index) - 0.5) * 0.0001;
12270
12311
  }
12271
12312
  };
12272
12313
  }
12314
+
12315
+ // --- Font availability spoofing ---
12316
+ if (document.fonts && typeof document.fonts.check === 'function') {
12317
+ var originalCheck = document.fonts.check.bind(document.fonts);
12318
+ document.fonts.check = function(font, text) {
12319
+ var family = String(font).match(/["']([^"']+)["']/)?.[1] || String(font).split(/\\s+/).at(-1);
12320
+ if (family && profile.fonts.includes(family)) {
12321
+ return true;
12322
+ }
12323
+ return originalCheck(font, text);
12324
+ };
12325
+ }
12273
12326
  })();`;
12274
12327
  }
12275
12328
 
@@ -12315,25 +12368,95 @@ var STEALTH_INIT_SCRIPT = `(() => {
12315
12368
  ['debug', 'log', 'info', 'error', 'warn', 'trace', 'dir'].forEach(_wrap);
12316
12369
  })();`;
12317
12370
  async function injectBrowserStealthScripts(context, input = {}) {
12371
+ if (input.profile !== void 0 && input.page !== void 0) {
12372
+ await applyCdpStealthOverrides(context, input.page, input.profile);
12373
+ }
12318
12374
  if (typeof context.addInitScript === "function") {
12319
12375
  await context.addInitScript({
12320
12376
  content: input.profile === void 0 ? STEALTH_INIT_SCRIPT : generateStealthInitScript(input.profile)
12321
12377
  });
12322
12378
  }
12323
12379
  }
12380
+ function buildUserAgentMetadata(profile) {
12381
+ const majorVersion = profile.browserVersion.split(".")[0] ?? "136";
12382
+ const brands = [
12383
+ { brand: "Chromium", version: majorVersion },
12384
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: majorVersion }] : [{ brand: "Google Chrome", version: majorVersion }],
12385
+ { brand: "Not-A.Brand", version: "99" }
12386
+ ];
12387
+ const fullVersionList = [
12388
+ { brand: "Chromium", version: profile.browserVersion },
12389
+ ...profile.browserBrand === "edge" ? [{ brand: "Microsoft Edge", version: profile.browserVersion }] : [{ brand: "Google Chrome", version: profile.browserVersion }],
12390
+ { brand: "Not-A.Brand", version: "99.0.0.0" }
12391
+ ];
12392
+ const platformMap = {
12393
+ macos: { platform: "macOS", platformVersion: "14.4.0", architecture: "arm" },
12394
+ windows: { platform: "Windows", platformVersion: "15.0.0", architecture: "x86" },
12395
+ linux: { platform: "Linux", platformVersion: "6.5.0", architecture: "x86" }
12396
+ };
12397
+ const platformInfo = platformMap[profile.platform] ?? platformMap.linux;
12398
+ return {
12399
+ brands,
12400
+ fullVersionList,
12401
+ platform: platformInfo.platform,
12402
+ platformVersion: platformInfo.platformVersion,
12403
+ architecture: platformInfo.architecture,
12404
+ model: "",
12405
+ mobile: false,
12406
+ bitness: "64",
12407
+ wow64: false
12408
+ };
12409
+ }
12410
+ async function applyCdpStealthOverrides(context, page, profile) {
12411
+ const contextWithCdp = context;
12412
+ if (typeof contextWithCdp.newCDPSession !== "function") {
12413
+ return;
12414
+ }
12415
+ let cdp;
12416
+ try {
12417
+ cdp = await contextWithCdp.newCDPSession(page);
12418
+ } catch {
12419
+ return;
12420
+ }
12421
+ try {
12422
+ const platformString = profile.platform === "macos" ? "MacIntel" : profile.platform === "windows" ? "Win32" : "Linux x86_64";
12423
+ await cdp.send("Network.setUserAgentOverride", {
12424
+ userAgent: profile.userAgent,
12425
+ acceptLanguage: `${profile.locale},en;q=0.9`,
12426
+ platform: platformString,
12427
+ userAgentMetadata: buildUserAgentMetadata(profile)
12428
+ });
12429
+ await cdp.send("Emulation.setDeviceMetricsOverride", {
12430
+ width: profile.viewport.width,
12431
+ height: profile.viewport.height,
12432
+ deviceScaleFactor: profile.devicePixelRatio,
12433
+ mobile: false,
12434
+ screenWidth: profile.screenResolution.width,
12435
+ screenHeight: profile.screenResolution.height
12436
+ });
12437
+ await cdp.send("Emulation.setLocaleOverride", {
12438
+ locale: profile.locale
12439
+ }).catch(() => void 0);
12440
+ await cdp.send("Emulation.setTimezoneOverride", {
12441
+ timezoneId: profile.timezoneId
12442
+ }).catch(() => void 0);
12443
+ await cdp.detach();
12444
+ } catch {
12445
+ }
12446
+ }
12324
12447
 
12325
12448
  // src/local-browser/stealth-profiles.ts
12326
12449
  var PROFILE_PRESETS = [
12327
12450
  {
12328
12451
  platform: "macos",
12329
12452
  browserBrand: "chrome",
12330
- browserVersion: "133.0.6943.99",
12331
- userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.99 Safari/537.36",
12453
+ browserVersion: "136.0.7103.93",
12454
+ userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
12332
12455
  viewport: { width: 1440, height: 900 },
12333
12456
  screenResolution: { width: 1512, height: 982 },
12334
12457
  devicePixelRatio: 2,
12335
12458
  maxTouchPoints: 0,
12336
- webglVendor: "Apple Inc.",
12459
+ webglVendor: "Apple",
12337
12460
  webglRenderer: "Apple M2",
12338
12461
  fonts: ["SF Pro Text", "Helvetica Neue", "Arial", "Menlo", "Apple Color Emoji"],
12339
12462
  locale: "en-US",
@@ -12342,8 +12465,8 @@ var PROFILE_PRESETS = [
12342
12465
  {
12343
12466
  platform: "windows",
12344
12467
  browserBrand: "chrome",
12345
- browserVersion: "133.0.6943.99",
12346
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.99 Safari/537.36",
12468
+ browserVersion: "136.0.7103.93",
12469
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
12347
12470
  viewport: { width: 1536, height: 864 },
12348
12471
  screenResolution: { width: 1920, height: 1080 },
12349
12472
  devicePixelRatio: 1.25,
@@ -12357,8 +12480,8 @@ var PROFILE_PRESETS = [
12357
12480
  {
12358
12481
  platform: "windows",
12359
12482
  browserBrand: "edge",
12360
- browserVersion: "133.0.3065.82",
12361
- userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.3065.82",
12483
+ browserVersion: "136.0.3240.50",
12484
+ userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.3240.50",
12362
12485
  viewport: { width: 1536, height: 864 },
12363
12486
  screenResolution: { width: 1920, height: 1080 },
12364
12487
  devicePixelRatio: 1.25,
@@ -12372,8 +12495,8 @@ var PROFILE_PRESETS = [
12372
12495
  {
12373
12496
  platform: "linux",
12374
12497
  browserBrand: "chrome",
12375
- browserVersion: "133.0.6943.99",
12376
- userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.6943.99 Safari/537.36",
12498
+ browserVersion: "136.0.7103.93",
12499
+ userAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36",
12377
12500
  viewport: { width: 1366, height: 768 },
12378
12501
  screenResolution: { width: 1366, height: 768 },
12379
12502
  devicePixelRatio: 1,
@@ -12733,7 +12856,8 @@ var OpensteerBrowserManager = class {
12733
12856
  await clearChromeSingletonEntries(userDataDir);
12734
12857
  const launched = await launchOwnedBrowser({
12735
12858
  userDataDir,
12736
- ...this.launchOptions === void 0 ? {} : { launch: this.launchOptions }
12859
+ ...this.launchOptions === void 0 ? {} : { launch: this.launchOptions },
12860
+ ...this.contextOptions?.viewport === void 0 ? {} : { viewport: this.contextOptions.viewport }
12737
12861
  });
12738
12862
  try {
12739
12863
  return await this.createAttachedEngine({
@@ -12781,7 +12905,8 @@ var OpensteerBrowserManager = class {
12781
12905
  await this.ensurePersistentBrowserManifest(workspace);
12782
12906
  const launched = await launchOwnedBrowser({
12783
12907
  userDataDir: workspace.browserUserDataDir,
12784
- ...this.launchOptions === void 0 ? {} : { launch: this.launchOptions }
12908
+ ...this.launchOptions === void 0 ? {} : { launch: this.launchOptions },
12909
+ ...this.contextOptions?.viewport === void 0 ? {} : { viewport: this.contextOptions.viewport }
12785
12910
  });
12786
12911
  const liveRecord = {
12787
12912
  mode: "persistent",
@@ -12816,13 +12941,13 @@ var OpensteerBrowserManager = class {
12816
12941
  if (!context) {
12817
12942
  throw new Error("Connected browser did not expose a Chromium browser context.");
12818
12943
  }
12944
+ const page = input.freshTab || context.pages()[0] === void 0 ? await context.newPage() : context.pages()[0];
12945
+ await page.bringToFront?.();
12819
12946
  const stealthProfile = resolveStealthProfile(this.contextOptions?.stealthProfile);
12820
12947
  await injectBrowserStealthScripts(
12821
12948
  context,
12822
- stealthProfile === void 0 ? {} : { profile: stealthProfile }
12949
+ stealthProfile === void 0 ? {} : { profile: stealthProfile, page }
12823
12950
  );
12824
- const page = input.freshTab || context.pages()[0] === void 0 ? await context.newPage() : context.pages()[0];
12825
- await page.bringToFront?.();
12826
12951
  const engine = await enginePlaywright.createPlaywrightBrowserCoreEngine({
12827
12952
  browser,
12828
12953
  attachedContext: context,
@@ -13008,8 +13133,9 @@ async function resolveAttachEndpoint(browser) {
13008
13133
  async function launchOwnedBrowser(input) {
13009
13134
  await ensureDirectory(input.userDataDir);
13010
13135
  await clearChromeSingletonEntries(input.userDataDir);
13136
+ await sanitizeChromeProfile(input.userDataDir);
13011
13137
  const executablePath = resolveChromeExecutablePath(input.launch?.executablePath);
13012
- const args = buildChromeArgs(input.userDataDir, input.launch);
13138
+ const args = buildChromeArgs(input.userDataDir, input.launch, input.viewport);
13013
13139
  const child = child_process.spawn(executablePath, args, {
13014
13140
  stdio: ["ignore", "ignore", "pipe"],
13015
13141
  detached: process.platform !== "win32"
@@ -13036,7 +13162,8 @@ async function launchOwnedBrowser(input) {
13036
13162
  executablePath
13037
13163
  };
13038
13164
  }
13039
- function buildChromeArgs(userDataDir, launch) {
13165
+ function buildChromeArgs(userDataDir, launch, viewport) {
13166
+ const isHeadless = launch?.headless ?? true;
13040
13167
  const args = [
13041
13168
  "--remote-debugging-port=0",
13042
13169
  "--no-first-run",
@@ -13050,17 +13177,25 @@ function buildChromeArgs(userDataDir, launch) {
13050
13177
  "--disable-popup-blocking",
13051
13178
  "--disable-prompt-on-repost",
13052
13179
  "--disable-sync",
13180
+ "--disable-infobars",
13053
13181
  "--disable-features=Translate",
13054
13182
  "--enable-features=NetworkService,NetworkServiceInProcess",
13055
13183
  "--password-store=basic",
13056
13184
  "--use-mock-keychain",
13057
13185
  `--user-data-dir=${userDataDir}`
13058
13186
  ];
13059
- if (launch?.headless ?? true) {
13187
+ if (isHeadless) {
13060
13188
  args.push("--headless=new");
13061
- if (!(launch?.args ?? []).some((entry) => entry.startsWith("--window-size"))) {
13062
- args.push("--window-size=1280,800");
13063
- }
13189
+ }
13190
+ const hasUserWindowSize = (launch?.args ?? []).some(
13191
+ (entry) => entry.startsWith("--window-size")
13192
+ );
13193
+ if (!hasUserWindowSize) {
13194
+ const width = viewport?.width ?? 1440;
13195
+ const height = viewport?.height ?? 900;
13196
+ args.push(
13197
+ isHeadless ? `--window-size=${String(width)},${String(height)}` : `--window-size=${String(width)},${String(height + 150)}`
13198
+ );
13064
13199
  }
13065
13200
  args.push(...launch?.args ?? []);
13066
13201
  return args;
@@ -16918,8 +17053,8 @@ async function isExecutable(candidate) {
16918
17053
  }
16919
17054
  async function readDirSafe(directory) {
16920
17055
  try {
16921
- const { readdir: readdir3 } = await import('fs/promises');
16922
- return await readdir3(directory);
17056
+ const { readdir: readdir4 } = await import('fs/promises');
17057
+ return await readdir4(directory);
16923
17058
  } catch {
16924
17059
  return [];
16925
17060
  }