@agenticmail/enterprise 0.5.237 → 0.5.239
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/agent-heartbeat-FF6ASUZ4.js +510 -0
- package/dist/agent-heartbeat-QTYUXYH3.js +510 -0
- package/dist/agent-tools-X4H3KDRM.js +13855 -0
- package/dist/chunk-D5CKFCEL.js +2594 -0
- package/dist/chunk-DD36VGKL.js +3778 -0
- package/dist/chunk-FORLAPWB.js +4463 -0
- package/dist/chunk-J3J5XEWS.js +4463 -0
- package/dist/chunk-MCQ2Q4SC.js +3778 -0
- package/dist/chunk-T4DN77PH.js +1224 -0
- package/dist/chunk-TCQTHG7L.js +1224 -0
- package/dist/cli-agent-G4FLS4M5.js +1721 -0
- package/dist/cli-agent-HDEPHBZX.js +1721 -0
- package/dist/cli-serve-CO5UAKD2.js +114 -0
- package/dist/cli-serve-OHDYAC3L.js +114 -0
- package/dist/cli.js +3 -3
- package/dist/dashboard/docs/browser-providers.html +302 -0
- package/dist/dashboard/pages/agent-detail/meeting-browser.js +36 -23
- package/dist/index.js +3 -3
- package/dist/meetings-RR72OBSV.js +12 -0
- package/dist/routes-4YJNJJSS.js +13245 -0
- package/dist/routes-QU3MYXUG.js +13063 -0
- package/dist/runtime-2AQSHJKC.js +45 -0
- package/dist/runtime-A7DA7F74.js +45 -0
- package/dist/server-IQME5P6B.js +15 -0
- package/dist/server-VXVRSEFL.js +15 -0
- package/dist/setup-AEBSFYUE.js +20 -0
- package/dist/setup-OBCJB3R6.js +20 -0
- package/package.json +2 -2
- package/src/agent-tools/tools/browser.ts +375 -1
- package/src/dashboard/docs/browser-providers.html +302 -0
- package/src/dashboard/pages/agent-detail/meeting-browser.js +36 -23
- package/src/engine/agent-routes.ts +200 -13
- package/src/server.ts +12 -0
|
@@ -1180,7 +1180,92 @@ export function createAgentRoutes(opts: {
|
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
1182
|
const { execSync, spawn } = await import('node:child_process');
|
|
1183
|
-
const
|
|
1183
|
+
const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');
|
|
1184
|
+
const { join, dirname } = await import('node:path');
|
|
1185
|
+
const { homedir } = await import('node:os');
|
|
1186
|
+
|
|
1187
|
+
// ── Auto-detect Chrome/Chromium across all platforms ──
|
|
1188
|
+
const chromeCandidates = [
|
|
1189
|
+
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
|
|
1190
|
+
// macOS
|
|
1191
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
1192
|
+
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
1193
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
1194
|
+
// Linux
|
|
1195
|
+
'/usr/bin/google-chrome',
|
|
1196
|
+
'/usr/bin/google-chrome-stable',
|
|
1197
|
+
'/usr/bin/chromium',
|
|
1198
|
+
'/usr/bin/chromium-browser',
|
|
1199
|
+
'/snap/bin/chromium',
|
|
1200
|
+
'/usr/local/bin/chromium',
|
|
1201
|
+
// Windows
|
|
1202
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
1203
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
1204
|
+
// Playwright bundled (check common install locations)
|
|
1205
|
+
join(homedir(), '.cache', 'ms-playwright', 'chromium-*', 'chrome-linux', 'chrome'),
|
|
1206
|
+
join(homedir(), '.cache', 'ms-playwright', 'chromium-*', 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium'),
|
|
1207
|
+
].filter(Boolean) as string[];
|
|
1208
|
+
|
|
1209
|
+
let chromePath = '';
|
|
1210
|
+
for (const candidate of chromeCandidates) {
|
|
1211
|
+
if (candidate.includes('*')) {
|
|
1212
|
+
// Glob pattern — resolve with fs
|
|
1213
|
+
try {
|
|
1214
|
+
const { globSync } = await import('node:fs');
|
|
1215
|
+
const matches = (globSync as any)(candidate);
|
|
1216
|
+
if (matches?.length && existsSync(matches[0])) { chromePath = matches[0]; break; }
|
|
1217
|
+
} catch {
|
|
1218
|
+
// globSync not available in older Node, try manual resolve
|
|
1219
|
+
try {
|
|
1220
|
+
const parentDir = dirname(candidate.split('*')[0]);
|
|
1221
|
+
if (existsSync(parentDir)) {
|
|
1222
|
+
const { readdirSync } = await import('node:fs');
|
|
1223
|
+
const dirs = readdirSync(parentDir).filter((d: string) => d.startsWith('chromium-')).sort().reverse();
|
|
1224
|
+
for (const d of dirs) {
|
|
1225
|
+
const suffix = candidate.split('*')[1];
|
|
1226
|
+
const resolved = join(parentDir, d, suffix);
|
|
1227
|
+
if (existsSync(resolved)) { chromePath = resolved; break; }
|
|
1228
|
+
}
|
|
1229
|
+
if (chromePath) break;
|
|
1230
|
+
}
|
|
1231
|
+
} catch { /* skip */ }
|
|
1232
|
+
}
|
|
1233
|
+
} else if (existsSync(candidate)) {
|
|
1234
|
+
chromePath = candidate;
|
|
1235
|
+
break;
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// If no Chrome found, try to install Playwright Chromium automatically
|
|
1240
|
+
if (!chromePath) {
|
|
1241
|
+
try {
|
|
1242
|
+
console.log('[meeting-browser] No Chrome/Chromium found — installing Playwright Chromium...');
|
|
1243
|
+
execSync('npx playwright install chromium 2>&1', { timeout: 120_000, stdio: 'pipe' });
|
|
1244
|
+
// Re-check for Playwright Chromium
|
|
1245
|
+
const pwCacheDir = join(homedir(), '.cache', 'ms-playwright');
|
|
1246
|
+
if (existsSync(pwCacheDir)) {
|
|
1247
|
+
const { readdirSync } = await import('node:fs');
|
|
1248
|
+
const chromiumDirs = readdirSync(pwCacheDir).filter((d: string) => d.startsWith('chromium-')).sort().reverse();
|
|
1249
|
+
for (const d of chromiumDirs) {
|
|
1250
|
+
// Try Linux path
|
|
1251
|
+
const linuxPath = join(pwCacheDir, d, 'chrome-linux', 'chrome');
|
|
1252
|
+
if (existsSync(linuxPath)) { chromePath = linuxPath; break; }
|
|
1253
|
+
// Try macOS path
|
|
1254
|
+
const macPath = join(pwCacheDir, d, 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium');
|
|
1255
|
+
if (existsSync(macPath)) { chromePath = macPath; break; }
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
} catch (installErr: any) {
|
|
1259
|
+
console.error('[meeting-browser] Failed to auto-install Chromium:', installErr.message);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
if (!chromePath) {
|
|
1264
|
+
return c.json({
|
|
1265
|
+
error: 'No Chrome or Chromium browser found on this machine. Install Google Chrome or run: npx playwright install chromium',
|
|
1266
|
+
hint: 'On macOS: brew install --cask google-chrome | On Linux: apt install chromium-browser | On Windows: download from google.com/chrome',
|
|
1267
|
+
}, 400);
|
|
1268
|
+
}
|
|
1184
1269
|
|
|
1185
1270
|
// Check if a meeting browser is already running for this agent
|
|
1186
1271
|
const existingPort = (managed.config as any)?.meetingBrowserPort;
|
|
@@ -1194,6 +1279,52 @@ export function createAgentRoutes(opts: {
|
|
|
1194
1279
|
} catch { /* not running, will launch new one */ }
|
|
1195
1280
|
}
|
|
1196
1281
|
|
|
1282
|
+
// ── Create a realistic browser profile using agent identity ──
|
|
1283
|
+
const agentName = managed.displayName || managed.display_name || managed.name || (managed.config as any)?.displayName || (managed.config as any)?.name || 'Agent';
|
|
1284
|
+
const agentRole = (managed.config as any)?.role || (managed.config as any)?.description || 'AI Assistant';
|
|
1285
|
+
const profileDir = join(homedir(), '.agenticmail', 'browser-profiles', agentId);
|
|
1286
|
+
mkdirSync(profileDir, { recursive: true });
|
|
1287
|
+
|
|
1288
|
+
// Write Chrome preferences to make the browser look like a real user
|
|
1289
|
+
const prefsDir = join(profileDir, 'Default');
|
|
1290
|
+
mkdirSync(prefsDir, { recursive: true });
|
|
1291
|
+
const prefsFile = join(prefsDir, 'Preferences');
|
|
1292
|
+
if (!existsSync(prefsFile)) {
|
|
1293
|
+
const prefs = {
|
|
1294
|
+
profile: {
|
|
1295
|
+
name: agentName,
|
|
1296
|
+
avatar_index: Math.floor(Math.random() * 28), // Chrome has 28 avatar options
|
|
1297
|
+
managed_user_id: '',
|
|
1298
|
+
is_using_default_name: false,
|
|
1299
|
+
is_using_default_avatar: false,
|
|
1300
|
+
},
|
|
1301
|
+
browser: {
|
|
1302
|
+
has_seen_welcome_page: true,
|
|
1303
|
+
check_default_browser: false,
|
|
1304
|
+
},
|
|
1305
|
+
distribution: {
|
|
1306
|
+
import_bookmarks: false,
|
|
1307
|
+
import_history: false,
|
|
1308
|
+
import_search_engine: false,
|
|
1309
|
+
suppress_first_run_bubble: true,
|
|
1310
|
+
suppress_first_run_default_browser_prompt: true,
|
|
1311
|
+
skip_first_run_ui: true,
|
|
1312
|
+
make_chrome_default_for_user: false,
|
|
1313
|
+
},
|
|
1314
|
+
session: { restore_on_startup: 1 },
|
|
1315
|
+
search: { suggest_enabled: true },
|
|
1316
|
+
translate: { enabled: false },
|
|
1317
|
+
net: { network_prediction_options: 2 }, // don't prefetch
|
|
1318
|
+
webkit: { webprefs: { default_font_size: 16 } },
|
|
1319
|
+
download: { prompt_for_download: true, default_directory: join(profileDir, 'Downloads') },
|
|
1320
|
+
savefile: { default_directory: join(profileDir, 'Downloads') },
|
|
1321
|
+
credentials_enable_service: false,
|
|
1322
|
+
credentials_enable_autosign_in: false,
|
|
1323
|
+
};
|
|
1324
|
+
mkdirSync(join(profileDir, 'Downloads'), { recursive: true });
|
|
1325
|
+
writeFileSync(prefsFile, JSON.stringify(prefs, null, 2));
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1197
1328
|
// Find available port
|
|
1198
1329
|
const net = await import('node:net');
|
|
1199
1330
|
const port = await new Promise<number>((resolve, reject) => {
|
|
@@ -1205,7 +1336,7 @@ export function createAgentRoutes(opts: {
|
|
|
1205
1336
|
srv.on('error', reject);
|
|
1206
1337
|
});
|
|
1207
1338
|
|
|
1208
|
-
// Launch Chrome with meeting-optimized flags
|
|
1339
|
+
// Launch Chrome with meeting-optimized flags and realistic profile
|
|
1209
1340
|
const chromeArgs = [
|
|
1210
1341
|
`--remote-debugging-port=${port}`,
|
|
1211
1342
|
'--remote-debugging-address=127.0.0.1',
|
|
@@ -1215,23 +1346,35 @@ export function createAgentRoutes(opts: {
|
|
|
1215
1346
|
'--disable-sync',
|
|
1216
1347
|
'--disable-translate',
|
|
1217
1348
|
'--metrics-recording-only',
|
|
1218
|
-
'--no-sandbox',
|
|
1219
1349
|
// Meeting-specific: auto-grant camera/mic permissions
|
|
1220
1350
|
'--use-fake-ui-for-media-stream',
|
|
1221
1351
|
'--auto-accept-camera-and-microphone-capture',
|
|
1222
|
-
//
|
|
1223
|
-
'--
|
|
1352
|
+
// Anti-detection: remove automation indicators
|
|
1353
|
+
'--disable-blink-features=AutomationControlled',
|
|
1354
|
+
'--disable-infobars',
|
|
1224
1355
|
// Window size for meeting UI
|
|
1225
1356
|
'--window-size=1920,1080',
|
|
1226
1357
|
'--start-maximized',
|
|
1227
|
-
//
|
|
1228
|
-
|
|
1358
|
+
// Use the agent's persistent profile directory
|
|
1359
|
+
`--user-data-dir=${profileDir}`,
|
|
1360
|
+
// Realistic user-agent lang
|
|
1361
|
+
'--lang=en-US',
|
|
1229
1362
|
];
|
|
1230
1363
|
|
|
1364
|
+
// Add --no-sandbox on Linux (required for non-root in containers)
|
|
1365
|
+
if (process.platform === 'linux') {
|
|
1366
|
+
chromeArgs.push('--no-sandbox');
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// Detect display environment
|
|
1370
|
+
const display = process.env.DISPLAY || (process.platform === 'linux' ? ':99' : undefined);
|
|
1371
|
+
const envVars: Record<string, string> = { ...process.env } as any;
|
|
1372
|
+
if (display) envVars.DISPLAY = display;
|
|
1373
|
+
|
|
1231
1374
|
const child = spawn(chromePath, chromeArgs, {
|
|
1232
1375
|
detached: true,
|
|
1233
1376
|
stdio: 'ignore',
|
|
1234
|
-
env:
|
|
1377
|
+
env: envVars,
|
|
1235
1378
|
});
|
|
1236
1379
|
child.unref();
|
|
1237
1380
|
|
|
@@ -1328,15 +1471,45 @@ export function createAgentRoutes(opts: {
|
|
|
1328
1471
|
|
|
1329
1472
|
try {
|
|
1330
1473
|
if (provider === 'local') {
|
|
1331
|
-
// Test local Chromium availability
|
|
1474
|
+
// Test local Chromium availability — auto-detect across platforms
|
|
1332
1475
|
try {
|
|
1333
1476
|
const { execSync } = await import('node:child_process');
|
|
1334
|
-
const
|
|
1335
|
-
const
|
|
1477
|
+
const { existsSync } = await import('node:fs');
|
|
1478
|
+
const { homedir } = await import('node:os');
|
|
1479
|
+
const { join } = await import('node:path');
|
|
1480
|
+
const candidates = [
|
|
1481
|
+
cfg.executablePath,
|
|
1482
|
+
process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH,
|
|
1483
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
1484
|
+
'/usr/bin/google-chrome', '/usr/bin/google-chrome-stable',
|
|
1485
|
+
'/usr/bin/chromium', '/usr/bin/chromium-browser', '/snap/bin/chromium',
|
|
1486
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
1487
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
1488
|
+
].filter(Boolean) as string[];
|
|
1489
|
+
let foundPath = '';
|
|
1490
|
+
for (const p of candidates) { if (existsSync(p)) { foundPath = p; break; } }
|
|
1491
|
+
// Also check Playwright bundled chromium
|
|
1492
|
+
if (!foundPath) {
|
|
1493
|
+
const pwCache = join(homedir(), '.cache', 'ms-playwright');
|
|
1494
|
+
if (existsSync(pwCache)) {
|
|
1495
|
+
const { readdirSync } = await import('node:fs');
|
|
1496
|
+
const dirs = readdirSync(pwCache).filter((d: string) => d.startsWith('chromium-')).sort().reverse();
|
|
1497
|
+
for (const d of dirs) {
|
|
1498
|
+
const linuxP = join(pwCache, d, 'chrome-linux', 'chrome');
|
|
1499
|
+
const macP = join(pwCache, d, 'chrome-mac', 'Chromium.app', 'Contents', 'MacOS', 'Chromium');
|
|
1500
|
+
if (existsSync(linuxP)) { foundPath = linuxP; break; }
|
|
1501
|
+
if (existsSync(macP)) { foundPath = macP; break; }
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
if (!foundPath) {
|
|
1506
|
+
return c.json({ error: 'No Chrome or Chromium found. Install Google Chrome or run: npx playwright install chromium' });
|
|
1507
|
+
}
|
|
1508
|
+
const version = execSync(`"${foundPath}" --version 2>/dev/null || echo "not found"`, { timeout: 5000 }).toString().trim();
|
|
1336
1509
|
if (version.includes('not found')) {
|
|
1337
|
-
return c.json({ error: '
|
|
1510
|
+
return c.json({ error: 'Chrome found at ' + foundPath + ' but --version failed' });
|
|
1338
1511
|
}
|
|
1339
|
-
return c.json({ ok: true, browserVersion: version, provider: 'local' });
|
|
1512
|
+
return c.json({ ok: true, browserVersion: version, provider: 'local', path: foundPath });
|
|
1340
1513
|
} catch (e: any) {
|
|
1341
1514
|
return c.json({ error: 'Chromium not available: ' + e.message });
|
|
1342
1515
|
}
|
|
@@ -1405,6 +1578,20 @@ export function createAgentRoutes(opts: {
|
|
|
1405
1578
|
}
|
|
1406
1579
|
}
|
|
1407
1580
|
|
|
1581
|
+
if (provider === 'scrapingbee') {
|
|
1582
|
+
if (!cfg.scrapingbeeApiKey) return c.json({ error: 'ScrapingBee API key not configured' });
|
|
1583
|
+
try {
|
|
1584
|
+
const resp = await fetch(`https://app.scrapingbee.com/api/v1/usage?api_key=${cfg.scrapingbeeApiKey}`, {
|
|
1585
|
+
signal: AbortSignal.timeout(10000),
|
|
1586
|
+
});
|
|
1587
|
+
if (!resp.ok) return c.json({ error: `ScrapingBee returned ${resp.status}` });
|
|
1588
|
+
const data = await resp.json() as any;
|
|
1589
|
+
return c.json({ ok: true, provider: 'scrapingbee', creditsUsed: data.used_api_credit, creditsMax: data.max_api_credit });
|
|
1590
|
+
} catch (e: any) {
|
|
1591
|
+
return c.json({ error: 'Cannot connect to ScrapingBee: ' + e.message });
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1408
1595
|
return c.json({ ok: true, provider, note: 'Connection test not implemented for this provider' });
|
|
1409
1596
|
} catch (e: any) {
|
|
1410
1597
|
return c.json({ error: e.message });
|
package/src/server.ts
CHANGED
|
@@ -486,6 +486,18 @@ export function createServer(config: ServerConfig): ServerInstance {
|
|
|
486
486
|
app.get('/', (c) => c.redirect('/dashboard'));
|
|
487
487
|
app.get('/dashboard', serveDashboard);
|
|
488
488
|
|
|
489
|
+
// Serve documentation pages (browser-providers, etc.)
|
|
490
|
+
app.get('/docs/:page', (c) => {
|
|
491
|
+
const page = c.req.param('page').replace(/[^a-z0-9-]/gi, ''); // sanitize
|
|
492
|
+
const dir = dirname(fileURLToPath(import.meta.url));
|
|
493
|
+
const filePath = join(dir, 'dashboard', 'docs', page + '.html');
|
|
494
|
+
if (existsSync(filePath)) {
|
|
495
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
496
|
+
return new Response(content, { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' } });
|
|
497
|
+
}
|
|
498
|
+
return c.json({ error: 'Documentation page not found' }, 404);
|
|
499
|
+
});
|
|
500
|
+
|
|
489
501
|
// Serve dashboard JS modules and static assets (components/*.js, pages/*.js, app.js, assets/*)
|
|
490
502
|
const STATIC_MIME: Record<string, string> = { '.js': 'application/javascript; charset=utf-8', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.svg': 'image/svg+xml', '.ico': 'image/x-icon', '.gif': 'image/gif', '.webp': 'image/webp', '.css': 'text/css; charset=utf-8' };
|
|
491
503
|
app.get('/dashboard/*', (c) => {
|