@xbrowser/cli 1.18.2 → 1.20.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-TFFGGXOA.js → browser-NVC7MTML.js} +2 -2
- package/dist/{browser-AEQS6325.js → browser-PBBC7RAV.js} +2 -2
- package/dist/{browser-BEERPZPB.js → browser-Y6B3NS4Q.js} +1 -1
- package/dist/{cdp-driver-4UAV56SQ.js → cdp-driver-73F5CVH2.js} +1 -1
- package/dist/{cdp-driver-KT6HL33W.js → cdp-driver-QYFA4QTP.js} +1 -1
- package/dist/{cdp-driver-NNBPNFF2.js → cdp-driver-Z2PLAO42.js} +103 -19
- package/dist/{chunk-NA7IP6PO.js → chunk-75TLPVVZ.js} +13 -2
- package/dist/{chunk-MTNVT2T7.js → chunk-76EKW7YJ.js} +13 -2
- package/dist/{chunk-LL37GYPP.js → chunk-FDU5BCPV.js} +103 -19
- package/dist/{chunk-7SDM4EA4.js → chunk-T2KUVO4H.js} +115 -20
- package/dist/{chunk-DVKIL7H6.js → chunk-UYEJ66VX.js} +103 -19
- 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-SBYJXQZZ.js} +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
setActivePage,
|
|
73
73
|
sleep,
|
|
74
74
|
wheelDelta
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-T2KUVO4H.js";
|
|
76
76
|
import "./chunk-3KZ34AUC.js";
|
|
77
77
|
import {
|
|
78
78
|
errMsg
|
|
@@ -203,8 +203,8 @@ function asZodSchema(value) {
|
|
|
203
203
|
|
|
204
204
|
// src/executor.ts
|
|
205
205
|
import {
|
|
206
|
-
ok as
|
|
207
|
-
fail as
|
|
206
|
+
ok as ok30,
|
|
207
|
+
fail as fail15,
|
|
208
208
|
isCommandResult,
|
|
209
209
|
CompositeStorage as CompositeStorage2,
|
|
210
210
|
TipCollector as TipCollector2,
|
|
@@ -6362,6 +6362,709 @@ function describeSelector(strategy, value, name) {
|
|
|
6362
6362
|
}
|
|
6363
6363
|
}
|
|
6364
6364
|
|
|
6365
|
+
// src/commands/visual-tag.ts
|
|
6366
|
+
import { z as z29 } from "zod";
|
|
6367
|
+
import { ok as ok28, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6368
|
+
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6369
|
+
var TAG_SCRIPT = `
|
|
6370
|
+
(function() {
|
|
6371
|
+
// \u6E05\u9664\u65E7\u6807\u6CE8
|
|
6372
|
+
var old = document.getElementById('__xb-tag-overlay');
|
|
6373
|
+
if (old) old.remove();
|
|
6374
|
+
window.__xbTagMap = {};
|
|
6375
|
+
|
|
6376
|
+
var SAFE_SET = ${JSON.stringify(SAFE_SET)};
|
|
6377
|
+
function genId(idx) {
|
|
6378
|
+
var base = SAFE_SET.length;
|
|
6379
|
+
if (idx < base * base) return SAFE_SET[Math.floor(idx / base)] + SAFE_SET[idx % base];
|
|
6380
|
+
var i = idx - base * base;
|
|
6381
|
+
return SAFE_SET[Math.floor(i / (base * base))] + SAFE_SET[Math.floor(i / base) % base] + SAFE_SET[i % base];
|
|
6382
|
+
}
|
|
6383
|
+
|
|
6384
|
+
// \u627E\u6240\u6709\u53EF\u4EA4\u4E92\u5143\u7D20
|
|
6385
|
+
var els = [];
|
|
6386
|
+
var all = document.querySelectorAll('button, a[href], input, select, textarea, [onclick], [role="button"], [contenteditable], [class*="btn"], [class*="button"], [class*="link"]');
|
|
6387
|
+
for (var i = 0; i < all.length && els.length < 200; i++) {
|
|
6388
|
+
var el = all[i];
|
|
6389
|
+
var r = el.getBoundingClientRect();
|
|
6390
|
+
if (r.width < 10 || r.height < 10) continue;
|
|
6391
|
+
if (r.x < 0 || r.y < 0 || r.x + r.width > window.innerWidth || r.y + r.height > window.innerHeight + 100) continue;
|
|
6392
|
+
var style = getComputedStyle(el);
|
|
6393
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
|
|
6394
|
+
els.push({ el: el, rect: r });
|
|
6395
|
+
}
|
|
6396
|
+
|
|
6397
|
+
// \u521B\u5EFA\u53E0\u52A0 Canvas
|
|
6398
|
+
var canvas = document.createElement('canvas');
|
|
6399
|
+
canvas.id = '__xb-tag-overlay';
|
|
6400
|
+
canvas.width = window.innerWidth;
|
|
6401
|
+
canvas.height = Math.max(window.innerHeight, document.documentElement.scrollHeight);
|
|
6402
|
+
canvas.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:999999;';
|
|
6403
|
+
document.body.appendChild(canvas);
|
|
6404
|
+
var ctx = canvas.getContext('2d');
|
|
6405
|
+
|
|
6406
|
+
// \u7ED8\u5236\u6807\u7B7E
|
|
6407
|
+
for (var j = 0; j < els.length; j++) {
|
|
6408
|
+
var item = els[j];
|
|
6409
|
+
var id = genId(j);
|
|
6410
|
+
var x = item.rect.x;
|
|
6411
|
+
var y = item.rect.y;
|
|
6412
|
+
|
|
6413
|
+
// \u6807\u7B7E\u6846\uFF1A\u9AD8\u5BF9\u6BD4\uFF08\u9EC4\u5E95\u9ED1\u5B57\uFF09
|
|
6414
|
+
ctx.fillStyle = '#FFD700';
|
|
6415
|
+
ctx.fillRect(x - 2, y - 16, id.length * 8 + 8, 16);
|
|
6416
|
+
ctx.strokeStyle = '#000';
|
|
6417
|
+
ctx.lineWidth = 1.5;
|
|
6418
|
+
ctx.strokeRect(x - 2, y - 16, id.length * 8 + 8, 16);
|
|
6419
|
+
ctx.fillStyle = '#000';
|
|
6420
|
+
ctx.font = 'bold 12px monospace';
|
|
6421
|
+
ctx.fillText(id, x + 2, y - 5);
|
|
6422
|
+
|
|
6423
|
+
// \u5143\u7D20\u8F6E\u5ED3
|
|
6424
|
+
ctx.strokeStyle = '#FF0000';
|
|
6425
|
+
ctx.lineWidth = 1.5;
|
|
6426
|
+
ctx.strokeRect(x, y, item.rect.width, item.rect.height);
|
|
6427
|
+
|
|
6428
|
+
// \u5B58\u50A8 ID \u2192 \u5143\u7D20\u6620\u5C04
|
|
6429
|
+
window.__xbTagMap[id] = {
|
|
6430
|
+
tagName: item.el.tagName,
|
|
6431
|
+
text: (item.el.textContent || '').trim().slice(0, 50),
|
|
6432
|
+
rect: { x: x, y: y, w: item.rect.width, h: item.rect.height },
|
|
6433
|
+
selector: (function(e) {
|
|
6434
|
+
if (e.id) return '#' + e.id;
|
|
6435
|
+
if (e.getAttribute('data-testid')) return '[data-testid="' + e.getAttribute('data-testid') + '"]';
|
|
6436
|
+
// \u751F\u6210 nth-child \u9009\u62E9\u5668
|
|
6437
|
+
var path = [];
|
|
6438
|
+
var node = e;
|
|
6439
|
+
while (node && node !== document.body) {
|
|
6440
|
+
var idx = 1;
|
|
6441
|
+
var sib = node.previousElementSibling;
|
|
6442
|
+
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
6443
|
+
path.unshift(node.tagName.toLowerCase() + ':nth-of-type(' + idx + ')');
|
|
6444
|
+
node = node.parentElement;
|
|
6445
|
+
}
|
|
6446
|
+
return path.join(' > ');
|
|
6447
|
+
})(item.el)
|
|
6448
|
+
};
|
|
6449
|
+
}
|
|
6450
|
+
|
|
6451
|
+
return JSON.stringify({ tagged: els.length, overlay: true });
|
|
6452
|
+
})()
|
|
6453
|
+
`;
|
|
6454
|
+
var visualTagCommand = registerCommand({
|
|
6455
|
+
name: "visual-tag",
|
|
6456
|
+
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",
|
|
6457
|
+
scope: "page",
|
|
6458
|
+
parameters: z29.object({
|
|
6459
|
+
action: z29.enum(["tag", "lookup", "clear", "list"]),
|
|
6460
|
+
id: z29.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6461
|
+
}),
|
|
6462
|
+
result: z29.object({
|
|
6463
|
+
action: z29.string(),
|
|
6464
|
+
tagged: z29.number().optional(),
|
|
6465
|
+
id: z29.string().optional(),
|
|
6466
|
+
element: z29.record(z29.unknown()).optional()
|
|
6467
|
+
}),
|
|
6468
|
+
handler: async (p, ctx) => {
|
|
6469
|
+
switch (p.action) {
|
|
6470
|
+
case "tag": {
|
|
6471
|
+
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6472
|
+
const parsed = JSON.parse(result);
|
|
6473
|
+
return ok28({ action: "tag", tagged: parsed.tagged });
|
|
6474
|
+
}
|
|
6475
|
+
case "lookup": {
|
|
6476
|
+
if (!p.id) return fail13("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6477
|
+
const result = await ctx.page.evaluate(
|
|
6478
|
+
`(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'}); })()`
|
|
6479
|
+
);
|
|
6480
|
+
const parsed = JSON.parse(result);
|
|
6481
|
+
if (parsed.err) return fail13(`ID ${p.id}: ${parsed.err}`);
|
|
6482
|
+
return ok28({ action: "lookup", id: p.id, element: parsed });
|
|
6483
|
+
}
|
|
6484
|
+
case "list": {
|
|
6485
|
+
const result = await ctx.page.evaluate(
|
|
6486
|
+
`(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); })()`
|
|
6487
|
+
);
|
|
6488
|
+
return ok28({ action: "list", element: JSON.parse(result) });
|
|
6489
|
+
}
|
|
6490
|
+
case "clear": {
|
|
6491
|
+
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6492
|
+
return ok28({ action: "clear" });
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6495
|
+
}
|
|
6496
|
+
});
|
|
6497
|
+
|
|
6498
|
+
// src/commands/visual-tag-v2.ts
|
|
6499
|
+
import { z as z30 } from "zod";
|
|
6500
|
+
import { ok as ok29, fail as fail14 } from "@dyyz1993/xcli-core";
|
|
6501
|
+
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6502
|
+
var TAG_V2_SCRIPT = `
|
|
6503
|
+
(function() {
|
|
6504
|
+
var old = document.getElementById('__xb-tag-overlay');
|
|
6505
|
+
if (old) old.remove();
|
|
6506
|
+
window.__xbTagMap = {};
|
|
6507
|
+
window.__xbTagStats = {};
|
|
6508
|
+
|
|
6509
|
+
var SAFE_SET = ${JSON.stringify(SAFE_SET2)};
|
|
6510
|
+
var TYPE_PREFIX = { click:'k', input:'n', img:'m', list:'h', count:'p', text:'t' };
|
|
6511
|
+
function genId(prefix, idx) {
|
|
6512
|
+
var base = SAFE_SET.length;
|
|
6513
|
+
var suffix = SAFE_SET[Math.floor(idx / base) % base] + SAFE_SET[idx % base];
|
|
6514
|
+
return prefix + suffix;
|
|
6515
|
+
}
|
|
6516
|
+
|
|
6517
|
+
var counters = { click: 0, input: 0, img: 0, list: 0, count: 0, text: 0 };
|
|
6518
|
+
|
|
6519
|
+
var canvas = document.createElement('canvas');
|
|
6520
|
+
canvas.id = '__xb-tag-overlay';
|
|
6521
|
+
canvas.width = window.innerWidth;
|
|
6522
|
+
canvas.height = Math.max(window.innerHeight, document.documentElement.scrollHeight);
|
|
6523
|
+
canvas.style.cssText = 'position:fixed;top:0;left:0;pointer-events:none;z-index:999999;';
|
|
6524
|
+
document.body.appendChild(canvas);
|
|
6525
|
+
var ctx = canvas.getContext('2d');
|
|
6526
|
+
|
|
6527
|
+
function classifyElement(el) {
|
|
6528
|
+
var tag = el.tagName;
|
|
6529
|
+
var text = (el.textContent || '').trim();
|
|
6530
|
+
var cls = el.className || '';
|
|
6531
|
+
|
|
6532
|
+
// \u4F18\u5148\u7EA71\uFF1A\u6570\u5B57/\u8BA1\u6570\u5668\u2014\u2014\u5148\u4E8E\u5217\u8868\uFF08S129 \u9057\u7559\u95EE\u9898\u4FEE\u590D\uFF09
|
|
6533
|
+
var hasOnlySvgChildren = true;
|
|
6534
|
+
for (var ci = 0; ci < el.children.length; ci++) {
|
|
6535
|
+
if (el.children[ci].tagName.toUpperCase() !== 'SVG' && el.children[ci].tagName.toUpperCase() !== 'PATH' && el.children[ci].tagName.toUpperCase() !== 'SPAN') { hasOnlySvgChildren = false; break; }
|
|
6536
|
+
}
|
|
6537
|
+
if ((el.children.length === 0 || hasOnlySvgChildren) && text.length > 0 && text.length < 25) {
|
|
6538
|
+
var numMatch = /^[0-9]/.test(text) && text.length < 20;
|
|
6539
|
+
if (numMatch) return 'count';
|
|
6540
|
+
}
|
|
6541
|
+
// \u4F18\u5148\u7EA71.5\uFF1Aclass \u542B count/num/like/star/fork \u7684\u5BB9\u5668
|
|
6542
|
+
if (/count|num\b|like|star|fork|rating|badge/i.test(cls) && el.children.length <= 2) return 'count';
|
|
6543
|
+
|
|
6544
|
+
// \u4F18\u5148\u7EA72\uFF1A\u8F93\u5165\u6846
|
|
6545
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' ||
|
|
6546
|
+
el.getAttribute('contenteditable')) return 'input';
|
|
6547
|
+
|
|
6548
|
+
// \u4F18\u5148\u7EA73\uFF1A\u53EF\u70B9\u51FB\uFF08v3 \u6269\u5BBD\uFF1Adata-target/onclick/tab/menu/nav/link class\uFF09
|
|
6549
|
+
if (tag === 'BUTTON' || (el.getAttribute('role') === 'button') ||
|
|
6550
|
+
(tag === 'A' && el.getAttribute('href')) ||
|
|
6551
|
+
el.hasAttribute('onclick') || el.hasAttribute('data-target') ||
|
|
6552
|
+
/btn|button|click|action|tab\b|menu|nav\b|link\b/i.test(cls)) return 'click';
|
|
6553
|
+
|
|
6554
|
+
// \u4F18\u5148\u7EA74\uFF1A\u56FE\u7247\uFF08v3\uFF1A\u542B SVG \u56FE\u6807\uFF09
|
|
6555
|
+
if (tag === 'IMG' || (tag === 'SVG') ||
|
|
6556
|
+
(el.querySelector && el.querySelector('img,svg') &&
|
|
6557
|
+
el.children.length <= 2 && !text)) return 'img';
|
|
6558
|
+
|
|
6559
|
+
// \u4F18\u5148\u7EA74.5\uFF1A\u8868\u683C\u5355\u5143\u683C
|
|
6560
|
+
if (tag === 'TD' || tag === 'TH') return 'list';
|
|
6561
|
+
|
|
6562
|
+
// \u4F18\u5148\u7EA75\uFF1A\u5217\u8868\uFF08v3\uFF1A\u52A0 card\uFF09
|
|
6563
|
+
if (tag === 'UL' || tag === 'OL' || tag === 'LI' ||
|
|
6564
|
+
/list|item|feed|timeline|card/i.test(cls)) return 'list';
|
|
6565
|
+
|
|
6566
|
+
// \u4F18\u5148\u7EA76\uFF1A\u6587\u672C
|
|
6567
|
+
if (text.length > 20) return 'text';
|
|
6568
|
+
return null;
|
|
6569
|
+
}
|
|
6570
|
+
|
|
6571
|
+
var COLORS = {
|
|
6572
|
+
click: { stroke: '#FF0000', fill: '#FFD700' }, // \u7EA2+\u9EC4
|
|
6573
|
+
input: { stroke: '#0000FF', fill: '#ADD8E6' }, // \u84DD
|
|
6574
|
+
img: { stroke: '#00AA00', fill: '#90EE90' }, // \u7EFF
|
|
6575
|
+
list: { stroke: '#FFAA00', fill: '#FFE4B5' }, // \u6A59\u9EC4
|
|
6576
|
+
count: { stroke: '#9900CC', fill: '#E0B0FF' }, // \u7D2B
|
|
6577
|
+
text: { stroke: '#FF8C00', fill: '#FFECD2' }, // \u6A59
|
|
6578
|
+
};
|
|
6579
|
+
|
|
6580
|
+
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"]');
|
|
6581
|
+
|
|
6582
|
+
for (var i = 0; i < all.length && i < 3000; i++) {
|
|
6583
|
+
var el = all[i];
|
|
6584
|
+
var r = el.getBoundingClientRect();
|
|
6585
|
+
if (r.width < 8 || r.height < 8) continue;
|
|
6586
|
+
if (r.x < -50 || r.y < -50 || r.x > window.innerWidth || r.y > window.innerHeight + 200) continue;
|
|
6587
|
+
var style = getComputedStyle(el);
|
|
6588
|
+
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') continue;
|
|
6589
|
+
|
|
6590
|
+
var type = classifyElement(el);
|
|
6591
|
+
if (!type) continue;
|
|
6592
|
+
|
|
6593
|
+
var id = genId(TYPE_PREFIX[type] || 't', counters[type]);
|
|
6594
|
+
counters[type]++;
|
|
6595
|
+
var colors = COLORS[type];
|
|
6596
|
+
|
|
6597
|
+
// \u6807\u7B7E
|
|
6598
|
+
ctx.fillStyle = colors.fill;
|
|
6599
|
+
ctx.fillRect(r.x - 2, r.y - 14, id.length * 7 + 6, 14);
|
|
6600
|
+
ctx.strokeStyle = '#000';
|
|
6601
|
+
ctx.lineWidth = 1;
|
|
6602
|
+
ctx.strokeRect(r.x - 2, r.y - 14, id.length * 7 + 6, 14);
|
|
6603
|
+
ctx.fillStyle = '#000';
|
|
6604
|
+
ctx.font = 'bold 11px monospace';
|
|
6605
|
+
ctx.fillText(id, r.x + 1, r.y - 4);
|
|
6606
|
+
|
|
6607
|
+
// \u5143\u7D20\u6846\uFF08\u5206\u8272\uFF09
|
|
6608
|
+
ctx.strokeStyle = colors.stroke;
|
|
6609
|
+
ctx.lineWidth = 1.5;
|
|
6610
|
+
ctx.strokeRect(r.x, r.y, r.width, r.height);
|
|
6611
|
+
|
|
6612
|
+
// v4\uFF1A\u67E5\u7236\u7EA7\u6807\u6CE8 ID\uFF08\u5D4C\u5957\u5173\u7CFB\uFF09
|
|
6613
|
+
var parentId = null;
|
|
6614
|
+
var parentNode = el.parentElement;
|
|
6615
|
+
while (parentNode && parentNode !== document.body) {
|
|
6616
|
+
for (var pk in window.__xbTagMap) {
|
|
6617
|
+
if (window.__xbTagMap[pk]._el === parentNode) { parentId = pk; break; }
|
|
6618
|
+
}
|
|
6619
|
+
if (parentId) break;
|
|
6620
|
+
parentNode = parentNode.parentElement;
|
|
6621
|
+
}
|
|
6622
|
+
|
|
6623
|
+
// v6\uFF1A\u8868\u5355\u8BED\u4E49\u2014\u2014\u8BC6\u522B input \u7684\u5173\u8054 label
|
|
6624
|
+
var formLabel = null;
|
|
6625
|
+
if (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT') {
|
|
6626
|
+
var inputId = el.id;
|
|
6627
|
+
if (inputId) {
|
|
6628
|
+
var lbl = document.querySelector('label[for="' + inputId + '"]');
|
|
6629
|
+
if (lbl) formLabel = lbl.textContent.trim();
|
|
6630
|
+
}
|
|
6631
|
+
if (!formLabel) {
|
|
6632
|
+
var aria = el.getAttribute('aria-label');
|
|
6633
|
+
if (aria) formLabel = aria;
|
|
6634
|
+
}
|
|
6635
|
+
if (!formLabel) {
|
|
6636
|
+
var ph = el.getAttribute('placeholder');
|
|
6637
|
+
if (ph) formLabel = '(placeholder) ' + ph;
|
|
6638
|
+
}
|
|
6639
|
+
if (!formLabel) {
|
|
6640
|
+
var parentLbl = el.closest('label');
|
|
6641
|
+
if (parentLbl) formLabel = parentLbl.textContent.trim().slice(0, 30);
|
|
6642
|
+
}
|
|
6643
|
+
if (!formLabel) {
|
|
6644
|
+
var prev = el.previousElementSibling;
|
|
6645
|
+
if (prev && (prev.tagName === 'LABEL' || prev.tagName === 'SPAN' || prev.tagName === 'DIV') && prev.textContent.trim()) {
|
|
6646
|
+
formLabel = '(adjacent) ' + prev.textContent.trim().slice(0, 30);
|
|
6647
|
+
}
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
|
|
6651
|
+
// v7\uFF1A\u8868\u683C\u8BED\u4E49\u2014\u2014\u5355\u5143\u683C \u2192 \u5217\u540D + \u884C\u53F7
|
|
6652
|
+
var tableInfo = null;
|
|
6653
|
+
if (el.tagName === 'TD' || el.tagName === 'TH') {
|
|
6654
|
+
var table = el.closest('table');
|
|
6655
|
+
if (table) {
|
|
6656
|
+
var row = el.closest('tr');
|
|
6657
|
+
var cellIndex = el.cellIndex;
|
|
6658
|
+
var rowIndex = row ? row.rowIndex : -1;
|
|
6659
|
+
// \u627E\u8868\u5934\uFF08thead \u7684 th \u6216\u7B2C\u4E00\u884C\u7684 th\uFF09
|
|
6660
|
+
var header = table.querySelector('thead th:nth-child(' + (cellIndex + 1) + ')') ||
|
|
6661
|
+
table.querySelector('tr:first-child th:nth-child(' + (cellIndex + 1) + ')');
|
|
6662
|
+
var colName = header ? header.textContent.trim() : 'col-' + (cellIndex + 1);
|
|
6663
|
+
tableInfo = { col: colName, colIndex: cellIndex, rowIndex: rowIndex, value: el.textContent.trim().slice(0, 20) };
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
|
|
6667
|
+
window.__xbTagMap[id] = {
|
|
6668
|
+
type: type,
|
|
6669
|
+
parent: parentId,
|
|
6670
|
+
_el: el,
|
|
6671
|
+
formLabel: formLabel,
|
|
6672
|
+
table: tableInfo,
|
|
6673
|
+
tagName: el.tagName,
|
|
6674
|
+
text: (el.textContent || '').trim().slice(0, 40),
|
|
6675
|
+
num: (el.textContent || '').trim().match(/[\\d,.]+/)?.[0] || null,
|
|
6676
|
+
rect: { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) },
|
|
6677
|
+
selector: (function(e) {
|
|
6678
|
+
if (e.id) return '#' + e.id;
|
|
6679
|
+
if (e.getAttribute('data-testid')) return '[data-testid="' + e.getAttribute('data-testid') + '"]';
|
|
6680
|
+
var path = [];
|
|
6681
|
+
var node = e;
|
|
6682
|
+
while (node && node !== document.body) {
|
|
6683
|
+
var idx = 1;
|
|
6684
|
+
var sib = node.previousElementSibling;
|
|
6685
|
+
while (sib) { if (sib.tagName === node.tagName) idx++; sib = sib.previousElementSibling; }
|
|
6686
|
+
path.unshift(node.tagName.toLowerCase() + ':nth-of-type(' + idx + ')');
|
|
6687
|
+
node = node.parentElement;
|
|
6688
|
+
}
|
|
6689
|
+
return path.join(' > ');
|
|
6690
|
+
})(el)
|
|
6691
|
+
};
|
|
6692
|
+
}
|
|
6693
|
+
|
|
6694
|
+
// v9\uFF1A\u8DE8 frame \u6807\u6CE8\u2014\u2014\u9012\u5F52\u5904\u7406\u540C\u6E90 iframe \u5185\u7684\u5143\u7D20
|
|
6695
|
+
function tagFrame(doc, offsetX, offsetY) {
|
|
6696
|
+
var frameAll = doc.querySelectorAll('button, a[href], input, select, textarea, img, [onclick], [role=button], [contenteditable], [aria-label]');
|
|
6697
|
+
for (var fi = 0; fi < frameAll.length && fi < 100; fi++) {
|
|
6698
|
+
var fel = frameAll[fi];
|
|
6699
|
+
var fr = fel.getBoundingClientRect();
|
|
6700
|
+
if (fr.width < 8 || fr.height < 8) continue;
|
|
6701
|
+
var fType = classifyElement(fel);
|
|
6702
|
+
if (!fType) continue;
|
|
6703
|
+
var fId = genId(TYPE_PREFIX[fType] || 't', counters[fType]);
|
|
6704
|
+
counters[fType]++;
|
|
6705
|
+
var fColors = COLORS[fType];
|
|
6706
|
+
// \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
|
|
6707
|
+
var fx = fr.x + offsetX, fy = fr.y + offsetY;
|
|
6708
|
+
ctx.fillStyle = fColors.fill;
|
|
6709
|
+
ctx.fillRect(fx - 2, fy - 14, fId.length * 7 + 6, 14);
|
|
6710
|
+
ctx.strokeStyle = '#000'; ctx.lineWidth = 1;
|
|
6711
|
+
ctx.strokeRect(fx - 2, fy - 14, fId.length * 7 + 6, 14);
|
|
6712
|
+
ctx.fillStyle = '#000'; ctx.font = 'bold 11px monospace';
|
|
6713
|
+
ctx.fillText(fId, fx + 1, fy - 4);
|
|
6714
|
+
ctx.strokeStyle = fColors.stroke; ctx.lineWidth = 1.5;
|
|
6715
|
+
ctx.strokeRect(fx, fy, fr.width, fr.height);
|
|
6716
|
+
window.__xbTagMap[fId] = {
|
|
6717
|
+
type: fType, tagName: fel.tagName,
|
|
6718
|
+
text: (fel.textContent||'').trim().slice(0,40),
|
|
6719
|
+
num: (fel.textContent||'').trim().match(/[0-9,.]+/)?.[0] || null,
|
|
6720
|
+
formLabel: (fel.getAttribute('aria-label')||fel.getAttribute('placeholder')||'').slice(0,30) || null,
|
|
6721
|
+
frame: 'iframe',
|
|
6722
|
+
_el: fel,
|
|
6723
|
+
rect: {x:Math.round(fx),y:Math.round(fy),w:Math.round(fr.width),h:Math.round(fr.height)},
|
|
6724
|
+
selector: (function(e){return e.id?'#'+e.id:e.tagName.toLowerCase()}) (fel)
|
|
6725
|
+
};
|
|
6726
|
+
}
|
|
6727
|
+
// \u9012\u5F52\u5904\u7406\u5D4C\u5957 iframe
|
|
6728
|
+
var nestedFrames = doc.querySelectorAll('iframe');
|
|
6729
|
+
for (var nf = 0; nf < nestedFrames.length; nf++) {
|
|
6730
|
+
try {
|
|
6731
|
+
var nestedDoc = nestedFrames[nf].contentDocument;
|
|
6732
|
+
if (!nestedDoc) continue;
|
|
6733
|
+
var nestedRect = nestedFrames[nf].getBoundingClientRect();
|
|
6734
|
+
tagFrame(nestedDoc, nestedRect.x, nestedRect.y);
|
|
6735
|
+
} catch(e) { /* \u8DE8\u57DF iframe \u8DF3\u8FC7 */ }
|
|
6736
|
+
}
|
|
6737
|
+
}
|
|
6738
|
+
// \u904D\u5386\u4E3B\u6587\u6863\u7684\u6240\u6709\u540C\u6E90 iframe
|
|
6739
|
+
var mainFrames = document.querySelectorAll('iframe');
|
|
6740
|
+
for (var mf = 0; mf < mainFrames.length; mf++) {
|
|
6741
|
+
try {
|
|
6742
|
+
var mDoc = mainFrames[mf].contentDocument;
|
|
6743
|
+
if (!mDoc) continue;
|
|
6744
|
+
var mRect = mainFrames[mf].getBoundingClientRect();
|
|
6745
|
+
tagFrame(mDoc, mRect.x, mRect.y);
|
|
6746
|
+
} catch(e) { /* \u8DE8\u57DF\u8DF3\u8FC7 */ }
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
// v8\uFF1A\u52A8\u6001\u6807\u6CE8\u2014\u2014MutationObserver \u76D1\u542C\u65B0\u5143\u7D20\uFF0C\u81EA\u52A8\u8865\u5145\u6807\u6CE8
|
|
6750
|
+
if (window.__xbTagObserver) { window.__xbTagObserver.disconnect(); }
|
|
6751
|
+
window.__xbTagObserver = new MutationObserver(function(mutations) {
|
|
6752
|
+
var needsRetag = false;
|
|
6753
|
+
for (var mi = 0; mi < mutations.length; mi++) {
|
|
6754
|
+
if (mutations[mi].addedNodes.length > 0) { needsRetag = true; break; }
|
|
6755
|
+
}
|
|
6756
|
+
if (!needsRetag) return;
|
|
6757
|
+
// v8.1\uFF1A\u6E05\u7406\u88AB\u79FB\u9664\u5143\u7D20\u7684\u6807\u6CE8\uFF08\u6B7B\u6807\u6CE8\u4F1A\u7559\u5728 Canvas \u4E0A\uFF09
|
|
6758
|
+
for (var ri = 0; ri < mutations.length; ri++) {
|
|
6759
|
+
var removed = mutations[ri].removedNodes;
|
|
6760
|
+
for (var rj = 0; rj < removed.length; rj++) {
|
|
6761
|
+
var removedNode = removed[rj];
|
|
6762
|
+
if (!removedNode.tagName) continue;
|
|
6763
|
+
for (var rk in window.__xbTagMap) {
|
|
6764
|
+
var entry = window.__xbTagMap[rk];
|
|
6765
|
+
if (entry._el === removedNode || (entry._el && removedNode.contains && removedNode.contains(entry._el))) {
|
|
6766
|
+
delete window.__xbTagMap[rk];
|
|
6767
|
+
window.__xbTagStats.total--;
|
|
6768
|
+
}
|
|
6769
|
+
}
|
|
6770
|
+
}
|
|
6771
|
+
}
|
|
6772
|
+
// \u9632\u6296\uFF1A300ms \u5185\u7684\u8FDE\u7EED\u53D8\u5316\u53EA\u89E6\u53D1\u4E00\u6B21\u91CD\u6807\u6CE8
|
|
6773
|
+
clearTimeout(window.__xbTagRetagTimer);
|
|
6774
|
+
window.__xbTagRetagTimer = setTimeout(function() {
|
|
6775
|
+
// \u53EA\u6807\u6CE8\u65B0\u589E\u7684\u53EF\u89C1\u5143\u7D20\uFF08\u4E0D\u91CD\u753B\u6574\u4E2A Canvas\uFF09
|
|
6776
|
+
var ctx2 = document.getElementById('__xb-tag-overlay');
|
|
6777
|
+
if (!ctx2) return;
|
|
6778
|
+
var canvas2 = ctx2.getContext('2d');
|
|
6779
|
+
for (var ni = 0; ni < mutations.length; ni++) {
|
|
6780
|
+
var nodes = mutations[ni].addedNodes;
|
|
6781
|
+
for (var nj = 0; nj < nodes.length; nj++) {
|
|
6782
|
+
var node = nodes[nj];
|
|
6783
|
+
if (!node.getBoundingClientRect) continue;
|
|
6784
|
+
var r = node.getBoundingClientRect();
|
|
6785
|
+
if (r.width < 8 || r.height < 8) continue;
|
|
6786
|
+
// \u5206\u7C7B\u5E76\u6807\u6CE8
|
|
6787
|
+
var newType = classifyElement(node);
|
|
6788
|
+
if (!newType) continue;
|
|
6789
|
+
var newId = genId(TYPE_PREFIX[newType] || 't', counters[newType]);
|
|
6790
|
+
counters[newType]++;
|
|
6791
|
+
var colors = COLORS[newType];
|
|
6792
|
+
canvas2.fillStyle = colors.fill;
|
|
6793
|
+
canvas2.fillRect(r.x - 2, r.y - 14, newId.length * 7 + 6, 14);
|
|
6794
|
+
canvas2.strokeStyle = '#000';
|
|
6795
|
+
canvas2.lineWidth = 1;
|
|
6796
|
+
canvas2.strokeRect(r.x - 2, r.y - 14, newId.length * 7 + 6, 14);
|
|
6797
|
+
canvas2.fillStyle = '#000';
|
|
6798
|
+
canvas2.font = 'bold 11px monospace';
|
|
6799
|
+
canvas2.fillText(newId, r.x + 1, r.y - 4);
|
|
6800
|
+
canvas2.strokeStyle = colors.stroke;
|
|
6801
|
+
canvas2.lineWidth = 1.5;
|
|
6802
|
+
canvas2.strokeRect(r.x, r.y, r.width, r.height);
|
|
6803
|
+
// \u5B58\u6620\u5C04
|
|
6804
|
+
var parentId = null;
|
|
6805
|
+
var parentNode = node.parentElement;
|
|
6806
|
+
while (parentNode && parentNode !== document.body) {
|
|
6807
|
+
for (var pk in window.__xbTagMap) {
|
|
6808
|
+
if (window.__xbTagMap[pk]._el === parentNode) { parentId = pk; break; }
|
|
6809
|
+
}
|
|
6810
|
+
if (parentId) break;
|
|
6811
|
+
parentNode = parentNode.parentElement;
|
|
6812
|
+
}
|
|
6813
|
+
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)} };
|
|
6814
|
+
window.__xbTagStats.total++;
|
|
6815
|
+
}
|
|
6816
|
+
}
|
|
6817
|
+
// \u66F4\u65B0 serializable
|
|
6818
|
+
var ser = {};
|
|
6819
|
+
for (var sk2 in window.__xbTagMap) {
|
|
6820
|
+
var item = {};
|
|
6821
|
+
for (var key in window.__xbTagMap[sk2]) { if (key !== '_el') item[key] = window.__xbTagMap[sk2][key]; }
|
|
6822
|
+
ser[sk2] = item;
|
|
6823
|
+
}
|
|
6824
|
+
window.__xbTagSerializable = ser;
|
|
6825
|
+
}, 300);
|
|
6826
|
+
});
|
|
6827
|
+
window.__xbTagObserver.observe(document.body, { childList: true, subtree: true });
|
|
6828
|
+
|
|
6829
|
+
// v4\uFF1A\u751F\u6210\u53EF\u5E8F\u5217\u5316\u7248\u672C\uFF08\u53BB\u6389 _el DOM \u5F15\u7528\uFF09
|
|
6830
|
+
var serializable = {};
|
|
6831
|
+
for (var sk in window.__xbTagMap) {
|
|
6832
|
+
var item = {};
|
|
6833
|
+
for (var key in window.__xbTagMap[sk]) {
|
|
6834
|
+
if (key !== '_el') item[key] = window.__xbTagMap[sk][key];
|
|
6835
|
+
}
|
|
6836
|
+
serializable[sk] = item;
|
|
6837
|
+
}
|
|
6838
|
+
window.__xbTagSerializable = serializable;
|
|
6839
|
+
window.__xbTagStats = { total: Object.keys(window.__xbTagMap).length, byType: counters };
|
|
6840
|
+
return JSON.stringify(window.__xbTagStats);
|
|
6841
|
+
})()
|
|
6842
|
+
`;
|
|
6843
|
+
var visualTagV2Command = registerCommand({
|
|
6844
|
+
name: "visual-tag-v2",
|
|
6845
|
+
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",
|
|
6846
|
+
scope: "page",
|
|
6847
|
+
parameters: z30.object({
|
|
6848
|
+
action: z30.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
6849
|
+
id: z30.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
6850
|
+
query: z30.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
6851
|
+
type: z30.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
6852
|
+
"interact-action": z30.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
6853
|
+
value: z30.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6854
|
+
}),
|
|
6855
|
+
result: z30.object({
|
|
6856
|
+
action: z30.string(),
|
|
6857
|
+
total: z30.number().optional(),
|
|
6858
|
+
byType: z30.record(z30.number()).optional(),
|
|
6859
|
+
element: z30.record(z30.unknown()).optional()
|
|
6860
|
+
}),
|
|
6861
|
+
handler: async (p, ctx) => {
|
|
6862
|
+
switch (p.action) {
|
|
6863
|
+
case "tag": {
|
|
6864
|
+
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6865
|
+
const parsed = JSON.parse(result);
|
|
6866
|
+
return ok29({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6867
|
+
}
|
|
6868
|
+
case "lookup": {
|
|
6869
|
+
if (!p.id) return fail14("lookup \u9700\u8981 --id");
|
|
6870
|
+
const result = await ctx.page.evaluate(
|
|
6871
|
+
`(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'})})()`
|
|
6872
|
+
);
|
|
6873
|
+
const parsed = JSON.parse(result);
|
|
6874
|
+
if (parsed.err) return fail14(`ID ${p.id}: ${parsed.err}`);
|
|
6875
|
+
return ok29({ action: "lookup", id: p.id, element: parsed });
|
|
6876
|
+
}
|
|
6877
|
+
case "by-type": {
|
|
6878
|
+
const result = await ctx.page.evaluate(
|
|
6879
|
+
`(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)})()`
|
|
6880
|
+
);
|
|
6881
|
+
return ok29({ action: "by-type", element: JSON.parse(result) });
|
|
6882
|
+
}
|
|
6883
|
+
case "find": {
|
|
6884
|
+
const query = p.query;
|
|
6885
|
+
if (!query) return fail14('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6886
|
+
const result = await ctx.page.evaluate(
|
|
6887
|
+
`(function(){
|
|
6888
|
+
var map = window.__xbTagSerializable;
|
|
6889
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
6890
|
+
var query = ${JSON.stringify(query)};
|
|
6891
|
+
var results = [];
|
|
6892
|
+
// 1) \u76F4\u63A5\u6587\u672C\u5339\u914D
|
|
6893
|
+
for (var id in map) {
|
|
6894
|
+
var e = map[id];
|
|
6895
|
+
var text = (e.text || '').toLowerCase();
|
|
6896
|
+
var q = query.toLowerCase();
|
|
6897
|
+
if (text.includes(q)) {
|
|
6898
|
+
results.push({id:id, type:e.type, text:e.text, num:e.num, parent:e.parent, reason:'text-match'});
|
|
6899
|
+
}
|
|
6900
|
+
}
|
|
6901
|
+
// 2) \u7C7B\u578B\u5339\u914D\uFF08query \u542B"\u6309\u94AE"/"\u94FE\u63A5"/"\u56FE\u7247"/"\u6570\u5B57"\u7B49\uFF09
|
|
6902
|
+
var typeMap = {button:'click', link:'click', \u6309\u94AE:'click', \u94FE\u63A5:'click', \u56FE\u7247:'img', image:'img',
|
|
6903
|
+
\u8F93\u5165:'input', input:'input', \u5217\u8868:'list', list:'list', \u5361\u7247:'list', card:'list',
|
|
6904
|
+
\u6570\u5B57:'count', count:'count', \u8BA1\u6570:'count', \u6587\u672C:'text'};
|
|
6905
|
+
for (var tk in typeMap) {
|
|
6906
|
+
if (query.toLowerCase().includes(tk)) {
|
|
6907
|
+
for (var id2 in map) {
|
|
6908
|
+
if (map[id2].type === typeMap[tk]) {
|
|
6909
|
+
results.push({id:id2, type:map[id2].type, text:map[id2].text, num:map[id2].num, parent:map[id2].parent, reason:'type-match:'+tk});
|
|
6910
|
+
}
|
|
6911
|
+
}
|
|
6912
|
+
}
|
|
6913
|
+
}
|
|
6914
|
+
// 3) \u6570\u5B57\u5339\u914D\uFF08query \u542B\u6570\u5B57\uFF09
|
|
6915
|
+
var numMatch = query.match(/([0-9,.]+)/);
|
|
6916
|
+
if (numMatch && map) {
|
|
6917
|
+
var target = parseFloat(numMatch[1].replace(/,/g,''));
|
|
6918
|
+
for (var id3 in map) {
|
|
6919
|
+
if (map[id3].num && parseFloat(map[id3].num.replace(/,/g,'')) === target) {
|
|
6920
|
+
results.push({id:id3, type:map[id3].type, text:map[id3].text, num:map[id3].num, parent:map[id3].parent, reason:'num-match'});
|
|
6921
|
+
}
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6925
|
+
})()`
|
|
6926
|
+
);
|
|
6927
|
+
return ok29({ action: "find", query, element: JSON.parse(result) });
|
|
6928
|
+
}
|
|
6929
|
+
case "stats": {
|
|
6930
|
+
const result = await ctx.page.evaluate(
|
|
6931
|
+
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6932
|
+
);
|
|
6933
|
+
return ok29({ action: "stats", element: JSON.parse(result) });
|
|
6934
|
+
}
|
|
6935
|
+
case "interact": {
|
|
6936
|
+
const query = p.query;
|
|
6937
|
+
const pAny = p;
|
|
6938
|
+
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6939
|
+
const value = pAny.value;
|
|
6940
|
+
if (!query) return fail14("interact \u9700\u8981 --query \u53C2\u6570");
|
|
6941
|
+
if (!action) return fail14("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6942
|
+
const findResult = await ctx.page.evaluate(
|
|
6943
|
+
`(function(){
|
|
6944
|
+
var map = window.__xbTagSerializable;
|
|
6945
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
6946
|
+
var query = ${JSON.stringify(query)};
|
|
6947
|
+
var results = [];
|
|
6948
|
+
for (var id in map) {
|
|
6949
|
+
var e = map[id];
|
|
6950
|
+
var text = (e.text || '').toLowerCase();
|
|
6951
|
+
if (text.includes(query.toLowerCase())) {
|
|
6952
|
+
results.push({id:id, type:e.type, text:e.text, num:e.num, label:e.formLabel});
|
|
6953
|
+
}
|
|
6954
|
+
}
|
|
6955
|
+
// \u7C7B\u578B\u5339\u914D
|
|
6956
|
+
var typeMap = {button:'click', link:'click', \u6309\u94AE:'click', \u56FE\u7247:'img', image:'img',
|
|
6957
|
+
\u8F93\u5165:'input', input:'input', \u5217\u8868:'list', \u6570\u5B57:'count', count:'count'};
|
|
6958
|
+
for (var tk in typeMap) {
|
|
6959
|
+
if (query.toLowerCase().includes(tk)) {
|
|
6960
|
+
for (var id2 in map) {
|
|
6961
|
+
if (map[id2].type === typeMap[tk]) {
|
|
6962
|
+
results.push({id:id2, type:map[id2].type, text:map[id2].text, num:map[id2].num, label:map[id2].formLabel});
|
|
6963
|
+
}
|
|
6964
|
+
}
|
|
6965
|
+
}
|
|
6966
|
+
}
|
|
6967
|
+
return JSON.stringify({total:results.length, results:results.slice(0,10)});
|
|
6968
|
+
})()`
|
|
6969
|
+
);
|
|
6970
|
+
const parsed = JSON.parse(findResult);
|
|
6971
|
+
if (parsed.err) return fail14(parsed.err);
|
|
6972
|
+
if (!parsed.total || !parsed.results?.length) return fail14(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
6973
|
+
const target = parsed.results[0];
|
|
6974
|
+
if (action === "read") {
|
|
6975
|
+
return ok29({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
6976
|
+
}
|
|
6977
|
+
if (action === "click") {
|
|
6978
|
+
const el = await ctx.page.evaluate(
|
|
6979
|
+
`(function(){
|
|
6980
|
+
var map = window.__xbTagMap;
|
|
6981
|
+
if (!map) return null;
|
|
6982
|
+
var entry = map[${JSON.stringify(target.id)}];
|
|
6983
|
+
if (!entry || !entry._el) return null;
|
|
6984
|
+
var r = entry._el.getBoundingClientRect();
|
|
6985
|
+
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
6986
|
+
})()`
|
|
6987
|
+
);
|
|
6988
|
+
if (!el) return fail14(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
6989
|
+
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
6990
|
+
return ok29({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
6991
|
+
}
|
|
6992
|
+
if (action === "fill") {
|
|
6993
|
+
if (!value) return fail14("fill \u9700\u8981 --value \u53C2\u6570");
|
|
6994
|
+
const el = await ctx.page.evaluate(
|
|
6995
|
+
`(function(){
|
|
6996
|
+
var map = window.__xbTagMap;
|
|
6997
|
+
if (!map) return null;
|
|
6998
|
+
var entry = map[${JSON.stringify(target.id)}];
|
|
6999
|
+
if (!entry || !entry._el) return null;
|
|
7000
|
+
var r = entry._el.getBoundingClientRect();
|
|
7001
|
+
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7002
|
+
})()`
|
|
7003
|
+
);
|
|
7004
|
+
if (!el) return fail14(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7005
|
+
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7006
|
+
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7007
|
+
return ok29({ action: "interact", query, target, result: { filled: true, value } });
|
|
7008
|
+
}
|
|
7009
|
+
return fail14(`\u672A\u77E5 action: ${action}`);
|
|
7010
|
+
}
|
|
7011
|
+
case "export": {
|
|
7012
|
+
const result = await ctx.page.evaluate(
|
|
7013
|
+
`(function(){
|
|
7014
|
+
var map = window.__xbTagSerializable;
|
|
7015
|
+
if (!map) return JSON.stringify({err:'no-map'});
|
|
7016
|
+
// \u6309 type \u5206\u7EC4\u7EDF\u8BA1
|
|
7017
|
+
var byType = {};
|
|
7018
|
+
for (var id in map) {
|
|
7019
|
+
var t = map[id].type || 'unknown';
|
|
7020
|
+
byType[t] = (byType[t] || 0) + 1;
|
|
7021
|
+
}
|
|
7022
|
+
// \u6784\u5EFA\u5C42\u7EA7\u6811\uFF08parent \u2192 children\uFF09
|
|
7023
|
+
var tree = {};
|
|
7024
|
+
var roots = [];
|
|
7025
|
+
for (var id2 in map) {
|
|
7026
|
+
var parent = map[id2].parent;
|
|
7027
|
+
if (parent && map[parent]) {
|
|
7028
|
+
if (!tree[parent]) tree[parent] = [];
|
|
7029
|
+
tree[parent].push(id2);
|
|
7030
|
+
} else {
|
|
7031
|
+
roots.push(id2);
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
7034
|
+
// elements \u5BFC\u51FA\u6458\u8981\uFF08\u5B8C\u6574 DOM \u6620\u5C04\u592A\u5927\uFF0C\u53EA\u5BFC\u6838\u5FC3\u5B57\u6BB5\uFF09
|
|
7035
|
+
var elementsOut = {};
|
|
7036
|
+
for (var id3 in map) {
|
|
7037
|
+
elementsOut[id3] = {
|
|
7038
|
+
type: map[id3].type,
|
|
7039
|
+
text: (map[id3].text || '').slice(0, 20),
|
|
7040
|
+
num: map[id3].num,
|
|
7041
|
+
label: map[id3].formLabel,
|
|
7042
|
+
frame: map[id3].frame,
|
|
7043
|
+
parent: map[id3].parent,
|
|
7044
|
+
table: map[id3].table ? {col: map[id3].table.col, row: map[id3].table.rowIndex} : null
|
|
7045
|
+
};
|
|
7046
|
+
}
|
|
7047
|
+
return JSON.stringify({
|
|
7048
|
+
total: Object.keys(map).length,
|
|
7049
|
+
byType: byType,
|
|
7050
|
+
rootIds: roots.slice(0, 20),
|
|
7051
|
+
hierarchy: Object.keys(tree).slice(0, 50).reduce(function(acc, k) { acc[k] = tree[k]; return acc; }, {}),
|
|
7052
|
+
elements: elementsOut
|
|
7053
|
+
});
|
|
7054
|
+
})()`
|
|
7055
|
+
);
|
|
7056
|
+
const parsed = JSON.parse(result);
|
|
7057
|
+
if (parsed.err) return fail14(String(parsed.err));
|
|
7058
|
+
return ok29({ action: "export", element: parsed });
|
|
7059
|
+
}
|
|
7060
|
+
case "clear": {
|
|
7061
|
+
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7062
|
+
return ok29({ action: "clear" });
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
7065
|
+
}
|
|
7066
|
+
});
|
|
7067
|
+
|
|
6365
7068
|
// src/context.ts
|
|
6366
7069
|
function attachDetectAntiBot(ctx) {
|
|
6367
7070
|
ctx.detectAntiBot = async (page, config) => {
|
|
@@ -7468,7 +8171,7 @@ async function guardCheck(commandName) {
|
|
|
7468
8171
|
}
|
|
7469
8172
|
}
|
|
7470
8173
|
function errorResult(message) {
|
|
7471
|
-
return { ...
|
|
8174
|
+
return { ...fail15(message), duration: 0 };
|
|
7472
8175
|
}
|
|
7473
8176
|
function tipsToMessages(tips) {
|
|
7474
8177
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7545,7 +8248,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7545
8248
|
}
|
|
7546
8249
|
let targetPageOverride = null;
|
|
7547
8250
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7548
|
-
const { findTargetPage } = await import("./browser-
|
|
8251
|
+
const { findTargetPage } = await import("./browser-Y6B3NS4Q.js");
|
|
7549
8252
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7550
8253
|
if (!targetPageOverride) {
|
|
7551
8254
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7741,7 +8444,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7741
8444
|
timestamp: start
|
|
7742
8445
|
});
|
|
7743
8446
|
if (isSuccess) {
|
|
7744
|
-
return { ...
|
|
8447
|
+
return { ...ok30(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7745
8448
|
}
|
|
7746
8449
|
return { success: false, data: raw.data, message: raw.message, tips: mergedOrRaw, duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7747
8450
|
}
|
|
@@ -7755,7 +8458,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7755
8458
|
duration,
|
|
7756
8459
|
timestamp: start
|
|
7757
8460
|
});
|
|
7758
|
-
return { ...
|
|
8461
|
+
return { ...ok30(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
7759
8462
|
} catch (err) {
|
|
7760
8463
|
const end = Date.now();
|
|
7761
8464
|
const duration = end - start;
|
|
@@ -7800,7 +8503,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7800
8503
|
duration,
|
|
7801
8504
|
timestamp: start
|
|
7802
8505
|
});
|
|
7803
|
-
return { ...
|
|
8506
|
+
return { ...fail15(errorMessage), duration };
|
|
7804
8507
|
} finally {
|
|
7805
8508
|
}
|
|
7806
8509
|
}
|
|
@@ -7844,7 +8547,7 @@ async function executeChain(input, options) {
|
|
|
7844
8547
|
results.push({
|
|
7845
8548
|
command: cmdName,
|
|
7846
8549
|
raw: cmdStr,
|
|
7847
|
-
...
|
|
8550
|
+
...fail15(`Plugin "${cmdName}" requires a sub-command`),
|
|
7848
8551
|
duration: 0
|
|
7849
8552
|
});
|
|
7850
8553
|
if (type === "and") {
|
|
@@ -7863,7 +8566,7 @@ async function executeChain(input, options) {
|
|
|
7863
8566
|
results.push({
|
|
7864
8567
|
command: cmdName,
|
|
7865
8568
|
raw: cmdStr,
|
|
7866
|
-
...
|
|
8569
|
+
...fail15(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
7867
8570
|
duration: 0
|
|
7868
8571
|
});
|
|
7869
8572
|
if (type === "and") {
|
|
@@ -7967,7 +8670,7 @@ async function executeChain(input, options) {
|
|
|
7967
8670
|
results.push({
|
|
7968
8671
|
command: `${cmdName} ${subCommand}`,
|
|
7969
8672
|
raw: cmdStr,
|
|
7970
|
-
...
|
|
8673
|
+
...ok30(data),
|
|
7971
8674
|
duration: duration2,
|
|
7972
8675
|
...hookOutputs ? { hookOutputs } : {}
|
|
7973
8676
|
});
|
|
@@ -7995,7 +8698,7 @@ async function executeChain(input, options) {
|
|
|
7995
8698
|
results.push({
|
|
7996
8699
|
command: `${cmdName} ${subCommand}`,
|
|
7997
8700
|
raw: cmdStr,
|
|
7998
|
-
...
|
|
8701
|
+
...fail15(errorMessage),
|
|
7999
8702
|
duration: duration2
|
|
8000
8703
|
});
|
|
8001
8704
|
if (type === "and") {
|
|
@@ -10189,6 +10892,7 @@ var HTML_TAGS = /* @__PURE__ */ new Set([
|
|
|
10189
10892
|
var SELECTOR_DSL_PREFIXES = /^(text=|popup-text=|xpath=|role=|css=|chain=)/;
|
|
10190
10893
|
function normalizeSelector(input) {
|
|
10191
10894
|
if (!input) return input;
|
|
10895
|
+
if (typeof input !== "string") input = String(input);
|
|
10192
10896
|
if (/^[#\.\[\:\/]/.test(input)) return input;
|
|
10193
10897
|
if (input === "*") return input;
|
|
10194
10898
|
if (SELECTOR_DSL_PREFIXES.test(input)) return input;
|
|
@@ -13224,6 +13928,12 @@ function findEvalStart(argv) {
|
|
|
13224
13928
|
async function handleEvalScript(parts, argv) {
|
|
13225
13929
|
const cdpEndpoint = extractCdpFromArgv(argv);
|
|
13226
13930
|
const sessionName = extractSessionNameFromArgv(argv);
|
|
13931
|
+
if (parts[0] === "--script-b64" && parts[1]) {
|
|
13932
|
+
const chainResult2 = await executeChain(`eval --script-b64 ${parts[1]}`, { cdpEndpoint, sessionName });
|
|
13933
|
+
printChainResult(chainResult2);
|
|
13934
|
+
if (!chainResult2.success) throw new Error("Command failed");
|
|
13935
|
+
return;
|
|
13936
|
+
}
|
|
13227
13937
|
let frame;
|
|
13228
13938
|
const scriptLines = [];
|
|
13229
13939
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -13723,7 +14433,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13723
14433
|
const targetPage = pages[cmdTabIndex];
|
|
13724
14434
|
await targetPage.bringToFront().catch(() => {
|
|
13725
14435
|
});
|
|
13726
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
14436
|
+
const { setActivePage: setActivePage2 } = await import("./browser-Y6B3NS4Q.js");
|
|
13727
14437
|
setActivePage2(session, targetPage);
|
|
13728
14438
|
}
|
|
13729
14439
|
}
|
|
@@ -13999,7 +14709,7 @@ async function main() {
|
|
|
13999
14709
|
const command = process.argv[2];
|
|
14000
14710
|
const isLongRunning = command === "preview" || command === "serve";
|
|
14001
14711
|
if (!isLongRunning) {
|
|
14002
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
14712
|
+
const { ensureProcessCanExit } = await import("./browser-Y6B3NS4Q.js");
|
|
14003
14713
|
await ensureProcessCanExit().catch(() => {
|
|
14004
14714
|
});
|
|
14005
14715
|
process.exit(process.exitCode || exitCode);
|