@devicecloud.dev/dcd 4.4.9 → 5.0.0-beta.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 (97) hide show
  1. package/README.md +40 -2
  2. package/dist/commands/artifacts.d.ts +47 -18
  3. package/dist/commands/artifacts.js +68 -60
  4. package/dist/commands/cloud.d.ts +228 -88
  5. package/dist/commands/cloud.js +389 -288
  6. package/dist/commands/list.d.ts +39 -38
  7. package/dist/commands/list.js +122 -127
  8. package/dist/commands/live.d.ts +2 -0
  9. package/dist/commands/live.js +513 -0
  10. package/dist/commands/login.d.ts +17 -0
  11. package/dist/commands/login.js +250 -0
  12. package/dist/commands/logout.d.ts +2 -0
  13. package/dist/commands/logout.js +32 -0
  14. package/dist/commands/status.d.ts +23 -42
  15. package/dist/commands/status.js +162 -173
  16. package/dist/commands/switch-org.d.ts +12 -0
  17. package/dist/commands/switch-org.js +78 -0
  18. package/dist/commands/upgrade.d.ts +2 -0
  19. package/dist/commands/upgrade.js +122 -0
  20. package/dist/commands/upload.d.ts +33 -18
  21. package/dist/commands/upload.js +62 -67
  22. package/dist/commands/whoami.d.ts +2 -0
  23. package/dist/commands/whoami.js +34 -0
  24. package/dist/config/environments.d.ts +31 -0
  25. package/dist/config/environments.js +58 -0
  26. package/dist/config/flags/api.flags.d.ts +10 -2
  27. package/dist/config/flags/api.flags.js +12 -10
  28. package/dist/config/flags/binary.flags.d.ts +17 -4
  29. package/dist/config/flags/binary.flags.js +13 -14
  30. package/dist/config/flags/device.flags.d.ts +49 -11
  31. package/dist/config/flags/device.flags.js +41 -33
  32. package/dist/config/flags/environment.flags.d.ts +27 -6
  33. package/dist/config/flags/environment.flags.js +23 -25
  34. package/dist/config/flags/execution.flags.d.ts +35 -8
  35. package/dist/config/flags/execution.flags.js +30 -37
  36. package/dist/config/flags/github.flags.d.ts +23 -5
  37. package/dist/config/flags/github.flags.js +18 -11
  38. package/dist/config/flags/output.flags.d.ts +57 -13
  39. package/dist/config/flags/output.flags.js +47 -43
  40. package/dist/constants.d.ts +218 -51
  41. package/dist/constants.js +2 -2
  42. package/dist/gateways/api-gateway.d.ts +43 -12
  43. package/dist/gateways/api-gateway.js +240 -100
  44. package/dist/gateways/cli-auth-gateway.d.ts +13 -0
  45. package/dist/gateways/cli-auth-gateway.js +57 -0
  46. package/dist/gateways/supabase-gateway.d.ts +11 -11
  47. package/dist/gateways/supabase-gateway.js +15 -39
  48. package/dist/index.d.ts +2 -1
  49. package/dist/index.js +93 -2
  50. package/dist/methods.d.ts +3 -5
  51. package/dist/methods.js +170 -178
  52. package/dist/services/device-validation.service.d.ts +8 -0
  53. package/dist/services/device-validation.service.js +55 -35
  54. package/dist/services/execution-plan.service.js +27 -15
  55. package/dist/services/execution-plan.utils.d.ts +3 -0
  56. package/dist/services/execution-plan.utils.js +10 -32
  57. package/dist/services/metadata-extractor.service.d.ts +0 -2
  58. package/dist/services/metadata-extractor.service.js +57 -57
  59. package/dist/services/moropo.service.js +25 -24
  60. package/dist/services/report-download.service.d.ts +12 -1
  61. package/dist/services/report-download.service.js +31 -20
  62. package/dist/services/results-polling.service.d.ts +6 -7
  63. package/dist/services/results-polling.service.js +80 -33
  64. package/dist/services/telemetry.service.d.ts +40 -0
  65. package/dist/services/telemetry.service.js +230 -0
  66. package/dist/services/test-submission.service.js +2 -1
  67. package/dist/services/version.service.d.ts +3 -2
  68. package/dist/services/version.service.js +27 -11
  69. package/dist/types/domain/auth.types.d.ts +12 -0
  70. package/dist/types/{schema.types.js → domain/auth.types.js} +0 -1
  71. package/dist/types/domain/live.types.d.ts +76 -0
  72. package/dist/types/domain/live.types.js +4 -0
  73. package/dist/utils/auth.d.ts +13 -0
  74. package/dist/utils/auth.js +142 -0
  75. package/dist/utils/cli.d.ts +35 -0
  76. package/dist/utils/cli.js +127 -0
  77. package/dist/utils/compatibility.d.ts +2 -1
  78. package/dist/utils/compatibility.js +2 -2
  79. package/dist/utils/config-store.d.ts +35 -0
  80. package/dist/utils/config-store.js +125 -0
  81. package/dist/utils/connectivity.js +7 -3
  82. package/dist/utils/expo.js +14 -3
  83. package/dist/utils/orgs.d.ts +11 -0
  84. package/dist/utils/orgs.js +40 -0
  85. package/dist/utils/paths.d.ts +11 -0
  86. package/dist/utils/paths.js +24 -0
  87. package/dist/utils/progress.d.ts +13 -0
  88. package/dist/utils/progress.js +50 -0
  89. package/dist/utils/styling.d.ts +13 -5
  90. package/dist/utils/styling.js +37 -7
  91. package/package.json +26 -38
  92. package/bin/dev.cmd +0 -3
  93. package/bin/dev.js +0 -6
  94. package/bin/run.cmd +0 -3
  95. package/bin/run.js +0 -7
  96. package/dist/types/schema.types.d.ts +0 -2702
  97. package/oclif.manifest.json +0 -884
package/README.md CHANGED
@@ -1,16 +1,29 @@
1
1
  # devicecloud.dev CLI
2
2
 
3
-
4
3
  ---
5
4
 
6
5
  One line swap out for Maestro Cloud
7
6
 
8
- Install:
7
+ Install (no Node required):
8
+
9
+ ```sh-session
10
+ $ curl -fsSL https://get.devicecloud.dev/install.sh | sh
11
+ ```
12
+
13
+ On Windows:
14
+
15
+ ```powershell
16
+ irm https://get.devicecloud.dev/install.ps1 | iex
17
+ ```
18
+
19
+ Or via npm if you already have Node 22+:
9
20
 
10
21
  ```sh-session
11
22
  $ npm install -g @devicecloud.dev/dcd
12
23
  ```
13
24
 
25
+ Upgrade later with `dcd upgrade` (binary install) or `npm install -g @devicecloud.dev/dcd@latest` (npm install).
26
+
14
27
  Use:
15
28
 
16
29
  ```sh-session
@@ -19,3 +32,28 @@ $ dcd cloud --apiKey <apiKey> <appFile> .myFlows/
19
32
  ```
20
33
 
21
34
  See full documentation: [Docs](https://docs.devicecloud.dev)
35
+
36
+
37
+ ## Development
38
+
39
+ Requires Node 22+ and [pnpm](https://pnpm.io). `pnpm install` builds the CLI and installs the git hooks automatically.
40
+
41
+ ```sh-session
42
+ $ pnpm install # install deps, build, set up git hooks
43
+ $ pnpm dcd <args> # run the CLI from source
44
+ $ pnpm lint # ESLint
45
+ $ pnpm typecheck # strict tsc, no emit
46
+ $ pnpm test # build + boot mock API + integration/unit tests
47
+ ```
48
+
49
+ ### Secret scanning
50
+
51
+ A [gitleaks](https://github.com/gitleaks/gitleaks) scan runs in two places, both sharing the allowlist in `.gitleaks.toml`:
52
+
53
+ - **pre-commit hook** (via husky) — scans your staged changes and blocks the commit if a secret is found. Install the binary so it can run; without it the hook skips with a warning:
54
+ ```sh-session
55
+ $ brew install gitleaks # or see github.com/gitleaks/gitleaks#installing
56
+ ```
57
+ - **CI** — the `secret-scan` job scans the full history on every push and pull request, and is the enforced backstop regardless of local setup.
58
+
59
+
@@ -1,18 +1,47 @@
1
- import { Command } from '@oclif/core';
2
- export default class Artifacts extends Command {
3
- static description: string;
4
- static examples: string[];
5
- static flags: {
6
- apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
7
- apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
8
- debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
- 'upload-id': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
10
- 'download-artifacts': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
11
- 'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
12
- report: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
- 'allure-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
14
- 'html-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
15
- 'junit-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
- };
17
- run(): Promise<void>;
18
- }
1
+ export declare const artifactsCommand: import("citty").CommandDef<{
2
+ debug: {
3
+ type: "boolean";
4
+ default: false;
5
+ description: string;
6
+ };
7
+ 'upload-id': {
8
+ type: "string";
9
+ required: true;
10
+ description: string;
11
+ };
12
+ 'download-artifacts': {
13
+ type: "string";
14
+ description: string;
15
+ };
16
+ 'artifacts-path': {
17
+ type: "string";
18
+ description: string;
19
+ };
20
+ report: {
21
+ type: "string";
22
+ description: string;
23
+ };
24
+ 'allure-path': {
25
+ type: "string";
26
+ description: string;
27
+ };
28
+ 'html-path': {
29
+ type: "string";
30
+ description: string;
31
+ };
32
+ 'junit-path': {
33
+ type: "string";
34
+ description: string;
35
+ };
36
+ 'api-key': {
37
+ readonly type: "string";
38
+ readonly alias: ["apiKey"];
39
+ readonly description: "API key for devicecloud.dev (find this in the console UI). You can also set the DEVICE_CLOUD_API_KEY environment variable.";
40
+ };
41
+ 'api-url': {
42
+ readonly type: "string";
43
+ readonly alias: ["apiURL", "apiUrl"];
44
+ readonly description: "API base URL (defaults to the URL stored by `dcd login`, else prod)";
45
+ };
46
+ }>;
47
+ export default artifactsCommand;
@@ -1,93 +1,101 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const core_1 = require("@oclif/core");
4
- const constants_1 = require("../constants");
3
+ exports.artifactsCommand = void 0;
4
+ const citty_1 = require("citty");
5
+ const api_flags_1 = require("../config/flags/api.flags");
5
6
  const report_download_service_1 = require("../services/report-download.service");
6
- class Artifacts extends core_1.Command {
7
- static description = 'Download artifacts or reports for a completed test run';
8
- static examples = [
9
- '<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --download-artifacts FAILED',
10
- '<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --download-artifacts ALL --artifacts-path ./my-artifacts.zip',
11
- '<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --report junit',
12
- '<%= config.bin %> <%= command.id %> --upload-id 123e4567-e89b-12d3-a456-426614174000 --report allure --allure-path ./report.html',
13
- ];
14
- static flags = {
15
- apiKey: constants_1.flags.apiKey,
16
- apiUrl: constants_1.flags.apiUrl,
17
- debug: core_1.Flags.boolean({
7
+ const auth_1 = require("../utils/auth");
8
+ const cli_1 = require("../utils/cli");
9
+ const config_store_1 = require("../utils/config-store");
10
+ const DOWNLOAD_OPTIONS = ['ALL', 'FAILED'];
11
+ const REPORT_OPTIONS = ['allure', 'html', 'html-detailed', 'junit'];
12
+ exports.artifactsCommand = (0, citty_1.defineCommand)({
13
+ meta: {
14
+ name: 'artifacts',
15
+ description: 'Download artifacts or reports for a completed test run',
16
+ },
17
+ args: {
18
+ ...api_flags_1.apiFlags,
19
+ debug: {
20
+ type: 'boolean',
18
21
  default: false,
19
22
  description: 'Enable detailed debug logging for troubleshooting issues',
20
- }),
21
- 'upload-id': core_1.Flags.string({
22
- description: 'UUID of the completed upload to download artifacts for',
23
+ },
24
+ 'upload-id': {
25
+ type: 'string',
23
26
  required: true,
24
- }),
25
- 'download-artifacts': core_1.Flags.string({
26
- description: 'Download a zip containing the logs, screenshots and videos for this run. Options: ALL (everything), FAILED (failures only).',
27
- exclusive: ['report'],
28
- options: ['ALL', 'FAILED'],
29
- }),
30
- 'artifacts-path': core_1.Flags.string({
31
- dependsOn: ['download-artifacts'],
32
- description: 'Custom file path for downloaded artifacts (default: ./artifacts.zip)',
33
- }),
34
- report: core_1.Flags.string({
35
- description: 'Download a test report in the specified format.',
36
- exclusive: ['download-artifacts'],
37
- options: ['allure', 'html', 'html-detailed', 'junit'],
38
- }),
39
- 'allure-path': core_1.Flags.string({
40
- dependsOn: ['report'],
27
+ description: 'UUID of the completed upload to download artifacts for',
28
+ },
29
+ 'download-artifacts': {
30
+ type: 'string',
31
+ description: 'Download a zip containing the logs, screenshots and videos for this run (options: ALL, FAILED)',
32
+ },
33
+ 'artifacts-path': {
34
+ type: 'string',
35
+ description: 'Custom file path for downloaded artifacts (default: ./artifacts.zip). Requires --download-artifacts.',
36
+ },
37
+ report: {
38
+ type: 'string',
39
+ description: 'Download a test report in the specified format (options: allure, html, html-detailed, junit)',
40
+ },
41
+ 'allure-path': {
42
+ type: 'string',
41
43
  description: 'Custom file path for downloaded Allure report (default: ./report.html)',
42
- }),
43
- 'html-path': core_1.Flags.string({
44
- dependsOn: ['report'],
44
+ },
45
+ 'html-path': {
46
+ type: 'string',
45
47
  description: 'Custom file path for downloaded HTML report (default: ./report.html)',
46
- }),
47
- 'junit-path': core_1.Flags.string({
48
- dependsOn: ['report'],
48
+ },
49
+ 'junit-path': {
50
+ type: 'string',
49
51
  description: 'Custom file path for downloaded JUnit report (default: ./report.xml)',
50
- }),
51
- };
52
- async run() {
53
- const { flags } = await this.parse(Artifacts);
54
- const { apiKey: apiKeyFlag, apiUrl, debug, 'upload-id': uploadId, 'download-artifacts': downloadArtifacts, 'artifacts-path': artifactsPath, report, 'allure-path': allurePath, 'html-path': htmlPath, 'junit-path': junitPath, } = flags;
55
- const apiKey = apiKeyFlag || process.env.DEVICE_CLOUD_API_KEY;
56
- if (!apiKey) {
57
- this.error('API key is required. Please provide it via --api-key flag or DEVICE_CLOUD_API_KEY environment variable.');
58
- return;
52
+ },
53
+ },
54
+ async run({ args }) {
55
+ const apiKeyFlag = args['api-key'];
56
+ const apiUrl = (0, config_store_1.resolveApiUrl)(args['api-url']);
57
+ const debug = Boolean(args.debug);
58
+ const uploadId = args['upload-id'];
59
+ const downloadArtifacts = (0, cli_1.validateEnum)(args['download-artifacts'], DOWNLOAD_OPTIONS, 'download-artifacts');
60
+ const artifactsPath = args['artifacts-path'];
61
+ const report = (0, cli_1.validateEnum)(args.report, REPORT_OPTIONS, 'report');
62
+ const allurePath = args['allure-path'];
63
+ const htmlPath = args['html-path'];
64
+ const junitPath = args['junit-path'];
65
+ const auth = await (0, auth_1.resolveAuth)({ apiKeyFlag });
66
+ if (downloadArtifacts && report) {
67
+ throw new cli_1.CliError('--download-artifacts cannot also be provided when using --report (flags are mutually exclusive).');
59
68
  }
60
69
  if (!downloadArtifacts && !report) {
61
- this.error('Either --download-artifacts or --report must be specified.');
62
- return;
70
+ throw new cli_1.CliError('Either --download-artifacts or --report must be specified.');
63
71
  }
64
72
  const service = new report_download_service_1.ReportDownloadService();
65
73
  if (downloadArtifacts) {
66
74
  await service.downloadArtifacts({
67
- apiKey,
75
+ auth,
68
76
  apiUrl,
69
77
  artifactsPath: artifactsPath ?? './artifacts.zip',
70
78
  debug,
71
79
  downloadType: downloadArtifacts,
72
- logger: this.log.bind(this),
80
+ logger: (m) => cli_1.logger.log(m),
73
81
  uploadId,
74
- warnLogger: this.warn.bind(this),
82
+ warnLogger: (m) => cli_1.logger.warn(m),
75
83
  });
76
84
  }
77
85
  if (report) {
78
86
  await service.downloadReports({
79
87
  allurePath,
80
- apiKey,
88
+ auth,
81
89
  apiUrl,
82
90
  debug,
83
91
  htmlPath,
84
92
  junitPath,
85
- logger: this.log.bind(this),
93
+ logger: (m) => cli_1.logger.log(m),
86
94
  reportType: report,
87
95
  uploadId,
88
- warnLogger: this.warn.bind(this),
96
+ warnLogger: (m) => cli_1.logger.warn(m),
89
97
  });
90
98
  }
91
- }
92
- }
93
- exports.default = Artifacts;
99
+ },
100
+ });
101
+ exports.default = exports.artifactsCommand;
@@ -1,4 +1,3 @@
1
- import { Command } from '@oclif/core';
2
1
  /**
3
2
  * Primary CLI command for executing tests on DeviceCloud.
4
3
  * Orchestrates the complete test workflow:
@@ -11,90 +10,231 @@ import { Command } from '@oclif/core';
11
10
  *
12
11
  * Replaces `maestro cloud` with DeviceCloud-specific functionality.
13
12
  */
14
- export default class Cloud extends Command {
15
- static args: {
16
- firstFile: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
17
- secondFile: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
18
- };
19
- static description: string;
20
- static enableJsonFlag: boolean;
21
- static examples: string[];
22
- static flags: {
23
- 'artifacts-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
24
- 'junit-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
25
- 'allure-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
26
- 'html-path': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
27
- async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
28
- debug: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
29
- 'download-artifacts': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
30
- 'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
31
- json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
32
- 'json-file': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
33
- 'json-file-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
34
- quiet: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
35
- report: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
36
- branch: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
37
- 'commit-sha': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
38
- 'repo-name': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
39
- 'pr-number': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
40
- 'pr-url': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
41
- config: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
42
- 'exclude-flows': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
43
- 'exclude-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
44
- flows: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
45
- 'include-tags': import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
46
- 'maestro-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
47
- retry: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
48
- 'runner-type': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
49
- env: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
50
- metadata: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
51
- mitmHost: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
52
- mitmPath: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
53
- 'moropo-v1-api-key': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
54
- name: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
55
- 'android-api-level': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
56
- 'android-device': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
57
- 'device-locale': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
58
- 'google-play': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
59
- 'ios-device': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
60
- 'ios-version': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
61
- orientation: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
62
- 'show-crosshairs': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
63
- 'maestro-chrome-onboarding': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
64
- 'android-no-snapshot': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
65
- 'disable-animations': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
66
- 'app-binary-id': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
67
- 'app-file': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
68
- 'app-url': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
69
- 'ignore-sha-check': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
70
- apiKey: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
71
- apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
72
- };
73
- /** Service for device/OS compatibility validation */
74
- private deviceValidationService;
75
- /** Service for Moropo test framework integration */
76
- private moropoService;
77
- /** Service for downloading test reports and artifacts */
78
- private reportDownloadService;
79
- /** Service for polling test results with 10-second intervals */
80
- private resultsPollingService;
81
- /** Service for submitting tests to the API */
82
- private testSubmissionService;
83
- /**
84
- * Check for CLI updates and notify user if outdated
85
- * Compares current version with latest npm release
86
- * @returns Promise that resolves when version check is complete
87
- */
88
- private versionCheck;
89
- /** Service for CLI version checking */
90
- private versionService;
91
- /**
92
- * Main command execution entry point
93
- * Orchestrates the complete test submission and monitoring workflow
94
- * @returns Promise that resolves when command execution is complete
95
- * @throws RunFailedError if tests fail
96
- * @throws Error for infrastructure or configuration errors
97
- */
98
- run(): Promise<any>;
99
- protected toErrorJson(err: unknown): unknown;
100
- }
13
+ export declare const cloudCommand: import("citty").CommandDef<{
14
+ firstFile: {
15
+ type: "positional";
16
+ required: false;
17
+ description: string;
18
+ };
19
+ secondFile: {
20
+ type: "positional";
21
+ required: false;
22
+ description: string;
23
+ };
24
+ 'artifacts-path': {
25
+ readonly type: "string";
26
+ readonly description: "Custom file path for downloaded artifacts (default: ./artifacts.zip). Requires --download-artifacts.";
27
+ };
28
+ 'junit-path': {
29
+ readonly type: "string";
30
+ readonly description: "Custom file path for downloaded JUnit report (requires --report junit, default: ./report.xml)";
31
+ };
32
+ 'allure-path': {
33
+ readonly type: "string";
34
+ readonly description: "Custom file path for downloaded Allure report (requires --report allure, default: ./report.html)";
35
+ };
36
+ 'html-path': {
37
+ readonly type: "string";
38
+ readonly description: "Custom file path for downloaded HTML report (requires --report html, default: ./report.html)";
39
+ };
40
+ async: {
41
+ readonly type: "boolean";
42
+ readonly description: "Immediately return (exit code 0) from the command without waiting for the results of the run (useful for saving CI minutes)";
43
+ };
44
+ debug: {
45
+ readonly type: "boolean";
46
+ readonly default: false;
47
+ readonly description: "Enable detailed debug logging for troubleshooting issues";
48
+ };
49
+ 'download-artifacts': {
50
+ readonly type: "string";
51
+ readonly description: "Download a zip containing the logs, screenshots and videos for each result in this run (options: ALL, FAILED)";
52
+ };
53
+ 'dry-run': {
54
+ readonly type: "boolean";
55
+ readonly default: false;
56
+ readonly description: "Simulate the run without actually triggering the upload/test, useful for debugging workflow issues.";
57
+ };
58
+ json: {
59
+ readonly type: "boolean";
60
+ readonly description: "Output results in JSON format. Exit codes: 0 on success, 2 if the test run fails, 1 on CLI/infrastructure errors";
61
+ };
62
+ 'json-file': {
63
+ readonly type: "boolean";
64
+ readonly description: "Write JSON output to a file. File will be called <upload_id>_dcd.json unless you supply the --json-file-name flag - note: exits with code 0 even if the test run fails (CLI/infrastructure errors still exit 1)";
65
+ };
66
+ 'json-file-name': {
67
+ readonly type: "string";
68
+ readonly description: "A custom name for the JSON file (can also include relative path). Requires --json-file.";
69
+ };
70
+ quiet: {
71
+ readonly type: "boolean";
72
+ readonly alias: ["q"];
73
+ readonly default: false;
74
+ readonly description: "Quieter console output that won't provide progress updates";
75
+ };
76
+ report: {
77
+ readonly type: "string";
78
+ readonly alias: ["format"];
79
+ readonly description: "Generate and download test reports in the specified format (options: allure, junit, html, html-detailed). Use \"allure\" for a complete HTML report.";
80
+ };
81
+ branch: {
82
+ readonly type: "string";
83
+ readonly description: "Git branch name for this run (stored as gh_branch metadata)";
84
+ };
85
+ 'commit-sha': {
86
+ readonly type: "string";
87
+ readonly description: "Git commit SHA for this run (stored as gh_sha metadata)";
88
+ };
89
+ 'repo-name': {
90
+ readonly type: "string";
91
+ readonly description: "Repository in owner/repo format (stored as gh_repo metadata, e.g. \"acme/my-app\")";
92
+ };
93
+ 'pr-number': {
94
+ readonly type: "string";
95
+ readonly description: "Pull request number for this run (stored as gh_pr_number metadata)";
96
+ };
97
+ 'pr-url': {
98
+ readonly type: "string";
99
+ readonly description: "Pull request URL for this run (stored as gh_pr_url metadata)";
100
+ };
101
+ config: {
102
+ readonly type: "string";
103
+ readonly description: "Path to custom config.yaml file. If not provided, defaults to config.yaml in root flows folders.";
104
+ readonly valueHint: "path";
105
+ };
106
+ 'exclude-flows': {
107
+ readonly type: "string";
108
+ readonly description: "Sub directories to ignore when building the flow file list (comma-separated, may be repeated)";
109
+ };
110
+ 'exclude-tags': {
111
+ readonly type: "string";
112
+ readonly description: "Flows which have these tags will be excluded from the run (comma-separated, may be repeated)";
113
+ };
114
+ flows: {
115
+ readonly type: "string";
116
+ readonly description: "The path to the flow file or folder containing your flows";
117
+ };
118
+ 'include-tags': {
119
+ readonly type: "string";
120
+ readonly description: "Only flows which have these tags will be included in the run (comma-separated, may be repeated)";
121
+ };
122
+ 'maestro-version': {
123
+ readonly type: "string";
124
+ readonly alias: ["maestroVersion"];
125
+ readonly description: "Maestro version to run your flow against. Use \"latest\" for the most recent version. See https://docs.devicecloud.dev/configuration/maestro-versions for supported versions.";
126
+ };
127
+ retry: {
128
+ readonly type: "string";
129
+ readonly description: "Automatically retry the run up to the number of times specified (same as pressing retry in the UI) - this is free of charge";
130
+ };
131
+ 'runner-type': {
132
+ readonly type: "string";
133
+ readonly default: "default";
134
+ readonly description: "[experimental] The type of runner to use (options: default, m4, m1, gpu1, cpu1) - note: anything other than default or cpu1 will incur premium pricing tiers, see https://docs.devicecloud.dev/configuration/runner-type for more information.";
135
+ };
136
+ env: {
137
+ readonly type: "string";
138
+ readonly alias: ["e"];
139
+ readonly description: "One or more environment variables to inject into your flows (format: KEY=VALUE, may be repeated)";
140
+ readonly valueHint: "KEY=VALUE";
141
+ };
142
+ metadata: {
143
+ readonly type: "string";
144
+ readonly alias: ["m"];
145
+ readonly description: "Arbitrary key-value metadata to include with your test run (format: key=value, may be repeated)";
146
+ };
147
+ mitmHost: {
148
+ readonly type: "string";
149
+ readonly description: "used for mitmproxy support, enterprise only, contact support if interested";
150
+ };
151
+ mitmPath: {
152
+ readonly type: "string";
153
+ readonly description: "used for mitmproxy support, enterprise only, contact support if interested";
154
+ };
155
+ 'moropo-v1-api-key': {
156
+ readonly type: "string";
157
+ readonly description: "API key for Moropo v1 integration";
158
+ };
159
+ name: {
160
+ readonly type: "string";
161
+ readonly description: "A custom name for your upload (useful for tagging commits etc)";
162
+ };
163
+ 'android-api-level': {
164
+ readonly type: "string";
165
+ readonly description: `[Android only] Android API level to run your flow against (options: ${string})`;
166
+ };
167
+ 'android-device': {
168
+ readonly type: "string";
169
+ readonly description: `[Android only] Android device to run your flow against (options: ${string})`;
170
+ };
171
+ 'device-locale': {
172
+ readonly type: "string";
173
+ readonly description: "Locale that will be set to a device, ISO-639-1 code and uppercase ISO-3166-1 code e.g. \"de_DE\" for Germany";
174
+ };
175
+ 'google-play': {
176
+ readonly type: "boolean";
177
+ readonly default: false;
178
+ readonly description: "[Android only] Run your flow against Google Play devices";
179
+ };
180
+ 'ios-device': {
181
+ readonly type: "string";
182
+ readonly description: `[iOS only] iOS device to run your flow against (options: ${string})`;
183
+ };
184
+ 'ios-version': {
185
+ readonly type: "string";
186
+ readonly description: `[iOS only] iOS version to run your flow against (options: ${string})`;
187
+ };
188
+ orientation: {
189
+ readonly type: "string";
190
+ readonly description: "[Android only] The orientation of the device to run your flow against (0 = portrait, 90 = landscape)";
191
+ };
192
+ 'show-crosshairs': {
193
+ readonly type: "boolean";
194
+ readonly default: false;
195
+ readonly description: "[Android only] Display crosshairs for screen interactions during test execution";
196
+ };
197
+ 'maestro-chrome-onboarding': {
198
+ readonly type: "boolean";
199
+ readonly default: false;
200
+ readonly description: "[Android only] Force Maestro-based Chrome onboarding - note: this will slow your tests but can fix browser related crashes. See https://docs.devicecloud.dev/advanced/chrome-onboarding for more information.";
201
+ };
202
+ 'android-no-snapshot': {
203
+ readonly type: "boolean";
204
+ readonly default: false;
205
+ readonly description: "[Android only] Force cold boot instead of using snapshot boot. This is automatically enabled for API 35+ but can be used to force cold boot on older API levels.";
206
+ };
207
+ 'disable-animations': {
208
+ readonly type: "boolean";
209
+ readonly default: false;
210
+ readonly description: "Disable device animations during test execution. On Android, disables system animation scales. On iOS, enables Reduce Motion. Reduces CPU load and may improve test reliability.";
211
+ };
212
+ 'app-binary-id': {
213
+ readonly type: "string";
214
+ readonly description: "The ID of the app binary previously uploaded to devicecloud.dev";
215
+ };
216
+ 'app-file': {
217
+ readonly type: "string";
218
+ readonly description: "App binary to run your flows against";
219
+ readonly valueHint: "path";
220
+ };
221
+ 'app-url': {
222
+ readonly type: "string";
223
+ readonly description: "Signed URL to an Expo iOS build (.tar.gz). The archive is downloaded and extracted automatically. Expo signed URLs expire after ~1 hour.";
224
+ };
225
+ 'ignore-sha-check': {
226
+ readonly type: "boolean";
227
+ readonly description: "Ignore the sha hash check and upload the binary regardless of whether it already exists (not recommended)";
228
+ };
229
+ 'api-key': {
230
+ readonly type: "string";
231
+ readonly alias: ["apiKey"];
232
+ readonly description: "API key for devicecloud.dev (find this in the console UI). You can also set the DEVICE_CLOUD_API_KEY environment variable.";
233
+ };
234
+ 'api-url': {
235
+ readonly type: "string";
236
+ readonly alias: ["apiURL", "apiUrl"];
237
+ readonly description: "API base URL (defaults to the URL stored by `dcd login`, else prod)";
238
+ };
239
+ }>;
240
+ export default cloudCommand;