@xbrowser/cli 0.14.0 → 0.14.1

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/index.js CHANGED
@@ -1,9 +1,3 @@
1
- import {
2
- CaptchaDetector,
3
- HumanInteractionManager,
4
- ScreencastCapturer,
5
- WebhookNotifier
6
- } from "./chunk-VUJDJCIN.js";
7
1
  import {
8
2
  generateBashScript,
9
3
  generateJSScript,
@@ -52,24 +46,6 @@ import {
52
46
  networkAnomalyRule,
53
47
  pageLifecycleRule
54
48
  } from "./chunk-ZZ2TFWIV.js";
55
- import {
56
- PluginMetadataParser,
57
- createTarball
58
- } from "./chunk-OLB6UJ25.js";
59
- import {
60
- ensureProxyFetch
61
- } from "./chunk-VEKPHQBR.js";
62
- import {
63
- NPM_REGISTRY_URL,
64
- NPM_SCOPE,
65
- getCaptchaConfig,
66
- getConfigValue,
67
- getMarketplaceUrl,
68
- loadConfig,
69
- readJsonFile,
70
- resolveNpmPackageWithFallback,
71
- setConfigValue
72
- } from "./chunk-M7CMBPCA.js";
73
49
  import {
74
50
  forwardCommandLog,
75
51
  forwardNetworkAnalyze,
@@ -99,6 +75,21 @@ import {
99
75
  startDaemonProcess,
100
76
  stopDaemonProcess
101
77
  } from "./chunk-ATFTAKMN.js";
78
+ import {
79
+ CaptchaDetector,
80
+ HumanInteractionManager,
81
+ NPM_REGISTRY_URL,
82
+ NPM_SCOPE,
83
+ ScreencastCapturer,
84
+ WebhookNotifier,
85
+ getCaptchaConfig,
86
+ getConfigValue,
87
+ getMarketplaceUrl,
88
+ loadConfig,
89
+ readJsonFile,
90
+ resolveNpmPackageWithFallback,
91
+ setConfigValue
92
+ } from "./chunk-ITKPSIP7.js";
102
93
  import {
103
94
  __require
104
95
  } from "./chunk-3RG5ZIWI.js";
@@ -436,15 +427,15 @@ var clickCommand = registerCommand({
436
427
  let detectedNewPage;
437
428
  let cleanup;
438
429
  if (ctx.browserContext?.on) {
439
- const pagePromise = new Promise((resolve15) => {
430
+ const pagePromise = new Promise((resolve16) => {
440
431
  const timer = setTimeout(() => {
441
432
  ctx.browserContext.off("page", handler);
442
- resolve15(void 0);
433
+ resolve16(void 0);
443
434
  }, 3e3);
444
435
  const handler = (page2) => {
445
436
  clearTimeout(timer);
446
437
  ctx.browserContext.off("page", handler);
447
- resolve15(page2);
438
+ resolve16(page2);
448
439
  };
449
440
  ctx.browserContext.on("page", handler);
450
441
  });
@@ -1202,7 +1193,7 @@ var consoleCheckCommand = registerCommand({
1202
1193
  await page.goto(p.url, { waitUntil: "domcontentloaded" });
1203
1194
  }
1204
1195
  const messages = await page.evaluate((args) => {
1205
- return new Promise((resolve15) => {
1196
+ return new Promise((resolve16) => {
1206
1197
  const collected = [];
1207
1198
  const originalConsole = {
1208
1199
  log: console.log,
@@ -1269,7 +1260,7 @@ ${a.stack || ""}`;
1269
1260
  console.warn = originalConsole.warn;
1270
1261
  console.error = originalConsole.error;
1271
1262
  console.info = originalConsole.info;
1272
- resolve15(collected);
1263
+ resolve16(collected);
1273
1264
  }, args.duration);
1274
1265
  });
1275
1266
  }, { duration: p.duration });
@@ -1681,7 +1672,7 @@ async function executeAction(page, action) {
1681
1672
  if (action.selector) {
1682
1673
  await page.waitForSelector(action.selector, { timeout: 3e4 });
1683
1674
  } else if (action.milliseconds) {
1684
- await new Promise((resolve15) => setTimeout(resolve15, action.milliseconds));
1675
+ await new Promise((resolve16) => setTimeout(resolve16, action.milliseconds));
1685
1676
  } else {
1686
1677
  throw new Error("wait action requires either milliseconds or selector");
1687
1678
  }
@@ -1764,8 +1755,8 @@ var actionsCommand = registerCommand({
1764
1755
  results.push(result);
1765
1756
  }
1766
1757
  })();
1767
- const timeoutPromise = new Promise((resolve15) => {
1768
- setTimeout(resolve15, timeoutMs);
1758
+ const timeoutPromise = new Promise((resolve16) => {
1759
+ setTimeout(resolve16, timeoutMs);
1769
1760
  });
1770
1761
  await Promise.race([executionPromise, timeoutPromise]);
1771
1762
  const title = await ctx.page.title();
@@ -2439,11 +2430,11 @@ async function navigateForMap(page, url, timeout = 15e3) {
2439
2430
  }
2440
2431
  async function extractPageLinks(page, baseUrl) {
2441
2432
  await navigateForMap(page, baseUrl);
2442
- await new Promise((resolve15) => setTimeout(resolve15, 2e3));
2433
+ await new Promise((resolve16) => setTimeout(resolve16, 2e3));
2443
2434
  await page.evaluate(() => {
2444
2435
  window.scrollTo(0, document.body.scrollHeight);
2445
2436
  });
2446
- await new Promise((resolve15) => setTimeout(resolve15, 1e3));
2437
+ await new Promise((resolve16) => setTimeout(resolve16, 1e3));
2447
2438
  const origin = new URL(baseUrl).origin;
2448
2439
  const rawLinks = await page.evaluate((evalOrigin) => {
2449
2440
  return Array.from(document.querySelectorAll("a[href]")).map((a) => {
@@ -4550,25 +4541,25 @@ aria snapshot\uFF1A
4550
4541
  async function analyzeWithLLM(ariaSnapshot) {
4551
4542
  const piBin = process.env.PI_CLI_PATH || "pi";
4552
4543
  const prompt = LLM_PROMPT.replace("{snapshot}", ariaSnapshot.slice(0, 4e3));
4553
- return new Promise((resolve15) => {
4544
+ return new Promise((resolve16) => {
4554
4545
  execFile(
4555
4546
  piBin,
4556
4547
  ["--provider", LLM_PROVIDER, "--model", LLM_MODEL, prompt],
4557
4548
  { timeout: LLM_TIMEOUT_MS, maxBuffer: 1024 * 1024 },
4558
4549
  (err, stdout, _stderr) => {
4559
4550
  if (err) {
4560
- resolve15(null);
4551
+ resolve16(null);
4561
4552
  return;
4562
4553
  }
4563
4554
  const output = (stdout || "").trim();
4564
4555
  if (!output) {
4565
- resolve15(null);
4556
+ resolve16(null);
4566
4557
  return;
4567
4558
  }
4568
4559
  try {
4569
4560
  const parsed = parse(output);
4570
4561
  if (!parsed || typeof parsed !== "object") {
4571
- resolve15(null);
4562
+ resolve16(null);
4572
4563
  return;
4573
4564
  }
4574
4565
  const elements = {};
@@ -4583,9 +4574,9 @@ async function analyzeWithLLM(ariaSnapshot) {
4583
4574
  };
4584
4575
  }
4585
4576
  }
4586
- resolve15(Object.keys(elements).length > 0 ? elements : null);
4577
+ resolve16(Object.keys(elements).length > 0 ? elements : null);
4587
4578
  } catch {
4588
- resolve15(null);
4579
+ resolve16(null);
4589
4580
  }
4590
4581
  }
4591
4582
  );
@@ -5138,11 +5129,11 @@ function resolveScriptContent(params) {
5138
5129
  async function readStdin() {
5139
5130
  const { createReadStream } = await import("fs");
5140
5131
  const { createInterface: createInterface2 } = await import("readline");
5141
- return new Promise((resolve15, reject) => {
5132
+ return new Promise((resolve16, reject) => {
5142
5133
  const lines = [];
5143
5134
  const rl = createInterface2({ input: createReadStream("/dev/stdin") });
5144
5135
  rl.on("line", (line) => lines.push(line));
5145
- rl.on("close", () => resolve15(lines.join("\n")));
5136
+ rl.on("close", () => resolve16(lines.join("\n")));
5146
5137
  rl.on("error", reject);
5147
5138
  });
5148
5139
  }
@@ -5880,12 +5871,82 @@ var promoCommand = registerCommand({
5880
5871
  import {
5881
5872
  Core
5882
5873
  } from "@dyyz1993/xcli-core";
5883
- import { resolve as resolve7 } from "path";
5884
- import { existsSync as existsSync4, readdirSync } from "fs";
5874
+ import { resolve as resolve8 } from "path";
5875
+ import { existsSync as existsSync5, readdirSync } from "fs";
5885
5876
  import { homedir as homedir2 } from "os";
5886
5877
 
5878
+ // src/plugin/metadata-parser.ts
5879
+ import { existsSync as existsSync3 } from "fs";
5880
+ import { resolve as resolve7 } from "path";
5881
+ var PluginMetadataParser = class {
5882
+ static XBROWSER_KEYWORDS = ["xbrowser", "xbrowser-plugin"];
5883
+ static parseFromPackageJson(pluginPath) {
5884
+ const packageJsonPath = resolve7(pluginPath, "package.json");
5885
+ if (!existsSync3(packageJsonPath)) {
5886
+ return null;
5887
+ }
5888
+ const packageJson = readJsonFile(packageJsonPath, null);
5889
+ if (!packageJson) return null;
5890
+ if (!packageJson.xbrowser) {
5891
+ return null;
5892
+ }
5893
+ const xbrowser = packageJson.xbrowser;
5894
+ const metadata = {
5895
+ id: xbrowser.id || packageJson.name,
5896
+ name: xbrowser.name || packageJson.name,
5897
+ description: xbrowser.description || packageJson.description || "",
5898
+ version: xbrowser.version || packageJson.version || "1.0.0",
5899
+ author: xbrowser.author || this.extractAuthor(packageJson.author),
5900
+ homepage: xbrowser.homepage || packageJson.homepage,
5901
+ commands: xbrowser.commands,
5902
+ sites: xbrowser.sites,
5903
+ tags: xbrowser.tags,
5904
+ screenshot: xbrowser.screenshot,
5905
+ license: xbrowser.license || packageJson.license
5906
+ };
5907
+ return metadata;
5908
+ }
5909
+ static isXBrowserPlugin(packageJson) {
5910
+ if (packageJson.xbrowser) {
5911
+ return true;
5912
+ }
5913
+ const keywords = packageJson.keywords;
5914
+ if (!keywords) return false;
5915
+ return this.XBROWSER_KEYWORDS.some((kw) => keywords.includes(kw));
5916
+ }
5917
+ static fromNPMResult(result) {
5918
+ const author = typeof result.author === "string" ? result.author : result.author?.name || "Unknown";
5919
+ return {
5920
+ id: result.name,
5921
+ name: result.name.replace(/^xbrowser-plugin-/, "").replace(/^@[^/]+\//, ""),
5922
+ description: result.description || "",
5923
+ version: result.version,
5924
+ author,
5925
+ homepage: result.homepage || result.links?.homepage,
5926
+ tags: result.keywords,
5927
+ license: ""
5928
+ };
5929
+ }
5930
+ static extractAuthor(author) {
5931
+ if (typeof author === "string") return author;
5932
+ if (typeof author === "object" && author !== null) {
5933
+ const authorObj = author;
5934
+ return authorObj.name || "Unknown";
5935
+ }
5936
+ return "Unknown";
5937
+ }
5938
+ static validateMetadata(metadata) {
5939
+ const errors = [];
5940
+ if (!metadata.id) errors.push("id is required");
5941
+ if (!metadata.name) errors.push("name is required");
5942
+ if (!metadata.description) errors.push("description is required");
5943
+ if (!metadata.version) errors.push("version is required");
5944
+ return errors;
5945
+ }
5946
+ };
5947
+
5887
5948
  // src/plugin/ensure-deps.ts
5888
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
5949
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
5889
5950
  import { join as join2 } from "path";
5890
5951
  import { execSync as execSync6 } from "child_process";
5891
5952
  var SHARED_PLUGIN_DEPENDENCIES = {
@@ -5894,11 +5955,11 @@ var SHARED_PLUGIN_DEPENDENCIES = {
5894
5955
  };
5895
5956
  function ensurePluginDependencies(pluginsDir) {
5896
5957
  const zodPath = join2(pluginsDir, "node_modules", "zod");
5897
- if (existsSync3(zodPath)) return;
5958
+ if (existsSync4(zodPath)) return;
5898
5959
  mkdirSync2(pluginsDir, { recursive: true });
5899
5960
  const pkgPath = join2(pluginsDir, "package.json");
5900
5961
  let pkg2 = {};
5901
- if (existsSync3(pkgPath)) {
5962
+ if (existsSync4(pkgPath)) {
5902
5963
  try {
5903
5964
  pkg2 = readJsonFile(pkgPath, {});
5904
5965
  } catch {
@@ -5912,7 +5973,7 @@ function ensurePluginDependencies(pluginsDir) {
5912
5973
  needsInstall = true;
5913
5974
  }
5914
5975
  }
5915
- if (!needsInstall && existsSync3(join2(pluginsDir, "node_modules"))) return;
5976
+ if (!needsInstall && existsSync4(join2(pluginsDir, "node_modules"))) return;
5916
5977
  pkg2.dependencies = existingDeps;
5917
5978
  pkg2.private = true;
5918
5979
  pkg2.description = pkg2.description || "xbrowser plugins \u2014 shared dependencies";
@@ -5946,7 +6007,7 @@ var XBrowserPluginLoader = class {
5946
6007
  envPrefix: "XBROWSER",
5947
6008
  pluginDirs: [
5948
6009
  ...DEFAULT_PLUGIN_DIRS,
5949
- resolve7(cwd, ".xcli/plugins")
6010
+ resolve8(cwd, ".xcli/plugins")
5950
6011
  ]
5951
6012
  };
5952
6013
  this.core = new Core(coreConfig);
@@ -5985,31 +6046,31 @@ var XBrowserPluginLoader = class {
5985
6046
  }
5986
6047
  async scanAndLoad() {
5987
6048
  const cwd = this.options.cwd || process.cwd();
5988
- const globalDir = this.options.globalDir || resolve7(homedir2(), ".xbrowser/plugins");
6049
+ const globalDir = this.options.globalDir || resolve8(homedir2(), ".xbrowser/plugins");
5989
6050
  ensurePluginDependencies(globalDir);
5990
6051
  const dirs = [
5991
- resolve7(cwd, ".xcli/plugins"),
5992
- resolve7(cwd, "../.xcli/plugins"),
5993
- this.options.userDir || resolve7(homedir2(), ".xcli/plugins"),
6052
+ resolve8(cwd, ".xcli/plugins"),
6053
+ resolve8(cwd, "../.xcli/plugins"),
6054
+ this.options.userDir || resolve8(homedir2(), ".xcli/plugins"),
5994
6055
  globalDir
5995
6056
  ];
5996
6057
  const loaded = [];
5997
6058
  const seen = /* @__PURE__ */ new Set();
5998
6059
  for (const dir of dirs) {
5999
- if (!existsSync4(dir)) continue;
6060
+ if (!existsSync5(dir)) continue;
6000
6061
  const entries = readdirSync(dir, { withFileTypes: true });
6001
6062
  for (const entry of entries) {
6002
6063
  if (!entry.isDirectory()) continue;
6003
6064
  if (seen.has(entry.name)) continue;
6004
6065
  seen.add(entry.name);
6005
- const pluginDir = resolve7(dir, entry.name);
6006
- let indexPath = resolve7(pluginDir, "index.js");
6007
- if (!existsSync4(indexPath)) {
6008
- indexPath = resolve7(pluginDir, "index.ts");
6066
+ const pluginDir = resolve8(dir, entry.name);
6067
+ let indexPath = resolve8(pluginDir, "index.js");
6068
+ if (!existsSync5(indexPath)) {
6069
+ indexPath = resolve8(pluginDir, "index.ts");
6009
6070
  }
6010
- if (!existsSync4(indexPath)) continue;
6071
+ if (!existsSync5(indexPath)) continue;
6011
6072
  try {
6012
- if (!existsSync4(resolve7(pluginDir, "package.json"))) {
6073
+ if (!existsSync5(resolve8(pluginDir, "package.json"))) {
6013
6074
  console.warn(`\u26A0\uFE0F Plugin "${entry.name}" has no package.json. Use "xbrowser create ${entry.name} --template static" for proper structure.`);
6014
6075
  } else {
6015
6076
  const metadata = PluginMetadataParser.parseFromPackageJson(pluginDir);
@@ -6026,22 +6087,6 @@ var XBrowserPluginLoader = class {
6026
6087
  }
6027
6088
  }
6028
6089
  }
6029
- try {
6030
- const { default: setupMarketplace } = await import("./marketplace-FPT5YLKB.js");
6031
- setupMarketplace(this.loader.getAPI());
6032
- } catch (err) {
6033
- if (process.env.XBROWSER_DEBUG) {
6034
- console.warn(`\u26A0\uFE0F Built-in marketplace plugin load failed: ${err instanceof Error ? err.message : String(err)}`);
6035
- }
6036
- }
6037
- try {
6038
- const { default: setupAdmin } = await import("./admin-MDGF4CET.js");
6039
- setupAdmin(this.loader.getAPI());
6040
- } catch (err) {
6041
- if (process.env.XBROWSER_DEBUG) {
6042
- console.warn(`\u26A0\uFE0F Built-in admin plugin load failed: ${err instanceof Error ? err.message : String(err)}`);
6043
- }
6044
- }
6045
6090
  return loaded;
6046
6091
  }
6047
6092
  async unload() {
@@ -6442,7 +6487,7 @@ var TipsManager = class {
6442
6487
  }
6443
6488
  }
6444
6489
  debounce() {
6445
- return new Promise((resolve15) => setTimeout(resolve15, DEBOUNCE_MS));
6490
+ return new Promise((resolve16) => setTimeout(resolve16, DEBOUNCE_MS));
6446
6491
  }
6447
6492
  formatTips(tips) {
6448
6493
  return tips.map((tip) => {
@@ -6469,6 +6514,24 @@ function getTipsManager() {
6469
6514
  return globalTipsManager;
6470
6515
  }
6471
6516
 
6517
+ // src/hooks/loader.ts
6518
+ var builtinHooks = {
6519
+ screenshot: () => import("./screenshot-CWAWMXVA.js").then((m) => m.screenshotHook)
6520
+ };
6521
+ async function loadHooks() {
6522
+ const names = process.env.XBROWSER_HOOKS;
6523
+ if (!names) return [];
6524
+ const hooks = [];
6525
+ for (const name of names.split(",")) {
6526
+ const trimmed = name.trim();
6527
+ const factory = builtinHooks[trimmed];
6528
+ if (factory) {
6529
+ hooks.push(await factory());
6530
+ }
6531
+ }
6532
+ return hooks;
6533
+ }
6534
+
6472
6535
  // src/executor.ts
6473
6536
  import { homedir as homedir3 } from "os";
6474
6537
  import { join as join3 } from "path";
@@ -6631,9 +6694,22 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6631
6694
  }
6632
6695
  }
6633
6696
  try {
6697
+ const hooks = await loadHooks();
6698
+ if (hooks.length > 0 && session?.page) {
6699
+ await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
6700
+ }
6634
6701
  const raw = await command.handler(params, ctx);
6635
6702
  const end = Date.now();
6636
6703
  const duration = end - start;
6704
+ let hookOutputs;
6705
+ if (hooks.length > 0 && session?.page) {
6706
+ const outputs = [];
6707
+ for (const h of hooks) {
6708
+ const output = await h.onAfterCommand?.({ page: session.page, command: commandName, params, result: raw, duration });
6709
+ if (output) outputs.push({ _hook: h.name, ...output });
6710
+ }
6711
+ if (outputs.length > 0) hookOutputs = outputs;
6712
+ }
6637
6713
  if (session && isCommandResult(raw)) {
6638
6714
  const resultData = raw.data;
6639
6715
  const convUrl = resultData?.conversationUrl;
@@ -6681,9 +6757,9 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6681
6757
  timestamp: start
6682
6758
  });
6683
6759
  if (isSuccess) {
6684
- return { ...ok25(raw.data, merged.length > 0 ? merged : raw.tips), duration };
6760
+ return { ...ok25(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
6685
6761
  }
6686
- return { success: false, data: raw.data, message: raw.message, tips: merged.length > 0 ? merged : raw.tips || [], duration };
6762
+ return { success: false, data: raw.data, message: raw.message, tips: merged.length > 0 ? merged : raw.tips || [], duration, ...hookOutputs ? { hookOutputs } : {} };
6687
6763
  }
6688
6764
  recordArchive(session?.id, sessionName, {
6689
6765
  step: 0,
@@ -6694,7 +6770,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6694
6770
  duration,
6695
6771
  timestamp: start
6696
6772
  });
6697
- return { ...ok25(raw, smartTips), duration };
6773
+ return { ...ok25(raw, smartTips), duration, ...hookOutputs ? { hookOutputs } : {} };
6698
6774
  } catch (err) {
6699
6775
  const end = Date.now();
6700
6776
  const duration = end - start;
@@ -6965,7 +7041,7 @@ function attachWaitForHuman(ctx, getOrCreateWSServer) {
6965
7041
  if (!ctx.page) {
6966
7042
  throw new Error("waitForHuman requires an active page");
6967
7043
  }
6968
- const { HumanInteractionManager: HumanInteractionManager2 } = await import("./human-interaction-QPHNDD76.js");
7044
+ const { HumanInteractionManager: HumanInteractionManager2 } = await import("./human-interaction-W753RVJB.js");
6969
7045
  const wsServer2 = await getOrCreateWSServer(ctx.browserContext);
6970
7046
  const manager = new HumanInteractionManager2(wsServer2, ctx.page);
6971
7047
  return manager.waitForHuman(options);
@@ -7209,21 +7285,21 @@ var configBuiltin = {
7209
7285
 
7210
7286
  // src/plugin/installer.ts
7211
7287
  import {
7212
- existsSync as existsSync11,
7288
+ existsSync as existsSync12,
7213
7289
  readdirSync as readdirSync3,
7214
7290
  mkdirSync as mkdirSync7,
7215
7291
  rmSync as rmSync7
7216
7292
  } from "fs";
7217
- import { resolve as resolve14, basename as basename2 } from "path";
7293
+ import { resolve as resolve15, basename as basename2 } from "path";
7218
7294
  import { homedir as homedir4 } from "os";
7219
7295
 
7220
7296
  // src/plugin/install-sources/local.ts
7221
- import { existsSync as existsSync6, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
7222
- import { resolve as resolve9 } from "path";
7297
+ import { existsSync as existsSync7, cpSync as cpSync2, rmSync as rmSync2 } from "fs";
7298
+ import { resolve as resolve10 } from "path";
7223
7299
 
7224
7300
  // src/plugin/install-utils.ts
7225
7301
  import {
7226
- existsSync as existsSync5,
7302
+ existsSync as existsSync6,
7227
7303
  readdirSync as readdirSync2,
7228
7304
  cpSync,
7229
7305
  rmSync,
@@ -7231,10 +7307,56 @@ import {
7231
7307
  readFileSync as readFileSync9,
7232
7308
  createWriteStream
7233
7309
  } from "fs";
7234
- import { resolve as resolve8 } from "path";
7310
+ import { resolve as resolve9 } from "path";
7235
7311
  import { execSync as execSync7 } from "child_process";
7236
7312
  import { pipeline } from "stream/promises";
7237
7313
  import { Readable } from "stream";
7314
+
7315
+ // src/utils/proxy-fetch.ts
7316
+ var patched = false;
7317
+ async function ensureProxyFetch() {
7318
+ if (patched) return;
7319
+ patched = true;
7320
+ if (process.env.https_proxy && !process.env.HTTPS_PROXY) {
7321
+ process.env.HTTPS_PROXY = process.env.https_proxy;
7322
+ }
7323
+ if (process.env.http_proxy && !process.env.HTTP_PROXY) {
7324
+ process.env.HTTP_PROXY = process.env.http_proxy;
7325
+ }
7326
+ if (process.env.all_proxy && !process.env.ALL_PROXY) {
7327
+ process.env.ALL_PROXY = process.env.all_proxy;
7328
+ }
7329
+ const proxyUrl = process.env.https_proxy || process.env.HTTPS_PROXY || process.env.http_proxy || process.env.HTTP_PROXY || process.env.all_proxy || process.env.ALL_PROXY;
7330
+ if (!proxyUrl) return;
7331
+ try {
7332
+ const undici = await import("undici");
7333
+ const EnvHttpProxyAgent = undici.EnvHttpProxyAgent;
7334
+ const uFetch = undici.fetch;
7335
+ const UFormData = undici.FormData;
7336
+ if (EnvHttpProxyAgent && uFetch && UFormData) {
7337
+ const agent = new EnvHttpProxyAgent();
7338
+ globalThis.fetch = ((input, init) => {
7339
+ const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
7340
+ const body = init?.body;
7341
+ if (body instanceof globalThis.FormData && !(body instanceof UFormData)) {
7342
+ const ufd = new UFormData();
7343
+ body.forEach((value, key) => {
7344
+ if (value instanceof Blob) {
7345
+ ufd.append(key, value, value.name || "file");
7346
+ } else {
7347
+ ufd.append(key, value);
7348
+ }
7349
+ });
7350
+ return uFetch(url, { ...init, body: ufd, dispatcher: agent });
7351
+ }
7352
+ return uFetch(url, { ...init, dispatcher: agent });
7353
+ });
7354
+ }
7355
+ } catch {
7356
+ }
7357
+ }
7358
+
7359
+ // src/plugin/install-utils.ts
7238
7360
  async function downloadToFile(url, destPath) {
7239
7361
  await ensureProxyFetch();
7240
7362
  if (url.startsWith("file://")) {
@@ -7261,11 +7383,11 @@ function flattenPackageRoot(targetDir) {
7261
7383
  const dirs = entries.filter((e) => e.isDirectory());
7262
7384
  const files = entries.filter((e) => !e.isDirectory());
7263
7385
  if (dirs.length === 1 && files.length === 0) {
7264
- const pkgDir = resolve8(targetDir, dirs[0].name);
7386
+ const pkgDir = resolve9(targetDir, dirs[0].name);
7265
7387
  const items = readdirSync2(pkgDir);
7266
7388
  for (const item of items) {
7267
- const src = resolve8(pkgDir, item);
7268
- const dst = resolve8(targetDir, item);
7389
+ const src = resolve9(pkgDir, item);
7390
+ const dst = resolve9(targetDir, item);
7269
7391
  cpSync(src, dst, { recursive: true, force: true });
7270
7392
  }
7271
7393
  rmSync(pkgDir, { recursive: true, force: true });
@@ -7273,15 +7395,15 @@ function flattenPackageRoot(targetDir) {
7273
7395
  }
7274
7396
  async function verifyPlugin(dir) {
7275
7397
  const warnings = [];
7276
- const indexPath = resolve8(dir, "index.ts");
7277
- if (!existsSync5(indexPath)) {
7278
- const indexJs = resolve8(dir, "index.js");
7279
- if (!existsSync5(indexJs)) {
7398
+ const indexPath = resolve9(dir, "index.ts");
7399
+ if (!existsSync6(indexPath)) {
7400
+ const indexJs = resolve9(dir, "index.js");
7401
+ if (!existsSync6(indexJs)) {
7280
7402
  return { valid: false, error: "No index.ts or index.js entry point found", warnings };
7281
7403
  }
7282
7404
  }
7283
- const pkgPath = resolve8(dir, "package.json");
7284
- if (!existsSync5(pkgPath)) {
7405
+ const pkgPath = resolve9(dir, "package.json");
7406
+ if (!existsSync6(pkgPath)) {
7285
7407
  warnings.push("No package.json found");
7286
7408
  } else {
7287
7409
  try {
@@ -7304,8 +7426,8 @@ function safeCleanup(dir) {
7304
7426
 
7305
7427
  // src/plugin/install-sources/local.ts
7306
7428
  async function installFromLocal(source, name, targetDir) {
7307
- const srcPath = resolve9(source);
7308
- if (!existsSync6(srcPath)) {
7429
+ const srcPath = resolve10(source);
7430
+ if (!existsSync7(srcPath)) {
7309
7431
  throw new Error(`Local path does not exist: ${srcPath}`);
7310
7432
  }
7311
7433
  const tmpTarget = `${targetDir}-tmp-${Date.now()}`;
@@ -7318,7 +7440,7 @@ async function installFromLocal(source, name, targetDir) {
7318
7440
  safeCleanup(tmpTarget);
7319
7441
  throw new Error(`Invalid plugin: ${verify.error}`);
7320
7442
  }
7321
- if (existsSync6(targetDir)) {
7443
+ if (existsSync7(targetDir)) {
7322
7444
  rmSync2(targetDir, { recursive: true, force: true });
7323
7445
  }
7324
7446
  cpSync2(tmpTarget, targetDir, { recursive: true, force: true });
@@ -7338,8 +7460,8 @@ async function installFromLocal(source, name, targetDir) {
7338
7460
  }
7339
7461
 
7340
7462
  // src/plugin/install-sources/npm.ts
7341
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync4, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
7342
- import { resolve as resolve10, join as join4 } from "path";
7463
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync4, rmSync as rmSync3, cpSync as cpSync3 } from "fs";
7464
+ import { resolve as resolve11, join as join4 } from "path";
7343
7465
  import { tmpdir } from "os";
7344
7466
  async function installFromNpm(packageName, name, targetDir) {
7345
7467
  await ensureProxyFetch();
@@ -7372,12 +7494,12 @@ async function installFromNpm(packageName, name, targetDir) {
7372
7494
  if (!verify.valid) {
7373
7495
  throw new Error(`Invalid npm plugin: ${verify.error}`);
7374
7496
  }
7375
- if (existsSync7(targetDir)) {
7497
+ if (existsSync8(targetDir)) {
7376
7498
  rmSync3(targetDir, { recursive: true, force: true });
7377
7499
  }
7378
7500
  cpSync3(extractDir, targetDir, { recursive: true, force: true });
7379
- const pkgPath = resolve10(targetDir, "package.json");
7380
- if (existsSync7(pkgPath)) {
7501
+ const pkgPath = resolve11(targetDir, "package.json");
7502
+ if (existsSync8(pkgPath)) {
7381
7503
  const pkg2 = JSON.parse(readFileSync10(pkgPath, "utf-8"));
7382
7504
  if (!pkg2._npmSource) {
7383
7505
  pkg2._npmSource = { name: packageName, version: latestVersion };
@@ -7398,8 +7520,8 @@ async function installFromNpm(packageName, name, targetDir) {
7398
7520
  }
7399
7521
 
7400
7522
  // src/plugin/install-sources/git.ts
7401
- import { existsSync as existsSync8, readFileSync as readFileSync11, writeFileSync as writeFileSync5, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
7402
- import { resolve as resolve11, join as join5 } from "path";
7523
+ import { existsSync as existsSync9, readFileSync as readFileSync11, writeFileSync as writeFileSync5, rmSync as rmSync4, cpSync as cpSync4 } from "fs";
7524
+ import { resolve as resolve12, join as join5 } from "path";
7403
7525
  import { tmpdir as tmpdir2 } from "os";
7404
7526
  import { execSync as execSync8 } from "child_process";
7405
7527
  async function installFromGit(gitUrl, name, targetDir) {
@@ -7412,13 +7534,13 @@ async function installFromGit(gitUrl, name, targetDir) {
7412
7534
  if (!verify.valid) {
7413
7535
  throw new Error(`Invalid git plugin: ${verify.error}`);
7414
7536
  }
7415
- if (existsSync8(targetDir)) {
7537
+ if (existsSync9(targetDir)) {
7416
7538
  rmSync4(targetDir, { recursive: true, force: true });
7417
7539
  }
7418
7540
  cpSync4(tmpDir, targetDir, { recursive: true, force: true });
7419
- rmSync4(resolve11(targetDir, ".git"), { recursive: true, force: true });
7420
- const pkgPath = resolve11(targetDir, "package.json");
7421
- if (existsSync8(pkgPath)) {
7541
+ rmSync4(resolve12(targetDir, ".git"), { recursive: true, force: true });
7542
+ const pkgPath = resolve12(targetDir, "package.json");
7543
+ if (existsSync9(pkgPath)) {
7422
7544
  const pkg2 = JSON.parse(readFileSync11(pkgPath, "utf-8"));
7423
7545
  if (!pkg2._gitSource) {
7424
7546
  pkg2._gitSource = { url: gitUrl };
@@ -7439,8 +7561,8 @@ async function installFromGit(gitUrl, name, targetDir) {
7439
7561
  }
7440
7562
 
7441
7563
  // src/plugin/install-sources/url.ts
7442
- import { existsSync as existsSync9, readFileSync as readFileSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, rmSync as rmSync5, cpSync as cpSync5 } from "fs";
7443
- import { resolve as resolve12, join as join6, basename } from "path";
7564
+ import { existsSync as existsSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, rmSync as rmSync5, cpSync as cpSync5 } from "fs";
7565
+ import { resolve as resolve13, join as join6, basename } from "path";
7444
7566
  import { tmpdir as tmpdir3 } from "os";
7445
7567
  async function installFromUrl(url, name, targetDir) {
7446
7568
  const tmpDir = join6(tmpdir3(), `xbrowser-url-${Date.now()}`);
@@ -7458,12 +7580,12 @@ async function installFromUrl(url, name, targetDir) {
7458
7580
  if (!verify.valid) {
7459
7581
  throw new Error(`Invalid plugin from URL: ${verify.error}`);
7460
7582
  }
7461
- if (existsSync9(targetDir)) {
7583
+ if (existsSync10(targetDir)) {
7462
7584
  rmSync5(targetDir, { recursive: true, force: true });
7463
7585
  }
7464
7586
  cpSync5(extractDir, targetDir, { recursive: true, force: true });
7465
- const pkgPath = resolve12(targetDir, "package.json");
7466
- if (existsSync9(pkgPath)) {
7587
+ const pkgPath = resolve13(targetDir, "package.json");
7588
+ if (existsSync10(pkgPath)) {
7467
7589
  const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
7468
7590
  if (!pkg2._urlSource) {
7469
7591
  pkg2._urlSource = { url };
@@ -7485,14 +7607,14 @@ async function installFromUrl(url, name, targetDir) {
7485
7607
 
7486
7608
  // src/plugin/install-sources/marketplace.ts
7487
7609
  import {
7488
- existsSync as existsSync10,
7610
+ existsSync as existsSync11,
7489
7611
  mkdirSync as mkdirSync6,
7490
7612
  writeFileSync as writeFileSync7,
7491
7613
  readFileSync as readFileSync13,
7492
7614
  rmSync as rmSync6,
7493
7615
  cpSync as cpSync6
7494
7616
  } from "fs";
7495
- import { resolve as resolve13, join as join7, dirname as dirname2 } from "path";
7617
+ import { resolve as resolve14, join as join7, dirname as dirname2 } from "path";
7496
7618
  import { tmpdir as tmpdir4 } from "os";
7497
7619
  import { gunzipSync } from "zlib";
7498
7620
  async function installFromMarketplace(pluginsDir, slug, options) {
@@ -7509,8 +7631,8 @@ async function installFromMarketplace(pluginsDir, slug, options) {
7509
7631
  }
7510
7632
  const plugin = detailData.data;
7511
7633
  const name = options?.name || String(plugin.slug || slug);
7512
- const targetDir = resolve13(pluginsDir, name);
7513
- if (existsSync10(targetDir) && !options?.force) {
7634
+ const targetDir = resolve14(pluginsDir, name);
7635
+ if (existsSync11(targetDir) && !options?.force) {
7514
7636
  throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
7515
7637
  }
7516
7638
  mkdirSync6(targetDir, { recursive: true });
@@ -7545,12 +7667,12 @@ function isManifestArray(data) {
7545
7667
  return Array.isArray(data) && data.length > 0 && typeof data[0].path === "string" && typeof data[0].content === "string";
7546
7668
  }
7547
7669
  function extractManifestToDir(manifest, targetDir) {
7548
- if (existsSync10(targetDir)) {
7670
+ if (existsSync11(targetDir)) {
7549
7671
  rmSync6(targetDir, { recursive: true, force: true });
7550
7672
  }
7551
7673
  mkdirSync6(targetDir, { recursive: true });
7552
7674
  for (const file of manifest) {
7553
- const filePath = resolve13(targetDir, file.path);
7675
+ const filePath = resolve14(targetDir, file.path);
7554
7676
  mkdirSync6(dirname2(filePath), { recursive: true });
7555
7677
  writeFileSync7(filePath, Buffer.from(file.content, "base64"));
7556
7678
  }
@@ -7588,7 +7710,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
7588
7710
  const extractDir = join7(tmpDir, "extracted");
7589
7711
  extractTarGz(tarballPath, extractDir);
7590
7712
  flattenPackageRoot(extractDir);
7591
- if (existsSync10(targetDir)) {
7713
+ if (existsSync11(targetDir)) {
7592
7714
  rmSync6(targetDir, { recursive: true, force: true });
7593
7715
  }
7594
7716
  cpSync6(extractDir, targetDir, { recursive: true, force: true });
@@ -7605,7 +7727,7 @@ async function downloadAndExtractMarketplaceTarball(baseUrl, slug, tmpDir, targe
7605
7727
  const extractDir = join7(tmpDir, "extracted");
7606
7728
  extractTarGz(tarballPath, extractDir);
7607
7729
  flattenPackageRoot(extractDir);
7608
- if (existsSync10(targetDir)) {
7730
+ if (existsSync11(targetDir)) {
7609
7731
  rmSync6(targetDir, { recursive: true, force: true });
7610
7732
  }
7611
7733
  cpSync6(extractDir, targetDir, { recursive: true, force: true });
@@ -7640,8 +7762,8 @@ function writeMarketplacePackageJson(plugin, slug, name, baseUrl, targetDir) {
7640
7762
  url: baseUrl
7641
7763
  }
7642
7764
  };
7643
- const pkgPath = resolve13(targetDir, "package.json");
7644
- if (!existsSync10(pkgPath)) {
7765
+ const pkgPath = resolve14(targetDir, "package.json");
7766
+ if (!existsSync11(pkgPath)) {
7645
7767
  writeFileSync7(pkgPath, JSON.stringify(packageJson, null, 2));
7646
7768
  } else {
7647
7769
  try {
@@ -7658,7 +7780,7 @@ function writeMarketplacePackageJson(plugin, slug, name, baseUrl, targetDir) {
7658
7780
  }
7659
7781
  }
7660
7782
  function ensureIndexFile(plugin, name, targetDir) {
7661
- if (!existsSync10(resolve13(targetDir, "index.ts")) && !existsSync10(resolve13(targetDir, "index.js"))) {
7783
+ if (!existsSync11(resolve14(targetDir, "index.ts")) && !existsSync11(resolve14(targetDir, "index.js"))) {
7662
7784
  const commands = plugin.commands || [];
7663
7785
  const commandHandlers = commands.length > 0 ? commands.map((cmd) => {
7664
7786
  return [
@@ -7674,7 +7796,7 @@ function ensureIndexFile(plugin, name, targetDir) {
7674
7796
  ` });`
7675
7797
  ].join("\n");
7676
7798
  writeFileSync7(
7677
- resolve13(targetDir, "index.ts"),
7799
+ resolve14(targetDir, "index.ts"),
7678
7800
  [
7679
7801
  `import type { XCLIAPI } from '@dyyz1993/xcli-core';`,
7680
7802
  ``,
@@ -7695,7 +7817,7 @@ function ensureIndexFile(plugin, name, targetDir) {
7695
7817
  var PluginInstaller = class {
7696
7818
  pluginsDir;
7697
7819
  constructor(pluginsDir) {
7698
- this.pluginsDir = pluginsDir || resolve14(homedir4(), ".xbrowser/plugins");
7820
+ this.pluginsDir = pluginsDir || resolve15(homedir4(), ".xbrowser/plugins");
7699
7821
  }
7700
7822
  getPluginsDir() {
7701
7823
  return this.pluginsDir;
@@ -7711,8 +7833,8 @@ var PluginInstaller = class {
7711
7833
  async install(source, options) {
7712
7834
  const type = this.detectSourceType(source);
7713
7835
  const name = options?.name || this.deriveName(source, type);
7714
- const targetDir = resolve14(this.pluginsDir, name);
7715
- if (existsSync11(targetDir) && !options?.force) {
7836
+ const targetDir = resolve15(this.pluginsDir, name);
7837
+ if (existsSync12(targetDir) && !options?.force) {
7716
7838
  throw new Error(`Plugin "${name}" already exists. Use --force to overwrite.`);
7717
7839
  }
7718
7840
  mkdirSync7(targetDir, { recursive: true });
@@ -7772,8 +7894,8 @@ var PluginInstaller = class {
7772
7894
  * @throws If the plugin is not installed.
7773
7895
  */
7774
7896
  async uninstall(name) {
7775
- const targetDir = resolve14(this.pluginsDir, name);
7776
- if (!existsSync11(targetDir)) {
7897
+ const targetDir = resolve15(this.pluginsDir, name);
7898
+ if (!existsSync12(targetDir)) {
7777
7899
  throw new Error(`Plugin "${name}" not found`);
7778
7900
  }
7779
7901
  rmSync7(targetDir, { recursive: true, force: true });
@@ -7784,18 +7906,18 @@ var PluginInstaller = class {
7784
7906
  * @returns Array of installed plugin information.
7785
7907
  */
7786
7908
  async list(_options) {
7787
- if (!existsSync11(this.pluginsDir)) return [];
7909
+ if (!existsSync12(this.pluginsDir)) return [];
7788
7910
  const entries = readdirSync3(this.pluginsDir, { withFileTypes: true });
7789
7911
  const plugins = [];
7790
7912
  for (const entry of entries) {
7791
7913
  if (!entry.isDirectory()) continue;
7792
- const pluginPath = resolve14(this.pluginsDir, entry.name);
7793
- const indexPath = resolve14(pluginPath, "index.ts");
7794
- const indexJsPath = resolve14(pluginPath, "index.js");
7795
- if (!existsSync11(indexPath) && !existsSync11(indexJsPath)) continue;
7914
+ const pluginPath = resolve15(this.pluginsDir, entry.name);
7915
+ const indexPath = resolve15(pluginPath, "index.ts");
7916
+ const indexJsPath = resolve15(pluginPath, "index.js");
7917
+ if (!existsSync12(indexPath) && !existsSync12(indexJsPath)) continue;
7796
7918
  const metadata = PluginMetadataParser.parseFromPackageJson(pluginPath);
7797
7919
  let source = "local";
7798
- const pkg2 = readJsonFile(resolve14(pluginPath, "package.json"), {});
7920
+ const pkg2 = readJsonFile(resolve15(pluginPath, "package.json"), {});
7799
7921
  if (pkg2._marketplace) source = "marketplace";
7800
7922
  else if (pkg2._npmSource) source = "npm";
7801
7923
  else if (pkg2._gitSource) source = "git";
@@ -7819,10 +7941,10 @@ var PluginInstaller = class {
7819
7941
  }
7820
7942
  if (source.startsWith("file://")) {
7821
7943
  const filePath = decodeURIComponent(new URL(source).pathname);
7822
- if (existsSync11(filePath)) return "url";
7944
+ if (existsSync12(filePath)) return "url";
7823
7945
  }
7824
7946
  if (source.endsWith(".git") || source.includes("github.com/")) return "git";
7825
- if (existsSync11(resolve14(source))) return "local";
7947
+ if (existsSync12(resolve15(source))) return "local";
7826
7948
  return "npm";
7827
7949
  }
7828
7950
  deriveName(source, type) {
@@ -7898,10 +8020,6 @@ function handlePluginHelp() {
7898
8020
  " uninstall <name> Uninstall a plugin",
7899
8021
  " list [--json] List installed plugins",
7900
8022
  " reload <name> Reload a plugin",
7901
- " publish [--registry <url>] [--dry-run] Publish plugin to marketplace",
7902
- " login [--token <api-key>] [--registry <url>] Login to marketplace",
7903
- " whoami Show current logged-in user",
7904
- " logout Logout from marketplace",
7905
8023
  "",
7906
8024
  "Examples:",
7907
8025
  " xbrowser plugin search scraper",
@@ -7909,12 +8027,7 @@ function handlePluginHelp() {
7909
8027
  " xbrowser plugin install ./my-plugin",
7910
8028
  " xbrowser plugin uninstall my-plugin",
7911
8029
  " xbrowser plugin list",
7912
- " xbrowser plugin reload my-plugin",
7913
- " xbrowser plugin publish",
7914
- " xbrowser plugin publish --dry-run",
7915
- " xbrowser plugin login --token my-api-key",
7916
- " xbrowser plugin whoami",
7917
- " xbrowser plugin logout"
8030
+ " xbrowser plugin reload my-plugin"
7918
8031
  ].join("\n");
7919
8032
  }
7920
8033
  var pluginInstallBuiltin = {
@@ -8216,76 +8329,60 @@ var NPMSearcher = class {
8216
8329
  }
8217
8330
  };
8218
8331
 
8219
- // src/plugin/marketplace-search.ts
8220
- var MarketplaceSearcher = class {
8221
- static getBaseUrl() {
8222
- return getMarketplaceUrl();
8223
- }
8224
- static async search(options = {}) {
8225
- await ensureProxyFetch();
8226
- const { query = "", tag, site, limit = 20 } = options;
8227
- const baseUrl = this.getBaseUrl();
8228
- const params = new URLSearchParams();
8229
- if (query) params.set("q", query);
8230
- if (tag) params.set("tag", tag);
8231
- if (site) params.set("site", site);
8232
- params.set("limit", String(limit));
8233
- const url = `${baseUrl}/api/plugins/search?${params.toString()}`;
8234
- try {
8235
- const response = await fetch(url);
8236
- if (!response.ok) {
8237
- return [];
8238
- }
8239
- const data = await response.json();
8240
- if (!data.success || !data.data?.items) {
8241
- return [];
8242
- }
8243
- return data.data.items.map((item) => this.parseMarketplacePlugin(item));
8244
- } catch {
8245
- return [];
8246
- }
8247
- }
8248
- static async getPluginDetail(slug) {
8249
- await ensureProxyFetch();
8250
- const baseUrl = this.getBaseUrl();
8251
- const url = `${baseUrl}/api/plugins/${slug}`;
8252
- try {
8253
- const response = await fetch(url);
8254
- if (!response.ok) return null;
8255
- const data = await response.json();
8256
- if (!data.success || !data.data) return null;
8257
- return this.parseMarketplacePlugin(data.data);
8258
- } catch {
8259
- return null;
8260
- }
8261
- }
8262
- static parseMarketplacePlugin(item) {
8263
- return {
8332
+ // src/builtins/plugin-search.ts
8333
+ async function searchFromMarketplacePlugin(options, loader) {
8334
+ const sites = loader.getCore().loader.getSites();
8335
+ const marketplaceSite = sites.find((s) => s.name === "marketplace");
8336
+ if (!marketplaceSite) return [];
8337
+ const searchCmd = marketplaceSite.getCommand("search");
8338
+ if (!searchCmd) return [];
8339
+ try {
8340
+ const result = await searchCmd.handler(
8341
+ {
8342
+ query: options.query,
8343
+ tag: options.tag,
8344
+ site: options.site,
8345
+ limit: options.limit
8346
+ },
8347
+ {}
8348
+ );
8349
+ const items = extractItems(result);
8350
+ return items.map((item) => ({
8264
8351
  source: "marketplace",
8265
- slug: String(item.slug || ""),
8266
8352
  name: String(item.name || ""),
8267
8353
  version: String(item.version || "latest"),
8268
8354
  description: String(item.description || ""),
8269
- author: String(item.authorName || "Unknown"),
8270
- homepage: typeof item.homepageUrl === "string" ? item.homepageUrl : void 0,
8271
- repository: typeof item.repositoryUrl === "string" ? item.repositoryUrl : void 0,
8272
- keywords: Array.isArray(item.tags) ? item.tags.map(String) : [],
8355
+ author: String(item.author || ""),
8356
+ homepage: typeof item.homepage === "string" ? item.homepage : void 0,
8273
8357
  tags: Array.isArray(item.tags) ? item.tags.map(String) : [],
8274
- sites: Array.isArray(item.siteUrls) ? item.siteUrls.map(String) : [],
8275
- commands: Array.isArray(item.commands) ? item.commands.map(String) : [],
8276
- downloads: typeof item.downloadCount === "number" ? item.downloadCount : 0,
8277
- license: typeof item.license === "string" ? item.license : void 0
8278
- };
8358
+ downloads: typeof item.downloads === "number" ? item.downloads : 0,
8359
+ slug: String(item.slug || ""),
8360
+ commands: Array.isArray(item.commands) ? item.commands.map(String) : []
8361
+ }));
8362
+ } catch {
8363
+ return [];
8279
8364
  }
8280
- };
8281
-
8282
- // src/builtins/plugin-search.ts
8365
+ }
8366
+ function extractItems(result) {
8367
+ if (!result || typeof result !== "object") return [];
8368
+ const r = result;
8369
+ if ("data" in r) {
8370
+ const data = r.data;
8371
+ if (data && "items" in data && Array.isArray(data.items)) {
8372
+ return data.items;
8373
+ }
8374
+ }
8375
+ if ("items" in r && Array.isArray(r.items)) {
8376
+ return r.items;
8377
+ }
8378
+ return [];
8379
+ }
8283
8380
  var pluginSearchBuiltin = {
8284
8381
  name: "plugin search",
8285
8382
  description: "Search for xbrowser plugins on npm registry and marketplace",
8286
8383
  help: {
8287
8384
  usage: "xbrowser plugin search <query> [options]",
8288
- description: "Search npm registry and marketplace for xbrowser-compatible plugins",
8385
+ description: "Search npm registry and installed plugin search providers for xbrowser-compatible plugins",
8289
8386
  options: [
8290
8387
  { name: "--tag <tag>", description: "Filter by plugin tag" },
8291
8388
  { name: "--site <site>", description: "Filter by target site" },
@@ -8307,26 +8404,24 @@ var pluginSearchBuiltin = {
8307
8404
  limit: options["limit"] ? Number.parseInt(String(options["limit"])) : 20
8308
8405
  };
8309
8406
  console.log(
8310
- `Searching npm registry and marketplace for xbrowser plugins...${query ? ` (query: "${query}")` : ""}`
8407
+ `Searching for xbrowser plugins...${query ? ` (query: "${query}")` : ""}`
8311
8408
  );
8312
- const [npmSettled, marketplaceSettled] = await Promise.allSettled([
8409
+ const loader = await getPluginLoader();
8410
+ const [npmSettled, pluginSettled] = await Promise.allSettled([
8313
8411
  NPMSearcher.search(searchOptions),
8314
- MarketplaceSearcher.search(searchOptions)
8412
+ searchFromMarketplacePlugin(searchOptions, loader)
8315
8413
  ]);
8316
8414
  const npmResults = npmSettled.status === "fulfilled" ? npmSettled.value : [];
8317
- const marketplaceResults = marketplaceSettled.status === "fulfilled" ? marketplaceSettled.value : [];
8415
+ const pluginResults = pluginSettled.status === "fulfilled" ? pluginSettled.value : [];
8318
8416
  if (npmSettled.status === "rejected") {
8319
8417
  console.warn(`Warning: npm search failed: ${npmSettled.reason}`);
8320
8418
  }
8321
- if (marketplaceSettled.status === "rejected") {
8322
- console.warn(`Warning: marketplace search failed: ${marketplaceSettled.reason}`);
8323
- }
8324
- const total = npmResults.length + marketplaceResults.length;
8419
+ const total = npmResults.length + pluginResults.length;
8325
8420
  if (total === 0) {
8326
8421
  console.log("No plugins found.");
8327
8422
  return;
8328
8423
  }
8329
- console.log(`Found ${total} plugin(s) (npm: ${npmResults.length}, marketplace: ${marketplaceResults.length}):
8424
+ console.log(`Found ${total} plugin(s) (npm: ${npmResults.length}, plugins: ${pluginResults.length}):
8330
8425
  `);
8331
8426
  if (npmResults.length > 0) {
8332
8427
  console.log("--- npm ---\n");
@@ -8350,14 +8445,14 @@ var pluginSearchBuiltin = {
8350
8445
  console.log("");
8351
8446
  });
8352
8447
  }
8353
- if (marketplaceResults.length > 0) {
8448
+ if (pluginResults.length > 0) {
8354
8449
  console.log("--- marketplace ---\n");
8355
- marketplaceResults.forEach((result, idx) => {
8450
+ pluginResults.forEach((result, idx) => {
8356
8451
  console.log(`${idx + 1}. ${result.name} [marketplace]`);
8357
8452
  console.log(` ${result.description}`);
8358
8453
  console.log(` Version: ${result.version}`);
8359
- console.log(` Author: ${result.author}`);
8360
- console.log(` Downloads: ${result.downloads}`);
8454
+ if (result.author) console.log(` Author: ${result.author}`);
8455
+ if (result.downloads) console.log(` Downloads: ${result.downloads}`);
8361
8456
  if (result.tags && result.tags.length > 0) {
8362
8457
  console.log(` Tags: ${result.tags.join(", ")}`);
8363
8458
  }
@@ -8367,7 +8462,9 @@ var pluginSearchBuiltin = {
8367
8462
  if (result.homepage) {
8368
8463
  console.log(` Homepage: ${result.homepage}`);
8369
8464
  }
8370
- console.log(` Install: xbrowser plugin install ${result.slug} --from-marketplace`);
8465
+ if (result.slug) {
8466
+ console.log(` Install: xbrowser plugin install ${result.slug} --from-marketplace`);
8467
+ }
8371
8468
  console.log("");
8372
8469
  });
8373
8470
  }
@@ -9253,6 +9350,67 @@ function applyRegistryOverride(options) {
9253
9350
  process.env.XBROWSER_MARKETPLACE_URL = registry2;
9254
9351
  }
9255
9352
  }
9353
+ function extractItems2(result) {
9354
+ if (!result || typeof result !== "object") return [];
9355
+ const r = result;
9356
+ if ("data" in r) {
9357
+ const data = r.data;
9358
+ if (data && "items" in data && Array.isArray(data.items)) {
9359
+ return data.items;
9360
+ }
9361
+ }
9362
+ if ("items" in r && Array.isArray(r.items)) {
9363
+ return r.items;
9364
+ }
9365
+ return [];
9366
+ }
9367
+ async function searchFromMarketplacePlugin2(options, loader) {
9368
+ const sites = loader.getCore().loader.getSites();
9369
+ const marketplaceSite = sites.find((s) => s.name === "marketplace");
9370
+ if (!marketplaceSite) return [];
9371
+ const searchCmd = marketplaceSite.getCommand("search");
9372
+ if (!searchCmd) return [];
9373
+ try {
9374
+ const result = await searchCmd.handler(
9375
+ {
9376
+ query: options.query,
9377
+ tag: options.tag,
9378
+ site: options.site,
9379
+ limit: options.limit
9380
+ },
9381
+ {}
9382
+ );
9383
+ const items = extractItems2(result);
9384
+ return items.map((item) => ({ ...item, source: "marketplace" }));
9385
+ } catch {
9386
+ return [];
9387
+ }
9388
+ }
9389
+ async function infoFromMarketplacePlugin(slug, loader) {
9390
+ const sites = loader.getCore().loader.getSites();
9391
+ const marketplaceSite = sites.find((s) => s.name === "marketplace");
9392
+ if (!marketplaceSite) return null;
9393
+ const infoCmd = marketplaceSite.getCommand("info");
9394
+ if (!infoCmd) return null;
9395
+ try {
9396
+ const result = await infoCmd.handler({ slug }, {});
9397
+ if (!result || typeof result !== "object") return null;
9398
+ const r = result;
9399
+ let plugin = null;
9400
+ if ("data" in r) {
9401
+ const data = r.data;
9402
+ plugin = data?.plugin || null;
9403
+ }
9404
+ if (!plugin && "plugin" in r) {
9405
+ plugin = r.plugin;
9406
+ }
9407
+ if (plugin && plugin.name) {
9408
+ return { ...plugin, source: "marketplace" };
9409
+ }
9410
+ } catch {
9411
+ }
9412
+ return null;
9413
+ }
9256
9414
  async function handleSearch(args, options, mode) {
9257
9415
  const query = args[0] || "";
9258
9416
  applyRegistryOverride(options);
@@ -9260,11 +9418,10 @@ async function handleSearch(args, options, mode) {
9260
9418
  const searchLimit = options.limit ? Number(options.limit) : 20;
9261
9419
  const searchOpts = { query, tag: options.tag, site: options.site, limit: searchLimit };
9262
9420
  const results = [];
9263
- const marketplaceResults = await MarketplaceSearcher.search(searchOpts);
9264
- for (const r of marketplaceResults) {
9265
- results.push({ ...r, source: "marketplace" });
9266
- }
9267
- if (marketplaceResults.length === 0) {
9421
+ const loader = await getPluginLoader();
9422
+ const pluginResults = await searchFromMarketplacePlugin2(searchOpts, loader);
9423
+ results.push(...pluginResults);
9424
+ if (pluginResults.length === 0) {
9268
9425
  try {
9269
9426
  const npmResults = await NPMSearcher.search(searchOpts);
9270
9427
  for (const r of npmResults) {
@@ -9297,12 +9454,11 @@ async function handlePluginInfo(args, options, mode) {
9297
9454
  if (!slug) outputError("Usage: xbrowser plugin info <slug>");
9298
9455
  applyRegistryOverride(options);
9299
9456
  await ensureProxyFetch();
9300
- const marketplaceUrl = getMarketplaceUrl();
9457
+ const loader = await getPluginLoader();
9301
9458
  try {
9302
- const resp = await fetch(`${marketplaceUrl}/api/plugins/${slug}`);
9303
- if (resp.ok) {
9304
- const raw = await resp.json();
9305
- const d = raw.data || raw;
9459
+ const pluginInfo = await infoFromMarketplacePlugin(slug, loader);
9460
+ if (pluginInfo) {
9461
+ const d = pluginInfo;
9306
9462
  if (mode === "json") {
9307
9463
  outputResult({ source: "marketplace", ...d }, mode);
9308
9464
  return;
@@ -9310,12 +9466,11 @@ async function handlePluginInfo(args, options, mode) {
9310
9466
  console.log(`\u540D\u79F0: ${d.name || ""}`);
9311
9467
  console.log(`\u7248\u672C: ${d.version || ""}`);
9312
9468
  console.log(`\u63CF\u8FF0: ${d.description || ""}`);
9313
- console.log(`\u4F5C\u8005: ${d.authorName || d.author || ""}`);
9314
- console.log(`\u72B6\u6001: ${d.status || ""}`);
9469
+ console.log(`\u4F5C\u8005: ${d.author || ""}`);
9315
9470
  console.log(`\u547D\u4EE4: ${(d.commands || []).join(", ")}`);
9316
- console.log(`\u4E0B\u8F7D\u91CF: ${d.downloadCount || 0}`);
9471
+ console.log(`\u4E0B\u8F7D\u91CF: ${d.downloads || 0}`);
9317
9472
  console.log(`\u6807\u7B7E: ${(d.tags || []).join(", ")}`);
9318
- console.log(`\u7F51\u7AD9: ${(d.siteUrls || []).join(", ")}`);
9473
+ console.log(`\u7F51\u7AD9: ${(d.sites || []).join(", ")}`);
9319
9474
  return;
9320
9475
  }
9321
9476
  } catch {
@@ -10264,24 +10419,6 @@ Commands:
10264
10419
  viewer [--name <n>] [--selector <sel>] Generate viewer URL
10265
10420
  help Show this help
10266
10421
  --version, -v Show version
10267
-
10268
- Marketplace & Admin:
10269
- marketplace publish [--dry-run] Publish plugin to marketplace
10270
- marketplace login [--token <key>] Login to marketplace
10271
- marketplace register Register developer account
10272
- marketplace whoami Show current user
10273
- marketplace logout Logout from marketplace
10274
- admin pending List pending plugins (admin only)
10275
- admin approve <slug> Approve a plugin (admin only)
10276
- admin reject <slug> [--reason] Reject a plugin (admin only)
10277
- admin feature <slug> Toggle featured (admin only)
10278
- admin remove <slug> Remove a plugin (admin only)
10279
- admin stats Dashboard stats (admin only)
10280
- admin inventory Plugin inventory (admin only)
10281
- admin list [--status <status>] List all plugins (admin only)
10282
- admin bulk-approve <slugs...> Bulk approve (admin only)
10283
- admin cleanup Reset data (admin only)
10284
-
10285
10422
  Plugin Commands:
10286
10423
  Installed plugins provide additional commands.
10287
10424
  Use 'xbrowser plugin list' to see installed plugins and their commands.
@@ -10644,19 +10781,19 @@ function headersToObject(headers) {
10644
10781
  return result;
10645
10782
  }
10646
10783
  function readBody(req) {
10647
- return new Promise((resolve15, reject) => {
10784
+ return new Promise((resolve16, reject) => {
10648
10785
  const chunks = [];
10649
10786
  req.on("data", (chunk) => chunks.push(chunk));
10650
10787
  req.on("end", () => {
10651
10788
  const raw = Buffer.concat(chunks).toString("utf-8");
10652
10789
  if (!raw) {
10653
- resolve15(null);
10790
+ resolve16(null);
10654
10791
  return;
10655
10792
  }
10656
10793
  try {
10657
- resolve15(JSON.parse(raw));
10794
+ resolve16(JSON.parse(raw));
10658
10795
  } catch {
10659
- resolve15(null);
10796
+ resolve16(null);
10660
10797
  }
10661
10798
  });
10662
10799
  req.on("error", reject);
@@ -10701,7 +10838,7 @@ var HTTPServer = class {
10701
10838
  res.end(JSON.stringify({ error: "INTERNAL_ERROR", message, statusCode: 500 }));
10702
10839
  });
10703
10840
  });
10704
- return new Promise((resolve15, reject) => {
10841
+ return new Promise((resolve16, reject) => {
10705
10842
  const server = this.server;
10706
10843
  server.on("error", (err) => {
10707
10844
  this.server = null;
@@ -10713,7 +10850,7 @@ var HTTPServer = class {
10713
10850
  this.port = addr.port;
10714
10851
  }
10715
10852
  console.log(`HTTP server listening on http://${this.host}:${this.port}`);
10716
- resolve15({ port: this.port, host: this.host });
10853
+ resolve16({ port: this.port, host: this.host });
10717
10854
  });
10718
10855
  });
10719
10856
  }
@@ -10724,13 +10861,13 @@ var HTTPServer = class {
10724
10861
  */
10725
10862
  async stop() {
10726
10863
  if (!this.server) return;
10727
- return new Promise((resolve15, reject) => {
10864
+ return new Promise((resolve16, reject) => {
10728
10865
  this.server.close((err) => {
10729
10866
  if (err) {
10730
10867
  reject(err);
10731
10868
  } else {
10732
10869
  this.server = null;
10733
- resolve15();
10870
+ resolve16();
10734
10871
  }
10735
10872
  });
10736
10873
  });
@@ -12404,8 +12541,8 @@ var WSServer = class extends EventEmitter {
12404
12541
  case "file_list": {
12405
12542
  try {
12406
12543
  const { readdirSync: readdirSync5, statSync } = await import("fs");
12407
- const { join: join11, resolve: resolve15 } = await import("path");
12408
- const targetPath = resolve15(msg.path);
12544
+ const { join: join11, resolve: resolve16 } = await import("path");
12545
+ const targetPath = resolve16(msg.path);
12409
12546
  const entries = readdirSync5(targetPath);
12410
12547
  const files = entries.map((name) => {
12411
12548
  try {
@@ -12424,8 +12561,8 @@ var WSServer = class extends EventEmitter {
12424
12561
  case "file_download": {
12425
12562
  try {
12426
12563
  const { readFileSync: readFileSync16 } = await import("fs");
12427
- const { resolve: resolve15, basename: basename3 } = await import("path");
12428
- const targetPath = resolve15(msg.path);
12564
+ const { resolve: resolve16, basename: basename3 } = await import("path");
12565
+ const targetPath = resolve16(msg.path);
12429
12566
  const data = readFileSync16(targetPath);
12430
12567
  const base64 = data.toString("base64");
12431
12568
  const ext = targetPath.split(".").pop()?.toLowerCase() || "";
@@ -12531,7 +12668,7 @@ var WSServer = class extends EventEmitter {
12531
12668
  this.isRunning = false;
12532
12669
  return;
12533
12670
  }
12534
- return new Promise((resolve15, reject) => {
12671
+ return new Promise((resolve16, reject) => {
12535
12672
  this.wsServer.close((err) => {
12536
12673
  if (err) {
12537
12674
  reject(err);
@@ -12539,7 +12676,7 @@ var WSServer = class extends EventEmitter {
12539
12676
  this.wsServer = null;
12540
12677
  this.isRunning = false;
12541
12678
  this.emit("stopped");
12542
- resolve15();
12679
+ resolve16();
12543
12680
  }
12544
12681
  });
12545
12682
  });
@@ -13720,7 +13857,7 @@ var DataCollector = class {
13720
13857
  return context;
13721
13858
  }
13722
13859
  sleep(ms) {
13723
- return new Promise((resolve15) => setTimeout(resolve15, ms));
13860
+ return new Promise((resolve16) => setTimeout(resolve16, ms));
13724
13861
  }
13725
13862
  async exportResults(outputPath, format = "json") {
13726
13863
  switch (format) {
@@ -13783,7 +13920,6 @@ export {
13783
13920
  createCDPInterceptor,
13784
13921
  createRuleEngine,
13785
13922
  createSession,
13786
- createTarball,
13787
13923
  destroyBrowser,
13788
13924
  destroyBrowser as destroySessionManager,
13789
13925
  domMutationRule,