adb-ready 0.1.0 → 0.1.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.
- package/CHANGELOG.md +30 -1
- package/README.md +1 -1
- package/dist/cli.js +146 -32
- package/dist/cli.js.map +11 -10
- package/docs/automation.md +1 -1
- package/docs/logs-and-context.md +4 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,33 @@ breaking changes.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.1.2] - 2026-09-10
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Start live log streams at the current buffer position by default, while
|
|
17
|
+
keeping explicit history available through `--tail`, `--since`, and `--dump`.
|
|
18
|
+
- Color live logcat and child output by parsed severity and conservative message
|
|
19
|
+
semantics without treating every `stderr` line as an error.
|
|
20
|
+
- Present a safely handled `Ctrl-C` as an interruption while preserving exit
|
|
21
|
+
code 130 and a failed machine result for automation.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- Correlate duplicate ADB 37 mDNS service-name and stable endpoint transports
|
|
26
|
+
only when exact discovery and observed hardware identity prove they match.
|
|
27
|
+
- Prevent port-list results from being misclassified as saved-session results in
|
|
28
|
+
human and plain output.
|
|
29
|
+
- Emit saved session timelines as one event per NDJSON line followed by a compact
|
|
30
|
+
result summary instead of duplicating the complete event array.
|
|
31
|
+
|
|
32
|
+
## [0.1.1] - 2026-09-10
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
|
|
36
|
+
- Keep successful background target and port health probes in diagnostic
|
|
37
|
+
events without repeatedly printing them over development-server output.
|
|
38
|
+
|
|
12
39
|
## [0.1.0] - 2026-09-10
|
|
13
40
|
|
|
14
41
|
### Added
|
|
@@ -25,5 +52,7 @@ breaking changes.
|
|
|
25
52
|
explainable configuration precedence.
|
|
26
53
|
- Human, plain, JSON, and NDJSON output across Node, Bun, and Deno entrypoints.
|
|
27
54
|
|
|
28
|
-
[Unreleased]: https://github.com/Adam014/adb-ready/compare/v0.1.
|
|
55
|
+
[Unreleased]: https://github.com/Adam014/adb-ready/compare/v0.1.2...HEAD
|
|
56
|
+
[0.1.2]: https://github.com/Adam014/adb-ready/compare/v0.1.1...v0.1.2
|
|
57
|
+
[0.1.1]: https://github.com/Adam014/adb-ready/compare/v0.1.0...v0.1.1
|
|
29
58
|
[0.1.0]: https://github.com/Adam014/adb-ready/compare/v0.0.1-alpha.0...v0.1.0
|
package/README.md
CHANGED
|
@@ -195,7 +195,7 @@ Android transport backend.
|
|
|
195
195
|
[Changelog](./CHANGELOG.md) · [Contributing](./CONTRIBUTING.md) ·
|
|
196
196
|
[Security](./SECURITY.md) · [MIT License](./LICENSE)
|
|
197
197
|
|
|
198
|
-
ADB Ready is Android-only. The `0.1.
|
|
198
|
+
ADB Ready is Android-only. The `0.1.x` releases focus on target acquisition,
|
|
199
199
|
ports, development-session recovery, logs, diagnostics, and automation. App
|
|
200
200
|
lifecycle, files, screenshots, screen recording, and shell workflows come
|
|
201
201
|
after this core is proven on real projects.
|
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import process9 from "node:process";
|
|
|
9
9
|
// package.json
|
|
10
10
|
var package_default = {
|
|
11
11
|
name: "adb-ready",
|
|
12
|
-
version: "0.1.
|
|
12
|
+
version: "0.1.2",
|
|
13
13
|
description: "Make an Android target ready, then keep the development session working.",
|
|
14
14
|
private: false,
|
|
15
15
|
type: "module",
|
|
@@ -837,6 +837,7 @@ class AdbClient {
|
|
|
837
837
|
async#observe(operation, message, args, parse, signal, options = {}) {
|
|
838
838
|
const operationId = this.#idFactory();
|
|
839
839
|
const correlation = { ...this.#options.correlation, operationId };
|
|
840
|
+
const background = this.#options.presentation === "background";
|
|
840
841
|
const finalArgs = [
|
|
841
842
|
...options.useServerArguments === false ? [] : this.#serverArguments(),
|
|
842
843
|
...args
|
|
@@ -844,12 +845,13 @@ class AdbClient {
|
|
|
844
845
|
this.#options.bus.emit({
|
|
845
846
|
type: "operation.started",
|
|
846
847
|
source: `adb.${operation}`,
|
|
847
|
-
severity: "info",
|
|
848
|
+
severity: background ? "debug" : "info",
|
|
848
849
|
message,
|
|
849
850
|
correlation,
|
|
850
851
|
data: {
|
|
851
852
|
executable: redactText(this.#options.executable).value,
|
|
852
|
-
args: finalArgs.map((argument) => redactText(argument).value)
|
|
853
|
+
args: finalArgs.map((argument) => redactText(argument).value),
|
|
854
|
+
...background ? { presentation: "background" } : {}
|
|
853
855
|
}
|
|
854
856
|
});
|
|
855
857
|
const request = {
|
|
@@ -865,10 +867,13 @@ class AdbClient {
|
|
|
865
867
|
this.#options.bus.emit({
|
|
866
868
|
type: succeeded ? "operation.completed" : "operation.failed",
|
|
867
869
|
source: `adb.${operation}`,
|
|
868
|
-
severity: succeeded ? "info" : "error",
|
|
870
|
+
severity: succeeded ? background ? "debug" : "info" : "error",
|
|
869
871
|
message: succeeded ? `${message} completed` : `${message} failed`,
|
|
870
872
|
correlation,
|
|
871
|
-
data:
|
|
873
|
+
data: {
|
|
874
|
+
...processMetadata(result),
|
|
875
|
+
...background ? { presentation: "background" } : {}
|
|
876
|
+
}
|
|
872
877
|
});
|
|
873
878
|
return {
|
|
874
879
|
operationId,
|
|
@@ -1550,9 +1555,10 @@ function targetInventoryProblems(targets, correlation) {
|
|
|
1550
1555
|
const problems = [];
|
|
1551
1556
|
for (const target of targets) {
|
|
1552
1557
|
const serialCounts = new Map;
|
|
1558
|
+
const hasStableTransport = target.transports.some(({ stable }) => stable);
|
|
1553
1559
|
for (const transport of target.transports) {
|
|
1554
1560
|
serialCounts.set(transport.serial, (serialCounts.get(transport.serial) ?? 0) + 1);
|
|
1555
|
-
if (!transport.stable) {
|
|
1561
|
+
if (!transport.stable && !hasStableTransport) {
|
|
1556
1562
|
problems.push({
|
|
1557
1563
|
code: ProblemCode.UnstableTargetSerial,
|
|
1558
1564
|
category: "target.identity",
|
|
@@ -2706,6 +2712,44 @@ function isStableAdbSerial(serial) {
|
|
|
2706
2712
|
}
|
|
2707
2713
|
return true;
|
|
2708
2714
|
}
|
|
2715
|
+
function normalizedServiceSerial(value) {
|
|
2716
|
+
return value.trim().replace(/\.+$/u, "");
|
|
2717
|
+
}
|
|
2718
|
+
function serviceSerial(service) {
|
|
2719
|
+
return normalizedServiceSerial(`${service.instance}.${service.rawServiceType}`);
|
|
2720
|
+
}
|
|
2721
|
+
function correlateMdnsTransportIdentities(observations, services) {
|
|
2722
|
+
const identityByEndpoint = new Map;
|
|
2723
|
+
for (const observation of observations) {
|
|
2724
|
+
const hardwareSerial = observation.hardwareSerial?.trim();
|
|
2725
|
+
const endpoint = parseAdbNetworkEndpoint(observation.device.serial);
|
|
2726
|
+
if (hardwareSerial === undefined || hardwareSerial === "" || endpoint === undefined)
|
|
2727
|
+
continue;
|
|
2728
|
+
const identities = identityByEndpoint.get(endpoint.serial) ?? new Set;
|
|
2729
|
+
identities.add(hardwareSerial);
|
|
2730
|
+
identityByEndpoint.set(endpoint.serial, identities);
|
|
2731
|
+
}
|
|
2732
|
+
return observations.map((observation) => {
|
|
2733
|
+
if (observation.hardwareSerial !== undefined || !isMdnsServiceSerial(observation.device.serial)) {
|
|
2734
|
+
return observation;
|
|
2735
|
+
}
|
|
2736
|
+
const matchingServices = services.filter((service) => serviceSerial(service) === normalizedServiceSerial(observation.device.serial));
|
|
2737
|
+
const identities = new Set;
|
|
2738
|
+
for (const service of matchingServices) {
|
|
2739
|
+
const advertisedIdentity = service.hardwareSerial?.trim();
|
|
2740
|
+
if (advertisedIdentity !== undefined && advertisedIdentity !== "") {
|
|
2741
|
+
identities.add(advertisedIdentity);
|
|
2742
|
+
}
|
|
2743
|
+
for (const endpoint of [service.endpoint, ...service.alternateEndpoints ?? []]) {
|
|
2744
|
+
for (const identity of identityByEndpoint.get(endpoint.serial) ?? []) {
|
|
2745
|
+
identities.add(identity);
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
const [hardwareSerial] = identities;
|
|
2750
|
+
return identities.size === 1 && hardwareSerial !== undefined ? { ...observation, hardwareSerial } : observation;
|
|
2751
|
+
});
|
|
2752
|
+
}
|
|
2709
2753
|
function transportKind(device, services) {
|
|
2710
2754
|
if (/^emulator-\d+$/u.test(device.serial)) {
|
|
2711
2755
|
return "emulator";
|
|
@@ -2963,6 +3007,7 @@ function finish(context, data, problems) {
|
|
|
2963
3007
|
const finished = context.clock();
|
|
2964
3008
|
const exitCode = exitCodeForProblems(problems);
|
|
2965
3009
|
const ok = exitCode === 0 /* Success */;
|
|
3010
|
+
const interrupted = exitCode === 130 /* Interrupted */;
|
|
2966
3011
|
const result = {
|
|
2967
3012
|
schemaVersion: SCHEMA_VERSION,
|
|
2968
3013
|
command: context.command,
|
|
@@ -2975,10 +3020,10 @@ function finish(context, data, problems) {
|
|
|
2975
3020
|
problems
|
|
2976
3021
|
};
|
|
2977
3022
|
context.bus.emit({
|
|
2978
|
-
type: ok ? "command.completed" : "command.failed",
|
|
3023
|
+
type: ok ? "command.completed" : interrupted ? "command.interrupted" : "command.failed",
|
|
2979
3024
|
source: `command.${context.command}`,
|
|
2980
|
-
severity: ok ? "info" : "error",
|
|
2981
|
-
message: ok ? `${context.command} completed` : `${context.command} failed`,
|
|
3025
|
+
severity: ok ? "info" : interrupted ? "warning" : "error",
|
|
3026
|
+
message: ok ? `${context.command} completed` : interrupted ? `${context.command} interrupted` : `${context.command} failed`,
|
|
2982
3027
|
correlation: { commandId: context.commandId },
|
|
2983
3028
|
data: { exitCode, problemCount: problems.length }
|
|
2984
3029
|
});
|
|
@@ -3157,13 +3202,14 @@ async function inspectTargets(client, devices, commandId, signal, hostFeatures)
|
|
|
3157
3202
|
}
|
|
3158
3203
|
});
|
|
3159
3204
|
const services = mdnsAvailable ? mdns.value : [];
|
|
3160
|
-
const
|
|
3205
|
+
const observations = devices.map((device) => {
|
|
3161
3206
|
const hardwareSerial = identityBySerial.get(device.serial);
|
|
3162
3207
|
return {
|
|
3163
3208
|
device,
|
|
3164
3209
|
...hardwareSerial === undefined ? {} : { hardwareSerial }
|
|
3165
3210
|
};
|
|
3166
|
-
})
|
|
3211
|
+
});
|
|
3212
|
+
const inventory = buildTargetInventory(correlateMdnsTransportIdentities(observations, services), services);
|
|
3167
3213
|
return {
|
|
3168
3214
|
targets: inventory.targets,
|
|
3169
3215
|
discovery: {
|
|
@@ -3911,7 +3957,7 @@ async function runLogs(options, config = {}, dependencies = {}, signal) {
|
|
|
3911
3957
|
"-v",
|
|
3912
3958
|
"threadtime",
|
|
3913
3959
|
...buffers.flatMap((buffer) => ["-b", buffer]),
|
|
3914
|
-
...options.tail === undefined && options.since === undefined ? options.dump ? ["-d"] : [] : [options.dump ? "-t" : "-T", String(options.tail ?? options.since)],
|
|
3960
|
+
...options.tail === undefined && options.since === undefined ? options.dump ? ["-d"] : ["-T", "1"] : [options.dump ? "-t" : "-T", String(options.tail ?? options.since)],
|
|
3915
3961
|
...resolvedUid === undefined ? [] : [`--uid=${String(resolvedUid)}`],
|
|
3916
3962
|
...resolvedPid === undefined ? [] : [`--pid=${String(resolvedPid)}`],
|
|
3917
3963
|
...filters
|
|
@@ -4063,16 +4109,18 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4063
4109
|
}
|
|
4064
4110
|
}
|
|
4065
4111
|
const complete = async (data) => {
|
|
4066
|
-
|
|
4067
|
-
|
|
4112
|
+
const interrupted = problems.some(({ code }) => code === ProblemCode.OperationInterrupted);
|
|
4113
|
+
const failed = problems.some(({ code, severity }) => severity === "error" && code !== ProblemCode.OperationInterrupted);
|
|
4114
|
+
if (failed) {
|
|
4115
|
+
transition("failed", problems.find(({ code, severity }) => severity === "error" && code !== ProblemCode.OperationInterrupted)?.summary ?? "failed");
|
|
4068
4116
|
}
|
|
4069
4117
|
transition("stopping", "finalizing owned session resources");
|
|
4070
4118
|
transition("ended", "session command finalized");
|
|
4071
4119
|
bus.emit({
|
|
4072
4120
|
type: "session.ended",
|
|
4073
4121
|
source: "session",
|
|
4074
|
-
severity:
|
|
4075
|
-
message: "Development session ended",
|
|
4122
|
+
severity: failed ? "error" : interrupted ? "warning" : "info",
|
|
4123
|
+
message: interrupted ? "Development session ended safely after interruption" : "Development session ended",
|
|
4076
4124
|
correlation: { commandId: context.commandId, sessionId }
|
|
4077
4125
|
});
|
|
4078
4126
|
const execution2 = finish(context, data, problems);
|
|
@@ -4185,7 +4233,7 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4185
4233
|
if (normalizedPorts.problems.length > 0)
|
|
4186
4234
|
return await complete(null);
|
|
4187
4235
|
const targetCorrelation = { ...correlation, targetId: selected.target.id };
|
|
4188
|
-
const
|
|
4236
|
+
const clientOptions = {
|
|
4189
4237
|
executable,
|
|
4190
4238
|
bus,
|
|
4191
4239
|
correlation: targetCorrelation,
|
|
@@ -4194,7 +4242,9 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4194
4242
|
...config.timeoutMs === undefined ? {} : { timeoutMs: config.timeoutMs },
|
|
4195
4243
|
...dependencies.runner === undefined ? {} : { runner: dependencies.runner },
|
|
4196
4244
|
idFactory
|
|
4197
|
-
}
|
|
4245
|
+
};
|
|
4246
|
+
const client = new AdbClient(clientOptions);
|
|
4247
|
+
const healthClient = new AdbClient({ ...clientOptions, presentation: "background" });
|
|
4198
4248
|
const listed = await client.listPortMappings(target, "reverse", signal);
|
|
4199
4249
|
if (!processSucceeded(listed.process)) {
|
|
4200
4250
|
problems.push(operationProblem("reverse-list", listed, context.commandId));
|
|
@@ -4499,6 +4549,8 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4499
4549
|
"logcat",
|
|
4500
4550
|
"-v",
|
|
4501
4551
|
"threadtime",
|
|
4552
|
+
"-T",
|
|
4553
|
+
"1",
|
|
4502
4554
|
"ReactNativeJS:V",
|
|
4503
4555
|
"ReactNative:V",
|
|
4504
4556
|
"AndroidRuntime:E",
|
|
@@ -4593,7 +4645,7 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4593
4645
|
const abortWatcher = () => watchController.abort();
|
|
4594
4646
|
signal?.addEventListener("abort", abortWatcher, { once: true });
|
|
4595
4647
|
const observeSession = async (watchSignal) => {
|
|
4596
|
-
const state = await
|
|
4648
|
+
const state = await healthClient.getState(target.serial, watchSignal);
|
|
4597
4649
|
if (!processSucceeded(state.process) || state.value !== "device") {
|
|
4598
4650
|
return {
|
|
4599
4651
|
targetReady: false,
|
|
@@ -4604,7 +4656,7 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4604
4656
|
detail: `Target ${target.serial} is not ready.`
|
|
4605
4657
|
};
|
|
4606
4658
|
}
|
|
4607
|
-
const mappings = await
|
|
4659
|
+
const mappings = await healthClient.listPortMappings(target, "reverse", watchSignal);
|
|
4608
4660
|
if (!processSucceeded(mappings.process)) {
|
|
4609
4661
|
return {
|
|
4610
4662
|
targetReady: true,
|
|
@@ -4867,7 +4919,7 @@ async function runDev(options, config = {}, dependencies = {}, signal) {
|
|
|
4867
4919
|
await runHookPhase("finally", {}, false);
|
|
4868
4920
|
const execution = await complete({
|
|
4869
4921
|
...baseData(),
|
|
4870
|
-
status: problems.some(({ severity }) => severity === "error") ? "failed" : "completed",
|
|
4922
|
+
status: problems.some(({ code, severity }) => severity === "error" && code !== ProblemCode.OperationInterrupted) ? "failed" : problems.some(({ code }) => code === ProblemCode.OperationInterrupted) ? "interrupted" : "completed",
|
|
4871
4923
|
ports: {
|
|
4872
4924
|
requested: normalizedPorts.mappings,
|
|
4873
4925
|
created,
|
|
@@ -6978,6 +7030,8 @@ class ProgressRenderer {
|
|
|
6978
7030
|
this.#spinner.dispose();
|
|
6979
7031
|
}
|
|
6980
7032
|
onEvent(event) {
|
|
7033
|
+
if (event.data?.presentation === "background")
|
|
7034
|
+
return;
|
|
6981
7035
|
if (event.type === "operation.started") {
|
|
6982
7036
|
this.#spinner.start(event.message);
|
|
6983
7037
|
} else if (event.type === "operation.completed") {
|
|
@@ -7051,7 +7105,13 @@ function isLogsData(value) {
|
|
|
7051
7105
|
return isRecord(value) && isRecord(value.selected) && Array.isArray(value.filters) && Array.isArray(value.records) && typeof value.dropped === "number";
|
|
7052
7106
|
}
|
|
7053
7107
|
function isSessionCommandData(value) {
|
|
7054
|
-
|
|
7108
|
+
if (!isRecord(value))
|
|
7109
|
+
return false;
|
|
7110
|
+
if (value.action === "list")
|
|
7111
|
+
return Array.isArray(value.sessions);
|
|
7112
|
+
if (value.action === "show")
|
|
7113
|
+
return isRecord(value.session);
|
|
7114
|
+
return value.action === "events" && isRecord(value.session) && Array.isArray(value.events);
|
|
7055
7115
|
}
|
|
7056
7116
|
function isProblemsCommandData(value) {
|
|
7057
7117
|
return isRecord(value) && typeof value.sessionId === "string" && typeof value.status === "string" && Array.isArray(value.problems);
|
|
@@ -7084,7 +7144,7 @@ function wirelessServiceLabel(service) {
|
|
|
7084
7144
|
}
|
|
7085
7145
|
function problemLines(problem, capabilities, verbose) {
|
|
7086
7146
|
const glyphs = symbols(capabilities);
|
|
7087
|
-
const marker = problem.severity === "error" ? style.failure(glyphs.failure, capabilities) : style.warning(glyphs.warning, capabilities);
|
|
7147
|
+
const marker = problem.severity === "error" && problem.code !== ProblemCode.OperationInterrupted ? style.failure(glyphs.failure, capabilities) : style.warning(glyphs.warning, capabilities);
|
|
7088
7148
|
const lines = [
|
|
7089
7149
|
`${marker} ${style.strong(clean(problem.summary), capabilities)}`,
|
|
7090
7150
|
` ${clean(problem.detail)}`
|
|
@@ -7120,11 +7180,13 @@ function renderHuman(result, options) {
|
|
|
7120
7180
|
}
|
|
7121
7181
|
if (result.command === "dev" && isDevData(result.data)) {
|
|
7122
7182
|
const data = result.data;
|
|
7183
|
+
const sessionMarker = data.status === "interrupted" ? style.warning(glyphs.warning, capabilities) : data.status === "failed" ? style.failure(glyphs.failure, capabilities) : style.success(glyphs.success, capabilities);
|
|
7123
7184
|
lines.push(`${style.success(glyphs.success, capabilities)} Target ${clean(data.selected.target.name)} · ${clean(data.selected.transport.serial)}`, `${style.success(glyphs.success, capabilities)} Project ${clean(data.project.name ?? data.project.root)} · ${clean(data.preset)}`, `${style.success(glyphs.success, capabilities)} Ports ${String(data.ports.requested.length)} ready · ${String(data.ports.created.length)} created · ${String(data.ports.reused.length)} reused`, `${style.success(glyphs.success, capabilities)} Command ${clean(data.command.executable)} ${data.command.args.map(clean).join(" ")}`);
|
|
7124
7185
|
if (data.child !== undefined) {
|
|
7125
|
-
|
|
7186
|
+
const childMarker = data.status === "interrupted" ? style.warning(glyphs.warning, capabilities) : data.child.exitCode === 0 ? style.success(glyphs.success, capabilities) : style.failure(glyphs.failure, capabilities);
|
|
7187
|
+
lines.push(`${childMarker} Child ${data.child.exitCode === null ? clean(data.child.signal) : `exit ${String(data.child.exitCode)}`}`);
|
|
7126
7188
|
}
|
|
7127
|
-
lines.push(`${style.success(glyphs.success, capabilities)} Journal ${String(data.journal.events.length)} events${data.journal.dropped === 0 ? "" : ` · ${String(data.journal.dropped)} dropped`}`, `${data.recovery.failed ? style.failure(glyphs.failure, capabilities) : style.success(glyphs.success, capabilities)} Recovery ${data.recovery.failed ? "failed" : data.recovery.recoveries === 0 ? "healthy" : `${String(data.recovery.recoveries)} verified repair(s)`}`, `${
|
|
7189
|
+
lines.push(`${style.success(glyphs.success, capabilities)} Journal ${String(data.journal.events.length)} events${data.journal.dropped === 0 ? "" : ` · ${String(data.journal.dropped)} dropped`}`, `${data.recovery.failed ? style.failure(glyphs.failure, capabilities) : style.success(glyphs.success, capabilities)} Recovery ${data.recovery.failed ? "failed" : data.recovery.recoveries === 0 ? "healthy" : `${String(data.recovery.recoveries)} verified repair(s)`}`, `${sessionMarker} Session ${clean(data.sessionId)} · ${clean(data.status)}`);
|
|
7128
7190
|
}
|
|
7129
7191
|
if (result.command === "logs" && isLogsData(result.data)) {
|
|
7130
7192
|
const data = result.data;
|
|
@@ -7252,7 +7314,8 @@ function renderHuman(result, options) {
|
|
|
7252
7314
|
lines.push(...problemLines(problem, capabilities, options.verbose ?? false));
|
|
7253
7315
|
}
|
|
7254
7316
|
}
|
|
7255
|
-
const
|
|
7317
|
+
const interrupted = result.problems.some(({ code }) => code === ProblemCode.OperationInterrupted) && !result.problems.some(({ code, severity }) => severity === "error" && code !== ProblemCode.OperationInterrupted);
|
|
7318
|
+
const status = result.ok ? `${style.success(glyphs.success, capabilities)} Completed in ${String(result.durationMs)}ms` : interrupted ? `${style.warning(glyphs.warning, capabilities)} Interrupted safely in ${String(result.durationMs)}ms` : `${style.failure(glyphs.failure, capabilities)} Failed in ${String(result.durationMs)}ms`;
|
|
7256
7319
|
lines.push("", status);
|
|
7257
7320
|
sink.write(`${lines.join(`
|
|
7258
7321
|
`)}
|
|
@@ -7491,8 +7554,25 @@ function renderResult(result, options) {
|
|
|
7491
7554
|
options.sink.write(`${JSON.stringify(result)}
|
|
7492
7555
|
`);
|
|
7493
7556
|
} else if (options.format === "ndjson") {
|
|
7494
|
-
|
|
7557
|
+
if (isSessionCommandData(result.data) && result.data.action === "events") {
|
|
7558
|
+
for (const event of result.data.events) {
|
|
7559
|
+
options.sink.write(`${JSON.stringify({ kind: "event", ...event })}
|
|
7560
|
+
`);
|
|
7561
|
+
}
|
|
7562
|
+
options.sink.write(`${JSON.stringify({
|
|
7563
|
+
kind: "result",
|
|
7564
|
+
...result,
|
|
7565
|
+
data: {
|
|
7566
|
+
action: result.data.action,
|
|
7567
|
+
session: result.data.session,
|
|
7568
|
+
eventCount: result.data.events.length
|
|
7569
|
+
}
|
|
7570
|
+
})}
|
|
7495
7571
|
`);
|
|
7572
|
+
} else {
|
|
7573
|
+
options.sink.write(`${JSON.stringify({ kind: "result", ...result })}
|
|
7574
|
+
`);
|
|
7575
|
+
}
|
|
7496
7576
|
} else if (options.format === "plain") {
|
|
7497
7577
|
renderPlain(result, options.sink);
|
|
7498
7578
|
} else {
|
|
@@ -7514,6 +7594,37 @@ class NdjsonEventRenderer {
|
|
|
7514
7594
|
}
|
|
7515
7595
|
}
|
|
7516
7596
|
|
|
7597
|
+
// src/ui/stream-renderer.ts
|
|
7598
|
+
var ERROR_LINE = /(?:^|\s)(?:err!|error|fatal|exception|failed|failure|crash)(?::|\b)/iu;
|
|
7599
|
+
var WARNING_LINE = /(?:^|\s)(?:warn|warning|deprecated|deprecation)(?::|\b)/iu;
|
|
7600
|
+
var SUCCESS_LINE = /(?:^|\s)(?:ready|started|bundled|done|success|completed)(?::|\b)/iu;
|
|
7601
|
+
var PROGRESS_LINE = /(?:^|\s)(?:starting|building|bundling|opening|waiting)(?::|\b)/iu;
|
|
7602
|
+
function renderLogStreamLine(line, capabilities) {
|
|
7603
|
+
const safe = sanitizeTerminalText(line);
|
|
7604
|
+
const parsed = parseLogcatThreadtimeLine(safe);
|
|
7605
|
+
if (parsed?.priority === "E" || parsed?.priority === "F" || parsed?.priority === "A") {
|
|
7606
|
+
return style.failure(safe, capabilities);
|
|
7607
|
+
}
|
|
7608
|
+
if (parsed?.priority === "W")
|
|
7609
|
+
return style.warning(safe, capabilities);
|
|
7610
|
+
if (parsed?.priority === "D" || parsed?.priority === "V") {
|
|
7611
|
+
return style.dim(safe, capabilities);
|
|
7612
|
+
}
|
|
7613
|
+
if (parsed?.priority === "I")
|
|
7614
|
+
return style.accent(safe, capabilities);
|
|
7615
|
+
if (ERROR_LINE.test(safe))
|
|
7616
|
+
return style.failure(safe, capabilities);
|
|
7617
|
+
if (WARNING_LINE.test(safe))
|
|
7618
|
+
return style.warning(safe, capabilities);
|
|
7619
|
+
return safe;
|
|
7620
|
+
}
|
|
7621
|
+
function renderChildStreamLine(stream, line, capabilities) {
|
|
7622
|
+
const safe = sanitizeTerminalText(line);
|
|
7623
|
+
const prefix = style.dim(stream === "stderr" ? "│" : " ", capabilities);
|
|
7624
|
+
const rendered = ERROR_LINE.test(safe) ? style.failure(safe, capabilities) : WARNING_LINE.test(safe) ? style.warning(safe, capabilities) : SUCCESS_LINE.test(safe) ? style.success(safe, capabilities) : PROGRESS_LINE.test(safe) ? style.accent(safe, capabilities) : safe;
|
|
7625
|
+
return `${prefix} ${rendered}`;
|
|
7626
|
+
}
|
|
7627
|
+
|
|
7517
7628
|
// src/ui/terminal.ts
|
|
7518
7629
|
function environmentFlag(value) {
|
|
7519
7630
|
if (value === undefined) {
|
|
@@ -8262,7 +8373,8 @@ Lists every target visible to ADB. Add --select to open the keyboard picker.
|
|
|
8262
8373
|
`,
|
|
8263
8374
|
logs: `Usage: adb-ready logs [options]
|
|
8264
8375
|
|
|
8265
|
-
Streams parsed, redacted logcat records from one deterministic target.
|
|
8376
|
+
Streams parsed, redacted logcat records from one deterministic target. Live
|
|
8377
|
+
streams follow from now by default instead of replaying the device buffer.
|
|
8266
8378
|
|
|
8267
8379
|
Log options:
|
|
8268
8380
|
--package NAME Resolve and filter the currently running app process
|
|
@@ -8838,8 +8950,10 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
|
|
|
8838
8950
|
...options.logTail === undefined ? {} : { tail: options.logTail },
|
|
8839
8951
|
...options.logDump === undefined ? {} : { dump: options.logDump },
|
|
8840
8952
|
...options.logMaxRecords === undefined ? {} : { maxRecords: options.logMaxRecords },
|
|
8841
|
-
...options.format === "human" && !options.quiet ? {
|
|
8842
|
-
|
|
8953
|
+
...options.format === "human" && !options.quiet ? {
|
|
8954
|
+
onLine: (line) => io.error.write(`${renderLogStreamLine(line, errorCapabilities)}
|
|
8955
|
+
`)
|
|
8956
|
+
} : {}
|
|
8843
8957
|
}, config, commandDependencies, signal);
|
|
8844
8958
|
} else if (options.command === "dev") {
|
|
8845
8959
|
execution2 = await runDev({
|
|
@@ -8881,7 +8995,7 @@ async function runCliInternal(argv, io, dependencies = {}, signal) {
|
|
|
8881
8995
|
},
|
|
8882
8996
|
...options.format === "human" && !options.quiet ? {
|
|
8883
8997
|
onChildLine: (stream, line) => {
|
|
8884
|
-
io.error.write(`${stream
|
|
8998
|
+
io.error.write(`${renderChildStreamLine(stream, line, errorCapabilities)}
|
|
8885
8999
|
`);
|
|
8886
9000
|
}
|
|
8887
9001
|
} : {}
|
|
@@ -9051,4 +9165,4 @@ try {
|
|
|
9051
9165
|
process10.removeListener("SIGTERM", abort);
|
|
9052
9166
|
}
|
|
9053
9167
|
|
|
9054
|
-
//# debugId=
|
|
9168
|
+
//# debugId=D3161FCA6036C77564756E2164756E21
|