@hasna/browser 0.4.5 → 0.4.7
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/LICENSE +1 -1
- package/README.md +14 -1
- package/dist/cli/commands/tools.d.ts.map +1 -1
- package/dist/cli/index.js +1262 -773
- package/dist/db/gallery.d.ts.map +1 -1
- package/dist/engines/tui.d.ts +62 -22
- package/dist/engines/tui.d.ts.map +1 -1
- package/dist/index.js +345 -100
- package/dist/lib/actions.d.ts +2 -1
- package/dist/lib/actions.d.ts.map +1 -1
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/session.d.ts +4 -0
- package/dist/lib/session.d.ts.map +1 -1
- package/dist/lib/stealth.d.ts.map +1 -1
- package/dist/mcp/actions.d.ts.map +1 -1
- package/dist/mcp/agents.d.ts +3 -0
- package/dist/mcp/agents.d.ts.map +1 -0
- package/dist/mcp/gallery.d.ts +3 -0
- package/dist/mcp/gallery.d.ts.map +1 -0
- package/dist/mcp/index.js +914 -526
- package/dist/mcp/integration.d.ts +3 -0
- package/dist/mcp/integration.d.ts.map +1 -0
- package/dist/mcp/meta-regression.test.d.ts +2 -0
- package/dist/mcp/meta-regression.test.d.ts.map +1 -0
- package/dist/mcp/meta.d.ts.map +1 -1
- package/dist/mcp/sessions.d.ts.map +1 -1
- package/dist/mcp/tui.d.ts.map +1 -1
- package/dist/server/index.js +460 -145
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,6 @@ var __create = Object.create;
|
|
|
3
3
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
7
|
function __accessProp(key) {
|
|
9
8
|
return this[key];
|
|
@@ -30,23 +29,6 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
30
29
|
cache.set(mod, to);
|
|
31
30
|
return to;
|
|
32
31
|
};
|
|
33
|
-
var __toCommonJS = (from) => {
|
|
34
|
-
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
35
|
-
if (entry)
|
|
36
|
-
return entry;
|
|
37
|
-
entry = __defProp({}, "__esModule", { value: true });
|
|
38
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
39
|
-
for (var key of __getOwnPropNames(from))
|
|
40
|
-
if (!__hasOwnProp.call(entry, key))
|
|
41
|
-
__defProp(entry, key, {
|
|
42
|
-
get: __accessProp.bind(from, key),
|
|
43
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
__moduleCache.set(from, entry);
|
|
47
|
-
return entry;
|
|
48
|
-
};
|
|
49
|
-
var __moduleCache;
|
|
50
32
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
51
33
|
var __returnValue = (v) => v;
|
|
52
34
|
function __exportSetter(name, newValue) {
|
|
@@ -10851,6 +10833,7 @@ function watchPage(page, opts) {
|
|
|
10851
10833
|
const changes = [];
|
|
10852
10834
|
const intervalMs = opts?.intervalMs ?? 500;
|
|
10853
10835
|
const maxChanges = opts?.maxChanges ?? 50;
|
|
10836
|
+
const sessionId = opts?.sessionId;
|
|
10854
10837
|
const interval = setInterval(async () => {
|
|
10855
10838
|
if (changes.length >= maxChanges)
|
|
10856
10839
|
return;
|
|
@@ -10864,7 +10847,7 @@ function watchPage(page, opts) {
|
|
|
10864
10847
|
}
|
|
10865
10848
|
} catch {}
|
|
10866
10849
|
}, intervalMs);
|
|
10867
|
-
activeWatches.set(id, { interval, changes });
|
|
10850
|
+
activeWatches.set(id, { interval, changes, sessionId });
|
|
10868
10851
|
return {
|
|
10869
10852
|
id,
|
|
10870
10853
|
stop: () => {
|
|
@@ -10883,10 +10866,12 @@ function stopWatch(watchId) {
|
|
|
10883
10866
|
activeWatches.delete(watchId);
|
|
10884
10867
|
}
|
|
10885
10868
|
}
|
|
10886
|
-
function stopAllWatchesForSession(
|
|
10887
|
-
for (const [id, w] of activeWatches) {
|
|
10888
|
-
|
|
10889
|
-
|
|
10869
|
+
function stopAllWatchesForSession(sessionId) {
|
|
10870
|
+
for (const [id, w] of [...activeWatches]) {
|
|
10871
|
+
if (!sessionId || w.sessionId === sessionId) {
|
|
10872
|
+
clearInterval(w.interval);
|
|
10873
|
+
activeWatches.delete(id);
|
|
10874
|
+
}
|
|
10890
10875
|
}
|
|
10891
10876
|
}
|
|
10892
10877
|
async function clickRef(page, sessionId, ref, opts) {
|
|
@@ -14623,7 +14608,7 @@ var require_operation = __commonJS((exports, module) => {
|
|
|
14623
14608
|
// node_modules/@img/colour/color.cjs
|
|
14624
14609
|
var require_color = __commonJS((exports, module) => {
|
|
14625
14610
|
var __defProp3 = Object.defineProperty;
|
|
14626
|
-
var
|
|
14611
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14627
14612
|
var __getOwnPropNames3 = Object.getOwnPropertyNames;
|
|
14628
14613
|
var __hasOwnProp3 = Object.prototype.hasOwnProperty;
|
|
14629
14614
|
var __export3 = (target, all) => {
|
|
@@ -14634,16 +14619,16 @@ var require_color = __commonJS((exports, module) => {
|
|
|
14634
14619
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
14635
14620
|
for (let key of __getOwnPropNames3(from))
|
|
14636
14621
|
if (!__hasOwnProp3.call(to, key) && key !== except)
|
|
14637
|
-
__defProp3(to, key, { get: () => from[key], enumerable: !(desc =
|
|
14622
|
+
__defProp3(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14638
14623
|
}
|
|
14639
14624
|
return to;
|
|
14640
14625
|
};
|
|
14641
|
-
var
|
|
14626
|
+
var __toCommonJS = (mod) => __copyProps(__defProp3({}, "__esModule", { value: true }), mod);
|
|
14642
14627
|
var index_exports = {};
|
|
14643
14628
|
__export3(index_exports, {
|
|
14644
14629
|
default: () => index_default
|
|
14645
14630
|
});
|
|
14646
|
-
module.exports =
|
|
14631
|
+
module.exports = __toCommonJS(index_exports);
|
|
14647
14632
|
var colors = {
|
|
14648
14633
|
aliceblue: [240, 248, 255],
|
|
14649
14634
|
antiquewhite: [250, 235, 215],
|
|
@@ -18441,6 +18426,207 @@ var THEMES = {
|
|
|
18441
18426
|
brightWhite: "#ffffff"
|
|
18442
18427
|
}
|
|
18443
18428
|
};
|
|
18429
|
+
async function configureDomRenderer(page, options) {
|
|
18430
|
+
await page.evaluate((opts) => {
|
|
18431
|
+
const runtimeKey = "__takumiTuiDomRenderer";
|
|
18432
|
+
const rootId = "takumi-tui-dom-root";
|
|
18433
|
+
const styleId = "takumi-tui-dom-style";
|
|
18434
|
+
const win = window;
|
|
18435
|
+
const ensureStyle = () => {
|
|
18436
|
+
let style = document.getElementById(styleId);
|
|
18437
|
+
if (!style) {
|
|
18438
|
+
style = document.createElement("style");
|
|
18439
|
+
style.id = styleId;
|
|
18440
|
+
document.head.appendChild(style);
|
|
18441
|
+
}
|
|
18442
|
+
style.textContent = `
|
|
18443
|
+
#${rootId} {
|
|
18444
|
+
position: absolute;
|
|
18445
|
+
inset: 0;
|
|
18446
|
+
overflow: hidden;
|
|
18447
|
+
display: flex;
|
|
18448
|
+
flex-direction: column;
|
|
18449
|
+
white-space: pre;
|
|
18450
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
18451
|
+
line-height: 1.2;
|
|
18452
|
+
background: var(--takumi-tui-bg, #1e1e1e);
|
|
18453
|
+
color: var(--takumi-tui-fg, #d4d4d4);
|
|
18454
|
+
z-index: 4;
|
|
18455
|
+
pointer-events: none;
|
|
18456
|
+
user-select: text;
|
|
18457
|
+
}
|
|
18458
|
+
#${rootId}[data-active="0"] {
|
|
18459
|
+
display: none;
|
|
18460
|
+
}
|
|
18461
|
+
#${rootId} .takumi-tui-dom-row {
|
|
18462
|
+
display: flex;
|
|
18463
|
+
min-height: 1.2em;
|
|
18464
|
+
}
|
|
18465
|
+
#${rootId} .takumi-tui-dom-cell {
|
|
18466
|
+
display: inline-flex;
|
|
18467
|
+
align-items: center;
|
|
18468
|
+
justify-content: center;
|
|
18469
|
+
min-width: 0.62em;
|
|
18470
|
+
height: 1.2em;
|
|
18471
|
+
}
|
|
18472
|
+
#${rootId} .takumi-tui-dom-cell[data-cursor="true"] {
|
|
18473
|
+
outline: 1px solid currentColor;
|
|
18474
|
+
outline-offset: -1px;
|
|
18475
|
+
}
|
|
18476
|
+
body[data-takumi-dom-render="1"] .xterm-rows,
|
|
18477
|
+
body[data-takumi-dom-render="1"] .xterm-text-layer,
|
|
18478
|
+
body[data-takumi-dom-render="1"] .xterm-cursor-layer,
|
|
18479
|
+
body[data-takumi-dom-render="1"] .xterm-selection-layer {
|
|
18480
|
+
opacity: 0 !important;
|
|
18481
|
+
}
|
|
18482
|
+
`;
|
|
18483
|
+
};
|
|
18484
|
+
const ensureRoot = () => {
|
|
18485
|
+
let root = document.getElementById(rootId);
|
|
18486
|
+
if (!root) {
|
|
18487
|
+
root = document.createElement("div");
|
|
18488
|
+
root.id = rootId;
|
|
18489
|
+
root.setAttribute("role", "grid");
|
|
18490
|
+
root.setAttribute("aria-label", "Terminal DOM renderer");
|
|
18491
|
+
const host = document.getElementById("terminal-container") ?? document.querySelector(".xterm") ?? document.body;
|
|
18492
|
+
if (getComputedStyle(host).position === "static") {
|
|
18493
|
+
host.style.position = "relative";
|
|
18494
|
+
}
|
|
18495
|
+
host.appendChild(root);
|
|
18496
|
+
}
|
|
18497
|
+
root.style.setProperty("--takumi-tui-bg", opts.theme === "light" ? "#ffffff" : "#1e1e1e");
|
|
18498
|
+
root.style.setProperty("--takumi-tui-fg", opts.theme === "light" ? "#1e1e1e" : "#d4d4d4");
|
|
18499
|
+
root.style.fontSize = `${opts.fontSize ?? 14}px`;
|
|
18500
|
+
root.dataset.active = opts.active ? "1" : "0";
|
|
18501
|
+
if (opts.active)
|
|
18502
|
+
root.removeAttribute("aria-hidden");
|
|
18503
|
+
else
|
|
18504
|
+
root.setAttribute("aria-hidden", "true");
|
|
18505
|
+
document.body.dataset.takumiDomRender = opts.active ? "1" : "0";
|
|
18506
|
+
return root;
|
|
18507
|
+
};
|
|
18508
|
+
const readCellChars = (line, col) => {
|
|
18509
|
+
try {
|
|
18510
|
+
const cell = typeof line?.getCell === "function" ? line.getCell(col) : null;
|
|
18511
|
+
const chars = typeof cell?.getChars === "function" ? cell.getChars() : "";
|
|
18512
|
+
if (chars)
|
|
18513
|
+
return chars;
|
|
18514
|
+
} catch {}
|
|
18515
|
+
try {
|
|
18516
|
+
const text = typeof line?.translateToString === "function" ? line.translateToString(false, col, col + 1) : "";
|
|
18517
|
+
if (text)
|
|
18518
|
+
return text;
|
|
18519
|
+
} catch {}
|
|
18520
|
+
return " ";
|
|
18521
|
+
};
|
|
18522
|
+
const buildState = (activeOnly) => {
|
|
18523
|
+
const term = win.term ?? win.terminal;
|
|
18524
|
+
if (!term?.buffer?.active) {
|
|
18525
|
+
return {
|
|
18526
|
+
text: "",
|
|
18527
|
+
rows: [],
|
|
18528
|
+
row_count: 0,
|
|
18529
|
+
cols: null,
|
|
18530
|
+
total_rows: 0,
|
|
18531
|
+
buffer_length: null,
|
|
18532
|
+
cursor_row: -1,
|
|
18533
|
+
cursor_col: -1,
|
|
18534
|
+
font_size: null,
|
|
18535
|
+
theme: opts.theme
|
|
18536
|
+
};
|
|
18537
|
+
}
|
|
18538
|
+
const buf = term.buffer.active;
|
|
18539
|
+
const rows = [];
|
|
18540
|
+
const root = ensureRoot();
|
|
18541
|
+
const fragment = document.createDocumentFragment();
|
|
18542
|
+
for (let row = 0;row < buf.length; row++) {
|
|
18543
|
+
const line = buf.getLine(row);
|
|
18544
|
+
if (!line)
|
|
18545
|
+
continue;
|
|
18546
|
+
const rowEl = document.createElement("div");
|
|
18547
|
+
rowEl.className = "takumi-tui-dom-row";
|
|
18548
|
+
rowEl.setAttribute("role", "row");
|
|
18549
|
+
rowEl.dataset.row = String(row);
|
|
18550
|
+
rowEl.setAttribute("aria-rowindex", String(row + 1));
|
|
18551
|
+
let rowText = "";
|
|
18552
|
+
for (let col = 0;col < term.cols; col++) {
|
|
18553
|
+
const char = readCellChars(line, col) || " ";
|
|
18554
|
+
rowText += char;
|
|
18555
|
+
const cellEl = document.createElement("span");
|
|
18556
|
+
cellEl.className = "takumi-tui-dom-cell";
|
|
18557
|
+
cellEl.setAttribute("role", "gridcell");
|
|
18558
|
+
cellEl.dataset.row = String(row);
|
|
18559
|
+
cellEl.dataset.col = String(col);
|
|
18560
|
+
cellEl.setAttribute("aria-colindex", String(col + 1));
|
|
18561
|
+
cellEl.textContent = char;
|
|
18562
|
+
if (buf.cursorY === row && buf.cursorX === col) {
|
|
18563
|
+
cellEl.dataset.cursor = "true";
|
|
18564
|
+
}
|
|
18565
|
+
rowEl.appendChild(cellEl);
|
|
18566
|
+
}
|
|
18567
|
+
rows.push(rowText.replace(/\s+$/g, ""));
|
|
18568
|
+
rowEl.setAttribute("aria-label", rows[rows.length - 1] || " ");
|
|
18569
|
+
fragment.appendChild(rowEl);
|
|
18570
|
+
}
|
|
18571
|
+
root.replaceChildren(fragment);
|
|
18572
|
+
root.setAttribute("aria-rowcount", String(rows.length));
|
|
18573
|
+
root.dataset.method = "dom";
|
|
18574
|
+
return {
|
|
18575
|
+
text: rows.join(`
|
|
18576
|
+
`).trimEnd(),
|
|
18577
|
+
rows,
|
|
18578
|
+
row_count: rows.length,
|
|
18579
|
+
cols: term.cols,
|
|
18580
|
+
total_rows: term.rows,
|
|
18581
|
+
buffer_length: buf.length,
|
|
18582
|
+
cursor_row: buf.cursorY,
|
|
18583
|
+
cursor_col: buf.cursorX,
|
|
18584
|
+
font_size: term.options?.fontSize ?? null,
|
|
18585
|
+
theme: term.options?.theme?.background === "#ffffff" ? "light" : "dark"
|
|
18586
|
+
};
|
|
18587
|
+
};
|
|
18588
|
+
ensureStyle();
|
|
18589
|
+
ensureRoot();
|
|
18590
|
+
if (!win[runtimeKey]) {
|
|
18591
|
+
win[runtimeKey] = {
|
|
18592
|
+
sync: () => buildState(false),
|
|
18593
|
+
activate: (active) => {
|
|
18594
|
+
const root = ensureRoot();
|
|
18595
|
+
root.dataset.active = active ? "1" : "0";
|
|
18596
|
+
if (active)
|
|
18597
|
+
root.removeAttribute("aria-hidden");
|
|
18598
|
+
else
|
|
18599
|
+
root.setAttribute("aria-hidden", "true");
|
|
18600
|
+
document.body.dataset.takumiDomRender = active ? "1" : "0";
|
|
18601
|
+
}
|
|
18602
|
+
};
|
|
18603
|
+
const intervalId = window.setInterval(() => {
|
|
18604
|
+
try {
|
|
18605
|
+
win[runtimeKey]?.sync?.();
|
|
18606
|
+
} catch {}
|
|
18607
|
+
}, 50);
|
|
18608
|
+
win[runtimeKey].intervalId = intervalId;
|
|
18609
|
+
}
|
|
18610
|
+
win[runtimeKey].activate(opts.active);
|
|
18611
|
+
win[runtimeKey].sync();
|
|
18612
|
+
}, options);
|
|
18613
|
+
}
|
|
18614
|
+
async function destroyDomRenderer(page) {
|
|
18615
|
+
await page.evaluate(() => {
|
|
18616
|
+
const runtimeKey = "__takumiTuiDomRenderer";
|
|
18617
|
+
const win = window;
|
|
18618
|
+
if (win[runtimeKey]?.intervalId) {
|
|
18619
|
+
clearInterval(win[runtimeKey].intervalId);
|
|
18620
|
+
}
|
|
18621
|
+
delete win[runtimeKey];
|
|
18622
|
+
document.getElementById("takumi-tui-dom-root")?.remove();
|
|
18623
|
+
document.getElementById("takumi-tui-dom-style")?.remove();
|
|
18624
|
+
delete document.body.dataset.takumiDomRender;
|
|
18625
|
+
}).catch(() => {});
|
|
18626
|
+
}
|
|
18627
|
+
function isDomMethod(method) {
|
|
18628
|
+
return method === "dom";
|
|
18629
|
+
}
|
|
18444
18630
|
function isTuiAvailable() {
|
|
18445
18631
|
try {
|
|
18446
18632
|
execSync2("which ttyd", { stdio: "ignore" });
|
|
@@ -18453,7 +18639,7 @@ async function findAvailablePort(startPort) {
|
|
|
18453
18639
|
let port = startPort;
|
|
18454
18640
|
for (let i = 0;i < 100; i++) {
|
|
18455
18641
|
try {
|
|
18456
|
-
|
|
18642
|
+
await fetch(`http://localhost:${port}`);
|
|
18457
18643
|
port++;
|
|
18458
18644
|
} catch {
|
|
18459
18645
|
return port;
|
|
@@ -18479,24 +18665,16 @@ async function launchTui(command, options = {}) {
|
|
|
18479
18665
|
}
|
|
18480
18666
|
const port = await findAvailablePort(nextPort);
|
|
18481
18667
|
nextPort = port + 1;
|
|
18482
|
-
const ttydProcess = spawn2("ttyd", ["--writable", "--port", String(port), "/bin/sh", "-c", command], {
|
|
18483
|
-
stdio: "ignore",
|
|
18484
|
-
detached: false
|
|
18485
|
-
});
|
|
18668
|
+
const ttydProcess = spawn2("ttyd", ["--writable", "--port", String(port), "/bin/sh", "-c", command], { stdio: "ignore", detached: false });
|
|
18486
18669
|
ttydProcess.on("error", (err) => {
|
|
18487
18670
|
console.error(`[tui] ttyd process error: ${err.message}`);
|
|
18488
18671
|
});
|
|
18489
18672
|
try {
|
|
18490
18673
|
await waitForTtyd(port);
|
|
18491
18674
|
const viewport = options.viewport ?? { width: 1280, height: 720 };
|
|
18492
|
-
const browser = await launchPlaywright({
|
|
18493
|
-
headless: options.headless ?? true,
|
|
18494
|
-
viewport
|
|
18495
|
-
});
|
|
18675
|
+
const browser = await launchPlaywright({ headless: options.headless ?? true, viewport });
|
|
18496
18676
|
const page = await getPage(browser, { viewport });
|
|
18497
|
-
await page.goto(`http://localhost:${port}`, {
|
|
18498
|
-
waitUntil: "domcontentloaded"
|
|
18499
|
-
});
|
|
18677
|
+
await page.goto(`http://localhost:${port}`, { waitUntil: "domcontentloaded" });
|
|
18500
18678
|
await page.waitForSelector(".xterm-screen", { timeout: 1e4 });
|
|
18501
18679
|
let resolvedTheme = "dark";
|
|
18502
18680
|
const requestedTheme = options.theme ?? "system";
|
|
@@ -18515,16 +18693,15 @@ async function launchTui(command, options = {}) {
|
|
|
18515
18693
|
const themeColors = THEMES[resolvedTheme];
|
|
18516
18694
|
await page.evaluate((theme) => {
|
|
18517
18695
|
const term = window.term ?? window.terminal;
|
|
18518
|
-
if (term?.options)
|
|
18696
|
+
if (term?.options)
|
|
18519
18697
|
term.options.theme = theme;
|
|
18520
|
-
}
|
|
18521
18698
|
document.body.style.backgroundColor = theme.background;
|
|
18522
18699
|
const container = document.getElementById("terminal-container");
|
|
18523
18700
|
if (container)
|
|
18524
18701
|
container.style.backgroundColor = theme.background;
|
|
18525
|
-
const
|
|
18526
|
-
if (
|
|
18527
|
-
|
|
18702
|
+
const vp = document.querySelector(".xterm-viewport");
|
|
18703
|
+
if (vp)
|
|
18704
|
+
vp.style.backgroundColor = theme.background;
|
|
18528
18705
|
}, themeColors);
|
|
18529
18706
|
if (options.fontSize) {
|
|
18530
18707
|
await page.evaluate((size) => {
|
|
@@ -18533,13 +18710,31 @@ async function launchTui(command, options = {}) {
|
|
|
18533
18710
|
term.options.fontSize = size;
|
|
18534
18711
|
}, options.fontSize);
|
|
18535
18712
|
}
|
|
18536
|
-
|
|
18713
|
+
const method = options.method ?? "buffer";
|
|
18714
|
+
await configureDomRenderer(page, {
|
|
18715
|
+
active: isDomMethod(method),
|
|
18716
|
+
theme: resolvedTheme,
|
|
18717
|
+
fontSize: options.fontSize
|
|
18718
|
+
});
|
|
18719
|
+
return {
|
|
18720
|
+
ttydProcess,
|
|
18721
|
+
port,
|
|
18722
|
+
browser,
|
|
18723
|
+
page,
|
|
18724
|
+
theme: resolvedTheme,
|
|
18725
|
+
method,
|
|
18726
|
+
lastHealthCheck: Date.now(),
|
|
18727
|
+
reconnectCount: 0
|
|
18728
|
+
};
|
|
18537
18729
|
} catch (err) {
|
|
18538
|
-
|
|
18730
|
+
try {
|
|
18731
|
+
ttydProcess.kill("SIGTERM");
|
|
18732
|
+
} catch {}
|
|
18539
18733
|
throw err;
|
|
18540
18734
|
}
|
|
18541
18735
|
}
|
|
18542
18736
|
async function closeTui(session) {
|
|
18737
|
+
await destroyDomRenderer(session.page);
|
|
18543
18738
|
try {
|
|
18544
18739
|
await session.page.close();
|
|
18545
18740
|
} catch {}
|
|
@@ -18549,6 +18744,9 @@ async function closeTui(session) {
|
|
|
18549
18744
|
try {
|
|
18550
18745
|
session.ttydProcess.kill("SIGTERM");
|
|
18551
18746
|
} catch {}
|
|
18747
|
+
try {
|
|
18748
|
+
session.ttydProcess.kill("SIGKILL");
|
|
18749
|
+
} catch {}
|
|
18552
18750
|
}
|
|
18553
18751
|
|
|
18554
18752
|
// src/engines/selector.ts
|
|
@@ -18816,19 +19014,13 @@ Object.defineProperty(navigator, 'plugins', {
|
|
|
18816
19014
|
{ name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', description: '', length: 1 },
|
|
18817
19015
|
{ name: 'Native Client', filename: 'internal-nacl-plugin', description: '', length: 2 },
|
|
18818
19016
|
];
|
|
18819
|
-
// Mimic PluginArray interface
|
|
18820
|
-
const pluginArray =
|
|
19017
|
+
// Mimic PluginArray interface \u2014 guard against removed prototypes
|
|
19018
|
+
const pluginArray = {};
|
|
18821
19019
|
plugins.forEach((p, i) => {
|
|
18822
|
-
const plugin =
|
|
18823
|
-
Object.defineProperties(plugin, {
|
|
18824
|
-
name: { value: p.name, enumerable: true },
|
|
18825
|
-
filename: { value: p.filename, enumerable: true },
|
|
18826
|
-
description: { value: p.description, enumerable: true },
|
|
18827
|
-
length: { value: p.length, enumerable: true },
|
|
18828
|
-
});
|
|
19020
|
+
const plugin = { ...p, item: () => null };
|
|
18829
19021
|
pluginArray[i] = plugin;
|
|
18830
19022
|
});
|
|
18831
|
-
|
|
19023
|
+
pluginArray.length = plugins.length;
|
|
18832
19024
|
pluginArray.item = (i) => pluginArray[i] || null;
|
|
18833
19025
|
pluginArray.namedItem = (name) => plugins.find(p => p.name === name) ? pluginArray[plugins.findIndex(p => p.name === name)] : null;
|
|
18834
19026
|
pluginArray.refresh = () => {};
|
|
@@ -18883,14 +19075,16 @@ if (ttlInterval.unref)
|
|
|
18883
19075
|
var DB_PRUNE_INTERVAL_MS = 30 * 60000;
|
|
18884
19076
|
var DB_RETENTION_HOURS = 24;
|
|
18885
19077
|
var dbPruneInterval = setInterval(() => {
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
19078
|
+
(async () => {
|
|
19079
|
+
try {
|
|
19080
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_schema(), exports_schema));
|
|
19081
|
+
const db = getDatabase2();
|
|
19082
|
+
const cutoff = new Date(Date.now() - DB_RETENTION_HOURS * 3600000).toISOString();
|
|
19083
|
+
db.prepare("DELETE FROM network_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
19084
|
+
db.prepare("DELETE FROM console_log WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
19085
|
+
db.prepare("DELETE FROM snapshots WHERE session_id IN (SELECT id FROM sessions WHERE status != 'active') AND timestamp < ?").run(cutoff);
|
|
19086
|
+
} catch {}
|
|
19087
|
+
})();
|
|
18894
19088
|
}, DB_PRUNE_INTERVAL_MS);
|
|
18895
19089
|
if (dbPruneInterval.unref)
|
|
18896
19090
|
dbPruneInterval.unref();
|
|
@@ -18926,7 +19120,7 @@ async function createSession2(opts = {}) {
|
|
|
18926
19120
|
try {
|
|
18927
19121
|
cleanups2.push(setupDialogHandler(page2, session2.id));
|
|
18928
19122
|
} catch {}
|
|
18929
|
-
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 });
|
|
19123
|
+
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, startUrl: opts.startUrl ?? "" });
|
|
18930
19124
|
return { session: session2, page: page2 };
|
|
18931
19125
|
}
|
|
18932
19126
|
const engine = opts.engine === "auto" || !opts.engine ? selectEngine(opts.useCase ?? "spa_navigate" /* SPA_NAVIGATE */, opts.engine) : opts.engine;
|
|
@@ -18940,13 +19134,29 @@ async function createSession2(opts = {}) {
|
|
|
18940
19134
|
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
18941
19135
|
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
18942
19136
|
} else {
|
|
18943
|
-
|
|
19137
|
+
const testView = new BunWebViewSession({
|
|
18944
19138
|
width: opts.viewport?.width ?? 1280,
|
|
18945
19139
|
height: opts.viewport?.height ?? 720,
|
|
18946
19140
|
profile: opts.name ?? undefined
|
|
18947
19141
|
});
|
|
18948
|
-
|
|
18949
|
-
|
|
19142
|
+
let bunWorks = true;
|
|
19143
|
+
try {
|
|
19144
|
+
await testView.goto("data:text/html,<html></html>");
|
|
19145
|
+
} catch {
|
|
19146
|
+
bunWorks = false;
|
|
19147
|
+
try {
|
|
19148
|
+
await testView.close();
|
|
19149
|
+
} catch {}
|
|
19150
|
+
}
|
|
19151
|
+
if (!bunWorks) {
|
|
19152
|
+
console.warn("[browser] Bun.WebView exists but Chrome not available \u2014 falling back to playwright");
|
|
19153
|
+
browser = await launchPlaywright({ headless: opts.headless ?? true, viewport: opts.viewport, userAgent: opts.userAgent });
|
|
19154
|
+
page = await getPage(browser, { viewport: opts.viewport, userAgent: opts.userAgent });
|
|
19155
|
+
} else {
|
|
19156
|
+
bunView = testView;
|
|
19157
|
+
if (opts.stealth) {}
|
|
19158
|
+
page = createBunProxy(bunView);
|
|
19159
|
+
}
|
|
18950
19160
|
}
|
|
18951
19161
|
} else if (resolvedEngine === "lightpanda") {
|
|
18952
19162
|
browser = await connectLightpanda();
|
|
@@ -18958,7 +19168,8 @@ async function createSession2(opts = {}) {
|
|
|
18958
19168
|
headless: opts.headless ?? true,
|
|
18959
19169
|
viewport: opts.viewport,
|
|
18960
19170
|
theme: opts.tuiTheme ?? "system",
|
|
18961
|
-
fontSize: opts.tuiFontSize
|
|
19171
|
+
fontSize: opts.tuiFontSize,
|
|
19172
|
+
method: opts.tuiMethod ?? "buffer"
|
|
18962
19173
|
});
|
|
18963
19174
|
browser = tuiSess.browser;
|
|
18964
19175
|
page = tuiSess.page;
|
|
@@ -18984,7 +19195,7 @@ async function createSession2(opts = {}) {
|
|
|
18984
19195
|
try {
|
|
18985
19196
|
cleanups2.push(setupDialogHandler(page, session2.id));
|
|
18986
19197
|
} catch {}
|
|
18987
|
-
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 });
|
|
19198
|
+
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, startUrl: opts.startUrl ?? "bash" });
|
|
18988
19199
|
return { session: session2, page };
|
|
18989
19200
|
} else {
|
|
18990
19201
|
browser = await pool.acquire(opts.headless ?? true);
|
|
@@ -19056,7 +19267,7 @@ async function createSession2(opts = {}) {
|
|
|
19056
19267
|
} catch {}
|
|
19057
19268
|
}
|
|
19058
19269
|
}
|
|
19059
|
-
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 });
|
|
19270
|
+
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, startUrl: opts.startUrl ?? "" });
|
|
19060
19271
|
if (opts.startUrl) {
|
|
19061
19272
|
try {
|
|
19062
19273
|
if (bunView) {
|
|
@@ -19108,6 +19319,23 @@ function getSessionEngine(sessionId) {
|
|
|
19108
19319
|
function hasActiveHandle(sessionId) {
|
|
19109
19320
|
return handles.has(sessionId);
|
|
19110
19321
|
}
|
|
19322
|
+
function getSessionTuiSession(sessionId) {
|
|
19323
|
+
return handles.get(sessionId)?.tuiSession ?? null;
|
|
19324
|
+
}
|
|
19325
|
+
function setSessionTui(sessionId, tuiSess) {
|
|
19326
|
+
const handle = handles.get(sessionId);
|
|
19327
|
+
if (!handle)
|
|
19328
|
+
throw new SessionNotFoundError(sessionId);
|
|
19329
|
+
handle.tuiSession = tuiSess;
|
|
19330
|
+
handle.page = tuiSess.page;
|
|
19331
|
+
if (tuiSess.browser !== handle.browser) {
|
|
19332
|
+
handle.browser = tuiSess.browser;
|
|
19333
|
+
}
|
|
19334
|
+
handle.lastActivity = Date.now();
|
|
19335
|
+
}
|
|
19336
|
+
function getSessionCommand(sessionId) {
|
|
19337
|
+
return handles.get(sessionId)?.startUrl ?? "bash";
|
|
19338
|
+
}
|
|
19111
19339
|
function setSessionPage(sessionId, page) {
|
|
19112
19340
|
const handle = handles.get(sessionId);
|
|
19113
19341
|
if (!handle)
|
|
@@ -19116,38 +19344,43 @@ function setSessionPage(sessionId, page) {
|
|
|
19116
19344
|
}
|
|
19117
19345
|
async function closeSession2(sessionId) {
|
|
19118
19346
|
const handle = handles.get(sessionId);
|
|
19119
|
-
|
|
19120
|
-
|
|
19121
|
-
|
|
19122
|
-
|
|
19123
|
-
|
|
19124
|
-
|
|
19125
|
-
|
|
19126
|
-
|
|
19127
|
-
|
|
19128
|
-
|
|
19129
|
-
|
|
19130
|
-
|
|
19131
|
-
|
|
19132
|
-
|
|
19133
|
-
|
|
19134
|
-
|
|
19347
|
+
try {
|
|
19348
|
+
if (handle) {
|
|
19349
|
+
for (const cleanup of handle.cleanups) {
|
|
19350
|
+
try {
|
|
19351
|
+
cleanup();
|
|
19352
|
+
} catch {}
|
|
19353
|
+
}
|
|
19354
|
+
if (handle.bunView) {
|
|
19355
|
+
try {
|
|
19356
|
+
await handle.bunView.close();
|
|
19357
|
+
} catch {}
|
|
19358
|
+
} else if (handle.tuiSession) {} else {
|
|
19359
|
+
try {
|
|
19360
|
+
await handle.page.context().close();
|
|
19361
|
+
} catch {}
|
|
19362
|
+
try {
|
|
19363
|
+
if (handle.browser)
|
|
19364
|
+
pool.release(handle.browser);
|
|
19365
|
+
} catch {}
|
|
19366
|
+
}
|
|
19135
19367
|
}
|
|
19368
|
+
try {
|
|
19369
|
+
const { clearLastSnapshot: clearLastSnapshot2, clearSessionRefs: clearSessionRefs2 } = await Promise.resolve().then(() => (init_snapshot(), exports_snapshot));
|
|
19370
|
+
clearLastSnapshot2(sessionId);
|
|
19371
|
+
clearSessionRefs2(sessionId);
|
|
19372
|
+
} catch {}
|
|
19373
|
+
try {
|
|
19374
|
+
const { stopAllWatchesForSession: stopAllWatchesForSession2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
19375
|
+
stopAllWatchesForSession2(sessionId);
|
|
19376
|
+
} catch {}
|
|
19377
|
+
try {
|
|
19378
|
+
const { clearDialogs: clearDialogs2 } = await Promise.resolve().then(() => (init_dialogs(), exports_dialogs));
|
|
19379
|
+
clearDialogs2(sessionId);
|
|
19380
|
+
} catch {}
|
|
19381
|
+
} finally {
|
|
19136
19382
|
handles.delete(sessionId);
|
|
19137
19383
|
}
|
|
19138
|
-
try {
|
|
19139
|
-
const { clearLastSnapshot: clearLastSnapshot2, clearSessionRefs: clearSessionRefs2 } = await Promise.resolve().then(() => (init_snapshot(), exports_snapshot));
|
|
19140
|
-
clearLastSnapshot2(sessionId);
|
|
19141
|
-
clearSessionRefs2(sessionId);
|
|
19142
|
-
} catch {}
|
|
19143
|
-
try {
|
|
19144
|
-
const { stopAllWatchesForSession: stopAllWatchesForSession2 } = await Promise.resolve().then(() => (init_actions(), exports_actions));
|
|
19145
|
-
stopAllWatchesForSession2(sessionId);
|
|
19146
|
-
} catch {}
|
|
19147
|
-
try {
|
|
19148
|
-
const { clearDialogs: clearDialogs2 } = await Promise.resolve().then(() => (init_dialogs(), exports_dialogs));
|
|
19149
|
-
clearDialogs2(sessionId);
|
|
19150
|
-
} catch {}
|
|
19151
19384
|
return closeSession(sessionId);
|
|
19152
19385
|
}
|
|
19153
19386
|
function listSessions2(filter) {
|
|
@@ -19479,6 +19712,12 @@ import { mkdirSync as mkdirSync7 } from "fs";
|
|
|
19479
19712
|
// src/db/gallery.ts
|
|
19480
19713
|
init_schema();
|
|
19481
19714
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
19715
|
+
function validateDataPath(filePath) {
|
|
19716
|
+
if (filePath.includes("..")) {
|
|
19717
|
+
throw new Error(`File path must not contain '..': ${filePath}`);
|
|
19718
|
+
}
|
|
19719
|
+
return filePath;
|
|
19720
|
+
}
|
|
19482
19721
|
function deserialize3(row) {
|
|
19483
19722
|
return {
|
|
19484
19723
|
id: row.id,
|
|
@@ -19503,6 +19742,9 @@ function deserialize3(row) {
|
|
|
19503
19742
|
function createEntry(data) {
|
|
19504
19743
|
const db = getDatabase();
|
|
19505
19744
|
const id = randomUUID10();
|
|
19745
|
+
validateDataPath(data.path);
|
|
19746
|
+
if (data.thumbnail_path)
|
|
19747
|
+
validateDataPath(data.thumbnail_path);
|
|
19506
19748
|
db.prepare(`
|
|
19507
19749
|
INSERT INTO gallery_entries
|
|
19508
19750
|
(id, session_id, project_id, url, title, path, thumbnail_path, format,
|
|
@@ -20017,6 +20259,7 @@ export {
|
|
|
20017
20259
|
startRecording,
|
|
20018
20260
|
startHAR,
|
|
20019
20261
|
startCoverage,
|
|
20262
|
+
setSessionTui,
|
|
20020
20263
|
setSessionStorage,
|
|
20021
20264
|
setSessionPage,
|
|
20022
20265
|
setLocalStorage,
|
|
@@ -20065,9 +20308,11 @@ export {
|
|
|
20065
20308
|
getTimingEntries,
|
|
20066
20309
|
getText,
|
|
20067
20310
|
getSnapshot,
|
|
20311
|
+
getSessionTuiSession,
|
|
20068
20312
|
getSessionStorage,
|
|
20069
20313
|
getSessionPage,
|
|
20070
20314
|
getSessionEngine,
|
|
20315
|
+
getSessionCommand,
|
|
20071
20316
|
getSessionByName2 as getSessionByName,
|
|
20072
20317
|
getSessionBunView,
|
|
20073
20318
|
getSessionBrowser,
|
package/dist/lib/actions.d.ts
CHANGED
|
@@ -73,10 +73,11 @@ export declare function watchPage(page: Page, opts?: {
|
|
|
73
73
|
selector?: string;
|
|
74
74
|
intervalMs?: number;
|
|
75
75
|
maxChanges?: number;
|
|
76
|
+
sessionId?: string;
|
|
76
77
|
}): WatchHandle;
|
|
77
78
|
export declare function getWatchChanges(watchId: string): string[];
|
|
78
79
|
export declare function stopWatch(watchId: string): void;
|
|
79
|
-
export declare function stopAllWatchesForSession(
|
|
80
|
+
export declare function stopAllWatchesForSession(sessionId?: string): void;
|
|
80
81
|
export declare function clickRef(page: Page, sessionId: string, ref: string, opts?: {
|
|
81
82
|
timeout?: number;
|
|
82
83
|
}): Promise<void>;
|