@xbrowser/cli 1.0.2 → 1.0.4
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-GITRHHFO.js → browser-5CTOA2WS.js} +3 -3
- package/dist/{browser-R56O3CW6.js → browser-ITLZZDHJ.js} +4 -2
- package/dist/{browser-ZJOZB5CR.js → browser-IUJXXNBT.js} +5 -4
- package/dist/{cdp-driver-BE3FOMRN.js → cdp-driver-4X3DK6PS.js} +19 -5
- package/dist/{cdp-driver-TOPYJIFL.js → cdp-driver-D6WMSMWX.js} +3 -2
- package/dist/{chunk-Q4IGYTKR.js → chunk-6WOSXSCQ.js} +6 -2
- package/dist/{chunk-ZZ2TFWIV.js → chunk-ABXMBNQ6.js} +1 -1
- package/dist/{chunk-JPHCY4TC.js → chunk-AMI64BSD.js} +9 -1
- package/dist/{chunk-CAFNSGYM.js → chunk-DKWR54XQ.js} +24 -8
- package/dist/chunk-GDKLH7ZY.js +8 -0
- package/dist/{chunk-QIK2I3VQ.js → chunk-LRBSUKUZ.js} +7 -4
- package/dist/{chunk-PPG4D2EW.js → chunk-N2JFPWMI.js} +21 -5
- package/dist/{chunk-BBMRDUYQ.js → chunk-TNEN6VQ2.js} +4 -1
- package/dist/{chunk-JPA2ZT2R.js → chunk-TWWOIJM7.js} +7 -4
- package/dist/cli.js +185 -107
- package/dist/{daemon-client-UZZEHHIV.js → daemon-client-3JOKX2L2.js} +2 -1
- package/dist/{daemon-client-DRCUMNHK.js → daemon-client-DIEHGP5B.js} +5 -2
- package/dist/daemon-main.js +154 -89
- package/dist/index.d.ts +1 -1
- package/dist/index.js +193 -116
- package/dist/{launcher-QUJ4M2VS.js → launcher-L2JNDB2H.js} +2 -1
- package/dist/{launcher-YARP45UY.js → launcher-OZXJQPNG.js} +1 -1
- package/dist/{proxy-LV4BJ5RC.js → proxy-C6CK3UH5.js} +1 -1
- package/dist/{session-replayer-GLTUICSD.js → session-replayer-MY27H4DX.js} +1 -1
- package/package.json +1 -1
package/dist/daemon-main.js
CHANGED
|
@@ -21,25 +21,28 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-LRBSUKUZ.js";
|
|
25
|
+
import "./chunk-N2JFPWMI.js";
|
|
26
|
+
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
28
28
|
getDaemonConfig,
|
|
29
29
|
getDaemonProcessStatus
|
|
30
30
|
} from "./chunk-WJRE55TN.js";
|
|
31
|
+
import {
|
|
32
|
+
errMsg
|
|
33
|
+
} from "./chunk-GDKLH7ZY.js";
|
|
31
34
|
import "./chunk-KFQGP6VL.js";
|
|
32
35
|
|
|
33
36
|
// src/daemon/daemon-main.ts
|
|
34
37
|
import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, appendFileSync } from "fs";
|
|
35
|
-
import { join as
|
|
36
|
-
import { homedir as
|
|
38
|
+
import { join as join9 } from "path";
|
|
39
|
+
import { homedir as homedir9 } from "os";
|
|
37
40
|
import { startHttpServer } from "@dyyz1993/xcli-core";
|
|
38
41
|
|
|
39
42
|
// src/daemon/rpc-handlers.ts
|
|
40
43
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync6 } from "fs";
|
|
41
|
-
import { join as
|
|
42
|
-
import { homedir as
|
|
44
|
+
import { join as join8 } from "path";
|
|
45
|
+
import { homedir as homedir8 } from "os";
|
|
43
46
|
import {
|
|
44
47
|
createSessionMeta,
|
|
45
48
|
removeSession
|
|
@@ -50,8 +53,8 @@ import {
|
|
|
50
53
|
ok as ok25,
|
|
51
54
|
fail as fail7,
|
|
52
55
|
isCommandResult,
|
|
53
|
-
CompositeStorage,
|
|
54
|
-
TipCollector,
|
|
56
|
+
CompositeStorage as CompositeStorage2,
|
|
57
|
+
TipCollector as TipCollector2,
|
|
55
58
|
normalizeTips as normalizeTips6,
|
|
56
59
|
configureArchiveStore,
|
|
57
60
|
appendCommandToArchive,
|
|
@@ -169,6 +172,53 @@ function parsePluginParams(args, schema, base = {}) {
|
|
|
169
172
|
return result;
|
|
170
173
|
}
|
|
171
174
|
|
|
175
|
+
// src/utils/stub-context.ts
|
|
176
|
+
import { join } from "path";
|
|
177
|
+
import { homedir } from "os";
|
|
178
|
+
import { TipCollector, CompositeStorage } from "@dyyz1993/xcli-core";
|
|
179
|
+
var CONFIG_DIR = join(homedir(), ".xbrowser");
|
|
180
|
+
var NoopSiteInstance = class {
|
|
181
|
+
name = "stub";
|
|
182
|
+
url = "";
|
|
183
|
+
config = { name: "stub" };
|
|
184
|
+
command() {
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
group() {
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
login() {
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
logout() {
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
async isLoggedIn() {
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
async requireLogin() {
|
|
200
|
+
}
|
|
201
|
+
getStorage() {
|
|
202
|
+
return new CompositeStorage("stub", CONFIG_DIR, "xbrowser");
|
|
203
|
+
}
|
|
204
|
+
getAllCommands() {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
getCommand() {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
getOriginalHandler() {
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
async executeLogin() {
|
|
214
|
+
}
|
|
215
|
+
async executeLogout() {
|
|
216
|
+
}
|
|
217
|
+
async restoreLogin() {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
172
222
|
// src/commands/navigation.ts
|
|
173
223
|
import { z } from "zod";
|
|
174
224
|
import { ok } from "@dyyz1993/xcli-core";
|
|
@@ -216,7 +266,7 @@ async function detectSsr(page) {
|
|
|
216
266
|
try {
|
|
217
267
|
const result = await page.evaluate((vars) => {
|
|
218
268
|
for (const varName of vars) {
|
|
219
|
-
const value = window
|
|
269
|
+
const value = Reflect.get(window, varName);
|
|
220
270
|
if (value != null && typeof value === "object") {
|
|
221
271
|
const keys = Object.keys(value).slice(0, 10);
|
|
222
272
|
return { variable: varName, keys };
|
|
@@ -932,9 +982,9 @@ var clearLocalStorageCommand = registerCommand({
|
|
|
932
982
|
import { z as z9 } from "zod";
|
|
933
983
|
import { ok as ok9 } from "@dyyz1993/xcli-core";
|
|
934
984
|
import { writeFileSync, mkdirSync } from "fs";
|
|
935
|
-
import { join } from "path";
|
|
936
|
-
import { homedir } from "os";
|
|
937
|
-
var SCREENSHOTS_DIR =
|
|
985
|
+
import { join as join2 } from "path";
|
|
986
|
+
import { homedir as homedir2 } from "os";
|
|
987
|
+
var SCREENSHOTS_DIR = join2(homedir2(), ".xbrowser", "screenshots");
|
|
938
988
|
function ensureScreenshotsDir() {
|
|
939
989
|
mkdirSync(SCREENSHOTS_DIR, { recursive: true });
|
|
940
990
|
}
|
|
@@ -942,7 +992,7 @@ function generateScreenshotPath(format) {
|
|
|
942
992
|
const timestamp = Date.now();
|
|
943
993
|
const random = Math.random().toString(36).slice(2, 8);
|
|
944
994
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
945
|
-
return
|
|
995
|
+
return join2(SCREENSHOTS_DIR, `screenshot-${timestamp}-${random}.${ext}`);
|
|
946
996
|
}
|
|
947
997
|
var screenshotCommand = registerCommand({
|
|
948
998
|
name: "screenshot",
|
|
@@ -1565,7 +1615,7 @@ var healthCheckCommand = registerCommand({
|
|
|
1565
1615
|
issues.push({
|
|
1566
1616
|
severity: "error",
|
|
1567
1617
|
category: "links",
|
|
1568
|
-
message: `Broken link (fetch error): ${href} \u2014 ${err
|
|
1618
|
+
message: `Broken link (fetch error): ${href} \u2014 ${errMsg(err) || "unknown"}`
|
|
1569
1619
|
});
|
|
1570
1620
|
}
|
|
1571
1621
|
}
|
|
@@ -1599,9 +1649,9 @@ var healthCheckCommand = registerCommand({
|
|
|
1599
1649
|
import { z as z14 } from "zod";
|
|
1600
1650
|
import { ok as ok14 } from "@dyyz1993/xcli-core";
|
|
1601
1651
|
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1602
|
-
import { join as
|
|
1603
|
-
import { homedir as
|
|
1604
|
-
var SCREENSHOTS_DIR2 =
|
|
1652
|
+
import { join as join3 } from "path";
|
|
1653
|
+
import { homedir as homedir3 } from "os";
|
|
1654
|
+
var SCREENSHOTS_DIR2 = join3(homedir3(), ".xbrowser", "screenshots");
|
|
1605
1655
|
function ensureScreenshotsDir2() {
|
|
1606
1656
|
mkdirSync2(SCREENSHOTS_DIR2, { recursive: true });
|
|
1607
1657
|
}
|
|
@@ -1609,7 +1659,7 @@ function generateScreenshotPath2(format) {
|
|
|
1609
1659
|
const timestamp = Date.now();
|
|
1610
1660
|
const random = Math.random().toString(36).slice(2, 8);
|
|
1611
1661
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
1612
|
-
return
|
|
1662
|
+
return join3(SCREENSHOTS_DIR2, `screenshot-${timestamp}-${random}.${ext}`);
|
|
1613
1663
|
}
|
|
1614
1664
|
var waitActionSchema = z14.object({
|
|
1615
1665
|
type: z14.literal("wait"),
|
|
@@ -4111,8 +4161,8 @@ async function resolveRefParams(page, params, selectorKeys, cache, sessionId) {
|
|
|
4111
4161
|
|
|
4112
4162
|
// src/utils/site-semantics.ts
|
|
4113
4163
|
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync, readFileSync } from "fs";
|
|
4114
|
-
import { join as
|
|
4115
|
-
import { homedir as
|
|
4164
|
+
import { join as join4, dirname } from "path";
|
|
4165
|
+
import { homedir as homedir4 } from "os";
|
|
4116
4166
|
import { stringify, parse } from "yaml";
|
|
4117
4167
|
import { execFile } from "child_process";
|
|
4118
4168
|
var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
|
|
@@ -4189,10 +4239,10 @@ function inferAction(role, label) {
|
|
|
4189
4239
|
return {};
|
|
4190
4240
|
}
|
|
4191
4241
|
function getSemanticsDir() {
|
|
4192
|
-
return
|
|
4242
|
+
return join4(homedir4(), ".xbrowser", "site-semantics");
|
|
4193
4243
|
}
|
|
4194
4244
|
function getSemanticsPath(domain) {
|
|
4195
|
-
return
|
|
4245
|
+
return join4(getSemanticsDir(), `${domain}.yaml`);
|
|
4196
4246
|
}
|
|
4197
4247
|
function extractDomain2(url) {
|
|
4198
4248
|
try {
|
|
@@ -4664,7 +4714,7 @@ async function actOnPage(page, sessionId, input) {
|
|
|
4664
4714
|
ref: normalizedRef,
|
|
4665
4715
|
success: false,
|
|
4666
4716
|
reason: "browser_error",
|
|
4667
|
-
message: error
|
|
4717
|
+
message: errMsg(error),
|
|
4668
4718
|
stale,
|
|
4669
4719
|
screenHash: hash,
|
|
4670
4720
|
target: refMatch?.target
|
|
@@ -4748,7 +4798,7 @@ async function waitForPage(page, input) {
|
|
|
4748
4798
|
matched: input.selector ? "selector" : input.text ? "text" : input.url ? "url" : input.load ? "load" : input.fn ? "fn" : "screenHashChanged",
|
|
4749
4799
|
timeout,
|
|
4750
4800
|
elapsed: Date.now() - startedAt,
|
|
4751
|
-
message: error
|
|
4801
|
+
message: errMsg(error)
|
|
4752
4802
|
};
|
|
4753
4803
|
}
|
|
4754
4804
|
return {
|
|
@@ -5683,11 +5733,11 @@ async function detectWebdriverExposure(page) {
|
|
|
5683
5733
|
try {
|
|
5684
5734
|
const webdriver = await page.evaluate(() => {
|
|
5685
5735
|
return {
|
|
5686
|
-
webdriver:
|
|
5736
|
+
webdriver: navigator.webdriver,
|
|
5687
5737
|
webdriverScriptFn: !!window.__webdriver_script_fn,
|
|
5688
5738
|
webdriverEvaluate: !!window.__webdriver_evaluate,
|
|
5689
5739
|
chrome: !!window.chrome,
|
|
5690
|
-
permissions:
|
|
5740
|
+
permissions: navigator.permissions
|
|
5691
5741
|
};
|
|
5692
5742
|
}).catch(() => null);
|
|
5693
5743
|
if (!webdriver) {
|
|
@@ -5773,7 +5823,7 @@ import {
|
|
|
5773
5823
|
} from "@dyyz1993/xcli-core";
|
|
5774
5824
|
import { resolve as resolve2 } from "path";
|
|
5775
5825
|
import { existsSync as existsSync4, readdirSync } from "fs";
|
|
5776
|
-
import { homedir as
|
|
5826
|
+
import { homedir as homedir5 } from "os";
|
|
5777
5827
|
|
|
5778
5828
|
// src/plugin/metadata-parser.ts
|
|
5779
5829
|
import { existsSync as existsSync2 } from "fs";
|
|
@@ -5860,17 +5910,17 @@ var PluginMetadataParser = class {
|
|
|
5860
5910
|
|
|
5861
5911
|
// src/plugin/ensure-deps.ts
|
|
5862
5912
|
import { existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
5863
|
-
import { join as
|
|
5913
|
+
import { join as join5 } from "path";
|
|
5864
5914
|
import { execSync } from "child_process";
|
|
5865
5915
|
var SHARED_PLUGIN_DEPENDENCIES = {
|
|
5866
5916
|
"zod": "^3.24.0",
|
|
5867
5917
|
"@dyyz1993/xcli-core": "^0.12.1"
|
|
5868
5918
|
};
|
|
5869
5919
|
function ensurePluginDependencies(pluginsDir) {
|
|
5870
|
-
const zodPath =
|
|
5920
|
+
const zodPath = join5(pluginsDir, "node_modules", "zod");
|
|
5871
5921
|
if (existsSync3(zodPath)) return;
|
|
5872
5922
|
mkdirSync4(pluginsDir, { recursive: true });
|
|
5873
|
-
const pkgPath =
|
|
5923
|
+
const pkgPath = join5(pluginsDir, "package.json");
|
|
5874
5924
|
let pkg = {};
|
|
5875
5925
|
if (existsSync3(pkgPath)) {
|
|
5876
5926
|
try {
|
|
@@ -5886,7 +5936,7 @@ function ensurePluginDependencies(pluginsDir) {
|
|
|
5886
5936
|
needsInstall = true;
|
|
5887
5937
|
}
|
|
5888
5938
|
}
|
|
5889
|
-
if (!needsInstall && existsSync3(
|
|
5939
|
+
if (!needsInstall && existsSync3(join5(pluginsDir, "node_modules"))) return;
|
|
5890
5940
|
pkg.dependencies = existingDeps;
|
|
5891
5941
|
pkg.private = true;
|
|
5892
5942
|
pkg.description = pkg.description || "xbrowser plugins \u2014 shared dependencies";
|
|
@@ -6047,19 +6097,26 @@ var patched = false;
|
|
|
6047
6097
|
function patchLoginRequired() {
|
|
6048
6098
|
if (patched) return;
|
|
6049
6099
|
patched = true;
|
|
6050
|
-
const
|
|
6051
|
-
const
|
|
6052
|
-
|
|
6053
|
-
const result =
|
|
6100
|
+
const target = SiteInstanceImpl.prototype;
|
|
6101
|
+
const originalCommand = target.command;
|
|
6102
|
+
const wrapped = function(...args) {
|
|
6103
|
+
const result = originalCommand.apply(this, args);
|
|
6104
|
+
const [name, cmd] = args;
|
|
6054
6105
|
const loginRequired = cmd.loginRequired;
|
|
6055
6106
|
if (loginRequired) {
|
|
6056
|
-
const
|
|
6107
|
+
const commands = this.commands;
|
|
6108
|
+
const entry = commands?.get(name);
|
|
6057
6109
|
if (entry) {
|
|
6058
6110
|
entry.loginRequired = loginRequired;
|
|
6059
6111
|
}
|
|
6060
6112
|
}
|
|
6061
6113
|
return result;
|
|
6062
6114
|
};
|
|
6115
|
+
Object.defineProperty(target, "command", {
|
|
6116
|
+
value: wrapped,
|
|
6117
|
+
writable: true,
|
|
6118
|
+
configurable: true
|
|
6119
|
+
});
|
|
6063
6120
|
}
|
|
6064
6121
|
|
|
6065
6122
|
// src/plugin/loader.ts
|
|
@@ -6126,12 +6183,12 @@ var XBrowserPluginLoader = class {
|
|
|
6126
6183
|
}
|
|
6127
6184
|
async scanAndLoad() {
|
|
6128
6185
|
const cwd = this.options.cwd || process.cwd();
|
|
6129
|
-
const globalDir = this.options.globalDir || resolve2(
|
|
6186
|
+
const globalDir = this.options.globalDir || resolve2(homedir5(), ".xbrowser/plugins");
|
|
6130
6187
|
ensurePluginDependencies(globalDir);
|
|
6131
6188
|
const dirs = [
|
|
6132
6189
|
resolve2(cwd, ".xcli/plugins"),
|
|
6133
6190
|
resolve2(cwd, "../.xcli/plugins"),
|
|
6134
|
-
this.options.userDir || resolve2(
|
|
6191
|
+
this.options.userDir || resolve2(homedir5(), ".xcli/plugins"),
|
|
6135
6192
|
globalDir
|
|
6136
6193
|
];
|
|
6137
6194
|
const loaded = [];
|
|
@@ -6753,15 +6810,14 @@ var HOOK_REGISTRY = {
|
|
|
6753
6810
|
recorder: {
|
|
6754
6811
|
name: "recorder",
|
|
6755
6812
|
onAfterCommand: async (ctx) => {
|
|
6756
|
-
const
|
|
6757
|
-
const logs = ctxAny.__commandLogs || [];
|
|
6813
|
+
const logs = ("__commandLogs" in ctx ? ctx.__commandLogs : void 0) || [];
|
|
6758
6814
|
logs.push({
|
|
6759
6815
|
timestamp: Date.now(),
|
|
6760
6816
|
command: ctx.command,
|
|
6761
6817
|
params: JSON.parse(JSON.stringify(ctx.params)),
|
|
6762
6818
|
duration: ctx.duration
|
|
6763
6819
|
});
|
|
6764
|
-
|
|
6820
|
+
Reflect.set(ctx, "__commandLogs", logs);
|
|
6765
6821
|
return void 0;
|
|
6766
6822
|
}
|
|
6767
6823
|
}
|
|
@@ -6789,15 +6845,15 @@ async function loadHooks() {
|
|
|
6789
6845
|
}
|
|
6790
6846
|
|
|
6791
6847
|
// src/executor.ts
|
|
6792
|
-
import { homedir as
|
|
6793
|
-
import { join as
|
|
6848
|
+
import { homedir as homedir6 } from "os";
|
|
6849
|
+
import { join as join6 } from "path";
|
|
6794
6850
|
var NAVIGATION_COMMANDS = /* @__PURE__ */ new Set(["goto", "back", "forward", "refresh"]);
|
|
6795
6851
|
var snapshotHintShown = /* @__PURE__ */ new WeakSet();
|
|
6796
|
-
var
|
|
6852
|
+
var CONFIG_DIR2 = join6(homedir6(), ".xbrowser");
|
|
6797
6853
|
var storageCache = /* @__PURE__ */ new Map();
|
|
6798
6854
|
function getPluginStorage(pluginName) {
|
|
6799
6855
|
if (!storageCache.has(pluginName)) {
|
|
6800
|
-
storageCache.set(pluginName, new
|
|
6856
|
+
storageCache.set(pluginName, new CompositeStorage2(pluginName, CONFIG_DIR2, "xbrowser"));
|
|
6801
6857
|
}
|
|
6802
6858
|
return storageCache.get(pluginName);
|
|
6803
6859
|
}
|
|
@@ -6805,7 +6861,7 @@ var archiveInitialized = false;
|
|
|
6805
6861
|
function ensureArchiveInit() {
|
|
6806
6862
|
if (!archiveInitialized) {
|
|
6807
6863
|
try {
|
|
6808
|
-
configureArchiveStore({ archiveDir:
|
|
6864
|
+
configureArchiveStore({ archiveDir: join6(homedir6(), ".xbrowser", "archives") });
|
|
6809
6865
|
} catch {
|
|
6810
6866
|
}
|
|
6811
6867
|
archiveInitialized = true;
|
|
@@ -6862,7 +6918,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6862
6918
|
}
|
|
6863
6919
|
let targetPageOverride = null;
|
|
6864
6920
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6865
|
-
const { findTargetPage } = await import("./browser-
|
|
6921
|
+
const { findTargetPage } = await import("./browser-ITLZZDHJ.js");
|
|
6866
6922
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6867
6923
|
if (!targetPageOverride) {
|
|
6868
6924
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -6879,7 +6935,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6879
6935
|
params = result.data;
|
|
6880
6936
|
}
|
|
6881
6937
|
if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
6882
|
-
const { forwardExec } = await import("./daemon-client-
|
|
6938
|
+
const { forwardExec } = await import("./daemon-client-DIEHGP5B.js");
|
|
6883
6939
|
const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
|
|
6884
6940
|
if (result) return result;
|
|
6885
6941
|
}
|
|
@@ -6930,9 +6986,9 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6930
6986
|
throw new Error(msg);
|
|
6931
6987
|
},
|
|
6932
6988
|
config: {},
|
|
6933
|
-
site:
|
|
6989
|
+
site: new NoopSiteInstance(),
|
|
6934
6990
|
cliName: "xbrowser",
|
|
6935
|
-
tips: new
|
|
6991
|
+
tips: new TipCollector2()
|
|
6936
6992
|
};
|
|
6937
6993
|
const start = Date.now();
|
|
6938
6994
|
if (session) {
|
|
@@ -7045,7 +7101,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7045
7101
|
} catch (err) {
|
|
7046
7102
|
const end = Date.now();
|
|
7047
7103
|
const duration = end - start;
|
|
7048
|
-
const errorMessage = err
|
|
7104
|
+
const errorMessage = errMsg(err);
|
|
7049
7105
|
if (session) {
|
|
7050
7106
|
streamCommandEvent(session.id, {
|
|
7051
7107
|
sessionId: session.id,
|
|
@@ -7158,7 +7214,7 @@ async function executeChain(input, options) {
|
|
|
7158
7214
|
config: {},
|
|
7159
7215
|
site,
|
|
7160
7216
|
cliName: "xbrowser",
|
|
7161
|
-
tips: new
|
|
7217
|
+
tips: new TipCollector2()
|
|
7162
7218
|
};
|
|
7163
7219
|
const start2 = Date.now();
|
|
7164
7220
|
try {
|
|
@@ -7245,7 +7301,7 @@ async function executeChain(input, options) {
|
|
|
7245
7301
|
}
|
|
7246
7302
|
} catch (err) {
|
|
7247
7303
|
const duration2 = Date.now() - start2;
|
|
7248
|
-
const errorMessage = err
|
|
7304
|
+
const errorMessage = errMsg(err);
|
|
7249
7305
|
recordArchive(session.id, sessionName, {
|
|
7250
7306
|
step: results.length,
|
|
7251
7307
|
command: `${cmdName} ${subCommand}`,
|
|
@@ -7555,7 +7611,7 @@ async function replayEntry(entry, options = {}) {
|
|
|
7555
7611
|
size: 0,
|
|
7556
7612
|
bodyMatch: false,
|
|
7557
7613
|
duration: 0,
|
|
7558
|
-
error: err
|
|
7614
|
+
error: errMsg(err)
|
|
7559
7615
|
}
|
|
7560
7616
|
};
|
|
7561
7617
|
}
|
|
@@ -7563,9 +7619,9 @@ async function replayEntry(entry, options = {}) {
|
|
|
7563
7619
|
|
|
7564
7620
|
// src/daemon/feedback-store.ts
|
|
7565
7621
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5 } from "fs";
|
|
7566
|
-
import { join as
|
|
7567
|
-
import { homedir as
|
|
7568
|
-
var FEEDBACK_FILE =
|
|
7622
|
+
import { join as join7 } from "path";
|
|
7623
|
+
import { homedir as homedir7 } from "os";
|
|
7624
|
+
var FEEDBACK_FILE = join7(homedir7(), ".xbrowser", "feedback.json");
|
|
7569
7625
|
var FeedbackStore = class {
|
|
7570
7626
|
entries = [];
|
|
7571
7627
|
constructor() {
|
|
@@ -7581,7 +7637,7 @@ var FeedbackStore = class {
|
|
|
7581
7637
|
}
|
|
7582
7638
|
save() {
|
|
7583
7639
|
try {
|
|
7584
|
-
mkdirSync5(
|
|
7640
|
+
mkdirSync5(join7(homedir7(), ".xbrowser"), { recursive: true });
|
|
7585
7641
|
writeFileSync6(FEEDBACK_FILE, JSON.stringify(this.entries, null, 2));
|
|
7586
7642
|
} catch {
|
|
7587
7643
|
}
|
|
@@ -7743,7 +7799,7 @@ var PlaybackEngine = class _PlaybackEngine {
|
|
|
7743
7799
|
const content = fs2.readFileSync(filePath, "utf-8");
|
|
7744
7800
|
const raw = filePath.endsWith(".json") ? JSON.parse(content) : yaml.parse(content);
|
|
7745
7801
|
let recording;
|
|
7746
|
-
const checkpoints = raw.checkpoints
|
|
7802
|
+
const checkpoints = "checkpoints" in raw ? raw.checkpoints : [];
|
|
7747
7803
|
if (raw.events && raw.events.length > 0) {
|
|
7748
7804
|
recording = raw;
|
|
7749
7805
|
} else if (raw.actions && raw.actions.length > 0) {
|
|
@@ -7816,7 +7872,7 @@ var PlaybackEngine = class _PlaybackEngine {
|
|
|
7816
7872
|
errors.push({
|
|
7817
7873
|
eventIndex: i,
|
|
7818
7874
|
event,
|
|
7819
|
-
error: err
|
|
7875
|
+
error: errMsg(err)
|
|
7820
7876
|
});
|
|
7821
7877
|
if (stopOnError) break;
|
|
7822
7878
|
}
|
|
@@ -7880,7 +7936,7 @@ var PlaybackEngine = class _PlaybackEngine {
|
|
|
7880
7936
|
// src/daemon/rpc-handlers.ts
|
|
7881
7937
|
var activeRecorders = /* @__PURE__ */ new Map();
|
|
7882
7938
|
var replayResumeResolvers = /* @__PURE__ */ new Map();
|
|
7883
|
-
var
|
|
7939
|
+
var CONFIG_DIR3 = join8(homedir8(), ".xbrowser");
|
|
7884
7940
|
var RECORDING_INJECT_JS = `
|
|
7885
7941
|
(function(){
|
|
7886
7942
|
if(window.__xb_rec) return;
|
|
@@ -8237,19 +8293,27 @@ function createRPCHandler() {
|
|
|
8237
8293
|
const analyzed = enrichEntries(scored);
|
|
8238
8294
|
return { session: sessionName, total: entries.length, analyzed };
|
|
8239
8295
|
}
|
|
8296
|
+
function extractCurlOptions(params) {
|
|
8297
|
+
return {
|
|
8298
|
+
includeHeaders: params.includeHeaders,
|
|
8299
|
+
includeBody: params.includeBody,
|
|
8300
|
+
compressed: params.compressed,
|
|
8301
|
+
insecure: params.insecure
|
|
8302
|
+
};
|
|
8303
|
+
}
|
|
8240
8304
|
function handleNetworkCurl(params) {
|
|
8241
8305
|
const sessionName = params.session || "default";
|
|
8242
8306
|
const id = params.id;
|
|
8243
8307
|
const entry = networkStore.inspect(sessionName, id);
|
|
8244
8308
|
if (!entry.capture) return { error: `Entry #${id} not found` };
|
|
8245
|
-
return generateCurl(entry.capture, params);
|
|
8309
|
+
return generateCurl(entry.capture, extractCurlOptions(params));
|
|
8246
8310
|
}
|
|
8247
8311
|
async function handleNetworkReplay(params) {
|
|
8248
8312
|
const sessionName = params.session || "default";
|
|
8249
8313
|
const id = params.id;
|
|
8250
8314
|
const entry = networkStore.inspect(sessionName, id);
|
|
8251
8315
|
if (!entry.capture) return { error: `Entry #${id} not found` };
|
|
8252
|
-
return await replayEntry(entry.capture, params);
|
|
8316
|
+
return await replayEntry(entry.capture, extractCurlOptions(params));
|
|
8253
8317
|
}
|
|
8254
8318
|
function handleNetworkLike(params) {
|
|
8255
8319
|
const sessionName = params.session || "default";
|
|
@@ -8320,9 +8384,9 @@ function createRPCHandler() {
|
|
|
8320
8384
|
if (!sess) return { ok: false, error: "No session" };
|
|
8321
8385
|
try {
|
|
8322
8386
|
const events = await sess.page.evaluate(() => window.__xb_evts || []);
|
|
8323
|
-
const recordingsDir =
|
|
8387
|
+
const recordingsDir = join8(CONFIG_DIR3, "recordings");
|
|
8324
8388
|
mkdirSync6(recordingsDir, { recursive: true });
|
|
8325
|
-
const outPath = params.path ||
|
|
8389
|
+
const outPath = params.path || join8(recordingsDir, `recording-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`);
|
|
8326
8390
|
writeFileSync7(outPath, JSON.stringify({
|
|
8327
8391
|
startUrl: sess.page.url(),
|
|
8328
8392
|
recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8330,7 +8394,7 @@ function createRPCHandler() {
|
|
|
8330
8394
|
}, null, 2));
|
|
8331
8395
|
return { ok: true, path: outPath, events: events.length };
|
|
8332
8396
|
} catch (e) {
|
|
8333
|
-
return { ok: false, error: e
|
|
8397
|
+
return { ok: false, error: errMsg(e) };
|
|
8334
8398
|
}
|
|
8335
8399
|
}
|
|
8336
8400
|
function handleCommandLog(params) {
|
|
@@ -8363,9 +8427,8 @@ function createRPCHandler() {
|
|
|
8363
8427
|
if (session?.page) {
|
|
8364
8428
|
element = await session.page.evaluate((sel) => {
|
|
8365
8429
|
const el = document.querySelector(sel);
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
return w.__xb_describe(el);
|
|
8430
|
+
if (!el || typeof window.__xb_describe !== "function") return null;
|
|
8431
|
+
return window.__xb_describe(el);
|
|
8369
8432
|
}, selector);
|
|
8370
8433
|
}
|
|
8371
8434
|
} catch {
|
|
@@ -8410,7 +8473,7 @@ function createRPCHandler() {
|
|
|
8410
8473
|
cdpEndpoint: session.cdpEndpoint
|
|
8411
8474
|
});
|
|
8412
8475
|
} catch (e) {
|
|
8413
|
-
return { ok: false, error: "Failed to auto-create session: " + e
|
|
8476
|
+
return { ok: false, error: "Failed to auto-create session: " + errMsg(e) };
|
|
8414
8477
|
}
|
|
8415
8478
|
}
|
|
8416
8479
|
try {
|
|
@@ -8419,7 +8482,7 @@ function createRPCHandler() {
|
|
|
8419
8482
|
activeRecorders.set(sessionName, recorder);
|
|
8420
8483
|
return { ok: true, session: sessionName, startUrl: url || session.page.url() };
|
|
8421
8484
|
} catch (e) {
|
|
8422
|
-
return { ok: false, error: e
|
|
8485
|
+
return { ok: false, error: errMsg(e) };
|
|
8423
8486
|
}
|
|
8424
8487
|
}
|
|
8425
8488
|
async function handleRecordStop(params) {
|
|
@@ -8451,7 +8514,7 @@ function createRPCHandler() {
|
|
|
8451
8514
|
};
|
|
8452
8515
|
} catch (e) {
|
|
8453
8516
|
activeRecorders.delete(sessionName);
|
|
8454
|
-
return { ok: false, error: e
|
|
8517
|
+
return { ok: false, error: errMsg(e) };
|
|
8455
8518
|
}
|
|
8456
8519
|
}
|
|
8457
8520
|
function handleRecordStatus(params) {
|
|
@@ -8519,14 +8582,14 @@ function createRPCHandler() {
|
|
|
8519
8582
|
const sessionName = params.session || "default";
|
|
8520
8583
|
const slowMo = params.slowMo || 1;
|
|
8521
8584
|
if (!file) {
|
|
8522
|
-
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1,
|
|
8585
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Missing file parameter" }] };
|
|
8523
8586
|
}
|
|
8524
8587
|
const session = findSession(sessionName);
|
|
8525
8588
|
if (!session) {
|
|
8526
|
-
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1,
|
|
8589
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Session not found: " + sessionName }] };
|
|
8527
8590
|
}
|
|
8528
8591
|
if (!session.page) {
|
|
8529
|
-
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1,
|
|
8592
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Session has no page: " + sessionName }] };
|
|
8530
8593
|
}
|
|
8531
8594
|
let rawContent;
|
|
8532
8595
|
let parsed;
|
|
@@ -8534,12 +8597,12 @@ function createRPCHandler() {
|
|
|
8534
8597
|
rawContent = readFileSync6(file, "utf8");
|
|
8535
8598
|
parsed = JSON.parse(rawContent);
|
|
8536
8599
|
} catch (e) {
|
|
8537
|
-
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1,
|
|
8600
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Failed to read/parse file: " + String(e) }] };
|
|
8538
8601
|
}
|
|
8539
8602
|
const isNewFormat = Array.isArray(parsed.actions);
|
|
8540
8603
|
if (isNewFormat) {
|
|
8541
8604
|
try {
|
|
8542
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
8605
|
+
const { SessionReplayer } = await import("./session-replayer-MY27H4DX.js");
|
|
8543
8606
|
const replayer = new SessionReplayer({
|
|
8544
8607
|
page: session.page,
|
|
8545
8608
|
stepDelay: slowMo * 500,
|
|
@@ -8550,6 +8613,9 @@ function createRPCHandler() {
|
|
|
8550
8613
|
console.error(`[replay] Error at step ${action.type}: ${error.message}`);
|
|
8551
8614
|
}
|
|
8552
8615
|
});
|
|
8616
|
+
if (!Array.isArray(parsed.actions) || typeof parsed.startUrl !== "string") {
|
|
8617
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Invalid recording format: missing actions or startUrl" }] };
|
|
8618
|
+
}
|
|
8553
8619
|
await replayer.load(parsed);
|
|
8554
8620
|
const startTime = Date.now();
|
|
8555
8621
|
const result2 = await replayer.run();
|
|
@@ -8565,7 +8631,7 @@ function createRPCHandler() {
|
|
|
8565
8631
|
} catch (e) {
|
|
8566
8632
|
const msg = e instanceof Error ? e.message : String(e);
|
|
8567
8633
|
console.error("[replay] SessionReplayer error:", msg);
|
|
8568
|
-
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1,
|
|
8634
|
+
return { ok: false, success: false, duration: 0, eventsPlayed: 0, totalEvents: 0, errors: [{ eventIndex: -1, error: "Replay failed: " + msg }] };
|
|
8569
8635
|
}
|
|
8570
8636
|
}
|
|
8571
8637
|
const engine = PlaybackEngine.fromFile(session.page, file);
|
|
@@ -9117,14 +9183,13 @@ var ElementMonitor = class {
|
|
|
9117
9183
|
document.addEventListener("focusin", (e) => {
|
|
9118
9184
|
const el = e.target;
|
|
9119
9185
|
if (el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.contentEditable === "true") {
|
|
9120
|
-
|
|
9121
|
-
w.__xb_focus_seq = (w.__xb_focus_seq || 0) + 1;
|
|
9186
|
+
window.__xb_focus_seq = (window.__xb_focus_seq || 0) + 1;
|
|
9122
9187
|
const info = {
|
|
9123
9188
|
selector: "",
|
|
9124
9189
|
tag: el.tagName,
|
|
9125
9190
|
value: el.value || "",
|
|
9126
9191
|
placeholder: el.placeholder || "",
|
|
9127
|
-
seq:
|
|
9192
|
+
seq: window.__xb_focus_seq
|
|
9128
9193
|
};
|
|
9129
9194
|
if (el.id) info.selector = "#" + el.id;
|
|
9130
9195
|
else if (el.getAttribute("name")) info.selector = '[name="' + el.getAttribute("name") + '"]';
|
|
@@ -9132,7 +9197,7 @@ var ElementMonitor = class {
|
|
|
9132
9197
|
if (el.tagName === "INPUT" && el.type === "file") {
|
|
9133
9198
|
info.isFileInput = true;
|
|
9134
9199
|
}
|
|
9135
|
-
|
|
9200
|
+
window.__xb_last_focused = info;
|
|
9136
9201
|
}
|
|
9137
9202
|
}, true);
|
|
9138
9203
|
document.addEventListener("focusout", () => {
|
|
@@ -9639,12 +9704,12 @@ var FileListHandler = class {
|
|
|
9639
9704
|
const msg = ctx.message;
|
|
9640
9705
|
try {
|
|
9641
9706
|
const { readdirSync: readdirSync2, statSync } = await import("fs");
|
|
9642
|
-
const { join:
|
|
9707
|
+
const { join: join10, resolve: resolve3 } = await import("path");
|
|
9643
9708
|
const targetPath = resolve3(msg.path);
|
|
9644
9709
|
const entries = readdirSync2(targetPath);
|
|
9645
9710
|
const files = entries.map((name) => {
|
|
9646
9711
|
try {
|
|
9647
|
-
const stat = statSync(
|
|
9712
|
+
const stat = statSync(join10(targetPath, name));
|
|
9648
9713
|
return { name, isDir: stat.isDirectory(), size: stat.size, modified: stat.mtime.toISOString() };
|
|
9649
9714
|
} catch {
|
|
9650
9715
|
return { name, isDir: false, size: 0, modified: "" };
|
|
@@ -11305,8 +11370,8 @@ connectWS();
|
|
|
11305
11370
|
}
|
|
11306
11371
|
|
|
11307
11372
|
// src/daemon/daemon-main.ts
|
|
11308
|
-
var
|
|
11309
|
-
var LOG_FILE =
|
|
11373
|
+
var CONFIG_DIR4 = join9(homedir9(), ".xbrowser");
|
|
11374
|
+
var LOG_FILE = join9(CONFIG_DIR4, "daemon.log");
|
|
11310
11375
|
function log(msg) {
|
|
11311
11376
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
11312
11377
|
const line = `[DAEMON ${ts}] ${msg}
|
|
@@ -11360,8 +11425,8 @@ async function main() {
|
|
|
11360
11425
|
rpcHandler.setPreviewWS(previewWS);
|
|
11361
11426
|
previewWS.on("screencast-started", (sid) => log(`Preview screencast started: ${sid}`));
|
|
11362
11427
|
previewWS.on("screencast-stopped", (sid) => log(`Preview screencast stopped: ${sid}`));
|
|
11363
|
-
mkdirSync7(
|
|
11364
|
-
writeFileSync8(
|
|
11428
|
+
mkdirSync7(CONFIG_DIR4, { recursive: true });
|
|
11429
|
+
writeFileSync8(join9(CONFIG_DIR4, "daemon.json"), JSON.stringify({
|
|
11365
11430
|
port: daemonPort,
|
|
11366
11431
|
pid: process.pid,
|
|
11367
11432
|
startedAt: Date.now()
|