@xbrowser/cli 1.25.2 → 1.27.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-L3TUDYY3.js → browser-4IYIHZ6R.js} +3 -3
- package/dist/{browser-33QQWEDI.js → browser-NYYCR4O7.js} +2 -2
- package/dist/{browser-4LOJSMWV.js → browser-ZD53IMUJ.js} +3 -3
- package/dist/{cdp-driver-BYW7WY7E.js → cdp-driver-4X6Q62WI.js} +2 -2
- package/dist/{cdp-driver-5YVI5AIS.js → cdp-driver-EFEW4ZEN.js} +2 -2
- package/dist/{cdp-driver-MEK5EDEK.js → cdp-driver-HB744QB4.js} +3 -3
- package/dist/{chunk-ZOYM7QMS.js → chunk-3PUOISKE.js} +1 -1
- package/dist/{chunk-2EEAXSBA.js → chunk-HSYRAV3H.js} +3 -3
- package/dist/{chunk-DRKL2RFQ.js → chunk-IDXOIXQR.js} +320 -144
- package/dist/{chunk-U6GFDVNI.js → chunk-J3HXZVSN.js} +3 -3
- package/dist/{chunk-NNI5RT4A.js → chunk-KECYFWJO.js} +1 -1
- package/dist/{chunk-CGNHGAIJ.js → chunk-ME5FO5YV.js} +3 -3
- package/dist/{chunk-MYH6FIBZ.js → chunk-SEEWE5SJ.js} +5 -1
- package/dist/{chunk-VCVDILH6.js → chunk-T2AI24A5.js} +5 -1
- package/dist/{chunk-PO27V5UH.js → chunk-YITK42HZ.js} +320 -144
- package/dist/cli.js +6 -6
- package/dist/daemon-main.js +326 -150
- package/dist/index.js +7 -7
- package/dist/{launcher-LUOMMGZC.js → launcher-SJ44X25U.js} +1 -1
- package/dist/{launcher-IK2FKW6T.js → launcher-XHKIC4GP.js} +1 -1
- package/dist/{server-IBQGNDSB.js → server-WDDGIV3C.js} +147 -4
- package/dist/{server-EZJW6IHU.js → server-YKMRFDEM.js} +146 -3
- package/dist/{session-replayer-PJIUH7KI.js → session-replayer-TXTNTG33.js} +89 -44
- package/package.json +1 -1
package/dist/daemon-main.js
CHANGED
|
@@ -38,10 +38,10 @@ import {
|
|
|
38
38
|
resolveLaunchOpts,
|
|
39
39
|
saveSessionDiskMeta,
|
|
40
40
|
setActivePage
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-3PUOISKE.js";
|
|
42
42
|
import {
|
|
43
43
|
createRuleEngine
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-ME5FO5YV.js";
|
|
45
45
|
import {
|
|
46
46
|
queryJS
|
|
47
47
|
} from "./chunk-A7NEA4PA.js";
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
sleep,
|
|
51
51
|
wheelDelta
|
|
52
52
|
} from "./chunk-R3F4K2SB.js";
|
|
53
|
-
import "./chunk-
|
|
53
|
+
import "./chunk-SEEWE5SJ.js";
|
|
54
54
|
import {
|
|
55
55
|
errMsg
|
|
56
56
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -102,12 +102,12 @@ function classifyFailure(message) {
|
|
|
102
102
|
|
|
103
103
|
// src/executor.ts
|
|
104
104
|
import {
|
|
105
|
-
ok as
|
|
106
|
-
fail as
|
|
105
|
+
ok as ok32,
|
|
106
|
+
fail as fail17,
|
|
107
107
|
isCommandResult,
|
|
108
108
|
CompositeStorage as CompositeStorage2,
|
|
109
109
|
TipCollector as TipCollector2,
|
|
110
|
-
normalizeTips as
|
|
110
|
+
normalizeTips as normalizeTips7,
|
|
111
111
|
configureArchiveStore,
|
|
112
112
|
appendCommandToArchive,
|
|
113
113
|
checkGuard,
|
|
@@ -535,10 +535,14 @@ var clickCommand = registerCommand({
|
|
|
535
535
|
targetIdsBefore = /* @__PURE__ */ new Set();
|
|
536
536
|
}
|
|
537
537
|
const pagePromise = new Promise((resolve) => {
|
|
538
|
+
const waitMs = (() => {
|
|
539
|
+
const v = parseInt(process.env.XBROWSER_NEW_TAB_WAIT ?? "250", 10);
|
|
540
|
+
return Number.isFinite(v) && v > 0 ? v : 250;
|
|
541
|
+
})();
|
|
538
542
|
const timer = setTimeout(() => {
|
|
539
543
|
ctx.browserContext.off("page", handler);
|
|
540
544
|
resolve(void 0);
|
|
541
|
-
},
|
|
545
|
+
}, waitMs);
|
|
542
546
|
const handler = (page2) => {
|
|
543
547
|
if (targetIdsBefore.has(targetIdOf(page2))) return;
|
|
544
548
|
try {
|
|
@@ -5875,26 +5879,193 @@ var waitForCommand = registerCommand({
|
|
|
5875
5879
|
}
|
|
5876
5880
|
});
|
|
5877
5881
|
|
|
5878
|
-
// src/commands/
|
|
5882
|
+
// src/commands/task.ts
|
|
5879
5883
|
import { z as z27 } from "zod";
|
|
5880
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5881
|
-
var
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5884
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5885
|
+
var DECISION_SYSTEM = `\u4F60\u662F\u6D4F\u89C8\u5668\u4EFB\u52A1\u51B3\u7B56\u5668\u3002\u6839\u636E\u76EE\u6807\u3001\u5F53\u524D\u9875\u9762\u5143\u7D20\u6E05\u5355\uFF08\u6BCF\u9879\u5E26 @eN \u7F16\u53F7\uFF09\u548C\u5DF2\u6267\u884C\u5386\u53F2\uFF0C\u8F93\u51FA\u4E0B\u4E00\u6B65\u52A8\u4F5C\u3002
|
|
5886
|
+
|
|
5887
|
+
\u53EF\u7528\u52A8\u4F5C\uFF08\u53EA\u80FD\u8F93\u51FA\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8F93\u51FA\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\uFF09\uFF1A
|
|
5888
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5889
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5890
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5891
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5892
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5893
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5894
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5895
|
+
|
|
5896
|
+
\u89C4\u5219\uFF1A
|
|
5897
|
+
1. ref \u5FC5\u987B\u539F\u6837\u6765\u81EA\u672C\u6B21\u5143\u7D20\u6E05\u5355\uFF1B\u6E05\u5355\u91CC\u6CA1\u6709\u80FD\u63A8\u8FDB\u76EE\u6807\u7684\u5143\u7D20\u5C31\u8F93\u51FA blocked\u3002
|
|
5898
|
+
2. \u76EE\u6807\u5DF2\u5B8C\u6210\uFF08\u9875\u9762\u4E0A\u80FD\u786E\u8BA4\u7ED3\u679C\uFF09\u5C31\u8F93\u51FA done\uFF0Cvalue \u5199\u5B8C\u6210\u6458\u8981\u3002
|
|
5899
|
+
3. \u4E0D\u8981\u91CD\u590D\u521A\u5931\u8D25\u8FC7\u7684\u540C\u4E00\u52A8\u4F5C\uFF1B\u8FDE\u7EED\u5931\u8D25\u6362\u601D\u8DEF\u6216 blocked\u3002`;
|
|
5900
|
+
function extractDecision(raw) {
|
|
5901
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
5902
|
+
const start = s.indexOf("{");
|
|
5903
|
+
if (start < 0) return null;
|
|
5904
|
+
let depth = 0;
|
|
5905
|
+
for (let i = start; i < s.length; i++) {
|
|
5906
|
+
if (s[i] === "{") depth++;
|
|
5907
|
+
else if (s[i] === "}") {
|
|
5908
|
+
depth--;
|
|
5909
|
+
if (depth === 0) {
|
|
5910
|
+
try {
|
|
5911
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
5912
|
+
} catch {
|
|
5913
|
+
return null;
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
}
|
|
5917
|
+
}
|
|
5918
|
+
return null;
|
|
5919
|
+
}
|
|
5920
|
+
var taskCommand = registerCommand({
|
|
5921
|
+
name: "task",
|
|
5922
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
5923
|
+
scope: "page",
|
|
5924
|
+
parameters: z27.object({
|
|
5925
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
5926
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
5927
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
5928
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
5929
|
+
}),
|
|
5930
|
+
result: z27.object({
|
|
5931
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
5932
|
+
summary: z27.string().optional(),
|
|
5933
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
5934
|
+
finalUrl: z27.string().optional(),
|
|
5935
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
5936
|
+
}).passthrough(),
|
|
5937
|
+
handler: async (p, ctx) => {
|
|
5938
|
+
const creds = loadVLMCredentials2();
|
|
5939
|
+
if (!creds) {
|
|
5940
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
5941
|
+
}
|
|
5942
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
5943
|
+
const started = Date.now();
|
|
5944
|
+
const steps = [];
|
|
5945
|
+
const history = [];
|
|
5946
|
+
let llmCalls = 0;
|
|
5947
|
+
let status = "max_steps";
|
|
5948
|
+
let summary = "";
|
|
5949
|
+
let lastError = "";
|
|
5950
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
5951
|
+
if (Date.now() - started > p.timeout) {
|
|
5952
|
+
status = "blocked";
|
|
5953
|
+
summary = `timeout after ${step - 1} steps`;
|
|
5954
|
+
break;
|
|
5955
|
+
}
|
|
5956
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
5957
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
5958
|
+
const screenHash = obs.screenHash;
|
|
5959
|
+
const userPayload = [
|
|
5960
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
5961
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
5962
|
+
compact,
|
|
5963
|
+
history.length ? `
|
|
5964
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
5965
|
+
${history.slice(-6).join("\n")}` : ""
|
|
5966
|
+
].filter(Boolean).join("\n");
|
|
5967
|
+
let raw = "";
|
|
5968
|
+
try {
|
|
5969
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
5970
|
+
|
|
5971
|
+
---
|
|
5972
|
+
|
|
5973
|
+
${userPayload}` }], 900);
|
|
5974
|
+
llmCalls++;
|
|
5975
|
+
} catch (e) {
|
|
5976
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
5977
|
+
status = "error";
|
|
5978
|
+
summary = `LLM call failed: ${lastError}`;
|
|
5979
|
+
break;
|
|
5980
|
+
}
|
|
5981
|
+
const decision = extractDecision(raw);
|
|
5982
|
+
if (!decision || typeof decision.action !== "string") {
|
|
5983
|
+
status = "blocked";
|
|
5984
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
5985
|
+
break;
|
|
5986
|
+
}
|
|
5987
|
+
const action = decision.action;
|
|
5988
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
5989
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
5990
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
5991
|
+
if (action === "done") {
|
|
5992
|
+
status = "done";
|
|
5993
|
+
summary = value || thought || "task done";
|
|
5994
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
5995
|
+
break;
|
|
5996
|
+
}
|
|
5997
|
+
if (action === "blocked") {
|
|
5998
|
+
status = "blocked";
|
|
5999
|
+
summary = value || thought || "LLM judged blocked";
|
|
6000
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
6001
|
+
break;
|
|
6002
|
+
}
|
|
6003
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
6004
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
6005
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
6006
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
6007
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
6008
|
+
continue;
|
|
6009
|
+
}
|
|
6010
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
6011
|
+
action,
|
|
6012
|
+
ref: normalizedRef,
|
|
6013
|
+
value,
|
|
6014
|
+
selector: void 0,
|
|
6015
|
+
force: false,
|
|
6016
|
+
timeout: 1e4
|
|
6017
|
+
});
|
|
6018
|
+
const record = {
|
|
6019
|
+
step,
|
|
6020
|
+
thought,
|
|
6021
|
+
action,
|
|
6022
|
+
ref: normalizedRef,
|
|
6023
|
+
value,
|
|
6024
|
+
ok: res.success === true,
|
|
6025
|
+
stale: res.stale,
|
|
6026
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6027
|
+
screenHash
|
|
6028
|
+
};
|
|
6029
|
+
steps.push(record);
|
|
6030
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6031
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6032
|
+
const last3 = steps.slice(-3);
|
|
6033
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6034
|
+
status = "blocked";
|
|
6035
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6036
|
+
break;
|
|
6037
|
+
}
|
|
6038
|
+
}
|
|
6039
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6040
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6041
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6042
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6043
|
+
return ok26(data, normalizeTips5([
|
|
6044
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6045
|
+
]));
|
|
6046
|
+
}
|
|
6047
|
+
});
|
|
6048
|
+
|
|
6049
|
+
// src/commands/tab.ts
|
|
6050
|
+
import { z as z28 } from "zod";
|
|
6051
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6052
|
+
var TabParams = z28.object({
|
|
6053
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6054
|
+
url: z28.string().optional(),
|
|
6055
|
+
index: z28.number().int().min(0).optional()
|
|
5885
6056
|
});
|
|
5886
6057
|
var tabCommand = registerCommand({
|
|
5887
6058
|
name: "tab",
|
|
5888
6059
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5889
6060
|
scope: "page",
|
|
5890
6061
|
parameters: TabParams,
|
|
5891
|
-
result:
|
|
5892
|
-
success:
|
|
5893
|
-
data:
|
|
6062
|
+
result: z28.object({
|
|
6063
|
+
success: z28.boolean(),
|
|
6064
|
+
data: z28.unknown()
|
|
5894
6065
|
}),
|
|
5895
6066
|
handler: async (p, ctx) => {
|
|
5896
6067
|
if (!ctx.browserContext) {
|
|
5897
|
-
return
|
|
6068
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
5898
6069
|
}
|
|
5899
6070
|
const pages = ctx.browserContext.pages();
|
|
5900
6071
|
switch (p.subcommand) {
|
|
@@ -5907,7 +6078,7 @@ var tabCommand = registerCommand({
|
|
|
5907
6078
|
case "switch":
|
|
5908
6079
|
return handleSwitch(p, pages, ctx);
|
|
5909
6080
|
default:
|
|
5910
|
-
return
|
|
6081
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
5911
6082
|
}
|
|
5912
6083
|
}
|
|
5913
6084
|
});
|
|
@@ -5922,7 +6093,7 @@ async function handleList(pages, ctx) {
|
|
|
5922
6093
|
if (isActive) activeIndex = i;
|
|
5923
6094
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5924
6095
|
}
|
|
5925
|
-
return
|
|
6096
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
5926
6097
|
}
|
|
5927
6098
|
async function handleNew(p, _pages, ctx) {
|
|
5928
6099
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5950,7 +6121,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5950
6121
|
const title = await newPage.title().catch(() => "");
|
|
5951
6122
|
const allPages = ctx.browserContext.pages();
|
|
5952
6123
|
const newIndex = allPages.indexOf(newPage);
|
|
5953
|
-
return
|
|
6124
|
+
return ok27({
|
|
5954
6125
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5955
6126
|
url: newPage.url(),
|
|
5956
6127
|
title,
|
|
@@ -5961,11 +6132,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5961
6132
|
async function handleClose(p, ctx) {
|
|
5962
6133
|
const currentPages = ctx.browserContext.pages();
|
|
5963
6134
|
if (currentPages.length <= 1) {
|
|
5964
|
-
return
|
|
6135
|
+
return fail13("Cannot close the last remaining tab");
|
|
5965
6136
|
}
|
|
5966
6137
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5967
6138
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5968
|
-
return
|
|
6139
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5969
6140
|
}
|
|
5970
6141
|
const pageToClose = currentPages[closeIndex];
|
|
5971
6142
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5980,7 +6151,7 @@ async function handleClose(p, ctx) {
|
|
|
5980
6151
|
}
|
|
5981
6152
|
ctx.page = newActivePage;
|
|
5982
6153
|
}
|
|
5983
|
-
return
|
|
6154
|
+
return ok27({
|
|
5984
6155
|
closedIndex: closeIndex,
|
|
5985
6156
|
total: remainingPages.length,
|
|
5986
6157
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5988,10 +6159,10 @@ async function handleClose(p, ctx) {
|
|
|
5988
6159
|
}
|
|
5989
6160
|
async function handleSwitch(p, pages, ctx) {
|
|
5990
6161
|
if (p.index === void 0) {
|
|
5991
|
-
return
|
|
6162
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
5992
6163
|
}
|
|
5993
6164
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5994
|
-
return
|
|
6165
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5995
6166
|
}
|
|
5996
6167
|
const targetPage = pages[p.index];
|
|
5997
6168
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -6013,7 +6184,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6013
6184
|
}
|
|
6014
6185
|
ctx.page = targetPage;
|
|
6015
6186
|
const title = await targetPage.title().catch(() => "");
|
|
6016
|
-
return
|
|
6187
|
+
return ok27({
|
|
6017
6188
|
index: p.index,
|
|
6018
6189
|
url: targetPage.url(),
|
|
6019
6190
|
title,
|
|
@@ -6022,8 +6193,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6022
6193
|
}
|
|
6023
6194
|
|
|
6024
6195
|
// src/commands/addinitscript.ts
|
|
6025
|
-
import { z as
|
|
6026
|
-
import { ok as
|
|
6196
|
+
import { z as z29 } from "zod";
|
|
6197
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6027
6198
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6028
6199
|
|
|
6029
6200
|
// src/chain-parser.ts
|
|
@@ -6164,14 +6335,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6164
6335
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6165
6336
|
|
|
6166
6337
|
// src/commands/addinitscript.ts
|
|
6167
|
-
var InitScriptParams =
|
|
6168
|
-
script:
|
|
6169
|
-
file:
|
|
6170
|
-
stdin:
|
|
6171
|
-
name:
|
|
6172
|
-
list:
|
|
6173
|
-
remove:
|
|
6174
|
-
base64:
|
|
6338
|
+
var InitScriptParams = z29.object({
|
|
6339
|
+
script: z29.string().optional(),
|
|
6340
|
+
file: z29.string().optional(),
|
|
6341
|
+
stdin: z29.boolean().optional(),
|
|
6342
|
+
name: z29.string().optional(),
|
|
6343
|
+
list: z29.boolean().optional(),
|
|
6344
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6345
|
+
base64: z29.string().optional()
|
|
6175
6346
|
});
|
|
6176
6347
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6177
6348
|
function resolveScriptContent(params) {
|
|
@@ -6205,14 +6376,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6205
6376
|
description: "Add an initialization script that runs on every page load",
|
|
6206
6377
|
scope: "page",
|
|
6207
6378
|
parameters: InitScriptParams,
|
|
6208
|
-
result:
|
|
6209
|
-
scripts:
|
|
6210
|
-
removed:
|
|
6211
|
-
existed:
|
|
6212
|
-
error:
|
|
6213
|
-
registered:
|
|
6214
|
-
hint:
|
|
6215
|
-
executedImmediately:
|
|
6379
|
+
result: z29.object({
|
|
6380
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6381
|
+
removed: z29.string().optional(),
|
|
6382
|
+
existed: z29.boolean().optional(),
|
|
6383
|
+
error: z29.string().optional(),
|
|
6384
|
+
registered: z29.string().optional(),
|
|
6385
|
+
hint: z29.string().optional(),
|
|
6386
|
+
executedImmediately: z29.boolean().optional()
|
|
6216
6387
|
}).passthrough(),
|
|
6217
6388
|
handler: async (params, ctx) => {
|
|
6218
6389
|
if (params.list) {
|
|
@@ -6221,20 +6392,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6221
6392
|
size: content2.length,
|
|
6222
6393
|
preview: content2.slice(0, 80)
|
|
6223
6394
|
}));
|
|
6224
|
-
return
|
|
6395
|
+
return ok28({ scripts });
|
|
6225
6396
|
}
|
|
6226
6397
|
if (params.remove && typeof params.remove === "string") {
|
|
6227
6398
|
const existed = registeredScripts.delete(params.remove);
|
|
6228
|
-
return
|
|
6399
|
+
return ok28({ removed: params.remove, existed });
|
|
6229
6400
|
}
|
|
6230
6401
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6231
6402
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6232
6403
|
const existed = registeredScripts.delete(removeTarget);
|
|
6233
|
-
return
|
|
6404
|
+
return ok28({ removed: removeTarget, existed });
|
|
6234
6405
|
}
|
|
6235
6406
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6236
6407
|
if (!content) {
|
|
6237
|
-
return
|
|
6408
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6238
6409
|
}
|
|
6239
6410
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6240
6411
|
registeredScripts.set(scriptName, content);
|
|
@@ -6242,45 +6413,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6242
6413
|
try {
|
|
6243
6414
|
await ctx.page.evaluate(content);
|
|
6244
6415
|
} catch {
|
|
6245
|
-
return
|
|
6416
|
+
return ok28({
|
|
6246
6417
|
registered: scriptName,
|
|
6247
6418
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6248
6419
|
});
|
|
6249
6420
|
}
|
|
6250
|
-
return
|
|
6421
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6251
6422
|
}
|
|
6252
6423
|
});
|
|
6253
6424
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6254
6425
|
|
|
6255
6426
|
// src/commands/find.ts
|
|
6256
|
-
import { z as
|
|
6257
|
-
import { ok as
|
|
6258
|
-
var actionSchema2 =
|
|
6427
|
+
import { z as z30 } from "zod";
|
|
6428
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6429
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6259
6430
|
var findCommand = registerCommand({
|
|
6260
6431
|
name: "find",
|
|
6261
6432
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6262
6433
|
scope: "page",
|
|
6263
|
-
parameters:
|
|
6264
|
-
strategy:
|
|
6265
|
-
value:
|
|
6266
|
-
name:
|
|
6267
|
-
exact:
|
|
6268
|
-
operation:
|
|
6434
|
+
parameters: z30.object({
|
|
6435
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6436
|
+
value: z30.string(),
|
|
6437
|
+
name: z30.string().optional(),
|
|
6438
|
+
exact: z30.boolean().optional().default(false),
|
|
6439
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6269
6440
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6270
|
-
actionValue:
|
|
6271
|
-
index:
|
|
6272
|
-
click:
|
|
6273
|
-
fill:
|
|
6274
|
-
type:
|
|
6275
|
-
select:
|
|
6276
|
-
hover:
|
|
6277
|
-
check:
|
|
6278
|
-
timeout:
|
|
6441
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6442
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6443
|
+
click: z30.boolean().optional().default(false),
|
|
6444
|
+
fill: z30.string().optional(),
|
|
6445
|
+
type: z30.string().optional(),
|
|
6446
|
+
select: z30.string().optional(),
|
|
6447
|
+
hover: z30.boolean().optional().default(false),
|
|
6448
|
+
check: z30.boolean().optional().default(false),
|
|
6449
|
+
timeout: z30.number().optional().default(1e4)
|
|
6279
6450
|
}),
|
|
6280
|
-
result:
|
|
6281
|
-
matched:
|
|
6282
|
-
selector:
|
|
6283
|
-
action:
|
|
6451
|
+
result: z30.object({
|
|
6452
|
+
matched: z30.number(),
|
|
6453
|
+
selector: z30.string(),
|
|
6454
|
+
action: z30.string().optional()
|
|
6284
6455
|
}),
|
|
6285
6456
|
handler: async (p, ctx) => {
|
|
6286
6457
|
const page = ctx.page;
|
|
@@ -6295,7 +6466,7 @@ var findCommand = registerCommand({
|
|
|
6295
6466
|
});
|
|
6296
6467
|
const count = await locator.count();
|
|
6297
6468
|
if (count === 0) {
|
|
6298
|
-
return
|
|
6469
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6299
6470
|
}
|
|
6300
6471
|
const tips = [];
|
|
6301
6472
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6307,15 +6478,15 @@ var findCommand = registerCommand({
|
|
|
6307
6478
|
await target.click({ timeout: p.timeout, force: true });
|
|
6308
6479
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6309
6480
|
} else if (actionName === "fill") {
|
|
6310
|
-
if (actionValue === void 0) return
|
|
6481
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6311
6482
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6312
6483
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6313
6484
|
} else if (actionName === "type") {
|
|
6314
|
-
if (actionValue === void 0) return
|
|
6485
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6315
6486
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6316
6487
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6317
6488
|
} else if (actionName === "select") {
|
|
6318
|
-
if (actionValue === void 0) return
|
|
6489
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6319
6490
|
await target.selectOption(actionValue);
|
|
6320
6491
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6321
6492
|
} else if (actionName === "hover") {
|
|
@@ -6329,8 +6500,8 @@ var findCommand = registerCommand({
|
|
|
6329
6500
|
}
|
|
6330
6501
|
});
|
|
6331
6502
|
function okWithTips(data, tips) {
|
|
6332
|
-
const result =
|
|
6333
|
-
if (tips.length > 0) result.tips =
|
|
6503
|
+
const result = ok29(data);
|
|
6504
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6334
6505
|
return result;
|
|
6335
6506
|
}
|
|
6336
6507
|
function parseOperation(operation) {
|
|
@@ -6428,8 +6599,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6428
6599
|
}
|
|
6429
6600
|
|
|
6430
6601
|
// src/commands/visual-tag.ts
|
|
6431
|
-
import { z as
|
|
6432
|
-
import { ok as
|
|
6602
|
+
import { z as z31 } from "zod";
|
|
6603
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6433
6604
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6434
6605
|
var TAG_SCRIPT = `
|
|
6435
6606
|
(function() {
|
|
@@ -6520,49 +6691,49 @@ var visualTagCommand = registerCommand({
|
|
|
6520
6691
|
name: "visual-tag",
|
|
6521
6692
|
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",
|
|
6522
6693
|
scope: "page",
|
|
6523
|
-
parameters:
|
|
6524
|
-
action:
|
|
6525
|
-
id:
|
|
6694
|
+
parameters: z31.object({
|
|
6695
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6696
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6526
6697
|
}),
|
|
6527
|
-
result:
|
|
6528
|
-
action:
|
|
6529
|
-
tagged:
|
|
6530
|
-
id:
|
|
6531
|
-
element:
|
|
6698
|
+
result: z31.object({
|
|
6699
|
+
action: z31.string(),
|
|
6700
|
+
tagged: z31.number().optional(),
|
|
6701
|
+
id: z31.string().optional(),
|
|
6702
|
+
element: z31.record(z31.unknown()).optional()
|
|
6532
6703
|
}),
|
|
6533
6704
|
handler: async (p, ctx) => {
|
|
6534
6705
|
switch (p.action) {
|
|
6535
6706
|
case "tag": {
|
|
6536
6707
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6537
6708
|
const parsed = JSON.parse(result);
|
|
6538
|
-
return
|
|
6709
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6539
6710
|
}
|
|
6540
6711
|
case "lookup": {
|
|
6541
|
-
if (!p.id) return
|
|
6712
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6542
6713
|
const result = await ctx.page.evaluate(
|
|
6543
6714
|
`(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'}); })()`
|
|
6544
6715
|
);
|
|
6545
6716
|
const parsed = JSON.parse(result);
|
|
6546
|
-
if (parsed.err) return
|
|
6547
|
-
return
|
|
6717
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6718
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6548
6719
|
}
|
|
6549
6720
|
case "list": {
|
|
6550
6721
|
const result = await ctx.page.evaluate(
|
|
6551
6722
|
`(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); })()`
|
|
6552
6723
|
);
|
|
6553
|
-
return
|
|
6724
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6554
6725
|
}
|
|
6555
6726
|
case "clear": {
|
|
6556
6727
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6557
|
-
return
|
|
6728
|
+
return ok30({ action: "clear" });
|
|
6558
6729
|
}
|
|
6559
6730
|
}
|
|
6560
6731
|
}
|
|
6561
6732
|
});
|
|
6562
6733
|
|
|
6563
6734
|
// src/commands/visual-tag-v2.ts
|
|
6564
|
-
import { z as
|
|
6565
|
-
import { ok as
|
|
6735
|
+
import { z as z32 } from "zod";
|
|
6736
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6566
6737
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6567
6738
|
var TAG_V2_SCRIPT = `
|
|
6568
6739
|
(function() {
|
|
@@ -6909,45 +7080,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6909
7080
|
name: "visual-tag-v2",
|
|
6910
7081
|
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",
|
|
6911
7082
|
scope: "page",
|
|
6912
|
-
parameters:
|
|
6913
|
-
action:
|
|
6914
|
-
id:
|
|
6915
|
-
query:
|
|
6916
|
-
type:
|
|
6917
|
-
"interact-action":
|
|
6918
|
-
value:
|
|
7083
|
+
parameters: z32.object({
|
|
7084
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7085
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7086
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7087
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7088
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7089
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6919
7090
|
}),
|
|
6920
|
-
result:
|
|
6921
|
-
action:
|
|
6922
|
-
total:
|
|
6923
|
-
byType:
|
|
6924
|
-
element:
|
|
7091
|
+
result: z32.object({
|
|
7092
|
+
action: z32.string(),
|
|
7093
|
+
total: z32.number().optional(),
|
|
7094
|
+
byType: z32.record(z32.number()).optional(),
|
|
7095
|
+
element: z32.record(z32.unknown()).optional()
|
|
6925
7096
|
}),
|
|
6926
7097
|
handler: async (p, ctx) => {
|
|
6927
7098
|
switch (p.action) {
|
|
6928
7099
|
case "tag": {
|
|
6929
7100
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6930
7101
|
const parsed = JSON.parse(result);
|
|
6931
|
-
return
|
|
7102
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6932
7103
|
}
|
|
6933
7104
|
case "lookup": {
|
|
6934
|
-
if (!p.id) return
|
|
7105
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6935
7106
|
const result = await ctx.page.evaluate(
|
|
6936
7107
|
`(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'})})()`
|
|
6937
7108
|
);
|
|
6938
7109
|
const parsed = JSON.parse(result);
|
|
6939
|
-
if (parsed.err) return
|
|
6940
|
-
return
|
|
7110
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7111
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6941
7112
|
}
|
|
6942
7113
|
case "by-type": {
|
|
6943
7114
|
const result = await ctx.page.evaluate(
|
|
6944
7115
|
`(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)})()`
|
|
6945
7116
|
);
|
|
6946
|
-
return
|
|
7117
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6947
7118
|
}
|
|
6948
7119
|
case "find": {
|
|
6949
7120
|
const query = p.query;
|
|
6950
|
-
if (!query) return
|
|
7121
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6951
7122
|
const result = await ctx.page.evaluate(
|
|
6952
7123
|
`(function(){
|
|
6953
7124
|
var map = window.__xbTagSerializable;
|
|
@@ -6989,21 +7160,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6989
7160
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6990
7161
|
})()`
|
|
6991
7162
|
);
|
|
6992
|
-
return
|
|
7163
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
6993
7164
|
}
|
|
6994
7165
|
case "stats": {
|
|
6995
7166
|
const result = await ctx.page.evaluate(
|
|
6996
7167
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6997
7168
|
);
|
|
6998
|
-
return
|
|
7169
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
6999
7170
|
}
|
|
7000
7171
|
case "interact": {
|
|
7001
7172
|
const query = p.query;
|
|
7002
7173
|
const pAny = p;
|
|
7003
7174
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
7004
7175
|
const value = pAny.value;
|
|
7005
|
-
if (!query) return
|
|
7006
|
-
if (!action) return
|
|
7176
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7177
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
7007
7178
|
const findResult = await ctx.page.evaluate(
|
|
7008
7179
|
`(function(){
|
|
7009
7180
|
var map = window.__xbTagSerializable;
|
|
@@ -7033,11 +7204,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7033
7204
|
})()`
|
|
7034
7205
|
);
|
|
7035
7206
|
const parsed = JSON.parse(findResult);
|
|
7036
|
-
if (parsed.err) return
|
|
7037
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7207
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7208
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7038
7209
|
const target = parsed.results[0];
|
|
7039
7210
|
if (action === "read") {
|
|
7040
|
-
return
|
|
7211
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7041
7212
|
}
|
|
7042
7213
|
if (action === "click") {
|
|
7043
7214
|
const el = await ctx.page.evaluate(
|
|
@@ -7050,12 +7221,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7050
7221
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7051
7222
|
})()`
|
|
7052
7223
|
);
|
|
7053
|
-
if (!el) return
|
|
7224
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7054
7225
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7055
|
-
return
|
|
7226
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7056
7227
|
}
|
|
7057
7228
|
if (action === "fill") {
|
|
7058
|
-
if (!value) return
|
|
7229
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7059
7230
|
const el = await ctx.page.evaluate(
|
|
7060
7231
|
`(function(){
|
|
7061
7232
|
var map = window.__xbTagMap;
|
|
@@ -7066,12 +7237,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7066
7237
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7067
7238
|
})()`
|
|
7068
7239
|
);
|
|
7069
|
-
if (!el) return
|
|
7240
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7070
7241
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7071
7242
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7072
|
-
return
|
|
7243
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7073
7244
|
}
|
|
7074
|
-
return
|
|
7245
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7075
7246
|
}
|
|
7076
7247
|
case "export": {
|
|
7077
7248
|
const result = await ctx.page.evaluate(
|
|
@@ -7119,12 +7290,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7119
7290
|
})()`
|
|
7120
7291
|
);
|
|
7121
7292
|
const parsed = JSON.parse(result);
|
|
7122
|
-
if (parsed.err) return
|
|
7123
|
-
return
|
|
7293
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7294
|
+
return ok31({ action: "export", element: parsed });
|
|
7124
7295
|
}
|
|
7125
7296
|
case "clear": {
|
|
7126
7297
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7127
|
-
return
|
|
7298
|
+
return ok31({ action: "clear" });
|
|
7128
7299
|
}
|
|
7129
7300
|
}
|
|
7130
7301
|
}
|
|
@@ -7533,7 +7704,10 @@ function buildSnapshot(elements) {
|
|
|
7533
7704
|
}
|
|
7534
7705
|
|
|
7535
7706
|
// src/tips/index.ts
|
|
7536
|
-
|
|
7707
|
+
function tipsDebounceMs() {
|
|
7708
|
+
const v = parseInt(process.env.XBROWSER_TIPS_DEBOUNCE ?? "120", 10);
|
|
7709
|
+
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
7710
|
+
}
|
|
7537
7711
|
var SKIP_DETECT_COMMANDS = /* @__PURE__ */ new Set([
|
|
7538
7712
|
"goto",
|
|
7539
7713
|
// 导航命令不需要检测
|
|
@@ -7625,7 +7799,9 @@ var TipsManager = class {
|
|
|
7625
7799
|
}
|
|
7626
7800
|
}
|
|
7627
7801
|
debounce() {
|
|
7628
|
-
|
|
7802
|
+
const ms = tipsDebounceMs();
|
|
7803
|
+
if (ms <= 0) return Promise.resolve();
|
|
7804
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7629
7805
|
}
|
|
7630
7806
|
formatTips(tips) {
|
|
7631
7807
|
return tips.map((tip) => {
|
|
@@ -7794,7 +7970,7 @@ async function guardCheck(commandName) {
|
|
|
7794
7970
|
}
|
|
7795
7971
|
}
|
|
7796
7972
|
function errorResult(message) {
|
|
7797
|
-
return { ...
|
|
7973
|
+
return { ...fail17(message), duration: 0 };
|
|
7798
7974
|
}
|
|
7799
7975
|
function tipsToMessages(tips) {
|
|
7800
7976
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7871,7 +8047,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7871
8047
|
}
|
|
7872
8048
|
let targetPageOverride = null;
|
|
7873
8049
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7874
|
-
const { findTargetPage } = await import("./browser-
|
|
8050
|
+
const { findTargetPage } = await import("./browser-ZD53IMUJ.js");
|
|
7875
8051
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7876
8052
|
if (!targetPageOverride) {
|
|
7877
8053
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7983,7 +8159,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7983
8159
|
const cache = /* @__PURE__ */ new Map();
|
|
7984
8160
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
7985
8161
|
if (resolved.tips.length > 0) {
|
|
7986
|
-
refTips =
|
|
8162
|
+
refTips = normalizeTips7(resolved.tips);
|
|
7987
8163
|
params = resolved.params;
|
|
7988
8164
|
}
|
|
7989
8165
|
}
|
|
@@ -8051,8 +8227,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8051
8227
|
}
|
|
8052
8228
|
const merged = [
|
|
8053
8229
|
...raw.tips || [],
|
|
8054
|
-
...
|
|
8055
|
-
...snapshotHint ?
|
|
8230
|
+
...normalizeTips7(smartTips),
|
|
8231
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8056
8232
|
...refTips
|
|
8057
8233
|
];
|
|
8058
8234
|
const isSuccess = raw.success !== false;
|
|
@@ -8067,7 +8243,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8067
8243
|
timestamp: start
|
|
8068
8244
|
});
|
|
8069
8245
|
if (isSuccess) {
|
|
8070
|
-
return { ...
|
|
8246
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8071
8247
|
}
|
|
8072
8248
|
const fc = classifyFailure(raw.message);
|
|
8073
8249
|
return {
|
|
@@ -8080,7 +8256,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8080
8256
|
...hookOutputs ? { hookOutputs } : {}
|
|
8081
8257
|
};
|
|
8082
8258
|
}
|
|
8083
|
-
const smartTipNormalized =
|
|
8259
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8084
8260
|
recordArchive(session?.id, sessionName, {
|
|
8085
8261
|
step: 0,
|
|
8086
8262
|
command: commandName,
|
|
@@ -8090,7 +8266,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8090
8266
|
duration,
|
|
8091
8267
|
timestamp: start
|
|
8092
8268
|
});
|
|
8093
|
-
return { ...
|
|
8269
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8094
8270
|
} catch (err) {
|
|
8095
8271
|
const end = Date.now();
|
|
8096
8272
|
const duration = end - start;
|
|
@@ -8135,7 +8311,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8135
8311
|
duration,
|
|
8136
8312
|
timestamp: start
|
|
8137
8313
|
});
|
|
8138
|
-
return { ...
|
|
8314
|
+
return { ...fail17(errorMessage), duration };
|
|
8139
8315
|
} finally {
|
|
8140
8316
|
}
|
|
8141
8317
|
}
|
|
@@ -8180,7 +8356,7 @@ async function executeChain(input, options) {
|
|
|
8180
8356
|
results.push({
|
|
8181
8357
|
command: cmdName,
|
|
8182
8358
|
raw: cmdStr,
|
|
8183
|
-
...
|
|
8359
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8184
8360
|
duration: 0
|
|
8185
8361
|
});
|
|
8186
8362
|
if (type === "and") {
|
|
@@ -8199,7 +8375,7 @@ async function executeChain(input, options) {
|
|
|
8199
8375
|
results.push({
|
|
8200
8376
|
command: cmdName,
|
|
8201
8377
|
raw: cmdStr,
|
|
8202
|
-
...
|
|
8378
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8203
8379
|
duration: 0
|
|
8204
8380
|
});
|
|
8205
8381
|
if (type === "and") {
|
|
@@ -8269,7 +8445,7 @@ async function executeChain(input, options) {
|
|
|
8269
8445
|
success: false,
|
|
8270
8446
|
data: data2,
|
|
8271
8447
|
message: loginGuard.message,
|
|
8272
|
-
tips:
|
|
8448
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
8273
8449
|
duration: duration3
|
|
8274
8450
|
});
|
|
8275
8451
|
if (type === "and") {
|
|
@@ -8311,7 +8487,7 @@ async function executeChain(input, options) {
|
|
|
8311
8487
|
results.push({
|
|
8312
8488
|
command: `${cmdName} ${subCommand}`,
|
|
8313
8489
|
raw: cmdStr,
|
|
8314
|
-
...
|
|
8490
|
+
...ok32(data),
|
|
8315
8491
|
duration: duration2,
|
|
8316
8492
|
...hookOutputs ? { hookOutputs } : {}
|
|
8317
8493
|
});
|
|
@@ -8339,7 +8515,7 @@ async function executeChain(input, options) {
|
|
|
8339
8515
|
results.push({
|
|
8340
8516
|
command: `${cmdName} ${subCommand}`,
|
|
8341
8517
|
raw: cmdStr,
|
|
8342
|
-
...
|
|
8518
|
+
...fail17(errorMessage),
|
|
8343
8519
|
duration: duration2
|
|
8344
8520
|
});
|
|
8345
8521
|
if (type === "and") {
|
|
@@ -9711,7 +9887,7 @@ function createRPCHandler() {
|
|
|
9711
9887
|
if (isNewFormat) {
|
|
9712
9888
|
try {
|
|
9713
9889
|
const replayErrors = [];
|
|
9714
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
9890
|
+
const { SessionReplayer } = await import("./session-replayer-TXTNTG33.js");
|
|
9715
9891
|
const replayer = new SessionReplayer({
|
|
9716
9892
|
page: session.page,
|
|
9717
9893
|
stepDelay: slowMo * 500,
|
|
@@ -9763,10 +9939,10 @@ function createRPCHandler() {
|
|
|
9763
9939
|
const errors = Array.isArray(input.errors) ? input.errors : [];
|
|
9764
9940
|
const eventsPlayed = typeof input.eventsPlayed === "number" ? input.eventsPlayed : 0;
|
|
9765
9941
|
const totalEvents = typeof input.totalEvents === "number" ? input.totalEvents : eventsPlayed + errors.length;
|
|
9766
|
-
const
|
|
9942
|
+
const ok33 = input.ok ?? errors.length === 0;
|
|
9767
9943
|
return {
|
|
9768
|
-
ok:
|
|
9769
|
-
success:
|
|
9944
|
+
ok: ok33,
|
|
9945
|
+
success: ok33,
|
|
9770
9946
|
duration: typeof input.duration === "number" ? input.duration : 0,
|
|
9771
9947
|
eventsPlayed,
|
|
9772
9948
|
totalEvents,
|