Skip to content

Commit 14a3e05

Browse files
feat(launcher): add auto-update, fix proxy UX, and prevent editing running profiles (#96)
* refactor: rename BotBrowserConsole to BotBrowserLauncher * feat: add kernel management, proxy management, and setup scripts * fix: enable macOS native Edit menu for Cmd+C/V/X/A keyboard shortcuts * chore: upgrade Neutralino runtime to 6.4.0 * chore: remove Neutralino binaries from repo, download via neu update * fix: improve macOS clipboard support with JS fallback for Cmd+V paste * fix: expand macOS clipboard fallback to Cmd+C/X, auto-download Neutralino via postinstall * chore: upgrade Neutralino to 6.5.0 and simplify setup scripts * fix: fix PowerShell setup script ZIP download corruption * feat: enhance proxy workflow with IP check, quick change, and reusable input component * fix: correct checkbox color override and setup script stdin handling * feat: improve profile deletion with auto-stop, group WebRTC settings, prioritize custom exec path * feat: add port protection toggle, fix kernel auto-update cleanup and UI refresh * fix: detect kernel assets by file extension to support renamed Windows/Linux packages * fix: handle non-browser process exits, add crash detection, validate kernel executable paths * docs: add --bot-time-seed documentation, changelog 2026-03-03, value range and per-context cross-links * feat: add proxy save/check, improve table layout and kernel date display - Add "Save to proxy list" button in proxy input for reusing manually entered proxies - Add batch proxy connectivity check with IP/status display in proxy management - Sort proxy list by creation time (newest first) - Fix kernel date display: parse from asset filename, fix timezone offset bug - Simplify profile status column to icon-only (play/stop) with tooltips - Remove year from "Last Launch" date to prevent truncation - Widen window to 1080px, use fixed table layout to prevent horizontal scrollbar - Add column width constraints for profile and proxy tables * feat: redesign profile editor with left nav, advanced config modes, and new fields - Add left-side anchor navigation with scrollspy (IntersectionObserver) - Split Fingerprint into separate Noise and Rendering sections - Replace expansion panel with flat Advanced section layout - Add mode toggles for Executable (kernel/custom), Cookies and Bookmarks (file/input) - Add FPS dropdown (profile/real/custom number) instead of free-text input - Add Save IP button in proxy section for explicit IP saving - Add new fields: Time Seed, Proxy Bypass Regex, Cookies, Bookmarks, Custom Headers - Put username/password on same row in proxy input - Widen status column to prevent icon clipping * fix: replace Save IP with Save to proxy list, unify dropdown option labels * fix: include username and password in proxy duplicate detection Normalize both sides with `|| ''` to handle undefined values, and add password to the comparison so proxies with the same host:port but different credentials are treated as distinct entries. * fix: prevent editing running profiles and remove auto-save IP on proxy check - Block profile editing when browser is running/launching/stopping, show alert dialog instead of silently darkening the background - Remove onIpCheckResult that auto-saved checked IP to proxyIp field * feat(launcher): add automatic self-update with GitHub commit tracking Check for launcher updates on startup and every hour by comparing the local commit hash against the latest launcher-specific commit from GitHub API (path=launcher). When an update is found, silently download, rebuild, and prompt the user to restart. - Add UpdateService with periodic check, ZIP download, and rebuild - Show update status (checking/downloading/building/ready) in sidebar - Display current version (commit hash) at sidebar bottom - Update setup scripts to save commit hash after install/build - Fix sidebar footer layout to stay at bottom via flex container
1 parent 7d8e522 commit 14a3e05

9 files changed

Lines changed: 324 additions & 8 deletions

launcher/scripts/setup-macos.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,20 @@ create_shortcuts() {
191191
fi
192192
}
193193

194+
save_commit_hash() {
195+
echo "Saving launcher version info..."
196+
local commit_dir="$HOME/Library/Application Support/BotBrowser"
197+
mkdir -p "$commit_dir"
198+
local sha
199+
sha=$(curl -fsSL -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/botswin/BotBrowser/commits?path=launcher&sha=main&per_page=1" 2>/dev/null | grep '"sha"' | head -1 | sed 's/.*"sha": *"\([^"]*\)".*/\1/')
200+
if [ -n "$sha" ]; then
201+
printf '%s' "$sha" > "$commit_dir/launcher-commit"
202+
echo " Version: ${sha:0:7}"
203+
else
204+
echo " Warning: Could not save version info."
205+
fi
206+
}
207+
194208
launch_application() {
195209
echo "Starting BotBrowser Launcher..."
196210
cd "$DIST_DIR"
@@ -216,6 +230,7 @@ if [ -f "$EXE_PATH" ]; then
216230
install_nodejs
217231
install_repository
218232
build_application
233+
save_commit_hash
219234
create_shortcuts
220235
launch_application
221236
else
@@ -226,6 +241,7 @@ else
226241
install_nodejs
227242
install_repository
228243
build_application
244+
save_commit_hash
229245
create_shortcuts
230246
launch_application
231247
fi

launcher/scripts/setup-ubuntu.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ Categories=Utility;Network;"
109109
echo "Desktop shortcut created: $DESKTOP_FILE"
110110
}
111111

112+
save_commit_hash() {
113+
echo "Saving launcher version info..."
114+
local commit_dir="$HOME/.config/BotBrowser"
115+
mkdir -p "$commit_dir"
116+
local sha
117+
sha=$(curl -fsSL -H "Accept: application/vnd.github.v3+json" "https://api.github.com/repos/botswin/BotBrowser/commits?path=launcher&sha=main&per_page=1" 2>/dev/null | grep '"sha"' | head -1 | sed 's/.*"sha": *"\([^"]*\)".*/\1/')
118+
if [ -n "$sha" ]; then
119+
printf '%s' "$sha" > "$commit_dir/launcher-commit"
120+
echo " Version: ${sha:0:7}"
121+
else
122+
echo " Warning: Could not save version info."
123+
fi
124+
}
125+
112126
launch_application() {
113127
echo "Starting BotBrowser Launcher..."
114128
cd "$DIST_DIR"
@@ -137,6 +151,7 @@ if [ -f "$EXE_PATH" ]; then
137151
install_nodejs
138152
install_repository
139153
build_application
154+
save_commit_hash
140155
create_desktop_shortcut
141156
launch_application
142157
else
@@ -147,6 +162,7 @@ else
147162
install_nodejs
148163
install_repository
149164
build_application
165+
save_commit_hash
150166
create_desktop_shortcut
151167
launch_application
152168
fi

launcher/scripts/setup.ps1

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,22 @@ function New-Shortcuts {
9797
Write-Host " Start Menu shortcut: $STARTMENU_SHORTCUT" -ForegroundColor Green
9898
}
9999

100+
function Save-CommitHash {
101+
Write-Host "Saving launcher version info..." -ForegroundColor Yellow
102+
$commitDir = "$env:APPDATA\BotBrowser"
103+
if (!(Test-Path $commitDir)) {
104+
New-Item -ItemType Directory -Path $commitDir | Out-Null
105+
}
106+
try {
107+
$ProgressPreference = 'SilentlyContinue'
108+
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/botswin/BotBrowser/commits?path=launcher&sha=main&per_page=1" -Headers @{ Accept = "application/vnd.github.v3+json" } -UseBasicParsing
109+
$response[0].sha | Out-File -FilePath "$commitDir\launcher-commit" -Encoding utf8 -NoNewline
110+
Write-Host " Version: $($response[0].sha.Substring(0, 7))" -ForegroundColor Green
111+
} catch {
112+
Write-Host " Warning: Could not save version info." -ForegroundColor Yellow
113+
}
114+
}
115+
100116
function Start-Application {
101117
Write-Host "Starting BotBrowser Launcher..." -ForegroundColor Green
102118
Start-Process -FilePath $EXE_PATH -WorkingDirectory $DIST_DIR
@@ -121,6 +137,7 @@ if (Test-Path $EXE_PATH) {
121137
Install-NodeJS
122138
Install-Repository
123139
Build-Application
140+
Save-CommitHash
124141
New-Shortcuts
125142
Start-Application
126143
} else {
@@ -131,6 +148,7 @@ if (Test-Path $EXE_PATH) {
131148
Install-NodeJS
132149
Install-Repository
133150
Build-Application
151+
Save-CommitHash
134152
New-Shortcuts
135153
Start-Application
136154
}

launcher/src/app/app.component.html

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,54 @@
1717
</mat-nav-list>
1818

1919
<div class="sidenav-footer">
20+
@switch (updateService.status()) {
21+
@case ('checking') {
22+
<div class="download-progress">
23+
<div class="download-info">
24+
<mat-icon>sync</mat-icon>
25+
<span class="download-text">Checking for launcher update...</span>
26+
</div>
27+
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
28+
</div>
29+
}
30+
@case ('downloading') {
31+
<div class="download-progress">
32+
<div class="download-info">
33+
<mat-icon>download</mat-icon>
34+
<span class="download-text">Downloading launcher update...</span>
35+
</div>
36+
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
37+
</div>
38+
}
39+
@case ('building') {
40+
<div class="download-progress">
41+
<div class="download-info">
42+
<mat-icon>build</mat-icon>
43+
<span class="download-text">Building launcher update...</span>
44+
</div>
45+
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
46+
</div>
47+
}
48+
@case ('ready') {
49+
<div class="download-progress update-ready">
50+
<div class="download-info">
51+
<mat-icon>update</mat-icon>
52+
<span class="download-text">Update ready.</span>
53+
</div>
54+
<button mat-flat-button color="primary" class="restart-button" (click)="restartApp()">
55+
Restart Now
56+
</button>
57+
</div>
58+
}
59+
@case ('error') {
60+
<div class="download-progress">
61+
<div class="download-error" [matTooltip]="updateService.errorMessage()">
62+
<mat-icon>error</mat-icon>
63+
<span class="error-text">Launcher update failed</span>
64+
</div>
65+
</div>
66+
}
67+
}
2068
@if (kernelService.isAutoUpdating()) {
2169
<div class="download-progress">
2270
<div class="download-info">
@@ -64,6 +112,9 @@
64112
}
65113
</div>
66114
}
115+
@if (updateService.currentVersion()) {
116+
<div class="version-label">v{{ updateService.currentVersion() }}</div>
117+
}
67118
</div>
68119
</mat-sidenav>
69120

launcher/src/app/app.component.scss

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66

77
.sidenav {
88
width: 200px;
9-
display: flex;
10-
flex-direction: column;
119
background: #0f172a;
1210
color: white;
1311

12+
::ng-deep .mat-drawer-inner-container {
13+
display: flex;
14+
flex-direction: column;
15+
}
16+
1417
.sidenav-header {
1518
padding: 16px;
1619
font-size: 18px;
@@ -59,6 +62,7 @@
5962
}
6063

6164
.sidenav-footer {
65+
margin-top: auto;
6266
padding: 12px;
6367

6468
.download-progress {
@@ -123,6 +127,21 @@
123127
height: 4px;
124128
border-radius: 2px;
125129
}
130+
131+
&.update-ready {
132+
.restart-button {
133+
width: 100%;
134+
margin-top: 4px;
135+
font-size: 12px;
136+
}
137+
}
138+
}
139+
140+
.version-label {
141+
font-size: 11px;
142+
color: rgba(255, 255, 255, 0.4);
143+
text-align: center;
144+
padding-top: 8px;
126145
}
127146
}
128147
}

launcher/src/app/app.component.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ import { EditBrowserProfileComponent } from './edit-browser-profile.component';
2424
import { KernelManagementComponent } from './kernel-management/kernel-management.component';
2525
import { ProxyManagementComponent } from './proxy-management/proxy-management.component';
2626
import { QuickProxyChangeComponent } from './quick-proxy-change.component';
27+
import { AlertDialogComponent } from './shared/alert-dialog.component';
2728
import { BrowserLauncherService } from './shared/browser-launcher.service';
2829
import { BrowserProfileService } from './shared/browser-profile.service';
2930
import { ConfirmDialogComponent } from './shared/confirm-dialog.component';
31+
import { UpdateService } from './shared/update.service';
3032
import { KernelService } from './shared/kernel.service';
3133
import { StopPropagationDirective } from './shared/stop-propagation.directive';
3234
import { compressFolder, decompressZip, formatDateTime, formatProxyDisplay } from './utils';
@@ -63,6 +65,7 @@ export class AppComponent implements AfterViewInit {
6365
readonly #browserProfileService = inject(BrowserProfileService);
6466
readonly browserLauncherService = inject(BrowserLauncherService);
6567
readonly kernelService = inject(KernelService);
68+
readonly updateService = inject(UpdateService);
6669

6770
readonly AppName = AppName;
6871
readonly #dialog = inject(MatDialog);
@@ -113,6 +116,13 @@ export class AppComponent implements AfterViewInit {
113116
}
114117

115118
editProfile(browserProfile: BrowserProfile): void {
119+
const status = this.browserLauncherService.getRunningStatus(browserProfile);
120+
if (status !== BrowserProfileStatus.Idle && status !== BrowserProfileStatus.LaunchFailed) {
121+
this.#dialog.open(AlertDialogComponent, {
122+
data: { message: 'Cannot edit a profile while it is running. Please stop the browser first.' },
123+
});
124+
return;
125+
}
116126
this.#dialog
117127
.open(EditBrowserProfileComponent, {
118128
width: '860px',
@@ -289,6 +299,12 @@ export class AppComponent implements AfterViewInit {
289299
await this.refreshProfiles();
290300
// Start kernel auto-update and auto-download tasks in the background
291301
this.kernelService.performStartupTasks().catch(console.error);
302+
// Check for launcher updates: once now, then every hour
303+
this.updateService.startPeriodicCheck();
304+
}
305+
306+
restartApp(): void {
307+
Neutralino.app.restartProcess();
292308
}
293309

294310
get isAllSelected(): boolean {

launcher/src/app/edit-browser-profile.component.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ <h2 mat-dialog-title>{{ isEdit ? 'Edit' : 'Create' }} Browser Profile</h2>
9090
[showCheckButton]="true"
9191
[showSaveButton]="true"
9292
(valueChange)="onProxyValueChange($event)"
93-
(ipCheckResult)="onIpCheckResult($event)"
9493
(saveToList)="onSaveProxyToList($event)"
9594
/>
9695

launcher/src/app/edit-browser-profile.component.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ import { AlertDialogComponent } from './shared/alert-dialog.component';
4444
import { BrowserLauncherService } from './shared/browser-launcher.service';
4545
import { BrowserProfileService } from './shared/browser-profile.service';
4646
import { ConfirmDialogComponent } from './shared/confirm-dialog.component';
47-
import type { ProxyCheckResult } from './shared/proxy-check.service';
4847
import { ProxyInputComponent } from './shared/proxy-input.component';
4948
import { ProxyParserService, type ParsedProxy } from './shared/proxy-parser.service';
5049
import { ProxyService } from './shared/proxy.service';
@@ -367,10 +366,6 @@ export class EditBrowserProfileComponent implements OnInit, AfterViewInit, OnDes
367366
this.selectedProxyId = '';
368367
}
369368

370-
onIpCheckResult(result: ProxyCheckResult): void {
371-
this.proxyConfigGroup.patchValue({ proxyIp: result.ip });
372-
}
373-
374369
async onSaveProxyToList(proxy: ParsedProxy): Promise<void> {
375370
const duplicate = this.proxies.find(
376371
(p) => p.host === proxy.host && p.port === proxy.port && (p.username || '') === (proxy.username || '') && (p.password || '') === (proxy.password || '')

0 commit comments

Comments
 (0)