deepadb 1.0.5 → 1.0.7

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.
@@ -134,5 +134,191 @@ export function registerMultiDeviceTools(ctx) {
134
134
  return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
135
135
  }
136
136
  });
137
+ /**
138
+ * Predefined comparative test profiles.
139
+ * Each profile is a set of shell commands with labels, grouped by category.
140
+ * Commands must be safe, read-only operations suitable for automated execution.
141
+ */
142
+ const TEST_PROFILES = {
143
+ firmware: {
144
+ description: "Compare firmware components across devices",
145
+ checks: [
146
+ { label: "Baseband version", command: "getprop gsm.version.baseband" },
147
+ { label: "Bootloader", command: "getprop ro.bootloader" },
148
+ { label: "Kernel version", command: "uname -r" },
149
+ { label: "Security patch", command: "getprop ro.build.version.security_patch" },
150
+ { label: "Android version", command: "getprop ro.build.version.release" },
151
+ { label: "Build fingerprint", command: "getprop ro.build.fingerprint" },
152
+ { label: "Build ID", command: "getprop ro.build.id" },
153
+ { label: "Vendor security patch", command: "getprop ro.vendor.build.security_patch" },
154
+ ],
155
+ },
156
+ security: {
157
+ description: "Compare security configuration across devices",
158
+ checks: [
159
+ { label: "SELinux mode", command: "getenforce" },
160
+ { label: "Verified boot state", command: "getprop ro.boot.verifiedbootstate" },
161
+ { label: "Flash lock", command: "getprop ro.boot.flash.locked" },
162
+ { label: "Secure boot", command: "getprop ro.boot.secure_boot" },
163
+ { label: "Security patch", command: "getprop ro.build.version.security_patch" },
164
+ { label: "Encryption state", command: "getprop ro.crypto.state" },
165
+ { label: "DM-verity mode", command: "getprop ro.boot.veritymode" },
166
+ { label: "Build type", command: "getprop ro.build.type" },
167
+ ],
168
+ },
169
+ network: {
170
+ description: "Compare network and radio state across devices",
171
+ checks: [
172
+ { label: "Network type", command: "getprop gsm.network.type" },
173
+ { label: "Operator", command: "getprop gsm.operator.alpha" },
174
+ { label: "SIM state", command: "getprop gsm.sim.state" },
175
+ { label: "WiFi interface", command: "getprop wifi.interface" },
176
+ { label: "Radio technology", command: "getprop ro.telephony.default_network" },
177
+ { label: "Multisim config", command: "getprop persist.radio.multisim.config" },
178
+ ],
179
+ },
180
+ identity: {
181
+ description: "Compare device identity and hardware across devices",
182
+ checks: [
183
+ { label: "Model", command: "getprop ro.product.model" },
184
+ { label: "Device codename", command: "getprop ro.product.device" },
185
+ { label: "Chipset", command: "getprop ro.hardware.chipname" },
186
+ { label: "Platform", command: "getprop ro.board.platform" },
187
+ { label: "SOC model", command: "getprop ro.soc.model" },
188
+ { label: "SDK version", command: "getprop ro.build.version.sdk" },
189
+ { label: "Architecture", command: "getprop ro.product.cpu.abi" },
190
+ { label: "RAM", command: "cat /proc/meminfo | head -1" },
191
+ ],
192
+ },
193
+ };
194
+ ctx.server.tool("adb_multi_test", "Run a comparative test workflow across all connected devices (host + QEMU guests). Executes a predefined diagnostic profile or custom command list on every device in parallel, compares results per-check, and reports matches and differences. Profiles: 'firmware' (baseband, bootloader, kernel, security patch), 'security' (SELinux, verified boot, encryption), 'network' (radio, WiFi, SIM), 'identity' (model, chipset, architecture), 'full' (all profiles). Custom commands also supported.", {
195
+ profile: z.enum(["firmware", "security", "network", "identity", "full"]).optional()
196
+ .describe("Predefined test profile to run. 'full' runs all profiles."),
197
+ commands: z.array(z.object({
198
+ label: z.string().describe("Human-readable label for this check"),
199
+ command: z.string().describe("Shell command to execute"),
200
+ })).max(50).optional()
201
+ .describe("Custom checks to run (max 50). Each has a label and command."),
202
+ devices: z.array(z.string()).optional()
203
+ .describe("Device serials to target (omit for all online devices)"),
204
+ timeout: z.number().min(1000).max(60000).optional().default(10000)
205
+ .describe("Timeout per command per device in ms (1s-60s, default 10s)"),
206
+ }, async ({ profile, commands, devices, timeout }) => {
207
+ try {
208
+ if (!profile && !commands) {
209
+ // List available profiles
210
+ const profileList = Object.entries(TEST_PROFILES)
211
+ .map(([name, p]) => ` ${name}: ${p.description} (${p.checks.length} checks)`)
212
+ .join("\n");
213
+ return {
214
+ content: [{
215
+ type: "text",
216
+ text: `Specify a profile or custom commands.\n\nAvailable profiles:\n${profileList}\n full: Run all profiles combined\n\nExample: adb_multi_test profile="firmware"\nCustom: adb_multi_test commands=[{label: "Uptime", command: "uptime"}]`,
217
+ }],
218
+ };
219
+ }
220
+ // Build the check list
221
+ let checks = [];
222
+ if (profile === "full") {
223
+ for (const p of Object.values(TEST_PROFILES)) {
224
+ checks.push(...p.checks);
225
+ }
226
+ }
227
+ else if (profile) {
228
+ checks = TEST_PROFILES[profile].checks;
229
+ }
230
+ if (commands) {
231
+ checks.push(...commands);
232
+ }
233
+ // Security check all commands
234
+ for (const check of checks) {
235
+ const blocked = ctx.security.checkCommand(check.command);
236
+ if (blocked) {
237
+ return { content: [{ type: "text", text: `Blocked command in check "${check.label}": ${blocked}` }], isError: true };
238
+ }
239
+ }
240
+ // Resolve target devices
241
+ const allDevices = await ctx.deviceManager.listDevices();
242
+ const online = allDevices.filter((d) => d.state === "device");
243
+ const targets = devices
244
+ ? online.filter((d) => devices.includes(d.serial))
245
+ : online;
246
+ if (targets.length === 0) {
247
+ return { content: [{ type: "text", text: "No matching online devices found." }], isError: true };
248
+ }
249
+ const sections = [];
250
+ const profileName = profile === "full" ? "Full Diagnostic" : profile ? TEST_PROFILES[profile].description : "Custom";
251
+ sections.push(`=== Comparative Test: ${profileName} ===`);
252
+ sections.push(`Devices: ${targets.map(d => d.model ? `${d.serial} (${d.model})` : d.serial).join(", ")}`);
253
+ sections.push(`Checks: ${checks.length}`);
254
+ let matches = 0;
255
+ let differences = 0;
256
+ let errors = 0;
257
+ // Run each check across all devices
258
+ for (const check of checks) {
259
+ const results = await Promise.allSettled(targets.map(async (d) => {
260
+ const result = await ctx.bridge.shell(check.command, {
261
+ device: d.serial, timeout, ignoreExitCode: true,
262
+ });
263
+ return { serial: d.serial, model: d.model, output: result.stdout.trim() };
264
+ }));
265
+ const succeeded = results
266
+ .filter((r) => r.status === "fulfilled")
267
+ .map((r) => r.value);
268
+ const failed = results.filter((r) => r.status === "rejected");
269
+ if (succeeded.length === 0) {
270
+ sections.push(`\n✗ ${check.label}: All devices failed`);
271
+ errors += targets.length;
272
+ continue;
273
+ }
274
+ errors += failed.length;
275
+ // Compare outputs
276
+ const allSame = succeeded.length >= 2 && succeeded.every((r) => r.output === succeeded[0].output);
277
+ if (allSame) {
278
+ matches++;
279
+ const value = succeeded[0].output || "(empty)";
280
+ // Truncate long identical values
281
+ const display = value.length > 120 ? value.substring(0, 120) + "..." : value;
282
+ sections.push(`\n✓ ${check.label}: MATCH — ${display}`);
283
+ }
284
+ else if (succeeded.length === 1) {
285
+ matches++;
286
+ sections.push(`\n✓ ${check.label}: ${succeeded[0].output || "(empty)"}`);
287
+ }
288
+ else {
289
+ differences++;
290
+ sections.push(`\n✗ ${check.label}: DIFFERS`);
291
+ for (const r of succeeded) {
292
+ const label = r.model ? `${r.serial} (${r.model})` : r.serial;
293
+ const value = r.output || "(empty)";
294
+ const display = value.length > 200 ? value.substring(0, 200) + "..." : value;
295
+ sections.push(` ${label}: ${display}`);
296
+ }
297
+ }
298
+ if (failed.length > 0) {
299
+ for (let i = 0; i < results.length; i++) {
300
+ if (results[i].status === "rejected") {
301
+ const reason = results[i].reason;
302
+ const label = targets[i].model ? `${targets[i].serial} (${targets[i].model})` : targets[i].serial;
303
+ sections.push(` ${label}: Error — ${reason instanceof Error ? reason.message : reason}`);
304
+ }
305
+ }
306
+ }
307
+ }
308
+ // Summary
309
+ sections.push(`\n${"─".repeat(50)}`);
310
+ sections.push(`Summary: ${checks.length} checks, ${matches} match${matches !== 1 ? "es" : ""}, ${differences} difference${differences !== 1 ? "s" : ""}, ${errors} error${errors !== 1 ? "s" : ""}`);
311
+ if (differences === 0 && errors === 0 && targets.length >= 2) {
312
+ sections.push("✓ All checks consistent across devices");
313
+ }
314
+ else if (differences > 0) {
315
+ sections.push("⚠ Differences detected — review per-check details above");
316
+ }
317
+ return { content: [{ type: "text", text: sections.join("\n") }] };
318
+ }
319
+ catch (error) {
320
+ return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
321
+ }
322
+ });
137
323
  }
138
324
  //# sourceMappingURL=multi-device.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"multi-device.js","sourceRoot":"","sources":["../../src/tools/multi-device.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multi-device.js","sourceRoot":"","sources":["../../src/tools/multi-device.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"qemu.d.ts","sourceRoot":"","sources":["../../src/tools/qemu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAiNjD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAyqBxD"}
1
+ {"version":3,"file":"qemu.d.ts","sourceRoot":"","sources":["../../src/tools/qemu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AA0QjD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAg5BxD"}
@@ -16,10 +16,11 @@
16
16
  import { z } from "zod";
17
17
  import { join, resolve, basename } from "path";
18
18
  import { mkdirSync, existsSync, readdirSync, statSync, unlinkSync } from "fs";
19
- import { spawn, spawnSync } from "child_process";
19
+ import { execFile, spawn, spawnSync } from "child_process";
20
20
  import { OutputProcessor } from "../middleware/output-processor.js";
21
21
  import { isOnDevice } from "../config/config.js";
22
22
  import { registerCleanup, unregisterCleanup } from "../middleware/cleanup.js";
23
+ import { LocalBridge } from "../bridge/local-bridge.js";
23
24
  /** Maximum concurrent QEMU VMs to prevent resource exhaustion. */
24
25
  const MAX_VMS = 3;
25
26
  /**
@@ -156,11 +157,63 @@ function verifyContainment(filePath, imageDir) {
156
157
  const resolvedDir = resolve(imageDir);
157
158
  return resolved.startsWith(resolvedDir + "/") || resolved.startsWith(resolvedDir + "\\");
158
159
  }
159
- /** Register cleanup to kill all QEMU VMs on process exit. */
160
+ /**
161
+ * Find the `adb` binary in the system PATH.
162
+ * Required for guest ADB connectivity (connecting to VMs).
163
+ * Returns null if not found — the tool will suggest installation instructions.
164
+ *
165
+ * SECURITY: The path is discovered from the system, never user-supplied.
166
+ * Only standard Termux locations are checked.
167
+ */
168
+ function findAdbBinary() {
169
+ try {
170
+ const result = spawnSync("which", ["adb"], { timeout: 3000 });
171
+ if (result.status === 0 && result.stdout) {
172
+ const path = result.stdout.toString().trim();
173
+ if (path.length > 0 && existsSync(path))
174
+ return path;
175
+ }
176
+ }
177
+ catch { /* which not available or failed */ }
178
+ // Fallback: common Termux location
179
+ const termuxAdb = "/data/data/com.termux/files/usr/bin/adb";
180
+ if (existsSync(termuxAdb))
181
+ return termuxAdb;
182
+ return null;
183
+ }
184
+ /**
185
+ * Execute an ADB command directly using the system adb binary.
186
+ * Bypasses the bridge (which uses LocalBridge in on-device mode) because
187
+ * guest ADB connectivity requires the actual ADB client/server protocol.
188
+ *
189
+ * SECURITY: Only called with internally-constructed arguments (never raw user input).
190
+ * Host/port values are derived from the runningVms map, not user-supplied.
191
+ */
192
+ function execAdb(adbPath, args, timeout = 15000) {
193
+ return new Promise((resolve) => {
194
+ execFile(adbPath, args, { timeout, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
195
+ resolve({
196
+ stdout: stdout?.toString() ?? "",
197
+ stderr: stderr?.toString() ?? "",
198
+ exitCode: error?.code != null ? (typeof error.code === "number" ? error.code : 1) : 0,
199
+ });
200
+ });
201
+ });
202
+ }
203
+ /** Register cleanup to disconnect and kill all QEMU VMs on process exit. */
160
204
  function updateCleanup() {
161
205
  if (runningVms.size > 0) {
162
206
  registerCleanup("qemu-vms", () => {
207
+ const adbPath = findAdbBinary();
163
208
  for (const [, vm] of runningVms) {
209
+ // Disconnect guest ADB before killing QEMU (best-effort, sync)
210
+ if (vm.connected && vm.guestSerial && adbPath) {
211
+ try {
212
+ spawnSync(adbPath, ["disconnect", vm.guestSerial], { timeout: 3000 });
213
+ }
214
+ catch { /* best-effort */ }
215
+ LocalBridge.unregisterGuestDevice(vm.guestSerial);
216
+ }
164
217
  try {
165
218
  vm.process.kill("SIGKILL");
166
219
  }
@@ -607,6 +660,8 @@ export function registerQemuTools(ctx) {
607
660
  qemuPid: null,
608
661
  pidFile: pidFilePath,
609
662
  rootElevated: useKvm,
663
+ connected: false,
664
+ guestSerial: null,
610
665
  };
611
666
  runningVms.set(safeName, vmInfo);
612
667
  updateCleanup();
@@ -624,6 +679,14 @@ export function registerQemuTools(ctx) {
624
679
  });
625
680
  proc.on("exit", (code) => {
626
681
  ctx.logger.info(`[qemu:${safeName}] Exited (code: ${code})`);
682
+ const exitedVm = runningVms.get(safeName);
683
+ if (exitedVm) {
684
+ if (exitedVm.guestSerial) {
685
+ LocalBridge.unregisterGuestDevice(exitedVm.guestSerial);
686
+ }
687
+ exitedVm.connected = false;
688
+ exitedVm.guestSerial = null;
689
+ }
627
690
  runningVms.delete(safeName);
628
691
  updateCleanup();
629
692
  });
@@ -692,6 +755,20 @@ export function registerQemuTools(ctx) {
692
755
  if (!vm) {
693
756
  return { content: [{ type: "text", text: `VM '${safeName}' is not running.` }], isError: true };
694
757
  }
758
+ // Disconnect guest ADB before killing QEMU (prevents stale ADB entries)
759
+ if (vm.connected && vm.guestSerial) {
760
+ const adbPath = findAdbBinary();
761
+ if (adbPath) {
762
+ try {
763
+ await execAdb(adbPath, ["disconnect", vm.guestSerial], 5000);
764
+ ctx.deviceManager.invalidateCache();
765
+ }
766
+ catch { /* best-effort */ }
767
+ }
768
+ LocalBridge.unregisterGuestDevice(vm.guestSerial);
769
+ vm.connected = false;
770
+ vm.guestSerial = null;
771
+ }
695
772
  try {
696
773
  vm.process.kill(force ? "SIGKILL" : "SIGTERM");
697
774
  }
@@ -771,6 +848,12 @@ export function registerQemuTools(ctx) {
771
848
  sections.push(` Image: ${basename(vm.imagePath)}`);
772
849
  sections.push(` Resources: ${vm.memoryMb} MB RAM, ${vm.cpus} CPU(s)`);
773
850
  sections.push(` ADB: localhost:${vm.adbPort} → guest:5555`);
851
+ if (vm.connected && vm.guestSerial) {
852
+ sections.push(` Guest ADB: ✓ connected (serial: ${vm.guestSerial})`);
853
+ }
854
+ else {
855
+ sections.push(` Guest ADB: not connected (use adb_qemu_connect)`);
856
+ }
774
857
  sections.push(` Uptime: ${uptimeMin}m ${uptimeSec}s`);
775
858
  }
776
859
  }
@@ -787,5 +870,166 @@ export function registerQemuTools(ctx) {
787
870
  return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
788
871
  }
789
872
  });
873
+ ctx.server.tool("adb_qemu_connect", "Connect to a running QEMU VM's ADB service, making the guest appear as a device for DeepADB tools. Requires the guest OS to have an ADB daemon running (e.g., Android guest with USB debugging enabled). Requires the 'adb' binary (install with: pkg install android-tools). Connections are restricted to localhost only — no remote host connections allowed.", {
874
+ name: z.string().describe("VM name to connect to (must be running)"),
875
+ timeout: z.number().min(3000).max(30000).optional().default(10000)
876
+ .describe("Connection timeout in milliseconds (3s-30s). Default 10s."),
877
+ }, async ({ name, timeout }) => {
878
+ try {
879
+ if (!isOnDevice()) {
880
+ return { content: [{ type: "text", text: "QEMU tools are only available in on-device mode." }], isError: true };
881
+ }
882
+ const safeName = sanitizeName(name);
883
+ const vm = runningVms.get(safeName);
884
+ if (!vm) {
885
+ return { content: [{ type: "text", text: `VM '${safeName}' is not running.` }], isError: true };
886
+ }
887
+ if (vm.connected) {
888
+ return { content: [{ type: "text", text: `VM '${safeName}' is already connected (serial: ${vm.guestSerial}).` }] };
889
+ }
890
+ // Find ADB binary
891
+ const adbPath = findAdbBinary();
892
+ if (!adbPath) {
893
+ return {
894
+ content: [{
895
+ type: "text",
896
+ text: "ADB binary not found. Install with: pkg install android-tools\nThen retry: adb_qemu_connect",
897
+ }],
898
+ isError: true,
899
+ };
900
+ }
901
+ // SECURITY: Only connect to localhost — never to external hosts.
902
+ // The port is derived from the running VM's configuration, not user input.
903
+ const guestSerial = `localhost:${vm.adbPort}`;
904
+ // Ensure ADB server is running
905
+ await execAdb(adbPath, ["start-server"], 10000);
906
+ // Connect to guest ADB
907
+ const connectResult = await execAdb(adbPath, ["connect", guestSerial], timeout);
908
+ const output = (connectResult.stdout + connectResult.stderr).trim();
909
+ // Check for success patterns
910
+ const isConnected = output.includes("connected to") || output.includes("already connected");
911
+ if (isConnected) {
912
+ vm.connected = true;
913
+ vm.guestSerial = guestSerial;
914
+ LocalBridge.registerGuestDevice(guestSerial);
915
+ ctx.deviceManager.invalidateCache();
916
+ // Verify the guest appears in device list
917
+ const devicesResult = await execAdb(adbPath, ["devices", "-l"], 5000);
918
+ const guestLine = devicesResult.stdout.split("\n")
919
+ .find(line => line.includes(guestSerial));
920
+ const sections = [];
921
+ sections.push(`✓ Connected to VM '${safeName}' guest ADB`);
922
+ sections.push(`Guest serial: ${guestSerial}`);
923
+ if (guestLine) {
924
+ sections.push(`Device status: ${guestLine.trim()}`);
925
+ }
926
+ sections.push(`\nRun commands on guest: adb_qemu_guest_shell name="${safeName}" command="getprop ro.build.display.id"`);
927
+ sections.push(`Disconnect: adb_qemu_disconnect name="${safeName}"`);
928
+ return { content: [{ type: "text", text: sections.join("\n") }] };
929
+ }
930
+ return {
931
+ content: [{
932
+ type: "text",
933
+ text: `Failed to connect to VM '${safeName}' on ${guestSerial}.\n${output}\n\nEnsure the guest OS has an ADB daemon running (e.g., Android with USB debugging enabled).`,
934
+ }],
935
+ isError: true,
936
+ };
937
+ }
938
+ catch (error) {
939
+ return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
940
+ }
941
+ });
942
+ ctx.server.tool("adb_qemu_disconnect", "Disconnect from a QEMU VM's ADB service. Removes the guest from the device list.", {
943
+ name: z.string().describe("VM name to disconnect from"),
944
+ }, async ({ name }) => {
945
+ try {
946
+ if (!isOnDevice()) {
947
+ return { content: [{ type: "text", text: "QEMU tools are only available in on-device mode." }], isError: true };
948
+ }
949
+ const safeName = sanitizeName(name);
950
+ const vm = runningVms.get(safeName);
951
+ if (!vm) {
952
+ return { content: [{ type: "text", text: `VM '${safeName}' is not running.` }], isError: true };
953
+ }
954
+ if (!vm.connected || !vm.guestSerial) {
955
+ return { content: [{ type: "text", text: `VM '${safeName}' is not connected.` }] };
956
+ }
957
+ const adbPath = findAdbBinary();
958
+ if (!adbPath) {
959
+ // Can't disconnect without ADB, but clear state anyway
960
+ LocalBridge.unregisterGuestDevice(vm.guestSerial);
961
+ vm.connected = false;
962
+ vm.guestSerial = null;
963
+ return { content: [{ type: "text", text: `Cleared connection state for '${safeName}' (ADB binary not found).` }] };
964
+ }
965
+ const serial = vm.guestSerial;
966
+ await execAdb(adbPath, ["disconnect", serial], 5000);
967
+ vm.connected = false;
968
+ vm.guestSerial = null;
969
+ LocalBridge.unregisterGuestDevice(serial);
970
+ ctx.deviceManager.invalidateCache();
971
+ return { content: [{ type: "text", text: `✓ Disconnected from VM '${safeName}' (was ${serial}).` }] };
972
+ }
973
+ catch (error) {
974
+ return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
975
+ }
976
+ });
977
+ ctx.server.tool("adb_qemu_guest_shell", "Execute a shell command on a QEMU guest VM via ADB. The VM must be connected first (use adb_qemu_connect). The guest serial is derived internally — no user-supplied host/IP reaches the ADB binary. Subject to the same security middleware checks as adb_shell.", {
978
+ name: z.string().describe("VM name (must be connected via adb_qemu_connect)"),
979
+ command: z.string().describe("Shell command to execute on the guest"),
980
+ timeout: z.number().min(1000).max(60000).optional().default(15000)
981
+ .describe("Command timeout in milliseconds (1s-60s). Default 15s."),
982
+ }, async ({ name, command, timeout }) => {
983
+ try {
984
+ if (!isOnDevice()) {
985
+ return { content: [{ type: "text", text: "QEMU tools are only available in on-device mode." }], isError: true };
986
+ }
987
+ // Security: command goes through the same security middleware as adb_shell
988
+ const blocked = ctx.security.checkCommand(command);
989
+ if (blocked) {
990
+ return { content: [{ type: "text", text: blocked }], isError: true };
991
+ }
992
+ const safeName = sanitizeName(name);
993
+ const vm = runningVms.get(safeName);
994
+ if (!vm) {
995
+ return { content: [{ type: "text", text: `VM '${safeName}' is not running.` }], isError: true };
996
+ }
997
+ if (!vm.connected || !vm.guestSerial) {
998
+ return {
999
+ content: [{
1000
+ type: "text",
1001
+ text: `VM '${safeName}' is not connected. Run adb_qemu_connect first.`,
1002
+ }],
1003
+ isError: true,
1004
+ };
1005
+ }
1006
+ const adbPath = findAdbBinary();
1007
+ if (!adbPath) {
1008
+ return { content: [{ type: "text", text: "ADB binary not found. Install with: pkg install android-tools" }], isError: true };
1009
+ }
1010
+ // SECURITY: The serial is derived from the running VM's internal state (localhost:<port>).
1011
+ // It is NEVER constructed from user input. This prevents injection of arbitrary
1012
+ // host addresses into the adb command.
1013
+ const result = await execAdb(adbPath, ["-s", vm.guestSerial, "shell", command], timeout);
1014
+ if (result.exitCode !== 0 && result.stderr.includes("device offline")) {
1015
+ if (vm.guestSerial)
1016
+ LocalBridge.unregisterGuestDevice(vm.guestSerial);
1017
+ vm.connected = false;
1018
+ vm.guestSerial = null;
1019
+ return {
1020
+ content: [{
1021
+ type: "text",
1022
+ text: `Guest '${safeName}' is offline (ADB connection lost). Reconnect with adb_qemu_connect.`,
1023
+ }],
1024
+ isError: true,
1025
+ };
1026
+ }
1027
+ const output = result.stdout.trim() || result.stderr.trim() || "(no output)";
1028
+ return { content: [{ type: "text", text: OutputProcessor.process(output) }] };
1029
+ }
1030
+ catch (error) {
1031
+ return { content: [{ type: "text", text: OutputProcessor.formatError(error) }], isError: true };
1032
+ }
1033
+ });
790
1034
  }
791
1035
  //# sourceMappingURL=qemu.js.map