adb-ready 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,33 @@ deprecation policy in [Stability and versioning](./docs/stability.md).
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [1.0.4] - 2026-10-04
13
+
14
+ ### Added
15
+
16
+ - Add GitHub Sponsors repository metadata and npm funding metadata so users can
17
+ discover the supported funding path from GitHub and `npm fund`.
18
+
19
+ ### Changed
20
+
21
+ - Surface a dedicated Sponsor action directly below the technical badges on
22
+ the GitHub and npm landing pages while retaining the detailed section below.
23
+
24
+ ## [1.0.3] - 2026-10-01
25
+
26
+ ### Fixed
27
+
28
+ - Allow large APK and split-APK installs up to five minutes by default instead
29
+ of inheriting the five-second probe timeout, while preserving an explicit
30
+ `--timeout` override.
31
+ - Recover the same remembered wireless target for `--last` after a local ADB
32
+ server restart or Wireless debugging port rotation, verifying hardware
33
+ identity before accepting a newly advertised endpoint.
34
+ - Explain when foreground launch verification is blocked by the Android lock
35
+ screen instead of returning only a generic launch-postcondition failure.
36
+ - Isolate runtime-smoke remembered-target state so repository verification can
37
+ never overwrite a developer's real `--last` target with a fixture device.
38
+
12
39
  ## [1.0.2] - 2026-09-30
13
40
 
14
41
  ### Changed
@@ -551,7 +578,9 @@ deprecation policy in [Stability and versioning](./docs/stability.md).
551
578
  explainable configuration precedence.
552
579
  - Human, plain, JSON, and NDJSON output across Node, Bun, and Deno entrypoints.
553
580
 
554
- [Unreleased]: https://github.com/Adam014/adb-ready/compare/v1.0.2...HEAD
581
+ [Unreleased]: https://github.com/Adam014/adb-ready/compare/v1.0.4...HEAD
582
+ [1.0.4]: https://github.com/Adam014/adb-ready/compare/v1.0.3...v1.0.4
583
+ [1.0.3]: https://github.com/Adam014/adb-ready/compare/v1.0.2...v1.0.3
555
584
  [1.0.2]: https://github.com/Adam014/adb-ready/compare/v1.0.1...v1.0.2
556
585
  [1.0.1]: https://github.com/Adam014/adb-ready/compare/v1.0.0...v1.0.1
557
586
  [1.0.0]: https://github.com/Adam014/adb-ready/compare/v0.9.0...v1.0.0
package/README.md CHANGED
@@ -21,6 +21,8 @@ verified evidence—for developers, agents, and CI.
21
21
  [![Capacitor](https://img.shields.io/badge/Capacitor-supported-119EFF?logo=capacitor&logoColor=white)](./docs/dev-sessions.md)
22
22
  [![Platforms](https://img.shields.io/badge/hosts-macOS_%C2%B7_Linux_%C2%B7_Windows-64748b)](./COMPATIBILITY.md)
23
23
 
24
+ [![Sponsor ADB Ready](https://img.shields.io/badge/Sponsor-ADB_Ready-EA4AAA?style=for-the-badge&logo=githubsponsors&logoColor=white)](https://github.com/sponsors/Adam014)
25
+
24
26
  [Quick start](#quick-start) · [What it does](#what-adb-ready-does) ·
25
27
  [AI agents](#with-a-coding-agent) · [CI](#in-ci-and-automation) ·
26
28
  [Documentation](#documentation)
@@ -307,6 +309,14 @@ Android transport backend.
307
309
  Run `adb-ready --help` for the complete command list or
308
310
  `adb-ready help COMMAND` for focused options.
309
311
 
312
+ ## Sponsors
313
+
314
+ ADB Ready is independently developed and maintained. Sponsorship helps fund
315
+ compatibility testing, real-device validation, CI, documentation, and reliable
316
+ releases.
317
+
318
+ [Sponsor ADB Ready and my open-source work →](https://github.com/sponsors/Adam014)
319
+
310
320
  ## Project
311
321
 
312
322
  [Changelog](./CHANGELOG.md) · [Contributing](./CONTRIBUTING.md) ·
package/dist/cli.js CHANGED
@@ -3304,7 +3304,7 @@ import process15 from "node:process";
3304
3304
  // package.json
3305
3305
  var package_default = {
3306
3306
  name: "adb-ready",
3307
- version: "1.0.2",
3307
+ version: "1.0.4",
3308
3308
  description: "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
3309
3309
  private: false,
3310
3310
  type: "module",
@@ -3363,6 +3363,7 @@ var package_default = {
3363
3363
  url: "https://github.com/Adam014/adb-ready/issues"
3364
3364
  },
3365
3365
  homepage: "https://github.com/Adam014/adb-ready#readme",
3366
+ funding: "https://github.com/sponsors/Adam014",
3366
3367
  author: {
3367
3368
  name: "Adam Stádník",
3368
3369
  email: "adam.stadnik@seznam.cz",
@@ -45756,6 +45757,7 @@ async function runDev(options, config4 = {}, dependencies = {}, signal) {
45756
45757
  }
45757
45758
 
45758
45759
  // src/app/app-commands.ts
45760
+ var DEFAULT_APP_INSTALL_TIMEOUT_MS = 5 * 60000;
45759
45761
  function plannedArgs(ready, config4, args) {
45760
45762
  return [
45761
45763
  ...config4.adbHost === undefined ? [] : ["-H", config4.adbHost],
@@ -46030,7 +46032,9 @@ async function launchApp(ready, applicationId, explicitActivity, commandId, prob
46030
46032
  }
46031
46033
  const activeValue = active?.value;
46032
46034
  if (active === undefined || !succeeded(active.process) || activeValue?.applicationId !== applicationId) {
46033
- problems.push(problem("APP_LAUNCH_UNVERIFIED", "app.lifecycle", `${applicationId} did not become the foreground app.`, "ADB accepted the launch request, but the foreground postcondition was not met.", commandId, [
46035
+ const lockState = await ready.client.targetCommand(ready.target, "app-launch-lock-state", "Reading Android lock-screen state after launch", ["shell", "dumpsys", "window", "policy"], parseAndroidLockState, signal, { maxBufferBytes: 4 * 1024 * 1024 });
46036
+ const targetIsLocked = succeeded(lockState.process) && lockState.value === "locked";
46037
+ problems.push(problem("APP_LAUNCH_UNVERIFIED", "app.lifecycle", `${applicationId} did not become the foreground app.`, targetIsLocked ? "ADB launched the app, but Android is locked. Unlock the selected target, then retry." : "ADB accepted the launch request, but the foreground postcondition was not met.", commandId, [
46034
46038
  {
46035
46039
  source: "adb.activity",
46036
46040
  field: "foreground",
@@ -46038,7 +46042,14 @@ async function launchApp(ready, applicationId, explicitActivity, commandId, prob
46038
46042
  applicationId: activeValue.applicationId,
46039
46043
  activity: activeValue.activity
46040
46044
  }
46041
- }
46045
+ },
46046
+ ...targetIsLocked ? [
46047
+ {
46048
+ source: "adb.window-policy",
46049
+ field: "lockState",
46050
+ value: "locked"
46051
+ }
46052
+ ] : []
46042
46053
  ]));
46043
46054
  return;
46044
46055
  }
@@ -46148,7 +46159,9 @@ async function runApp(request, config4 = {}, dependencies = {}, signal) {
46148
46159
  ...request.replace === true ? ["-r"] : [],
46149
46160
  ...request.grantRuntimePermissions === true ? ["-g"] : [],
46150
46161
  ...artifacts
46151
- ], (output) => output.trim(), signal);
46162
+ ], (output) => output.trim(), signal, {
46163
+ ...config4.timeoutWasDefault === true ? { timeoutMs: DEFAULT_APP_INSTALL_TIMEOUT_MS } : config4.timeoutMs === undefined ? {} : { timeoutMs: config4.timeoutMs }
46164
+ });
46152
46165
  if (!succeeded(installed.process) || !/\bSuccess\b/u.test(installed.value)) {
46153
46166
  problems.push(operationProblem("app-install", installed, current.commandId));
46154
46167
  return finish2(current, null, problems);
@@ -50569,6 +50582,7 @@ function commandConfig(loaded, bound, selector, transportId) {
50569
50582
  ...values.adbHost === undefined ? {} : { adbHost: values.adbHost },
50570
50583
  ...values.adbPort === undefined ? {} : { adbPort: values.adbPort },
50571
50584
  timeoutMs: values.timeoutMs,
50585
+ timeoutWasDefault: loaded.provenance.timeoutMs?.source === "default",
50572
50586
  uiTimeoutMs: loaded.provenance.timeoutMs?.source === "default" ? 15000 : values.timeoutMs,
50573
50587
  ...values.targetAliases === undefined ? {} : { targetAliases: values.targetAliases },
50574
50588
  ...bound?.transportId !== undefined ? { targetTransportId: bound.transportId } : bound !== undefined ? { targetSelector: bound.serial } : transportId !== undefined ? { targetTransportId: transportId } : selector === undefined ? {} : { targetSelector: selector }
@@ -60772,6 +60786,7 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60772
60786
  ...values2.adbHost === undefined ? {} : { adbHost: values2.adbHost },
60773
60787
  ...values2.adbPort === undefined ? {} : { adbPort: values2.adbPort },
60774
60788
  timeoutMs: values2.timeoutMs,
60789
+ timeoutWasDefault: loaded.config.provenance.timeoutMs?.source === "default",
60775
60790
  uiTimeoutMs: loaded.config.provenance.timeoutMs?.source === "default" ? 15000 : values2.timeoutMs,
60776
60791
  ...options.device === undefined ? {} : { targetSelector: options.device },
60777
60792
  ...options.transportId === undefined ? {} : { targetTransportId: options.transportId },
@@ -60922,16 +60937,42 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60922
60937
  }
60923
60938
  const offlineDevPlan = (options.command === "dev" || options.command === "run") && options.dryRun;
60924
60939
  let preparedSelection;
60925
- if (options.command === "app" && (options.appAction !== "resolve" || options.select) || options.command === "apps" || options.command === "capture" || (options.command === "dev" || options.command === "run") && !offlineDevPlan || options.command === "inspect" || options.command === "logs" || options.command === "open" || options.command === "ui" || options.command === "ports") {
60940
+ if (options.command === "app" && (options.appAction !== "resolve" || options.select) || options.command === "apps" || options.command === "capture" || options.command === "devices" && options.remembered || (options.command === "dev" || options.command === "run") && !offlineDevPlan || options.command === "inspect" || options.command === "logs" || options.command === "open" || options.command === "ui" || options.command === "ports") {
60926
60941
  let inventory = await runDevices(config4, commandDependencies, signal);
60927
60942
  let selectable = inventory.result.data?.targets.filter((target) => target.transports.some(({ stable, state }) => stable && state === "device")) ?? [];
60928
- if ((options.command === "dev" || options.command === "run") && selectable.length === 0 && !options.dryRun) {
60929
- const acquisition = planTargetAcquisition({
60943
+ if ((options.command === "dev" || options.command === "run" || options.remembered) && selectable.length === 0 && !options.dryRun) {
60944
+ let acquisition = planTargetAcquisition({
60930
60945
  ...config4.targetSelector === undefined ? {} : { selector: config4.targetSelector },
60931
60946
  ...values2.targetAliases === undefined ? {} : { aliases: values2.targetAliases },
60932
60947
  ...lastTarget === undefined ? {} : { remembered: lastTarget },
60933
60948
  services: inventory.result.data?.discovery.mdns.services ?? []
60934
60949
  });
60950
+ if (acquisition.kind === "ambiguous" && options.remembered && lastTarget?.hardwareSerial !== undefined) {
60951
+ const services = inventory.result.data?.discovery.mdns.services ?? [];
60952
+ const endpoints = [
60953
+ ...new Set(services.flatMap((service) => (service.serviceType === "legacy" || service.serviceType === "connect" && service.knownDevice !== false) && service.endpoint.version === 4 ? [service.endpoint.serial] : []))
60954
+ ];
60955
+ for (const candidate of endpoints) {
60956
+ const verified = await runConnect(candidate, {
60957
+ ...config4,
60958
+ endpointWasDiscovered: true,
60959
+ discoveredEndpointCandidates: [candidate]
60960
+ }, commandDependencies, signal);
60961
+ const data = verified.result.data;
60962
+ if (verified.result.ok && data !== null && "serial" in data && data.hardwareSerial === lastTarget.hardwareSerial) {
60963
+ acquisition = {
60964
+ kind: "connect",
60965
+ endpoint: data.serial,
60966
+ candidates: [data.serial],
60967
+ discovered: true,
60968
+ reason: "remembered-identity"
60969
+ };
60970
+ break;
60971
+ }
60972
+ if (signal?.aborted === true)
60973
+ break;
60974
+ }
60975
+ }
60935
60976
  if (acquisition.kind === "connect") {
60936
60977
  const connected = await runConnect(acquisition.endpoint, acquisition.discovered ? {
60937
60978
  ...config4,
@@ -60974,11 +61015,13 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60974
61015
  } else {
60975
61016
  preparedSelection = selected2.result.data.selected;
60976
61017
  const transport = preparedSelection.transport;
60977
- if (options.avdName !== undefined || transport.transportId === undefined) {
60978
- config4.targetSelector = transport.serial;
60979
- delete config4.targetTransportId;
60980
- } else {
60981
- config4.targetTransportId = transport.transportId;
61018
+ if (options.command !== "devices") {
61019
+ if (options.avdName !== undefined || transport.transportId === undefined) {
61020
+ config4.targetSelector = transport.serial;
61021
+ delete config4.targetTransportId;
61022
+ } else {
61023
+ config4.targetTransportId = transport.transportId;
61024
+ }
60982
61025
  }
60983
61026
  }
60984
61027
  }
@@ -61628,4 +61671,4 @@ try {
61628
61671
  process16.removeListener("SIGTERM", abort);
61629
61672
  }
61630
61673
 
61631
- //# debugId=EEFE4EA2C406032664756E2164756E21
61674
+ //# debugId=E6D58EBBDFCFA90A64756E2164756E21
@@ -66,8 +66,14 @@ created them, then pass those `.apk` files explicitly.
66
66
 
67
67
  - Installation accepts one ordinary APK or an explicit complete split APK set.
68
68
  `.apks`, `.aab`, and implicit downloads are not accepted yet.
69
+ - APK installation allows up to five minutes by default so large artifacts can
70
+ cross a real wireless ADB connection. An explicit global `--timeout` still
71
+ overrides that installation default.
69
72
  - Install, launch, stop, restart, and explicit deep-link handlers are checked
70
73
  after ADB accepts the request.
74
+ - When Android accepts a launch but the selected target remains behind its lock
75
+ screen, ADB Ready reports the locked state and asks you to unlock and retry;
76
+ it never attempts to bypass the device lock.
71
77
  - `restart` is a verified stop followed by a verified launch.
72
78
  - Add `--activity .MainActivity` only when Android cannot resolve a launchable
73
79
  activity.
@@ -31,6 +31,12 @@ adb-ready devices --last
31
31
  `--device` accepts an exact ADB serial or a configured alias. `--transport-id`
32
32
  disambiguates duplicate transports. `--last` resolves the last verified target
33
33
  identity; it does not silently choose an unrelated visible device.
34
+ If a local ADB server restart drops the stable wireless transport, `--last`
35
+ first reconnects the exact remembered endpoint when discovery still advertises
36
+ it, then verifies the target again. If Wireless debugging rotates the endpoint,
37
+ ADB Ready probes only already-known connect services and accepts a replacement
38
+ only after its hardware identity matches the remembered target. It never
39
+ substitutes an unrelated device.
34
40
 
35
41
  An exact serial, serial-backed alias, or transport ID also bounds target-side
36
42
  identity inspection to that transport. ADB Ready does not query unrelated
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adb-ready",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -59,6 +59,7 @@
59
59
  "url": "https://github.com/Adam014/adb-ready/issues"
60
60
  },
61
61
  "homepage": "https://github.com/Adam014/adb-ready#readme",
62
+ "funding": "https://github.com/sponsors/Adam014",
62
63
  "author": {
63
64
  "name": "Adam Stádník",
64
65
  "email": "adam.stadnik@seznam.cz",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "title": "ADB Ready agent tool contract",
3
3
  "schemaVersion": 1,
4
- "packageVersion": "1.0.2",
4
+ "packageVersion": "1.0.4",
5
5
  "protocolVersion": "2025-11-25",
6
6
  "transport": "stdio",
7
7
  "tools": [
@@ -3,7 +3,7 @@ name: adb-ready
3
3
  description: Prepare, automate, debug, and verify one Android target through the ADB Ready MCP server. Use for Android development sessions, app lifecycle work, UI automation, failure evidence, screenshots, and agent-driven device checks.
4
4
  ---
5
5
 
6
- <!-- Generated by adb-ready 1.0.2; do not edit. -->
6
+ <!-- Generated by adb-ready 1.0.4; do not edit. -->
7
7
 
8
8
  # ADB Ready
9
9
 
@@ -51,4 +51,4 @@ Use the typed `adb-ready` MCP tools. Do not replace them with generic shell or r
51
51
  - `session`: 12 tools
52
52
  - `ui`: 29 tools
53
53
 
54
- Contract: ADB Ready 1.0.2, agent schema v1.
54
+ Contract: ADB Ready 1.0.4, agent schema v1.