fix(test): guard dev smoke cli args

This commit is contained in:
Vincent Koc
2026-06-20 02:27:50 +02:00
parent 208bed06e1
commit 7dca9210c9
6 changed files with 281 additions and 18 deletions
+70 -9
View File
@@ -15,13 +15,15 @@ function writeStderrLine(message: string): void {
}
function writeUsage(): void {
writeStderrLine(
"Usage: bun scripts/dev/gateway-smoke.ts --url <wss://host[:port]> --token <gateway.auth.token>\n" +
"Or set env: OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN",
);
writeStderrLine(usage());
}
type GatewaySmokeClient = ReturnType<typeof createGatewayWsClient>;
type GatewaySmokeCliOptions = {
help: boolean;
token?: string;
urlRaw?: string;
};
type GatewaySmokeDeps = {
createClient?: typeof createGatewayWsClient;
@@ -29,6 +31,54 @@ type GatewaySmokeDeps = {
stdout?: (message: string) => void;
};
class GatewaySmokeArgError extends Error {}
const BOOLEAN_FLAGS = new Set(["--help", "-h"]);
const VALUE_FLAGS = new Set(["--url", "--token"]);
function usage(): string {
return [
"Usage: bun scripts/dev/gateway-smoke.ts --url <wss://host[:port]> --token <gateway.auth.token>",
"Or set env: OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN",
"",
"Options:",
" --url <url> Gateway websocket URL",
" --token <token> Gateway auth token",
" -h, --help Show this help",
].join("\n");
}
function validateArgs(argv: readonly string[]): void {
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index] ?? "";
if (BOOLEAN_FLAGS.has(arg)) {
continue;
}
if (VALUE_FLAGS.has(arg)) {
const value = argv[index + 1];
if (!value || value.startsWith("--")) {
throw new GatewaySmokeArgError(`${arg} requires a value`);
}
index += 1;
continue;
}
throw new GatewaySmokeArgError(`Unknown argument: ${arg}`);
}
}
function parseGatewaySmokeCli(
argv = process.argv.slice(2),
env: NodeJS.ProcessEnv = process.env,
): GatewaySmokeCliOptions {
validateArgs(argv);
const { get: getArg, has } = createArgReader([...argv]);
return {
help: has("--help") || has("-h"),
token: getArg("--token") ?? env.OPENCLAW_GATEWAY_TOKEN,
urlRaw: getArg("--url") ?? env.OPENCLAW_GATEWAY_URL,
};
}
function isRecord(value: unknown): value is Record<string, unknown> {
return value !== null && typeof value === "object" && !Array.isArray(value);
}
@@ -158,14 +208,25 @@ export async function runGatewaySmoke(
}
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
const { get: getArg } = createArgReader();
const urlRaw = getArg("--url") ?? process.env.OPENCLAW_GATEWAY_URL;
const token = getArg("--token") ?? process.env.OPENCLAW_GATEWAY_TOKEN;
let cli: GatewaySmokeCliOptions;
try {
cli = parseGatewaySmokeCli();
} catch (error) {
writeStderrLine(error instanceof Error ? error.message : String(error));
process.exit(1);
}
if (!urlRaw || !token) {
if (cli.help) {
writeStdoutLine(usage());
} else if (!cli.urlRaw || !cli.token) {
writeUsage();
process.exitCode = 1;
} else {
process.exitCode = await runGatewaySmoke({ token, urlRaw });
process.exitCode = await runGatewaySmoke({ token: cli.token, urlRaw: cli.urlRaw });
}
}
export const testing = {
parseGatewaySmokeCli,
usage,
};
+46 -4
View File
@@ -17,12 +17,57 @@ function writeStderrLine(message: string): void {
process.stderr.write(`${message}\n`);
}
function usage(): string {
return [
"Usage: bun scripts/dev/ios-node-e2e.ts --url <wss://host[:port]> --token <gateway.auth.token> [options]",
"Or set env: OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN",
"",
"Options:",
" --node <id|name-substring> Select a connected iOS node",
" --wait-seconds <n> Seconds to wait for an iOS node (default: 25)",
" --dangerous Include camera/screen commands",
" --json Print JSON results",
" -h, --help Show this help",
].join("\n");
}
const argv = process.argv.slice(2);
const getArg = (flag: string) => {
const index = argv.indexOf(flag);
return index === -1 ? undefined : argv[index + 1];
};
const hasFlag = (flag: string) => argv.includes(flag);
const BOOLEAN_FLAGS = new Set(["--dangerous", "--help", "-h", "--json"]);
const VALUE_FLAGS = new Set(["--node", "--token", "--url", "--wait-seconds"]);
function failCli(message: string): never {
writeStderrLine(message);
process.exit(1);
}
function validateArgs(): void {
for (let index = 0; index < argv.length; index += 1) {
const arg = argv[index] ?? "";
if (BOOLEAN_FLAGS.has(arg)) {
continue;
}
if (VALUE_FLAGS.has(arg)) {
const value = argv[index + 1];
if (!value || value.startsWith("--")) {
failCli(`${arg} requires a value`);
}
index += 1;
continue;
}
failCli(`Unknown argument: ${arg}`);
}
}
if (hasFlag("--help") || hasFlag("-h")) {
writeStdoutLine(usage());
process.exit(0);
}
validateArgs();
type NodeListPayload = {
ts?: number;
@@ -46,10 +91,7 @@ const dangerous = hasFlag("--dangerous") || process.env.OPENCLAW_RUN_DANGEROUS =
const jsonOut = hasFlag("--json");
if (!urlRaw || !token) {
writeStderrLine(
"Usage: bun scripts/dev/ios-node-e2e.ts --url <wss://host[:port]> --token <gateway.auth.token> [--node <id|name-substring>] [--dangerous] [--json]\n" +
"Or set env: OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN",
);
writeStderrLine(usage());
process.exit(1);
}
+54 -4
View File
@@ -32,6 +32,17 @@ class UsageError extends Error {
readonly exitCode = 1;
}
class CliArgumentError extends UsageError {}
type DevicePairTelegramArgs = {
accountId?: string;
chatId?: string;
help: boolean;
};
const BOOLEAN_FLAGS = new Set(["--help", "-h"]);
const VALUE_FLAGS = new Set(["--account", "-a", "--chat", "-c"]);
function writeStdoutLine(...parts: string[]): void {
process.stdout.write(`${parts.join(" ")}\n`);
}
@@ -57,9 +68,41 @@ function readArg(args: string[], flag: string, short?: string): string | undefin
function usage(): string {
return [
"Usage: bun scripts/dev/test-device-pair-telegram.ts --chat <telegram-chat-id> [--account <accountId>]",
"",
"Options:",
" --chat, -c <id> Telegram chat id",
" --account, -a <id> Telegram account id",
" -h, --help Show this help",
].join("\n");
}
function validateArgs(args: readonly string[]): void {
for (let index = 0; index < args.length; index += 1) {
const arg = args[index] ?? "";
if (BOOLEAN_FLAGS.has(arg)) {
continue;
}
if (VALUE_FLAGS.has(arg)) {
const value = args[index + 1];
if (!value || value.startsWith("--")) {
throw new CliArgumentError(`${arg} requires a value`);
}
index += 1;
continue;
}
throw new CliArgumentError(`Unknown argument: ${arg}`);
}
}
function parseDevicePairTelegramArgs(args: readonly string[]): DevicePairTelegramArgs {
validateArgs(args);
return {
accountId: readArg([...args], "--account", "-a"),
chatId: readArg([...args], "--chat", "-c"),
help: args.includes("--help") || args.includes("-h"),
};
}
async function loadTelegramRuntimeSendMessage(): Promise<SendMessageTelegram> {
const specifier = "../../extensions/telegram/runtime-api.js";
const runtime = (await import(specifier)) as { sendMessageTelegram?: SendMessageTelegram };
@@ -86,8 +129,10 @@ async function runDevicePairTelegram(
args = process.argv.slice(2),
deps: DevicePairTelegramDeps = createDefaultDeps(),
): Promise<DevicePairTelegramResult> {
const chatId = readArg(args, "--chat", "-c");
const accountId = readArg(args, "--account", "-a");
const { accountId, chatId, help } = parseDevicePairTelegramArgs(args);
if (help) {
throw new UsageError(usage());
}
if (!chatId) {
throw new UsageError(usage());
}
@@ -133,7 +178,12 @@ async function runDevicePairTelegram(
async function main(): Promise<void> {
try {
const result = await runDevicePairTelegram();
const args = process.argv.slice(2);
if (args.includes("--help") || args.includes("-h")) {
writeStdoutLine(usage());
return;
}
const result = await runDevicePairTelegram(args);
writeStdoutLine(
"Sent split /pair messages to",
result.chatId,
@@ -150,4 +200,4 @@ if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
await main();
}
export { runDevicePairTelegram };
export { parseDevicePairTelegramArgs, runDevicePairTelegram };