Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Notes:
- If XCTest returns 0 nodes (e.g., foreground app changed), agent-device falls back to AX when available.

Flags:
- `--version, -V` print version and exit
- `--platform ios|android`
- `--device <name>`
- `--udid <udid>` (iOS)
Expand Down
6 changes: 6 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { parseArgs, usage } from './utils/args.ts';
import { asAppError, AppError } from './utils/errors.ts';
import { formatSnapshotText, printHumanError, printJson } from './utils/output.ts';
import { readVersion } from './utils/version.ts';
import { pathToFileURL } from 'node:url';
import { sendToDaemon } from './daemon-client.ts';
import fs from 'node:fs';
Expand All @@ -10,6 +11,11 @@ import path from 'node:path';
export async function runCli(argv: string[]): Promise<void> {
const parsed = parseArgs(argv);

if (parsed.flags.version) {
process.stdout.write(`${readVersion()}\n`);
process.exit(0);
}

if (parsed.flags.help || !parsed.command) {
process.stdout.write(`${usage()}\n`);
process.exit(parsed.flags.help ? 0 : 1);
Expand Down
25 changes: 1 addition & 24 deletions src/daemon-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import net from 'node:net';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { AppError } from './utils/errors.ts';
import type { CommandFlags } from './core/dispatch.ts';
import { runCmdDetached } from './utils/exec.ts';
import { findProjectRoot, readVersion } from './utils/version.ts';

export type DaemonRequest = {
token: string;
Expand Down Expand Up @@ -134,33 +134,10 @@ async function sendRequest(info: DaemonInfo, req: DaemonRequest): Promise<Daemon
});
}

function readVersion(): string {
try {
const root = findProjectRoot();
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as {
version?: string;
};
return pkg.version ?? '0.0.0';
} catch {
return '0.0.0';
}
}

function resolveRequestTimeoutMs(): number {
const raw = process.env.AGENT_DEVICE_DAEMON_TIMEOUT_MS;
if (!raw) return 60000;
const parsed = Number(raw);
if (!Number.isFinite(parsed)) return 60000;
return Math.max(1000, Math.floor(parsed));
}

function findProjectRoot(): string {
const start = path.dirname(fileURLToPath(import.meta.url));
let current = start;
for (let i = 0; i < 6; i += 1) {
const pkgPath = path.join(current, 'package.json');
if (fs.existsSync(pkgPath)) return current;
current = path.dirname(current);
}
return start;
}
25 changes: 1 addition & 24 deletions src/daemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import crypto from 'node:crypto';
import { fileURLToPath } from 'node:url';
import { dispatchCommand, type CommandFlags } from './core/dispatch.ts';
import { isCommandSupportedOnDevice } from './core/capabilities.ts';
import { asAppError, AppError } from './utils/errors.ts';
import { readVersion } from './utils/version.ts';
import { stopIosRunnerSession } from './platforms/ios/runner-client.ts';
import type { DaemonRequest, DaemonResponse } from './daemon/types.ts';
import { SessionStore } from './daemon/session-store.ts';
Expand Down Expand Up @@ -203,26 +203,3 @@ function start(): void {
}

start();

function readVersion(): string {
try {
const root = findProjectRoot();
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as {
version?: string;
};
return pkg.version ?? '0.0.0';
} catch {
return '0.0.0';
}
}

function findProjectRoot(): string {
const start = path.dirname(fileURLToPath(import.meta.url));
let current = start;
for (let i = 0; i < 6; i += 1) {
const pkgPath = path.join(current, 'package.json');
if (fs.existsSync(pkgPath)) return current;
current = path.dirname(current);
}
return start;
}
8 changes: 7 additions & 1 deletion src/utils/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@ export type ParsedArgs = {
noRecord?: boolean;
replayUpdate?: boolean;
help: boolean;
version: boolean;
};
};

export function parseArgs(argv: string[]): ParsedArgs {
const flags: ParsedArgs['flags'] = { json: false, help: false };
const flags: ParsedArgs['flags'] = { json: false, help: false, version: false };
const positionals: string[] = [];

for (let i = 0; i < argv.length; i += 1) {
Expand All @@ -42,6 +43,10 @@ export function parseArgs(argv: string[]): ParsedArgs {
flags.help = true;
continue;
}
if (arg === '--version' || arg === '-V') {
flags.version = true;
continue;
}
if (arg === '--verbose' || arg === '-v') {
flags.verbose = true;
continue;
Expand Down Expand Up @@ -229,5 +234,6 @@ Flags:
--update, -u Replay: update selectors and rewrite replay file in place
--user-installed Apps: list user-installed packages (Android only)
--all Apps: list all packages (Android only)
--version, -V Print version and exit
`;
}
26 changes: 26 additions & 0 deletions src/utils/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

export function readVersion(): string {
try {
const root = findProjectRoot();
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) as {
version?: string;
};
return pkg.version ?? '0.0.0';
} catch {
return '0.0.0';
}
}

export function findProjectRoot(): string {
const start = path.dirname(fileURLToPath(import.meta.url));
let current = start;
for (let i = 0; i < 6; i += 1) {
const pkgPath = path.join(current, 'package.json');
if (fs.existsSync(pkgPath)) return current;
current = path.dirname(current);
}
return start;
}
12 changes: 12 additions & 0 deletions test/integration/smoke-cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ test('cli --help returns usage', () => {
assert.match(result.stdout, /agent-device/i);
});

test('cli --version prints semver and exits 0', () => {
const result = runCli(['--version']);
assert.equal(result.status, 0, result.stderr);
assert.match(result.stdout, /^\d+\.\d+\.\d+/i);
});

test('cli -V prints semver and exits 0', () => {
const result = runCli(['-V']);
assert.equal(result.status, 0, result.stderr);
assert.match(result.stdout, /^\d+\.\d+\.\d+/i);
});

test('cli without command prints usage and exits 1', () => {
const result = runCli([]);
assert.equal(result.status, 1, result.stderr);
Expand Down
Loading