@desplega.ai/qa-use 2.1.7 → 2.2.3

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 (158) 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/lib/browser/index.d.ts +10 -0
  10. package/dist/lib/browser/index.d.ts.map +1 -1
  11. package/dist/lib/browser/index.js +29 -0
  12. package/dist/lib/browser/index.js.map +1 -1
  13. package/dist/package.json +2 -1
  14. package/dist/src/cli/commands/browser/back.d.ts +6 -0
  15. package/dist/src/cli/commands/browser/back.d.ts.map +1 -0
  16. package/dist/src/cli/commands/browser/back.js +42 -0
  17. package/dist/src/cli/commands/browser/back.js.map +1 -0
  18. package/dist/src/cli/commands/browser/check.d.ts +6 -0
  19. package/dist/src/cli/commands/browser/check.d.ts.map +1 -0
  20. package/dist/src/cli/commands/browser/check.js +62 -0
  21. package/dist/src/cli/commands/browser/check.js.map +1 -0
  22. package/dist/src/cli/commands/browser/click.d.ts +6 -0
  23. package/dist/src/cli/commands/browser/click.d.ts.map +1 -0
  24. package/dist/src/cli/commands/browser/click.js +63 -0
  25. package/dist/src/cli/commands/browser/click.js.map +1 -0
  26. package/dist/src/cli/commands/browser/close.d.ts +6 -0
  27. package/dist/src/cli/commands/browser/close.d.ts.map +1 -0
  28. package/dist/src/cli/commands/browser/close.js +44 -0
  29. package/dist/src/cli/commands/browser/close.js.map +1 -0
  30. package/dist/src/cli/commands/browser/create.d.ts +6 -0
  31. package/dist/src/cli/commands/browser/create.d.ts.map +1 -0
  32. package/dist/src/cli/commands/browser/create.js +284 -0
  33. package/dist/src/cli/commands/browser/create.js.map +1 -0
  34. package/dist/src/cli/commands/browser/fill.d.ts +6 -0
  35. package/dist/src/cli/commands/browser/fill.d.ts.map +1 -0
  36. package/dist/src/cli/commands/browser/fill.js +83 -0
  37. package/dist/src/cli/commands/browser/fill.js.map +1 -0
  38. package/dist/src/cli/commands/browser/forward.d.ts +6 -0
  39. package/dist/src/cli/commands/browser/forward.d.ts.map +1 -0
  40. package/dist/src/cli/commands/browser/forward.js +42 -0
  41. package/dist/src/cli/commands/browser/forward.js.map +1 -0
  42. package/dist/src/cli/commands/browser/get-blocks.d.ts +6 -0
  43. package/dist/src/cli/commands/browser/get-blocks.d.ts.map +1 -0
  44. package/dist/src/cli/commands/browser/get-blocks.js +35 -0
  45. package/dist/src/cli/commands/browser/get-blocks.js.map +1 -0
  46. package/dist/src/cli/commands/browser/goto.d.ts +6 -0
  47. package/dist/src/cli/commands/browser/goto.d.ts.map +1 -0
  48. package/dist/src/cli/commands/browser/goto.js +53 -0
  49. package/dist/src/cli/commands/browser/goto.js.map +1 -0
  50. package/dist/src/cli/commands/browser/hover.d.ts +6 -0
  51. package/dist/src/cli/commands/browser/hover.d.ts.map +1 -0
  52. package/dist/src/cli/commands/browser/hover.js +63 -0
  53. package/dist/src/cli/commands/browser/hover.js.map +1 -0
  54. package/dist/src/cli/commands/browser/index.d.ts +9 -0
  55. package/dist/src/cli/commands/browser/index.d.ts.map +1 -0
  56. package/dist/src/cli/commands/browser/index.js +71 -0
  57. package/dist/src/cli/commands/browser/index.js.map +1 -0
  58. package/dist/src/cli/commands/browser/list.d.ts +6 -0
  59. package/dist/src/cli/commands/browser/list.d.ts.map +1 -0
  60. package/dist/src/cli/commands/browser/list.js +85 -0
  61. package/dist/src/cli/commands/browser/list.js.map +1 -0
  62. package/dist/src/cli/commands/browser/press.d.ts +6 -0
  63. package/dist/src/cli/commands/browser/press.d.ts.map +1 -0
  64. package/dist/src/cli/commands/browser/press.js +67 -0
  65. package/dist/src/cli/commands/browser/press.js.map +1 -0
  66. package/dist/src/cli/commands/browser/reload.d.ts +6 -0
  67. package/dist/src/cli/commands/browser/reload.d.ts.map +1 -0
  68. package/dist/src/cli/commands/browser/reload.js +42 -0
  69. package/dist/src/cli/commands/browser/reload.js.map +1 -0
  70. package/dist/src/cli/commands/browser/run.d.ts +6 -0
  71. package/dist/src/cli/commands/browser/run.d.ts.map +1 -0
  72. package/dist/src/cli/commands/browser/run.js +618 -0
  73. package/dist/src/cli/commands/browser/run.js.map +1 -0
  74. package/dist/src/cli/commands/browser/screenshot.d.ts +6 -0
  75. package/dist/src/cli/commands/browser/screenshot.d.ts.map +1 -0
  76. package/dist/src/cli/commands/browser/screenshot.js +72 -0
  77. package/dist/src/cli/commands/browser/screenshot.js.map +1 -0
  78. package/dist/src/cli/commands/browser/scroll-into-view.d.ts +6 -0
  79. package/dist/src/cli/commands/browser/scroll-into-view.d.ts.map +1 -0
  80. package/dist/src/cli/commands/browser/scroll-into-view.js +64 -0
  81. package/dist/src/cli/commands/browser/scroll-into-view.js.map +1 -0
  82. package/dist/src/cli/commands/browser/scroll.d.ts +6 -0
  83. package/dist/src/cli/commands/browser/scroll.d.ts.map +1 -0
  84. package/dist/src/cli/commands/browser/scroll.js +63 -0
  85. package/dist/src/cli/commands/browser/scroll.js.map +1 -0
  86. package/dist/src/cli/commands/browser/select.d.ts +6 -0
  87. package/dist/src/cli/commands/browser/select.d.ts.map +1 -0
  88. package/dist/src/cli/commands/browser/select.js +83 -0
  89. package/dist/src/cli/commands/browser/select.js.map +1 -0
  90. package/dist/src/cli/commands/browser/snapshot.d.ts +6 -0
  91. package/dist/src/cli/commands/browser/snapshot.d.ts.map +1 -0
  92. package/dist/src/cli/commands/browser/snapshot.js +72 -0
  93. package/dist/src/cli/commands/browser/snapshot.js.map +1 -0
  94. package/dist/src/cli/commands/browser/status.d.ts +6 -0
  95. package/dist/src/cli/commands/browser/status.d.ts.map +1 -0
  96. package/dist/src/cli/commands/browser/status.js +91 -0
  97. package/dist/src/cli/commands/browser/status.js.map +1 -0
  98. package/dist/src/cli/commands/browser/stream.d.ts +6 -0
  99. package/dist/src/cli/commands/browser/stream.d.ts.map +1 -0
  100. package/dist/src/cli/commands/browser/stream.js +135 -0
  101. package/dist/src/cli/commands/browser/stream.js.map +1 -0
  102. package/dist/src/cli/commands/browser/tunnel.d.ts +13 -0
  103. package/dist/src/cli/commands/browser/tunnel.d.ts.map +1 -0
  104. package/dist/src/cli/commands/browser/tunnel.js +225 -0
  105. package/dist/src/cli/commands/browser/tunnel.js.map +1 -0
  106. package/dist/src/cli/commands/browser/type.d.ts +6 -0
  107. package/dist/src/cli/commands/browser/type.d.ts.map +1 -0
  108. package/dist/src/cli/commands/browser/type.js +61 -0
  109. package/dist/src/cli/commands/browser/type.js.map +1 -0
  110. package/dist/src/cli/commands/browser/uncheck.d.ts +6 -0
  111. package/dist/src/cli/commands/browser/uncheck.d.ts.map +1 -0
  112. package/dist/src/cli/commands/browser/uncheck.js +62 -0
  113. package/dist/src/cli/commands/browser/uncheck.js.map +1 -0
  114. package/dist/src/cli/commands/browser/url.d.ts +6 -0
  115. package/dist/src/cli/commands/browser/url.d.ts.map +1 -0
  116. package/dist/src/cli/commands/browser/url.js +40 -0
  117. package/dist/src/cli/commands/browser/url.js.map +1 -0
  118. package/dist/src/cli/commands/browser/wait-for-load.d.ts +6 -0
  119. package/dist/src/cli/commands/browser/wait-for-load.d.ts.map +1 -0
  120. package/dist/src/cli/commands/browser/wait-for-load.js +50 -0
  121. package/dist/src/cli/commands/browser/wait-for-load.js.map +1 -0
  122. package/dist/src/cli/commands/browser/wait-for-selector.d.ts +6 -0
  123. package/dist/src/cli/commands/browser/wait-for-selector.d.ts.map +1 -0
  124. package/dist/src/cli/commands/browser/wait-for-selector.js +52 -0
  125. package/dist/src/cli/commands/browser/wait-for-selector.js.map +1 -0
  126. package/dist/src/cli/commands/browser/wait.d.ts +6 -0
  127. package/dist/src/cli/commands/browser/wait.d.ts.map +1 -0
  128. package/dist/src/cli/commands/browser/wait.js +60 -0
  129. package/dist/src/cli/commands/browser/wait.js.map +1 -0
  130. package/dist/src/cli/commands/info.d.ts +1 -1
  131. package/dist/src/cli/commands/info.d.ts.map +1 -1
  132. package/dist/src/cli/commands/info.js +178 -15
  133. package/dist/src/cli/commands/info.js.map +1 -1
  134. package/dist/src/cli/commands/install-deps.d.ts +6 -0
  135. package/dist/src/cli/commands/install-deps.d.ts.map +1 -0
  136. package/dist/src/cli/commands/install-deps.js +52 -0
  137. package/dist/src/cli/commands/install-deps.js.map +1 -0
  138. package/dist/src/cli/commands/test/run.d.ts.map +1 -1
  139. package/dist/src/cli/commands/test/run.js +32 -7
  140. package/dist/src/cli/commands/test/run.js.map +1 -1
  141. package/dist/src/cli/index.js +4 -0
  142. package/dist/src/cli/index.js.map +1 -1
  143. package/dist/src/cli/lib/browser-sessions.d.ts +72 -0
  144. package/dist/src/cli/lib/browser-sessions.d.ts.map +1 -0
  145. package/dist/src/cli/lib/browser-sessions.js +184 -0
  146. package/dist/src/cli/lib/browser-sessions.js.map +1 -0
  147. package/dist/src/cli/lib/browser.d.ts +5 -0
  148. package/dist/src/cli/lib/browser.d.ts.map +1 -1
  149. package/dist/src/cli/lib/browser.js +19 -0
  150. package/dist/src/cli/lib/browser.js.map +1 -1
  151. package/dist/src/cli/lib/config.d.ts.map +1 -1
  152. package/dist/src/cli/lib/config.js +3 -0
  153. package/dist/src/cli/lib/config.js.map +1 -1
  154. package/lib/api/browser-types.ts +278 -0
  155. package/lib/api/browser.test.ts +378 -0
  156. package/lib/api/browser.ts +279 -0
  157. package/lib/browser/index.ts +37 -0
  158. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"back.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/back.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;AAMrD,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;KACjF,MAAM,CAAC,KAAK,EAAE,OAAoB,EAAE,EAAE;IACrC,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,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,EAAE;YACrD,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACvC,MAAM,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,mBAAmB,CAAC,CAAC,CAAC;YACxD,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 check - Check a checkbox by ref or semantic text
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const checkCommand: Command;
6
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/check.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,eAAO,MAAM,YAAY,SAiDrB,CAAC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * qa-use browser check - Check a checkbox by ref or semantic text
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
+ /**
10
+ * Normalize ref by stripping leading @ if present
11
+ */
12
+ function normalizeRef(ref) {
13
+ return ref.startsWith('@') ? ref.slice(1) : ref;
14
+ }
15
+ export const checkCommand = new Command('check')
16
+ .description('Check a checkbox by ref or semantic description')
17
+ .argument('[ref]', 'Element ref from snapshot (e.g., "e3" or "@e3")')
18
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
19
+ .option('-t, --text <description>', 'Semantic element description (AI-based, slower)')
20
+ .action(async (ref, options) => {
21
+ try {
22
+ // Validate that either ref or --text is provided
23
+ if (!ref && !options.text) {
24
+ console.log(error('Either <ref> argument or --text option is required'));
25
+ process.exit(1);
26
+ }
27
+ const config = await loadConfig();
28
+ if (!config.api_key) {
29
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
30
+ process.exit(1);
31
+ }
32
+ const client = new BrowserApiClient(config.api_url);
33
+ client.setApiKey(config.api_key);
34
+ const resolved = await resolveSessionId({
35
+ explicitId: options.sessionId,
36
+ client,
37
+ });
38
+ // Build action with either ref or text
39
+ const action = { type: 'check' };
40
+ if (ref) {
41
+ action.ref = normalizeRef(ref);
42
+ }
43
+ else if (options.text) {
44
+ action.text = options.text;
45
+ }
46
+ const result = await client.executeAction(resolved.id, action);
47
+ if (result.success) {
48
+ const target = ref ? `checkbox ${normalizeRef(ref)}` : `"${options.text}"`;
49
+ console.log(success(`Checked ${target}`));
50
+ await touchSession(resolved.id);
51
+ }
52
+ else {
53
+ console.log(error(result.error || 'Check failed'));
54
+ process.exit(1);
55
+ }
56
+ }
57
+ catch (err) {
58
+ console.log(error(err instanceof Error ? err.message : 'Failed to check checkbox'));
59
+ process.exit(1);
60
+ }
61
+ });
62
+ //# sourceMappingURL=check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/check.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * qa-use browser click - Click element by ref or semantic text
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const clickCommand: Command;
6
+ //# sourceMappingURL=click.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/click.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,eAAO,MAAM,YAAY,SAkDrB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * qa-use browser click - Click element by ref or semantic text
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
+ /**
10
+ * Normalize ref by stripping leading @ if present
11
+ */
12
+ function normalizeRef(ref) {
13
+ return ref.startsWith('@') ? ref.slice(1) : ref;
14
+ }
15
+ export const clickCommand = new Command('click')
16
+ .description('Click an element by ref or semantic description')
17
+ .argument('[ref]', 'Element ref from snapshot (e.g., "e3" or "@e3")')
18
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
19
+ .option('-t, --text <description>', 'Semantic element description (AI-based, slower)')
20
+ .action(async (ref, options) => {
21
+ try {
22
+ // Validate that either ref or --text is provided
23
+ if (!ref && !options.text) {
24
+ console.log(error('Either <ref> argument or --text option is required'));
25
+ process.exit(1);
26
+ }
27
+ const config = await loadConfig();
28
+ if (!config.api_key) {
29
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
30
+ process.exit(1);
31
+ }
32
+ const client = new BrowserApiClient(config.api_url);
33
+ client.setApiKey(config.api_key);
34
+ const resolved = await resolveSessionId({
35
+ explicitId: options.sessionId,
36
+ client,
37
+ });
38
+ // Build action with either ref or text
39
+ const action = { type: 'click' };
40
+ if (ref) {
41
+ action.ref = normalizeRef(ref);
42
+ }
43
+ else if (options.text) {
44
+ action.text = options.text;
45
+ }
46
+ const result = await client.executeAction(resolved.id, action);
47
+ if (result.success) {
48
+ const target = ref ? `element ${normalizeRef(ref)}` : `"${options.text}"`;
49
+ console.log(success(`Clicked ${target}`));
50
+ await touchSession(resolved.id);
51
+ }
52
+ else {
53
+ const hint = result.error || 'Click failed';
54
+ console.log(error(`${hint}. Use 'qa-use browser snapshot' to see available elements.`));
55
+ process.exit(1);
56
+ }
57
+ }
58
+ catch (err) {
59
+ console.log(error(err instanceof Error ? err.message : 'Failed to click element'));
60
+ process.exit(1);
61
+ }
62
+ });
63
+ //# sourceMappingURL=click.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/click.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * qa-use browser close - Close a browser session
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const closeCommand: Command;
6
+ //# sourceMappingURL=close.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/close.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,YAAY,SAwCrB,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * qa-use browser close - Close a browser session
3
+ */
4
+ import { Command } from 'commander';
5
+ import { BrowserApiClient } from '../../../../lib/api/browser.js';
6
+ import { resolveSessionId, removeStoredSession } from '../../lib/browser-sessions.js';
7
+ import { loadConfig } from '../../lib/config.js';
8
+ import { success, error, info } from '../../lib/output.js';
9
+ export const closeCommand = new Command('close')
10
+ .description('Close a browser session')
11
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
12
+ .action(async (options) => {
13
+ try {
14
+ // Load configuration
15
+ const config = await loadConfig();
16
+ if (!config.api_key) {
17
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
18
+ process.exit(1);
19
+ }
20
+ // Create client and set API key
21
+ const client = new BrowserApiClient(config.api_url);
22
+ client.setApiKey(config.api_key);
23
+ // Resolve session ID
24
+ const resolved = await resolveSessionId({
25
+ explicitId: options.sessionId,
26
+ client,
27
+ });
28
+ console.log(info(`Closing session ${resolved.id}...`));
29
+ // Close session on API
30
+ await client.deleteSession(resolved.id);
31
+ // Remove from local storage
32
+ await removeStoredSession(resolved.id);
33
+ console.log(success(`Session ${resolved.id} closed successfully`));
34
+ // Show source if auto-resolved
35
+ if (resolved.source === 'stored') {
36
+ console.log(info('(Session was auto-resolved from local storage)'));
37
+ }
38
+ }
39
+ catch (err) {
40
+ console.log(error(err instanceof Error ? err.message : 'Failed to close session'));
41
+ process.exit(1);
42
+ }
43
+ });
44
+ //# sourceMappingURL=close.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/close.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,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAM3D,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,yBAAyB,CAAC;KACtC,MAAM,CAAC,uBAAuB,EAAE,gDAAgD,CAAC;KACjF,MAAM,CAAC,KAAK,EAAE,OAAqB,EAAE,EAAE;IACtC,IAAI,CAAC;QACH,qBAAqB;QACrB,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,gCAAgC;QAChC,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACpD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjC,qBAAqB;QACrB,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC;YACtC,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,MAAM;SACP,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAEvD,uBAAuB;QACvB,MAAM,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAExC,4BAA4B;QAC5B,MAAM,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEvC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,QAAQ,CAAC,EAAE,sBAAsB,CAAC,CAAC,CAAC;QAEnE,+BAA+B;QAC/B,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC,CAAC;QACtE,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 create - Create a new browser session
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const createCommand: Command;
6
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/create.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,eAAO,MAAM,aAAa,SA4DtB,CAAC"}
@@ -0,0 +1,284 @@
1
+ /**
2
+ * qa-use browser create - Create a new browser session
3
+ */
4
+ import { Command } from 'commander';
5
+ import { BrowserApiClient } from '../../../../lib/api/browser.js';
6
+ import { BrowserManager } from '../../../../lib/browser/index.js';
7
+ import { TunnelManager } from '../../../../lib/tunnel/index.js';
8
+ import { storeSession, createStoredSession, removeStoredSession, } from '../../lib/browser-sessions.js';
9
+ import { loadConfig } from '../../lib/config.js';
10
+ import { success, error, info, warning } from '../../lib/output.js';
11
+ import { ensureBrowsersInstalled } from '../../lib/browser.js';
12
+ export const createCommand = new Command('create')
13
+ .description('Create a new browser session')
14
+ .option('--headless', 'Run browser in headless mode (default: true for remote, false for tunnel)')
15
+ .option('--no-headless', 'Run browser with visible UI')
16
+ .option('--viewport <type>', 'Viewport type: desktop, mobile, or tablet (default: desktop)', 'desktop')
17
+ .option('--timeout <seconds>', 'Session timeout in seconds (default: 300)', '300')
18
+ .option('--ws-url <url>', 'WebSocket URL for remote/tunneled browser')
19
+ .option('--tunnel', 'Start local browser with tunnel (keeps process running)')
20
+ .option('-s, --subdomain <name>', 'Custom tunnel subdomain (only with --tunnel)')
21
+ .action(async (options) => {
22
+ // Validate mutually exclusive options
23
+ if (options.tunnel && options.wsUrl) {
24
+ console.log(error('Cannot use both --tunnel and --ws-url'));
25
+ process.exit(1);
26
+ }
27
+ if (options.subdomain && !options.tunnel) {
28
+ console.log(error('--subdomain can only be used with --tunnel'));
29
+ process.exit(1);
30
+ }
31
+ // Load configuration
32
+ const config = await loadConfig();
33
+ if (!config.api_key) {
34
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
35
+ process.exit(1);
36
+ }
37
+ // Validate viewport type
38
+ const validViewports = ['desktop', 'mobile', 'tablet'];
39
+ const viewport = (options.viewport || 'desktop');
40
+ if (!validViewports.includes(viewport)) {
41
+ console.log(error(`Invalid viewport: ${viewport}. Must be one of: ${validViewports.join(', ')}`));
42
+ process.exit(1);
43
+ }
44
+ // Parse timeout
45
+ const timeout = parseInt(String(options.timeout), 10);
46
+ if (isNaN(timeout) || timeout < 60 || timeout > 3600) {
47
+ console.log(error('Timeout must be between 60 and 3600 seconds'));
48
+ process.exit(1);
49
+ }
50
+ // Create client and set API key
51
+ const client = new BrowserApiClient(config.api_url);
52
+ client.setApiKey(config.api_key);
53
+ if (options.tunnel) {
54
+ // Tunnel mode: start local browser + tunnel, then create session
55
+ await runTunnelMode(client, config.api_key, options, viewport, timeout);
56
+ }
57
+ else {
58
+ // Normal mode: create remote session and exit
59
+ await createRemoteSession(client, options, viewport, timeout);
60
+ }
61
+ });
62
+ /**
63
+ * Create a remote browser session (normal mode)
64
+ */
65
+ async function createRemoteSession(client, options, viewport, timeout) {
66
+ try {
67
+ console.log(info('Creating browser session...'));
68
+ // Create session
69
+ const session = await client.createSession({
70
+ headless: options.headless !== false,
71
+ viewport,
72
+ timeout,
73
+ ws_url: options.wsUrl,
74
+ });
75
+ console.log(info(`Session created: ${session.id}`));
76
+ console.log(info(`Status: ${session.status}`));
77
+ // Wait for session to become active if starting
78
+ if (session.status === 'starting') {
79
+ console.log(info('Waiting for session to become active...'));
80
+ const activeSession = await client.waitForStatus(session.id, 'active', 60000);
81
+ console.log(success(`Session ${activeSession.id} is now active`));
82
+ }
83
+ else if (session.status === 'active') {
84
+ console.log(success(`Session ${session.id} is active`));
85
+ }
86
+ // Store session locally
87
+ const storedSession = createStoredSession(session.id);
88
+ await storeSession(storedSession);
89
+ // Print session info
90
+ console.log('');
91
+ console.log(`Session ID: ${session.id}`);
92
+ console.log(`Viewport: ${viewport}`);
93
+ console.log(`Headless: ${options.headless !== false}`);
94
+ console.log(`Timeout: ${timeout}s`);
95
+ if (options.wsUrl) {
96
+ console.log(`WebSocket URL: ${options.wsUrl}`);
97
+ }
98
+ }
99
+ catch (err) {
100
+ console.log(error(err instanceof Error ? err.message : 'Failed to create session'));
101
+ process.exit(1);
102
+ }
103
+ }
104
+ /**
105
+ * Tunnel mode: start local browser + tunnel + API session, then keep running
106
+ */
107
+ async function runTunnelMode(client, apiKey, options, viewport, timeout) {
108
+ // Check that browsers are installed before expensive operations
109
+ ensureBrowsersInstalled();
110
+ // Track resources for cleanup
111
+ let browser = null;
112
+ let tunnel = null;
113
+ let sessionId = null;
114
+ let heartbeatIntervalId = null;
115
+ // Cleanup function
116
+ const cleanup = async (exitCode = 0) => {
117
+ console.log('');
118
+ console.log(info('Shutting down...'));
119
+ // Stop heartbeat
120
+ if (heartbeatIntervalId) {
121
+ clearInterval(heartbeatIntervalId);
122
+ console.log(success('Heartbeat stopped'));
123
+ }
124
+ // Close API session and remove from local storage
125
+ if (sessionId && client) {
126
+ try {
127
+ await client.deleteSession(sessionId);
128
+ await removeStoredSession(sessionId);
129
+ console.log(success('API session closed'));
130
+ }
131
+ catch (err) {
132
+ console.log(warning(`Session cleanup: ${err instanceof Error ? err.message : 'Unknown error'}`));
133
+ }
134
+ }
135
+ // Stop tunnel
136
+ if (tunnel) {
137
+ try {
138
+ await tunnel.stopTunnel();
139
+ console.log(success('Tunnel closed'));
140
+ }
141
+ catch (err) {
142
+ console.log(warning(`Tunnel cleanup: ${err instanceof Error ? err.message : 'Unknown error'}`));
143
+ }
144
+ }
145
+ // Stop browser
146
+ if (browser) {
147
+ try {
148
+ await browser.stopBrowser();
149
+ console.log(success('Browser closed'));
150
+ }
151
+ catch (err) {
152
+ console.log(warning(`Browser cleanup: ${err instanceof Error ? err.message : 'Unknown error'}`));
153
+ }
154
+ }
155
+ console.log('');
156
+ console.log(info('Tunnel mode stopped'));
157
+ process.exit(exitCode);
158
+ };
159
+ // Handle signals for graceful shutdown
160
+ process.on('SIGINT', () => cleanup(0));
161
+ process.on('SIGTERM', () => cleanup(0));
162
+ try {
163
+ // Default to visible browser for tunnel mode (unless --headless explicitly set)
164
+ const headless = options.headless === true;
165
+ console.log('');
166
+ console.log(info('Starting browser with tunnel...'));
167
+ console.log(`Mode: ${headless ? 'Headless' : 'Visible Browser'}`);
168
+ console.log('');
169
+ // Step 1: Start local browser
170
+ console.log(info('Starting browser...'));
171
+ browser = new BrowserManager();
172
+ const browserResult = await browser.startBrowser({ headless });
173
+ const wsEndpoint = browserResult.wsEndpoint;
174
+ console.log(success('Browser started'));
175
+ // Step 2: Start tunnel with deterministic subdomain
176
+ console.log(info('Creating tunnel...'));
177
+ tunnel = new TunnelManager();
178
+ const wsUrl = new URL(wsEndpoint);
179
+ const browserPort = parseInt(wsUrl.port);
180
+ await tunnel.startTunnel(browserPort, {
181
+ subdomain: options.subdomain,
182
+ apiKey: apiKey,
183
+ sessionIndex: 0,
184
+ });
185
+ console.log(success('Tunnel created'));
186
+ // Step 3: Get tunneled WebSocket URL
187
+ const localWsUrl = browser.getWebSocketEndpoint();
188
+ if (!localWsUrl) {
189
+ console.log(error('Failed to get browser WebSocket endpoint'));
190
+ await cleanup(1);
191
+ return;
192
+ }
193
+ const tunneledWsUrl = tunnel.getWebSocketUrl(localWsUrl);
194
+ if (!tunneledWsUrl) {
195
+ console.log(error('Failed to create tunneled WebSocket URL'));
196
+ await cleanup(1);
197
+ return;
198
+ }
199
+ console.log(info(`Tunneled WebSocket: ${tunneledWsUrl}`));
200
+ console.log('');
201
+ // Step 4: Create API session with tunneled ws_url
202
+ console.log(info('Creating API session...'));
203
+ const session = await client.createSession({
204
+ headless,
205
+ viewport,
206
+ timeout,
207
+ ws_url: tunneledWsUrl,
208
+ });
209
+ sessionId = session.id;
210
+ console.log(info(`Session created: ${session.id}`));
211
+ // Wait for session to become active if starting
212
+ if (session.status === 'starting') {
213
+ console.log(info('Waiting for session to become active...'));
214
+ await client.waitForStatus(session.id, 'active', 60000);
215
+ }
216
+ console.log(success('Session is active'));
217
+ // Store session locally
218
+ const storedSession = createStoredSession(session.id);
219
+ await storeSession(storedSession);
220
+ // Print session info
221
+ console.log('');
222
+ console.log('='.repeat(50));
223
+ console.log(success('Browser tunnel ready!'));
224
+ console.log('='.repeat(50));
225
+ console.log('');
226
+ console.log(`Session ID: ${session.id}`);
227
+ console.log(`Viewport: ${viewport}`);
228
+ console.log(`Headless: ${headless}`);
229
+ console.log(`Timeout: ${timeout}s`);
230
+ console.log(`WebSocket URL: ${tunneledWsUrl}`);
231
+ console.log('');
232
+ console.log(info('Use this session with other browser commands:'));
233
+ console.log(` qa-use browser goto https://example.com`);
234
+ console.log(` qa-use browser screenshot`);
235
+ console.log(` qa-use browser snapshot`);
236
+ console.log('');
237
+ console.log(info('Press Ctrl+C to stop'));
238
+ console.log('');
239
+ // Step 5: Set up heartbeat to check session and tunnel health
240
+ let heartbeatCount = 0;
241
+ const heartbeatInterval = 30000; // 30 seconds
242
+ heartbeatIntervalId = setInterval(async () => {
243
+ heartbeatCount++;
244
+ const timestamp = new Date().toLocaleTimeString();
245
+ try {
246
+ // Check if API session still exists
247
+ const sessionStatus = await client.getSession(sessionId);
248
+ if (sessionStatus.status === 'closed') {
249
+ console.log(`[${timestamp}] Session closed externally, shutting down...`);
250
+ await removeStoredSession(sessionId);
251
+ sessionId = null;
252
+ await cleanup(0);
253
+ return;
254
+ }
255
+ // Check tunnel health
256
+ const tunnelHealthy = await tunnel.checkHealth();
257
+ if (tunnelHealthy) {
258
+ console.log(`[${timestamp}] Heartbeat #${heartbeatCount} - healthy`);
259
+ }
260
+ else {
261
+ console.log(`[${timestamp}] ${warning(`Heartbeat #${heartbeatCount} - tunnel unhealthy`)}`);
262
+ }
263
+ }
264
+ catch (err) {
265
+ const errMessage = err instanceof Error ? err.message : 'Unknown error';
266
+ // If session not found, it was closed externally
267
+ if (errMessage.includes('not found') || errMessage.includes('404')) {
268
+ console.log(`[${timestamp}] Session closed externally, shutting down...`);
269
+ await removeStoredSession(sessionId);
270
+ sessionId = null;
271
+ await cleanup(0);
272
+ return;
273
+ }
274
+ console.log(`[${timestamp}] ${warning(`Heartbeat error: ${errMessage}`)}`);
275
+ }
276
+ }, heartbeatInterval);
277
+ // Keep the process running
278
+ }
279
+ catch (err) {
280
+ console.log(error(err instanceof Error ? err.message : 'Failed to start tunnel'));
281
+ await cleanup(1);
282
+ }
283
+ }
284
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/create.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * qa-use browser fill - Fill input field by ref or semantic text
3
+ */
4
+ import { Command } from 'commander';
5
+ export declare const fillCommand: Command;
6
+ //# sourceMappingURL=fill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fill.d.ts","sourceRoot":"","sources":["../../../../../src/cli/commands/browser/fill.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,eAAO,MAAM,WAAW,SA0ErB,CAAC"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * qa-use browser fill - Fill input field by ref or semantic text
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
+ /**
10
+ * Normalize ref by stripping leading @ if present
11
+ */
12
+ function normalizeRef(ref) {
13
+ return ref.startsWith('@') ? ref.slice(1) : ref;
14
+ }
15
+ export const fillCommand = new Command('fill')
16
+ .description('Fill an input field by ref or semantic description')
17
+ .argument('[ref]', 'Element ref from snapshot (e.g., "e4" or "@e4")')
18
+ .argument('<value>', 'Value to fill into the field')
19
+ .option('-s, --session-id <id>', 'Session ID (auto-resolved if only one session)')
20
+ .option('-t, --text <description>', 'Semantic element description (AI-based, slower)')
21
+ .action(async (refOrValue, valueOrUndefined, options) => {
22
+ try {
23
+ // Handle argument parsing: if --text is used, first arg is value; otherwise first is ref, second is value
24
+ let ref;
25
+ let value;
26
+ if (options.text) {
27
+ // When using --text, the first argument is the value
28
+ value = refOrValue;
29
+ if (!value) {
30
+ console.log(error('Value argument is required'));
31
+ process.exit(1);
32
+ }
33
+ }
34
+ else {
35
+ // Normal mode: first arg is ref, second is value
36
+ ref = refOrValue;
37
+ value = valueOrUndefined;
38
+ if (!ref || !value) {
39
+ console.log(error('Both <ref> and <value> arguments are required (or use --text with <value>)'));
40
+ process.exit(1);
41
+ }
42
+ }
43
+ const config = await loadConfig();
44
+ if (!config.api_key) {
45
+ console.log(error('API key not configured. Run `qa-use setup` first.'));
46
+ process.exit(1);
47
+ }
48
+ const client = new BrowserApiClient(config.api_url);
49
+ client.setApiKey(config.api_key);
50
+ const resolved = await resolveSessionId({
51
+ explicitId: options.sessionId,
52
+ client,
53
+ });
54
+ // Build action with either ref or text
55
+ const action = {
56
+ type: 'fill',
57
+ value,
58
+ };
59
+ if (ref) {
60
+ action.ref = normalizeRef(ref);
61
+ }
62
+ else if (options.text) {
63
+ action.text = options.text;
64
+ }
65
+ const result = await client.executeAction(resolved.id, action);
66
+ if (result.success) {
67
+ const displayValue = value.length > 50 ? value.slice(0, 47) + '...' : value;
68
+ const target = ref ? normalizeRef(ref) : `"${options.text}"`;
69
+ console.log(success(`Filled ${target} with "${displayValue}"`));
70
+ await touchSession(resolved.id);
71
+ }
72
+ else {
73
+ const hint = result.error || 'Fill failed';
74
+ console.log(error(`${hint}. Use 'qa-use browser snapshot' to see available elements.`));
75
+ process.exit(1);
76
+ }
77
+ }
78
+ catch (err) {
79
+ console.log(error(err instanceof Error ? err.message : 'Failed to fill input'));
80
+ process.exit(1);
81
+ }
82
+ });
83
+ //# sourceMappingURL=fill.js.map