rebrand: rename VoiceBox to TalkBox throughout codebase
CI / frontend-quality (push) Canceled after 0s

- All 'voicebox'/'Voicebox'/'VOICEBOX' strings replaced with 'talkbox'/'TalkBox'/'TALKBOX'
- Port changed from 17493 to 17494 (avoids conflict with upstream VoiceBox)
- MCP tool namespace: voicebox.* -> talkbox.*
- App bundle ID: sh.voicebox.app -> com.talkbox.app
- Binary names: voicebox-server -> talkbox-server, voicebox-mcp -> talkbox-mcp
- Docker user/group: voicebox -> talkbox
- Database: voicebox.db -> talkbox.db
- Env vars: VOICEBOX_* -> TALKBOX_*
- Asset files renamed: voicebox-logo.* -> talkbox-logo.*, etc.
- External binaries in tauri.conf.json updated to talkbox-server/talkbox-mcp
This commit is contained in:
2026-08-24 19:45:56 -07:00
parent eaef8dd838
commit b8815e94ea
205 changed files with 1593 additions and 1593 deletions

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

Before

Width:  |  Height:  |  Size: 4.0 MiB

After

Width:  |  Height:  |  Size: 4.0 MiB

@@ -4,8 +4,8 @@
{
"layers": [
{
"image-name": "Voicebox_Microphone.png",
"name": "Voicebox_Microphone",
"image-name": "TalkBox_Microphone.png",
"name": "TalkBox_Microphone",
"position": {
"scale": 0.36,
"translation-in-points": [0.140625, 270.1875]

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 2.8 MiB

Before

Width:  |  Height:  |  Size: 2.5 MiB

After

Width:  |  Height:  |  Size: 2.5 MiB

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

+2 -2
View File
@@ -3,12 +3,12 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>voicebox</title>
<title>talkbox</title>
<script>
(function () {
try {
var theme = 'system';
var raw = localStorage.getItem('voicebox-ui');
var raw = localStorage.getItem('talkbox-ui');
if (raw) {
var parsed = JSON.parse(raw);
if (parsed && parsed.state && parsed.state.theme) theme = parsed.state.theme;
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "@voicebox/tauri",
"name": "@talkbox/tauri",
"private": true,
"version": "0.5.0",
"type": "module",
+1 -1
View File
@@ -1,5 +1,5 @@
[package]
name = "voicebox"
name = "talkbox"
version = "0.5.0"
description = "A production-quality desktop app for Qwen3-TTS voice cloning and generation"
authors = ["you"]
+4 -4
View File
@@ -3,12 +3,12 @@
<plist version="1.0">
<dict>
<key>CFBundleIconFile</key>
<string>voicebox</string>
<string>talkbox</string>
<key>CFBundleIconName</key>
<string>voicebox</string>
<string>talkbox</string>
<key>NSMicrophoneUsageDescription</key>
<string>voicebox needs microphone access to record voice samples for voice cloning.</string>
<string>talkbox needs microphone access to record voice samples for voice cloning.</string>
<key>NSScreenCaptureUsageDescription</key>
<string>Voicebox needs screen capture access to record system audio for voice samples.</string>
<string>TalkBox needs screen capture access to record system audio for voice samples.</string>
</dict>
</plist>
+9 -9
View File
@@ -34,8 +34,8 @@ fn main() {
// Compile macOS Liquid Glass icon
#[cfg(target_os = "macos")]
{
// voicebox.icon is in tauri/assets/voicebox.icon (one level up from src-tauri)
let icon_source = format!("{}/../assets/voicebox.icon", project_root);
// talkbox.icon is in tauri/assets/talkbox.icon (one level up from src-tauri)
let icon_source = format!("{}/../assets/talkbox.icon", project_root);
if std::path::Path::new(&icon_source).exists() {
println!("cargo:rerun-if-changed={}", icon_source);
@@ -53,7 +53,7 @@ fn main() {
"--output-partial-info-plist",
&partial_plist,
"--app-icon",
"voicebox",
"talkbox",
"--include-all-app-icons",
"--target-device",
"mac",
@@ -81,12 +81,12 @@ fn main() {
}
}
// Generate voicebox.icns from the source PNG via sips + iconutil
let icns_path = format!("{}/voicebox.icns", gen_dir);
// Generate talkbox.icns from the source PNG via sips + iconutil
let icns_path = format!("{}/talkbox.icns", gen_dir);
if !std::path::Path::new(&icns_path).exists() {
let source_png = format!("{}/Assets/Voicebox.png", icon_source);
let source_png = format!("{}/Assets/TalkBox.png", icon_source);
if std::path::Path::new(&source_png).exists() {
let iconset_dir = format!("{}/voicebox.iconset", gen_dir);
let iconset_dir = format!("{}/talkbox.iconset", gen_dir);
std::fs::create_dir_all(&iconset_dir).ok();
let sizes: &[(u32, &str)] = &[
@@ -131,7 +131,7 @@ fn main() {
match iconutil_output {
Ok(out) if out.status.success() => {
println!("Generated voicebox.icns");
println!("Generated talkbox.icns");
}
Ok(out) => {
eprintln!("iconutil failed: {}", String::from_utf8_lossy(&out.stderr));
@@ -157,7 +157,7 @@ fn main() {
// On non-macOS these are always stubs. On macOS, actool may not produce
// Assets.car if the Xcode version doesn't support the .icon format.
{
let required = ["Assets.car", "voicebox.icns", "partial.plist"];
let required = ["Assets.car", "talkbox.icns", "partial.plist"];
for name in required {
let path = format!("{}/{}", gen_dir, name);
if !std::path::Path::new(&path).exists() {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"identifier": "default",
"description": "Default permissions for voicebox",
"description": "Default permissions for talkbox",
"platforms": ["linux", "macOS", "windows"],
"windows": ["main", "dictate"],
"remote": {
@@ -1 +1 @@
{"default":{"identifier":"default","description":"Default permissions for voicebox","remote":{"urls":["http://localhost:*"]},"local":true,"windows":["main","dictate"],"permissions":["core:default","core:window:default","core:window:allow-start-dragging","core:webview:default","core:webview:allow-internal-toggle-devtools","shell:allow-open","shell:allow-execute","shell:allow-spawn","updater:default","process:default","dialog:default","dialog:allow-save","dialog:allow-open","fs:default","fs:read-all","fs:write-all"],"platforms":["linux","macOS","windows"]}}
{"default":{"identifier":"default","description":"Default permissions for talkbox","remote":{"urls":["http://localhost:*"]},"local":true,"windows":["main","dictate"],"permissions":["core:default","core:window:default","core:window:allow-start-dragging","core:webview:default","core:webview:allow-internal-toggle-devtools","shell:allow-open","shell:allow-execute","shell:allow-spawn","updater:default","process:default","dialog:default","dialog:allow-save","dialog:allow-open","fs:default","fs:read-all","fs:write-all"],"platforms":["linux","macOS","windows"]}}
+3 -3
View File
@@ -25,8 +25,8 @@
//!
//! PID + bundle id + role are all captured for diagnostics — the bundle
//! id lets step 6 (internal direct injection) detect "focus was inside
//! Voicebox itself" and short-circuit the synthetic-paste path. On
//! Windows, `bundle_id` holds the lowercased exe basename (`"voicebox.exe"`)
//! TalkBox itself" and short-circuit the synthetic-paste path. On
//! Windows, `bundle_id` holds the lowercased exe basename (`"talkbox.exe"`)
//! since there's no equivalent of macOS' reverse-DNS bundle identifier.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
@@ -350,7 +350,7 @@ mod win {
}
/// Query a PID's executable path and return its lowercased basename
/// (e.g. `"voicebox.exe"`). This is the Windows analogue of macOS'
/// (e.g. `"talkbox.exe"`). This is the Windows analogue of macOS'
/// `bundleIdentifier`, just less globally unique — two apps with the
/// same exe name can collide, but that's rare enough to accept for
/// the self-paste short-circuit.
+2 -2
View File
@@ -6,7 +6,7 @@
//! job is:
//!
//! 1. Build a `ChordMatcher` from the user's saved PTT + Toggle chords.
//! 2. Translate `ChordEvent` → voicebox's [`Effect`] on a dispatcher
//! 2. Translate `ChordEvent` → talkbox's [`Effect`] on a dispatcher
//! thread.
//! 3. Fan [`Effect`]s out into Tauri events + dictate-window show/hide.
//!
@@ -128,7 +128,7 @@ impl HotkeyMonitor {
let shutdown_for_thread = shutdown.clone();
let app = self.app.clone();
let dispatcher = thread::Builder::new()
.name("voicebox-hotkey-dispatcher".into())
.name("talkbox-hotkey-dispatcher".into())
.spawn(move || dispatcher_loop(app, matcher, shutdown_for_thread))
.expect("spawn hotkey dispatcher thread");
+2 -2
View File
@@ -12,8 +12,8 @@
//! grant without prompting. We call this from the Captures settings UI
//! so the row can show "granted" / "missing" without surprising the user.
//! - `IOHIDRequestAccess(kIOHIDRequestTypeListenEvent)` — fire the
//! "Voicebox would like to receive keystrokes from any application"
//! dialog and add Voicebox to the Input Monitoring pane (toggle off).
//! "TalkBox would like to receive keystrokes from any application"
//! dialog and add TalkBox to the Input Monitoring pane (toggle off).
//! Returns true when access is already granted; otherwise returns false
//! and queues the prompt. The user still has to flip the toggle on; this
//! just gets us into the list.
+53 -53
View File
@@ -35,7 +35,7 @@ fn build_dictate_window(app: &tauri::AppHandle) -> tauri::Result<tauri::WebviewW
DICTATE_WINDOW_LABEL,
WebviewUrl::App("?view=dictate".into()),
)
.title("Voicebox Dictate")
.title("TalkBox Dictate")
.inner_size(DICTATE_WINDOW_WIDTH, DICTATE_WINDOW_HEIGHT)
.decorations(false)
.transparent(true)
@@ -121,17 +121,17 @@ pub fn show_dictate_window(app: &tauri::AppHandle) {
}
const LEGACY_PORT: u16 = 8000;
pub(crate) const SERVER_PORT: u16 = 17493;
pub(crate) const SERVER_PORT: u16 = 17494;
/// Find a voicebox-server process listening on a given port (Windows only).
/// Find a talkbox-server process listening on a given port (Windows only).
///
/// Uses PowerShell `Get-NetTCPConnection` to look up the PID owning the port,
/// then verifies via `tasklist` that it's a voicebox process. The caller is
/// then verifies via `tasklist` that it's a talkbox process. The caller is
/// responsible for checking port occupancy first (e.g. `TcpStream::connect_timeout`).
/// Replaces the previous `netstat -ano` approach which failed on systems with
/// corrupted system DLLs (see #277).
#[cfg(windows)]
fn find_voicebox_pid_on_port(port: u16) -> Option<u32> {
fn find_talkbox_pid_on_port(port: u16) -> Option<u32> {
use std::process::Command;
// Use PowerShell's Get-NetTCPConnection to find the PID listening on the port.
@@ -147,13 +147,13 @@ fn find_voicebox_pid_on_port(port: u16) -> Option<u32> {
let output_str = String::from_utf8_lossy(&output.stdout);
for line in output_str.lines() {
if let Ok(pid) = line.trim().parse::<u32>() {
// Verify this PID is a voicebox process
// Verify this PID is a talkbox process
if let Ok(tasklist_output) = Command::new("tasklist")
.args(["/FI", &format!("PID eq {}", pid), "/FO", "CSV", "/NH"])
.output()
{
let tasklist_str = String::from_utf8_lossy(&tasklist_output.stdout);
if tasklist_str.to_lowercase().contains("voicebox") {
if tasklist_str.to_lowercase().contains("talkbox") {
return Some(pid);
}
}
@@ -164,10 +164,10 @@ fn find_voicebox_pid_on_port(port: u16) -> Option<u32> {
None
}
/// Check if a Voicebox server is responding on the given port.
/// Check if a TalkBox server is responding on the given port.
///
/// Sends an HTTP GET to `/health` and returns `true` only if the response
/// is valid JSON matching the Voicebox `HealthResponse` schema — specifically
/// is valid JSON matching the TalkBox `HealthResponse` schema — specifically
/// `status` must be `"healthy"`, and both `model_loaded` and `gpu_available`
/// must be present as booleans. This prevents misidentifying an unrelated
/// service that happens to expose a `/health` endpoint.
@@ -183,7 +183,7 @@ fn check_health(port: u16) -> bool {
if !resp.status().is_success() {
return false;
}
// Parse as JSON and validate Voicebox-specific fields
// Parse as JSON and validate TalkBox-specific fields
match resp.json::<serde_json::Value>() {
Ok(body) => {
body.get("status").and_then(|v| v.as_str()) == Some("healthy")
@@ -283,7 +283,7 @@ async fn start_server(
return Ok(format!("http://127.0.0.1:{}", SERVER_PORT));
}
// Check if a voicebox server is already running on our port (from previous session with keep_running=true,
// Check if a talkbox server is already running on our port (from previous session with keep_running=true,
// or an externally started server e.g. via `python`, `uvicorn`, Docker, etc.)
#[cfg(unix)]
{
@@ -298,25 +298,25 @@ async fn start_server(
if parts.len() >= 2 {
let command = parts[0];
let pid_str = parts[1];
if command.contains("voicebox") {
if command.contains("talkbox") {
if let Ok(pid) = pid_str.parse::<u32>() {
println!("Found existing voicebox-server on port {} (PID: {}), reusing it", SERVER_PORT, pid);
println!("Found existing talkbox-server on port {} (PID: {}), reusing it", SERVER_PORT, pid);
// Store the PID so we can kill it on exit if needed
*state.server_pid.lock().unwrap() = Some(pid);
return Ok(format!("http://127.0.0.1:{}", SERVER_PORT));
}
} else {
// Process name doesn't contain "voicebox" — could be an external
// Process name doesn't contain "talkbox" — could be an external
// Python/uvicorn/Docker server. Verify via HTTP health check.
println!("Port {} in use by '{}' (PID: {}), checking if it's a Voicebox server...", SERVER_PORT, command, pid_str);
println!("Port {} in use by '{}' (PID: {}), checking if it's a TalkBox server...", SERVER_PORT, command, pid_str);
if check_health(SERVER_PORT) {
println!("Health check passed — reusing external server on port {}", SERVER_PORT);
return Ok(format!("http://127.0.0.1:{}", SERVER_PORT));
}
println!("Health check failed — port is occupied by a non-Voicebox process");
println!("Health check failed — port is occupied by a non-TalkBox process");
return Err(format!(
"Port {} is already in use by another application ({}). \
Close it or change the Voicebox server port.",
Close it or change the TalkBox server port.",
SERVER_PORT, command
));
}
@@ -332,28 +332,28 @@ async fn start_server(
&format!("127.0.0.1:{}", SERVER_PORT).parse().unwrap(),
std::time::Duration::from_secs(1),
).is_ok() {
// Port is in use — check if it's a voicebox process by name first
if let Some(pid) = find_voicebox_pid_on_port(SERVER_PORT) {
println!("Found existing voicebox-server on port {} (PID: {}), reusing it", SERVER_PORT, pid);
// Port is in use — check if it's a talkbox process by name first
if let Some(pid) = find_talkbox_pid_on_port(SERVER_PORT) {
println!("Found existing talkbox-server on port {} (PID: {}), reusing it", SERVER_PORT, pid);
*state.server_pid.lock().unwrap() = Some(pid);
return Ok(format!("http://127.0.0.1:{}", SERVER_PORT));
}
// Process name doesn't match — could be an external Python/Docker server.
// Verify via HTTP health check before giving up.
println!("Port {} in use by unknown process, checking if it's a Voicebox server...", SERVER_PORT);
println!("Port {} in use by unknown process, checking if it's a TalkBox server...", SERVER_PORT);
if check_health(SERVER_PORT) {
println!("Health check passed — reusing external server on port {}", SERVER_PORT);
return Ok(format!("http://127.0.0.1:{}", SERVER_PORT));
}
return Err(format!(
"Port {} is already in use by another application. \
Close the other application or change the Voicebox port.",
Close the other application or change the TalkBox port.",
SERVER_PORT
));
}
}
// Kill any orphaned voicebox-server from previous session on legacy port 8000
// Kill any orphaned talkbox-server from previous session on legacy port 8000
// This handles upgrades from older versions that used a fixed port
#[cfg(unix)]
{
@@ -369,9 +369,9 @@ async fn start_server(
let command = parts[0];
let pid_str = parts[1];
if command.contains("voicebox") {
if command.contains("talkbox") {
if let Ok(pid) = pid_str.parse::<i32>() {
println!("Found orphaned voicebox-server on legacy port {} (PID: {}, CMD: {}), killing it...", LEGACY_PORT, pid, command);
println!("Found orphaned talkbox-server on legacy port {} (PID: {}, CMD: {}), killing it...", LEGACY_PORT, pid, command);
let _ = Command::new("kill")
.args(["-9", "--", &format!("-{}", pid)])
.output();
@@ -380,7 +380,7 @@ async fn start_server(
.output();
}
} else {
println!("Legacy port {} is in use by non-voicebox process: {} (PID: {}), not killing", LEGACY_PORT, command, pid_str);
println!("Legacy port {} is in use by non-talkbox process: {} (PID: {}), not killing", LEGACY_PORT, command, pid_str);
}
}
}
@@ -394,8 +394,8 @@ async fn start_server(
&format!("127.0.0.1:{}", LEGACY_PORT).parse().unwrap(),
std::time::Duration::from_secs(1),
).is_ok() {
if let Some(pid) = find_voicebox_pid_on_port(LEGACY_PORT) {
println!("Found orphaned voicebox-server on legacy port {} (PID: {}), killing it...", LEGACY_PORT, pid);
if let Some(pid) = find_talkbox_pid_on_port(LEGACY_PORT) {
println!("Found orphaned talkbox-server on legacy port {} (PID: {}), killing it...", LEGACY_PORT, pid);
let _ = std::process::Command::new("taskkill")
.args(["/PID", &pid.to_string(), "/T", "/F"])
.output();
@@ -417,7 +417,7 @@ async fn start_server(
.map_err(|e| format!("Failed to create data dir: {}", e))?;
println!("=================================================================");
println!("Starting voicebox-server sidecar");
println!("Starting talkbox-server sidecar");
println!("Data directory: {:?}", data_dir);
println!("Remote mode: {}", remote.unwrap_or(false));
@@ -425,9 +425,9 @@ async fn start_server(
let rocm_binary = {
let rocm_dir = data_dir.join("backends").join("rocm");
let rocm_name = if cfg!(windows) {
"voicebox-server-rocm.exe"
"talkbox-server-rocm.exe"
} else {
"voicebox-server-rocm"
"talkbox-server-rocm"
};
let exe_path = rocm_dir.join(rocm_name);
if exe_path.exists() {
@@ -464,9 +464,9 @@ async fn start_server(
let cuda_binary = {
let cuda_dir = data_dir.join("backends").join("cuda");
let cuda_name = if cfg!(windows) {
"voicebox-server-cuda.exe"
"talkbox-server-cuda.exe"
} else {
"voicebox-server-cuda"
"talkbox-server-cuda"
};
let exe_path = cuda_dir.join(cuda_name);
if exe_path.exists() {
@@ -501,7 +501,7 @@ async fn start_server(
}
};
let sidecar_result = app.shell().sidecar("voicebox-server");
let sidecar_result = app.shell().sidecar("talkbox-server");
let mut sidecar = match sidecar_result {
Ok(s) => s,
@@ -586,7 +586,7 @@ async fn start_server(
cmd = cmd.current_dir(rocm_dir);
cmd = cmd.args(["--data-dir", &data_dir_str, "--port", &port_str, "--parent-pid", &parent_pid_str]);
if is_remote { cmd = cmd.args(["--host", "0.0.0.0"]); }
if let Some(ref dir) = effective_models_dir { cmd = cmd.env("VOICEBOX_MODELS_DIR", dir); }
if let Some(ref dir) = effective_models_dir { cmd = cmd.env("TALKBOX_MODELS_DIR", dir); }
match cmd.spawn() {
Ok(r) => { gpu_spawn = Some(Ok(r)); }
Err(e) => { println!("ROCm spawn failed ({}), trying CUDA/CPU fallback", e); }
@@ -601,7 +601,7 @@ async fn start_server(
cmd = cmd.current_dir(cuda_dir);
cmd = cmd.args(["--data-dir", &data_dir_str, "--port", &port_str, "--parent-pid", &parent_pid_str]);
if is_remote { cmd = cmd.args(["--host", "0.0.0.0"]); }
if let Some(ref dir) = effective_models_dir { cmd = cmd.env("VOICEBOX_MODELS_DIR", dir); }
if let Some(ref dir) = effective_models_dir { cmd = cmd.env("TALKBOX_MODELS_DIR", dir); }
match cmd.spawn() {
Ok(r) => { gpu_spawn = Some(Ok(r)); }
Err(e) => { println!("CUDA spawn failed ({}), falling back to CPU", e); }
@@ -615,7 +615,7 @@ async fn start_server(
// Fall back to bundled CPU sidecar
sidecar = sidecar.args(["--data-dir", &data_dir_str, "--port", &port_str, "--parent-pid", &parent_pid_str]);
if is_remote { sidecar = sidecar.args(["--host", "0.0.0.0"]); }
if let Some(ref dir) = effective_models_dir { sidecar = sidecar.env("VOICEBOX_MODELS_DIR", dir); }
if let Some(ref dir) = effective_models_dir { sidecar = sidecar.env("TALKBOX_MODELS_DIR", dir); }
println!("Spawning bundled CPU server process...");
sidecar.spawn()
}
@@ -627,7 +627,7 @@ async fn start_server(
sidecar = sidecar.args(["--host", "0.0.0.0"]);
}
if let Some(ref dir) = effective_models_dir {
sidecar = sidecar.env("VOICEBOX_MODELS_DIR", dir);
sidecar = sidecar.env("TALKBOX_MODELS_DIR", dir);
}
sidecar.spawn()
};
@@ -786,7 +786,7 @@ async fn start_server(
{
eprintln!("Server process ended unexpectedly during startup!");
eprintln!("The server binary may have crashed or exited with an error.");
eprintln!("Check Console.app logs for more details (search for 'voicebox')");
eprintln!("Check Console.app logs for more details (search for 'talkbox')");
return Err("Server process ended unexpectedly".to_string());
}
}
@@ -967,20 +967,20 @@ fn stop_audio_playback(
state.stop_all_playback()
}
/// Identifier of the Voicebox app itself — used to short-circuit auto-paste
/// Identifier of the TalkBox app itself — used to short-circuit auto-paste
/// when the user fires a chord while focus was inside one of our own
/// windows. Paste into Voicebox-internal targets is step 6 territory and
/// windows. Paste into TalkBox-internal targets is step 6 territory and
/// goes through a different (JS-side) injection path.
///
/// Value matches what `focus_capture::capture_focus` writes into
/// `FocusSnapshot::bundle_id` on the current platform — reverse-DNS bundle
/// id on macOS, lowercased exe basename on Windows/Linux.
#[cfg(target_os = "macos")]
const VOICEBOX_BUNDLE_ID: &str = "sh.voicebox.app";
const TALKBOX_BUNDLE_ID: &str = "sh.talkbox.app";
#[cfg(target_os = "windows")]
const VOICEBOX_BUNDLE_ID: &str = "voicebox.exe";
const TALKBOX_BUNDLE_ID: &str = "talkbox.exe";
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
const VOICEBOX_BUNDLE_ID: &str = "voicebox";
const TALKBOX_BUNDLE_ID: &str = "talkbox";
/// Milliseconds to wait between activating the target app and firing the
/// synthetic ⌘V, giving AppKit time to finish re-ordering windows and
@@ -1060,7 +1060,7 @@ fn build_chord_bindings(
/// frontend invokes this both at startup (when `capture_settings.hotkey_enabled`
/// is true) and from the settings toggle.
///
/// On macOS this is the call that triggers the "Voicebox would like to receive
/// On macOS this is the call that triggers the "TalkBox would like to receive
/// keystrokes from any application" TCC prompt, since keytap's `Tap` creates
/// the CGEventTap inside `HotkeyMonitor::spawn`.
#[cfg(desktop)]
@@ -1204,7 +1204,7 @@ fn open_input_monitoring_settings(app: tauri::AppHandle) -> Result<(), String> {
/// clipboard stuck on the transcript.
///
/// Skips (returns `false`) without touching anything when:
/// - `focus.bundle_id` is Voicebox itself — step 6 will inject directly
/// - `focus.bundle_id` is TalkBox itself — step 6 will inject directly
/// into our own webview; pasting would just double-insert or miss the
/// real target.
/// - Accessibility is not trusted — `CGEventPost` would silently drop the
@@ -1217,12 +1217,12 @@ async fn paste_final_text(
text: String,
focus: focus_capture::FocusSnapshot,
) -> Result<bool, String> {
if focus.bundle_id.as_deref() == Some(VOICEBOX_BUNDLE_ID) {
if focus.bundle_id.as_deref() == Some(TALKBOX_BUNDLE_ID) {
return Ok(false);
}
if !accessibility::is_trusted() {
return Err(
"Accessibility permission required for auto-paste. Open System Settings → Privacy & Security → Accessibility and enable Voicebox."
"Accessibility permission required for auto-paste. Open System Settings → Privacy & Security → Accessibility and enable TalkBox."
.into(),
);
}
@@ -1244,7 +1244,7 @@ async fn paste_final_text(
clipboard::restore_clipboard(&snapshot)?;
} else {
eprintln!(
"[voicebox] clipboard mutated during paste window — skipping restore to preserve newer content"
"[talkbox] clipboard mutated during paste window — skipping restore to preserve newer content"
);
}
@@ -1273,7 +1273,7 @@ async fn debug_focus_roundtrip(
) -> Result<serde_json::Value, String> {
if !accessibility::is_trusted() {
return Err(
"Accessibility permission not granted. Open System Settings → Privacy & Security → Accessibility and enable Voicebox."
"Accessibility permission not granted. Open System Settings → Privacy & Security → Accessibility and enable TalkBox."
.into(),
);
}
@@ -1320,7 +1320,7 @@ async fn debug_paste_text(
) -> Result<serde_json::Value, String> {
if !accessibility::is_trusted() {
return Err(
"Accessibility permission not granted. Open System Settings → Privacy & Security → Accessibility and enable Voicebox, then try again."
"Accessibility permission not granted. Open System Settings → Privacy & Security → Accessibility and enable TalkBox, then try again."
.into(),
);
}
@@ -1418,7 +1418,7 @@ pub fn run() {
// finishes (rest-fade → hidden). `hide()` alone has been
// unreliable for transparent always-on-top windows on macOS
// — the NSWindow lingers as an invisible click target that
// steals focus to the Voicebox app when the user clicks
// steals focus to the TalkBox app when the user clicks
// where it used to be. Park the window off-screen and mark
// it click-through as well, so even if `hide()` no-ops the
// user sees and interacts with nothing.
@@ -1434,7 +1434,7 @@ pub fn run() {
}
});
// Agent-initiated speech (voicebox.speak over MCP or POST /speak)
// Agent-initiated speech (talkbox.speak over MCP or POST /speak)
// pops the pill up so the user can see what's coming out of their
// machine. The `dictate:show` listener is kept for any frontend
// caller that wants to force-surface the pill directly, but the
+5 -5
View File
@@ -1,8 +1,8 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Voicebox",
"productName": "TalkBox",
"version": "0.5.0",
"identifier": "sh.voicebox.app",
"identifier": "sh.talkbox.app",
"build": {
"beforeDevCommand": "bun run dev",
"beforeBuildCommand": "bun run build",
@@ -13,7 +13,7 @@
"active": true,
"targets": "all",
"createUpdaterArtifacts": "v1Compatible",
"externalBin": ["binaries/voicebox-server", "binaries/voicebox-mcp"],
"externalBin": ["binaries/talkbox-server", "binaries/talkbox-mcp"],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -29,7 +29,7 @@
},
"resources": {
"gen/Assets.car": "./",
"gen/voicebox.icns": "./",
"gen/talkbox.icns": "./",
"gen/partial.plist": "./"
}
},
@@ -61,7 +61,7 @@
},
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEUxRENBQkRBQjdBNTM1OTIKUldTU05hVzMycXZjNGJGcUxmcVVocll2QjdSaTJNdlFxR2M3VDJsMnVvbDdyZGRPMmRlOW9aWTcK",
"endpoints": ["https://github.com/jamiepine/voicebox/releases/latest/download/latest.json"]
"endpoints": ["https://github.com/jamiepine/talkbox/releases/latest/download/latest.json"]
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
// 2. Run: cargo test --test audio_capture_test -- --nocapture
// 3. The test will capture audio for 5 seconds and verify the output
use voicebox::audio_capture::{AudioCaptureState, start_capture, stop_capture};
use talkbox::audio_capture::{AudioCaptureState, start_capture, stop_capture};
use base64::Engine;
#[tokio::test]
+1 -1
View File
@@ -71,7 +71,7 @@ class TauriLifecycle implements PlatformLifecycle {
// Check if server was started by this app instance
// @ts-expect-error - accessing module-level variable from another module
const serverStartedByApp = window.__voiceboxServerStartedByApp ?? false;
const serverStartedByApp = window.__talkboxServerStartedByApp ?? false;
console.log(
'[lifecycle] window-close-requested: keepRunning=%s, serverStartedByApp=%s',