@xbrowser/cli 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,13 +24,13 @@ import {
24
24
  } from "./chunk-F3ZWFCJJ.js";
25
25
 
26
26
  // src/daemon/daemon-main.ts
27
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, appendFileSync } from "fs";
27
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync6, appendFileSync } from "fs";
28
28
  import { join as join6 } from "path";
29
29
  import { homedir as homedir6 } from "os";
30
30
  import { startHttpServer } from "@dyyz1993/xcli-core";
31
31
 
32
32
  // src/daemon/rpc-handlers.ts
33
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
33
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
34
34
  import { join as join5 } from "path";
35
35
  import { homedir as homedir5 } from "os";
36
36
  import {
@@ -129,7 +129,18 @@ function parsePluginParams(args, schema, base = {}) {
129
129
  if (value === "true") params[key] = true;
130
130
  else if (value === "false") params[key] = false;
131
131
  else if (/^\d+$/.test(value)) params[key] = parseInt(value, 10);
132
- else params[key] = value;
132
+ else {
133
+ try {
134
+ const parsed = JSON.parse(value);
135
+ if (Array.isArray(parsed) || typeof parsed === "object" && parsed !== null) {
136
+ params[key] = parsed;
137
+ } else {
138
+ params[key] = value;
139
+ }
140
+ } catch {
141
+ params[key] = value;
142
+ }
143
+ }
133
144
  i++;
134
145
  } else {
135
146
  params[key] = true;
@@ -6206,8 +6217,48 @@ async function loadHooks() {
6206
6217
  // src/executor.ts
6207
6218
  import { homedir as homedir3 } from "os";
6208
6219
  import { join as join3 } from "path";
6220
+ import { existsSync as existsSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
6209
6221
  var NAVIGATION_COMMANDS = /* @__PURE__ */ new Set(["goto", "back", "forward", "refresh"]);
6210
6222
  var snapshotHintShown = /* @__PURE__ */ new WeakSet();
6223
+ var STORAGE_DIR = join3(homedir3(), ".xbrowser", "storage");
6224
+ var storageCache = /* @__PURE__ */ new Map();
6225
+ function getPluginStorage(pluginName) {
6226
+ if (!storageCache.has(pluginName)) {
6227
+ const filePath = join3(STORAGE_DIR, `${pluginName}.json`);
6228
+ let data = {};
6229
+ const load3 = () => {
6230
+ if (existsSync6(filePath)) {
6231
+ try {
6232
+ data = JSON.parse(readFileSync10(filePath, "utf-8"));
6233
+ } catch {
6234
+ data = {};
6235
+ }
6236
+ }
6237
+ };
6238
+ const save = () => {
6239
+ mkdirSync3(STORAGE_DIR, { recursive: true });
6240
+ writeFileSync5(filePath, JSON.stringify(data, null, 2), "utf-8");
6241
+ };
6242
+ load3();
6243
+ storageCache.set(pluginName, {
6244
+ get: async (key) => data[key] ?? null,
6245
+ set: async (key, value) => {
6246
+ data[key] = value;
6247
+ save();
6248
+ },
6249
+ delete: async (key) => {
6250
+ delete data[key];
6251
+ save();
6252
+ },
6253
+ clear: async () => {
6254
+ data = {};
6255
+ save();
6256
+ },
6257
+ keys: async () => Object.keys(data)
6258
+ });
6259
+ }
6260
+ return storageCache.get(pluginName);
6261
+ }
6211
6262
  var archiveInitialized = false;
6212
6263
  function ensureArchiveInit() {
6213
6264
  if (!archiveInitialized) {
@@ -6315,16 +6366,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
6315
6366
  args: [],
6316
6367
  options: {},
6317
6368
  cwd: process.cwd(),
6318
- storage: {
6319
- get: async () => null,
6320
- set: async () => {
6321
- },
6322
- delete: async () => {
6323
- },
6324
- clear: async () => {
6325
- },
6326
- keys: async () => []
6327
- },
6369
+ storage: getPluginStorage(commandName),
6328
6370
  output: {
6329
6371
  mode: "text",
6330
6372
  showTips: false,
@@ -6547,16 +6589,7 @@ async function executeChain(input, options) {
6547
6589
  browser: session.context.browser(),
6548
6590
  browserContext: session.context,
6549
6591
  sessionId: session.id,
6550
- storage: {
6551
- get: async (_key) => null,
6552
- set: async (_key, _value) => {
6553
- },
6554
- delete: async (_key) => {
6555
- },
6556
- clear: async () => {
6557
- },
6558
- keys: async () => []
6559
- },
6592
+ storage: getPluginStorage(cmdName),
6560
6593
  output: { mode: "text", showTips: false, color: false, emoji: false },
6561
6594
  error: (msg) => {
6562
6595
  throw new Error(msg);
@@ -6567,8 +6600,21 @@ async function executeChain(input, options) {
6567
6600
  };
6568
6601
  const start2 = Date.now();
6569
6602
  try {
6603
+ const hooks = await loadHooks();
6604
+ if (hooks.length > 0) {
6605
+ await Promise.all(hooks.map((h) => h.onBeforeCommand?.({ page: session.page, command: `${cmdName} ${subCommand}`, params: pluginParams })));
6606
+ }
6570
6607
  const raw = await cmdEntry.handler(pluginParams, pluginCtx);
6571
6608
  const duration2 = Date.now() - start2;
6609
+ let hookOutputs;
6610
+ if (hooks.length > 0) {
6611
+ const outputs = [];
6612
+ for (const h of hooks) {
6613
+ const output = await h.onAfterCommand?.({ page: session.page, command: `${cmdName} ${subCommand}`, params: pluginParams, result: raw, duration: duration2 });
6614
+ if (output) outputs.push({ _hook: h.name, ...output });
6615
+ }
6616
+ if (outputs.length > 0) hookOutputs = outputs;
6617
+ }
6572
6618
  const data = raw?.data ?? raw;
6573
6619
  recordArchive(session.id, sessionName, {
6574
6620
  step: results.length,
@@ -6583,7 +6629,8 @@ async function executeChain(input, options) {
6583
6629
  command: `${cmdName} ${subCommand}`,
6584
6630
  raw: cmdStr,
6585
6631
  ...ok25(data),
6586
- duration: duration2
6632
+ duration: duration2,
6633
+ ...hookOutputs ? { hookOutputs } : {}
6587
6634
  });
6588
6635
  if (type === "or") {
6589
6636
  return {
@@ -6647,7 +6694,8 @@ async function executeChain(input, options) {
6647
6694
  data: result.data,
6648
6695
  message: result.message,
6649
6696
  duration,
6650
- tips: result.tips
6697
+ tips: result.tips,
6698
+ ...result.hookOutputs ? { hookOutputs: result.hookOutputs } : {}
6651
6699
  };
6652
6700
  results.push(stepResult);
6653
6701
  if (type === "and" && !result.success) {
@@ -6912,7 +6960,7 @@ async function replayEntry(entry, options = {}) {
6912
6960
  }
6913
6961
 
6914
6962
  // src/daemon/feedback-store.ts
6915
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
6963
+ import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4 } from "fs";
6916
6964
  import { join as join4 } from "path";
6917
6965
  import { homedir as homedir4 } from "os";
6918
6966
  var FEEDBACK_FILE = join4(homedir4(), ".xbrowser", "feedback.json");
@@ -6923,7 +6971,7 @@ var FeedbackStore = class {
6923
6971
  }
6924
6972
  load() {
6925
6973
  try {
6926
- const data = readFileSync10(FEEDBACK_FILE, "utf8");
6974
+ const data = readFileSync11(FEEDBACK_FILE, "utf8");
6927
6975
  this.entries = JSON.parse(data);
6928
6976
  } catch {
6929
6977
  this.entries = [];
@@ -6931,8 +6979,8 @@ var FeedbackStore = class {
6931
6979
  }
6932
6980
  save() {
6933
6981
  try {
6934
- mkdirSync3(join4(homedir4(), ".xbrowser"), { recursive: true });
6935
- writeFileSync5(FEEDBACK_FILE, JSON.stringify(this.entries, null, 2));
6982
+ mkdirSync4(join4(homedir4(), ".xbrowser"), { recursive: true });
6983
+ writeFileSync6(FEEDBACK_FILE, JSON.stringify(this.entries, null, 2));
6936
6984
  } catch {
6937
6985
  }
6938
6986
  }
@@ -7603,9 +7651,9 @@ function createRPCHandler() {
7603
7651
  try {
7604
7652
  const events = await sess.page.evaluate(() => window.__xb_evts || []);
7605
7653
  const recordingsDir = join5(CONFIG_DIR, "recordings");
7606
- mkdirSync4(recordingsDir, { recursive: true });
7654
+ mkdirSync5(recordingsDir, { recursive: true });
7607
7655
  const outPath = params.path || join5(recordingsDir, `recording-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.json`);
7608
- writeFileSync6(outPath, JSON.stringify({
7656
+ writeFileSync7(outPath, JSON.stringify({
7609
7657
  startUrl: sess.page.url(),
7610
7658
  recordedAt: (/* @__PURE__ */ new Date()).toISOString(),
7611
7659
  events
@@ -8658,10 +8706,10 @@ var WSServer = class extends EventEmitter {
8658
8706
  }
8659
8707
  case "file_download": {
8660
8708
  try {
8661
- const { readFileSync: readFileSync12 } = await import("fs");
8709
+ const { readFileSync: readFileSync13 } = await import("fs");
8662
8710
  const { resolve: resolve9, basename } = await import("path");
8663
8711
  const targetPath = resolve9(msg.path);
8664
- const data = readFileSync12(targetPath);
8712
+ const data = readFileSync13(targetPath);
8665
8713
  const base64 = data.toString("base64");
8666
8714
  const ext = targetPath.split(".").pop()?.toLowerCase() || "";
8667
8715
  const mimeMap = {
@@ -9960,8 +10008,8 @@ async function main() {
9960
10008
  rpcHandler.setPreviewWS(previewWS);
9961
10009
  previewWS.on("screencast-started", (sid) => log(`Preview screencast started: ${sid}`));
9962
10010
  previewWS.on("screencast-stopped", (sid) => log(`Preview screencast stopped: ${sid}`));
9963
- mkdirSync5(CONFIG_DIR2, { recursive: true });
9964
- writeFileSync7(join6(CONFIG_DIR2, "daemon.json"), JSON.stringify({
10011
+ mkdirSync6(CONFIG_DIR2, { recursive: true });
10012
+ writeFileSync8(join6(CONFIG_DIR2, "daemon.json"), JSON.stringify({
9965
10013
  port: daemonPort,
9966
10014
  pid: process.pid,
9967
10015
  startedAt: Date.now()