@xbrowser/cli 1.25.2 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{browser-L3TUDYY3.js → browser-4IYIHZ6R.js} +3 -3
- package/dist/{browser-33QQWEDI.js → browser-NYYCR4O7.js} +2 -2
- package/dist/{browser-4LOJSMWV.js → browser-ZD53IMUJ.js} +3 -3
- package/dist/{cdp-driver-BYW7WY7E.js → cdp-driver-4X6Q62WI.js} +2 -2
- package/dist/{cdp-driver-5YVI5AIS.js → cdp-driver-EFEW4ZEN.js} +2 -2
- package/dist/{cdp-driver-MEK5EDEK.js → cdp-driver-HB744QB4.js} +3 -3
- package/dist/{chunk-ZOYM7QMS.js → chunk-3PUOISKE.js} +1 -1
- package/dist/{chunk-2EEAXSBA.js → chunk-HSYRAV3H.js} +3 -3
- package/dist/{chunk-DRKL2RFQ.js → chunk-IDXOIXQR.js} +320 -144
- package/dist/{chunk-U6GFDVNI.js → chunk-J3HXZVSN.js} +3 -3
- package/dist/{chunk-NNI5RT4A.js → chunk-KECYFWJO.js} +1 -1
- package/dist/{chunk-CGNHGAIJ.js → chunk-ME5FO5YV.js} +3 -3
- package/dist/{chunk-MYH6FIBZ.js → chunk-SEEWE5SJ.js} +5 -1
- package/dist/{chunk-VCVDILH6.js → chunk-T2AI24A5.js} +5 -1
- package/dist/{chunk-PO27V5UH.js → chunk-YITK42HZ.js} +320 -144
- package/dist/cli.js +6 -6
- package/dist/daemon-main.js +326 -150
- package/dist/index.js +7 -7
- package/dist/{launcher-LUOMMGZC.js → launcher-SJ44X25U.js} +1 -1
- package/dist/{launcher-IK2FKW6T.js → launcher-XHKIC4GP.js} +1 -1
- package/dist/{server-IBQGNDSB.js → server-WDDGIV3C.js} +147 -4
- package/dist/{server-EZJW6IHU.js → server-YKMRFDEM.js} +146 -3
- package/dist/{session-replayer-PJIUH7KI.js → session-replayer-TXTNTG33.js} +89 -44
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resolveLaunchOpts,
|
|
10
10
|
saveSessionDiskMeta,
|
|
11
11
|
setActivePage
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-KECYFWJO.js";
|
|
13
13
|
import {
|
|
14
14
|
detectAntiBot,
|
|
15
15
|
formatDetectionMessage
|
|
@@ -867,10 +867,14 @@ var clickCommand = registerCommand({
|
|
|
867
867
|
targetIdsBefore = /* @__PURE__ */ new Set();
|
|
868
868
|
}
|
|
869
869
|
const pagePromise = new Promise((resolve3) => {
|
|
870
|
+
const waitMs = (() => {
|
|
871
|
+
const v = parseInt(process.env.XBROWSER_NEW_TAB_WAIT ?? "250", 10);
|
|
872
|
+
return Number.isFinite(v) && v > 0 ? v : 250;
|
|
873
|
+
})();
|
|
870
874
|
const timer = setTimeout(() => {
|
|
871
875
|
ctx.browserContext.off("page", handler);
|
|
872
876
|
resolve3(void 0);
|
|
873
|
-
},
|
|
877
|
+
}, waitMs);
|
|
874
878
|
const handler = (page2) => {
|
|
875
879
|
if (targetIdsBefore.has(targetIdOf(page2))) return;
|
|
876
880
|
try {
|
|
@@ -6053,26 +6057,193 @@ var waitForCommand = registerCommand({
|
|
|
6053
6057
|
}
|
|
6054
6058
|
});
|
|
6055
6059
|
|
|
6056
|
-
// src/commands/
|
|
6060
|
+
// src/commands/task.ts
|
|
6057
6061
|
import { z as z27 } from "zod";
|
|
6058
|
-
import { ok as ok26, fail as fail12 } from "@dyyz1993/xcli-core";
|
|
6059
|
-
var
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6062
|
+
import { ok as ok26, fail as fail12, normalizeTips as normalizeTips5 } from "@dyyz1993/xcli-core";
|
|
6063
|
+
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
|
|
6064
|
+
|
|
6065
|
+
\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
|
|
6066
|
+
{"action":"click","ref":"@eN","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6067
|
+
{"action":"fill","ref":"@eN","value":"\u6587\u672C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6068
|
+
{"action":"select","ref":"@eN","value":"\u9009\u9879\u503C","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6069
|
+
{"action":"press","value":"Enter","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6070
|
+
{"action":"scroll","value":"down \u6216 up","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6071
|
+
{"action":"done","value":"\u5B8C\u6210\u6458\u8981","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6072
|
+
{"action":"blocked","value":"\u5361\u4F4F\u539F\u56E0","thought":"\u4E3A\u4EC0\u4E48"}
|
|
6073
|
+
|
|
6074
|
+
\u89C4\u5219\uFF1A
|
|
6075
|
+
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
|
|
6076
|
+
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
|
|
6077
|
+
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`;
|
|
6078
|
+
function extractDecision(raw) {
|
|
6079
|
+
let s = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "");
|
|
6080
|
+
const start = s.indexOf("{");
|
|
6081
|
+
if (start < 0) return null;
|
|
6082
|
+
let depth = 0;
|
|
6083
|
+
for (let i = start; i < s.length; i++) {
|
|
6084
|
+
if (s[i] === "{") depth++;
|
|
6085
|
+
else if (s[i] === "}") {
|
|
6086
|
+
depth--;
|
|
6087
|
+
if (depth === 0) {
|
|
6088
|
+
try {
|
|
6089
|
+
return JSON.parse(s.slice(start, i + 1));
|
|
6090
|
+
} catch {
|
|
6091
|
+
return null;
|
|
6092
|
+
}
|
|
6093
|
+
}
|
|
6094
|
+
}
|
|
6095
|
+
}
|
|
6096
|
+
return null;
|
|
6097
|
+
}
|
|
6098
|
+
var taskCommand = registerCommand({
|
|
6099
|
+
name: "task",
|
|
6100
|
+
description: "Autonomous goal loop: observe refs \u2192 LLM decides \u2192 act, until done/blocked (budget-capped)",
|
|
6101
|
+
scope: "page",
|
|
6102
|
+
parameters: z27.object({
|
|
6103
|
+
goal: z27.string().describe("Natural-language goal"),
|
|
6104
|
+
maxSteps: z27.number().int().positive().max(50).optional().default(15).describe("Hard action budget"),
|
|
6105
|
+
timeout: z27.number().optional().default(18e4).describe("Wall clock budget in ms"),
|
|
6106
|
+
limit: z27.number().int().positive().max(300).optional().default(80).describe("Max targets per observe")
|
|
6107
|
+
}),
|
|
6108
|
+
result: z27.object({
|
|
6109
|
+
status: z27.enum(["done", "blocked", "max_steps", "error"]),
|
|
6110
|
+
summary: z27.string().optional(),
|
|
6111
|
+
steps: z27.array(z27.record(z27.unknown())),
|
|
6112
|
+
finalUrl: z27.string().optional(),
|
|
6113
|
+
usage: z27.object({ llmCalls: z27.number(), steps: z27.number() }).passthrough().optional()
|
|
6114
|
+
}).passthrough(),
|
|
6115
|
+
handler: async (p, ctx) => {
|
|
6116
|
+
const creds = loadVLMCredentials2();
|
|
6117
|
+
if (!creds) {
|
|
6118
|
+
return fail12("task \u9700\u8981\u51B3\u7B56\u6A21\u578B\u51ED\u8BC1\uFF1A\u8BBE\u7F6E XBROWSER_VLM_CONFIG \u6216 ~/.zcode/v2/config.json");
|
|
6119
|
+
}
|
|
6120
|
+
const model = process.env.XBROWSER_TASK_MODEL || creds.model;
|
|
6121
|
+
const started = Date.now();
|
|
6122
|
+
const steps = [];
|
|
6123
|
+
const history = [];
|
|
6124
|
+
let llmCalls = 0;
|
|
6125
|
+
let status = "max_steps";
|
|
6126
|
+
let summary = "";
|
|
6127
|
+
let lastError = "";
|
|
6128
|
+
for (let step = 1; step <= p.maxSteps; step++) {
|
|
6129
|
+
if (Date.now() - started > p.timeout) {
|
|
6130
|
+
status = "blocked";
|
|
6131
|
+
summary = `timeout after ${step - 1} steps`;
|
|
6132
|
+
break;
|
|
6133
|
+
}
|
|
6134
|
+
const obs = await observePage(ctx.page, ctx.sessionId, { limit: p.limit, includeHidden: false });
|
|
6135
|
+
const compact = obs.compact ?? obs.targets.map((t, i) => `@e${i + 1} [${t.tag ?? ""}] ${t.name ?? ""}`).join("\n");
|
|
6136
|
+
const screenHash = obs.screenHash;
|
|
6137
|
+
const userPayload = [
|
|
6138
|
+
`\u76EE\u6807\uFF1A${p.goal}`,
|
|
6139
|
+
`\u5F53\u524D\u9875\u9762\uFF08URL: ${obs.url ?? ""}\uFF09\uFF1A`,
|
|
6140
|
+
compact,
|
|
6141
|
+
history.length ? `
|
|
6142
|
+
\u5DF2\u6267\u884C\uFF08\u52FF\u91CD\u590D\u5931\u8D25\u52A8\u4F5C\uFF09\uFF1A
|
|
6143
|
+
${history.slice(-6).join("\n")}` : ""
|
|
6144
|
+
].filter(Boolean).join("\n");
|
|
6145
|
+
let raw = "";
|
|
6146
|
+
try {
|
|
6147
|
+
raw = await vlmAsk({ ...creds, model }, [{ type: "text", text: `${DECISION_SYSTEM}
|
|
6148
|
+
|
|
6149
|
+
---
|
|
6150
|
+
|
|
6151
|
+
${userPayload}` }], 900);
|
|
6152
|
+
llmCalls++;
|
|
6153
|
+
} catch (e) {
|
|
6154
|
+
lastError = e instanceof Error ? e.message : String(e);
|
|
6155
|
+
status = "error";
|
|
6156
|
+
summary = `LLM call failed: ${lastError}`;
|
|
6157
|
+
break;
|
|
6158
|
+
}
|
|
6159
|
+
const decision = extractDecision(raw);
|
|
6160
|
+
if (!decision || typeof decision.action !== "string") {
|
|
6161
|
+
status = "blocked";
|
|
6162
|
+
summary = `LLM returned unparsable decision: ${raw.slice(0, 120)}`;
|
|
6163
|
+
break;
|
|
6164
|
+
}
|
|
6165
|
+
const action = decision.action;
|
|
6166
|
+
const ref = typeof decision.ref === "string" ? decision.ref : void 0;
|
|
6167
|
+
const value = typeof decision.value === "string" ? decision.value : void 0;
|
|
6168
|
+
const thought = typeof decision.thought === "string" ? decision.thought : void 0;
|
|
6169
|
+
if (action === "done") {
|
|
6170
|
+
status = "done";
|
|
6171
|
+
summary = value || thought || "task done";
|
|
6172
|
+
steps.push({ step, thought, action: "done", ok: true, screenHash });
|
|
6173
|
+
break;
|
|
6174
|
+
}
|
|
6175
|
+
if (action === "blocked") {
|
|
6176
|
+
status = "blocked";
|
|
6177
|
+
summary = value || thought || "LLM judged blocked";
|
|
6178
|
+
steps.push({ step, thought, action: "blocked", ok: true, screenHash });
|
|
6179
|
+
break;
|
|
6180
|
+
}
|
|
6181
|
+
const legalRefs = new Set(obs.targets.map((t, i) => t.ref ?? `e${i + 1}`));
|
|
6182
|
+
const normalizedRef = ref ? legalRefs.has(ref.replace("@", "")) || legalRefs.has(ref) ? ref : void 0 : void 0;
|
|
6183
|
+
if (ref && !normalizedRef && action !== "scroll" && action !== "press") {
|
|
6184
|
+
history.push(`step${step}: ${action} ${ref} REJECTED (ref not in current list)`);
|
|
6185
|
+
steps.push({ step, thought, action, ref, ok: false, error: "ref not in current list", screenHash });
|
|
6186
|
+
continue;
|
|
6187
|
+
}
|
|
6188
|
+
const res = await actOnPage(ctx.page, ctx.sessionId, {
|
|
6189
|
+
action,
|
|
6190
|
+
ref: normalizedRef,
|
|
6191
|
+
value,
|
|
6192
|
+
selector: void 0,
|
|
6193
|
+
force: false,
|
|
6194
|
+
timeout: 1e4
|
|
6195
|
+
});
|
|
6196
|
+
const record = {
|
|
6197
|
+
step,
|
|
6198
|
+
thought,
|
|
6199
|
+
action,
|
|
6200
|
+
ref: normalizedRef,
|
|
6201
|
+
value,
|
|
6202
|
+
ok: res.success === true,
|
|
6203
|
+
stale: res.stale,
|
|
6204
|
+
error: res.success ? void 0 : res.message || res.reason,
|
|
6205
|
+
screenHash
|
|
6206
|
+
};
|
|
6207
|
+
steps.push(record);
|
|
6208
|
+
history.push(`step${step}: ${action} ${normalizedRef ?? ""} ${value ?? ""} -> ${res.success ? "ok" : `failed(${res.reason || res.message})`}`);
|
|
6209
|
+
const sig = (s) => `${s.action}|${s.ref ?? ""}|${s.value ?? ""}`;
|
|
6210
|
+
const last3 = steps.slice(-3);
|
|
6211
|
+
if (last3.length === 3 && new Set(last3.map(sig)).size === 1) {
|
|
6212
|
+
status = "blocked";
|
|
6213
|
+
summary = "dead loop: identical action repeated 3 times";
|
|
6214
|
+
break;
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
if (status === "max_steps") summary = summary || `hit maxSteps=${p.maxSteps}`;
|
|
6218
|
+
const finalUrl = ctx.page ? ctx.page.url() : void 0;
|
|
6219
|
+
const data = { status, summary, steps, finalUrl, usage: { llmCalls, steps: steps.length } };
|
|
6220
|
+
if (status === "error") return fail12(summary || lastError, normalizeTips5([`completed steps: ${steps.length}`]));
|
|
6221
|
+
return ok26(data, normalizeTips5([
|
|
6222
|
+
status === "done" ? `\u2705 task done (${steps.length} steps, ${llmCalls} LLM calls)` : `\u26A0\uFE0F task ${status}: ${summary.slice(0, 80)}`
|
|
6223
|
+
]));
|
|
6224
|
+
}
|
|
6225
|
+
});
|
|
6226
|
+
|
|
6227
|
+
// src/commands/tab.ts
|
|
6228
|
+
import { z as z28 } from "zod";
|
|
6229
|
+
import { ok as ok27, fail as fail13 } from "@dyyz1993/xcli-core";
|
|
6230
|
+
var TabParams = z28.object({
|
|
6231
|
+
subcommand: z28.enum(["list", "new", "close", "switch"]),
|
|
6232
|
+
url: z28.string().optional(),
|
|
6233
|
+
index: z28.number().int().min(0).optional()
|
|
6063
6234
|
});
|
|
6064
6235
|
var tabCommand = registerCommand({
|
|
6065
6236
|
name: "tab",
|
|
6066
6237
|
description: "Manage browser tabs: list, new, close, switch",
|
|
6067
6238
|
scope: "page",
|
|
6068
6239
|
parameters: TabParams,
|
|
6069
|
-
result:
|
|
6070
|
-
success:
|
|
6071
|
-
data:
|
|
6240
|
+
result: z28.object({
|
|
6241
|
+
success: z28.boolean(),
|
|
6242
|
+
data: z28.unknown()
|
|
6072
6243
|
}),
|
|
6073
6244
|
handler: async (p, ctx) => {
|
|
6074
6245
|
if (!ctx.browserContext) {
|
|
6075
|
-
return
|
|
6246
|
+
return fail13("No browser context available. Use --cdp to connect to a browser first.");
|
|
6076
6247
|
}
|
|
6077
6248
|
const pages = ctx.browserContext.pages();
|
|
6078
6249
|
switch (p.subcommand) {
|
|
@@ -6085,7 +6256,7 @@ var tabCommand = registerCommand({
|
|
|
6085
6256
|
case "switch":
|
|
6086
6257
|
return handleSwitch(p, pages, ctx);
|
|
6087
6258
|
default:
|
|
6088
|
-
return
|
|
6259
|
+
return fail13(`Unknown subcommand: ${p.subcommand}`);
|
|
6089
6260
|
}
|
|
6090
6261
|
}
|
|
6091
6262
|
});
|
|
@@ -6100,7 +6271,7 @@ async function handleList(pages, ctx) {
|
|
|
6100
6271
|
if (isActive) activeIndex = i;
|
|
6101
6272
|
tabs.push({ index: i, url, title, active: isActive });
|
|
6102
6273
|
}
|
|
6103
|
-
return
|
|
6274
|
+
return ok27({ tabs, total: tabs.length, activeIndex });
|
|
6104
6275
|
}
|
|
6105
6276
|
async function handleNew(p, _pages, ctx) {
|
|
6106
6277
|
const newPage = await ctx.browserContext.newPage();
|
|
@@ -6128,7 +6299,7 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6128
6299
|
const title = await newPage.title().catch(() => "");
|
|
6129
6300
|
const allPages = ctx.browserContext.pages();
|
|
6130
6301
|
const newIndex = allPages.indexOf(newPage);
|
|
6131
|
-
return
|
|
6302
|
+
return ok27({
|
|
6132
6303
|
index: newIndex >= 0 ? newIndex : allPages.length - 1,
|
|
6133
6304
|
url: newPage.url(),
|
|
6134
6305
|
title,
|
|
@@ -6139,11 +6310,11 @@ async function handleNew(p, _pages, ctx) {
|
|
|
6139
6310
|
async function handleClose(p, ctx) {
|
|
6140
6311
|
const currentPages = ctx.browserContext.pages();
|
|
6141
6312
|
if (currentPages.length <= 1) {
|
|
6142
|
-
return
|
|
6313
|
+
return fail13("Cannot close the last remaining tab");
|
|
6143
6314
|
}
|
|
6144
6315
|
const closeIndex = p.index ?? currentPages.findIndex((pg) => pg === ctx.page);
|
|
6145
6316
|
if (closeIndex < 0 || closeIndex >= currentPages.length) {
|
|
6146
|
-
return
|
|
6317
|
+
return fail13(`Invalid tab index: ${closeIndex}. Valid range: 0-${currentPages.length - 1}`);
|
|
6147
6318
|
}
|
|
6148
6319
|
const pageToClose = currentPages[closeIndex];
|
|
6149
6320
|
const isActivePage = pageToClose === ctx.page;
|
|
@@ -6158,7 +6329,7 @@ async function handleClose(p, ctx) {
|
|
|
6158
6329
|
}
|
|
6159
6330
|
ctx.page = newActivePage;
|
|
6160
6331
|
}
|
|
6161
|
-
return
|
|
6332
|
+
return ok27({
|
|
6162
6333
|
closedIndex: closeIndex,
|
|
6163
6334
|
total: remainingPages.length,
|
|
6164
6335
|
activeIndex: isActivePage ? closeIndex < remainingPages.length ? closeIndex : remainingPages.length - 1 : remainingPages.findIndex((pg) => pg === ctx.page)
|
|
@@ -6166,10 +6337,10 @@ async function handleClose(p, ctx) {
|
|
|
6166
6337
|
}
|
|
6167
6338
|
async function handleSwitch(p, pages, ctx) {
|
|
6168
6339
|
if (p.index === void 0) {
|
|
6169
|
-
return
|
|
6340
|
+
return fail13("Parameter --index is required for switch subcommand");
|
|
6170
6341
|
}
|
|
6171
6342
|
if (p.index < 0 || p.index >= pages.length) {
|
|
6172
|
-
return
|
|
6343
|
+
return fail13(`Invalid tab index: ${p.index}. Valid range: 0-${pages.length - 1}`);
|
|
6173
6344
|
}
|
|
6174
6345
|
const targetPage = pages[p.index];
|
|
6175
6346
|
await targetPage.bringToFront().catch(() => {
|
|
@@ -6191,7 +6362,7 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6191
6362
|
}
|
|
6192
6363
|
ctx.page = targetPage;
|
|
6193
6364
|
const title = await targetPage.title().catch(() => "");
|
|
6194
|
-
return
|
|
6365
|
+
return ok27({
|
|
6195
6366
|
index: p.index,
|
|
6196
6367
|
url: targetPage.url(),
|
|
6197
6368
|
title,
|
|
@@ -6200,17 +6371,17 @@ async function handleSwitch(p, pages, ctx) {
|
|
|
6200
6371
|
}
|
|
6201
6372
|
|
|
6202
6373
|
// src/commands/addinitscript.ts
|
|
6203
|
-
import { z as
|
|
6204
|
-
import { ok as
|
|
6374
|
+
import { z as z29 } from "zod";
|
|
6375
|
+
import { ok as ok28 } from "@dyyz1993/xcli-core";
|
|
6205
6376
|
import { readFileSync as readFileSync4 } from "fs";
|
|
6206
|
-
var InitScriptParams =
|
|
6207
|
-
script:
|
|
6208
|
-
file:
|
|
6209
|
-
stdin:
|
|
6210
|
-
name:
|
|
6211
|
-
list:
|
|
6212
|
-
remove:
|
|
6213
|
-
base64:
|
|
6377
|
+
var InitScriptParams = z29.object({
|
|
6378
|
+
script: z29.string().optional(),
|
|
6379
|
+
file: z29.string().optional(),
|
|
6380
|
+
stdin: z29.boolean().optional(),
|
|
6381
|
+
name: z29.string().optional(),
|
|
6382
|
+
list: z29.boolean().optional(),
|
|
6383
|
+
remove: z29.union([z29.string(), z29.boolean()]).optional(),
|
|
6384
|
+
base64: z29.string().optional()
|
|
6214
6385
|
});
|
|
6215
6386
|
var registeredScripts = /* @__PURE__ */ new Map();
|
|
6216
6387
|
function resolveScriptContent(params) {
|
|
@@ -6244,14 +6415,14 @@ var addInitScriptCommand = registerCommand({
|
|
|
6244
6415
|
description: "Add an initialization script that runs on every page load",
|
|
6245
6416
|
scope: "page",
|
|
6246
6417
|
parameters: InitScriptParams,
|
|
6247
|
-
result:
|
|
6248
|
-
scripts:
|
|
6249
|
-
removed:
|
|
6250
|
-
existed:
|
|
6251
|
-
error:
|
|
6252
|
-
registered:
|
|
6253
|
-
hint:
|
|
6254
|
-
executedImmediately:
|
|
6418
|
+
result: z29.object({
|
|
6419
|
+
scripts: z29.array(z29.object({ name: z29.string(), size: z29.number(), preview: z29.string() })).optional(),
|
|
6420
|
+
removed: z29.string().optional(),
|
|
6421
|
+
existed: z29.boolean().optional(),
|
|
6422
|
+
error: z29.string().optional(),
|
|
6423
|
+
registered: z29.string().optional(),
|
|
6424
|
+
hint: z29.string().optional(),
|
|
6425
|
+
executedImmediately: z29.boolean().optional()
|
|
6255
6426
|
}).passthrough(),
|
|
6256
6427
|
handler: async (params, ctx) => {
|
|
6257
6428
|
if (params.list) {
|
|
@@ -6260,20 +6431,20 @@ var addInitScriptCommand = registerCommand({
|
|
|
6260
6431
|
size: content2.length,
|
|
6261
6432
|
preview: content2.slice(0, 80)
|
|
6262
6433
|
}));
|
|
6263
|
-
return
|
|
6434
|
+
return ok28({ scripts });
|
|
6264
6435
|
}
|
|
6265
6436
|
if (params.remove && typeof params.remove === "string") {
|
|
6266
6437
|
const existed = registeredScripts.delete(params.remove);
|
|
6267
|
-
return
|
|
6438
|
+
return ok28({ removed: params.remove, existed });
|
|
6268
6439
|
}
|
|
6269
6440
|
const removeTarget = (typeof params.remove === "string" ? params.remove : null) || (params.name && !resolveScriptContent(params) ? params.name : null);
|
|
6270
6441
|
if (removeTarget && !resolveScriptContent(params)) {
|
|
6271
6442
|
const existed = registeredScripts.delete(removeTarget);
|
|
6272
|
-
return
|
|
6443
|
+
return ok28({ removed: removeTarget, existed });
|
|
6273
6444
|
}
|
|
6274
6445
|
let content = params.stdin ? await readStdin() : resolveScriptContent(params);
|
|
6275
6446
|
if (!content) {
|
|
6276
|
-
return
|
|
6447
|
+
return ok28({ error: "No script content provided. Use --script, --file, --stdin, or --base64" });
|
|
6277
6448
|
}
|
|
6278
6449
|
const scriptName = params.name ?? `script-${Date.now()}`;
|
|
6279
6450
|
registeredScripts.set(scriptName, content);
|
|
@@ -6281,45 +6452,45 @@ var addInitScriptCommand = registerCommand({
|
|
|
6281
6452
|
try {
|
|
6282
6453
|
await ctx.page.evaluate(content);
|
|
6283
6454
|
} catch {
|
|
6284
|
-
return
|
|
6455
|
+
return ok28({
|
|
6285
6456
|
registered: scriptName,
|
|
6286
6457
|
hint: "Script registered for future page loads; immediate execution skipped (page may not be ready)"
|
|
6287
6458
|
});
|
|
6288
6459
|
}
|
|
6289
|
-
return
|
|
6460
|
+
return ok28({ registered: scriptName, executedImmediately: true });
|
|
6290
6461
|
}
|
|
6291
6462
|
});
|
|
6292
6463
|
registerCommandDefinition("addinitscript", ["script"]);
|
|
6293
6464
|
|
|
6294
6465
|
// src/commands/find.ts
|
|
6295
|
-
import { z as
|
|
6296
|
-
import { ok as
|
|
6297
|
-
var actionSchema2 =
|
|
6466
|
+
import { z as z30 } from "zod";
|
|
6467
|
+
import { ok as ok29, fail as fail14, normalizeTips as normalizeTips6 } from "@dyyz1993/xcli-core";
|
|
6468
|
+
var actionSchema2 = z30.enum(["click", "fill", "type", "select", "hover", "check"]);
|
|
6298
6469
|
var findCommand = registerCommand({
|
|
6299
6470
|
name: "find",
|
|
6300
6471
|
description: "Find elements by semantic strategy (text/role/label/placeholder/testid) and optionally perform an action",
|
|
6301
6472
|
scope: "page",
|
|
6302
|
-
parameters:
|
|
6303
|
-
strategy:
|
|
6304
|
-
value:
|
|
6305
|
-
name:
|
|
6306
|
-
exact:
|
|
6307
|
-
operation:
|
|
6473
|
+
parameters: z30.object({
|
|
6474
|
+
strategy: z30.enum(["text", "role", "label", "placeholder", "testid", "alt", "title", "first", "last", "nth"]),
|
|
6475
|
+
value: z30.string(),
|
|
6476
|
+
name: z30.string().optional(),
|
|
6477
|
+
exact: z30.boolean().optional().default(false),
|
|
6478
|
+
operation: z30.string().optional().describe('Trailing operation syntax, e.g. click, fill "text", type "text"'),
|
|
6308
6479
|
action: actionSchema2.optional().describe("Action to perform when not using trailing operation syntax"),
|
|
6309
|
-
actionValue:
|
|
6310
|
-
index:
|
|
6311
|
-
click:
|
|
6312
|
-
fill:
|
|
6313
|
-
type:
|
|
6314
|
-
select:
|
|
6315
|
-
hover:
|
|
6316
|
-
check:
|
|
6317
|
-
timeout:
|
|
6480
|
+
actionValue: z30.string().optional().describe("Value for fill/type/select when using action"),
|
|
6481
|
+
index: z30.number().int().optional().describe("Index for nth strategy"),
|
|
6482
|
+
click: z30.boolean().optional().default(false),
|
|
6483
|
+
fill: z30.string().optional(),
|
|
6484
|
+
type: z30.string().optional(),
|
|
6485
|
+
select: z30.string().optional(),
|
|
6486
|
+
hover: z30.boolean().optional().default(false),
|
|
6487
|
+
check: z30.boolean().optional().default(false),
|
|
6488
|
+
timeout: z30.number().optional().default(1e4)
|
|
6318
6489
|
}),
|
|
6319
|
-
result:
|
|
6320
|
-
matched:
|
|
6321
|
-
selector:
|
|
6322
|
-
action:
|
|
6490
|
+
result: z30.object({
|
|
6491
|
+
matched: z30.number(),
|
|
6492
|
+
selector: z30.string(),
|
|
6493
|
+
action: z30.string().optional()
|
|
6323
6494
|
}),
|
|
6324
6495
|
handler: async (p, ctx) => {
|
|
6325
6496
|
const page = ctx.page;
|
|
@@ -6334,7 +6505,7 @@ var findCommand = registerCommand({
|
|
|
6334
6505
|
});
|
|
6335
6506
|
const count = await locator.count();
|
|
6336
6507
|
if (count === 0) {
|
|
6337
|
-
return
|
|
6508
|
+
return fail14(`No element found with ${p.strategy}="${p.value}"`);
|
|
6338
6509
|
}
|
|
6339
6510
|
const tips = [];
|
|
6340
6511
|
const target = selectTarget(locator, p.strategy);
|
|
@@ -6346,15 +6517,15 @@ var findCommand = registerCommand({
|
|
|
6346
6517
|
await target.click({ timeout: p.timeout, force: true });
|
|
6347
6518
|
return okWithTips({ matched: count, selector, action: "click" }, tips);
|
|
6348
6519
|
} else if (actionName === "fill") {
|
|
6349
|
-
if (actionValue === void 0) return
|
|
6520
|
+
if (actionValue === void 0) return fail14("find fill requires a value");
|
|
6350
6521
|
await target.fill(actionValue, { timeout: p.timeout, force: true });
|
|
6351
6522
|
return okWithTips({ matched: count, selector, action: `fill("${actionValue}")` }, tips);
|
|
6352
6523
|
} else if (actionName === "type") {
|
|
6353
|
-
if (actionValue === void 0) return
|
|
6524
|
+
if (actionValue === void 0) return fail14("find type requires a value");
|
|
6354
6525
|
await target.type(actionValue, { delay: 10, timeout: p.timeout });
|
|
6355
6526
|
return okWithTips({ matched: count, selector, action: `type("${actionValue}")` }, tips);
|
|
6356
6527
|
} else if (actionName === "select") {
|
|
6357
|
-
if (actionValue === void 0) return
|
|
6528
|
+
if (actionValue === void 0) return fail14("find select requires a value");
|
|
6358
6529
|
await target.selectOption(actionValue);
|
|
6359
6530
|
return okWithTips({ matched: count, selector, action: `select("${actionValue}")` }, tips);
|
|
6360
6531
|
} else if (actionName === "hover") {
|
|
@@ -6368,8 +6539,8 @@ var findCommand = registerCommand({
|
|
|
6368
6539
|
}
|
|
6369
6540
|
});
|
|
6370
6541
|
function okWithTips(data, tips) {
|
|
6371
|
-
const result =
|
|
6372
|
-
if (tips.length > 0) result.tips =
|
|
6542
|
+
const result = ok29(data);
|
|
6543
|
+
if (tips.length > 0) result.tips = normalizeTips6(tips);
|
|
6373
6544
|
return result;
|
|
6374
6545
|
}
|
|
6375
6546
|
function parseOperation(operation) {
|
|
@@ -6467,8 +6638,8 @@ function describeSelector(strategy, value, name) {
|
|
|
6467
6638
|
}
|
|
6468
6639
|
|
|
6469
6640
|
// src/commands/visual-tag.ts
|
|
6470
|
-
import { z as
|
|
6471
|
-
import { ok as
|
|
6641
|
+
import { z as z31 } from "zod";
|
|
6642
|
+
import { ok as ok30, fail as fail15 } from "@dyyz1993/xcli-core";
|
|
6472
6643
|
var SAFE_SET = "ahjkmnprtw3479".split("");
|
|
6473
6644
|
var TAG_SCRIPT = `
|
|
6474
6645
|
(function() {
|
|
@@ -6559,49 +6730,49 @@ var visualTagCommand = registerCommand({
|
|
|
6559
6730
|
name: "visual-tag",
|
|
6560
6731
|
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",
|
|
6561
6732
|
scope: "page",
|
|
6562
|
-
parameters:
|
|
6563
|
-
action:
|
|
6564
|
-
id:
|
|
6733
|
+
parameters: z31.object({
|
|
6734
|
+
action: z31.enum(["tag", "lookup", "clear", "list"]),
|
|
6735
|
+
id: z31.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID")
|
|
6565
6736
|
}),
|
|
6566
|
-
result:
|
|
6567
|
-
action:
|
|
6568
|
-
tagged:
|
|
6569
|
-
id:
|
|
6570
|
-
element:
|
|
6737
|
+
result: z31.object({
|
|
6738
|
+
action: z31.string(),
|
|
6739
|
+
tagged: z31.number().optional(),
|
|
6740
|
+
id: z31.string().optional(),
|
|
6741
|
+
element: z31.record(z31.unknown()).optional()
|
|
6571
6742
|
}),
|
|
6572
6743
|
handler: async (p, ctx) => {
|
|
6573
6744
|
switch (p.action) {
|
|
6574
6745
|
case "tag": {
|
|
6575
6746
|
const result = await ctx.page.evaluate(TAG_SCRIPT);
|
|
6576
6747
|
const parsed = JSON.parse(result);
|
|
6577
|
-
return
|
|
6748
|
+
return ok30({ action: "tag", tagged: parsed.tagged });
|
|
6578
6749
|
}
|
|
6579
6750
|
case "lookup": {
|
|
6580
|
-
if (!p.id) return
|
|
6751
|
+
if (!p.id) return fail15("lookup \u9700\u8981 --id \u53C2\u6570");
|
|
6581
6752
|
const result = await ctx.page.evaluate(
|
|
6582
6753
|
`(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'}); })()`
|
|
6583
6754
|
);
|
|
6584
6755
|
const parsed = JSON.parse(result);
|
|
6585
|
-
if (parsed.err) return
|
|
6586
|
-
return
|
|
6756
|
+
if (parsed.err) return fail15(`ID ${p.id}: ${parsed.err}`);
|
|
6757
|
+
return ok30({ action: "lookup", id: p.id, element: parsed });
|
|
6587
6758
|
}
|
|
6588
6759
|
case "list": {
|
|
6589
6760
|
const result = await ctx.page.evaluate(
|
|
6590
6761
|
`(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); })()`
|
|
6591
6762
|
);
|
|
6592
|
-
return
|
|
6763
|
+
return ok30({ action: "list", element: JSON.parse(result) });
|
|
6593
6764
|
}
|
|
6594
6765
|
case "clear": {
|
|
6595
6766
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;return 'cleared'})()`);
|
|
6596
|
-
return
|
|
6767
|
+
return ok30({ action: "clear" });
|
|
6597
6768
|
}
|
|
6598
6769
|
}
|
|
6599
6770
|
}
|
|
6600
6771
|
});
|
|
6601
6772
|
|
|
6602
6773
|
// src/commands/visual-tag-v2.ts
|
|
6603
|
-
import { z as
|
|
6604
|
-
import { ok as
|
|
6774
|
+
import { z as z32 } from "zod";
|
|
6775
|
+
import { ok as ok31, fail as fail16 } from "@dyyz1993/xcli-core";
|
|
6605
6776
|
var SAFE_SET2 = "ahjkmnprtw3479".split("");
|
|
6606
6777
|
var TAG_V2_SCRIPT = `
|
|
6607
6778
|
(function() {
|
|
@@ -6948,45 +7119,45 @@ var visualTagV2Command = registerCommand({
|
|
|
6948
7119
|
name: "visual-tag-v2",
|
|
6949
7120
|
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",
|
|
6950
7121
|
scope: "page",
|
|
6951
|
-
parameters:
|
|
6952
|
-
action:
|
|
6953
|
-
id:
|
|
6954
|
-
query:
|
|
6955
|
-
type:
|
|
6956
|
-
"interact-action":
|
|
6957
|
-
value:
|
|
7122
|
+
parameters: z32.object({
|
|
7123
|
+
action: z32.enum(["tag", "lookup", "clear", "stats", "by-type", "find", "export", "interact"]),
|
|
7124
|
+
id: z32.string().optional().describe("lookup \u65F6\u6307\u5B9A\u8981\u67E5\u7684 ID"),
|
|
7125
|
+
query: z32.string().optional().describe('find \u65F6\u6307\u5B9A\u641C\u7D22\u8BCD\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09'),
|
|
7126
|
+
type: z32.string().optional().describe("by-type \u65F6\u8FC7\u6EE4\u7C7B\u578B\uFF1Aclick/input/img/list/count/text"),
|
|
7127
|
+
"interact-action": z32.enum(["click", "fill", "read"]).optional().describe("interact \u52A8\u4F5C\u7C7B\u578B"),
|
|
7128
|
+
value: z32.string().optional().describe("fill \u65F6\u7684\u586B\u5145\u503C")
|
|
6958
7129
|
}),
|
|
6959
|
-
result:
|
|
6960
|
-
action:
|
|
6961
|
-
total:
|
|
6962
|
-
byType:
|
|
6963
|
-
element:
|
|
7130
|
+
result: z32.object({
|
|
7131
|
+
action: z32.string(),
|
|
7132
|
+
total: z32.number().optional(),
|
|
7133
|
+
byType: z32.record(z32.number()).optional(),
|
|
7134
|
+
element: z32.record(z32.unknown()).optional()
|
|
6964
7135
|
}),
|
|
6965
7136
|
handler: async (p, ctx) => {
|
|
6966
7137
|
switch (p.action) {
|
|
6967
7138
|
case "tag": {
|
|
6968
7139
|
const result = await ctx.page.evaluate(TAG_V2_SCRIPT);
|
|
6969
7140
|
const parsed = JSON.parse(result);
|
|
6970
|
-
return
|
|
7141
|
+
return ok31({ action: "tag", total: parsed.total, byType: parsed.byType });
|
|
6971
7142
|
}
|
|
6972
7143
|
case "lookup": {
|
|
6973
|
-
if (!p.id) return
|
|
7144
|
+
if (!p.id) return fail16("lookup \u9700\u8981 --id");
|
|
6974
7145
|
const result = await ctx.page.evaluate(
|
|
6975
7146
|
`(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'})})()`
|
|
6976
7147
|
);
|
|
6977
7148
|
const parsed = JSON.parse(result);
|
|
6978
|
-
if (parsed.err) return
|
|
6979
|
-
return
|
|
7149
|
+
if (parsed.err) return fail16(`ID ${p.id}: ${parsed.err}`);
|
|
7150
|
+
return ok31({ action: "lookup", id: p.id, element: parsed });
|
|
6980
7151
|
}
|
|
6981
7152
|
case "by-type": {
|
|
6982
7153
|
const result = await ctx.page.evaluate(
|
|
6983
7154
|
`(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)})()`
|
|
6984
7155
|
);
|
|
6985
|
-
return
|
|
7156
|
+
return ok31({ action: "by-type", element: JSON.parse(result) });
|
|
6986
7157
|
}
|
|
6987
7158
|
case "find": {
|
|
6988
7159
|
const query = p.query;
|
|
6989
|
-
if (!query) return
|
|
7160
|
+
if (!query) return fail16('find \u9700\u8981 --query \u53C2\u6570\uFF08\u5982 "\u627E\u6709AI\u7F16\u7A0B\u6807\u7B7E\u7684\u5361\u7247"\uFF09');
|
|
6990
7161
|
const result = await ctx.page.evaluate(
|
|
6991
7162
|
`(function(){
|
|
6992
7163
|
var map = window.__xbTagSerializable;
|
|
@@ -7028,21 +7199,21 @@ var visualTagV2Command = registerCommand({
|
|
|
7028
7199
|
return JSON.stringify({total:results.length, results:results.slice(0,20)});
|
|
7029
7200
|
})()`
|
|
7030
7201
|
);
|
|
7031
|
-
return
|
|
7202
|
+
return ok31({ action: "find", query, element: JSON.parse(result) });
|
|
7032
7203
|
}
|
|
7033
7204
|
case "stats": {
|
|
7034
7205
|
const result = await ctx.page.evaluate(
|
|
7035
7206
|
`(function(){return JSON.stringify(window.__xbTagStats||{})})()`
|
|
7036
7207
|
);
|
|
7037
|
-
return
|
|
7208
|
+
return ok31({ action: "stats", element: JSON.parse(result) });
|
|
7038
7209
|
}
|
|
7039
7210
|
case "interact": {
|
|
7040
7211
|
const query = p.query;
|
|
7041
7212
|
const pAny = p;
|
|
7042
7213
|
const action = pAny["interact-action"] || pAny.interactAction || pAny.interact_action;
|
|
7043
7214
|
const value = pAny.value;
|
|
7044
|
-
if (!query) return
|
|
7045
|
-
if (!action) return
|
|
7215
|
+
if (!query) return fail16("interact \u9700\u8981 --query \u53C2\u6570");
|
|
7216
|
+
if (!action) return fail16("interact \u9700\u8981 --interact-action \u53C2\u6570\uFF08click/fill/read\uFF09");
|
|
7046
7217
|
const findResult = await ctx.page.evaluate(
|
|
7047
7218
|
`(function(){
|
|
7048
7219
|
var map = window.__xbTagSerializable;
|
|
@@ -7072,11 +7243,11 @@ var visualTagV2Command = registerCommand({
|
|
|
7072
7243
|
})()`
|
|
7073
7244
|
);
|
|
7074
7245
|
const parsed = JSON.parse(findResult);
|
|
7075
|
-
if (parsed.err) return
|
|
7076
|
-
if (!parsed.total || !parsed.results?.length) return
|
|
7246
|
+
if (parsed.err) return fail16(parsed.err);
|
|
7247
|
+
if (!parsed.total || !parsed.results?.length) return fail16(`\u672A\u627E\u5230\u5339\u914D "${query}" \u7684\u5143\u7D20`);
|
|
7077
7248
|
const target = parsed.results[0];
|
|
7078
7249
|
if (action === "read") {
|
|
7079
|
-
return
|
|
7250
|
+
return ok31({ action: "interact", query, target, result: { read: target.text || target.label } });
|
|
7080
7251
|
}
|
|
7081
7252
|
if (action === "click") {
|
|
7082
7253
|
const el = await ctx.page.evaluate(
|
|
@@ -7089,12 +7260,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7089
7260
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7090
7261
|
})()`
|
|
7091
7262
|
);
|
|
7092
|
-
if (!el) return
|
|
7263
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7093
7264
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7094
|
-
return
|
|
7265
|
+
return ok31({ action: "interact", query, target, result: { clicked: true, x: el.x, y: el.y } });
|
|
7095
7266
|
}
|
|
7096
7267
|
if (action === "fill") {
|
|
7097
|
-
if (!value) return
|
|
7268
|
+
if (!value) return fail16("fill \u9700\u8981 --value \u53C2\u6570");
|
|
7098
7269
|
const el = await ctx.page.evaluate(
|
|
7099
7270
|
`(function(){
|
|
7100
7271
|
var map = window.__xbTagMap;
|
|
@@ -7105,12 +7276,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7105
7276
|
return {x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)};
|
|
7106
7277
|
})()`
|
|
7107
7278
|
);
|
|
7108
|
-
if (!el) return
|
|
7279
|
+
if (!el) return fail16(`\u5143\u7D20 ${target.id} \u4E0D\u53EF\u4EA4\u4E92`);
|
|
7109
7280
|
await ctx.page.mouse.click(el.x, el.y, { stealth: true });
|
|
7110
7281
|
await ctx.page.keyboard.type(value, { stealth: true });
|
|
7111
|
-
return
|
|
7282
|
+
return ok31({ action: "interact", query, target, result: { filled: true, value } });
|
|
7112
7283
|
}
|
|
7113
|
-
return
|
|
7284
|
+
return fail16(`\u672A\u77E5 action: ${action}`);
|
|
7114
7285
|
}
|
|
7115
7286
|
case "export": {
|
|
7116
7287
|
const result = await ctx.page.evaluate(
|
|
@@ -7158,12 +7329,12 @@ var visualTagV2Command = registerCommand({
|
|
|
7158
7329
|
})()`
|
|
7159
7330
|
);
|
|
7160
7331
|
const parsed = JSON.parse(result);
|
|
7161
|
-
if (parsed.err) return
|
|
7162
|
-
return
|
|
7332
|
+
if (parsed.err) return fail16(String(parsed.err));
|
|
7333
|
+
return ok31({ action: "export", element: parsed });
|
|
7163
7334
|
}
|
|
7164
7335
|
case "clear": {
|
|
7165
7336
|
await ctx.page.evaluate(`(function(){var o=document.getElementById('__xb-tag-overlay');if(o)o.remove();window.__xbTagMap=null;window.__xbTagStats=null;return 'ok'})()`);
|
|
7166
|
-
return
|
|
7337
|
+
return ok31({ action: "clear" });
|
|
7167
7338
|
}
|
|
7168
7339
|
}
|
|
7169
7340
|
}
|
|
@@ -7689,12 +7860,12 @@ function classifyFailure(message) {
|
|
|
7689
7860
|
|
|
7690
7861
|
// src/executor.ts
|
|
7691
7862
|
import {
|
|
7692
|
-
ok as
|
|
7693
|
-
fail as
|
|
7863
|
+
ok as ok32,
|
|
7864
|
+
fail as fail17,
|
|
7694
7865
|
isCommandResult,
|
|
7695
7866
|
CompositeStorage as CompositeStorage2,
|
|
7696
7867
|
TipCollector as TipCollector2,
|
|
7697
|
-
normalizeTips as
|
|
7868
|
+
normalizeTips as normalizeTips7,
|
|
7698
7869
|
configureArchiveStore,
|
|
7699
7870
|
appendCommandToArchive,
|
|
7700
7871
|
checkGuard,
|
|
@@ -8295,7 +8466,10 @@ function buildSnapshot(elements) {
|
|
|
8295
8466
|
}
|
|
8296
8467
|
|
|
8297
8468
|
// src/tips/index.ts
|
|
8298
|
-
|
|
8469
|
+
function tipsDebounceMs() {
|
|
8470
|
+
const v = parseInt(process.env.XBROWSER_TIPS_DEBOUNCE ?? "120", 10);
|
|
8471
|
+
return Number.isFinite(v) && v > 0 ? v : 0;
|
|
8472
|
+
}
|
|
8299
8473
|
var SKIP_DETECT_COMMANDS = /* @__PURE__ */ new Set([
|
|
8300
8474
|
"goto",
|
|
8301
8475
|
// 导航命令不需要检测
|
|
@@ -8387,7 +8561,9 @@ var TipsManager = class {
|
|
|
8387
8561
|
}
|
|
8388
8562
|
}
|
|
8389
8563
|
debounce() {
|
|
8390
|
-
|
|
8564
|
+
const ms = tipsDebounceMs();
|
|
8565
|
+
if (ms <= 0) return Promise.resolve();
|
|
8566
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
8391
8567
|
}
|
|
8392
8568
|
formatTips(tips) {
|
|
8393
8569
|
return tips.map((tip) => {
|
|
@@ -8556,7 +8732,7 @@ async function guardCheck(commandName) {
|
|
|
8556
8732
|
}
|
|
8557
8733
|
}
|
|
8558
8734
|
function errorResult(message) {
|
|
8559
|
-
return { ...
|
|
8735
|
+
return { ...fail17(message), duration: 0 };
|
|
8560
8736
|
}
|
|
8561
8737
|
function tipsToMessages(tips) {
|
|
8562
8738
|
if (!tips || tips.length === 0) return [];
|
|
@@ -8636,7 +8812,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8636
8812
|
}
|
|
8637
8813
|
let targetPageOverride = null;
|
|
8638
8814
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
8639
|
-
const { findTargetPage } = await import("./browser-
|
|
8815
|
+
const { findTargetPage } = await import("./browser-4IYIHZ6R.js");
|
|
8640
8816
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
8641
8817
|
if (!targetPageOverride) {
|
|
8642
8818
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8748,7 +8924,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8748
8924
|
const cache = /* @__PURE__ */ new Map();
|
|
8749
8925
|
const resolved = await resolveRefParams(session.page, params, command.selectorParams, cache, session.id);
|
|
8750
8926
|
if (resolved.tips.length > 0) {
|
|
8751
|
-
refTips =
|
|
8927
|
+
refTips = normalizeTips7(resolved.tips);
|
|
8752
8928
|
params = resolved.params;
|
|
8753
8929
|
}
|
|
8754
8930
|
}
|
|
@@ -8816,8 +8992,8 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8816
8992
|
}
|
|
8817
8993
|
const merged = [
|
|
8818
8994
|
...raw.tips || [],
|
|
8819
|
-
...
|
|
8820
|
-
...snapshotHint ?
|
|
8995
|
+
...normalizeTips7(smartTips),
|
|
8996
|
+
...snapshotHint ? normalizeTips7([snapshotHint]) : [],
|
|
8821
8997
|
...refTips
|
|
8822
8998
|
];
|
|
8823
8999
|
const isSuccess = raw.success !== false;
|
|
@@ -8832,7 +9008,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8832
9008
|
timestamp: start
|
|
8833
9009
|
});
|
|
8834
9010
|
if (isSuccess) {
|
|
8835
|
-
return { ...
|
|
9011
|
+
return { ...ok32(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8836
9012
|
}
|
|
8837
9013
|
const fc = classifyFailure(raw.message);
|
|
8838
9014
|
return {
|
|
@@ -8845,7 +9021,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8845
9021
|
...hookOutputs ? { hookOutputs } : {}
|
|
8846
9022
|
};
|
|
8847
9023
|
}
|
|
8848
|
-
const smartTipNormalized =
|
|
9024
|
+
const smartTipNormalized = normalizeTips7(smartTips);
|
|
8849
9025
|
recordArchive(session?.id, sessionName, {
|
|
8850
9026
|
step: 0,
|
|
8851
9027
|
command: commandName,
|
|
@@ -8855,7 +9031,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8855
9031
|
duration,
|
|
8856
9032
|
timestamp: start
|
|
8857
9033
|
});
|
|
8858
|
-
return { ...
|
|
9034
|
+
return { ...ok32(raw, smartTipNormalized), duration, ...hookOutputs ? { hookOutputs } : {} };
|
|
8859
9035
|
} catch (err) {
|
|
8860
9036
|
const end = Date.now();
|
|
8861
9037
|
const duration = end - start;
|
|
@@ -8900,7 +9076,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8900
9076
|
duration,
|
|
8901
9077
|
timestamp: start
|
|
8902
9078
|
});
|
|
8903
|
-
return { ...
|
|
9079
|
+
return { ...fail17(errorMessage), duration };
|
|
8904
9080
|
} finally {
|
|
8905
9081
|
}
|
|
8906
9082
|
}
|
|
@@ -8945,7 +9121,7 @@ async function executeChain(input, options) {
|
|
|
8945
9121
|
results.push({
|
|
8946
9122
|
command: cmdName,
|
|
8947
9123
|
raw: cmdStr,
|
|
8948
|
-
...
|
|
9124
|
+
...fail17(`Plugin "${cmdName}" requires a sub-command`),
|
|
8949
9125
|
duration: 0
|
|
8950
9126
|
});
|
|
8951
9127
|
if (type === "and") {
|
|
@@ -8964,7 +9140,7 @@ async function executeChain(input, options) {
|
|
|
8964
9140
|
results.push({
|
|
8965
9141
|
command: cmdName,
|
|
8966
9142
|
raw: cmdStr,
|
|
8967
|
-
...
|
|
9143
|
+
...fail17(`Unknown command "${subCommand}" for plugin "${cmdName}"`),
|
|
8968
9144
|
duration: 0
|
|
8969
9145
|
});
|
|
8970
9146
|
if (type === "and") {
|
|
@@ -9034,7 +9210,7 @@ async function executeChain(input, options) {
|
|
|
9034
9210
|
success: false,
|
|
9035
9211
|
data: data2,
|
|
9036
9212
|
message: loginGuard.message,
|
|
9037
|
-
tips:
|
|
9213
|
+
tips: normalizeTips7(loginGuard.tips),
|
|
9038
9214
|
duration: duration3
|
|
9039
9215
|
});
|
|
9040
9216
|
if (type === "and") {
|
|
@@ -9076,7 +9252,7 @@ async function executeChain(input, options) {
|
|
|
9076
9252
|
results.push({
|
|
9077
9253
|
command: `${cmdName} ${subCommand}`,
|
|
9078
9254
|
raw: cmdStr,
|
|
9079
|
-
...
|
|
9255
|
+
...ok32(data),
|
|
9080
9256
|
duration: duration2,
|
|
9081
9257
|
...hookOutputs ? { hookOutputs } : {}
|
|
9082
9258
|
});
|
|
@@ -9104,7 +9280,7 @@ async function executeChain(input, options) {
|
|
|
9104
9280
|
results.push({
|
|
9105
9281
|
command: `${cmdName} ${subCommand}`,
|
|
9106
9282
|
raw: cmdStr,
|
|
9107
|
-
...
|
|
9283
|
+
...fail17(errorMessage),
|
|
9108
9284
|
duration: duration2
|
|
9109
9285
|
});
|
|
9110
9286
|
if (type === "and") {
|