@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.
- package/LICENSE +21 -0
- package/README.md +212 -0
- package/assets/dictate-listening.ico +0 -0
- package/assets/dictate-listening.png +0 -0
- package/assets/dictate.ico +0 -0
- package/assets/dictate.png +0 -0
- package/config/default-config.yaml +17 -0
- package/install-windows-wizard.ps1 +547 -0
- package/install-windows.ps1 +422 -0
- package/install.ps1 +87 -0
- package/install.sh +303 -0
- package/npm/dictate-lifecycle.mjs +49 -0
- package/package.json +50 -0
- package/uninstall-windows.ps1 +83 -0
- package/uninstall.ps1 +51 -0
- package/uninstall.sh +117 -0
- package/update-windows.ps1 +70 -0
- package/update.ps1 +115 -0
- package/update.sh +34 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[switch]$NoVerify,
|
|
3
|
+
[switch]$NoPrepareTurbo,
|
|
4
|
+
[switch]$NoShortcut,
|
|
5
|
+
[switch]$NoStartup,
|
|
6
|
+
[switch]$ForceStartup,
|
|
7
|
+
[switch]$RecreateVenv,
|
|
8
|
+
[switch]$SkipGitPull
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
$ErrorActionPreference = "Stop"
|
|
12
|
+
|
|
13
|
+
function Get-StartMenuProgramsDir {
|
|
14
|
+
$programsDir = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs"
|
|
15
|
+
if (-not $env:APPDATA) {
|
|
16
|
+
$programsDir = Join-Path $HOME "AppData\Roaming\Microsoft\Windows\Start Menu\Programs"
|
|
17
|
+
}
|
|
18
|
+
return $programsDir
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function Remove-LegacyEntries {
|
|
22
|
+
$programsDir = Get-StartMenuProgramsDir
|
|
23
|
+
Remove-Item -Force -ErrorAction SilentlyContinue -Path (Join-Path $programsDir "Dictate Controls.lnk")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function Get-StartupShortcutPath {
|
|
27
|
+
$programsDir = Get-StartMenuProgramsDir
|
|
28
|
+
return (Join-Path (Join-Path $programsDir "Startup") "Dictate.lnk")
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function Stop-DictateProcesses {
|
|
32
|
+
$currentPid = $PID
|
|
33
|
+
$matches = Get-CimInstance Win32_Process |
|
|
34
|
+
Where-Object {
|
|
35
|
+
$_.ProcessId -ne $currentPid -and (
|
|
36
|
+
$_.Name -in @("dictate.exe", "dictate-controls.exe") -or
|
|
37
|
+
$_.CommandLine -like '*dictate.exe* --type-backend pynput*' -or
|
|
38
|
+
$_.CommandLine -like '*pythonw.exe* -m dictate --type-backend pynput*' -or
|
|
39
|
+
$_.CommandLine -like '*dictate-daemon.cmd*' -or
|
|
40
|
+
$_.CommandLine -like '*dictate-controls*'
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
foreach ($match in $matches) {
|
|
44
|
+
Stop-Process -Id $match.ProcessId -Force -ErrorAction SilentlyContinue
|
|
45
|
+
}
|
|
46
|
+
Start-Sleep -Milliseconds 500
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if ((-not $SkipGitPull) -and (Test-Path (Join-Path $PSScriptRoot ".git"))) {
|
|
50
|
+
Write-Host "==> Updating source checkout"
|
|
51
|
+
& git -C $PSScriptRoot pull --ff-only
|
|
52
|
+
if ($LASTEXITCODE -ne 0) {
|
|
53
|
+
throw "git pull failed with exit code $LASTEXITCODE."
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Remove-LegacyEntries
|
|
58
|
+
Stop-DictateProcesses
|
|
59
|
+
|
|
60
|
+
$installerArgs = @("-ExecutionPolicy", "Bypass", "-File", (Join-Path $PSScriptRoot "install-windows.ps1"))
|
|
61
|
+
if ($NoVerify) { $installerArgs += "-NoVerify" }
|
|
62
|
+
if ($NoPrepareTurbo) { $installerArgs += "-NoPrepareTurbo" }
|
|
63
|
+
if ($NoShortcut) { $installerArgs += "-NoShortcut" }
|
|
64
|
+
if ($NoStartup -or ((-not $ForceStartup) -and (-not (Test-Path (Get-StartupShortcutPath))))) { $installerArgs += "-NoStartup" }
|
|
65
|
+
if ($RecreateVenv) { $installerArgs += "-RecreateVenv" }
|
|
66
|
+
|
|
67
|
+
& powershell @installerArgs
|
|
68
|
+
if ($LASTEXITCODE -ne 0) {
|
|
69
|
+
throw "Dictate Windows update failed with exit code $LASTEXITCODE."
|
|
70
|
+
}
|
package/update.ps1
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[string]$InstallRoot,
|
|
3
|
+
[string]$ArchiveUrl,
|
|
4
|
+
[switch]$NoVerify,
|
|
5
|
+
[switch]$NoPrepareTurbo,
|
|
6
|
+
[switch]$NoShortcut,
|
|
7
|
+
[switch]$NoStartup,
|
|
8
|
+
[switch]$ForceStartup,
|
|
9
|
+
[switch]$RecreateVenv
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
$ErrorActionPreference = "Stop"
|
|
13
|
+
$DictateVersion = "2026.6.3"
|
|
14
|
+
|
|
15
|
+
if (-not $ArchiveUrl) {
|
|
16
|
+
$ArchiveUrl = "https://github.com/arcforgelabs/dictate/archive/refs/tags/v$DictateVersion.zip"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (-not $InstallRoot) {
|
|
20
|
+
$currentDirectory = [System.IO.Directory]::GetCurrentDirectory()
|
|
21
|
+
$candidateSource = Join-Path $currentDirectory "source"
|
|
22
|
+
if (
|
|
23
|
+
(Test-Path (Join-Path $candidateSource "update-windows.ps1")) -and
|
|
24
|
+
(Test-Path (Join-Path $candidateSource "pyproject.toml")) -and
|
|
25
|
+
(Test-Path (Join-Path $candidateSource "src\dictate"))
|
|
26
|
+
) {
|
|
27
|
+
$InstallRoot = $currentDirectory
|
|
28
|
+
} else {
|
|
29
|
+
$base = $env:LOCALAPPDATA
|
|
30
|
+
if (-not $base) {
|
|
31
|
+
$base = Join-Path $HOME "AppData\Local"
|
|
32
|
+
}
|
|
33
|
+
$InstallRoot = Join-Path $base "Dictate"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
$installRootPath = [System.IO.Path]::GetFullPath($InstallRoot)
|
|
38
|
+
$sourceDir = Join-Path $installRootPath "source"
|
|
39
|
+
$stagingRoot = Join-Path $env:TEMP ("dictate-update-" + [guid]::NewGuid().ToString("N"))
|
|
40
|
+
$archivePath = Join-Path $stagingRoot "dictate.zip"
|
|
41
|
+
|
|
42
|
+
function Stop-DictateProcesses {
|
|
43
|
+
$currentPid = $PID
|
|
44
|
+
$matches = Get-CimInstance Win32_Process |
|
|
45
|
+
Where-Object {
|
|
46
|
+
$_.ProcessId -ne $currentPid -and (
|
|
47
|
+
$_.Name -in @("dictate.exe", "dictate-controls.exe") -or
|
|
48
|
+
$_.CommandLine -like '*dictate.exe* --type-backend pynput*' -or
|
|
49
|
+
$_.CommandLine -like '*pythonw.exe* -m dictate --type-backend pynput*' -or
|
|
50
|
+
$_.CommandLine -like '*dictate-daemon.cmd*' -or
|
|
51
|
+
$_.CommandLine -like '*dictate-controls*'
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
foreach ($match in $matches) {
|
|
55
|
+
Stop-Process -Id $match.ProcessId -Force -ErrorAction SilentlyContinue
|
|
56
|
+
}
|
|
57
|
+
Start-Sleep -Milliseconds 500
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Write-Host "==> Updating Dictate in $installRootPath"
|
|
61
|
+
New-Item -ItemType Directory -Force -Path $stagingRoot | Out-Null
|
|
62
|
+
New-Item -ItemType Directory -Force -Path $installRootPath | Out-Null
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
if (Test-Path -LiteralPath $ArchiveUrl) {
|
|
66
|
+
Write-Host "==> Copying local archive $ArchiveUrl"
|
|
67
|
+
Copy-Item -Force -LiteralPath $ArchiveUrl -Destination $archivePath
|
|
68
|
+
} else {
|
|
69
|
+
Write-Host "==> Downloading $ArchiveUrl"
|
|
70
|
+
Invoke-WebRequest -UseBasicParsing -Uri $ArchiveUrl -OutFile $archivePath
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Write-Host "==> Expanding source archive"
|
|
74
|
+
Expand-Archive -Force -Path $archivePath -DestinationPath $stagingRoot
|
|
75
|
+
$expanded = Get-ChildItem -Path $stagingRoot -Directory |
|
|
76
|
+
Where-Object { Test-Path (Join-Path $_.FullName "update-windows.ps1") } |
|
|
77
|
+
Select-Object -First 1
|
|
78
|
+
if (-not $expanded) {
|
|
79
|
+
throw "Downloaded archive did not contain update-windows.ps1."
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (Test-Path $sourceDir) {
|
|
83
|
+
Stop-DictateProcesses
|
|
84
|
+
Write-Host "==> Replacing existing managed source: $sourceDir"
|
|
85
|
+
Remove-Item -Recurse -Force $sourceDir
|
|
86
|
+
}
|
|
87
|
+
Move-Item -Path $expanded.FullName -Destination $sourceDir
|
|
88
|
+
|
|
89
|
+
$updaterArgs = @(
|
|
90
|
+
"-ExecutionPolicy",
|
|
91
|
+
"Bypass",
|
|
92
|
+
"-File",
|
|
93
|
+
(Join-Path $sourceDir "update-windows.ps1"),
|
|
94
|
+
"-SkipGitPull"
|
|
95
|
+
)
|
|
96
|
+
if ($NoVerify) { $updaterArgs += "-NoVerify" }
|
|
97
|
+
if ($NoPrepareTurbo) { $updaterArgs += "-NoPrepareTurbo" }
|
|
98
|
+
if ($NoShortcut) { $updaterArgs += "-NoShortcut" }
|
|
99
|
+
if ($NoStartup) { $updaterArgs += "-NoStartup" }
|
|
100
|
+
if ($ForceStartup) { $updaterArgs += "-ForceStartup" }
|
|
101
|
+
if ($RecreateVenv) { $updaterArgs += "-RecreateVenv" }
|
|
102
|
+
|
|
103
|
+
Write-Host "==> Running Dictate Windows updater"
|
|
104
|
+
& powershell @updaterArgs
|
|
105
|
+
if ($LASTEXITCODE -ne 0) {
|
|
106
|
+
throw "Dictate Windows updater failed with exit code $LASTEXITCODE."
|
|
107
|
+
}
|
|
108
|
+
} finally {
|
|
109
|
+
if (Test-Path $stagingRoot) {
|
|
110
|
+
Remove-Item -Recurse -Force $stagingRoot
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
Write-Host ""
|
|
115
|
+
Write-Host "Dictate updated from: $sourceDir"
|
package/update.sh
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Update Dictate and migrate old launcher/icon names from previous installs.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
6
|
+
INSTALL_DIR="$HOME/.local/share/dictate"
|
|
7
|
+
DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
|
|
8
|
+
AUTOSTART_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/autostart"
|
|
9
|
+
ICON_DIR="$INSTALL_DIR/share/icons"
|
|
10
|
+
AUTOSTART_PATH="$AUTOSTART_DIR/dictate.desktop"
|
|
11
|
+
|
|
12
|
+
cleanup_legacy_entries() {
|
|
13
|
+
rm -f "$DESKTOP_DIR/dictate-settings.desktop"
|
|
14
|
+
rm -f "$ICON_DIR/dictate-controls.png" "$ICON_DIR/dictate.png"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if [ -d "$SCRIPT_DIR/.git" ]; then
|
|
18
|
+
git -C "$SCRIPT_DIR" pull --ff-only
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
cleanup_legacy_entries
|
|
22
|
+
|
|
23
|
+
args=("$@")
|
|
24
|
+
startup_option_seen=0
|
|
25
|
+
for arg in "${args[@]}"; do
|
|
26
|
+
if [ "$arg" = "--no-startup" ]; then
|
|
27
|
+
startup_option_seen=1
|
|
28
|
+
fi
|
|
29
|
+
done
|
|
30
|
+
if [ "$startup_option_seen" -eq 0 ] && [ ! -e "$AUTOSTART_PATH" ]; then
|
|
31
|
+
args+=("--no-startup")
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
"$SCRIPT_DIR/install.sh" "${args[@]}"
|