adb-ready 1.0.2 → 1.0.3

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,21 @@ deprecation policy in [Stability and versioning](./docs/stability.md).
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [1.0.3] - 2026-10-01
13
+
14
+ ### Fixed
15
+
16
+ - Allow large APK and split-APK installs up to five minutes by default instead
17
+ of inheriting the five-second probe timeout, while preserving an explicit
18
+ `--timeout` override.
19
+ - Recover the same remembered wireless target for `--last` after a local ADB
20
+ server restart or Wireless debugging port rotation, verifying hardware
21
+ identity before accepting a newly advertised endpoint.
22
+ - Explain when foreground launch verification is blocked by the Android lock
23
+ screen instead of returning only a generic launch-postcondition failure.
24
+ - Isolate runtime-smoke remembered-target state so repository verification can
25
+ never overwrite a developer's real `--last` target with a fixture device.
26
+
12
27
  ## [1.0.2] - 2026-09-30
13
28
 
14
29
  ### Changed
@@ -551,7 +566,8 @@ deprecation policy in [Stability and versioning](./docs/stability.md).
551
566
  explainable configuration precedence.
552
567
  - Human, plain, JSON, and NDJSON output across Node, Bun, and Deno entrypoints.
553
568
 
554
- [Unreleased]: https://github.com/Adam014/adb-ready/compare/v1.0.2...HEAD
569
+ [Unreleased]: https://github.com/Adam014/adb-ready/compare/v1.0.3...HEAD
570
+ [1.0.3]: https://github.com/Adam014/adb-ready/compare/v1.0.2...v1.0.3
555
571
  [1.0.2]: https://github.com/Adam014/adb-ready/compare/v1.0.1...v1.0.2
556
572
  [1.0.1]: https://github.com/Adam014/adb-ready/compare/v1.0.0...v1.0.1
557
573
  [1.0.0]: https://github.com/Adam014/adb-ready/compare/v0.9.0...v1.0.0
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.3",
3308
3308
  description: "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
3309
3309
  private: false,
3310
3310
  type: "module",
@@ -45756,6 +45756,7 @@ async function runDev(options, config4 = {}, dependencies = {}, signal) {
45756
45756
  }
45757
45757
 
45758
45758
  // src/app/app-commands.ts
45759
+ var DEFAULT_APP_INSTALL_TIMEOUT_MS = 5 * 60000;
45759
45760
  function plannedArgs(ready, config4, args) {
45760
45761
  return [
45761
45762
  ...config4.adbHost === undefined ? [] : ["-H", config4.adbHost],
@@ -46030,7 +46031,9 @@ async function launchApp(ready, applicationId, explicitActivity, commandId, prob
46030
46031
  }
46031
46032
  const activeValue = active?.value;
46032
46033
  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, [
46034
+ 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 });
46035
+ const targetIsLocked = succeeded(lockState.process) && lockState.value === "locked";
46036
+ 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
46037
  {
46035
46038
  source: "adb.activity",
46036
46039
  field: "foreground",
@@ -46038,7 +46041,14 @@ async function launchApp(ready, applicationId, explicitActivity, commandId, prob
46038
46041
  applicationId: activeValue.applicationId,
46039
46042
  activity: activeValue.activity
46040
46043
  }
46041
- }
46044
+ },
46045
+ ...targetIsLocked ? [
46046
+ {
46047
+ source: "adb.window-policy",
46048
+ field: "lockState",
46049
+ value: "locked"
46050
+ }
46051
+ ] : []
46042
46052
  ]));
46043
46053
  return;
46044
46054
  }
@@ -46148,7 +46158,9 @@ async function runApp(request, config4 = {}, dependencies = {}, signal) {
46148
46158
  ...request.replace === true ? ["-r"] : [],
46149
46159
  ...request.grantRuntimePermissions === true ? ["-g"] : [],
46150
46160
  ...artifacts
46151
- ], (output) => output.trim(), signal);
46161
+ ], (output) => output.trim(), signal, {
46162
+ ...config4.timeoutWasDefault === true ? { timeoutMs: DEFAULT_APP_INSTALL_TIMEOUT_MS } : config4.timeoutMs === undefined ? {} : { timeoutMs: config4.timeoutMs }
46163
+ });
46152
46164
  if (!succeeded(installed.process) || !/\bSuccess\b/u.test(installed.value)) {
46153
46165
  problems.push(operationProblem("app-install", installed, current.commandId));
46154
46166
  return finish2(current, null, problems);
@@ -50569,6 +50581,7 @@ function commandConfig(loaded, bound, selector, transportId) {
50569
50581
  ...values.adbHost === undefined ? {} : { adbHost: values.adbHost },
50570
50582
  ...values.adbPort === undefined ? {} : { adbPort: values.adbPort },
50571
50583
  timeoutMs: values.timeoutMs,
50584
+ timeoutWasDefault: loaded.provenance.timeoutMs?.source === "default",
50572
50585
  uiTimeoutMs: loaded.provenance.timeoutMs?.source === "default" ? 15000 : values.timeoutMs,
50573
50586
  ...values.targetAliases === undefined ? {} : { targetAliases: values.targetAliases },
50574
50587
  ...bound?.transportId !== undefined ? { targetTransportId: bound.transportId } : bound !== undefined ? { targetSelector: bound.serial } : transportId !== undefined ? { targetTransportId: transportId } : selector === undefined ? {} : { targetSelector: selector }
@@ -60772,6 +60785,7 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60772
60785
  ...values2.adbHost === undefined ? {} : { adbHost: values2.adbHost },
60773
60786
  ...values2.adbPort === undefined ? {} : { adbPort: values2.adbPort },
60774
60787
  timeoutMs: values2.timeoutMs,
60788
+ timeoutWasDefault: loaded.config.provenance.timeoutMs?.source === "default",
60775
60789
  uiTimeoutMs: loaded.config.provenance.timeoutMs?.source === "default" ? 15000 : values2.timeoutMs,
60776
60790
  ...options.device === undefined ? {} : { targetSelector: options.device },
60777
60791
  ...options.transportId === undefined ? {} : { targetTransportId: options.transportId },
@@ -60922,16 +60936,42 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60922
60936
  }
60923
60937
  const offlineDevPlan = (options.command === "dev" || options.command === "run") && options.dryRun;
60924
60938
  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") {
60939
+ 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
60940
  let inventory = await runDevices(config4, commandDependencies, signal);
60927
60941
  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({
60942
+ if ((options.command === "dev" || options.command === "run" || options.remembered) && selectable.length === 0 && !options.dryRun) {
60943
+ let acquisition = planTargetAcquisition({
60930
60944
  ...config4.targetSelector === undefined ? {} : { selector: config4.targetSelector },
60931
60945
  ...values2.targetAliases === undefined ? {} : { aliases: values2.targetAliases },
60932
60946
  ...lastTarget === undefined ? {} : { remembered: lastTarget },
60933
60947
  services: inventory.result.data?.discovery.mdns.services ?? []
60934
60948
  });
60949
+ if (acquisition.kind === "ambiguous" && options.remembered && lastTarget?.hardwareSerial !== undefined) {
60950
+ const services = inventory.result.data?.discovery.mdns.services ?? [];
60951
+ const endpoints = [
60952
+ ...new Set(services.flatMap((service) => (service.serviceType === "legacy" || service.serviceType === "connect" && service.knownDevice !== false) && service.endpoint.version === 4 ? [service.endpoint.serial] : []))
60953
+ ];
60954
+ for (const candidate of endpoints) {
60955
+ const verified = await runConnect(candidate, {
60956
+ ...config4,
60957
+ endpointWasDiscovered: true,
60958
+ discoveredEndpointCandidates: [candidate]
60959
+ }, commandDependencies, signal);
60960
+ const data = verified.result.data;
60961
+ if (verified.result.ok && data !== null && "serial" in data && data.hardwareSerial === lastTarget.hardwareSerial) {
60962
+ acquisition = {
60963
+ kind: "connect",
60964
+ endpoint: data.serial,
60965
+ candidates: [data.serial],
60966
+ discovered: true,
60967
+ reason: "remembered-identity"
60968
+ };
60969
+ break;
60970
+ }
60971
+ if (signal?.aborted === true)
60972
+ break;
60973
+ }
60974
+ }
60935
60975
  if (acquisition.kind === "connect") {
60936
60976
  const connected = await runConnect(acquisition.endpoint, acquisition.discovered ? {
60937
60977
  ...config4,
@@ -60974,11 +61014,13 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
60974
61014
  } else {
60975
61015
  preparedSelection = selected2.result.data.selected;
60976
61016
  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;
61017
+ if (options.command !== "devices") {
61018
+ if (options.avdName !== undefined || transport.transportId === undefined) {
61019
+ config4.targetSelector = transport.serial;
61020
+ delete config4.targetTransportId;
61021
+ } else {
61022
+ config4.targetTransportId = transport.transportId;
61023
+ }
60982
61024
  }
60983
61025
  }
60984
61026
  }
@@ -61628,4 +61670,4 @@ try {
61628
61670
  process16.removeListener("SIGTERM", abort);
61629
61671
  }
61630
61672
 
61631
- //# debugId=EEFE4EA2C406032664756E2164756E21
61673
+ //# debugId=2A90A8EB1D4EFD3D64756E2164756E21
@@ -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.3",
4
4
  "description": "Agent-ready Android CLI for reliable ADB sessions, app automation, and verified evidence.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -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.3",
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.3; 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.3, agent schema v1.