browser4-cli 0.1.23 → 0.1.25

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.
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser4-cli",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Browser automation CLI for AI agents",
5
5
  "type": "module",
6
6
  "files": [
@@ -1,6 +1,6 @@
1
1
  <#
2
2
  .SYNOPSIS
3
- Install browser4-cli download the native binary and set it up on your PATH.
3
+ Install browser4-cli -- download the native binary and set it up on your PATH.
4
4
 
5
5
  .DESCRIPTION
6
6
  Detects your OS and CPU architecture, downloads the matching native binary from
@@ -14,8 +14,8 @@
14
14
  Download sources (auto-selected by locale; use -Source to override):
15
15
  Outside China: 1. GitHub Releases -> 2. Aliyun OSS
16
16
  China mainland: 1. Aliyun OSS -> 2. GitHub Releases
17
- GitHub Releases https://github.com/platonai/Browser4
18
- Aliyun OSS https://browser4.oss-cn-beijing.aliyuncs.com
17
+ GitHub Releases -- https://github.com/platonai/Browser4
18
+ Aliyun OSS -- https://browser4.oss-cn-beijing.aliyuncs.com
19
19
 
20
20
  .PARAMETER Version
21
21
  Release version tag to download (e.g. "v4.11.0" or "v0.1.12-cli").
@@ -27,7 +27,7 @@
27
27
 
28
28
  .PARAMETER Source
29
29
  Force a specific download source: "github" or "oss".
30
- Default (auto): locale-aware OSS first in China mainland, GitHub first elsewhere.
30
+ Default (auto): locale-aware -- OSS first in China mainland, GitHub first elsewhere.
31
31
 
32
32
  .PARAMETER AddToPath
33
33
  Add the install directory to the current user's PATH environment variable.
@@ -39,17 +39,21 @@
39
39
  .PARAMETER DryRun
40
40
  Print what would be done without actually doing it.
41
41
 
42
+ .PARAMETER SkipIfInstalled
43
+ Skip download if the binary already exists at the install path.
44
+ By default the script always downloads the latest version.
45
+
42
46
  .PARAMETER SkipLocal
43
47
  Skip checking for a locally-bundled binary alongside the script.
44
48
  By default the script looks for the platform binary in its own directory
45
- before downloading use this to force a fresh download.
49
+ before downloading -- use this to force a fresh download.
46
50
 
47
51
  .PARAMETER Locate
48
52
  Print detection results (OS, architecture, script location, China locale)
49
53
  and exit without installing. Useful for diagnostics.
50
54
 
51
55
  .EXAMPLE
52
- # Quick install default location, latest version, add to PATH
56
+ # Quick install -- default location, latest version, add to PATH
53
57
  powershell -ExecutionPolicy Bypass -File install-browser4-cli.ps1
54
58
 
55
59
  .EXAMPLE
@@ -61,7 +65,7 @@
61
65
  powershell -ExecutionPolicy Bypass -File install-browser4-cli.ps1 -Source oss -InstallDir "C:\tools\browser4"
62
66
 
63
67
  .EXAMPLE
64
- # Run diagnostics see what the script detects without installing
68
+ # Run diagnostics -- see what the script detects without installing
65
69
  powershell -ExecutionPolicy Bypass -File install-browser4-cli.ps1 -Locate
66
70
 
67
71
  .EXAMPLE
@@ -73,6 +77,10 @@
73
77
  # Force download even when a local binary exists
74
78
  powershell -ExecutionPolicy Bypass -File install-browser4-cli.ps1 -SkipLocal
75
79
 
80
+ .EXAMPLE
81
+ # Skip download if already installed (opt out of default reinstall)
82
+ powershell -ExecutionPolicy Bypass -File install-browser4-cli.ps1 -SkipIfInstalled
83
+
76
84
  .EXAMPLE
77
85
  # For China mainland: OSS is auto-preferred via locale detection,
78
86
  # or force it explicitly
@@ -83,20 +91,21 @@
83
91
  param(
84
92
  [string]$Version = "",
85
93
  [string]$InstallDir = "",
86
- [ValidateSet("github", "oss")]
94
+ [ValidateSet("", "github", "oss")]
87
95
  [string]$Source = "",
88
96
  [bool]$AddToPath = $true,
89
97
  [switch]$Silent,
90
98
  [switch]$DryRun,
99
+ [switch]$SkipIfInstalled,
91
100
  [switch]$SkipLocal,
92
101
  [switch]$Locate
93
102
  )
94
103
 
95
104
  $ErrorActionPreference = "Stop"
96
105
 
97
- # ──────────────────────────────────────────────
98
- # Script location find ourselves on disk
99
- # ──────────────────────────────────────────────
106
+ # ----------------------------------------------
107
+ # Script location -- find ourselves on disk
108
+ # ----------------------------------------------
100
109
 
101
110
  # $PSScriptRoot is the directory containing this script (PS 3+).
102
111
  # Falls back to $MyInvocation for edge cases (dot-sourced, PS 2).
@@ -146,11 +155,11 @@ function Test-LocalBinary {
146
155
  }
147
156
  }
148
157
 
149
- # ──────────────────────────────────────────────
158
+ # ----------------------------------------------
150
159
  # OS detection (compatible with PS 5.1+)
151
- # ──────────────────────────────────────────────
160
+ # ----------------------------------------------
152
161
 
153
- # Avoid assigning to $IsLinux / $IsWindows / $IsMacOS directly
162
+ # Avoid assigning to $IsLinux / $IsWindows / $IsMacOS directly --
154
163
  # they are read-only automatic variables in PowerShell 7+.
155
164
  if ($PSVersionTable.PSVersion.Major -ge 6) {
156
165
  $script:OSWin = $IsWindows
@@ -162,9 +171,9 @@ if ($PSVersionTable.PSVersion.Major -ge 6) {
162
171
  $script:OSLinux = $false
163
172
  }
164
173
 
165
- # ──────────────────────────────────────────────
174
+ # ----------------------------------------------
166
175
  # Helpers
167
- # ──────────────────────────────────────────────
176
+ # ----------------------------------------------
168
177
 
169
178
  function Write-Summary {
170
179
  param([string]$Message, [string]$Color = "White")
@@ -173,22 +182,22 @@ function Write-Summary {
173
182
 
174
183
  function Write-Step {
175
184
  param([string]$Message)
176
- if (-not $Silent) { Write-Host " » $Message" -ForegroundColor Gray }
185
+ if (-not $Silent) { Write-Host " >> $Message" -ForegroundColor Gray }
177
186
  }
178
187
 
179
188
  function Write-Check {
180
189
  param([string]$Message)
181
- if (-not $Silent) { Write-Host " $Message" -ForegroundColor Green }
190
+ if (-not $Silent) { Write-Host " [v] $Message" -ForegroundColor Green }
182
191
  }
183
192
 
184
193
  function Write-WarnMsg {
185
194
  param([string]$Message)
186
- if (-not $Silent) { Write-Host " $Message" -ForegroundColor Yellow }
195
+ if (-not $Silent) { Write-Host " [!] $Message" -ForegroundColor Yellow }
187
196
  }
188
197
 
189
- # ──────────────────────────────────────────────
198
+ # ----------------------------------------------
190
199
  # Detection
191
- # ──────────────────────────────────────────────
200
+ # ----------------------------------------------
192
201
 
193
202
  function Get-PlatformKey {
194
203
  $arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) { "arm64" } else { "x64" }
@@ -237,29 +246,29 @@ function Get-DefaultInstallDir {
237
246
  throw "Unsupported OS"
238
247
  }
239
248
 
240
- # ──────────────────────────────────────────────
249
+ # ----------------------------------------------
241
250
  # China mainland locale detection (zero-network)
242
- # ──────────────────────────────────────────────
251
+ # ----------------------------------------------
243
252
 
244
253
  <#
245
254
  .SYNOPSIS
246
255
  Detect whether the current system is likely in China mainland.
247
- Uses only local env vars and .NET APIs no network calls.
256
+ Uses only local env vars and .NET APIs -- no network calls.
248
257
  #>
249
258
  function Test-ChinaLocale {
250
- # 1 Locale env vars
259
+ # 1 -- Locale env vars
251
260
  $lang = $env:LC_ALL, $env:LANG, $env:LC_CTYPE, $env:LC_MESSAGES | Where-Object { $_ } | Select-Object -First 1
252
261
  if ($lang -and ($lang -match '^zh_CN' -or $lang -match '^zh-CN' -or $lang -match '^Chinese \(Simplified\)_China')) {
253
262
  return $true
254
263
  }
255
264
 
256
- # 2 TZ env var
265
+ # 2 -- TZ env var
257
266
  $tzEnv = $env:TZ
258
267
  if ($tzEnv -and ($tzEnv -match '^Asia/(Shanghai|Chongqing|Urumqi|Harbin)$')) {
259
268
  return $true
260
269
  }
261
270
 
262
- # 3 .NET TimeZoneInfo (works on Windows and Unix PowerShell 7+)
271
+ # 3 -- .NET TimeZoneInfo (works on Windows and Unix PowerShell 7+)
263
272
  try {
264
273
  $tzId = [System.TimeZoneInfo]::Local.Id
265
274
  if ($tzId -match '^Asia/(Shanghai|Chongqing|Urumqi|Harbin)$') {
@@ -269,7 +278,7 @@ function Test-ChinaLocale {
269
278
  # TimeZoneInfo not available (unlikely on PS 5.1+ but guard anyway)
270
279
  }
271
280
 
272
- # 4 /etc/timezone (PowerShell on Linux/macOS)
281
+ # 4 -- /etc/timezone (PowerShell on Linux/macOS)
273
282
  if (-not $script:OSWin -and (Test-Path '/etc/timezone')) {
274
283
  try {
275
284
  $tz = Get-Content '/etc/timezone' -Raw -ErrorAction Stop
@@ -277,16 +286,16 @@ function Test-ChinaLocale {
277
286
  return $true
278
287
  }
279
288
  } catch {
280
- # Permission or read error skip
289
+ # Permission or read error -- skip
281
290
  }
282
291
  }
283
292
 
284
293
  return $false
285
294
  }
286
295
 
287
- # ──────────────────────────────────────────────
296
+ # ----------------------------------------------
288
297
  # Download URLs
289
- # ──────────────────────────────────────────────
298
+ # ----------------------------------------------
290
299
 
291
300
  $GITHUB_REPO = "platonai/Browser4"
292
301
  $OSS_BASE = "https://browser4.oss-cn-beijing.aliyuncs.com"
@@ -347,7 +356,7 @@ function Invoke-Download {
347
356
  Write-Check "Downloaded $( [math]::Round($size / 1MB, 1) ) MB"
348
357
  return $true
349
358
  } else {
350
- Write-WarnMsg "Downloaded file too small ($size bytes) may be an error page"
359
+ Write-WarnMsg "Downloaded file too small ($size bytes) -- may be an error page"
351
360
  Remove-Item $OutFile -Force -ErrorAction SilentlyContinue
352
361
  return $false
353
362
  }
@@ -360,9 +369,9 @@ function Invoke-Download {
360
369
  }
361
370
  }
362
371
 
363
- # ──────────────────────────────────────────────
372
+ # ----------------------------------------------
364
373
  # Symlinks
365
- # ──────────────────────────────────────────────
374
+ # ----------------------------------------------
366
375
 
367
376
  function New-PlatformLink {
368
377
  param([string]$LinkPath, [string]$TargetName, [string]$DisplayName)
@@ -373,7 +382,7 @@ function New-PlatformLink {
373
382
  Write-Check "Created symlink: $DisplayName -> $TargetName"
374
383
  return $true
375
384
  } catch {
376
- # Symbolic link failed try hard link on Windows
385
+ # Symbolic link failed -- try hard link on Windows
377
386
  }
378
387
 
379
388
  # Try hard link (Windows, same volume)
@@ -384,7 +393,7 @@ function New-PlatformLink {
384
393
  Write-Check "Created hard link: $DisplayName -> $TargetName"
385
394
  return $true
386
395
  } catch {
387
- # Hard link also failed create a .cmd wrapper as last resort
396
+ # Hard link also failed -- create a .cmd wrapper as last resort
388
397
  }
389
398
 
390
399
  # Last resort: .cmd wrapper that forwards all arguments
@@ -451,9 +460,9 @@ function New-Symlinks {
451
460
  }
452
461
  }
453
462
 
454
- # ──────────────────────────────────────────────
463
+ # ----------------------------------------------
455
464
  # PATH management
456
- # ──────────────────────────────────────────────
465
+ # ----------------------------------------------
457
466
 
458
467
  function Add-DirectoryToUserPath {
459
468
  param([string]$Dir)
@@ -485,14 +494,55 @@ function Add-DirectoryToUserPath {
485
494
  $env:Path = "$env:Path;$Dir"
486
495
  }
487
496
 
488
- # ──────────────────────────────────────────────
497
+ # ----------------------------------------------
498
+ # Helper: replace a binary that may be locked (i.e. currently running)
499
+ # ----------------------------------------------
500
+ function Set-BinaryFile {
501
+ param(
502
+ [Parameter(Mandatory=$true)] [string]$TargetPath,
503
+ [Parameter(Mandatory=$true)] [string]$SourcePath,
504
+ [Parameter(Mandatory=$false)] [switch]$Move # $true = move temp file, $false = copy
505
+ )
506
+
507
+ if (Test-Path $TargetPath) {
508
+ # Remove any stale .old from a previous upgrade
509
+ $oldPath = "$TargetPath.old"
510
+ try {
511
+ if (Test-Path $oldPath) { Remove-Item $oldPath -Force -ErrorAction Stop }
512
+ } catch { }
513
+
514
+ try {
515
+ Remove-Item $TargetPath -Force -ErrorAction Stop
516
+ } catch {
517
+ # The binary is locked (likely the currently-running process).
518
+ # On Windows we can rename a running executable — move the old binary
519
+ # out of the way, place the new one alongside, and clean up the old one
520
+ # on the next install/upgrade.
521
+ try {
522
+ Move-Item $TargetPath $oldPath -Force -ErrorAction Stop
523
+ Write-WarnMsg "Existing binary is locked (it may be running)."
524
+ Write-WarnMsg "The old copy will be cleaned up on the next install or upgrade."
525
+ } catch {
526
+ throw "Cannot replace '$TargetPath' — it is locked and cannot be renamed. Close all browser4-cli processes and try again."
527
+ }
528
+ }
529
+ }
530
+
531
+ # Place the new binary at the target path
532
+ if ($Move) {
533
+ Move-Item $SourcePath $TargetPath -Force -ErrorAction Stop
534
+ } else {
535
+ Copy-Item $SourcePath $TargetPath -Force -ErrorAction Stop
536
+ }
537
+ }
538
+ # ----------------------------------------------
489
539
  # Main
490
- # ──────────────────────────────────────────────
540
+ # ----------------------------------------------
491
541
 
492
542
  function Main {
493
- Write-Summary "╔════════════════════════════════════════╗" -Color Cyan
494
- Write-Summary "browser4-cli Installer" -Color Cyan
495
- Write-Summary "╚════════════════════════════════════════╝" -Color Cyan
543
+ Write-Summary "==========================================" -Color Cyan
544
+ Write-Summary " browser4-cli Installer" -Color Cyan
545
+ Write-Summary "==========================================" -Color Cyan
496
546
  Write-Summary ""
497
547
 
498
548
  # Auto-detect China mainland locale when no explicit source is given
@@ -507,9 +557,9 @@ function Main {
507
557
  $platformKey = Get-PlatformKey
508
558
  $binaryName = Get-BinaryName -PlatformKey $platformKey
509
559
 
510
- # ── Locate mode: print diagnostics and exit ──
560
+ # -- Locate mode: print diagnostics and exit --
511
561
  if ($Locate) {
512
- Write-Summary "─── Locate / diagnostics ───" -Color Cyan
562
+ Write-Summary "--- Locate / diagnostics ---" -Color Cyan
513
563
  Write-Summary ""
514
564
  Write-Step "Script dir: $ScriptDir"
515
565
  Write-Step "Platform key: $platformKey"
@@ -566,7 +616,7 @@ function Main {
566
616
 
567
617
  $binaryPath = Join-Path $installDir $binaryName
568
618
 
569
- # ── Local binary discovery (bundled/sideload) ──
619
+ # -- Local binary discovery (bundled/sideload) --
570
620
  $useLocalBinary = $false
571
621
  if (-not $SkipLocal) {
572
622
  $localBinaryPath = Find-LocalBinary -BinaryName $binaryName
@@ -576,21 +626,20 @@ function Main {
576
626
  Write-Check "Local binary verified (--version OK)"
577
627
  $useLocalBinary = $true
578
628
  } else {
579
- Write-WarnMsg "Local binary found but --version check failed will download instead"
629
+ Write-WarnMsg "Local binary found but --version check failed -- will download instead"
580
630
  }
581
631
  }
582
632
  } elseif ($SkipLocal) {
583
633
  Write-Step "Skipping local binary check (-SkipLocal)"
584
634
  }
585
635
 
586
- # If binary already exists and no version override, skip download
587
- if ((Test-Path $binaryPath) -and (-not $Version) -and (-not $useLocalBinary)) {
636
+ # Skip download only when --skip-if-installed is set and binary already exists
637
+ if ((Test-Path $binaryPath) -and (-not $Version) -and $SkipIfInstalled -and (-not $useLocalBinary)) {
588
638
  Write-Check "Binary already installed: $binaryPath"
589
639
  } elseif ($useLocalBinary) {
590
640
  # Copy local binary to install dir
591
641
  if (-not $DryRun) {
592
- if (Test-Path $binaryPath) { Remove-Item $binaryPath -Force }
593
- Copy-Item $localBinaryPath $binaryPath -Force
642
+ Set-BinaryFile -TargetPath $binaryPath -SourcePath $localBinaryPath
594
643
  }
595
644
  Write-Check "Installed (local): $binaryPath"
596
645
  } else {
@@ -628,8 +677,7 @@ Please check:
628
677
 
629
678
  # Move from temp to install dir
630
679
  if (-not $DryRun) {
631
- if (Test-Path $binaryPath) { Remove-Item $binaryPath -Force }
632
- Move-Item $tempFile $binaryPath -Force
680
+ Set-BinaryFile -TargetPath $binaryPath -SourcePath $tempFile -Move
633
681
  }
634
682
  Write-Check "Installed: $binaryPath"
635
683
  }
@@ -672,10 +720,10 @@ Please check:
672
720
  if (-not $DryRun) {
673
721
  try {
674
722
  $versionOutput = & $binaryPath --version 2>&1
675
- Write-Summary " browser4-cli installed successfully" -Color Green
723
+ Write-Summary "[v] browser4-cli installed successfully" -Color Green
676
724
  Write-Summary " Version: $versionOutput"
677
725
  } catch {
678
- Write-Summary " Binary installed at: $binaryPath" -Color Green
726
+ Write-Summary "[v] Binary installed at: $binaryPath" -Color Green
679
727
  Write-WarnMsg "Could not verify --version (this is normal on first install)"
680
728
  }
681
729
  } else {