@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
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
resolveLaunchOpts,
|
|
21
21
|
saveSessionDiskMeta,
|
|
22
22
|
setActivePage
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-HSYRAV3H.js";
|
|
24
24
|
import {
|
|
25
25
|
rand,
|
|
26
26
|
sleep,
|
|
@@ -63,12 +63,12 @@ function classifyFailure(message) {
|
|
|
63
63
|
|
|
64
64
|
// src/executor.ts
|
|
65
65
|
import {
|
|
66
|
-
ok as
|
|
67
|
-
fail as
|
|
66
|
+
ok as ok32,
|
|
67
|
+
fail as fail17,
|
|
68
68
|
isCommandResult,
|
|
69
69
|
CompositeStorage as CompositeStorage2,
|
|
70
70
|
TipCollector as TipCollector2,
|
|
71
|
-
normalizeTips as
|
|
71
|
+
normalizeTips as normalizeTips7,
|
|
72
72
|
configureArchiveStore,
|
|
73
73
|
appendCommandToArchive,
|
|
74
74
|
checkGuard,
|
|
@@ -515,10 +515,14 @@ var clickCommand = registerCommand({
|
|
|
515
515
|
targetIdsBefore = /* @__PURE__ */ new Set();
|
|
516
516
|
}
|
|
517
517
|
const pagePromise = new Promise((resolve3) => {
|
|
518
|
+
const waitMs = (() => {
|
|
519
|
+
const v = parseInt(process.env.XBROWSER_NEW_TAB_WAIT ?? "250", 10);
|
|
520
|
+
return Number.isFinite(v) && v > 0 ? v : 250;
|
|
521
|
+
})();
|
|
518
522
|
const timer = setTimeout(() => {
|
|
519
523
|
ctx.browserContext.off("page", handler);
|
|
520
524
|
resolve3(void 0);
|
|
521
|
-
},
|
|
525
|
+
}, waitMs);
|
|
522
526
|
const handler = (page2) => {
|
|
523
527
|
if (targetIdsBefore.has(targetIdOf(page2))) return;
|
|
524
528
|
try {
|
|
@@ -5855,26 +5859,193 @@ var waitForCommand = registerCommand({
|
|
|
5855
5859
|
}
|
|
5856
5860
|
});
|
|
5857
5861
|
|
|
5858
|
-
// src/commands/
|
|
5862
|
+
// src/commands/task.ts
|
|
5859
5863
|
import { z as z27 } from "zod";
|
|
5860
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5861
|
-
var
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5864
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5865
|
+
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
|
|
5866
|
+
|
|
5867
|
+
\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
|
|
5868
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5869
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5870
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5871
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5872
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5873
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5874
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5875
|
+
|
|
5876
|
+
\u89C4\u5219\uFF1A
|
|
5877
|
+
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
|
|
5878
|
+
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
|
|
5879
|
+
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`;
|
|
5880
|
+
function extractDecision(raw) {
|
|
5881
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
5882
|
+
const start = s.indexOf("{");
|
|
5883
|
+
if (start < 0) return null;
|
|
5884
|
+
let depth = 0;
|
|
5885
|
+
for (let i = start; i < s.length; i++) {
|
|
5886
|
+
if (s[i] === "{") depth++;
|
|
5887
|
+
else if (s[i] === "}") {
|
|
5888
|
+
depth--;
|
|
5889
|
+
if (depth === 0) {
|
|
5890
|
+
try {
|
|
5891
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
5892
|
+
} catch {
|
|
5893
|
+
return null;
|
|
5894
|
+
}
|
|
5895
|
+
}
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
return null;
|
|
5899
|
+
}
|
|
5900
|
+
var taskCommand = registerCommand({
|
|
5901
|
+
name: "task",
|
|
5902
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
5903
|
+
scope: "page",
|
|
5904
|
+
parameters: z27.object({
|
|
5905
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
5906
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
5907
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
5908
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
5909
|
+
}),
|
|
5910
|
+
result: z27.object({
|
|
5911
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
5912
|
+
summary: z27.string().optional(),
|
|
5913
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
5914
|
+
finalUrl: z27.string().optional(),
|
|
5915
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
5916
|
+
}).passthrough(),
|
|
5917
|
+
handler: async (p, ctx) => {
|
|
5918
|
+
const creds = loadVLMCredentials2();
|
|
5919
|
+
if (!creds) {
|
|
5920
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
5921
|
+
}
|
|
5922
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
5923
|
+
const started = Date.now();
|
|
5924
|
+
const steps = [];
|
|
5925
|
+
const history = [];
|
|
5926
|
+
let llmCalls = 0;
|
|
5927
|
+
let status = "max_steps";
|
|
5928
|
+
let summary = "";
|
|
5929
|
+
let lastError = "";
|
|
5930
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
5931
|
+
if (Date.now() - started > p.timeout) {
|
|
5932
|
+
status = "blocked";
|
|
5933
|
+
summary = `timeout after ${step - 1} steps`;
|
|
5934
|
+
break;
|
|
5935
|
+
}
|
|
5936
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
5937
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
5938
|
+
const screenHash = obs.screenHash;
|
|
5939
|
+
const userPayload = [
|
|
5940
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
5941
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
5942
|
+
compact,
|
|
5943
|
+
history.length ? `
|
|
5944
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
5945
|
+
${history.slice(-6).join("\n")}` : ""
|
|
5946
|
+
].filter(Boolean).join("\n");
|
|
5947
|
+
let raw = "";
|
|
5948
|
+
try {
|
|
5949
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
5950
|
+
|
|
5951
|
+
---
|
|
5952
|
+
|
|
5953
|
+
${userPayload}` }], 900);
|
|
5954
|
+
llmCalls++;
|
|
5955
|
+
} catch (e) {
|
|
5956
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
5957
|
+
status = "error";
|
|
5958
|
+
summary = `LLM call failed: ${lastError}`;
|
|
5959
|
+
break;
|
|
5960
|
+
}
|
|
5961
|
+
const decision = extractDecision(raw);
|
|
5962
|
+
if (!decision || typeof decision.action !== "string") {
|
|
5963
|
+
status = "blocked";
|
|
5964
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
5965
|
+
break;
|
|
5966
|
+
}
|
|
5967
|
+
const action = decision.action;
|
|
5968
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
5969
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
5970
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
5971
|
+
if (action === "done") {
|
|
5972
|
+
status = "done";
|
|
5973
|
+
summary = value || thought || "task done";
|
|
5974
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
5975
|
+
break;
|
|
5976
|
+
}
|
|
5977
|
+
if (action === "blocked") {
|
|
5978
|
+
status = "blocked";
|
|
5979
|
+
summary = value || thought || "LLM judged blocked";
|
|
5980
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
5981
|
+
break;
|
|
5982
|
+
}
|
|
5983
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
5984
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
5985
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
5986
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
5987
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
5988
|
+
continue;
|
|
5989
|
+
}
|
|
5990
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
5991
|
+
action,
|
|
5992
|
+
ref: normalizedRef,
|
|
5993
|
+
value,
|
|
5994
|
+
selector: void 0,
|
|
5995
|
+
force: false,
|
|
5996
|
+
timeout: 1e4
|
|
5997
|
+
});
|
|
5998
|
+
const record = {
|
|
5999
|
+
step,
|
|
6000
|
+
thought,
|
|
6001
|
+
action,
|
|
6002
|
+
ref: normalizedRef,
|
|
6003
|
+
value,
|
|
6004
|
+
ok: res.success === true,
|
|
6005
|
+
stale: res.stale,
|
|
6006
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6007
|
+
screenHash
|
|
6008
|
+
};
|
|
6009
|
+
steps.push(record);
|
|
6010
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6011
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6012
|
+
const last3 = steps.slice(-3);
|
|
6013
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6014
|
+
status = "blocked";
|
|
6015
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6016
|
+
break;
|
|
6017
|
+
}
|
|
6018
|
+
}
|
|
6019
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6020
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6021
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6022
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6023
|
+
return ok26(data, normalizeTips5([
|
|
6024
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6025
|
+
]));
|
|
6026
|
+
}
|
|
6027
|
+
});
|
|
6028
|
+
|
|
6029
|
+
// src/commands/tab.ts
|
|
6030
|
+
import { z as z28 } from "zod";
|
|
6031
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6032
|
+
var TabParams = z28.object({
|
|
6033
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6034
|
+
url: z28.string().optional(),
|
|
6035
|
+
index: z28.number().int().min(0).optional()
|
|
5865
6036
|
});
|
|
5866
6037
|
var tabCommand = registerCommand({
|
|
5867
6038
|
name: "tab",
|
|
5868
6039
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5869
6040
|
scope: "page",
|
|
5870
6041
|
parameters: TabParams,
|
|
5871
|
-
result:
|
|
5872
|
-
success:
|
|
5873
|
-
data:
|
|
6042
|
+
result: z28.object({
|
|
6043
|
+
success: z28.boolean(),
|
|
6044
|
+
data: z28.unknown()
|
|
5874
6045
|
}),
|
|
5875
6046
|
handler: async (p, ctx) => {
|
|
5876
6047
|
if (!ctx.browserContext) {
|
|
5877
|
-
return
|
|
6048
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
5878
6049
|
}
|
|
5879
6050
|
const pages = ctx.browserContext.pages();
|
|
5880
6051
|
switch (p.subcommand) {
|
|
@@ -5887,7 +6058,7 @@ var tabCommand = registerCommand({
|
|
|
5887
6058
|
case "switch":
|
|
5888
6059
|
return handleSwitch(p, pages, ctx);
|
|
5889
6060
|
default:
|
|
5890
|
-
return
|
|
6061
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
5891
6062
|
}
|
|
5892
6063
|
}
|
|
5893
6064
|
});
|
|
@@ -5902,7 +6073,7 @@ async function handleList(pages, ctx) {
|
|
|
5902
6073
|
if (isActive) activeIndex = i;
|
|
5903
6074
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5904
6075
|
}
|
|
5905
|
-
return
|
|
6076
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
5906
6077
|
}
|
|
5907
6078
|
async function handleNew(p, _pages, ctx) {
|
|
5908
6079
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5930,7 +6101,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5930
6101
|
const title = await newPage.title().catch(() => "");
|
|
5931
6102
|
const allPages = ctx.browserContext.pages();
|
|
5932
6103
|
const newIndex = allPages.indexOf(newPage);
|
|
5933
|
-
return
|
|
6104
|
+
return ok27({
|
|
5934
6105
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5935
6106
|
url: newPage.url(),
|
|
5936
6107
|
title,
|
|
@@ -5941,11 +6112,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5941
6112
|
async function handleClose(p, ctx) {
|
|
5942
6113
|
const currentPages = ctx.browserContext.pages();
|
|
5943
6114
|
if (currentPages.length <= 1) {
|
|
5944
|
-
return
|
|
6115
|
+
return fail13("Cannot close the last remaining tab");
|
|
5945
6116
|
}
|
|
5946
6117
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5947
6118
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5948
|
-
return
|
|
6119
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5949
6120
|
}
|
|
5950
6121
|
const pageToClose = currentPages[closeIndex];
|
|
5951
6122
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5960,7 +6131,7 @@ async function handleClose(p, ctx) {
|
|
|
5960
6131
|
}
|
|
5961
6132
|
ctx.page = newActivePage;
|
|
5962
6133
|
}
|
|
5963
|
-
return
|
|
6134
|
+
return ok27({
|
|
5964
6135
|
closedIndex: closeIndex,
|
|
5965
6136
|
total: remainingPages.length,
|
|
5966
6137
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5968,10 +6139,10 @@ async function handleClose(p, ctx) {
|
|
|
5968
6139
|
}
|
|
5969
6140
|
async function handleSwitch(p, pages, ctx) {
|
|
5970
6141
|
if (p.index === void 0) {
|
|
5971
|
-
return
|
|
6142
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
5972
6143
|
}
|
|
5973
6144
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5974
|
-
return
|
|
6145
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5975
6146
|
}
|
|
5976
6147
|
const targetPage = pages[p.index];
|
|
5977
6148
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5993,7 +6164,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5993
6164
|
}
|
|
5994
6165
|
ctx.page = targetPage;
|
|
5995
6166
|
const title = await targetPage.title().catch(() => "");
|
|
5996
|
-
return
|
|
6167
|
+
return ok27({
|
|
5997
6168
|
index: p.index,
|
|
5998
6169
|
url: targetPage.url(),
|
|
5999
6170
|
title,
|
|
@@ -6002,8 +6173,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6002
6173
|
}
|
|
6003
6174
|
|
|
6004
6175
|
// src/commands/addinitscript.ts
|
|
6005
|
-
import { z as
|
|
6006
|
-
import { ok as
|
|
6176
|
+
import { z as z29 } from "zod";
|
|
6177
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6007
6178
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6008
6179
|
|
|
6009
6180
|
// src/chain-parser.ts
|
|
@@ -6144,14 +6315,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6144
6315
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6145
6316
|
|
|
6146
6317
|
// src/commands/addinitscript.ts
|
|
6147
|
-
var InitScriptParams =
|
|
6148
|
-
script:
|
|
6149
|
-
file:
|
|
6150
|
-
stdin:
|
|
6151
|
-
name:
|
|
6152
|
-
list:
|
|
6153
|
-
remove:
|
|
6154
|
-
base64:
|
|
6318
|
+
var InitScriptParams = z29.object({
|
|
6319
|
+
script: z29.string().optional(),
|
|
6320
|
+
file: z29.string().optional(),
|
|
6321
|
+
stdin: z29.boolean().optional(),
|
|
6322
|
+
name: z29.string().optional(),
|
|
6323
|
+
list: z29.boolean().optional(),
|
|
6324
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6325
|
+
base64: z29.string().optional()
|
|
6155
6326
|
});
|
|
6156
6327
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6157
6328
|
function resolveScriptContent(params) {
|
|
@@ -6185,14 +6356,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6185
6356
|
description: "Add an initialization script that runs on every page load",
|
|
6186
6357
|
scope: "page",
|
|
6187
6358
|
parameters: InitScriptParams,
|
|
6188
|
-
result:
|
|
6189
|
-
scripts:
|
|
6190
|
-
removed:
|
|
6191
|
-
existed:
|
|
6192
|
-
error:
|
|
6193
|
-
registered:
|
|
6194
|
-
hint:
|
|
6195
|
-
executedImmediately:
|
|
6359
|
+
result: z29.object({
|
|
6360
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6361
|
+
removed: z29.string().optional(),
|
|
6362
|
+
existed: z29.boolean().optional(),
|
|
6363
|
+
error: z29.string().optional(),
|
|
6364
|
+
registered: z29.string().optional(),
|
|
6365
|
+
hint: z29.string().optional(),
|
|
6366
|
+
executedImmediately: z29.boolean().optional()
|
|
6196
6367
|
}).passthrough(),
|
|
6197
6368
|
handler: async (params, ctx) => {
|
|
6198
6369
|
if (params.list) {
|
|
@@ -6201,20 +6372,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6201
6372
|
size: content2.length,
|
|
6202
6373
|
preview: content2.slice(0, 80)
|
|
6203
6374
|
}));
|
|
6204
|
-
return
|
|
6375
|
+
return ok28({ scripts });
|
|
6205
6376
|
}
|
|
6206
6377
|
if (params.remove && typeof params.remove === "string") {
|
|
6207
6378
|
const existed = registeredScripts.delete(params.remove);
|
|
6208
|
-
return
|
|
6379
|
+
return ok28({ removed: params.remove, existed });
|
|
6209
6380
|
}
|
|
6210
6381
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6211
6382
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6212
6383
|
const existed = registeredScripts.delete(removeTarget);
|
|
6213
|
-
return
|
|
6384
|
+
return ok28({ removed: removeTarget, existed });
|
|
6214
6385
|
}
|
|
6215
6386
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6216
6387
|
if (!content) {
|
|
6217
|
-
return
|
|
6388
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6218
6389
|
}
|
|
6219
6390
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6220
6391
|
registeredScripts.set(scriptName, content);
|
|
@@ -6222,45 +6393,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6222
6393
|
try {
|
|
6223
6394
|
await ctx.page.evaluate(content);
|
|
6224
6395
|
} catch {
|
|
6225
|
-
return
|
|
6396
|
+
return ok28({
|
|
6226
6397
|
registered: scriptName,
|
|
6227
6398
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6228
6399
|
});
|
|
6229
6400
|
}
|
|
6230
|
-
return
|
|
6401
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6231
6402
|
}
|
|
6232
6403
|
});
|
|
6233
6404
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6234
6405
|
|
|
6235
6406
|
// src/commands/find.ts
|
|
6236
|
-
import { z as
|
|
6237
|
-
import { ok as
|
|
6238
|
-
var actionSchema2 =
|
|
6407
|
+
import { z as z30 } from "zod";
|
|
6408
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6409
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6239
6410
|
var findCommand = registerCommand({
|
|
6240
6411
|
name: "find",
|
|
6241
6412
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6242
6413
|
scope: "page",
|
|
6243
|
-
parameters:
|
|
6244
|
-
strategy:
|
|
6245
|
-
value:
|
|
6246
|
-
name:
|
|
6247
|
-
exact:
|
|
6248
|
-
operation:
|
|
6414
|
+
parameters: z30.object({
|
|
6415
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6416
|
+
value: z30.string(),
|
|
6417
|
+
name: z30.string().optional(),
|
|
6418
|
+
exact: z30.boolean().optional().default(false),
|
|
6419
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6249
6420
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6250
|
-
actionValue:
|
|
6251
|
-
index:
|
|
6252
|
-
click:
|
|
6253
|
-
fill:
|
|
6254
|
-
type:
|
|
6255
|
-
select:
|
|
6256
|
-
hover:
|
|
6257
|
-
check:
|
|
6258
|
-
timeout:
|
|
6421
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6422
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6423
|
+
click: z30.boolean().optional().default(false),
|
|
6424
|
+
fill: z30.string().optional(),
|
|
6425
|
+
type: z30.string().optional(),
|
|
6426
|
+
select: z30.string().optional(),
|
|
6427
|
+
hover: z30.boolean().optional().default(false),
|
|
6428
|
+
check: z30.boolean().optional().default(false),
|
|
6429
|
+
timeout: z30.number().optional().default(1e4)
|
|
6259
6430
|
}),
|
|
6260
|
-
result:
|
|
6261
|
-
matched:
|
|
6262
|
-
selector:
|
|
6263
|
-
action:
|
|
6431
|
+
result: z30.object({
|
|
6432
|
+
matched: z30.number(),
|
|
6433
|
+
selector: z30.string(),
|
|
6434
|
+
action: z30.string().optional()
|
|
6264
6435
|
}),
|
|
6265
6436
|
handler: async (p, ctx) => {
|
|
6266
6437
|
const page = ctx.page;
|
|
@@ -6275,7 +6446,7 @@ var findCommand = registerCommand({
|
|
|
6275
6446
|
});
|
|
6276
6447
|
const count = await locator.count();
|
|
6277
6448
|
if (count === 0) {
|
|
6278
|
-
return
|
|
6449
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6279
6450
|
}
|
|
6280
6451
|
const tips = [];
|
|
6281
6452
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6287,15 +6458,15 @@ var findCommand = registerCommand({
|
|
|
6287
6458
|
await target.click({ timeout: p.timeout, force: true });
|
|
6288
6459
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6289
6460
|
} else if (actionName === "fill") {
|
|
6290
|
-
if (actionValue === void 0) return
|
|
6461
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6291
6462
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6292
6463
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6293
6464
|
} else if (actionName === "type") {
|
|
6294
|
-
if (actionValue === void 0) return
|
|
6465
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6295
6466
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6296
6467
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6297
6468
|
} else if (actionName === "select") {
|
|
6298
|
-
if (actionValue === void 0) return
|
|
6469
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6299
6470
|
await target.selectOption(actionValue);
|
|
6300
6471
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6301
6472
|
} else if (actionName === "hover") {
|
|
@@ -6309,8 +6480,8 @@ var findCommand = registerCommand({
|
|
|
6309
6480
|
}
|
|
6310
6481
|
});
|
|
6311
6482
|
function okWithTips(data, tips) {
|
|
6312
|
-
const result =
|
|
6313
|
-
if (tips.length > 0) result.tips =
|
|
6483
|
+
const result = ok29(data);
|
|
6484
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6314
6485
|
return result;
|
|
6315
6486
|
}
|
|
6316
6487
|
function parseOperation(operation) {
|
|
@@ -6408,8 +6579,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6408
6579
|
}
|
|
6409
6580
|
|
|
6410
6581
|
// src/commands/visual-tag.ts
|
|
6411
|
-
import { z as
|
|
6412
|
-
import { ok as
|
|
6582
|
+
import { z as z31 } from "zod";
|
|
6583
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6413
6584
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6414
6585
|
var TAG_SCRIPT = `
|
|
6415
6586
|
(function() {
|
|
@@ -6500,49 +6671,49 @@ var visualTagCommand = registerCommand({
|
|
|
6500
6671
|
name: "visual-tag",
|
|
6501
6672
|
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",
|
|
6502
6673
|
scope: "page",
|
|
6503
|
-
parameters:
|
|
6504
|
-
action:
|
|
6505
|
-
id:
|
|
6674
|
+
parameters: z31.object({
|
|
6675
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6676
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6506
6677
|
}),
|
|
6507
|
-
result:
|
|
6508
|
-
action:
|
|
6509
|
-
tagged:
|
|
6510
|
-
id:
|
|
6511
|
-
element:
|
|
6678
|
+
result: z31.object({
|
|
6679
|
+
action: z31.string(),
|
|
6680
|
+
tagged: z31.number().optional(),
|
|
6681
|
+
id: z31.string().optional(),
|
|
6682
|
+
element: z31.record(z31.unknown()).optional()
|
|
6512
6683
|
}),
|
|
6513
6684
|
handler: async (p, ctx) => {
|
|
6514
6685
|
switch (p.action) {
|
|
6515
6686
|
case "tag": {
|
|
6516
6687
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6517
6688
|
const parsed = JSON.parse(result);
|
|
6518
|
-
return
|
|
6689
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6519
6690
|
}
|
|
6520
6691
|
case "lookup": {
|
|
6521
|
-
if (!p.id) return
|
|
6692
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6522
6693
|
const result = await ctx.page.evaluate(
|
|
6523
6694
|
`(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'}); })()`
|
|
6524
6695
|
);
|
|
6525
6696
|
const parsed = JSON.parse(result);
|
|
6526
|
-
if (parsed.err) return
|
|
6527
|
-
return
|
|
6697
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6698
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6528
6699
|
}
|
|
6529
6700
|
case "list": {
|
|
6530
6701
|
const result = await ctx.page.evaluate(
|
|
6531
6702
|
`(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); })()`
|
|
6532
6703
|
);
|
|
6533
|
-
return
|
|
6704
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6534
6705
|
}
|
|
6535
6706
|
case "clear": {
|
|
6536
6707
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6537
|
-
return
|
|
6708
|
+
return ok30({ action: "clear" });
|
|
6538
6709
|
}
|
|
6539
6710
|
}
|
|
6540
6711
|
}
|
|
6541
6712
|
});
|
|
6542
6713
|
|
|
6543
6714
|
// src/commands/visual-tag-v2.ts
|
|
6544
|
-
import { z as
|
|
6545
|
-
import { ok as
|
|
6715
|
+
import { z as z32 } from "zod";
|
|
6716
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6546
6717
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6547
6718
|
var TAG_V2_SCRIPT = `
|
|
6548
6719
|
(function() {
|
|
@@ -6889,45 +7060,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6889
7060
|
name: "visual-tag-v2",
|
|
6890
7061
|
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",
|
|
6891
7062
|
scope: "page",
|
|
6892
|
-
parameters:
|
|
6893
|
-
action:
|
|
6894
|
-
id:
|
|
6895
|
-
query:
|
|
6896
|
-
type:
|
|
6897
|
-
"interact-action":
|
|
6898
|
-
value:
|
|
7063
|
+
parameters: z32.object({
|
|
7064
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7065
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7066
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7067
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7068
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7069
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6899
7070
|
}),
|
|
6900
|
-
result:
|
|
6901
|
-
action:
|
|
6902
|
-
total:
|
|
6903
|
-
byType:
|
|
6904
|
-
element:
|
|
7071
|
+
result: z32.object({
|
|
7072
|
+
action: z32.string(),
|
|
7073
|
+
total: z32.number().optional(),
|
|
7074
|
+
byType: z32.record(z32.number()).optional(),
|
|
7075
|
+
element: z32.record(z32.unknown()).optional()
|
|
6905
7076
|
}),
|
|
6906
7077
|
handler: async (p, ctx) => {
|
|
6907
7078
|
switch (p.action) {
|
|
6908
7079
|
case "tag": {
|
|
6909
7080
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6910
7081
|
const parsed = JSON.parse(result);
|
|
6911
|
-
return
|
|
7082
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6912
7083
|
}
|
|
6913
7084
|
case "lookup": {
|
|
6914
|
-
if (!p.id) return
|
|
7085
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6915
7086
|
const result = await ctx.page.evaluate(
|
|
6916
7087
|
`(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'})})()`
|
|
6917
7088
|
);
|
|
6918
7089
|
const parsed = JSON.parse(result);
|
|
6919
|
-
if (parsed.err) return
|
|
6920
|
-
return
|
|
7090
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7091
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6921
7092
|
}
|
|
6922
7093
|
case "by-type": {
|
|
6923
7094
|
const result = await ctx.page.evaluate(
|
|
6924
7095
|
`(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)})()`
|
|
6925
7096
|
);
|
|
6926
|
-
return
|
|
7097
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6927
7098
|
}
|
|
6928
7099
|
case "find": {
|
|
6929
7100
|
const query = p.query;
|
|
6930
|
-
if (!query) return
|
|
7101
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6931
7102
|
const result = await ctx.page.evaluate(
|
|
6932
7103
|
`(function(){
|
|
6933
7104
|
var map = window.__xbTagSerializable;
|
|
@@ -6969,21 +7140,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6969
7140
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6970
7141
|
})()`
|
|
6971
7142
|
);
|
|
6972
|
-
return
|
|
7143
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
6973
7144
|
}
|
|
6974
7145
|
case "stats": {
|
|
6975
7146
|
const result = await ctx.page.evaluate(
|
|
6976
7147
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6977
7148
|
);
|
|
6978
|
-
return
|
|
7149
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
6979
7150
|
}
|
|
6980
7151
|
case "interact": {
|
|
6981
7152
|
const query = p.query;
|
|
6982
7153
|
const pAny = p;
|
|
6983
7154
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6984
7155
|
const value = pAny.value;
|
|
6985
|
-
if (!query) return
|
|
6986
|
-
if (!action) return
|
|
7156
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7157
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6987
7158
|
const findResult = await ctx.page.evaluate(
|
|
6988
7159
|
`(function(){
|
|
6989
7160
|
var map = window.__xbTagSerializable;
|
|
@@ -7013,11 +7184,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7013
7184
|
})()`
|
|
7014
7185
|
);
|
|
7015
7186
|
const parsed = JSON.parse(findResult);
|
|
7016
|
-
if (parsed.err) return
|
|
7017
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7187
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7188
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7018
7189
|
const target = parsed.results[0];
|
|
7019
7190
|
if (action === "read") {
|
|
7020
|
-
return
|
|
7191
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7021
7192
|
}
|
|
7022
7193
|
if (action === "click") {
|
|
7023
7194
|
const el = await ctx.page.evaluate(
|
|
@@ -7030,12 +7201,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7030
7201
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7031
7202
|
})()`
|
|
7032
7203
|
);
|
|
7033
|
-
if (!el) return
|
|
7204
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7034
7205
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7035
|
-
return
|
|
7206
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7036
7207
|
}
|
|
7037
7208
|
if (action === "fill") {
|
|
7038
|
-
if (!value) return
|
|
7209
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7039
7210
|
const el = await ctx.page.evaluate(
|
|
7040
7211
|
`(function(){
|
|
7041
7212
|
var map = window.__xbTagMap;
|
|
@@ -7046,12 +7217,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7046
7217
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7047
7218
|
})()`
|
|
7048
7219
|
);
|
|
7049
|
-
if (!el) return
|
|
7220
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7050
7221
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7051
7222
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7052
|
-
return
|
|
7223
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7053
7224
|
}
|
|
7054
|
-
return
|
|
7225
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7055
7226
|
}
|
|
7056
7227
|
case "export": {
|
|
7057
7228
|
const result = await ctx.page.evaluate(
|
|
@@ -7099,12 +7270,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7099
7270
|
})()`
|
|
7100
7271
|
);
|
|
7101
7272
|
const parsed = JSON.parse(result);
|
|
7102
|
-
if (parsed.err) return
|
|
7103
|
-
return
|
|
7273
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7274
|
+
return ok31({ action: "export", element: parsed });
|
|
7104
7275
|
}
|
|
7105
7276
|
case "clear": {
|
|
7106
7277
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7107
|
-
return
|
|
7278
|
+
return ok31({ action: "clear" });
|
|
7108
7279
|
}
|
|
7109
7280
|
}
|
|
7110
7281
|
}
|
|
@@ -7981,7 +8152,10 @@ function buildSnapshot(elements) {
|
|
|
7981
8152
|
}
|
|
7982
8153
|
|
|
7983
8154
|
// src/tips/index.ts
|
|
7984
|
-
|
|
8155
|
+
function tipsDebounceMs() {
|
|
8156
|
+
const v = parseInt(process.env.XBROWSER_TIPS_DEBOUNCE ?? "120", 10);
|
|
8157
|
+
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
8158
|
+
}
|
|
7985
8159
|
var SKIP_DETECT_COMMANDS = /* @__PURE__ */ new Set([
|
|
7986
8160
|
"goto",
|
|
7987
8161
|
// 导航命令不需要检测
|
|
@@ -8073,7 +8247,9 @@ var TipsManager = class {
|
|
|
8073
8247
|
}
|
|
8074
8248
|
}
|
|
8075
8249
|
debounce() {
|
|
8076
|
-
|
|
8250
|
+
const ms = tipsDebounceMs();
|
|
8251
|
+
if (ms <= 0) return Promise.resolve();
|
|
8252
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
8077
8253
|
}
|
|
8078
8254
|
formatTips(tips) {
|
|
8079
8255
|
return tips.map((tip) => {
|
|
@@ -8242,7 +8418,7 @@ async function guardCheck(commandName) {
|
|
|
8242
8418
|
}
|
|
8243
8419
|
}
|
|
8244
8420
|
function errorResult(message) {
|
|
8245
|
-
return { ...
|
|
8421
|
+
return { ...fail17(message), duration: 0 };
|
|
8246
8422
|
}
|
|
8247
8423
|
function tipsToMessages(tips) {
|
|
8248
8424
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8319,7 +8495,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8319
8495
|
}
|
|
8320
8496
|
let targetPageOverride = null;
|
|
8321
8497
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
8322
|
-
const { findTargetPage } = await import("./browser-
|
|
8498
|
+
const { findTargetPage } = await import("./browser-NYYCR4O7.js");
|
|
8323
8499
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
8324
8500
|
if (!targetPageOverride) {
|
|
8325
8501
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8431,7 +8607,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8431
8607
|
const cache = /* @__PURE__ */ new Map();
|
|
8432
8608
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
8433
8609
|
if (resolved.tips.length > 0) {
|
|
8434
|
-
refTips =
|
|
8610
|
+
refTips = normalizeTips7(resolved.tips);
|
|
8435
8611
|
params = resolved.params;
|
|
8436
8612
|
}
|
|
8437
8613
|
}
|
|
@@ -8499,8 +8675,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8499
8675
|
}
|
|
8500
8676
|
const merged = [
|
|
8501
8677
|
...raw.tips || [],
|
|
8502
|
-
...
|
|
8503
|
-
...snapshotHint ?
|
|
8678
|
+
...normalizeTips7(smartTips),
|
|
8679
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8504
8680
|
...refTips
|
|
8505
8681
|
];
|
|
8506
8682
|
const isSuccess = raw.success !== false;
|
|
@@ -8515,7 +8691,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8515
8691
|
timestamp: start
|
|
8516
8692
|
});
|
|
8517
8693
|
if (isSuccess) {
|
|
8518
|
-
return { ...
|
|
8694
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8519
8695
|
}
|
|
8520
8696
|
const fc = classifyFailure(raw.message);
|
|
8521
8697
|
return {
|
|
@@ -8528,7 +8704,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8528
8704
|
...hookOutputs ? { hookOutputs } : {}
|
|
8529
8705
|
};
|
|
8530
8706
|
}
|
|
8531
|
-
const smartTipNormalized =
|
|
8707
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8532
8708
|
recordArchive(session?.id, sessionName, {
|
|
8533
8709
|
step: 0,
|
|
8534
8710
|
command: commandName,
|
|
@@ -8538,7 +8714,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8538
8714
|
duration,
|
|
8539
8715
|
timestamp: start
|
|
8540
8716
|
});
|
|
8541
|
-
return { ...
|
|
8717
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8542
8718
|
} catch (err) {
|
|
8543
8719
|
const end = Date.now();
|
|
8544
8720
|
const duration = end - start;
|
|
@@ -8583,7 +8759,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8583
8759
|
duration,
|
|
8584
8760
|
timestamp: start
|
|
8585
8761
|
});
|
|
8586
|
-
return { ...
|
|
8762
|
+
return { ...fail17(errorMessage), duration };
|
|
8587
8763
|
} finally {
|
|
8588
8764
|
}
|
|
8589
8765
|
}
|
|
@@ -8628,7 +8804,7 @@ async function executeChain(input, options) {
|
|
|
8628
8804
|
results.push({
|
|
8629
8805
|
command: cmdName,
|
|
8630
8806
|
raw: cmdStr,
|
|
8631
|
-
...
|
|
8807
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8632
8808
|
duration: 0
|
|
8633
8809
|
});
|
|
8634
8810
|
if (type === "and") {
|
|
@@ -8647,7 +8823,7 @@ async function executeChain(input, options) {
|
|
|
8647
8823
|
results.push({
|
|
8648
8824
|
command: cmdName,
|
|
8649
8825
|
raw: cmdStr,
|
|
8650
|
-
...
|
|
8826
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8651
8827
|
duration: 0
|
|
8652
8828
|
});
|
|
8653
8829
|
if (type === "and") {
|
|
@@ -8717,7 +8893,7 @@ async function executeChain(input, options) {
|
|
|
8717
8893
|
success: false,
|
|
8718
8894
|
data: data2,
|
|
8719
8895
|
message: loginGuard.message,
|
|
8720
|
-
tips:
|
|
8896
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
8721
8897
|
duration: duration3
|
|
8722
8898
|
});
|
|
8723
8899
|
if (type === "and") {
|
|
@@ -8759,7 +8935,7 @@ async function executeChain(input, options) {
|
|
|
8759
8935
|
results.push({
|
|
8760
8936
|
command: `${cmdName} ${subCommand}`,
|
|
8761
8937
|
raw: cmdStr,
|
|
8762
|
-
...
|
|
8938
|
+
...ok32(data),
|
|
8763
8939
|
duration: duration2,
|
|
8764
8940
|
...hookOutputs ? { hookOutputs } : {}
|
|
8765
8941
|
});
|
|
@@ -8787,7 +8963,7 @@ async function executeChain(input, options) {
|
|
|
8787
8963
|
results.push({
|
|
8788
8964
|
command: `${cmdName} ${subCommand}`,
|
|
8789
8965
|
raw: cmdStr,
|
|
8790
|
-
...
|
|
8966
|
+
...fail17(errorMessage),
|
|
8791
8967
|
duration: duration2
|
|
8792
8968
|
});
|
|
8793
8969
|
if (type === "and") {
|