feat(identity): rename user-visible identity to voculinux with one-time legacy import

The fork takes its own name everywhere a user can see it: binaries
(voculinux, voculinux-gui), desktop entry, autostart, tray, D-Bus
namespace (com.voculinux.Voculinux, no alias for the old name),
config/data/cache dirs, single-instance lock, IBus engine identity,
tray icons, resource prefixes, VOCULINUX_* environment names, and the
update-checker user agent. The internal Python module stays vocalinux
and the distribution metadata keeps the upstream URLs as provenance.

On first run a previous Vocalinux install's config.json, custom
dictionary, and portal restore token are copied once into the new
locations (new config always wins, no merge, no write-back); models
re-resolve through the pinned-checksum download path. An offline
naming-sweep test proves no old-name strings remain on user-visible
surfaces outside the allowlist.

Refs #18
This commit is contained in:
soubarnak
2026-11-06 01:29:39 +05:30
parent c565e6d946
commit ea7be5f111
251 changed files with 2449 additions and 1991 deletions
+122 -122
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# Vocalinux Installer
# This script installs the Vocalinux application and its dependencies
# Voculinux Installer
# This script installs the Voculinux application and its dependencies
# -E: ERR trap propagates into functions/subshells
# -e: exit on unhandled command failure -u: error on unset variables
@@ -118,7 +118,7 @@ is_kde_plasma_session() {
print_kde_wayland_ibus_hint() {
print_warning "KDE Plasma Wayland detected."
print_info "For direct dictation into apps, open System Settings -> Keyboard -> Virtual Keyboard and select 'IBus Wayland'."
print_info "After changing it, restart Vocalinux or log out and back in."
print_info "After changing it, restart Voculinux or log out and back in."
}
# Read a numeric PID from a file (instance.lock / engine.pid). Empty if missing/invalid.
@@ -133,9 +133,9 @@ read_pid_file() {
fi
}
# True only for the Vocalinux app / IBus engine — not editors, shells, or tests
# whose argv merely contains the string "vocalinux" (e.g. cwd under the repo).
is_vocalinux_process() {
# True only for the Voculinux app / IBus engine — not editors, shells, or tests
# whose argv merely contains the string "voculinux" (e.g. cwd under the repo).
is_voculinux_process() {
local pid="$1"
if [ "$pid" = "$$" ] || [ "$pid" = "$PPID" ]; then
@@ -163,18 +163,18 @@ is_vocalinux_process() {
return 0
fi
# IBus engine: .../vocalinux/.../ibus_engine.py
if [[ "$cmdline" == *"ibus_engine.py"* && "$cmdline" == *"vocalinux"* ]]; then
# IBus engine: .../voculinux/.../ibus_engine.py
if [[ "$cmdline" == *"ibus_engine.py"* && "$cmdline" == *"voculinux"* ]]; then
return 0
fi
# Console-script entrypoints. Setuptools scripts are executed as
# `python …/bin/vocalinux`, so argv0 is python — scan every arg for the
# script path (require …/bin/vocalinux to avoid matching a repo directory).
# `python …/bin/voculinux`, so argv0 is python — scan every arg for the
# script path (require …/bin/voculinux to avoid matching a repo directory).
local arg
while IFS= read -r -d '' arg; do
case "$arg" in
vocalinux|vocalinux-gui|*/bin/vocalinux|*/bin/vocalinux-gui)
voculinux|voculinux-gui|*/bin/voculinux|*/bin/voculinux-gui)
return 0
;;
esac
@@ -184,16 +184,16 @@ is_vocalinux_process() {
}
# Prefer the PIDs the app writes; fall back to narrow entrypoint patterns only.
# Deliberately does NOT use `pgrep -f vocalinux` (matches editors/shells/cwd paths).
get_vocalinux_pids() {
# Deliberately does NOT use `pgrep -f voculinux` (matches editors/shells/cwd paths).
get_voculinux_pids() {
local data_home="${XDG_DATA_HOME:-$HOME/.local/share}"
local -A seen=()
local pid candidate
local -a candidates=()
for candidate in \
"$(read_pid_file "$data_home/vocalinux/instance.lock")" \
"$(read_pid_file "$data_home/vocalinux-ibus/engine.pid")"
"$(read_pid_file "$data_home/voculinux/instance.lock")" \
"$(read_pid_file "$data_home/voculinux-ibus/engine.pid")"
do
[ -n "$candidate" ] && candidates+=("$candidate")
done
@@ -202,16 +202,16 @@ get_vocalinux_pids() {
while read -r candidate; do
[ -n "$candidate" ] && candidates+=("$candidate")
done < <(
pgrep -u "$(id -u)" -x vocalinux 2>/dev/null || true
pgrep -u "$(id -u)" -x vocalinux-gui 2>/dev/null || true
pgrep -u "$(id -u)" -f -- '-m vocalinux\.main' 2>/dev/null || true
pgrep -u "$(id -u)" -f -- 'vocalinux/.*/ibus_engine\.py' 2>/dev/null || true
pgrep -u "$(id -u)" -x voculinux 2>/dev/null || true
pgrep -u "$(id -u)" -x voculinux-gui 2>/dev/null || true
pgrep -u "$(id -u)" -f -- '-m voculinux\.main' 2>/dev/null || true
pgrep -u "$(id -u)" -f -- 'voculinux/.*/ibus_engine\.py' 2>/dev/null || true
)
for pid in "${candidates[@]}"; do
[ -n "${seen[$pid]:-}" ] && continue
seen[$pid]=1
if is_vocalinux_process "$pid"; then
if is_voculinux_process "$pid"; then
echo "$pid"
fi
done
@@ -219,10 +219,10 @@ get_vocalinux_pids() {
check_running_processes() {
local PIDS
PIDS=$(get_vocalinux_pids || true)
PIDS=$(get_voculinux_pids || true)
if [ -n "$PIDS" ]; then
print_warning "Found running Vocalinux process(es):"
print_warning "Found running Voculinux process(es):"
local pid
for pid in $PIDS; do
local cmd
@@ -232,24 +232,24 @@ check_running_processes() {
echo ""
if [[ "$NON_INTERACTIVE" == "yes" ]]; then
print_info "Non-interactive mode: stopping Vocalinux automatically..."
print_info "Non-interactive mode: stopping Voculinux automatically..."
else
read_prompt -p "Vocalinux must be stopped before installation. Kill running process(es)? (Y/n) " -n 1 -r
read_prompt -p "Voculinux must be stopped before installation. Kill running process(es)? (Y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Nn]$ ]]; then
print_error "Cannot proceed with installation while Vocalinux is running."
print_info "Please stop Vocalinux manually and run the installer again."
print_error "Cannot proceed with installation while Voculinux is running."
print_info "Please stop Voculinux manually and run the installer again."
exit "$EXIT_USER_ABORT"
fi
fi
print_info "Stopping Vocalinux..."
print_info "Stopping Voculinux..."
# shellcheck disable=SC2086
echo $PIDS | xargs -r kill -TERM 2>/dev/null || true
sleep 2
local REMAINING_PIDS
REMAINING_PIDS=$(get_vocalinux_pids || true)
REMAINING_PIDS=$(get_voculinux_pids || true)
if [ -n "$REMAINING_PIDS" ]; then
print_warning "Some processes still running, forcing termination..."
@@ -259,13 +259,13 @@ check_running_processes() {
fi
local FINAL_PIDS
FINAL_PIDS=$(get_vocalinux_pids || true)
FINAL_PIDS=$(get_voculinux_pids || true)
if [ -n "$FINAL_PIDS" ]; then
print_error "Could not terminate all Vocalinux processes: $FINAL_PIDS"
print_error "Could not terminate all Voculinux processes: $FINAL_PIDS"
print_error "Please manually kill these processes and run the installer again."
exit "$EXIT_USER_ABORT"
else
print_success "All Vocalinux processes stopped"
print_success "All Voculinux processes stopped"
fi
fi
}
@@ -373,7 +373,7 @@ while [[ $# -gt 0 ]]; do
shift
;;
--help)
echo "Vocalinux Installer"
echo "Voculinux Installer"
echo ""
echo "Usage: $0 [options]"
echo ""
@@ -410,7 +410,7 @@ while [[ $# -gt 0 ]]; do
echo " $0 --dev --test # Dev mode with tests"
echo ""
echo "During installation a full transcript is saved to"
echo " ~/.local/state/vocalinux/install-<timestamp>.log"
echo " ~/.local/state/voculinux/install-<timestamp>.log"
echo ""
echo "Exit codes:"
echo " 0 success"
@@ -437,7 +437,7 @@ fi
# Global install log: everything (stdout + stderr) is teed to this file so
# failures can be debugged after the fact. The path is printed at exit.
# ---------------------------------------------------------------------------
INSTALL_LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/vocalinux"
INSTALL_LOG_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/voculinux"
if ! mkdir -p "$INSTALL_LOG_DIR" 2>/dev/null; then
INSTALL_LOG_DIR="${TMPDIR:-/tmp}"
fi
@@ -447,18 +447,18 @@ exec > >(tee -a "$INSTALL_LOG_FILE") 2>&1
# Scratch directory for pip logs, model downloads, and other temps.
# Removed on success; kept for inspection (with a notice) when the install fails.
# Exporting TMPDIR routes pip/wget/curl scratch files into this directory.
VOCALINUX_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/vocalinux-install.XXXXXXXX")"
export TMPDIR="$VOCALINUX_TMP_DIR"
VOCULINUX_TMP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/voculinux-install.XXXXXXXX")"
export TMPDIR="$VOCULINUX_TMP_DIR"
cleanup_on_exit() {
local rc=$?
if [ "$rc" -eq "$EXIT_OK" ]; then
rm -rf "$VOCALINUX_TMP_DIR"
rm -rf "$VOCULINUX_TMP_DIR"
else
print_error ""
print_error "Installation did not complete (exit code $rc)."
print_error "Full install log: $INSTALL_LOG_FILE"
print_error "Scratch files kept for inspection: $VOCALINUX_TMP_DIR"
print_error "Scratch files kept for inspection: $VOCULINUX_TMP_DIR"
fi
}
trap cleanup_on_exit EXIT
@@ -478,7 +478,7 @@ cat << "EOF"
EOF
print_info "Vocalinux Installer"
print_info "Voculinux Installer"
print_info "=============================="
echo ""
@@ -509,21 +509,21 @@ resolve_install_tag() {
resolve_install_tag
# Check if running from within the vocalinux repo or remotely (via curl)
# VOCALINUX_REPO_URL overrides the clone source so the remote-install gate can
# Check if running from within the voculinux repo or remotely (via curl)
# VOCULINUX_REPO_URL overrides the clone source so the remote-install gate can
# serve a tag from a local mirror; public installs use the repository below.
REPO_URL="${VOCALINUX_REPO_URL:-https://github.com/VocaHQ/vocalinux.git}"
REPO_URL="${VOCULINUX_REPO_URL:-https://github.com/VocaHQ/vocalinux.git}"
INSTALL_DIR=""
CLEANUP_ON_EXIT="${VOCALINUX_REMOTE_INSTALL:-no}"
CLEANUP_ON_EXIT="${VOCULINUX_REMOTE_INSTALL:-no}"
handoff_to_tagged_installer() {
local tagged_installer="$INSTALL_DIR/install.sh"
local remote_venv="$HOME/.local/share/vocalinux/venv"
local remote_venv="$HOME/.local/share/voculinux/venv"
if grep -q 'CLEANUP_ON_EXIT="${VOCALINUX_REMOTE_INSTALL:-no}"' "$tagged_installer"; then
export VOCALINUX_REMOTE_INSTALL=yes
export TMPDIR="$(dirname "$VOCALINUX_TMP_DIR")"
rmdir "$VOCALINUX_TMP_DIR"
if grep -q 'CLEANUP_ON_EXIT="${VOCULINUX_REMOTE_INSTALL:-no}"' "$tagged_installer"; then
export VOCULINUX_REMOTE_INSTALL=yes
export TMPDIR="$(dirname "$VOCULINUX_TMP_DIR")"
rmdir "$VOCULINUX_TMP_DIR"
# A bootstrap read from a pipe (curl | bash) leaves its unread tail on
# stdin: bash hands the pipe to the tagged installer, which reads its
# commands from a file instead, so nothing drains it. A producer still
@@ -537,12 +537,12 @@ handoff_to_tagged_installer() {
fi
bash "$tagged_installer" "${INSTALLER_ARGS[@]}" "--venv-dir=$remote_venv" || return $?
if [ ! -f "$INSTALL_DIR/activate-vocalinux.sh" ]; then
print_error "The tagged installer did not create activate-vocalinux.sh."
if [ ! -f "$INSTALL_DIR/activate-voculinux.sh" ]; then
print_error "The tagged installer did not create activate-voculinux.sh."
return 1
fi
mkdir -p "$HOME/.local/bin"
mv "$INSTALL_DIR/activate-vocalinux.sh" "$HOME/.local/bin/activate-vocalinux.sh"
mv "$INSTALL_DIR/activate-voculinux.sh" "$HOME/.local/bin/activate-voculinux.sh"
}
# Function to check and install git if needed
@@ -664,17 +664,17 @@ ensure_git_installed() {
print_success "git installed successfully!"
}
# Check if running from within the vocalinux repository
# Validate that pyproject.toml/setup.py actually belongs to vocalinux before entering local repo mode
IS_VOCALINUX_LOCAL=false
if [ -f "pyproject.toml" ] && grep -q 'name = "vocalinux"' "pyproject.toml" 2>/dev/null; then
IS_VOCALINUX_LOCAL=true
elif [ -f "setup.py" ] && grep -q "vocalinux" "setup.py" 2>/dev/null; then
IS_VOCALINUX_LOCAL=true
# Check if running from within the voculinux repository
# Validate that pyproject.toml/setup.py actually belongs to voculinux before entering local repo mode
IS_VOCULINUX_LOCAL=false
if [ -f "pyproject.toml" ] && grep -q 'name = "voculinux"' "pyproject.toml" 2>/dev/null; then
IS_VOCULINUX_LOCAL=true
elif [ -f "setup.py" ] && grep -q "voculinux" "setup.py" 2>/dev/null; then
IS_VOCULINUX_LOCAL=true
fi
if [ "$IS_VOCALINUX_LOCAL" = true ]; then
# Running from within the vocalinux repo
if [ "$IS_VOCULINUX_LOCAL" = true ]; then
# Running from within the voculinux repo
INSTALL_DIR="$(pwd)"
print_info "Running from local repository: $INSTALL_DIR"
# Convert relative VENV_DIR to absolute for wrapper scripts.
@@ -690,26 +690,26 @@ else
print_error "Re-run with an explicit release tag, e.g.: --tag=<release>"
exit "$EXIT_NETWORK"
fi
print_info "Installing Vocalinux version: ${INSTALL_TAG}"
print_info "Installing Voculinux version: ${INSTALL_TAG}"
# Ensure git is installed before attempting to clone
ensure_git_installed
INSTALL_DIR="$HOME/.local/share/vocalinux-install"
INSTALL_DIR="$HOME/.local/share/voculinux-install"
mkdir -p "$INSTALL_DIR"
if [ -d "$INSTALL_DIR/.git" ]; then
print_info "Updating existing clone..."
cd "$INSTALL_DIR"
if ! git fetch origin tag "$INSTALL_TAG" || ! git reset --hard "$INSTALL_TAG"; then
print_error "Failed to update the Vocalinux clone to $INSTALL_TAG."
print_error "Failed to update the Voculinux clone to $INSTALL_TAG."
print_error "Check the install log and your network connection: $INSTALL_LOG_FILE"
exit "$EXIT_NETWORK"
fi
else
rm -rf "$INSTALL_DIR"
git clone --depth 1 --branch "$INSTALL_TAG" "$REPO_URL" "$INSTALL_DIR" || {
print_error "Failed to clone Vocalinux repository"
print_error "Failed to clone Voculinux repository"
exit "$EXIT_NETWORK"
}
cd "$INSTALL_DIR"
@@ -1270,7 +1270,7 @@ detect_distro
# Check compatibility. These tiers mirror docs/DISTRO_COMPATIBILITY.md, and the
# distro matrix builds on ubuntu, debian and fedora. Nothing here decides whether
# the install can proceed: what Vocalinux needs is an interpreter at the floor
# the install can proceed: what Voculinux needs is an interpreter at the floor
# and that interpreter's distro PyGObject, checked by check_python_version()
# (fatal) and require_distro_gi() further down. This block only says how much
# help the package step is likely to be, so it must not turn away a distro the
@@ -1286,7 +1286,7 @@ case "$DISTRO_FAMILY" in
;;
*)
print_warning "This installer has not been tested on $DISTRO_NAME; you may need to install dependencies manually."
print_warning "Vocalinux itself does not care which distribution it runs on, only that Python and PyGObject are new enough."
print_warning "Voculinux itself does not care which distribution it runs on, only that Python and PyGObject are new enough."
if [[ "$NON_INTERACTIVE" == "yes" ]]; then
print_info "Non-interactive mode: continuing anyway..."
else
@@ -1301,8 +1301,8 @@ esac
# Define XDG directories early: existing-install detection and the mode menu
# need CONFIG_DIR before system dependency installation asks anything.
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/vocalinux"
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/vocalinux"
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/voculinux"
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/voculinux"
DESKTOP_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/applications"
ICON_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor/scalable/apps"
@@ -1322,7 +1322,7 @@ choose_installation_mode() {
echo ""
echo "Installation Mode:"
if [[ "${EXISTING_INSTALL:-no}" == "yes" ]]; then
echo " 1. Upgrade (keep current settings) - update Vocalinux, keep your setup"
echo " 1. Upgrade (keep current settings) - update Voculinux, keep your setup"
echo " 2. Interactive - guided setup with recommendations"
echo " 3. Automatic - quick install with defaults (whisper.cpp)"
echo ""
@@ -1653,7 +1653,7 @@ install_pinned_build_tools() {
print_info "Installing pinned pip and source-build tools..."
"$VENV_DIR/bin/python" -m pip install --require-hashes --no-deps \
--only-binary=:all: --ignore-installed \
-r "$reqs_file" --log "$VOCALINUX_TMP_DIR/bootstrap.log"
-r "$reqs_file" --log "$VOCULINUX_TMP_DIR/bootstrap.log"
}
install_pinned_build_tools || {
print_error "Failed to install the pinned build tools. Check requirements/installer-build.txt."
@@ -1668,15 +1668,15 @@ if [[ "$CLEANUP_ON_EXIT" == "yes" ]]; then
else
ACTIVATION_SCRIPT_DIR="."
fi
ACTIVATION_SCRIPT="$ACTIVATION_SCRIPT_DIR/activate-vocalinux.sh"
ACTIVATION_SCRIPT="$ACTIVATION_SCRIPT_DIR/activate-voculinux.sh"
cat > "$ACTIVATION_SCRIPT" << EOF
#!/bin/bash
# This script activates the Vocalinux virtual environment
# This script activates the Voculinux virtual environment
export PYTHONNOUSERSITE=1
source "$VENV_DIR/bin/activate"
echo "Vocalinux virtual environment activated."
echo "To start the application, run: vocalinux"
echo "Voculinux virtual environment activated."
echo "To start the application, run: voculinux"
EOF
chmod +x "$ACTIVATION_SCRIPT"
print_info "Created activation script: $ACTIVATION_SCRIPT"
@@ -1897,7 +1897,7 @@ install_cpu_pywhispercpp() {
pip_reinstall_pywhispercpp() {
local pip_log="$1"
shift
local reqs_file="$VOCALINUX_TMP_DIR/pywhispercpp.txt"
local reqs_file="$VOCULINUX_TMP_DIR/pywhispercpp.txt"
"$VENV_DIR/bin/python" "$INSTALL_DIR/scripts/installer_requirements.py" \
"$INSTALL_DIR/requirements/runtime.txt" "$reqs_file" --package pywhispercpp || return 1
# --no-deps preserves the locked runtime and avoids reinstalling numpy
@@ -2190,7 +2190,7 @@ install_whispercpp_with_gpu_support() {
fi
if ! is_pywhispercpp_installed; then
print_warning "pywhispercpp is still unavailable; setting VOSK as the default engine so Vocalinux can start."
print_warning "pywhispercpp is still unavailable; setting VOSK as the default engine so Voculinux can start."
print_warning "You can switch back to whisper.cpp from Settings after reinstalling pywhispercpp."
SELECTED_ENGINE="vosk"
@@ -2304,7 +2304,7 @@ pip_install_extras_skip_pygobject() {
# Function to install Python package with error handling and verification
install_python_package() {
# Pip logs live in the install scratch dir so a failed run can keep them.
local PIP_LOG_DIR="$VOCALINUX_TMP_DIR/pip"
local PIP_LOG_DIR="$VOCULINUX_TMP_DIR/pip"
mkdir -p "$PIP_LOG_DIR"
local PIP_LOG_FILE="$PIP_LOG_DIR/pip_log.txt"
@@ -2351,21 +2351,21 @@ PY
print_success "Neural VAD support installed and verified successfully."
else
print_warning "Neural VAD dependencies installed, but Silero VAD could not be verified."
print_warning "Vocalinux will use amplitude-based VAD until this is resolved."
print_warning "Voculinux will use amplitude-based VAD until this is resolved."
fi
else
print_warning "Failed to install neural VAD support."
print_warning "Vocalinux will still work using amplitude-based VAD."
print_warning "Voculinux will still work using amplitude-based VAD."
print_warning "Check the pip log for details: $PIP_LOG_FILE"
fi
}
if [[ "$DEV_MODE" == "yes" ]]; then
print_info "Installing Vocalinux in development mode..."
print_info "Installing Voculinux in development mode..."
# Install in development mode with logging
pip_install_project_skip_pygobject "$PIP_LOG_FILE" -e . || {
print_error "Failed to install Vocalinux in development mode."
print_error "Failed to install Voculinux in development mode."
print_error "Check the pip log for details: $PIP_LOG_FILE"
return 1
}
@@ -2389,11 +2389,11 @@ PY
install_whispercpp_with_gpu_support "$PIP_LOG_FILE"
fi
else
print_info "Installing Vocalinux..."
print_info "Installing Voculinux..."
# Install the package with logging (includes pywhispercpp by default)
pip_install_project_skip_pygobject "$PIP_LOG_FILE" . || {
print_error "Failed to install Vocalinux."
print_error "Failed to install Voculinux."
print_error "Check the pip log for details: $PIP_LOG_FILE"
return 1
}
@@ -2701,8 +2701,8 @@ FASTER_WHISPER_CONFIG
# Verify installation
if verify_package_installed; then
print_success "Vocalinux package installed successfully!"
# Pip logs stay under VOCALINUX_TMP_DIR; the EXIT trap removes that
print_success "Voculinux package installed successfully!"
# Pip logs stay under VOCULINUX_TMP_DIR; the EXIT trap removes that
# directory on success and keeps it when a later step fails.
# GI_TYPELIB_PATH was already detected at the start of install_python_package
@@ -2720,10 +2720,10 @@ else
exec $EXEC_CMD
fi'
# Create vocalinux wrapper script
cat > "$HOME/.local/bin/vocalinux" << WRAPPER_EOF
# Create voculinux wrapper script
cat > "$HOME/.local/bin/voculinux" << WRAPPER_EOF
#!/bin/bash
# Wrapper script for Vocalinux that sets required environment variables
# Wrapper script for Voculinux that sets required environment variables
# and applies the 'input' group for keyboard shortcuts on Wayland
export PYTHONNOUSERSITE=1
export GI_TYPELIB_PATH=$GI_TYPELIB_DETECTED
@@ -2754,16 +2754,16 @@ if [ -n "\$PYWHISPERCPP_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="\$PYWHISPERCPP_LIBRARY_PATH\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}"
fi
EXEC_CMD="$VENV_DIR/bin/vocalinux \$*"
EXEC_CMD="$VENV_DIR/bin/voculinux \$*"
$SG_CHECK
WRAPPER_EOF
chmod +x "$HOME/.local/bin/vocalinux"
print_info "Created wrapper: ~/.local/bin/vocalinux"
chmod +x "$HOME/.local/bin/voculinux"
print_info "Created wrapper: ~/.local/bin/voculinux"
# Create vocalinux-gui wrapper script
cat > "$HOME/.local/bin/vocalinux-gui" << WRAPPER_EOF
# Create voculinux-gui wrapper script
cat > "$HOME/.local/bin/voculinux-gui" << WRAPPER_EOF
#!/bin/bash
# Wrapper script for Vocalinux GUI that sets required environment variables
# Wrapper script for Voculinux GUI that sets required environment variables
# and applies the 'input' group for keyboard shortcuts on Wayland
export PYTHONNOUSERSITE=1
export GI_TYPELIB_PATH=$GI_TYPELIB_DETECTED
@@ -2794,11 +2794,11 @@ if [ -n "\$PYWHISPERCPP_LIBRARY_PATH" ]; then
export LD_LIBRARY_PATH="\$PYWHISPERCPP_LIBRARY_PATH\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}"
fi
EXEC_CMD="$VENV_DIR/bin/vocalinux-gui \$*"
EXEC_CMD="$VENV_DIR/bin/voculinux-gui \$*"
$SG_CHECK
WRAPPER_EOF
chmod +x "$HOME/.local/bin/vocalinux-gui"
print_info "Created wrapper: ~/.local/bin/vocalinux-gui"
chmod +x "$HOME/.local/bin/voculinux-gui"
print_info "Created wrapper: ~/.local/bin/voculinux-gui"
# Check if ~/.local/bin is in PATH
if [[ ":$PATH:" != *":$HOME/.local/bin:"* ]]; then
@@ -2809,7 +2809,7 @@ WRAPPER_EOF
return 0
else
print_error "Vocalinux package installation verification failed."
print_error "Voculinux package installation verification failed."
print_error "Check the pip log for details: $PIP_LOG_FILE"
return 1
fi
@@ -2817,7 +2817,7 @@ WRAPPER_EOF
# Install Python package
if ! install_python_package; then
print_error "Failed to install Vocalinux package. Installation cannot continue."
print_error "Failed to install Voculinux package. Installation cannot continue."
exit "$EXIT_NETWORK"
fi
@@ -2907,7 +2907,7 @@ PY
if [[ "${UPGRADE_MODE:-no}" == "yes" ]]; then
# Upgrade mode never rewrites config.json: report instead of repairing.
print_error "Vocalinux cannot start with this configuration and the engine is not installed."
print_error "Voculinux cannot start with this configuration and the engine is not installed."
print_error "Install the engine: $VENV_DIR/bin/pip install $(engine_pip_name "$CONFIGURED_ENGINE")"
print_error "or edit $CONFIG_FILE and set speech_recognition.engine to an installed engine."
return 1
@@ -2934,7 +2934,7 @@ PY
fi
done
print_error "Vocalinux cannot start with this configuration and no working engine is available."
print_error "Voculinux cannot start with this configuration and no working engine is available."
print_error "Install the engine: $VENV_DIR/bin/pip install $(engine_pip_name "$CONFIGURED_ENGINE")"
print_error "or edit $CONFIG_FILE and set speech_recognition.engine to an installed engine."
return 1
@@ -2954,7 +2954,7 @@ run_tests() {
# Check if pytest is installed in the virtual environment
if ! "$VENV_DIR/bin/python" -c "import pytest" &>/dev/null; then
print_info "Installing pytest and related packages..."
local PIP_LOG_FILE="$VOCALINUX_TMP_DIR/test-deps.log"
local PIP_LOG_FILE="$VOCULINUX_TMP_DIR/test-deps.log"
pip_install_extras_skip_pygobject "$PIP_LOG_FILE" dev || {
print_error "Failed to install pytest. Cannot run tests."
return 1
@@ -2962,7 +2962,7 @@ run_tests() {
fi
# Create a directory for test results
local TEST_RESULTS_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/vocalinux/test_results"
local TEST_RESULTS_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/voculinux/test_results"
mkdir -p "$TEST_RESULTS_DIR"
local TEST_RESULTS_FILE="$TEST_RESULTS_DIR/pytest_$(date +%Y%m%d_%H%M%S).xml"
@@ -3007,21 +3007,21 @@ verify_installation() {
ISSUES=$((ISSUES + 1))
fi
# Check if vocalinux command is available
if ! command -v vocalinux &>/dev/null && [ ! -f "$VENV_DIR/bin/vocalinux" ]; then
print_error "Vocalinux command not found."
# Check if voculinux command is available
if ! command -v voculinux &>/dev/null && [ ! -f "$VENV_DIR/bin/voculinux" ]; then
print_error "Voculinux command not found."
ISSUES=$((ISSUES + 1))
fi
# Check if desktop entry is installed
if [ ! -f "$DESKTOP_DIR/vocalinux.desktop" ]; then
if [ ! -f "$DESKTOP_DIR/voculinux.desktop" ]; then
print_warning "Desktop entry not found. Application may not appear in application menu."
ISSUES=$((ISSUES + 1))
fi
# Check if icons are installed
local ICON_COUNT=0
for icon in vocalinux.svg vocalinux-microphone.svg vocalinux-microphone-off.svg vocalinux-microphone-process.svg; do
for icon in voculinux.svg voculinux-microphone.svg voculinux-microphone-off.svg voculinux-microphone-process.svg; do
if [ -f "$ICON_DIR/$icon" ]; then
ICON_COUNT=$((ICON_COUNT + 1))
fi
@@ -3034,7 +3034,7 @@ verify_installation() {
# Check if Python package is importable using venv python
if ! "$VENV_DIR/bin/python" -c "import vocalinux" &>/dev/null; then
print_error "Vocalinux Python package cannot be imported."
print_error "Voculinux Python package cannot be imported."
ISSUES=$((ISSUES + 1))
fi
@@ -3094,7 +3094,7 @@ EOF
# Success or warning message
if [ "$ISSUES" -eq 0 ]; then
print_success "Vocalinux has been installed successfully!"
print_success "Voculinux has been installed successfully!"
else
print_warning "Installation complete with $ISSUES minor issue(s)"
print_warning "The application should still work normally."
@@ -3141,12 +3141,12 @@ EOF
echo " 📦 What Was Installed"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " Application: Vocalinux (voice dictation for Linux)"
echo " Application: Voculinux (voice dictation for Linux)"
echo " Engine: $ENGINE_DISPLAY_NAME"
if [[ -n "$BACKEND_INFO" ]]; then
echo " Backend: $BACKEND_INFO"
fi
echo " Location: ${INSTALL_DIR:-\$HOME/.local/share/vocalinux}"
echo " Location: ${INSTALL_DIR:-\$HOME/.local/share/voculinux}"
echo " Virtual Env: $VENV_DIR"
echo " Config: $CONFIG_DIR"
echo ""
@@ -3155,9 +3155,9 @@ EOF
echo " 🚀 Getting Started"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "1. Launch Vocalinux"
echo " • From app menu: Look for 'Vocalinux'"
echo " • From terminal: Run 'vocalinux' command"
echo "1. Launch Voculinux"
echo " • From app menu: Look for 'Voculinux'"
echo " • From terminal: Run 'voculinux' command"
echo ""
echo "2. Find the icon in your system tray (top bar)"
echo " • Click for settings and status"
@@ -3180,16 +3180,16 @@ EOF
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " 🔧 Managing Vocalinux"
echo " 🔧 Managing Voculinux"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Commands:"
echo " vocalinux Start the application"
echo " vocalinux --debug Start with debug logging"
echo " vocalinux-gui Open settings GUI"
echo " voculinux Start the application"
echo " voculinux --debug Start with debug logging"
echo " voculinux-gui Open settings GUI"
echo ""
echo "To activate the virtual environment:"
echo " source ${ACTIVATION_SCRIPT:-activate-vocalinux.sh}"
echo " source ${ACTIVATION_SCRIPT:-activate-voculinux.sh}"
echo ""
echo "To uninstall:"
echo " ./uninstall.sh"
@@ -3215,10 +3215,10 @@ EOF
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Virtual environment: $VENV_DIR"
echo "Desktop entry: $DESKTOP_DIR/vocalinux.desktop"
echo "Desktop entry: $DESKTOP_DIR/voculinux.desktop"
echo "Configuration: $CONFIG_DIR"
echo "Data directory: $DATA_DIR"
echo "Wrapper script: $HOME/.local/bin/vocalinux"
echo "Wrapper script: $HOME/.local/bin/voculinux"
echo ""
fi
}