@copado/agentia-cli 0.112.0-alpha.0 → 0.113.0-alpha.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 (277) hide show
  1. package/README.md +1965 -410
  2. package/dist/commands/testing/build/abort.d.ts +7 -1
  3. package/dist/commands/testing/build/abort.js +13 -3
  4. package/dist/commands/testing/build/abort.js.map +1 -1
  5. package/dist/commands/testing/build/get.d.ts +18 -0
  6. package/dist/commands/testing/build/get.js +38 -0
  7. package/dist/commands/testing/build/get.js.map +1 -0
  8. package/dist/commands/testing/build/latest.d.ts +12 -0
  9. package/dist/commands/testing/build/latest.js +40 -0
  10. package/dist/commands/testing/build/latest.js.map +1 -0
  11. package/dist/commands/testing/build/list.d.ts +6 -1
  12. package/dist/commands/testing/build/list.js +23 -1
  13. package/dist/commands/testing/build/list.js.map +1 -1
  14. package/dist/commands/testing/build/logs.d.ts +6 -0
  15. package/dist/commands/testing/build/logs.js +8 -1
  16. package/dist/commands/testing/build/logs.js.map +1 -1
  17. package/dist/commands/testing/build/run.d.ts +27 -4
  18. package/dist/commands/testing/build/run.js +4 -18
  19. package/dist/commands/testing/build/run.js.map +1 -1
  20. package/dist/commands/testing/build/search.d.ts +21 -0
  21. package/dist/commands/testing/build/search.js +57 -0
  22. package/dist/commands/testing/build/search.js.map +1 -0
  23. package/dist/commands/testing/create.d.ts +1 -15
  24. package/dist/commands/testing/create.js +1 -43
  25. package/dist/commands/testing/create.js.map +1 -1
  26. package/dist/commands/testing/data-table/create.d.ts +30 -0
  27. package/dist/commands/testing/data-table/create.js +52 -0
  28. package/dist/commands/testing/data-table/create.js.map +1 -0
  29. package/dist/commands/testing/data-table/delete.d.ts +25 -0
  30. package/dist/commands/testing/data-table/delete.js +40 -0
  31. package/dist/commands/testing/data-table/delete.js.map +1 -0
  32. package/dist/commands/testing/data-table/export.d.ts +33 -0
  33. package/dist/commands/testing/data-table/export.js +59 -0
  34. package/dist/commands/testing/data-table/export.js.map +1 -0
  35. package/dist/commands/testing/data-table/get.d.ts +21 -0
  36. package/dist/commands/testing/data-table/get.js +35 -0
  37. package/dist/commands/testing/data-table/get.js.map +1 -0
  38. package/dist/commands/testing/data-table/list.d.ts +16 -0
  39. package/dist/commands/testing/data-table/list.js +33 -0
  40. package/dist/commands/testing/data-table/list.js.map +1 -0
  41. package/dist/commands/testing/data-table/update.d.ts +34 -0
  42. package/dist/commands/testing/data-table/update.js +64 -0
  43. package/dist/commands/testing/data-table/update.js.map +1 -0
  44. package/dist/commands/testing/job/create.d.ts +18 -0
  45. package/dist/commands/testing/job/create.js +60 -4
  46. package/dist/commands/testing/job/create.js.map +1 -1
  47. package/dist/commands/testing/job/delete.d.ts +6 -1
  48. package/dist/commands/testing/job/delete.js +13 -3
  49. package/dist/commands/testing/job/delete.js.map +1 -1
  50. package/dist/commands/testing/job/refs.d.ts +17 -0
  51. package/dist/commands/testing/job/refs.js +30 -0
  52. package/dist/commands/testing/job/refs.js.map +1 -0
  53. package/dist/commands/testing/job/schedule/get.d.ts +23 -0
  54. package/dist/commands/testing/job/schedule/get.js +31 -0
  55. package/dist/commands/testing/job/schedule/get.js.map +1 -0
  56. package/dist/commands/testing/job/schedule/remove.d.ts +24 -0
  57. package/dist/commands/testing/job/schedule/remove.js +34 -0
  58. package/dist/commands/testing/job/schedule/remove.js.map +1 -0
  59. package/dist/commands/testing/job/schedule/set.d.ts +23 -0
  60. package/dist/commands/testing/job/schedule/set.js +39 -0
  61. package/dist/commands/testing/job/schedule/set.js.map +1 -0
  62. package/dist/commands/testing/job/update.d.ts +2 -0
  63. package/dist/commands/testing/job/update.js +7 -1
  64. package/dist/commands/testing/job/update.js.map +1 -1
  65. package/dist/commands/testing/job/upload.d.ts +6 -0
  66. package/dist/commands/testing/job/upload.js +22 -0
  67. package/dist/commands/testing/job/upload.js.map +1 -1
  68. package/dist/commands/testing/live/continue.d.ts +20 -0
  69. package/dist/commands/testing/live/continue.js +21 -0
  70. package/dist/commands/testing/live/continue.js.map +1 -0
  71. package/dist/commands/testing/live/execute.d.ts +30 -0
  72. package/dist/commands/testing/live/execute.js +43 -0
  73. package/dist/commands/testing/live/execute.js.map +1 -0
  74. package/dist/commands/testing/live/history.d.ts +23 -0
  75. package/dist/commands/testing/live/history.js +35 -0
  76. package/dist/commands/testing/live/history.js.map +1 -0
  77. package/dist/commands/testing/live/inspect.d.ts +18 -0
  78. package/dist/commands/testing/live/inspect.js +30 -0
  79. package/dist/commands/testing/live/inspect.js.map +1 -0
  80. package/dist/commands/testing/live/interrupt.d.ts +20 -0
  81. package/dist/commands/testing/live/interrupt.js +21 -0
  82. package/dist/commands/testing/live/interrupt.js.map +1 -0
  83. package/dist/commands/testing/live/recorder.d.ts +23 -0
  84. package/dist/commands/testing/live/recorder.js +134 -0
  85. package/dist/commands/testing/live/recorder.js.map +1 -0
  86. package/dist/commands/testing/live/reports.d.ts +20 -0
  87. package/dist/commands/testing/live/reports.js +31 -0
  88. package/dist/commands/testing/live/reports.js.map +1 -0
  89. package/dist/commands/testing/live/screenshot.d.ts +23 -0
  90. package/dist/commands/testing/live/screenshot.js +25 -0
  91. package/dist/commands/testing/live/screenshot.js.map +1 -0
  92. package/dist/commands/testing/live/set-options.d.ts +27 -0
  93. package/dist/commands/testing/live/set-options.js +28 -0
  94. package/dist/commands/testing/live/set-options.js.map +1 -0
  95. package/dist/commands/testing/live/start.d.ts +29 -0
  96. package/dist/commands/testing/live/start.js +53 -0
  97. package/dist/commands/testing/live/start.js.map +1 -0
  98. package/dist/commands/testing/live/status.d.ts +19 -0
  99. package/dist/commands/testing/live/status.js +27 -0
  100. package/dist/commands/testing/live/status.js.map +1 -0
  101. package/dist/commands/testing/live/stop.d.ts +24 -0
  102. package/dist/commands/testing/live/stop.js +38 -0
  103. package/dist/commands/testing/live/stop.js.map +1 -0
  104. package/dist/commands/testing/live/view.d.ts +16 -0
  105. package/dist/commands/testing/live/view.js +36 -0
  106. package/dist/commands/testing/live/view.js.map +1 -0
  107. package/dist/commands/testing/logs.d.ts +6 -0
  108. package/dist/commands/testing/logs.js +8 -1
  109. package/dist/commands/testing/logs.js.map +1 -1
  110. package/dist/commands/testing/project/create.d.ts +3 -0
  111. package/dist/commands/testing/project/create.js +17 -1
  112. package/dist/commands/testing/project/create.js.map +1 -1
  113. package/dist/commands/testing/project/delete.d.ts +7 -2
  114. package/dist/commands/testing/project/delete.js +15 -3
  115. package/dist/commands/testing/project/delete.js.map +1 -1
  116. package/dist/commands/testing/project/get.js +1 -1
  117. package/dist/commands/testing/project/get.js.map +1 -1
  118. package/dist/commands/testing/project/permission/get.d.ts +13 -0
  119. package/dist/commands/testing/project/permission/get.js +21 -0
  120. package/dist/commands/testing/project/permission/get.js.map +1 -0
  121. package/dist/commands/testing/project/permission/list.d.ts +13 -0
  122. package/dist/commands/testing/project/permission/list.js +21 -0
  123. package/dist/commands/testing/project/permission/list.js.map +1 -0
  124. package/dist/commands/testing/project/permission/set.d.ts +19 -0
  125. package/dist/commands/testing/project/permission/set.js +33 -0
  126. package/dist/commands/testing/project/permission/set.js.map +1 -0
  127. package/dist/commands/testing/project/permission/update.d.ts +19 -0
  128. package/dist/commands/testing/project/permission/update.js +33 -0
  129. package/dist/commands/testing/project/permission/update.js.map +1 -0
  130. package/dist/commands/testing/project/update.d.ts +14 -0
  131. package/dist/commands/testing/project/update.js +28 -0
  132. package/dist/commands/testing/project/update.js.map +1 -0
  133. package/dist/commands/testing/robot/create.d.ts +4 -1
  134. package/dist/commands/testing/robot/create.js +20 -5
  135. package/dist/commands/testing/robot/create.js.map +1 -1
  136. package/dist/commands/testing/robot/delete.d.ts +6 -1
  137. package/dist/commands/testing/robot/delete.js +13 -3
  138. package/dist/commands/testing/robot/delete.js.map +1 -1
  139. package/dist/commands/testing/robot/update.d.ts +19 -0
  140. package/dist/commands/testing/robot/update.js +49 -0
  141. package/dist/commands/testing/robot/update.js.map +1 -0
  142. package/dist/commands/testing/run.d.ts +27 -4
  143. package/dist/commands/testing/run.js +4 -11
  144. package/dist/commands/testing/run.js.map +1 -1
  145. package/dist/commands/testing/test/run.d.ts +27 -11
  146. package/dist/commands/testing/test/run.js +5 -37
  147. package/dist/commands/testing/test/run.js.map +1 -1
  148. package/dist/commands/testing/update.d.ts +6 -0
  149. package/dist/commands/testing/update.js +10 -0
  150. package/dist/commands/testing/update.js.map +1 -1
  151. package/dist/commands/testing/user-parameter/create.d.ts +19 -0
  152. package/dist/commands/testing/user-parameter/create.js +45 -0
  153. package/dist/commands/testing/user-parameter/create.js.map +1 -0
  154. package/dist/commands/testing/user-parameter/delete.d.ts +21 -0
  155. package/dist/commands/testing/user-parameter/delete.js +33 -0
  156. package/dist/commands/testing/user-parameter/delete.js.map +1 -0
  157. package/dist/commands/testing/user-parameter/get.d.ts +13 -0
  158. package/dist/commands/testing/user-parameter/get.js +21 -0
  159. package/dist/commands/testing/user-parameter/get.js.map +1 -0
  160. package/dist/commands/testing/user-parameter/list.d.ts +12 -0
  161. package/dist/commands/testing/user-parameter/list.js +23 -0
  162. package/dist/commands/testing/user-parameter/list.js.map +1 -0
  163. package/dist/commands/testing/user-parameter/update.d.ts +23 -0
  164. package/dist/commands/testing/user-parameter/update.js +45 -0
  165. package/dist/commands/testing/user-parameter/update.js.map +1 -0
  166. package/dist/commands/testing/variable/create.d.ts +6 -2
  167. package/dist/commands/testing/variable/create.js +14 -5
  168. package/dist/commands/testing/variable/create.js.map +1 -1
  169. package/dist/commands/testing/variable/delete.d.ts +6 -1
  170. package/dist/commands/testing/variable/delete.js +13 -3
  171. package/dist/commands/testing/variable/delete.js.map +1 -1
  172. package/dist/commands/testing/variable/get.d.ts +13 -0
  173. package/dist/commands/testing/variable/get.js +25 -0
  174. package/dist/commands/testing/variable/get.js.map +1 -0
  175. package/dist/commands/testing/variable/list.d.ts +4 -0
  176. package/dist/commands/testing/variable/list.js +15 -3
  177. package/dist/commands/testing/variable/list.js.map +1 -1
  178. package/dist/commands/testing/variable/update.d.ts +6 -2
  179. package/dist/commands/testing/variable/update.js +11 -5
  180. package/dist/commands/testing/variable/update.js.map +1 -1
  181. package/dist/lib/credential-store.d.ts +3 -0
  182. package/dist/lib/credential-store.js +16 -0
  183. package/dist/lib/credential-store.js.map +1 -1
  184. package/dist/lib/mcp/command-id.js +3 -0
  185. package/dist/lib/mcp/command-id.js.map +1 -1
  186. package/dist/lib/mcp/testing-live-tools.d.ts +126 -0
  187. package/dist/lib/mcp/testing-live-tools.js +215 -0
  188. package/dist/lib/mcp/testing-live-tools.js.map +1 -0
  189. package/dist/lib/mcp/testing-tools.d.ts +455 -9
  190. package/dist/lib/mcp/testing-tools.js +677 -37
  191. package/dist/lib/mcp/testing-tools.js.map +1 -1
  192. package/dist/lib/mcp/tools.d.ts +551 -14
  193. package/dist/lib/testing-config.d.ts +3 -0
  194. package/dist/lib/testing-config.js +9 -0
  195. package/dist/lib/testing-config.js.map +1 -1
  196. package/dist/lib/testing-confirmation.d.ts +14 -0
  197. package/dist/lib/testing-confirmation.js +17 -0
  198. package/dist/lib/testing-confirmation.js.map +1 -0
  199. package/dist/lib/testing-data-command.d.ts +21 -0
  200. package/dist/lib/testing-data-command.js +49 -0
  201. package/dist/lib/testing-data-command.js.map +1 -0
  202. package/dist/lib/testing-data-core.d.ts +22 -0
  203. package/dist/lib/testing-data-core.js +208 -0
  204. package/dist/lib/testing-data-core.js.map +1 -0
  205. package/dist/lib/testing-data-export.d.ts +1 -0
  206. package/dist/lib/testing-data-export.js +2 -0
  207. package/dist/lib/testing-data-export.js.map +1 -0
  208. package/dist/lib/testing-data-import.d.ts +1 -0
  209. package/dist/lib/testing-data-import.js +2 -0
  210. package/dist/lib/testing-data-import.js.map +1 -0
  211. package/dist/lib/testing-data-io.d.ts +21 -0
  212. package/dist/lib/testing-data-io.js +236 -0
  213. package/dist/lib/testing-data-io.js.map +1 -0
  214. package/dist/lib/testing-data-operations.d.ts +36 -0
  215. package/dist/lib/testing-data-operations.js +91 -0
  216. package/dist/lib/testing-data-operations.js.map +1 -0
  217. package/dist/lib/testing-data-types.d.ts +41 -0
  218. package/dist/lib/testing-data-types.js +3 -0
  219. package/dist/lib/testing-data-types.js.map +1 -0
  220. package/dist/lib/testing-flags.d.ts +62 -1
  221. package/dist/lib/testing-flags.js +177 -1
  222. package/dist/lib/testing-flags.js.map +1 -1
  223. package/dist/lib/testing-gateway.d.ts +17 -3
  224. package/dist/lib/testing-gateway.js +175 -45
  225. package/dist/lib/testing-gateway.js.map +1 -1
  226. package/dist/lib/testing-live-command.d.ts +24 -0
  227. package/dist/lib/testing-live-command.js +56 -0
  228. package/dist/lib/testing-live-command.js.map +1 -0
  229. package/dist/lib/testing-live-endpoints.d.ts +14 -0
  230. package/dist/lib/testing-live-endpoints.js +34 -0
  231. package/dist/lib/testing-live-endpoints.js.map +1 -0
  232. package/dist/lib/testing-live-history.d.ts +11 -0
  233. package/dist/lib/testing-live-history.js +96 -0
  234. package/dist/lib/testing-live-history.js.map +1 -0
  235. package/dist/lib/testing-live-operations.d.ts +118 -0
  236. package/dist/lib/testing-live-operations.js +676 -0
  237. package/dist/lib/testing-live-operations.js.map +1 -0
  238. package/dist/lib/testing-live-recorder.d.ts +14 -0
  239. package/dist/lib/testing-live-recorder.js +122 -0
  240. package/dist/lib/testing-live-recorder.js.map +1 -0
  241. package/dist/lib/testing-live-robot.d.ts +16 -0
  242. package/dist/lib/testing-live-robot.js +158 -0
  243. package/dist/lib/testing-live-robot.js.map +1 -0
  244. package/dist/lib/testing-live-state.d.ts +4 -0
  245. package/dist/lib/testing-live-state.js +90 -0
  246. package/dist/lib/testing-live-state.js.map +1 -0
  247. package/dist/lib/testing-live-types.d.ts +92 -0
  248. package/dist/lib/testing-live-types.js +2 -0
  249. package/dist/lib/testing-live-types.js.map +1 -0
  250. package/dist/lib/testing-operations.d.ts +157 -5
  251. package/dist/lib/testing-operations.js +829 -66
  252. package/dist/lib/testing-operations.js.map +1 -1
  253. package/dist/lib/testing-run-command.d.ts +25 -0
  254. package/dist/lib/testing-run-command.js +94 -0
  255. package/dist/lib/testing-run-command.js.map +1 -0
  256. package/dist/lib/testing-sanitization.d.ts +11 -0
  257. package/dist/lib/testing-sanitization.js +135 -0
  258. package/dist/lib/testing-sanitization.js.map +1 -0
  259. package/dist/lib/testing-schedule.d.ts +23 -0
  260. package/dist/lib/testing-schedule.js +48 -0
  261. package/dist/lib/testing-schedule.js.map +1 -0
  262. package/dist/lib/testing-secret-input.d.ts +12 -0
  263. package/dist/lib/testing-secret-input.js +56 -0
  264. package/dist/lib/testing-secret-input.js.map +1 -0
  265. package/dist/lib/testing-session.d.ts +8 -0
  266. package/dist/lib/testing-session.js +82 -0
  267. package/dist/lib/testing-session.js.map +1 -0
  268. package/dist/lib/testing-types.d.ts +143 -13
  269. package/dist/lib/testing-types.js +110 -5
  270. package/dist/lib/testing-types.js.map +1 -1
  271. package/dist/lib/testing-watch.d.ts +4 -0
  272. package/dist/lib/testing-watch.js +45 -0
  273. package/dist/lib/testing-watch.js.map +1 -0
  274. package/oclif.manifest.json +8354 -3760
  275. package/package.json +12 -1
  276. package/templates/skills/agentia-testing/SKILL.md +9 -6
  277. package/templates/skills/agentia-testing/references/tests.md +70 -36
@@ -1,5 +1,5 @@
1
1
  import { Flags } from '@oclif/core';
2
- import { TESTING_RECORD_BUILD_OPTIONS } from './testing-types.js';
2
+ import { TESTING_CONSOLE_COLORS, TESTING_RECORD_BUILD_OPTIONS, TESTING_RUN_TYPES, } from './testing-types.js';
3
3
  export const testingProjectFlag = {
4
4
  project: Flags.integer({
5
5
  char: 'p',
@@ -7,6 +7,38 @@ export const testingProjectFlag = {
7
7
  required: true,
8
8
  }),
9
9
  };
10
+ export const testingYesFlag = {
11
+ yes: Flags.boolean({
12
+ char: 'y',
13
+ default: false,
14
+ description: 'Skip the destructive confirmation prompt.',
15
+ }),
16
+ };
17
+ export const testingSecretInputFlags = {
18
+ 'no-trim': Flags.boolean({
19
+ default: false,
20
+ description: 'Preserve leading and trailing whitespace in the supplied value.',
21
+ exclusive: ['trim'],
22
+ }),
23
+ trim: Flags.boolean({
24
+ default: false,
25
+ description: 'Trim leading and trailing whitespace (the default policy).',
26
+ exclusive: ['no-trim'],
27
+ }),
28
+ value: Flags.string({
29
+ description: 'Value supplied directly. Prefer file/stdin for sensitive values.',
30
+ exclusive: ['value-file', 'value-stdin'],
31
+ }),
32
+ 'value-file': Flags.string({
33
+ description: 'Read the value from a bounded regular file.',
34
+ exclusive: ['value', 'value-stdin'],
35
+ }),
36
+ 'value-stdin': Flags.boolean({
37
+ default: false,
38
+ description: 'Read the value from stdin.',
39
+ exclusive: ['value', 'value-file'],
40
+ }),
41
+ };
10
42
  export const testingJobFlag = {
11
43
  job: Flags.integer({
12
44
  char: 'j',
@@ -23,14 +55,52 @@ export const testingRunOptionFlags = {
23
55
  branch: Flags.string({
24
56
  description: 'Git branch/ref to use for this run. Mutually exclusive with --tag.',
25
57
  }),
58
+ 'console-colors': Flags.option({
59
+ description: 'Control Robot Framework console colors.',
60
+ options: [...TESTING_CONSOLE_COLORS],
61
+ })(),
62
+ 'console-width': Flags.integer({
63
+ description: 'Set Robot Framework console width.',
64
+ min: 1,
65
+ }),
66
+ datatable: Flags.string({
67
+ description: 'Data table and 1-based datasets as TABLE_ID:1,2-4. Repeat for zipped table selections.',
68
+ multiple: true,
69
+ }),
70
+ doc: Flags.string({
71
+ description: 'Set top-level Robot Framework suite documentation.',
72
+ }),
73
+ 'dry-run': Flags.boolean({
74
+ default: false,
75
+ description: 'Validate Robot Framework data without executing library keywords.',
76
+ }),
26
77
  exclude: Flags.string({
27
78
  description: 'Robot Framework tag to exclude from this run. Can be provided multiple times.',
28
79
  multiple: true,
29
80
  }),
81
+ 'exit-on-error': Flags.boolean({
82
+ default: false,
83
+ description: 'Stop execution when Robot Framework encounters a data or import error.',
84
+ }),
85
+ 'exit-on-failure': Flags.boolean({
86
+ default: false,
87
+ description: 'Stop execution when a critical Robot Framework test fails.',
88
+ }),
30
89
  include: Flags.string({
31
90
  description: 'Robot Framework tag to include in this run. Can be provided multiple times.',
32
91
  multiple: true,
33
92
  }),
93
+ metadata: Flags.string({
94
+ description: 'Robot Framework suite metadata. Can be provided multiple times.',
95
+ multiple: true,
96
+ }),
97
+ name: Flags.string({
98
+ description: 'Set the top-level Robot Framework suite name.',
99
+ }),
100
+ 'no-exit-code': Flags.boolean({
101
+ default: false,
102
+ description: 'Return exit code zero even when the waited CRT run fails.',
103
+ }),
34
104
  param: Flags.string({
35
105
  description: 'Execution parameter in KEY=VALUE format. Can be provided multiple times.',
36
106
  multiple: true,
@@ -46,9 +116,63 @@ export const testingRunOptionFlags = {
46
116
  default: false,
47
117
  description: 'Rerun failed tests from the latest failed run. Mutually exclusive with --rerun-failed.',
48
118
  }),
119
+ 'run-empty-suite': Flags.boolean({
120
+ default: false,
121
+ description: 'Execute even when the selected Robot Framework suite is empty.',
122
+ }),
123
+ 'run-type': Flags.option({
124
+ description: 'CRT run type. Regression is sent as normal; development is sent unchanged.',
125
+ options: [...TESTING_RUN_TYPES],
126
+ })(),
127
+ 'save-artifacts': Flags.string({
128
+ description: 'Save the completed run output ZIP to this explicit file path.',
129
+ }),
130
+ 'set-tag': Flags.string({
131
+ description: 'Set a tag on all executed tests. Can be provided multiple times.',
132
+ multiple: true,
133
+ }),
134
+ skip: Flags.string({
135
+ description: 'Skip tests matching this tag. Can be provided multiple times.',
136
+ multiple: true,
137
+ }),
138
+ 'skip-on-failure': Flags.string({
139
+ description: 'Skip failures for tests matching this tag. Can be provided multiple times.',
140
+ multiple: true,
141
+ }),
142
+ 'stream-logs': Flags.boolean({
143
+ default: false,
144
+ description: 'Stream new CRT log text while waiting (human output only).',
145
+ }),
146
+ suite: Flags.string({
147
+ description: 'Select a Robot Framework suite. Can be provided multiple times.',
148
+ multiple: true,
149
+ }),
49
150
  tag: Flags.string({
50
151
  description: 'Git tag to use for this run. Mutually exclusive with --branch.',
51
152
  }),
153
+ test: Flags.string({
154
+ description: 'Select a Robot Framework test/task. Can be provided multiple times.',
155
+ multiple: true,
156
+ }),
157
+ timeout: Flags.integer({
158
+ default: 60,
159
+ description: 'Maximum number of minutes to wait for a terminal result.',
160
+ min: 1,
161
+ }),
162
+ variable: Flags.string({
163
+ description: 'Set a Robot Framework variable. Can be provided multiple times.',
164
+ multiple: true,
165
+ }),
166
+ 'wait-for-result': Flags.boolean({
167
+ default: false,
168
+ description: 'Poll CRT until the started build reaches a terminal result.',
169
+ }),
170
+ watch: Flags.string({
171
+ description: 'Watch a directory and rerun after debounced file changes (human output only).',
172
+ }),
173
+ xunit: Flags.string({
174
+ description: 'Extract xunit_report.xml from completed run artifacts to this explicit file path.',
175
+ }),
52
176
  };
53
177
  export const testingOutputFlags = {
54
178
  output: Flags.string({
@@ -56,6 +180,31 @@ export const testingOutputFlags = {
56
180
  description: 'Write raw output to this file path.',
57
181
  }),
58
182
  };
183
+ export const testingLogOptionFlags = {
184
+ container: Flags.string({
185
+ description: 'Read a specific CRT log stream/container.',
186
+ }),
187
+ 'limit-bytes': Flags.integer({
188
+ description: 'Limit fetched log data to this many bytes.',
189
+ min: 1,
190
+ }),
191
+ pretty: Flags.boolean({
192
+ default: false,
193
+ description: 'Request readable log formatting.',
194
+ }),
195
+ 'since-seconds': Flags.integer({
196
+ description: 'Fetch log lines from the last N seconds.',
197
+ min: 0,
198
+ }),
199
+ 'tail-lines': Flags.integer({
200
+ description: 'Return only the last N log lines.',
201
+ min: 0,
202
+ }),
203
+ timestamps: Flags.boolean({
204
+ default: false,
205
+ description: 'Add timestamps to log lines.',
206
+ }),
207
+ };
59
208
  export const testingFileInputFlags = {
60
209
  dir: Flags.string({
61
210
  description: 'Directory containing Robot Framework files to upload. Can be provided multiple times.',
@@ -76,6 +225,16 @@ export const testingGitStorageFlags = {
76
225
  }),
77
226
  'git-password': Flags.string({
78
227
  description: 'Git password/token for repository access. Prefer --git-domain-credential when available.',
228
+ exclusive: ['git-password-file', 'git-password-stdin'],
229
+ }),
230
+ 'git-password-file': Flags.string({
231
+ description: 'Read a bounded Git password/token from a regular file.',
232
+ exclusive: ['git-password', 'git-password-stdin'],
233
+ }),
234
+ 'git-password-stdin': Flags.boolean({
235
+ default: false,
236
+ description: 'Read a Git password/token from stdin.',
237
+ exclusive: ['git-password', 'git-password-file'],
79
238
  }),
80
239
  'git-tag': Flags.string({
81
240
  description: 'Git tag to use for a Git-backed CRT job. Mutually exclusive with --git-branch.',
@@ -114,15 +273,32 @@ export function testingRunOptions(flags, ids) {
114
273
  }
115
274
  return {
116
275
  branch: flags.branch,
276
+ consoleColors: flags['console-colors'],
277
+ consoleWidth: flags['console-width'],
278
+ dataTables: flags.datatable,
279
+ doc: flags.doc,
280
+ dryRun: flags['dry-run'],
117
281
  exclude: flags.exclude,
282
+ exitOnError: flags['exit-on-error'],
283
+ exitOnFailure: flags['exit-on-failure'],
118
284
  include: flags.include,
119
285
  jobId: ids.jobId,
286
+ metadata: flags.metadata,
287
+ name: flags.name,
120
288
  parameters: (flags.param ?? []).map((param) => parseTestingParameter(param)),
121
289
  projectId: ids.projectId,
122
290
  record: flags.record,
123
291
  rerunFailedFromLatest: flags['rerun-failed-from-latest'] === true ? true : undefined,
124
292
  rerunFailedId: flags['rerun-failed'],
293
+ runEmptySuite: flags['run-empty-suite'],
294
+ runType: flags['run-type'],
295
+ setTags: flags['set-tag'],
296
+ skip: flags.skip,
297
+ skipOnFailure: flags['skip-on-failure'],
298
+ suites: flags.suite,
125
299
  tag: flags.tag,
300
+ tests: flags.test,
301
+ variables: flags.variable,
126
302
  };
127
303
  }
128
304
  function parseTestingParameter(spec) {
@@ -1 +1 @@
1
- {"version":3,"file":"testing-flags.js","sourceRoot":"","sources":["../../src/lib/testing-flags.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing-flags.js","sourceRoot":"","sources":["../../src/lib/testing-flags.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,24 @@
1
1
  import { URL } from 'node:url';
2
2
  import { type TestingConnectionOverrides } from './testing-config.js';
3
3
  export declare const TESTING_DEFAULT_TIMEOUT_MS = 45000;
4
+ export declare const TESTING_MAX_RESPONSE_BYTES: number;
5
+ export declare const TESTING_MAX_ARTIFACT_BYTES: number;
4
6
  export type TestingRequest = {
7
+ auth?: {
8
+ cookie: string;
9
+ mode: 'session';
10
+ xsrfToken?: string;
11
+ };
5
12
  body?: unknown;
6
13
  endpoint: string;
14
+ headers?: Record<string, string>;
15
+ maxResponseBytes?: number;
7
16
  method: 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT';
8
- responseType?: 'json' | 'text';
9
- service: 'pace' | 'platform';
17
+ responseType?: 'buffer' | 'json' | 'text';
18
+ service: 'metrics' | 'pace' | 'platform' | 'session' | 'test-data';
19
+ sessionPath?: string;
10
20
  };
11
- export type TestingHttpRequestFn = (url: URL, method: string, headers: Record<string, string>, body: unknown, timeoutMs: number) => Promise<string>;
21
+ export type TestingHttpRequestFn = (url: URL, method: string, headers: Record<string, string>, body: unknown, timeoutMs: number, maxResponseBytes?: number) => Promise<Buffer | string>;
12
22
  export type TestingGatewayCallOptions = TestingConnectionOverrides & {
13
23
  timeoutMs?: number;
14
24
  };
@@ -28,6 +38,7 @@ export declare class TestingGatewayError extends Error {
28
38
  }
29
39
  export declare class TestingGateway {
30
40
  static call<T = unknown>(request: TestingRequest, options?: TestingGatewayCallOptions): Promise<T>;
41
+ static downloadArtifact(location: string, options?: TestingGatewayCallOptions): Promise<Buffer>;
31
42
  static resolveAndValidateDomain(pat: string, orgId: number, customDomain?: string): Promise<string>;
32
43
  static validateCredentials(options: {
33
44
  domain: string;
@@ -35,6 +46,9 @@ export declare class TestingGateway {
35
46
  pat: string;
36
47
  }): Promise<void>;
37
48
  }
49
+ export declare function resolveTestingArtifactUrl(location: string, configuredDomain: string): URL;
50
+ export declare function resolveTestingSessionUrl(location: string, configuredDomain: string): URL;
51
+ export declare function resolveTestingSessionWebSocketUrl(sessionPath: string, configuredDomain: string): URL;
38
52
  export declare function validateCrtCredentials(options: {
39
53
  domain: string;
40
54
  orgId: number;
@@ -2,10 +2,13 @@ import * as http from 'node:http';
2
2
  import * as https from 'node:https';
3
3
  import { URL } from 'node:url';
4
4
  import { createTransactionId, CRT_GATEWAY_EVENT_SERVICE, gatewayRefererHeaders, gatewayUserAgent, getGatewayTransactionId, scheduleGatewayEventLog, } from './cicd-gateway.js';
5
- import { formatDebugBody, logVerboseDebug } from './debug.js';
6
- import { CRT_DISCOVERY_DOMAINS, normalizeCrtDomain, paceBaseUrl, platformBaseUrl, resolveTestingCredentials, } from './testing-config.js';
5
+ import { logVerboseDebug } from './debug.js';
6
+ import { CRT_DISCOVERY_DOMAINS, metricsBaseUrl, normalizeCrtDomain, paceBaseUrl, platformBaseUrl, resolveTestingCredentials, sessionsBaseUrl, testDataBaseUrl, } from './testing-config.js';
7
+ import { sanitizeTestingUrl, summarizeTestingDebugRequest, summarizeTestingDebugResponse, TESTING_REDACTED, testingProviderErrorMessage, } from './testing-sanitization.js';
7
8
  import { testingProjectsEndpoint } from './testing-types.js';
8
9
  export const TESTING_DEFAULT_TIMEOUT_MS = 45_000;
10
+ export const TESTING_MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
11
+ export const TESTING_MAX_ARTIFACT_BYTES = 100 * 1024 * 1024;
9
12
  export class TestingGatewayError extends Error {
10
13
  requestMethod;
11
14
  requestUrl;
@@ -40,22 +43,9 @@ function parseRetryAfterHeader(value) {
40
43
  const dateMs = Date.parse(trimmed);
41
44
  return Number.isNaN(dateMs) ? undefined : Math.max(0, Math.ceil((dateMs - Date.now()) / 1000));
42
45
  }
43
- function extractErrorMessage(raw) {
44
- try {
45
- const parsed = JSON.parse(raw);
46
- for (const value of [parsed.message, parsed.error, parsed.title]) {
47
- if (typeof value === 'string' && value.trim().length > 0)
48
- return value.trim();
49
- }
50
- }
51
- catch {
52
- return raw.trim().length > 0 ? raw.trim() : undefined;
53
- }
54
- return undefined;
55
- }
56
- function defaultHttpsRequest(url, method, headers, body, timeoutMs) {
46
+ function defaultHttpsRequest(url, method, headers, body, timeoutMs, maxResponseBytes = TESTING_MAX_RESPONSE_BYTES) {
57
47
  const hasBody = body !== undefined;
58
- const payload = hasBody ? JSON.stringify(body) : '';
48
+ const payload = hasBody ? (typeof body === 'string' ? body : JSON.stringify(body)) : '';
59
49
  const requestHeaders = {
60
50
  Accept: 'application/json',
61
51
  ...headers,
@@ -75,17 +65,25 @@ function defaultHttpsRequest(url, method, headers, body, timeoutMs) {
75
65
  timeout: timeoutMs,
76
66
  }, (res) => {
77
67
  const chunks = [];
78
- res.on('data', (chunk) => chunks.push(chunk));
68
+ let responseBytes = 0;
69
+ res.on('data', (chunk) => {
70
+ responseBytes += chunk.length;
71
+ if (responseBytes > maxResponseBytes) {
72
+ req.destroy(new TestingGatewayError(`CRT response exceeded the ${maxResponseBytes} byte safety limit.`));
73
+ return;
74
+ }
75
+ chunks.push(chunk);
76
+ });
79
77
  res.on('end', () => {
80
- const raw = Buffer.concat(chunks).toString('utf8');
78
+ const raw = Buffer.concat(chunks);
81
79
  const status = res.statusCode ?? 0;
82
80
  if (status >= 400) {
81
+ const text = raw.toString('utf8');
83
82
  logVerboseDebug('CRT response', {
84
- body: formatDebugBody(raw),
83
+ body: summarizeTestingDebugResponse(text),
85
84
  status,
86
85
  });
87
- const message = extractErrorMessage(raw) ?? `CRT request failed (${status}).`;
88
- reject(new TestingGatewayError(message, {
86
+ reject(new TestingGatewayError(testingProviderErrorMessage(text, status), {
89
87
  retryAfterSeconds: status === 429 ? parseRetryAfterHeader(res.headers['retry-after']) : undefined,
90
88
  statusCode: status,
91
89
  }));
@@ -105,7 +103,23 @@ function defaultHttpsRequest(url, method, headers, body, timeoutMs) {
105
103
  }
106
104
  let httpRequestFn = defaultHttpsRequest;
107
105
  function requestUrl(request, domain) {
108
- const baseUrl = request.service === 'platform' ? platformBaseUrl(domain) : paceBaseUrl(domain);
106
+ if (request.service === 'session') {
107
+ if (request.sessionPath === undefined) {
108
+ throw new TestingGatewayError('CRT session requests require a validated session path.');
109
+ }
110
+ const base = resolveTestingSessionUrl(request.sessionPath, domain);
111
+ if (!/^\/api\/[a-z-]+$/u.test(request.endpoint)) {
112
+ throw new TestingGatewayError('CRT session endpoint has an unexpected format.');
113
+ }
114
+ return new URL(`${base.pathname}${request.endpoint}`, `${base.protocol}//${base.host}`);
115
+ }
116
+ const baseUrl = request.service === 'platform'
117
+ ? platformBaseUrl(domain)
118
+ : request.service === 'metrics'
119
+ ? metricsBaseUrl(domain)
120
+ : request.service === 'test-data'
121
+ ? testDataBaseUrl(domain)
122
+ : paceBaseUrl(domain);
109
123
  return new URL(request.endpoint, `${baseUrl}/`);
110
124
  }
111
125
  function withRequestSuffix(message, request) {
@@ -114,36 +128,58 @@ function withRequestSuffix(message, request) {
114
128
  return message;
115
129
  return message.endsWith('.') ? `${message} ${suffix}` : `${message}. ${suffix}`;
116
130
  }
117
- function maskSecret(value) {
118
- if (value.length <= 8) {
119
- return '<masked>';
120
- }
121
- return `${value.slice(0, 4)}...${value.slice(-4)}`;
122
- }
123
131
  function maskTestingHeaders(headers) {
124
- const masked = { ...headers };
125
- if (masked['X-Authorization'] !== undefined) {
126
- masked['X-Authorization'] = maskSecret(masked['X-Authorization']);
132
+ const masked = {};
133
+ for (const [key, value] of Object.entries(headers)) {
134
+ masked[key] = /authorization|cookie|csrf|xsrf/iu.test(key) ? TESTING_REDACTED : value;
127
135
  }
128
136
  return masked;
129
137
  }
130
138
  async function executeTestingRequest(request, options = {}) {
131
139
  const credentials = resolveTestingCredentials(options);
140
+ if (request.service === 'test-data' && request.auth?.mode !== 'session') {
141
+ throw new TestingGatewayError('CRT test-data requests require an in-memory session.');
142
+ }
143
+ if (request.service === 'session' && request.auth?.mode !== 'session') {
144
+ throw new TestingGatewayError('CRT live session requests require an in-memory session.');
145
+ }
146
+ if (request.service === 'test-data' &&
147
+ Object.keys(request.headers ?? {}).some((key) => key.toLowerCase() === 'x-authorization')) {
148
+ throw new TestingGatewayError('CRT test-data requests must not send X-Authorization.');
149
+ }
150
+ if (request.service !== 'test-data' && request.service !== 'session' && request.auth !== undefined) {
151
+ throw new TestingGatewayError('CRT session authentication is restricted to session services.');
152
+ }
132
153
  const url = requestUrl(request, credentials.domain);
133
- const requestInfo = { method: request.method, url: url.toString() };
154
+ const safeUrl = sanitizeTestingUrl(url);
155
+ const requestInfo = { method: request.method, url: safeUrl };
134
156
  const transactionId = transactionIdForRequest();
157
+ const authenticationHeaders = {};
158
+ if (request.auth?.mode === 'session') {
159
+ authenticationHeaders.Cookie = request.auth.cookie;
160
+ if (request.auth.xsrfToken !== undefined)
161
+ authenticationHeaders['X-XSRF-TOKEN'] = request.auth.xsrfToken;
162
+ }
163
+ else {
164
+ authenticationHeaders['X-Authorization'] = credentials.pak;
165
+ }
135
166
  const headers = {
136
167
  ...gatewayRefererHeaders(),
168
+ ...request.headers,
137
169
  'User-Agent': userAgent(),
138
- 'X-Authorization': credentials.pak,
170
+ ...authenticationHeaders,
139
171
  'x-transaction-id': transactionId,
140
172
  };
141
173
  let raw;
142
174
  logVerboseDebug('CRT request', {
143
- body: request.body ?? null,
175
+ body: summarizeTestingDebugRequest(request.body, {
176
+ redactValues: request.service === 'session' ||
177
+ request.endpoint.includes('/secrets') ||
178
+ request.endpoint.includes('/user-parameters'),
179
+ }),
144
180
  headers: maskTestingHeaders(headers),
145
181
  method: request.method,
146
- url: url.toString(),
182
+ url: safeUrl,
147
183
  });
148
184
  try {
149
185
  scheduleGatewayEventLog({
@@ -151,30 +187,45 @@ async function executeTestingRequest(request, options = {}) {
151
187
  method: request.method,
152
188
  orgId: credentials.orgId.toString(),
153
189
  service: CRT_GATEWAY_EVENT_SERVICE,
154
- url: url.toString(),
190
+ url: safeUrl,
155
191
  });
156
- raw = await httpRequestFn(url, request.method, headers, request.body, options.timeoutMs ?? TESTING_DEFAULT_TIMEOUT_MS);
192
+ raw = await httpRequestFn(url, request.method, headers, request.body, options.timeoutMs ?? TESTING_DEFAULT_TIMEOUT_MS, request.maxResponseBytes ?? TESTING_MAX_RESPONSE_BYTES);
157
193
  }
158
194
  catch (error) {
159
195
  if (error instanceof TestingGatewayError) {
160
- throw new TestingGatewayError(withRequestSuffix(error.message, requestInfo), {
196
+ const message = error.statusCode === undefined
197
+ ? error.message.startsWith('CRT response exceeded')
198
+ ? error.message
199
+ : 'CRT request failed.'
200
+ : testingProviderErrorMessage(JSON.stringify({ message: error.message }), error.statusCode);
201
+ const safeMessage = request.service === 'session' ? message : withRequestSuffix(message, requestInfo);
202
+ throw new TestingGatewayError(safeMessage, {
161
203
  request: requestInfo,
162
204
  retryAfterSeconds: error.retryAfterSeconds,
163
205
  statusCode: error.statusCode,
164
206
  });
165
207
  }
166
- throw error;
208
+ const message = request.service === 'session'
209
+ ? 'CRT live request failed before receiving a response.'
210
+ : withRequestSuffix('CRT request failed before receiving a response', requestInfo);
211
+ throw new TestingGatewayError(message, {
212
+ request: requestInfo,
213
+ });
167
214
  }
168
- logVerboseDebug('CRT response', formatDebugBody(raw));
169
- if (raw.trim().length === 0)
215
+ const responseBuffer = typeof raw === 'string' ? Buffer.from(raw, 'utf8') : raw;
216
+ const responseText = responseBuffer.toString('utf8');
217
+ logVerboseDebug('CRT response', summarizeTestingDebugResponse(responseText, request.responseType));
218
+ if (responseBuffer.length === 0)
170
219
  return undefined;
220
+ if (request.responseType === 'buffer')
221
+ return responseBuffer;
171
222
  if (request.responseType === 'text')
172
- return raw;
223
+ return responseText;
173
224
  try {
174
- return JSON.parse(raw);
225
+ return JSON.parse(responseText);
175
226
  }
176
227
  catch {
177
- throw new TestingGatewayError(withRequestSuffix(`CRT API returned non-JSON response: ${raw}`, requestInfo), {
228
+ throw new TestingGatewayError(withRequestSuffix('CRT API returned an unexpected non-JSON response', requestInfo), {
178
229
  request: requestInfo,
179
230
  });
180
231
  }
@@ -183,6 +234,17 @@ export class TestingGateway {
183
234
  static async call(request, options = {}) {
184
235
  return executeTestingRequest(request, options);
185
236
  }
237
+ static async downloadArtifact(location, options = {}) {
238
+ const credentials = resolveTestingCredentials(options);
239
+ const url = resolveTestingArtifactUrl(location, credentials.domain);
240
+ return executeTestingRequest({
241
+ endpoint: `${url.pathname}${url.search}`,
242
+ maxResponseBytes: TESTING_MAX_ARTIFACT_BYTES,
243
+ method: 'GET',
244
+ responseType: 'buffer',
245
+ service: 'pace',
246
+ }, options);
247
+ }
186
248
  static async resolveAndValidateDomain(pat, orgId, customDomain) {
187
249
  return resolveAndValidateCrtDomain(pat, orgId, customDomain);
188
250
  }
@@ -190,6 +252,74 @@ export class TestingGateway {
190
252
  await validateCrtCredentials(options);
191
253
  }
192
254
  }
255
+ export function resolveTestingArtifactUrl(location, configuredDomain) {
256
+ const value = location.trim();
257
+ if (value.length === 0)
258
+ throw new Error('CRT artifact URL is empty.');
259
+ if (value.startsWith('//'))
260
+ throw new Error('CRT artifact URL must be relative or use HTTPS.');
261
+ const expectedHost = `api.${normalizeCrtDomain(configuredDomain)}`;
262
+ const absolute = /^[a-z][a-z\d+.-]*:/iu.test(value);
263
+ if (!absolute) {
264
+ let decodedPath;
265
+ try {
266
+ decodedPath = decodeURIComponent(value.split(/[?#]/u, 1)[0] ?? '');
267
+ }
268
+ catch {
269
+ throw new Error('CRT artifact URL contains invalid path encoding.');
270
+ }
271
+ if (decodedPath.split('/').includes('..')) {
272
+ throw new Error('CRT artifact URL must not contain path traversal.');
273
+ }
274
+ }
275
+ const url = new URL(value, `https://${expectedHost}/`);
276
+ if (url.protocol !== 'https:' || url.hostname !== expectedHost || url.port.length > 0) {
277
+ throw new Error(`CRT artifact URL must use HTTPS on ${expectedHost}.`);
278
+ }
279
+ if (url.username.length > 0 || url.password.length > 0) {
280
+ throw new Error('CRT artifact URL must not contain credentials.');
281
+ }
282
+ if (absolute && !value.toLowerCase().startsWith('https://')) {
283
+ throw new Error('CRT artifact URL must be relative or use HTTPS.');
284
+ }
285
+ return url;
286
+ }
287
+ export function resolveTestingSessionUrl(location, configuredDomain) {
288
+ const expectedHost = `sessions.${normalizeCrtDomain(configuredDomain)}`;
289
+ const value = location.trim();
290
+ if (value.length === 0 || value.startsWith('//'))
291
+ throw new Error('CRT live session URL is invalid.');
292
+ const url = new URL(value, `${sessionsBaseUrl(configuredDomain)}/`);
293
+ if (url.protocol !== 'https:' ||
294
+ url.hostname !== expectedHost ||
295
+ url.port.length > 0 ||
296
+ url.username.length > 0 ||
297
+ url.password.length > 0) {
298
+ throw new Error(`CRT live session URL must use HTTPS on ${expectedHost}.`);
299
+ }
300
+ if (url.search.length > 0 || url.hash.length > 0) {
301
+ throw new Error('CRT live session URL must not contain query parameters or fragments.');
302
+ }
303
+ let decodedPath;
304
+ try {
305
+ decodedPath = decodeURIComponent(url.pathname);
306
+ }
307
+ catch {
308
+ throw new Error('CRT live session URL contains invalid path encoding.');
309
+ }
310
+ if (decodedPath.split('/').includes('..') || !/^\/live-testing\/\d+\/?$/u.test(decodedPath)) {
311
+ throw new Error('CRT live session URL has an unexpected path.');
312
+ }
313
+ url.pathname = decodedPath.replace(/\/$/u, '');
314
+ return url;
315
+ }
316
+ export function resolveTestingSessionWebSocketUrl(sessionPath, configuredDomain) {
317
+ const session = resolveTestingSessionUrl(sessionPath, configuredDomain);
318
+ const url = new URL(session);
319
+ url.protocol = 'wss:';
320
+ url.pathname = `${url.pathname}/client/websocket`;
321
+ return url;
322
+ }
193
323
  export async function validateCrtCredentials(options) {
194
324
  const domain = normalizeCrtDomain(options.domain);
195
325
  await executeTestingRequest({