browser4-cli 0.1.26 → 0.1.27
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.
- package/README.md +610 -621
- package/bin/browser4-cli-darwin-arm64 +0 -0
- package/bin/browser4-cli-darwin-x64 +0 -0
- package/bin/browser4-cli-linux-arm64 +0 -0
- package/bin/browser4-cli-linux-musl-arm64 +0 -0
- package/bin/browser4-cli-linux-musl-x64 +0 -0
- package/bin/browser4-cli-linux-x64 +0 -0
- package/bin/browser4-cli-win32-x64.exe +0 -0
- package/package.json +1 -1
- package/scripts/enumerate-help.ps1 +382 -0
- package/scripts/smoke-test-runtime-bundle.sh +257 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#!/usr/bin/env pwsh
|
|
2
|
+
<#
|
|
3
|
+
.SYNOPSIS
|
|
4
|
+
Enumerates every browser4-cli command and subcommand, prints help
|
|
5
|
+
information, and saves output to categorized files.
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
This script discovers all browser4-cli commands (including hidden ones),
|
|
8
|
+
generates detailed help for each, and organizes the output into:
|
|
9
|
+
- A top-level help overview
|
|
10
|
+
- One file per command (with numbered prefixes for ordering)
|
|
11
|
+
- Prefix group overviews (swarm, agent, htmlsnapshot, crawl, snapshot)
|
|
12
|
+
- An INDEX.md for easy navigation
|
|
13
|
+
|
|
14
|
+
Output is saved to: <repo-root>/cli/help-output/
|
|
15
|
+
.PARAMETER Binary
|
|
16
|
+
Path to the browser4-cli binary. Defaults to the release build in the
|
|
17
|
+
workspace: cli/browser4-cli/target/release/browser4-cli.exe
|
|
18
|
+
.PARAMETER OutDir
|
|
19
|
+
Directory for help output. Defaults to cli/help-output/ under the repo root.
|
|
20
|
+
.EXAMPLE
|
|
21
|
+
.\enumerate-help.ps1
|
|
22
|
+
.\enumerate-help.ps1 -Binary "C:\tools\browser4-cli.exe" -OutDir ".\docs\cli-help"
|
|
23
|
+
#>
|
|
24
|
+
|
|
25
|
+
param(
|
|
26
|
+
[string]$Binary,
|
|
27
|
+
[string]$OutDir
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
$ErrorActionPreference = "Stop"
|
|
31
|
+
|
|
32
|
+
# ---- Resolve paths ----------------------------------------------------------
|
|
33
|
+
$RepoRoot = Resolve-Path "$PSScriptRoot\..\.."
|
|
34
|
+
|
|
35
|
+
if (-not $Binary) {
|
|
36
|
+
$Binary = Join-Path $RepoRoot "cli\browser4-cli\target\release\browser4-cli.exe"
|
|
37
|
+
}
|
|
38
|
+
if (-not $OutDir) {
|
|
39
|
+
$OutDir = Join-Path $RepoRoot "cli\help-output"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (-not (Test-Path $Binary)) {
|
|
43
|
+
Write-Error "browser4-cli binary not found at: $Binary"
|
|
44
|
+
Write-Host "Build it first: cd cli/browser4-cli && cargo build --release"
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# Ensure output directory exists
|
|
49
|
+
$null = New-Item -ItemType Directory -Force -Path $OutDir
|
|
50
|
+
|
|
51
|
+
# Normalize binary path for reliable invocation
|
|
52
|
+
$Binary = Resolve-Path $Binary
|
|
53
|
+
|
|
54
|
+
Write-Host "browser4-cli binary : $Binary"
|
|
55
|
+
Write-Host "Output directory : $OutDir"
|
|
56
|
+
Write-Host ""
|
|
57
|
+
|
|
58
|
+
# ---- Helper: invoke the CLI and capture output ------------------------------
|
|
59
|
+
function Invoke-Cli {
|
|
60
|
+
param([string[]]$Arguments)
|
|
61
|
+
$psi = [System.Diagnostics.ProcessStartInfo]::new()
|
|
62
|
+
$psi.FileName = $Binary
|
|
63
|
+
$psi.Arguments = $Arguments -join ' '
|
|
64
|
+
$psi.RedirectStandardOutput = $true
|
|
65
|
+
$psi.RedirectStandardError = $true
|
|
66
|
+
$psi.UseShellExecute = $false
|
|
67
|
+
$psi.CreateNoWindow = $true
|
|
68
|
+
$psi.StandardOutputEncoding = [System.Text.Encoding]::UTF8
|
|
69
|
+
$psi.StandardErrorEncoding = [System.Text.Encoding]::UTF8
|
|
70
|
+
|
|
71
|
+
$proc = [System.Diagnostics.Process]::new()
|
|
72
|
+
$proc.StartInfo = $psi
|
|
73
|
+
$null = $proc.Start()
|
|
74
|
+
$stdout = $proc.StandardOutput.ReadToEnd()
|
|
75
|
+
$stderr = $proc.StandardError.ReadToEnd()
|
|
76
|
+
$proc.WaitForExit(10000) | Out-Null
|
|
77
|
+
|
|
78
|
+
# Combine: stdout first, then stderr (stderr carries errors / tips)
|
|
79
|
+
$result = $stdout
|
|
80
|
+
if ($stderr.Trim().Length -gt 0) {
|
|
81
|
+
if ($result.Length -gt 0) { $result += "`n" }
|
|
82
|
+
$result += $stderr
|
|
83
|
+
}
|
|
84
|
+
return $result.TrimEnd()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# ---- Command definitions ----------------------------------------------------
|
|
88
|
+
|
|
89
|
+
# Each entry: @{ Name = "<internal-name>"; HelpArgs = @("<arg1>", ...) }
|
|
90
|
+
#
|
|
91
|
+
# For simple commands (no spaced public form), use:
|
|
92
|
+
# HelpArgs = @("--help", "<internal-name>")
|
|
93
|
+
#
|
|
94
|
+
# For commands with a spaced public form, use:
|
|
95
|
+
# HelpArgs = @("<prefix>", "<sub>", "--help")
|
|
96
|
+
# Because `browser4-cli --help agent-run` is rejected; must use
|
|
97
|
+
# `browser4-cli agent run --help` instead.
|
|
98
|
+
|
|
99
|
+
$Commands = @(
|
|
100
|
+
# -- Browser sessions --
|
|
101
|
+
@{ Name = "open"; HelpArgs = @("--help", "open") },
|
|
102
|
+
@{ Name = "attach"; HelpArgs = @("--help", "attach") },
|
|
103
|
+
@{ Name = "close"; HelpArgs = @("--help", "close") },
|
|
104
|
+
@{ Name = "list"; HelpArgs = @("--help", "list") },
|
|
105
|
+
@{ Name = "close-all"; HelpArgs = @("--help", "close-all") },
|
|
106
|
+
@{ Name = "kill-all"; HelpArgs = @("--help", "kill-all") },
|
|
107
|
+
@{ Name = "stop"; HelpArgs = @("--help", "stop") },
|
|
108
|
+
@{ Name = "status"; HelpArgs = @("--help", "status") },
|
|
109
|
+
@{ Name = "doctor"; HelpArgs = @("--help", "doctor") },
|
|
110
|
+
|
|
111
|
+
# -- Navigation --
|
|
112
|
+
@{ Name = "goto"; HelpArgs = @("--help", "goto") },
|
|
113
|
+
@{ Name = "go-back"; HelpArgs = @("--help", "go-back") },
|
|
114
|
+
@{ Name = "go-forward"; HelpArgs = @("--help", "go-forward") },
|
|
115
|
+
@{ Name = "reload"; HelpArgs = @("--help", "reload") },
|
|
116
|
+
|
|
117
|
+
# -- Keyboard --
|
|
118
|
+
@{ Name = "press"; HelpArgs = @("--help", "press") },
|
|
119
|
+
@{ Name = "type"; HelpArgs = @("--help", "type") },
|
|
120
|
+
@{ Name = "keydown"; HelpArgs = @("--help", "keydown") },
|
|
121
|
+
@{ Name = "keyup"; HelpArgs = @("--help", "keyup") },
|
|
122
|
+
@{ Name = "fill"; HelpArgs = @("--help", "fill") },
|
|
123
|
+
|
|
124
|
+
# -- Mouse --
|
|
125
|
+
@{ Name = "click"; HelpArgs = @("--help", "click") },
|
|
126
|
+
@{ Name = "dblclick"; HelpArgs = @("--help", "dblclick") },
|
|
127
|
+
@{ Name = "hover"; HelpArgs = @("--help", "hover") },
|
|
128
|
+
@{ Name = "drag"; HelpArgs = @("--help", "drag") },
|
|
129
|
+
@{ Name = "mousemove"; HelpArgs = @("--help", "mousemove") },
|
|
130
|
+
@{ Name = "mousedown"; HelpArgs = @("--help", "mousedown") },
|
|
131
|
+
@{ Name = "mouseup"; HelpArgs = @("--help", "mouseup") },
|
|
132
|
+
@{ Name = "mousewheel"; HelpArgs = @("--help", "mousewheel") },
|
|
133
|
+
@{ Name = "scroll"; HelpArgs = @("--help", "scroll") },
|
|
134
|
+
|
|
135
|
+
# -- Core --
|
|
136
|
+
@{ Name = "snapshot"; HelpArgs = @("--help", "snapshot") },
|
|
137
|
+
@{ Name = "get"; HelpArgs = @("--help", "get") },
|
|
138
|
+
@{ Name = "eval"; HelpArgs = @("--help", "eval") },
|
|
139
|
+
@{ Name = "wait"; HelpArgs = @("--help", "wait") },
|
|
140
|
+
@{ Name = "select"; HelpArgs = @("--help", "select") },
|
|
141
|
+
@{ Name = "check"; HelpArgs = @("--help", "check") },
|
|
142
|
+
@{ Name = "uncheck"; HelpArgs = @("--help", "uncheck") },
|
|
143
|
+
@{ Name = "dialog-accept"; HelpArgs = @("--help", "dialog-accept") },
|
|
144
|
+
@{ Name = "dialog-dismiss"; HelpArgs = @("--help", "dialog-dismiss") },
|
|
145
|
+
@{ Name = "resize"; HelpArgs = @("--help", "resize") },
|
|
146
|
+
@{ Name = "delete-data"; HelpArgs = @("--help", "delete-data") },
|
|
147
|
+
@{ Name = "batch"; HelpArgs = @("--help", "batch") },
|
|
148
|
+
@{ Name = "generate-locator"; HelpArgs = @("--help", "generate-locator") },
|
|
149
|
+
|
|
150
|
+
# -- Export --
|
|
151
|
+
@{ Name = "screenshot"; HelpArgs = @("--help", "screenshot") },
|
|
152
|
+
@{ Name = "pdf"; HelpArgs = @("--help", "pdf") },
|
|
153
|
+
|
|
154
|
+
# -- Tabs --
|
|
155
|
+
@{ Name = "tab-list"; HelpArgs = @("--help", "tab-list") },
|
|
156
|
+
@{ Name = "tab-new"; HelpArgs = @("--help", "tab-new") },
|
|
157
|
+
@{ Name = "tab-close"; HelpArgs = @("--help", "tab-close") },
|
|
158
|
+
@{ Name = "tab-select"; HelpArgs = @("--help", "tab-select") },
|
|
159
|
+
|
|
160
|
+
# -- Storage --
|
|
161
|
+
@{ Name = "state-save"; HelpArgs = @("--help", "state-save") },
|
|
162
|
+
@{ Name = "state-load"; HelpArgs = @("--help", "state-load") },
|
|
163
|
+
@{ Name = "cookie-list"; HelpArgs = @("--help", "cookie-list") },
|
|
164
|
+
@{ Name = "cookie-get"; HelpArgs = @("--help", "cookie-get") },
|
|
165
|
+
@{ Name = "cookie-set"; HelpArgs = @("--help", "cookie-set") },
|
|
166
|
+
@{ Name = "cookie-delete"; HelpArgs = @("--help", "cookie-delete") },
|
|
167
|
+
@{ Name = "cookie-clear"; HelpArgs = @("--help", "cookie-clear") },
|
|
168
|
+
@{ Name = "localstorage-list"; HelpArgs = @("--help", "localstorage-list") },
|
|
169
|
+
@{ Name = "localstorage-get"; HelpArgs = @("--help", "localstorage-get") },
|
|
170
|
+
@{ Name = "localstorage-set"; HelpArgs = @("--help", "localstorage-set") },
|
|
171
|
+
@{ Name = "localstorage-delete"; HelpArgs = @("--help", "localstorage-delete") },
|
|
172
|
+
@{ Name = "localstorage-clear"; HelpArgs = @("--help", "localstorage-clear") },
|
|
173
|
+
@{ Name = "sessionstorage-list"; HelpArgs = @("--help", "sessionstorage-list") },
|
|
174
|
+
@{ Name = "sessionstorage-get"; HelpArgs = @("--help", "sessionstorage-get") },
|
|
175
|
+
@{ Name = "sessionstorage-set"; HelpArgs = @("--help", "sessionstorage-set") },
|
|
176
|
+
@{ Name = "sessionstorage-delete"; HelpArgs = @("--help", "sessionstorage-delete") },
|
|
177
|
+
@{ Name = "sessionstorage-clear"; HelpArgs = @("--help", "sessionstorage-clear") },
|
|
178
|
+
|
|
179
|
+
# -- Agent (hidden: agent-run, agent-status, agent-result) --
|
|
180
|
+
@{ Name = "extract"; HelpArgs = @("--help", "extract") },
|
|
181
|
+
# agent-list is a standalone command, not hidden
|
|
182
|
+
@{ Name = "agent-list"; HelpArgs = @("--help", "agent-list") },
|
|
183
|
+
|
|
184
|
+
# -- Snapshot subcommands (spaced-form: htmlsnapshot *, snapshot grep) --
|
|
185
|
+
@{ Name = "snapshot-grep"; HelpArgs = @("--help", "snapshot-grep") },
|
|
186
|
+
|
|
187
|
+
# -- DOM Snapshot (base command + spaced subcommands) --
|
|
188
|
+
@{ Name = "htmlsnapshot"; HelpArgs = @("--help", "htmlsnapshot") },
|
|
189
|
+
|
|
190
|
+
# -- Crawl --
|
|
191
|
+
@{ Name = "crawl"; HelpArgs = @("--help", "crawl") },
|
|
192
|
+
|
|
193
|
+
# -- Install / Admin --
|
|
194
|
+
@{ Name = "install"; HelpArgs = @("--help", "install") },
|
|
195
|
+
@{ Name = "upgrade"; HelpArgs = @("--help", "upgrade") },
|
|
196
|
+
@{ Name = "uninstall"; HelpArgs = @("--help", "uninstall") },
|
|
197
|
+
@{ Name = "loop"; HelpArgs = @("--help", "loop") }
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Commands with spaced public forms — the CLI rejects `--help <kebab-name>`
|
|
201
|
+
# for these, so we use `<prefix> <sub> --help` instead.
|
|
202
|
+
$SpacedCommands = @(
|
|
203
|
+
# Agent subcommands (hidden)
|
|
204
|
+
@{ Name = "agent-run"; HelpArgs = @("agent", "run", "--help") },
|
|
205
|
+
@{ Name = "agent-status"; HelpArgs = @("agent", "status", "--help") },
|
|
206
|
+
@{ Name = "agent-result"; HelpArgs = @("agent", "result", "--help") },
|
|
207
|
+
|
|
208
|
+
# Swarm subcommands
|
|
209
|
+
@{ Name = "swarm-create"; HelpArgs = @("swarm", "create", "--help") },
|
|
210
|
+
@{ Name = "swarm-submit"; HelpArgs = @("swarm", "submit", "--help") },
|
|
211
|
+
@{ Name = "swarm-query"; HelpArgs = @("swarm", "query", "--help") },
|
|
212
|
+
@{ Name = "swarm-status"; HelpArgs = @("swarm", "status", "--help") },
|
|
213
|
+
@{ Name = "swarm-result"; HelpArgs = @("swarm", "result", "--help") },
|
|
214
|
+
@{ Name = "swarm-list"; HelpArgs = @("swarm", "list", "--help") },
|
|
215
|
+
|
|
216
|
+
# DOM Snapshot subcommands
|
|
217
|
+
@{ Name = "htmlsnapshot-get"; HelpArgs = @("htmlsnapshot", "get", "--help") },
|
|
218
|
+
@{ Name = "htmlsnapshot-get-all"; HelpArgs = @("htmlsnapshot", "get", "all", "--help") },
|
|
219
|
+
@{ Name = "htmlsnapshot-query"; HelpArgs = @("htmlsnapshot", "query", "--help") },
|
|
220
|
+
@{ Name = "htmlsnapshot-export"; HelpArgs = @("htmlsnapshot", "export", "--help") },
|
|
221
|
+
@{ Name = "htmlsnapshot-summary"; HelpArgs = @("htmlsnapshot", "summary", "--help") },
|
|
222
|
+
@{ Name = "htmlsnapshot-grep"; HelpArgs = @("htmlsnapshot", "grep", "--help") },
|
|
223
|
+
@{ Name = "htmlsnapshot-inspect"; HelpArgs = @("htmlsnapshot", "inspect", "--help") },
|
|
224
|
+
|
|
225
|
+
# Crawl subcommand
|
|
226
|
+
@{ Name = "crawl-list"; HelpArgs = @("crawl", "list", "--help") }
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Hidden commands (not shown in top-level help, but included for completeness)
|
|
230
|
+
$HiddenCommands = @(
|
|
231
|
+
@{ Name = "upload"; HelpArgs = @("--help", "upload") },
|
|
232
|
+
@{ Name = "console"; HelpArgs = @("--help", "console") },
|
|
233
|
+
@{ Name = "summarize"; HelpArgs = @("--help", "summarize") }
|
|
234
|
+
)
|
|
235
|
+
# Note: agent-run, agent-status, agent-result are also hidden but already in $SpacedCommands
|
|
236
|
+
|
|
237
|
+
# Prefix groups to generate overview pages for
|
|
238
|
+
$PrefixGroups = @(
|
|
239
|
+
@{ Name = "swarm"; HelpArgs = @("--help", "swarm") },
|
|
240
|
+
@{ Name = "agent"; HelpArgs = @("--help", "agent") },
|
|
241
|
+
@{ Name = "htmlsnapshot"; HelpArgs = @("--help", "htmlsnapshot") },
|
|
242
|
+
@{ Name = "crawl"; HelpArgs = @("--help", "crawl") },
|
|
243
|
+
@{ Name = "snapshot"; HelpArgs = @("--help", "snapshot") }
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# ---- Generate help files ----------------------------------------------------
|
|
247
|
+
|
|
248
|
+
$allFiles = @() # Track generated files for the index
|
|
249
|
+
|
|
250
|
+
# 1. Top-level help
|
|
251
|
+
Write-Host "[1/5] Generating top-level help..."
|
|
252
|
+
$topHelp = Invoke-Cli -Arguments @("--help")
|
|
253
|
+
$topFile = "00-top-level-help.txt"
|
|
254
|
+
$topHelp | Out-File -FilePath (Join-Path $OutDir $topFile) -Encoding utf8
|
|
255
|
+
$allFiles += @{ Path = $topFile; Label = "Top-level help (browser4-cli --help)" }
|
|
256
|
+
Write-Host " -> $topFile"
|
|
257
|
+
|
|
258
|
+
# 2. Per-command help (simple commands)
|
|
259
|
+
Write-Host "[2/5] Generating per-command help ($($Commands.Count) simple commands)..."
|
|
260
|
+
$idx = 0
|
|
261
|
+
foreach ($cmd in $Commands) {
|
|
262
|
+
$idx++
|
|
263
|
+
$padIdx = $idx.ToString("00")
|
|
264
|
+
$safeName = $cmd.Name -replace '[<>:"/\\|?*]', '_'
|
|
265
|
+
$fileName = "$padIdx-$safeName.txt"
|
|
266
|
+
|
|
267
|
+
Write-Host " [$idx/$($Commands.Count)] $($cmd.Name)"
|
|
268
|
+
$help = Invoke-Cli -Arguments $cmd.HelpArgs
|
|
269
|
+
$help | Out-File -FilePath (Join-Path $OutDir $fileName) -Encoding utf8
|
|
270
|
+
$allFiles += @{ Path = $fileName; Label = $cmd.Name }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# 3. Spaced-form command help
|
|
274
|
+
Write-Host "[3/5] Generating spaced-form command help ($($SpacedCommands.Count) commands)..."
|
|
275
|
+
$baseIdx = $idx
|
|
276
|
+
foreach ($cmd in $SpacedCommands) {
|
|
277
|
+
$idx++
|
|
278
|
+
$padIdx = $idx.ToString("00")
|
|
279
|
+
$safeName = $cmd.Name -replace '[<>:"/\\|?*]', '_'
|
|
280
|
+
$fileName = "$padIdx-$safeName.txt"
|
|
281
|
+
|
|
282
|
+
Write-Host " [$($idx - $baseIdx)/$($SpacedCommands.Count)] $($cmd.Name)"
|
|
283
|
+
$help = Invoke-Cli -Arguments $cmd.HelpArgs
|
|
284
|
+
$help | Out-File -FilePath (Join-Path $OutDir $fileName) -Encoding utf8
|
|
285
|
+
$allFiles += @{ Path = $fileName; Label = $cmd.Name }
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
# 4. Hidden commands
|
|
289
|
+
Write-Host "[4/5] Generating hidden-command help ($($HiddenCommands.Count) commands)..."
|
|
290
|
+
$baseIdx = $idx
|
|
291
|
+
foreach ($cmd in $HiddenCommands) {
|
|
292
|
+
$idx++
|
|
293
|
+
$padIdx = $idx.ToString("00")
|
|
294
|
+
$safeName = $cmd.Name -replace '[<>:"/\\|?*]', '_'
|
|
295
|
+
$fileName = "$padIdx-$safeName.txt"
|
|
296
|
+
|
|
297
|
+
Write-Host " [$($idx - $baseIdx)/$($HiddenCommands.Count)] $($cmd.Name) [hidden]"
|
|
298
|
+
$help = Invoke-Cli -Arguments $cmd.HelpArgs
|
|
299
|
+
$help | Out-File -FilePath (Join-Path $OutDir $fileName) -Encoding utf8
|
|
300
|
+
$allFiles += @{ Path = $fileName; Label = "$($cmd.Name) (hidden)" }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
# 5. Prefix group overviews
|
|
304
|
+
Write-Host "[5/5] Generating prefix group overviews..."
|
|
305
|
+
foreach ($group in $PrefixGroups) {
|
|
306
|
+
$safeName = $group.Name
|
|
307
|
+
$fileName = "prefix-$safeName.txt"
|
|
308
|
+
|
|
309
|
+
Write-Host " prefix: $($group.Name)"
|
|
310
|
+
# For prefix groups, `--help <prefix>` prints subcommands
|
|
311
|
+
$help = Invoke-Cli -Arguments $group.HelpArgs
|
|
312
|
+
$help | Out-File -FilePath (Join-Path $OutDir $fileName) -Encoding utf8
|
|
313
|
+
$allFiles += @{ Path = $fileName; Label = "Prefix group: $($group.Name)" }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
# ---- Generate INDEX.md ------------------------------------------------------
|
|
317
|
+
Write-Host ""
|
|
318
|
+
Write-Host "Generating INDEX.md..."
|
|
319
|
+
|
|
320
|
+
$indexLines = @(
|
|
321
|
+
"# browser4-cli Help Reference",
|
|
322
|
+
"",
|
|
323
|
+
"Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')",
|
|
324
|
+
"Binary: $Binary",
|
|
325
|
+
"",
|
|
326
|
+
"## Overview",
|
|
327
|
+
"",
|
|
328
|
+
"This directory contains the complete help output for every browser4-cli",
|
|
329
|
+
"command and subcommand.",
|
|
330
|
+
"",
|
|
331
|
+
"## Files",
|
|
332
|
+
""
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
foreach ($entry in $allFiles) {
|
|
336
|
+
$indexLines += "- [$($entry.Label)]($($entry.Path))"
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
$totalCmdCount = $Commands.Count + $SpacedCommands.Count + $HiddenCommands.Count
|
|
340
|
+
$visibleCount = $totalCmdCount - 5 # 5 hidden: upload, console, summarize, agent-run, agent-result
|
|
341
|
+
|
|
342
|
+
$indexLines += (
|
|
343
|
+
"",
|
|
344
|
+
"## Quick Reference",
|
|
345
|
+
"",
|
|
346
|
+
"### Global help",
|
|
347
|
+
'```',
|
|
348
|
+
"browser4-cli --help",
|
|
349
|
+
'```',
|
|
350
|
+
"",
|
|
351
|
+
"### Per-command help (simple commands)",
|
|
352
|
+
'```',
|
|
353
|
+
"browser4-cli --help <command>",
|
|
354
|
+
'```',
|
|
355
|
+
"",
|
|
356
|
+
"### Per-command help (spaced subcommands)",
|
|
357
|
+
'```',
|
|
358
|
+
"browser4-cli <prefix> <sub> --help # e.g. browser4-cli swarm create --help",
|
|
359
|
+
"browser4-cli help <prefix> <sub> # equivalent",
|
|
360
|
+
'```',
|
|
361
|
+
"",
|
|
362
|
+
"### Prefix group overview",
|
|
363
|
+
'```',
|
|
364
|
+
"browser4-cli --help <prefix> # e.g. browser4-cli --help swarm",
|
|
365
|
+
'```',
|
|
366
|
+
"",
|
|
367
|
+
"## Command Count",
|
|
368
|
+
"",
|
|
369
|
+
"- **Total commands**: $totalCmdCount",
|
|
370
|
+
"- **Visible commands**: $visibleCount (5 hidden)",
|
|
371
|
+
"- **Hidden commands**: upload, console, summarize, agent-run, agent-status, agent-result",
|
|
372
|
+
""
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
$indexContent = $indexLines -join "`n"
|
|
376
|
+
$indexPath = Join-Path $OutDir "INDEX.md"
|
|
377
|
+
$indexContent | Out-File -FilePath $indexPath -Encoding utf8
|
|
378
|
+
|
|
379
|
+
Write-Host "Done! All help files saved to: $OutDir"
|
|
380
|
+
Write-Host " Total files: $($allFiles.Count + 1) (including INDEX.md)"
|
|
381
|
+
Write-Host ""
|
|
382
|
+
Write-Host "Start here: $(Join-Path $OutDir 'INDEX.md')"
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# ---------------------------------------------------------------------------
|
|
3
|
+
# smoke-test-runtime-bundle.sh — Minimal CLI smoke test against a runtime bundle
|
|
4
|
+
# ---------------------------------------------------------------------------
|
|
5
|
+
# Usage:
|
|
6
|
+
# smoke-test-runtime-bundle.sh <cli-binary> <bundle-archive> [test-port] [timeout-secs]
|
|
7
|
+
#
|
|
8
|
+
# This script:
|
|
9
|
+
# 1. Extracts the platform runtime bundle (.tar.gz or .zip)
|
|
10
|
+
# 2. Sets up a local "installed" runtime directory (no network download)
|
|
11
|
+
# 3. Starts a Python HTTP server serving a minimal interactive page
|
|
12
|
+
# 4. Runs CLI commands: open → goto → type → click → close → kill-all
|
|
13
|
+
# 5. Reports pass/fail for each step
|
|
14
|
+
#
|
|
15
|
+
# Designed for CI (GitHub Actions) but also runs on developer machines.
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
CLI_BINARY="${1:?Usage: $0 <cli-binary> <bundle-archive> [test-port] [timeout-secs]}"
|
|
20
|
+
BUNDLE_ARCHIVE="${2:?}"
|
|
21
|
+
TEST_PORT="${3:-0}" # 0 = OS picks a free port
|
|
22
|
+
TIMEOUT_SECS="${4:-300}"
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# helpers
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
RED='\033[0;31m'
|
|
28
|
+
GREEN='\033[0;32m'
|
|
29
|
+
YELLOW='\033[1;33m'
|
|
30
|
+
NC='\033[0m' # No Color
|
|
31
|
+
|
|
32
|
+
pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
|
|
33
|
+
fail() { echo -e "${RED}[FAIL]${NC} $*"; }
|
|
34
|
+
info() { echo -e "${YELLOW}[INFO]${NC} $*"; }
|
|
35
|
+
|
|
36
|
+
cleanup() {
|
|
37
|
+
if [ -n "${HTTP_PID:-}" ] && kill -0 "$HTTP_PID" 2>/dev/null; then
|
|
38
|
+
kill "$HTTP_PID" 2>/dev/null || true
|
|
39
|
+
wait "$HTTP_PID" 2>/dev/null || true
|
|
40
|
+
fi
|
|
41
|
+
if [ -n "${TEMP_DIR:-}" ] && [ -d "$TEMP_DIR" ]; then
|
|
42
|
+
rm -rf "$TEMP_DIR"
|
|
43
|
+
fi
|
|
44
|
+
}
|
|
45
|
+
trap cleanup EXIT
|
|
46
|
+
|
|
47
|
+
# Resolve a free TCP port (port 0 not universally supported by Python http.server)
|
|
48
|
+
find_free_port() {
|
|
49
|
+
python3 -c '
|
|
50
|
+
import socket
|
|
51
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
52
|
+
s.bind(("127.0.0.1", 0))
|
|
53
|
+
print(s.getsockname()[1])
|
|
54
|
+
s.close()
|
|
55
|
+
' 2>/dev/null || python -c '
|
|
56
|
+
import socket
|
|
57
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
58
|
+
s.bind(("127.0.0.1", 0))
|
|
59
|
+
print(s.getsockname()[1])
|
|
60
|
+
s.close()
|
|
61
|
+
'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# ---------------------------------------------------------------------------
|
|
65
|
+
# validate inputs
|
|
66
|
+
# ---------------------------------------------------------------------------
|
|
67
|
+
if [ ! -f "$CLI_BINARY" ]; then
|
|
68
|
+
fail "CLI binary not found: $CLI_BINARY"
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
if [ ! -f "$BUNDLE_ARCHIVE" ]; then
|
|
72
|
+
fail "Bundle archive not found: $BUNDLE_ARCHIVE"
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if [ "$TEST_PORT" -eq 0 ]; then
|
|
77
|
+
TEST_PORT=$(find_free_port)
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# ---------------------------------------------------------------------------
|
|
81
|
+
# step 1: set up installed runtime directory
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
info "Setting up runtime directory..."
|
|
84
|
+
|
|
85
|
+
TEMP_DIR=$(mktemp -d)
|
|
86
|
+
RUNTIME_DIR="$TEMP_DIR/runtime-data"
|
|
87
|
+
VERSIONS_DIR="$RUNTIME_DIR/runtime" # daemon.rs: RUNTIME_VERSIONS_DIR_NAME
|
|
88
|
+
BUNDLE_TAG="v99.99.99-smoke"
|
|
89
|
+
BUNDLE_DIR="$VERSIONS_DIR/$BUNDLE_TAG" # versioned_install_dir(tag)
|
|
90
|
+
STATE_DIR="$TEMP_DIR/state"
|
|
91
|
+
WORKSPACE_DIR="$TEMP_DIR/workspace"
|
|
92
|
+
SERVER_LOG_DIR="$TEMP_DIR/server-logs"
|
|
93
|
+
|
|
94
|
+
mkdir -p "$BUNDLE_DIR" "$STATE_DIR" "$WORKSPACE_DIR" "$SERVER_LOG_DIR"
|
|
95
|
+
EXTRACT_DIR="$TEMP_DIR/extract"
|
|
96
|
+
mkdir -p "$EXTRACT_DIR"
|
|
97
|
+
|
|
98
|
+
# Extract archive (supports both .tar.gz and .zip)
|
|
99
|
+
case "$BUNDLE_ARCHIVE" in
|
|
100
|
+
*.tar.gz)
|
|
101
|
+
tar xzf "$BUNDLE_ARCHIVE" -C "$EXTRACT_DIR"
|
|
102
|
+
;;
|
|
103
|
+
*.zip)
|
|
104
|
+
python3 -c "
|
|
105
|
+
import zipfile, sys
|
|
106
|
+
with zipfile.ZipFile('$BUNDLE_ARCHIVE', 'r') as z:
|
|
107
|
+
z.extractall('$EXTRACT_DIR')
|
|
108
|
+
" 2>/dev/null || unzip -q "$BUNDLE_ARCHIVE" -d "$EXTRACT_DIR"
|
|
109
|
+
;;
|
|
110
|
+
*)
|
|
111
|
+
fail "Unsupported archive format: $BUNDLE_ARCHIVE (expected .tar.gz or .zip)"
|
|
112
|
+
exit 1
|
|
113
|
+
;;
|
|
114
|
+
esac
|
|
115
|
+
|
|
116
|
+
# Find the bundle root (the directory containing runtime-bundle.json)
|
|
117
|
+
BUNDLE_ROOT=$(find "$EXTRACT_DIR" -name 'runtime-bundle.json' -maxdepth 5 | head -1 | xargs dirname 2>/dev/null || true)
|
|
118
|
+
if [ -z "$BUNDLE_ROOT" ] || [ ! -d "$BUNDLE_ROOT" ]; then
|
|
119
|
+
fail "Could not find runtime-bundle.json in extracted archive"
|
|
120
|
+
find "$EXTRACT_DIR" -maxdepth 3 -type d | while read -r d; do info " $d"; done
|
|
121
|
+
exit 1
|
|
122
|
+
fi
|
|
123
|
+
info "Bundle root: $BUNDLE_ROOT"
|
|
124
|
+
|
|
125
|
+
# Copy bundle contents into the versioned install directory
|
|
126
|
+
cp -r "$BUNDLE_ROOT"/* "$BUNDLE_DIR/" 2>/dev/null || cp -r "$BUNDLE_ROOT"/. "$BUNDLE_DIR/"
|
|
127
|
+
|
|
128
|
+
# Write minimal installation metadata (daemon.rs: BROWSER4_INSTALL_METADATA_FILE_NAME)
|
|
129
|
+
cat > "$BUNDLE_DIR/browser4-installation.json" <<META
|
|
130
|
+
{"tag":"$BUNDLE_TAG","asset_name":"smoke-test","download_url":"local","installed_at":"2026-01-01T00:00:00Z"}
|
|
131
|
+
META
|
|
132
|
+
|
|
133
|
+
# Write current.tag marker (daemon.rs: CURRENT_TAG_FILE_NAME)
|
|
134
|
+
echo "$BUNDLE_TAG" > "$VERSIONS_DIR/current.tag"
|
|
135
|
+
|
|
136
|
+
# On Unix, make the bundled java executable
|
|
137
|
+
if [ -f "$BUNDLE_DIR/runtime/bin/java" ]; then
|
|
138
|
+
chmod +x "$BUNDLE_DIR/runtime/bin/java" 2>/dev/null || true
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
info "Runtime directory: $RUNTIME_DIR"
|
|
142
|
+
info "Bundle version dir: $BUNDLE_DIR"
|
|
143
|
+
|
|
144
|
+
# ---------------------------------------------------------------------------
|
|
145
|
+
# step 2: start test page server
|
|
146
|
+
# ---------------------------------------------------------------------------
|
|
147
|
+
info "Starting test HTTP server on port $TEST_PORT..."
|
|
148
|
+
|
|
149
|
+
TEST_PAGE="$TEMP_DIR/test.html"
|
|
150
|
+
cat > "$TEST_PAGE" <<'HTML'
|
|
151
|
+
<!DOCTYPE html>
|
|
152
|
+
<html><head><meta charset="utf-8"><title>Smoke Test</title></head><body>
|
|
153
|
+
<h1>Browser4 Smoke Test</h1>
|
|
154
|
+
<input id="input1" type="text" value="">
|
|
155
|
+
<button id="btn1" onclick="document.getElementById('input1').value='clicked'">Click Me</button>
|
|
156
|
+
</body></html>
|
|
157
|
+
HTML
|
|
158
|
+
|
|
159
|
+
python3 -m http.server "$TEST_PORT" --bind 127.0.0.1 > /dev/null 2>&1 &
|
|
160
|
+
HTTP_PID=$!
|
|
161
|
+
TEST_URL="http://127.0.0.1:$TEST_PORT/test.html"
|
|
162
|
+
|
|
163
|
+
# Wait for HTTP server to be ready
|
|
164
|
+
for i in $(seq 1 10); do
|
|
165
|
+
if curl -s -o /dev/null "$TEST_URL" 2>/dev/null; then
|
|
166
|
+
break
|
|
167
|
+
fi
|
|
168
|
+
sleep 0.5
|
|
169
|
+
done
|
|
170
|
+
|
|
171
|
+
# ---------------------------------------------------------------------------
|
|
172
|
+
# step 3: determine server URL (let CLI auto-start the server)
|
|
173
|
+
# ---------------------------------------------------------------------------
|
|
174
|
+
# The CLI auto-starts the Browser4 server on the first command that needs it.
|
|
175
|
+
# We DON'T pass --server so the CLI manages the server lifecycle itself.
|
|
176
|
+
# This tests the full "CLI starts jlink JRE server" code path.
|
|
177
|
+
|
|
178
|
+
SERVER_PORT=$(find_free_port)
|
|
179
|
+
SERVER_URL="http://127.0.0.1:$SERVER_PORT"
|
|
180
|
+
|
|
181
|
+
run_cli() {
|
|
182
|
+
# Set env vars that the CLI checks:
|
|
183
|
+
# BROWSER4_RUNTIME_DIR → where the installed runtime lives
|
|
184
|
+
# BROWSER4_CLI_STATE_DIR → where CLI session state is persisted
|
|
185
|
+
# BROWSER4_SERVER_LOG_DIR → where server startup logs go
|
|
186
|
+
BROWSER4_CLI_STATE_DIR="$STATE_DIR" \
|
|
187
|
+
BROWSER4_RUNTIME_DIR="$RUNTIME_DIR" \
|
|
188
|
+
BROWSER4_SERVER_LOG_DIR="$SERVER_LOG_DIR" \
|
|
189
|
+
"$CLI_BINARY" --server "$SERVER_URL" "$@"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
FAILED_STEPS=0
|
|
193
|
+
TOTAL_STEPS=0
|
|
194
|
+
|
|
195
|
+
check_step() {
|
|
196
|
+
local label="$1"
|
|
197
|
+
shift
|
|
198
|
+
TOTAL_STEPS=$((TOTAL_STEPS + 1))
|
|
199
|
+
echo ""
|
|
200
|
+
info "--- $label ---"
|
|
201
|
+
if run_cli "$@" 2>&1; then
|
|
202
|
+
pass "$label"
|
|
203
|
+
else
|
|
204
|
+
fail "$label"
|
|
205
|
+
FAILED_STEPS=$((FAILED_STEPS + 1))
|
|
206
|
+
# On first failure, dump the server log if available
|
|
207
|
+
if [ "$FAILED_STEPS" -eq 1 ]; then
|
|
208
|
+
if [ -d "$SERVER_LOG_DIR" ] && [ -n "$(ls -A "$SERVER_LOG_DIR" 2>/dev/null)" ]; then
|
|
209
|
+
info "--- server log (last 80 lines) ---"
|
|
210
|
+
find "$SERVER_LOG_DIR" -type f -name '*.log' -exec tail -80 {} \; 2>/dev/null || true
|
|
211
|
+
fi
|
|
212
|
+
# Also check the temp dir for server logs (default location)
|
|
213
|
+
local default_log_dir="${TMPDIR:-/tmp}/browser4/browser4-cli/tmp/cli"
|
|
214
|
+
if [ -d "$default_log_dir" ] && [ -n "$(ls -A "$default_log_dir" 2>/dev/null)" ]; then
|
|
215
|
+
info "--- default server log (last 80 lines) ---"
|
|
216
|
+
find "$default_log_dir" -type f -name '*.log' -exec tail -80 {} \; 2>/dev/null || true
|
|
217
|
+
fi
|
|
218
|
+
fi
|
|
219
|
+
fi
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
# ---------------------------------------------------------------------------
|
|
223
|
+
# step 4: run CLI commands
|
|
224
|
+
# ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
# 4a. open — starts the server, opens a browser session, navigates to the page
|
|
227
|
+
check_step "open" open "$TEST_URL" --profile-mode SEQUENTIAL --interact-level FASTEST
|
|
228
|
+
|
|
229
|
+
# 4b. goto — navigate to the page (should be a no-op or refresh)
|
|
230
|
+
check_step "goto" goto "$TEST_URL"
|
|
231
|
+
|
|
232
|
+
# 4c. type — fill the input field
|
|
233
|
+
check_step "type" type "hello-smoke" "#input1"
|
|
234
|
+
|
|
235
|
+
# 4d. click — click the button
|
|
236
|
+
check_step "click" click "#btn1"
|
|
237
|
+
|
|
238
|
+
# 4e. close — close the active session
|
|
239
|
+
check_step "close" close
|
|
240
|
+
|
|
241
|
+
# 4f. kill-all — stop the server and clean up
|
|
242
|
+
check_step "kill-all" kill-all
|
|
243
|
+
|
|
244
|
+
# ---------------------------------------------------------------------------
|
|
245
|
+
# step 5: report
|
|
246
|
+
# ---------------------------------------------------------------------------
|
|
247
|
+
echo ""
|
|
248
|
+
echo "========================================"
|
|
249
|
+
if [ "$FAILED_STEPS" -eq 0 ]; then
|
|
250
|
+
pass "SMOKE TEST PASSED ($TOTAL_STEPS/$TOTAL_STEPS steps OK)"
|
|
251
|
+
exit 0
|
|
252
|
+
else
|
|
253
|
+
fail "SMOKE TEST FAILED ($FAILED_STEPS/$TOTAL_STEPS steps failed)"
|
|
254
|
+
info "Server logs at: $SERVER_LOG_DIR"
|
|
255
|
+
info "Temp directory: $TEMP_DIR"
|
|
256
|
+
exit 1
|
|
257
|
+
fi
|