@hasna/browser 0.3.7 → 0.4.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.
- package/dist/cli/index.js +557 -395
- package/dist/engines/selector.d.ts.map +1 -1
- package/dist/engines/tui.d.ts +49 -0
- package/dist/engines/tui.d.ts.map +1 -0
- package/dist/engines/tui.test.d.ts +2 -0
- package/dist/engines/tui.test.d.ts.map +1 -0
- package/dist/index.js +8362 -7856
- package/dist/lib/actions.d.ts +1 -0
- package/dist/lib/actions.d.ts.map +1 -1
- package/dist/lib/coordination.d.ts.map +1 -1
- package/dist/lib/login-scripts.d.ts +89 -0
- package/dist/lib/login-scripts.d.ts.map +1 -0
- package/dist/lib/network.d.ts.map +1 -1
- package/dist/lib/page-memory.d.ts.map +1 -1
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/task-queue.d.ts.map +1 -1
- package/dist/mcp/index.js +553 -391
- package/dist/server/index.js +1157 -327
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -6,60 +6,39 @@ var __defProp = Object.defineProperty;
|
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
function __accessProp(key) {
|
|
10
|
-
return this[key];
|
|
11
|
-
}
|
|
12
|
-
var __toESMCache_node;
|
|
13
|
-
var __toESMCache_esm;
|
|
14
9
|
var __toESM = (mod, isNodeMode, target) => {
|
|
15
|
-
var canCache = mod != null && typeof mod === "object";
|
|
16
|
-
if (canCache) {
|
|
17
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
18
|
-
var cached = cache.get(mod);
|
|
19
|
-
if (cached)
|
|
20
|
-
return cached;
|
|
21
|
-
}
|
|
22
10
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
23
11
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
24
12
|
for (let key of __getOwnPropNames(mod))
|
|
25
13
|
if (!__hasOwnProp.call(to, key))
|
|
26
14
|
__defProp(to, key, {
|
|
27
|
-
get:
|
|
15
|
+
get: () => mod[key],
|
|
28
16
|
enumerable: true
|
|
29
17
|
});
|
|
30
|
-
if (canCache)
|
|
31
|
-
cache.set(mod, to);
|
|
32
18
|
return to;
|
|
33
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
34
21
|
var __toCommonJS = (from) => {
|
|
35
|
-
var entry =
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
36
23
|
if (entry)
|
|
37
24
|
return entry;
|
|
38
25
|
entry = __defProp({}, "__esModule", { value: true });
|
|
39
|
-
if (from && typeof from === "object" || typeof from === "function")
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
45
|
-
});
|
|
46
|
-
}
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
47
31
|
__moduleCache.set(from, entry);
|
|
48
32
|
return entry;
|
|
49
33
|
};
|
|
50
|
-
var __moduleCache;
|
|
51
34
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
52
|
-
var __returnValue = (v) => v;
|
|
53
|
-
function __exportSetter(name, newValue) {
|
|
54
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
55
|
-
}
|
|
56
35
|
var __export = (target, all) => {
|
|
57
36
|
for (var name in all)
|
|
58
37
|
__defProp(target, name, {
|
|
59
38
|
get: all[name],
|
|
60
39
|
enumerable: true,
|
|
61
40
|
configurable: true,
|
|
62
|
-
set:
|
|
41
|
+
set: (newValue) => all[name] = () => newValue
|
|
63
42
|
});
|
|
64
43
|
};
|
|
65
44
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -2177,11 +2156,11 @@ import { homedir as homedir4 } from "os";
|
|
|
2177
2156
|
import { join as join4 } from "path";
|
|
2178
2157
|
import { join as join6, dirname } from "path";
|
|
2179
2158
|
import { homedir as homedir5, platform } from "os";
|
|
2180
|
-
function
|
|
2159
|
+
function __accessProp(key) {
|
|
2181
2160
|
return this[key];
|
|
2182
2161
|
}
|
|
2183
|
-
function
|
|
2184
|
-
this[name] =
|
|
2162
|
+
function __exportSetter(name, newValue) {
|
|
2163
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
2185
2164
|
}
|
|
2186
2165
|
function translateSql(sql, dialect) {
|
|
2187
2166
|
if (dialect === "sqlite")
|
|
@@ -3211,10 +3190,10 @@ class SyncProgressTracker {
|
|
|
3211
3190
|
}
|
|
3212
3191
|
}
|
|
3213
3192
|
}
|
|
3214
|
-
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2,
|
|
3193
|
+
var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __toESMCache_node, __toESMCache_esm, __toESM2 = (mod, isNodeMode, target) => {
|
|
3215
3194
|
var canCache = mod != null && typeof mod === "object";
|
|
3216
3195
|
if (canCache) {
|
|
3217
|
-
var cache = isNodeMode ?
|
|
3196
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
3218
3197
|
var cached = cache.get(mod);
|
|
3219
3198
|
if (cached)
|
|
3220
3199
|
return cached;
|
|
@@ -3224,19 +3203,19 @@ var __create2, __getProtoOf2, __defProp2, __getOwnPropNames2, __hasOwnProp2, __t
|
|
|
3224
3203
|
for (let key of __getOwnPropNames2(mod))
|
|
3225
3204
|
if (!__hasOwnProp2.call(to, key))
|
|
3226
3205
|
__defProp2(to, key, {
|
|
3227
|
-
get:
|
|
3206
|
+
get: __accessProp.bind(mod, key),
|
|
3228
3207
|
enumerable: true
|
|
3229
3208
|
});
|
|
3230
3209
|
if (canCache)
|
|
3231
3210
|
cache.set(mod, to);
|
|
3232
3211
|
return to;
|
|
3233
|
-
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports),
|
|
3212
|
+
}, __commonJS2 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue = (v) => v, __export2 = (target, all) => {
|
|
3234
3213
|
for (var name in all)
|
|
3235
3214
|
__defProp2(target, name, {
|
|
3236
3215
|
get: all[name],
|
|
3237
3216
|
enumerable: true,
|
|
3238
3217
|
configurable: true,
|
|
3239
|
-
set:
|
|
3218
|
+
set: __exportSetter.bind(all, name)
|
|
3240
3219
|
});
|
|
3241
3220
|
}, __esm2 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), __require2, require_postgres_array, require_arrayParser, require_postgres_date, require_mutable, require_postgres_interval, require_postgres_bytea, require_textParsers, require_pg_int8, require_binaryParsers, require_builtins, require_pg_types, require_defaults, require_utils, require_utils_legacy, require_utils_webcrypto, require_utils2, require_cert_signatures, require_sasl, require_type_overrides, require_pg_connection_string, require_connection_parameters, require_result, require_query, require_messages, require_buffer_writer, require_serializer, require_buffer_reader, require_parser, require_dist, require_empty, require_stream, require_connection, require_split2, require_helper, require_lib, require_client, require_pg_pool, require_query2, require_client2, require_lib2, import_lib, Client, Pool, Connection, types, Query, DatabaseError, escapeIdentifier, escapeLiteral, Result, TypeOverrides, defaults, esm_default, init_esm, init_adapter, util, objectUtil, ZodParsedType, getParsedType = (data) => {
|
|
3242
3221
|
const t = typeof data;
|
|
@@ -12653,6 +12632,89 @@ var init_bun_webview = __esm(() => {
|
|
|
12653
12632
|
};
|
|
12654
12633
|
});
|
|
12655
12634
|
|
|
12635
|
+
// src/engines/tui.ts
|
|
12636
|
+
import { execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
12637
|
+
function isTuiAvailable() {
|
|
12638
|
+
try {
|
|
12639
|
+
execSync2("which ttyd", { stdio: "ignore" });
|
|
12640
|
+
return true;
|
|
12641
|
+
} catch {
|
|
12642
|
+
return false;
|
|
12643
|
+
}
|
|
12644
|
+
}
|
|
12645
|
+
async function findAvailablePort(startPort) {
|
|
12646
|
+
let port = startPort;
|
|
12647
|
+
for (let i = 0;i < 100; i++) {
|
|
12648
|
+
try {
|
|
12649
|
+
const resp = await fetch(`http://localhost:${port}`);
|
|
12650
|
+
port++;
|
|
12651
|
+
} catch {
|
|
12652
|
+
return port;
|
|
12653
|
+
}
|
|
12654
|
+
}
|
|
12655
|
+
throw new BrowserError("No available port found for ttyd", "TUI_PORT_EXHAUSTED");
|
|
12656
|
+
}
|
|
12657
|
+
async function waitForTtyd(port, timeoutMs = 1e4) {
|
|
12658
|
+
const start = Date.now();
|
|
12659
|
+
while (Date.now() - start < timeoutMs) {
|
|
12660
|
+
try {
|
|
12661
|
+
const resp = await fetch(`http://localhost:${port}`);
|
|
12662
|
+
if (resp.ok || resp.status === 200)
|
|
12663
|
+
return;
|
|
12664
|
+
} catch {}
|
|
12665
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
12666
|
+
}
|
|
12667
|
+
throw new BrowserError(`ttyd did not start within ${timeoutMs}ms`, "TUI_TIMEOUT");
|
|
12668
|
+
}
|
|
12669
|
+
async function launchTui(command, options = {}) {
|
|
12670
|
+
if (!isTuiAvailable()) {
|
|
12671
|
+
throw new BrowserError("ttyd not found \u2014 install with: brew install ttyd", "TUI_NOT_AVAILABLE");
|
|
12672
|
+
}
|
|
12673
|
+
const port = await findAvailablePort(nextPort);
|
|
12674
|
+
nextPort = port + 1;
|
|
12675
|
+
const ttydProcess = spawn2("ttyd", ["--writable", "--port", String(port), "/bin/sh", "-c", command], {
|
|
12676
|
+
stdio: "ignore",
|
|
12677
|
+
detached: false
|
|
12678
|
+
});
|
|
12679
|
+
ttydProcess.on("error", (err) => {
|
|
12680
|
+
console.error(`[tui] ttyd process error: ${err.message}`);
|
|
12681
|
+
});
|
|
12682
|
+
try {
|
|
12683
|
+
await waitForTtyd(port);
|
|
12684
|
+
const viewport = options.viewport ?? { width: 1280, height: 720 };
|
|
12685
|
+
const browser = await launchPlaywright({
|
|
12686
|
+
headless: options.headless ?? true,
|
|
12687
|
+
viewport
|
|
12688
|
+
});
|
|
12689
|
+
const page = await getPage(browser, { viewport });
|
|
12690
|
+
await page.goto(`http://localhost:${port}`, {
|
|
12691
|
+
waitUntil: "domcontentloaded"
|
|
12692
|
+
});
|
|
12693
|
+
await page.waitForSelector(".xterm-screen", { timeout: 1e4 });
|
|
12694
|
+
return { ttydProcess, port, browser, page };
|
|
12695
|
+
} catch (err) {
|
|
12696
|
+
ttydProcess.kill();
|
|
12697
|
+
throw err;
|
|
12698
|
+
}
|
|
12699
|
+
}
|
|
12700
|
+
async function closeTui(session) {
|
|
12701
|
+
try {
|
|
12702
|
+
await session.page.close();
|
|
12703
|
+
} catch {}
|
|
12704
|
+
try {
|
|
12705
|
+
await session.browser.close();
|
|
12706
|
+
} catch {}
|
|
12707
|
+
try {
|
|
12708
|
+
session.ttydProcess.kill("SIGTERM");
|
|
12709
|
+
} catch {}
|
|
12710
|
+
}
|
|
12711
|
+
var DEFAULT_TTYD_PORT_START = 7780, nextPort;
|
|
12712
|
+
var init_tui = __esm(() => {
|
|
12713
|
+
init_types();
|
|
12714
|
+
init_playwright();
|
|
12715
|
+
nextPort = DEFAULT_TTYD_PORT_START;
|
|
12716
|
+
});
|
|
12717
|
+
|
|
12656
12718
|
// src/engines/selector.ts
|
|
12657
12719
|
function selectEngine(useCase, explicit) {
|
|
12658
12720
|
if (explicit && explicit !== "auto")
|
|
@@ -12676,6 +12738,7 @@ var init_selector = __esm(() => {
|
|
|
12676
12738
|
init_types();
|
|
12677
12739
|
init_lightpanda();
|
|
12678
12740
|
init_bun_webview();
|
|
12741
|
+
init_tui();
|
|
12679
12742
|
ENGINE_MAP = {
|
|
12680
12743
|
["scrape" /* SCRAPE */]: "bun",
|
|
12681
12744
|
["extract_links" /* EXTRACT_LINKS */]: "bun",
|
|
@@ -12686,6 +12749,7 @@ var init_selector = __esm(() => {
|
|
|
12686
12749
|
["auth_flow" /* AUTH_FLOW */]: "playwright",
|
|
12687
12750
|
["multi_tab" /* MULTI_TAB */]: "playwright",
|
|
12688
12751
|
["record_replay" /* RECORD_REPLAY */]: "playwright",
|
|
12752
|
+
["terminal_test" /* TERMINAL_TEST */]: "tui",
|
|
12689
12753
|
["network_monitor" /* NETWORK_MONITOR */]: "cdp",
|
|
12690
12754
|
["har_capture" /* HAR_CAPTURE */]: "cdp",
|
|
12691
12755
|
["perf_profile" /* PERF_PROFILE */]: "cdp",
|
|
@@ -12811,7 +12875,8 @@ function startHAR(page) {
|
|
|
12811
12875
|
},
|
|
12812
12876
|
timings: { send: 0, wait: duration, receive: 0 }
|
|
12813
12877
|
};
|
|
12814
|
-
entries.
|
|
12878
|
+
if (entries.length < HAR_MAX_ENTRIES)
|
|
12879
|
+
entries.push(entry);
|
|
12815
12880
|
};
|
|
12816
12881
|
const onRequestFailed = (req) => {
|
|
12817
12882
|
requestStart.delete(req.url() + req.method());
|
|
@@ -12836,6 +12901,7 @@ function startHAR(page) {
|
|
|
12836
12901
|
}
|
|
12837
12902
|
};
|
|
12838
12903
|
}
|
|
12904
|
+
var HAR_MAX_ENTRIES = 5000;
|
|
12839
12905
|
var init_network = __esm(() => {
|
|
12840
12906
|
init_network_log();
|
|
12841
12907
|
});
|
|
@@ -13238,337 +13304,6 @@ var init_storage_state = __esm(() => {
|
|
|
13238
13304
|
STATES_DIR = join8(getDataDir2(), "states");
|
|
13239
13305
|
});
|
|
13240
13306
|
|
|
13241
|
-
// src/lib/session.ts
|
|
13242
|
-
var exports_session = {};
|
|
13243
|
-
__export(exports_session, {
|
|
13244
|
-
setSessionPage: () => setSessionPage,
|
|
13245
|
-
renameSession: () => renameSession2,
|
|
13246
|
-
listSessions: () => listSessions2,
|
|
13247
|
-
isBunSession: () => isBunSession,
|
|
13248
|
-
isAutoGallery: () => isAutoGallery,
|
|
13249
|
-
hasActiveHandle: () => hasActiveHandle,
|
|
13250
|
-
getTokenBudget: () => getTokenBudget,
|
|
13251
|
-
getSessionPage: () => getSessionPage,
|
|
13252
|
-
getSessionEngine: () => getSessionEngine,
|
|
13253
|
-
getSessionByName: () => getSessionByName2,
|
|
13254
|
-
getSessionBunView: () => getSessionBunView,
|
|
13255
|
-
getSessionBrowser: () => getSessionBrowser,
|
|
13256
|
-
getSession: () => getSession2,
|
|
13257
|
-
getDefaultSession: () => getDefaultSession,
|
|
13258
|
-
getActiveSessions: () => getActiveSessions,
|
|
13259
|
-
getActiveSessionForAgent: () => getActiveSessionForAgent2,
|
|
13260
|
-
createSession: () => createSession2,
|
|
13261
|
-
countActiveSessions: () => countActiveSessions2,
|
|
13262
|
-
closeSession: () => closeSession2,
|
|
13263
|
-
closeAllSessions: () => closeAllSessions,
|
|
13264
|
-
browserPool: () => pool
|
|
13265
|
-
});
|
|
13266
|
-
function createBunProxy(view) {
|
|
13267
|
-
return view;
|
|
13268
|
-
}
|
|
13269
|
-
async function createSession2(opts = {}) {
|
|
13270
|
-
if (opts.cdpUrl) {
|
|
13271
|
-
const { connectToExistingBrowser: connectToExistingBrowser2 } = await Promise.resolve().then(() => (init_cdp(), exports_cdp));
|
|
13272
|
-
const cdpBrowser = await connectToExistingBrowser2(opts.cdpUrl);
|
|
13273
|
-
const contexts = cdpBrowser.contexts();
|
|
13274
|
-
const context = contexts.length > 0 ? contexts[0] : await cdpBrowser.newContext();
|
|
13275
|
-
const pages = context.pages();
|
|
13276
|
-
const page2 = pages.length > 0 ? pages[0] : await context.newPage();
|
|
13277
|
-
const session2 = createSession({
|
|
13278
|
-
engine: "cdp",
|
|
13279
|
-
projectId: opts.projectId,
|
|
13280
|
-
agentId: opts.agentId,
|
|
13281
|
-
startUrl: page2.url(),
|
|
13282
|
-
name: opts.name ?? "attached"
|
|
13283
|
-
});
|
|
13284
|
-
const cleanups2 = [];
|
|
13285
|
-
if (opts.captureNetwork !== false) {
|
|
13286
|
-
try {
|
|
13287
|
-
cleanups2.push(enableNetworkLogging(page2, session2.id));
|
|
13288
|
-
} catch {}
|
|
13289
|
-
}
|
|
13290
|
-
if (opts.captureConsole !== false) {
|
|
13291
|
-
try {
|
|
13292
|
-
cleanups2.push(enableConsoleCapture(page2, session2.id));
|
|
13293
|
-
} catch {}
|
|
13294
|
-
}
|
|
13295
|
-
try {
|
|
13296
|
-
cleanups2.push(setupDialogHandler(page2, session2.id));
|
|
13297
|
-
} catch {}
|
|
13298
|
-
handles.set(session2.id, { browser: cdpBrowser, bunView: null, page: page2, engine: "cdp", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
13299
|
-
return { session: session2, page: page2 };
|
|
13300
|
-
}
|
|
13301
|
-
const engine = opts.engine === "auto" || !opts.engine ? selectEngine(opts.useCase ?? "spa_navigate" /* SPA_NAVIGATE */, opts.engine) : opts.engine;
|
|
13302
|
-
const resolvedEngine = engine === "auto" ? "playwright" : engine;
|
|
13303
|
-
let browser = null;
|
|
13304
|
-
let bunView = null;
|
|
13305
|
-
let page;
|
|
13306
|
-
if (resolvedEngine === "bun") {
|
|
13307
|
-
if (!isBunWebViewAvailable()) {
|
|
13308
|
-
console.warn("[browser] Bun.WebView requested but not available \u2014 falling back to playwright. Run: bun upgrade --canary");
|
|
13309
|
-
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13310
|
-
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13311
|
-
} else {
|
|
13312
|
-
bunView = new BunWebViewSession({
|
|
13313
|
-
width: opts.viewport?.width ?? 1280,
|
|
13314
|
-
height: opts.viewport?.height ?? 720,
|
|
13315
|
-
profile: opts.name ?? undefined
|
|
13316
|
-
});
|
|
13317
|
-
if (opts.stealth) {}
|
|
13318
|
-
page = createBunProxy(bunView);
|
|
13319
|
-
}
|
|
13320
|
-
} else if (resolvedEngine === "lightpanda") {
|
|
13321
|
-
browser = await connectLightpanda();
|
|
13322
|
-
const context = await browser.newContext({ viewport: opts.viewport ?? { width: 1280, height: 720 } });
|
|
13323
|
-
page = await context.newPage();
|
|
13324
|
-
} else {
|
|
13325
|
-
browser = await pool.acquire(opts.headless ?? true);
|
|
13326
|
-
if (opts.storageState) {
|
|
13327
|
-
const { loadStatePath: loadStatePath2 } = await Promise.resolve().then(() => (init_storage_state(), exports_storage_state));
|
|
13328
|
-
const statePath2 = loadStatePath2(opts.storageState);
|
|
13329
|
-
if (statePath2) {
|
|
13330
|
-
const context = await browser.newContext({
|
|
13331
|
-
viewport: opts.viewport ?? { width: 1280, height: 720 },
|
|
13332
|
-
userAgent: opts.userAgent,
|
|
13333
|
-
storageState: statePath2
|
|
13334
|
-
});
|
|
13335
|
-
page = await context.newPage();
|
|
13336
|
-
} else {
|
|
13337
|
-
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13338
|
-
}
|
|
13339
|
-
} else {
|
|
13340
|
-
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
13341
|
-
}
|
|
13342
|
-
}
|
|
13343
|
-
const sessionName = opts.name ?? (opts.startUrl ? (() => {
|
|
13344
|
-
try {
|
|
13345
|
-
return new URL(opts.startUrl).hostname;
|
|
13346
|
-
} catch {
|
|
13347
|
-
return;
|
|
13348
|
-
}
|
|
13349
|
-
})() : undefined);
|
|
13350
|
-
const session = createSession({
|
|
13351
|
-
engine: bunView ? "bun" : browser ? resolvedEngine : resolvedEngine,
|
|
13352
|
-
projectId: opts.projectId,
|
|
13353
|
-
agentId: opts.agentId,
|
|
13354
|
-
startUrl: opts.startUrl,
|
|
13355
|
-
name: sessionName
|
|
13356
|
-
});
|
|
13357
|
-
if (opts.stealth && !bunView) {
|
|
13358
|
-
try {
|
|
13359
|
-
await applyStealthPatches(page);
|
|
13360
|
-
} catch {}
|
|
13361
|
-
}
|
|
13362
|
-
const cleanups = [];
|
|
13363
|
-
if (!bunView) {
|
|
13364
|
-
if (opts.captureNetwork !== false) {
|
|
13365
|
-
try {
|
|
13366
|
-
cleanups.push(enableNetworkLogging(page, session.id));
|
|
13367
|
-
} catch {}
|
|
13368
|
-
}
|
|
13369
|
-
if (opts.captureConsole !== false) {
|
|
13370
|
-
try {
|
|
13371
|
-
cleanups.push(enableConsoleCapture(page, session.id));
|
|
13372
|
-
} catch {}
|
|
13373
|
-
}
|
|
13374
|
-
try {
|
|
13375
|
-
cleanups.push(setupDialogHandler(page, session.id));
|
|
13376
|
-
} catch {}
|
|
13377
|
-
} else {
|
|
13378
|
-
if (opts.captureConsole !== false) {
|
|
13379
|
-
try {
|
|
13380
|
-
const { logConsoleMessage: logConsoleMessage2 } = await Promise.resolve().then(() => (init_console_log(), exports_console_log));
|
|
13381
|
-
await bunView.addInitScript(`
|
|
13382
|
-
(() => {
|
|
13383
|
-
const orig = { log: console.log, warn: console.warn, error: console.error, debug: console.debug, info: console.info };
|
|
13384
|
-
['log','warn','error','debug','info'].forEach(level => {
|
|
13385
|
-
console[level] = (...args) => {
|
|
13386
|
-
orig[level](...args);
|
|
13387
|
-
};
|
|
13388
|
-
});
|
|
13389
|
-
})()
|
|
13390
|
-
`);
|
|
13391
|
-
} catch {}
|
|
13392
|
-
}
|
|
13393
|
-
}
|
|
13394
|
-
handles.set(session.id, { browser, bunView, page, engine: bunView ? "bun" : resolvedEngine, cleanups, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
13395
|
-
if (opts.startUrl) {
|
|
13396
|
-
try {
|
|
13397
|
-
if (bunView) {
|
|
13398
|
-
await bunView.goto(opts.startUrl);
|
|
13399
|
-
} else {
|
|
13400
|
-
await page.goto(opts.startUrl, { waitUntil: "domcontentloaded" });
|
|
13401
|
-
}
|
|
13402
|
-
} catch {}
|
|
13403
|
-
}
|
|
13404
|
-
return { session, page };
|
|
13405
|
-
}
|
|
13406
|
-
function getSessionPage(sessionId) {
|
|
13407
|
-
const handle = handles.get(sessionId);
|
|
13408
|
-
if (!handle)
|
|
13409
|
-
throw new SessionNotFoundError(sessionId);
|
|
13410
|
-
try {
|
|
13411
|
-
if (handle.bunView) {
|
|
13412
|
-
handle.bunView.url();
|
|
13413
|
-
} else {
|
|
13414
|
-
handle.page.url();
|
|
13415
|
-
}
|
|
13416
|
-
} catch {
|
|
13417
|
-
handles.delete(sessionId);
|
|
13418
|
-
throw new SessionNotFoundError(sessionId);
|
|
13419
|
-
}
|
|
13420
|
-
handle.lastActivity = Date.now();
|
|
13421
|
-
return handle.page;
|
|
13422
|
-
}
|
|
13423
|
-
function getSessionBunView(sessionId) {
|
|
13424
|
-
return handles.get(sessionId)?.bunView ?? null;
|
|
13425
|
-
}
|
|
13426
|
-
function isBunSession(sessionId) {
|
|
13427
|
-
return handles.get(sessionId)?.engine === "bun";
|
|
13428
|
-
}
|
|
13429
|
-
function getSessionBrowser(sessionId) {
|
|
13430
|
-
const handle = handles.get(sessionId);
|
|
13431
|
-
if (!handle)
|
|
13432
|
-
throw new SessionNotFoundError(sessionId);
|
|
13433
|
-
if (!handle.browser)
|
|
13434
|
-
throw new BrowserError("This session uses Bun.WebView (no Playwright browser)", "NO_PLAYWRIGHT_BROWSER");
|
|
13435
|
-
return handle.browser;
|
|
13436
|
-
}
|
|
13437
|
-
function getSessionEngine(sessionId) {
|
|
13438
|
-
const handle = handles.get(sessionId);
|
|
13439
|
-
if (!handle)
|
|
13440
|
-
throw new SessionNotFoundError(sessionId);
|
|
13441
|
-
return handle.engine;
|
|
13442
|
-
}
|
|
13443
|
-
function hasActiveHandle(sessionId) {
|
|
13444
|
-
return handles.has(sessionId);
|
|
13445
|
-
}
|
|
13446
|
-
function setSessionPage(sessionId, page) {
|
|
13447
|
-
const handle = handles.get(sessionId);
|
|
13448
|
-
if (!handle)
|
|
13449
|
-
throw new SessionNotFoundError(sessionId);
|
|
13450
|
-
handle.page = page;
|
|
13451
|
-
}
|
|
13452
|
-
async function closeSession2(sessionId) {
|
|
13453
|
-
const handle = handles.get(sessionId);
|
|
13454
|
-
if (handle) {
|
|
13455
|
-
for (const cleanup of handle.cleanups) {
|
|
13456
|
-
try {
|
|
13457
|
-
cleanup();
|
|
13458
|
-
} catch {}
|
|
13459
|
-
}
|
|
13460
|
-
if (handle.bunView) {
|
|
13461
|
-
try {
|
|
13462
|
-
await handle.bunView.close();
|
|
13463
|
-
} catch {}
|
|
13464
|
-
} else {
|
|
13465
|
-
try {
|
|
13466
|
-
await handle.page.context().close();
|
|
13467
|
-
} catch {}
|
|
13468
|
-
if (handle.browser)
|
|
13469
|
-
pool.release(handle.browser);
|
|
13470
|
-
}
|
|
13471
|
-
handles.delete(sessionId);
|
|
13472
|
-
}
|
|
13473
|
-
return closeSession(sessionId);
|
|
13474
|
-
}
|
|
13475
|
-
function getSession2(sessionId) {
|
|
13476
|
-
return getSession(sessionId);
|
|
13477
|
-
}
|
|
13478
|
-
function listSessions2(filter) {
|
|
13479
|
-
return listSessions(filter);
|
|
13480
|
-
}
|
|
13481
|
-
function getActiveSessions() {
|
|
13482
|
-
return listSessions({ status: "active" });
|
|
13483
|
-
}
|
|
13484
|
-
async function closeAllSessions() {
|
|
13485
|
-
for (const [id] of handles) {
|
|
13486
|
-
await closeSession2(id).catch(() => {});
|
|
13487
|
-
}
|
|
13488
|
-
await pool.destroyAll();
|
|
13489
|
-
}
|
|
13490
|
-
function getSessionByName2(name) {
|
|
13491
|
-
return getSessionByName(name);
|
|
13492
|
-
}
|
|
13493
|
-
function renameSession2(id, name) {
|
|
13494
|
-
return renameSession(id, name);
|
|
13495
|
-
}
|
|
13496
|
-
function getTokenBudget(sessionId) {
|
|
13497
|
-
const handle = handles.get(sessionId);
|
|
13498
|
-
return handle ? handle.tokenBudget : null;
|
|
13499
|
-
}
|
|
13500
|
-
function getActiveSessionForAgent2(agentId) {
|
|
13501
|
-
const session = getActiveSessionForAgent(agentId);
|
|
13502
|
-
if (!session)
|
|
13503
|
-
return null;
|
|
13504
|
-
const handle = handles.get(session.id);
|
|
13505
|
-
if (!handle)
|
|
13506
|
-
return null;
|
|
13507
|
-
try {
|
|
13508
|
-
if (handle.bunView)
|
|
13509
|
-
handle.bunView.url();
|
|
13510
|
-
else
|
|
13511
|
-
handle.page.url();
|
|
13512
|
-
} catch {
|
|
13513
|
-
handles.delete(session.id);
|
|
13514
|
-
return null;
|
|
13515
|
-
}
|
|
13516
|
-
return { session, page: handle.page };
|
|
13517
|
-
}
|
|
13518
|
-
function getDefaultSession() {
|
|
13519
|
-
const session = getDefaultActiveSession();
|
|
13520
|
-
if (!session)
|
|
13521
|
-
return null;
|
|
13522
|
-
const handle = handles.get(session.id);
|
|
13523
|
-
if (!handle)
|
|
13524
|
-
return null;
|
|
13525
|
-
try {
|
|
13526
|
-
if (handle.bunView)
|
|
13527
|
-
handle.bunView.url();
|
|
13528
|
-
else
|
|
13529
|
-
handle.page.url();
|
|
13530
|
-
} catch {
|
|
13531
|
-
handles.delete(session.id);
|
|
13532
|
-
return null;
|
|
13533
|
-
}
|
|
13534
|
-
return { session, page: handle.page };
|
|
13535
|
-
}
|
|
13536
|
-
function isAutoGallery(sessionId) {
|
|
13537
|
-
return handles.get(sessionId)?.autoGallery ?? false;
|
|
13538
|
-
}
|
|
13539
|
-
function countActiveSessions2() {
|
|
13540
|
-
return countActiveSessions();
|
|
13541
|
-
}
|
|
13542
|
-
var handles, pool, SESSION_TTL_MS, ttlInterval;
|
|
13543
|
-
var init_session = __esm(() => {
|
|
13544
|
-
init_types();
|
|
13545
|
-
init_types();
|
|
13546
|
-
init_sessions();
|
|
13547
|
-
init_playwright();
|
|
13548
|
-
init_lightpanda();
|
|
13549
|
-
init_bun_webview();
|
|
13550
|
-
init_selector();
|
|
13551
|
-
init_network();
|
|
13552
|
-
init_console();
|
|
13553
|
-
init_stealth();
|
|
13554
|
-
init_dialogs();
|
|
13555
|
-
handles = new Map;
|
|
13556
|
-
pool = new BrowserPool(5);
|
|
13557
|
-
SESSION_TTL_MS = parseInt(process.env["SESSION_TTL_MINUTES"] ?? "10", 10) * 60000;
|
|
13558
|
-
ttlInterval = setInterval(async () => {
|
|
13559
|
-
const now = Date.now();
|
|
13560
|
-
for (const [id, handle] of handles) {
|
|
13561
|
-
if (now - handle.lastActivity > SESSION_TTL_MS) {
|
|
13562
|
-
try {
|
|
13563
|
-
await closeSession2(id);
|
|
13564
|
-
} catch {}
|
|
13565
|
-
}
|
|
13566
|
-
}
|
|
13567
|
-
}, 60000);
|
|
13568
|
-
if (ttlInterval.unref)
|
|
13569
|
-
ttlInterval.unref();
|
|
13570
|
-
});
|
|
13571
|
-
|
|
13572
13307
|
// src/lib/snapshot.ts
|
|
13573
13308
|
var exports_snapshot = {};
|
|
13574
13309
|
__export(exports_snapshot, {
|
|
@@ -13919,6 +13654,7 @@ __export(exports_actions, {
|
|
|
13919
13654
|
typeRef: () => typeRef,
|
|
13920
13655
|
type: () => type,
|
|
13921
13656
|
stopWatch: () => stopWatch,
|
|
13657
|
+
stopAllWatchesForSession: () => stopAllWatchesForSession,
|
|
13922
13658
|
selectRef: () => selectRef,
|
|
13923
13659
|
selectOption: () => selectOption,
|
|
13924
13660
|
scrollTo: () => scrollTo,
|
|
@@ -14245,6 +13981,12 @@ function stopWatch(watchId) {
|
|
|
14245
13981
|
activeWatches.delete(watchId);
|
|
14246
13982
|
}
|
|
14247
13983
|
}
|
|
13984
|
+
function stopAllWatchesForSession(_sessionId) {
|
|
13985
|
+
for (const [id, w] of activeWatches) {
|
|
13986
|
+
clearInterval(w.interval);
|
|
13987
|
+
activeWatches.delete(id);
|
|
13988
|
+
}
|
|
13989
|
+
}
|
|
14248
13990
|
async function clickRef(page, sessionId, ref, opts) {
|
|
14249
13991
|
try {
|
|
14250
13992
|
const locator = getRefLocator(page, sessionId, ref);
|
|
@@ -14320,6 +14062,396 @@ var init_actions = __esm(() => {
|
|
|
14320
14062
|
activeWatches = new Map;
|
|
14321
14063
|
});
|
|
14322
14064
|
|
|
14065
|
+
// src/lib/session.ts
|
|
14066
|
+
var exports_session = {};
|
|
14067
|
+
__export(exports_session, {
|
|
14068
|
+
setSessionPage: () => setSessionPage,
|
|
14069
|
+
renameSession: () => renameSession2,
|
|
14070
|
+
listSessions: () => listSessions2,
|
|
14071
|
+
isBunSession: () => isBunSession,
|
|
14072
|
+
isAutoGallery: () => isAutoGallery,
|
|
14073
|
+
hasActiveHandle: () => hasActiveHandle,
|
|
14074
|
+
getTokenBudget: () => getTokenBudget,
|
|
14075
|
+
getSessionPage: () => getSessionPage,
|
|
14076
|
+
getSessionEngine: () => getSessionEngine,
|
|
14077
|
+
getSessionByName: () => getSessionByName2,
|
|
14078
|
+
getSessionBunView: () => getSessionBunView,
|
|
14079
|
+
getSessionBrowser: () => getSessionBrowser,
|
|
14080
|
+
getSession: () => getSession2,
|
|
14081
|
+
getDefaultSession: () => getDefaultSession,
|
|
14082
|
+
getActiveSessions: () => getActiveSessions,
|
|
14083
|
+
getActiveSessionForAgent: () => getActiveSessionForAgent2,
|
|
14084
|
+
createSession: () => createSession2,
|
|
14085
|
+
countActiveSessions: () => countActiveSessions2,
|
|
14086
|
+
closeSession: () => closeSession2,
|
|
14087
|
+
closeAllSessions: () => closeAllSessions,
|
|
14088
|
+
browserPool: () => pool
|
|
14089
|
+
});
|
|
14090
|
+
function createBunProxy(view) {
|
|
14091
|
+
return view;
|
|
14092
|
+
}
|
|
14093
|
+
async function createSession2(opts = {}) {
|
|
14094
|
+
if (opts.cdpUrl) {
|
|
14095
|
+
const { connectToExistingBrowser: connectToExistingBrowser2 } = await Promise.resolve().then(() => (init_cdp(), exports_cdp));
|
|
14096
|
+
const cdpBrowser = await connectToExistingBrowser2(opts.cdpUrl);
|
|
14097
|
+
const contexts = cdpBrowser.contexts();
|
|
14098
|
+
const context = contexts.length > 0 ? contexts[0] : await cdpBrowser.newContext();
|
|
14099
|
+
const pages = context.pages();
|
|
14100
|
+
const page2 = pages.length > 0 ? pages[0] : await context.newPage();
|
|
14101
|
+
const session2 = createSession({
|
|
14102
|
+
engine: "cdp",
|
|
14103
|
+
projectId: opts.projectId,
|
|
14104
|
+
agentId: opts.agentId,
|
|
14105
|
+
startUrl: page2.url(),
|
|
14106
|
+
name: opts.name ?? "attached"
|
|
14107
|
+
});
|
|
14108
|
+
const cleanups2 = [];
|
|
14109
|
+
if (opts.captureNetwork !== false) {
|
|
14110
|
+
try {
|
|
14111
|
+
cleanups2.push(enableNetworkLogging(page2, session2.id));
|
|
14112
|
+
} catch {}
|
|
14113
|
+
}
|
|
14114
|
+
if (opts.captureConsole !== false) {
|
|
14115
|
+
try {
|
|
14116
|
+
cleanups2.push(enableConsoleCapture(page2, session2.id));
|
|
14117
|
+
} catch {}
|
|
14118
|
+
}
|
|
14119
|
+
try {
|
|
14120
|
+
cleanups2.push(setupDialogHandler(page2, session2.id));
|
|
14121
|
+
} catch {}
|
|
14122
|
+
handles.set(session2.id, { browser: cdpBrowser, bunView: null, tuiSession: null, page: page2, engine: "cdp", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
14123
|
+
return { session: session2, page: page2 };
|
|
14124
|
+
}
|
|
14125
|
+
const engine = opts.engine === "auto" || !opts.engine ? selectEngine(opts.useCase ?? "spa_navigate" /* SPA_NAVIGATE */, opts.engine) : opts.engine;
|
|
14126
|
+
const resolvedEngine = engine === "auto" ? "playwright" : engine;
|
|
14127
|
+
let browser = null;
|
|
14128
|
+
let bunView = null;
|
|
14129
|
+
let page;
|
|
14130
|
+
if (resolvedEngine === "bun") {
|
|
14131
|
+
if (!isBunWebViewAvailable()) {
|
|
14132
|
+
console.warn("[browser] Bun.WebView requested but not available \u2014 falling back to playwright. Run: bun upgrade --canary");
|
|
14133
|
+
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
14134
|
+
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
14135
|
+
} else {
|
|
14136
|
+
bunView = new BunWebViewSession({
|
|
14137
|
+
width: opts.viewport?.width ?? 1280,
|
|
14138
|
+
height: opts.viewport?.height ?? 720,
|
|
14139
|
+
profile: opts.name ?? undefined
|
|
14140
|
+
});
|
|
14141
|
+
if (opts.stealth) {}
|
|
14142
|
+
page = createBunProxy(bunView);
|
|
14143
|
+
}
|
|
14144
|
+
} else if (resolvedEngine === "lightpanda") {
|
|
14145
|
+
browser = await connectLightpanda();
|
|
14146
|
+
const context = await browser.newContext({ viewport: opts.viewport ?? { width: 1280, height: 720 } });
|
|
14147
|
+
page = await context.newPage();
|
|
14148
|
+
} else if (resolvedEngine === "tui") {
|
|
14149
|
+
const command = opts.startUrl ?? "bash";
|
|
14150
|
+
const tuiSess = await launchTui(command, {
|
|
14151
|
+
headless: opts.headless ?? true,
|
|
14152
|
+
viewport: opts.viewport
|
|
14153
|
+
});
|
|
14154
|
+
browser = tuiSess.browser;
|
|
14155
|
+
page = tuiSess.page;
|
|
14156
|
+
const session2 = createSession({
|
|
14157
|
+
engine: "tui",
|
|
14158
|
+
projectId: opts.projectId,
|
|
14159
|
+
agentId: opts.agentId,
|
|
14160
|
+
startUrl: opts.startUrl,
|
|
14161
|
+
name: opts.name ?? "tui"
|
|
14162
|
+
});
|
|
14163
|
+
const cleanups2 = [];
|
|
14164
|
+
cleanups2.push(() => closeTui(tuiSess));
|
|
14165
|
+
if (opts.captureNetwork !== false) {
|
|
14166
|
+
try {
|
|
14167
|
+
cleanups2.push(enableNetworkLogging(page, session2.id));
|
|
14168
|
+
} catch {}
|
|
14169
|
+
}
|
|
14170
|
+
if (opts.captureConsole !== false) {
|
|
14171
|
+
try {
|
|
14172
|
+
cleanups2.push(enableConsoleCapture(page, session2.id));
|
|
14173
|
+
} catch {}
|
|
14174
|
+
}
|
|
14175
|
+
try {
|
|
14176
|
+
cleanups2.push(setupDialogHandler(page, session2.id));
|
|
14177
|
+
} catch {}
|
|
14178
|
+
handles.set(session2.id, { browser, bunView: null, tuiSession: tuiSess, page, engine: "tui", cleanups: cleanups2, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
14179
|
+
return { session: session2, page };
|
|
14180
|
+
} else {
|
|
14181
|
+
browser = await pool.acquire(opts.headless ?? true);
|
|
14182
|
+
if (opts.storageState) {
|
|
14183
|
+
const { loadStatePath: loadStatePath2 } = await Promise.resolve().then(() => (init_storage_state(), exports_storage_state));
|
|
14184
|
+
const statePath2 = loadStatePath2(opts.storageState);
|
|
14185
|
+
if (statePath2) {
|
|
14186
|
+
const context = await browser.newContext({
|
|
14187
|
+
viewport: opts.viewport ?? { width: 1280, height: 720 },
|
|
14188
|
+
userAgent: opts.userAgent,
|
|
14189
|
+
storageState: statePath2
|
|
14190
|
+
});
|
|
14191
|
+
page = await context.newPage();
|
|
14192
|
+
} else {
|
|
14193
|
+
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
14194
|
+
}
|
|
14195
|
+
} else {
|
|
14196
|
+
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
14197
|
+
}
|
|
14198
|
+
}
|
|
14199
|
+
const sessionName = opts.name ?? (opts.startUrl ? (() => {
|
|
14200
|
+
try {
|
|
14201
|
+
return new URL(opts.startUrl).hostname;
|
|
14202
|
+
} catch {
|
|
14203
|
+
return;
|
|
14204
|
+
}
|
|
14205
|
+
})() : undefined);
|
|
14206
|
+
const session = createSession({
|
|
14207
|
+
engine: bunView ? "bun" : browser ? resolvedEngine : resolvedEngine,
|
|
14208
|
+
projectId: opts.projectId,
|
|
14209
|
+
agentId: opts.agentId,
|
|
14210
|
+
startUrl: opts.startUrl,
|
|
14211
|
+
name: sessionName
|
|
14212
|
+
});
|
|
14213
|
+
if (opts.stealth && !bunView) {
|
|
14214
|
+
try {
|
|
14215
|
+
await applyStealthPatches(page);
|
|
14216
|
+
} catch {}
|
|
14217
|
+
}
|
|
14218
|
+
const cleanups = [];
|
|
14219
|
+
if (!bunView) {
|
|
14220
|
+
if (opts.captureNetwork !== false) {
|
|
14221
|
+
try {
|
|
14222
|
+
cleanups.push(enableNetworkLogging(page, session.id));
|
|
14223
|
+
} catch {}
|
|
14224
|
+
}
|
|
14225
|
+
if (opts.captureConsole !== false) {
|
|
14226
|
+
try {
|
|
14227
|
+
cleanups.push(enableConsoleCapture(page, session.id));
|
|
14228
|
+
} catch {}
|
|
14229
|
+
}
|
|
14230
|
+
try {
|
|
14231
|
+
cleanups.push(setupDialogHandler(page, session.id));
|
|
14232
|
+
} catch {}
|
|
14233
|
+
} else {
|
|
14234
|
+
if (opts.captureConsole !== false) {
|
|
14235
|
+
try {
|
|
14236
|
+
const { logConsoleMessage: logConsoleMessage2 } = await Promise.resolve().then(() => (init_console_log(), exports_console_log));
|
|
14237
|
+
await bunView.addInitScript(`
|
|
14238
|
+
(() => {
|
|
14239
|
+
const orig = { log: console.log, warn: console.warn, error: console.error, debug: console.debug, info: console.info };
|
|
14240
|
+
['log','warn','error','debug','info'].forEach(level => {
|
|
14241
|
+
console[level] = (...args) => {
|
|
14242
|
+
orig[level](...args);
|
|
14243
|
+
};
|
|
14244
|
+
});
|
|
14245
|
+
})()
|
|
14246
|
+
`);
|
|
14247
|
+
} catch {}
|
|
14248
|
+
}
|
|
14249
|
+
}
|
|
14250
|
+
handles.set(session.id, { browser, bunView, tuiSession: null, page, engine: bunView ? "bun" : resolvedEngine, cleanups, tokenBudget: { total: 0, used: 0 }, lastActivity: Date.now(), autoGallery: opts.autoGallery ?? false });
|
|
14251
|
+
if (opts.startUrl) {
|
|
14252
|
+
try {
|
|
14253
|
+
if (bunView) {
|
|
14254
|
+
await bunView.goto(opts.startUrl);
|
|
14255
|
+
} else {
|
|
14256
|
+
await page.goto(opts.startUrl, { waitUntil: "domcontentloaded" });
|
|
14257
|
+
}
|
|
14258
|
+
} catch {}
|
|
14259
|
+
}
|
|
14260
|
+
return { session, page };
|
|
14261
|
+
}
|
|
14262
|
+
function getSessionPage(sessionId) {
|
|
14263
|
+
const handle = handles.get(sessionId);
|
|
14264
|
+
if (!handle)
|
|
14265
|
+
throw new SessionNotFoundError(sessionId);
|
|
14266
|
+
try {
|
|
14267
|
+
if (handle.bunView) {
|
|
14268
|
+
handle.bunView.url();
|
|
14269
|
+
} else {
|
|
14270
|
+
handle.page.url();
|
|
14271
|
+
}
|
|
14272
|
+
} catch {
|
|
14273
|
+
handles.delete(sessionId);
|
|
14274
|
+
throw new SessionNotFoundError(sessionId);
|
|
14275
|
+
}
|
|
14276
|
+
handle.lastActivity = Date.now();
|
|
14277
|
+
return handle.page;
|
|
14278
|
+
}
|
|
14279
|
+
function getSessionBunView(sessionId) {
|
|
14280
|
+
return handles.get(sessionId)?.bunView ?? null;
|
|
14281
|
+
}
|
|
14282
|
+
function isBunSession(sessionId) {
|
|
14283
|
+
return handles.get(sessionId)?.engine === "bun";
|
|
14284
|
+
}
|
|
14285
|
+
function getSessionBrowser(sessionId) {
|
|
14286
|
+
const handle = handles.get(sessionId);
|
|
14287
|
+
if (!handle)
|
|
14288
|
+
throw new SessionNotFoundError(sessionId);
|
|
14289
|
+
if (!handle.browser)
|
|
14290
|
+
throw new BrowserError("This session uses Bun.WebView (no Playwright browser)", "NO_PLAYWRIGHT_BROWSER");
|
|
14291
|
+
return handle.browser;
|
|
14292
|
+
}
|
|
14293
|
+
function getSessionEngine(sessionId) {
|
|
14294
|
+
const handle = handles.get(sessionId);
|
|
14295
|
+
if (!handle)
|
|
14296
|
+
throw new SessionNotFoundError(sessionId);
|
|
14297
|
+
return handle.engine;
|
|
14298
|
+
}
|
|
14299
|
+
function hasActiveHandle(sessionId) {
|
|
14300
|
+
return handles.has(sessionId);
|
|
14301
|
+
}
|
|
14302
|
+
function setSessionPage(sessionId, page) {
|
|
14303
|
+
const handle = handles.get(sessionId);
|
|
14304
|
+
if (!handle)
|
|
14305
|
+
throw new SessionNotFoundError(sessionId);
|
|
14306
|
+
handle.page = page;
|
|
14307
|
+
}
|
|
14308
|
+
async function closeSession2(sessionId) {
|
|
14309
|
+
const handle = handles.get(sessionId);
|
|
14310
|
+
if (handle) {
|
|
14311
|
+
for (const cleanup of handle.cleanups) {
|
|
14312
|
+
try {
|
|
14313
|
+
cleanup();
|
|
14314
|
+
} catch {}
|
|
14315
|
+
}
|
|
14316
|
+
if (handle.bunView) {
|
|
14317
|
+
try {
|
|
14318
|
+
await handle.bunView.close();
|
|
14319
|
+
} catch {}
|
|
14320
|
+
} else if (handle.tuiSession) {} else {
|
|
14321
|
+
try {
|
|
14322
|
+
await handle.page.context().close();
|
|
14323
|
+
} catch {}
|
|
14324
|
+
if (handle.browser)
|
|
14325
|
+
pool.release(handle.browser);
|
|
14326
|
+
}
|
|
14327
|
+
handles.delete(sessionId);
|
|
14328
|
+
}
|
|
14329
|
+
try {
|
|
14330
|
+
const { clearLastSnapshot: clearLastSnapshot2, clearSessionRefs: clearSessionRefs2 } = await Promise.resolve().then(() => (init_snapshot(), exports_snapshot));
|
|
14331
|
+
clearLastSnapshot2(sessionId);
|
|
14332
|
+
clearSessionRefs2(sessionId);
|
|
14333
|
+
} catch {}
|
|
14334
|
+
try {
|
|
14335
|
+
const { stopAllWatchesForSession: stopAllWatchesForSession2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
14336
|
+
stopAllWatchesForSession2(sessionId);
|
|
14337
|
+
} catch {}
|
|
14338
|
+
try {
|
|
14339
|
+
const { clearDialogs: clearDialogs2 } = await Promise.resolve().then(() => (init_dialogs(), exports_dialogs));
|
|
14340
|
+
clearDialogs2(sessionId);
|
|
14341
|
+
} catch {}
|
|
14342
|
+
return closeSession(sessionId);
|
|
14343
|
+
}
|
|
14344
|
+
function getSession2(sessionId) {
|
|
14345
|
+
return getSession(sessionId);
|
|
14346
|
+
}
|
|
14347
|
+
function listSessions2(filter) {
|
|
14348
|
+
return listSessions(filter);
|
|
14349
|
+
}
|
|
14350
|
+
function getActiveSessions() {
|
|
14351
|
+
return listSessions({ status: "active" });
|
|
14352
|
+
}
|
|
14353
|
+
async function closeAllSessions() {
|
|
14354
|
+
for (const [id] of handles) {
|
|
14355
|
+
await closeSession2(id).catch(() => {});
|
|
14356
|
+
}
|
|
14357
|
+
await pool.destroyAll();
|
|
14358
|
+
}
|
|
14359
|
+
function getSessionByName2(name) {
|
|
14360
|
+
return getSessionByName(name);
|
|
14361
|
+
}
|
|
14362
|
+
function renameSession2(id, name) {
|
|
14363
|
+
return renameSession(id, name);
|
|
14364
|
+
}
|
|
14365
|
+
function getTokenBudget(sessionId) {
|
|
14366
|
+
const handle = handles.get(sessionId);
|
|
14367
|
+
return handle ? handle.tokenBudget : null;
|
|
14368
|
+
}
|
|
14369
|
+
function getActiveSessionForAgent2(agentId) {
|
|
14370
|
+
const session = getActiveSessionForAgent(agentId);
|
|
14371
|
+
if (!session)
|
|
14372
|
+
return null;
|
|
14373
|
+
const handle = handles.get(session.id);
|
|
14374
|
+
if (!handle)
|
|
14375
|
+
return null;
|
|
14376
|
+
try {
|
|
14377
|
+
if (handle.bunView)
|
|
14378
|
+
handle.bunView.url();
|
|
14379
|
+
else
|
|
14380
|
+
handle.page.url();
|
|
14381
|
+
} catch {
|
|
14382
|
+
handles.delete(session.id);
|
|
14383
|
+
return null;
|
|
14384
|
+
}
|
|
14385
|
+
return { session, page: handle.page };
|
|
14386
|
+
}
|
|
14387
|
+
function getDefaultSession() {
|
|
14388
|
+
const session = getDefaultActiveSession();
|
|
14389
|
+
if (!session)
|
|
14390
|
+
return null;
|
|
14391
|
+
const handle = handles.get(session.id);
|
|
14392
|
+
if (!handle)
|
|
14393
|
+
return null;
|
|
14394
|
+
try {
|
|
14395
|
+
if (handle.bunView)
|
|
14396
|
+
handle.bunView.url();
|
|
14397
|
+
else
|
|
14398
|
+
handle.page.url();
|
|
14399
|
+
} catch {
|
|
14400
|
+
handles.delete(session.id);
|
|
14401
|
+
return null;
|
|
14402
|
+
}
|
|
14403
|
+
return { session, page: handle.page };
|
|
14404
|
+
}
|
|
14405
|
+
function isAutoGallery(sessionId) {
|
|
14406
|
+
return handles.get(sessionId)?.autoGallery ?? false;
|
|
14407
|
+
}
|
|
14408
|
+
function countActiveSessions2() {
|
|
14409
|
+
return countActiveSessions();
|
|
14410
|
+
}
|
|
14411
|
+
var handles, pool, SESSION_TTL_MS, ttlInterval, DB_PRUNE_INTERVAL_MS, DB_RETENTION_HOURS = 24, dbPruneInterval;
|
|
14412
|
+
var init_session = __esm(() => {
|
|
14413
|
+
init_types();
|
|
14414
|
+
init_types();
|
|
14415
|
+
init_sessions();
|
|
14416
|
+
init_playwright();
|
|
14417
|
+
init_lightpanda();
|
|
14418
|
+
init_bun_webview();
|
|
14419
|
+
init_selector();
|
|
14420
|
+
init_tui();
|
|
14421
|
+
init_network();
|
|
14422
|
+
init_console();
|
|
14423
|
+
init_stealth();
|
|
14424
|
+
init_dialogs();
|
|
14425
|
+
handles = new Map;
|
|
14426
|
+
pool = new BrowserPool(5);
|
|
14427
|
+
SESSION_TTL_MS = parseInt(process.env["SESSION_TTL_MINUTES"] ?? "10", 10) * 60000;
|
|
14428
|
+
ttlInterval = setInterval(async () => {
|
|
14429
|
+
const now = Date.now();
|
|
14430
|
+
for (const [id, handle] of handles) {
|
|
14431
|
+
if (now - handle.lastActivity > SESSION_TTL_MS) {
|
|
14432
|
+
try {
|
|
14433
|
+
await closeSession2(id);
|
|
14434
|
+
} catch {}
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
}, 60000);
|
|
14438
|
+
if (ttlInterval.unref)
|
|
14439
|
+
ttlInterval.unref();
|
|
14440
|
+
DB_PRUNE_INTERVAL_MS = 30 * 60000;
|
|
14441
|
+
dbPruneInterval = setInterval(() => {
|
|
14442
|
+
try {
|
|
14443
|
+
const { getDatabase: getDatabase2 } = (init_schema(), __toCommonJS(exports_schema));
|
|
14444
|
+
const db = getDatabase2();
|
|
14445
|
+
const cutoff = new Date(Date.now() - DB_RETENTION_HOURS * 3600000).toISOString();
|
|
14446
|
+
db.prepare("DELETE FROM network_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
14447
|
+
db.prepare("DELETE FROM console_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
14448
|
+
db.prepare("DELETE FROM snapshots WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
14449
|
+
} catch {}
|
|
14450
|
+
}, DB_PRUNE_INTERVAL_MS);
|
|
14451
|
+
if (dbPruneInterval.unref)
|
|
14452
|
+
dbPruneInterval.unref();
|
|
14453
|
+
});
|
|
14454
|
+
|
|
14323
14455
|
// src/lib/extractor.ts
|
|
14324
14456
|
var exports_extractor = {};
|
|
14325
14457
|
__export(exports_extractor, {
|
|
@@ -27446,7 +27578,7 @@ var init_helpers = __esm(() => {
|
|
|
27446
27578
|
// src/mcp/sessions.ts
|
|
27447
27579
|
function register4(server) {
|
|
27448
27580
|
server.tool("browser_session_create", "Create a new browser session. If agent_id is set and already has an active session, returns the existing one (use force_new to override). If session_id is omitted on other tools, the single active session is auto-selected. Use cdp_url to attach to an already-running Chrome instance.", {
|
|
27449
|
-
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "auto"]).optional().default("auto"),
|
|
27581
|
+
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "tui", "auto"]).optional().default("auto"),
|
|
27450
27582
|
use_case: exports_external2.string().optional(),
|
|
27451
27583
|
project_id: exports_external2.string().optional(),
|
|
27452
27584
|
agent_id: exports_external2.string().optional(),
|
|
@@ -32183,7 +32315,7 @@ function register8(server) {
|
|
|
32183
32315
|
max_pages: exports_external2.number().optional().default(50),
|
|
32184
32316
|
same_domain: exports_external2.boolean().optional().default(true),
|
|
32185
32317
|
project_id: exports_external2.string().optional(),
|
|
32186
|
-
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "auto"]).optional().default("auto")
|
|
32318
|
+
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "tui", "auto"]).optional().default("auto")
|
|
32187
32319
|
}, async ({ url, max_depth, max_pages, same_domain, project_id, engine }) => {
|
|
32188
32320
|
try {
|
|
32189
32321
|
const result = await crawl(url, {
|
|
@@ -32351,7 +32483,7 @@ function register9(server) {
|
|
|
32351
32483
|
server.tool("browser_script_run", "Run a saved script asynchronously. Returns run_id immediately \u2014 poll with browser_script_status for step-by-step progress. Scripts combine browser actions + connector calls + AI reasoning. Works with any engine (Bun.WebView, Playwright, CDP).", {
|
|
32352
32484
|
name: exports_external2.string().describe("Script name"),
|
|
32353
32485
|
session_id: exports_external2.string().optional(),
|
|
32354
|
-
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "auto"]).optional().default("auto"),
|
|
32486
|
+
engine: exports_external2.enum(["playwright", "cdp", "lightpanda", "bun", "tui", "auto"]).optional().default("auto"),
|
|
32355
32487
|
variables: exports_external2.record(exports_external2.string()).optional().describe("Override script variables")
|
|
32356
32488
|
}, async ({ name, session_id, engine, variables }) => {
|
|
32357
32489
|
try {
|
|
@@ -32606,8 +32738,8 @@ import { join as join33 } from "path";
|
|
|
32606
32738
|
import { existsSync as existsSync43, mkdirSync as mkdirSync4, readFileSync as readFileSync33, writeFileSync as writeFileSync33 } from "fs";
|
|
32607
32739
|
import { homedir as homedir33 } from "os";
|
|
32608
32740
|
import { join as join43 } from "path";
|
|
32609
|
-
function
|
|
32610
|
-
this[name] =
|
|
32741
|
+
function __exportSetter2(name, newValue) {
|
|
32742
|
+
this[name] = __returnValue2.bind(null, newValue);
|
|
32611
32743
|
}
|
|
32612
32744
|
function isInMemoryDb(path) {
|
|
32613
32745
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
@@ -35721,13 +35853,13 @@ function clearActiveModel() {
|
|
|
35721
35853
|
delete config.activeModel;
|
|
35722
35854
|
writeConfig(config);
|
|
35723
35855
|
}
|
|
35724
|
-
var __defProp3,
|
|
35856
|
+
var __defProp3, __returnValue2 = (v) => v, __export3 = (target, all) => {
|
|
35725
35857
|
for (var name in all)
|
|
35726
35858
|
__defProp3(target, name, {
|
|
35727
35859
|
get: all[name],
|
|
35728
35860
|
enumerable: true,
|
|
35729
35861
|
configurable: true,
|
|
35730
|
-
set:
|
|
35862
|
+
set: __exportSetter2.bind(all, name)
|
|
35731
35863
|
});
|
|
35732
35864
|
}, __esm3 = (fn, res) => () => (fn && (res = fn(fn = 0)), res), exports_database, MIGRATIONS, _db2 = null, init_database, AgentConflictError, EntityNotFoundError, MemoryNotFoundError, DuplicateMemoryError, MemoryExpiredError, InvalidScopeError, VersionConflictError, MemoryConflictError, OPENAI_EMBED_URL = "https://api.openai.com/v1/embeddings", EMBED_MODEL = "text-embedding-3-small", EMBED_DIMENSIONS = 1536, REDACTED = "[REDACTED]", SECRET_PATTERNS, _idCounter = 0, hookRegistry, INSTRUCTION_PATTERNS, PROMOTIONAL_PATTERNS, RECALL_PROMOTE_THRESHOLD = 3, CONFLICT_WINDOW_MS, MEMORY_WRITE_TTL = 30, MemoryLockConflictError, sessionFocus, STOP_WORDS, DEFAULT_CONFIG, VALID_SCOPES, VALID_CATEGORIES, defaultSyncAgents, DEFAULT_AUTO_MEMORY_CONFIG, MEMORY_EXTRACTION_SYSTEM_PROMPT = `You are a precise memory extraction engine for an AI agent.
|
|
35733
35865
|
Given text, extract facts worth remembering as structured JSON.
|
|
@@ -37108,6 +37240,11 @@ async function rememberPage(url, facts, tags) {
|
|
|
37108
37240
|
return;
|
|
37109
37241
|
} catch {}
|
|
37110
37242
|
}
|
|
37243
|
+
if (inMemoryCache.size >= MEMORY_MAX_SIZE && !inMemoryCache.has(key)) {
|
|
37244
|
+
const firstKey = inMemoryCache.keys().next().value;
|
|
37245
|
+
if (firstKey)
|
|
37246
|
+
inMemoryCache.delete(firstKey);
|
|
37247
|
+
}
|
|
37111
37248
|
inMemoryCache.set(key, {
|
|
37112
37249
|
data: memory,
|
|
37113
37250
|
expires: Date.now() + DEFAULT_TTL_HOURS * 60 * 60 * 1000
|
|
@@ -37137,9 +37274,18 @@ async function forgetPage(url) {
|
|
|
37137
37274
|
const key = cacheKey(url);
|
|
37138
37275
|
inMemoryCache.delete(key);
|
|
37139
37276
|
}
|
|
37140
|
-
var MEMORY_KEY_PREFIX = "browser-page:", DEFAULT_TTL_HOURS = 24, inMemoryCache;
|
|
37277
|
+
var MEMORY_KEY_PREFIX = "browser-page:", DEFAULT_TTL_HOURS = 24, inMemoryCache, MEMORY_MAX_SIZE = 200, _memorySweeper;
|
|
37141
37278
|
var init_page_memory = __esm(() => {
|
|
37142
37279
|
inMemoryCache = new Map;
|
|
37280
|
+
_memorySweeper = setInterval(() => {
|
|
37281
|
+
const now2 = Date.now();
|
|
37282
|
+
for (const [key, entry] of inMemoryCache) {
|
|
37283
|
+
if (entry.expires <= now2)
|
|
37284
|
+
inMemoryCache.delete(key);
|
|
37285
|
+
}
|
|
37286
|
+
}, 300000);
|
|
37287
|
+
if (_memorySweeper.unref)
|
|
37288
|
+
_memorySweeper.unref();
|
|
37143
37289
|
});
|
|
37144
37290
|
|
|
37145
37291
|
// node_modules/@hasna/conversations/dist/index.js
|
|
@@ -37236,11 +37382,11 @@ import { randomUUID as randomUUID22 } from "crypto";
|
|
|
37236
37382
|
import { readFileSync as readFileSync24, writeFileSync as writeFileSync7, mkdirSync as mkdirSync34 } from "fs";
|
|
37237
37383
|
import { join as join44, dirname as dirname24 } from "path";
|
|
37238
37384
|
import { homedir as homedir42 } from "os";
|
|
37239
|
-
function
|
|
37385
|
+
function __accessProp2(key) {
|
|
37240
37386
|
return this[key];
|
|
37241
37387
|
}
|
|
37242
|
-
function
|
|
37243
|
-
this[name] =
|
|
37388
|
+
function __exportSetter3(name, newValue) {
|
|
37389
|
+
this[name] = __returnValue3.bind(null, newValue);
|
|
37244
37390
|
}
|
|
37245
37391
|
function getDbPath3() {
|
|
37246
37392
|
if (process.env.CONVERSATIONS_DB_PATH)
|
|
@@ -39225,10 +39371,10 @@ function getGraphStats() {
|
|
|
39225
39371
|
map[r.relation] = r.c;
|
|
39226
39372
|
return { total_edges: total, by_relation: map };
|
|
39227
39373
|
}
|
|
39228
|
-
var __create3, __getProtoOf3, __defProp4, __getOwnPropNames3, __getOwnPropDesc2, __hasOwnProp3,
|
|
39374
|
+
var __create3, __getProtoOf3, __defProp4, __getOwnPropNames3, __getOwnPropDesc2, __hasOwnProp3, __toESMCache_node2, __toESMCache_esm2, __toESM3 = (mod, isNodeMode, target) => {
|
|
39229
39375
|
var canCache = mod != null && typeof mod === "object";
|
|
39230
39376
|
if (canCache) {
|
|
39231
|
-
var cache = isNodeMode ?
|
|
39377
|
+
var cache = isNodeMode ? __toESMCache_node2 ??= new WeakMap : __toESMCache_esm2 ??= new WeakMap;
|
|
39232
39378
|
var cached = cache.get(mod);
|
|
39233
39379
|
if (cached)
|
|
39234
39380
|
return cached;
|
|
@@ -39238,7 +39384,7 @@ var __create3, __getProtoOf3, __defProp4, __getOwnPropNames3, __getOwnPropDesc2,
|
|
|
39238
39384
|
for (let key of __getOwnPropNames3(mod))
|
|
39239
39385
|
if (!__hasOwnProp3.call(to, key))
|
|
39240
39386
|
__defProp4(to, key, {
|
|
39241
|
-
get:
|
|
39387
|
+
get: __accessProp2.bind(mod, key),
|
|
39242
39388
|
enumerable: true
|
|
39243
39389
|
});
|
|
39244
39390
|
if (canCache)
|
|
@@ -39253,19 +39399,19 @@ var __create3, __getProtoOf3, __defProp4, __getOwnPropNames3, __getOwnPropDesc2,
|
|
|
39253
39399
|
for (var key of __getOwnPropNames3(from))
|
|
39254
39400
|
if (!__hasOwnProp3.call(entry, key))
|
|
39255
39401
|
__defProp4(entry, key, {
|
|
39256
|
-
get:
|
|
39402
|
+
get: __accessProp2.bind(from, key),
|
|
39257
39403
|
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
39258
39404
|
});
|
|
39259
39405
|
}
|
|
39260
39406
|
__moduleCache2.set(from, entry);
|
|
39261
39407
|
return entry;
|
|
39262
|
-
}, __moduleCache2, __commonJS3 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports),
|
|
39408
|
+
}, __moduleCache2, __commonJS3 = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports), __returnValue3 = (v) => v, __export4 = (target, all) => {
|
|
39263
39409
|
for (var name in all)
|
|
39264
39410
|
__defProp4(target, name, {
|
|
39265
39411
|
get: all[name],
|
|
39266
39412
|
enumerable: true,
|
|
39267
39413
|
configurable: true,
|
|
39268
|
-
set:
|
|
39414
|
+
set: __exportSetter3.bind(all, name)
|
|
39269
39415
|
});
|
|
39270
39416
|
}, exports_db, db = null, init_db = () => {}, require_react_development, require_react, cachedConfig = null, configLoadedAt = 0, CONFIG_CACHE_MS = 1e4, import_react, AGENT_NAMES, AGENT_ID_FILE, cachedAutoName = null, ONLINE_THRESHOLD_SECONDS = 60, CONFLICT_THRESHOLD_SECONDS, DEFAULT_LOCK_EXPIRY_MS, STALE_HEARTBEAT_SECONDS, STOPWORDS;
|
|
39271
39417
|
var init_dist4 = __esm(() => {
|
|
@@ -41603,6 +41749,11 @@ async function announceNavigation(url, sessionId, agentName = "browser-agent") {
|
|
|
41603
41749
|
await sdk.sendMessage(SPACE_NAME, `\uD83C\uDF10 Navigating to ${hostname} (session: ${sessionId.slice(0, 8)})`);
|
|
41604
41750
|
} catch {}
|
|
41605
41751
|
}
|
|
41752
|
+
if (activeNavigations.size >= NAV_MAX_SIZE && !activeNavigations.has(hostname)) {
|
|
41753
|
+
const firstKey = activeNavigations.keys().next().value;
|
|
41754
|
+
if (firstKey)
|
|
41755
|
+
activeNavigations.delete(firstKey);
|
|
41756
|
+
}
|
|
41606
41757
|
activeNavigations.set(hostname, { agentName, timestamp: Date.now() });
|
|
41607
41758
|
}
|
|
41608
41759
|
async function checkDuplicate2(url) {
|
|
@@ -41638,10 +41789,19 @@ async function checkDuplicate2(url) {
|
|
|
41638
41789
|
}
|
|
41639
41790
|
return { is_duplicate: false };
|
|
41640
41791
|
}
|
|
41641
|
-
var SPACE_NAME = "browser", DUPLICATE_WINDOW_MS, activeNavigations;
|
|
41792
|
+
var SPACE_NAME = "browser", DUPLICATE_WINDOW_MS, activeNavigations, NAV_MAX_SIZE = 200, _navSweeper;
|
|
41642
41793
|
var init_coordination = __esm(() => {
|
|
41643
41794
|
DUPLICATE_WINDOW_MS = 5 * 60 * 1000;
|
|
41644
41795
|
activeNavigations = new Map;
|
|
41796
|
+
_navSweeper = setInterval(() => {
|
|
41797
|
+
const cutoff = Date.now() - DUPLICATE_WINDOW_MS;
|
|
41798
|
+
for (const [key, entry] of activeNavigations) {
|
|
41799
|
+
if (entry.timestamp < cutoff)
|
|
41800
|
+
activeNavigations.delete(key);
|
|
41801
|
+
}
|
|
41802
|
+
}, 120000);
|
|
41803
|
+
if (_navSweeper.unref)
|
|
41804
|
+
_navSweeper.unref();
|
|
41645
41805
|
});
|
|
41646
41806
|
|
|
41647
41807
|
// node_modules/@hasna/todos/dist/index.js
|
|
@@ -41865,7 +42025,7 @@ import { existsSync as existsSync62 } from "fs";
|
|
|
41865
42025
|
import { join as join62 } from "path";
|
|
41866
42026
|
import { readFileSync as readFileSync43, statSync as statSync22 } from "fs";
|
|
41867
42027
|
import { relative as relative2, resolve as resolve23, join as join72 } from "path";
|
|
41868
|
-
import { execSync as
|
|
42028
|
+
import { execSync as execSync3 } from "child_process";
|
|
41869
42029
|
|
|
41870
42030
|
class TodosClient {
|
|
41871
42031
|
baseUrl;
|
|
@@ -46213,7 +46373,7 @@ function parseGitHubUrl(url) {
|
|
|
46213
46373
|
return { owner: match[1], repo: match[2], number: parseInt(match[3], 10) };
|
|
46214
46374
|
}
|
|
46215
46375
|
function fetchGitHubIssue(owner, repo, number) {
|
|
46216
|
-
const json2 =
|
|
46376
|
+
const json2 = execSync3(`gh api repos/${owner}/${repo}/issues/${number}`, { encoding: "utf-8", timeout: 15000 });
|
|
46217
46377
|
const data = JSON.parse(json2);
|
|
46218
46378
|
return {
|
|
46219
46379
|
number: data.number,
|
|
@@ -47244,6 +47404,8 @@ Skill: ${task.skill}` : ""}`,
|
|
|
47244
47404
|
};
|
|
47245
47405
|
} catch {}
|
|
47246
47406
|
}
|
|
47407
|
+
if (inMemoryQueue.length >= QUEUE_MAX_SIZE)
|
|
47408
|
+
inMemoryQueue.shift();
|
|
47247
47409
|
const id = `btask-${Date.now()}`;
|
|
47248
47410
|
const entry = { ...task, id, status: "pending", created_at: new Date().toISOString() };
|
|
47249
47411
|
inMemoryQueue.push(entry);
|
|
@@ -47277,7 +47439,7 @@ async function completeBrowserTask(taskId, result) {
|
|
|
47277
47439
|
if (idx >= 0)
|
|
47278
47440
|
inMemoryQueue.splice(idx, 1);
|
|
47279
47441
|
}
|
|
47280
|
-
var inMemoryQueue;
|
|
47442
|
+
var QUEUE_MAX_SIZE = 100, inMemoryQueue;
|
|
47281
47443
|
var init_task_queue = __esm(() => {
|
|
47282
47444
|
inMemoryQueue = [];
|
|
47283
47445
|
});
|
|
@@ -49441,9 +49603,9 @@ ${entries.length} entries`));
|
|
|
49441
49603
|
});
|
|
49442
49604
|
program2.command("install-browser").description("Install a browser engine").option("--engine <engine>", "Engine to install: lightpanda|chromium", "chromium").action(async (opts) => {
|
|
49443
49605
|
if (opts.engine === "chromium") {
|
|
49444
|
-
const { execSync:
|
|
49606
|
+
const { execSync: execSync4 } = await import("child_process");
|
|
49445
49607
|
console.log(chalk4.gray("Installing Chromium via Playwright..."));
|
|
49446
|
-
|
|
49608
|
+
execSync4("bunx playwright install chromium", { stdio: "inherit" });
|
|
49447
49609
|
console.log(chalk4.green("\u2713 Chromium installed"));
|
|
49448
49610
|
} else if (opts.engine === "lightpanda") {
|
|
49449
49611
|
console.log(chalk4.yellow("Lightpanda must be installed manually."));
|
|
@@ -49463,12 +49625,12 @@ ${entries.length} entries`));
|
|
|
49463
49625
|
console.log(chalk4.gray(` PID: ${status.pid}, Port: ${status.port}, Sessions: ${status.sessions ?? "?"}`));
|
|
49464
49626
|
return;
|
|
49465
49627
|
}
|
|
49466
|
-
const { spawn:
|
|
49628
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
49467
49629
|
const { writeFileSync: writeFileSync9, mkdirSync: mkdirSync17 } = await import("fs");
|
|
49468
49630
|
const { dirname: dirname6 } = await import("path");
|
|
49469
49631
|
const pidFile = getDaemonPidFile2();
|
|
49470
49632
|
mkdirSync17(dirname6(pidFile), { recursive: true });
|
|
49471
|
-
const child =
|
|
49633
|
+
const child = spawn3(process.execPath, [import.meta.dir + "/../../server/index.js"], {
|
|
49472
49634
|
detached: true,
|
|
49473
49635
|
stdio: "ignore",
|
|
49474
49636
|
env: { ...process.env, BROWSER_SERVER_PORT: opts.port }
|