v0.2.0: System tray, IPC status, VAD, hotkey grab, and polish
- Add system tray icon with Exit menu (tray-icon/muda) - Add IPC daemon status via named pipe (Windows) / Unix socket (Linux) - Add `mouth status` command to query running daemon - Add daemon lock to prevent multiple instances - Hide Windows console window when running as daemon - Wire up Silero VAD model download and speech filtering - Switch hotkey listener from rdev::listen to rdev::grab to consume hotkeys - Add hotkey capture mode in interactive config (press keys instead of typing) - Add all missing key names (brackets, punctuation, numpad, etc.) - Fix ONNX tensor type mismatches (encoder wants i64, decoder wants i32) - Add 300ms lead-in silence to compensate for mic startup latency - Add 300ms trailing recording after stop for speech not to be clipped - Add 50ms silence before audio feedback blips for device warmup - Reduce overlay size (150x18, was 200x36) - Add PolyForm Noncommercial 1.0.0 license - Flesh out user-focused README - Update release script with Gitea/GitHub forge support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+116
-32
@@ -1,11 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ============================================================
|
||||
# Release configuration
|
||||
# ============================================================
|
||||
REPO="https://gitea.dcglab.co.uk/steve/mouth"
|
||||
FORGE="gitea" # "gitea" (uses tea CLI) or "github" (uses gh CLI)
|
||||
|
||||
# ============================================================
|
||||
# Derived variables
|
||||
# ============================================================
|
||||
VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
||||
RELEASE_DIR="release/v${VERSION}"
|
||||
BINARY_NAME="mouth"
|
||||
TAG="v${VERSION}"
|
||||
|
||||
echo "=== Mouth Release Build v${VERSION} ==="
|
||||
echo "=== Mouth Release Build ${TAG} ==="
|
||||
echo "Forge: ${FORGE} (${REPO})"
|
||||
echo ""
|
||||
|
||||
# Ensure we're in the project root
|
||||
@@ -14,6 +25,22 @@ if [ ! -f Cargo.toml ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check CLI tools
|
||||
if [ "${FORGE}" = "gitea" ]; then
|
||||
if ! command -v tea &>/dev/null; then
|
||||
echo "ERROR: 'tea' CLI not found. Install: https://gitea.com/gitea/tea"
|
||||
exit 1
|
||||
fi
|
||||
elif [ "${FORGE}" = "github" ]; then
|
||||
if ! command -v gh &>/dev/null; then
|
||||
echo "ERROR: 'gh' CLI not found. Install: https://cli.github.com"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "ERROR: Unknown forge '${FORGE}'. Must be 'gitea' or 'github'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean previous release artifacts for this version
|
||||
rm -rf "${RELEASE_DIR}"
|
||||
mkdir -p "${RELEASE_DIR}"
|
||||
@@ -32,19 +59,12 @@ build_target() {
|
||||
if cargo build --release --target "${target}" 2>&1; then
|
||||
local binary="target/${target}/release/${BINARY_NAME}${ext}"
|
||||
if [ -f "${binary}" ]; then
|
||||
local archive="${RELEASE_DIR}/${BINARY_NAME}-v${VERSION}-${target}"
|
||||
local archive="${RELEASE_DIR}/${BINARY_NAME}-${TAG}-${target}"
|
||||
if [ -n "${ext}" ]; then
|
||||
# Windows: zip
|
||||
local zip_name="${archive}.zip"
|
||||
zip -j "${zip_name}" "${binary}" 2>/dev/null || {
|
||||
# Fallback if zip not installed
|
||||
cp "${binary}" "${archive}${ext}"
|
||||
echo " -> ${archive}${ext}"
|
||||
BUILT+=("${archive}${ext}")
|
||||
return
|
||||
}
|
||||
echo " -> ${zip_name}"
|
||||
BUILT+=("${zip_name}")
|
||||
# Windows: ship the exe directly
|
||||
cp "${binary}" "${archive}${ext}"
|
||||
echo " -> ${archive}${ext}"
|
||||
BUILT+=("${archive}${ext}")
|
||||
else
|
||||
# Linux/macOS: tar.gz
|
||||
local tar_name="${archive}.tar.gz"
|
||||
@@ -71,30 +91,15 @@ build_target() {
|
||||
build_target "x86_64-unknown-linux-gnu" "Linux x86_64"
|
||||
|
||||
# Windows x86_64 (MSVC target via cargo-xwin)
|
||||
# ort requires the MSVC target — the GNU/MinGW target has no prebuilt
|
||||
# ONNX Runtime binaries. cargo-xwin cross-compiles using the MSVC
|
||||
# toolchain from Linux without needing a Windows machine.
|
||||
#
|
||||
# Install once:
|
||||
# cargo install cargo-xwin
|
||||
# rustup target add x86_64-pc-windows-msvc
|
||||
#
|
||||
if command -v cargo-xwin &>/dev/null && rustup target list --installed | grep -q x86_64-pc-windows-msvc; then
|
||||
echo "--- Building Windows x86_64 (x86_64-pc-windows-msvc via cargo-xwin) ---"
|
||||
if cargo xwin build --release --target x86_64-pc-windows-msvc 2>&1; then
|
||||
local_binary="target/x86_64-pc-windows-msvc/release/${BINARY_NAME}.exe"
|
||||
if [ -f "${local_binary}" ]; then
|
||||
archive="${RELEASE_DIR}/${BINARY_NAME}-v${VERSION}-x86_64-pc-windows-msvc"
|
||||
zip_name="${archive}.zip"
|
||||
zip -j "${zip_name}" "${local_binary}" 2>/dev/null || {
|
||||
cp "${local_binary}" "${archive}.exe"
|
||||
echo " -> ${archive}.exe"
|
||||
BUILT+=("${archive}.exe")
|
||||
}
|
||||
if [ -f "${zip_name}" ]; then
|
||||
echo " -> ${zip_name}"
|
||||
BUILT+=("${zip_name}")
|
||||
fi
|
||||
archive="${RELEASE_DIR}/${BINARY_NAME}-${TAG}-x86_64-pc-windows-msvc.exe"
|
||||
cp "${local_binary}" "${archive}"
|
||||
echo " -> ${archive}"
|
||||
BUILT+=("${archive}")
|
||||
else
|
||||
echo " WARN: Binary not found"
|
||||
FAILED+=("Windows x86_64 (MSVC)")
|
||||
@@ -149,3 +154,82 @@ if [ ${#BUILT[@]} -gt 0 ]; then
|
||||
cat checksums-sha256.txt
|
||||
cd - > /dev/null
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Publish release
|
||||
# ============================================================
|
||||
|
||||
if [ ${#BUILT[@]} -eq 0 ]; then
|
||||
echo ""
|
||||
echo "No successful builds — skipping release publish."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -rp "Publish release ${TAG} to ${FORGE}? [y/N] " confirm
|
||||
if [[ ! "${confirm}" =~ ^[Yy]$ ]]; then
|
||||
echo "Skipped. Artifacts are in ${RELEASE_DIR}/"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Ensure the git tag exists
|
||||
if ! git rev-parse "${TAG}" &>/dev/null; then
|
||||
echo "Creating git tag ${TAG}..."
|
||||
git tag -a "${TAG}" -m "Release ${TAG}"
|
||||
git push origin "${TAG}"
|
||||
fi
|
||||
|
||||
# Collect all release files (artifacts + checksums)
|
||||
RELEASE_FILES=()
|
||||
for b in "${BUILT[@]}"; do
|
||||
RELEASE_FILES+=("${b}")
|
||||
done
|
||||
RELEASE_FILES+=("${RELEASE_DIR}/checksums-sha256.txt")
|
||||
|
||||
RELEASE_TITLE="Mouth ${TAG}"
|
||||
RELEASE_BODY="## Mouth ${TAG}
|
||||
|
||||
### Downloads
|
||||
$(for b in "${BUILT[@]}"; do echo "- $(basename "${b}")"; done)
|
||||
|
||||
### Checksums (SHA256)
|
||||
\`\`\`
|
||||
$(cat "${RELEASE_DIR}/checksums-sha256.txt")
|
||||
\`\`\`
|
||||
"
|
||||
|
||||
if [ "${FORGE}" = "gitea" ]; then
|
||||
echo "Publishing to Gitea via tea..."
|
||||
|
||||
# Extract host and owner/repo from REPO URL
|
||||
REPO_OWNER_NAME=$(echo "${REPO}" | sed 's|.*://[^/]*/||')
|
||||
|
||||
# Create the release
|
||||
tea release create \
|
||||
--repo "${REPO_OWNER_NAME}" \
|
||||
--tag "${TAG}" \
|
||||
--title "${RELEASE_TITLE}" \
|
||||
--note "${RELEASE_BODY}"
|
||||
|
||||
# Upload assets
|
||||
for f in "${RELEASE_FILES[@]}"; do
|
||||
echo " Uploading $(basename "${f}")..."
|
||||
tea release asset create \
|
||||
--repo "${REPO_OWNER_NAME}" \
|
||||
--tag "${TAG}" \
|
||||
--name "$(basename "${f}")" \
|
||||
--file "${f}"
|
||||
done
|
||||
|
||||
elif [ "${FORGE}" = "github" ]; then
|
||||
echo "Publishing to GitHub via gh..."
|
||||
|
||||
gh release create "${TAG}" \
|
||||
--repo "${REPO}" \
|
||||
--title "${RELEASE_TITLE}" \
|
||||
--notes "${RELEASE_BODY}" \
|
||||
"${RELEASE_FILES[@]}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Release ${TAG} published to ${FORGE}! ==="
|
||||
|
||||
Reference in New Issue
Block a user