@xbrowser/cli 1.18.2 → 1.19.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/{browser-BEERPZPB.js → browser-6LH6KJSW.js} +1 -1
- package/dist/{browser-TFFGGXOA.js → browser-TUD2KA5G.js} +2 -2
- package/dist/{browser-AEQS6325.js → browser-Y5SIE6LY.js} +2 -2
- package/dist/{cdp-driver-KT6HL33W.js → cdp-driver-2EECZW4X.js} +1 -1
- package/dist/{cdp-driver-4UAV56SQ.js → cdp-driver-7HO5SRNN.js} +1 -1
- package/dist/{cdp-driver-NNBPNFF2.js → cdp-driver-E7G3VHIB.js} +41 -3
- package/dist/{chunk-MTNVT2T7.js → chunk-2BPZ25RE.js} +13 -2
- package/dist/{chunk-NA7IP6PO.js → chunk-C6PW3CPA.js} +13 -2
- package/dist/{chunk-DVKIL7H6.js → chunk-GKYSCHT4.js} +41 -3
- package/dist/{chunk-7SDM4EA4.js → chunk-KLXLNQI5.js} +53 -4
- package/dist/{chunk-LL37GYPP.js → chunk-LKJZYVIX.js} +41 -3
- package/dist/cli.js +724 -14
- package/dist/daemon-main.js +732 -17
- package/dist/index.js +725 -15
- package/dist/{session-replayer-J4GXUULG.js → session-replayer-RODZYHM3.js} +1 -1
- package/package.json +1 -1
package/dist/daemon-main.js
CHANGED
|
@@ -34,13 +34,13 @@ import {
|
|
|
34
34
|
resolveLaunchOpts,
|
|
35
35
|
saveSessionDiskMeta,
|
|
36
36
|
setActivePage
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-C6PW3CPA.js";
|
|
38
38
|
import {
|
|
39
39
|
createRuleEngine,
|
|
40
40
|
rand,
|
|
41
41
|
sleep,
|
|
42
42
|
wheelDelta
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-GKYSCHT4.js";
|
|
44
44
|
import {
|
|
45
45
|
queryJS
|
|
46
46
|
} from "./chunk-3FWLW7FS.js";
|
|
@@ -69,8 +69,8 @@ import {
|
|
|
69
69
|
|
|
70
70
|
// src/executor.ts
|
|
71
71
|
import {
|
|
72
|
-
ok as
|
|
73
|
-
fail as
|
|
72
|
+
ok as ok30,
|
|
73
|
+
fail as fail15,
|
|
74
74
|
isCommandResult,
|
|
75
75
|
CompositeStorage as CompositeStorage2,
|
|
76
76
|
TipCollector as TipCollector2,
|
|
@@ -6322,6 +6322,709 @@ function describeSelector(strategy, value, name) {
|
|
|
6322
6322
|
}
|
|
6323
6323
|
}
|
|
6324
6324
|
|
|
6325
|
+
// src/commands/visual-tag.ts
|
|
6326
|
+
import { z as z29 } from "zod";
|
|
6327
|
+
import { ok as ok28, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6328
|
+
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6329
|
+
var TAG_SCRIPT = `
|
|
6330
|
+
(function() {
|
|
6331
|
+
// \u6E05\u9664\u65E7\u6807\u6CE8
|
|
6332
|
+
var old = document.getElementById('__xb-tag-overlay');
|
|
6333
|
+
if (old) old.remove();
|
|
6334
|
+
window.__xbTagMap = {};
|
|
6335
|
+
|
|
6336
|
+
var SAFE_SET = ${JSON.stringify(SAFE_SET)};
|
|
6337
|
+
function genId(idx) {
|
|
6338
|
+
var base = SAFE_SET.length;
|
|
6339
|
+
if (idx < base * base) return SAFE_SET[Math.floor(idx / base)] + SAFE_SET[idx % base];
|
|
6340
|
+
var i = idx - base * base;
|
|
6341
|
+
return SAFE_SET[Math.floor(i / (base * base))] + SAFE_SET[Math.floor(i / base) % base] + SAFE_SET[i % base];
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
// \u627E\u6240\u6709\u53EF\u4EA4\u4E92\u5143\u7D20
|
|
6345
|
+
var els = [];
|
|
6346
|
+
var all = document.querySelectorAll('button, a[href], input, select, textarea, [onclick], [role="button"], [contenteditable], [class*="btn"], [class*="button"], [class*="link"]');
|
|
6347
|
+
for (var i = 0; i < all.length && els.length < 200; i++) {
|
|
6348
|
+
var el = all[i];
|
|
6349
|
+
var r = el.getBoundingClientRect();
|
|
6350
|
+
if (r.width < 10 || r.height < 10) continue;
|
|
6351
|
+
if (r.x < 0 || r.y < 0 || r.x + r.width > window.innerWidth || r.y + r.height > window.innerHeight + 100) continue;
|
|
6352
|
+
var style = getComputedStyle(el);
|
|
6353
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
|
|
6354
|
+
els.push({ el: el, rect: r });
|
|
6355
|
+
}
|
|
6356
|
+
|
|
6357
|
+
// \u521B\u5EFA\u53E0\u52A0 Canvas
|
|
6358
|
+
var canvas = document.createElement('canvas');
|
|
6359
|
+
canvas.id = '__xb-tag-overlay';
|
|
6360
|
+
canvas.width = window.innerWidth;
|
|
6361
|
+
canvas.height = Math.max(window.innerHeight, document.documentElement.scrollHeight);
|
|
6362
|
+
canvas.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:999999;';
|
|
6363
|
+
document.body.appendChild(canvas);
|
|
6364
|
+
var ctx = canvas.getContext('2d');
|
|
6365
|
+
|
|
6366
|
+
// \u7ED8\u5236\u6807\u7B7E
|
|
6367
|
+
for (var j = 0; j < els.length; j++) {
|
|
6368
|
+
var item = els[j];
|
|
6369
|
+
var id = genId(j);
|
|
6370
|
+
var x = item.rect.x;
|
|
6371
|
+
var y = item.rect.y;
|
|
6372
|
+
|
|
6373
|
+
// \u6807\u7B7E\u6846\uFF1A\u9AD8\u5BF9\u6BD4\uFF08\u9EC4\u5E95\u9ED1\u5B57\uFF09
|
|
6374
|
+
ctx.fillStyle = '#FFD700';
|
|
6375
|
+
ctx.fillRect(x - 2, y - 16, id.length * 8 + 8, 16);
|
|
6376
|
+
ctx.strokeStyle = '#000';
|
|
6377
|
+
ctx.lineWidth = 1.5;
|
|
6378
|
+
ctx.strokeRect(x - 2, y - 16, id.length * 8 + 8, 16);
|
|
6379
|
+
ctx.fillStyle = '#000';
|
|
6380
|
+
ctx.font = 'bold 12px monospace';
|
|
6381
|
+
ctx.fillText(id, x + 2, y - 5);
|
|
6382
|
+
|
|
6383
|
+
// \u5143\u7D20\u8F6E\u5ED3
|
|
6384
|
+
ctx.strokeStyle = '#FF0000';
|
|
6385
|
+
ctx.lineWidth = 1.5;
|
|
6386
|
+
ctx.strokeRect(x, y, item.rect.width, item.rect.height);
|
|
6387
|
+
|
|
6388
|
+
// \u5B58\u50A8 ID \u2192 \u5143\u7D20\u6620\u5C04
|
|
6389
|
+
window.__xbTagMap[id] = {
|
|
6390
|
+
tagName: item.el.tagName,
|
|
6391
|
+
text: (item.el.textContent || '').trim().slice(0, 50),
|
|
6392
|
+
rect: { x: x, y: y, w: item.rect.width, h: item.rect.height },
|
|
6393
|
+
selector: (function(e) {
|
|
6394
|
+
if (e.id) return '#' + e.id;
|
|
6395
|
+
if (e.getAttribute('data-testid')) return '[data-testid="' + e.getAttribute('data-testid') + '"]';
|
|
6396
|
+
// \u751F\u6210 nth-child \u9009\u62E9\u5668
|
|
6397
|
+
var path = [];
|
|
6398
|
+
var node = e;
|
|
6399
|
+
while (node && node !== document.body) {
|
|
6400
|
+
var idx = 1;
|
|
6401
|
+
var sib = node.previousElementSibling;
|
|
6402
|
+
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
6403
|
+
path.unshift(node.tagName.toLowerCase() + ':nth-of-type(' + idx + ')');
|
|
6404
|
+
node = node.parentElement;
|
|
6405
|
+
}
|
|
6406
|
+
return path.join(' > ');
|
|
6407
|
+
})(item.el)
|
|
6408
|
+
};
|
|
6409
|
+
}
|
|
6410
|
+
|
|
6411
|
+
return JSON.stringify({ tagged: els.length, overlay: true });
|
|
6412
|
+
})()
|
|
6413
|
+
`;
|
|
6414
|
+
var visualTagCommand = registerCommand({
|
|
6415
|
+
name: "visual-tag",
|
|
6416
|
+
description: "\u5728\u9875\u9762\u4E0A\u7ED9\u53EF\u4EA4\u4E92\u5143\u7D20\u53E0\u52A0\u9632\u6DF7\u6DC6\u77ED ID \u6807\u7B7E\uFF08\u89C6\u89C9\u5B9A\u4F4D\u7528\uFF09",
|
|
6417
|
+
scope: "page",
|
|
6418
|
+
parameters: z29.object({
|
|
6419
|
+
action: z29.enum(["tag", "lookup", "clear", "list"]),
|
|
6420
|
+
id: z29.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6421
|
+
}),
|
|
6422
|
+
result: z29.object({
|
|
6423
|
+
action: z29.string(),
|
|
6424
|
+
tagged: z29.number().optional(),
|
|
6425
|
+
id: z29.string().optional(),
|
|
6426
|
+
element: z29.record(z29.unknown()).optional()
|
|
6427
|
+
}),
|
|
6428
|
+
handler: async (p, ctx) => {
|
|
6429
|
+
switch (p.action) {
|
|
6430
|
+
case "tag": {
|
|
6431
|
+
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6432
|
+
const parsed = JSON.parse(result);
|
|
6433
|
+
return ok28({ action: "tag", tagged: parsed.tagged });
|
|
6434
|
+
}
|
|
6435
|
+
case "lookup": {
|
|
6436
|
+
if (!p.id) return fail13("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6437
|
+
const result = await ctx.page.evaluate(
|
|
6438
|
+
`(function() { var m = window.__xbTagMap; if (!m) return JSON.stringify({err:'no-map'}); var e = m[${JSON.stringify(p.id)}]; return e ? JSON.stringify(e) : JSON.stringify({err:'not-found'}); })()`
|
|
6439
|
+
);
|
|
6440
|
+
const parsed = JSON.parse(result);
|
|
6441
|
+
if (parsed.err) return fail13(`ID ${p.id}: ${parsed.err}`);
|
|
6442
|
+
return ok28({ action: "lookup", id: p.id, element: parsed });
|
|
6443
|
+
}
|
|
6444
|
+
case "list": {
|
|
6445
|
+
const result = await ctx.page.evaluate(
|
|
6446
|
+
`(function() { var m = window.__xbTagMap; if (!m) return '{}'; var out = {}; for (var k in m) { out[k] = m[k].text || m[k].tagName; } return JSON.stringify(out); })()`
|
|
6447
|
+
);
|
|
6448
|
+
return ok28({ action: "list", element: JSON.parse(result) });
|
|
6449
|
+
}
|
|
6450
|
+
case "clear": {
|
|
6451
|
+
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6452
|
+
return ok28({ action: "clear" });
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
}
|
|
6456
|
+
});
|
|
6457
|
+
|
|
6458
|
+
// src/commands/visual-tag-v2.ts
|
|
6459
|
+
import { z as z30 } from "zod";
|
|
6460
|
+
import { ok as ok29, fail as fail14 } from "@dyyz1993/xcli-core";
|
|
6461
|
+
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6462
|
+
var TAG_V2_SCRIPT = `
|
|
6463
|
+
(function() {
|
|
6464
|
+
var old = document.getElementById('__xb-tag-overlay');
|
|
6465
|
+
if (old) old.remove();
|
|
6466
|
+
window.__xbTagMap = {};
|
|
6467
|
+
window.__xbTagStats = {};
|
|
6468
|
+
|
|
6469
|
+
var SAFE_SET = ${JSON.stringify(SAFE_SET2)};
|
|
6470
|
+
var TYPE_PREFIX = { click:'k', input:'n', img:'m', list:'h', count:'p', text:'t' };
|
|
6471
|
+
function genId(prefix, idx) {
|
|
6472
|
+
var base = SAFE_SET.length;
|
|
6473
|
+
var suffix = SAFE_SET[Math.floor(idx / base) % base] + SAFE_SET[idx % base];
|
|
6474
|
+
return prefix + suffix;
|
|
6475
|
+
}
|
|
6476
|
+
|
|
6477
|
+
var counters = { click: 0, input: 0, img: 0, list: 0, count: 0, text: 0 };
|
|
6478
|
+
|
|
6479
|
+
var canvas = document.createElement('canvas');
|
|
6480
|
+
canvas.id = '__xb-tag-overlay';
|
|
6481
|
+
canvas.width = window.innerWidth;
|
|
6482
|
+
canvas.height = Math.max(window.innerHeight, document.documentElement.scrollHeight);
|
|
6483
|
+
canvas.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:999999;';
|
|
6484
|
+
document.body.appendChild(canvas);
|
|
6485
|
+
var ctx = canvas.getContext('2d');
|
|
6486
|
+
|
|
6487
|
+
function classifyElement(el) {
|
|
6488
|
+
var tag = el.tagName;
|
|
6489
|
+
var text = (el.textContent || '').trim();
|
|
6490
|
+
var cls = el.className || '';
|
|
6491
|
+
|
|
6492
|
+
// \u4F18\u5148\u7EA71\uFF1A\u6570\u5B57/\u8BA1\u6570\u5668\u2014\u2014\u5148\u4E8E\u5217\u8868\uFF08S129 \u9057\u7559\u95EE\u9898\u4FEE\u590D\uFF09
|
|
6493
|
+
var hasOnlySvgChildren = true;
|
|
6494
|
+
for (var ci = 0; ci < el.children.length; ci++) {
|
|
6495
|
+
if (el.children[ci].tagName.toUpperCase() !== 'SVG' && el.children[ci].tagName.toUpperCase() !== 'PATH' && el.children[ci].tagName.toUpperCase() !== 'SPAN') { hasOnlySvgChildren = false; break; }
|
|
6496
|
+
}
|
|
6497
|
+
if ((el.children.length === 0 || hasOnlySvgChildren) && text.length > 0 && text.length < 25) {
|
|
6498
|
+
var numMatch = /^[0-9]/.test(text) && text.length < 20;
|
|
6499
|
+
if (numMatch) return 'count';
|
|
6500
|
+
}
|
|
6501
|
+
// \u4F18\u5148\u7EA71.5\uFF1Aclass \u542B count/num/like/star/fork \u7684\u5BB9\u5668
|
|
6502
|
+
if (/count|num\b|like|star|fork|rating|badge/i.test(cls) && el.children.length <= 2) return 'count';
|
|
6503
|
+
|
|
6504
|
+
// \u4F18\u5148\u7EA72\uFF1A\u8F93\u5165\u6846
|
|
6505
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' ||
|
|
6506
|
+
el.getAttribute('contenteditable')) return 'input';
|
|
6507
|
+
|
|
6508
|
+
// \u4F18\u5148\u7EA73\uFF1A\u53EF\u70B9\u51FB\uFF08v3 \u6269\u5BBD\uFF1Adata-target/onclick/tab/menu/nav/link class\uFF09
|
|
6509
|
+
if (tag === 'BUTTON' || (el.getAttribute('role') === 'button') ||
|
|
6510
|
+
(tag === 'A' && el.getAttribute('href')) ||
|
|
6511
|
+
el.hasAttribute('onclick') || el.hasAttribute('data-target') ||
|
|
6512
|
+
/btn|button|click|action|tab\b|menu|nav\b|link\b/i.test(cls)) return 'click';
|
|
6513
|
+
|
|
6514
|
+
// \u4F18\u5148\u7EA74\uFF1A\u56FE\u7247\uFF08v3\uFF1A\u542B SVG \u56FE\u6807\uFF09
|
|
6515
|
+
if (tag === 'IMG' || (tag === 'SVG') ||
|
|
6516
|
+
(el.querySelector && el.querySelector('img,svg') &&
|
|
6517
|
+
el.children.length <= 2 && !text)) return 'img';
|
|
6518
|
+
|
|
6519
|
+
// \u4F18\u5148\u7EA74.5\uFF1A\u8868\u683C\u5355\u5143\u683C
|
|
6520
|
+
if (tag === 'TD' || tag === 'TH') return 'list';
|
|
6521
|
+
|
|
6522
|
+
// \u4F18\u5148\u7EA75\uFF1A\u5217\u8868\uFF08v3\uFF1A\u52A0 card\uFF09
|
|
6523
|
+
if (tag === 'UL' || tag === 'OL' || tag === 'LI' ||
|
|
6524
|
+
/list|item|feed|timeline|card/i.test(cls)) return 'list';
|
|
6525
|
+
|
|
6526
|
+
// \u4F18\u5148\u7EA76\uFF1A\u6587\u672C
|
|
6527
|
+
if (text.length > 20) return 'text';
|
|
6528
|
+
return null;
|
|
6529
|
+
}
|
|
6530
|
+
|
|
6531
|
+
var COLORS = {
|
|
6532
|
+
click: { stroke: '#FF0000', fill: '#FFD700' }, // \u7EA2+\u9EC4
|
|
6533
|
+
input: { stroke: '#0000FF', fill: '#ADD8E6' }, // \u84DD
|
|
6534
|
+
img: { stroke: '#00AA00', fill: '#90EE90' }, // \u7EFF
|
|
6535
|
+
list: { stroke: '#FFAA00', fill: '#FFE4B5' }, // \u6A59\u9EC4
|
|
6536
|
+
count: { stroke: '#9900CC', fill: '#E0B0FF' }, // \u7D2B
|
|
6537
|
+
text: { stroke: '#FF8C00', fill: '#FFECD2' }, // \u6A59
|
|
6538
|
+
};
|
|
6539
|
+
|
|
6540
|
+
var all = document.querySelectorAll('button, a[href], td, th, input, select, textarea, img, ul, ol, li, svg, [onclick], [role="button"], [contenteditable], [aria-label], [data-target], [class*="btn"], [class*="list"], [class*="item"], [class*="count"], [class*="num"], [class*="like"], [class*="comment"], [class*="stat"], [class*="card"], [class*="tab"], [class*="menu"], [class*="nav"], [class*="link"], [class*="Link"], [class*="Card"]');
|
|
6541
|
+
|
|
6542
|
+
for (var i = 0; i < all.length && i < 3000; i++) {
|
|
6543
|
+
var el = all[i];
|
|
6544
|
+
var r = el.getBoundingClientRect();
|
|
6545
|
+
if (r.width < 8 || r.height < 8) continue;
|
|
6546
|
+
if (r.x < -50 || r.y < -50 || r.x > window.innerWidth || r.y > window.innerHeight + 200) continue;
|
|
6547
|
+
var style = getComputedStyle(el);
|
|
6548
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
|
|
6549
|
+
|
|
6550
|
+
var type = classifyElement(el);
|
|
6551
|
+
if (!type) continue;
|
|
6552
|
+
|
|
6553
|
+
var id = genId(TYPE_PREFIX[type] || 't', counters[type]);
|
|
6554
|
+
counters[type]++;
|
|
6555
|
+
var colors = COLORS[type];
|
|
6556
|
+
|
|
6557
|
+
// \u6807\u7B7E
|
|
6558
|
+
ctx.fillStyle = colors.fill;
|
|
6559
|
+
ctx.fillRect(r.x - 2, r.y - 14, id.length * 7 + 6, 14);
|
|
6560
|
+
ctx.strokeStyle = '#000';
|
|
6561
|
+
ctx.lineWidth = 1;
|
|
6562
|
+
ctx.strokeRect(r.x - 2, r.y - 14, id.length * 7 + 6, 14);
|
|
6563
|
+
ctx.fillStyle = '#000';
|
|
6564
|
+
ctx.font = 'bold 11px monospace';
|
|
6565
|
+
ctx.fillText(id, r.x + 1, r.y - 4);
|
|
6566
|
+
|
|
6567
|
+
// \u5143\u7D20\u6846\uFF08\u5206\u8272\uFF09
|
|
6568
|
+
ctx.strokeStyle = colors.stroke;
|
|
6569
|
+
ctx.lineWidth = 1.5;
|
|
6570
|
+
ctx.strokeRect(r.x, r.y, r.width, r.height);
|
|
6571
|
+
|
|
6572
|
+
// v4\uFF1A\u67E5\u7236\u7EA7\u6807\u6CE8 ID\uFF08\u5D4C\u5957\u5173\u7CFB\uFF09
|
|
6573
|
+
var parentId = null;
|
|
6574
|
+
var parentNode = el.parentElement;
|
|
6575
|
+
while (parentNode && parentNode !== document.body) {
|
|
6576
|
+
for (var pk in window.__xbTagMap) {
|
|
6577
|
+
if (window.__xbTagMap[pk]._el === parentNode) { parentId = pk; break; }
|
|
6578
|
+
}
|
|
6579
|
+
if (parentId) break;
|
|
6580
|
+
parentNode = parentNode.parentElement;
|
|
6581
|
+
}
|
|
6582
|
+
|
|
6583
|
+
// v6\uFF1A\u8868\u5355\u8BED\u4E49\u2014\u2014\u8BC6\u522B input \u7684\u5173\u8054 label
|
|
6584
|
+
var formLabel = null;
|
|
6585
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') {
|
|
6586
|
+
var inputId = el.id;
|
|
6587
|
+
if (inputId) {
|
|
6588
|
+
var lbl = document.querySelector('label[for="' + inputId + '"]');
|
|
6589
|
+
if (lbl) formLabel = lbl.textContent.trim();
|
|
6590
|
+
}
|
|
6591
|
+
if (!formLabel) {
|
|
6592
|
+
var aria = el.getAttribute('aria-label');
|
|
6593
|
+
if (aria) formLabel = aria;
|
|
6594
|
+
}
|
|
6595
|
+
if (!formLabel) {
|
|
6596
|
+
var ph = el.getAttribute('placeholder');
|
|
6597
|
+
if (ph) formLabel = '(placeholder) ' + ph;
|
|
6598
|
+
}
|
|
6599
|
+
if (!formLabel) {
|
|
6600
|
+
var parentLbl = el.closest('label');
|
|
6601
|
+
if (parentLbl) formLabel = parentLbl.textContent.trim().slice(0, 30);
|
|
6602
|
+
}
|
|
6603
|
+
if (!formLabel) {
|
|
6604
|
+
var prev = el.previousElementSibling;
|
|
6605
|
+
if (prev && (prev.tagName === 'LABEL' || prev.tagName === 'SPAN' || prev.tagName === 'DIV') && prev.textContent.trim()) {
|
|
6606
|
+
formLabel = '(adjacent) ' + prev.textContent.trim().slice(0, 30);
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6611
|
+
// v7\uFF1A\u8868\u683C\u8BED\u4E49\u2014\u2014\u5355\u5143\u683C \u2192 \u5217\u540D + \u884C\u53F7
|
|
6612
|
+
var tableInfo = null;
|
|
6613
|
+
if (el.tagName === 'TD' || el.tagName === 'TH') {
|
|
6614
|
+
var table = el.closest('table');
|
|
6615
|
+
if (table) {
|
|
6616
|
+
var row = el.closest('tr');
|
|
6617
|
+
var cellIndex = el.cellIndex;
|
|
6618
|
+
var rowIndex = row ? row.rowIndex : -1;
|
|
6619
|
+
// \u627E\u8868\u5934\uFF08thead \u7684 th \u6216\u7B2C\u4E00\u884C\u7684 th\uFF09
|
|
6620
|
+
var header = table.querySelector('thead th:nth-child(' + (cellIndex + 1) + ')') ||
|
|
6621
|
+
table.querySelector('tr:first-child th:nth-child(' + (cellIndex + 1) + ')');
|
|
6622
|
+
var colName = header ? header.textContent.trim() : 'col-' + (cellIndex + 1);
|
|
6623
|
+
tableInfo = { col: colName, colIndex: cellIndex, rowIndex: rowIndex, value: el.textContent.trim().slice(0, 20) };
|
|
6624
|
+
}
|
|
6625
|
+
}
|
|
6626
|
+
|
|
6627
|
+
window.__xbTagMap[id] = {
|
|
6628
|
+
type: type,
|
|
6629
|
+
parent: parentId,
|
|
6630
|
+
_el: el,
|
|
6631
|
+
formLabel: formLabel,
|
|
6632
|
+
table: tableInfo,
|
|
6633
|
+
tagName: el.tagName,
|
|
6634
|
+
text: (el.textContent || '').trim().slice(0, 40),
|
|
6635
|
+
num: (el.textContent || '').trim().match(/[\\d,.]+/)?.[0] || null,
|
|
6636
|
+
rect: { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) },
|
|
6637
|
+
selector: (function(e) {
|
|
6638
|
+
if (e.id) return '#' + e.id;
|
|
6639
|
+
if (e.getAttribute('data-testid')) return '[data-testid="' + e.getAttribute('data-testid') + '"]';
|
|
6640
|
+
var path = [];
|
|
6641
|
+
var node = e;
|
|
6642
|
+
while (node && node !== document.body) {
|
|
6643
|
+
var idx = 1;
|
|
6644
|
+
var sib = node.previousElementSibling;
|
|
6645
|
+
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
6646
|
+
path.unshift(node.tagName.toLowerCase() + ':nth-of-type(' + idx + ')');
|
|
6647
|
+
node = node.parentElement;
|
|
6648
|
+
}
|
|
6649
|
+
return path.join(' > ');
|
|
6650
|
+
})(el)
|
|
6651
|
+
};
|
|
6652
|
+
}
|
|
6653
|
+
|
|
6654
|
+
// v9\uFF1A\u8DE8 frame \u6807\u6CE8\u2014\u2014\u9012\u5F52\u5904\u7406\u540C\u6E90 iframe \u5185\u7684\u5143\u7D20
|
|
6655
|
+
function tagFrame(doc, offsetX, offsetY) {
|
|
6656
|
+
var frameAll = doc.querySelectorAll('button, a[href], input, select, textarea, img, [onclick], [role=button], [contenteditable], [aria-label]');
|
|
6657
|
+
for (var fi = 0; fi < frameAll.length && fi < 100; fi++) {
|
|
6658
|
+
var fel = frameAll[fi];
|
|
6659
|
+
var fr = fel.getBoundingClientRect();
|
|
6660
|
+
if (fr.width < 8 || fr.height < 8) continue;
|
|
6661
|
+
var fType = classifyElement(fel);
|
|
6662
|
+
if (!fType) continue;
|
|
6663
|
+
var fId = genId(TYPE_PREFIX[fType] || 't', counters[fType]);
|
|
6664
|
+
counters[fType]++;
|
|
6665
|
+
var fColors = COLORS[fType];
|
|
6666
|
+
// \u5750\u6807\u504F\u79FB\u5230\u4E3B\u6587\u6863 Canvas\uFF08iframe \u5728\u4E3B\u6587\u6863\u4E2D\u7684\u4F4D\u7F6E + \u5143\u7D20\u5728 iframe \u4E2D\u7684\u4F4D\u7F6E\uFF09
|
|
6667
|
+
var fx = fr.x + offsetX, fy = fr.y + offsetY;
|
|
6668
|
+
ctx.fillStyle = fColors.fill;
|
|
6669
|
+
ctx.fillRect(fx - 2, fy - 14, fId.length * 7 + 6, 14);
|
|
6670
|
+
ctx.strokeStyle = '#000'; ctx.lineWidth = 1;
|
|
6671
|
+
ctx.strokeRect(fx - 2, fy - 14, fId.length * 7 + 6, 14);
|
|
6672
|
+
ctx.fillStyle = '#000'; ctx.font = 'bold 11px monospace';
|
|
6673
|
+
ctx.fillText(fId, fx + 1, fy - 4);
|
|
6674
|
+
ctx.strokeStyle = fColors.stroke; ctx.lineWidth = 1.5;
|
|
6675
|
+
ctx.strokeRect(fx, fy, fr.width, fr.height);
|
|
6676
|
+
window.__xbTagMap[fId] = {
|
|
6677
|
+
type: fType, tagName: fel.tagName,
|
|
6678
|
+
text: (fel.textContent||'').trim().slice(0,40),
|
|
6679
|
+
num: (fel.textContent||'').trim().match(/[0-9,.]+/)?.[0] || null,
|
|
6680
|
+
formLabel: (fel.getAttribute('aria-label')||fel.getAttribute('placeholder')||'').slice(0,30) || null,
|
|
6681
|
+
frame: 'iframe',
|
|
6682
|
+
_el: fel,
|
|
6683
|
+
rect: {x:Math.round(fx),y:Math.round(fy),w:Math.round(fr.width),h:Math.round(fr.height)},
|
|
6684
|
+
selector: (function(e){return e.id?'#'+e.id:e.tagName.toLowerCase()}) (fel)
|
|
6685
|
+
};
|
|
6686
|
+
}
|
|
6687
|
+
// \u9012\u5F52\u5904\u7406\u5D4C\u5957 iframe
|
|
6688
|
+
var nestedFrames = doc.querySelectorAll('iframe');
|
|
6689
|
+
for (var nf = 0; nf < nestedFrames.length; nf++) {
|
|
6690
|
+
try {
|
|
6691
|
+
var nestedDoc = nestedFrames[nf].contentDocument;
|
|
6692
|
+
if (!nestedDoc) continue;
|
|
6693
|
+
var nestedRect = nestedFrames[nf].getBoundingClientRect();
|
|
6694
|
+
tagFrame(nestedDoc, nestedRect.x, nestedRect.y);
|
|
6695
|
+
} catch(e) { /* \u8DE8\u57DF iframe \u8DF3\u8FC7 */ }
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
// \u904D\u5386\u4E3B\u6587\u6863\u7684\u6240\u6709\u540C\u6E90 iframe
|
|
6699
|
+
var mainFrames = document.querySelectorAll('iframe');
|
|
6700
|
+
for (var mf = 0; mf < mainFrames.length; mf++) {
|
|
6701
|
+
try {
|
|
6702
|
+
var mDoc = mainFrames[mf].contentDocument;
|
|
6703
|
+
if (!mDoc) continue;
|
|
6704
|
+
var mRect = mainFrames[mf].getBoundingClientRect();
|
|
6705
|
+
tagFrame(mDoc, mRect.x, mRect.y);
|
|
6706
|
+
} catch(e) { /* \u8DE8\u57DF\u8DF3\u8FC7 */ }
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6709
|
+
// v8\uFF1A\u52A8\u6001\u6807\u6CE8\u2014\u2014MutationObserver \u76D1\u542C\u65B0\u5143\u7D20\uFF0C\u81EA\u52A8\u8865\u5145\u6807\u6CE8
|
|
6710
|
+
if (window.__xbTagObserver) { window.__xbTagObserver.disconnect(); }
|
|
6711
|
+
window.__xbTagObserver = new MutationObserver(function(mutations) {
|
|
6712
|
+
var needsRetag = false;
|
|
6713
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
6714
|
+
if (mutations[mi].addedNodes.length > 0) { needsRetag = true; break; }
|
|
6715
|
+
}
|
|
6716
|
+
if (!needsRetag) return;
|
|
6717
|
+
// v8.1\uFF1A\u6E05\u7406\u88AB\u79FB\u9664\u5143\u7D20\u7684\u6807\u6CE8\uFF08\u6B7B\u6807\u6CE8\u4F1A\u7559\u5728 Canvas \u4E0A\uFF09
|
|
6718
|
+
for (var ri = 0; ri < mutations.length; ri++) {
|
|
6719
|
+
var removed = mutations[ri].removedNodes;
|
|
6720
|
+
for (var rj = 0; rj < removed.length; rj++) {
|
|
6721
|
+
var removedNode = removed[rj];
|
|
6722
|
+
if (!removedNode.tagName) continue;
|
|
6723
|
+
for (var rk in window.__xbTagMap) {
|
|
6724
|
+
var entry = window.__xbTagMap[rk];
|
|
6725
|
+
if (entry._el === removedNode || (entry._el && removedNode.contains && removedNode.contains(entry._el))) {
|
|
6726
|
+
delete window.__xbTagMap[rk];
|
|
6727
|
+
window.__xbTagStats.total--;
|
|
6728
|
+
}
|
|
6729
|
+
}
|
|
6730
|
+
}
|
|
6731
|
+
}
|
|
6732
|
+
// \u9632\u6296\uFF1A300ms \u5185\u7684\u8FDE\u7EED\u53D8\u5316\u53EA\u89E6\u53D1\u4E00\u6B21\u91CD\u6807\u6CE8
|
|
6733
|
+
clearTimeout(window.__xbTagRetagTimer);
|
|
6734
|
+
window.__xbTagRetagTimer = setTimeout(function() {
|
|
6735
|
+
// \u53EA\u6807\u6CE8\u65B0\u589E\u7684\u53EF\u89C1\u5143\u7D20\uFF08\u4E0D\u91CD\u753B\u6574\u4E2A Canvas\uFF09
|
|
6736
|
+
var ctx2 = document.getElementById('__xb-tag-overlay');
|
|
6737
|
+
if (!ctx2) return;
|
|
6738
|
+
var canvas2 = ctx2.getContext('2d');
|
|
6739
|
+
for (var ni = 0; ni < mutations.length; ni++) {
|
|
6740
|
+
var nodes = mutations[ni].addedNodes;
|
|
6741
|
+
for (var nj = 0; nj < nodes.length; nj++) {
|
|
6742
|
+
var node = nodes[nj];
|
|
6743
|
+
if (!node.getBoundingClientRect) continue;
|
|
6744
|
+
var r = node.getBoundingClientRect();
|
|
6745
|
+
if (r.width < 8 || r.height < 8) continue;
|
|
6746
|
+
// \u5206\u7C7B\u5E76\u6807\u6CE8
|
|
6747
|
+
var newType = classifyElement(node);
|
|
6748
|
+
if (!newType) continue;
|
|
6749
|
+
var newId = genId(TYPE_PREFIX[newType] || 't', counters[newType]);
|
|
6750
|
+
counters[newType]++;
|
|
6751
|
+
var colors = COLORS[newType];
|
|
6752
|
+
canvas2.fillStyle = colors.fill;
|
|
6753
|
+
canvas2.fillRect(r.x - 2, r.y - 14, newId.length * 7 + 6, 14);
|
|
6754
|
+
canvas2.strokeStyle = '#000';
|
|
6755
|
+
canvas2.lineWidth = 1;
|
|
6756
|
+
canvas2.strokeRect(r.x - 2, r.y - 14, newId.length * 7 + 6, 14);
|
|
6757
|
+
canvas2.fillStyle = '#000';
|
|
6758
|
+
canvas2.font = 'bold 11px monospace';
|
|
6759
|
+
canvas2.fillText(newId, r.x + 1, r.y - 4);
|
|
6760
|
+
canvas2.strokeStyle = colors.stroke;
|
|
6761
|
+
canvas2.lineWidth = 1.5;
|
|
6762
|
+
canvas2.strokeRect(r.x, r.y, r.width, r.height);
|
|
6763
|
+
// \u5B58\u6620\u5C04
|
|
6764
|
+
var parentId = null;
|
|
6765
|
+
var parentNode = node.parentElement;
|
|
6766
|
+
while (parentNode && parentNode !== document.body) {
|
|
6767
|
+
for (var pk in window.__xbTagMap) {
|
|
6768
|
+
if (window.__xbTagMap[pk]._el === parentNode) { parentId = pk; break; }
|
|
6769
|
+
}
|
|
6770
|
+
if (parentId) break;
|
|
6771
|
+
parentNode = parentNode.parentElement;
|
|
6772
|
+
}
|
|
6773
|
+
window.__xbTagMap[newId] = { type: newType, tagName: node.tagName, text: (node.textContent||'').trim().slice(0,40), parent: parentId, _el: node, rect: {x:Math.round(r.x),y:Math.round(r.y),w:Math.round(r.width),h:Math.round(r.height)} };
|
|
6774
|
+
window.__xbTagStats.total++;
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
// \u66F4\u65B0 serializable
|
|
6778
|
+
var ser = {};
|
|
6779
|
+
for (var sk2 in window.__xbTagMap) {
|
|
6780
|
+
var item = {};
|
|
6781
|
+
for (var key in window.__xbTagMap[sk2]) { if (key !== '_el') item[key] = window.__xbTagMap[sk2][key]; }
|
|
6782
|
+
ser[sk2] = item;
|
|
6783
|
+
}
|
|
6784
|
+
window.__xbTagSerializable = ser;
|
|
6785
|
+
}, 300);
|
|
6786
|
+
});
|
|
6787
|
+
window.__xbTagObserver.observe(document.body, { childList: true, subtree: true });
|
|
6788
|
+
|
|
6789
|
+
// v4\uFF1A\u751F\u6210\u53EF\u5E8F\u5217\u5316\u7248\u672C\uFF08\u53BB\u6389 _el DOM \u5F15\u7528\uFF09
|
|
6790
|
+
var serializable = {};
|
|
6791
|
+
for (var sk in window.__xbTagMap) {
|
|
6792
|
+
var item = {};
|
|
6793
|
+
for (var key in window.__xbTagMap[sk]) {
|
|
6794
|
+
if (key !== '_el') item[key] = window.__xbTagMap[sk][key];
|
|
6795
|
+
}
|
|
6796
|
+
serializable[sk] = item;
|
|
6797
|
+
}
|
|
6798
|
+
window.__xbTagSerializable = serializable;
|
|
6799
|
+
window.__xbTagStats = { total: Object.keys(window.__xbTagMap).length, byType: counters };
|
|
6800
|
+
return JSON.stringify(window.__xbTagStats);
|
|
6801
|
+
})()
|
|
6802
|
+
`;
|
|
6803
|
+
var visualTagV2Command = registerCommand({
|
|
6804
|
+
name: "visual-tag-v2",
|
|
6805
|
+
description: "\u5206\u8272\u6807\u6CE8\u9875\u9762\u5143\u7D20\uFF08\u7EA2=\u53EF\u70B9\u51FB \u84DD=\u8F93\u5165 \u7EFF=\u56FE\u7247 \u9EC4=\u5217\u8868 \u7D2B=\u6570\u5B57 \u6A59=\u6587\u672C\uFF09",
|
|
6806
|
+
scope: "page",
|
|
6807
|
+
parameters: z30.object({
|
|
6808
|
+
action: z30.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
6809
|
+
id: z30.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
6810
|
+
query: z30.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
6811
|
+
type: z30.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
6812
|
+
"interact-action": z30.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
6813
|
+
value: z30.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6814
|
+
}),
|
|
6815
|
+
result: z30.object({
|
|
6816
|
+
action: z30.string(),
|
|
6817
|
+
total: z30.number().optional(),
|
|
6818
|
+
byType: z30.record(z30.number()).optional(),
|
|
6819
|
+
element: z30.record(z30.unknown()).optional()
|
|
6820
|
+
}),
|
|
6821
|
+
handler: async (p, ctx) => {
|
|
6822
|
+
switch (p.action) {
|
|
6823
|
+
case "tag": {
|
|
6824
|
+
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6825
|
+
const parsed = JSON.parse(result);
|
|
6826
|
+
return ok29({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6827
|
+
}
|
|
6828
|
+
case "lookup": {
|
|
6829
|
+
if (!p.id) return fail14("lookup \u9700\u8981 --id");
|
|
6830
|
+
const result = await ctx.page.evaluate(
|
|
6831
|
+
`(function(){var m=window.__xbTagMap;if(!m)return JSON.stringify({err:'no-map'});var e=m[${JSON.stringify(p.id)}];return e?JSON.stringify(e):JSON.stringify({err:'not-found'})})()`
|
|
6832
|
+
);
|
|
6833
|
+
const parsed = JSON.parse(result);
|
|
6834
|
+
if (parsed.err) return fail14(`ID ${p.id}: ${parsed.err}`);
|
|
6835
|
+
return ok29({ action: "lookup", id: p.id, element: parsed });
|
|
6836
|
+
}
|
|
6837
|
+
case "by-type": {
|
|
6838
|
+
const result = await ctx.page.evaluate(
|
|
6839
|
+
`(function(){var m=window.__xbTagMap;if(!m)return'{}';var out={};for(var k in m){if(!${JSON.stringify(p.type || "")}||m[k].type===${JSON.stringify(p.type || "")}){out[k]={type:m[k].type,text:m[k].text,num:m[k].num,label:m[k].formLabel}}}return JSON.stringify(out)})()`
|
|
6840
|
+
);
|
|
6841
|
+
return ok29({ action: "by-type", element: JSON.parse(result) });
|
|
6842
|
+
}
|
|
6843
|
+
case "find": {
|
|
6844
|
+
const query = p.query;
|
|
6845
|
+
if (!query) return fail14('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6846
|
+
const result = await ctx.page.evaluate(
|
|
6847
|
+
`(function(){
|
|
6848
|
+
var map = window.__xbTagSerializable;
|
|
6849
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
6850
|
+
var query = ${JSON.stringify(query)};
|
|
6851
|
+
var results = [];
|
|
6852
|
+
// 1) \u76F4\u63A5\u6587\u672C\u5339\u914D
|
|
6853
|
+
for (var id in map) {
|
|
6854
|
+
var e = map[id];
|
|
6855
|
+
var text = (e.text || '').toLowerCase();
|
|
6856
|
+
var q = query.toLowerCase();
|
|
6857
|
+
if (text.includes(q)) {
|
|
6858
|
+
results.push({id:id, type:e.type, text:e.text, num:e.num, parent:e.parent, reason:'text-match'});
|
|
6859
|
+
}
|
|
6860
|
+
}
|
|
6861
|
+
// 2) \u7C7B\u578B\u5339\u914D\uFF08query \u542B"\u6309\u94AE"/"\u94FE\u63A5"/"\u56FE\u7247"/"\u6570\u5B57"\u7B49\uFF09
|
|
6862
|
+
var typeMap = {button:'click', link:'click', \u6309\u94AE:'click', \u94FE\u63A5:'click', \u56FE\u7247:'img', image:'img',
|
|
6863
|
+
\u8F93\u5165:'input', input:'input', \u5217\u8868:'list', list:'list', \u5361\u7247:'list', card:'list',
|
|
6864
|
+
\u6570\u5B57:'count', count:'count', \u8BA1\u6570:'count', \u6587\u672C:'text'};
|
|
6865
|
+
for (var tk in typeMap) {
|
|
6866
|
+
if (query.toLowerCase().includes(tk)) {
|
|
6867
|
+
for (var id2 in map) {
|
|
6868
|
+
if (map[id2].type === typeMap[tk]) {
|
|
6869
|
+
results.push({id:id2, type:map[id2].type, text:map[id2].text, num:map[id2].num, parent:map[id2].parent, reason:'type-match:'+tk});
|
|
6870
|
+
}
|
|
6871
|
+
}
|
|
6872
|
+
}
|
|
6873
|
+
}
|
|
6874
|
+
// 3) \u6570\u5B57\u5339\u914D\uFF08query \u542B\u6570\u5B57\uFF09
|
|
6875
|
+
var numMatch = query.match(/([0-9,.]+)/);
|
|
6876
|
+
if (numMatch && map) {
|
|
6877
|
+
var target = parseFloat(numMatch[1].replace(/,/g,''));
|
|
6878
|
+
for (var id3 in map) {
|
|
6879
|
+
if (map[id3].num && parseFloat(map[id3].num.replace(/,/g,'')) === target) {
|
|
6880
|
+
results.push({id:id3, type:map[id3].type, text:map[id3].text, num:map[id3].num, parent:map[id3].parent, reason:'num-match'});
|
|
6881
|
+
}
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6885
|
+
})()`
|
|
6886
|
+
);
|
|
6887
|
+
return ok29({ action: "find", query, element: JSON.parse(result) });
|
|
6888
|
+
}
|
|
6889
|
+
case "stats": {
|
|
6890
|
+
const result = await ctx.page.evaluate(
|
|
6891
|
+
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6892
|
+
);
|
|
6893
|
+
return ok29({ action: "stats", element: JSON.parse(result) });
|
|
6894
|
+
}
|
|
6895
|
+
case "interact": {
|
|
6896
|
+
const query = p.query;
|
|
6897
|
+
const pAny = p;
|
|
6898
|
+
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6899
|
+
const value = pAny.value;
|
|
6900
|
+
if (!query) return fail14("interact \u9700\u8981 --query \u53C2\u6570");
|
|
6901
|
+
if (!action) return fail14("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6902
|
+
const findResult = await ctx.page.evaluate(
|
|
6903
|
+
`(function(){
|
|
6904
|
+
var map = window.__xbTagSerializable;
|
|
6905
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
6906
|
+
var query = ${JSON.stringify(query)};
|
|
6907
|
+
var results = [];
|
|
6908
|
+
for (var id in map) {
|
|
6909
|
+
var e = map[id];
|
|
6910
|
+
var text = (e.text || '').toLowerCase();
|
|
6911
|
+
if (text.includes(query.toLowerCase())) {
|
|
6912
|
+
results.push({id:id, type:e.type, text:e.text, num:e.num, label:e.formLabel});
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
6915
|
+
// \u7C7B\u578B\u5339\u914D
|
|
6916
|
+
var typeMap = {button:'click', link:'click', \u6309\u94AE:'click', \u56FE\u7247:'img', image:'img',
|
|
6917
|
+
\u8F93\u5165:'input', input:'input', \u5217\u8868:'list', \u6570\u5B57:'count', count:'count'};
|
|
6918
|
+
for (var tk in typeMap) {
|
|
6919
|
+
if (query.toLowerCase().includes(tk)) {
|
|
6920
|
+
for (var id2 in map) {
|
|
6921
|
+
if (map[id2].type === typeMap[tk]) {
|
|
6922
|
+
results.push({id:id2, type:map[id2].type, text:map[id2].text, num:map[id2].num, label:map[id2].formLabel});
|
|
6923
|
+
}
|
|
6924
|
+
}
|
|
6925
|
+
}
|
|
6926
|
+
}
|
|
6927
|
+
return JSON.stringify({total:results.length, results:results.slice(0,10)});
|
|
6928
|
+
})()`
|
|
6929
|
+
);
|
|
6930
|
+
const parsed = JSON.parse(findResult);
|
|
6931
|
+
if (parsed.err) return fail14(parsed.err);
|
|
6932
|
+
if (!parsed.total || !parsed.results?.length) return fail14(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
6933
|
+
const target = parsed.results[0];
|
|
6934
|
+
if (action === "read") {
|
|
6935
|
+
return ok29({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
6936
|
+
}
|
|
6937
|
+
if (action === "click") {
|
|
6938
|
+
const el = await ctx.page.evaluate(
|
|
6939
|
+
`(function(){
|
|
6940
|
+
var map = window.__xbTagMap;
|
|
6941
|
+
if (!map) return null;
|
|
6942
|
+
var entry = map[${JSON.stringify(target.id)}];
|
|
6943
|
+
if (!entry || !entry._el) return null;
|
|
6944
|
+
var r = entry._el.getBoundingClientRect();
|
|
6945
|
+
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6946
|
+
})()`
|
|
6947
|
+
);
|
|
6948
|
+
if (!el) return fail14(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6949
|
+
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6950
|
+
return ok29({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
6951
|
+
}
|
|
6952
|
+
if (action === "fill") {
|
|
6953
|
+
if (!value) return fail14("fill \u9700\u8981 --value \u53C2\u6570");
|
|
6954
|
+
const el = await ctx.page.evaluate(
|
|
6955
|
+
`(function(){
|
|
6956
|
+
var map = window.__xbTagMap;
|
|
6957
|
+
if (!map) return null;
|
|
6958
|
+
var entry = map[${JSON.stringify(target.id)}];
|
|
6959
|
+
if (!entry || !entry._el) return null;
|
|
6960
|
+
var r = entry._el.getBoundingClientRect();
|
|
6961
|
+
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6962
|
+
})()`
|
|
6963
|
+
);
|
|
6964
|
+
if (!el) return fail14(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6965
|
+
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6966
|
+
await ctx.page.keyboard.type(value, { stealth: true });
|
|
6967
|
+
return ok29({ action: "interact", query, target, result: { filled: true, value } });
|
|
6968
|
+
}
|
|
6969
|
+
return fail14(`\u672A\u77E5 action: ${action}`);
|
|
6970
|
+
}
|
|
6971
|
+
case "export": {
|
|
6972
|
+
const result = await ctx.page.evaluate(
|
|
6973
|
+
`(function(){
|
|
6974
|
+
var map = window.__xbTagSerializable;
|
|
6975
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
6976
|
+
// \u6309 type \u5206\u7EC4\u7EDF\u8BA1
|
|
6977
|
+
var byType = {};
|
|
6978
|
+
for (var id in map) {
|
|
6979
|
+
var t = map[id].type || 'unknown';
|
|
6980
|
+
byType[t] = (byType[t] || 0) + 1;
|
|
6981
|
+
}
|
|
6982
|
+
// \u6784\u5EFA\u5C42\u7EA7\u6811\uFF08parent \u2192 children\uFF09
|
|
6983
|
+
var tree = {};
|
|
6984
|
+
var roots = [];
|
|
6985
|
+
for (var id2 in map) {
|
|
6986
|
+
var parent = map[id2].parent;
|
|
6987
|
+
if (parent && map[parent]) {
|
|
6988
|
+
if (!tree[parent]) tree[parent] = [];
|
|
6989
|
+
tree[parent].push(id2);
|
|
6990
|
+
} else {
|
|
6991
|
+
roots.push(id2);
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
// elements \u5BFC\u51FA\u6458\u8981\uFF08\u5B8C\u6574 DOM \u6620\u5C04\u592A\u5927\uFF0C\u53EA\u5BFC\u6838\u5FC3\u5B57\u6BB5\uFF09
|
|
6995
|
+
var elementsOut = {};
|
|
6996
|
+
for (var id3 in map) {
|
|
6997
|
+
elementsOut[id3] = {
|
|
6998
|
+
type: map[id3].type,
|
|
6999
|
+
text: (map[id3].text || '').slice(0, 20),
|
|
7000
|
+
num: map[id3].num,
|
|
7001
|
+
label: map[id3].formLabel,
|
|
7002
|
+
frame: map[id3].frame,
|
|
7003
|
+
parent: map[id3].parent,
|
|
7004
|
+
table: map[id3].table ? {col: map[id3].table.col, row: map[id3].table.rowIndex} : null
|
|
7005
|
+
};
|
|
7006
|
+
}
|
|
7007
|
+
return JSON.stringify({
|
|
7008
|
+
total: Object.keys(map).length,
|
|
7009
|
+
byType: byType,
|
|
7010
|
+
rootIds: roots.slice(0, 20),
|
|
7011
|
+
hierarchy: Object.keys(tree).slice(0, 50).reduce(function(acc, k) { acc[k] = tree[k]; return acc; }, {}),
|
|
7012
|
+
elements: elementsOut
|
|
7013
|
+
});
|
|
7014
|
+
})()`
|
|
7015
|
+
);
|
|
7016
|
+
const parsed = JSON.parse(result);
|
|
7017
|
+
if (parsed.err) return fail14(String(parsed.err));
|
|
7018
|
+
return ok29({ action: "export", element: parsed });
|
|
7019
|
+
}
|
|
7020
|
+
case "clear": {
|
|
7021
|
+
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7022
|
+
return ok29({ action: "clear" });
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
});
|
|
7027
|
+
|
|
6325
7028
|
// src/context.ts
|
|
6326
7029
|
function attachDetectAntiBot(ctx) {
|
|
6327
7030
|
ctx.detectAntiBot = async (page, config) => {
|
|
@@ -6986,7 +7689,7 @@ async function guardCheck(commandName) {
|
|
|
6986
7689
|
}
|
|
6987
7690
|
}
|
|
6988
7691
|
function errorResult(message) {
|
|
6989
|
-
return { ...
|
|
7692
|
+
return { ...fail15(message), duration: 0 };
|
|
6990
7693
|
}
|
|
6991
7694
|
function tipsToMessages(tips) {
|
|
6992
7695
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7063,7 +7766,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7063
7766
|
}
|
|
7064
7767
|
let targetPageOverride = null;
|
|
7065
7768
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7066
|
-
const { findTargetPage } = await import("./browser-
|
|
7769
|
+
const { findTargetPage } = await import("./browser-Y5SIE6LY.js");
|
|
7067
7770
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7068
7771
|
if (!targetPageOverride) {
|
|
7069
7772
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7259,7 +7962,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7259
7962
|
timestamp: start
|
|
7260
7963
|
});
|
|
7261
7964
|
if (isSuccess) {
|
|
7262
|
-
return { ...
|
|
7965
|
+
return { ...ok30(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7263
7966
|
}
|
|
7264
7967
|
return { success: false, data: raw.data, message: raw.message, tips: mergedOrRaw, duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7265
7968
|
}
|
|
@@ -7273,7 +7976,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7273
7976
|
duration,
|
|
7274
7977
|
timestamp: start
|
|
7275
7978
|
});
|
|
7276
|
-
return { ...
|
|
7979
|
+
return { ...ok30(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7277
7980
|
} catch (err) {
|
|
7278
7981
|
const end = Date.now();
|
|
7279
7982
|
const duration = end - start;
|
|
@@ -7318,7 +8021,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7318
8021
|
duration,
|
|
7319
8022
|
timestamp: start
|
|
7320
8023
|
});
|
|
7321
|
-
return { ...
|
|
8024
|
+
return { ...fail15(errorMessage), duration };
|
|
7322
8025
|
} finally {
|
|
7323
8026
|
}
|
|
7324
8027
|
}
|
|
@@ -7362,7 +8065,7 @@ async function executeChain(input, options) {
|
|
|
7362
8065
|
results.push({
|
|
7363
8066
|
command: cmdName,
|
|
7364
8067
|
raw: cmdStr,
|
|
7365
|
-
...
|
|
8068
|
+
...fail15(`Plugin "${cmdName}" requires a sub-command`),
|
|
7366
8069
|
duration: 0
|
|
7367
8070
|
});
|
|
7368
8071
|
if (type === "and") {
|
|
@@ -7381,7 +8084,7 @@ async function executeChain(input, options) {
|
|
|
7381
8084
|
results.push({
|
|
7382
8085
|
command: cmdName,
|
|
7383
8086
|
raw: cmdStr,
|
|
7384
|
-
...
|
|
8087
|
+
...fail15(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7385
8088
|
duration: 0
|
|
7386
8089
|
});
|
|
7387
8090
|
if (type === "and") {
|
|
@@ -7485,7 +8188,7 @@ async function executeChain(input, options) {
|
|
|
7485
8188
|
results.push({
|
|
7486
8189
|
command: `${cmdName} ${subCommand}`,
|
|
7487
8190
|
raw: cmdStr,
|
|
7488
|
-
...
|
|
8191
|
+
...ok30(data),
|
|
7489
8192
|
duration: duration2,
|
|
7490
8193
|
...hookOutputs ? { hookOutputs } : {}
|
|
7491
8194
|
});
|
|
@@ -7513,7 +8216,7 @@ async function executeChain(input, options) {
|
|
|
7513
8216
|
results.push({
|
|
7514
8217
|
command: `${cmdName} ${subCommand}`,
|
|
7515
8218
|
raw: cmdStr,
|
|
7516
|
-
...
|
|
8219
|
+
...fail15(errorMessage),
|
|
7517
8220
|
duration: duration2
|
|
7518
8221
|
});
|
|
7519
8222
|
if (type === "and") {
|
|
@@ -8885,7 +9588,7 @@ function createRPCHandler() {
|
|
|
8885
9588
|
if (isNewFormat) {
|
|
8886
9589
|
try {
|
|
8887
9590
|
const replayErrors = [];
|
|
8888
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
9591
|
+
const { SessionReplayer } = await import("./session-replayer-RODZYHM3.js");
|
|
8889
9592
|
const replayer = new SessionReplayer({
|
|
8890
9593
|
page: session.page,
|
|
8891
9594
|
stepDelay: slowMo * 500,
|
|
@@ -8935,10 +9638,10 @@ function createRPCHandler() {
|
|
|
8935
9638
|
const errors = Array.isArray(input.errors) ? input.errors : [];
|
|
8936
9639
|
const eventsPlayed = typeof input.eventsPlayed === "number" ? input.eventsPlayed : 0;
|
|
8937
9640
|
const totalEvents = typeof input.totalEvents === "number" ? input.totalEvents : eventsPlayed + errors.length;
|
|
8938
|
-
const
|
|
9641
|
+
const ok31 = input.ok ?? errors.length === 0;
|
|
8939
9642
|
return {
|
|
8940
|
-
ok:
|
|
8941
|
-
success:
|
|
9643
|
+
ok: ok31,
|
|
9644
|
+
success: ok31,
|
|
8942
9645
|
duration: typeof input.duration === "number" ? input.duration : 0,
|
|
8943
9646
|
eventsPlayed,
|
|
8944
9647
|
totalEvents,
|
|
@@ -12060,6 +12763,18 @@ async function main() {
|
|
|
12060
12763
|
log(`unhandledRejection: ${msg}`);
|
|
12061
12764
|
console.error("Daemon unhandledRejection:", msg);
|
|
12062
12765
|
});
|
|
12766
|
+
try {
|
|
12767
|
+
const bridgeUp = await fetch("http://127.0.0.1:9347/status").then((r) => r.ok).catch(() => false);
|
|
12768
|
+
if (!bridgeUp) {
|
|
12769
|
+
const { spawn } = await import("child_process");
|
|
12770
|
+
const path2 = await import("path");
|
|
12771
|
+
const serverPath = path2.join(process.cwd(), ".xcli", "plugins", "chrome-bridge", "server.mjs");
|
|
12772
|
+
const child = spawn(process.execPath, [serverPath, "9346"], { detached: true, stdio: "ignore" });
|
|
12773
|
+
child.unref();
|
|
12774
|
+
log("chrome-bridge server auto-started (WS:9346/HTTP:9347)");
|
|
12775
|
+
}
|
|
12776
|
+
} catch {
|
|
12777
|
+
}
|
|
12063
12778
|
setInterval(() => {
|
|
12064
12779
|
}, 6e4);
|
|
12065
12780
|
}
|