@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
|
@@ -74,6 +74,25 @@ function getRefTarget(sessionKey2, ref) {
|
|
|
74
74
|
if (!session || !target) return null;
|
|
75
75
|
return { screenHash: session.screenHash, target };
|
|
76
76
|
}
|
|
77
|
+
function inheritStableRefs(key, rawTargets) {
|
|
78
|
+
const prev = sessions.get(key);
|
|
79
|
+
if (!prev || prev.targets.size === 0) {
|
|
80
|
+
return rawTargets.map((target, index) => ({ ...target, ref: `e${index + 1}` }));
|
|
81
|
+
}
|
|
82
|
+
const bySelector = /* @__PURE__ */ new Map();
|
|
83
|
+
let maxId = 0;
|
|
84
|
+
for (const [ref, target] of prev.targets) {
|
|
85
|
+
bySelector.set(target.selector, ref);
|
|
86
|
+
const id = Number(ref.slice(1));
|
|
87
|
+
if (Number.isFinite(id) && id > maxId) maxId = id;
|
|
88
|
+
}
|
|
89
|
+
let next = maxId + 1;
|
|
90
|
+
return rawTargets.map((target) => {
|
|
91
|
+
const inherited = bySelector.get(target.selector);
|
|
92
|
+
if (inherited) return { ...target, ref: inherited };
|
|
93
|
+
return { ...target, ref: `e${next++}` };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
77
96
|
|
|
78
97
|
// src/runtime/agent-runtime.ts
|
|
79
98
|
function sessionKey(sessionId) {
|
|
@@ -225,10 +244,7 @@ async function observePage(page, sessionId, options = {}) {
|
|
|
225
244
|
{ includeHidden: !!options.includeHidden, limit: options.limit ?? 80 }
|
|
226
245
|
)
|
|
227
246
|
]);
|
|
228
|
-
const targets =
|
|
229
|
-
ref: `e${index + 1}`,
|
|
230
|
-
...target
|
|
231
|
-
}));
|
|
247
|
+
const targets = inheritStableRefs(sessionKey(sessionId), raw.targets);
|
|
232
248
|
replaceRefs(sessionKey(sessionId), raw.screenHash, targets);
|
|
233
249
|
return {
|
|
234
250
|
url: page.url(),
|
|
@@ -1637,9 +1653,12 @@ var visionTaskCommand = registerCommand({
|
|
|
1637
1653
|
} catch {
|
|
1638
1654
|
}
|
|
1639
1655
|
}
|
|
1640
|
-
const
|
|
1656
|
+
const shotQuality = Math.max(30, Math.min(95, parseInt(process.env.XBROWSER_VLM_SHOT_QUALITY ?? "75", 10) || 75));
|
|
1657
|
+
const buffer = await page.screenshot({ type: "jpeg", quality: shotQuality });
|
|
1641
1658
|
const b64 = buffer.toString("base64");
|
|
1642
|
-
const
|
|
1659
|
+
const vp = typeof page.viewportSize === "function" ? page.viewportSize() : null;
|
|
1660
|
+
const w = vp?.width ?? pngDims(b64).w;
|
|
1661
|
+
const h = vp?.height ?? pngDims(b64).h;
|
|
1643
1662
|
const obsText = [
|
|
1644
1663
|
`\u4EFB\u52A1\uFF1A${p.task}`,
|
|
1645
1664
|
`\u622A\u56FE\u5C3A\u5BF8\uFF1A${w}x${h}\uFF08\u5750\u6807\u539F\u70B9\uFF1A\u5DE6\u4E0A\u89D2\uFF09`,
|
|
@@ -1648,7 +1667,7 @@ var visionTaskCommand = registerCommand({
|
|
|
1648
1667
|
${history.slice(-6).join("\n")}` : "\u5C1A\u65E0\u52A8\u4F5C\u3002"
|
|
1649
1668
|
].join("\n");
|
|
1650
1669
|
const reply = await vlmAskRetry(creds, [
|
|
1651
|
-
{ type: "image", source: { type: "base64", media_type: "image/png", data: b64 } },
|
|
1670
|
+
{ type: "image", source: { type: "base64", media_type: shotQuality >= 100 ? "image/png" : "image/jpeg", data: b64 } },
|
|
1652
1671
|
{ type: "text", text: `${SYSTEM_PROMPT}
|
|
1653
1672
|
|
|
1654
1673
|
${obsText}` }
|
|
@@ -6057,26 +6076,193 @@ var waitForCommand = registerCommand({
|
|
|
6057
6076
|
}
|
|
6058
6077
|
});
|
|
6059
6078
|
|
|
6060
|
-
// src/commands/
|
|
6079
|
+
// src/commands/task.ts
|
|
6061
6080
|
import { z as z27 } from "zod";
|
|
6062
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
6063
|
-
var
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6081
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
6082
|
+
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
|
|
6083
|
+
|
|
6084
|
+
\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
|
|
6085
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6086
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6087
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6088
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6089
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6090
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6091
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6092
|
+
|
|
6093
|
+
\u89C4\u5219\uFF1A
|
|
6094
|
+
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
|
|
6095
|
+
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
|
|
6096
|
+
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`;
|
|
6097
|
+
function extractDecision(raw) {
|
|
6098
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
6099
|
+
const start = s.indexOf("{");
|
|
6100
|
+
if (start < 0) return null;
|
|
6101
|
+
let depth = 0;
|
|
6102
|
+
for (let i = start; i < s.length; i++) {
|
|
6103
|
+
if (s[i] === "{") depth++;
|
|
6104
|
+
else if (s[i] === "}") {
|
|
6105
|
+
depth--;
|
|
6106
|
+
if (depth === 0) {
|
|
6107
|
+
try {
|
|
6108
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
6109
|
+
} catch {
|
|
6110
|
+
return null;
|
|
6111
|
+
}
|
|
6112
|
+
}
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
return null;
|
|
6116
|
+
}
|
|
6117
|
+
var taskCommand = registerCommand({
|
|
6118
|
+
name: "task",
|
|
6119
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
6120
|
+
scope: "page",
|
|
6121
|
+
parameters: z27.object({
|
|
6122
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
6123
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
6124
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
6125
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
6126
|
+
}),
|
|
6127
|
+
result: z27.object({
|
|
6128
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
6129
|
+
summary: z27.string().optional(),
|
|
6130
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
6131
|
+
finalUrl: z27.string().optional(),
|
|
6132
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
6133
|
+
}).passthrough(),
|
|
6134
|
+
handler: async (p, ctx) => {
|
|
6135
|
+
const creds = loadVLMCredentials2();
|
|
6136
|
+
if (!creds) {
|
|
6137
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
6138
|
+
}
|
|
6139
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
6140
|
+
const started = Date.now();
|
|
6141
|
+
const steps = [];
|
|
6142
|
+
const history = [];
|
|
6143
|
+
let llmCalls = 0;
|
|
6144
|
+
let status = "max_steps";
|
|
6145
|
+
let summary = "";
|
|
6146
|
+
let lastError = "";
|
|
6147
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
6148
|
+
if (Date.now() - started > p.timeout) {
|
|
6149
|
+
status = "blocked";
|
|
6150
|
+
summary = `timeout after ${step - 1} steps`;
|
|
6151
|
+
break;
|
|
6152
|
+
}
|
|
6153
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
6154
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
6155
|
+
const screenHash = obs.screenHash;
|
|
6156
|
+
const userPayload = [
|
|
6157
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
6158
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
6159
|
+
compact,
|
|
6160
|
+
history.length ? `
|
|
6161
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
6162
|
+
${history.slice(-6).join("\n")}` : ""
|
|
6163
|
+
].filter(Boolean).join("\n");
|
|
6164
|
+
let raw = "";
|
|
6165
|
+
try {
|
|
6166
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
6167
|
+
|
|
6168
|
+
---
|
|
6169
|
+
|
|
6170
|
+
${userPayload}` }], 900);
|
|
6171
|
+
llmCalls++;
|
|
6172
|
+
} catch (e) {
|
|
6173
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
6174
|
+
status = "error";
|
|
6175
|
+
summary = `LLM call failed: ${lastError}`;
|
|
6176
|
+
break;
|
|
6177
|
+
}
|
|
6178
|
+
const decision = extractDecision(raw);
|
|
6179
|
+
if (!decision || typeof decision.action !== "string") {
|
|
6180
|
+
status = "blocked";
|
|
6181
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
6182
|
+
break;
|
|
6183
|
+
}
|
|
6184
|
+
const action = decision.action;
|
|
6185
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
6186
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
6187
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
6188
|
+
if (action === "done") {
|
|
6189
|
+
status = "done";
|
|
6190
|
+
summary = value || thought || "task done";
|
|
6191
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
6192
|
+
break;
|
|
6193
|
+
}
|
|
6194
|
+
if (action === "blocked") {
|
|
6195
|
+
status = "blocked";
|
|
6196
|
+
summary = value || thought || "LLM judged blocked";
|
|
6197
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
6198
|
+
break;
|
|
6199
|
+
}
|
|
6200
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
6201
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
6202
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
6203
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
6204
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
6205
|
+
continue;
|
|
6206
|
+
}
|
|
6207
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
6208
|
+
action,
|
|
6209
|
+
ref: normalizedRef,
|
|
6210
|
+
value,
|
|
6211
|
+
selector: void 0,
|
|
6212
|
+
force: false,
|
|
6213
|
+
timeout: 1e4
|
|
6214
|
+
});
|
|
6215
|
+
const record = {
|
|
6216
|
+
step,
|
|
6217
|
+
thought,
|
|
6218
|
+
action,
|
|
6219
|
+
ref: normalizedRef,
|
|
6220
|
+
value,
|
|
6221
|
+
ok: res.success === true,
|
|
6222
|
+
stale: res.stale,
|
|
6223
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6224
|
+
screenHash
|
|
6225
|
+
};
|
|
6226
|
+
steps.push(record);
|
|
6227
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6228
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6229
|
+
const last3 = steps.slice(-3);
|
|
6230
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6231
|
+
status = "blocked";
|
|
6232
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6233
|
+
break;
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6236
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6237
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6238
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6239
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6240
|
+
return ok26(data, normalizeTips5([
|
|
6241
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6242
|
+
]));
|
|
6243
|
+
}
|
|
6244
|
+
});
|
|
6245
|
+
|
|
6246
|
+
// src/commands/tab.ts
|
|
6247
|
+
import { z as z28 } from "zod";
|
|
6248
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6249
|
+
var TabParams = z28.object({
|
|
6250
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6251
|
+
url: z28.string().optional(),
|
|
6252
|
+
index: z28.number().int().min(0).optional()
|
|
6067
6253
|
});
|
|
6068
6254
|
var tabCommand = registerCommand({
|
|
6069
6255
|
name: "tab",
|
|
6070
6256
|
description: "Manage browser tabs: list, new, close, switch",
|
|
6071
6257
|
scope: "page",
|
|
6072
6258
|
parameters: TabParams,
|
|
6073
|
-
result:
|
|
6074
|
-
success:
|
|
6075
|
-
data:
|
|
6259
|
+
result: z28.object({
|
|
6260
|
+
success: z28.boolean(),
|
|
6261
|
+
data: z28.unknown()
|
|
6076
6262
|
}),
|
|
6077
6263
|
handler: async (p, ctx) => {
|
|
6078
6264
|
if (!ctx.browserContext) {
|
|
6079
|
-
return
|
|
6265
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
6080
6266
|
}
|
|
6081
6267
|
const pages = ctx.browserContext.pages();
|
|
6082
6268
|
switch (p.subcommand) {
|
|
@@ -6089,7 +6275,7 @@ var tabCommand = registerCommand({
|
|
|
6089
6275
|
case "switch":
|
|
6090
6276
|
return handleSwitch(p, pages, ctx);
|
|
6091
6277
|
default:
|
|
6092
|
-
return
|
|
6278
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
6093
6279
|
}
|
|
6094
6280
|
}
|
|
6095
6281
|
});
|
|
@@ -6104,7 +6290,7 @@ async function handleList(pages, ctx) {
|
|
|
6104
6290
|
if (isActive) activeIndex = i;
|
|
6105
6291
|
tabs.push({ index: i, url, title, active: isActive });
|
|
6106
6292
|
}
|
|
6107
|
-
return
|
|
6293
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
6108
6294
|
}
|
|
6109
6295
|
async function handleNew(p, _pages, ctx) {
|
|
6110
6296
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -6132,7 +6318,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6132
6318
|
const title = await newPage.title().catch(() => "");
|
|
6133
6319
|
const allPages = ctx.browserContext.pages();
|
|
6134
6320
|
const newIndex = allPages.indexOf(newPage);
|
|
6135
|
-
return
|
|
6321
|
+
return ok27({
|
|
6136
6322
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
6137
6323
|
url: newPage.url(),
|
|
6138
6324
|
title,
|
|
@@ -6143,11 +6329,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6143
6329
|
async function handleClose(p, ctx) {
|
|
6144
6330
|
const currentPages = ctx.browserContext.pages();
|
|
6145
6331
|
if (currentPages.length <= 1) {
|
|
6146
|
-
return
|
|
6332
|
+
return fail13("Cannot close the last remaining tab");
|
|
6147
6333
|
}
|
|
6148
6334
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
6149
6335
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
6150
|
-
return
|
|
6336
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
6151
6337
|
}
|
|
6152
6338
|
const pageToClose = currentPages[closeIndex];
|
|
6153
6339
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -6162,7 +6348,7 @@ async function handleClose(p, ctx) {
|
|
|
6162
6348
|
}
|
|
6163
6349
|
ctx.page = newActivePage;
|
|
6164
6350
|
}
|
|
6165
|
-
return
|
|
6351
|
+
return ok27({
|
|
6166
6352
|
closedIndex: closeIndex,
|
|
6167
6353
|
total: remainingPages.length,
|
|
6168
6354
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -6170,10 +6356,10 @@ async function handleClose(p, ctx) {
|
|
|
6170
6356
|
}
|
|
6171
6357
|
async function handleSwitch(p, pages, ctx) {
|
|
6172
6358
|
if (p.index === void 0) {
|
|
6173
|
-
return
|
|
6359
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
6174
6360
|
}
|
|
6175
6361
|
if (p.index < 0 || p.index >= pages.length) {
|
|
6176
|
-
return
|
|
6362
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
6177
6363
|
}
|
|
6178
6364
|
const targetPage = pages[p.index];
|
|
6179
6365
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -6195,7 +6381,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6195
6381
|
}
|
|
6196
6382
|
ctx.page = targetPage;
|
|
6197
6383
|
const title = await targetPage.title().catch(() => "");
|
|
6198
|
-
return
|
|
6384
|
+
return ok27({
|
|
6199
6385
|
index: p.index,
|
|
6200
6386
|
url: targetPage.url(),
|
|
6201
6387
|
title,
|
|
@@ -6204,17 +6390,17 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6204
6390
|
}
|
|
6205
6391
|
|
|
6206
6392
|
// src/commands/addinitscript.ts
|
|
6207
|
-
import { z as
|
|
6208
|
-
import { ok as
|
|
6393
|
+
import { z as z29 } from "zod";
|
|
6394
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6209
6395
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6210
|
-
var InitScriptParams =
|
|
6211
|
-
script:
|
|
6212
|
-
file:
|
|
6213
|
-
stdin:
|
|
6214
|
-
name:
|
|
6215
|
-
list:
|
|
6216
|
-
remove:
|
|
6217
|
-
base64:
|
|
6396
|
+
var InitScriptParams = z29.object({
|
|
6397
|
+
script: z29.string().optional(),
|
|
6398
|
+
file: z29.string().optional(),
|
|
6399
|
+
stdin: z29.boolean().optional(),
|
|
6400
|
+
name: z29.string().optional(),
|
|
6401
|
+
list: z29.boolean().optional(),
|
|
6402
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6403
|
+
base64: z29.string().optional()
|
|
6218
6404
|
});
|
|
6219
6405
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6220
6406
|
function resolveScriptContent(params) {
|
|
@@ -6248,14 +6434,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6248
6434
|
description: "Add an initialization script that runs on every page load",
|
|
6249
6435
|
scope: "page",
|
|
6250
6436
|
parameters: InitScriptParams,
|
|
6251
|
-
result:
|
|
6252
|
-
scripts:
|
|
6253
|
-
removed:
|
|
6254
|
-
existed:
|
|
6255
|
-
error:
|
|
6256
|
-
registered:
|
|
6257
|
-
hint:
|
|
6258
|
-
executedImmediately:
|
|
6437
|
+
result: z29.object({
|
|
6438
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6439
|
+
removed: z29.string().optional(),
|
|
6440
|
+
existed: z29.boolean().optional(),
|
|
6441
|
+
error: z29.string().optional(),
|
|
6442
|
+
registered: z29.string().optional(),
|
|
6443
|
+
hint: z29.string().optional(),
|
|
6444
|
+
executedImmediately: z29.boolean().optional()
|
|
6259
6445
|
}).passthrough(),
|
|
6260
6446
|
handler: async (params, ctx) => {
|
|
6261
6447
|
if (params.list) {
|
|
@@ -6264,20 +6450,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6264
6450
|
size: content2.length,
|
|
6265
6451
|
preview: content2.slice(0, 80)
|
|
6266
6452
|
}));
|
|
6267
|
-
return
|
|
6453
|
+
return ok28({ scripts });
|
|
6268
6454
|
}
|
|
6269
6455
|
if (params.remove && typeof params.remove === "string") {
|
|
6270
6456
|
const existed = registeredScripts.delete(params.remove);
|
|
6271
|
-
return
|
|
6457
|
+
return ok28({ removed: params.remove, existed });
|
|
6272
6458
|
}
|
|
6273
6459
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6274
6460
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6275
6461
|
const existed = registeredScripts.delete(removeTarget);
|
|
6276
|
-
return
|
|
6462
|
+
return ok28({ removed: removeTarget, existed });
|
|
6277
6463
|
}
|
|
6278
6464
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6279
6465
|
if (!content) {
|
|
6280
|
-
return
|
|
6466
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6281
6467
|
}
|
|
6282
6468
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6283
6469
|
registeredScripts.set(scriptName, content);
|
|
@@ -6285,45 +6471,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6285
6471
|
try {
|
|
6286
6472
|
await ctx.page.evaluate(content);
|
|
6287
6473
|
} catch {
|
|
6288
|
-
return
|
|
6474
|
+
return ok28({
|
|
6289
6475
|
registered: scriptName,
|
|
6290
6476
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6291
6477
|
});
|
|
6292
6478
|
}
|
|
6293
|
-
return
|
|
6479
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6294
6480
|
}
|
|
6295
6481
|
});
|
|
6296
6482
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6297
6483
|
|
|
6298
6484
|
// src/commands/find.ts
|
|
6299
|
-
import { z as
|
|
6300
|
-
import { ok as
|
|
6301
|
-
var actionSchema2 =
|
|
6485
|
+
import { z as z30 } from "zod";
|
|
6486
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6487
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6302
6488
|
var findCommand = registerCommand({
|
|
6303
6489
|
name: "find",
|
|
6304
6490
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6305
6491
|
scope: "page",
|
|
6306
|
-
parameters:
|
|
6307
|
-
strategy:
|
|
6308
|
-
value:
|
|
6309
|
-
name:
|
|
6310
|
-
exact:
|
|
6311
|
-
operation:
|
|
6492
|
+
parameters: z30.object({
|
|
6493
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6494
|
+
value: z30.string(),
|
|
6495
|
+
name: z30.string().optional(),
|
|
6496
|
+
exact: z30.boolean().optional().default(false),
|
|
6497
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6312
6498
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6313
|
-
actionValue:
|
|
6314
|
-
index:
|
|
6315
|
-
click:
|
|
6316
|
-
fill:
|
|
6317
|
-
type:
|
|
6318
|
-
select:
|
|
6319
|
-
hover:
|
|
6320
|
-
check:
|
|
6321
|
-
timeout:
|
|
6499
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6500
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6501
|
+
click: z30.boolean().optional().default(false),
|
|
6502
|
+
fill: z30.string().optional(),
|
|
6503
|
+
type: z30.string().optional(),
|
|
6504
|
+
select: z30.string().optional(),
|
|
6505
|
+
hover: z30.boolean().optional().default(false),
|
|
6506
|
+
check: z30.boolean().optional().default(false),
|
|
6507
|
+
timeout: z30.number().optional().default(1e4)
|
|
6322
6508
|
}),
|
|
6323
|
-
result:
|
|
6324
|
-
matched:
|
|
6325
|
-
selector:
|
|
6326
|
-
action:
|
|
6509
|
+
result: z30.object({
|
|
6510
|
+
matched: z30.number(),
|
|
6511
|
+
selector: z30.string(),
|
|
6512
|
+
action: z30.string().optional()
|
|
6327
6513
|
}),
|
|
6328
6514
|
handler: async (p, ctx) => {
|
|
6329
6515
|
const page = ctx.page;
|
|
@@ -6338,7 +6524,7 @@ var findCommand = registerCommand({
|
|
|
6338
6524
|
});
|
|
6339
6525
|
const count = await locator.count();
|
|
6340
6526
|
if (count === 0) {
|
|
6341
|
-
return
|
|
6527
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6342
6528
|
}
|
|
6343
6529
|
const tips = [];
|
|
6344
6530
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6350,15 +6536,15 @@ var findCommand = registerCommand({
|
|
|
6350
6536
|
await target.click({ timeout: p.timeout, force: true });
|
|
6351
6537
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6352
6538
|
} else if (actionName === "fill") {
|
|
6353
|
-
if (actionValue === void 0) return
|
|
6539
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6354
6540
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6355
6541
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6356
6542
|
} else if (actionName === "type") {
|
|
6357
|
-
if (actionValue === void 0) return
|
|
6543
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6358
6544
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6359
6545
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6360
6546
|
} else if (actionName === "select") {
|
|
6361
|
-
if (actionValue === void 0) return
|
|
6547
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6362
6548
|
await target.selectOption(actionValue);
|
|
6363
6549
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6364
6550
|
} else if (actionName === "hover") {
|
|
@@ -6372,8 +6558,8 @@ var findCommand = registerCommand({
|
|
|
6372
6558
|
}
|
|
6373
6559
|
});
|
|
6374
6560
|
function okWithTips(data, tips) {
|
|
6375
|
-
const result =
|
|
6376
|
-
if (tips.length > 0) result.tips =
|
|
6561
|
+
const result = ok29(data);
|
|
6562
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6377
6563
|
return result;
|
|
6378
6564
|
}
|
|
6379
6565
|
function parseOperation(operation) {
|
|
@@ -6471,8 +6657,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6471
6657
|
}
|
|
6472
6658
|
|
|
6473
6659
|
// src/commands/visual-tag.ts
|
|
6474
|
-
import { z as
|
|
6475
|
-
import { ok as
|
|
6660
|
+
import { z as z31 } from "zod";
|
|
6661
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6476
6662
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6477
6663
|
var TAG_SCRIPT = `
|
|
6478
6664
|
(function() {
|
|
@@ -6563,49 +6749,49 @@ var visualTagCommand = registerCommand({
|
|
|
6563
6749
|
name: "visual-tag",
|
|
6564
6750
|
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",
|
|
6565
6751
|
scope: "page",
|
|
6566
|
-
parameters:
|
|
6567
|
-
action:
|
|
6568
|
-
id:
|
|
6752
|
+
parameters: z31.object({
|
|
6753
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6754
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6569
6755
|
}),
|
|
6570
|
-
result:
|
|
6571
|
-
action:
|
|
6572
|
-
tagged:
|
|
6573
|
-
id:
|
|
6574
|
-
element:
|
|
6756
|
+
result: z31.object({
|
|
6757
|
+
action: z31.string(),
|
|
6758
|
+
tagged: z31.number().optional(),
|
|
6759
|
+
id: z31.string().optional(),
|
|
6760
|
+
element: z31.record(z31.unknown()).optional()
|
|
6575
6761
|
}),
|
|
6576
6762
|
handler: async (p, ctx) => {
|
|
6577
6763
|
switch (p.action) {
|
|
6578
6764
|
case "tag": {
|
|
6579
6765
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6580
6766
|
const parsed = JSON.parse(result);
|
|
6581
|
-
return
|
|
6767
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6582
6768
|
}
|
|
6583
6769
|
case "lookup": {
|
|
6584
|
-
if (!p.id) return
|
|
6770
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6585
6771
|
const result = await ctx.page.evaluate(
|
|
6586
6772
|
`(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'}); })()`
|
|
6587
6773
|
);
|
|
6588
6774
|
const parsed = JSON.parse(result);
|
|
6589
|
-
if (parsed.err) return
|
|
6590
|
-
return
|
|
6775
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6776
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6591
6777
|
}
|
|
6592
6778
|
case "list": {
|
|
6593
6779
|
const result = await ctx.page.evaluate(
|
|
6594
6780
|
`(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); })()`
|
|
6595
6781
|
);
|
|
6596
|
-
return
|
|
6782
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6597
6783
|
}
|
|
6598
6784
|
case "clear": {
|
|
6599
6785
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6600
|
-
return
|
|
6786
|
+
return ok30({ action: "clear" });
|
|
6601
6787
|
}
|
|
6602
6788
|
}
|
|
6603
6789
|
}
|
|
6604
6790
|
});
|
|
6605
6791
|
|
|
6606
6792
|
// src/commands/visual-tag-v2.ts
|
|
6607
|
-
import { z as
|
|
6608
|
-
import { ok as
|
|
6793
|
+
import { z as z32 } from "zod";
|
|
6794
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6609
6795
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6610
6796
|
var TAG_V2_SCRIPT = `
|
|
6611
6797
|
(function() {
|
|
@@ -6952,45 +7138,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6952
7138
|
name: "visual-tag-v2",
|
|
6953
7139
|
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",
|
|
6954
7140
|
scope: "page",
|
|
6955
|
-
parameters:
|
|
6956
|
-
action:
|
|
6957
|
-
id:
|
|
6958
|
-
query:
|
|
6959
|
-
type:
|
|
6960
|
-
"interact-action":
|
|
6961
|
-
value:
|
|
7141
|
+
parameters: z32.object({
|
|
7142
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7143
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7144
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7145
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7146
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7147
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6962
7148
|
}),
|
|
6963
|
-
result:
|
|
6964
|
-
action:
|
|
6965
|
-
total:
|
|
6966
|
-
byType:
|
|
6967
|
-
element:
|
|
7149
|
+
result: z32.object({
|
|
7150
|
+
action: z32.string(),
|
|
7151
|
+
total: z32.number().optional(),
|
|
7152
|
+
byType: z32.record(z32.number()).optional(),
|
|
7153
|
+
element: z32.record(z32.unknown()).optional()
|
|
6968
7154
|
}),
|
|
6969
7155
|
handler: async (p, ctx) => {
|
|
6970
7156
|
switch (p.action) {
|
|
6971
7157
|
case "tag": {
|
|
6972
7158
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6973
7159
|
const parsed = JSON.parse(result);
|
|
6974
|
-
return
|
|
7160
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6975
7161
|
}
|
|
6976
7162
|
case "lookup": {
|
|
6977
|
-
if (!p.id) return
|
|
7163
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6978
7164
|
const result = await ctx.page.evaluate(
|
|
6979
7165
|
`(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'})})()`
|
|
6980
7166
|
);
|
|
6981
7167
|
const parsed = JSON.parse(result);
|
|
6982
|
-
if (parsed.err) return
|
|
6983
|
-
return
|
|
7168
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7169
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6984
7170
|
}
|
|
6985
7171
|
case "by-type": {
|
|
6986
7172
|
const result = await ctx.page.evaluate(
|
|
6987
7173
|
`(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)})()`
|
|
6988
7174
|
);
|
|
6989
|
-
return
|
|
7175
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6990
7176
|
}
|
|
6991
7177
|
case "find": {
|
|
6992
7178
|
const query = p.query;
|
|
6993
|
-
if (!query) return
|
|
7179
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6994
7180
|
const result = await ctx.page.evaluate(
|
|
6995
7181
|
`(function(){
|
|
6996
7182
|
var map = window.__xbTagSerializable;
|
|
@@ -7032,21 +7218,21 @@ var visualTagV2Command = registerCommand({
|
|
|
7032
7218
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
7033
7219
|
})()`
|
|
7034
7220
|
);
|
|
7035
|
-
return
|
|
7221
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
7036
7222
|
}
|
|
7037
7223
|
case "stats": {
|
|
7038
7224
|
const result = await ctx.page.evaluate(
|
|
7039
7225
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
7040
7226
|
);
|
|
7041
|
-
return
|
|
7227
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
7042
7228
|
}
|
|
7043
7229
|
case "interact": {
|
|
7044
7230
|
const query = p.query;
|
|
7045
7231
|
const pAny = p;
|
|
7046
7232
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
7047
7233
|
const value = pAny.value;
|
|
7048
|
-
if (!query) return
|
|
7049
|
-
if (!action) return
|
|
7234
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7235
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
7050
7236
|
const findResult = await ctx.page.evaluate(
|
|
7051
7237
|
`(function(){
|
|
7052
7238
|
var map = window.__xbTagSerializable;
|
|
@@ -7076,11 +7262,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7076
7262
|
})()`
|
|
7077
7263
|
);
|
|
7078
7264
|
const parsed = JSON.parse(findResult);
|
|
7079
|
-
if (parsed.err) return
|
|
7080
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7265
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7266
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7081
7267
|
const target = parsed.results[0];
|
|
7082
7268
|
if (action === "read") {
|
|
7083
|
-
return
|
|
7269
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7084
7270
|
}
|
|
7085
7271
|
if (action === "click") {
|
|
7086
7272
|
const el = await ctx.page.evaluate(
|
|
@@ -7093,12 +7279,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7093
7279
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7094
7280
|
})()`
|
|
7095
7281
|
);
|
|
7096
|
-
if (!el) return
|
|
7282
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7097
7283
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7098
|
-
return
|
|
7284
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7099
7285
|
}
|
|
7100
7286
|
if (action === "fill") {
|
|
7101
|
-
if (!value) return
|
|
7287
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7102
7288
|
const el = await ctx.page.evaluate(
|
|
7103
7289
|
`(function(){
|
|
7104
7290
|
var map = window.__xbTagMap;
|
|
@@ -7109,12 +7295,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7109
7295
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7110
7296
|
})()`
|
|
7111
7297
|
);
|
|
7112
|
-
if (!el) return
|
|
7298
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7113
7299
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7114
7300
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7115
|
-
return
|
|
7301
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7116
7302
|
}
|
|
7117
|
-
return
|
|
7303
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7118
7304
|
}
|
|
7119
7305
|
case "export": {
|
|
7120
7306
|
const result = await ctx.page.evaluate(
|
|
@@ -7162,12 +7348,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7162
7348
|
})()`
|
|
7163
7349
|
);
|
|
7164
7350
|
const parsed = JSON.parse(result);
|
|
7165
|
-
if (parsed.err) return
|
|
7166
|
-
return
|
|
7351
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7352
|
+
return ok31({ action: "export", element: parsed });
|
|
7167
7353
|
}
|
|
7168
7354
|
case "clear": {
|
|
7169
7355
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7170
|
-
return
|
|
7356
|
+
return ok31({ action: "clear" });
|
|
7171
7357
|
}
|
|
7172
7358
|
}
|
|
7173
7359
|
}
|
|
@@ -7693,12 +7879,12 @@ function classifyFailure(message) {
|
|
|
7693
7879
|
|
|
7694
7880
|
// src/executor.ts
|
|
7695
7881
|
import {
|
|
7696
|
-
ok as
|
|
7697
|
-
fail as
|
|
7882
|
+
ok as ok32,
|
|
7883
|
+
fail as fail17,
|
|
7698
7884
|
isCommandResult,
|
|
7699
7885
|
CompositeStorage as CompositeStorage2,
|
|
7700
7886
|
TipCollector as TipCollector2,
|
|
7701
|
-
normalizeTips as
|
|
7887
|
+
normalizeTips as normalizeTips7,
|
|
7702
7888
|
configureArchiveStore,
|
|
7703
7889
|
appendCommandToArchive,
|
|
7704
7890
|
checkGuard,
|
|
@@ -8565,7 +8751,7 @@ async function guardCheck(commandName) {
|
|
|
8565
8751
|
}
|
|
8566
8752
|
}
|
|
8567
8753
|
function errorResult(message) {
|
|
8568
|
-
return { ...
|
|
8754
|
+
return { ...fail17(message), duration: 0 };
|
|
8569
8755
|
}
|
|
8570
8756
|
function tipsToMessages(tips) {
|
|
8571
8757
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8757,7 +8943,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8757
8943
|
const cache = /* @__PURE__ */ new Map();
|
|
8758
8944
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
8759
8945
|
if (resolved.tips.length > 0) {
|
|
8760
|
-
refTips =
|
|
8946
|
+
refTips = normalizeTips7(resolved.tips);
|
|
8761
8947
|
params = resolved.params;
|
|
8762
8948
|
}
|
|
8763
8949
|
}
|
|
@@ -8825,8 +9011,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8825
9011
|
}
|
|
8826
9012
|
const merged = [
|
|
8827
9013
|
...raw.tips || [],
|
|
8828
|
-
...
|
|
8829
|
-
...snapshotHint ?
|
|
9014
|
+
...normalizeTips7(smartTips),
|
|
9015
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8830
9016
|
...refTips
|
|
8831
9017
|
];
|
|
8832
9018
|
const isSuccess = raw.success !== false;
|
|
@@ -8841,7 +9027,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8841
9027
|
timestamp: start
|
|
8842
9028
|
});
|
|
8843
9029
|
if (isSuccess) {
|
|
8844
|
-
return { ...
|
|
9030
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8845
9031
|
}
|
|
8846
9032
|
const fc = classifyFailure(raw.message);
|
|
8847
9033
|
return {
|
|
@@ -8854,7 +9040,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8854
9040
|
...hookOutputs ? { hookOutputs } : {}
|
|
8855
9041
|
};
|
|
8856
9042
|
}
|
|
8857
|
-
const smartTipNormalized =
|
|
9043
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8858
9044
|
recordArchive(session?.id, sessionName, {
|
|
8859
9045
|
step: 0,
|
|
8860
9046
|
command: commandName,
|
|
@@ -8864,7 +9050,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8864
9050
|
duration,
|
|
8865
9051
|
timestamp: start
|
|
8866
9052
|
});
|
|
8867
|
-
return { ...
|
|
9053
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8868
9054
|
} catch (err) {
|
|
8869
9055
|
const end = Date.now();
|
|
8870
9056
|
const duration = end - start;
|
|
@@ -8909,7 +9095,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8909
9095
|
duration,
|
|
8910
9096
|
timestamp: start
|
|
8911
9097
|
});
|
|
8912
|
-
return { ...
|
|
9098
|
+
return { ...fail17(errorMessage), duration };
|
|
8913
9099
|
} finally {
|
|
8914
9100
|
}
|
|
8915
9101
|
}
|
|
@@ -8954,7 +9140,7 @@ async function executeChain(input, options) {
|
|
|
8954
9140
|
results.push({
|
|
8955
9141
|
command: cmdName,
|
|
8956
9142
|
raw: cmdStr,
|
|
8957
|
-
...
|
|
9143
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8958
9144
|
duration: 0
|
|
8959
9145
|
});
|
|
8960
9146
|
if (type === "and") {
|
|
@@ -8973,7 +9159,7 @@ async function executeChain(input, options) {
|
|
|
8973
9159
|
results.push({
|
|
8974
9160
|
command: cmdName,
|
|
8975
9161
|
raw: cmdStr,
|
|
8976
|
-
...
|
|
9162
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8977
9163
|
duration: 0
|
|
8978
9164
|
});
|
|
8979
9165
|
if (type === "and") {
|
|
@@ -9043,7 +9229,7 @@ async function executeChain(input, options) {
|
|
|
9043
9229
|
success: false,
|
|
9044
9230
|
data: data2,
|
|
9045
9231
|
message: loginGuard.message,
|
|
9046
|
-
tips:
|
|
9232
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
9047
9233
|
duration: duration3
|
|
9048
9234
|
});
|
|
9049
9235
|
if (type === "and") {
|
|
@@ -9085,7 +9271,7 @@ async function executeChain(input, options) {
|
|
|
9085
9271
|
results.push({
|
|
9086
9272
|
command: `${cmdName} ${subCommand}`,
|
|
9087
9273
|
raw: cmdStr,
|
|
9088
|
-
...
|
|
9274
|
+
...ok32(data),
|
|
9089
9275
|
duration: duration2,
|
|
9090
9276
|
...hookOutputs ? { hookOutputs } : {}
|
|
9091
9277
|
});
|
|
@@ -9113,7 +9299,7 @@ async function executeChain(input, options) {
|
|
|
9113
9299
|
results.push({
|
|
9114
9300
|
command: `${cmdName} ${subCommand}`,
|
|
9115
9301
|
raw: cmdStr,
|
|
9116
|
-
...
|
|
9302
|
+
...fail17(errorMessage),
|
|
9117
9303
|
duration: duration2
|
|
9118
9304
|
});
|
|
9119
9305
|
if (type === "and") {
|