feat: add milestone 6 CLI polish

Add shell completion generation, improve first-run device messaging,
and include HTTP endpoint details in daemon startup output.
This commit is contained in:
44r0n7
2026-04-15 15:56:21 -04:00
parent b8a0a0ff16
commit 26cc0c973a
10 changed files with 164 additions and 111 deletions
+1 -13
View File
@@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
use tokio::fs;
/// The complete daemon configuration loaded from TOML.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(default)]
pub struct TvctlConfig {
/// Runtime daemon settings.
@@ -24,18 +24,6 @@ pub struct TvctlConfig {
pub dev: DevConfig,
}
impl Default for TvctlConfig {
fn default() -> Self {
Self {
daemon: DaemonConfig::default(),
discovery: DiscoveryConfig::default(),
devices: DeviceConfig::default(),
remote: RemoteConfig::default(),
dev: DevConfig::default(),
}
}
}
impl TvctlConfig {
/// Load configuration from the default XDG path or return defaults when absent.
pub async fn load() -> anyhow::Result<Self> {
+12 -12
View File
@@ -183,7 +183,9 @@ async fn set_socket_permissions(path: &Path) -> anyhow::Result<()> {
Ok(())
}
async fn start_http_server_if_enabled(daemon: SharedDaemon) -> anyhow::Result<Option<JoinHandle<()>>> {
async fn start_http_server_if_enabled(
daemon: SharedDaemon,
) -> anyhow::Result<Option<JoinHandle<()>>> {
let (enabled, host, port) = {
let guard = daemon.lock().await;
(
@@ -469,17 +471,15 @@ pub(crate) async fn execute_request(
Ok(device) => device,
Err(response) => return (response, false),
};
if clear {
if let Err(error) = guard.app_cache.clear_platform(&device.platform).await {
return (
DaemonResponse::error(
"app_cache_clear_failed",
format!("Failed to clear the cached app list: {error}"),
Some("Check permissions for ~/.local/share/tvctl/cache.".to_string()),
),
false,
);
}
if clear && let Err(error) = guard.app_cache.clear_platform(&device.platform).await {
return (
DaemonResponse::error(
"app_cache_clear_failed",
format!("Failed to clear the cached app list: {error}"),
Some("Check permissions for ~/.local/share/tvctl/cache.".to_string()),
),
false,
);
}
match guard.adapters.list_apps(&device).await {
Ok(apps) => match guard
+1 -9
View File
@@ -179,19 +179,11 @@ impl Default for DeviceRegistry {
}
/// A registry of platform adapters available to the daemon.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct AdapterRegistry {
roku: RokuAdapter,
}
impl Default for AdapterRegistry {
fn default() -> Self {
Self {
roku: RokuAdapter::new(),
}
}
}
impl AdapterRegistry {
/// Build the adapter registry from the loaded daemon config.
pub fn from_config(config: &TvctlConfig) -> Self {