diff --git a/src/cli/adbCommands.ts b/src/cli/adbCommands.ts index ff566916d4..d86da63dd1 100644 --- a/src/cli/adbCommands.ts +++ b/src/cli/adbCommands.ts @@ -207,10 +207,7 @@ export const registerAdbCommands = ( description: "List one device directory with kinds, permissions, and sizes", args: z.object({ serial, - "device-path": z - .string() - .min(1) - .describe("Absolute device directory path to list"), + "device-path": adbInputSchemas.list_adb_directory.shape.device_path, }), run: ({ args }) => execute(CLI_COMMANDS.listAdbDirectory, "list_adb_directory", { @@ -275,15 +272,9 @@ export const registerAdbCommands = ( }); cli.command(CLI_COMMANDS.resolveAdbPackages, { description: "Find installed packages by case-insensitive name substring", - args: z.object({ - serial, - query: z.string().min(2).describe("Package-name substring to find"), - }), + args: adbInputSchemas.resolve_adb_packages, run: ({ args }) => - execute(CLI_COMMANDS.resolveAdbPackages, "resolve_adb_packages", { - serial: args.serial, - query: args.query, - }), + execute(CLI_COMMANDS.resolveAdbPackages, "resolve_adb_packages", args), }); cli.command(CLI_COMMANDS.installAdbPackage, { description: diff --git a/src/cli/argumentErrors.ts b/src/cli/argumentErrors.ts index 7249c22fa7..0becf11a73 100644 --- a/src/cli/argumentErrors.ts +++ b/src/cli/argumentErrors.ts @@ -20,6 +20,8 @@ const adbPackageCommands = new Set([ const isAdbSelector = (command: string, field: string): boolean => (command.includes("-adb-") && field === "serial") || (adbPackageCommands.has(command) && field === "package") || + (command === "list-adb-directory" && field === "device-path") || + (command === "resolve-adb-packages" && field === "query") || (command === "start-adb-activity" && ["action", "component", "data-uri"].includes(field)); diff --git a/tests/acceptance/applications/adbPackageInventoryCoverage.test.ts b/tests/acceptance/applications/adbPackageInventoryCoverage.test.ts index 69f6523d50..06651fedb7 100644 --- a/tests/acceptance/applications/adbPackageInventoryCoverage.test.ts +++ b/tests/acceptance/applications/adbPackageInventoryCoverage.test.ts @@ -1,6 +1,7 @@ import { writeFile } from "node:fs/promises"; import { join } from "node:path"; +import { Ajv2020 } from "ajv/dist/2020.js"; import { expect } from "vitest"; import { toolContract } from "../../../src/contracts/toolContracts.js"; @@ -10,6 +11,44 @@ import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js"; import { cliTest, runFileCli } from "../../support/cli/cliFixture.js"; const PACKAGE_LINE = "package:/data/app/example/base.apk=com.example.app"; + +cliTest.for([ + { + command: "list-adb-directory", + field: "device-path", + valid: "/sdcard", + invalid: "sdcard", + constraint: { expected: "regex" }, + }, + { + command: "resolve-adb-packages", + field: "query", + valid: "a".repeat(256), + invalid: "a".repeat(257), + constraint: { maximum: 256 }, + }, +])( + "publishes the enforced ADB selector constraint for $command", + async ({ command, field, valid, invalid, constraint }, { cli }) => { + const schema = await cli.run({ + arguments: [command, "--schema", "--json"], + }); + expect(schema.exitCode, schema.stderr).toBe(0); + const output = schema.json as { args: Parameters[0] }; + const validate = new Ajv2020({ strict: false }).compile(output.args); + const serial = "emulator-5554"; + expect(validate({ serial, [field]: valid })).toBe(true); + expect(validate({ serial, [field]: invalid })).toBe(false); + const result = await cli.run({ + arguments: [command, serial, invalid, "--json"], + }); + expect(result.exitCode).toBe(1); + expect(result.json).toMatchObject({ + code: "VALIDATION_ERROR", + fieldErrors: [expect.objectContaining({ path: field, ...constraint })], + }); + }, +); const unrecognized = (count: number) => Array.from( { length: count },