@mcesystems/usbmuxd-instance-manager 1.0.72 → 1.0.73
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/README.md +74 -1
- package/dist/cli.js +194 -85
- package/dist/cli.js.map +4 -4
- package/dist/cli.mjs +193 -84
- package/dist/cli.mjs.map +4 -4
- package/dist/index.js +170 -61
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +169 -60
- package/dist/index.mjs.map +4 -4
- package/dist/types/InstanceManager.d.ts +2 -0
- package/dist/types/InstanceManager.d.ts.map +1 -1
- package/dist/types/LockdownSync.d.ts +16 -0
- package/dist/types/LockdownSync.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +12 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/cli.ts", "../src/UsbmuxdService.ts", "../src/InstanceManager.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport { UsbmuxdService } from \"./UsbmuxdService.js\";\n\nconst { logInfo, logError, logHeader, logDataObject } = createLoggers(\"usbmuxd-cli\");\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst options: Record<string, string> = {};\n\nfor (let i = 0; i < args.length; i++) {\n\tif (args[i].startsWith(\"--\")) {\n\t\tconst key = args[i].substring(2);\n\t\tconst value = args[i + 1];\n\t\tif (value && !value.startsWith(\"--\")) {\n\t\t\toptions[key] = value;\n\t\t\ti++;\n\t\t}\n\t}\n}\n\n// Build configuration from command line\nconst config = {\n\tbatchSize: options.batchSize ? Number.parseInt(options.batchSize, 10) : 4,\n\tbasePort: options.basePort ? Number.parseInt(options.basePort, 10) : 27015,\n\tmaxInstances: options.maxInstances ? Number.parseInt(options.maxInstances, 10) : 20,\n\tusbmuxdPath: options.usbmuxdPath || \"C:\\\\Program Files\\\\usbmuxd-win-mce\\\\usbmuxd.exe\",\n\tverboseLogging: options.verbose !== \"false\",\n\tappleVendorId: options.appleVid || \"05AC\",\n};\n\nlogHeader(\"usbmuxd Instance Manager\");\nlogDataObject(\"Multi-instance manager for iOS device connections\", { config });\n\n// Create and start service\nconst service = new UsbmuxdService(config);\n\n// Handle graceful shutdown\nprocess.on(\"SIGINT\", async () => {\n\tlogInfo(\"\");\n\tlogInfo(\"Received SIGINT, shutting down gracefully...\");\n\ttry {\n\t\tawait service.stop();\n\t\tlogInfo(\"Shutdown complete\");\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tlogError(\"Error during shutdown:\", error);\n\t\tprocess.exit(1);\n\t}\n});\n\nprocess.on(\"SIGTERM\", async () => {\n\tlogInfo(\"\");\n\tlogInfo(\"Received SIGTERM, shutting down gracefully...\");\n\ttry {\n\t\tawait service.stop();\n\t\tlogInfo(\"Shutdown complete\");\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tlogError(\"Error during shutdown:\", error);\n\t\tprocess.exit(1);\n\t}\n});\n\n// Print stats every 30 seconds\nsetInterval(() => {\n\tconst stats = service.getStats();\n\tconst instances = service.getInstances();\n\n\tlogHeader(\n\t\t`Uptime: ${stats.uptimeSeconds}s | Instances: ${stats.instanceCount} | Devices: ${stats.deviceCount}`\n\t);\n\n\tif (instances.length > 0) {\n\t\tlogDataObject(\"Active instances:\", { instances });\n\t}\n}, 30000);\n\n// Print help if --help flag (before starting service)\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n\tlogInfo(\"Usage: usbmuxd-instance-manager [OPTIONS]\");\n\tlogInfo(\"\");\n\tlogInfo(\"Options:\");\n\tlogInfo(\" --batchSize <n> Number of devices per instance (default: 4)\");\n\tlogInfo(\" --basePort <port> Base TCP port for first instance (default: 27015)\");\n\tlogInfo(\" --maxInstances <n> Maximum number of instances (default: 20)\");\n\tlogInfo(\" --usbmuxdPath <path> Path to usbmuxd executable\");\n\tlogInfo(\" --verbose <true|false> Enable verbose logging (default: true)\");\n\tlogInfo(\" --appleVid <vid> Apple Vendor ID in hex (default: 05AC)\");\n\tlogInfo(\" -h, --help Show this help message\");\n\tlogInfo(\"\");\n\tlogInfo(\"Examples:\");\n\tlogInfo(\" usbmuxd-instance-manager\");\n\tlogInfo(\" usbmuxd-instance-manager --batchSize 6 --basePort 27020\");\n\tlogInfo(\"\");\n\tprocess.exit(0);\n}\n\n// Start the service\ntry {\n\tservice.start();\n} catch (error) {\n\tlogError(\"Failed to start service:\", error);\n\tprocess.exit(1);\n}\n", "import { EventEmitter } from \"node:events\";\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport UsbDeviceListener from \"@mcesystems/usb-device-listener\";\nimport type { DeviceInfo } from \"@mcesystems/usb-device-listener\";\nimport { InstanceManager } from \"./InstanceManager.js\";\nimport type { DeviceMapping, InstanceManagerConfig, UsbmuxdInstance } from \"./types/index.js\";\n\nconst { logInfo, logError } = createLoggers(\"usbmuxd-instance-manager\");\n\n/**\n * Main service that integrates usb-device-listener with InstanceManager\n * Monitors iOS devices and manages usbmuxd instances automatically.\n * Extends EventEmitter: forwards instance-started, instance-stopped, device-assigned,\n * device-removed, instance-log, instance-exited from the underlying manager.\n */\nexport class UsbmuxdService extends EventEmitter {\n\tprivate manager: InstanceManager;\n\tprivate usbListener: UsbDeviceListener;\n\tprivate isListening = false;\n\n\tconstructor(config: Partial<InstanceManagerConfig> = {}) {\n\t\tsuper();\n\t\tthis.manager = new InstanceManager(config);\n\t\tthis.usbListener = new UsbDeviceListener();\n\t\tthis.setupEventHandlers();\n\t}\n\n\t/**\n\t * Forward manager events to service subscribers (no logging; CLI/examples handle logging).\n\t */\n\tprivate setupEventHandlers(): void {\n\t\tthis.manager.on(\"instance-started\", (instance: UsbmuxdInstance) => {\n\t\t\tthis.emit(\"instance-started\", instance);\n\t\t});\n\n\t\tthis.manager.on(\"instance-stopped\", (instance: UsbmuxdInstance) => {\n\t\t\tthis.emit(\"instance-stopped\", instance);\n\t\t});\n\n\t\tthis.manager.on(\n\t\t\t\"device-assigned\",\n\t\t\t(payload: { device: DeviceInfo; instance: UsbmuxdInstance; mapping: DeviceMapping }) => {\n\t\t\t\tthis.emit(\"device-assigned\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"device-removed\",\n\t\t\t(payload: { device: DeviceInfo; instance: UsbmuxdInstance }) => {\n\t\t\t\tthis.emit(\"device-removed\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"instance-log\",\n\t\t\t(payload: { instanceId: number; level: string; message: string }) => {\n\t\t\t\tthis.emit(\"instance-log\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"instance-exited\",\n\t\t\t(payload: { instanceId: number; code: number | null; signal: string | null }) => {\n\t\t\t\tthis.emit(\"instance-exited\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\"device-paired\", (payload: { udid: string; mapping: DeviceMapping }) => {\n\t\t\tthis.emit(\"device-paired\", payload);\n\t\t});\n\t}\n\n\t/**\n\t * Start the service\n\t * Begins monitoring for iOS devices\n\t */\n\tpublic start(): void {\n\t\tif (this.isListening) {\n\t\t\tthrow new Error(\"Service is already running\");\n\t\t}\n\n\t\tconst config = this.manager.getConfig();\n\n\t\t// Convert Apple VID from hex to decimal for comparison\n\t\tconst appleVid = Number.parseInt(config.appleVendorId, 16);\n\n\t\tlogInfo(\"Starting service...\");\n\t\tlogInfo(`Batch size: ${config.batchSize} devices per instance`);\n\t\tlogInfo(`Base port: ${config.basePort}`);\n\t\tlogInfo(`Max instances: ${config.maxInstances}`);\n\t\tlogInfo(`usbmuxd path: ${config.usbmuxdPath}`);\n\t\tlogInfo(`Monitoring Apple devices (VID: ${config.appleVendorId})`);\n\n\t\t// Set up device listener callbacks\n\t\tthis.usbListener.onDeviceAdd(async (device: DeviceInfo) => {\n\t\t\t// Filter for Apple devices only\n\t\t\tif (device.vid !== appleVid) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlogInfo(`Apple device connected: ${device.deviceId} (${device.deviceName || \"Unknown\"})`);\n\n\t\t\ttry {\n\t\t\t\tawait this.manager.onDeviceConnected(device);\n\t\t\t} catch (error) {\n\t\t\t\tlogError(\"Error handling device connection:\", error);\n\t\t\t}\n\t\t});\n\n\t\tthis.usbListener.onDeviceRemove(async (device: DeviceInfo) => {\n\t\t\t// Filter for Apple devices only\n\t\t\tif (device.vid !== appleVid) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlogInfo(`Apple device disconnected: ${device.deviceId}`);\n\n\t\t\ttry {\n\t\t\t\tawait this.manager.onDeviceDisconnected(device);\n\t\t\t} catch (error) {\n\t\t\t\tlogError(\"Error handling device disconnection:\", error);\n\t\t\t}\n\t\t});\n\n\t\t// Start listening for USB events\n\t\ttry {\n\t\t\tthis.usbListener.startListening({\n\t\t\t\ttargetDevices: [], // Monitor all devices, we'll filter by VID\n\t\t\t});\n\n\t\t\tthis.isListening = true;\n\t\t\tthis.manager.start();\n\n\t\t\tlogInfo(\"Service started successfully\");\n\t\t\tlogInfo(\"Waiting for iOS devices...\");\n\t\t} catch (error) {\n\t\t\tlogError(\"Failed to start USB listener:\", error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the service\n\t * Stops monitoring and terminates all instances\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (!this.isListening) {\n\t\t\treturn;\n\t\t}\n\n\t\tlogInfo(\"Stopping service...\");\n\n\t\t// Stop USB listener\n\t\tthis.usbListener.stopListening();\n\t\tthis.isListening = false;\n\n\t\t// Stop all instances\n\t\tawait this.manager.stop();\n\n\t\tlogInfo(\"Service stopped\");\n\t}\n\n\t/**\n\t * Get device port mapping\n\t */\n\tpublic getDevicePort(udid: string): number | null {\n\t\treturn this.manager.getDevicePort(udid);\n\t}\n\n\t/**\n\t * Get all device mappings\n\t */\n\tpublic getDeviceMappings() {\n\t\treturn this.manager.getDeviceMappings();\n\t}\n\n\t/**\n\t * Get all running instances\n\t */\n\tpublic getInstances() {\n\t\treturn this.manager.getInstances();\n\t}\n\n\t/**\n\t * Get service statistics\n\t */\n\tpublic getStats() {\n\t\treturn this.manager.getStats();\n\t}\n\n\t/**\n\t * Get current configuration\n\t */\n\tpublic getConfig() {\n\t\treturn this.manager.getConfig();\n\t}\n\n\t/**\n\t * Pair a device with the usbmuxd host.\n\t * This is required once per device before most commands will work.\n\t * The pairing record is stored in WSL and persists across restarts.\n\t *\n\t * @param udid Device UDID to pair\n\t * @param goIosPath Optional path to go-ios binary\n\t * @returns true if pairing succeeded, false otherwise\n\t */\n\tpublic async pairDevice(udid: string, goIosPath?: string): Promise<boolean> {\n\t\treturn this.manager.pairDevice(udid, goIosPath);\n\t}\n}\n", "import { type ChildProcess, exec, spawn } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport { promisify } from \"node:util\";\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport type {\n\tDeviceInfo,\n\tDeviceMapping,\n\tInstanceManagerConfig,\n\tManagerStats,\n\tUsbmuxdInstance,\n} from \"./types/index.js\";\n\nconst { logInfo, logWarning } = createLoggers(\"usbmuxd-instance-manager\");\n\nconst execAsync = promisify(exec);\n\n/**\n * Path to usbipd executable (Program Files location on Windows)\n */\nconst USBIPD_PATH = '\"C:\\\\Program Files\\\\usbipd-win\\\\usbipd.exe\"';\n\n/**\n * Represents a USB device from usbipd list output\n */\ninterface UsbipdDevice {\n\tbusId: string;\n\tvid: string;\n\tpid: string;\n\tdescription: string;\n\tstate: string;\n}\n\n/**\n * Parse usbipd list output to extract device information\n */\nfunction parseUsbipdList(output: string): UsbipdDevice[] {\n\tconst devices: UsbipdDevice[] = [];\n\t// Handle both \\r\\n and \\n line endings\n\tconst lines = output.split(/\\r?\\n/);\n\n\tfor (const line of lines) {\n\t\t// Format: \"4-5 05ac:12a8 Apple Mobile Device USB Composite Device Shared (forced)\"\n\t\t// More flexible regex: busid, vid:pid, then anything else\n\t\tconst match = line.match(/^(\\d+-\\d+)\\s+([0-9a-f]{4}):([0-9a-f]{4})\\s+(.+)$/i);\n\t\tif (match) {\n\t\t\t// Split the rest into description and state (state is the last word(s) after multiple spaces)\n\t\t\tconst rest = match[4].trim();\n\t\t\tconst stateMatch = rest.match(/^(.+?)\\s{2,}(\\S.*)$/);\n\t\t\tconst description = stateMatch ? stateMatch[1].trim() : rest;\n\t\t\tconst state = stateMatch ? stateMatch[2].trim() : \"Unknown\";\n\n\t\t\tdevices.push({\n\t\t\t\tbusId: match[1],\n\t\t\t\tvid: match[2].toUpperCase(),\n\t\t\t\tpid: match[3].toUpperCase(),\n\t\t\t\tdescription,\n\t\t\t\tstate,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn devices;\n}\n\n/**\n * Default configuration for the instance manager\n */\nconst DEFAULT_CONFIG: InstanceManagerConfig = {\n\tbatchSize: 4,\n\tbasePort: 27015,\n\tmaxInstances: 20,\n\tusbmuxdPath: \"usbmuxd\", // Path inside WSL2\n\twslDistribution: \"alpine-usbmuxd-build\", // Alpine WSL2 distribution name\n\tverboseLogging: true,\n\tappleVendorId: \"05AC\",\n};\n\n/**\n * Manages multiple usbmuxd instances with batch device allocation\n *\n * @example\n * const manager = new InstanceManager({\n * batchSize: 4,\n * basePort: 27015,\n * });\n *\n * manager.on('instance-started', (instance) => {\n * logInfo(`Instance ${instance.id} started on port ${instance.port}`);\n * });\n *\n * manager.start();\n */\nexport class InstanceManager extends EventEmitter {\n\tprivate config: InstanceManagerConfig;\n\tprivate instances: Map<number, UsbmuxdInstance> = new Map();\n\tprivate deviceMappings: Map<string, DeviceMapping> = new Map();\n\tprivate processes: Map<number, ChildProcess> = new Map();\n\tprivate nextInstanceId = 1;\n\tprivate startedAt: Date | null = null;\n\tprivate isRunning = false;\n\n\t/** Tracks which devices have been attached to WSL */\n\tprivate attachedDevices: Set<string> = new Set();\n\n\t/** Cached WSL IP address for connecting from Windows */\n\tprivate wslIpAddress: string | null = null;\n\n\tconstructor(config: Partial<InstanceManagerConfig> = {}) {\n\t\tsuper();\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\t/**\n\t * Detect the WSL2 IP address for the configured distribution\n\t * This IP is needed to connect from Windows to services inside WSL\n\t */\n\tprivate async detectWslIpAddress(): Promise<string> {\n\t\tif (this.wslIpAddress) {\n\t\t\treturn this.wslIpAddress;\n\t\t}\n\n\t\tconst distro = this.config.wslDistribution || \"alpine-usbmuxd-build\";\n\n\t\ttry {\n\t\t\t// Try to get IP from eth0 interface\n\t\t\tconst { stdout } = await execAsync(`wsl -d ${distro} -- ip -4 addr show eth0`);\n\t\t\tconst match = stdout.match(/inet\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)/);\n\t\t\tif (match) {\n\t\t\t\tthis.wslIpAddress = match[1];\n\t\t\t\tlogInfo(`Detected WSL IP address: ${this.wslIpAddress}`);\n\t\t\t\treturn this.wslIpAddress;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to detect WSL IP via ip addr: ${error}`);\n\t\t}\n\n\t\t// Fallback: try hostname -I\n\t\ttry {\n\t\t\tconst { stdout } = await execAsync(`wsl -d ${distro} -- hostname -I`);\n\t\t\tconst ip = stdout.trim().split(/\\s+/)[0];\n\t\t\tif (ip && /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(ip)) {\n\t\t\t\tthis.wslIpAddress = ip;\n\t\t\t\tlogInfo(`Detected WSL IP address (hostname): ${this.wslIpAddress}`);\n\t\t\t\treturn this.wslIpAddress;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to detect WSL IP via hostname: ${error}`);\n\t\t}\n\n\t\t// Last resort fallback - localhost (may work with WSL2 mirrored networking)\n\t\tlogWarning(\"Could not detect WSL IP, falling back to localhost\");\n\t\tthis.wslIpAddress = \"127.0.0.1\";\n\t\treturn this.wslIpAddress;\n\t}\n\n\t/**\n\t * Start the instance manager\n\t */\n\tpublic start(): void {\n\t\tif (this.isRunning) {\n\t\t\tthrow new Error(\"Instance manager is already running\");\n\t\t}\n\n\t\tthis.isRunning = true;\n\t\tthis.startedAt = new Date();\n\t\tthis.emit(\"started\");\n\t}\n\n\t/**\n\t * Stop the instance manager and all instances\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (!this.isRunning) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.isRunning = false;\n\n\t\t// Detach all devices from WSL\n\t\tconst detachPromises = Array.from(this.attachedDevices).map((busId) =>\n\t\t\tthis.detachDeviceFromWsl(busId)\n\t\t);\n\t\tawait Promise.all(detachPromises);\n\t\tthis.attachedDevices.clear();\n\n\t\t// Stop all instances\n\t\tconst stopPromises = Array.from(this.instances.keys()).map((id) => this.stopInstance(id));\n\n\t\tawait Promise.all(stopPromises);\n\n\t\tthis.instances.clear();\n\t\tthis.deviceMappings.clear();\n\t\tthis.processes.clear();\n\n\t\tthis.emit(\"stopped\");\n\t}\n\n\t/**\n\t * Find the usbipd bus ID for a device by matching VID/PID\n\t */\n\tprivate async findBusIdForDevice(device: DeviceInfo): Promise<string | null> {\n\t\ttry {\n\t\t\tconst { stdout } = await execAsync(`${USBIPD_PATH} list`);\n\t\t\tconst usbipdDevices = parseUsbipdList(stdout);\n\n\t\t\t// Convert device VID/PID to hex string for comparison\n\t\t\tconst deviceVid = device.vid.toString(16).toUpperCase().padStart(4, \"0\");\n\t\t\tconst devicePid = device.pid.toString(16).toUpperCase().padStart(4, \"0\");\n\n\t\t\tlogInfo(`Looking for device with VID:PID ${deviceVid}:${devicePid}`);\n\t\t\tlogInfo(`Found ${usbipdDevices.length} devices from usbipd list`);\n\n\t\t\t// Find matching device by VID/PID\n\t\t\tconst match = usbipdDevices.find((d) => d.vid === deviceVid && d.pid === devicePid);\n\n\t\t\tif (match) {\n\t\t\t\tlogInfo(\n\t\t\t\t\t`Found usbipd bus ID ${match.busId} for device ${device.deviceId} (${deviceVid}:${devicePid})`\n\t\t\t\t);\n\t\t\t\treturn match.busId;\n\t\t\t}\n\n\t\t\t// Debug: log all parsed devices to help diagnose\n\t\t\tfor (const d of usbipdDevices) {\n\t\t\t\tlogInfo(` usbipd device: ${d.busId} ${d.vid}:${d.pid} \"${d.description}\"`);\n\t\t\t}\n\n\t\t\tlogWarning(\n\t\t\t\t`Could not find usbipd bus ID for device ${device.deviceId} (${deviceVid}:${devicePid})`\n\t\t\t);\n\t\t\treturn null;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to run usbipd list: ${error}`);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Ensure the WSL distribution is running\n\t */\n\tprivate async ensureWslRunning(): Promise<boolean> {\n\t\tconst distro = this.config.wslDistribution;\n\n\t\ttry {\n\t\t\tif (distro) {\n\t\t\t\t// Start specific distribution\n\t\t\t\tlogInfo(`Starting WSL distribution: ${distro}...`);\n\t\t\t\tawait execAsync(`wsl -d ${distro} -- echo \"WSL started\"`);\n\t\t\t} else {\n\t\t\t\t// Start default WSL\n\t\t\t\tlogInfo(\"Starting default WSL distribution...\");\n\t\t\t\tawait execAsync(`wsl -- echo \"WSL started\"`);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to start WSL: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Attach a device to WSL via usbipd\n\t * Note: This requires administrator privileges\n\t */\n\tprivate async attachDeviceToWsl(busId: string): Promise<boolean> {\n\t\tconst distro = this.config.wslDistribution;\n\n\t\ttry {\n\t\t\t// Ensure WSL is running first\n\t\t\tawait this.ensureWslRunning();\n\n\t\t\t// Bind the device (make it shareable)\n\t\t\tlogInfo(`Binding device ${busId}...`);\n\t\t\tawait execAsync(`${USBIPD_PATH} bind --busid ${busId} --force`);\n\n\t\t\t// Attach to WSL (use specific distro if configured, otherwise let usbipd pick)\n\t\t\tif (distro) {\n\t\t\t\tlogInfo(`Attaching device ${busId} to WSL distribution ${distro}...`);\n\t\t\t\tawait execAsync(`${USBIPD_PATH} attach --wsl=${distro} --busid=${busId}`);\n\t\t\t} else {\n\t\t\t\tlogInfo(`Attaching device ${busId} to default WSL...`);\n\t\t\t\tawait execAsync(`${USBIPD_PATH} attach --wsl --busid=${busId}`);\n\t\t\t}\n\n\t\t\tlogInfo(`Device ${busId} attached to WSL successfully`);\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to attach device ${busId} to WSL: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Detach a device from WSL via usbipd\n\t */\n\tprivate async detachDeviceFromWsl(busId: string): Promise<void> {\n\t\ttry {\n\t\t\tawait execAsync(`${USBIPD_PATH} detach --busid=${busId}`);\n\t\t\tlogInfo(`Device ${busId} detached from WSL`);\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to detach device ${busId}: ${error}`);\n\t\t}\n\t}\n\n\t/**\n\t * Handle device connection\n\t * Attaches device to WSL, then assigns to an existing instance or creates a new one\n\t */\n\tpublic async onDeviceConnected(device: DeviceInfo): Promise<void> {\n\t\t// Check if device is already mapped\n\t\tif (this.deviceMappings.has(device.deviceId)) {\n\t\t\tlogWarning(`Device ${device.deviceId} is already connected`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Step 1: Find the usbipd bus ID for this device\n\t\tconst busId = await this.findBusIdForDevice(device);\n\t\tif (!busId) {\n\t\t\tlogWarning(`Cannot attach device ${device.deviceId} - bus ID not found`);\n\t\t\t// Continue anyway - maybe it's already attached or not needed\n\t\t}\n\n\t\t// Step 2: Attach device to WSL (if not already attached)\n\t\tif (busId && !this.attachedDevices.has(busId)) {\n\t\t\tconst attached = await this.attachDeviceToWsl(busId);\n\t\t\tif (attached) {\n\t\t\t\tthis.attachedDevices.add(busId);\n\t\t\t\t// Give WSL a moment to recognize the device\n\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t\t\t}\n\t\t}\n\n\t\t// Step 3: Find an instance with available capacity\n\t\tlet targetInstance = this.findInstanceWithCapacity();\n\n\t\t// If no instance has capacity, create a new one\n\t\tif (!targetInstance) {\n\t\t\tif (this.instances.size >= this.config.maxInstances) {\n\t\t\t\tthrow new Error(`Maximum number of instances (${this.config.maxInstances}) reached`);\n\t\t\t}\n\n\t\t\ttargetInstance = await this.createInstance();\n\t\t}\n\n\t\t// Add device to instance\n\t\ttargetInstance.deviceUdids.push(device.deviceId);\n\n\t\t// Create mapping (include host and busId for cleanup on disconnect)\n\t\tconst mapping: DeviceMapping = {\n\t\t\tudid: device.deviceId,\n\t\t\tinstanceId: targetInstance.id,\n\t\t\thost: targetInstance.host,\n\t\t\tport: targetInstance.port,\n\t\t\taddedAt: new Date(),\n\t\t\tbusId: busId ?? undefined,\n\t\t};\n\n\t\tthis.deviceMappings.set(device.deviceId, mapping);\n\n\t\tthis.emit(\"device-assigned\", {\n\t\t\tdevice,\n\t\t\tinstance: targetInstance,\n\t\t\tmapping,\n\t\t});\n\t}\n\n\t/**\n\t * Pair a device with the usbmuxd host.\n\t * This is required once per device before most commands will work.\n\t * The pairing record is stored in WSL and persists across restarts.\n\t *\n\t * @param udid Device UDID to pair\n\t * @param goIosPath Optional path to go-ios binary (defaults to \"ios\")\n\t * @returns true if pairing succeeded, false otherwise\n\t */\n\tpublic async pairDevice(udid: string, goIosPath = \"ios\"): Promise<boolean> {\n\t\tconst mapping = this.deviceMappings.get(udid);\n\t\tif (!mapping) {\n\t\t\tlogWarning(`Cannot pair device ${udid} - not found in mappings`);\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst socketAddress = `${mapping.host}:${mapping.port}`;\n\t\t\tlogInfo(`Pairing device ${udid} via ${socketAddress}...`);\n\n\t\t\t// Run go-ios pair command with USBMUXD_SOCKET_ADDRESS set\n\t\t\tconst { stderr } = await execAsync(`\"${goIosPath}\" pair --udid=${udid}`, {\n\t\t\t\tenv: { ...process.env, USBMUXD_SOCKET_ADDRESS: socketAddress },\n\t\t\t});\n\n\t\t\tif (stderr?.includes(\"error\")) {\n\t\t\t\tlogWarning(`Pairing warning for ${udid}: ${stderr}`);\n\t\t\t}\n\n\t\t\tlogInfo(`Device ${udid} paired successfully`);\n\t\t\tthis.emit(\"device-paired\", { udid, mapping });\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to pair device ${udid}: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Handle device disconnection\n\t * Detaches from WSL, removes device from instance, and stops instance if empty\n\t */\n\tpublic async onDeviceDisconnected(device: DeviceInfo): Promise<void> {\n\t\tconst mapping = this.deviceMappings.get(device.deviceId);\n\t\tif (!mapping) {\n\t\t\tlogWarning(`Device ${device.deviceId} was not tracked`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Detach device from WSL if it was attached\n\t\tif (mapping.busId) {\n\t\t\tawait this.detachDeviceFromWsl(mapping.busId);\n\t\t\tthis.attachedDevices.delete(mapping.busId);\n\t\t}\n\n\t\tconst instance = this.instances.get(mapping.instanceId);\n\t\tif (!instance) {\n\t\t\tlogWarning(`Instance ${mapping.instanceId} not found`);\n\t\t\tthis.deviceMappings.delete(device.deviceId);\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove device from instance\n\t\tconst deviceIndex = instance.deviceUdids.indexOf(device.deviceId);\n\t\tif (deviceIndex > -1) {\n\t\t\tinstance.deviceUdids.splice(deviceIndex, 1);\n\t\t}\n\n\t\t// Remove mapping\n\t\tthis.deviceMappings.delete(device.deviceId);\n\n\t\tthis.emit(\"device-removed\", {\n\t\t\tdevice,\n\t\t\tinstance,\n\t\t});\n\n\t\t// If instance is now empty, stop it\n\t\tif (instance.deviceUdids.length === 0) {\n\t\t\tawait this.stopInstance(instance.id);\n\t\t}\n\t}\n\n\t/**\n\t * Find an instance with available capacity\n\t */\n\tprivate findInstanceWithCapacity(): UsbmuxdInstance | null {\n\t\tfor (const instance of this.instances.values()) {\n\t\t\tif (instance.deviceUdids.length < this.config.batchSize) {\n\t\t\t\treturn instance;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a new usbmuxd instance\n\t */\n\tprivate async createInstance(): Promise<UsbmuxdInstance> {\n\t\tconst instanceId = this.nextInstanceId++;\n\t\tconst port = this.config.basePort + instanceId - 1;\n\n\t\t// Detect WSL IP for connecting from Windows\n\t\tconst host = await this.detectWslIpAddress();\n\n\t\t// Build usbmuxd arguments\n\t\tconst usbmuxdArgs = [\n\t\t\t\"-f\", // Foreground\n\t\t\t\"-v\", // Verbose (if enabled)\n\t\t\t\"-S\",\n\t\t\t`0.0.0.0:${port}`, // Listen on all interfaces (for Windows \u2192 WSL2)\n\t\t\t\"--pidfile\",\n\t\t\t\"NONE\",\n\t\t];\n\n\t\tif (!this.config.verboseLogging) {\n\t\t\t// Remove -v if not verbose\n\t\t\tusbmuxdArgs.splice(1, 1);\n\t\t}\n\n\t\t// Build WSL command: wsl -d <distro> usbmuxd <args>\n\t\tconst wslArgs = [\n\t\t\t\"-d\",\n\t\t\tthis.config.wslDistribution || \"alpine-usbmuxd-build\",\n\t\t\tthis.config.usbmuxdPath,\n\t\t\t...usbmuxdArgs,\n\t\t];\n\n\t\t// Spawn via WSL\n\t\tconst process = spawn(\"wsl\", wslArgs, {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: false, // Show console for debugging\n\t\t});\n\n\t\t// Handle process output\n\t\tprocess.stdout?.on(\"data\", (data) => {\n\t\t\tthis.emit(\"instance-log\", {\n\t\t\t\tinstanceId,\n\t\t\t\tlevel: \"info\",\n\t\t\t\tmessage: data.toString().trim(),\n\t\t\t});\n\t\t});\n\n\t\tprocess.stderr?.on(\"data\", (data) => {\n\t\t\tthis.emit(\"instance-log\", {\n\t\t\t\tinstanceId,\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage: data.toString().trim(),\n\t\t\t});\n\t\t});\n\n\t\t// Handle process exit\n\t\tprocess.on(\"exit\", (code, signal) => {\n\t\t\tthis.emit(\"instance-exited\", {\n\t\t\t\tinstanceId,\n\t\t\t\tcode,\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\t// Clean up instance and process references, but keep device mappings intact.\n\t\t\t// Device mappings represent the logical port assignment and should only be\n\t\t\t// removed when the device is physically disconnected (via onDeviceDisconnected).\n\t\t\t// Consumers can listen to 'instance-exited' to react to unexpected exits.\n\t\t\tif (this.instances.has(instanceId)) {\n\t\t\t\tthis.instances.delete(instanceId);\n\t\t\t\tthis.processes.delete(instanceId);\n\t\t\t}\n\t\t});\n\n\t\t// Create instance record (pid is set synchronously by Node after spawn)\n\t\tconst pid = process.pid;\n\t\tif (pid === undefined) {\n\t\t\tprocess.kill(\"SIGKILL\");\n\t\t\tthrow new Error(\"Failed to get PID for usbmuxd instance\");\n\t\t}\n\t\tconst instance: UsbmuxdInstance = {\n\t\t\tid: instanceId,\n\t\t\thost,\n\t\t\tport,\n\t\t\tpid,\n\t\t\tdeviceUdids: [],\n\t\t\tstartedAt: new Date(),\n\t\t};\n\n\t\tthis.instances.set(instanceId, instance);\n\t\tthis.processes.set(instanceId, process);\n\n\t\tthis.emit(\"instance-started\", instance);\n\n\t\t// Wait a bit for the instance to start listening\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t\treturn instance;\n\t}\n\n\t/**\n\t * Stop a specific instance\n\t */\n\tprivate async stopInstance(instanceId: number): Promise<void> {\n\t\tconst instance = this.instances.get(instanceId);\n\t\tconst process = this.processes.get(instanceId);\n\n\t\tif (!instance || !process) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Kill the process\n\t\tprocess.kill(\"SIGTERM\");\n\n\t\t// Wait for process to exit\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t// Force kill if not exited\n\t\t\t\tif (!process.killed) {\n\t\t\t\t\tprocess.kill(\"SIGKILL\");\n\t\t\t\t}\n\t\t\t\tresolve();\n\t\t\t}, 5000);\n\n\t\t\tprocess.once(\"exit\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\n\t\t// Clean up\n\t\tthis.instances.delete(instanceId);\n\t\tthis.processes.delete(instanceId);\n\n\t\t// Remove device mappings\n\t\tfor (const [udid, mapping] of this.deviceMappings.entries()) {\n\t\t\tif (mapping.instanceId === instanceId) {\n\t\t\t\tthis.deviceMappings.delete(udid);\n\t\t\t}\n\t\t}\n\n\t\tthis.emit(\"instance-stopped\", instance);\n\t}\n\n\t/**\n\t * Get device-to-port mapping for a specific UDID\n\t */\n\tpublic getDevicePort(udid: string): number | null {\n\t\tconst mapping = this.deviceMappings.get(udid);\n\t\treturn mapping ? mapping.port : null;\n\t}\n\n\t/**\n\t * Get all device mappings\n\t */\n\tpublic getDeviceMappings(): DeviceMapping[] {\n\t\treturn Array.from(this.deviceMappings.values());\n\t}\n\n\t/**\n\t * Get all running instances\n\t */\n\tpublic getInstances(): UsbmuxdInstance[] {\n\t\treturn Array.from(this.instances.values());\n\t}\n\n\t/**\n\t * Get manager statistics\n\t */\n\tpublic getStats(): ManagerStats {\n\t\tconst now = Date.now();\n\t\tconst startTime = this.startedAt?.getTime() || now;\n\t\tconst uptimeSeconds = Math.floor((now - startTime) / 1000);\n\n\t\treturn {\n\t\t\tinstanceCount: this.instances.size,\n\t\t\tdeviceCount: this.deviceMappings.size,\n\t\t\tuptimeSeconds,\n\t\t\tstartedAt: this.startedAt || new Date(),\n\t\t};\n\t}\n\n\t/**\n\t * Get current configuration\n\t */\n\tpublic getConfig(): InstanceManagerConfig {\n\t\treturn { ...this.config };\n\t}\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_tool_debug_g4", "import_node_events", "import_tool_debug_g4", "config", "process", "logInfo", "config", "UsbDeviceListener", "logInfo", "logError"]
|
|
3
|
+
"sources": ["../src/cli.ts", "../src/UsbmuxdService.ts", "../src/InstanceManager.ts", "../src/LockdownSync.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport { UsbmuxdService } from \"./UsbmuxdService.js\";\n\nconst { logInfo, logError, logHeader, logDataObject } = createLoggers(\"usbmuxd-cli\");\n\n// Parse command line arguments\nconst args = process.argv.slice(2);\nconst options: Record<string, string> = {};\n\nfor (let i = 0; i < args.length; i++) {\n\tif (args[i].startsWith(\"--\")) {\n\t\tconst key = args[i].substring(2);\n\t\tconst value = args[i + 1];\n\t\tif (value && !value.startsWith(\"--\")) {\n\t\t\toptions[key] = value;\n\t\t\ti++;\n\t\t}\n\t}\n}\n\n// Build configuration from command line\n// usbmuxdPath is the binary run inside WSL (Alpine) \u2014 must be the Linux usbmuxd, not the Windows exe\nconst config = {\n\tbatchSize: options.batchSize ? Number.parseInt(options.batchSize, 10) : 4,\n\tbasePort: options.basePort ? Number.parseInt(options.basePort, 10) : 27015,\n\tmaxInstances: options.maxInstances ? Number.parseInt(options.maxInstances, 10) : 20,\n\tusbmuxdPath: options.usbmuxdPath || \"usbmuxd\",\n\tverboseLogging: options.verbose !== \"false\",\n\tappleVendorId: options.appleVid || \"05AC\",\n};\n\nlogHeader(\"usbmuxd Instance Manager\");\nlogDataObject(\"Multi-instance manager for iOS device connections\", { config });\n\n// Create and start service\nconst service = new UsbmuxdService(config);\n\n// Handle graceful shutdown\nprocess.on(\"SIGINT\", async () => {\n\tlogInfo(\"\");\n\tlogInfo(\"Received SIGINT, shutting down gracefully...\");\n\ttry {\n\t\tawait service.stop();\n\t\tlogInfo(\"Shutdown complete\");\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tlogError(\"Error during shutdown:\", error);\n\t\tprocess.exit(1);\n\t}\n});\n\nprocess.on(\"SIGTERM\", async () => {\n\tlogInfo(\"\");\n\tlogInfo(\"Received SIGTERM, shutting down gracefully...\");\n\ttry {\n\t\tawait service.stop();\n\t\tlogInfo(\"Shutdown complete\");\n\t\tprocess.exit(0);\n\t} catch (error) {\n\t\tlogError(\"Error during shutdown:\", error);\n\t\tprocess.exit(1);\n\t}\n});\n\n// Print stats every 30 seconds\nsetInterval(() => {\n\tconst stats = service.getStats();\n\tconst instances = service.getInstances();\n\n\tlogHeader(\n\t\t`Uptime: ${stats.uptimeSeconds}s | Instances: ${stats.instanceCount} | Devices: ${stats.deviceCount}`\n\t);\n\n\tif (instances.length > 0) {\n\t\tlogDataObject(\"Active instances:\", { instances });\n\t}\n}, 30000);\n\n// Print help if --help flag (before starting service)\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n\tlogInfo(\"Usage: usbmuxd-instance-manager [OPTIONS]\");\n\tlogInfo(\"\");\n\tlogInfo(\"Options:\");\n\tlogInfo(\" --batchSize <n> Number of devices per instance (default: 4)\");\n\tlogInfo(\" --basePort <port> Base TCP port for first instance (default: 27015)\");\n\tlogInfo(\" --maxInstances <n> Maximum number of instances (default: 20)\");\n\tlogInfo(\" --usbmuxdPath <path> Path to usbmuxd executable\");\n\tlogInfo(\" --verbose <true|false> Enable verbose logging (default: true)\");\n\tlogInfo(\" --appleVid <vid> Apple Vendor ID in hex (default: 05AC)\");\n\tlogInfo(\" -h, --help Show this help message\");\n\tlogInfo(\"\");\n\tlogInfo(\"Examples:\");\n\tlogInfo(\" usbmuxd-instance-manager\");\n\tlogInfo(\" usbmuxd-instance-manager --batchSize 6 --basePort 27020\");\n\tlogInfo(\"\");\n\tprocess.exit(0);\n}\n\n// Start the service\ntry {\n\tservice.start();\n} catch (error) {\n\tlogError(\"Failed to start service:\", error);\n\tprocess.exit(1);\n}\n", "import { EventEmitter } from \"node:events\";\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport UsbDeviceListener from \"@mcesystems/usb-device-listener\";\nimport type { DeviceInfo } from \"@mcesystems/usb-device-listener\";\nimport { InstanceManager } from \"./InstanceManager.js\";\nimport type { DeviceMapping, InstanceManagerConfig, UsbmuxdInstance } from \"./types/index.js\";\n\nconst { logInfo, logError } = createLoggers(\"usbmuxd-instance-manager\");\n\n/**\n * Main service that integrates usb-device-listener with InstanceManager\n * Monitors iOS devices and manages usbmuxd instances automatically.\n * Extends EventEmitter: forwards instance-started, instance-stopped, device-assigned,\n * device-removed, instance-log, instance-exited from the underlying manager.\n */\nexport class UsbmuxdService extends EventEmitter {\n\tprivate manager: InstanceManager;\n\tprivate usbListener: UsbDeviceListener;\n\tprivate isListening = false;\n\n\tconstructor(config: Partial<InstanceManagerConfig> = {}) {\n\t\tsuper();\n\t\tthis.manager = new InstanceManager(config);\n\t\tthis.usbListener = new UsbDeviceListener();\n\t\tthis.setupEventHandlers();\n\t}\n\n\t/**\n\t * Forward manager events to service subscribers (no logging; CLI/examples handle logging).\n\t */\n\tprivate setupEventHandlers(): void {\n\t\tthis.manager.on(\"instance-started\", (instance: UsbmuxdInstance) => {\n\t\t\tthis.emit(\"instance-started\", instance);\n\t\t});\n\n\t\tthis.manager.on(\"instance-stopped\", (instance: UsbmuxdInstance) => {\n\t\t\tthis.emit(\"instance-stopped\", instance);\n\t\t});\n\n\t\tthis.manager.on(\n\t\t\t\"device-assigned\",\n\t\t\t(payload: { device: DeviceInfo; instance: UsbmuxdInstance; mapping: DeviceMapping }) => {\n\t\t\t\tthis.emit(\"device-assigned\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"device-removed\",\n\t\t\t(payload: { device: DeviceInfo; instance: UsbmuxdInstance }) => {\n\t\t\t\tthis.emit(\"device-removed\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"instance-log\",\n\t\t\t(payload: { instanceId: number; level: string; message: string }) => {\n\t\t\t\tthis.emit(\"instance-log\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\n\t\t\t\"instance-exited\",\n\t\t\t(payload: { instanceId: number; code: number | null; signal: string | null }) => {\n\t\t\t\tthis.emit(\"instance-exited\", payload);\n\t\t\t}\n\t\t);\n\n\t\tthis.manager.on(\"device-paired\", (payload: { udid: string; mapping: DeviceMapping }) => {\n\t\t\tthis.emit(\"device-paired\", payload);\n\t\t});\n\t}\n\n\t/**\n\t * Start the service\n\t * Begins monitoring for iOS devices\n\t */\n\tpublic start(): void {\n\t\tif (this.isListening) {\n\t\t\tthrow new Error(\"Service is already running\");\n\t\t}\n\n\t\tconst config = this.manager.getConfig();\n\n\t\t// Convert Apple VID from hex to decimal for comparison\n\t\tconst appleVid = Number.parseInt(config.appleVendorId, 16);\n\n\t\tlogInfo(\"Starting service...\");\n\t\tlogInfo(`Batch size: ${config.batchSize} devices per instance`);\n\t\tlogInfo(`Base port: ${config.basePort}`);\n\t\tlogInfo(`Max instances: ${config.maxInstances}`);\n\t\tlogInfo(`usbmuxd path: ${config.usbmuxdPath}`);\n\t\tlogInfo(`Monitoring Apple devices (VID: ${config.appleVendorId})`);\n\n\t\t// Set up device listener callbacks\n\t\tthis.usbListener.onDeviceAdd(async (device: DeviceInfo) => {\n\t\t\t// Filter for Apple devices only\n\t\t\tif (device.vid !== appleVid) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlogInfo(`Apple device connected: ${device.deviceId} (${device.deviceName || \"Unknown\"})`);\n\n\t\t\ttry {\n\t\t\t\tawait this.manager.onDeviceConnected(device);\n\t\t\t} catch (error) {\n\t\t\t\tlogError(\"Error handling device connection:\", error);\n\t\t\t}\n\t\t});\n\n\t\tthis.usbListener.onDeviceRemove(async (device: DeviceInfo) => {\n\t\t\t// Filter for Apple devices only\n\t\t\tif (device.vid !== appleVid) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlogInfo(`Apple device disconnected: ${device.deviceId}`);\n\n\t\t\ttry {\n\t\t\t\tawait this.manager.onDeviceDisconnected(device);\n\t\t\t} catch (error) {\n\t\t\t\tlogError(\"Error handling device disconnection:\", error);\n\t\t\t}\n\t\t});\n\n\t\t// Start listening for USB events\n\t\ttry {\n\t\t\tthis.usbListener.startListening({\n\t\t\t\ttargetDevices: [], // Monitor all devices, we'll filter by VID\n\t\t\t});\n\n\t\t\tthis.isListening = true;\n\t\t\tthis.manager.start();\n\n\t\t\tlogInfo(\"Service started successfully\");\n\t\t\tlogInfo(\"Waiting for iOS devices...\");\n\t\t} catch (error) {\n\t\t\tlogError(\"Failed to start USB listener:\", error);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Stop the service\n\t * Stops monitoring and terminates all instances\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (!this.isListening) {\n\t\t\treturn;\n\t\t}\n\n\t\tlogInfo(\"Stopping service...\");\n\n\t\t// Stop USB listener\n\t\tthis.usbListener.stopListening();\n\t\tthis.isListening = false;\n\n\t\t// Stop all instances\n\t\tawait this.manager.stop();\n\n\t\tlogInfo(\"Service stopped\");\n\t}\n\n\t/**\n\t * Get device port mapping\n\t */\n\tpublic getDevicePort(udid: string): number | null {\n\t\treturn this.manager.getDevicePort(udid);\n\t}\n\n\t/**\n\t * Get all device mappings\n\t */\n\tpublic getDeviceMappings() {\n\t\treturn this.manager.getDeviceMappings();\n\t}\n\n\t/**\n\t * Get all running instances\n\t */\n\tpublic getInstances() {\n\t\treturn this.manager.getInstances();\n\t}\n\n\t/**\n\t * Get service statistics\n\t */\n\tpublic getStats() {\n\t\treturn this.manager.getStats();\n\t}\n\n\t/**\n\t * Get current configuration\n\t */\n\tpublic getConfig() {\n\t\treturn this.manager.getConfig();\n\t}\n\n\t/**\n\t * Pair a device with the usbmuxd host.\n\t * This is required once per device before most commands will work.\n\t * The pairing record is stored in WSL and persists across restarts.\n\t *\n\t * @param udid Device UDID to pair\n\t * @param goIosPath Optional path to go-ios binary\n\t * @returns true if pairing succeeded, false otherwise\n\t */\n\tpublic async pairDevice(udid: string, goIosPath?: string): Promise<boolean> {\n\t\treturn this.manager.pairDevice(udid, goIosPath);\n\t}\n}\n", "import { type ChildProcess, exec, spawn } from \"node:child_process\";\nimport { EventEmitter } from \"node:events\";\nimport { promisify } from \"node:util\";\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport { syncFromAlpine, syncToAlpine } from \"./LockdownSync.js\";\nimport type {\n\tDeviceInfo,\n\tDeviceMapping,\n\tInstanceManagerConfig,\n\tManagerStats,\n\tUsbmuxdInstance,\n} from \"./types/index.js\";\n\nconst { logInfo, logWarning } = createLoggers(\"usbmuxd-instance-manager\");\n\nconst execAsync = promisify(exec);\n\n/**\n * Path to usbipd executable (Program Files location on Windows)\n */\nconst USBIPD_PATH = '\"C:\\\\Program Files\\\\usbipd-win\\\\usbipd.exe\"';\n\n/**\n * Represents a USB device from usbipd list output\n */\ninterface UsbipdDevice {\n\tbusId: string;\n\tvid: string;\n\tpid: string;\n\tdescription: string;\n\tstate: string;\n}\n\n/**\n * Parse usbipd list output to extract device information\n */\nfunction parseUsbipdList(output: string): UsbipdDevice[] {\n\tconst devices: UsbipdDevice[] = [];\n\t// Handle both \\r\\n and \\n line endings\n\tconst lines = output.split(/\\r?\\n/);\n\n\tfor (const line of lines) {\n\t\t// Format: \"4-5 05ac:12a8 Apple Mobile Device USB Composite Device Shared (forced)\"\n\t\t// More flexible regex: busid, vid:pid, then anything else\n\t\tconst match = line.match(/^(\\d+-\\d+)\\s+([0-9a-f]{4}):([0-9a-f]{4})\\s+(.+)$/i);\n\t\tif (match) {\n\t\t\t// Split the rest into description and state (state is the last word(s) after multiple spaces)\n\t\t\tconst rest = match[4].trim();\n\t\t\tconst stateMatch = rest.match(/^(.+?)\\s{2,}(\\S.*)$/);\n\t\t\tconst description = stateMatch ? stateMatch[1].trim() : rest;\n\t\t\tconst state = stateMatch ? stateMatch[2].trim() : \"Unknown\";\n\n\t\t\tdevices.push({\n\t\t\t\tbusId: match[1],\n\t\t\t\tvid: match[2].toUpperCase(),\n\t\t\t\tpid: match[3].toUpperCase(),\n\t\t\t\tdescription,\n\t\t\t\tstate,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn devices;\n}\n\n/**\n * Default configuration for the instance manager\n */\nconst DEFAULT_CONFIG: InstanceManagerConfig = {\n\tbatchSize: 4,\n\tbasePort: 27015,\n\tmaxInstances: 20,\n\tusbmuxdPath: \"usbmuxd\", // Path inside WSL2\n\twslDistribution: \"alpine-usbmuxd-build\", // Alpine WSL2 distribution name\n\tverboseLogging: true,\n\tappleVendorId: \"05AC\",\n\tlockdownWindowsPath: \"C:\\\\ProgramData\\\\mce\\\\lockdown\",\n\tlockdownSyncEnabled: true,\n};\n\n/**\n * Manages multiple usbmuxd instances with batch device allocation\n *\n * @example\n * const manager = new InstanceManager({\n * batchSize: 4,\n * basePort: 27015,\n * });\n *\n * manager.on('instance-started', (instance) => {\n * logInfo(`Instance ${instance.id} started on port ${instance.port}`);\n * });\n *\n * manager.start();\n */\nexport class InstanceManager extends EventEmitter {\n\tprivate config: InstanceManagerConfig;\n\tprivate instances: Map<number, UsbmuxdInstance> = new Map();\n\tprivate deviceMappings: Map<string, DeviceMapping> = new Map();\n\tprivate processes: Map<number, ChildProcess> = new Map();\n\tprivate nextInstanceId = 1;\n\tprivate startedAt: Date | null = null;\n\tprivate isRunning = false;\n\n\t/** Tracks which devices have been attached to WSL */\n\tprivate attachedDevices: Set<string> = new Set();\n\n\t/** Device IDs currently in the attach flow (ignore disconnect until attach completes) */\n\tprivate pendingAttachDevices: Set<string> = new Set();\n\n\t/** Cached WSL IP address for connecting from Windows */\n\tprivate wslIpAddress: string | null = null;\n\n\tconstructor(config: Partial<InstanceManagerConfig> = {}) {\n\t\tsuper();\n\t\tthis.config = { ...DEFAULT_CONFIG, ...config };\n\t}\n\n\t/**\n\t * Detect the WSL2 IP address for the configured distribution\n\t * This IP is needed to connect from Windows to services inside WSL\n\t */\n\tprivate async detectWslIpAddress(): Promise<string> {\n\t\tif (this.wslIpAddress) {\n\t\t\treturn this.wslIpAddress;\n\t\t}\n\n\t\tconst distro = this.config.wslDistribution || \"alpine-usbmuxd-build\";\n\n\t\ttry {\n\t\t\t// Try to get IP from eth0 interface\n\t\t\tconst { stdout } = await execAsync(`wsl -d ${distro} -- ip -4 addr show eth0`);\n\t\t\tconst match = stdout.match(/inet\\s+(\\d+\\.\\d+\\.\\d+\\.\\d+)/);\n\t\t\tif (match) {\n\t\t\t\tthis.wslIpAddress = match[1];\n\t\t\t\tlogInfo(`Detected WSL IP address: ${this.wslIpAddress}`);\n\t\t\t\treturn this.wslIpAddress;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to detect WSL IP via ip addr: ${error}`);\n\t\t}\n\n\t\t// Fallback: try hostname -I\n\t\ttry {\n\t\t\tconst { stdout } = await execAsync(`wsl -d ${distro} -- hostname -I`);\n\t\t\tconst ip = stdout.trim().split(/\\s+/)[0];\n\t\t\tif (ip && /^\\d+\\.\\d+\\.\\d+\\.\\d+$/.test(ip)) {\n\t\t\t\tthis.wslIpAddress = ip;\n\t\t\t\tlogInfo(`Detected WSL IP address (hostname): ${this.wslIpAddress}`);\n\t\t\t\treturn this.wslIpAddress;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to detect WSL IP via hostname: ${error}`);\n\t\t}\n\n\t\t// Last resort fallback - localhost (may work with WSL2 mirrored networking)\n\t\tlogWarning(\"Could not detect WSL IP, falling back to localhost\");\n\t\tthis.wslIpAddress = \"127.0.0.1\";\n\t\treturn this.wslIpAddress;\n\t}\n\n\t/**\n\t * Start the instance manager\n\t */\n\tpublic start(): void {\n\t\tif (this.isRunning) {\n\t\t\tthrow new Error(\"Instance manager is already running\");\n\t\t}\n\n\t\tthis.isRunning = true;\n\t\tthis.startedAt = new Date();\n\t\tthis.emit(\"started\");\n\t}\n\n\t/**\n\t * Stop the instance manager and all instances\n\t */\n\tpublic async stop(): Promise<void> {\n\t\tif (!this.isRunning) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.isRunning = false;\n\n\t\t// Sync lockdown files from Alpine to Windows (before clearing mappings)\n\t\tconst udids = Array.from(this.deviceMappings.keys());\n\t\tawait syncFromAlpine(udids, this.config);\n\n\t\t// Detach all devices from WSL\n\t\tconst detachPromises = Array.from(this.attachedDevices).map((busId) =>\n\t\t\tthis.detachDeviceFromWsl(busId)\n\t\t);\n\t\tawait Promise.all(detachPromises);\n\t\tthis.attachedDevices.clear();\n\n\t\t// Stop all instances\n\t\tconst stopPromises = Array.from(this.instances.keys()).map((id) => this.stopInstance(id));\n\n\t\tawait Promise.all(stopPromises);\n\n\t\tthis.instances.clear();\n\t\tthis.deviceMappings.clear();\n\t\tthis.processes.clear();\n\n\t\tthis.emit(\"stopped\");\n\t}\n\n\t/**\n\t * Find the usbipd bus ID for a device by matching VID/PID\n\t */\n\tprivate async findBusIdForDevice(device: DeviceInfo): Promise<string | null> {\n\t\ttry {\n\t\t\tconst { stdout } = await execAsync(`${USBIPD_PATH} list`);\n\t\t\tconst usbipdDevices = parseUsbipdList(stdout);\n\n\t\t\t// Convert device VID/PID to hex string for comparison\n\t\t\tconst deviceVid = device.vid.toString(16).toUpperCase().padStart(4, \"0\");\n\t\t\tconst devicePid = device.pid.toString(16).toUpperCase().padStart(4, \"0\");\n\n\t\t\tlogInfo(`Looking for device with VID:PID ${deviceVid}:${devicePid}`);\n\t\t\tlogInfo(`Found ${usbipdDevices.length} devices from usbipd list`);\n\n\t\t\t// Find matching device by VID/PID\n\t\t\tconst match = usbipdDevices.find((d) => d.vid === deviceVid && d.pid === devicePid);\n\n\t\t\tif (match) {\n\t\t\t\tlogInfo(\n\t\t\t\t\t`Found usbipd bus ID ${match.busId} for device ${device.deviceId} (${deviceVid}:${devicePid})`\n\t\t\t\t);\n\t\t\t\treturn match.busId;\n\t\t\t}\n\n\t\t\t// Debug: log all parsed devices to help diagnose\n\t\t\tfor (const d of usbipdDevices) {\n\t\t\t\tlogInfo(` usbipd device: ${d.busId} ${d.vid}:${d.pid} \"${d.description}\"`);\n\t\t\t}\n\n\t\t\tlogWarning(\n\t\t\t\t`Could not find usbipd bus ID for device ${device.deviceId} (${deviceVid}:${devicePid})`\n\t\t\t);\n\t\t\treturn null;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to run usbipd list: ${error}`);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Ensure the WSL distribution is running\n\t */\n\tprivate async ensureWslRunning(): Promise<boolean> {\n\t\tconst distro = this.config.wslDistribution;\n\n\t\ttry {\n\t\t\tif (distro) {\n\t\t\t\t// Start specific distribution\n\t\t\t\tlogInfo(`Starting WSL distribution: ${distro}...`);\n\t\t\t\tawait execAsync(`wsl -d ${distro} -- echo \"WSL started\"`);\n\t\t\t} else {\n\t\t\t\t// Start default WSL\n\t\t\t\tlogInfo(\"Starting default WSL distribution...\");\n\t\t\t\tawait execAsync(`wsl -- echo \"WSL started\"`);\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to start WSL: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Attach a device to WSL via usbipd\n\t * Note: This requires administrator privileges\n\t */\n\tprivate async attachDeviceToWsl(busId: string): Promise<boolean> {\n\t\tconst distro = this.config.wslDistribution;\n\n\t\ttry {\n\t\t\t// Ensure WSL is running first\n\t\t\tawait this.ensureWslRunning();\n\n\t\t\t// Bind the device (make it shareable)\n\t\t\tlogInfo(`Binding device ${busId}...`);\n\t\t\tawait execAsync(`${USBIPD_PATH} bind --busid ${busId} --force`);\n\n\t\t\t// Attach to WSL (use specific distro if configured, otherwise let usbipd pick)\n\t\t\tif (distro) {\n\t\t\t\tlogInfo(`Attaching device ${busId} to WSL distribution ${distro}...`);\n\t\t\t\tawait execAsync(`${USBIPD_PATH} attach --wsl=${distro} --busid=${busId}`);\n\t\t\t} else {\n\t\t\t\tlogInfo(`Attaching device ${busId} to default WSL...`);\n\t\t\t\tawait execAsync(`${USBIPD_PATH} attach --wsl --busid=${busId}`);\n\t\t\t}\n\n\t\t\tlogInfo(`Device ${busId} attached to WSL successfully`);\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t// Device already attached (e.g. from a previous run) \u2014 treat as success so we still start usbmuxd\n\t\t\tif (message.includes(\"already attached to a client\")) {\n\t\t\t\tlogInfo(`Device ${busId} is already attached to WSL, continuing`);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tlogWarning(`Failed to attach device ${busId} to WSL: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Detach a device from WSL via usbipd\n\t */\n\tprivate async detachDeviceFromWsl(busId: string): Promise<void> {\n\t\ttry {\n\t\t\tawait execAsync(`${USBIPD_PATH} detach --busid=${busId}`);\n\t\t\tlogInfo(`Device ${busId} detached from WSL`);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tif (message.includes(\"no device with busid\") || message.includes(\"There is no device\")) {\n\t\t\t\tlogInfo(`Device ${busId} already detached`);\n\t\t\t} else {\n\t\t\t\tlogWarning(`Failed to detach device ${busId}: ${error}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handle device connection\n\t * Attaches device to WSL, then assigns to an existing instance or creates a new one\n\t */\n\tpublic async onDeviceConnected(device: DeviceInfo): Promise<void> {\n\t\t// Check if device is already mapped\n\t\tif (this.deviceMappings.has(device.deviceId)) {\n\t\t\tlogWarning(`Device ${device.deviceId} is already connected`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Sync this device's lockdown file to Alpine so pairing can be skipped\n\t\tawait syncToAlpine(device.deviceId, this.config);\n\n\t\t// Step 1: Find the usbipd bus ID for this device\n\t\tconst busId = await this.findBusIdForDevice(device);\n\t\tif (!busId) {\n\t\t\tlogWarning(`Cannot attach device ${device.deviceId} - bus ID not found`);\n\t\t\t// Continue anyway - maybe it's already attached or not needed\n\t\t}\n\n\t\t// Step 2: Attach device to WSL (if not already attached)\n\t\tif (busId && !this.attachedDevices.has(busId)) {\n\t\t\tthis.pendingAttachDevices.add(device.deviceId);\n\t\t\ttry {\n\t\t\t\tconst attached = await this.attachDeviceToWsl(busId);\n\t\t\t\tif (attached) {\n\t\t\t\t\tthis.attachedDevices.add(busId);\n\t\t\t\t\t// Give WSL a moment to recognize the device\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 1000));\n\t\t\t\t}\n\t\t\t} finally {\n\t\t\t\tthis.pendingAttachDevices.delete(device.deviceId);\n\t\t\t}\n\t\t}\n\n\t\t// Step 3: Find an instance with available capacity\n\t\tlet targetInstance = this.findInstanceWithCapacity();\n\n\t\t// If no instance has capacity, create a new one\n\t\tif (!targetInstance) {\n\t\t\tif (this.instances.size >= this.config.maxInstances) {\n\t\t\t\tthrow new Error(`Maximum number of instances (${this.config.maxInstances}) reached`);\n\t\t\t}\n\n\t\t\ttargetInstance = await this.createInstance();\n\t\t}\n\n\t\t// Add device to instance\n\t\ttargetInstance.deviceUdids.push(device.deviceId);\n\n\t\t// Create mapping (include host and busId for cleanup on disconnect)\n\t\tconst mapping: DeviceMapping = {\n\t\t\tudid: device.deviceId,\n\t\t\tinstanceId: targetInstance.id,\n\t\t\thost: targetInstance.host,\n\t\t\tport: targetInstance.port,\n\t\t\taddedAt: new Date(),\n\t\t\tbusId: busId ?? undefined,\n\t\t};\n\n\t\tthis.deviceMappings.set(device.deviceId, mapping);\n\n\t\tthis.emit(\"device-assigned\", {\n\t\t\tdevice,\n\t\t\tinstance: targetInstance,\n\t\t\tmapping,\n\t\t});\n\t}\n\n\t/**\n\t * Pair a device with the usbmuxd host.\n\t * This is required once per device before most commands will work.\n\t * The pairing record is stored in WSL and persists across restarts.\n\t *\n\t * @param udid Device UDID to pair\n\t * @param goIosPath Optional path to go-ios binary (defaults to \"ios\")\n\t * @returns true if pairing succeeded, false otherwise\n\t */\n\tpublic async pairDevice(udid: string, goIosPath = \"ios\"): Promise<boolean> {\n\t\tconst mapping = this.deviceMappings.get(udid);\n\t\tif (!mapping) {\n\t\t\tlogWarning(`Cannot pair device ${udid} - not found in mappings`);\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst socketAddress = `${mapping.host}:${mapping.port}`;\n\t\t\tlogInfo(`Pairing device ${udid} via ${socketAddress}...`);\n\n\t\t\t// Run go-ios pair command with USBMUXD_SOCKET_ADDRESS set\n\t\t\tconst { stderr } = await execAsync(`\"${goIosPath}\" pair --udid=${udid}`, {\n\t\t\t\tenv: { ...process.env, USBMUXD_SOCKET_ADDRESS: socketAddress },\n\t\t\t});\n\n\t\t\tif (stderr?.includes(\"error\")) {\n\t\t\t\tlogWarning(`Pairing warning for ${udid}: ${stderr}`);\n\t\t\t}\n\n\t\t\tlogInfo(`Device ${udid} paired successfully`);\n\t\t\tthis.emit(\"device-paired\", { udid, mapping });\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tlogWarning(`Failed to pair device ${udid}: ${error}`);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Handle device disconnection\n\t * Detaches from WSL, removes device from instance, and stops instance if empty\n\t */\n\tpublic async onDeviceDisconnected(device: DeviceInfo): Promise<void> {\n\t\t// Ignore disconnect while we're still attaching this device (Windows sees disconnect when device moves to WSL)\n\t\tif (this.pendingAttachDevices.has(device.deviceId)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst mapping = this.deviceMappings.get(device.deviceId);\n\t\tif (!mapping) {\n\t\t\tlogWarning(`Device ${device.deviceId} was not tracked`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Detach device from WSL if it was attached\n\t\tif (mapping.busId) {\n\t\t\tawait this.detachDeviceFromWsl(mapping.busId);\n\t\t\tthis.attachedDevices.delete(mapping.busId);\n\t\t}\n\n\t\tconst instance = this.instances.get(mapping.instanceId);\n\t\tif (!instance) {\n\t\t\tlogWarning(`Instance ${mapping.instanceId} not found`);\n\t\t\tthis.deviceMappings.delete(device.deviceId);\n\t\t\treturn;\n\t\t}\n\n\t\t// Remove device from instance\n\t\tconst deviceIndex = instance.deviceUdids.indexOf(device.deviceId);\n\t\tif (deviceIndex > -1) {\n\t\t\tinstance.deviceUdids.splice(deviceIndex, 1);\n\t\t}\n\n\t\t// Remove mapping\n\t\tthis.deviceMappings.delete(device.deviceId);\n\n\t\tthis.emit(\"device-removed\", {\n\t\t\tdevice,\n\t\t\tinstance,\n\t\t});\n\n\t\t// If instance is now empty, stop it\n\t\tif (instance.deviceUdids.length === 0) {\n\t\t\tawait this.stopInstance(instance.id);\n\t\t}\n\t}\n\n\t/**\n\t * Find an instance with available capacity\n\t */\n\tprivate findInstanceWithCapacity(): UsbmuxdInstance | null {\n\t\tfor (const instance of this.instances.values()) {\n\t\t\tif (instance.deviceUdids.length < this.config.batchSize) {\n\t\t\t\treturn instance;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create a new usbmuxd instance\n\t */\n\tprivate async createInstance(): Promise<UsbmuxdInstance> {\n\t\tconst instanceId = this.nextInstanceId++;\n\t\tconst port = this.config.basePort + instanceId - 1;\n\n\t\t// Detect WSL IP for connecting from Windows\n\t\tconst host = await this.detectWslIpAddress();\n\n\t\t// Build usbmuxd arguments\n\t\tconst usbmuxdArgs = [\n\t\t\t\"-f\", // Foreground\n\t\t\t\"-v\", // Verbose (if enabled)\n\t\t\t\"-S\",\n\t\t\t`0.0.0.0:${port}`, // Listen on all interfaces (for Windows \u2192 WSL2)\n\t\t\t\"--pidfile\",\n\t\t\t\"NONE\",\n\t\t];\n\n\t\tif (!this.config.verboseLogging) {\n\t\t\t// Remove -v if not verbose\n\t\t\tusbmuxdArgs.splice(1, 1);\n\t\t}\n\n\t\t// Build WSL command: wsl -d <distro> usbmuxd <args>\n\t\tconst wslArgs = [\n\t\t\t\"-d\",\n\t\t\tthis.config.wslDistribution || \"alpine-usbmuxd-build\",\n\t\t\tthis.config.usbmuxdPath,\n\t\t\t...usbmuxdArgs,\n\t\t];\n\n\t\t// Spawn via WSL\n\t\tconst process = spawn(\"wsl\", wslArgs, {\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: false, // Show console for debugging\n\t\t});\n\n\t\t// Handle process output\n\t\tprocess.stdout?.on(\"data\", (data) => {\n\t\t\tthis.emit(\"instance-log\", {\n\t\t\t\tinstanceId,\n\t\t\t\tlevel: \"info\",\n\t\t\t\tmessage: data.toString().trim(),\n\t\t\t});\n\t\t});\n\n\t\tprocess.stderr?.on(\"data\", (data) => {\n\t\t\tthis.emit(\"instance-log\", {\n\t\t\t\tinstanceId,\n\t\t\t\tlevel: \"error\",\n\t\t\t\tmessage: data.toString().trim(),\n\t\t\t});\n\t\t});\n\n\t\t// Handle process exit\n\t\tprocess.on(\"exit\", (code, signal) => {\n\t\t\tthis.emit(\"instance-exited\", {\n\t\t\t\tinstanceId,\n\t\t\t\tcode,\n\t\t\t\tsignal,\n\t\t\t});\n\n\t\t\t// Clean up instance and process references, but keep device mappings intact.\n\t\t\t// Device mappings represent the logical port assignment and should only be\n\t\t\t// removed when the device is physically disconnected (via onDeviceDisconnected).\n\t\t\t// Consumers can listen to 'instance-exited' to react to unexpected exits.\n\t\t\tif (this.instances.has(instanceId)) {\n\t\t\t\tthis.instances.delete(instanceId);\n\t\t\t\tthis.processes.delete(instanceId);\n\t\t\t}\n\t\t});\n\n\t\t// Create instance record (pid is set synchronously by Node after spawn)\n\t\tconst pid = process.pid;\n\t\tif (pid === undefined) {\n\t\t\tprocess.kill(\"SIGKILL\");\n\t\t\tthrow new Error(\"Failed to get PID for usbmuxd instance\");\n\t\t}\n\t\tconst instance: UsbmuxdInstance = {\n\t\t\tid: instanceId,\n\t\t\thost,\n\t\t\tport,\n\t\t\tpid,\n\t\t\tdeviceUdids: [],\n\t\t\tstartedAt: new Date(),\n\t\t};\n\n\t\tthis.instances.set(instanceId, instance);\n\t\tthis.processes.set(instanceId, process);\n\n\t\tthis.emit(\"instance-started\", instance);\n\n\t\t// Wait a bit for the instance to start listening\n\t\tawait new Promise((resolve) => setTimeout(resolve, 500));\n\n\t\treturn instance;\n\t}\n\n\t/**\n\t * Stop a specific instance\n\t */\n\tprivate async stopInstance(instanceId: number): Promise<void> {\n\t\tconst instance = this.instances.get(instanceId);\n\t\tconst process = this.processes.get(instanceId);\n\n\t\tif (!instance || !process) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Kill the process\n\t\tprocess.kill(\"SIGTERM\");\n\n\t\t// Wait for process to exit\n\t\tawait new Promise<void>((resolve) => {\n\t\t\tconst timeout = setTimeout(() => {\n\t\t\t\t// Force kill if not exited\n\t\t\t\tif (!process.killed) {\n\t\t\t\t\tprocess.kill(\"SIGKILL\");\n\t\t\t\t}\n\t\t\t\tresolve();\n\t\t\t}, 5000);\n\n\t\t\tprocess.once(\"exit\", () => {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\n\t\t// Clean up\n\t\tthis.instances.delete(instanceId);\n\t\tthis.processes.delete(instanceId);\n\n\t\t// Remove device mappings\n\t\tfor (const [udid, mapping] of this.deviceMappings.entries()) {\n\t\t\tif (mapping.instanceId === instanceId) {\n\t\t\t\tthis.deviceMappings.delete(udid);\n\t\t\t}\n\t\t}\n\n\t\tthis.emit(\"instance-stopped\", instance);\n\t}\n\n\t/**\n\t * Get device-to-port mapping for a specific UDID\n\t */\n\tpublic getDevicePort(udid: string): number | null {\n\t\tconst mapping = this.deviceMappings.get(udid);\n\t\treturn mapping ? mapping.port : null;\n\t}\n\n\t/**\n\t * Get all device mappings\n\t */\n\tpublic getDeviceMappings(): DeviceMapping[] {\n\t\treturn Array.from(this.deviceMappings.values());\n\t}\n\n\t/**\n\t * Get all running instances\n\t */\n\tpublic getInstances(): UsbmuxdInstance[] {\n\t\treturn Array.from(this.instances.values());\n\t}\n\n\t/**\n\t * Get manager statistics\n\t */\n\tpublic getStats(): ManagerStats {\n\t\tconst now = Date.now();\n\t\tconst startTime = this.startedAt?.getTime() || now;\n\t\tconst uptimeSeconds = Math.floor((now - startTime) / 1000);\n\n\t\treturn {\n\t\t\tinstanceCount: this.instances.size,\n\t\t\tdeviceCount: this.deviceMappings.size,\n\t\t\tuptimeSeconds,\n\t\t\tstartedAt: this.startedAt || new Date(),\n\t\t};\n\t}\n\n\t/**\n\t * Get current configuration\n\t */\n\tpublic getConfig(): InstanceManagerConfig {\n\t\treturn { ...this.config };\n\t}\n}\n", "import { exec } from \"node:child_process\";\nimport { existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { createLoggers } from \"@mcesystems/tool-debug-g4\";\nimport type { InstanceManagerConfig } from \"./types/index.js\";\n\nconst { logInfo, logWarning } = createLoggers(\"usbmuxd-instance-manager\");\n\nconst execAsync = promisify(exec);\n\nconst ALPINE_LOCKDOWN_DIR = \"/var/lib/lockdown\";\nconst SYSTEM_CONFIG_PLIST = \"SystemConfiguration.plist\";\n\n/**\n * Convert a Windows path to the equivalent path inside WSL (e.g. C:\\foo\\bar -> /mnt/c/foo/bar).\n */\nexport function windowsPathToWsl(windowsPath: string): string {\n\tconst normalized = windowsPath.replace(/\\\\/g, \"/\").trim();\n\tconst driveMatch = normalized.match(/^([a-zA-Z]):\\/?(.*)$/);\n\tif (driveMatch) {\n\t\tconst drive = driveMatch[1].toLowerCase();\n\t\tconst rest = driveMatch[2] || \"\";\n\t\treturn `/mnt/${drive}${rest ? `/${rest}` : \"\"}`;\n\t}\n\treturn normalized;\n}\n\n/**\n * Copy a single device's lockdown plist from Windows to Alpine so usbmuxd can use it (skip pairing).\n * No-op if lockdown sync is disabled, path is empty, or the file does not exist on Windows.\n */\nexport async function syncToAlpine(udid: string, config: InstanceManagerConfig): Promise<void> {\n\tif (!config.lockdownSyncEnabled || !config.lockdownWindowsPath?.trim()) {\n\t\treturn;\n\t}\n\n\tconst windowsDir = config.lockdownWindowsPath.trim();\n\tconst windowsFile = join(windowsDir, `${udid}.plist`);\n\n\tif (!existsSync(windowsFile)) {\n\t\treturn;\n\t}\n\n\tconst distro = config.wslDistribution || \"alpine-usbmuxd-build\";\n\tconst wslSource = windowsPathToWsl(windowsFile);\n\tconst wslDestDir = ALPINE_LOCKDOWN_DIR;\n\n\ttry {\n\t\tawait execAsync(\n\t\t\t`wsl -d ${distro} -- sh -c \"mkdir -p ${wslDestDir} && cp '${wslSource}' '${wslDestDir}/'\"`\n\t\t);\n\t\tlogInfo(`Lockdown sync: copied ${udid}.plist to Alpine`);\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait execAsync(\n\t\t\t\t`wsl -d ${distro} -- sh -c \"mkdir -p ${wslDestDir} && sudo cp '${wslSource}' '${wslDestDir}/'\"`\n\t\t\t);\n\t\t\tlogInfo(`Lockdown sync: copied ${udid}.plist to Alpine (via sudo)`);\n\t\t} catch (sudoError) {\n\t\t\tlogWarning(\n\t\t\t\t`Lockdown sync to Alpine failed for ${udid}: ${error}. Sudo fallback failed: ${sudoError}. Ensure /var/lib/lockdown is writable or use passwordless sudo.`\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Copy lockdown plists from Alpine back to Windows (for devices that were assigned this session).\n * Also copies SystemConfiguration.plist if present in Alpine.\n */\nexport async function syncFromAlpine(\n\tudids: string[],\n\tconfig: InstanceManagerConfig\n): Promise<void> {\n\tif (!config.lockdownSyncEnabled || !config.lockdownWindowsPath?.trim()) {\n\t\treturn;\n\t}\n\n\tconst windowsDir = config.lockdownWindowsPath.trim();\n\n\ttry {\n\t\tmkdirSync(windowsDir, { recursive: true });\n\t} catch (error) {\n\t\tlogWarning(`Lockdown sync: could not create Windows dir ${windowsDir}: ${error}`);\n\t\treturn;\n\t}\n\n\tconst distro = config.wslDistribution || \"alpine-usbmuxd-build\";\n\tconst wslDestDir = windowsPathToWsl(windowsDir);\n\n\tfor (const udid of udids) {\n\t\tconst plist = `${udid}.plist`;\n\t\ttry {\n\t\t\tawait execAsync(\n\t\t\t\t`wsl -d ${distro} -- sh -c \"test -f '${ALPINE_LOCKDOWN_DIR}/${plist}' && cp '${ALPINE_LOCKDOWN_DIR}/${plist}' '${wslDestDir}/'\"`\n\t\t\t);\n\t\t\tlogInfo(`Lockdown sync: copied ${plist} from Alpine to Windows`);\n\t\t} catch {\n\t\t\t// File may not exist in Alpine; skip\n\t\t}\n\t}\n\n\ttry {\n\t\tawait execAsync(\n\t\t\t`wsl -d ${distro} -- sh -c \"test -f '${ALPINE_LOCKDOWN_DIR}/${SYSTEM_CONFIG_PLIST}' && cp '${ALPINE_LOCKDOWN_DIR}/${SYSTEM_CONFIG_PLIST}' '${wslDestDir}/'\"`\n\t\t);\n\t\tlogInfo(`Lockdown sync: copied ${SYSTEM_CONFIG_PLIST} from Alpine to Windows`);\n\t} catch {\n\t\t// Optional file; skip\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_tool_debug_g4", "import_node_events", "import_tool_debug_g4", "import_node_child_process", "import_node_util", "import_tool_debug_g4", "config", "logInfo", "logWarning", "execAsync", "config", "process", "logInfo", "config", "UsbDeviceListener", "logInfo", "logError"]
|
|
7
7
|
}
|