@xbrowser/cli 0.14.0 → 0.14.2

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.
@@ -22,21 +22,15 @@ import {
22
22
  saveSessionDiskMeta,
23
23
  setActivePage
24
24
  } from "./chunk-F3ZWFCJJ.js";
25
- import {
26
- PluginMetadataParser
27
- } from "./chunk-DESA2KMG.js";
28
- import {
29
- readJsonFile
30
- } from "./chunk-YEN2ODUI.js";
31
25
 
32
26
  // src/daemon/daemon-main.ts
33
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, appendFileSync } from "fs";
27
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, appendFileSync } from "fs";
34
28
  import { join as join6 } from "path";
35
29
  import { homedir as homedir6 } from "os";
36
30
  import { startHttpServer } from "@dyyz1993/xcli-core";
37
31
 
38
32
  // src/daemon/rpc-handlers.ts
39
- import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "fs";
33
+ import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
40
34
  import { join as join5 } from "path";
41
35
  import { homedir as homedir5 } from "os";
42
36
  import {
@@ -368,15 +362,15 @@ var clickCommand = registerCommand({
368
362
  let detectedNewPage;
369
363
  let cleanup;
370
364
  if (ctx.browserContext?.on) {
371
- const pagePromise = new Promise((resolve8) => {
365
+ const pagePromise = new Promise((resolve9) => {
372
366
  const timer = setTimeout(() => {
373
367
  ctx.browserContext.off("page", handler);
374
- resolve8(void 0);
368
+ resolve9(void 0);
375
369
  }, 3e3);
376
370
  const handler = (page2) => {
377
371
  clearTimeout(timer);
378
372
  ctx.browserContext.off("page", handler);
379
- resolve8(page2);
373
+ resolve9(page2);
380
374
  };
381
375
  ctx.browserContext.on("page", handler);
382
376
  });
@@ -1134,7 +1128,7 @@ var consoleCheckCommand = registerCommand({
1134
1128
  await page.goto(p.url, { waitUntil: "domcontentloaded" });
1135
1129
  }
1136
1130
  const messages = await page.evaluate((args) => {
1137
- return new Promise((resolve8) => {
1131
+ return new Promise((resolve9) => {
1138
1132
  const collected = [];
1139
1133
  const originalConsole = {
1140
1134
  log: console.log,
@@ -1201,7 +1195,7 @@ ${a.stack || ""}`;
1201
1195
  console.warn = originalConsole.warn;
1202
1196
  console.error = originalConsole.error;
1203
1197
  console.info = originalConsole.info;
1204
- resolve8(collected);
1198
+ resolve9(collected);
1205
1199
  }, args.duration);
1206
1200
  });
1207
1201
  }, { duration: p.duration });
@@ -1613,7 +1607,7 @@ async function executeAction(page, action) {
1613
1607
  if (action.selector) {
1614
1608
  await page.waitForSelector(action.selector, { timeout: 3e4 });
1615
1609
  } else if (action.milliseconds) {
1616
- await new Promise((resolve8) => setTimeout(resolve8, action.milliseconds));
1610
+ await new Promise((resolve9) => setTimeout(resolve9, action.milliseconds));
1617
1611
  } else {
1618
1612
  throw new Error("wait action requires either milliseconds or selector");
1619
1613
  }
@@ -1696,8 +1690,8 @@ var actionsCommand = registerCommand({
1696
1690
  results.push(result);
1697
1691
  }
1698
1692
  })();
1699
- const timeoutPromise = new Promise((resolve8) => {
1700
- setTimeout(resolve8, timeoutMs);
1693
+ const timeoutPromise = new Promise((resolve9) => {
1694
+ setTimeout(resolve9, timeoutMs);
1701
1695
  });
1702
1696
  await Promise.race([executionPromise, timeoutPromise]);
1703
1697
  const title = await ctx.page.title();
@@ -2371,11 +2365,11 @@ async function navigateForMap(page, url, timeout = 15e3) {
2371
2365
  }
2372
2366
  async function extractPageLinks(page, baseUrl) {
2373
2367
  await navigateForMap(page, baseUrl);
2374
- await new Promise((resolve8) => setTimeout(resolve8, 2e3));
2368
+ await new Promise((resolve9) => setTimeout(resolve9, 2e3));
2375
2369
  await page.evaluate(() => {
2376
2370
  window.scrollTo(0, document.body.scrollHeight);
2377
2371
  });
2378
- await new Promise((resolve8) => setTimeout(resolve8, 1e3));
2372
+ await new Promise((resolve9) => setTimeout(resolve9, 1e3));
2379
2373
  const origin = new URL(baseUrl).origin;
2380
2374
  const rawLinks = await page.evaluate((evalOrigin) => {
2381
2375
  return Array.from(document.querySelectorAll("a[href]")).map((a) => {
@@ -4205,25 +4199,25 @@ aria snapshot\uFF1A
4205
4199
  async function analyzeWithLLM(ariaSnapshot) {
4206
4200
  const piBin = process.env.PI_CLI_PATH || "pi";
4207
4201
  const prompt = LLM_PROMPT.replace("{snapshot}", ariaSnapshot.slice(0, 4e3));
4208
- return new Promise((resolve8) => {
4202
+ return new Promise((resolve9) => {
4209
4203
  execFile(
4210
4204
  piBin,
4211
4205
  ["--provider", LLM_PROVIDER, "--model", LLM_MODEL, prompt],
4212
4206
  { timeout: LLM_TIMEOUT_MS, maxBuffer: 1024 * 1024 },
4213
4207
  (err, stdout, _stderr) => {
4214
4208
  if (err) {
4215
- resolve8(null);
4209
+ resolve9(null);
4216
4210
  return;
4217
4211
  }
4218
4212
  const output = (stdout || "").trim();
4219
4213
  if (!output) {
4220
- resolve8(null);
4214
+ resolve9(null);
4221
4215
  return;
4222
4216
  }
4223
4217
  try {
4224
4218
  const parsed = parse(output);
4225
4219
  if (!parsed || typeof parsed !== "object") {
4226
- resolve8(null);
4220
+ resolve9(null);
4227
4221
  return;
4228
4222
  }
4229
4223
  const elements = {};
@@ -4238,9 +4232,9 @@ async function analyzeWithLLM(ariaSnapshot) {
4238
4232
  };
4239
4233
  }
4240
4234
  }
4241
- resolve8(Object.keys(elements).length > 0 ? elements : null);
4235
+ resolve9(Object.keys(elements).length > 0 ? elements : null);
4242
4236
  } catch {
4243
- resolve8(null);
4237
+ resolve9(null);
4244
4238
  }
4245
4239
  }
4246
4240
  );
@@ -4793,11 +4787,11 @@ function resolveScriptContent(params) {
4793
4787
  async function readStdin() {
4794
4788
  const { createReadStream } = await import("fs");
4795
4789
  const { createInterface } = await import("readline");
4796
- return new Promise((resolve8, reject) => {
4790
+ return new Promise((resolve9, reject) => {
4797
4791
  const lines = [];
4798
4792
  const rl = createInterface({ input: createReadStream("/dev/stdin") });
4799
4793
  rl.on("line", (line) => lines.push(line));
4800
- rl.on("close", () => resolve8(lines.join("\n")));
4794
+ rl.on("close", () => resolve9(lines.join("\n")));
4801
4795
  rl.on("error", reject);
4802
4796
  });
4803
4797
  }
@@ -5535,12 +5529,95 @@ var promoCommand = registerCommand({
5535
5529
  import {
5536
5530
  Core
5537
5531
  } from "@dyyz1993/xcli-core";
5538
- import { resolve as resolve7 } from "path";
5539
- import { existsSync as existsSync4, readdirSync } from "fs";
5532
+ import { resolve as resolve8 } from "path";
5533
+ import { existsSync as existsSync5, readdirSync } from "fs";
5540
5534
  import { homedir as homedir2 } from "os";
5541
5535
 
5536
+ // src/plugin/metadata-parser.ts
5537
+ import { existsSync as existsSync3 } from "fs";
5538
+ import { resolve as resolve7 } from "path";
5539
+
5540
+ // src/utils/json-file.ts
5541
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync3 } from "fs";
5542
+ function readJsonFile(filePath, defaultValue) {
5543
+ try {
5544
+ const content = readFileSync9(filePath, "utf-8");
5545
+ return JSON.parse(content);
5546
+ } catch {
5547
+ return defaultValue;
5548
+ }
5549
+ }
5550
+
5551
+ // src/plugin/metadata-parser.ts
5552
+ var PluginMetadataParser = class {
5553
+ static XBROWSER_KEYWORDS = ["xbrowser", "xbrowser-plugin"];
5554
+ static parseFromPackageJson(pluginPath) {
5555
+ const packageJsonPath = resolve7(pluginPath, "package.json");
5556
+ if (!existsSync3(packageJsonPath)) {
5557
+ return null;
5558
+ }
5559
+ const packageJson = readJsonFile(packageJsonPath, null);
5560
+ if (!packageJson) return null;
5561
+ if (!packageJson.xbrowser) {
5562
+ return null;
5563
+ }
5564
+ const xbrowser = packageJson.xbrowser;
5565
+ const metadata = {
5566
+ id: xbrowser.id || packageJson.name,
5567
+ name: xbrowser.name || packageJson.name,
5568
+ description: xbrowser.description || packageJson.description || "",
5569
+ version: xbrowser.version || packageJson.version || "1.0.0",
5570
+ author: xbrowser.author || this.extractAuthor(packageJson.author),
5571
+ homepage: xbrowser.homepage || packageJson.homepage,
5572
+ commands: xbrowser.commands,
5573
+ sites: xbrowser.sites,
5574
+ tags: xbrowser.tags,
5575
+ screenshot: xbrowser.screenshot,
5576
+ license: xbrowser.license || packageJson.license
5577
+ };
5578
+ return metadata;
5579
+ }
5580
+ static isXBrowserPlugin(packageJson) {
5581
+ if (packageJson.xbrowser) {
5582
+ return true;
5583
+ }
5584
+ const keywords = packageJson.keywords;
5585
+ if (!keywords) return false;
5586
+ return this.XBROWSER_KEYWORDS.some((kw) => keywords.includes(kw));
5587
+ }
5588
+ static fromNPMResult(result) {
5589
+ const author = typeof result.author === "string" ? result.author : result.author?.name || "Unknown";
5590
+ return {
5591
+ id: result.name,
5592
+ name: result.name.replace(/^xbrowser-plugin-/, "").replace(/^@[^/]+\//, ""),
5593
+ description: result.description || "",
5594
+ version: result.version,
5595
+ author,
5596
+ homepage: result.homepage || result.links?.homepage,
5597
+ tags: result.keywords,
5598
+ license: ""
5599
+ };
5600
+ }
5601
+ static extractAuthor(author) {
5602
+ if (typeof author === "string") return author;
5603
+ if (typeof author === "object" && author !== null) {
5604
+ const authorObj = author;
5605
+ return authorObj.name || "Unknown";
5606
+ }
5607
+ return "Unknown";
5608
+ }
5609
+ static validateMetadata(metadata) {
5610
+ const errors = [];
5611
+ if (!metadata.id) errors.push("id is required");
5612
+ if (!metadata.name) errors.push("name is required");
5613
+ if (!metadata.description) errors.push("description is required");
5614
+ if (!metadata.version) errors.push("version is required");
5615
+ return errors;
5616
+ }
5617
+ };
5618
+
5542
5619
  // src/plugin/ensure-deps.ts
5543
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
5620
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4 } from "fs";
5544
5621
  import { join as join2 } from "path";
5545
5622
  import { execSync as execSync6 } from "child_process";
5546
5623
  var SHARED_PLUGIN_DEPENDENCIES = {
@@ -5549,11 +5626,11 @@ var SHARED_PLUGIN_DEPENDENCIES = {
5549
5626
  };
5550
5627
  function ensurePluginDependencies(pluginsDir) {
5551
5628
  const zodPath = join2(pluginsDir, "node_modules", "zod");
5552
- if (existsSync3(zodPath)) return;
5629
+ if (existsSync4(zodPath)) return;
5553
5630
  mkdirSync2(pluginsDir, { recursive: true });
5554
5631
  const pkgPath = join2(pluginsDir, "package.json");
5555
5632
  let pkg = {};
5556
- if (existsSync3(pkgPath)) {
5633
+ if (existsSync4(pkgPath)) {
5557
5634
  try {
5558
5635
  pkg = readJsonFile(pkgPath, {});
5559
5636
  } catch {
@@ -5567,11 +5644,11 @@ function ensurePluginDependencies(pluginsDir) {
5567
5644
  needsInstall = true;
5568
5645
  }
5569
5646
  }
5570
- if (!needsInstall && existsSync3(join2(pluginsDir, "node_modules"))) return;
5647
+ if (!needsInstall && existsSync4(join2(pluginsDir, "node_modules"))) return;
5571
5648
  pkg.dependencies = existingDeps;
5572
5649
  pkg.private = true;
5573
5650
  pkg.description = pkg.description || "xbrowser plugins \u2014 shared dependencies";
5574
- writeFileSync3(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
5651
+ writeFileSync4(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
5575
5652
  try {
5576
5653
  execSync6("npm install --production --no-package-lock --no-fund --no-audit", {
5577
5654
  cwd: pluginsDir,
@@ -5601,7 +5678,7 @@ var XBrowserPluginLoader = class {
5601
5678
  envPrefix: "XBROWSER",
5602
5679
  pluginDirs: [
5603
5680
  ...DEFAULT_PLUGIN_DIRS,
5604
- resolve7(cwd, ".xcli/plugins")
5681
+ resolve8(cwd, ".xcli/plugins")
5605
5682
  ]
5606
5683
  };
5607
5684
  this.core = new Core(coreConfig);
@@ -5640,31 +5717,31 @@ var XBrowserPluginLoader = class {
5640
5717
  }
5641
5718
  async scanAndLoad() {
5642
5719
  const cwd = this.options.cwd || process.cwd();
5643
- const globalDir = this.options.globalDir || resolve7(homedir2(), ".xbrowser/plugins");
5720
+ const globalDir = this.options.globalDir || resolve8(homedir2(), ".xbrowser/plugins");
5644
5721
  ensurePluginDependencies(globalDir);
5645
5722
  const dirs = [
5646
- resolve7(cwd, ".xcli/plugins"),
5647
- resolve7(cwd, "../.xcli/plugins"),
5648
- this.options.userDir || resolve7(homedir2(), ".xcli/plugins"),
5723
+ resolve8(cwd, ".xcli/plugins"),
5724
+ resolve8(cwd, "../.xcli/plugins"),
5725
+ this.options.userDir || resolve8(homedir2(), ".xcli/plugins"),
5649
5726
  globalDir
5650
5727
  ];
5651
5728
  const loaded = [];
5652
5729
  const seen = /* @__PURE__ */ new Set();
5653
5730
  for (const dir of dirs) {
5654
- if (!existsSync4(dir)) continue;
5731
+ if (!existsSync5(dir)) continue;
5655
5732
  const entries = readdirSync(dir, { withFileTypes: true });
5656
5733
  for (const entry of entries) {
5657
5734
  if (!entry.isDirectory()) continue;
5658
5735
  if (seen.has(entry.name)) continue;
5659
5736
  seen.add(entry.name);
5660
- const pluginDir = resolve7(dir, entry.name);
5661
- let indexPath = resolve7(pluginDir, "index.js");
5662
- if (!existsSync4(indexPath)) {
5663
- indexPath = resolve7(pluginDir, "index.ts");
5737
+ const pluginDir = resolve8(dir, entry.name);
5738
+ let indexPath = resolve8(pluginDir, "index.js");
5739
+ if (!existsSync5(indexPath)) {
5740
+ indexPath = resolve8(pluginDir, "index.ts");
5664
5741
  }
5665
- if (!existsSync4(indexPath)) continue;
5742
+ if (!existsSync5(indexPath)) continue;
5666
5743
  try {
5667
- if (!existsSync4(resolve7(pluginDir, "package.json"))) {
5744
+ if (!existsSync5(resolve8(pluginDir, "package.json"))) {
5668
5745
  console.warn(`\u26A0\uFE0F Plugin "${entry.name}" has no package.json. Use "xbrowser create ${entry.name} --template static" for proper structure.`);
5669
5746
  } else {
5670
5747
  const metadata = PluginMetadataParser.parseFromPackageJson(pluginDir);
@@ -5681,22 +5758,6 @@ var XBrowserPluginLoader = class {
5681
5758
  }
5682
5759
  }
5683
5760
  }
5684
- try {
5685
- const { default: setupMarketplace } = await import("./marketplace-FCVN5OTZ.js");
5686
- setupMarketplace(this.loader.getAPI());
5687
- } catch (err) {
5688
- if (process.env.XBROWSER_DEBUG) {
5689
- console.warn(`\u26A0\uFE0F Built-in marketplace plugin load failed: ${err instanceof Error ? err.message : String(err)}`);
5690
- }
5691
- }
5692
- try {
5693
- const { default: setupAdmin } = await import("./admin-6UTU2RZ2.js");
5694
- setupAdmin(this.loader.getAPI());
5695
- } catch (err) {
5696
- if (process.env.XBROWSER_DEBUG) {
5697
- console.warn(`\u26A0\uFE0F Built-in admin plugin load failed: ${err instanceof Error ? err.message : String(err)}`);
5698
- }
5699
- }
5700
5761
  return loaded;
5701
5762
  }
5702
5763
  async unload() {
@@ -6097,7 +6158,7 @@ var TipsManager = class {
6097
6158
  }
6098
6159
  }
6099
6160
  debounce() {
6100
- return new Promise((resolve8) => setTimeout(resolve8, DEBOUNCE_MS));
6161
+ return new Promise((resolve9) => setTimeout(resolve9, DEBOUNCE_MS));
6101
6162
  }
6102
6163
  formatTips(tips) {
6103
6164
  return tips.map((tip) => {
@@ -6124,6 +6185,24 @@ function getTipsManager() {
6124
6185
  return globalTipsManager;
6125
6186
  }
6126
6187
 
6188
+ // src/hooks/loader.ts
6189
+ var builtinHooks = {
6190
+ screenshot: () => import("./screenshot-MB6R7RSS.js").then((m) => m.screenshotHook)
6191
+ };
6192
+ async function loadHooks() {
6193
+ const names = process.env.XBROWSER_HOOKS;
6194
+ if (!names) return [];
6195
+ const hooks = [];
6196
+ for (const name of names.split(",")) {
6197
+ const trimmed = name.trim();
6198
+ const factory = builtinHooks[trimmed];
6199
+ if (factory) {
6200
+ hooks.push(await factory());
6201
+ }
6202
+ }
6203
+ return hooks;
6204
+ }
6205
+
6127
6206
  // src/executor.ts
6128
6207
  import { homedir as homedir3 } from "os";
6129
6208
  import { join as join3 } from "path";
@@ -6283,9 +6362,22 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6283
6362
  }
6284
6363
  }
6285
6364
  try {
6365
+ const hooks = await loadHooks();
6366
+ if (hooks.length > 0 && session?.page) {
6367
+ await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: commandName, params })));
6368
+ }
6286
6369
  const raw = await command.handler(params, ctx);
6287
6370
  const end = Date.now();
6288
6371
  const duration = end - start;
6372
+ let hookOutputs;
6373
+ if (hooks.length > 0 && session?.page) {
6374
+ const outputs = [];
6375
+ for (const h of hooks) {
6376
+ const output = await h.onAfterCommand?.({ page: session.page, command: commandName, params, result: raw, duration });
6377
+ if (output) outputs.push({ _hook: h.name, ...output });
6378
+ }
6379
+ if (outputs.length > 0) hookOutputs = outputs;
6380
+ }
6289
6381
  if (session && isCommandResult(raw)) {
6290
6382
  const resultData = raw.data;
6291
6383
  const convUrl = resultData?.conversationUrl;
@@ -6333,9 +6425,9 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6333
6425
  timestamp: start
6334
6426
  });
6335
6427
  if (isSuccess) {
6336
- return { ...ok25(raw.data, merged.length > 0 ? merged : raw.tips), duration };
6428
+ return { ...ok25(raw.data, merged.length > 0 ? merged : raw.tips), duration, ...hookOutputs ? { hookOutputs } : {} };
6337
6429
  }
6338
- return { success: false, data: raw.data, message: raw.message, tips: merged.length > 0 ? merged : raw.tips || [], duration };
6430
+ return { success: false, data: raw.data, message: raw.message, tips: merged.length > 0 ? merged : raw.tips || [], duration, ...hookOutputs ? { hookOutputs } : {} };
6339
6431
  }
6340
6432
  recordArchive(session?.id, sessionName, {
6341
6433
  step: 0,
@@ -6346,7 +6438,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6346
6438
  duration,
6347
6439
  timestamp: start
6348
6440
  });
6349
- return { ...ok25(raw, smartTips), duration };
6441
+ return { ...ok25(raw, smartTips), duration, ...hookOutputs ? { hookOutputs } : {} };
6350
6442
  } catch (err) {
6351
6443
  const end = Date.now();
6352
6444
  const duration = end - start;
@@ -6820,7 +6912,7 @@ async function replayEntry(entry, options = {}) {
6820
6912
  }
6821
6913
 
6822
6914
  // src/daemon/feedback-store.ts
6823
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
6915
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
6824
6916
  import { join as join4 } from "path";
6825
6917
  import { homedir as homedir4 } from "os";
6826
6918
  var FEEDBACK_FILE = join4(homedir4(), ".xbrowser", "feedback.json");
@@ -6831,7 +6923,7 @@ var FeedbackStore = class {
6831
6923
  }
6832
6924
  load() {
6833
6925
  try {
6834
- const data = readFileSync9(FEEDBACK_FILE, "utf8");
6926
+ const data = readFileSync10(FEEDBACK_FILE, "utf8");
6835
6927
  this.entries = JSON.parse(data);
6836
6928
  } catch {
6837
6929
  this.entries = [];
@@ -6840,7 +6932,7 @@ var FeedbackStore = class {
6840
6932
  save() {
6841
6933
  try {
6842
6934
  mkdirSync3(join4(homedir4(), ".xbrowser"), { recursive: true });
6843
- writeFileSync4(FEEDBACK_FILE, JSON.stringify(this.entries, null, 2));
6935
+ writeFileSync5(FEEDBACK_FILE, JSON.stringify(this.entries, null, 2));
6844
6936
  } catch {
6845
6937
  }
6846
6938
  }
@@ -7513,7 +7605,7 @@ function createRPCHandler() {
7513
7605
  const recordingsDir = join5(CONFIG_DIR, "recordings");
7514
7606
  mkdirSync4(recordingsDir, { recursive: true });
7515
7607
  const outPath = params.path || join5(recordingsDir, `recording-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`);
7516
- writeFileSync5(outPath, JSON.stringify({
7608
+ writeFileSync6(outPath, JSON.stringify({
7517
7609
  startUrl: sess.page.url(),
7518
7610
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
7519
7611
  events
@@ -7683,8 +7775,8 @@ function createRPCHandler() {
7683
7775
  const result = await engine.play({
7684
7776
  slowMo,
7685
7777
  onCheckpoint: async (checkpoint) => {
7686
- return new Promise((resolve8) => {
7687
- replayResumeResolvers.set(sessionName, () => resolve8(true));
7778
+ return new Promise((resolve9) => {
7779
+ replayResumeResolvers.set(sessionName, () => resolve9(true));
7688
7780
  console.log(`[replay] Checkpoint reached: [${checkpoint.type}] ${checkpoint.hint}`);
7689
7781
  console.log('[replay] Send "replay:resume" RPC to continue.');
7690
7782
  });
@@ -8547,8 +8639,8 @@ var WSServer = class extends EventEmitter {
8547
8639
  case "file_list": {
8548
8640
  try {
8549
8641
  const { readdirSync: readdirSync2, statSync } = await import("fs");
8550
- const { join: join7, resolve: resolve8 } = await import("path");
8551
- const targetPath = resolve8(msg.path);
8642
+ const { join: join7, resolve: resolve9 } = await import("path");
8643
+ const targetPath = resolve9(msg.path);
8552
8644
  const entries = readdirSync2(targetPath);
8553
8645
  const files = entries.map((name) => {
8554
8646
  try {
@@ -8566,10 +8658,10 @@ var WSServer = class extends EventEmitter {
8566
8658
  }
8567
8659
  case "file_download": {
8568
8660
  try {
8569
- const { readFileSync: readFileSync11 } = await import("fs");
8570
- const { resolve: resolve8, basename } = await import("path");
8571
- const targetPath = resolve8(msg.path);
8572
- const data = readFileSync11(targetPath);
8661
+ const { readFileSync: readFileSync12 } = await import("fs");
8662
+ const { resolve: resolve9, basename } = await import("path");
8663
+ const targetPath = resolve9(msg.path);
8664
+ const data = readFileSync12(targetPath);
8573
8665
  const base64 = data.toString("base64");
8574
8666
  const ext = targetPath.split(".").pop()?.toLowerCase() || "";
8575
8667
  const mimeMap = {
@@ -8674,7 +8766,7 @@ var WSServer = class extends EventEmitter {
8674
8766
  this.isRunning = false;
8675
8767
  return;
8676
8768
  }
8677
- return new Promise((resolve8, reject) => {
8769
+ return new Promise((resolve9, reject) => {
8678
8770
  this.wsServer.close((err) => {
8679
8771
  if (err) {
8680
8772
  reject(err);
@@ -8682,7 +8774,7 @@ var WSServer = class extends EventEmitter {
8682
8774
  this.wsServer = null;
8683
8775
  this.isRunning = false;
8684
8776
  this.emit("stopped");
8685
- resolve8();
8777
+ resolve9();
8686
8778
  }
8687
8779
  });
8688
8780
  });
@@ -9869,7 +9961,7 @@ async function main() {
9869
9961
  previewWS.on("screencast-started", (sid) => log(`Preview screencast started: ${sid}`));
9870
9962
  previewWS.on("screencast-stopped", (sid) => log(`Preview screencast stopped: ${sid}`));
9871
9963
  mkdirSync5(CONFIG_DIR2, { recursive: true });
9872
- writeFileSync6(join6(CONFIG_DIR2, "daemon.json"), JSON.stringify({
9964
+ writeFileSync7(join6(CONFIG_DIR2, "daemon.json"), JSON.stringify({
9873
9965
  port: daemonPort,
9874
9966
  pid: process.pid,
9875
9967
  startedAt: Date.now()
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  HumanInteractionManager
3
- } from "./chunk-VUJDJCIN.js";
4
- import "./chunk-M7CMBPCA.js";
3
+ } from "./chunk-ITKPSIP7.js";
5
4
  import "./chunk-3RG5ZIWI.js";
6
5
  export {
7
6
  HumanInteractionManager
package/dist/index.d.ts CHANGED
@@ -260,12 +260,17 @@ declare class WSServer extends EventEmitter {
260
260
  /**
261
261
  * Result of a single command execution.
262
262
  */
263
+ interface HookOutput {
264
+ _hook: string;
265
+ [key: string]: unknown;
266
+ }
263
267
  interface ExecutionResult {
264
268
  success: boolean;
265
269
  data: unknown;
266
270
  message?: string;
267
271
  duration: number;
268
272
  tips?: string[];
273
+ hookOutputs?: HookOutput[];
269
274
  }
270
275
  /**
271
276
  * Result of a single step within a command chain execution.
@@ -278,6 +283,7 @@ interface ChainStepResult {
278
283
  message?: string;
279
284
  duration: number;
280
285
  tips?: string[];
286
+ hookOutputs?: HookOutput[];
281
287
  }
282
288
  /**
283
289
  * Result of executing a command chain (multiple commands linked with &&, ||, etc.).
@@ -1055,73 +1061,6 @@ declare class PluginInstaller {
1055
1061
  private deriveName;
1056
1062
  }
1057
1063
 
1058
- /**
1059
- * Authentication configuration for publishing to a registry.
1060
- */
1061
- interface AuthConfig {
1062
- token: string;
1063
- registry: string;
1064
- }
1065
- type StorageType = 'npm' | 'r2';
1066
- /**
1067
- * Options for publishing a plugin.
1068
- */
1069
- interface PublishOptions {
1070
- registry: string;
1071
- token: string;
1072
- dryRun?: boolean;
1073
- storage?: StorageType;
1074
- }
1075
- interface CommandDocParam {
1076
- name: string;
1077
- type: string;
1078
- description: string;
1079
- required: boolean;
1080
- default?: unknown;
1081
- }
1082
- interface CommandDocExample {
1083
- cmd: string;
1084
- description: string;
1085
- }
1086
- interface CommandDoc {
1087
- name: string;
1088
- description: string;
1089
- parameters: CommandDocParam[];
1090
- examples?: CommandDocExample[];
1091
- }
1092
- /**
1093
- * Result of creating a plugin tarball for publishing.
1094
- */
1095
- interface PublishResult {
1096
- name: string;
1097
- version: string;
1098
- slug: string;
1099
- description: string;
1100
- author: string;
1101
- commands: string[];
1102
- commandsDocs: CommandDoc[];
1103
- readme: string | null;
1104
- tags: string[];
1105
- sites: string[];
1106
- fileCount: number;
1107
- size: number;
1108
- checksum: string;
1109
- formData: FormData;
1110
- }
1111
- /**
1112
- * Create a publishable tarball from a plugin directory.
1113
- *
1114
- * Collects plugin files, extracts metadata from package.json, detects
1115
- * registered commands from source code, and prepares a FormData payload
1116
- * for uploading to the marketplace or an npm-based registry.
1117
- *
1118
- * @param pluginDir - Path to the plugin directory containing `index.ts`.
1119
- * @param options - Publish options including registry, token, storage type, and dry-run flag.
1120
- * @returns A PublishResult with metadata and the prepared FormData.
1121
- * @throws If `index.ts` is missing or the plugin has no description.
1122
- */
1123
- declare function createTarball(pluginDir: string, options: PublishOptions): Promise<PublishResult>;
1124
-
1125
1064
  /**
1126
1065
  * A single recorded browser event (click, type, scroll, navigate, etc.).
1127
1066
  */
@@ -2310,4 +2249,4 @@ declare function advise(decision: DecisionResult, originalMethod: string): Advis
2310
2249
  /** Convenience factory: create and start a CDP interceptor proxy with defaults. */
2311
2250
  declare function createCDPInterceptor(config: CDPInterceptorConfig): Promise<CDPInterceptorProxy>;
2312
2251
 
2313
- export { type APIRequest, type APIResponse, type AdvisoryResult, type AnalysisResult, type AuthConfig, BROWSER_SCOPE, type BatchCollectResult, type BrowserCommandContext, type BrowserCommandDefinition, type BrowserLaunchOptions, type BuiltinCommand, type BuiltinContext, type CDPError, type CDPInterceptorConfig, CDPInterceptorProxy, type CDPInterceptorRule, type CDPInterceptorStats, type CDPLogEntry, type CDPMessage, type CDPRequest, type CDPResponse, type CaptchaDetectionResult, CaptchaDetector, type ChainExecutionResult, type ChainRequest, type ChainStepResult, type CollectResult, type CollectorConfig, type CommandMessage, type CompanyInfo, type ContextChange, type DaemonInfo, DataCollector, DataStorage, type DecisionAction, type DecisionResult, type DomainStat, type ElementRef, type ExecRequest, type ExecutionResult, HTTPServer, type HTTPServerConfig, type HTTPServerError, HumanInteractionManager, type InstallOptions, type InstalledPlugin, type ManagedSession, type MessageDirection, type NetworkEntry, type ParsedPipeline, PlaybackEngine, type PlaybackOptions, type PlaybackResult, PluginInstaller, type PluginLoaderOptions, type PublishOptions, type PublishResult, type RecordedEvent, RecorderController, type RecorderStatus, type Recording, type RecordingControlFile, type RecordingData, type RecordingEvent, type RecordingSession, type RecordingStep, type RecordingSummary, type RegisteredCommand, ResultAnalyzer, type RuleContext, type RuleEngine, type ScopeDefinition, type ScopeLevel, ScreencastCapturer, type ScreencastFrame, type ScreencastMessage, type ScreencastOptions, type SearchResult, type ManagedSession as SessionInfo, SessionRecorder, type StatusMessage, type StorageConfig, type UserAction, type ViolationSeverity, type WSInboundMessage, type WSMessage, WSServer, type WSServerConfig, type WaitForHumanOptions, type WaitForHumanResult, WebhookNotifier, type WebhookPayload, XBrowserPluginLoader, advise, allBuiltins, assertPageScope, attachWaitForHuman, automationSignalsRule, checkBrowserScope, routeCommand as cliRoute, closeAllSessions as closeAllBrowserSessions, closeAllSessions, closeSession, closeSessionByName, createCDPInterceptor, createRuleEngine, createSession, createTarball, destroyBrowser, destroyBrowser as destroySessionManager, domMutationRule, emulationOverrideRule, eventSimulationRule, executeChain, executeCommand, extractAndSave, extractRecording, filterRecording, findSession, findSession as findSessionInfo, fingerprintingRule, generateBashScript, generateJSScript, generatePythonScript, getAllSessions as getAllBrowserSessions, getAllCommands, getBrowser, getBuiltin, getCaptchaConfig, getCommand, getCommandNames, getCompanyType, getDaemonProcessStatus, getPlatformName, getSessionPage, getWSServerFromCache, inputKeystrokeRule, isChainInput, getAllSessions as listAllBrowserSessions, listSessions, mouseTrajectoryRule, networkAnomalyRule, normalizeSelector, openSession, pageLifecycleRule, parseCommandArgs, parseCommandChain, parseExcludeTypes, printExtractSummary, readCommandFile, readStdin, registerCommand, registerCommandDefinition, resetForTesting, setWSServer, setWSServerCache, splitCommand, startDaemonProcess, stopDaemonProcess, version };
2252
+ export { type APIRequest, type APIResponse, type AdvisoryResult, type AnalysisResult, BROWSER_SCOPE, type BatchCollectResult, type BrowserCommandContext, type BrowserCommandDefinition, type BrowserLaunchOptions, type BuiltinCommand, type BuiltinContext, type CDPError, type CDPInterceptorConfig, CDPInterceptorProxy, type CDPInterceptorRule, type CDPInterceptorStats, type CDPLogEntry, type CDPMessage, type CDPRequest, type CDPResponse, type CaptchaDetectionResult, CaptchaDetector, type ChainExecutionResult, type ChainRequest, type ChainStepResult, type CollectResult, type CollectorConfig, type CommandMessage, type CompanyInfo, type ContextChange, type DaemonInfo, DataCollector, DataStorage, type DecisionAction, type DecisionResult, type DomainStat, type ElementRef, type ExecRequest, type ExecutionResult, HTTPServer, type HTTPServerConfig, type HTTPServerError, HumanInteractionManager, type InstallOptions, type InstalledPlugin, type ManagedSession, type MessageDirection, type NetworkEntry, type ParsedPipeline, PlaybackEngine, type PlaybackOptions, type PlaybackResult, PluginInstaller, type PluginLoaderOptions, type RecordedEvent, RecorderController, type RecorderStatus, type Recording, type RecordingControlFile, type RecordingData, type RecordingEvent, type RecordingSession, type RecordingStep, type RecordingSummary, type RegisteredCommand, ResultAnalyzer, type RuleContext, type RuleEngine, type ScopeDefinition, type ScopeLevel, ScreencastCapturer, type ScreencastFrame, type ScreencastMessage, type ScreencastOptions, type SearchResult, type ManagedSession as SessionInfo, SessionRecorder, type StatusMessage, type StorageConfig, type UserAction, type ViolationSeverity, type WSInboundMessage, type WSMessage, WSServer, type WSServerConfig, type WaitForHumanOptions, type WaitForHumanResult, WebhookNotifier, type WebhookPayload, XBrowserPluginLoader, advise, allBuiltins, assertPageScope, attachWaitForHuman, automationSignalsRule, checkBrowserScope, routeCommand as cliRoute, closeAllSessions as closeAllBrowserSessions, closeAllSessions, closeSession, closeSessionByName, createCDPInterceptor, createRuleEngine, createSession, destroyBrowser, destroyBrowser as destroySessionManager, domMutationRule, emulationOverrideRule, eventSimulationRule, executeChain, executeCommand, extractAndSave, extractRecording, filterRecording, findSession, findSession as findSessionInfo, fingerprintingRule, generateBashScript, generateJSScript, generatePythonScript, getAllSessions as getAllBrowserSessions, getAllCommands, getBrowser, getBuiltin, getCaptchaConfig, getCommand, getCommandNames, getCompanyType, getDaemonProcessStatus, getPlatformName, getSessionPage, getWSServerFromCache, inputKeystrokeRule, isChainInput, getAllSessions as listAllBrowserSessions, listSessions, mouseTrajectoryRule, networkAnomalyRule, normalizeSelector, openSession, pageLifecycleRule, parseCommandArgs, parseCommandChain, parseExcludeTypes, printExtractSummary, readCommandFile, readStdin, registerCommand, registerCommandDefinition, resetForTesting, setWSServer, setWSServerCache, splitCommand, startDaemonProcess, stopDaemonProcess, version };