@desplega.ai/qa-use 2.1.5 → 2.2.2

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 (145) hide show
  1. package/dist/lib/api/browser-types.d.ts +175 -0
  2. package/dist/lib/api/browser-types.d.ts.map +1 -0
  3. package/dist/lib/api/browser-types.js +5 -0
  4. package/dist/lib/api/browser-types.js.map +1 -0
  5. package/dist/lib/api/browser.d.ts +66 -0
  6. package/dist/lib/api/browser.d.ts.map +1 -0
  7. package/dist/lib/api/browser.js +223 -0
  8. package/dist/lib/api/browser.js.map +1 -0
  9. package/dist/package.json +2 -1
  10. package/dist/src/cli/commands/browser/back.d.ts +6 -0
  11. package/dist/src/cli/commands/browser/back.d.ts.map +1 -0
  12. package/dist/src/cli/commands/browser/back.js +42 -0
  13. package/dist/src/cli/commands/browser/back.js.map +1 -0
  14. package/dist/src/cli/commands/browser/check.d.ts +6 -0
  15. package/dist/src/cli/commands/browser/check.d.ts.map +1 -0
  16. package/dist/src/cli/commands/browser/check.js +62 -0
  17. package/dist/src/cli/commands/browser/check.js.map +1 -0
  18. package/dist/src/cli/commands/browser/click.d.ts +6 -0
  19. package/dist/src/cli/commands/browser/click.d.ts.map +1 -0
  20. package/dist/src/cli/commands/browser/click.js +63 -0
  21. package/dist/src/cli/commands/browser/click.js.map +1 -0
  22. package/dist/src/cli/commands/browser/close.d.ts +6 -0
  23. package/dist/src/cli/commands/browser/close.d.ts.map +1 -0
  24. package/dist/src/cli/commands/browser/close.js +44 -0
  25. package/dist/src/cli/commands/browser/close.js.map +1 -0
  26. package/dist/src/cli/commands/browser/create.d.ts +6 -0
  27. package/dist/src/cli/commands/browser/create.d.ts.map +1 -0
  28. package/dist/src/cli/commands/browser/create.js +281 -0
  29. package/dist/src/cli/commands/browser/create.js.map +1 -0
  30. package/dist/src/cli/commands/browser/fill.d.ts +6 -0
  31. package/dist/src/cli/commands/browser/fill.d.ts.map +1 -0
  32. package/dist/src/cli/commands/browser/fill.js +83 -0
  33. package/dist/src/cli/commands/browser/fill.js.map +1 -0
  34. package/dist/src/cli/commands/browser/forward.d.ts +6 -0
  35. package/dist/src/cli/commands/browser/forward.d.ts.map +1 -0
  36. package/dist/src/cli/commands/browser/forward.js +42 -0
  37. package/dist/src/cli/commands/browser/forward.js.map +1 -0
  38. package/dist/src/cli/commands/browser/get-blocks.d.ts +6 -0
  39. package/dist/src/cli/commands/browser/get-blocks.d.ts.map +1 -0
  40. package/dist/src/cli/commands/browser/get-blocks.js +35 -0
  41. package/dist/src/cli/commands/browser/get-blocks.js.map +1 -0
  42. package/dist/src/cli/commands/browser/goto.d.ts +6 -0
  43. package/dist/src/cli/commands/browser/goto.d.ts.map +1 -0
  44. package/dist/src/cli/commands/browser/goto.js +53 -0
  45. package/dist/src/cli/commands/browser/goto.js.map +1 -0
  46. package/dist/src/cli/commands/browser/hover.d.ts +6 -0
  47. package/dist/src/cli/commands/browser/hover.d.ts.map +1 -0
  48. package/dist/src/cli/commands/browser/hover.js +63 -0
  49. package/dist/src/cli/commands/browser/hover.js.map +1 -0
  50. package/dist/src/cli/commands/browser/index.d.ts +9 -0
  51. package/dist/src/cli/commands/browser/index.d.ts.map +1 -0
  52. package/dist/src/cli/commands/browser/index.js +71 -0
  53. package/dist/src/cli/commands/browser/index.js.map +1 -0
  54. package/dist/src/cli/commands/browser/list.d.ts +6 -0
  55. package/dist/src/cli/commands/browser/list.d.ts.map +1 -0
  56. package/dist/src/cli/commands/browser/list.js +85 -0
  57. package/dist/src/cli/commands/browser/list.js.map +1 -0
  58. package/dist/src/cli/commands/browser/press.d.ts +6 -0
  59. package/dist/src/cli/commands/browser/press.d.ts.map +1 -0
  60. package/dist/src/cli/commands/browser/press.js +67 -0
  61. package/dist/src/cli/commands/browser/press.js.map +1 -0
  62. package/dist/src/cli/commands/browser/reload.d.ts +6 -0
  63. package/dist/src/cli/commands/browser/reload.d.ts.map +1 -0
  64. package/dist/src/cli/commands/browser/reload.js +42 -0
  65. package/dist/src/cli/commands/browser/reload.js.map +1 -0
  66. package/dist/src/cli/commands/browser/run.d.ts +6 -0
  67. package/dist/src/cli/commands/browser/run.d.ts.map +1 -0
  68. package/dist/src/cli/commands/browser/run.js +618 -0
  69. package/dist/src/cli/commands/browser/run.js.map +1 -0
  70. package/dist/src/cli/commands/browser/screenshot.d.ts +6 -0
  71. package/dist/src/cli/commands/browser/screenshot.d.ts.map +1 -0
  72. package/dist/src/cli/commands/browser/screenshot.js +72 -0
  73. package/dist/src/cli/commands/browser/screenshot.js.map +1 -0
  74. package/dist/src/cli/commands/browser/scroll-into-view.d.ts +6 -0
  75. package/dist/src/cli/commands/browser/scroll-into-view.d.ts.map +1 -0
  76. package/dist/src/cli/commands/browser/scroll-into-view.js +64 -0
  77. package/dist/src/cli/commands/browser/scroll-into-view.js.map +1 -0
  78. package/dist/src/cli/commands/browser/scroll.d.ts +6 -0
  79. package/dist/src/cli/commands/browser/scroll.d.ts.map +1 -0
  80. package/dist/src/cli/commands/browser/scroll.js +63 -0
  81. package/dist/src/cli/commands/browser/scroll.js.map +1 -0
  82. package/dist/src/cli/commands/browser/select.d.ts +6 -0
  83. package/dist/src/cli/commands/browser/select.d.ts.map +1 -0
  84. package/dist/src/cli/commands/browser/select.js +83 -0
  85. package/dist/src/cli/commands/browser/select.js.map +1 -0
  86. package/dist/src/cli/commands/browser/snapshot.d.ts +6 -0
  87. package/dist/src/cli/commands/browser/snapshot.d.ts.map +1 -0
  88. package/dist/src/cli/commands/browser/snapshot.js +72 -0
  89. package/dist/src/cli/commands/browser/snapshot.js.map +1 -0
  90. package/dist/src/cli/commands/browser/status.d.ts +6 -0
  91. package/dist/src/cli/commands/browser/status.d.ts.map +1 -0
  92. package/dist/src/cli/commands/browser/status.js +91 -0
  93. package/dist/src/cli/commands/browser/status.js.map +1 -0
  94. package/dist/src/cli/commands/browser/stream.d.ts +6 -0
  95. package/dist/src/cli/commands/browser/stream.d.ts.map +1 -0
  96. package/dist/src/cli/commands/browser/stream.js +135 -0
  97. package/dist/src/cli/commands/browser/stream.js.map +1 -0
  98. package/dist/src/cli/commands/browser/tunnel.d.ts +13 -0
  99. package/dist/src/cli/commands/browser/tunnel.d.ts.map +1 -0
  100. package/dist/src/cli/commands/browser/tunnel.js +225 -0
  101. package/dist/src/cli/commands/browser/tunnel.js.map +1 -0
  102. package/dist/src/cli/commands/browser/type.d.ts +6 -0
  103. package/dist/src/cli/commands/browser/type.d.ts.map +1 -0
  104. package/dist/src/cli/commands/browser/type.js +61 -0
  105. package/dist/src/cli/commands/browser/type.js.map +1 -0
  106. package/dist/src/cli/commands/browser/uncheck.d.ts +6 -0
  107. package/dist/src/cli/commands/browser/uncheck.d.ts.map +1 -0
  108. package/dist/src/cli/commands/browser/uncheck.js +62 -0
  109. package/dist/src/cli/commands/browser/uncheck.js.map +1 -0
  110. package/dist/src/cli/commands/browser/url.d.ts +6 -0
  111. package/dist/src/cli/commands/browser/url.d.ts.map +1 -0
  112. package/dist/src/cli/commands/browser/url.js +40 -0
  113. package/dist/src/cli/commands/browser/url.js.map +1 -0
  114. package/dist/src/cli/commands/browser/wait-for-load.d.ts +6 -0
  115. package/dist/src/cli/commands/browser/wait-for-load.d.ts.map +1 -0
  116. package/dist/src/cli/commands/browser/wait-for-load.js +50 -0
  117. package/dist/src/cli/commands/browser/wait-for-load.js.map +1 -0
  118. package/dist/src/cli/commands/browser/wait-for-selector.d.ts +6 -0
  119. package/dist/src/cli/commands/browser/wait-for-selector.d.ts.map +1 -0
  120. package/dist/src/cli/commands/browser/wait-for-selector.js +52 -0
  121. package/dist/src/cli/commands/browser/wait-for-selector.js.map +1 -0
  122. package/dist/src/cli/commands/browser/wait.d.ts +6 -0
  123. package/dist/src/cli/commands/browser/wait.d.ts.map +1 -0
  124. package/dist/src/cli/commands/browser/wait.js +60 -0
  125. package/dist/src/cli/commands/browser/wait.js.map +1 -0
  126. package/dist/src/cli/commands/test/run.d.ts.map +1 -1
  127. package/dist/src/cli/commands/test/run.js +39 -8
  128. package/dist/src/cli/commands/test/run.js.map +1 -1
  129. package/dist/src/cli/index.js +2 -0
  130. package/dist/src/cli/index.js.map +1 -1
  131. package/dist/src/cli/lib/browser-sessions.d.ts +72 -0
  132. package/dist/src/cli/lib/browser-sessions.d.ts.map +1 -0
  133. package/dist/src/cli/lib/browser-sessions.js +184 -0
  134. package/dist/src/cli/lib/browser-sessions.js.map +1 -0
  135. package/dist/src/cli/lib/download.d.ts +2 -2
  136. package/dist/src/cli/lib/download.d.ts.map +1 -1
  137. package/dist/src/cli/lib/download.js +21 -5
  138. package/dist/src/cli/lib/download.js.map +1 -1
  139. package/dist/src/cli/lib/output.d.ts.map +1 -1
  140. package/dist/src/cli/lib/output.js +11 -4
  141. package/dist/src/cli/lib/output.js.map +1 -1
  142. package/lib/api/browser-types.ts +278 -0
  143. package/lib/api/browser.test.ts +378 -0
  144. package/lib/api/browser.ts +279 -0
  145. package/package.json +2 -1
@@ -0,0 +1,50 @@
1
+ /**
2
+ * qa-use browser wait-for-load - Wait for page load state
3
+ */
4
+ import { Command } from 'commander';
5
+ import { BrowserApiClient } from '../../../../lib/api/browser.js';
6
+ import { resolveSessionId, touchSession } from '../../lib/browser-sessions.js';
7
+ import { loadConfig } from '../../lib/config.js';
8
+ import { success, error } from '../../lib/output.js';
9
+ export const waitForLoadCommand = new Command('wait-for-load')
10
+ .description('Wait for page load state')
11
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
12
+ .option('--state <state>', 'Load state to wait for (load|domcontentloaded|networkidle)', 'load')
13
+ .option('--timeout <ms>', 'Timeout in milliseconds', '30000')
14
+ .action(async (options) => {
15
+ try {
16
+ const config = await loadConfig();
17
+ if (!config.api_key) {
18
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
19
+ process.exit(1);
20
+ }
21
+ const client = new BrowserApiClient(config.api_url);
22
+ client.setApiKey(config.api_key);
23
+ const resolved = await resolveSessionId({
24
+ explicitId: options.sessionId,
25
+ client,
26
+ });
27
+ const state = options.state;
28
+ if (!['load', 'domcontentloaded', 'networkidle'].includes(state)) {
29
+ console.log(error('Invalid state. Must be: load, domcontentloaded, or networkidle'));
30
+ process.exit(1);
31
+ }
32
+ const result = await client.executeAction(resolved.id, {
33
+ type: 'wait_for_load',
34
+ state,
35
+ });
36
+ if (result.success) {
37
+ console.log(success(`Page reached ${state} state`));
38
+ await touchSession(resolved.id);
39
+ }
40
+ else {
41
+ console.log(error(result.error || 'Wait for load failed'));
42
+ process.exit(1);
43
+ }
44
+ }
45
+ catch (err) {
46
+ console.log(error(err instanceof Error ? err.message : 'Failed to wait for load'));
47
+ process.exit(1);
48
+ }
49
+ });
50
+ //# sourceMappingURL=wait-for-load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-load.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/wait-for-load.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAQrD,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,OAAO,CAAC,eAAe,CAAC;KAC3D,WAAW,CAAC,0BAA0B,CAAC;KACvC,MAAM,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;KACjF,MAAM,CAAC,iBAAiB,EAAE,4DAA4D,EAAE,MAAM,CAAC;KAC/F,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,EAAE,OAAO,CAAC;KAC5D,MAAM,CAAC,KAAK,EAAE,OAA2B,EAAE,EAAE;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC;YACtC,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,OAAO,CAAC,KAAoD,CAAC;QAC3E,IAAI,CAAC,CAAC,MAAM,EAAE,kBAAkB,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC,CAAC;YACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,EAAE;YACrD,IAAI,EAAE,eAAe;YACrB,KAAK;SACN,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACpD,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,sBAAsB,CAAC,CAAC,CAAC;YAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC;QACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * qa-use browser wait-for-selector - Wait for CSS selector to reach a state
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const waitForSelectorCommand: Command;
6
+ //# sourceMappingURL=wait-for-selector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-selector.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/wait-for-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,eAAO,MAAM,sBAAsB,SA6C/B,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * qa-use browser wait-for-selector - Wait for CSS selector to reach a state
3
+ */
4
+ import { Command } from 'commander';
5
+ import { BrowserApiClient } from '../../../../lib/api/browser.js';
6
+ import { resolveSessionId, touchSession } from '../../lib/browser-sessions.js';
7
+ import { loadConfig } from '../../lib/config.js';
8
+ import { success, error } from '../../lib/output.js';
9
+ export const waitForSelectorCommand = new Command('wait-for-selector')
10
+ .description('Wait for CSS selector to reach a state')
11
+ .argument('<selector>', 'CSS selector to wait for')
12
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
13
+ .option('--state <state>', 'State to wait for (visible|hidden|attached|detached)', 'visible')
14
+ .option('--timeout <ms>', 'Timeout in milliseconds', '30000')
15
+ .action(async (selector, options) => {
16
+ try {
17
+ const config = await loadConfig();
18
+ if (!config.api_key) {
19
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
20
+ process.exit(1);
21
+ }
22
+ const client = new BrowserApiClient(config.api_url);
23
+ client.setApiKey(config.api_key);
24
+ const resolved = await resolveSessionId({
25
+ explicitId: options.sessionId,
26
+ client,
27
+ });
28
+ const state = options.state;
29
+ if (!['visible', 'hidden', 'attached', 'detached'].includes(state)) {
30
+ console.log(error('Invalid state. Must be: visible, hidden, attached, or detached'));
31
+ process.exit(1);
32
+ }
33
+ const result = await client.executeAction(resolved.id, {
34
+ type: 'wait_for_selector',
35
+ selector,
36
+ state,
37
+ });
38
+ if (result.success) {
39
+ console.log(success(`Selector "${selector}" is ${state}`));
40
+ await touchSession(resolved.id);
41
+ }
42
+ else {
43
+ console.log(error(result.error || 'Wait for selector failed'));
44
+ process.exit(1);
45
+ }
46
+ }
47
+ catch (err) {
48
+ console.log(error(err instanceof Error ? err.message : 'Failed to wait for selector'));
49
+ process.exit(1);
50
+ }
51
+ });
52
+ //# sourceMappingURL=wait-for-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-selector.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/wait-for-selector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAQrD,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,OAAO,CAAC,mBAAmB,CAAC;KACnE,WAAW,CAAC,wCAAwC,CAAC;KACrD,QAAQ,CAAC,YAAY,EAAE,0BAA0B,CAAC;KAClD,MAAM,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;KACjF,MAAM,CAAC,iBAAiB,EAAE,sDAAsD,EAAE,SAAS,CAAC;KAC5F,MAAM,CAAC,gBAAgB,EAAE,yBAAyB,EAAE,OAAO,CAAC;KAC5D,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,OAA+B,EAAE,EAAE;IAClE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjC,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC;YACtC,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,MAAM;SACP,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,OAAO,CAAC,KAAuD,CAAC;QAC9E,IAAI,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC,CAAC;YACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,EAAE;YACrD,IAAI,EAAE,mBAAmB;YACzB,QAAQ;YACR,KAAK;SACN,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,QAAQ,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC;YAC3D,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,0BAA0B,CAAC,CAAC,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * qa-use browser wait - Wait for a fixed duration
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const waitCommand: Command;
6
+ //# sourceMappingURL=wait.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/wait.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,WAAW,SAsDpB,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * qa-use browser wait - Wait for a fixed duration
3
+ */
4
+ import { Command } from 'commander';
5
+ import { BrowserApiClient } from '../../../../lib/api/browser.js';
6
+ import { resolveSessionId, touchSession } from '../../lib/browser-sessions.js';
7
+ import { loadConfig } from '../../lib/config.js';
8
+ import { success, error } from '../../lib/output.js';
9
+ export const waitCommand = new Command('wait')
10
+ .description('Wait for a specified duration')
11
+ .argument('<ms>', 'Duration to wait in milliseconds')
12
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
13
+ .action(async (msStr, options) => {
14
+ try {
15
+ // Load configuration
16
+ const config = await loadConfig();
17
+ if (!config.api_key) {
18
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
19
+ process.exit(1);
20
+ }
21
+ // Parse duration
22
+ const durationMs = parseInt(msStr, 10);
23
+ if (isNaN(durationMs) || durationMs <= 0) {
24
+ console.log(error('Duration must be a positive number in milliseconds'));
25
+ process.exit(1);
26
+ }
27
+ if (durationMs > 60000) {
28
+ console.log(error('Maximum wait duration is 60000ms (1 minute)'));
29
+ process.exit(1);
30
+ }
31
+ // Create client and set API key
32
+ const client = new BrowserApiClient(config.api_url);
33
+ client.setApiKey(config.api_key);
34
+ // Resolve session ID
35
+ const resolved = await resolveSessionId({
36
+ explicitId: options.sessionId,
37
+ client,
38
+ });
39
+ // Execute wait action
40
+ const result = await client.executeAction(resolved.id, {
41
+ type: 'wait',
42
+ duration_ms: durationMs,
43
+ });
44
+ if (result.success) {
45
+ // Format duration for display
46
+ const displayDuration = durationMs >= 1000 ? `${durationMs / 1000}s` : `${durationMs}ms`;
47
+ console.log(success(`Waited ${displayDuration}`));
48
+ await touchSession(resolved.id);
49
+ }
50
+ else {
51
+ console.log(error(result.error || 'Wait failed'));
52
+ process.exit(1);
53
+ }
54
+ }
55
+ catch (err) {
56
+ console.log(error(err instanceof Error ? err.message : 'Failed to wait'));
57
+ process.exit(1);
58
+ }
59
+ });
60
+ //# sourceMappingURL=wait.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/wait.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/test/run.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,eAAO,MAAM,UAAU,SA2JnB,CAAC"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/test/run.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCpC,eAAO,MAAM,UAAU,SAiMnB,CAAC"}
@@ -19,7 +19,9 @@ export const runCommand = new Command('run')
19
19
  .option('--id <uuid>', 'Run cloud test by ID instead of local file')
20
20
  .option('--all', 'Run all tests in test directory')
21
21
  .option('--persist', 'Save test to cloud after run')
22
- .option('--headful', 'Show browser window (default: headless)')
22
+ .option('--tunnel', 'Start local browser with tunnel (required for localhost URLs)')
23
+ .option('--headful', 'Show browser window (use with --tunnel)')
24
+ .option('--ws-url <url>', 'Use existing tunneled browser (from `browser create --tunnel`)')
23
25
  .option('--autofix', 'Enable AI self-healing (default: off)')
24
26
  .option('--screenshots', 'Capture screenshots at each step')
25
27
  .option('--download', 'Download all assets (screenshots, recordings, HAR) to /tmp/qa-use/downloads/')
@@ -73,19 +75,48 @@ export const runCommand = new Command('run')
73
75
  applyVariableOverrides(testDefinitions, options.var);
74
76
  console.log(success(`Applied ${Object.keys(options.var).length} variable overrides\n`));
75
77
  }
76
- // If headful, start local browser with tunnel for remote execution
78
+ // Determine ws_url: from --ws-url flag, --tunnel (starts new browser), or none (backend browser)
77
79
  let browserSession = null;
80
+ let wsUrl = options.wsUrl;
78
81
  try {
79
- if (options.headful) {
80
- console.log('Starting local browser with tunnel for headful mode...');
82
+ // Validate flag combinations
83
+ if (options.wsUrl && (options.tunnel || options.headful)) {
84
+ console.log(error('Cannot use --ws-url with --tunnel or --headful'));
85
+ process.exit(1);
86
+ }
87
+ // Check if running in development mode (localhost API)
88
+ const isDevelopment = process.env.NODE_ENV === 'development' ||
89
+ config.api_url?.includes('localhost') ||
90
+ config.api_url?.includes('127.0.0.1');
91
+ // Handle --headful without --tunnel
92
+ if (options.headful && !options.tunnel) {
93
+ if (isDevelopment) {
94
+ // In development, allow --headful alone for backwards compatibility
95
+ console.log('⚠️ Note: --headful without --tunnel is deprecated. Use --tunnel --headful instead.');
96
+ options.tunnel = true; // Implicitly enable tunnel
97
+ }
98
+ else {
99
+ console.log(error('--headful requires --tunnel flag'));
100
+ console.log(' Use: qa-use test run <name> --tunnel --headful');
101
+ console.log(' Or for headless local browser: qa-use test run <name> --tunnel');
102
+ process.exit(1);
103
+ }
104
+ }
105
+ if (options.tunnel) {
106
+ const headless = !options.headful;
107
+ console.log(`Starting local browser with tunnel (${headless ? 'headless' : 'visible'})...`);
81
108
  console.log('⏳ First run may take a moment while the tunnel establishes connection');
82
109
  browserSession = await startBrowserWithTunnel(undefined, {
83
- headless: false,
110
+ headless,
84
111
  apiKey: config.api_key,
85
112
  sessionIndex: 0,
86
113
  });
114
+ wsUrl = getEffectiveWsUrl(browserSession);
87
115
  console.log(success('Browser ready, running test...'));
88
116
  }
117
+ else if (options.wsUrl) {
118
+ console.log(`Using existing tunneled browser: ${options.wsUrl}`);
119
+ }
89
120
  // Clear any previous screenshots and downloads
90
121
  clearStepScreenshots();
91
122
  clearDownloadedFiles();
@@ -95,10 +126,10 @@ export const runCommand = new Command('run')
95
126
  test_id: options.id,
96
127
  persist: options.persist || config.defaults?.persist || false,
97
128
  // When using ws_url, headless flag is irrelevant (backend uses our browser)
98
- headless: browserSession ? true : (config.defaults?.headless ?? true),
129
+ headless: wsUrl ? true : (config.defaults?.headless ?? true),
99
130
  allow_fix: options.autofix || config.defaults?.allow_fix || false,
100
131
  capture_screenshots: options.screenshots || options.download || false,
101
- ws_url: browserSession ? getEffectiveWsUrl(browserSession) : undefined,
132
+ ws_url: wsUrl,
102
133
  }, {
103
134
  verbose: options.verbose || false,
104
135
  updateLocal: options.updateLocal || false,
@@ -109,7 +140,7 @@ export const runCommand = new Command('run')
109
140
  });
110
141
  // Download assets if --download option is enabled
111
142
  if (options.download && result.assets && result.run_id) {
112
- const downloadedAssets = await downloadAssets(result.assets, '/tmp/qa-use/downloads', testDefinitions?.[0]?.id || undefined, result.run_id);
143
+ const downloadedAssets = await downloadAssets(result.assets, '/tmp/qa-use/downloads', testDefinitions?.[0]?.id || undefined, result.run_id, sourceFile);
113
144
  // Add downloaded assets to the tracking list
114
145
  for (const asset of downloadedAssets) {
115
146
  addDownloadedFile(asset.type, asset.path);
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../../src/cli/commands/test/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../../src/cli/commands/test/run.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ import { setupCommand } from './commands/setup.js';
8
8
  import { infoCommand } from './commands/info.js';
9
9
  import { testCommand } from './commands/test/index.js';
10
10
  import { mcpCommand } from './commands/mcp.js';
11
+ import { browserCommand } from './commands/browser/index.js';
11
12
  // Get version from package.json
12
13
  const require = createRequire(import.meta.url);
13
14
  const { version } = require('../../package.json');
@@ -18,6 +19,7 @@ program.addCommand(setupCommand);
18
19
  program.addCommand(infoCommand);
19
20
  program.addCommand(testCommand);
20
21
  program.addCommand(mcpCommand);
22
+ program.addCommand(browserCommand);
21
23
  // Parse command line arguments
22
24
  program.parse();
23
25
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,gCAAgC;AAChC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1F,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAE/B,+BAA+B;AAC/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AAEA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,gCAAgC;AAChC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,oCAAoC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1F,oBAAoB;AACpB,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AAEnC,+BAA+B;AAC/B,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Browser session persistence utilities
3
+ *
4
+ * Stores active browser sessions in ~/.qa-use.json under "browser_sessions" key.
5
+ * Provides session resolution logic for commands that need a session ID.
6
+ */
7
+ import type { BrowserApiClient } from '../../../lib/api/browser.js';
8
+ export interface StoredSession {
9
+ id: string;
10
+ created_at: string;
11
+ last_updated: string;
12
+ }
13
+ /**
14
+ * Load all stored sessions from config file
15
+ */
16
+ export declare function loadStoredSessions(): Promise<StoredSession[]>;
17
+ /**
18
+ * Store a new session or update an existing one
19
+ */
20
+ export declare function storeSession(session: StoredSession): Promise<void>;
21
+ /**
22
+ * Remove a session from storage by ID
23
+ */
24
+ export declare function removeStoredSession(id: string): Promise<void>;
25
+ /**
26
+ * Update the last_updated timestamp for a session
27
+ */
28
+ export declare function touchSession(id: string): Promise<void>;
29
+ /**
30
+ * Check if a session is stale (last_updated > 1 hour ago)
31
+ */
32
+ export declare function isSessionStale(session: StoredSession): boolean;
33
+ /**
34
+ * Clean up stale sessions from storage
35
+ * Note: This only removes from local storage, does not close sessions on API
36
+ */
37
+ export declare function cleanStaleSessions(): Promise<StoredSession[]>;
38
+ /**
39
+ * Get non-stale sessions
40
+ */
41
+ export declare function getActiveSessions(): Promise<StoredSession[]>;
42
+ export interface SessionResolutionOptions {
43
+ /** Explicit session ID from -s/--session-id flag */
44
+ explicitId?: string;
45
+ /** The BrowserApiClient to use for verification */
46
+ client: BrowserApiClient;
47
+ /** Whether to verify the session exists on the API (default: true) */
48
+ verify?: boolean;
49
+ }
50
+ export interface ResolvedSession {
51
+ id: string;
52
+ source: 'explicit' | 'stored';
53
+ }
54
+ /**
55
+ * Resolve which session ID to use based on provided flags and stored sessions.
56
+ *
57
+ * Resolution rules:
58
+ * 1. If explicitId is provided, use that session
59
+ * 2. Otherwise, check stored sessions:
60
+ * - Filter out stale sessions
61
+ * - If exactly one active session, use it
62
+ * - If multiple active sessions, throw error listing them
63
+ * - If no active sessions, throw error with create suggestion
64
+ *
65
+ * @throws Error if no session can be resolved or verification fails
66
+ */
67
+ export declare function resolveSessionId(options: SessionResolutionOptions): Promise<ResolvedSession>;
68
+ /**
69
+ * Create a new stored session entry
70
+ */
71
+ export declare function createStoredSession(id: string): StoredSession;
72
+ //# sourceMappingURL=browser-sessions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-sessions.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/browser-sessions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAMpE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AA6CD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnE;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAI9D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAWnE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAGlE;AAMD,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,MAAM,EAAE,gBAAgB,CAAC;IACzB,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,GAAG,QAAQ,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,eAAe,CAAC,CAsD1B;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAO7D"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Browser session persistence utilities
3
+ *
4
+ * Stores active browser sessions in ~/.qa-use.json under "browser_sessions" key.
5
+ * Provides session resolution logic for commands that need a session ID.
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { homedir } from 'os';
10
+ // ==========================================
11
+ // Configuration
12
+ // ==========================================
13
+ const CONFIG_PATH = join(homedir(), '.qa-use.json');
14
+ const STALE_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour
15
+ // ==========================================
16
+ // Config File Operations
17
+ // ==========================================
18
+ /**
19
+ * Load the config file from ~/.qa-use.json
20
+ */
21
+ function loadConfig() {
22
+ if (!existsSync(CONFIG_PATH)) {
23
+ return {};
24
+ }
25
+ try {
26
+ const content = readFileSync(CONFIG_PATH, 'utf-8');
27
+ return JSON.parse(content);
28
+ }
29
+ catch {
30
+ return {};
31
+ }
32
+ }
33
+ /**
34
+ * Save the config file to ~/.qa-use.json
35
+ */
36
+ function saveConfig(config) {
37
+ writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
38
+ }
39
+ // ==========================================
40
+ // Session Storage Operations
41
+ // ==========================================
42
+ /**
43
+ * Load all stored sessions from config file
44
+ */
45
+ export async function loadStoredSessions() {
46
+ const config = loadConfig();
47
+ return config.browser_sessions || [];
48
+ }
49
+ /**
50
+ * Store a new session or update an existing one
51
+ */
52
+ export async function storeSession(session) {
53
+ const config = loadConfig();
54
+ const sessions = config.browser_sessions || [];
55
+ // Find existing session with same ID
56
+ const existingIndex = sessions.findIndex((s) => s.id === session.id);
57
+ if (existingIndex >= 0) {
58
+ // Update existing session
59
+ sessions[existingIndex] = session;
60
+ }
61
+ else {
62
+ // Add new session
63
+ sessions.push(session);
64
+ }
65
+ config.browser_sessions = sessions;
66
+ saveConfig(config);
67
+ }
68
+ /**
69
+ * Remove a session from storage by ID
70
+ */
71
+ export async function removeStoredSession(id) {
72
+ const config = loadConfig();
73
+ const sessions = config.browser_sessions || [];
74
+ config.browser_sessions = sessions.filter((s) => s.id !== id);
75
+ saveConfig(config);
76
+ }
77
+ /**
78
+ * Update the last_updated timestamp for a session
79
+ */
80
+ export async function touchSession(id) {
81
+ const config = loadConfig();
82
+ const sessions = config.browser_sessions || [];
83
+ const session = sessions.find((s) => s.id === id);
84
+ if (session) {
85
+ session.last_updated = new Date().toISOString();
86
+ saveConfig(config);
87
+ }
88
+ }
89
+ /**
90
+ * Check if a session is stale (last_updated > 1 hour ago)
91
+ */
92
+ export function isSessionStale(session) {
93
+ const lastUpdated = new Date(session.last_updated).getTime();
94
+ const now = Date.now();
95
+ return now - lastUpdated > STALE_THRESHOLD_MS;
96
+ }
97
+ /**
98
+ * Clean up stale sessions from storage
99
+ * Note: This only removes from local storage, does not close sessions on API
100
+ */
101
+ export async function cleanStaleSessions() {
102
+ const config = loadConfig();
103
+ const sessions = config.browser_sessions || [];
104
+ const stale = sessions.filter(isSessionStale);
105
+ const active = sessions.filter((s) => !isSessionStale(s));
106
+ config.browser_sessions = active;
107
+ saveConfig(config);
108
+ return stale;
109
+ }
110
+ /**
111
+ * Get non-stale sessions
112
+ */
113
+ export async function getActiveSessions() {
114
+ const sessions = await loadStoredSessions();
115
+ return sessions.filter((s) => !isSessionStale(s));
116
+ }
117
+ /**
118
+ * Resolve which session ID to use based on provided flags and stored sessions.
119
+ *
120
+ * Resolution rules:
121
+ * 1. If explicitId is provided, use that session
122
+ * 2. Otherwise, check stored sessions:
123
+ * - Filter out stale sessions
124
+ * - If exactly one active session, use it
125
+ * - If multiple active sessions, throw error listing them
126
+ * - If no active sessions, throw error with create suggestion
127
+ *
128
+ * @throws Error if no session can be resolved or verification fails
129
+ */
130
+ export async function resolveSessionId(options) {
131
+ const { explicitId, client, verify = true } = options;
132
+ let sessionId;
133
+ let source;
134
+ if (explicitId) {
135
+ // Use explicit session ID
136
+ sessionId = explicitId;
137
+ source = 'explicit';
138
+ }
139
+ else {
140
+ // Get non-stale stored sessions
141
+ const activeSessions = await getActiveSessions();
142
+ if (activeSessions.length === 0) {
143
+ throw new Error('No active session found. Run `qa-use browser create` to create a new session.');
144
+ }
145
+ if (activeSessions.length > 1) {
146
+ const sessionList = activeSessions.map((s) => ` - ${s.id}`).join('\n');
147
+ throw new Error(`Multiple active sessions found. Please specify one with -s/--session-id:\n${sessionList}`);
148
+ }
149
+ // Exactly one active session
150
+ sessionId = activeSessions[0].id;
151
+ source = 'stored';
152
+ }
153
+ // Verify session exists on API if requested
154
+ if (verify) {
155
+ try {
156
+ await client.getSession(sessionId);
157
+ }
158
+ catch (error) {
159
+ // If session not found on API, remove from local storage
160
+ await removeStoredSession(sessionId);
161
+ if (source === 'stored') {
162
+ throw new Error(`Stored session ${sessionId} is no longer active. Run \`qa-use browser create\` to create a new session.`);
163
+ }
164
+ else {
165
+ throw new Error(`Session ${sessionId} not found.`);
166
+ }
167
+ }
168
+ // Update last_updated timestamp since we just verified it
169
+ await touchSession(sessionId);
170
+ }
171
+ return { id: sessionId, source };
172
+ }
173
+ /**
174
+ * Create a new stored session entry
175
+ */
176
+ export function createStoredSession(id) {
177
+ const now = new Date().toISOString();
178
+ return {
179
+ id,
180
+ created_at: now,
181
+ last_updated: now,
182
+ };
183
+ }
184
+ //# sourceMappingURL=browser-sessions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-sessions.js","sourceRoot":"","sources":["../../../../src/cli/lib/browser-sessions.ts"],"names":[],"mappings":"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"}
@@ -12,14 +12,14 @@ export declare function getExtensionFromUrl(url: string): string;
12
12
  /**
13
13
  * Build download path for a test asset
14
14
  */
15
- export declare function buildDownloadPath(baseDir: string, testId: string | undefined, runId: string, assetType: 'screenshot' | 'recording' | 'har', fileName: string): string;
15
+ export declare function buildDownloadPath(baseDir: string, testId: string | undefined, runId: string, assetType: 'screenshot' | 'recording' | 'har', fileName: string, sourceFile?: string): string;
16
16
  /**
17
17
  * Download assets (recording, HAR) from test result
18
18
  */
19
19
  export declare function downloadAssets(assets: {
20
20
  recording_url?: string;
21
21
  har_url?: string;
22
- }, baseDir: string, testId: string | undefined, runId: string): Promise<Array<{
22
+ }, baseDir: string, testId: string | undefined, runId: string, sourceFile?: string): Promise<Array<{
23
23
  type: string;
24
24
  path: string;
25
25
  }>>;