@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
|
@@ -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,
|
|
@@ -1285,9 +1285,12 @@ var visionTaskCommand = registerCommand({
|
|
|
1285
1285
|
} catch {
|
|
1286
1286
|
}
|
|
1287
1287
|
}
|
|
1288
|
-
const
|
|
1288
|
+
const shotQuality = Math.max(30, Math.min(95, parseInt(process.env.XBROWSER_VLM_SHOT_QUALITY ?? "75", 10) || 75));
|
|
1289
|
+
const buffer = await page.screenshot({ type: "jpeg", quality: shotQuality });
|
|
1289
1290
|
const b64 = buffer.toString("base64");
|
|
1290
|
-
const
|
|
1291
|
+
const vp = typeof page.viewportSize === "function" ? page.viewportSize() : null;
|
|
1292
|
+
const w = vp?.width ?? pngDims(b64).w;
|
|
1293
|
+
const h = vp?.height ?? pngDims(b64).h;
|
|
1291
1294
|
const obsText = [
|
|
1292
1295
|
`\u4EFB\u52A1\uFF1A${p.task}`,
|
|
1293
1296
|
`\u622A\u56FE\u5C3A\u5BF8\uFF1A${w}x${h}\uFF08\u5750\u6807\u539F\u70B9\uFF1A\u5DE6\u4E0A\u89D2\uFF09`,
|
|
@@ -1296,7 +1299,7 @@ var visionTaskCommand = registerCommand({
|
|
|
1296
1299
|
${history.slice(-6).join("\n")}` : "\u5C1A\u65E0\u52A8\u4F5C\u3002"
|
|
1297
1300
|
].join("\n");
|
|
1298
1301
|
const reply = await vlmAskRetry(creds, [
|
|
1299
|
-
{ type: "image", source: { type: "base64", media_type: "image/png", data: b64 } },
|
|
1302
|
+
{ type: "image", source: { type: "base64", media_type: shotQuality >= 100 ? "image/png" : "image/jpeg", data: b64 } },
|
|
1300
1303
|
{ type: "text", text: `${SYSTEM_PROMPT}
|
|
1301
1304
|
|
|
1302
1305
|
${obsText}` }
|
|
@@ -4740,6 +4743,25 @@ function getRefTarget(sessionKey2, ref) {
|
|
|
4740
4743
|
if (!session || !target) return null;
|
|
4741
4744
|
return { screenHash: session.screenHash, target };
|
|
4742
4745
|
}
|
|
4746
|
+
function inheritStableRefs(key, rawTargets) {
|
|
4747
|
+
const prev = sessions.get(key);
|
|
4748
|
+
if (!prev || prev.targets.size === 0) {
|
|
4749
|
+
return rawTargets.map((target, index) => ({ ...target, ref: `e${index + 1}` }));
|
|
4750
|
+
}
|
|
4751
|
+
const bySelector = /* @__PURE__ */ new Map();
|
|
4752
|
+
let maxId = 0;
|
|
4753
|
+
for (const [ref, target] of prev.targets) {
|
|
4754
|
+
bySelector.set(target.selector, ref);
|
|
4755
|
+
const id = Number(ref.slice(1));
|
|
4756
|
+
if (Number.isFinite(id) && id > maxId) maxId = id;
|
|
4757
|
+
}
|
|
4758
|
+
let next = maxId + 1;
|
|
4759
|
+
return rawTargets.map((target) => {
|
|
4760
|
+
const inherited = bySelector.get(target.selector);
|
|
4761
|
+
if (inherited) return { ...target, ref: inherited };
|
|
4762
|
+
return { ...target, ref: `e${next++}` };
|
|
4763
|
+
});
|
|
4764
|
+
}
|
|
4743
4765
|
|
|
4744
4766
|
// src/utils/resolve-selector.ts
|
|
4745
4767
|
function buildElementSelector(el) {
|
|
@@ -5364,10 +5386,7 @@ async function observePage(page, sessionId, options = {}) {
|
|
|
5364
5386
|
{ includeHidden: !!options.includeHidden, limit: options.limit ?? 80 }
|
|
5365
5387
|
)
|
|
5366
5388
|
]);
|
|
5367
|
-
const targets =
|
|
5368
|
-
ref: `e${index + 1}`,
|
|
5369
|
-
...target
|
|
5370
|
-
}));
|
|
5389
|
+
const targets = inheritStableRefs(sessionKey(sessionId), raw.targets);
|
|
5371
5390
|
replaceRefs(sessionKey(sessionId), raw.screenHash, targets);
|
|
5372
5391
|
return {
|
|
5373
5392
|
url: page.url(),
|
|
@@ -5859,26 +5878,193 @@ var waitForCommand = registerCommand({
|
|
|
5859
5878
|
}
|
|
5860
5879
|
});
|
|
5861
5880
|
|
|
5862
|
-
// src/commands/
|
|
5881
|
+
// src/commands/task.ts
|
|
5863
5882
|
import { z as z27 } from "zod";
|
|
5864
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
5865
|
-
var
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5883
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
5884
|
+
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
|
|
5885
|
+
|
|
5886
|
+
\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
|
|
5887
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5888
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5889
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5890
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5891
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5892
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5893
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
5894
|
+
|
|
5895
|
+
\u89C4\u5219\uFF1A
|
|
5896
|
+
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
|
|
5897
|
+
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
|
|
5898
|
+
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`;
|
|
5899
|
+
function extractDecision(raw) {
|
|
5900
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
5901
|
+
const start = s.indexOf("{");
|
|
5902
|
+
if (start < 0) return null;
|
|
5903
|
+
let depth = 0;
|
|
5904
|
+
for (let i = start; i < s.length; i++) {
|
|
5905
|
+
if (s[i] === "{") depth++;
|
|
5906
|
+
else if (s[i] === "}") {
|
|
5907
|
+
depth--;
|
|
5908
|
+
if (depth === 0) {
|
|
5909
|
+
try {
|
|
5910
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
5911
|
+
} catch {
|
|
5912
|
+
return null;
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
}
|
|
5916
|
+
}
|
|
5917
|
+
return null;
|
|
5918
|
+
}
|
|
5919
|
+
var taskCommand = registerCommand({
|
|
5920
|
+
name: "task",
|
|
5921
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
5922
|
+
scope: "page",
|
|
5923
|
+
parameters: z27.object({
|
|
5924
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
5925
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
5926
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
5927
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
5928
|
+
}),
|
|
5929
|
+
result: z27.object({
|
|
5930
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
5931
|
+
summary: z27.string().optional(),
|
|
5932
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
5933
|
+
finalUrl: z27.string().optional(),
|
|
5934
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
5935
|
+
}).passthrough(),
|
|
5936
|
+
handler: async (p, ctx) => {
|
|
5937
|
+
const creds = loadVLMCredentials2();
|
|
5938
|
+
if (!creds) {
|
|
5939
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
5940
|
+
}
|
|
5941
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
5942
|
+
const started = Date.now();
|
|
5943
|
+
const steps = [];
|
|
5944
|
+
const history = [];
|
|
5945
|
+
let llmCalls = 0;
|
|
5946
|
+
let status = "max_steps";
|
|
5947
|
+
let summary = "";
|
|
5948
|
+
let lastError = "";
|
|
5949
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
5950
|
+
if (Date.now() - started > p.timeout) {
|
|
5951
|
+
status = "blocked";
|
|
5952
|
+
summary = `timeout after ${step - 1} steps`;
|
|
5953
|
+
break;
|
|
5954
|
+
}
|
|
5955
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
5956
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
5957
|
+
const screenHash = obs.screenHash;
|
|
5958
|
+
const userPayload = [
|
|
5959
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
5960
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
5961
|
+
compact,
|
|
5962
|
+
history.length ? `
|
|
5963
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
5964
|
+
${history.slice(-6).join("\n")}` : ""
|
|
5965
|
+
].filter(Boolean).join("\n");
|
|
5966
|
+
let raw = "";
|
|
5967
|
+
try {
|
|
5968
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
5969
|
+
|
|
5970
|
+
---
|
|
5971
|
+
|
|
5972
|
+
${userPayload}` }], 900);
|
|
5973
|
+
llmCalls++;
|
|
5974
|
+
} catch (e) {
|
|
5975
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
5976
|
+
status = "error";
|
|
5977
|
+
summary = `LLM call failed: ${lastError}`;
|
|
5978
|
+
break;
|
|
5979
|
+
}
|
|
5980
|
+
const decision = extractDecision(raw);
|
|
5981
|
+
if (!decision || typeof decision.action !== "string") {
|
|
5982
|
+
status = "blocked";
|
|
5983
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
5984
|
+
break;
|
|
5985
|
+
}
|
|
5986
|
+
const action = decision.action;
|
|
5987
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
5988
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
5989
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
5990
|
+
if (action === "done") {
|
|
5991
|
+
status = "done";
|
|
5992
|
+
summary = value || thought || "task done";
|
|
5993
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
5994
|
+
break;
|
|
5995
|
+
}
|
|
5996
|
+
if (action === "blocked") {
|
|
5997
|
+
status = "blocked";
|
|
5998
|
+
summary = value || thought || "LLM judged blocked";
|
|
5999
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
6000
|
+
break;
|
|
6001
|
+
}
|
|
6002
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
6003
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
6004
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
6005
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
6006
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
6007
|
+
continue;
|
|
6008
|
+
}
|
|
6009
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
6010
|
+
action,
|
|
6011
|
+
ref: normalizedRef,
|
|
6012
|
+
value,
|
|
6013
|
+
selector: void 0,
|
|
6014
|
+
force: false,
|
|
6015
|
+
timeout: 1e4
|
|
6016
|
+
});
|
|
6017
|
+
const record = {
|
|
6018
|
+
step,
|
|
6019
|
+
thought,
|
|
6020
|
+
action,
|
|
6021
|
+
ref: normalizedRef,
|
|
6022
|
+
value,
|
|
6023
|
+
ok: res.success === true,
|
|
6024
|
+
stale: res.stale,
|
|
6025
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6026
|
+
screenHash
|
|
6027
|
+
};
|
|
6028
|
+
steps.push(record);
|
|
6029
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6030
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6031
|
+
const last3 = steps.slice(-3);
|
|
6032
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6033
|
+
status = "blocked";
|
|
6034
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6035
|
+
break;
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6039
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6040
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6041
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6042
|
+
return ok26(data, normalizeTips5([
|
|
6043
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6044
|
+
]));
|
|
6045
|
+
}
|
|
6046
|
+
});
|
|
6047
|
+
|
|
6048
|
+
// src/commands/tab.ts
|
|
6049
|
+
import { z as z28 } from "zod";
|
|
6050
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6051
|
+
var TabParams = z28.object({
|
|
6052
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6053
|
+
url: z28.string().optional(),
|
|
6054
|
+
index: z28.number().int().min(0).optional()
|
|
5869
6055
|
});
|
|
5870
6056
|
var tabCommand = registerCommand({
|
|
5871
6057
|
name: "tab",
|
|
5872
6058
|
description: "Manage browser tabs: list, new, close, switch",
|
|
5873
6059
|
scope: "page",
|
|
5874
6060
|
parameters: TabParams,
|
|
5875
|
-
result:
|
|
5876
|
-
success:
|
|
5877
|
-
data:
|
|
6061
|
+
result: z28.object({
|
|
6062
|
+
success: z28.boolean(),
|
|
6063
|
+
data: z28.unknown()
|
|
5878
6064
|
}),
|
|
5879
6065
|
handler: async (p, ctx) => {
|
|
5880
6066
|
if (!ctx.browserContext) {
|
|
5881
|
-
return
|
|
6067
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
5882
6068
|
}
|
|
5883
6069
|
const pages = ctx.browserContext.pages();
|
|
5884
6070
|
switch (p.subcommand) {
|
|
@@ -5891,7 +6077,7 @@ var tabCommand = registerCommand({
|
|
|
5891
6077
|
case "switch":
|
|
5892
6078
|
return handleSwitch(p, pages, ctx);
|
|
5893
6079
|
default:
|
|
5894
|
-
return
|
|
6080
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
5895
6081
|
}
|
|
5896
6082
|
}
|
|
5897
6083
|
});
|
|
@@ -5906,7 +6092,7 @@ async function handleList(pages, ctx) {
|
|
|
5906
6092
|
if (isActive) activeIndex = i;
|
|
5907
6093
|
tabs.push({ index: i, url, title, active: isActive });
|
|
5908
6094
|
}
|
|
5909
|
-
return
|
|
6095
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
5910
6096
|
}
|
|
5911
6097
|
async function handleNew(p, _pages, ctx) {
|
|
5912
6098
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -5934,7 +6120,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5934
6120
|
const title = await newPage.title().catch(() => "");
|
|
5935
6121
|
const allPages = ctx.browserContext.pages();
|
|
5936
6122
|
const newIndex = allPages.indexOf(newPage);
|
|
5937
|
-
return
|
|
6123
|
+
return ok27({
|
|
5938
6124
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
5939
6125
|
url: newPage.url(),
|
|
5940
6126
|
title,
|
|
@@ -5945,11 +6131,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
5945
6131
|
async function handleClose(p, ctx) {
|
|
5946
6132
|
const currentPages = ctx.browserContext.pages();
|
|
5947
6133
|
if (currentPages.length <= 1) {
|
|
5948
|
-
return
|
|
6134
|
+
return fail13("Cannot close the last remaining tab");
|
|
5949
6135
|
}
|
|
5950
6136
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
5951
6137
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
5952
|
-
return
|
|
6138
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
5953
6139
|
}
|
|
5954
6140
|
const pageToClose = currentPages[closeIndex];
|
|
5955
6141
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -5964,7 +6150,7 @@ async function handleClose(p, ctx) {
|
|
|
5964
6150
|
}
|
|
5965
6151
|
ctx.page = newActivePage;
|
|
5966
6152
|
}
|
|
5967
|
-
return
|
|
6153
|
+
return ok27({
|
|
5968
6154
|
closedIndex: closeIndex,
|
|
5969
6155
|
total: remainingPages.length,
|
|
5970
6156
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -5972,10 +6158,10 @@ async function handleClose(p, ctx) {
|
|
|
5972
6158
|
}
|
|
5973
6159
|
async function handleSwitch(p, pages, ctx) {
|
|
5974
6160
|
if (p.index === void 0) {
|
|
5975
|
-
return
|
|
6161
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
5976
6162
|
}
|
|
5977
6163
|
if (p.index < 0 || p.index >= pages.length) {
|
|
5978
|
-
return
|
|
6164
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
5979
6165
|
}
|
|
5980
6166
|
const targetPage = pages[p.index];
|
|
5981
6167
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -5997,7 +6183,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
5997
6183
|
}
|
|
5998
6184
|
ctx.page = targetPage;
|
|
5999
6185
|
const title = await targetPage.title().catch(() => "");
|
|
6000
|
-
return
|
|
6186
|
+
return ok27({
|
|
6001
6187
|
index: p.index,
|
|
6002
6188
|
url: targetPage.url(),
|
|
6003
6189
|
title,
|
|
@@ -6006,8 +6192,8 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6006
6192
|
}
|
|
6007
6193
|
|
|
6008
6194
|
// src/commands/addinitscript.ts
|
|
6009
|
-
import { z as
|
|
6010
|
-
import { ok as
|
|
6195
|
+
import { z as z29 } from "zod";
|
|
6196
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6011
6197
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6012
6198
|
|
|
6013
6199
|
// src/chain-parser.ts
|
|
@@ -6148,14 +6334,14 @@ registerCommandDefinition("tab", ["subcommand"]);
|
|
|
6148
6334
|
registerCommandDefinition("mouse", ["action", "x", "y"]);
|
|
6149
6335
|
|
|
6150
6336
|
// src/commands/addinitscript.ts
|
|
6151
|
-
var InitScriptParams =
|
|
6152
|
-
script:
|
|
6153
|
-
file:
|
|
6154
|
-
stdin:
|
|
6155
|
-
name:
|
|
6156
|
-
list:
|
|
6157
|
-
remove:
|
|
6158
|
-
base64:
|
|
6337
|
+
var InitScriptParams = z29.object({
|
|
6338
|
+
script: z29.string().optional(),
|
|
6339
|
+
file: z29.string().optional(),
|
|
6340
|
+
stdin: z29.boolean().optional(),
|
|
6341
|
+
name: z29.string().optional(),
|
|
6342
|
+
list: z29.boolean().optional(),
|
|
6343
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6344
|
+
base64: z29.string().optional()
|
|
6159
6345
|
});
|
|
6160
6346
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6161
6347
|
function resolveScriptContent(params) {
|
|
@@ -6189,14 +6375,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6189
6375
|
description: "Add an initialization script that runs on every page load",
|
|
6190
6376
|
scope: "page",
|
|
6191
6377
|
parameters: InitScriptParams,
|
|
6192
|
-
result:
|
|
6193
|
-
scripts:
|
|
6194
|
-
removed:
|
|
6195
|
-
existed:
|
|
6196
|
-
error:
|
|
6197
|
-
registered:
|
|
6198
|
-
hint:
|
|
6199
|
-
executedImmediately:
|
|
6378
|
+
result: z29.object({
|
|
6379
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6380
|
+
removed: z29.string().optional(),
|
|
6381
|
+
existed: z29.boolean().optional(),
|
|
6382
|
+
error: z29.string().optional(),
|
|
6383
|
+
registered: z29.string().optional(),
|
|
6384
|
+
hint: z29.string().optional(),
|
|
6385
|
+
executedImmediately: z29.boolean().optional()
|
|
6200
6386
|
}).passthrough(),
|
|
6201
6387
|
handler: async (params, ctx) => {
|
|
6202
6388
|
if (params.list) {
|
|
@@ -6205,20 +6391,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6205
6391
|
size: content2.length,
|
|
6206
6392
|
preview: content2.slice(0, 80)
|
|
6207
6393
|
}));
|
|
6208
|
-
return
|
|
6394
|
+
return ok28({ scripts });
|
|
6209
6395
|
}
|
|
6210
6396
|
if (params.remove && typeof params.remove === "string") {
|
|
6211
6397
|
const existed = registeredScripts.delete(params.remove);
|
|
6212
|
-
return
|
|
6398
|
+
return ok28({ removed: params.remove, existed });
|
|
6213
6399
|
}
|
|
6214
6400
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6215
6401
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6216
6402
|
const existed = registeredScripts.delete(removeTarget);
|
|
6217
|
-
return
|
|
6403
|
+
return ok28({ removed: removeTarget, existed });
|
|
6218
6404
|
}
|
|
6219
6405
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6220
6406
|
if (!content) {
|
|
6221
|
-
return
|
|
6407
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6222
6408
|
}
|
|
6223
6409
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6224
6410
|
registeredScripts.set(scriptName, content);
|
|
@@ -6226,45 +6412,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6226
6412
|
try {
|
|
6227
6413
|
await ctx.page.evaluate(content);
|
|
6228
6414
|
} catch {
|
|
6229
|
-
return
|
|
6415
|
+
return ok28({
|
|
6230
6416
|
registered: scriptName,
|
|
6231
6417
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6232
6418
|
});
|
|
6233
6419
|
}
|
|
6234
|
-
return
|
|
6420
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6235
6421
|
}
|
|
6236
6422
|
});
|
|
6237
6423
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6238
6424
|
|
|
6239
6425
|
// src/commands/find.ts
|
|
6240
|
-
import { z as
|
|
6241
|
-
import { ok as
|
|
6242
|
-
var actionSchema2 =
|
|
6426
|
+
import { z as z30 } from "zod";
|
|
6427
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6428
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6243
6429
|
var findCommand = registerCommand({
|
|
6244
6430
|
name: "find",
|
|
6245
6431
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6246
6432
|
scope: "page",
|
|
6247
|
-
parameters:
|
|
6248
|
-
strategy:
|
|
6249
|
-
value:
|
|
6250
|
-
name:
|
|
6251
|
-
exact:
|
|
6252
|
-
operation:
|
|
6433
|
+
parameters: z30.object({
|
|
6434
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6435
|
+
value: z30.string(),
|
|
6436
|
+
name: z30.string().optional(),
|
|
6437
|
+
exact: z30.boolean().optional().default(false),
|
|
6438
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6253
6439
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6254
|
-
actionValue:
|
|
6255
|
-
index:
|
|
6256
|
-
click:
|
|
6257
|
-
fill:
|
|
6258
|
-
type:
|
|
6259
|
-
select:
|
|
6260
|
-
hover:
|
|
6261
|
-
check:
|
|
6262
|
-
timeout:
|
|
6440
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6441
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6442
|
+
click: z30.boolean().optional().default(false),
|
|
6443
|
+
fill: z30.string().optional(),
|
|
6444
|
+
type: z30.string().optional(),
|
|
6445
|
+
select: z30.string().optional(),
|
|
6446
|
+
hover: z30.boolean().optional().default(false),
|
|
6447
|
+
check: z30.boolean().optional().default(false),
|
|
6448
|
+
timeout: z30.number().optional().default(1e4)
|
|
6263
6449
|
}),
|
|
6264
|
-
result:
|
|
6265
|
-
matched:
|
|
6266
|
-
selector:
|
|
6267
|
-
action:
|
|
6450
|
+
result: z30.object({
|
|
6451
|
+
matched: z30.number(),
|
|
6452
|
+
selector: z30.string(),
|
|
6453
|
+
action: z30.string().optional()
|
|
6268
6454
|
}),
|
|
6269
6455
|
handler: async (p, ctx) => {
|
|
6270
6456
|
const page = ctx.page;
|
|
@@ -6279,7 +6465,7 @@ var findCommand = registerCommand({
|
|
|
6279
6465
|
});
|
|
6280
6466
|
const count = await locator.count();
|
|
6281
6467
|
if (count === 0) {
|
|
6282
|
-
return
|
|
6468
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6283
6469
|
}
|
|
6284
6470
|
const tips = [];
|
|
6285
6471
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6291,15 +6477,15 @@ var findCommand = registerCommand({
|
|
|
6291
6477
|
await target.click({ timeout: p.timeout, force: true });
|
|
6292
6478
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6293
6479
|
} else if (actionName === "fill") {
|
|
6294
|
-
if (actionValue === void 0) return
|
|
6480
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6295
6481
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6296
6482
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6297
6483
|
} else if (actionName === "type") {
|
|
6298
|
-
if (actionValue === void 0) return
|
|
6484
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6299
6485
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6300
6486
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6301
6487
|
} else if (actionName === "select") {
|
|
6302
|
-
if (actionValue === void 0) return
|
|
6488
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6303
6489
|
await target.selectOption(actionValue);
|
|
6304
6490
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6305
6491
|
} else if (actionName === "hover") {
|
|
@@ -6313,8 +6499,8 @@ var findCommand = registerCommand({
|
|
|
6313
6499
|
}
|
|
6314
6500
|
});
|
|
6315
6501
|
function okWithTips(data, tips) {
|
|
6316
|
-
const result =
|
|
6317
|
-
if (tips.length > 0) result.tips =
|
|
6502
|
+
const result = ok29(data);
|
|
6503
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6318
6504
|
return result;
|
|
6319
6505
|
}
|
|
6320
6506
|
function parseOperation(operation) {
|
|
@@ -6412,8 +6598,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6412
6598
|
}
|
|
6413
6599
|
|
|
6414
6600
|
// src/commands/visual-tag.ts
|
|
6415
|
-
import { z as
|
|
6416
|
-
import { ok as
|
|
6601
|
+
import { z as z31 } from "zod";
|
|
6602
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6417
6603
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6418
6604
|
var TAG_SCRIPT = `
|
|
6419
6605
|
(function() {
|
|
@@ -6504,49 +6690,49 @@ var visualTagCommand = registerCommand({
|
|
|
6504
6690
|
name: "visual-tag",
|
|
6505
6691
|
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",
|
|
6506
6692
|
scope: "page",
|
|
6507
|
-
parameters:
|
|
6508
|
-
action:
|
|
6509
|
-
id:
|
|
6693
|
+
parameters: z31.object({
|
|
6694
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6695
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6510
6696
|
}),
|
|
6511
|
-
result:
|
|
6512
|
-
action:
|
|
6513
|
-
tagged:
|
|
6514
|
-
id:
|
|
6515
|
-
element:
|
|
6697
|
+
result: z31.object({
|
|
6698
|
+
action: z31.string(),
|
|
6699
|
+
tagged: z31.number().optional(),
|
|
6700
|
+
id: z31.string().optional(),
|
|
6701
|
+
element: z31.record(z31.unknown()).optional()
|
|
6516
6702
|
}),
|
|
6517
6703
|
handler: async (p, ctx) => {
|
|
6518
6704
|
switch (p.action) {
|
|
6519
6705
|
case "tag": {
|
|
6520
6706
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6521
6707
|
const parsed = JSON.parse(result);
|
|
6522
|
-
return
|
|
6708
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6523
6709
|
}
|
|
6524
6710
|
case "lookup": {
|
|
6525
|
-
if (!p.id) return
|
|
6711
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6526
6712
|
const result = await ctx.page.evaluate(
|
|
6527
6713
|
`(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'}); })()`
|
|
6528
6714
|
);
|
|
6529
6715
|
const parsed = JSON.parse(result);
|
|
6530
|
-
if (parsed.err) return
|
|
6531
|
-
return
|
|
6716
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6717
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6532
6718
|
}
|
|
6533
6719
|
case "list": {
|
|
6534
6720
|
const result = await ctx.page.evaluate(
|
|
6535
6721
|
`(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); })()`
|
|
6536
6722
|
);
|
|
6537
|
-
return
|
|
6723
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6538
6724
|
}
|
|
6539
6725
|
case "clear": {
|
|
6540
6726
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6541
|
-
return
|
|
6727
|
+
return ok30({ action: "clear" });
|
|
6542
6728
|
}
|
|
6543
6729
|
}
|
|
6544
6730
|
}
|
|
6545
6731
|
});
|
|
6546
6732
|
|
|
6547
6733
|
// src/commands/visual-tag-v2.ts
|
|
6548
|
-
import { z as
|
|
6549
|
-
import { ok as
|
|
6734
|
+
import { z as z32 } from "zod";
|
|
6735
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6550
6736
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6551
6737
|
var TAG_V2_SCRIPT = `
|
|
6552
6738
|
(function() {
|
|
@@ -6893,45 +7079,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6893
7079
|
name: "visual-tag-v2",
|
|
6894
7080
|
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",
|
|
6895
7081
|
scope: "page",
|
|
6896
|
-
parameters:
|
|
6897
|
-
action:
|
|
6898
|
-
id:
|
|
6899
|
-
query:
|
|
6900
|
-
type:
|
|
6901
|
-
"interact-action":
|
|
6902
|
-
value:
|
|
7082
|
+
parameters: z32.object({
|
|
7083
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7084
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7085
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7086
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7087
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7088
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6903
7089
|
}),
|
|
6904
|
-
result:
|
|
6905
|
-
action:
|
|
6906
|
-
total:
|
|
6907
|
-
byType:
|
|
6908
|
-
element:
|
|
7090
|
+
result: z32.object({
|
|
7091
|
+
action: z32.string(),
|
|
7092
|
+
total: z32.number().optional(),
|
|
7093
|
+
byType: z32.record(z32.number()).optional(),
|
|
7094
|
+
element: z32.record(z32.unknown()).optional()
|
|
6909
7095
|
}),
|
|
6910
7096
|
handler: async (p, ctx) => {
|
|
6911
7097
|
switch (p.action) {
|
|
6912
7098
|
case "tag": {
|
|
6913
7099
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6914
7100
|
const parsed = JSON.parse(result);
|
|
6915
|
-
return
|
|
7101
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6916
7102
|
}
|
|
6917
7103
|
case "lookup": {
|
|
6918
|
-
if (!p.id) return
|
|
7104
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6919
7105
|
const result = await ctx.page.evaluate(
|
|
6920
7106
|
`(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'})})()`
|
|
6921
7107
|
);
|
|
6922
7108
|
const parsed = JSON.parse(result);
|
|
6923
|
-
if (parsed.err) return
|
|
6924
|
-
return
|
|
7109
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7110
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6925
7111
|
}
|
|
6926
7112
|
case "by-type": {
|
|
6927
7113
|
const result = await ctx.page.evaluate(
|
|
6928
7114
|
`(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)})()`
|
|
6929
7115
|
);
|
|
6930
|
-
return
|
|
7116
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6931
7117
|
}
|
|
6932
7118
|
case "find": {
|
|
6933
7119
|
const query = p.query;
|
|
6934
|
-
if (!query) return
|
|
7120
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6935
7121
|
const result = await ctx.page.evaluate(
|
|
6936
7122
|
`(function(){
|
|
6937
7123
|
var map = window.__xbTagSerializable;
|
|
@@ -6973,21 +7159,21 @@ var visualTagV2Command = registerCommand({
|
|
|
6973
7159
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
6974
7160
|
})()`
|
|
6975
7161
|
);
|
|
6976
|
-
return
|
|
7162
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
6977
7163
|
}
|
|
6978
7164
|
case "stats": {
|
|
6979
7165
|
const result = await ctx.page.evaluate(
|
|
6980
7166
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
6981
7167
|
);
|
|
6982
|
-
return
|
|
7168
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
6983
7169
|
}
|
|
6984
7170
|
case "interact": {
|
|
6985
7171
|
const query = p.query;
|
|
6986
7172
|
const pAny = p;
|
|
6987
7173
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
6988
7174
|
const value = pAny.value;
|
|
6989
|
-
if (!query) return
|
|
6990
|
-
if (!action) return
|
|
7175
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7176
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
6991
7177
|
const findResult = await ctx.page.evaluate(
|
|
6992
7178
|
`(function(){
|
|
6993
7179
|
var map = window.__xbTagSerializable;
|
|
@@ -7017,11 +7203,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7017
7203
|
})()`
|
|
7018
7204
|
);
|
|
7019
7205
|
const parsed = JSON.parse(findResult);
|
|
7020
|
-
if (parsed.err) return
|
|
7021
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7206
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7207
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7022
7208
|
const target = parsed.results[0];
|
|
7023
7209
|
if (action === "read") {
|
|
7024
|
-
return
|
|
7210
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7025
7211
|
}
|
|
7026
7212
|
if (action === "click") {
|
|
7027
7213
|
const el = await ctx.page.evaluate(
|
|
@@ -7034,12 +7220,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7034
7220
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7035
7221
|
})()`
|
|
7036
7222
|
);
|
|
7037
|
-
if (!el) return
|
|
7223
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7038
7224
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7039
|
-
return
|
|
7225
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7040
7226
|
}
|
|
7041
7227
|
if (action === "fill") {
|
|
7042
|
-
if (!value) return
|
|
7228
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7043
7229
|
const el = await ctx.page.evaluate(
|
|
7044
7230
|
`(function(){
|
|
7045
7231
|
var map = window.__xbTagMap;
|
|
@@ -7050,12 +7236,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7050
7236
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7051
7237
|
})()`
|
|
7052
7238
|
);
|
|
7053
|
-
if (!el) return
|
|
7239
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7054
7240
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7055
7241
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7056
|
-
return
|
|
7242
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7057
7243
|
}
|
|
7058
|
-
return
|
|
7244
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7059
7245
|
}
|
|
7060
7246
|
case "export": {
|
|
7061
7247
|
const result = await ctx.page.evaluate(
|
|
@@ -7103,12 +7289,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7103
7289
|
})()`
|
|
7104
7290
|
);
|
|
7105
7291
|
const parsed = JSON.parse(result);
|
|
7106
|
-
if (parsed.err) return
|
|
7107
|
-
return
|
|
7292
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7293
|
+
return ok31({ action: "export", element: parsed });
|
|
7108
7294
|
}
|
|
7109
7295
|
case "clear": {
|
|
7110
7296
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7111
|
-
return
|
|
7297
|
+
return ok31({ action: "clear" });
|
|
7112
7298
|
}
|
|
7113
7299
|
}
|
|
7114
7300
|
}
|
|
@@ -8251,7 +8437,7 @@ async function guardCheck(commandName) {
|
|
|
8251
8437
|
}
|
|
8252
8438
|
}
|
|
8253
8439
|
function errorResult(message) {
|
|
8254
|
-
return { ...
|
|
8440
|
+
return { ...fail17(message), duration: 0 };
|
|
8255
8441
|
}
|
|
8256
8442
|
function tipsToMessages(tips) {
|
|
8257
8443
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8440,7 +8626,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8440
8626
|
const cache = /* @__PURE__ */ new Map();
|
|
8441
8627
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
8442
8628
|
if (resolved.tips.length > 0) {
|
|
8443
|
-
refTips =
|
|
8629
|
+
refTips = normalizeTips7(resolved.tips);
|
|
8444
8630
|
params = resolved.params;
|
|
8445
8631
|
}
|
|
8446
8632
|
}
|
|
@@ -8508,8 +8694,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8508
8694
|
}
|
|
8509
8695
|
const merged = [
|
|
8510
8696
|
...raw.tips || [],
|
|
8511
|
-
...
|
|
8512
|
-
...snapshotHint ?
|
|
8697
|
+
...normalizeTips7(smartTips),
|
|
8698
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8513
8699
|
...refTips
|
|
8514
8700
|
];
|
|
8515
8701
|
const isSuccess = raw.success !== false;
|
|
@@ -8524,7 +8710,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8524
8710
|
timestamp: start
|
|
8525
8711
|
});
|
|
8526
8712
|
if (isSuccess) {
|
|
8527
|
-
return { ...
|
|
8713
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8528
8714
|
}
|
|
8529
8715
|
const fc = classifyFailure(raw.message);
|
|
8530
8716
|
return {
|
|
@@ -8537,7 +8723,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8537
8723
|
...hookOutputs ? { hookOutputs } : {}
|
|
8538
8724
|
};
|
|
8539
8725
|
}
|
|
8540
|
-
const smartTipNormalized =
|
|
8726
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8541
8727
|
recordArchive(session?.id, sessionName, {
|
|
8542
8728
|
step: 0,
|
|
8543
8729
|
command: commandName,
|
|
@@ -8547,7 +8733,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8547
8733
|
duration,
|
|
8548
8734
|
timestamp: start
|
|
8549
8735
|
});
|
|
8550
|
-
return { ...
|
|
8736
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8551
8737
|
} catch (err) {
|
|
8552
8738
|
const end = Date.now();
|
|
8553
8739
|
const duration = end - start;
|
|
@@ -8592,7 +8778,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8592
8778
|
duration,
|
|
8593
8779
|
timestamp: start
|
|
8594
8780
|
});
|
|
8595
|
-
return { ...
|
|
8781
|
+
return { ...fail17(errorMessage), duration };
|
|
8596
8782
|
} finally {
|
|
8597
8783
|
}
|
|
8598
8784
|
}
|
|
@@ -8637,7 +8823,7 @@ async function executeChain(input, options) {
|
|
|
8637
8823
|
results.push({
|
|
8638
8824
|
command: cmdName,
|
|
8639
8825
|
raw: cmdStr,
|
|
8640
|
-
...
|
|
8826
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8641
8827
|
duration: 0
|
|
8642
8828
|
});
|
|
8643
8829
|
if (type === "and") {
|
|
@@ -8656,7 +8842,7 @@ async function executeChain(input, options) {
|
|
|
8656
8842
|
results.push({
|
|
8657
8843
|
command: cmdName,
|
|
8658
8844
|
raw: cmdStr,
|
|
8659
|
-
...
|
|
8845
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8660
8846
|
duration: 0
|
|
8661
8847
|
});
|
|
8662
8848
|
if (type === "and") {
|
|
@@ -8726,7 +8912,7 @@ async function executeChain(input, options) {
|
|
|
8726
8912
|
success: false,
|
|
8727
8913
|
data: data2,
|
|
8728
8914
|
message: loginGuard.message,
|
|
8729
|
-
tips:
|
|
8915
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
8730
8916
|
duration: duration3
|
|
8731
8917
|
});
|
|
8732
8918
|
if (type === "and") {
|
|
@@ -8768,7 +8954,7 @@ async function executeChain(input, options) {
|
|
|
8768
8954
|
results.push({
|
|
8769
8955
|
command: `${cmdName} ${subCommand}`,
|
|
8770
8956
|
raw: cmdStr,
|
|
8771
|
-
...
|
|
8957
|
+
...ok32(data),
|
|
8772
8958
|
duration: duration2,
|
|
8773
8959
|
...hookOutputs ? { hookOutputs } : {}
|
|
8774
8960
|
});
|
|
@@ -8796,7 +8982,7 @@ async function executeChain(input, options) {
|
|
|
8796
8982
|
results.push({
|
|
8797
8983
|
command: `${cmdName} ${subCommand}`,
|
|
8798
8984
|
raw: cmdStr,
|
|
8799
|
-
...
|
|
8985
|
+
...fail17(errorMessage),
|
|
8800
8986
|
duration: duration2
|
|
8801
8987
|
});
|
|
8802
8988
|
if (type === "and") {
|