@desplega.ai/qa-use 2.14.0 → 2.15.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 (127) hide show
  1. package/README.md +23 -0
  2. package/dist/lib/env/index.d.ts +13 -0
  3. package/dist/lib/env/index.d.ts.map +1 -1
  4. package/dist/lib/env/index.js +35 -0
  5. package/dist/lib/env/index.js.map +1 -1
  6. package/dist/lib/env/localhost.d.ts +22 -0
  7. package/dist/lib/env/localhost.d.ts.map +1 -0
  8. package/dist/lib/env/localhost.js +49 -0
  9. package/dist/lib/env/localhost.js.map +1 -0
  10. package/dist/lib/env/paths.d.ts +27 -0
  11. package/dist/lib/env/paths.d.ts.map +1 -0
  12. package/dist/lib/env/paths.js +42 -0
  13. package/dist/lib/env/paths.js.map +1 -0
  14. package/dist/lib/env/sessions.d.ts +55 -0
  15. package/dist/lib/env/sessions.d.ts.map +1 -0
  16. package/dist/lib/env/sessions.js +128 -0
  17. package/dist/lib/env/sessions.js.map +1 -0
  18. package/dist/lib/tunnel/errors.d.ts +61 -0
  19. package/dist/lib/tunnel/errors.d.ts.map +1 -0
  20. package/dist/lib/tunnel/errors.js +152 -0
  21. package/dist/lib/tunnel/errors.js.map +1 -0
  22. package/dist/lib/tunnel/index.d.ts.map +1 -1
  23. package/dist/lib/tunnel/index.js +26 -11
  24. package/dist/lib/tunnel/index.js.map +1 -1
  25. package/dist/lib/tunnel/registry.d.ts +182 -0
  26. package/dist/lib/tunnel/registry.d.ts.map +1 -0
  27. package/dist/lib/tunnel/registry.js +561 -0
  28. package/dist/lib/tunnel/registry.js.map +1 -0
  29. package/dist/package.json +1 -1
  30. package/dist/src/cli/commands/browser/_detached.d.ts +27 -0
  31. package/dist/src/cli/commands/browser/_detached.d.ts.map +1 -0
  32. package/dist/src/cli/commands/browser/_detached.js +422 -0
  33. package/dist/src/cli/commands/browser/_detached.js.map +1 -0
  34. package/dist/src/cli/commands/browser/close.d.ts +7 -0
  35. package/dist/src/cli/commands/browser/close.d.ts.map +1 -1
  36. package/dist/src/cli/commands/browser/close.js +101 -5
  37. package/dist/src/cli/commands/browser/close.js.map +1 -1
  38. package/dist/src/cli/commands/browser/create.d.ts +7 -0
  39. package/dist/src/cli/commands/browser/create.d.ts.map +1 -1
  40. package/dist/src/cli/commands/browser/create.js +233 -25
  41. package/dist/src/cli/commands/browser/create.js.map +1 -1
  42. package/dist/src/cli/commands/browser/index.d.ts.map +1 -1
  43. package/dist/src/cli/commands/browser/index.js +3 -0
  44. package/dist/src/cli/commands/browser/index.js.map +1 -1
  45. package/dist/src/cli/commands/browser/run.d.ts.map +1 -1
  46. package/dist/src/cli/commands/browser/run.js +13 -6
  47. package/dist/src/cli/commands/browser/run.js.map +1 -1
  48. package/dist/src/cli/commands/browser/status.d.ts +4 -0
  49. package/dist/src/cli/commands/browser/status.d.ts.map +1 -1
  50. package/dist/src/cli/commands/browser/status.js +85 -3
  51. package/dist/src/cli/commands/browser/status.js.map +1 -1
  52. package/dist/src/cli/commands/doctor.d.ts +45 -0
  53. package/dist/src/cli/commands/doctor.d.ts.map +1 -0
  54. package/dist/src/cli/commands/doctor.js +267 -0
  55. package/dist/src/cli/commands/doctor.js.map +1 -0
  56. package/dist/src/cli/commands/test/run.d.ts.map +1 -1
  57. package/dist/src/cli/commands/test/run.js +29 -18
  58. package/dist/src/cli/commands/test/run.js.map +1 -1
  59. package/dist/src/cli/commands/tunnel/close.d.ts +18 -0
  60. package/dist/src/cli/commands/tunnel/close.d.ts.map +1 -0
  61. package/dist/src/cli/commands/tunnel/close.js +154 -0
  62. package/dist/src/cli/commands/tunnel/close.js.map +1 -0
  63. package/dist/src/cli/commands/tunnel/index.d.ts +6 -0
  64. package/dist/src/cli/commands/tunnel/index.d.ts.map +1 -0
  65. package/dist/src/cli/commands/tunnel/index.js +17 -0
  66. package/dist/src/cli/commands/tunnel/index.js.map +1 -0
  67. package/dist/src/cli/commands/tunnel/ls.d.ts +10 -0
  68. package/dist/src/cli/commands/tunnel/ls.d.ts.map +1 -0
  69. package/dist/src/cli/commands/tunnel/ls.js +89 -0
  70. package/dist/src/cli/commands/tunnel/ls.js.map +1 -0
  71. package/dist/src/cli/commands/tunnel/start.d.ts +15 -0
  72. package/dist/src/cli/commands/tunnel/start.d.ts.map +1 -0
  73. package/dist/src/cli/commands/tunnel/start.js +65 -0
  74. package/dist/src/cli/commands/tunnel/start.js.map +1 -0
  75. package/dist/src/cli/commands/tunnel/status.d.ts +8 -0
  76. package/dist/src/cli/commands/tunnel/status.d.ts.map +1 -0
  77. package/dist/src/cli/commands/tunnel/status.js +58 -0
  78. package/dist/src/cli/commands/tunnel/status.js.map +1 -0
  79. package/dist/src/cli/generated/docs-content.d.ts +1 -1
  80. package/dist/src/cli/generated/docs-content.d.ts.map +1 -1
  81. package/dist/src/cli/generated/docs-content.js +157 -100
  82. package/dist/src/cli/generated/docs-content.js.map +1 -1
  83. package/dist/src/cli/index.js +8 -0
  84. package/dist/src/cli/index.js.map +1 -1
  85. package/dist/src/cli/lib/browser.d.ts +25 -9
  86. package/dist/src/cli/lib/browser.d.ts.map +1 -1
  87. package/dist/src/cli/lib/browser.js +73 -42
  88. package/dist/src/cli/lib/browser.js.map +1 -1
  89. package/dist/src/cli/lib/cli-entry.d.ts +40 -0
  90. package/dist/src/cli/lib/cli-entry.d.ts.map +1 -0
  91. package/dist/src/cli/lib/cli-entry.js +65 -0
  92. package/dist/src/cli/lib/cli-entry.js.map +1 -0
  93. package/dist/src/cli/lib/config.d.ts.map +1 -1
  94. package/dist/src/cli/lib/config.js +8 -4
  95. package/dist/src/cli/lib/config.js.map +1 -1
  96. package/dist/src/cli/lib/startup-sweep.d.ts +45 -0
  97. package/dist/src/cli/lib/startup-sweep.d.ts.map +1 -0
  98. package/dist/src/cli/lib/startup-sweep.js +246 -0
  99. package/dist/src/cli/lib/startup-sweep.js.map +1 -0
  100. package/dist/src/cli/lib/tunnel-banner.d.ts +33 -0
  101. package/dist/src/cli/lib/tunnel-banner.d.ts.map +1 -0
  102. package/dist/src/cli/lib/tunnel-banner.js +55 -0
  103. package/dist/src/cli/lib/tunnel-banner.js.map +1 -0
  104. package/dist/src/cli/lib/tunnel-error-hint.d.ts +20 -0
  105. package/dist/src/cli/lib/tunnel-error-hint.d.ts.map +1 -0
  106. package/dist/src/cli/lib/tunnel-error-hint.js +48 -0
  107. package/dist/src/cli/lib/tunnel-error-hint.js.map +1 -0
  108. package/dist/src/cli/lib/tunnel-option.d.ts +27 -0
  109. package/dist/src/cli/lib/tunnel-option.d.ts.map +1 -0
  110. package/dist/src/cli/lib/tunnel-option.js +77 -0
  111. package/dist/src/cli/lib/tunnel-option.js.map +1 -0
  112. package/dist/src/cli/lib/tunnel-resolve.d.ts +42 -0
  113. package/dist/src/cli/lib/tunnel-resolve.d.ts.map +1 -0
  114. package/dist/src/cli/lib/tunnel-resolve.js +72 -0
  115. package/dist/src/cli/lib/tunnel-resolve.js.map +1 -0
  116. package/lib/env/index.ts +51 -0
  117. package/lib/env/localhost.test.ts +63 -0
  118. package/lib/env/localhost.ts +51 -0
  119. package/lib/env/paths.ts +46 -0
  120. package/lib/env/sessions.test.ts +109 -0
  121. package/lib/env/sessions.ts +155 -0
  122. package/lib/tunnel/errors.test.ts +105 -0
  123. package/lib/tunnel/errors.ts +169 -0
  124. package/lib/tunnel/index.ts +26 -11
  125. package/lib/tunnel/registry.test.ts +420 -0
  126. package/lib/tunnel/registry.ts +646 -0
  127. package/package.json +1 -1
@@ -56,11 +56,18 @@ qa-use info
56
56
 
57
57
  **CLI Workflow:**
58
58
  \`\`\`bash
59
- # Create browser session
59
+ # Create browser session (returns immediately — runs detached in the background)
60
60
  qa-use browser create --viewport desktop
61
61
 
62
- # For localhost testing
63
- qa-use browser create --tunnel --no-headless
62
+ # For localhost testing — auto-tunnels when base URL is localhost and API is remote.
63
+ # No flag needed for the common case:
64
+ qa-use browser create --no-headless http://localhost:3000
65
+
66
+ # Force a tunnel even in dev mode:
67
+ qa-use browser create --tunnel on --no-headless
68
+
69
+ # Opt out of auto-tunnel (e.g. backend is also local):
70
+ qa-use browser create --no-tunnel
64
71
 
65
72
  # Navigate
66
73
  qa-use browser goto https://example.com
@@ -76,6 +83,30 @@ qa-use browser fill e5 "text"
76
83
  qa-use browser close
77
84
  \`\`\`
78
85
 
86
+ **Background session management:**
87
+
88
+ \`qa-use browser create\` returns immediately — the actual browser + tunnel run in a detached child process so your terminal stays free. Manage sessions with:
89
+
90
+ \`\`\`bash
91
+ qa-use browser status --list # Show all active sessions across processes
92
+ qa-use browser status # Details for the auto-resolved session
93
+ qa-use browser close <id> # Close a specific session
94
+ qa-use doctor # Reap stale sessions/tunnels (dead PIDs)
95
+ qa-use doctor --dry-run # Preview what would be cleaned
96
+ \`\`\`
97
+
98
+ **Tunnel commands:**
99
+
100
+ Cross-process tunnel registry — multiple commands share a single tunnel per target:
101
+
102
+ \`\`\`bash
103
+ qa-use tunnel start <url> # Acquire a tunnel (released immediately unless --hold)
104
+ qa-use tunnel start <url> --hold # Keep the tunnel up until Ctrl+C
105
+ qa-use tunnel ls # List active tunnels (target, public URL, refcount)
106
+ qa-use tunnel status <target> # Detail for a single tunnel
107
+ qa-use tunnel close <target> # Force-release a tunnel (kills detached holders)
108
+ \`\`\`
109
+
79
110
  **Plugin Shortcut:**
80
111
  \`\`\`
81
112
  /qa-use:explore https://example.com
@@ -114,8 +145,8 @@ Blocks are atomic recorded interactions from a browser session. They are:
114
145
  **How blocks work:**
115
146
 
116
147
  \`\`\`bash
117
- # 1. Create session and interact
118
- qa-use browser create --tunnel --no-headless
148
+ # 1. Create session and interact (auto-tunnels localhost)
149
+ qa-use browser create --no-headless
119
150
  qa-use browser goto https://example.com
120
151
  qa-use browser snapshot # Returns: [ref=e1] button
121
152
  qa-use browser click e1 # Records as block
@@ -218,17 +249,22 @@ local tests.
218
249
  |---------|-------------|
219
250
  | \`qa-use browser create\` | Create remote browser session |
220
251
  | \`qa-use browser create <url>\` | Create session and navigate to URL |
221
- | \`qa-use browser create --tunnel\` | Create local browser with API tunnel |
222
- | \`qa-use browser create --no-headless\` | Show browser window (tunnel mode only) |
252
+ | \`qa-use browser create --tunnel [auto\\|on\\|off]\` | Tunnel mode default \`auto\` (localhost + remote API). \`--no-tunnel\` is sugar for \`off\`. |
253
+ | \`qa-use browser create --no-headless\` | Show browser window (paired with a local/tunnel browser) |
223
254
  | \`qa-use browser create --viewport <size>\` | Set viewport: \`desktop\`, \`tablet\`, \`mobile\` |
224
255
  | \`qa-use browser create --ws-url <url>\` | Connect to existing WebSocket browser |
225
256
  | \`qa-use browser create --after-test-id <uuid>\` | Run a test first, then become interactive |
226
257
  | \`qa-use browser create --var <key=value>\` | Override app config variables (repeatable) |
227
258
  | \`qa-use browser list\` | List active sessions |
228
259
  | \`qa-use browser status\` | Show current session details (app_url, recording_url, etc.) |
260
+ | \`qa-use browser status --list\` | Show all active sessions across processes |
229
261
  | \`qa-use browser close\` | Close active session |
262
+ | \`qa-use browser close <id>\` | Close a specific session by id |
263
+ | \`qa-use doctor\` | Reap stale sessions/tunnels (dead PIDs) |
264
+ | \`qa-use tunnel ls\` | List active tunnels in the registry |
265
+ | \`qa-use tunnel start <url> --hold\` | Hold a public tunnel for external consumers |
230
266
 
231
- Sessions auto-persist in \`~/.qa-use.json\`. One active session = no \`-s\` flag needed.
267
+ Sessions auto-persist in \`~/.qa-use.json\`. One active session = no \`-s\` flag needed. \`browser create\` returns immediately — the browser + tunnel run in a detached child. Use \`qa-use doctor\` if stale state accumulates.
232
268
 
233
269
  ### Navigation
234
270
 
@@ -284,7 +320,7 @@ Use diff output to interact with newly appeared elements directly, without runni
284
320
  |---------|-------------|
285
321
  | \`qa-use test run <name>\` | Run test by name |
286
322
  | \`qa-use test run --all\` | Run all tests |
287
- | \`qa-use test run <name> --tunnel\` | Run with local browser tunnel |
323
+ | \`qa-use test run <name> --tunnel [mode]\` | Override tunnel mode (\`auto\`, \`on\`, \`off\`). \`--no-tunnel\` is sugar for \`off\`. Bare \`--tunnel\` is sugar for \`on\`. |
288
324
  | \`qa-use test run <name> --download\` | Download assets to \`/tmp/qa-use/downloads/\` |
289
325
  | \`qa-use test run <name> --var key=value\` | Override variable |
290
326
  | \`qa-use test validate <name>\` | Validate test syntax |
@@ -399,8 +435,8 @@ qa-use browser logs console
399
435
 
400
436
  **CLI Workflow:**
401
437
  \`\`\`bash
402
- # 1. Create session
403
- qa-use browser create --tunnel --no-headless
438
+ # 1. Create session (auto-tunnels localhost targets)
439
+ qa-use browser create --no-headless
404
440
 
405
441
  # 2. Navigate and interact
406
442
  qa-use browser goto https://example.com
@@ -466,7 +502,7 @@ qa-use test run login
466
502
  **CLI Workflow:**
467
503
  \`\`\`bash
468
504
  # Create session and navigate
469
- qa-use browser create --tunnel --no-headless
505
+ qa-use browser create --no-headless
470
506
  qa-use browser goto https://evals.desplega.ai/checkboxes
471
507
 
472
508
  # goto shows diff — initial page load shows all elements:
@@ -555,32 +591,28 @@ jobs:
555
591
 
556
592
  ## Advanced Topics
557
593
 
558
- ### Localhost Testing (Tunnel Mode)
594
+ ### Localhost Testing (Auto-Tunnel)
559
595
 
560
- **When to use tunnel mode:**
596
+ **qa-use auto-tunnels localhost targets when the API is remote.** No flag required for the common case:
561
597
 
562
- \`\`\`
563
- Testing localhost (http://localhost:3000)?
564
- ├─ YES Use --tunnel
565
- │ └─ qa-use browser create --tunnel [--no-headless]
566
- │ (Starts local Playwright, creates localtunnel, keeps running)
567
-
568
- └─ NO (Public URL) → Use remote browser (default)
569
- └─ qa-use browser create
570
- (Uses desplega.ai cloud browser via WebSocket)
598
+ \`\`\`bash
599
+ qa-use browser create --no-headless http://localhost:3000
600
+ qa-use test run my_test # auto-tunnels if base_url is localhost
571
601
  \`\`\`
572
602
 
573
- **The \`--tunnel\` flag is a binary choice:**
574
- - **Local tunnel mode**: Playwright on your machine + localtunnel
575
- - **Remote mode**: WebSocket URL to cloud-hosted browser
603
+ **Tri-state \`--tunnel\` flag:**
576
604
 
577
- **For test execution:**
578
- \`\`\`bash
579
- # Local app
580
- qa-use test run my_test --tunnel [--headful]
605
+ | Value | Behavior |
606
+ |-------|----------|
607
+ | \`auto\` (default) | Tunnel iff base URL is localhost AND API URL is remote |
608
+ | \`on\` (or bare \`--tunnel\`) | Force a tunnel even in dev mode |
609
+ | \`off\` (or \`--no-tunnel\`) | Never tunnel |
581
610
 
582
- # Public app
583
- qa-use test run my_test
611
+ \`\`\`
612
+ Testing localhost (http://localhost:3000)?
613
+ ├─ API remote (default) → auto-tunnels. No flag needed.
614
+ ├─ API also local (dev) → no tunnel by default. Use --tunnel on to force.
615
+ └─ Public URL target → no tunnel (remote cloud browser)
584
616
  \`\`\`
585
617
 
586
618
  **Plugin shortcuts handle tunnel detection automatically:**
@@ -615,8 +647,8 @@ Sessions are stored in \`~/.qa-use.json\` and have:
615
647
 
616
648
  **Sharing sessions across processes:**
617
649
  \`\`\`bash
618
- # Process 1: Create session
619
- qa-use browser create --tunnel
650
+ # Process 1: Create session (auto-tunnels if target is localhost + API remote)
651
+ qa-use browser create http://localhost:3000
620
652
  # Output: ws://localhost:12345/browser/abc123
621
653
 
622
654
  # Process 2: Connect to session
@@ -681,7 +713,7 @@ See [references/test-format.md](references/test-format.md) for complete specific
681
713
  | \`browser close <session-id>\` | \`browser close\` |
682
714
  | Guessing element refs | Use refs from diff output or \`snapshot\` |
683
715
  | Running \`snapshot\` after every action | Use diff output; only \`snapshot\` when needed |
684
- | Testing localhost without \`--tunnel\` | Use \`--tunnel\` flag |
716
+ | Forcing \`--tunnel\` in dev (both local) | Rely on auto-mode, or use \`--tunnel on\` explicitly |
685
717
  | \`test sync --pull\` | \`test sync pull\` (subcommand, not flag) |
686
718
  | \`test sync --push\` | \`test sync push\` (subcommand, not flag) |
687
719
 
@@ -745,9 +777,10 @@ qa-use browser create [url] [options]
745
777
  |------|-------------|
746
778
  | \`[url]\` | URL to navigate to after session is ready |
747
779
  | \`--viewport <size>\` | Viewport size: \`desktop\` (1280x720), \`tablet\` (768x1024), \`mobile\` (375x667) |
748
- | \`--tunnel\` | Run local browser with API tunnel (for localhost testing) |
749
- | \`--headless\` | Run in headless mode (default with \`--tunnel\`) |
750
- | \`--no-headless\` | Show browser window (use with \`--tunnel\` for debugging) |
780
+ | \`--tunnel [mode]\` | Tunnel mode: \`auto\` (default tunnel iff localhost base + remote API), \`on\` (force), \`off\` (never). Bare \`--tunnel\` is sugar for \`on\`. |
781
+ | \`--no-tunnel\` | Shortcut for \`--tunnel off\` |
782
+ | \`--headless\` | Run in headless mode (default for tunnel/local browsers) |
783
+ | \`--no-headless\` | Show browser window (debugging) |
751
784
  | \`--ws-url <url>\` | Connect to existing WebSocket browser endpoint |
752
785
  | \`--after-test-id <uuid>\` | Run a test before session becomes interactive (start after login, etc.) |
753
786
 
@@ -756,8 +789,9 @@ qa-use browser create [url] [options]
756
789
  qa-use browser create # Remote browser, default viewport
757
790
  qa-use browser create https://example.com # Remote browser, navigate to URL
758
791
  qa-use browser create --viewport mobile # Remote browser, mobile viewport
759
- qa-use browser create --tunnel # Local headless browser with tunnel
760
- qa-use browser create --tunnel --no-headless # Local visible browser for debugging
792
+ qa-use browser create http://localhost:3000 # Auto-tunnels (localhost + remote API)
793
+ qa-use browser create --tunnel on --no-headless # Force tunnel + visible browser
794
+ qa-use browser create --no-tunnel # Opt out of auto-tunnel
761
795
  qa-use browser create --ws-url wss://... # Connect to existing browser
762
796
  qa-use browser create --after-test-id <uuid> # Start session after running a test
763
797
  qa-use browser create --after-test-id <uuid> https://example.com/dashboard # After login, go to dashboard
@@ -1202,11 +1236,11 @@ Opens interactive REPL for browser commands. Use \`--after-test-id\` to start th
1202
1236
 
1203
1237
  ## Local Browser with Tunnel
1204
1238
 
1205
- The \`--tunnel\` flag starts a real browser on your machine with a tunnel for API control:
1239
+ qa-use auto-tunnels when your target is localhost and the API is remote — no flag required. Use the tri-state \`--tunnel\` flag only to override:
1206
1240
 
1207
1241
  1. **Browser runs locally** - you can see it (with \`--no-headless\`)
1208
1242
  2. **API controls via tunnel** - cloud API sends commands through the tunnel
1209
- 3. **Auto-cleanup** - session closes when you press Ctrl+C or run \`browser close\`
1243
+ 3. **Detached lifecycle** - \`browser create\` returns immediately; the tunnel runs in a background child until \`browser close\` or TTL
1210
1244
 
1211
1245
  **Use cases:**
1212
1246
  - Debugging tests visually
@@ -1214,17 +1248,22 @@ The \`--tunnel\` flag starts a real browser on your machine with a tunnel for AP
1214
1248
  - Developing tests interactively
1215
1249
 
1216
1250
  \`\`\`bash
1217
- # Start visible local browser
1218
- qa-use browser create --tunnel --no-headless
1251
+ # Auto-mode localhost + remote API tunnels automatically
1252
+ qa-use browser create --no-headless http://localhost:3000
1219
1253
 
1220
- # Now interact normally
1221
- qa-use browser goto http://localhost:3000
1254
+ # Force a tunnel in dev mode (both sides local)
1255
+ qa-use browser create --tunnel on --no-headless
1256
+
1257
+ # Opt out of tunnel entirely
1258
+ qa-use browser create --no-tunnel
1259
+
1260
+ # Interact normally
1222
1261
  qa-use browser snapshot
1223
1262
  qa-use browser click e3
1224
-
1225
- # Watch the browser respond in real-time
1226
1263
  \`\`\`
1227
1264
 
1265
+ See [localhost-testing.md](localhost-testing.md) for full tunnel mode documentation, \`qa-use tunnel *\` commands, and \`qa-use doctor\`.
1266
+
1228
1267
  ---
1229
1268
 
1230
1269
  > **Runtime access:** \`qa-use docs browser-commands\` | All topics: \`qa-use docs --list\`
@@ -1800,7 +1839,9 @@ Test Failed
1800
1839
  title: 'Localhost Testing',
1801
1840
  content: `# Localhost Testing
1802
1841
 
1803
- Testing applications running on \`localhost\` requires a tunnel because the cloud-hosted browser cannot access your local machine.
1842
+ **When your base URL is localhost and your API is remote, qa-use auto-tunnels. No flag required.**
1843
+
1844
+ Testing applications running on \`localhost\` usually requires a tunnel because the cloud-hosted browser cannot reach your local machine. qa-use detects this automatically — the tri-state \`--tunnel\` flag only needs to be set for the edge cases.
1804
1845
 
1805
1846
  ## Why Tunnels Are Needed
1806
1847
 
@@ -1832,79 +1873,83 @@ With tunnel: Local browser accesses localhost,
1832
1873
  API controls browser through tunnel
1833
1874
  \`\`\`
1834
1875
 
1835
- ## Using \`--tunnel\` Flag
1876
+ ## Auto-Tunnel (Default)
1836
1877
 
1837
- The simplest approach - add \`--tunnel\` to your test run command:
1878
+ For the common case your app on \`http://localhost:3000\`, your API at \`https://api.desplega.ai\` — you don't need to pass any flag:
1838
1879
 
1839
1880
  \`\`\`bash
1840
- qa-use test run my-test --tunnel
1881
+ # Base URL is localhost, API is remote → qa-use auto-tunnels
1882
+ qa-use browser create --no-headless http://localhost:3000
1883
+ qa-use test run my-test
1841
1884
  \`\`\`
1842
1885
 
1843
1886
  This:
1844
- 1. Starts a local headless browser
1887
+ 1. Starts a local browser (Playwright)
1845
1888
  2. Creates a tunnel for API control
1846
- 3. Runs the test
1847
- 4. Cleans up automatically
1889
+ 3. Runs your commands/tests
1890
+ 4. Cleans up automatically when the session closes
1848
1891
 
1849
- ### With Visible Browser
1892
+ ## Tri-State \`--tunnel\` Flag
1850
1893
 
1851
- For debugging, add \`--headful\`:
1894
+ Use \`--tunnel\` only when you need to override the auto-decision:
1852
1895
 
1853
- \`\`\`bash
1854
- qa-use test run my-test --tunnel --headful
1896
+ | Flag form | Mode | When to use |
1897
+ |-----------|------|-------------|
1898
+ | _(none)_ | \`auto\` | Default. Tunnel iff localhost base + remote API. |
1899
+ | \`--tunnel\` / \`--tunnel on\` | \`on\` | Force a tunnel — e.g. dev mode where both API and app are local. |
1900
+ | \`--no-tunnel\` / \`--tunnel off\` | \`off\` | Never tunnel — e.g. both sides are on your machine and you want the cloud browser to stay out of it. |
1901
+ | \`--tunnel auto\` | \`auto\` | Explicit form (same as omitting). |
1902
+
1903
+ You can also pin a project-wide default in \`~/.qa-use.json\`:
1904
+
1905
+ \`\`\`json
1906
+ {
1907
+ "tunnel": "on"
1908
+ }
1855
1909
  \`\`\`
1856
1910
 
1857
- ## Persistent Tunnel Session
1911
+ CLI flag beats config; config beats the \`auto\` default.
1858
1912
 
1859
- For running multiple tests or interactive development, create a persistent tunnel session:
1913
+ ### With Visible Browser
1860
1914
 
1861
- ### Terminal 1: Start Tunnel
1915
+ For debugging, add \`--no-headless\`:
1862
1916
 
1863
1917
  \`\`\`bash
1864
- qa-use browser create --tunnel --no-headless
1918
+ qa-use browser create --no-headless http://localhost:3000
1919
+ qa-use test run my-test --no-headless
1865
1920
  \`\`\`
1866
1921
 
1867
- Output:
1868
- \`\`\`
1869
- Session created: abc123
1870
- WebSocket URL: wss://tunnel.desplega.ai/abc123
1871
- Tunnel active. Press Ctrl+C to stop.
1872
- \`\`\`
1922
+ ## Holding a Tunnel Outside a Browser Session
1873
1923
 
1874
- ### Terminal 2: Run Tests
1924
+ If you just need a public URL (for webhook testing, sharing a dev build with a remote backend, etc.) without spinning up a browser session, use \`qa-use tunnel\`:
1875
1925
 
1876
1926
  \`\`\`bash
1877
- # Run test against the tunneled browser
1878
- qa-use test run my-test --ws-url wss://tunnel.desplega.ai/abc123
1927
+ # Acquire and hold a public tunnel to localhost:3000 until Ctrl+C
1928
+ qa-use tunnel start http://localhost:3000 --hold
1879
1929
 
1880
- # Or run multiple tests
1881
- qa-use test run login --ws-url wss://tunnel.desplega.ai/abc123
1882
- qa-use test run checkout --ws-url wss://tunnel.desplega.ai/abc123
1930
+ # From another shell, inspect the registry
1931
+ qa-use tunnel ls
1932
+ qa-use tunnel status http://localhost:3000
1883
1933
  \`\`\`
1884
1934
 
1885
- ### Benefits
1886
-
1887
- - **Reuse browser session** - no startup time between tests
1888
- - **Watch execution** - see what's happening in real-time
1889
- - **Debug interactively** - use browser commands between test runs
1890
- - **Inspect state** - check page state after failures
1935
+ The tunnel registry refcounts — if a \`browser create\` session and \`tunnel start --hold\` point at the same target, they share one tunnel and the tunnel stays up as long as either holder exists.
1891
1936
 
1892
- ## Browser Session Commands with Tunnel
1937
+ ## Browser Session Commands with Localhost
1893
1938
 
1894
- You can also use browser commands directly for exploration:
1939
+ Detached \`browser create\` returns immediately — the browser + tunnel run in a background child. Your terminal is free for the next command:
1895
1940
 
1896
1941
  \`\`\`bash
1897
- # Create tunneled session
1898
- qa-use browser create --tunnel --no-headless
1899
-
1900
- # Navigate to your local app
1901
- qa-use browser goto http://localhost:3000
1942
+ # Create session — returns in < 3s, background child holds the browser
1943
+ qa-use browser create --no-headless http://localhost:3000
1902
1944
 
1903
1945
  # Explore
1904
1946
  qa-use browser snapshot
1905
1947
  qa-use browser click e3
1906
1948
  qa-use browser screenshot
1907
1949
 
1950
+ # List all active sessions (across processes)
1951
+ qa-use browser status --list
1952
+
1908
1953
  # Close when done
1909
1954
  qa-use browser close
1910
1955
  \`\`\`
@@ -1927,13 +1972,24 @@ steps:
1927
1972
  Override at runtime:
1928
1973
 
1929
1974
  \`\`\`bash
1930
- # Local development
1931
- qa-use test run my-test --tunnel --var base_url=http://localhost:3000
1975
+ # Local development — auto-tunnels
1976
+ qa-use test run my-test --var base_url=http://localhost:3000
1932
1977
 
1933
- # Staging
1978
+ # Staging — no tunnel
1934
1979
  qa-use test run my-test --var base_url=https://staging.example.com
1935
1980
  \`\`\`
1936
1981
 
1982
+ ## Cleaning Up Stale State
1983
+
1984
+ Detached sessions persist PID + registry files in \`~/.qa-use/\`. If a child crashes or is killed with \`SIGKILL\`, stale entries can linger. Reap them with:
1985
+
1986
+ \`\`\`bash
1987
+ qa-use doctor # Reap stale sessions + tunnels (dead PIDs)
1988
+ qa-use doctor --dry-run # Preview what would be cleaned
1989
+ \`\`\`
1990
+
1991
+ A bounded startup sweep also runs silently on every CLI invocation, so most stale state is cleaned opportunistically — \`doctor\` is the explicit escape hatch when you want to see and audit the reaping.
1992
+
1937
1993
  ## Common Issues
1938
1994
 
1939
1995
  ### "Connection refused" / "Network error"
@@ -1949,10 +2005,7 @@ curl http://localhost:3000
1949
2005
 
1950
2006
  The tunnel process was interrupted.
1951
2007
 
1952
- **Fix:** Restart the tunnel:
1953
- \`\`\`bash
1954
- qa-use browser create --tunnel
1955
- \`\`\`
2008
+ **Fix:** Re-run the command — \`browser create\` will acquire a fresh tunnel. If stale registry entries remain, run \`qa-use doctor\`.
1956
2009
 
1957
2010
  ### "localhost" resolved differently
1958
2011
 
@@ -1975,17 +2028,21 @@ qa-use browser goto http://localhost:3000
1975
2028
  # Test HTTPS only in staging/prod environments
1976
2029
  \`\`\`
1977
2030
 
2031
+ ### Tunnel errors have triage hints
2032
+
2033
+ Structured tunnel errors (\`TunnelNetworkError\`, \`TunnelAuthError\`, \`TunnelQuotaError\`, \`TunnelUnknownError\`) print a \`Next steps:\` block with the \`--no-tunnel\` opt-out and other recovery hints. No silent retries — failures surface immediately.
2034
+
1978
2035
  ## Best Practices
1979
2036
 
1980
- 1. **Use \`--tunnel\` for all localhost tests** - Don't forget, or tests will fail with confusing network errors
2037
+ 1. **Trust auto-mode** Don't pass \`--tunnel\` unless you're overriding the default.
1981
2038
 
1982
- 2. **Keep tunnel running during development** - Create once, run many tests
2039
+ 2. **Use \`--tunnel on\` in pure-local dev** When both your API and app are on localhost, auto-mode skips the tunnel; add \`--tunnel on\` if the cloud still needs to reach you.
1983
2040
 
1984
- 3. **Use \`--no-headless\` for debugging** - Watch what's happening
2041
+ 3. **Use \`--no-headless\` for debugging** Watch what's happening.
1985
2042
 
1986
- 4. **Save WebSocket URL** - Copy it from tunnel output for reuse in \`--ws-url\`
2043
+ 4. **\`qa-use tunnel start --hold\` for shared public URLs** When a tunnel needs to outlive any single command.
1987
2044
 
1988
- 5. **Clean up sessions** - Run \`qa-use browser close\` when done to free resources
2045
+ 5. **\`qa-use doctor\` if state feels stale** Fast, safe, and \`--dry-run\` previews the plan.
1989
2046
 
1990
2047
  ---
1991
2048
 
@@ -1 +1 @@
1
- {"version":3,"file":"docs-content.js","sourceRoot":"","sources":["../../../../src/cli/generated/docs-content.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"docs-content.js","sourceRoot":"","sources":["../../../../src/cli/generated/docs-content.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ import { appContextCommand } from './commands/app-context/index.js';
10
10
  import { browserCommand } from './commands/browser/index.js';
11
11
  import { dataAssetCommand } from './commands/data-asset/index.js';
12
12
  import { docsCommand } from './commands/docs.js';
13
+ import { doctorCommand } from './commands/doctor.js';
13
14
  import { infoCommand } from './commands/info.js';
14
15
  import { installDepsCommand } from './commands/install-deps.js';
15
16
  import { issuesCommand } from './commands/issues/index.js';
@@ -18,8 +19,10 @@ import { personaCommand } from './commands/persona/index.js';
18
19
  import { setupCommand } from './commands/setup.js';
19
20
  import { suiteCommand } from './commands/suite/index.js';
20
21
  import { testCommand } from './commands/test/index.js';
22
+ import { tunnelCommand } from './commands/tunnel/index.js';
21
23
  import { updateCommand } from './commands/update.js';
22
24
  import { usageCommand } from './commands/usage.js';
25
+ import { kickoffStartupSweep } from './lib/startup-sweep.js';
23
26
  import { checkForUpdateAsync, getUpdateHintForHelp, shouldSkipCheck, showUpdateHintIfAvailable, } from './lib/update-check.js';
24
27
  // Get version from package.json
25
28
  const require = createRequire(import.meta.url);
@@ -37,6 +40,7 @@ program.addCommand(testCommand);
37
40
  program.addCommand(suiteCommand);
38
41
  program.addCommand(mcpCommand);
39
42
  program.addCommand(browserCommand);
43
+ program.addCommand(tunnelCommand());
40
44
  program.addCommand(installDepsCommand);
41
45
  program.addCommand(updateCommand);
42
46
  program.addCommand(apiCommand);
@@ -46,6 +50,10 @@ program.addCommand(personaCommand);
46
50
  program.addCommand(dataAssetCommand);
47
51
  program.addCommand(issuesCommand);
48
52
  program.addCommand(usageCommand);
53
+ program.addCommand(doctorCommand);
54
+ // Bounded startup sweep — reaps orphaned PID files silently. Budget-capped
55
+ // at 250 ms, skips itself when `doctor` or `__browser-detach` is running.
56
+ kickoffStartupSweep();
49
57
  // Auto-update hint (reads from cache, fires async fetch — never blocks)
50
58
  if (!shouldSkipCheck(process.argv)) {
51
59
  showUpdateHintIfAvailable(version);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,19 @@
5
5
  * and browser WebSocket connection for remote test execution.
6
6
  */
7
7
  import { BrowserManager } from '../../../lib/browser/index.js';
8
- import { TunnelManager } from '../../../lib/tunnel/index.js';
8
+ import type { TunnelManager } from '../../../lib/tunnel/index.js';
9
+ import { type TunnelHandle } from '../../../lib/tunnel/registry.js';
10
+ import { type TunnelMode } from './tunnel-resolve.js';
9
11
  export interface BrowserTunnelSession {
10
12
  browser: BrowserManager;
13
+ /**
14
+ * Back-compat shim: historical callers check `session.tunnel` for
15
+ * truthiness to decide "is a tunnel active?". Sourced from the
16
+ * registry's in-process cache; callers never construct one directly.
17
+ */
11
18
  tunnel: TunnelManager | null;
19
+ /** Registry handle owning this tunnel (null when no tunnel). */
20
+ tunnelHandle: TunnelHandle | null;
12
21
  wsUrl: string;
13
22
  publicWsUrl: string | null;
14
23
  isLocalhost: boolean;
@@ -17,20 +26,27 @@ export interface BrowserTunnelOptions {
17
26
  headless?: boolean;
18
27
  apiKey?: string;
19
28
  sessionIndex?: number;
29
+ /**
30
+ * Effective tri-state tunnel mode after CLI/config resolution.
31
+ * Defaults to `'auto'` so callers that don't care about the flag
32
+ * still pick up the Phase-2 auto-inference.
33
+ */
34
+ tunnelMode?: TunnelMode;
35
+ /**
36
+ * API URL used to detect dev mode. When the API URL is itself
37
+ * localhost, `'auto'` skips the tunnel.
38
+ */
39
+ apiUrl?: string;
40
+ /**
41
+ * Suppress the stderr auto-tunnel banner (e.g. for `--json` callers).
42
+ */
43
+ quiet?: boolean;
20
44
  }
21
- /**
22
- * Check if a URL points to localhost
23
- */
24
- export declare function isLocalhostUrl(url: string): boolean;
25
45
  /**
26
46
  * Check if Playwright browsers are installed and exit with helpful message if not.
27
47
  * This is a guard function to call before expensive tunnel/browser operations.
28
48
  */
29
49
  export declare function ensureBrowsersInstalled(): void;
30
- /**
31
- * Get the port from a URL
32
- */
33
- export declare function getPortFromUrl(url: string): number;
34
50
  /**
35
51
  * Start browser and tunnel (if needed for localhost testing)
36
52
  *
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/browser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAYnD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAY9C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWlD;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CA2C/B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAKxF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAaxF"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../../src/cli/lib/browser.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,KAAK,YAAY,EAAkB,MAAM,iCAAiC,CAAC;AAIpF,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAiBzE,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,cAAc,CAAC;IACxB;;;;OAIG;IACH,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,gEAAgE;IAChE,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAY9C;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAmF/B;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAOxF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,CAaxF"}