farai 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -6490,6 +6490,8 @@ function ensureDefaultConfig() {
6490
6490
  servers[id2] = defaults[id2];
6491
6491
  if (needsMigration && isLegacyPwnoMcpDefault(servers["pwno-mcp"]))
6492
6492
  delete servers["pwno-mcp"];
6493
+ if (needsMigration && isLegacyDefaultPlaywright(servers["playwright"]))
6494
+ servers["playwright"] = defaults["playwright"];
6493
6495
  writeConfig({
6494
6496
  ...current,
6495
6497
  configVersion: CURRENT_CONFIG_VERSION,
@@ -6506,10 +6508,21 @@ function isLegacyPwnoMcpDefault(entry) {
6506
6508
  return false;
6507
6509
  return entry.args.includes("ghcr.io/pwno-io/pwno-mcp:v0.2.1") && entry.args.includes("--stdio");
6508
6510
  }
6511
+ function isLegacyDefaultPlaywright(entry) {
6512
+ if (!entry || entry.command !== "playwright-mcp" || !Array.isArray(entry.args))
6513
+ return false;
6514
+ const args = entry.args.map(String);
6515
+ if (!args.includes("--headless"))
6516
+ return false;
6517
+ const execIndex = args.indexOf("--executable-path");
6518
+ if (execIndex >= 0 && args[execIndex + 1] && args[execIndex + 1] !== "/usr/bin/chromium")
6519
+ return false;
6520
+ return true;
6521
+ }
6509
6522
  function positiveInteger(value) {
6510
6523
  return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : undefined;
6511
6524
  }
6512
- var DEFAULT_TRANSPARENT_PROXY_PORTS, CONFIG_MAX_BYTES, LSP_SERVER_IDS, CURRENT_CONFIG_VERSION = 4, DEFAULT_CONFIG_TEMPLATE;
6525
+ var DEFAULT_TRANSPARENT_PROXY_PORTS, CONFIG_MAX_BYTES, LSP_SERVER_IDS, CURRENT_CONFIG_VERSION = 7, DEFAULT_CONFIG_TEMPLATE;
6513
6526
  var init_config = __esm(() => {
6514
6527
  init_mcp_builtins();
6515
6528
  init_credential_store();
@@ -6547,8 +6560,8 @@ autoStartProxy = true
6547
6560
  port = 31337
6548
6561
 
6549
6562
  [mcp_servers.playwright]
6550
- command = "playwright-mcp"
6551
- args = ["--headless", "--browser", "chromium", "--executable-path", "/usr/bin/chromium", "--no-sandbox", "--ignore-https-errors", "--isolated"]
6563
+ command = "xvfb-run"
6564
+ args = ["-a", "playwright-mcp", "--browser", "chromium", "--no-sandbox", "--ignore-https-errors", "--isolated"]
6552
6565
  run_in_container = true
6553
6566
  enabled = true
6554
6567
  required = false
@@ -8784,8 +8797,8 @@ var init_process_output = __esm(() => {
8784
8797
 
8785
8798
  // src/version.ts
8786
8799
  function resolveFaraiVersion() {
8787
- if ("0.3.5")
8788
- return "0.3.5";
8800
+ if ("0.3.7")
8801
+ return "0.3.7";
8789
8802
  try {
8790
8803
  const parsed = JSON.parse(readBoundedFileTextSync(new URL("../package.json", import.meta.url), 1024 * 1024, "package metadata"));
8791
8804
  if (typeof parsed.version === "string" && parsed.version)
@@ -28695,6 +28708,12 @@ function compactError2(value) {
28695
28708
  async function runAdb(context, argline, timeoutMs, maxBytes = 2000000) {
28696
28709
  return backend(context).exec(argline, timeoutMs, context.signal, maxBytes);
28697
28710
  }
28711
+ async function runAdbChecked(context, argline, timeoutMs, maxBytes = 2000000) {
28712
+ const result = await runAdb(context, argline, timeoutMs, maxBytes);
28713
+ if (adbUnavailable(result))
28714
+ throw new Error("adb is not available in the container");
28715
+ return result;
28716
+ }
28698
28717
  function adbEnvPrefix() {
28699
28718
  const parts = ADB_SERVER_ENV.filter((name) => (process.env[name] ?? "").trim()).map((name) => `${name}=${shellQuote7(process.env[name].trim())}`);
28700
28719
  return parts.length ? `${parts.join(" ")} ` : "";
@@ -28733,12 +28752,10 @@ function parseDevices(stdout) {
28733
28752
  return devices;
28734
28753
  }
28735
28754
  async function resolveDevice(context, serial, timeoutMs = 15000) {
28736
- const provided = serial?.trim();
28755
+ const provided = typeof serial === "string" ? serial.trim() : "";
28737
28756
  if (provided)
28738
28757
  return provided;
28739
- const result = await runAdb(context, `${adbBase()} devices -l`, timeoutMs);
28740
- if (adbUnavailable(result))
28741
- throw new Error("adb is not available in the container");
28758
+ const result = await runAdbChecked(context, `${adbBase()} devices -l`, timeoutMs);
28742
28759
  const online = parseDevices(result.stdout).filter((device) => device.state === "device");
28743
28760
  if (online.length === 0)
28744
28761
  throw new Error("no android device is connected; use android_connect to attach one over tcp/ip");
@@ -28784,9 +28801,7 @@ var init_device = __esm(() => {
28784
28801
  assertObject(args, "args");
28785
28802
  const raw = asString(args.address, "address").trim();
28786
28803
  const address = /:\d+$/.test(raw) ? raw : `${raw}:5555`;
28787
- const result = await runAdb(context, `${adbBase()} connect ${shellQuote7(address)}`, 30000);
28788
- if (adbUnavailable(result))
28789
- throw new Error("adb is not available in the container");
28804
+ const result = await runAdbChecked(context, `${adbBase()} connect ${shellQuote7(address)}`, 30000);
28790
28805
  const text2 = `${result.stdout}${result.stderr}`.trim();
28791
28806
  const ok = /connected to/i.test(text2) && !/cannot|failed|unable|refused/i.test(text2);
28792
28807
  return {
@@ -28815,9 +28830,7 @@ var init_device = __esm(() => {
28815
28830
  renderModel: defaultModelRenderer,
28816
28831
  run: async (args, context) => {
28817
28832
  assertObject(args, "args");
28818
- const result = await runAdb(context, `${adbBase()} devices -l`, 15000);
28819
- if (adbUnavailable(result))
28820
- throw new Error("adb is not available in the container");
28833
+ const result = await runAdbChecked(context, `${adbBase()} devices -l`, 15000);
28821
28834
  const devices = parseDevices(result.stdout);
28822
28835
  const online = devices.filter((device) => device.state === "device");
28823
28836
  const output = devices.length ? devices.map((device) => `${device.serial} ${device.state}${device.model ? ` model:${device.model}` : ""}`).join(`
@@ -28855,10 +28868,8 @@ var init_device = __esm(() => {
28855
28868
  run: async (args, context) => {
28856
28869
  assertObject(args, "args");
28857
28870
  const command = asString(args.command, "command");
28858
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
28859
- const result = await runAdb(context, `${adbPrefix(serial)} shell ${shellQuote7(command)}`, 60000);
28860
- if (adbUnavailable(result))
28861
- throw new Error("adb is not available in the container");
28871
+ const serial = await resolveDevice(context, args.serial);
28872
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell ${shellQuote7(command)}`, 60000);
28862
28873
  const output = `${result.stdout}${result.stderr ? `
28863
28874
  ${result.stderr}` : ""}`.trim();
28864
28875
  return {
@@ -28897,11 +28908,9 @@ ${result.stderr}` : ""}`.trim();
28897
28908
  renderModel: defaultModelRenderer,
28898
28909
  run: async (args, context) => {
28899
28910
  assertObject(args, "args");
28900
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
28911
+ const serial = await resolveDevice(context, args.serial);
28901
28912
  const thirdParty = args.thirdPartyOnly === true;
28902
- const result = await runAdb(context, `${adbPrefix(serial)} shell pm list packages${thirdParty ? " -3" : ""}`, 30000);
28903
- if (adbUnavailable(result))
28904
- throw new Error("adb is not available in the container");
28913
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell pm list packages${thirdParty ? " -3" : ""}`, 30000);
28905
28914
  const filter = typeof args.filter === "string" ? args.filter.trim().toLowerCase() : "";
28906
28915
  let packages = result.stdout.split(`
28907
28916
  `).map((line) => line.replace(/^package:/, "").trim()).filter(Boolean);
@@ -28938,12 +28947,10 @@ ${result.stderr}` : ""}`.trim();
28938
28947
  renderModel: defaultModelRenderer,
28939
28948
  run: async (args, context) => {
28940
28949
  assertObject(args, "args");
28941
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
28950
+ const serial = await resolveDevice(context, args.serial);
28942
28951
  const props = ["ro.build.version.release", "ro.build.version.sdk", "ro.product.model", "ro.product.manufacturer", "ro.product.cpu.abi", "ro.build.type"];
28943
28952
  const command = `${adbPrefix(serial)} shell ${shellQuote7(`for p in ${props.join(" ")}; do echo "$p=$(getprop $p)"; done; echo su=$(command -v su || echo none)`)}`;
28944
- const result = await runAdb(context, command, 30000);
28945
- if (adbUnavailable(result))
28946
- throw new Error("adb is not available in the container");
28953
+ const result = await runAdbChecked(context, command, 30000);
28947
28954
  const info = {};
28948
28955
  for (const line of result.stdout.split(`
28949
28956
  `)) {
@@ -28990,13 +28997,11 @@ ${result.stderr}` : ""}`.trim();
28990
28997
  renderModel: defaultModelRenderer,
28991
28998
  run: async (args, context) => {
28992
28999
  assertObject(args, "args");
28993
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29000
+ const serial = await resolveDevice(context, args.serial);
28994
29001
  const lines = typeof args.lines === "number" && Number.isInteger(args.lines) ? Math.max(1, Math.min(5000, args.lines)) : 200;
28995
29002
  const tag = typeof args.tag === "string" && args.tag.trim() ? args.tag.trim() : "";
28996
29003
  const filter = tag ? ` -s ${shellQuote7(tag)}` : "";
28997
- const result = await runAdb(context, `${adbPrefix(serial)} logcat -d -t ${lines}${filter}`, 30000);
28998
- if (adbUnavailable(result))
28999
- throw new Error("adb is not available in the container");
29004
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} logcat -d -t ${lines}${filter}`, 30000);
29000
29005
  const output = result.stdout.trim();
29001
29006
  return {
29002
29007
  ok: result.exitCode === 0,
@@ -29043,11 +29048,9 @@ function appLifecycleTool(name, verb) {
29043
29048
  run: async (args, context) => {
29044
29049
  assertObject(args, "args");
29045
29050
  const pkg = sanitizePackage(asString(args.package, "package"));
29046
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29051
+ const serial = await resolveDevice(context, args.serial);
29047
29052
  const shell = verb === "start" ? `monkey -p ${shellQuote7(pkg)} -c android.intent.category.LAUNCHER 1` : `am force-stop ${shellQuote7(pkg)}`;
29048
- const result = await runAdb(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000);
29049
- if (adbUnavailable(result))
29050
- throw new Error("adb is not available in the container");
29053
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000);
29051
29054
  const output = `${result.stdout}${result.stderr ? `
29052
29055
  ${result.stderr}` : ""}`.trim();
29053
29056
  const ok = result.exitCode === 0 && !/error|no activities found/i.test(output);
@@ -29094,10 +29097,8 @@ var init_app = __esm(() => {
29094
29097
  run: async (args, context) => {
29095
29098
  assertObject(args, "args");
29096
29099
  const pkg = sanitizePackage(asString(args.package, "package"));
29097
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29098
- const pathResult = await runAdb(context, `${adbPrefix(serial)} shell pm path ${shellQuote7(pkg)}`, 30000);
29099
- if (adbUnavailable(pathResult))
29100
- throw new Error("adb is not available in the container");
29100
+ const serial = await resolveDevice(context, args.serial);
29101
+ const pathResult = await runAdbChecked(context, `${adbPrefix(serial)} shell pm path ${shellQuote7(pkg)}`, 30000);
29101
29102
  const remotes = pathResult.stdout.split(`
29102
29103
  `).map((line) => line.replace(/^package:/, "").trim()).filter(Boolean);
29103
29104
  if (remotes.length === 0)
@@ -29151,10 +29152,8 @@ var init_app = __esm(() => {
29151
29152
  run: async (args, context) => {
29152
29153
  assertObject(args, "args");
29153
29154
  const apkPath = asString(args.apkPath, "apkPath").trim();
29154
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29155
- const result = await runAdb(context, `${adbPrefix(serial)} install -r ${shellQuote7(apkPath)}`, 120000);
29156
- if (adbUnavailable(result))
29157
- throw new Error("adb is not available in the container");
29155
+ const serial = await resolveDevice(context, args.serial);
29156
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} install -r ${shellQuote7(apkPath)}`, 120000);
29158
29157
  const text2 = `${result.stdout}${result.stderr}`.trim();
29159
29158
  const ok = /success/i.test(text2);
29160
29159
  return {
@@ -29199,11 +29198,9 @@ var init_app = __esm(() => {
29199
29198
  assertObject(args, "args");
29200
29199
  const uri = asString(args.uri, "uri").trim();
29201
29200
  const pkg = typeof args.package === "string" && args.package.trim() ? sanitizePackage(args.package) : "";
29202
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29201
+ const serial = await resolveDevice(context, args.serial);
29203
29202
  const shell = `am start -a android.intent.action.VIEW -d ${shellQuote7(uri)}${pkg ? ` ${shellQuote7(pkg)}` : ""}`;
29204
- const result = await runAdb(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000);
29205
- if (adbUnavailable(result))
29206
- throw new Error("adb is not available in the container");
29203
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000);
29207
29204
  const output = `${result.stdout}${result.stderr ? `
29208
29205
  ${result.stderr}` : ""}`.trim();
29209
29206
  const ok = result.exitCode === 0 && !/error|exception/i.test(output);
@@ -29247,11 +29244,9 @@ ${result.stderr}` : ""}`.trim();
29247
29244
  assertObject(args, "args");
29248
29245
  const path = asString(args.path, "path").trim();
29249
29246
  const pkg = typeof args.package === "string" && args.package.trim() ? sanitizePackage(args.package) : "";
29250
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29247
+ const serial = await resolveDevice(context, args.serial);
29251
29248
  const shell = pkg ? `run-as ${shellQuote7(pkg)} cat ${shellQuote7(path)}` : `cat ${shellQuote7(path)}`;
29252
- const result = await runAdb(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000, 4000000);
29253
- if (adbUnavailable(result))
29254
- throw new Error("adb is not available in the container");
29249
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell ${shellQuote7(shell)}`, 30000, 4000000);
29255
29250
  const ok = result.exitCode === 0 && !/no such file|permission denied|not debuggable|run-as:/i.test(result.stderr);
29256
29251
  return {
29257
29252
  ok,
@@ -29606,9 +29601,7 @@ function findUiNode(nodes, selector) {
29606
29601
  }
29607
29602
  async function dumpHierarchy(context, serial) {
29608
29603
  const remote = "/sdcard/farai_uidump.xml";
29609
- const dump = await runAdb(context, `${adbPrefix(serial)} shell uiautomator dump ${remote}`, 30000);
29610
- if (adbUnavailable(dump))
29611
- throw new Error("adb is not available in the container");
29604
+ const dump = await runAdbChecked(context, `${adbPrefix(serial)} shell uiautomator dump ${remote}`, 30000);
29612
29605
  const read = await runAdb(context, `${adbPrefix(serial)} shell cat ${remote}`, 20000, 8000000);
29613
29606
  const xml = read.stdout.trim();
29614
29607
  if (!xml.includes("<hierarchy") && !xml.includes("<node")) {
@@ -29650,7 +29643,7 @@ var init_ui = __esm(() => {
29650
29643
  renderModel: defaultModelRenderer,
29651
29644
  run: async (args, context) => {
29652
29645
  assertObject(args, "args");
29653
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29646
+ const serial = await resolveDevice(context, args.serial);
29654
29647
  const xml = await dumpHierarchy(context, serial);
29655
29648
  const all = parseUiNodes(xml);
29656
29649
  const clickableOnly = args.clickableOnly !== false;
@@ -29685,7 +29678,7 @@ var init_ui = __esm(() => {
29685
29678
  renderModel: defaultModelRenderer,
29686
29679
  run: async (args, context) => {
29687
29680
  assertObject(args, "args");
29688
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29681
+ const serial = await resolveDevice(context, args.serial);
29689
29682
  const xml = await dumpHierarchy(context, serial);
29690
29683
  return {
29691
29684
  ok: true,
@@ -29714,13 +29707,11 @@ var init_ui = __esm(() => {
29714
29707
  renderModel: defaultModelRenderer,
29715
29708
  run: async (args, context) => {
29716
29709
  assertObject(args, "args");
29717
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29710
+ const serial = await resolveDevice(context, args.serial);
29718
29711
  const remote = "/sdcard/farai_screen.png";
29719
29712
  const local = `android/screenshots/${Date.now()}.png`;
29720
29713
  await runAdb(context, `mkdir -p android/screenshots`, 1e4);
29721
- const cap = await runAdb(context, `${adbPrefix(serial)} shell screencap -p ${remote}`, 30000);
29722
- if (adbUnavailable(cap))
29723
- throw new Error("adb is not available in the container");
29714
+ const cap = await runAdbChecked(context, `${adbPrefix(serial)} shell screencap -p ${remote}`, 30000);
29724
29715
  const pull = await runAdb(context, `${adbPrefix(serial)} pull ${remote} ${shellQuote7(local)}`, 40000);
29725
29716
  const ok = pull.exitCode === 0;
29726
29717
  return {
@@ -29766,10 +29757,8 @@ var init_ui = __esm(() => {
29766
29757
  const y = Number(args.y);
29767
29758
  if (!Number.isInteger(x) || !Number.isInteger(y))
29768
29759
  throw new Error("x and y must be integers");
29769
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29770
- const result = await runAdb(context, `${adbPrefix(serial)} shell input tap ${x} ${y}`, 20000);
29771
- if (adbUnavailable(result))
29772
- throw new Error("adb is not available in the container");
29760
+ const serial = await resolveDevice(context, args.serial);
29761
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell input tap ${x} ${y}`, 20000);
29773
29762
  return {
29774
29763
  ok: result.exitCode === 0,
29775
29764
  summary: `tapped ${x},${y}`,
@@ -29824,7 +29813,7 @@ var init_ui = __esm(() => {
29824
29813
  };
29825
29814
  if (!selector.resourceId && !selector.text && !selector.contentDesc)
29826
29815
  throw new Error("provide at least one of resourceId, text, or contentDesc");
29827
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29816
+ const serial = await resolveDevice(context, args.serial);
29828
29817
  const xml = await dumpHierarchy(context, serial);
29829
29818
  const node = findUiNode(parseUiNodes(xml), selector);
29830
29819
  if (!node)
@@ -29875,11 +29864,9 @@ var init_ui = __esm(() => {
29875
29864
  run: async (args, context) => {
29876
29865
  assertObject(args, "args");
29877
29866
  const text2 = asString(args.text, "text");
29878
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29867
+ const serial = await resolveDevice(context, args.serial);
29879
29868
  const escaped = text2.replace(/(["\\$`])/g, "\\$1").replace(/ /g, "%s");
29880
- const result = await runAdb(context, `${adbPrefix(serial)} shell input text ${shellQuote7(escaped)}`, 20000);
29881
- if (adbUnavailable(result))
29882
- throw new Error("adb is not available in the container");
29869
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell input text ${shellQuote7(escaped)}`, 20000);
29883
29870
  return {
29884
29871
  ok: result.exitCode === 0,
29885
29872
  summary: `typed ${text2.length} char(s)`,
@@ -29938,11 +29925,9 @@ var init_ui = __esm(() => {
29938
29925
  if (coords.some((value) => !Number.isInteger(value)))
29939
29926
  throw new Error("x1, y1, x2, y2 must be integers");
29940
29927
  const duration = typeof args.durationMs === "number" && Number.isInteger(args.durationMs) ? Math.max(50, Math.min(1e4, args.durationMs)) : 300;
29941
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29928
+ const serial = await resolveDevice(context, args.serial);
29942
29929
  const [x1, y1, x2, y2] = coords;
29943
- const result = await runAdb(context, `${adbPrefix(serial)} shell input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`, 20000);
29944
- if (adbUnavailable(result))
29945
- throw new Error("adb is not available in the container");
29930
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`, 20000);
29946
29931
  return {
29947
29932
  ok: result.exitCode === 0,
29948
29933
  summary: `swiped ${x1},${y1} -> ${x2},${y2}`,
@@ -29995,10 +29980,8 @@ var init_ui = __esm(() => {
29995
29980
  const code = KEYEVENTS[key] ?? (/^\d+$/.test(key) ? Number(key) : undefined);
29996
29981
  if (code === undefined)
29997
29982
  throw new Error(`unknown key "${key}"; use a named key or a numeric keycode`);
29998
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
29999
- const result = await runAdb(context, `${adbPrefix(serial)} shell input keyevent ${code}`, 20000);
30000
- if (adbUnavailable(result))
30001
- throw new Error("adb is not available in the container");
29983
+ const serial = await resolveDevice(context, args.serial);
29984
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell input keyevent ${code}`, 20000);
30002
29985
  return {
30003
29986
  ok: result.exitCode === 0,
30004
29987
  summary: `sent key ${key} (${code})`,
@@ -30028,10 +30011,8 @@ var init_ui = __esm(() => {
30028
30011
  renderModel: defaultModelRenderer,
30029
30012
  run: async (args, context) => {
30030
30013
  assertObject(args, "args");
30031
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30032
- const result = await runAdb(context, `${adbPrefix(serial)} shell wm size`, 20000);
30033
- if (adbUnavailable(result))
30034
- throw new Error("adb is not available in the container");
30014
+ const serial = await resolveDevice(context, args.serial);
30015
+ const result = await runAdbChecked(context, `${adbPrefix(serial)} shell wm size`, 20000);
30035
30016
  const size = /(\d+)x(\d+)/.exec(result.stdout);
30036
30017
  return {
30037
30018
  ok: result.exitCode === 0,
@@ -30096,7 +30077,7 @@ var init_ui = __esm(() => {
30096
30077
  if (!selector.resourceId && !selector.text && !selector.contentDesc)
30097
30078
  throw new Error("provide at least one of resourceId, text, or contentDesc");
30098
30079
  const timeoutSeconds = typeof args.timeoutSeconds === "number" && Number.isInteger(args.timeoutSeconds) ? Math.max(1, Math.min(120, args.timeoutSeconds)) : 15;
30099
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30080
+ const serial = await resolveDevice(context, args.serial);
30100
30081
  const deadline = Date.now() + timeoutSeconds * 1000;
30101
30082
  let attempts = 0;
30102
30083
  while (Date.now() < deadline) {
@@ -30381,7 +30362,7 @@ var init_frida = __esm(() => {
30381
30362
  renderModel: defaultModelRenderer,
30382
30363
  run: async (args, context) => {
30383
30364
  assertObject(args, "args");
30384
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30365
+ const serial = await resolveDevice(context, args.serial);
30385
30366
  const version = await backend(context).exec("frida --version 2>/dev/null || true", 15000, context.signal);
30386
30367
  const fridaTools = version.stdout.trim();
30387
30368
  const binary = await runAdb(context, `${adbPrefix(serial)} shell ls ${DEVICE_SERVER_PATH} 2>/dev/null`, 15000);
@@ -30429,7 +30410,7 @@ var init_frida = __esm(() => {
30429
30410
  const requested = typeof args.version === "string" && args.version.trim() ? args.version.trim() : "";
30430
30411
  if (requested && !/^\d+(\.\d+){1,3}$/.test(requested))
30431
30412
  throw new Error("version must look like 16.5.9");
30432
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30413
+ const serial = await resolveDevice(context, args.serial);
30433
30414
  const steps = [];
30434
30415
  let version = (await backend(context).exec("frida --version 2>/dev/null", 15000, context.signal)).stdout.trim();
30435
30416
  if (requested || !version) {
@@ -30449,9 +30430,7 @@ var init_frida = __esm(() => {
30449
30430
  serial
30450
30431
  }
30451
30432
  };
30452
- const abiResult = await runAdb(context, `${adbPrefix(serial)} shell getprop ro.product.cpu.abi`, 15000);
30453
- if (adbUnavailable(abiResult))
30454
- throw new Error("adb is not available in the container");
30433
+ const abiResult = await runAdbChecked(context, `${adbPrefix(serial)} shell getprop ro.product.cpu.abi`, 15000);
30455
30434
  const abi = abiResult.stdout.trim().replace(/\r/g, "");
30456
30435
  const arch = ABI_MAP[abi];
30457
30436
  if (!arch)
@@ -30511,7 +30490,7 @@ var init_frida = __esm(() => {
30511
30490
  renderModel: defaultModelRenderer,
30512
30491
  run: async (args, context) => {
30513
30492
  assertObject(args, "args");
30514
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30493
+ const serial = await resolveDevice(context, args.serial);
30515
30494
  const listFlag = args.applicationsOnly === true ? "-ai" : "-a";
30516
30495
  const deviceFlag = `-D ${shellQuote7(serial)}`;
30517
30496
  const result = await backend(context).exec(`${adbEnvPrefix()}frida-ps ${listFlag} ${deviceFlag} 2>&1`, 40000, context.signal);
@@ -30573,7 +30552,7 @@ var init_frida = __esm(() => {
30573
30552
  const target = asString(args.target, "target").trim();
30574
30553
  const mode = args.mode === "spawn" ? "spawn" : "attach";
30575
30554
  const durationSeconds = typeof args.durationSeconds === "number" && Number.isInteger(args.durationSeconds) ? Math.max(1, Math.min(600, args.durationSeconds)) : 15;
30576
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30555
+ const serial = await resolveDevice(context, args.serial);
30577
30556
  await writeAsset(context, RUNNER_PATH, FRIDA_RUNNER);
30578
30557
  const command = fridaRunCommand(serial, mode, target, scriptPath, durationSeconds);
30579
30558
  if (args.background === true) {
@@ -30650,7 +30629,7 @@ ${messages.map((m) => JSON.stringify(m)).join(`
30650
30629
  throw new Error(`unknown bypass type: ${type}; use ssl or root`);
30651
30630
  const pkg = asString(args.package, "package").trim();
30652
30631
  const durationSeconds = typeof args.durationSeconds === "number" && Number.isInteger(args.durationSeconds) ? Math.max(1, Math.min(600, args.durationSeconds)) : 30;
30653
- const serial = await resolveDevice(context, typeof args.serial === "string" ? args.serial : undefined);
30632
+ const serial = await resolveDevice(context, args.serial);
30654
30633
  const scriptPath = `${ASSET_DIR}/scripts/bypass_${type}.js`;
30655
30634
  await writeAsset(context, RUNNER_PATH, FRIDA_RUNNER);
30656
30635
  await writeAsset(context, scriptPath, script);
@@ -32484,7 +32463,7 @@ function normalizeModelsDevProviderHint(providerID, profile) {
32484
32463
  if (providerID !== DEFAULT_PROVIDER_ID)
32485
32464
  return providerID;
32486
32465
  if (!profile && resolveModel().baseUrl === DEFAULT_MODEL_BASE_URL)
32487
- return DEFAULT_SOURCE_PROVIDER_ID;
32466
+ return DEFAULT_MODEL_PROVIDER_ID;
32488
32467
  return;
32489
32468
  }
32490
32469
  function readRecentModelSelections() {
@@ -32961,7 +32940,7 @@ function ensureConcrete(resolved) {
32961
32940
  function modelsDevCachePath() {
32962
32941
  return join18(globalDataDir(), "cache", "models-dev.json");
32963
32942
  }
32964
- var DEFAULT_PROVIDER_ID = "default", DEFAULT_SOURCE_PROVIDER_ID, MODELS_DEV_URL = "https://models.dev/api.json", MODELS_DEV_CACHE_TTL_MS, MODELS_DEV_STALE_TTL_MS, MODELS_DEV_FETCH_TIMEOUT_MS = 4000, MODELS_DEV_MAX_BYTES, RECENT_MODEL_LIMIT = 12, modelsDevRefreshes;
32943
+ var DEFAULT_PROVIDER_ID = "default", MODELS_DEV_URL = "https://models.dev/api.json", MODELS_DEV_CACHE_TTL_MS, MODELS_DEV_STALE_TTL_MS, MODELS_DEV_FETCH_TIMEOUT_MS = 4000, MODELS_DEV_MAX_BYTES, RECENT_MODEL_LIMIT = 12, modelsDevRefreshes;
32965
32944
  var init_model_catalog = __esm(() => {
32966
32945
  init_default_model();
32967
32946
  init_global_config();
@@ -32973,7 +32952,6 @@ var init_model_catalog = __esm(() => {
32973
32952
  init_file_read();
32974
32953
  init_atomic_file();
32975
32954
  init_private_path();
32976
- DEFAULT_SOURCE_PROVIDER_ID = DEFAULT_MODEL_PROVIDER_ID;
32977
32955
  MODELS_DEV_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
32978
32956
  MODELS_DEV_STALE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
32979
32957
  MODELS_DEV_MAX_BYTES = 16 * 1024 * 1024;
@@ -44980,6 +44958,17 @@ var init_runtime = __esm(() => {
44980
44958
 
44981
44959
  // src/branding.ts
44982
44960
  import figlet from "figlet";
44961
+ function printBannerOnce() {
44962
+ if (bannerPrinted)
44963
+ return;
44964
+ bannerPrinted = true;
44965
+ console.log(FARAI_BANNER);
44966
+ }
44967
+ function clearBannerIfShown() {
44968
+ if (!bannerPrinted || !process.stdout.isTTY)
44969
+ return;
44970
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
44971
+ }
44983
44972
  function renderFaraiBanner() {
44984
44973
  try {
44985
44974
  return figlet.textSync("farai", {
@@ -44989,7 +44978,7 @@ function renderFaraiBanner() {
44989
44978
  return "farai";
44990
44979
  }
44991
44980
  }
44992
- var FARAI_BANNER, FARAI_BANNER_LINES;
44981
+ var FARAI_BANNER, FARAI_BANNER_LINES, bannerPrinted = false;
44993
44982
  var init_branding = __esm(() => {
44994
44983
  FARAI_BANNER = renderFaraiBanner();
44995
44984
  FARAI_BANNER_LINES = FARAI_BANNER.split(`
@@ -45834,6 +45823,7 @@ async function runStartupContentPreflight(workspace) {
45834
45823
  }
45835
45824
  async function promptForUpdate(version, knowledge, skills) {
45836
45825
  const contents = [knowledge ? "knowledge" : undefined, skills ? "skills" : undefined].filter(Boolean).join(" + ");
45826
+ printBannerOnce();
45837
45827
  console.log("");
45838
45828
  console.log(`farai content ${version} is available${contents ? ` (${contents})` : ""}`);
45839
45829
  const interfaceHandle = createInterface({
@@ -45888,6 +45878,7 @@ function errorMessage7(error) {
45888
45878
  return error instanceof Error ? error.message : String(error);
45889
45879
  }
45890
45880
  var init_preflight = __esm(() => {
45881
+ init_branding();
45891
45882
  init_config();
45892
45883
  init_updater();
45893
45884
  });
@@ -45925,6 +45916,7 @@ async function runStartupContainerPreflight(workspace) {
45925
45916
  return "continue";
45926
45917
  }
45927
45918
  async function promptForImagePull(exists) {
45919
+ printBannerOnce();
45928
45920
  console.log("");
45929
45921
  console.log(exists ? "a newer kali container image is available" : "kali container image is not installed");
45930
45922
  const interfaceHandle = createInterface2({
@@ -45959,6 +45951,7 @@ async function spawnPull() {
45959
45951
  return await proc.exited;
45960
45952
  }
45961
45953
  var init_preflight2 = __esm(() => {
45954
+ init_branding();
45962
45955
  init_config();
45963
45956
  init_docker_environment();
45964
45957
  init_kali();
@@ -46157,20 +46150,23 @@ function readSignal() {
46157
46150
  }
46158
46151
  }
46159
46152
  if (Listener) {
46160
- const sSlot = this.observers ? this.observers.length : 0;
46161
- if (!Listener.sources) {
46162
- Listener.sources = [this];
46163
- Listener.sourceSlots = [sSlot];
46164
- } else {
46165
- Listener.sources.push(this);
46166
- Listener.sourceSlots.push(sSlot);
46167
- }
46168
- if (!this.observers) {
46169
- this.observers = [Listener];
46170
- this.observerSlots = [Listener.sources.length - 1];
46171
- } else {
46172
- this.observers.push(Listener);
46173
- this.observerSlots.push(Listener.sources.length - 1);
46153
+ const observers = this.observers;
46154
+ if (!observers || observers[observers.length - 1] !== Listener) {
46155
+ const sSlot = observers ? observers.length : 0;
46156
+ if (!Listener.sources) {
46157
+ Listener.sources = [this];
46158
+ Listener.sourceSlots = [sSlot];
46159
+ } else {
46160
+ Listener.sources.push(this);
46161
+ Listener.sourceSlots.push(sSlot);
46162
+ }
46163
+ if (!observers) {
46164
+ this.observers = [Listener];
46165
+ this.observerSlots = [Listener.sources.length - 1];
46166
+ } else {
46167
+ observers.push(Listener);
46168
+ this.observerSlots.push(Listener.sources.length - 1);
46169
+ }
46174
46170
  }
46175
46171
  }
46176
46172
  if (runningTransition && Transition.sources.has(this))
@@ -46316,10 +46312,13 @@ function createComputation(fn, init, pure, state = STALE, options) {
46316
46312
  const ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
46317
46313
  onCleanup(() => ordinary.dispose());
46318
46314
  let inTransition;
46315
+ let trackedOrdinary = false;
46319
46316
  const triggerInTransition = () => startTransition(trigger).then(() => {
46320
46317
  if (inTransition) {
46321
46318
  inTransition.dispose();
46322
46319
  inTransition = undefined;
46320
+ if (!trackedOrdinary)
46321
+ trigger();
46323
46322
  }
46324
46323
  });
46325
46324
  c.fn = (x) => {
@@ -46329,6 +46328,7 @@ function createComputation(fn, init, pure, state = STALE, options) {
46329
46328
  inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition);
46330
46329
  return inTransition.track(x);
46331
46330
  }
46331
+ trackedOrdinary = true;
46332
46332
  return ordinary.track(x);
46333
46333
  };
46334
46334
  }
@@ -46609,7 +46609,15 @@ function resolveChildren(children2) {
46609
46609
  const results = [];
46610
46610
  for (let i = 0;i < children2.length; i++) {
46611
46611
  const result = resolveChildren(children2[i]);
46612
- Array.isArray(result) ? results.push.apply(results, result) : results.push(result);
46612
+ if (Array.isArray(result)) {
46613
+ if (result.length < 32768)
46614
+ results.push.apply(results, result);
46615
+ else
46616
+ for (let j = 0;j < result.length; j++)
46617
+ results.push(result[j]);
46618
+ } else {
46619
+ results.push(result);
46620
+ }
46613
46621
  }
46614
46622
  return results;
46615
46623
  }
@@ -46877,16 +46885,18 @@ function splitProps(props, ...keys) {
46877
46885
  const len = keys.length;
46878
46886
  if (SUPPORTS_PROXY && $PROXY in props) {
46879
46887
  const blocked = len > 1 ? keys.flat() : keys[0];
46888
+ const claimed = new Set;
46880
46889
  const res = keys.map((k) => {
46890
+ const owned = k.filter((property) => !claimed.has(property) && (claimed.add(property), true));
46881
46891
  return new Proxy({
46882
46892
  get(property) {
46883
- return k.includes(property) ? props[property] : undefined;
46893
+ return owned.includes(property) ? props[property] : undefined;
46884
46894
  },
46885
46895
  has(property) {
46886
- return k.includes(property) && property in props;
46896
+ return owned.includes(property) && property in props;
46887
46897
  },
46888
46898
  keys() {
46889
- return k.filter((property) => (property in props));
46899
+ return owned.filter((property) => (property in props));
46890
46900
  }
46891
46901
  }, propTraps);
46892
46902
  });
@@ -48178,11 +48188,20 @@ function wrap$1(value) {
48178
48188
  value: p = new Proxy(value, proxyTraps$1)
48179
48189
  });
48180
48190
  if (!Array.isArray(value)) {
48181
- const keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value);
48191
+ const keys = Object.keys(value), desc = Object.getOwnPropertyDescriptors(value), proto = Object.getPrototypeOf(value);
48192
+ const isClass = proto !== null && value !== null && typeof value === "object" && !Array.isArray(value) && proto !== Object.prototype;
48193
+ if (isClass) {
48194
+ const descriptors = Object.getOwnPropertyDescriptors(proto);
48195
+ keys.push(...Object.keys(descriptors));
48196
+ Object.assign(desc, descriptors);
48197
+ }
48182
48198
  for (let i = 0, l = keys.length;i < l; i++) {
48183
48199
  const prop = keys[i];
48200
+ if (isClass && prop === "constructor")
48201
+ continue;
48184
48202
  if (desc[prop].get) {
48185
48203
  Object.defineProperty(value, prop, {
48204
+ configurable: true,
48186
48205
  enumerable: desc[prop].enumerable,
48187
48206
  get: desc[prop].get.bind(p)
48188
48207
  });
@@ -48264,6 +48283,9 @@ function ownKeys(target) {
48264
48283
  return Reflect.ownKeys(target);
48265
48284
  }
48266
48285
  function setProperty(state, property, value, deleting = false) {
48286
+ if (property === "__proto__") {
48287
+ return;
48288
+ }
48267
48289
  if (!deleting && state[property] === value)
48268
48290
  return;
48269
48291
  const prev = state[property], len = state.length;
@@ -48290,9 +48312,14 @@ function mergeStoreNode(state, value) {
48290
48312
  const keys = Object.keys(value);
48291
48313
  for (let i = 0;i < keys.length; i += 1) {
48292
48314
  const key = keys[i];
48315
+ if (isUnsafeKey$1(key))
48316
+ continue;
48293
48317
  setProperty(state, key, value[key]);
48294
48318
  }
48295
48319
  }
48320
+ function isUnsafeKey$1(property) {
48321
+ return property === "__proto__" || property === "constructor" || property === "prototype";
48322
+ }
48296
48323
  function updateArray(current, next) {
48297
48324
  if (typeof next === "function")
48298
48325
  next = next(current);
@@ -48315,6 +48342,9 @@ function updatePath(current, path, traversed = []) {
48315
48342
  if (path.length > 1) {
48316
48343
  part = path.shift();
48317
48344
  const partType = typeof part, isArray = Array.isArray(current);
48345
+ if (partType === "string" && (part === "__proto__" || path.length > 1 && isUnsafeKey$1(part))) {
48346
+ return;
48347
+ }
48318
48348
  if (Array.isArray(part)) {
48319
48349
  for (let i = 0;i < part.length; i++) {
48320
48350
  updatePath(current, [part[i]].concat(path), traversed);
@@ -48368,7 +48398,12 @@ function createStore(...[store, options]) {
48368
48398
  }
48369
48399
  return [wrappedStore, setStore];
48370
48400
  }
48401
+ function isUnsafeKey(property) {
48402
+ return property === "__proto__" || property === "constructor" || property === "prototype";
48403
+ }
48371
48404
  function applyState(target, parent, property, merge, key) {
48405
+ if (isUnsafeKey(property))
48406
+ return;
48372
48407
  const previous = parent[property];
48373
48408
  if (target === previous)
48374
48409
  return;
@@ -48434,6 +48469,8 @@ function applyState(target, parent, property, merge, key) {
48434
48469
  }
48435
48470
  const targetKeys = Object.keys(target);
48436
48471
  for (let i = 0, len = targetKeys.length;i < len; i++) {
48472
+ if (isUnsafeKey(targetKeys[i]))
48473
+ continue;
48437
48474
  applyState(target[targetKeys[i]], previous, targetKeys[i], merge, key);
48438
48475
  }
48439
48476
  const previousKeys = Object.keys(previous);
@@ -48492,7 +48529,7 @@ var init_store2 = __esm(() => {
48492
48529
  return value;
48493
48530
  if (!tracked) {
48494
48531
  const desc = Object.getOwnPropertyDescriptor(target, property);
48495
- if (getListener() && (typeof value !== "function" || target.hasOwnProperty(property)) && !(desc && desc.get))
48532
+ if (getListener() && (typeof value !== "function" || Object.prototype.hasOwnProperty.call(target, property)) && !(desc && desc.get))
48496
48533
  value = getNode(nodes, property, value)();
48497
48534
  }
48498
48535
  return isWrappable(value) ? wrap$1(value) : value;
@@ -48519,6 +48556,8 @@ var init_store2 = __esm(() => {
48519
48556
  if (property === $RAW)
48520
48557
  return target;
48521
48558
  const value = target[property];
48559
+ if (property === $PROXY || property === $TRACK || property === $NODE || property === $HAS || property === "__proto__")
48560
+ return value;
48522
48561
  let proxy;
48523
48562
  return isWrappable(value) ? producers.get(value) || (producers.set(value, proxy = new Proxy(value, setterTraps)), proxy) : value;
48524
48563
  },
@@ -67982,7 +68021,7 @@ function footerRightItems(backgroundActivities, subagents, browserContexts, queu
67982
68021
  items.push({
67983
68022
  id: "update",
67984
68023
  kind: "update",
67985
- text: `update ${updateNotice.latestVersion}`
68024
+ text: `update available ${updateNotice.latestVersion}`
67986
68025
  });
67987
68026
  }
67988
68027
  if (contextUsage && contextUsage.tokens >= 0) {
@@ -76193,7 +76232,6 @@ async function initLab(args2) {
76193
76232
  }
76194
76233
  async function launchTui(workspace, sessionId) {
76195
76234
  ensureDefaultUserConfig();
76196
- console.log(FARAI_BANNER);
76197
76235
  const {
76198
76236
  runStartupContentPreflight: runStartupContentPreflight2
76199
76237
  } = await Promise.resolve().then(() => (init_preflight(), exports_preflight));
@@ -76209,6 +76247,7 @@ async function launchTui(workspace, sessionId) {
76209
76247
  process.exitCode = 130;
76210
76248
  return;
76211
76249
  }
76250
+ clearBannerIfShown();
76212
76251
  if (import.meta.path.endsWith(".ts")) {
76213
76252
  const sourceTuiPreload = "@opentui/solid/preload";
76214
76253
  await import(sourceTuiPreload);
@@ -76422,5 +76461,5 @@ Examples:
76422
76461
  `);
76423
76462
  }
76424
76463
 
76425
- //# debugId=321574D9A553E4CA64756E2164756E21
76464
+ //# debugId=63285462E91F7E5864756E2164756E21
76426
76465
  //# sourceMappingURL=index.js.map