lightman-agent 1.0.12 → 1.0.15

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.
@@ -1,117 +1,101 @@
1
- ' LIGHTMAN Kiosk Launcher
2
- ' Runs at user logon AND at system startup to start the kiosk browser.
3
- ' Waits for the agent service to be ready before launching Chrome.
4
- ' If the agent is already managing Chrome, this script exits gracefully.
5
-
6
- Set objShell = CreateObject("WScript.Shell")
7
- Set objFSO = CreateObject("Scripting.FileSystemObject")
8
-
9
- ' --- Configuration ---
10
- configPath = "C:\Program Files\Lightman\Agent\agent.config.json"
11
- maxWaitSeconds = 120 ' Max time to wait for agent service
12
- checkIntervalMs = 5000 ' Check every 5 seconds
13
-
14
- ' --- Wait for config file to exist (agent might still be installing) ---
15
- If Not objFSO.FileExists(configPath) Then
16
- WScript.Sleep 10000
17
- If Not objFSO.FileExists(configPath) Then
18
- WScript.Quit 1
19
- End If
20
- End If
21
-
22
- ' --- Read config ---
23
- Set objFile = objFSO.OpenTextFile(configPath, 1)
24
- jsonText = objFile.ReadAll
25
- objFile.Close
26
-
27
- browserPath = ExtractJsonValue(jsonText, "browserPath")
28
- defaultUrl = ExtractJsonValue(jsonText, "defaultUrl")
29
- browserExeName = LCase(ExtractFileName(browserPath))
30
-
31
- If browserExeName = "" Then
32
- browserExeName = "chrome.exe"
33
- End If
34
-
35
- If browserPath = "" Or defaultUrl = "" Then
36
- WScript.Quit 1
37
- End If
38
-
39
- ' --- Wait for network connectivity ---
40
- ' Try to ping the server (extract hostname from URL)
41
- waitedMs = 0
42
- Do While waitedMs < (maxWaitSeconds * 1000)
43
- ' Check if the browser is already running (agent's KioskManager may have launched it)
44
- Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
45
- Set colProcesses = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = '" & browserExeName & "'")
46
- If colProcesses.Count > 0 Then
47
- ' Browser already running - agent is handling it. Exit gracefully.
48
- WScript.Quit 0
49
- End If
50
-
51
- ' Check if LIGHTMAN service is running
52
- Set colServices = objWMI.ExecQuery("SELECT State FROM Win32_Service WHERE DisplayName LIKE 'LIGHTMAN%'")
53
- serviceRunning = False
54
- For Each svc In colServices
55
- If LCase(svc.State) = "running" Then
56
- serviceRunning = True
57
- End If
58
- Next
59
-
60
- If serviceRunning Then
61
- ' Service is running - give it a few more seconds to launch Chrome itself
62
- WScript.Sleep 15000
63
-
64
- ' Re-check if the browser appeared (agent launched it)
65
- Set colProcesses2 = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = '" & browserExeName & "'")
66
- If colProcesses2.Count > 0 Then
67
- ' Agent launched the browser successfully. Exit.
68
- WScript.Quit 0
69
- End If
70
-
71
- ' Agent is running but hasn't launched the browser yet - we'll do it
72
- Exit Do
73
- End If
74
-
75
- WScript.Sleep checkIntervalMs
76
- waitedMs = waitedMs + checkIntervalMs
77
- Loop
78
-
79
- ' --- Build Chrome kiosk args ---
80
- chromeArgs = "--kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required"
81
-
82
- userDataDir = ExtractJsonValue(jsonText, "user-data-dir")
83
- If userDataDir = "" Then
84
- userDataDir = "C:\ProgramData\Lightman\chrome-kiosk"
85
- End If
86
- chromeArgs = chromeArgs & " --user-data-dir=""" & userDataDir & """"
87
-
88
- ' --- Launch Chrome ---
89
- objShell.Run """" & browserPath & """ " & chromeArgs & " """ & defaultUrl & """", 1, False
90
-
91
- ' ========================================================
92
- ' Helper: extract a string value from JSON by key
93
- ' ========================================================
94
- Function ExtractJsonValue(json, key)
95
- ExtractJsonValue = ""
96
- pos = InStr(json, """" & key & """")
97
- If pos = 0 Then Exit Function
98
- pos = InStr(pos, json, ":")
99
- If pos = 0 Then Exit Function
100
- pos = InStr(pos, json, """")
101
- If pos = 0 Then Exit Function
102
- pos = pos + 1
103
- endPos = InStr(pos, json, """")
104
- If endPos = 0 Then Exit Function
105
- ExtractJsonValue = Mid(json, pos, endPos - pos)
106
- End Function
107
-
108
- Function ExtractFileName(path)
109
- ExtractFileName = ""
110
- If path = "" Then Exit Function
111
- On Error Resume Next
112
- ExtractFileName = objFSO.GetFileName(path)
113
- If ExtractFileName = "" Then
114
- ExtractFileName = path
115
- End If
116
- On Error GoTo 0
117
- End Function
1
+ ' LIGHTMAN Kiosk Launcher
2
+ ' Runs at user logon AND at system startup to start the kiosk browser.
3
+ ' Waits for the agent service to be ready before launching Chrome.
4
+ ' If the agent is already managing Chrome, this script exits gracefully.
5
+
6
+ Set objShell = CreateObject("WScript.Shell")
7
+ Set objFSO = CreateObject("Scripting.FileSystemObject")
8
+
9
+ ' --- Configuration ---
10
+ configPath = "C:\Program Files\Lightman\Agent\agent.config.json"
11
+ maxWaitSeconds = 120 ' Max time to wait for agent service
12
+ checkIntervalMs = 5000 ' Check every 5 seconds
13
+
14
+ ' --- Wait for config file to exist (agent might still be installing) ---
15
+ If Not objFSO.FileExists(configPath) Then
16
+ WScript.Sleep 10000
17
+ If Not objFSO.FileExists(configPath) Then
18
+ WScript.Quit 1
19
+ End If
20
+ End If
21
+
22
+ ' --- Read config ---
23
+ Set objFile = objFSO.OpenTextFile(configPath, 1)
24
+ jsonText = objFile.ReadAll
25
+ objFile.Close
26
+
27
+ browserPath = ExtractJsonValue(jsonText, "browserPath")
28
+ defaultUrl = ExtractJsonValue(jsonText, "defaultUrl")
29
+
30
+ If browserPath = "" Or defaultUrl = "" Then
31
+ WScript.Quit 1
32
+ End If
33
+
34
+ ' --- Wait for network connectivity ---
35
+ ' Try to ping the server (extract hostname from URL)
36
+ waitedMs = 0
37
+ Do While waitedMs < (maxWaitSeconds * 1000)
38
+ ' Check if Chrome is already running (agent's KioskManager may have launched it)
39
+ Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
40
+ Set colProcesses = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = 'chrome.exe'")
41
+ If colProcesses.Count > 0 Then
42
+ ' Chrome already running - agent is handling it. Exit gracefully.
43
+ WScript.Quit 0
44
+ End If
45
+
46
+ ' Check if LIGHTMAN service is running
47
+ Set colServices = objWMI.ExecQuery("SELECT State FROM Win32_Service WHERE DisplayName LIKE 'LIGHTMAN%'")
48
+ serviceRunning = False
49
+ For Each svc In colServices
50
+ If LCase(svc.State) = "running" Then
51
+ serviceRunning = True
52
+ End If
53
+ Next
54
+
55
+ If serviceRunning Then
56
+ ' Service is running - give it a few more seconds to launch Chrome itself
57
+ WScript.Sleep 15000
58
+
59
+ ' Re-check if Chrome appeared (agent launched it)
60
+ Set colProcesses2 = objWMI.ExecQuery("SELECT ProcessId FROM Win32_Process WHERE Name = 'chrome.exe'")
61
+ If colProcesses2.Count > 0 Then
62
+ ' Agent launched Chrome successfully. Exit.
63
+ WScript.Quit 0
64
+ End If
65
+
66
+ ' Agent is running but hasn't launched Chrome yet - we'll do it
67
+ Exit Do
68
+ End If
69
+
70
+ WScript.Sleep checkIntervalMs
71
+ waitedMs = waitedMs + checkIntervalMs
72
+ Loop
73
+
74
+ ' --- Build Chrome kiosk args ---
75
+ chromeArgs = "--kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required"
76
+
77
+ userDataDir = ExtractJsonValue(jsonText, "user-data-dir")
78
+ If userDataDir = "" Then
79
+ userDataDir = "C:\ProgramData\Lightman\chrome-kiosk"
80
+ End If
81
+ chromeArgs = chromeArgs & " --user-data-dir=""" & userDataDir & """"
82
+
83
+ ' --- Launch Chrome ---
84
+ objShell.Run """" & browserPath & """ " & chromeArgs & " """ & defaultUrl & """", 1, False
85
+
86
+ ' ========================================================
87
+ ' Helper: extract a string value from JSON by key
88
+ ' ========================================================
89
+ Function ExtractJsonValue(json, key)
90
+ ExtractJsonValue = ""
91
+ pos = InStr(json, """" & key & """")
92
+ If pos = 0 Then Exit Function
93
+ pos = InStr(pos, json, ":")
94
+ If pos = 0 Then Exit Function
95
+ pos = InStr(pos, json, """")
96
+ If pos = 0 Then Exit Function
97
+ pos = pos + 1
98
+ endPos = InStr(pos, json, """")
99
+ If endPos = 0 Then Exit Function
100
+ ExtractJsonValue = Mid(json, pos, endPos - pos)
101
+ End Function
@@ -1,149 +1,128 @@
1
- @echo off
2
- REM ================================================================
3
- REM LIGHTMAN Shell - Replaces explorer.exe as the Windows shell
4
- REM ================================================================
5
- REM SINGLE SOURCE OF TRUTH: agent.config.json
6
- REM
7
- REM Boot flow:
8
- REM 1. Auto-login (no password)
9
- REM 2. This script runs INSTEAD of explorer.exe
10
- REM 3. Reads slug + browser from agent.config.json (THE ONLY SOURCE)
11
- REM 4. Waits for agent service (port 3403)
12
- REM 5. Launches Chrome fullscreen
13
- REM 6. If Chrome crashes, relaunches in 3 seconds (infinite loop)
14
- REM ================================================================
15
-
16
- set INSTALL_DIR=C:\Program Files\Lightman\Agent
17
- set CONFIG_FILE=%INSTALL_DIR%\agent.config.json
18
- set URL_SIDECAR=C:\ProgramData\Lightman\kiosk-url.txt
19
- set CHROME_DATA=C:\ProgramData\Lightman\chrome-kiosk
20
- set LOG_FILE=C:\ProgramData\Lightman\logs\shell.log
21
-
22
- REM Ensure directories exist
23
- if not exist "C:\ProgramData\Lightman\logs" mkdir "C:\ProgramData\Lightman\logs"
24
- if not exist "%CHROME_DATA%" mkdir "%CHROME_DATA%"
25
-
26
- echo [%date% %time%] ===== LIGHTMAN Shell starting ===== >> "%LOG_FILE%"
27
-
28
- REM ----------------------------------------------------------------
29
- REM Read slug and browser from agent.config.json ONLY
30
- REM No sidecar files, no hardcoded URLs, no confusion.
31
- REM ----------------------------------------------------------------
32
- set DEVICE_SLUG=
33
- set BROWSER=
34
- set URL=
35
-
36
- REM Wait for node.exe to be available
37
- set NODE_WAIT=0
38
- :wait_for_node
39
- where node >nul 2>&1
40
- if %errorlevel%==0 goto node_ready
41
- set /a NODE_WAIT+=1
42
- if %NODE_WAIT% geq 30 (
43
- echo [%date% %time%] ERROR: node.exe not found after 30s >> "%LOG_FILE%"
44
- goto use_fallbacks
45
- )
46
- timeout /t 1 /nobreak >nul
47
- goto wait_for_node
48
-
49
- :node_ready
50
-
51
- REM Read slug from config
52
- if exist "%CONFIG_FILE%" (
53
- for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do set DEVICE_SLUG=%%a
54
- )
55
-
56
- REM Read browser from config
57
- if exist "%CONFIG_FILE%" (
58
- for /f "delims=" %%a in ('node -e "try{const c=JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8'));console.log(c.kiosk&&c.kiosk.browserPath||'')}catch(e){console.log('')}" 2^>nul') do set BROWSER=%%a
59
- )
60
-
61
- :use_fallbacks
62
-
63
- REM Build URL from slug (ALWAYS from config, never from sidecar)
64
- if not "%DEVICE_SLUG%"=="" (
65
- set URL=http://localhost:3403/display/%DEVICE_SLUG%
66
- echo [%date% %time%] Slug: %DEVICE_SLUG% >> "%LOG_FILE%"
67
- ) else (
68
- set URL=http://localhost:3403/display
69
- echo [%date% %time%] WARNING: No slug in config! >> "%LOG_FILE%"
70
- )
71
-
72
- REM If agent wrote a URL sidecar (includes deviceId/apiKey), prefer it.
73
- if exist "%URL_SIDECAR%" (
74
- for /f "usebackq delims=" %%u in ("%URL_SIDECAR%") do set SIDE_URL=%%u
75
- if not "%SIDE_URL%"=="" (
76
- set URL=%SIDE_URL%
77
- echo [%date% %time%] Using sidecar URL >> "%LOG_FILE%"
78
- )
79
- )
80
-
81
- REM Fallback browser
82
- if "%BROWSER%"=="" (
83
- if exist "C:\Program Files\Google\Chrome\Application\chrome.exe" (
84
- set "BROWSER=C:\Program Files\Google\Chrome\Application\chrome.exe"
85
- ) else if exist "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" (
86
- set "BROWSER=C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
87
- ) else if exist "C:\Program Files\Microsoft\Edge\Application\msedge.exe" (
88
- set "BROWSER=C:\Program Files\Microsoft\Edge\Application\msedge.exe"
89
- ) else if exist "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" (
90
- set "BROWSER=C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
91
- ) else (
92
- echo [%date% %time%] ERROR: No supported kiosk browser found! >> "%LOG_FILE%"
93
- start explorer.exe
94
- exit /b 1
95
- )
96
- )
97
-
98
- echo [%date% %time%] Browser: %BROWSER% >> "%LOG_FILE%"
99
- echo [%date% %time%] URL: %URL% >> "%LOG_FILE%"
100
-
101
- REM ----------------------------------------------------------------
102
- REM Wait for agent service (port 3403)
103
- REM ----------------------------------------------------------------
104
- echo [%date% %time%] Waiting for port 3403... >> "%LOG_FILE%"
105
- set WAIT_COUNT=0
106
- set MAX_WAIT=60
107
-
108
- :wait_for_agent
109
- netstat -an | findstr ":3403.*LISTENING" >nul 2>&1
110
- if %errorlevel%==0 goto agent_ready
111
- set /a WAIT_COUNT+=1
112
- if %WAIT_COUNT% geq %MAX_WAIT% (
113
- echo [%date% %time%] Port 3403 not ready after %MAX_WAIT%s, launching anyway >> "%LOG_FILE%"
114
- goto agent_ready
115
- )
116
- timeout /t 1 /nobreak >nul
117
- goto wait_for_agent
118
-
119
- :agent_ready
120
- echo [%date% %time%] Agent ready >> "%LOG_FILE%"
121
-
122
- REM ----------------------------------------------------------------
123
- REM Infinite Chrome loop
124
- REM ----------------------------------------------------------------
125
- :loop
126
- REM Prefer sidecar URL for auth params/device routing; fallback to slug URL.
127
- set SIDE_URL=
128
- if exist "%URL_SIDECAR%" (
129
- for /f "usebackq delims=" %%u in ("%URL_SIDECAR%") do set SIDE_URL=%%u
130
- )
131
- if not "%SIDE_URL%"=="" (
132
- set URL=%SIDE_URL%
133
- ) else (
134
- REM Re-read slug from config on every loop iteration.
135
- if exist "%CONFIG_FILE%" (
136
- for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do (
137
- if not "%%a"=="" set URL=http://localhost:3403/display/%%a
138
- )
139
- )
140
- )
141
-
142
- echo [%date% %time%] Launching browser: %URL% >> "%LOG_FILE%"
143
-
144
- start /wait "" "%BROWSER%" --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required --disable-features=TranslateUI --user-data-dir="%CHROME_DATA%" "%URL%"
145
-
146
- echo [%date% %time%] Browser exited (code: %errorlevel%). Restarting in 3s... >> "%LOG_FILE%"
147
- timeout /t 3 /nobreak >nul
148
-
149
- goto loop
1
+ @echo off
2
+ REM ================================================================
3
+ REM LIGHTMAN Shell - Replaces explorer.exe as the Windows shell
4
+ REM ================================================================
5
+ REM SINGLE SOURCE OF TRUTH: agent.config.json
6
+ REM
7
+ REM Boot flow:
8
+ REM 1. Auto-login (no password)
9
+ REM 2. This script runs INSTEAD of explorer.exe
10
+ REM 3. Reads slug + browser from agent.config.json (THE ONLY SOURCE)
11
+ REM 4. Waits for agent service (port 3403)
12
+ REM 5. Launches Chrome fullscreen
13
+ REM 6. If Chrome crashes, relaunches in 3 seconds (infinite loop)
14
+ REM ================================================================
15
+
16
+ set INSTALL_DIR=C:\Program Files\Lightman\Agent
17
+ set CONFIG_FILE=%INSTALL_DIR%\agent.config.json
18
+ set CHROME_DATA=C:\ProgramData\Lightman\chrome-kiosk
19
+ set LOG_FILE=C:\ProgramData\Lightman\logs\shell.log
20
+
21
+ REM Ensure directories exist
22
+ if not exist "C:\ProgramData\Lightman\logs" mkdir "C:\ProgramData\Lightman\logs"
23
+ if not exist "%CHROME_DATA%" mkdir "%CHROME_DATA%"
24
+
25
+ echo [%date% %time%] ===== LIGHTMAN Shell starting ===== >> "%LOG_FILE%"
26
+
27
+ REM ----------------------------------------------------------------
28
+ REM Read slug and browser from agent.config.json ONLY
29
+ REM No sidecar files, no hardcoded URLs, no confusion.
30
+ REM ----------------------------------------------------------------
31
+ set DEVICE_SLUG=
32
+ set BROWSER=
33
+ set URL=
34
+
35
+ REM Wait for node.exe to be available
36
+ set NODE_WAIT=0
37
+ :wait_for_node
38
+ where node >nul 2>&1
39
+ if %errorlevel%==0 goto node_ready
40
+ set /a NODE_WAIT+=1
41
+ if %NODE_WAIT% geq 30 (
42
+ echo [%date% %time%] ERROR: node.exe not found after 30s >> "%LOG_FILE%"
43
+ goto use_fallbacks
44
+ )
45
+ timeout /t 1 /nobreak >nul
46
+ goto wait_for_node
47
+
48
+ :node_ready
49
+
50
+ REM Read slug from config
51
+ if exist "%CONFIG_FILE%" (
52
+ for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do set DEVICE_SLUG=%%a
53
+ )
54
+
55
+ REM Read browser from config
56
+ if exist "%CONFIG_FILE%" (
57
+ for /f "delims=" %%a in ('node -e "try{const c=JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8'));console.log(c.kiosk&&c.kiosk.browserPath||'')}catch(e){console.log('')}" 2^>nul') do set BROWSER=%%a
58
+ )
59
+
60
+ :use_fallbacks
61
+
62
+ REM Build URL from slug (ALWAYS from config, never from sidecar)
63
+ if not "%DEVICE_SLUG%"=="" (
64
+ set URL=http://localhost:3403/display/%DEVICE_SLUG%
65
+ echo [%date% %time%] Slug: %DEVICE_SLUG% >> "%LOG_FILE%"
66
+ ) else (
67
+ set URL=http://localhost:3403/display
68
+ echo [%date% %time%] WARNING: No slug in config! >> "%LOG_FILE%"
69
+ )
70
+
71
+ REM Fallback browser
72
+ if "%BROWSER%"=="" (
73
+ if exist "C:\Program Files\Google\Chrome\Application\chrome.exe" (
74
+ set "BROWSER=C:\Program Files\Google\Chrome\Application\chrome.exe"
75
+ ) else if exist "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" (
76
+ set "BROWSER=C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
77
+ ) else (
78
+ echo [%date% %time%] ERROR: Chrome not found! >> "%LOG_FILE%"
79
+ start explorer.exe
80
+ exit /b 1
81
+ )
82
+ )
83
+
84
+ echo [%date% %time%] Browser: %BROWSER% >> "%LOG_FILE%"
85
+ echo [%date% %time%] URL: %URL% >> "%LOG_FILE%"
86
+
87
+ REM ----------------------------------------------------------------
88
+ REM Wait for agent service (port 3403)
89
+ REM ----------------------------------------------------------------
90
+ echo [%date% %time%] Waiting for port 3403... >> "%LOG_FILE%"
91
+ set WAIT_COUNT=0
92
+ set MAX_WAIT=60
93
+
94
+ :wait_for_agent
95
+ netstat -an | findstr ":3403.*LISTENING" >nul 2>&1
96
+ if %errorlevel%==0 goto agent_ready
97
+ set /a WAIT_COUNT+=1
98
+ if %WAIT_COUNT% geq %MAX_WAIT% (
99
+ echo [%date% %time%] Port 3403 not ready after %MAX_WAIT%s, launching anyway >> "%LOG_FILE%"
100
+ goto agent_ready
101
+ )
102
+ timeout /t 1 /nobreak >nul
103
+ goto wait_for_agent
104
+
105
+ :agent_ready
106
+ echo [%date% %time%] Agent ready >> "%LOG_FILE%"
107
+
108
+ REM ----------------------------------------------------------------
109
+ REM Infinite Chrome loop
110
+ REM ----------------------------------------------------------------
111
+ :loop
112
+ REM Re-read slug from config on every loop iteration
113
+ REM This way if someone changes agent.config.json, the next
114
+ REM Chrome restart picks up the new slug automatically.
115
+ if exist "%CONFIG_FILE%" (
116
+ for /f "delims=" %%a in ('node -e "try{console.log(JSON.parse(require('fs').readFileSync(String.raw`%CONFIG_FILE%`,'utf8')).deviceSlug)}catch(e){console.log('')}" 2^>nul') do (
117
+ if not "%%a"=="" set URL=http://localhost:3403/display/%%a
118
+ )
119
+ )
120
+
121
+ echo [%date% %time%] Launching Chrome: %URL% >> "%LOG_FILE%"
122
+
123
+ start /wait "" "%BROWSER%" --kiosk --noerrdialogs --disable-infobars --disable-session-crashed-bubble --no-first-run --no-default-browser-check --start-fullscreen --disable-translate --disable-extensions --autoplay-policy=no-user-gesture-required --disable-features=TranslateUI --user-data-dir="%CHROME_DATA%" "%URL%"
124
+
125
+ echo [%date% %time%] Chrome exited (code: %errorlevel%). Restarting in 3s... >> "%LOG_FILE%"
126
+ timeout /t 3 /nobreak >nul
127
+
128
+ goto loop