@xbrowser/cli 1.26.0 → 1.28.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/{chunk-HDFQRDBC.js → chunk-OEC7ZSFW.js} +332 -146
- package/dist/{chunk-6OWOICQ3.js → chunk-WK3INZLA.js} +332 -146
- package/dist/cli.js +2 -2
- package/dist/daemon-main.js +335 -149
- package/dist/index.js +2 -2
- package/dist/{server-6KZ5NT6L.js → server-26SE6YZR.js} +1 -1
- package/dist/{server-65LCP6S6.js → server-JXF3JOAM.js} +1 -1
- package/package.json +1 -1
package/dist/daemon-main.js
CHANGED
|
@@ -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,
|
|
@@ -1305,9 +1305,12 @@ var visionTaskCommand = registerCommand({
|
|
|
1305
1305
|
} catch {
|
|
1306
1306
|
}
|
|
1307
1307
|
}
|
|
1308
|
-
const
|
|
1308
|
+
const shotQuality = Math.max(30, Math.min(95, parseInt(process.env.XBROWSER_VLM_SHOT_QUALITY ?? "75", 10) || 75));
|
|
1309
|
+
const buffer = await page.screenshot({ type: "jpeg", quality: shotQuality });
|
|
1309
1310
|
const b64 = buffer.toString("base64");
|
|
1310
|
-
const
|
|
1311
|
+
const vp = typeof page.viewportSize === "function" ? page.viewportSize() : null;
|
|
1312
|
+
const w = vp?.width ?? pngDims(b64).w;
|
|
1313
|
+
const h = vp?.height ?? pngDims(b64).h;
|
|
1311
1314
|
const obsText = [
|
|
1312
1315
|
`\u4EFB\u52A1\uFF1A${p.task}`,
|
|
1313
1316
|
`\u622A\u56FE\u5C3A\u5BF8\uFF1A${w}x${h}\uFF08\u5750\u6807\u539F\u70B9\uFF1A\u5DE6\u4E0A\u89D2\uFF09`,
|
|
@@ -1316,7 +1319,7 @@ var visionTaskCommand = registerCommand({
|
|
|
1316
1319
|
${history.slice(-6).join("\n")}` : "\u5C1A\u65E0\u52A8\u4F5C\u3002"
|
|
1317
1320
|
].join("\n");
|
|
1318
1321
|
const reply = await vlmAskRetry(creds, [
|
|
1319
|
-
{ type: "image", source: { type: "base64", media_type: "image/png", data: b64 } },
|
|
1322
|
+
{ type: "image", source: { type: "base64", media_type: shotQuality >= 100 ? "image/png" : "image/jpeg", data: b64 } },
|
|
1320
1323
|
{ type: "text", text: `${SYSTEM_PROMPT}
|
|
1321
1324
|
|
|
1322
1325
|
${obsText}` }
|
|
@@ -4760,6 +4763,25 @@ function getRefTarget(sessionKey2, ref) {
|
|
|
4760
4763
|
if (!session || !target) return null;
|
|
4761
4764
|
return { screenHash: session.screenHash, target };
|
|
4762
4765
|
}
|
|
4766
|
+
function inheritStableRefs(key, rawTargets) {
|
|
4767
|
+
const prev = sessions.get(key);
|
|
4768
|
+
if (!prev || prev.targets.size === 0) {
|
|
4769
|
+
return rawTargets.map((target, index) => ({ ...target, ref: `e${index + 1}` }));
|
|
4770
|
+
}
|
|
4771
|
+
const bySelector = /* @__PURE__ */ new Map();
|
|
4772
|
+
let maxId = 0;
|
|
4773
|
+
for (const [ref, target] of prev.targets) {
|
|
4774
|
+
bySelector.set(target.selector, ref);
|
|
4775
|
+
const id = Number(ref.slice(1));
|
|
4776
|
+
if (Number.isFinite(id) && id > maxId) maxId = id;
|
|
4777
|
+
}
|
|
4778
|
+
let next = maxId + 1;
|
|
4779
|
+
return rawTargets.map((target) => {
|
|
4780
|
+
const inherited = bySelector.get(target.selector);
|
|
4781
|
+
if (inherited) return { ...target, ref: inherited };
|
|
4782
|
+
return { ...target, ref: `e${next++}` };
|
|
4783
|
+
});
|
|
4784
|
+
}
|
|
4763
4785
|
|
|
4764
4786
|
// src/utils/resolve-selector.ts
|
|
4765
4787
|
function buildElementSelector(el) {
|
|
@@ -5384,10 +5406,7 @@ async function observePage(page, sessionId, options = {}) {
|
|
|
5384
5406
|
{ includeHidden: !!options.includeHidden, limit: options.limit ?? 80 }
|
|
5385
5407
|
)
|
|
5386
5408
|
]);
|
|
5387
|
-
const targets =
|
|
5388
|
-
ref: `e${index + 1}`,
|
|
5389
|
-
...target
|
|
5390
|
-
}));
|
|
5409
|
+
const targets = inheritStableRefs(sessionKey(sessionId), raw.targets);
|
|
5391
5410
|
replaceRefs(sessionKey(sessionId), raw.screenHash, targets);
|
|
5392
5411
|
return {
|
|
5393
5412
|
url: page.url(),
|
|
@@ -5879,26 +5898,193 @@ var waitForCommand = registerCommand({
|
|
|
5879
5898
|
}
|
|
5880
5899
|
});
|
|
5881
5900
|
|
|
5882
|
-
// src/commands/
|
|
5901
|
+
// src/commands/task.ts
|
|
5883
5902
|
import { z as z27 } from "zod";
|
|
5884
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5885
|
-
var
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5903
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5904
|
+
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
|
|
5905
|
+
|
|
5906
|
+
\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
|
|
5907
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5908
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5909
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5910
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5911
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5912
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5913
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5914
|
+
|
|
5915
|
+
\u89C4\u5219\uFF1A
|
|
5916
|
+
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
|
|
5917
|
+
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
|
|
5918
|
+
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`;
|
|
5919
|
+
function extractDecision(raw) {
|
|
5920
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
5921
|
+
const start = s.indexOf("{");
|
|
5922
|
+
if (start < 0) return null;
|
|
5923
|
+
let depth = 0;
|
|
5924
|
+
for (let i = start; i < s.length; i++) {
|
|
5925
|
+
if (s[i] === "{") depth++;
|
|
5926
|
+
else if (s[i] === "}") {
|
|
5927
|
+
depth--;
|
|
5928
|
+
if (depth === 0) {
|
|
5929
|
+
try {
|
|
5930
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
5931
|
+
} catch {
|
|
5932
|
+
return null;
|
|
5933
|
+
}
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
}
|
|
5937
|
+
return null;
|
|
5938
|
+
}
|
|
5939
|
+
var taskCommand = registerCommand({
|
|
5940
|
+
name: "task",
|
|
5941
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
5942
|
+
scope: "page",
|
|
5943
|
+
parameters: z27.object({
|
|
5944
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
5945
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
5946
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
5947
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
5948
|
+
}),
|
|
5949
|
+
result: z27.object({
|
|
5950
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
5951
|
+
summary: z27.string().optional(),
|
|
5952
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
5953
|
+
finalUrl: z27.string().optional(),
|
|
5954
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
5955
|
+
}).passthrough(),
|
|
5956
|
+
handler: async (p, ctx) => {
|
|
5957
|
+
const creds = loadVLMCredentials2();
|
|
5958
|
+
if (!creds) {
|
|
5959
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
5960
|
+
}
|
|
5961
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
5962
|
+
const started = Date.now();
|
|
5963
|
+
const steps = [];
|
|
5964
|
+
const history = [];
|
|
5965
|
+
let llmCalls = 0;
|
|
5966
|
+
let status = "max_steps";
|
|
5967
|
+
let summary = "";
|
|
5968
|
+
let lastError = "";
|
|
5969
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
5970
|
+
if (Date.now() - started > p.timeout) {
|
|
5971
|
+
status = "blocked";
|
|
5972
|
+
summary = `timeout after ${step - 1} steps`;
|
|
5973
|
+
break;
|
|
5974
|
+
}
|
|
5975
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
5976
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
5977
|
+
const screenHash = obs.screenHash;
|
|
5978
|
+
const userPayload = [
|
|
5979
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
5980
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
5981
|
+
compact,
|
|
5982
|
+
history.length ? `
|
|
5983
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
5984
|
+
${history.slice(-6).join("\n")}` : ""
|
|
5985
|
+
].filter(Boolean).join("\n");
|
|
5986
|
+
let raw = "";
|
|
5987
|
+
try {
|
|
5988
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
5989
|
+
|
|
5990
|
+
---
|
|
5991
|
+
|
|
5992
|
+
${userPayload}` }], 900);
|
|
5993
|
+
llmCalls++;
|
|
5994
|
+
} catch (e) {
|
|
5995
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
5996
|
+
status = "error";
|
|
5997
|
+
summary = `LLM call failed: ${lastError}`;
|
|
5998
|
+
break;
|
|
5999
|
+
}
|
|
6000
|
+
const decision = extractDecision(raw);
|
|
6001
|
+
if (!decision || typeof decision.action !== "string") {
|
|
6002
|
+
status = "blocked";
|
|
6003
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
6004
|
+
break;
|
|
6005
|
+
}
|
|
6006
|
+
const action = decision.action;
|
|
6007
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
6008
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
6009
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
6010
|
+
if (action === "done") {
|
|
6011
|
+
status = "done";
|
|
6012
|
+
summary = value || thought || "task done";
|
|
6013
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
6014
|
+
break;
|
|
6015
|
+
}
|
|
6016
|
+
if (action === "blocked") {
|
|
6017
|
+
status = "blocked";
|
|
6018
|
+
summary = value || thought || "LLM judged blocked";
|
|
6019
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
6020
|
+
break;
|
|
6021
|
+
}
|
|
6022
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
6023
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
6024
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
6025
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
6026
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
6027
|
+
continue;
|
|
6028
|
+
}
|
|
6029
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
6030
|
+
action,
|
|
6031
|
+
ref: normalizedRef,
|
|
6032
|
+
value,
|
|
6033
|
+
selector: void 0,
|
|
6034
|
+
force: false,
|
|
6035
|
+
timeout: 1e4
|
|
6036
|
+
});
|
|
6037
|
+
const record = {
|
|
6038
|
+
step,
|
|
6039
|
+
thought,
|
|
6040
|
+
action,
|
|
6041
|
+
ref: normalizedRef,
|
|
6042
|
+
value,
|
|
6043
|
+
ok: res.success === true,
|
|
6044
|
+
stale: res.stale,
|
|
6045
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6046
|
+
screenHash
|
|
6047
|
+
};
|
|
6048
|
+
steps.push(record);
|
|
6049
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6050
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6051
|
+
const last3 = steps.slice(-3);
|
|
6052
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6053
|
+
status = "blocked";
|
|
6054
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6055
|
+
break;
|
|
6056
|
+
}
|
|
6057
|
+
}
|
|
6058
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6059
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6060
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6061
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6062
|
+
return ok26(data, normalizeTips5([
|
|
6063
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6064
|
+
]));
|
|
6065
|
+
}
|
|
6066
|
+
});
|
|
6067
|
+
|
|
6068
|
+
// src/commands/tab.ts
|
|
6069
|
+
import { z as z28 } from "zod";
|
|
6070
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6071
|
+
var TabParams = z28.object({
|
|
6072
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6073
|
+
url: z28.string().optional(),
|
|
6074
|
+
index: z28.number().int().min(0).optional()
|
|
5889
6075
|
});
|
|
5890
6076
|
var tabCommand = registerCommand({
|
|
5891
6077
|
name: "tab",
|
|
5892
6078
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5893
6079
|
scope: "page",
|
|
5894
6080
|
parameters: TabParams,
|
|
5895
|
-
result:
|
|
5896
|
-
success:
|
|
5897
|
-
data:
|
|
6081
|
+
result: z28.object({
|
|
6082
|
+
success: z28.boolean(),
|
|
6083
|
+
data: z28.unknown()
|
|
5898
6084
|
}),
|
|
5899
6085
|
handler: async (p, ctx) => {
|
|
5900
6086
|
if (!ctx.browserContext) {
|
|
5901
|
-
return
|
|
6087
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
5902
6088
|
}
|
|
5903
6089
|
const pages = ctx.browserContext.pages();
|
|
5904
6090
|
switch (p.subcommand) {
|
|
@@ -5911,7 +6097,7 @@ var tabCommand = registerCommand({
|
|
|
5911
6097
|
case "switch":
|
|
5912
6098
|
return handleSwitch(p, pages, ctx);
|
|
5913
6099
|
default:
|
|
5914
|
-
return
|
|
6100
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
5915
6101
|
}
|
|
5916
6102
|
}
|
|
5917
6103
|
});
|
|
@@ -5926,7 +6112,7 @@ async function handleList(pages, ctx) {
|
|
|
5926
6112
|
if (isActive) activeIndex = i;
|
|
5927
6113
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5928
6114
|
}
|
|
5929
|
-
return
|
|
6115
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
5930
6116
|
}
|
|
5931
6117
|
async function handleNew(p, _pages, ctx) {
|
|
5932
6118
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5954,7 +6140,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5954
6140
|
const title = await newPage.title().catch(() => "");
|
|
5955
6141
|
const allPages = ctx.browserContext.pages();
|
|
5956
6142
|
const newIndex = allPages.indexOf(newPage);
|
|
5957
|
-
return
|
|
6143
|
+
return ok27({
|
|
5958
6144
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5959
6145
|
url: newPage.url(),
|
|
5960
6146
|
title,
|
|
@@ -5965,11 +6151,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5965
6151
|
async function handleClose(p, ctx) {
|
|
5966
6152
|
const currentPages = ctx.browserContext.pages();
|
|
5967
6153
|
if (currentPages.length <= 1) {
|
|
5968
|
-
return
|
|
6154
|
+
return fail13("Cannot close the last remaining tab");
|
|
5969
6155
|
}
|
|
5970
6156
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5971
6157
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5972
|
-
return
|
|
6158
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5973
6159
|
}
|
|
5974
6160
|
const pageToClose = currentPages[closeIndex];
|
|
5975
6161
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5984,7 +6170,7 @@ async function handleClose(p, ctx) {
|
|
|
5984
6170
|
}
|
|
5985
6171
|
ctx.page = newActivePage;
|
|
5986
6172
|
}
|
|
5987
|
-
return
|
|
6173
|
+
return ok27({
|
|
5988
6174
|
closedIndex: closeIndex,
|
|
5989
6175
|
total: remainingPages.length,
|
|
5990
6176
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5992,10 +6178,10 @@ async function handleClose(p, ctx) {
|
|
|
5992
6178
|
}
|
|
5993
6179
|
async function handleSwitch(p, pages, ctx) {
|
|
5994
6180
|
if (p.index === void 0) {
|
|
5995
|
-
return
|
|
6181
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
5996
6182
|
}
|
|
5997
6183
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5998
|
-
return
|
|
6184
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5999
6185
|
}
|
|
6000
6186
|
const targetPage = pages[p.index];
|
|
6001
6187
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -6017,7 +6203,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6017
6203
|
}
|
|
6018
6204
|
ctx.page = targetPage;
|
|
6019
6205
|
const title = await targetPage.title().catch(() => "");
|
|
6020
|
-
return
|
|
6206
|
+
return ok27({
|
|
6021
6207
|
index: p.index,
|
|
6022
6208
|
url: targetPage.url(),
|
|
6023
6209
|
title,
|
|
@@ -6026,8 +6212,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6026
6212
|
}
|
|
6027
6213
|
|
|
6028
6214
|
// src/commands/addinitscript.ts
|
|
6029
|
-
import { z as
|
|
6030
|
-
import { ok as
|
|
6215
|
+
import { z as z29 } from "zod";
|
|
6216
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6031
6217
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6032
6218
|
|
|
6033
6219
|
// src/chain-parser.ts
|
|
@@ -6168,14 +6354,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6168
6354
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6169
6355
|
|
|
6170
6356
|
// src/commands/addinitscript.ts
|
|
6171
|
-
var InitScriptParams =
|
|
6172
|
-
script:
|
|
6173
|
-
file:
|
|
6174
|
-
stdin:
|
|
6175
|
-
name:
|
|
6176
|
-
list:
|
|
6177
|
-
remove:
|
|
6178
|
-
base64:
|
|
6357
|
+
var InitScriptParams = z29.object({
|
|
6358
|
+
script: z29.string().optional(),
|
|
6359
|
+
file: z29.string().optional(),
|
|
6360
|
+
stdin: z29.boolean().optional(),
|
|
6361
|
+
name: z29.string().optional(),
|
|
6362
|
+
list: z29.boolean().optional(),
|
|
6363
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6364
|
+
base64: z29.string().optional()
|
|
6179
6365
|
});
|
|
6180
6366
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6181
6367
|
function resolveScriptContent(params) {
|
|
@@ -6209,14 +6395,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6209
6395
|
description: "Add an initialization script that runs on every page load",
|
|
6210
6396
|
scope: "page",
|
|
6211
6397
|
parameters: InitScriptParams,
|
|
6212
|
-
result:
|
|
6213
|
-
scripts:
|
|
6214
|
-
removed:
|
|
6215
|
-
existed:
|
|
6216
|
-
error:
|
|
6217
|
-
registered:
|
|
6218
|
-
hint:
|
|
6219
|
-
executedImmediately:
|
|
6398
|
+
result: z29.object({
|
|
6399
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6400
|
+
removed: z29.string().optional(),
|
|
6401
|
+
existed: z29.boolean().optional(),
|
|
6402
|
+
error: z29.string().optional(),
|
|
6403
|
+
registered: z29.string().optional(),
|
|
6404
|
+
hint: z29.string().optional(),
|
|
6405
|
+
executedImmediately: z29.boolean().optional()
|
|
6220
6406
|
}).passthrough(),
|
|
6221
6407
|
handler: async (params, ctx) => {
|
|
6222
6408
|
if (params.list) {
|
|
@@ -6225,20 +6411,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6225
6411
|
size: content2.length,
|
|
6226
6412
|
preview: content2.slice(0, 80)
|
|
6227
6413
|
}));
|
|
6228
|
-
return
|
|
6414
|
+
return ok28({ scripts });
|
|
6229
6415
|
}
|
|
6230
6416
|
if (params.remove && typeof params.remove === "string") {
|
|
6231
6417
|
const existed = registeredScripts.delete(params.remove);
|
|
6232
|
-
return
|
|
6418
|
+
return ok28({ removed: params.remove, existed });
|
|
6233
6419
|
}
|
|
6234
6420
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6235
6421
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6236
6422
|
const existed = registeredScripts.delete(removeTarget);
|
|
6237
|
-
return
|
|
6423
|
+
return ok28({ removed: removeTarget, existed });
|
|
6238
6424
|
}
|
|
6239
6425
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6240
6426
|
if (!content) {
|
|
6241
|
-
return
|
|
6427
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6242
6428
|
}
|
|
6243
6429
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6244
6430
|
registeredScripts.set(scriptName, content);
|
|
@@ -6246,45 +6432,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6246
6432
|
try {
|
|
6247
6433
|
await ctx.page.evaluate(content);
|
|
6248
6434
|
} catch {
|
|
6249
|
-
return
|
|
6435
|
+
return ok28({
|
|
6250
6436
|
registered: scriptName,
|
|
6251
6437
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6252
6438
|
});
|
|
6253
6439
|
}
|
|
6254
|
-
return
|
|
6440
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6255
6441
|
}
|
|
6256
6442
|
});
|
|
6257
6443
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6258
6444
|
|
|
6259
6445
|
// src/commands/find.ts
|
|
6260
|
-
import { z as
|
|
6261
|
-
import { ok as
|
|
6262
|
-
var actionSchema2 =
|
|
6446
|
+
import { z as z30 } from "zod";
|
|
6447
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6448
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6263
6449
|
var findCommand = registerCommand({
|
|
6264
6450
|
name: "find",
|
|
6265
6451
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6266
6452
|
scope: "page",
|
|
6267
|
-
parameters:
|
|
6268
|
-
strategy:
|
|
6269
|
-
value:
|
|
6270
|
-
name:
|
|
6271
|
-
exact:
|
|
6272
|
-
operation:
|
|
6453
|
+
parameters: z30.object({
|
|
6454
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6455
|
+
value: z30.string(),
|
|
6456
|
+
name: z30.string().optional(),
|
|
6457
|
+
exact: z30.boolean().optional().default(false),
|
|
6458
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6273
6459
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6274
|
-
actionValue:
|
|
6275
|
-
index:
|
|
6276
|
-
click:
|
|
6277
|
-
fill:
|
|
6278
|
-
type:
|
|
6279
|
-
select:
|
|
6280
|
-
hover:
|
|
6281
|
-
check:
|
|
6282
|
-
timeout:
|
|
6460
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6461
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6462
|
+
click: z30.boolean().optional().default(false),
|
|
6463
|
+
fill: z30.string().optional(),
|
|
6464
|
+
type: z30.string().optional(),
|
|
6465
|
+
select: z30.string().optional(),
|
|
6466
|
+
hover: z30.boolean().optional().default(false),
|
|
6467
|
+
check: z30.boolean().optional().default(false),
|
|
6468
|
+
timeout: z30.number().optional().default(1e4)
|
|
6283
6469
|
}),
|
|
6284
|
-
result:
|
|
6285
|
-
matched:
|
|
6286
|
-
selector:
|
|
6287
|
-
action:
|
|
6470
|
+
result: z30.object({
|
|
6471
|
+
matched: z30.number(),
|
|
6472
|
+
selector: z30.string(),
|
|
6473
|
+
action: z30.string().optional()
|
|
6288
6474
|
}),
|
|
6289
6475
|
handler: async (p, ctx) => {
|
|
6290
6476
|
const page = ctx.page;
|
|
@@ -6299,7 +6485,7 @@ var findCommand = registerCommand({
|
|
|
6299
6485
|
});
|
|
6300
6486
|
const count = await locator.count();
|
|
6301
6487
|
if (count === 0) {
|
|
6302
|
-
return
|
|
6488
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6303
6489
|
}
|
|
6304
6490
|
const tips = [];
|
|
6305
6491
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6311,15 +6497,15 @@ var findCommand = registerCommand({
|
|
|
6311
6497
|
await target.click({ timeout: p.timeout, force: true });
|
|
6312
6498
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6313
6499
|
} else if (actionName === "fill") {
|
|
6314
|
-
if (actionValue === void 0) return
|
|
6500
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6315
6501
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6316
6502
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6317
6503
|
} else if (actionName === "type") {
|
|
6318
|
-
if (actionValue === void 0) return
|
|
6504
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6319
6505
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6320
6506
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6321
6507
|
} else if (actionName === "select") {
|
|
6322
|
-
if (actionValue === void 0) return
|
|
6508
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6323
6509
|
await target.selectOption(actionValue);
|
|
6324
6510
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6325
6511
|
} else if (actionName === "hover") {
|
|
@@ -6333,8 +6519,8 @@ var findCommand = registerCommand({
|
|
|
6333
6519
|
}
|
|
6334
6520
|
});
|
|
6335
6521
|
function okWithTips(data, tips) {
|
|
6336
|
-
const result =
|
|
6337
|
-
if (tips.length > 0) result.tips =
|
|
6522
|
+
const result = ok29(data);
|
|
6523
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6338
6524
|
return result;
|
|
6339
6525
|
}
|
|
6340
6526
|
function parseOperation(operation) {
|
|
@@ -6432,8 +6618,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6432
6618
|
}
|
|
6433
6619
|
|
|
6434
6620
|
// src/commands/visual-tag.ts
|
|
6435
|
-
import { z as
|
|
6436
|
-
import { ok as
|
|
6621
|
+
import { z as z31 } from "zod";
|
|
6622
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6437
6623
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6438
6624
|
var TAG_SCRIPT = `
|
|
6439
6625
|
(function() {
|
|
@@ -6524,49 +6710,49 @@ var visualTagCommand = registerCommand({
|
|
|
6524
6710
|
name: "visual-tag",
|
|
6525
6711
|
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",
|
|
6526
6712
|
scope: "page",
|
|
6527
|
-
parameters:
|
|
6528
|
-
action:
|
|
6529
|
-
id:
|
|
6713
|
+
parameters: z31.object({
|
|
6714
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6715
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6530
6716
|
}),
|
|
6531
|
-
result:
|
|
6532
|
-
action:
|
|
6533
|
-
tagged:
|
|
6534
|
-
id:
|
|
6535
|
-
element:
|
|
6717
|
+
result: z31.object({
|
|
6718
|
+
action: z31.string(),
|
|
6719
|
+
tagged: z31.number().optional(),
|
|
6720
|
+
id: z31.string().optional(),
|
|
6721
|
+
element: z31.record(z31.unknown()).optional()
|
|
6536
6722
|
}),
|
|
6537
6723
|
handler: async (p, ctx) => {
|
|
6538
6724
|
switch (p.action) {
|
|
6539
6725
|
case "tag": {
|
|
6540
6726
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6541
6727
|
const parsed = JSON.parse(result);
|
|
6542
|
-
return
|
|
6728
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6543
6729
|
}
|
|
6544
6730
|
case "lookup": {
|
|
6545
|
-
if (!p.id) return
|
|
6731
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6546
6732
|
const result = await ctx.page.evaluate(
|
|
6547
6733
|
`(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'}); })()`
|
|
6548
6734
|
);
|
|
6549
6735
|
const parsed = JSON.parse(result);
|
|
6550
|
-
if (parsed.err) return
|
|
6551
|
-
return
|
|
6736
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6737
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6552
6738
|
}
|
|
6553
6739
|
case "list": {
|
|
6554
6740
|
const result = await ctx.page.evaluate(
|
|
6555
6741
|
`(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); })()`
|
|
6556
6742
|
);
|
|
6557
|
-
return
|
|
6743
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6558
6744
|
}
|
|
6559
6745
|
case "clear": {
|
|
6560
6746
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6561
|
-
return
|
|
6747
|
+
return ok30({ action: "clear" });
|
|
6562
6748
|
}
|
|
6563
6749
|
}
|
|
6564
6750
|
}
|
|
6565
6751
|
});
|
|
6566
6752
|
|
|
6567
6753
|
// src/commands/visual-tag-v2.ts
|
|
6568
|
-
import { z as
|
|
6569
|
-
import { ok as
|
|
6754
|
+
import { z as z32 } from "zod";
|
|
6755
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6570
6756
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6571
6757
|
var TAG_V2_SCRIPT = `
|
|
6572
6758
|
(function() {
|
|
@@ -6913,45 +7099,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6913
7099
|
name: "visual-tag-v2",
|
|
6914
7100
|
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",
|
|
6915
7101
|
scope: "page",
|
|
6916
|
-
parameters:
|
|
6917
|
-
action:
|
|
6918
|
-
id:
|
|
6919
|
-
query:
|
|
6920
|
-
type:
|
|
6921
|
-
"interact-action":
|
|
6922
|
-
value:
|
|
7102
|
+
parameters: z32.object({
|
|
7103
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7104
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7105
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7106
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7107
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7108
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6923
7109
|
}),
|
|
6924
|
-
result:
|
|
6925
|
-
action:
|
|
6926
|
-
total:
|
|
6927
|
-
byType:
|
|
6928
|
-
element:
|
|
7110
|
+
result: z32.object({
|
|
7111
|
+
action: z32.string(),
|
|
7112
|
+
total: z32.number().optional(),
|
|
7113
|
+
byType: z32.record(z32.number()).optional(),
|
|
7114
|
+
element: z32.record(z32.unknown()).optional()
|
|
6929
7115
|
}),
|
|
6930
7116
|
handler: async (p, ctx) => {
|
|
6931
7117
|
switch (p.action) {
|
|
6932
7118
|
case "tag": {
|
|
6933
7119
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6934
7120
|
const parsed = JSON.parse(result);
|
|
6935
|
-
return
|
|
7121
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6936
7122
|
}
|
|
6937
7123
|
case "lookup": {
|
|
6938
|
-
if (!p.id) return
|
|
7124
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6939
7125
|
const result = await ctx.page.evaluate(
|
|
6940
7126
|
`(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'})})()`
|
|
6941
7127
|
);
|
|
6942
7128
|
const parsed = JSON.parse(result);
|
|
6943
|
-
if (parsed.err) return
|
|
6944
|
-
return
|
|
7129
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7130
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6945
7131
|
}
|
|
6946
7132
|
case "by-type": {
|
|
6947
7133
|
const result = await ctx.page.evaluate(
|
|
6948
7134
|
`(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)})()`
|
|
6949
7135
|
);
|
|
6950
|
-
return
|
|
7136
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6951
7137
|
}
|
|
6952
7138
|
case "find": {
|
|
6953
7139
|
const query = p.query;
|
|
6954
|
-
if (!query) return
|
|
7140
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6955
7141
|
const result = await ctx.page.evaluate(
|
|
6956
7142
|
`(function(){
|
|
6957
7143
|
var map = window.__xbTagSerializable;
|
|
@@ -6993,21 +7179,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6993
7179
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6994
7180
|
})()`
|
|
6995
7181
|
);
|
|
6996
|
-
return
|
|
7182
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
6997
7183
|
}
|
|
6998
7184
|
case "stats": {
|
|
6999
7185
|
const result = await ctx.page.evaluate(
|
|
7000
7186
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
7001
7187
|
);
|
|
7002
|
-
return
|
|
7188
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
7003
7189
|
}
|
|
7004
7190
|
case "interact": {
|
|
7005
7191
|
const query = p.query;
|
|
7006
7192
|
const pAny = p;
|
|
7007
7193
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
7008
7194
|
const value = pAny.value;
|
|
7009
|
-
if (!query) return
|
|
7010
|
-
if (!action) return
|
|
7195
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7196
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
7011
7197
|
const findResult = await ctx.page.evaluate(
|
|
7012
7198
|
`(function(){
|
|
7013
7199
|
var map = window.__xbTagSerializable;
|
|
@@ -7037,11 +7223,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7037
7223
|
})()`
|
|
7038
7224
|
);
|
|
7039
7225
|
const parsed = JSON.parse(findResult);
|
|
7040
|
-
if (parsed.err) return
|
|
7041
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7226
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7227
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7042
7228
|
const target = parsed.results[0];
|
|
7043
7229
|
if (action === "read") {
|
|
7044
|
-
return
|
|
7230
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7045
7231
|
}
|
|
7046
7232
|
if (action === "click") {
|
|
7047
7233
|
const el = await ctx.page.evaluate(
|
|
@@ -7054,12 +7240,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7054
7240
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7055
7241
|
})()`
|
|
7056
7242
|
);
|
|
7057
|
-
if (!el) return
|
|
7243
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7058
7244
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7059
|
-
return
|
|
7245
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7060
7246
|
}
|
|
7061
7247
|
if (action === "fill") {
|
|
7062
|
-
if (!value) return
|
|
7248
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7063
7249
|
const el = await ctx.page.evaluate(
|
|
7064
7250
|
`(function(){
|
|
7065
7251
|
var map = window.__xbTagMap;
|
|
@@ -7070,12 +7256,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7070
7256
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7071
7257
|
})()`
|
|
7072
7258
|
);
|
|
7073
|
-
if (!el) return
|
|
7259
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7074
7260
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7075
7261
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7076
|
-
return
|
|
7262
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7077
7263
|
}
|
|
7078
|
-
return
|
|
7264
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7079
7265
|
}
|
|
7080
7266
|
case "export": {
|
|
7081
7267
|
const result = await ctx.page.evaluate(
|
|
@@ -7123,12 +7309,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7123
7309
|
})()`
|
|
7124
7310
|
);
|
|
7125
7311
|
const parsed = JSON.parse(result);
|
|
7126
|
-
if (parsed.err) return
|
|
7127
|
-
return
|
|
7312
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7313
|
+
return ok31({ action: "export", element: parsed });
|
|
7128
7314
|
}
|
|
7129
7315
|
case "clear": {
|
|
7130
7316
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7131
|
-
return
|
|
7317
|
+
return ok31({ action: "clear" });
|
|
7132
7318
|
}
|
|
7133
7319
|
}
|
|
7134
7320
|
}
|
|
@@ -7803,7 +7989,7 @@ async function guardCheck(commandName) {
|
|
|
7803
7989
|
}
|
|
7804
7990
|
}
|
|
7805
7991
|
function errorResult(message) {
|
|
7806
|
-
return { ...
|
|
7992
|
+
return { ...fail17(message), duration: 0 };
|
|
7807
7993
|
}
|
|
7808
7994
|
function tipsToMessages(tips) {
|
|
7809
7995
|
if (!tips || tips.length === 0) return [];
|
|
@@ -7992,7 +8178,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7992
8178
|
const cache = /* @__PURE__ */ new Map();
|
|
7993
8179
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
7994
8180
|
if (resolved.tips.length > 0) {
|
|
7995
|
-
refTips =
|
|
8181
|
+
refTips = normalizeTips7(resolved.tips);
|
|
7996
8182
|
params = resolved.params;
|
|
7997
8183
|
}
|
|
7998
8184
|
}
|
|
@@ -8060,8 +8246,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8060
8246
|
}
|
|
8061
8247
|
const merged = [
|
|
8062
8248
|
...raw.tips || [],
|
|
8063
|
-
...
|
|
8064
|
-
...snapshotHint ?
|
|
8249
|
+
...normalizeTips7(smartTips),
|
|
8250
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8065
8251
|
...refTips
|
|
8066
8252
|
];
|
|
8067
8253
|
const isSuccess = raw.success !== false;
|
|
@@ -8076,7 +8262,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8076
8262
|
timestamp: start
|
|
8077
8263
|
});
|
|
8078
8264
|
if (isSuccess) {
|
|
8079
|
-
return { ...
|
|
8265
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8080
8266
|
}
|
|
8081
8267
|
const fc = classifyFailure(raw.message);
|
|
8082
8268
|
return {
|
|
@@ -8089,7 +8275,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8089
8275
|
...hookOutputs ? { hookOutputs } : {}
|
|
8090
8276
|
};
|
|
8091
8277
|
}
|
|
8092
|
-
const smartTipNormalized =
|
|
8278
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8093
8279
|
recordArchive(session?.id, sessionName, {
|
|
8094
8280
|
step: 0,
|
|
8095
8281
|
command: commandName,
|
|
@@ -8099,7 +8285,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8099
8285
|
duration,
|
|
8100
8286
|
timestamp: start
|
|
8101
8287
|
});
|
|
8102
|
-
return { ...
|
|
8288
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8103
8289
|
} catch (err) {
|
|
8104
8290
|
const end = Date.now();
|
|
8105
8291
|
const duration = end - start;
|
|
@@ -8144,7 +8330,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8144
8330
|
duration,
|
|
8145
8331
|
timestamp: start
|
|
8146
8332
|
});
|
|
8147
|
-
return { ...
|
|
8333
|
+
return { ...fail17(errorMessage), duration };
|
|
8148
8334
|
} finally {
|
|
8149
8335
|
}
|
|
8150
8336
|
}
|
|
@@ -8189,7 +8375,7 @@ async function executeChain(input, options) {
|
|
|
8189
8375
|
results.push({
|
|
8190
8376
|
command: cmdName,
|
|
8191
8377
|
raw: cmdStr,
|
|
8192
|
-
...
|
|
8378
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8193
8379
|
duration: 0
|
|
8194
8380
|
});
|
|
8195
8381
|
if (type === "and") {
|
|
@@ -8208,7 +8394,7 @@ async function executeChain(input, options) {
|
|
|
8208
8394
|
results.push({
|
|
8209
8395
|
command: cmdName,
|
|
8210
8396
|
raw: cmdStr,
|
|
8211
|
-
...
|
|
8397
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8212
8398
|
duration: 0
|
|
8213
8399
|
});
|
|
8214
8400
|
if (type === "and") {
|
|
@@ -8278,7 +8464,7 @@ async function executeChain(input, options) {
|
|
|
8278
8464
|
success: false,
|
|
8279
8465
|
data: data2,
|
|
8280
8466
|
message: loginGuard.message,
|
|
8281
|
-
tips:
|
|
8467
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
8282
8468
|
duration: duration3
|
|
8283
8469
|
});
|
|
8284
8470
|
if (type === "and") {
|
|
@@ -8320,7 +8506,7 @@ async function executeChain(input, options) {
|
|
|
8320
8506
|
results.push({
|
|
8321
8507
|
command: `${cmdName} ${subCommand}`,
|
|
8322
8508
|
raw: cmdStr,
|
|
8323
|
-
...
|
|
8509
|
+
...ok32(data),
|
|
8324
8510
|
duration: duration2,
|
|
8325
8511
|
...hookOutputs ? { hookOutputs } : {}
|
|
8326
8512
|
});
|
|
@@ -8348,7 +8534,7 @@ async function executeChain(input, options) {
|
|
|
8348
8534
|
results.push({
|
|
8349
8535
|
command: `${cmdName} ${subCommand}`,
|
|
8350
8536
|
raw: cmdStr,
|
|
8351
|
-
...
|
|
8537
|
+
...fail17(errorMessage),
|
|
8352
8538
|
duration: duration2
|
|
8353
8539
|
});
|
|
8354
8540
|
if (type === "and") {
|
|
@@ -9772,10 +9958,10 @@ function createRPCHandler() {
|
|
|
9772
9958
|
const errors = Array.isArray(input.errors) ? input.errors : [];
|
|
9773
9959
|
const eventsPlayed = typeof input.eventsPlayed === "number" ? input.eventsPlayed : 0;
|
|
9774
9960
|
const totalEvents = typeof input.totalEvents === "number" ? input.totalEvents : eventsPlayed + errors.length;
|
|
9775
|
-
const
|
|
9961
|
+
const ok33 = input.ok ?? errors.length === 0;
|
|
9776
9962
|
return {
|
|
9777
|
-
ok:
|
|
9778
|
-
success:
|
|
9963
|
+
ok: ok33,
|
|
9964
|
+
success: ok33,
|
|
9779
9965
|
duration: typeof input.duration === "number" ? input.duration : 0,
|
|
9780
9966
|
eventsPlayed,
|
|
9781
9967
|
totalEvents,
|