@openruntime/cli 0.1.0

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.
Files changed (77) hide show
  1. package/assets/auth-connector/icon-128.png +0 -0
  2. package/assets/auth-connector/icon-16.png +0 -0
  3. package/assets/auth-connector/icon-32.png +0 -0
  4. package/assets/auth-connector/icon-48.png +0 -0
  5. package/dist/args.d.ts +9 -0
  6. package/dist/args.d.ts.map +1 -0
  7. package/dist/args.js +52 -0
  8. package/dist/args.js.map +1 -0
  9. package/dist/auth-connector.d.ts +66 -0
  10. package/dist/auth-connector.d.ts.map +1 -0
  11. package/dist/auth-connector.js +1031 -0
  12. package/dist/auth-connector.js.map +1 -0
  13. package/dist/bridge-process.d.ts +64 -0
  14. package/dist/bridge-process.d.ts.map +1 -0
  15. package/dist/bridge-process.js +228 -0
  16. package/dist/bridge-process.js.map +1 -0
  17. package/dist/browser.d.ts +25 -0
  18. package/dist/browser.d.ts.map +1 -0
  19. package/dist/browser.js +180 -0
  20. package/dist/browser.js.map +1 -0
  21. package/dist/client.d.ts +21 -0
  22. package/dist/client.d.ts.map +1 -0
  23. package/dist/client.js +132 -0
  24. package/dist/client.js.map +1 -0
  25. package/dist/command-definition.d.ts +19 -0
  26. package/dist/command-definition.d.ts.map +1 -0
  27. package/dist/command-definition.js +42 -0
  28. package/dist/command-definition.js.map +1 -0
  29. package/dist/command-skill.d.ts +5 -0
  30. package/dist/command-skill.d.ts.map +1 -0
  31. package/dist/command-skill.js +25 -0
  32. package/dist/command-skill.js.map +1 -0
  33. package/dist/entry.d.ts +2 -0
  34. package/dist/entry.d.ts.map +1 -0
  35. package/dist/entry.js +16 -0
  36. package/dist/entry.js.map +1 -0
  37. package/dist/extension-api.d.ts +85 -0
  38. package/dist/extension-api.d.ts.map +1 -0
  39. package/dist/extension-api.js +313 -0
  40. package/dist/extension-api.js.map +1 -0
  41. package/dist/extensions/types.d.ts +3 -0
  42. package/dist/extensions/types.d.ts.map +1 -0
  43. package/dist/extensions/types.js +2 -0
  44. package/dist/extensions/types.js.map +1 -0
  45. package/dist/external-extensions.d.ts +19 -0
  46. package/dist/external-extensions.d.ts.map +1 -0
  47. package/dist/external-extensions.js +168 -0
  48. package/dist/external-extensions.js.map +1 -0
  49. package/dist/help.d.ts +17 -0
  50. package/dist/help.d.ts.map +1 -0
  51. package/dist/help.js +214 -0
  52. package/dist/help.js.map +1 -0
  53. package/dist/index.d.ts +100 -0
  54. package/dist/index.d.ts.map +1 -0
  55. package/dist/index.js +1579 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/next-browser-profile-preload.d.ts +2 -0
  58. package/dist/next-browser-profile-preload.d.ts.map +1 -0
  59. package/dist/next-browser-profile-preload.js +391 -0
  60. package/dist/next-browser-profile-preload.js.map +1 -0
  61. package/dist/operation-log.d.ts +23 -0
  62. package/dist/operation-log.d.ts.map +1 -0
  63. package/dist/operation-log.js +76 -0
  64. package/dist/operation-log.js.map +1 -0
  65. package/dist/output.d.ts +42 -0
  66. package/dist/output.d.ts.map +1 -0
  67. package/dist/output.js +111 -0
  68. package/dist/output.js.map +1 -0
  69. package/dist/profile.d.ts +56 -0
  70. package/dist/profile.d.ts.map +1 -0
  71. package/dist/profile.js +414 -0
  72. package/dist/profile.js.map +1 -0
  73. package/dist/record.d.ts +17 -0
  74. package/dist/record.d.ts.map +1 -0
  75. package/dist/record.js +1494 -0
  76. package/dist/record.js.map +1 -0
  77. package/package.json +46 -0
package/dist/index.js ADDED
@@ -0,0 +1,1579 @@
1
+ #!/usr/bin/env node
2
+ import { once } from "node:events";
3
+ import { mkdtemp, writeFile } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { createBridgeServer } from "@openruntime/bridge";
7
+ import { createPackageInfo, OPEN_RUNTIME_BRIDGE_DEFAULT_PORT, OPEN_RUNTIME_SESSION_QUERY_PARAM } from "@openruntime/core";
8
+ import { getNumberOption, getOptionValue, getOptionValues, parseCliArgs } from "./args.js";
9
+ import { exportAuthProfileWithConnector } from "./auth-connector.js";
10
+ import { createConsoleLogScript, createGetWindowScript, createInteractiveTextClickScript, createNextBrowserRunner, createWaitEvalScript, parseBrowserJsonOutput } from "./browser.js";
11
+ import { canAutoStartBridge, createFileBridgeStateStore, createDetachedBridgeStarter, ensureBridge, stopManagedBridge, waitForSelectedRuntime } from "./bridge-process.js";
12
+ import { fetchInputOptions, fetchRuntimeResource, fetchRuntimes, normalizeBridgeUrl, runRuntimeAction, selectRuntime, waitForRuntime } from "./client.js";
13
+ import { isEntryPoint } from "./entry.js";
14
+ import { cliCommandReferences, createHelpText } from "./help.js";
15
+ import { validateCommandSkill } from "./command-skill.js";
16
+ import { createFileOperationLogStore, createOperationSessionId, normalizeOpenRuntimeUrlForMatch } from "./operation-log.js";
17
+ import { clearProfile, getProfileDirectory, importProfile, listProfile, readProfileInput, readProfileInputFile } from "./profile.js";
18
+ import { createInternalExtensionRecords, loadExternalCliExtensions } from "./external-extensions.js";
19
+ import { createOpenRuntimeExtensionApi } from "./extension-api.js";
20
+ import { createError, createCommandOutput, writeErrorOutput } from "./output.js";
21
+ import { runRecordCommand } from "./record.js";
22
+ export const cliPackageInfo = createPackageInfo("@openruntime/cli", "agent command line");
23
+ const PROFILE_INLINE_OUTPUT_MAX_CHARS = 32_768;
24
+ const BROWSER_COMMAND_NAMES = [
25
+ "open",
26
+ "goto",
27
+ "page-snapshot",
28
+ "click",
29
+ "fill",
30
+ "eval",
31
+ "wait-eval",
32
+ "get-window",
33
+ "screenshot",
34
+ "network",
35
+ "console",
36
+ "close"
37
+ ];
38
+ const RUNTIME_RESOURCE_COMMAND_NAMES = [
39
+ "targets",
40
+ "snapshot",
41
+ "events",
42
+ "actions"
43
+ ];
44
+ export function getCliCommandName() {
45
+ return "openruntime";
46
+ }
47
+ export function createOpenRuntimeCli(options = {}) {
48
+ const extensions = options.extensions ?? [];
49
+ const extensionRegistry = createExtensionRegistry(extensions);
50
+ const commandReferences = [
51
+ ...cliCommandReferences,
52
+ ...extensions.flatMap((extension) => extension.commandReferences ?? [])
53
+ ];
54
+ const commandSkillReferences = extensions.flatMap(createCommandSkillReferences);
55
+ const config = {
56
+ commandReferences,
57
+ commandSkillReferences,
58
+ extensionRegistry,
59
+ extensionLoadRecords: options.extensionLoadRecords ?? createInternalExtensionRecords(extensions)
60
+ };
61
+ const packageInfo = options.packageInfo ?? cliPackageInfo;
62
+ return {
63
+ packageInfo,
64
+ extensions: [...extensions],
65
+ run: async (argv = process.argv.slice(2), runOptions = {}) => await runCliWithConfig(config, argv, runOptions),
66
+ createHelpText: () => createHelpText({
67
+ commandReferences,
68
+ commandSkillReferences
69
+ }),
70
+ getCommandReferences: () => [...commandReferences]
71
+ };
72
+ }
73
+ export const defaultOpenRuntimeCli = createOpenRuntimeCli();
74
+ export async function runCli(argv = process.argv.slice(2), options = {}) {
75
+ const stderr = options.stderr ?? process.stderr;
76
+ const loaded = await createOpenRuntimeCliWithExternalExtensions();
77
+ for (const record of loaded.extensionLoadRecords) {
78
+ if (record.source === "external" && record.status !== "loaded") {
79
+ stderr.write(formatExternalExtensionWarning(record));
80
+ }
81
+ }
82
+ return await loaded.cli.run(argv, {
83
+ ...options,
84
+ stderr
85
+ });
86
+ }
87
+ export async function createOpenRuntimeCliWithExternalExtensions(options = {}, env = process.env) {
88
+ const internalExtensions = options.extensions ?? [];
89
+ const reservedNames = [
90
+ ...createBuiltInCommandNameSet(),
91
+ ...internalExtensions.map((extension) => extension.name)
92
+ ];
93
+ const external = await loadExternalCliExtensions({
94
+ reservedNames,
95
+ env
96
+ });
97
+ const extensionLoadRecords = [
98
+ ...createInternalExtensionRecords(internalExtensions),
99
+ ...external.records
100
+ ];
101
+ return {
102
+ cli: createOpenRuntimeCli({
103
+ ...options,
104
+ extensions: [
105
+ ...internalExtensions,
106
+ ...external.extensions
107
+ ],
108
+ extensionLoadRecords
109
+ }),
110
+ extensionLoadRecords
111
+ };
112
+ }
113
+ function formatExternalExtensionWarning(record) {
114
+ const location = record.path === undefined ? record.name : record.path;
115
+ const reason = record.reason ?? "unknown reason";
116
+ return `Skipped external OpenRuntime command ${location}: ${reason}\n`;
117
+ }
118
+ async function runCliWithConfig(config, argv, options) {
119
+ const stdout = options.stdout ?? process.stdout;
120
+ const stderr = options.stderr ?? process.stderr;
121
+ const fetcher = options.fetcher ?? fetch;
122
+ const browserRunner = options.browserRunner ?? createNextBrowserRunner();
123
+ const bridgeStarter = options.bridgeStarter ?? createDetachedBridgeStarter(import.meta.url);
124
+ const operationLogStore = createFileOperationLogStore(process.cwd(), options.operationLogDirectory);
125
+ const args = parseCliArgs(argv);
126
+ try {
127
+ if (args.command.length === 0 || hasOption(args, "help")) {
128
+ stdout.write(`${createHelpText({
129
+ commandReferences: config.commandReferences,
130
+ commandSkillReferences: config.commandSkillReferences
131
+ })}\n`);
132
+ return 0;
133
+ }
134
+ if (args.command[0] === "__bridge-server") {
135
+ return await runBridgeServerCommand(args, stdout, options.waitUntilClosed);
136
+ }
137
+ if (args.command[0] === "start") {
138
+ return await runStartCommand(args, stdout, fetcher, bridgeStarter, createBridgeStateStore(args, options.bridgeStateDirectory));
139
+ }
140
+ if (args.command[0] === "stop") {
141
+ return await runStopCommand(args, stdout, browserRunner, createBridgeStateStore(args, options.bridgeStateDirectory), operationLogStore, options.bridgeProcessController);
142
+ }
143
+ if (args.command[0] === "auth") {
144
+ return await runAuthCommand(args, stdout, browserRunner, options.authConnectorExporter ?? exportAuthProfileWithConnector, options.authStateApplier);
145
+ }
146
+ if (args.command[0] === "record") {
147
+ return await runRecordCommand({
148
+ args,
149
+ stdout,
150
+ fetcher,
151
+ browserRunner,
152
+ bridgeUrl: createBridgeUrl(args),
153
+ bridgeStarter,
154
+ bridgeStateStore: createBridgeStateStore(args, options.bridgeStateDirectory)
155
+ });
156
+ }
157
+ if (isBrowserCommand(args.command[0])) {
158
+ return await runBrowserCliCommand(args, stdout, stderr, fetcher, browserRunner, bridgeStarter, createBridgeStateStore(args, options.bridgeStateDirectory), operationLogStore);
159
+ }
160
+ if (args.command[0] === "runtimes") {
161
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(args, fetcher, bridgeStarter, createBridgeStateStore(args, options.bridgeStateDirectory));
162
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
163
+ writeJson(stdout, {
164
+ bridgeUrl,
165
+ runtimes
166
+ });
167
+ return 0;
168
+ }
169
+ if (isRuntimeResourceCommand(args.command[0])) {
170
+ const resourceCommand = args.command[0];
171
+ const commandArgs = applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "unless-selector");
172
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(commandArgs, fetcher, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory));
173
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
174
+ const runtime = selectRuntime(runtimes, createRuntimeSelector(commandArgs));
175
+ const result = await fetchRuntimeResource(fetcher, bridgeUrl, runtime, resourceCommand, createQuery(commandArgs, resourceCommand));
176
+ writeJson(stdout, result);
177
+ return 0;
178
+ }
179
+ if (args.command[0] === "input-options") {
180
+ const actionName = requireOption(args, "action");
181
+ const inputName = requireOption(args, "input");
182
+ const payload = parsePayloadOption(args);
183
+ const commandArgs = applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "unless-selector");
184
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(commandArgs, fetcher, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory));
185
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
186
+ const runtime = selectRuntime(runtimes, createRuntimeSelector(commandArgs));
187
+ const result = await fetchInputOptions(fetcher, bridgeUrl, runtime, actionName, inputName, payload, getNumberOption(args, "timeout"));
188
+ writeJson(stdout, result);
189
+ return 0;
190
+ }
191
+ if (args.command[0] === "run-action") {
192
+ const actionName = requireCommandArgument(args, 1, "action name");
193
+ const payload = parsePayloadOption(args);
194
+ const commandArgs = applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "unless-selector");
195
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(commandArgs, fetcher, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory));
196
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
197
+ const runtime = selectRuntime(runtimes, createRuntimeSelector(commandArgs));
198
+ const result = await runRuntimeAction(fetcher, bridgeUrl, runtime, actionName, payload);
199
+ writeJson(stdout, result);
200
+ return 0;
201
+ }
202
+ if (args.command[0] === "verify") {
203
+ const targetId = requireCommandArgument(args, 1, "target id");
204
+ const status = requireCommandArgument(args, 2, "status");
205
+ const commandArgs = applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "unless-selector");
206
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(commandArgs, fetcher, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory));
207
+ const where = parseWhereOptions(commandArgs);
208
+ try {
209
+ const result = await runVerifyCommand(commandArgs, fetcher, bridgeUrl, browserRunner, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory), targetId, status, where);
210
+ writeJson(stdout, result);
211
+ return result.result.success === true ? 0 : 1;
212
+ }
213
+ catch (error) {
214
+ const reason = error instanceof Error ? error.message : String(error);
215
+ writeJson(stdout, createVerifyCommandFailure(targetId, status, where, reason));
216
+ stderr.write(`${reason}\n`);
217
+ return 1;
218
+ }
219
+ }
220
+ if (args.command[0] === "wait-for") {
221
+ const targetId = requireCommandArgument(args, 1, "target id");
222
+ const status = requireCommandArgument(args, 2, "status");
223
+ const commandArgs = applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "unless-selector");
224
+ const bridgeUrl = await ensureLocalBridgeForRuntimeCommand(commandArgs, fetcher, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory));
225
+ const where = parseWhereOptions(commandArgs);
226
+ try {
227
+ const result = await waitForRuntimeCommand(commandArgs, fetcher, bridgeUrl, browserRunner, bridgeStarter, createBridgeStateStore(commandArgs, options.bridgeStateDirectory), targetId, status, where);
228
+ writeJson(stdout, result);
229
+ return isFailedWaitResult(result.result) ? 1 : 0;
230
+ }
231
+ catch (error) {
232
+ const reason = error instanceof Error ? error.message : String(error);
233
+ writeJson(stdout, createWaitForFailure(targetId, status, where, reason));
234
+ stderr.write(`${reason}\n`);
235
+ return 1;
236
+ }
237
+ }
238
+ const command = args.command[0];
239
+ if (command === undefined) {
240
+ throw createError({
241
+ code: "CLI_COMMAND_MISSING",
242
+ kind: "validation",
243
+ message: "Missing command.",
244
+ hint: "Run `openruntime --help` to see available commands."
245
+ });
246
+ }
247
+ const extension = config.extensionRegistry.get(command);
248
+ if (extension !== undefined) {
249
+ if (hasOption(args, "skill")) {
250
+ if (args.command.length !== 1 || getOptionValue(args, "skill") !== "true") {
251
+ throw createError({
252
+ code: "CLI_COMMAND_SKILL_USAGE_INVALID",
253
+ kind: "validation",
254
+ message: `Command skill lookup only accepts the command name.`,
255
+ hint: `Run \`openruntime ${command} --skill\`.`
256
+ });
257
+ }
258
+ if (extension.skill === undefined) {
259
+ throw createError({
260
+ code: "CLI_COMMAND_SKILL_UNAVAILABLE",
261
+ kind: "not_found",
262
+ message: `Command "${command}" does not provide a skill.`,
263
+ hint: "Run `openruntime --help` to see commands with available skills."
264
+ });
265
+ }
266
+ const skill = validateCommandSkill(extension.skill, extension.name);
267
+ stdout.write(`${skill.path}\n`);
268
+ return 0;
269
+ }
270
+ const openContext = await operationLogStore.read();
271
+ const extensionArgs = applyOpenContextDefaults(args, openContext);
272
+ const bridgeStateStore = createBridgeStateStore(extensionArgs, options.bridgeStateDirectory);
273
+ return await extension.run({
274
+ args: extensionArgs,
275
+ stdout,
276
+ stderr,
277
+ fetcher,
278
+ ...(openContext === undefined ? {} : { page: createExtensionPageContext(openContext) }),
279
+ openruntime: createOpenRuntimeExtensionApi({
280
+ args: extensionArgs,
281
+ fetcher,
282
+ browserRunner,
283
+ bridgeStarter,
284
+ bridgeStateStore,
285
+ ...(openContext === undefined ? {} : { openContext })
286
+ }),
287
+ output: createCommandOutput(stdout, extensionArgs.command.join(" "))
288
+ });
289
+ }
290
+ throw createError({
291
+ code: "CLI_UNKNOWN_COMMAND",
292
+ kind: "validation",
293
+ message: `Unknown command "${args.command.join(" ")}".`,
294
+ hint: "Run `openruntime --help` to see available commands."
295
+ });
296
+ }
297
+ catch (error) {
298
+ writeErrorOutput(stdout, args.command.join(" ") || "openruntime", error);
299
+ return 1;
300
+ }
301
+ }
302
+ function createExtensionRegistry(extensions) {
303
+ const registry = new Map();
304
+ const builtInCommandNames = createBuiltInCommandNameSet();
305
+ for (const extension of extensions) {
306
+ if (extension.name.length === 0) {
307
+ throw new Error("CLI command name must not be empty.");
308
+ }
309
+ if (builtInCommandNames.has(extension.name)) {
310
+ throw new Error(`CLI command "${extension.name}" conflicts with a built-in command.`);
311
+ }
312
+ if (registry.has(extension.name)) {
313
+ throw new Error(`CLI command "${extension.name}" is registered more than once.`);
314
+ }
315
+ if (extension.skill !== undefined) {
316
+ validateCommandSkill(extension.skill, extension.name);
317
+ }
318
+ registry.set(extension.name, extension);
319
+ }
320
+ return registry;
321
+ }
322
+ function createCommandSkillReferences(extension) {
323
+ if (extension.skill === undefined)
324
+ return [];
325
+ let category;
326
+ for (const reference of extension.commandReferences ?? []) {
327
+ if (reference.category === "Commands" || reference.category === "External Commands") {
328
+ category = reference.category;
329
+ break;
330
+ }
331
+ }
332
+ if (category === undefined)
333
+ return [];
334
+ return [{
335
+ category,
336
+ command: extension.name
337
+ }];
338
+ }
339
+ function createBuiltInCommandNameSet() {
340
+ return new Set([
341
+ "__bridge-server",
342
+ "start",
343
+ "stop",
344
+ "auth",
345
+ "record",
346
+ "runtimes",
347
+ "input-options",
348
+ "run-action",
349
+ "verify",
350
+ "wait-for",
351
+ ...BROWSER_COMMAND_NAMES,
352
+ ...RUNTIME_RESOURCE_COMMAND_NAMES
353
+ ]);
354
+ }
355
+ function createRuntimeSelector(args, options = {}) {
356
+ const selector = {};
357
+ const runtimeId = getOptionValue(args, "runtime");
358
+ const sessionId = getOptionValue(args, "session");
359
+ const url = getOptionValue(args, "url");
360
+ if (runtimeId !== undefined && options.ignoreRuntimeId !== true)
361
+ selector.runtimeId = runtimeId;
362
+ if (sessionId !== undefined)
363
+ selector.sessionId = sessionId;
364
+ if (url !== undefined)
365
+ selector.url = withOpenRuntimeSession(url, sessionId);
366
+ return selector;
367
+ }
368
+ async function ensureLocalBridgeForRuntimeCommand(args, fetcher, bridgeStarter, bridgeStateStore) {
369
+ const bridgeUrl = createBridgeUrl(args);
370
+ if (!canAutoStartBridge(bridgeUrl)) {
371
+ return bridgeUrl;
372
+ }
373
+ await ensureBridge({
374
+ fetcher,
375
+ bridgeUrl,
376
+ starter: bridgeStarter,
377
+ stateStore: bridgeStateStore,
378
+ ...createOptionalNumberProperty("port", getNumberOption(args, "port"))
379
+ });
380
+ return bridgeUrl;
381
+ }
382
+ function requireOption(args, name) {
383
+ const value = getOptionValue(args, name);
384
+ if (value === undefined || value.length === 0) {
385
+ throw createError({
386
+ code: "CLI_REQUIRED_OPTION_MISSING",
387
+ kind: "validation",
388
+ message: `Missing required option "--${name}".`,
389
+ details: {
390
+ option: name
391
+ }
392
+ });
393
+ }
394
+ return value;
395
+ }
396
+ function requireCommandArgument(args, index, label) {
397
+ const value = args.command[index];
398
+ if (value === undefined || value.length === 0) {
399
+ throw createError({
400
+ code: "CLI_REQUIRED_ARGUMENT_MISSING",
401
+ kind: "validation",
402
+ message: `Missing required ${label}.`,
403
+ details: {
404
+ argument: label,
405
+ index
406
+ }
407
+ });
408
+ }
409
+ return value;
410
+ }
411
+ function parsePayloadOption(args) {
412
+ const payload = getOptionValue(args, "payload");
413
+ if (payload === undefined)
414
+ return undefined;
415
+ let parsed;
416
+ try {
417
+ parsed = JSON.parse(payload);
418
+ }
419
+ catch {
420
+ throw createError({
421
+ code: "CLI_PAYLOAD_INVALID_JSON",
422
+ kind: "validation",
423
+ message: "--payload must be valid JSON.",
424
+ hint: "Pass --payload as a JSON object string."
425
+ });
426
+ }
427
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
428
+ throw createError({
429
+ code: "CLI_PAYLOAD_INVALID_SHAPE",
430
+ kind: "validation",
431
+ message: "--payload must be a JSON object.",
432
+ hint: "Pass --payload as a JSON object string."
433
+ });
434
+ }
435
+ return parsed;
436
+ }
437
+ function parseWhereOptions(args) {
438
+ const values = getOptionValues(args, "where");
439
+ if (values.length === 0)
440
+ return undefined;
441
+ return values.map((value) => {
442
+ const equalsIndex = value.indexOf("=");
443
+ if (equalsIndex <= 0) {
444
+ throw new Error("--where must use the form path=value.");
445
+ }
446
+ const path = value.slice(0, equalsIndex).trim();
447
+ if (path.length === 0) {
448
+ throw new Error("--where path must not be empty.");
449
+ }
450
+ return {
451
+ path,
452
+ equals: parseWhereValue(value.slice(equalsIndex + 1))
453
+ };
454
+ });
455
+ }
456
+ function parseWhereValue(rawValue) {
457
+ const value = rawValue.trim();
458
+ if (value.length === 0)
459
+ return "";
460
+ try {
461
+ return JSON.parse(value);
462
+ }
463
+ catch {
464
+ return value;
465
+ }
466
+ }
467
+ function createWaitForFailure(targetId, status, where, reason) {
468
+ const condition = {
469
+ id: targetId,
470
+ status
471
+ };
472
+ if (where !== undefined) {
473
+ condition.where = where;
474
+ }
475
+ return {
476
+ result: {
477
+ success: false,
478
+ condition,
479
+ reason
480
+ }
481
+ };
482
+ }
483
+ async function runVerifyCommand(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore, targetId, status, where) {
484
+ const waitResult = await waitForRuntimeCommand(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore, targetId, status, where);
485
+ const targetDefinitions = await fetchVerifyTargetDefinitions(fetcher, bridgeUrl, waitResult.runtime);
486
+ const waitPayload = waitResult.result;
487
+ const target = getVerifyTarget(targetId, waitPayload, targetDefinitions);
488
+ const targetClass = classifyVerifyTarget(target);
489
+ const businessTargetHints = getBusinessTargetHints(waitPayload, targetDefinitions, targetId);
490
+ const hasBusinessTarget = businessTargetHints.length > 0 || targetClass === "business";
491
+ const visibility = targetClass === "business" || hasBusinessTarget
492
+ ? createSkippedVisibility("Business target evidence is available.")
493
+ : await readVerifyVisibility(browserRunner);
494
+ const evidence = createVerifyEvidence({
495
+ targetId,
496
+ targetClass,
497
+ targetFound: target !== undefined,
498
+ waitPayload,
499
+ visibility,
500
+ businessTargetHints
501
+ });
502
+ const condition = {
503
+ id: targetId,
504
+ status
505
+ };
506
+ if (where !== undefined) {
507
+ condition.where = where;
508
+ }
509
+ return {
510
+ runtime: waitResult.runtime,
511
+ result: {
512
+ success: evidence.level === "business" && getWaitSuccess(waitPayload) === true,
513
+ condition,
514
+ evidence,
515
+ wait: waitPayload,
516
+ visibility
517
+ }
518
+ };
519
+ }
520
+ function createVerifyCommandFailure(targetId, status, where, reason) {
521
+ const waitFailure = createWaitForFailure(targetId, status, where, reason).result;
522
+ const condition = {
523
+ id: targetId,
524
+ status
525
+ };
526
+ if (where !== undefined) {
527
+ condition.where = where;
528
+ }
529
+ return {
530
+ result: {
531
+ success: false,
532
+ condition,
533
+ evidence: {
534
+ level: "insufficient",
535
+ scope: "none",
536
+ targetClass: "unknown",
537
+ businessVerified: false,
538
+ message: "OpenRuntime could not read enough runtime evidence to verify the requested result.",
539
+ nextStep: "Open or connect the page runtime first, then rerun verify; if no business target exists, use one one-time page check or add a minimal business target."
540
+ },
541
+ wait: waitFailure,
542
+ visibility: createSkippedVisibility("Runtime evidence was unavailable.")
543
+ }
544
+ };
545
+ }
546
+ async function fetchVerifyTargetDefinitions(fetcher, bridgeUrl, runtime) {
547
+ try {
548
+ const result = await fetchRuntimeResource(fetcher, bridgeUrl, runtime, "targets", new URLSearchParams());
549
+ return Array.isArray(result.result) ? result.result : [];
550
+ }
551
+ catch {
552
+ return [];
553
+ }
554
+ }
555
+ function createVerifyEvidence(options) {
556
+ const waitSuccess = getWaitSuccess(options.waitPayload);
557
+ if (options.targetClass === "business") {
558
+ if (waitSuccess === true) {
559
+ return {
560
+ level: "business",
561
+ scope: "business-result",
562
+ targetClass: "business",
563
+ businessVerified: true,
564
+ message: "The requested business target reached the expected status."
565
+ };
566
+ }
567
+ return {
568
+ level: "business",
569
+ scope: "business-result",
570
+ targetClass: "business",
571
+ businessVerified: false,
572
+ message: "The requested business target did not reach the expected status.",
573
+ nextStep: "Use the target error, current status, or related events to fix the business failure."
574
+ };
575
+ }
576
+ if (options.targetFound && options.targetClass !== "unknown") {
577
+ const nextStep = options.businessTargetHints.length > 0
578
+ ? `Use a business target for final verification, for example "${options.businessTargetHints[0]}".`
579
+ : getVisibilityNextStep(options.visibility);
580
+ return {
581
+ level: "runtime",
582
+ scope: "runtime-layer",
583
+ targetClass: options.targetClass,
584
+ businessVerified: false,
585
+ message: waitSuccess === true
586
+ ? "The requested runtime-layer target reached the expected status, but this does not prove the business result."
587
+ : "The requested runtime-layer target did not reach the expected status.",
588
+ nextStep,
589
+ ...(options.businessTargetHints.length === 0 ? {} : { businessTargetHints: options.businessTargetHints })
590
+ };
591
+ }
592
+ return {
593
+ level: "insufficient",
594
+ scope: "none",
595
+ targetClass: "unknown",
596
+ businessVerified: false,
597
+ message: "The requested target was not available as OpenRuntime evidence.",
598
+ nextStep: getVisibilityNextStep(options.visibility)
599
+ };
600
+ }
601
+ function getVisibilityNextStep(visibility) {
602
+ if (visibility.status === "blank") {
603
+ return "Treat the page as not verified; investigate the blank page or add a minimal business target before claiming success.";
604
+ }
605
+ if (visibility.status === "visible") {
606
+ return "For repeated verification, add a minimal business target; for a one-time check, label this as browser visibility evidence, not OpenRuntime business evidence.";
607
+ }
608
+ if (visibility.status === "unavailable") {
609
+ return "Use one one-time page check or add a minimal business target; do not claim business success from runtime-layer evidence alone.";
610
+ }
611
+ return "Add a minimal business target or perform one explicit page check before claiming business success.";
612
+ }
613
+ function getVerifyTarget(targetId, waitPayload, targetDefinitions) {
614
+ const waitTarget = getRecordField(waitPayload, "target");
615
+ if (isRuntimeSnapshotTargetLike(waitTarget)) {
616
+ return waitTarget;
617
+ }
618
+ const snapshot = getRuntimeSnapshot(waitPayload);
619
+ const snapshotTarget = snapshot?.targets[targetId];
620
+ if (snapshotTarget !== undefined) {
621
+ return snapshotTarget;
622
+ }
623
+ return targetDefinitions.find((target) => target.id === targetId);
624
+ }
625
+ function getBusinessTargetHints(waitPayload, targetDefinitions, requestedTargetId) {
626
+ const candidates = new Map();
627
+ for (const target of targetDefinitions) {
628
+ candidates.set(target.id, target);
629
+ }
630
+ const snapshot = getRuntimeSnapshot(waitPayload);
631
+ if (snapshot !== undefined) {
632
+ for (const target of Object.values(snapshot.targets)) {
633
+ candidates.set(target.id, target);
634
+ }
635
+ }
636
+ return [...candidates.values()]
637
+ .filter((target) => target.id !== requestedTargetId && classifyVerifyTarget(target) === "business")
638
+ .map((target) => target.id)
639
+ .slice(0, 5);
640
+ }
641
+ function classifyVerifyTarget(target) {
642
+ if (target === undefined)
643
+ return "unknown";
644
+ const id = target.id.toLowerCase();
645
+ const type = target.type.toLowerCase();
646
+ const source = target.source?.toLowerCase() ?? "";
647
+ const haystack = `${id} ${type} ${source}`;
648
+ if (id.startsWith("modern:garfish") || type.includes("garfish") || source.includes("garfish")) {
649
+ return "garfish";
650
+ }
651
+ if (id.startsWith("mf:") || type.startsWith("mf.") || source.includes("module-federation") || source === "mf") {
652
+ return "module-federation";
653
+ }
654
+ if (haystack.includes("vmok")) {
655
+ return "vmok";
656
+ }
657
+ if (id.startsWith("modern:") || type.startsWith("modern.") || source.includes("modern")) {
658
+ return "modern";
659
+ }
660
+ if (id.startsWith("openruntime:") || type.startsWith("openruntime.") || source === "openruntime") {
661
+ return "openruntime";
662
+ }
663
+ return "business";
664
+ }
665
+ async function readVerifyVisibility(browserRunner) {
666
+ const result = await browserRunner.run(["eval", createPageVisibilityScript()]);
667
+ if (result.exitCode !== 0) {
668
+ return {
669
+ checked: true,
670
+ status: "unavailable",
671
+ blank: null,
672
+ reason: result.stderr.trim() || result.stdout.trim() || "Browser visibility check failed."
673
+ };
674
+ }
675
+ try {
676
+ const parsed = parseBrowserJsonOutput(result.stdout);
677
+ if (!isRecord(parsed)) {
678
+ return {
679
+ checked: true,
680
+ status: "unknown",
681
+ blank: null,
682
+ reason: "Browser visibility check did not return an object."
683
+ };
684
+ }
685
+ const blank = typeof parsed.blank === "boolean" ? parsed.blank : null;
686
+ return {
687
+ checked: true,
688
+ status: blank === true ? "blank" : blank === false ? "visible" : "unknown",
689
+ blank,
690
+ details: {
691
+ ...createOptionalStringProperty("url", getStringValue(parsed.url)),
692
+ ...createOptionalStringProperty("title", getStringValue(parsed.title)),
693
+ ...createOptionalNumberProperty("textLength", getNumberValue(parsed.textLength)),
694
+ ...createOptionalNumberProperty("visibleElementCount", getNumberValue(parsed.visibleElementCount)),
695
+ ...createOptionalNumberProperty("bodyChildElementCount", getNumberValue(parsed.bodyChildElementCount)),
696
+ ...createOptionalNumberProperty("rootChildElementCount", getNumberValue(parsed.rootChildElementCount))
697
+ }
698
+ };
699
+ }
700
+ catch (error) {
701
+ return {
702
+ checked: true,
703
+ status: "unknown",
704
+ blank: null,
705
+ reason: error instanceof Error ? error.message : String(error)
706
+ };
707
+ }
708
+ }
709
+ function createSkippedVisibility(reason) {
710
+ return {
711
+ checked: false,
712
+ status: "unknown",
713
+ blank: null,
714
+ reason
715
+ };
716
+ }
717
+ function createPageVisibilityScript() {
718
+ return [
719
+ "(() => {",
720
+ " const body = document.body;",
721
+ " if (!body) return { blank: true, url: location.href, title: document.title, textLength: 0, visibleElementCount: 0, bodyChildElementCount: 0, rootChildElementCount: 0 };",
722
+ " const isVisible = (element) => {",
723
+ " const style = window.getComputedStyle(element);",
724
+ " const rect = element.getBoundingClientRect();",
725
+ " return style.visibility !== 'hidden' && style.display !== 'none' && rect.width > 0 && rect.height > 0;",
726
+ " };",
727
+ " const visibleElementCount = Array.from(body.querySelectorAll('*')).filter(isVisible).length;",
728
+ " const textLength = (body.innerText || '').replace(/\\s+/g, ' ').trim().length;",
729
+ " const root = document.querySelector('#root, #app, [data-openruntime-root], main, [role=\"main\"]');",
730
+ " const bodyChildElementCount = body.children.length;",
731
+ " const rootChildElementCount = root ? root.children.length : 0;",
732
+ " const blank = textLength === 0 && visibleElementCount <= 1 && bodyChildElementCount <= 1 && rootChildElementCount === 0;",
733
+ " return { blank, url: location.href, title: document.title, textLength, visibleElementCount, bodyChildElementCount, rootChildElementCount };",
734
+ "})()"
735
+ ].join("\n");
736
+ }
737
+ function getWaitSuccess(waitPayload) {
738
+ if (!isRecord(waitPayload))
739
+ return undefined;
740
+ return typeof waitPayload.success === "boolean" ? waitPayload.success : undefined;
741
+ }
742
+ function getRuntimeSnapshot(waitPayload) {
743
+ const snapshot = getRecordField(waitPayload, "snapshot");
744
+ if (!isRecord(snapshot) || !isRecord(snapshot.targets))
745
+ return undefined;
746
+ return snapshot;
747
+ }
748
+ function getRecordField(value, field) {
749
+ return isRecord(value) ? value[field] : undefined;
750
+ }
751
+ function isRuntimeSnapshotTargetLike(value) {
752
+ return isRecord(value) &&
753
+ typeof value.id === "string" &&
754
+ typeof value.type === "string" &&
755
+ typeof value.status === "string";
756
+ }
757
+ function isRecord(value) {
758
+ return value !== null && typeof value === "object" && !Array.isArray(value);
759
+ }
760
+ function getStringValue(value) {
761
+ return typeof value === "string" ? value : undefined;
762
+ }
763
+ function getNumberValue(value) {
764
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
765
+ }
766
+ async function runBrowserCliCommand(args, stdout, stderr, fetcher, browserRunner, bridgeStarter, bridgeStateStore, operationLogStore) {
767
+ const command = args.command[0];
768
+ if (command === "open") {
769
+ const url = requireCommandArgument(args, 1, "URL");
770
+ const sessionId = getOpenCommandSessionId(args);
771
+ const openedUrl = withOpenRuntimeSession(url, sessionId);
772
+ const bridgeUrl = hasOption(args, "no-bridge") ? null : createBridgeUrl(args);
773
+ await operationLogStore.remove();
774
+ if (!hasOption(args, "no-bridge")) {
775
+ await ensureBridge({
776
+ fetcher,
777
+ bridgeUrl: createBridgeUrl(args),
778
+ starter: bridgeStarter,
779
+ stateStore: bridgeStateStore,
780
+ ...createOptionalNumberProperty("port", getNumberOption(args, "port"))
781
+ });
782
+ }
783
+ const result = await browserRunner.run(createOpenBrowserArgs(args, url, sessionId), { ui: hasOption(args, "ui") });
784
+ if (result.exitCode !== 0) {
785
+ throw createError({
786
+ code: "PAGE_OPEN_FAILED",
787
+ kind: "browser",
788
+ message: result.stderr.trim() || result.stdout.trim() || "Could not open the page.",
789
+ details: {
790
+ url,
791
+ openedUrl,
792
+ ...(result.stdout.trim().length === 0 ? {} : { stdout: result.stdout.trim() }),
793
+ ...(result.stderr.trim().length === 0 ? {} : { stderr: result.stderr.trim() })
794
+ }
795
+ });
796
+ }
797
+ const openedAt = Date.now();
798
+ const normalizedUrl = normalizeOpenRuntimeUrlForMatch(openedUrl);
799
+ await operationLogStore.write({
800
+ command: "open",
801
+ url,
802
+ normalizedUrl,
803
+ bridgeUrl,
804
+ sessionId,
805
+ openedAt,
806
+ exitCode: result.exitCode
807
+ });
808
+ createCommandOutput(stdout, args.command.join(" ")).ok({
809
+ url,
810
+ openedUrl,
811
+ normalizedUrl,
812
+ bridgeUrl,
813
+ sessionId,
814
+ openedAt
815
+ }, "Page opened.");
816
+ return 0;
817
+ }
818
+ if (command === "close") {
819
+ const exitCode = await runBrowserAndPipe(browserRunner, createBrowserCommandArgs(args), stdout, stderr);
820
+ await operationLogStore.remove();
821
+ return exitCode;
822
+ }
823
+ const commandArgs = isBrowserPageCommand(command)
824
+ ? applyOpenContextDefaultsOrThrow(args, await operationLogStore.read(), "always")
825
+ : args;
826
+ if (command === "get-window") {
827
+ const path = requireCommandArgument(commandArgs, 1, "window path");
828
+ return await runBrowserAndPipe(browserRunner, ["eval", createGetWindowScript(path)], stdout, stderr);
829
+ }
830
+ if (command === "click") {
831
+ return await runClickCommand(commandArgs, stdout, stderr, browserRunner);
832
+ }
833
+ if (command === "wait-eval") {
834
+ const script = requireCommandArgument(commandArgs, 1, "eval script");
835
+ const result = await waitForBrowserEval(browserRunner, script, getNumberOption(commandArgs, "timeout"));
836
+ writeJson(stdout, result);
837
+ return 0;
838
+ }
839
+ if (command === "network") {
840
+ return await runNetworkCommand(commandArgs, stdout, stderr, browserRunner);
841
+ }
842
+ if (command === "console") {
843
+ return await runConsoleCommand(commandArgs, stdout, stderr, browserRunner);
844
+ }
845
+ return await runBrowserAndPipe(browserRunner, createBrowserCommandArgs(commandArgs), stdout, stderr);
846
+ }
847
+ async function runClickCommand(args, stdout, stderr, browserRunner) {
848
+ const target = requireCommandArgument(args, 1, "ref, selector, or text");
849
+ if (!shouldPreferInteractiveTextClick(target)) {
850
+ return await runBrowserAndPipe(browserRunner, ["click", target], stdout, stderr);
851
+ }
852
+ const result = await browserRunner.run(["eval", createInteractiveTextClickScript(target)]);
853
+ if (result.exitCode === 0) {
854
+ stdout.write("clicked\n");
855
+ return 0;
856
+ }
857
+ if (result.stdout.length > 0) {
858
+ stdout.write(result.stdout.endsWith("\n") ? result.stdout : `${result.stdout}\n`);
859
+ }
860
+ if (result.stderr.length > 0) {
861
+ stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`);
862
+ }
863
+ return result.exitCode;
864
+ }
865
+ async function waitForRuntimeCommand(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore, targetId, status, where) {
866
+ if (hasOption(args, "next") && hasOption(args, "strict")) {
867
+ throw new Error("--next cannot be used with --strict.");
868
+ }
869
+ if (hasOption(args, "strict")) {
870
+ const runtime = await selectRuntimeForWait(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore);
871
+ return await waitForRuntime(fetcher, bridgeUrl, runtime, targetId, status, getNumberOption(args, "timeout"), where);
872
+ }
873
+ return await waitForLatestRuntime(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore, targetId, status, where);
874
+ }
875
+ async function selectRuntimeForWait(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore) {
876
+ const selector = createRuntimeSelector(args);
877
+ try {
878
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
879
+ return selectRuntime(runtimes, selector);
880
+ }
881
+ catch (error) {
882
+ if (!hasOption(args, "open")) {
883
+ throw addOpenHint(error, selector);
884
+ }
885
+ const url = requireOption(args, "url");
886
+ await ensureBridge({
887
+ fetcher,
888
+ bridgeUrl,
889
+ starter: bridgeStarter,
890
+ stateStore: bridgeStateStore,
891
+ ...createOptionalNumberProperty("port", getNumberOption(args, "port"))
892
+ });
893
+ await runBrowserOrThrow(browserRunner, ["open", withOpenRuntimeSession(url, selector.sessionId)]);
894
+ return await waitForSelectedRuntime({
895
+ fetcher,
896
+ bridgeUrl,
897
+ selector,
898
+ ...createOptionalNumberProperty("timeout", getNumberOption(args, "timeout"))
899
+ });
900
+ }
901
+ }
902
+ async function waitForLatestRuntime(args, fetcher, bridgeUrl, browserRunner, bridgeStarter, bridgeStateStore, targetId, status, where) {
903
+ const selector = createRuntimeSelector(args, { ignoreRuntimeId: true });
904
+ const timeout = getNumberOption(args, "timeout") ?? 5000;
905
+ const deadline = Date.now() + timeout;
906
+ const ignoredRuntimeIds = hasOption(args, "next")
907
+ ? await collectConnectedRuntimeIds(fetcher, bridgeUrl, selector)
908
+ : new Set();
909
+ let lastError;
910
+ let lastResult;
911
+ let didOpen = false;
912
+ while (Date.now() <= deadline) {
913
+ const remainingTimeout = Math.max(1, deadline - Date.now());
914
+ try {
915
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
916
+ const runtime = selectRuntime(ignoredRuntimeIds.size === 0
917
+ ? runtimes
918
+ : runtimes.filter((item) => !ignoredRuntimeIds.has(item.runtimeId)), selector);
919
+ const result = await waitForRuntime(fetcher, bridgeUrl, runtime, targetId, status, remainingTimeout, where);
920
+ if (!isRetryableWaitResult(result.result)) {
921
+ return result;
922
+ }
923
+ lastResult = result;
924
+ }
925
+ catch (error) {
926
+ lastError = error;
927
+ if (!isRetryableWaitError(error)) {
928
+ throw error;
929
+ }
930
+ if (hasOption(args, "open") && !didOpen) {
931
+ didOpen = true;
932
+ const url = requireOption(args, "url");
933
+ await ensureBridge({
934
+ fetcher,
935
+ bridgeUrl,
936
+ starter: bridgeStarter,
937
+ stateStore: bridgeStateStore,
938
+ ...createOptionalNumberProperty("port", getNumberOption(args, "port"))
939
+ });
940
+ await runBrowserOrThrow(browserRunner, ["open", withOpenRuntimeSession(url, selector.sessionId)]);
941
+ }
942
+ }
943
+ await sleep(100);
944
+ }
945
+ if (lastResult !== undefined) {
946
+ return lastResult;
947
+ }
948
+ if (hasOption(args, "next")) {
949
+ throw addOpenHint(new Error("No new connected runtime was found before timeout."), selector);
950
+ }
951
+ throw addOpenHint(lastError ?? new Error("No connected runtime was found before timeout."), selector);
952
+ }
953
+ async function collectConnectedRuntimeIds(fetcher, bridgeUrl, selector) {
954
+ const runtimes = await fetchRuntimes(fetcher, bridgeUrl);
955
+ const matchingConnectedRuntimes = filterConnectedRuntimes(runtimes, selector);
956
+ return new Set(matchingConnectedRuntimes.map((runtime) => runtime.runtimeId));
957
+ }
958
+ function filterConnectedRuntimes(runtimes, selector) {
959
+ if (selector.runtimeId !== undefined) {
960
+ return runtimes.filter((runtime) => runtime.runtimeId === selector.runtimeId && runtime.status === "connected");
961
+ }
962
+ const sessionId = selector.sessionId ?? (selector.url === undefined ? undefined : getOpenRuntimeSessionId(selector.url));
963
+ const normalizedUrl = selector.url === undefined ? undefined : normalizeUrlWithoutOpenRuntimeSession(selector.url);
964
+ return runtimes.filter((runtime) => runtime.status === "connected" &&
965
+ (sessionId === undefined || runtime.sessionId === sessionId || getOpenRuntimeSessionId(runtime.url) === sessionId) &&
966
+ (normalizedUrl === undefined || normalizeUrlWithoutOpenRuntimeSession(runtime.url) === normalizedUrl));
967
+ }
968
+ function normalizeUrlWithoutOpenRuntimeSession(input) {
969
+ return normalizeOpenRuntimeUrlForMatch(input);
970
+ }
971
+ function getOpenRuntimeSessionId(input) {
972
+ try {
973
+ const sessionId = new URL(input).searchParams.get(OPEN_RUNTIME_SESSION_QUERY_PARAM);
974
+ return sessionId === null || sessionId.length === 0 ? undefined : sessionId;
975
+ }
976
+ catch {
977
+ return undefined;
978
+ }
979
+ }
980
+ async function runStartCommand(args, stdout, fetcher, bridgeStarter, bridgeStateStore) {
981
+ const result = await ensureBridge({
982
+ fetcher,
983
+ bridgeUrl: createBridgeUrl(args),
984
+ starter: bridgeStarter,
985
+ stateStore: bridgeStateStore,
986
+ ...createOptionalNumberProperty("port", getNumberOption(args, "port"))
987
+ });
988
+ writeJson(stdout, result);
989
+ return 0;
990
+ }
991
+ async function runStopCommand(args, stdout, browserRunner, bridgeStateStore, operationLogStore, bridgeProcessController) {
992
+ const closeResult = await browserRunner.run(["close"]);
993
+ await operationLogStore.remove();
994
+ const bridgeResult = await stopManagedBridge({
995
+ bridgeUrl: createBridgeUrl(args),
996
+ stateStore: bridgeStateStore,
997
+ ...createOptionalObjectProperty("processController", bridgeProcessController)
998
+ });
999
+ writeJson(stdout, {
1000
+ browser: {
1001
+ command: "close",
1002
+ exitCode: closeResult.exitCode
1003
+ },
1004
+ bridge: bridgeResult
1005
+ });
1006
+ return 0;
1007
+ }
1008
+ async function runAuthCommand(args, stdout, browserRunner, authConnectorExporter, authStateApplier) {
1009
+ const action = args.command[1];
1010
+ if (action === "export") {
1011
+ return await runAuthExportCommand(args, stdout, authConnectorExporter);
1012
+ }
1013
+ if (action === "import") {
1014
+ return await runAuthImportCommand(args, stdout, browserRunner, authStateApplier);
1015
+ }
1016
+ if (action === "list") {
1017
+ writeJson(stdout, await listProfile({
1018
+ profileDirectory: getProfileDirectory()
1019
+ }));
1020
+ return 0;
1021
+ }
1022
+ if (action === "clear") {
1023
+ const url = getOptionValue(args, "url") ?? args.command[2];
1024
+ await closeBrowserForProfileCommand(browserRunner, {
1025
+ allowMissingBrowser: true
1026
+ });
1027
+ writeJson(stdout, await clearProfile({
1028
+ profileDirectory: getProfileDirectory(),
1029
+ ...createOptionalStringProperty("url", url)
1030
+ }));
1031
+ return 0;
1032
+ }
1033
+ throw createError({
1034
+ code: "AUTH_COMMAND_INVALID",
1035
+ kind: "validation",
1036
+ message: "auth requires export, import, list, or clear.",
1037
+ outputCommand: "auth",
1038
+ hint: "Use `openruntime auth export --url <url>`, `openruntime auth import --input <path>`, `openruntime auth list`, or `openruntime auth clear --url <url>`."
1039
+ });
1040
+ }
1041
+ async function runAuthExportCommand(args, stdout, authConnectorExporter) {
1042
+ const requestedUrl = getOptionValue(args, "url") ?? args.command[2];
1043
+ if (requestedUrl === undefined || requestedUrl.length === 0) {
1044
+ throw createError({
1045
+ code: "AUTH_EXPORT_URL_REQUIRED",
1046
+ kind: "validation",
1047
+ message: "auth export requires --url <url>.",
1048
+ hint: "Use `openruntime auth export --url https://app.example.com`."
1049
+ });
1050
+ }
1051
+ const result = await authConnectorExporter({
1052
+ requestedUrl: normalizeAuthExportUrl(requestedUrl),
1053
+ ...createOptionalStringProperty("outputPath", getOptionValue(args, "output")),
1054
+ ...createOptionalNumberProperty("timeout", getNumberOption(args, "timeout")),
1055
+ ...createOptionalStringProperty("extensionDirectory", getOptionValue(args, "extension-dir")),
1056
+ ...createOptionalStringProperty("extensionInstallUrl", getOptionValue(args, "extension-install-url")),
1057
+ ...createOptionalStringProperty("extensionIconPath", getOptionValue(args, "extension-icon"))
1058
+ });
1059
+ stdout.write(`${await getPrintableProfileExportResult(result)}\n`);
1060
+ return 0;
1061
+ }
1062
+ async function runAuthImportCommand(args, stdout, browserRunner, authStateApplier) {
1063
+ await closeBrowserForProfileCommand(browserRunner);
1064
+ const inputPath = getOptionValue(args, "input");
1065
+ const input = inputPath === undefined
1066
+ ? await readProfileInput(args.command[2])
1067
+ : await readProfileInputFile(inputPath);
1068
+ const result = await importProfile({
1069
+ input,
1070
+ profileDirectory: getProfileDirectory(),
1071
+ ...createOptionalObjectProperty("applyAuthState", authStateApplier)
1072
+ });
1073
+ writeJson(stdout, result);
1074
+ return 0;
1075
+ }
1076
+ function normalizeAuthExportUrl(input) {
1077
+ let url;
1078
+ const trimmed = input.trim();
1079
+ const urlLike = hasUrlScheme(trimmed) ? trimmed : `https://${trimmed}`;
1080
+ try {
1081
+ url = new URL(urlLike);
1082
+ }
1083
+ catch {
1084
+ throw createError({
1085
+ code: "AUTH_EXPORT_URL_INVALID",
1086
+ kind: "validation",
1087
+ message: `Invalid auth export URL "${input}".`,
1088
+ hint: "Pass an http or https URL, or a plain domain."
1089
+ });
1090
+ }
1091
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
1092
+ throw createError({
1093
+ code: "AUTH_EXPORT_URL_UNSUPPORTED",
1094
+ kind: "validation",
1095
+ message: "Auth export URL must use http or https.",
1096
+ hint: "Pass an http or https URL, or a plain domain."
1097
+ });
1098
+ }
1099
+ return url.href;
1100
+ }
1101
+ function hasUrlScheme(input) {
1102
+ return /^[a-zA-Z][a-zA-Z\d+.-]*:\/\//.test(input);
1103
+ }
1104
+ async function getPrintableProfileExportResult(result) {
1105
+ if (result.path !== undefined)
1106
+ return result.path;
1107
+ if (result.content === undefined) {
1108
+ throw new Error("Profile export did not return content.");
1109
+ }
1110
+ if (result.content.length <= PROFILE_INLINE_OUTPUT_MAX_CHARS)
1111
+ return result.content;
1112
+ const directory = await mkdtemp(join(tmpdir(), "openruntime-profile-export-"));
1113
+ const path = join(directory, "openruntime-profile.oprprofile");
1114
+ await writeFile(path, `${result.content}\n`, {
1115
+ encoding: "utf8",
1116
+ mode: 0o600
1117
+ });
1118
+ return path;
1119
+ }
1120
+ async function closeBrowserForProfileCommand(browserRunner, options = {}) {
1121
+ const result = await browserRunner.run(["close"]);
1122
+ if (result.exitCode !== 0) {
1123
+ const message = result.stderr.trim() || result.stdout.trim() || "Could not close OpenRuntime browser.";
1124
+ if (options.allowMissingBrowser === true && isMissingBrowserCloseError(message)) {
1125
+ return;
1126
+ }
1127
+ throw new Error(message);
1128
+ }
1129
+ }
1130
+ function isMissingBrowserCloseError(message) {
1131
+ return message.includes("daemon failed to start")
1132
+ || message.includes("ECONNREFUSED")
1133
+ || message.includes("ENOENT");
1134
+ }
1135
+ function createBridgeUrl(args) {
1136
+ const bridge = getOptionValue(args, "bridge");
1137
+ if (bridge !== undefined) {
1138
+ return normalizeBridgeUrl(bridge);
1139
+ }
1140
+ const port = getNumberOption(args, "port");
1141
+ if (port !== undefined) {
1142
+ return `http://localhost:${port}`;
1143
+ }
1144
+ return normalizeBridgeUrl(undefined);
1145
+ }
1146
+ function createBridgeStateStore(args, stateDirectory) {
1147
+ return createFileBridgeStateStore(createBridgeUrl(args), stateDirectory);
1148
+ }
1149
+ function createOpenBrowserArgs(args, url, sessionId) {
1150
+ const browserArgs = ["open", withOpenRuntimeSession(url, sessionId)];
1151
+ const cookies = getOptionValue(args, "cookies");
1152
+ if (cookies !== undefined) {
1153
+ browserArgs.push("--cookies", cookies);
1154
+ }
1155
+ return browserArgs;
1156
+ }
1157
+ function getOpenCommandSessionId(args) {
1158
+ return getOptionValue(args, "session") ?? createOperationSessionId();
1159
+ }
1160
+ function createBrowserCommandArgs(args) {
1161
+ const command = args.command[0];
1162
+ if (command === "goto") {
1163
+ return ["goto", withOpenRuntimeSession(requireCommandArgument(args, 1, "URL"), getOptionValue(args, "session"))];
1164
+ }
1165
+ if (command === "page-snapshot") {
1166
+ return ["snapshot"];
1167
+ }
1168
+ if (command === "click") {
1169
+ return ["click", requireCommandArgument(args, 1, "ref, selector, or text")];
1170
+ }
1171
+ if (command === "fill") {
1172
+ return [
1173
+ "fill",
1174
+ requireCommandArgument(args, 1, "ref or selector"),
1175
+ requireCommandArgument(args, 2, "value")
1176
+ ];
1177
+ }
1178
+ if (command === "eval") {
1179
+ const file = getOptionValue(args, "file");
1180
+ if (file !== undefined) {
1181
+ return ["eval", "--file", file];
1182
+ }
1183
+ return ["eval", requireCommandArgument(args, 1, "eval script")];
1184
+ }
1185
+ if (command === "screenshot") {
1186
+ const browserArgs = ["screenshot", ...args.command.slice(1)];
1187
+ if (hasOption(args, "full-page")) {
1188
+ browserArgs.push("--full-page");
1189
+ }
1190
+ return browserArgs;
1191
+ }
1192
+ return ["close"];
1193
+ }
1194
+ function shouldPreferInteractiveTextClick(target) {
1195
+ const trimmed = target.trim();
1196
+ if (trimmed.length === 0)
1197
+ return false;
1198
+ if (/^e\d+$/.test(trimmed))
1199
+ return false;
1200
+ return !/^(css=|text=|role=|#|\[|\.|\w+\s*>)/.test(trimmed);
1201
+ }
1202
+ function withOpenRuntimeSession(input, sessionId) {
1203
+ if (sessionId === undefined || sessionId.length === 0)
1204
+ return input;
1205
+ try {
1206
+ const url = new URL(input);
1207
+ url.searchParams.set(OPEN_RUNTIME_SESSION_QUERY_PARAM, sessionId);
1208
+ return url.toString();
1209
+ }
1210
+ catch {
1211
+ return input;
1212
+ }
1213
+ }
1214
+ async function runBrowserAndPipe(browserRunner, browserArgs, stdout, stderr, options) {
1215
+ const result = await browserRunner.run(browserArgs, options);
1216
+ if (result.stdout.length > 0) {
1217
+ stdout.write(result.stdout.endsWith("\n") ? result.stdout : `${result.stdout}\n`);
1218
+ }
1219
+ if (result.stderr.length > 0) {
1220
+ stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`);
1221
+ }
1222
+ return result.exitCode;
1223
+ }
1224
+ async function runNetworkCommand(args, stdout, stderr, browserRunner) {
1225
+ const result = await browserRunner.run(["network"]);
1226
+ const urlQuery = getOptionValue(args, "url");
1227
+ const output = result.exitCode === 0 && urlQuery !== undefined
1228
+ ? filterNetworkOutputByUrl(result.stdout, urlQuery)
1229
+ : normalizeNetworkOutput(result.stdout);
1230
+ if (output.length > 0) {
1231
+ stdout.write(output.endsWith("\n") ? output : `${output}\n`);
1232
+ }
1233
+ if (result.stderr.length > 0) {
1234
+ stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`);
1235
+ }
1236
+ return result.exitCode;
1237
+ }
1238
+ async function runConsoleCommand(args, stdout, stderr, browserRunner) {
1239
+ const result = await browserRunner.run(["eval", createConsoleLogScript()]);
1240
+ if (result.exitCode !== 0) {
1241
+ if (result.stdout.length > 0) {
1242
+ stdout.write(result.stdout.endsWith("\n") ? result.stdout : `${result.stdout}\n`);
1243
+ }
1244
+ if (result.stderr.length > 0) {
1245
+ stderr.write(result.stderr.endsWith("\n") ? result.stderr : `${result.stderr}\n`);
1246
+ }
1247
+ return result.exitCode;
1248
+ }
1249
+ const entries = filterConsoleEntries(parseConsoleEntries(parseBrowserJsonOutput(result.stdout)), {
1250
+ ...createOptionalObjectProperty("levels", parseConsoleLevels(args)),
1251
+ ...createOptionalStringProperty("query", getOptionValue(args, "query")),
1252
+ ...createOptionalNumberProperty("limit", getNumberOption(args, "limit"))
1253
+ });
1254
+ writeJson(stdout, {
1255
+ entries,
1256
+ summary: summarizeConsoleEntries(entries)
1257
+ });
1258
+ return 0;
1259
+ }
1260
+ function parseConsoleEntries(value) {
1261
+ if (!Array.isArray(value))
1262
+ return [];
1263
+ return value.flatMap((entry) => {
1264
+ if (entry === null || typeof entry !== "object")
1265
+ return [];
1266
+ const item = entry;
1267
+ const level = normalizeConsoleLevel(item.level);
1268
+ if (level === undefined)
1269
+ return [];
1270
+ return [{
1271
+ level,
1272
+ args: typeof item.args === "string" ? item.args : String(item.args ?? ""),
1273
+ ...createOptionalNumberProperty("timestamp", typeof item.timestamp === "number" ? item.timestamp : undefined)
1274
+ }];
1275
+ });
1276
+ }
1277
+ function parseConsoleLevels(args) {
1278
+ const values = getOptionValues(args, "level");
1279
+ if (values.length === 0)
1280
+ return undefined;
1281
+ const levels = new Set();
1282
+ for (const value of values) {
1283
+ for (const rawLevel of value.split(",")) {
1284
+ const level = normalizeConsoleLevel(rawLevel.trim());
1285
+ if (level === undefined) {
1286
+ throw new Error(`Unsupported console level "${rawLevel}". Use log, info, warn, or error.`);
1287
+ }
1288
+ levels.add(level);
1289
+ }
1290
+ }
1291
+ return levels;
1292
+ }
1293
+ function normalizeConsoleLevel(value) {
1294
+ if (typeof value !== "string")
1295
+ return undefined;
1296
+ const normalized = value.toLowerCase();
1297
+ if (normalized === "warning")
1298
+ return "warn";
1299
+ if (normalized === "log" || normalized === "info" || normalized === "warn" || normalized === "error") {
1300
+ return normalized;
1301
+ }
1302
+ return undefined;
1303
+ }
1304
+ function filterConsoleEntries(entries, options) {
1305
+ const normalizedQuery = options.query?.toLowerCase();
1306
+ const filtered = entries.filter((entry) => (options.levels === undefined || options.levels.has(entry.level)) &&
1307
+ (normalizedQuery === undefined ||
1308
+ entry.level.includes(normalizedQuery) ||
1309
+ entry.args.toLowerCase().includes(normalizedQuery)));
1310
+ if (options.limit === undefined || options.limit < 0)
1311
+ return filtered;
1312
+ return filtered.slice(-options.limit);
1313
+ }
1314
+ function summarizeConsoleEntries(entries) {
1315
+ const summary = {
1316
+ total: entries.length,
1317
+ log: 0,
1318
+ info: 0,
1319
+ warn: 0,
1320
+ error: 0
1321
+ };
1322
+ for (const entry of entries) {
1323
+ summary[entry.level] += 1;
1324
+ }
1325
+ return summary;
1326
+ }
1327
+ function filterNetworkOutputByUrl(output, query) {
1328
+ const normalized = normalizeNetworkOutput(output);
1329
+ if (normalized.trim() === "(no requests)")
1330
+ return normalized;
1331
+ const lines = normalized.split(/\r?\n/);
1332
+ const filtered = lines.filter((line) => {
1333
+ if (line.length === 0 || line.startsWith("#"))
1334
+ return true;
1335
+ return getNetworkLineUrl(line)?.includes(query) ?? false;
1336
+ });
1337
+ return filtered.join("\n");
1338
+ }
1339
+ function normalizeNetworkOutput(output) {
1340
+ return output.split(/\r?\n/).filter((line) => !line.includes("network <idx>")).join("\n");
1341
+ }
1342
+ function getNetworkLineUrl(line) {
1343
+ const parts = line.trim().split(/\s+/);
1344
+ if (parts.length < 6)
1345
+ return undefined;
1346
+ return parts[5];
1347
+ }
1348
+ async function runBrowserOrThrow(browserRunner, browserArgs) {
1349
+ const result = await browserRunner.run(browserArgs);
1350
+ if (result.exitCode !== 0) {
1351
+ throw new Error(result.stderr.trim() || result.stdout.trim() || `next-browser ${browserArgs[0]} failed.`);
1352
+ }
1353
+ }
1354
+ async function waitForBrowserEval(browserRunner, script, timeout) {
1355
+ const deadline = Date.now() + (timeout ?? 5000);
1356
+ let lastValue;
1357
+ let lastError;
1358
+ while (Date.now() <= deadline) {
1359
+ const result = await browserRunner.run(["eval", createWaitEvalScript(script)]);
1360
+ if (result.exitCode === 0) {
1361
+ try {
1362
+ lastValue = parseBrowserJsonOutput(result.stdout);
1363
+ if (lastValue === true) {
1364
+ return {
1365
+ success: true,
1366
+ condition: { script },
1367
+ value: lastValue
1368
+ };
1369
+ }
1370
+ }
1371
+ catch (error) {
1372
+ lastError = error instanceof Error ? error.message : String(error);
1373
+ }
1374
+ }
1375
+ else {
1376
+ lastError = result.stderr.trim() || result.stdout.trim();
1377
+ }
1378
+ await sleep(100);
1379
+ }
1380
+ const failure = {
1381
+ success: false,
1382
+ condition: { script }
1383
+ };
1384
+ if (lastValue !== undefined) {
1385
+ failure.value = lastValue;
1386
+ }
1387
+ failure.reason = lastError === undefined
1388
+ ? "Condition did not become true before timeout."
1389
+ : `Condition did not become true before timeout. Last error: ${lastError}`;
1390
+ return failure;
1391
+ }
1392
+ function hasOption(args, name) {
1393
+ return args.options.has(name);
1394
+ }
1395
+ function applyOpenContextDefaults(args, openContext) {
1396
+ if (openContext === undefined) {
1397
+ return args;
1398
+ }
1399
+ const options = cloneOptions(args.options);
1400
+ if (openContext.bridgeUrl !== null) {
1401
+ setDefaultOption(options, "bridge", openContext.bridgeUrl);
1402
+ }
1403
+ if (!hasRuntimeSelectorOption(args)) {
1404
+ setDefaultOption(options, "url", openContext.url);
1405
+ if (openContext.sessionId !== null) {
1406
+ setDefaultOption(options, "session", openContext.sessionId);
1407
+ }
1408
+ }
1409
+ return {
1410
+ command: args.command,
1411
+ options
1412
+ };
1413
+ }
1414
+ function createExtensionPageContext(openContext) {
1415
+ return {
1416
+ url: openContext.url,
1417
+ openedUrl: withOpenRuntimeSession(openContext.url, openContext.sessionId ?? undefined),
1418
+ normalizedUrl: openContext.normalizedUrl,
1419
+ bridgeUrl: openContext.bridgeUrl,
1420
+ sessionId: openContext.sessionId,
1421
+ openedAt: openContext.openedAt
1422
+ };
1423
+ }
1424
+ function applyOpenContextDefaultsOrThrow(args, openContext, requirement) {
1425
+ if (openContext === undefined && (requirement === "always" || (!hasRuntimeSelectorOption(args) && !hasOption(args, "bridge")))) {
1426
+ throw createOpenContextRequiredError(args);
1427
+ }
1428
+ if (openContext !== undefined &&
1429
+ openContext.bridgeUrl === null &&
1430
+ requirement === "unless-selector" &&
1431
+ !hasRuntimeSelectorOption(args) &&
1432
+ !hasOption(args, "bridge")) {
1433
+ throw createError({
1434
+ code: "OPEN_CONTEXT_REQUIRES_BRIDGE",
1435
+ kind: "validation",
1436
+ message: "The opened page context was created without a Bridge.",
1437
+ retryable: false,
1438
+ hint: "Run `openruntime open <url>` without `--no-bridge`, or pass `--bridge <url>` explicitly."
1439
+ });
1440
+ }
1441
+ return applyOpenContextDefaults(args, openContext);
1442
+ }
1443
+ function createOpenContextRequiredError(args) {
1444
+ const command = args.command.join(" ") || "openruntime";
1445
+ return createError({
1446
+ code: "OPEN_CONTEXT_REQUIRED",
1447
+ kind: "validation",
1448
+ message: "No opened page context was found.",
1449
+ retryable: false,
1450
+ hint: `Run \`openruntime open <url>\` before \`openruntime ${command}\`.`,
1451
+ details: {
1452
+ command
1453
+ }
1454
+ });
1455
+ }
1456
+ function hasRuntimeSelectorOption(args) {
1457
+ return hasOption(args, "runtime") || hasOption(args, "session") || hasOption(args, "url");
1458
+ }
1459
+ function cloneOptions(options) {
1460
+ return new Map([...options.entries()].map(([name, values]) => [name, [...values]]));
1461
+ }
1462
+ function setDefaultOption(options, name, value) {
1463
+ if (!options.has(name)) {
1464
+ options.set(name, [value]);
1465
+ }
1466
+ }
1467
+ function isRetryableWaitResult(result) {
1468
+ if (result === null || typeof result !== "object")
1469
+ return false;
1470
+ const value = result;
1471
+ return value.success === false && value.reason === "Target is not registered.";
1472
+ }
1473
+ function isFailedWaitResult(result) {
1474
+ if (result === null || typeof result !== "object")
1475
+ return false;
1476
+ return result.success === false;
1477
+ }
1478
+ function isRetryableWaitError(error) {
1479
+ const message = error instanceof Error ? error.message : String(error);
1480
+ return message.startsWith("No connected runtime") ||
1481
+ /^Runtime ".*" was not found\.$/.test(message) ||
1482
+ /^Runtime ".*" is disconnected\.$/.test(message) ||
1483
+ message === "Runtime is disconnected.";
1484
+ }
1485
+ function addOpenHint(error, selector) {
1486
+ if (error instanceof Error && selector.url !== undefined && error.message.startsWith("No connected runtime matched")) {
1487
+ return new Error(`${error.message}\nRun \`openruntime open <url>\` before waiting.`);
1488
+ }
1489
+ return error instanceof Error ? error : new Error(String(error));
1490
+ }
1491
+ function createOptionalNumberProperty(name, value) {
1492
+ return value === undefined ? {} : { [name]: value };
1493
+ }
1494
+ function createOptionalStringProperty(name, value) {
1495
+ return value === undefined ? {} : { [name]: value };
1496
+ }
1497
+ function createOptionalObjectProperty(name, value) {
1498
+ return value === undefined ? {} : { [name]: value };
1499
+ }
1500
+ function isBrowserCommand(command) {
1501
+ return BROWSER_COMMAND_NAMES.includes(command);
1502
+ }
1503
+ function isBrowserPageCommand(command) {
1504
+ return isBrowserCommand(command) && command !== "open" && command !== "goto" && command !== "close";
1505
+ }
1506
+ async function runBridgeServerCommand(args, stdout, waitUntilClosed) {
1507
+ const server = createBridgeServer();
1508
+ const address = await server.listen({
1509
+ port: getNumberOption(args, "port") ?? OPEN_RUNTIME_BRIDGE_DEFAULT_PORT
1510
+ });
1511
+ stdout.write(`OpenRuntime Bridge listening on ${address.url}\n`);
1512
+ if (waitUntilClosed !== undefined) {
1513
+ await waitUntilClosed(server);
1514
+ }
1515
+ else {
1516
+ await waitForProcessExit(server);
1517
+ }
1518
+ return 0;
1519
+ }
1520
+ function createQuery(args, command) {
1521
+ const params = new URLSearchParams();
1522
+ const names = getQueryOptionNames(command);
1523
+ for (const name of names) {
1524
+ for (const value of getOptionValues(args, name)) {
1525
+ params.append(name, value);
1526
+ }
1527
+ }
1528
+ return params;
1529
+ }
1530
+ function getQueryOptionNames(command) {
1531
+ if (command === "targets" || command === "snapshot") {
1532
+ return ["id", "type", "source", "status", "query"];
1533
+ }
1534
+ if (command === "events") {
1535
+ return ["since", "target-id", "action", "type", "source", "status", "limit", "query"];
1536
+ }
1537
+ return ["name", "source", "risk", "enabled", "query"];
1538
+ }
1539
+ function isRuntimeResourceCommand(command) {
1540
+ return RUNTIME_RESOURCE_COMMAND_NAMES.includes(command);
1541
+ }
1542
+ async function waitForProcessExit(server) {
1543
+ const close = async () => {
1544
+ await server.close();
1545
+ };
1546
+ process.once("SIGINT", () => {
1547
+ void close();
1548
+ });
1549
+ process.once("SIGTERM", () => {
1550
+ void close();
1551
+ });
1552
+ await once(process, "beforeExit");
1553
+ }
1554
+ function writeJson(stdout, value) {
1555
+ stdout.write(`${JSON.stringify(value, null, 2)}\n`);
1556
+ }
1557
+ function sleep(milliseconds) {
1558
+ return new Promise((resolve) => {
1559
+ setTimeout(resolve, milliseconds);
1560
+ });
1561
+ }
1562
+ function isCliEntryPoint() {
1563
+ return isEntryPoint(process.argv[1], import.meta.url);
1564
+ }
1565
+ if (isCliEntryPoint()) {
1566
+ runCli().then((exitCode) => {
1567
+ process.exitCode = exitCode;
1568
+ });
1569
+ }
1570
+ export { getNumberOption, getOptionValue, getOptionValues, parseCliArgs } from "./args.js";
1571
+ export { createOpenRuntimeExtensionApi } from "./extension-api.js";
1572
+ export { convertAuthConnectorPayloadToStorageState, exportAuthProfileWithConnector, getDefaultAuthConnectorExtensionDirectory, openAuthConnectorSetupPage, writeAuthConnectorExtension } from "./auth-connector.js";
1573
+ export { createDefaultBrowserProfileDirectory, createNextBrowserEnvironment, createNextBrowserRunner, parseBrowserJsonOutput } from "./browser.js";
1574
+ export { fetchInputOptions, fetchRuntimeResource, fetchRuntimes, normalizeBridgeUrl, requestJson, runRuntimeAction, selectRuntime, waitForRuntime } from "./client.js";
1575
+ export { isEntryPoint } from "./entry.js";
1576
+ export { cliCommandReferences, createCliReferenceMarkdown, createHelpText } from "./help.js";
1577
+ export { defineCommand, validateCommand } from "./command-definition.js";
1578
+ export { createError, createCommandOutput, isCommandError, runWithOutputErrorBoundary, writeErrorOutput, writeNeedsInputOutput, writeOkOutput } from "./output.js";
1579
+ //# sourceMappingURL=index.js.map