@arcforgelabs/dictate 2026.6.3

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.
@@ -0,0 +1,547 @@
1
+ param(
2
+ [string]$InitialAction = "Install"
3
+ )
4
+
5
+ $ErrorActionPreference = "Stop"
6
+ $TermsUrl = "https://arcforge.au/terms"
7
+ $DocumentationUrl = "https://github.com/arcforgelabs/dictate#readme"
8
+ $HostedWindowsUpdateUrl = "https://cdn.jsdelivr.net/npm/@arcforgelabs/dictate@latest/update.ps1"
9
+
10
+ Add-Type -AssemblyName System.Windows.Forms
11
+ Add-Type -AssemblyName System.Drawing
12
+
13
+ function New-ActionRadio {
14
+ param(
15
+ [string]$Text,
16
+ [string]$Tag,
17
+ [int]$Top,
18
+ [bool]$Checked = $false
19
+ )
20
+ $radio = New-Object System.Windows.Forms.RadioButton
21
+ $radio.Text = $Text
22
+ $radio.Tag = $Tag
23
+ $radio.Left = 18
24
+ $radio.Top = $Top
25
+ $radio.Width = 430
26
+ $radio.Checked = $Checked
27
+ return $radio
28
+ }
29
+
30
+ function Get-SelectedAction {
31
+ foreach ($control in $actionsGroup.Controls) {
32
+ if ($control.Checked) {
33
+ return [string]$control.Tag
34
+ }
35
+ }
36
+ return "Install"
37
+ }
38
+
39
+ function Append-Log {
40
+ param([string]$Message)
41
+ $logBox.AppendText($Message + [Environment]::NewLine)
42
+ $logBox.SelectionStart = $logBox.TextLength
43
+ $logBox.ScrollToCaret()
44
+ }
45
+
46
+ function Open-ExternalUrl {
47
+ param([string]$Url)
48
+ Start-Process $Url
49
+ }
50
+
51
+ function Sync-RunButton {
52
+ if ($null -ne $runButton) {
53
+ $runButton.Enabled = $termsCheck.Checked
54
+ }
55
+ }
56
+
57
+ function Sync-ShortcutOptions {
58
+ if ($null -ne $startupCheck) {
59
+ if ($shortcutCheck.Checked) {
60
+ $startupCheck.Enabled = $true
61
+ } else {
62
+ $startupCheck.Checked = $false
63
+ $startupCheck.Enabled = $false
64
+ }
65
+ }
66
+ }
67
+
68
+ function Get-StartMenuProgramsDir {
69
+ $programsDir = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs"
70
+ if (-not $env:APPDATA) {
71
+ $programsDir = Join-Path $HOME "AppData\Roaming\Microsoft\Windows\Start Menu\Programs"
72
+ }
73
+ return $programsDir
74
+ }
75
+
76
+ function Get-StartupShortcutPath {
77
+ return (Join-Path (Join-Path (Get-StartMenuProgramsDir) "Startup") "Dictate.lnk")
78
+ }
79
+
80
+ function Drain-LogQueue {
81
+ param($Queue)
82
+ $line = $null
83
+ while ($Queue.TryDequeue([ref]$line)) {
84
+ Append-Log $line
85
+ $line = $null
86
+ }
87
+ }
88
+
89
+ function Invoke-LoggedProcess {
90
+ param(
91
+ [string]$Label,
92
+ [string]$FileName,
93
+ [string]$ArgumentString,
94
+ [string]$WorkingDirectory = $PSScriptRoot
95
+ )
96
+
97
+ Append-Log "==> $Label"
98
+ $psi = New-Object System.Diagnostics.ProcessStartInfo
99
+ $psi.FileName = $FileName
100
+ $psi.Arguments = $ArgumentString
101
+ $psi.WorkingDirectory = $WorkingDirectory
102
+ $psi.UseShellExecute = $false
103
+ $psi.RedirectStandardOutput = $true
104
+ $psi.RedirectStandardError = $true
105
+ $psi.CreateNoWindow = $true
106
+
107
+ $stdoutQueue = New-Object "System.Collections.Concurrent.ConcurrentQueue[string]"
108
+ $stderrQueue = New-Object "System.Collections.Concurrent.ConcurrentQueue[string]"
109
+ $stdoutHandler = [System.Diagnostics.DataReceivedEventHandler]{
110
+ param($sender, $eventArgs)
111
+ if ($null -ne $eventArgs.Data) {
112
+ $stdoutQueue.Enqueue($eventArgs.Data)
113
+ }
114
+ }
115
+ $stderrHandler = [System.Diagnostics.DataReceivedEventHandler]{
116
+ param($sender, $eventArgs)
117
+ if ($null -ne $eventArgs.Data) {
118
+ $stderrQueue.Enqueue($eventArgs.Data)
119
+ }
120
+ }
121
+
122
+ $process = New-Object System.Diagnostics.Process
123
+ $process.StartInfo = $psi
124
+ $process.add_OutputDataReceived($stdoutHandler)
125
+ $process.add_ErrorDataReceived($stderrHandler)
126
+ try {
127
+ [void]$process.Start()
128
+ $process.BeginOutputReadLine()
129
+ $process.BeginErrorReadLine()
130
+ while (-not $process.WaitForExit(100)) {
131
+ Drain-LogQueue $stdoutQueue
132
+ Drain-LogQueue $stderrQueue
133
+ [System.Windows.Forms.Application]::DoEvents()
134
+ }
135
+ $process.WaitForExit()
136
+ Drain-LogQueue $stdoutQueue
137
+ Drain-LogQueue $stderrQueue
138
+ if ($process.ExitCode -ne 0) {
139
+ throw "$Label failed with exit code $($process.ExitCode)."
140
+ }
141
+ } finally {
142
+ $process.remove_OutputDataReceived($stdoutHandler)
143
+ $process.remove_ErrorDataReceived($stderrHandler)
144
+ $process.Dispose()
145
+ }
146
+ }
147
+
148
+ function Invoke-Step {
149
+ param(
150
+ [string]$Label,
151
+ [string]$FilePath,
152
+ [string[]]$Arguments,
153
+ [string]$WorkingDirectory = $PSScriptRoot
154
+ )
155
+
156
+ $argumentString = (
157
+ @("-NoProfile", "-ExecutionPolicy", "Bypass", "-File", "`"$FilePath`"") + $Arguments
158
+ ) -join " "
159
+ Invoke-LoggedProcess -Label $Label -FileName "powershell" -ArgumentString $argumentString -WorkingDirectory $WorkingDirectory
160
+ }
161
+
162
+ function Invoke-DictateUpdate {
163
+ param([string[]]$Arguments)
164
+
165
+ if (Test-Path (Join-Path $PSScriptRoot ".git")) {
166
+ Invoke-Step "Updating Dictate" (Join-Path $PSScriptRoot "update-windows.ps1") $Arguments
167
+ return
168
+ }
169
+
170
+ $tempUpdater = Join-Path ([System.IO.Path]::GetTempPath()) ("dictate-update-" + [guid]::NewGuid().ToString("N") + ".ps1")
171
+ try {
172
+ Append-Log "==> Fetching current hosted updater"
173
+ Invoke-WebRequest -UseBasicParsing -Uri $HostedWindowsUpdateUrl -OutFile $tempUpdater
174
+ $workingDirectory = Split-Path -Parent $PSScriptRoot
175
+ Invoke-Step -Label "Updating Dictate from hosted source" -FilePath $tempUpdater -Arguments $Arguments -WorkingDirectory $workingDirectory
176
+ } finally {
177
+ Remove-Item -Force -ErrorAction SilentlyContinue -Path $tempUpdater
178
+ }
179
+ }
180
+
181
+ function Invoke-DictateDoctorFix {
182
+ $dictateExe = Join-Path $PSScriptRoot ".venv\Scripts\dictate.exe"
183
+ if (-not (Test-Path $dictateExe)) {
184
+ throw "Dictate is not installed in this source folder. Run Install first."
185
+ }
186
+
187
+ Invoke-LoggedProcess "Repairing Dictate with doctor --fix" $dictateExe "doctor --quick --fix --type-backend pynput"
188
+ }
189
+
190
+ function Start-SelectedAction {
191
+ $runButton.Enabled = $false
192
+ $closeButton.Enabled = $false
193
+ $logBox.Clear()
194
+ try {
195
+ if (-not $termsCheck.Checked) {
196
+ throw "Please acknowledge the Dictate terms before continuing."
197
+ }
198
+ $action = Get-SelectedAction
199
+ $commonArgs = @()
200
+ if (-not $verifyCheck.Checked) { $commonArgs += "-NoVerify" }
201
+ if (-not $prepareCheck.Checked) { $commonArgs += "-NoPrepareTurbo" }
202
+ if (-not $shortcutCheck.Checked) { $commonArgs += "-NoShortcut" }
203
+ if (-not $startupCheck.Checked) { $commonArgs += "-NoStartup" }
204
+
205
+ if ($action -eq "Install") {
206
+ Invoke-Step "Installing Dictate" (Join-Path $PSScriptRoot "install-windows.ps1") $commonArgs
207
+ } elseif ($action -eq "Update") {
208
+ $updateArgs = @($commonArgs)
209
+ if ($startupCheck.Checked) { $updateArgs += "-ForceStartup" }
210
+ Invoke-DictateUpdate $updateArgs
211
+ } elseif ($action -eq "Repair") {
212
+ Invoke-DictateDoctorFix
213
+ } elseif ($action -eq "Uninstall") {
214
+ $uninstallArgs = @()
215
+ if ($removeUserDataCheck.Checked) { $uninstallArgs += "-RemoveUserData" }
216
+ Invoke-Step "Uninstalling Dictate" (Join-Path $PSScriptRoot "uninstall-windows.ps1") $uninstallArgs
217
+ }
218
+ Append-Log ""
219
+ Append-Log "Done."
220
+ [System.Windows.Forms.MessageBox]::Show(
221
+ "Dictate $($action.ToLowerInvariant()) completed.",
222
+ "Dictate Setup",
223
+ [System.Windows.Forms.MessageBoxButtons]::OK,
224
+ [System.Windows.Forms.MessageBoxIcon]::Information
225
+ ) | Out-Null
226
+ } catch {
227
+ Append-Log ""
228
+ Append-Log "ERROR: $($_.Exception.Message)"
229
+ [System.Windows.Forms.MessageBox]::Show(
230
+ $_.Exception.Message,
231
+ "Dictate Setup",
232
+ [System.Windows.Forms.MessageBoxButtons]::OK,
233
+ [System.Windows.Forms.MessageBoxIcon]::Error
234
+ ) | Out-Null
235
+ } finally {
236
+ Sync-RunButton
237
+ $closeButton.Enabled = $true
238
+ }
239
+ }
240
+
241
+ $paper = [System.Drawing.Color]::FromArgb(239, 236, 230)
242
+ $surface = [System.Drawing.Color]::FromArgb(255, 255, 255)
243
+ $surface2 = [System.Drawing.Color]::FromArgb(247, 245, 241)
244
+ $surface3 = [System.Drawing.Color]::FromArgb(240, 237, 231)
245
+ $ink = [System.Drawing.Color]::FromArgb(27, 26, 22)
246
+ $muted = [System.Drawing.Color]::FromArgb(105, 101, 91)
247
+ $subtle = [System.Drawing.Color]::FromArgb(145, 139, 126)
248
+ $hairline = [System.Drawing.Color]::FromArgb(232, 228, 220)
249
+ $live = [System.Drawing.Color]::FromArgb(47, 143, 99)
250
+ $danger = [System.Drawing.Color]::FromArgb(197, 64, 44)
251
+
252
+ function New-UiFont {
253
+ param([float]$Size, [System.Drawing.FontStyle]$Style = [System.Drawing.FontStyle]::Regular)
254
+ return New-Object System.Drawing.Font("Segoe UI Variable Text", $Size, $Style)
255
+ }
256
+
257
+ function New-Panel {
258
+ param([int]$Left, [int]$Top, [int]$Width, [int]$Height, [System.Drawing.Color]$BackColor = $surface)
259
+ $panel = New-Object System.Windows.Forms.Panel
260
+ $panel.Left = $Left
261
+ $panel.Top = $Top
262
+ $panel.Width = $Width
263
+ $panel.Height = $Height
264
+ $panel.BackColor = $BackColor
265
+ return $panel
266
+ }
267
+
268
+ function New-Label {
269
+ param(
270
+ [string]$Text,
271
+ [int]$Left,
272
+ [int]$Top,
273
+ [int]$Width,
274
+ [int]$Height,
275
+ [float]$Size = 9,
276
+ [System.Drawing.FontStyle]$Style = [System.Drawing.FontStyle]::Regular,
277
+ [System.Drawing.Color]$Color = $ink
278
+ )
279
+ $label = New-Object System.Windows.Forms.Label
280
+ $label.Text = $Text
281
+ $label.Left = $Left
282
+ $label.Top = $Top
283
+ $label.Width = $Width
284
+ $label.Height = $Height
285
+ $label.Font = New-UiFont $Size $Style
286
+ $label.ForeColor = $Color
287
+ $label.BackColor = [System.Drawing.Color]::Transparent
288
+ return $label
289
+ }
290
+
291
+ $form = New-Object System.Windows.Forms.Form
292
+ $form.Text = "Dictate Setup"
293
+ $form.StartPosition = "CenterScreen"
294
+ $form.ClientSize = New-Object System.Drawing.Size(476, 596)
295
+ $form.FormBorderStyle = "FixedDialog"
296
+ $form.MaximizeBox = $false
297
+ $form.BackColor = $paper
298
+ $form.Font = New-UiFont 9
299
+
300
+ $window = New-Panel 18 18 440 560 $surface
301
+ $window.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
302
+ $form.Controls.Add($window)
303
+
304
+ $titleBar = New-Panel 0 0 440 40 $surface2
305
+ $window.Controls.Add($titleBar)
306
+
307
+ $mark = New-Label "A" 14 10 18 18 9 ([System.Drawing.FontStyle]::Bold) $ink
308
+ $mark.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
309
+ $titleBar.Controls.Add($mark)
310
+
311
+ $chromeTitle = New-Label "Dictate" 40 9 62 18 9 ([System.Drawing.FontStyle]::Bold) $ink
312
+ $titleBar.Controls.Add($chromeTitle)
313
+ $chromeMeta = New-Label "Setup" 102 10 80 18 8.5 ([System.Drawing.FontStyle]::Regular) $subtle
314
+ $titleBar.Controls.Add($chromeMeta)
315
+
316
+ $minButton = New-Object System.Windows.Forms.Button
317
+ $minButton.Text = "-"
318
+ $minButton.Left = 344
319
+ $minButton.Top = 7
320
+ $minButton.Width = 28
321
+ $minButton.Height = 24
322
+ $minButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
323
+ $minButton.FlatAppearance.BorderSize = 0
324
+ $minButton.BackColor = $surface2
325
+ $minButton.ForeColor = $muted
326
+ $minButton.Add_Click({ $form.WindowState = [System.Windows.Forms.FormWindowState]::Minimized })
327
+ $titleBar.Controls.Add($minButton)
328
+
329
+ $closeChromeButton = New-Object System.Windows.Forms.Button
330
+ $closeChromeButton.Text = "x"
331
+ $closeChromeButton.Left = 402
332
+ $closeChromeButton.Top = 7
333
+ $closeChromeButton.Width = 28
334
+ $closeChromeButton.Height = 24
335
+ $closeChromeButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
336
+ $closeChromeButton.FlatAppearance.BorderSize = 0
337
+ $closeChromeButton.BackColor = $surface2
338
+ $closeChromeButton.ForeColor = $muted
339
+ $closeChromeButton.Add_Click({ $form.Close() })
340
+ $titleBar.Controls.Add($closeChromeButton)
341
+
342
+ $hero = New-Panel 0 40 440 128 $surface
343
+ $window.Controls.Add($hero)
344
+
345
+ $orb = New-Panel 28 32 58 58 $surface2
346
+ $orb.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
347
+ $hero.Controls.Add($orb)
348
+ $orbIcon = New-Label "D" 0 13 56 30 18 ([System.Drawing.FontStyle]::Bold) $ink
349
+ $orbIcon.TextAlign = [System.Drawing.ContentAlignment]::MiddleCenter
350
+ $orb.Controls.Add($orbIcon)
351
+
352
+ $eyebrow = New-Label "SETUP" 108 27 80 18 7.5 ([System.Drawing.FontStyle]::Bold) $subtle
353
+ $hero.Controls.Add($eyebrow)
354
+ $title = New-Label "Dictate" 108 48 250 30 17 ([System.Drawing.FontStyle]::Bold) $ink
355
+ $hero.Controls.Add($title)
356
+ $subtitle = New-Label "Type as fast as you can speak." 108 82 270 24 10 ([System.Drawing.FontStyle]::Regular) $muted
357
+ $hero.Controls.Add($subtitle)
358
+
359
+ $trust = New-Panel 24 168 392 34 $surface
360
+ $trust.BorderStyle = [System.Windows.Forms.BorderStyle]::None
361
+ $window.Controls.Add($trust)
362
+ $trust.Controls.Add((New-Label "Arc Forge" 0 8 72 18 8.5 ([System.Drawing.FontStyle]::Bold) $ink))
363
+ $trust.Controls.Add((New-Label "- Verified publisher" 75 8 130 18 8.5 ([System.Drawing.FontStyle]::Regular) $muted))
364
+ $trust.Controls.Add((New-Label "local-first" 318 8 74 18 8 ([System.Drawing.FontStyle]::Regular) $subtle))
365
+
366
+ $actionsGroup = New-Panel 24 212 392 82 $surface2
367
+ $actionsGroup.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
368
+ $window.Controls.Add($actionsGroup)
369
+
370
+ $actionsLabel = New-Label "Action" 14 9 80 18 8 ([System.Drawing.FontStyle]::Bold) $subtle
371
+ $actionsGroup.Controls.Add($actionsLabel)
372
+
373
+ $actionsGroup.Controls.Add((New-ActionRadio "Install Dictate" "Install" 30 ($InitialAction -eq "Install")))
374
+ $actionsGroup.Controls.Add((New-ActionRadio "Update Dictate" "Update" 30 ($InitialAction -eq "Update")))
375
+ $actionsGroup.Controls[1].Left = 14
376
+ $actionsGroup.Controls[1].Width = 160
377
+ $actionsGroup.Controls[2].Left = 204
378
+ $actionsGroup.Controls[2].Width = 160
379
+ $actionsGroup.Controls.Add((New-ActionRadio "Repair launchers and runtime checks (doctor --fix)" "Repair" 54 ($InitialAction -eq "Repair")))
380
+ $actionsGroup.Controls.Add((New-ActionRadio "Uninstall Dictate" "Uninstall" 54 ($InitialAction -eq "Uninstall")))
381
+ $actionsGroup.Controls[3].Left = 14
382
+ $actionsGroup.Controls[3].Width = 320
383
+ $actionsGroup.Controls[4].Left = 204
384
+ $actionsGroup.Controls[4].Width = 160
385
+ foreach ($control in $actionsGroup.Controls) {
386
+ if ($control -is [System.Windows.Forms.RadioButton]) {
387
+ $control.BackColor = $surface2
388
+ $control.ForeColor = $ink
389
+ $control.Font = New-UiFont 8.5
390
+ }
391
+ }
392
+
393
+ $optionsGroup = New-Panel 24 306 392 122 $surface2
394
+ $optionsGroup.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
395
+ $window.Controls.Add($optionsGroup)
396
+
397
+ $optionsGroup.Controls.Add((New-Label "Advanced setup" 14 10 120 18 8 ([System.Drawing.FontStyle]::Bold) $subtle))
398
+
399
+ $startupCheck = New-Object System.Windows.Forms.CheckBox
400
+ $startupCheck.Text = "Launch on startup"
401
+ $startupCheck.Left = 14
402
+ $startupCheck.Top = 34
403
+ $startupCheck.Width = 170
404
+ $startupCheck.Checked = $true
405
+ $startupCheck.BackColor = $surface2
406
+ $startupCheck.ForeColor = $ink
407
+ $startupCheck.Font = New-UiFont 8.5
408
+ $optionsGroup.Controls.Add($startupCheck)
409
+ if ($InitialAction -eq "Update") {
410
+ $startupCheck.Checked = Test-Path (Get-StartupShortcutPath)
411
+ }
412
+
413
+ $shortcutCheck = New-Object System.Windows.Forms.CheckBox
414
+ $shortcutCheck.Text = "Create Start Menu entry"
415
+ $shortcutCheck.Left = 204
416
+ $shortcutCheck.Top = 34
417
+ $shortcutCheck.Width = 180
418
+ $shortcutCheck.Checked = $true
419
+ $shortcutCheck.BackColor = $surface2
420
+ $shortcutCheck.ForeColor = $ink
421
+ $shortcutCheck.Font = New-UiFont 8.5
422
+ $shortcutCheck.Add_CheckedChanged({ Sync-ShortcutOptions })
423
+ $optionsGroup.Controls.Add($shortcutCheck)
424
+
425
+ $prepareCheck = New-Object System.Windows.Forms.CheckBox
426
+ $prepareCheck.Text = "Prepare default local model"
427
+ $prepareCheck.Left = 14
428
+ $prepareCheck.Top = 61
429
+ $prepareCheck.Width = 190
430
+ $prepareCheck.Checked = $true
431
+ $prepareCheck.BackColor = $surface2
432
+ $prepareCheck.ForeColor = $ink
433
+ $prepareCheck.Font = New-UiFont 8.5
434
+ $optionsGroup.Controls.Add($prepareCheck)
435
+
436
+ $verifyCheck = New-Object System.Windows.Forms.CheckBox
437
+ $verifyCheck.Text = "Run verification"
438
+ $verifyCheck.Left = 204
439
+ $verifyCheck.Top = 61
440
+ $verifyCheck.Width = 150
441
+ $verifyCheck.Checked = $true
442
+ $verifyCheck.BackColor = $surface2
443
+ $verifyCheck.ForeColor = $ink
444
+ $verifyCheck.Font = New-UiFont 8.5
445
+ $optionsGroup.Controls.Add($verifyCheck)
446
+
447
+ $removeUserDataCheck = New-Object System.Windows.Forms.CheckBox
448
+ $removeUserDataCheck.Text = "Also remove user config, logs, history, and models"
449
+ $removeUserDataCheck.Left = 14
450
+ $removeUserDataCheck.Top = 88
451
+ $removeUserDataCheck.Width = 360
452
+ $removeUserDataCheck.Checked = $false
453
+ $removeUserDataCheck.BackColor = $surface2
454
+ $removeUserDataCheck.ForeColor = $ink
455
+ $removeUserDataCheck.Font = New-UiFont 8.5
456
+ $optionsGroup.Controls.Add($removeUserDataCheck)
457
+
458
+ $logBox = New-Object System.Windows.Forms.TextBox
459
+ $logBox.Left = 24
460
+ $logBox.Top = 438
461
+ $logBox.Width = 392
462
+ $logBox.Height = 62
463
+ $logBox.Multiline = $true
464
+ $logBox.ScrollBars = "Vertical"
465
+ $logBox.ReadOnly = $true
466
+ $logBox.BorderStyle = [System.Windows.Forms.BorderStyle]::FixedSingle
467
+ $logBox.BackColor = $surface3
468
+ $logBox.ForeColor = $muted
469
+ $logBox.Font = New-Object System.Drawing.Font("Consolas", 8)
470
+ $window.Controls.Add($logBox)
471
+
472
+ $footer = New-Panel 0 500 440 60 $surface2
473
+ $footer.Top = 500
474
+ $footer.Height = 60
475
+ $window.Controls.Add($footer)
476
+ $footer.SendToBack()
477
+
478
+ $termsCheck = New-Object System.Windows.Forms.CheckBox
479
+ $termsCheck.Text = "I understand Dictate has real-world risks and agree to the Arc Forge terms"
480
+ $termsCheck.Left = 24
481
+ $termsCheck.Top = 506
482
+ $termsCheck.Width = 322
483
+ $termsCheck.Checked = $false
484
+ $termsCheck.BackColor = $surface
485
+ $termsCheck.ForeColor = $muted
486
+ $termsCheck.Font = New-UiFont 7.8
487
+ $termsCheck.Add_CheckedChanged({ Sync-RunButton })
488
+ $window.Controls.Add($termsCheck)
489
+
490
+ $expectationLabel = New-Label "Support and maintenance are best-effort. Check important output and report issues." 42 526 330 16 7.5 ([System.Drawing.FontStyle]::Regular) $subtle
491
+ $window.Controls.Add($expectationLabel)
492
+
493
+ $termsLink = New-Object System.Windows.Forms.LinkLabel
494
+ $termsLink.Text = "Terms"
495
+ $termsLink.Left = 350
496
+ $termsLink.Top = 506
497
+ $termsLink.Width = 42
498
+ $termsLink.LinkColor = $muted
499
+ $termsLink.ActiveLinkColor = $ink
500
+ $termsLink.Font = New-UiFont 7.8
501
+ $termsLink.Add_Click({ Open-ExternalUrl $TermsUrl })
502
+ $window.Controls.Add($termsLink)
503
+
504
+ $docsLink = New-Object System.Windows.Forms.LinkLabel
505
+ $docsLink.Text = "Docs"
506
+ $docsLink.Left = 350
507
+ $docsLink.Top = 526
508
+ $docsLink.Width = 42
509
+ $docsLink.LinkColor = $muted
510
+ $docsLink.ActiveLinkColor = $ink
511
+ $docsLink.Font = New-UiFont 7.8
512
+ $docsLink.Add_Click({ Open-ExternalUrl $DocumentationUrl })
513
+ $window.Controls.Add($docsLink)
514
+
515
+ $runButton = New-Object System.Windows.Forms.Button
516
+ $runButton.Text = "Install"
517
+ $runButton.Left = 304
518
+ $runButton.Top = 526
519
+ $runButton.Width = 92
520
+ $runButton.Height = 30
521
+ $runButton.Enabled = $false
522
+ $runButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
523
+ $runButton.FlatAppearance.BorderSize = 0
524
+ $runButton.BackColor = $ink
525
+ $runButton.ForeColor = $surface
526
+ $runButton.Font = New-UiFont 8.5 ([System.Drawing.FontStyle]::Bold)
527
+ $runButton.Add_Click({ Start-SelectedAction })
528
+ $window.Controls.Add($runButton)
529
+
530
+ $closeButton = New-Object System.Windows.Forms.Button
531
+ $closeButton.Text = "Close"
532
+ $closeButton.Left = 218
533
+ $closeButton.Top = 526
534
+ $closeButton.Width = 76
535
+ $closeButton.Height = 30
536
+ $closeButton.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
537
+ $closeButton.FlatAppearance.BorderColor = $hairline
538
+ $closeButton.BackColor = $surface2
539
+ $closeButton.ForeColor = $muted
540
+ $closeButton.Font = New-UiFont 8.5
541
+ $closeButton.Add_Click({ $form.Close() })
542
+ $window.Controls.Add($closeButton)
543
+
544
+ Sync-ShortcutOptions
545
+ Sync-RunButton
546
+
547
+ [void]$form.ShowDialog()