@arcforgelabs/dictate 2026.6.18 → 2026.7.4
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/README.md +63 -42
- package/config/default-config.yaml +3 -1
- package/install-windows.ps1 +4 -2
- package/install.ps1 +1 -1
- package/install.sh +119 -18
- package/package.json +1 -1
- package/uninstall.sh +3 -0
- package/update.ps1 +1 -1
- package/update.sh +37 -1
package/README.md
CHANGED
|
@@ -6,18 +6,17 @@ Desktop dictation that types into the focused app.
|
|
|
6
6
|
speak, and it transcribes into whatever app you are already using.
|
|
7
7
|
|
|
8
8
|
Current status: early desktop app. Linux installs, Windows 11 source installs,
|
|
9
|
-
tray controls, startup integration,
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
tray controls, startup integration, local dictation history, update, and
|
|
10
|
+
uninstall paths are implemented. Microsoft Store packaging and submission
|
|
11
|
+
automation are maintained separately from GitHub releases; see `docs/GOALS.md`.
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
15
15
|
Windows 11 normal install:
|
|
16
16
|
|
|
17
|
-
The target public channel is Microsoft Store distribution.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
normal public install route.
|
|
17
|
+
The target public channel is Microsoft Store distribution. GitHub release
|
|
18
|
+
artifacts and the PowerShell bootstrap installer below are developer/source or
|
|
19
|
+
internal validation paths, not the normal public Windows install route.
|
|
21
20
|
|
|
22
21
|
Windows developer/source install from the hosted bootstrap:
|
|
23
22
|
|
|
@@ -27,13 +26,13 @@ powershell -ExecutionPolicy Bypass -Command "iwr -useb https://cdn.jsdelivr.net/
|
|
|
27
26
|
|
|
28
27
|
Open **Dictate** from the Start Menu after install.
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
Linux default install (per-user, no sudo for app updates):
|
|
31
30
|
|
|
32
31
|
```bash
|
|
33
32
|
./install-ubuntu.sh
|
|
34
33
|
```
|
|
35
34
|
|
|
36
|
-
Generic Linux
|
|
35
|
+
Generic Linux user install:
|
|
37
36
|
|
|
38
37
|
```bash
|
|
39
38
|
./install.sh
|
|
@@ -41,6 +40,14 @@ Generic Linux source install:
|
|
|
41
40
|
|
|
42
41
|
Open **Dictate** from the app launcher after install.
|
|
43
42
|
|
|
43
|
+
Linux system package install is also supported when you explicitly want a
|
|
44
|
+
machine-wide `.deb` install:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
DICTATE_BUNDLES=deb scripts/build-linux-desktop.sh
|
|
48
|
+
./install.sh --system
|
|
49
|
+
```
|
|
50
|
+
|
|
44
51
|
Windows developer/source install, from the repo/source directory:
|
|
45
52
|
|
|
46
53
|
```powershell
|
|
@@ -60,15 +67,13 @@ npx @arcforgelabs/dictate install
|
|
|
60
67
|
|
|
61
68
|
```text
|
|
62
69
|
Open Dictate
|
|
63
|
-
|
|
64
|
-
Set API key if using a hosted model
|
|
65
|
-
Set push-to-talk shortcut if desired
|
|
70
|
+
Use the mic button or configured push-to-talk shortcut
|
|
66
71
|
Hold shortcut, speak, release
|
|
67
|
-
Review
|
|
72
|
+
Review Dictations when needed
|
|
68
73
|
```
|
|
69
74
|
|
|
70
75
|
By default, Dictate installs a normal app launcher entry and starts on sign-in.
|
|
71
|
-
|
|
76
|
+
Advanced configuration is available through the `dictate config` CLI.
|
|
72
77
|
|
|
73
78
|
## Update And Uninstall
|
|
74
79
|
|
|
@@ -86,13 +91,19 @@ powershell -ExecutionPolicy Bypass -File .\update-windows.ps1
|
|
|
86
91
|
powershell -ExecutionPolicy Bypass -File .\uninstall-windows.ps1
|
|
87
92
|
```
|
|
88
93
|
|
|
89
|
-
Linux:
|
|
94
|
+
Linux user install:
|
|
90
95
|
|
|
91
96
|
```bash
|
|
92
97
|
./update.sh
|
|
93
98
|
./uninstall.sh
|
|
94
99
|
```
|
|
95
100
|
|
|
101
|
+
Linux system package update:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
./update.sh --system
|
|
105
|
+
```
|
|
106
|
+
|
|
96
107
|
Use `-RemoveUserData` on Windows or `--remove-user-data` on Linux only when you
|
|
97
108
|
also want to remove config, logs, history, and downloaded model data.
|
|
98
109
|
|
|
@@ -102,23 +113,18 @@ also want to remove config, logs, history, and downloaded model data.
|
|
|
102
113
|
- Runs as a tray app
|
|
103
114
|
- Types dictated text into the focused app
|
|
104
115
|
- Supports configurable push-to-talk
|
|
105
|
-
-
|
|
116
|
+
- Presents a simple capture-first desktop UI
|
|
106
117
|
- Supports launch on startup
|
|
107
|
-
- Stores hosted-provider API keys in the OS secret store
|
|
108
|
-
- Keeps a small
|
|
118
|
+
- Stores CLI-configured hosted-provider API keys in the OS secret store
|
|
119
|
+
- Keeps a small local dictations history for copy/paste recovery
|
|
109
120
|
- Provides installer, updater, uninstaller, and doctor paths
|
|
110
121
|
|
|
111
122
|
## Models
|
|
112
123
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- `xai/grok-speech-to-text`
|
|
118
|
-
- `gemini/gemini-3-flash-preview`
|
|
119
|
-
|
|
120
|
-
Local transcription can use CPU or GPU where supported. Hosted providers require
|
|
121
|
-
an API key before they can be selected.
|
|
124
|
+
The default path uses local faster-whisper transcription. The desktop UI keeps
|
|
125
|
+
model/provider choices out of the primary workflow. Advanced users and tests can
|
|
126
|
+
still configure explicit local or hosted providers through CLI options and
|
|
127
|
+
`dictate config`.
|
|
122
128
|
|
|
123
129
|
## Commands
|
|
124
130
|
|
|
@@ -132,11 +138,13 @@ dictate doctor --quick --fix
|
|
|
132
138
|
dictate doctor --check-model-load
|
|
133
139
|
```
|
|
134
140
|
|
|
135
|
-
|
|
136
|
-
automation and testing:
|
|
141
|
+
Advanced configuration remains available for automation and testing:
|
|
137
142
|
|
|
138
143
|
```bash
|
|
139
144
|
dictate --stt-backend faster-whisper --model turbo
|
|
145
|
+
dictate config show
|
|
146
|
+
dictate config set-provider online
|
|
147
|
+
dictate config set-key xai xai-YOUR_KEY_HERE
|
|
140
148
|
dictate --stt-backend openai --model gpt-4o-mini-transcribe
|
|
141
149
|
dictate --stt-backend xai --model grok-speech-to-text
|
|
142
150
|
dictate --stt-backend gemini --model gemini-3-flash-preview
|
|
@@ -164,33 +172,45 @@ and should not be packaged into the public repo default config.
|
|
|
164
172
|
## Safety
|
|
165
173
|
|
|
166
174
|
- Dictate does not intentionally write raw API keys to `config.yaml`.
|
|
167
|
-
- API keys configured
|
|
175
|
+
- API keys configured through the CLI use the OS secret store.
|
|
168
176
|
- Dictation text can be sensitive; check logs and issue reports before sharing.
|
|
169
177
|
- Important transcriptions should be verified before relying on them.
|
|
170
178
|
- Support and maintenance are best-effort.
|
|
171
179
|
|
|
172
180
|
## Desktop UI — the Quiet Console (preview)
|
|
173
181
|
|
|
174
|
-
A
|
|
182
|
+
A quiet desktop window sits alongside the tray — a capture home (the mic is the
|
|
183
|
+
record button), the notes list, and the ⌘K palette; no settings menu (config via
|
|
184
|
+
the `dictate config` CLI).
|
|
175
185
|
|
|
176
|
-
- [`ui/`](ui/README.md) — React/Vite front-end
|
|
177
|
-
|
|
186
|
+
- [`ui/`](ui/README.md) — React/Vite front-end. For UI work, **`cd ui && npm run
|
|
187
|
+
dev`** opens the whole app at `http://localhost:5173` against a built-in mock
|
|
188
|
+
(no engine, no Tauri, no STT) — the fast UI loop in a browser. Details, and
|
|
189
|
+
when to use the Tauri shell instead, are in that README's *Develop* section.
|
|
178
190
|
- [`ui-shell/`](ui-shell/README.md) — Tauri 2 shell that hosts it on Linux.
|
|
179
191
|
- `src/dictate/ui_server.py` — the loopback control server the UI talks to; the
|
|
180
|
-
tray
|
|
192
|
+
tray can launch the shell for the desktop capture surface.
|
|
181
193
|
- See [`design/PLAN.md`](design/PLAN.md) for the cross-platform plan.
|
|
182
194
|
|
|
183
|
-
**Install it like a normal app:**
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
**Install it like a normal app:** the default Linux channel is a per-user install
|
|
196
|
+
under `~/.local/share/dictate` with launchers in `~/.local/bin` and
|
|
197
|
+
`~/.local/share/applications`. App updates do not need sudo.
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
./install.sh
|
|
201
|
+
./update.sh
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Tagged releases can also attach a **self-contained** Linux **`.deb`** for users
|
|
205
|
+
who explicitly want a system package. It bundles the frozen Python engine inside
|
|
206
|
+
(PyInstaller sidecar), so there's no separate Python/pip step:
|
|
187
207
|
|
|
188
208
|
```bash
|
|
189
|
-
sudo apt install ./
|
|
209
|
+
sudo apt install ./Dictate_*_amd64.deb
|
|
190
210
|
```
|
|
191
211
|
|
|
192
|
-
The app lives in the tray
|
|
193
|
-
|
|
212
|
+
The app lives in the tray and desktop shell and does push-to-talk straight away.
|
|
213
|
+
Build the package yourself in one step with
|
|
194
214
|
[`scripts/build-linux-desktop.sh`](scripts/build-linux-desktop.sh) — see
|
|
195
215
|
[`ui-shell/README.md`](ui-shell/README.md). The `pip`/`install.sh` route remains
|
|
196
216
|
for source/dev installs.
|
|
@@ -203,7 +223,8 @@ for source/dev installs.
|
|
|
203
223
|
- [Desktop packaging & CI runbook](docs/desktop-packaging.md)
|
|
204
224
|
- [Microsoft Store automation](docs/msstore-automation.md)
|
|
205
225
|
- [Microsoft Store listing draft](docs/msstore-listing.md)
|
|
206
|
-
- [
|
|
226
|
+
- [Deployment security](docs/deployment-security.md)
|
|
227
|
+
- [Goals](docs/GOALS.md)
|
|
207
228
|
- [Development streams](docs/development-streams.md)
|
|
208
229
|
- [Security policy](SECURITY.md)
|
|
209
230
|
|
|
@@ -3,7 +3,9 @@ push_to_talk_combo: ctrl_r
|
|
|
3
3
|
stt_backend: faster-whisper
|
|
4
4
|
stt_compute_type: int8
|
|
5
5
|
stt_device: auto
|
|
6
|
-
# Local Whisper
|
|
6
|
+
# Local Whisper picks a hardware-aware default model when stt_model is unset:
|
|
7
|
+
# turbo on CUDA or a capable CPU (~8 GB RAM + >=8 cores), otherwise small.
|
|
8
|
+
# Set stt_model explicitly to override (e.g. tiny/base/small/medium/turbo):
|
|
7
9
|
# stt_model: turbo
|
|
8
10
|
# To avoid local compute, set one hosted backend:
|
|
9
11
|
# stt_backend: openai
|
package/install-windows.ps1
CHANGED
|
@@ -257,7 +257,7 @@ function Register-InstalledApp {
|
|
|
257
257
|
$keyPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\Dictate"
|
|
258
258
|
New-Item -Force -Path $keyPath | Out-Null
|
|
259
259
|
New-ItemProperty -Force -Path $keyPath -Name "DisplayName" -Value "Dictate" -PropertyType String | Out-Null
|
|
260
|
-
New-ItemProperty -Force -Path $keyPath -Name "DisplayVersion" -Value "2026.
|
|
260
|
+
New-ItemProperty -Force -Path $keyPath -Name "DisplayVersion" -Value "2026.7.4" -PropertyType String | Out-Null
|
|
261
261
|
New-ItemProperty -Force -Path $keyPath -Name "Publisher" -Value "Arc Forge Labs" -PropertyType String | Out-Null
|
|
262
262
|
New-ItemProperty -Force -Path $keyPath -Name "InstallLocation" -Value $InstallLocation -PropertyType String | Out-Null
|
|
263
263
|
if (Test-Path $DisplayIcon) {
|
|
@@ -395,7 +395,9 @@ Install-StartupShortcut -TargetPath $wscript -Arguments $trayArgs -WorkingDirect
|
|
|
395
395
|
Register-InstalledApp -InstallLocation $PSScriptRoot -DisplayIcon (Join-Path $PSScriptRoot "assets\dictate.ico")
|
|
396
396
|
|
|
397
397
|
if (-not $NoPrepareTurbo) {
|
|
398
|
-
|
|
398
|
+
# Omit --model so prepare-model resolves the hardware-aware local default
|
|
399
|
+
# (turbo on capable hardware, small on a weak CPU) instead of forcing turbo.
|
|
400
|
+
Invoke-Checked -Exe $venvPython -ArgumentList @("-m", "dictate", "prepare-model", "--stt-backend", "faster-whisper", "--device", "auto", "--compute-type", "int8") -Description "Preparing faster-whisper model"
|
|
399
401
|
}
|
|
400
402
|
|
|
401
403
|
if (-not $NoVerify) {
|
package/install.ps1
CHANGED
package/install.sh
CHANGED
|
@@ -11,6 +11,7 @@ DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
|
|
|
11
11
|
AUTOSTART_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/autostart"
|
|
12
12
|
ICON_DIR="$INSTALL_DIR/share/icons"
|
|
13
13
|
ICON_PATH="$ICON_DIR/dictate-simple.png"
|
|
14
|
+
DESKTOP_PATH="$DESKTOP_DIR/dictate.desktop"
|
|
14
15
|
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/dictate"
|
|
15
16
|
CONFIG_PATH="$CONFIG_DIR/config.yaml"
|
|
16
17
|
DEFAULT_CONFIG_SOURCE="$SCRIPT_DIR/config/default-config.yaml"
|
|
@@ -19,6 +20,7 @@ PREPARE_TURBO=1
|
|
|
19
20
|
SEED_DEFAULT_CONFIG=1
|
|
20
21
|
STARTUP=1
|
|
21
22
|
INSTALL_UI=1
|
|
23
|
+
INSTALL_SCOPE="user"
|
|
22
24
|
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
23
25
|
|
|
24
26
|
# Prefer the distro Python so --system-site-packages can see modules such as
|
|
@@ -29,17 +31,51 @@ fi
|
|
|
29
31
|
|
|
30
32
|
usage() {
|
|
31
33
|
cat <<EOF
|
|
32
|
-
Usage: $0 [--no-verify] [--no-prepare-turbo] [--no-seed-default-config] [--no-startup] [--no-ui] [--session-backend auto|x11|wayland]
|
|
34
|
+
Usage: $0 [--user|--system] [--no-verify] [--no-prepare-turbo] [--no-seed-default-config] [--no-startup] [--no-ui] [--session-backend auto|x11|wayland]
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
Default: --user.
|
|
37
|
+
|
|
38
|
+
--user installs dictate into ~/.local/share/dictate, links ~/.local/bin/dictate and
|
|
35
39
|
~/.local/bin/dictate-ui-server, seeds the default config on first install,
|
|
36
|
-
creates app launcher/autostart entries, prepares the faster-whisper
|
|
40
|
+
creates app launcher/autostart entries, prepares the hardware-aware faster-whisper model,
|
|
37
41
|
and installs the desktop "Quiet Console" UI shell when a build toolchain is
|
|
38
42
|
present (unless disabled). All steps degrade gracefully when prerequisites are
|
|
39
43
|
missing.
|
|
44
|
+
|
|
45
|
+
--system installs a Linux desktop package into system paths using apt/pkexec or
|
|
46
|
+
sudo. It is intentionally explicit because it requires administrator approval.
|
|
40
47
|
EOF
|
|
41
48
|
}
|
|
42
49
|
|
|
50
|
+
install_system_package() {
|
|
51
|
+
if [ "$(uname -s)" != "Linux" ]; then
|
|
52
|
+
echo "--system is only supported by this installer on Linux."
|
|
53
|
+
exit 2
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
local deb_path="${DICTATE_DEB:-}"
|
|
57
|
+
if [ -z "$deb_path" ]; then
|
|
58
|
+
deb_path="$(find "$SCRIPT_DIR/ui-shell/src-tauri/target/release/bundle/deb" -maxdepth 1 -name 'Dictate_*_amd64.deb' 2>/dev/null | sort | tail -n 1 || true)"
|
|
59
|
+
fi
|
|
60
|
+
if [ -z "$deb_path" ] || [ ! -f "$deb_path" ]; then
|
|
61
|
+
echo "No local .deb found. Build one first:"
|
|
62
|
+
echo " DICTATE_BUNDLES=deb scripts/build-linux-desktop.sh"
|
|
63
|
+
echo "Or pass one explicitly:"
|
|
64
|
+
echo " DICTATE_DEB=/path/to/Dictate_..._amd64.deb $0 --system"
|
|
65
|
+
exit 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
echo "Installing system package: $deb_path"
|
|
69
|
+
if command -v pkexec >/dev/null 2>&1; then
|
|
70
|
+
pkexec apt-get install -y "$deb_path"
|
|
71
|
+
elif command -v sudo >/dev/null 2>&1; then
|
|
72
|
+
sudo apt-get install -y "$deb_path"
|
|
73
|
+
else
|
|
74
|
+
echo "Need pkexec or sudo to install a system package."
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
|
|
43
79
|
detect_session_backend() {
|
|
44
80
|
if [ -n "${WAYLAND_DISPLAY:-}" ] || [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
|
|
45
81
|
printf 'wayland\n'
|
|
@@ -79,6 +115,12 @@ while [ "$#" -gt 0 ]; do
|
|
|
79
115
|
--no-ui)
|
|
80
116
|
INSTALL_UI=0
|
|
81
117
|
;;
|
|
118
|
+
--user)
|
|
119
|
+
INSTALL_SCOPE="user"
|
|
120
|
+
;;
|
|
121
|
+
--system)
|
|
122
|
+
INSTALL_SCOPE="system"
|
|
123
|
+
;;
|
|
82
124
|
--session-backend)
|
|
83
125
|
shift
|
|
84
126
|
SESSION_BACKEND="${1:-}"
|
|
@@ -98,6 +140,11 @@ while [ "$#" -gt 0 ]; do
|
|
|
98
140
|
shift
|
|
99
141
|
done
|
|
100
142
|
|
|
143
|
+
if [ "$INSTALL_SCOPE" = "system" ]; then
|
|
144
|
+
install_system_package
|
|
145
|
+
exit 0
|
|
146
|
+
fi
|
|
147
|
+
|
|
101
148
|
if [ "$SESSION_BACKEND" = "auto" ]; then
|
|
102
149
|
SESSION_BACKEND="$(detect_session_backend)"
|
|
103
150
|
fi
|
|
@@ -124,6 +171,34 @@ elif command -v rpm >/dev/null 2>&1 && rpm -q dictate >/dev/null 2>&1; then
|
|
|
124
171
|
echo " Use one install method. To remove the package first: sudo dnf remove dictate"
|
|
125
172
|
fi
|
|
126
173
|
|
|
174
|
+
# Stop any running Dictate engine before we overwrite it, so the new install can
|
|
175
|
+
# claim the single-instance lock cleanly instead of colliding with a stale daemon.
|
|
176
|
+
stop_running_dictate() {
|
|
177
|
+
# Prefer the installed CLI's own clean stop; it knows the lock location.
|
|
178
|
+
if command -v dictate >/dev/null 2>&1 && dictate stop --quiet 2>/dev/null; then
|
|
179
|
+
return 0
|
|
180
|
+
fi
|
|
181
|
+
# Fallback (older builds without `dictate stop`): kill via the lock PID file.
|
|
182
|
+
local lockdir
|
|
183
|
+
if [ -n "${XDG_RUNTIME_DIR:-}" ]; then
|
|
184
|
+
lockdir="$XDG_RUNTIME_DIR/dictate-daemon.lockdir"
|
|
185
|
+
else
|
|
186
|
+
lockdir="/tmp/dictate-daemon-$(id -u).lockdir"
|
|
187
|
+
fi
|
|
188
|
+
local pidfile="$lockdir/pid"
|
|
189
|
+
[ -f "$pidfile" ] || return 0
|
|
190
|
+
local pid
|
|
191
|
+
pid="$(cat "$pidfile" 2>/dev/null || true)"
|
|
192
|
+
[ -n "$pid" ] || return 0
|
|
193
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
194
|
+
kill "$pid" 2>/dev/null || true
|
|
195
|
+
for _ in 1 2 3 4 5 6 7 8 9 10; do kill -0 "$pid" 2>/dev/null || break; sleep 0.3; done
|
|
196
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
197
|
+
fi
|
|
198
|
+
}
|
|
199
|
+
echo "Stopping any running Dictate engine ..."
|
|
200
|
+
stop_running_dictate
|
|
201
|
+
|
|
127
202
|
echo "Creating venv at $INSTALL_DIR ..."
|
|
128
203
|
uv venv "$INSTALL_DIR/venv" --python "$PYTHON_BIN" --system-site-packages --quiet
|
|
129
204
|
|
|
@@ -143,8 +218,8 @@ install -m 644 "$SCRIPT_DIR/assets/dictate.png" "$ICON_PATH"
|
|
|
143
218
|
|
|
144
219
|
echo "Installing desktop entry ..."
|
|
145
220
|
mkdir -p "$DESKTOP_DIR"
|
|
146
|
-
rm -f "$DESKTOP_DIR/dictate-settings.desktop"
|
|
147
|
-
cat > "$
|
|
221
|
+
rm -f "$DESKTOP_DIR/dictate-settings.desktop" "$DESKTOP_DIR/Dictate.desktop" "$DESKTOP_DIR/dictate.desktop"
|
|
222
|
+
cat > "$DESKTOP_PATH" <<EOF
|
|
148
223
|
[Desktop Entry]
|
|
149
224
|
Name=Dictate
|
|
150
225
|
Comment=Dictate into the focused app
|
|
@@ -189,10 +264,6 @@ install_desktop_ui() {
|
|
|
189
264
|
local shell_src="$SCRIPT_DIR/ui-shell"
|
|
190
265
|
local target="$BIN_DIR/dictate-ui-shell"
|
|
191
266
|
|
|
192
|
-
if command -v dictate-ui-shell >/dev/null 2>&1; then
|
|
193
|
-
echo "Desktop UI shell already installed: $(command -v dictate-ui-shell)"
|
|
194
|
-
return 0
|
|
195
|
-
fi
|
|
196
267
|
if [ ! -d "$shell_src" ]; then
|
|
197
268
|
echo "Desktop UI shell sources not present; skipping the optional UI."
|
|
198
269
|
print_ui_hint
|
|
@@ -209,22 +280,52 @@ install_desktop_ui() {
|
|
|
209
280
|
npm --prefix "$SCRIPT_DIR/ui" ci >/dev/null 2>&1 \
|
|
210
281
|
|| npm --prefix "$SCRIPT_DIR/ui" install >/dev/null 2>&1 \
|
|
211
282
|
|| { echo "UI front-end install failed; skipping the optional shell."; print_ui_hint; return 0; }
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
283
|
+
npm --prefix "$shell_src" ci >/dev/null 2>&1 \
|
|
284
|
+
|| npm --prefix "$shell_src" install >/dev/null 2>&1 \
|
|
285
|
+
|| { echo "UI shell tooling install failed; skipping the optional shell."; print_ui_hint; return 0; }
|
|
286
|
+
# Build through the Tauri CLI, NOT a raw `cargo build`. The CLI enables the
|
|
287
|
+
# `custom-protocol` feature that embeds the frontend and serves it over the
|
|
288
|
+
# app protocol. A plain cargo build omits that feature, so the shell falls
|
|
289
|
+
# back to loading the dev server (localhost:5173) and shows "Could not connect
|
|
290
|
+
# to localhost: Connection refused" at runtime. --no-bundle: we only need the
|
|
291
|
+
# binary here, not a .deb/AppImage. (beforeBuildCommand rebuilds ui/dist.)
|
|
292
|
+
if ! ( cd "$shell_src" && npm run tauri -- build --no-bundle ); then
|
|
216
293
|
echo "Desktop UI shell build failed; the engine + tray remain fully functional."
|
|
217
294
|
print_ui_hint
|
|
218
295
|
return 0
|
|
219
296
|
fi
|
|
220
297
|
install -m 755 "$shell_src/src-tauri/target/release/dictate-ui-shell" "$target"
|
|
221
298
|
echo "Installed desktop UI shell: $target"
|
|
299
|
+
|
|
300
|
+
# Give the shell an absolute-path engine right next to it. The shell's
|
|
301
|
+
# bundled-engine lookup checks <exe_dir>/engine first — before any system
|
|
302
|
+
# path (e.g. a leftover /usr/lib/Dictate from an old .deb) and independent of
|
|
303
|
+
# the minimal PATH a desktop launcher provides. Pointing it at the per-user
|
|
304
|
+
# venv means one process both dictates and serves, and keeps sys.executable
|
|
305
|
+
# inside ~/.local so the install reads as "linux-user" and the in-app updater
|
|
306
|
+
# never needs sudo/pkexec.
|
|
307
|
+
local engine_dir="$BIN_DIR/engine"
|
|
308
|
+
mkdir -p "$engine_dir"
|
|
309
|
+
cat > "$engine_dir/dictate-engine" <<WRAP
|
|
310
|
+
#!/bin/sh
|
|
311
|
+
exec "$INSTALL_DIR/venv/bin/dictate" "\$@"
|
|
312
|
+
WRAP
|
|
313
|
+
chmod 755 "$engine_dir/dictate-engine"
|
|
314
|
+
echo "Installed per-user engine launcher: $engine_dir/dictate-engine"
|
|
222
315
|
}
|
|
223
316
|
|
|
224
317
|
if [ "$INSTALL_UI" -eq 1 ]; then
|
|
225
318
|
install_desktop_ui
|
|
226
319
|
fi
|
|
227
320
|
|
|
321
|
+
if [ -x "$BIN_DIR/dictate-ui-shell" ]; then
|
|
322
|
+
echo "Pointing launcher entries at the desktop UI shell ..."
|
|
323
|
+
sed -i "s|^Exec=.*|Exec=$BIN_DIR/dictate-ui-shell|" "$DESKTOP_PATH"
|
|
324
|
+
if [ "$STARTUP" -eq 1 ] && [ -f "$AUTOSTART_DIR/dictate.desktop" ]; then
|
|
325
|
+
sed -i "s|^Exec=.*|Exec=$BIN_DIR/dictate-ui-shell|" "$AUTOSTART_DIR/dictate.desktop"
|
|
326
|
+
fi
|
|
327
|
+
fi
|
|
328
|
+
|
|
228
329
|
if [ "$SEED_DEFAULT_CONFIG" -eq 1 ]; then
|
|
229
330
|
if [ ! -f "$CONFIG_PATH" ]; then
|
|
230
331
|
if [ ! -f "$DEFAULT_CONFIG_SOURCE" ]; then
|
|
@@ -269,14 +370,15 @@ run_logged_check() {
|
|
|
269
370
|
|
|
270
371
|
if [ "$PREPARE_TURBO" -eq 1 ]; then
|
|
271
372
|
PREPARE_LOG="/tmp/dictate-install-prepare.log"
|
|
373
|
+
# Omit --model so prepare-model resolves the hardware-aware local default
|
|
374
|
+
# (turbo on capable hardware, small on a weak CPU) instead of forcing turbo.
|
|
272
375
|
run_logged_check \
|
|
273
|
-
"dictate prepare-model --stt-backend faster-whisper --
|
|
376
|
+
"dictate prepare-model --stt-backend faster-whisper --device auto --compute-type int8" \
|
|
274
377
|
"$PREPARE_LOG" \
|
|
275
378
|
1800 \
|
|
276
379
|
"$DICTATE_BIN" \
|
|
277
380
|
prepare-model \
|
|
278
381
|
--stt-backend faster-whisper \
|
|
279
|
-
--model turbo \
|
|
280
382
|
--device auto \
|
|
281
383
|
--compute-type int8
|
|
282
384
|
fi
|
|
@@ -286,14 +388,13 @@ if [ "$VERIFY" -eq 1 ]; then
|
|
|
286
388
|
run_logged_check "dictate --help" "$VERIFY_LOG" 20 "$DICTATE_BIN" --help
|
|
287
389
|
run_logged_check "dictate benchmark --help" "$VERIFY_LOG" 20 "$DICTATE_BIN" benchmark --help
|
|
288
390
|
run_logged_check \
|
|
289
|
-
"dictate doctor --quick --stt-backend faster-whisper
|
|
391
|
+
"dictate doctor --quick --stt-backend faster-whisper" \
|
|
290
392
|
"$VERIFY_LOG" \
|
|
291
393
|
20 \
|
|
292
394
|
"$DICTATE_BIN" \
|
|
293
395
|
doctor \
|
|
294
396
|
--quick \
|
|
295
|
-
--stt-backend faster-whisper
|
|
296
|
-
--model turbo
|
|
397
|
+
--stt-backend faster-whisper
|
|
297
398
|
fi
|
|
298
399
|
|
|
299
400
|
if [ "$STARTUP" -eq 1 ]; then
|
package/package.json
CHANGED
package/uninstall.sh
CHANGED
|
@@ -4,6 +4,7 @@ set -euo pipefail
|
|
|
4
4
|
|
|
5
5
|
INSTALL_DIR="$HOME/.local/share/dictate"
|
|
6
6
|
BIN_PATH="$HOME/.local/bin/dictate"
|
|
7
|
+
UI_SHELL_BIN_PATH="$HOME/.local/bin/dictate-ui-shell"
|
|
7
8
|
UI_SERVER_BIN_PATH="$HOME/.local/bin/dictate-ui-server"
|
|
8
9
|
DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
|
|
9
10
|
AUTOSTART_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/autostart"
|
|
@@ -95,10 +96,12 @@ remove_managed_symlink() {
|
|
|
95
96
|
stop_source_processes
|
|
96
97
|
|
|
97
98
|
remove_file "$DESKTOP_DIR/dictate.desktop"
|
|
99
|
+
remove_file "$DESKTOP_DIR/Dictate.desktop"
|
|
98
100
|
remove_file "$DESKTOP_DIR/dictate-settings.desktop"
|
|
99
101
|
remove_file "$AUTOSTART_DIR/dictate.desktop"
|
|
100
102
|
|
|
101
103
|
remove_managed_symlink "$BIN_PATH" "$INSTALL_DIR/venv/bin/dictate"
|
|
104
|
+
remove_file "$UI_SHELL_BIN_PATH"
|
|
102
105
|
remove_managed_symlink "$UI_SERVER_BIN_PATH" "$INSTALL_DIR/venv/bin/dictate-ui-server"
|
|
103
106
|
|
|
104
107
|
rm -rf "$INSTALL_DIR/venv" "$INSTALL_DIR/share/icons" "$INSTALL_DIR/logs"
|
package/update.ps1
CHANGED
package/update.sh
CHANGED
|
@@ -8,19 +8,55 @@ DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
|
|
|
8
8
|
AUTOSTART_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/autostart"
|
|
9
9
|
ICON_DIR="$INSTALL_DIR/share/icons"
|
|
10
10
|
AUTOSTART_PATH="$AUTOSTART_DIR/dictate.desktop"
|
|
11
|
+
UPDATE_SCOPE="user"
|
|
12
|
+
|
|
13
|
+
usage() {
|
|
14
|
+
cat <<EOF
|
|
15
|
+
Usage: $0 [--user|--system] [install.sh options]
|
|
16
|
+
|
|
17
|
+
Default: --user.
|
|
18
|
+
|
|
19
|
+
--user updates the per-user install in ~/.local/share/dictate without sudo.
|
|
20
|
+
--system updates a Linux desktop package in system paths using apt/pkexec or sudo.
|
|
21
|
+
EOF
|
|
22
|
+
}
|
|
11
23
|
|
|
12
24
|
cleanup_legacy_entries() {
|
|
13
25
|
rm -f "$DESKTOP_DIR/dictate-settings.desktop"
|
|
14
26
|
rm -f "$ICON_DIR/dictate-controls.png" "$ICON_DIR/dictate.png"
|
|
15
27
|
}
|
|
16
28
|
|
|
29
|
+
args=()
|
|
30
|
+
while [ "$#" -gt 0 ]; do
|
|
31
|
+
case "$1" in
|
|
32
|
+
--user)
|
|
33
|
+
UPDATE_SCOPE="user"
|
|
34
|
+
;;
|
|
35
|
+
--system)
|
|
36
|
+
UPDATE_SCOPE="system"
|
|
37
|
+
;;
|
|
38
|
+
-h|--help)
|
|
39
|
+
usage
|
|
40
|
+
exit 0
|
|
41
|
+
;;
|
|
42
|
+
*)
|
|
43
|
+
args+=("$1")
|
|
44
|
+
;;
|
|
45
|
+
esac
|
|
46
|
+
shift
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
if [ "$UPDATE_SCOPE" = "system" ]; then
|
|
50
|
+
"$SCRIPT_DIR/install.sh" --system "${args[@]}"
|
|
51
|
+
exit 0
|
|
52
|
+
fi
|
|
53
|
+
|
|
17
54
|
if [ -d "$SCRIPT_DIR/.git" ]; then
|
|
18
55
|
git -C "$SCRIPT_DIR" pull --ff-only
|
|
19
56
|
fi
|
|
20
57
|
|
|
21
58
|
cleanup_legacy_entries
|
|
22
59
|
|
|
23
|
-
args=("$@")
|
|
24
60
|
startup_option_seen=0
|
|
25
61
|
for arg in "${args[@]}"; do
|
|
26
62
|
if [ "$arg" = "--no-startup" ]; then
|