@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/cli.js CHANGED
@@ -25,8 +25,8 @@ import {
25
25
  resolveLaunchOpts,
26
26
  saveSessionDiskMeta,
27
27
  setActivePage
28
- } from "./chunk-CAFNSGYM.js";
29
- import "./chunk-BBMRDUYQ.js";
28
+ } from "./chunk-DKWR54XQ.js";
29
+ import "./chunk-TNEN6VQ2.js";
30
30
  import {
31
31
  forwardCommandLog,
32
32
  forwardNetworkAnalyze,
@@ -54,11 +54,14 @@ import {
54
54
  killAllDaemonProcesses,
55
55
  startDaemonProcess,
56
56
  stopDaemonProcess
57
- } from "./chunk-Q4IGYTKR.js";
57
+ } from "./chunk-6WOSXSCQ.js";
58
+ import {
59
+ errMsg
60
+ } from "./chunk-GDKLH7ZY.js";
58
61
  import "./chunk-KFQGP6VL.js";
59
62
 
60
63
  // src/router.ts
61
- import { parseArgs, outputFormatter as outputFormatter2, isCommandResult as isCommandResult2, helpGenerator as helpGenerator2, TipCollector as TipCollector2, normalizeTips as normalizeTips7, tip as makeTip } from "@dyyz1993/xcli-core";
64
+ import { parseArgs, outputFormatter as outputFormatter2, isCommandResult as isCommandResult2, helpGenerator as helpGenerator2, TipCollector as TipCollector3, normalizeTips as normalizeTips7, tip as makeTip } from "@dyyz1993/xcli-core";
62
65
 
63
66
  // src/utils/positional-params.ts
64
67
  import { unquote } from "@dyyz1993/xcli-core";
@@ -170,6 +173,11 @@ function parsePluginParams(args, schema, base = {}) {
170
173
  return result;
171
174
  }
172
175
 
176
+ // src/utils/zod-internal.ts
177
+ function asZodSchema(value) {
178
+ return value;
179
+ }
180
+
173
181
  // src/version.ts
174
182
  import { createRequire } from "module";
175
183
  var require2 = createRequire(import.meta.url);
@@ -181,8 +189,8 @@ import {
181
189
  ok as ok25,
182
190
  fail as fail7,
183
191
  isCommandResult,
184
- CompositeStorage,
185
- TipCollector,
192
+ CompositeStorage as CompositeStorage2,
193
+ TipCollector as TipCollector2,
186
194
  normalizeTips as normalizeTips6,
187
195
  configureArchiveStore,
188
196
  appendCommandToArchive,
@@ -190,6 +198,69 @@ import {
190
198
  unquote as unquote2
191
199
  } from "@dyyz1993/xcli-core";
192
200
 
201
+ // src/utils/stub-context.ts
202
+ import { join } from "path";
203
+ import { homedir } from "os";
204
+ import { TipCollector, CompositeStorage } from "@dyyz1993/xcli-core";
205
+ var CONFIG_DIR = join(homedir(), ".xbrowser");
206
+ var NoopSiteInstance = class {
207
+ name = "stub";
208
+ url = "";
209
+ config = { name: "stub" };
210
+ command() {
211
+ return this;
212
+ }
213
+ group() {
214
+ return this;
215
+ }
216
+ login() {
217
+ return this;
218
+ }
219
+ logout() {
220
+ return this;
221
+ }
222
+ async isLoggedIn() {
223
+ return true;
224
+ }
225
+ async requireLogin() {
226
+ }
227
+ getStorage() {
228
+ return new CompositeStorage("stub", CONFIG_DIR, "xbrowser");
229
+ }
230
+ getAllCommands() {
231
+ return [];
232
+ }
233
+ getCommand() {
234
+ return null;
235
+ }
236
+ getOriginalHandler() {
237
+ return void 0;
238
+ }
239
+ async executeLogin() {
240
+ }
241
+ async executeLogout() {
242
+ }
243
+ async restoreLogin() {
244
+ return false;
245
+ }
246
+ };
247
+ function createStubContext(pluginName) {
248
+ return {
249
+ args: [],
250
+ options: {},
251
+ cwd: process.cwd(),
252
+ storage: new CompositeStorage(pluginName, CONFIG_DIR, "xbrowser"),
253
+ output: { mode: "text", showTips: false, color: false, emoji: false },
254
+ error: (msg) => {
255
+ throw new Error(msg);
256
+ },
257
+ config: {},
258
+ site: new NoopSiteInstance(),
259
+ cliName: "xbrowser",
260
+ tips: new TipCollector()
261
+ };
262
+ }
263
+
193
264
  // src/commands/navigation.ts
194
265
  import { z } from "zod";
195
266
  import { ok } from "@dyyz1993/xcli-core";
@@ -237,7 +308,7 @@ async function detectSsr(page) {
237
308
  try {
238
309
  const result = await page.evaluate((vars) => {
239
310
  for (const varName of vars) {
240
- const value = window[varName];
311
+ const value = Reflect.get(window, varName);
241
312
  if (value != null && typeof value === "object") {
242
313
  const keys = Object.keys(value).slice(0, 10);
243
314
  return { variable: varName, keys };
@@ -953,9 +1024,9 @@ var clearLocalStorageCommand = registerCommand({
953
1024
  import { z as z9 } from "zod";
954
1025
  import { ok as ok9 } from "@dyyz1993/xcli-core";
955
1026
  import { writeFileSync, mkdirSync } from "fs";
956
- import { join } from "path";
957
- import { homedir } from "os";
958
- var SCREENSHOTS_DIR = join(homedir(), ".xbrowser", "screenshots");
1027
+ import { join as join2 } from "path";
1028
+ import { homedir as homedir2 } from "os";
1029
+ var SCREENSHOTS_DIR = join2(homedir2(), ".xbrowser", "screenshots");
959
1030
  function ensureScreenshotsDir() {
960
1031
  mkdirSync(SCREENSHOTS_DIR, { recursive: true });
961
1032
  }
@@ -963,7 +1034,7 @@ function generateScreenshotPath(format) {
963
1034
  const timestamp = Date.now();
964
1035
  const random = Math.random().toString(36).slice(2, 8);
965
1036
  const ext = format === "jpeg" ? "jpg" : "png";
966
- return join(SCREENSHOTS_DIR, `screenshot-${timestamp}-${random}.${ext}`);
1037
+ return join2(SCREENSHOTS_DIR, `screenshot-${timestamp}-${random}.${ext}`);
967
1038
  }
968
1039
  var screenshotCommand = registerCommand({
969
1040
  name: "screenshot",
@@ -1586,7 +1657,7 @@ var healthCheckCommand = registerCommand({
1586
1657
  issues.push({
1587
1658
  severity: "error",
1588
1659
  category: "links",
1589
- message: `Broken link (fetch error): ${href} \u2014 ${err.message || "unknown"}`
1660
+ message: `Broken link (fetch error): ${href} \u2014 ${errMsg(err) || "unknown"}`
1590
1661
  });
1591
1662
  }
1592
1663
  }
@@ -1620,9 +1691,9 @@ var healthCheckCommand = registerCommand({
1620
1691
  import { z as z14 } from "zod";
1621
1692
  import { ok as ok14 } from "@dyyz1993/xcli-core";
1622
1693
  import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1623
- import { join as join2 } from "path";
1624
- import { homedir as homedir2 } from "os";
1625
- var SCREENSHOTS_DIR2 = join2(homedir2(), ".xbrowser", "screenshots");
1694
+ import { join as join3 } from "path";
1695
+ import { homedir as homedir3 } from "os";
1696
+ var SCREENSHOTS_DIR2 = join3(homedir3(), ".xbrowser", "screenshots");
1626
1697
  function ensureScreenshotsDir2() {
1627
1698
  mkdirSync2(SCREENSHOTS_DIR2, { recursive: true });
1628
1699
  }
@@ -1630,7 +1701,7 @@ function generateScreenshotPath2(format) {
1630
1701
  const timestamp = Date.now();
1631
1702
  const random = Math.random().toString(36).slice(2, 8);
1632
1703
  const ext = format === "jpeg" ? "jpg" : "png";
1633
- return join2(SCREENSHOTS_DIR2, `screenshot-${timestamp}-${random}.${ext}`);
1704
+ return join3(SCREENSHOTS_DIR2, `screenshot-${timestamp}-${random}.${ext}`);
1634
1705
  }
1635
1706
  var waitActionSchema = z14.object({
1636
1707
  type: z14.literal("wait"),
@@ -4132,8 +4203,8 @@ async function resolveRefParams(page, params, selectorKeys, cache, sessionId) {
4132
4203
 
4133
4204
  // src/utils/site-semantics.ts
4134
4205
  import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync, readFileSync } from "fs";
4135
- import { join as join3, dirname } from "path";
4136
- import { homedir as homedir3 } from "os";
4206
+ import { join as join4, dirname } from "path";
4207
+ import { homedir as homedir4 } from "os";
4137
4208
  import { stringify, parse } from "yaml";
4138
4209
  import { execFile } from "child_process";
4139
4210
  var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
@@ -4210,10 +4281,10 @@ function inferAction(role, label) {
4210
4281
  return {};
4211
4282
  }
4212
4283
  function getSemanticsDir() {
4213
- return join3(homedir3(), ".xbrowser", "site-semantics");
4284
+ return join4(homedir4(), ".xbrowser", "site-semantics");
4214
4285
  }
4215
4286
  function getSemanticsPath(domain) {
4216
- return join3(getSemanticsDir(), `${domain}.yaml`);
4287
+ return join4(getSemanticsDir(), `${domain}.yaml`);
4217
4288
  }
4218
4289
  function extractDomain2(url) {
4219
4290
  try {
@@ -4685,7 +4756,7 @@ async function actOnPage(page, sessionId, input) {
4685
4756
  ref: normalizedRef,
4686
4757
  success: false,
4687
4758
  reason: "browser_error",
4688
- message: error.message,
4759
+ message: errMsg(error),
4689
4760
  stale,
4690
4761
  screenHash: hash,
4691
4762
  target: refMatch?.target
@@ -4769,7 +4840,7 @@ async function waitForPage(page, input) {
4769
4840
  matched: input.selector ? "selector" : input.text ? "text" : input.url ? "url" : input.load ? "load" : input.fn ? "fn" : "screenHashChanged",
4770
4841
  timeout,
4771
4842
  elapsed: Date.now() - startedAt,
4772
- message: error.message
4843
+ message: errMsg(error)
4773
4844
  };
4774
4845
  }
4775
4846
  return {
@@ -5704,11 +5775,11 @@ async function detectWebdriverExposure(page) {
5704
5775
  try {
5705
5776
  const webdriver = await page.evaluate(() => {
5706
5777
  return {
5707
- webdriver: window.navigator && window.navigator instanceof Object ? window.navigator.webdriver : void 0,
5778
+ webdriver: navigator.webdriver,
5708
5779
  webdriverScriptFn: !!window.__webdriver_script_fn,
5709
5780
  webdriverEvaluate: !!window.__webdriver_evaluate,
5710
5781
  chrome: !!window.chrome,
5711
- permissions: window.navigator && window.navigator instanceof Object ? window.navigator.permissions : void 0
5782
+ permissions: navigator.permissions
5712
5783
  };
5713
5784
  }).catch(() => null);
5714
5785
  if (!webdriver) {
@@ -5794,7 +5865,7 @@ import {
5794
5865
  } from "@dyyz1993/xcli-core";
5795
5866
  import { resolve as resolve2 } from "path";
5796
5867
  import { existsSync as existsSync4, readdirSync } from "fs";
5797
- import { homedir as homedir4 } from "os";
5868
+ import { homedir as homedir5 } from "os";
5798
5869
 
5799
5870
  // src/plugin/metadata-parser.ts
5800
5871
  import { existsSync as existsSync2 } from "fs";
@@ -5881,17 +5952,17 @@ var PluginMetadataParser = class {
5881
5952
 
5882
5953
  // src/plugin/ensure-deps.ts
5883
5954
  import { existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
5884
- import { join as join4 } from "path";
5955
+ import { join as join5 } from "path";
5885
5956
  import { execSync } from "child_process";
5886
5957
  var SHARED_PLUGIN_DEPENDENCIES = {
5887
5958
  "zod": "^3.24.0",
5888
5959
  "@dyyz1993/xcli-core": "^0.12.1"
5889
5960
  };
5890
5961
  function ensurePluginDependencies(pluginsDir) {
5891
- const zodPath = join4(pluginsDir, "node_modules", "zod");
5962
+ const zodPath = join5(pluginsDir, "node_modules", "zod");
5892
5963
  if (existsSync3(zodPath)) return;
5893
5964
  mkdirSync4(pluginsDir, { recursive: true });
5894
- const pkgPath = join4(pluginsDir, "package.json");
5965
+ const pkgPath = join5(pluginsDir, "package.json");
5895
5966
  let pkg2 = {};
5896
5967
  if (existsSync3(pkgPath)) {
5897
5968
  try {
@@ -5907,7 +5978,7 @@ function ensurePluginDependencies(pluginsDir) {
5907
5978
  needsInstall = true;
5908
5979
  }
5909
5980
  }
5910
- if (!needsInstall && existsSync3(join4(pluginsDir, "node_modules"))) return;
5981
+ if (!needsInstall && existsSync3(join5(pluginsDir, "node_modules"))) return;
5911
5982
  pkg2.dependencies = existingDeps;
5912
5983
  pkg2.private = true;
5913
5984
  pkg2.description = pkg2.description || "xbrowser plugins \u2014 shared dependencies";
@@ -6068,19 +6139,26 @@ var patched = false;
6068
6139
  function patchLoginRequired() {
6069
6140
  if (patched) return;
6070
6141
  patched = true;
6071
- const proto = SiteInstanceImpl.prototype;
6072
- const original = proto.command;
6073
- proto.command = function(name, cmd) {
6074
- const result = original.call(this, name, cmd);
6142
+ const target = SiteInstanceImpl.prototype;
6143
+ const originalCommand = target.command;
6144
+ const wrapped = function(...args) {
6145
+ const result = originalCommand.apply(this, args);
6146
+ const [name, cmd] = args;
6075
6147
  const loginRequired = cmd.loginRequired;
6076
6148
  if (loginRequired) {
6077
- const entry = this.commands.get(name);
6149
+ const commands = this.commands;
6150
+ const entry = commands?.get(name);
6078
6151
  if (entry) {
6079
6152
  entry.loginRequired = loginRequired;
6080
6153
  }
6081
6154
  }
6082
6155
  return result;
6083
6156
  };
6157
+ Object.defineProperty(target, "command", {
6158
+ value: wrapped,
6159
+ writable: true,
6160
+ configurable: true
6161
+ });
6084
6162
  }
6085
6163
 
6086
6164
  // src/plugin/loader.ts
@@ -6147,12 +6225,12 @@ var XBrowserPluginLoader = class {
6147
6225
  }
6148
6226
  async scanAndLoad() {
6149
6227
  const cwd = this.options.cwd || process.cwd();
6150
- const globalDir = this.options.globalDir || resolve2(homedir4(), ".xbrowser/plugins");
6228
+ const globalDir = this.options.globalDir || resolve2(homedir5(), ".xbrowser/plugins");
6151
6229
  ensurePluginDependencies(globalDir);
6152
6230
  const dirs = [
6153
6231
  resolve2(cwd, ".xcli/plugins"),
6154
6232
  resolve2(cwd, "../.xcli/plugins"),
6155
- this.options.userDir || resolve2(homedir4(), ".xcli/plugins"),
6233
+ this.options.userDir || resolve2(homedir5(), ".xcli/plugins"),
6156
6234
  globalDir
6157
6235
  ];
6158
6236
  const loaded = [];
@@ -6774,15 +6852,14 @@ var HOOK_REGISTRY = {
6774
6852
  recorder: {
6775
6853
  name: "recorder",
6776
6854
  onAfterCommand: async (ctx) => {
6777
- const ctxAny = ctx;
6778
- const logs = ctxAny.__commandLogs || [];
6855
+ const logs = ("__commandLogs" in ctx ? ctx.__commandLogs : void 0) || [];
6779
6856
  logs.push({
6780
6857
  timestamp: Date.now(),
6781
6858
  command: ctx.command,
6782
6859
  params: JSON.parse(JSON.stringify(ctx.params)),
6783
6860
  duration: ctx.duration
6784
6861
  });
6785
- ctxAny.__commandLogs = logs;
6862
+ Reflect.set(ctx, "__commandLogs", logs);
6786
6863
  return void 0;
6787
6864
  }
6788
6865
  }
@@ -6810,15 +6887,15 @@ async function loadHooks() {
6810
6887
  }
6811
6888
 
6812
6889
  // src/executor.ts
6813
- import { homedir as homedir5 } from "os";
6814
- import { join as join5 } from "path";
6890
+ import { homedir as homedir6 } from "os";
6891
+ import { join as join6 } from "path";
6815
6892
  var NAVIGATION_COMMANDS = /* @__PURE__ */ new Set(["goto", "back", "forward", "refresh"]);
6816
6893
  var snapshotHintShown = /* @__PURE__ */ new WeakSet();
6817
- var CONFIG_DIR = join5(homedir5(), ".xbrowser");
6894
+ var CONFIG_DIR2 = join6(homedir6(), ".xbrowser");
6818
6895
  var storageCache = /* @__PURE__ */ new Map();
6819
6896
  function getPluginStorage(pluginName) {
6820
6897
  if (!storageCache.has(pluginName)) {
6821
- storageCache.set(pluginName, new CompositeStorage(pluginName, CONFIG_DIR, "xbrowser"));
6898
+ storageCache.set(pluginName, new CompositeStorage2(pluginName, CONFIG_DIR2, "xbrowser"));
6822
6899
  }
6823
6900
  return storageCache.get(pluginName);
6824
6901
  }
@@ -6826,7 +6903,7 @@ var archiveInitialized = false;
6826
6903
  function ensureArchiveInit() {
6827
6904
  if (!archiveInitialized) {
6828
6905
  try {
6829
- configureArchiveStore({ archiveDir: join5(homedir5(), ".xbrowser", "archives") });
6906
+ configureArchiveStore({ archiveDir: join6(homedir6(), ".xbrowser", "archives") });
6830
6907
  } catch {
6831
6908
  }
6832
6909
  archiveInitialized = true;
@@ -6883,7 +6960,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6883
6960
  }
6884
6961
  let targetPageOverride = null;
6885
6962
  if (_target && extraOpts?.cdpEndpoint) {
6886
- const { findTargetPage } = await import("./browser-R56O3CW6.js");
6963
+ const { findTargetPage } = await import("./browser-5CTOA2WS.js");
6887
6964
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
6888
6965
  if (!targetPageOverride) {
6889
6966
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -6900,7 +6977,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6900
6977
  params = result.data;
6901
6978
  }
6902
6979
  if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
6903
- const { forwardExec } = await import("./daemon-client-UZZEHHIV.js");
6980
+ const { forwardExec } = await import("./daemon-client-3JOKX2L2.js");
6904
6981
  const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
6905
6982
  if (result) return result;
6906
6983
  }
@@ -6951,9 +7028,9 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6951
7028
  throw new Error(msg);
6952
7029
  },
6953
7030
  config: {},
6954
- site: {},
7031
+ site: new NoopSiteInstance(),
6955
7032
  cliName: "xbrowser",
6956
- tips: new TipCollector()
7033
+ tips: new TipCollector2()
6957
7034
  };
6958
7035
  const start = Date.now();
6959
7036
  if (session) {
@@ -7066,7 +7143,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7066
7143
  } catch (err) {
7067
7144
  const end = Date.now();
7068
7145
  const duration = end - start;
7069
- const errorMessage = err.message;
7146
+ const errorMessage = errMsg(err);
7070
7147
  if (session) {
7071
7148
  streamCommandEvent(session.id, {
7072
7149
  sessionId: session.id,
@@ -7179,7 +7256,7 @@ async function executeChain(input, options) {
7179
7256
  config: {},
7180
7257
  site,
7181
7258
  cliName: "xbrowser",
7182
- tips: new TipCollector()
7259
+ tips: new TipCollector2()
7183
7260
  };
7184
7261
  const start2 = Date.now();
7185
7262
  try {
@@ -7266,7 +7343,7 @@ async function executeChain(input, options) {
7266
7343
  }
7267
7344
  } catch (err) {
7268
7345
  const duration2 = Date.now() - start2;
7269
- const errorMessage = err.message;
7346
+ const errorMessage = errMsg(err);
7270
7347
  recordArchive(session.id, sessionName, {
7271
7348
  step: results.length,
7272
7349
  command: `${cmdName} ${subCommand}`,
@@ -7465,11 +7542,11 @@ var sessionKillBuiltin = {
7465
7542
  };
7466
7543
 
7467
7544
  // src/config.ts
7468
- import { homedir as homedir6, tmpdir } from "os";
7469
- import { join as join6 } from "path";
7545
+ import { homedir as homedir7, tmpdir } from "os";
7546
+ import { join as join7 } from "path";
7470
7547
  import { loadConfig as coreLoadConfig, saveConfig as coreSaveConfig } from "@dyyz1993/xcli-core";
7471
7548
  function getConfigSource() {
7472
- return { configDir: join6(homedir6() || tmpdir(), ".xbrowser") };
7549
+ return { configDir: join7(homedir7() || tmpdir(), ".xbrowser") };
7473
7550
  }
7474
7551
  function loadConfig() {
7475
7552
  return coreLoadConfig(getConfigSource());
@@ -7589,7 +7666,7 @@ import {
7589
7666
  rmSync as rmSync6
7590
7667
  } from "fs";
7591
7668
  import { resolve as resolve8, basename as basename2 } from "path";
7592
- import { homedir as homedir7 } from "os";
7669
+ import { homedir as homedir8 } from "os";
7593
7670
 
7594
7671
  // src/plugin/install-sources/local.ts
7595
7672
  import { existsSync as existsSync5, cpSync, rmSync } from "fs";
@@ -7631,7 +7708,7 @@ async function installFromLocal(source, name, targetDir) {
7631
7708
 
7632
7709
  // src/plugin/install-sources/npm.ts
7633
7710
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync6, rmSync as rmSync2, cpSync as cpSync2 } from "fs";
7634
- import { resolve as resolve4, join as join7 } from "path";
7711
+ import { resolve as resolve4, join as join8 } from "path";
7635
7712
  import { tmpdir as tmpdir2 } from "os";
7636
7713
  import {
7637
7714
  downloadToFile,
@@ -7669,7 +7746,8 @@ async function ensureProxyFetch() {
7669
7746
  const body = init?.body;
7670
7747
  if (body instanceof globalThis.FormData && !(body instanceof UFormData)) {
7671
7748
  const ufd = new UFormData();
7672
- body.forEach((value, key) => {
7749
+ const domFormData = body;
7750
+ domFormData.forEach((value, key) => {
7673
7751
  if (value instanceof Blob) {
7674
7752
  ufd.append(key, value, value.name || "file");
7675
7753
  } else {
@@ -7703,13 +7781,13 @@ async function installFromNpm(packageName, name, targetDir) {
7703
7781
  throw new Error(`No tarball URL for ${packageName}@${latestVersion}`);
7704
7782
  }
7705
7783
  const tarballUrl = versionMeta.dist.tarball;
7706
- const tmpDir = join7(tmpdir2(), `xbrowser-npm-${Date.now()}`);
7784
+ const tmpDir = join8(tmpdir2(), `xbrowser-npm-${Date.now()}`);
7707
7785
  mkdirSync5(tmpDir, { recursive: true });
7708
7786
  let warnings = [];
7709
7787
  try {
7710
- const tarballPath = join7(tmpDir, `${name}.tgz`);
7788
+ const tarballPath = join8(tmpDir, `${name}.tgz`);
7711
7789
  await downloadToFile(tarballUrl, tarballPath);
7712
- const extractDir = join7(tmpDir, "extracted");
7790
+ const extractDir = join8(tmpDir, "extracted");
7713
7791
  extractTarGz(tarballPath, extractDir);
7714
7792
  flattenPackageRoot(extractDir);
7715
7793
  const verify = verifyPlugin2(extractDir, { metadataField: "xbrowser" });
@@ -7744,12 +7822,12 @@ async function installFromNpm(packageName, name, targetDir) {
7744
7822
 
7745
7823
  // src/plugin/install-sources/git.ts
7746
7824
  import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync7, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
7747
- import { resolve as resolve5, join as join8 } from "path";
7825
+ import { resolve as resolve5, join as join9 } from "path";
7748
7826
  import { tmpdir as tmpdir3 } from "os";
7749
7827
  import { execSync as execSync2 } from "child_process";
7750
7828
  import { verifyPlugin as verifyPlugin3, safeCleanup as safeCleanup3 } from "@dyyz1993/xcli-core";
7751
7829
  async function installFromGit(gitUrl, name, targetDir) {
7752
- const tmpDir = join8(tmpdir3(), `xbrowser-git-${Date.now()}`);
7830
+ const tmpDir = join9(tmpdir3(), `xbrowser-git-${Date.now()}`);
7753
7831
  let warnings = [];
7754
7832
  try {
7755
7833
  execSync2(`git clone --depth 1 "${gitUrl}" "${tmpDir}"`, { stdio: "pipe" });
@@ -7786,7 +7864,7 @@ async function installFromGit(gitUrl, name, targetDir) {
7786
7864
 
7787
7865
  // src/plugin/install-sources/url.ts
7788
7866
  import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync8, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
7789
- import { resolve as resolve6, join as join9, basename } from "path";
7867
+ import { resolve as resolve6, join as join10, basename } from "path";
7790
7868
  import { tmpdir as tmpdir4 } from "os";
7791
7869
  import {
7792
7870
  downloadToFile as downloadToFile2,
@@ -7796,14 +7874,14 @@ import {
7796
7874
  safeCleanup as safeCleanup4
7797
7875
  } from "@dyyz1993/xcli-core";
7798
7876
  async function installFromUrl(url, name, targetDir) {
7799
- const tmpDir = join9(tmpdir4(), `xbrowser-url-${Date.now()}`);
7877
+ const tmpDir = join10(tmpdir4(), `xbrowser-url-${Date.now()}`);
7800
7878
  mkdirSync6(tmpDir, { recursive: true });
7801
7879
  let warnings = [];
7802
7880
  try {
7803
7881
  const fileName = basename(new URL(url).pathname) || "plugin.tar.gz";
7804
- const tarballPath = join9(tmpDir, fileName);
7882
+ const tarballPath = join10(tmpDir, fileName);
7805
7883
  await downloadToFile2(url, tarballPath);
7806
- const extractDir = join9(tmpDir, "extracted");
7884
+ const extractDir = join10(tmpDir, "extracted");
7807
7885
  extractTarGz2(tarballPath, extractDir);
7808
7886
  flattenPackageRoot2(extractDir);
7809
7887
  const verify = verifyPlugin4(extractDir, { metadataField: "xbrowser" });
@@ -7845,7 +7923,7 @@ import {
7845
7923
  rmSync as rmSync5,
7846
7924
  cpSync as cpSync5
7847
7925
  } from "fs";
7848
- import { resolve as resolve7, join as join10, dirname as dirname2 } from "path";
7926
+ import { resolve as resolve7, join as join11, dirname as dirname2 } from "path";
7849
7927
  import { tmpdir as tmpdir5 } from "os";
7850
7928
  import { gunzipSync } from "zlib";
7851
7929
  import {
@@ -7874,7 +7952,7 @@ async function installFromMarketplace(pluginsDir, slug, options) {
7874
7952
  throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
7875
7953
  }
7876
7954
  mkdirSync7(targetDir, { recursive: true });
7877
- const tmpDir = join10(tmpdir5(), `xbrowser-marketplace-${Date.now()}`);
7955
+ const tmpDir = join11(tmpdir5(), `xbrowser-marketplace-${Date.now()}`);
7878
7956
  mkdirSync7(tmpDir, { recursive: true });
7879
7957
  const realSlug = String(plugin.slug || slug);
7880
7958
  try {
@@ -7937,7 +8015,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
7937
8015
  }
7938
8016
  if (tarballRes.status === 302 || tarballRes.headers.get("location")) {
7939
8017
  const redirectUrl = tarballRes.headers.get("location");
7940
- const tarballPath = join10(tmpDir, `${slug}.tar.gz`);
8018
+ const tarballPath = join11(tmpDir, `${slug}.tar.gz`);
7941
8019
  await downloadToFile3(redirectUrl, tarballPath);
7942
8020
  const buffer = readFileSync7(tarballPath);
7943
8021
  const manifest = tryParseAsGzippedManifest(buffer);
@@ -7945,7 +8023,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
7945
8023
  extractManifestToDir(manifest, targetDir);
7946
8024
  return;
7947
8025
  }
7948
- const extractDir = join10(tmpDir, "extracted");
8026
+ const extractDir = join11(tmpDir, "extracted");
7949
8027
  extractTarGz3(tarballPath, extractDir);
7950
8028
  flattenPackageRoot3(extractDir);
7951
8029
  if (existsSync9(targetDir)) {
@@ -7959,10 +8037,10 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
7959
8037
  extractManifestToDir(manifest, targetDir);
7960
8038
  return;
7961
8039
  }
7962
- const tarballPath = join10(tmpDir, `${slug}.tar.gz`);
8040
+ const tarballPath = join11(tmpDir, `${slug}.tar.gz`);
7963
8041
  writeFileSync9(tarballPath, buffer);
7964
8042
  try {
7965
- const extractDir = join10(tmpDir, "extracted");
8043
+ const extractDir = join11(tmpDir, "extracted");
7966
8044
  extractTarGz3(tarballPath, extractDir);
7967
8045
  flattenPackageRoot3(extractDir);
7968
8046
  if (existsSync9(targetDir)) {
@@ -8055,7 +8133,7 @@ function ensureIndexFile(plugin, name, targetDir) {
8055
8133
  var PluginInstaller = class {
8056
8134
  pluginsDir;
8057
8135
  constructor(pluginsDir) {
8058
- this.pluginsDir = pluginsDir || resolve8(homedir7(), ".xbrowser/plugins");
8136
+ this.pluginsDir = pluginsDir || resolve8(homedir8(), ".xbrowser/plugins");
8059
8137
  }
8060
8138
  getPluginsDir() {
8061
8139
  return this.pluginsDir;
@@ -8584,7 +8662,7 @@ async function searchFromMarketplacePlugin(options, loader) {
8584
8662
  site: options.site,
8585
8663
  limit: options.limit
8586
8664
  },
8587
- {}
8665
+ createStubContext("marketplace")
8588
8666
  );
8589
8667
  const items = extractItems(result);
8590
8668
  return items.map((item) => ({
@@ -9360,16 +9438,16 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9360
9438
  if (cmdDef) {
9361
9439
  if (mode === "json") {
9362
9440
  const paramsList = [];
9363
- const schema = cmdDef.parameters;
9441
+ const schema = asZodSchema(cmdDef.parameters);
9364
9442
  const shape = schema?.shape ?? schema?._def?.shape;
9365
9443
  if (shape) {
9366
9444
  for (const [key, value] of Object.entries(shape)) {
9367
- const fieldSchema = value;
9445
+ const fieldSchema = asZodSchema(value);
9368
9446
  const fieldDef = fieldSchema._def;
9369
9447
  const description = fieldSchema.description || fieldDef?.description || "";
9370
9448
  const typeName = fieldDef?.typeName || "";
9371
9449
  const isOptional = typeName === "ZodOptional" || typeof fieldSchema.isOptional === "function" && fieldSchema.isOptional();
9372
- const innerType = fieldDef?.innerType;
9450
+ const innerType = asZodSchema(fieldDef?.innerType);
9373
9451
  const innerTypeName = innerType?._def ? innerType._def.typeName : typeName;
9374
9452
  let type = "unknown";
9375
9453
  if (innerTypeName === "ZodString" || typeName === "ZodString") type = "string";
@@ -9687,15 +9765,15 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
9687
9765
  }
9688
9766
 
9689
9767
  // src/cli/session-routes.ts
9690
- import { homedir as homedir8 } from "os";
9691
- import { join as join12 } from "path";
9768
+ import { homedir as homedir9 } from "os";
9769
+ import { join as join13 } from "path";
9692
9770
  import { readdirSync as readdirSync3, rmSync as rmSync7 } from "fs";
9693
9771
  function cleanSessionFiles() {
9694
- const dir = join12(homedir8(), ".xbrowser", "sessions");
9772
+ const dir = join13(homedir9(), ".xbrowser", "sessions");
9695
9773
  let count = 0;
9696
9774
  try {
9697
9775
  for (const entry of readdirSync3(dir, { withFileTypes: true })) {
9698
- const p = join12(dir, entry.name);
9776
+ const p = join13(dir, entry.name);
9699
9777
  rmSync7(p, { recursive: true, force: true });
9700
9778
  count++;
9701
9779
  }
@@ -9779,8 +9857,7 @@ async function buildRuntimePluginInfo() {
9779
9857
  const cmds = site.getAllCommands();
9780
9858
  const commandNames = cmds.map((c) => c.name);
9781
9859
  if (commandNames.length === 0) continue;
9782
- const anySite = site;
9783
- const hasLoginHandler = typeof anySite.hasLoginCommand === "function" && anySite.hasLoginCommand();
9860
+ const hasLoginHandler = "hasLoginCommand" in site && typeof site.hasLoginCommand === "function" && site.hasLoginCommand();
9784
9861
  const configRequiresLogin = !!site.config.requiresLogin;
9785
9862
  const hasLogin = hasLoginHandler || configRequiresLogin;
9786
9863
  let loggedIn = null;
@@ -9830,7 +9907,7 @@ async function searchFromMarketplacePlugin2(options, loader) {
9830
9907
  site: options.site,
9831
9908
  limit: options.limit
9832
9909
  },
9833
- {}
9910
+ createStubContext("marketplace")
9834
9911
  );
9835
9912
  const items = extractItems2(result);
9836
9913
  return items.map((item) => ({ ...item, source: "marketplace" }));
@@ -9845,7 +9922,7 @@ async function infoFromMarketplacePlugin(slug, loader) {
9845
9922
  const infoCmd = marketplaceSite.getCommand("info");
9846
9923
  if (!infoCmd) return null;
9847
9924
  try {
9848
- const result = await infoCmd.handler({ slug }, {});
9925
+ const result = await infoCmd.handler({ slug }, createStubContext("marketplace"));
9849
9926
  if (!result || typeof result !== "object") return null;
9850
9927
  const r = result;
9851
9928
  let plugin = null;
@@ -9953,7 +10030,7 @@ async function handlePluginInfo(args, options, mode) {
9953
10030
  }
9954
10031
  console.error(`\u63D2\u4EF6 '${slug}' \u672A\u627E\u5230`);
9955
10032
  } catch (err) {
9956
- console.error("\u67E5\u8BE2\u5931\u8D25:", err.message);
10033
+ console.error("\u67E5\u8BE2\u5931\u8D25:", errMsg(err));
9957
10034
  }
9958
10035
  }
9959
10036
  async function handlePluginSchema(args, mode) {
@@ -10493,7 +10570,7 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
10493
10570
  const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-RTDGURIJ.js");
10494
10571
  const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
10495
10572
  const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync11 } = await import("fs");
10496
- const { join: join13 } = await import("path");
10573
+ const { join: join14 } = await import("path");
10497
10574
  const data = SessionRecorder2.readData(sessionName);
10498
10575
  if (!data) {
10499
10576
  outputError(`No recording found for session "${sessionName}". Run \`xbrowser record stop --session ${sessionName}\` first.`);
@@ -10505,14 +10582,14 @@ async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
10505
10582
  } catch {
10506
10583
  }
10507
10584
  const finalPluginName = pluginName || domain.split(".")[0] || "my-site";
10508
- const finalOutputDir = outputDir || join13(process.cwd(), ".xcli", "plugins", finalPluginName);
10585
+ const finalOutputDir = outputDir || join14(process.cwd(), ".xcli", "plugins", finalPluginName);
10509
10586
  const knowledge = readSiteKnowledge2(domain);
10510
10587
  const knowledgeMd = knowledge ? toMarkdown(knowledge) : "";
10511
10588
  const pluginCode = generatePluginCode(finalPluginName, domain, data, knowledgeMd);
10512
- mkdirSync10(join13(finalOutputDir), { recursive: true });
10513
- writeFileSync11(join13(finalOutputDir, "index.ts"), pluginCode, "utf-8");
10589
+ mkdirSync10(join14(finalOutputDir), { recursive: true });
10590
+ writeFileSync11(join14(finalOutputDir, "index.ts"), pluginCode, "utf-8");
10514
10591
  if (knowledgeMd) {
10515
- writeFileSync11(join13(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
10592
+ writeFileSync11(join14(finalOutputDir, "SITE_KNOWLEDGE.md"), knowledgeMd, "utf-8");
10516
10593
  }
10517
10594
  console.log("");
10518
10595
  console.log("=== Plugin Generated ===");
@@ -10644,9 +10721,9 @@ interface XBPage {
10644
10721
  }
10645
10722
 
10646
10723
  function ensurePage(ctx: CommandContext): XBPage {
10647
- const page = (ctx as Record<string, unknown>).page;
10724
+ const page = 'page' in ctx ? (ctx as Record<string, unknown>).page : undefined;
10648
10725
  if (!page) throw new Error('No active page. Start a session first.');
10649
- return page as unknown as XBPage;
10726
+ return page as XBPage;
10650
10727
  }
10651
10728
 
10652
10729
  export default createSite({
@@ -10679,7 +10756,7 @@ async function handleRun(filePath, options) {
10679
10756
  try {
10680
10757
  commands = readCommandFile(filePath);
10681
10758
  } catch (e) {
10682
- outputError(`Failed to read file '${filePath}': ${e.message}`);
10759
+ outputError(`Failed to read file '${filePath}': ${errMsg(e)}`);
10683
10760
  return;
10684
10761
  }
10685
10762
  if (commands.length === 0) {
@@ -11035,7 +11112,7 @@ async function handleNetCommand(args, options, mode, sessionName) {
11035
11112
  outputError(`Unknown net sub-command: ${subCommand}. Use: list, clear, top, log, around, analyze, curl, replay, inspect, like, dislike, export`);
11036
11113
  }
11037
11114
  } catch (err) {
11038
- outputError(err.message || "Network command failed");
11115
+ outputError(errMsg(err) || "Network command failed");
11039
11116
  }
11040
11117
  }
11041
11118
 
@@ -11560,7 +11637,7 @@ async function createSessionHandler(req) {
11560
11637
  createdAt: session.createdAt
11561
11638
  });
11562
11639
  } catch (err) {
11563
- return errorResponse(500, "INTERNAL_ERROR", err.message);
11640
+ return errorResponse(500, "INTERNAL_ERROR", errMsg(err));
11564
11641
  }
11565
11642
  }
11566
11643
  async function closeSession2(req) {
@@ -11655,7 +11732,7 @@ async function route(method, url, headers, body) {
11655
11732
  try {
11656
11733
  return await match.route.handler(req);
11657
11734
  } catch (err) {
11658
- return errorResponse(500, "INTERNAL_ERROR", err.message);
11735
+ return errorResponse(500, "INTERNAL_ERROR", errMsg(err));
11659
11736
  }
11660
11737
  }
11661
11738
  async function handleRequest(req, res, validateAuthFn) {
@@ -11813,8 +11890,9 @@ function showCommandHelp(siteName, cmd, siteConfig, mode) {
11813
11890
  if (mode === "json") {
11814
11891
  const paramsList = [];
11815
11892
  if (c.parameters) {
11816
- const def = c.parameters._def;
11817
- const shape = def.shape?.();
11893
+ const def = asZodSchema(c.parameters)._def;
11894
+ const rawShape = def?.shape;
11895
+ const shape = typeof rawShape === "function" ? rawShape() : rawShape;
11818
11896
  if (shape) {
11819
11897
  for (const [key, value] of Object.entries(shape)) {
11820
11898
  const info = extractZodFieldInfo(value);
@@ -12041,16 +12119,16 @@ async function routeCommand(argv, stdinCommands) {
12041
12119
  if (builtinCmd) {
12042
12120
  if (mode === "json") {
12043
12121
  const paramsList = [];
12044
- const schema = builtinCmd.parameters;
12122
+ const schema = asZodSchema(builtinCmd.parameters);
12045
12123
  const shape = schema?.shape ?? schema?._def?.shape;
12046
12124
  if (shape) {
12047
12125
  for (const [key, value] of Object.entries(shape)) {
12048
- const fieldSchema = value;
12126
+ const fieldSchema = asZodSchema(value);
12049
12127
  const fieldDef = fieldSchema._def;
12050
12128
  const description = fieldSchema.description || fieldDef?.description || "";
12051
12129
  const typeName = fieldDef?.typeName || "";
12052
12130
  const isOptional = typeName === "ZodOptional" || typeof fieldSchema.isOptional === "function" && fieldSchema.isOptional();
12053
- const innerType = fieldDef?.innerType;
12131
+ const innerType = asZodSchema(fieldDef?.innerType);
12054
12132
  const innerTypeName = innerType?._def ? innerType._def.typeName : typeName;
12055
12133
  let type = "unknown";
12056
12134
  if (innerTypeName === "ZodString" || typeName === "ZodString") type = "string";
@@ -12225,7 +12303,7 @@ Run "xbrowser ${command} --help" to see available commands.`
12225
12303
  const rawPluginArgs = subCmdIdx >= 0 ? argv.slice(subCmdIdx + 1) : [];
12226
12304
  const params = parsePluginParams(rawPluginArgs, cmdEntry.parameters);
12227
12305
  if (cmdEntry.parameters) {
12228
- const schemaAny = cmdEntry.parameters;
12306
+ const schemaAny = asZodSchema(cmdEntry.parameters);
12229
12307
  const def = schemaAny._def;
12230
12308
  const shapeOrFn = def?.shape ?? schemaAny.shape;
12231
12309
  const shapeObj = typeof shapeOrFn === "function" ? shapeOrFn() : shapeOrFn;
@@ -12249,10 +12327,10 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
12249
12327
  }
12250
12328
  const needsBrowser = cmdEntry.scope === "page" || cmdEntry.scope === "browser";
12251
12329
  if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
12252
- const { forwardExec } = await import("./daemon-client-UZZEHHIV.js");
12330
+ const { forwardExec } = await import("./daemon-client-3JOKX2L2.js");
12253
12331
  const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
12254
12332
  const result = await forwardExec(`${command}.${subCommand}`, params, sessionName, cdpEndpoint, userTimeout);
12255
- const resultData = result && typeof result === "object" ? result.data : void 0;
12333
+ const resultData = result && typeof result === "object" && "data" in result ? result.data : void 0;
12256
12334
  if (result && result.success === false && resultData?.code === "LOGIN_REQUIRED") {
12257
12335
  outputLoginRequired(result, mode);
12258
12336
  return;
@@ -12301,7 +12379,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
12301
12379
  waitForHuman: async (_opts) => {
12302
12380
  return { solved: false, timedOut: true };
12303
12381
  },
12304
- tips: new TipCollector2()
12382
+ tips: new TipCollector3()
12305
12383
  };
12306
12384
  try {
12307
12385
  const cmdStart = Date.now();
@@ -12555,7 +12633,7 @@ async function main() {
12555
12633
  const command = process.argv[2];
12556
12634
  const isLongRunning = command === "preview" || command === "serve";
12557
12635
  if (!isLongRunning) {
12558
- const { ensureProcessCanExit } = await import("./browser-R56O3CW6.js");
12636
+ const { ensureProcessCanExit } = await import("./browser-5CTOA2WS.js");
12559
12637
  await ensureProcessCanExit().catch(() => {
12560
12638
  });
12561
12639
  process.exit(exitCode);