/** * Deploy handler for the daemon. * Extracts package name from APK, installs, launches, checks for crashes. */ import { type AdbCommandRunner } from "../utils/port-owners.js"; import type { StayAwakeManager } from "./stay-awake-manager.js"; import type { LogcatManager } from "./logcat-manager.js"; export interface DeployOptions { apkPath: string; pin: string; crashWaitMs?: number; onEvent: (event: DeployEvent) => void; /** * Adb command runner. When supplied, deploy() uses it to scan for and * force-stop orphan apps holding the debugging port before install. * Tests inject a mock; production wires the real `adb` binary via * adbArgs(). */ adb?: AdbCommandRunner; /** * Target package name. When supplied, skips APK package-name extraction. * Used by tests to drive the port-conflict path without a real APK. */ targetPackage?: string; /** * TCP port to scan for conflicting LISTEN sockets. Defaults to 15702 * (Bevy BRP). Set for other frameworks (React Native Metro 8081, * Flutter DDS, custom RPC servers, etc.). */ debuggingPort?: number; } export interface InstallInfo { incremental: boolean; blocksTransferred?: number; totalBlocks?: number; bytesTransferred?: number; installSecs: number; apkSizeMB: number; } export type DeployResult = { ok: true; package: string; crashed: false; logcatFile: string; install?: InstallInfo; } | { ok: false; package: string; crashed: true; logcatFile: string; logcatLines?: string[]; error?: string; } | { ok: false; package: string; crashed: false; error: string; logcatFile?: string; }; export type DeployEvent = { type: 'adb_health'; status: 'connecting' | 'reconnecting' | 'restarting_server'; } | { type: 'adb_health'; status: 'recovered'; via: 'connect' | 'reconnect' | 'kill-server'; } | { type: 'adb_health'; status: 'failed'; error: string; } | { type: 'stay_awake'; status: 'already_enabled' | 'enabling' | 'enabled' | 'failed'; error?: string; } | { type: 'started'; package: string; apkSizeMB: number; incremental: boolean; } | { type: 'port_conflict_resolved'; port: number; stopped: Array<{ packageName: string; uid: number; }>; skipped: Array<{ uid: number; packageName: string | null; }>; } | { type: 'install_progress'; blocks: number; totalBlocks: number; pct: number; } | { type: 'installed'; installSecs: number; blocksTransferred?: number; totalBlocks?: number; bytesTransferred?: number; } | { type: 'launching'; } | { type: 'crash_check'; waitMs: number; } | ({ type: 'done'; } & DeployResult); export type ProgressUpdate = { kind: 'progress'; blocks: number; totalBlocks: number; pct: number; } | { kind: 'transferred'; blocksTransferred: number; totalBlocks: number; }; interface IncrementalProgressParser { feed(chunk: string): void; end(): void; } /** * Parses ADB_TRACE=incremental stderr ("in priority: N of M") into throttled * progress updates. Pure: no I/O, no side effects beyond the onUpdate callback. * Throttle: emits a `progress` update each time `current` advances by at least * 10% of `totalBlocks`. Always emits a final `transferred` update on `end()` * if any blocks were seen. */ export declare function parseIncrementalProgress(onUpdate: (u: ProgressUpdate) => void): IncrementalProgressParser; /** * Run the full deploy sequence. */ export declare function deploy(options: DeployOptions, stayAwake: StayAwakeManager, logcat: LogcatManager): Promise; /** * Test helper: collects events into an array. Returns the array; the caller * passes `collector.push` as the onEvent callback to deploy(). */ export declare function collectDeployEvents(): { events: DeployEvent[]; push: (e: DeployEvent) => void; }; export {}; //# sourceMappingURL=deploy.d.ts.map