browser-use 0.6.0 → 0.7.0

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.
Files changed (85) hide show
  1. package/README.md +29 -18
  2. package/dist/actor/element.js +24 -3
  3. package/dist/actor/mouse.js +21 -3
  4. package/dist/actor/page.js +33 -11
  5. package/dist/agent/gif.js +28 -3
  6. package/dist/agent/message-manager/service.js +2 -22
  7. package/dist/agent/message-manager/utils.js +15 -2
  8. package/dist/agent/message-manager/views.d.ts +7 -7
  9. package/dist/agent/message-manager/views.js +1 -0
  10. package/dist/agent/prompts.d.ts +3 -0
  11. package/dist/agent/prompts.js +22 -12
  12. package/dist/agent/service.d.ts +9 -1
  13. package/dist/agent/service.js +215 -81
  14. package/dist/agent/system_prompt.md +12 -11
  15. package/dist/agent/system_prompt_anthropic_flash.md +6 -5
  16. package/dist/agent/system_prompt_no_thinking.md +12 -11
  17. package/dist/agent/views.d.ts +2 -0
  18. package/dist/agent/views.js +48 -36
  19. package/dist/browser/extensions.js +20 -10
  20. package/dist/browser/profile.d.ts +4 -0
  21. package/dist/browser/profile.js +107 -4
  22. package/dist/browser/session.d.ts +28 -1
  23. package/dist/browser/session.js +1436 -528
  24. package/dist/browser/watchdogs/default-action-watchdog.js +32 -3
  25. package/dist/browser/watchdogs/downloads-watchdog.d.ts +4 -0
  26. package/dist/browser/watchdogs/downloads-watchdog.js +105 -9
  27. package/dist/browser/watchdogs/har-recording-watchdog.d.ts +1 -0
  28. package/dist/browser/watchdogs/har-recording-watchdog.js +54 -2
  29. package/dist/browser/watchdogs/permissions-watchdog.d.ts +5 -0
  30. package/dist/browser/watchdogs/permissions-watchdog.js +106 -3
  31. package/dist/browser/watchdogs/recording-watchdog.d.ts +2 -0
  32. package/dist/browser/watchdogs/recording-watchdog.js +54 -2
  33. package/dist/browser/watchdogs/security-watchdog.d.ts +1 -0
  34. package/dist/browser/watchdogs/security-watchdog.js +47 -7
  35. package/dist/browser/watchdogs/storage-state-watchdog.d.ts +6 -0
  36. package/dist/browser/watchdogs/storage-state-watchdog.js +206 -14
  37. package/dist/cli.d.ts +13 -2
  38. package/dist/cli.js +188 -8
  39. package/dist/code-use/namespace.js +52 -7
  40. package/dist/code-use/notebook-export.js +18 -2
  41. package/dist/code-use/service.js +1 -0
  42. package/dist/config.js +27 -5
  43. package/dist/controller/action-timeout.d.ts +9 -0
  44. package/dist/controller/action-timeout.js +95 -0
  45. package/dist/controller/registry/service.d.ts +1 -0
  46. package/dist/controller/registry/service.js +28 -1
  47. package/dist/controller/registry/views.d.ts +2 -0
  48. package/dist/controller/registry/views.js +44 -17
  49. package/dist/controller/service.d.ts +2 -1
  50. package/dist/controller/service.js +494 -329
  51. package/dist/filesystem/file-system.js +38 -8
  52. package/dist/integrations/gmail/service.js +30 -6
  53. package/dist/llm/browser-use/chat.js +2 -2
  54. package/dist/llm/codex/auth.d.ts +118 -0
  55. package/dist/llm/codex/auth.js +599 -0
  56. package/dist/llm/codex/chat.d.ts +70 -0
  57. package/dist/llm/codex/chat.js +392 -0
  58. package/dist/llm/codex/index.d.ts +2 -0
  59. package/dist/llm/codex/index.js +2 -0
  60. package/dist/llm/google/chat.js +18 -1
  61. package/dist/logging-config.js +22 -11
  62. package/dist/mcp/client.d.ts +1 -0
  63. package/dist/mcp/client.js +12 -10
  64. package/dist/mcp/redaction.d.ts +3 -0
  65. package/dist/mcp/redaction.js +132 -0
  66. package/dist/mcp/server.d.ts +2 -0
  67. package/dist/mcp/server.js +64 -22
  68. package/dist/observability.js +1 -1
  69. package/dist/screenshots/service.js +25 -2
  70. package/dist/skill-cli/direct.d.ts +4 -1
  71. package/dist/skill-cli/direct.js +260 -64
  72. package/dist/skill-cli/server.d.ts +1 -0
  73. package/dist/skill-cli/server.js +115 -25
  74. package/dist/skill-cli/tunnel.d.ts +1 -0
  75. package/dist/skill-cli/tunnel.js +16 -4
  76. package/dist/sync/auth.js +22 -9
  77. package/dist/telemetry/service.js +21 -2
  78. package/dist/telemetry/views.js +31 -8
  79. package/dist/tokens/custom-pricing.js +2 -2
  80. package/dist/tokens/openrouter-pricing.d.ts +11 -0
  81. package/dist/tokens/openrouter-pricing.js +102 -0
  82. package/dist/tokens/service.js +20 -16
  83. package/dist/utils.d.ts +3 -1
  84. package/dist/utils.js +4 -2
  85. package/package.json +75 -33
@@ -6,6 +6,33 @@ import PDFDocument from 'pdfkit';
6
6
  import { createRequire } from 'node:module';
7
7
  import { spawnSync } from 'node:child_process';
8
8
  const require = createRequire(import.meta.url);
9
+ const chmodPrivatePath = (targetPath, mode) => {
10
+ if (process.platform !== 'win32') {
11
+ fsSync.chmodSync(targetPath, mode);
12
+ }
13
+ };
14
+ const writePrivateTextFile = (filePath, content) => {
15
+ fsSync.writeFileSync(filePath, content, {
16
+ encoding: 'utf-8',
17
+ mode: 0o600,
18
+ });
19
+ chmodPrivatePath(filePath, 0o600);
20
+ };
21
+ const writePrivateBufferFile = (filePath, content) => {
22
+ fsSync.writeFileSync(filePath, content, { mode: 0o600 });
23
+ chmodPrivatePath(filePath, 0o600);
24
+ };
25
+ const writePrivateTextFileAsync = async (filePath, content) => {
26
+ await fsp.writeFile(filePath, content, {
27
+ encoding: 'utf-8',
28
+ mode: 0o600,
29
+ });
30
+ chmodPrivatePath(filePath, 0o600);
31
+ };
32
+ const writePrivateBufferFileAsync = async (filePath, content) => {
33
+ await fsp.writeFile(filePath, content, { mode: 0o600 });
34
+ chmodPrivatePath(filePath, 0o600);
35
+ };
9
36
  export async function extractPdfText(buffer) {
10
37
  const pdfParseModule = (await import('pdf-parse'));
11
38
  if (typeof pdfParseModule.default === 'function') {
@@ -256,10 +283,10 @@ class BaseFile {
256
283
  return this.content;
257
284
  }
258
285
  async syncToDisk(dir) {
259
- await fsp.writeFile(path.join(dir, this.fullName), this.content, 'utf-8');
286
+ await writePrivateTextFileAsync(path.join(dir, this.fullName), this.content);
260
287
  }
261
288
  syncToDiskSync(dir) {
262
- fsSync.writeFileSync(path.join(dir, this.fullName), this.content, 'utf-8');
289
+ writePrivateTextFile(path.join(dir, this.fullName), this.content);
263
290
  }
264
291
  async write(content, dir) {
265
292
  this.writeFileContent(content);
@@ -314,13 +341,14 @@ class PdfFile extends BaseFile {
314
341
  const filePath = path.join(dir, this.fullName);
315
342
  await new Promise((resolve, reject) => {
316
343
  const doc = new PDFDocument({ autoFirstPage: true });
317
- const stream = fsSync.createWriteStream(filePath);
344
+ const stream = fsSync.createWriteStream(filePath, { mode: 0o600 });
318
345
  doc.pipe(stream);
319
346
  doc.fontSize(12).text(this.content || '', { width: 500, align: 'left' });
320
347
  doc.end();
321
348
  stream.on('finish', resolve);
322
349
  stream.on('error', reject);
323
350
  });
351
+ chmodPrivatePath(filePath, 0o600);
324
352
  }
325
353
  syncToDiskSync(dir) {
326
354
  const filePath = path.join(dir, this.fullName);
@@ -330,7 +358,7 @@ const PDFDocument = require(${JSON.stringify(require.resolve('pdfkit'))});
330
358
  const filePath = ${JSON.stringify(filePath)};
331
359
  const content = ${JSON.stringify(this.content ?? '')};
332
360
  const doc = new PDFDocument({ autoFirstPage: true });
333
- const stream = createWriteStream(filePath);
361
+ const stream = createWriteStream(filePath, { mode: 0o600 });
334
362
  doc.pipe(stream);
335
363
  doc.fontSize(12).text(content || '', { width: 500, align: 'left' });
336
364
  doc.end();
@@ -348,6 +376,7 @@ stream.on('error', (err) => {
348
376
  `Could not write to file '${this.fullName}'.`;
349
377
  throw new FileSystemError(`Error: ${errorMsg.trim()}`);
350
378
  }
379
+ chmodPrivatePath(filePath, 0o600);
351
380
  }
352
381
  }
353
382
  class DocxFile extends BaseFile {
@@ -357,12 +386,12 @@ class DocxFile extends BaseFile {
357
386
  async syncToDisk(dir) {
358
387
  const filePath = path.join(dir, this.fullName);
359
388
  const docxBuffer = buildDocxBuffer(this.content || '');
360
- await fsp.writeFile(filePath, docxBuffer);
389
+ await writePrivateBufferFileAsync(filePath, docxBuffer);
361
390
  }
362
391
  syncToDiskSync(dir) {
363
392
  const filePath = path.join(dir, this.fullName);
364
393
  const docxBuffer = buildDocxBuffer(this.content || '');
365
- fsSync.writeFileSync(filePath, docxBuffer);
394
+ writePrivateBufferFile(filePath, docxBuffer);
366
395
  }
367
396
  }
368
397
  class HtmlFile extends BaseFile {
@@ -410,7 +439,8 @@ export class FileSystem {
410
439
  if (fsSync.existsSync(this.dataDir)) {
411
440
  fsSync.rmSync(this.dataDir, { recursive: true, force: true });
412
441
  }
413
- fsSync.mkdirSync(this.dataDir, { recursive: true });
442
+ fsSync.mkdirSync(this.dataDir, { recursive: true, mode: 0o700 });
443
+ chmodPrivatePath(this.dataDir, 0o700);
414
444
  if (createDefaultFiles) {
415
445
  this.createDefaultFiles();
416
446
  }
@@ -419,7 +449,7 @@ export class FileSystem {
419
449
  for (const filename of this.defaultFiles) {
420
450
  const file = this.instantiateFile(filename);
421
451
  this.files.set(filename, file);
422
- fsSync.writeFileSync(path.join(this.dataDir, filename), file.read(), 'utf-8');
452
+ writePrivateTextFile(path.join(this.dataDir, filename), file.read());
423
453
  }
424
454
  }
425
455
  isValidFilename(filename) {
@@ -9,6 +9,32 @@ import { google } from 'googleapis';
9
9
  import { createLogger } from '../../logging-config.js';
10
10
  import { CONFIG } from '../../config.js';
11
11
  const logger = createLogger('browser_use.gmail');
12
+ const chmodPrivatePath = (targetPath, mode) => {
13
+ if (process.platform === 'win32') {
14
+ return;
15
+ }
16
+ try {
17
+ fs.chmodSync(targetPath, mode);
18
+ }
19
+ catch {
20
+ /* best effort */
21
+ }
22
+ };
23
+ const ensurePrivateDirectory = (dirPath) => {
24
+ fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
25
+ chmodPrivatePath(dirPath, 0o700);
26
+ };
27
+ const readPrivateJsonFile = (filePath) => {
28
+ chmodPrivatePath(filePath, 0o600);
29
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
30
+ };
31
+ const writePrivateJsonFile = (filePath, value) => {
32
+ fs.writeFileSync(filePath, JSON.stringify(value), {
33
+ encoding: 'utf-8',
34
+ mode: 0o600,
35
+ });
36
+ chmodPrivatePath(filePath, 0o600);
37
+ };
12
38
  export class GmailService {
13
39
  static SCOPES = [
14
40
  'https://www.googleapis.com/auth/gmail.readonly',
@@ -27,9 +53,7 @@ export class GmailService {
27
53
  this.accessToken = options.access_token || null;
28
54
  // Ensure config directory exists (only if not using direct token)
29
55
  if (!this.accessToken) {
30
- if (!fs.existsSync(this.configDir)) {
31
- fs.mkdirSync(this.configDir, { recursive: true });
32
- }
56
+ ensurePrivateDirectory(this.configDir);
33
57
  }
34
58
  // Set up credential paths
35
59
  this.credentialsFile =
@@ -63,7 +87,7 @@ export class GmailService {
63
87
  // Original file-based authentication flow
64
88
  // Try to load existing tokens
65
89
  if (fs.existsSync(this.tokenFile)) {
66
- const tokenData = JSON.parse(fs.readFileSync(this.tokenFile, 'utf-8'));
90
+ const tokenData = readPrivateJsonFile(this.tokenFile);
67
91
  const auth = new google.auth.OAuth2();
68
92
  auth.setCredentials(tokenData);
69
93
  this.creds = auth;
@@ -90,7 +114,7 @@ export class GmailService {
90
114
  `4. Save as 'gmail_credentials.json' in ${this.configDir}/`);
91
115
  return false;
92
116
  }
93
- const credentials = JSON.parse(fs.readFileSync(this.credentialsFile, 'utf-8'));
117
+ const credentials = readPrivateJsonFile(this.credentialsFile);
94
118
  const { client_secret, client_id, redirect_uris } = credentials.installed || credentials.web;
95
119
  const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
96
120
  const authUrl = oAuth2Client.generateAuthUrl({
@@ -108,7 +132,7 @@ export class GmailService {
108
132
  '4. Implement token exchange logic');
109
133
  }
110
134
  // Save tokens for next time
111
- fs.writeFileSync(this.tokenFile, JSON.stringify(this.creds.credentials));
135
+ writePrivateJsonFile(this.tokenFile, this.creds.credentials);
112
136
  logger.info(`💾 Tokens saved to ${this.tokenFile}`);
113
137
  }
114
138
  // Build Gmail service
@@ -43,13 +43,13 @@ export class ChatBrowserUse {
43
43
  fast;
44
44
  fetchImplementation;
45
45
  constructor(options = {}) {
46
- const { model = 'bu-latest', apiKey = process.env.BROWSER_USE_API_KEY, baseUrl = process.env.BROWSER_USE_LLM_URL ??
46
+ const { model = 'bu-2-0', apiKey = process.env.BROWSER_USE_API_KEY, baseUrl = process.env.BROWSER_USE_LLM_URL ??
47
47
  'https://llm.api.browser-use.com', timeout = 120, maxRetries = 5, retryBaseDelay = 1.0, retryMaxDelay = 60.0, fast = false, fetchImplementation = fetch, } = options;
48
48
  const isValidModel = VALID_MODELS.has(model) || model.startsWith('browser-use/');
49
49
  if (!isValidModel) {
50
50
  throw new Error(`Invalid model: '${model}'. Must be one of bu-latest, bu-1-0, bu-2-0 or start with 'browser-use/'`);
51
51
  }
52
- this.model = model === 'bu-latest' ? 'bu-1-0' : model;
52
+ this.model = model === 'bu-latest' ? 'bu-2-0' : model;
53
53
  if (!apiKey) {
54
54
  throw new Error('You need to set the BROWSER_USE_API_KEY environment variable. Get your key at https://cloud.browser-use.com/new-api-key');
55
55
  }
@@ -0,0 +1,118 @@
1
+ export declare const CODEX_PROVIDER = "openai-codex";
2
+ export declare const DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api/codex";
3
+ export declare const CODEX_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
4
+ export declare const CODEX_OAUTH_TOKEN_URL = "https://auth.openai.com/oauth/token";
5
+ export declare const CODEX_DEVICE_AUTH_BASE_URL = "https://auth.openai.com";
6
+ export declare const CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDS = 120;
7
+ export interface CodexTokens {
8
+ access_token: string;
9
+ refresh_token: string;
10
+ [key: string]: unknown;
11
+ }
12
+ export interface CodexTokenRecord {
13
+ tokens: CodexTokens;
14
+ last_refresh: string | null;
15
+ auth_mode: string | null;
16
+ source: string | null;
17
+ }
18
+ export interface CodexRuntimeCredentials {
19
+ provider: typeof CODEX_PROVIDER;
20
+ base_url: string;
21
+ api_key: string;
22
+ source: string;
23
+ last_refresh: string | null;
24
+ auth_mode: 'chatgpt';
25
+ }
26
+ export interface CodexAuthStatus {
27
+ authenticated: boolean;
28
+ auth_store_path: string;
29
+ provider: typeof CODEX_PROVIDER;
30
+ base_url: string;
31
+ source: string | null;
32
+ last_refresh: string | null;
33
+ access_token_expiring: boolean | null;
34
+ error?: {
35
+ code: string;
36
+ message: string;
37
+ relogin_required: boolean;
38
+ };
39
+ }
40
+ export declare class CodexAuthError extends Error {
41
+ provider: string;
42
+ code: string;
43
+ relogin_required: boolean;
44
+ constructor(message: string, code?: string, reloginRequired?: boolean);
45
+ }
46
+ interface AuthPathOptions {
47
+ configDir?: string | null;
48
+ authStorePath?: string | null;
49
+ }
50
+ interface FetchOptions {
51
+ fetchImplementation?: typeof fetch;
52
+ timeoutMs?: number;
53
+ }
54
+ export interface RefreshCodexOAuthOptions extends FetchOptions {
55
+ tokenUrl?: string;
56
+ clientId?: string;
57
+ }
58
+ export interface ResolveCodexRuntimeCredentialsOptions extends RefreshCodexOAuthOptions, AuthPathOptions {
59
+ forceRefresh?: boolean;
60
+ refreshIfExpiring?: boolean;
61
+ refreshSkewSeconds?: number;
62
+ lockTimeoutMs?: number;
63
+ baseURL?: string | null;
64
+ }
65
+ export interface DeviceCodeLoginOptions extends FetchOptions {
66
+ issuer?: string;
67
+ clientId?: string;
68
+ stdout?: Pick<NodeJS.WriteStream, 'write'>;
69
+ sleep?: (ms: number) => Promise<void>;
70
+ maxWaitMs?: number;
71
+ now?: () => number;
72
+ }
73
+ export declare const getCodexAuthStorePath: (options?: AuthPathOptions) => string;
74
+ export declare const readCodexTokens: (options?: AuthPathOptions) => Promise<CodexTokenRecord>;
75
+ export declare const saveCodexTokens: (tokens: CodexTokens, options?: AuthPathOptions & {
76
+ lastRefresh?: string | null;
77
+ source?: string | null;
78
+ lockTimeoutMs?: number;
79
+ }) => Promise<void>;
80
+ export declare const clearCodexTokens: (options?: AuthPathOptions & {
81
+ lockTimeoutMs?: number;
82
+ }) => Promise<void>;
83
+ export declare const codexAccessTokenIsExpiring: (accessToken: string, skewSeconds?: number, nowMs?: number) => boolean;
84
+ export declare const getCodexCloudflareHeaders: (accessToken: string) => Record<string, string>;
85
+ export declare const importCodexCliTokens: (options?: {
86
+ codexHome?: string | null;
87
+ authPath?: string | null;
88
+ nowMs?: number;
89
+ }) => Promise<CodexTokens | null>;
90
+ export declare const refreshCodexOAuth: (accessToken: string, refreshToken: string, options?: RefreshCodexOAuthOptions) => Promise<CodexTokens & {
91
+ last_refresh: string;
92
+ }>;
93
+ export declare const resolveCodexRuntimeCredentials: (options?: ResolveCodexRuntimeCredentialsOptions) => Promise<CodexRuntimeCredentials>;
94
+ export declare const getCodexAuthStatus: (options?: AuthPathOptions & {
95
+ baseURL?: string | null;
96
+ }) => Promise<CodexAuthStatus>;
97
+ export declare const saveImportedCodexCliTokens: (options?: AuthPathOptions & {
98
+ codexHome?: string | null;
99
+ codexAuthPath?: string | null;
100
+ lockTimeoutMs?: number;
101
+ }) => Promise<boolean>;
102
+ export declare const loginCodexDeviceCode: (options?: DeviceCodeLoginOptions) => Promise<{
103
+ tokens: CodexTokens;
104
+ base_url: string;
105
+ last_refresh: string;
106
+ auth_mode: "chatgpt";
107
+ source: "device-code";
108
+ }>;
109
+ export declare const loginAndSaveCodexDeviceCode: (options?: DeviceCodeLoginOptions & AuthPathOptions & {
110
+ lockTimeoutMs?: number;
111
+ }) => Promise<{
112
+ tokens: CodexTokens;
113
+ base_url: string;
114
+ last_refresh: string;
115
+ auth_mode: "chatgpt";
116
+ source: "device-code";
117
+ }>;
118
+ export {};