chore: remove legacy TUI configurator; surface last config gap in GUI (#45)

Audit confirmed the Rich TUI (`meshai --config`) is a strict subset of the
dashboard GUI (covers FEWER sections) and nothing depends on it for bootstrap.
Strip it so the dashboard is the single config surface.

- delete meshai/cli/configurator.py (~1435 lines); cli/__init__ minimal
- main.py: drop --config + run_configurator dispatch (keep --config-file);
  bootstrap log now points to config.example.yaml / the dashboard
- docker-entrypoint.sh: remove the ttyd `meshai --config` block on :7682
  (default-config heredoc + bot exec loop untouched)
- docker-compose.yml + Dockerfile: drop the 7682 port + ttyd install (EXPOSE 8080)
- README / config.py header / config.example.yaml: de-reference the TUI
- drop `rich` from pyproject + requirements (grep-verified unused)

Close the only GUI config gap the audit found:
- Config.tsx weather tab: add openmeteo.url + wttr.url inputs (backend already
  round-trips the nested WeatherConfig dataclasses)

Bootstrap intact: config.example.yaml copy, entrypoint default-config write,
and defaulted Config() when no file exists all remain. `python3 -m meshai`
and `--config-file` unchanged. TS/import validated at Docker build.

Co-authored-by: Matt Johnson <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
malice 2026-07-05 16:21:32 -06:00 committed by GitHub
commit 5de683f7a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 30 additions and 1483 deletions

View file

@ -46,11 +46,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
curl \ curl \
# For process management # For process management
procps \ procps \
&& rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/apt/lists/*
# Install ttyd for web-based config interface (arch-aware)
&& TTYD_ARCH=$(dpkg --print-architecture | sed 's/amd64/x86_64/' | sed 's/arm64/aarch64/') \
&& curl -sL "https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.${TTYD_ARCH}" -o /usr/local/bin/ttyd \
&& chmod +x /usr/local/bin/ttyd
# Create non-root user # Create non-root user
RUN groupadd -g ${GID} meshai && \ RUN groupadd -g ${GID} meshai && \
@ -88,12 +84,12 @@ USER meshai
# Data volume mount point # Data volume mount point
VOLUME ["/data"] VOLUME ["/data"]
# Expose ttyd web config port # Expose dashboard port
EXPOSE 7682 8080 EXPOSE 8080
# Health check - verify bot process is alive via PID file # Health check - verify bot process is alive via PID file
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD test -f /tmp/meshai.pid && kill -0 $(cat /tmp/meshai.pid) 2>/dev/null && [ "$(cat /tmp/meshai.link 2>/dev/null)" = up ] || exit 1 CMD test -f /tmp/meshai.pid && kill -0 $(cat /tmp/meshai.pid) 2>/dev/null && [ "$(cat /tmp/meshai.link 2>/dev/null)" = up ] || exit 1
# Entrypoint handles config and ttyd # Entrypoint writes default config on first run, then starts the bot
ENTRYPOINT ["/app/docker-entrypoint.sh"] ENTRYPOINT ["/app/docker-entrypoint.sh"]

View file

@ -56,7 +56,7 @@ Everything is driven from the web UI, organized into **General**, **Meshtastic**
git clone https://github.com/zvx-echo6/meshai.git git clone https://github.com/zvx-echo6/meshai.git
cd meshai cd meshai
pip install -e . pip install -e .
meshai --config # interactive setup TUI cp config.example.yaml config.yaml # then edit config.yaml (or use the dashboard)
meshai meshai
``` ```

View file

@ -83,8 +83,8 @@ knowledge:
# === MESH DATA SOURCES === # === MESH DATA SOURCES ===
# Connect to Meshview and/or MeshMonitor instances for live mesh # Connect to Meshview and/or MeshMonitor instances for live mesh
# network analysis. Supports multiple sources. Configure via TUI # network analysis. Supports multiple sources. Configure via the
# with meshai --config (Mesh Sources menu). # dashboard (Mesh Sources) or by editing this file directly.
# #
# mesh_sources: # mesh_sources:
# - name: "my-meshview" # - name: "my-meshview"

View file

@ -1137,6 +1137,20 @@ function WeatherSection({ data, onChange }: { data: WeatherConfig; onChange: (d:
placeholder="Your city, state" placeholder="Your city, state"
helper="Location when none specified" helper="Location when none specified"
/> />
<TextInput
label="Open-Meteo base URL (advanced)"
value={data.openmeteo.url}
onChange={(v) => onChange({ ...data, openmeteo: { ...data.openmeteo, url: v } })}
placeholder="https://api.open-meteo.com/v1"
helper="Override the Open-Meteo API endpoint (leave default unless self-hosting)"
/>
<TextInput
label="wttr.in base URL (advanced)"
value={data.wttr.url}
onChange={(v) => onChange({ ...data, wttr: { ...data.wttr, url: v } })}
placeholder="https://wttr.in"
helper="Override the wttr.in endpoint (leave default unless self-hosting)"
/>
</div> </div>
) )
} }

View file

@ -1,15 +1,15 @@
# MeshAI Docker Compose Configuration # MeshAI Docker Compose Configuration
# #
# Usage: # Usage:
# docker compose up -d # Start bot + web config # docker compose up -d # Start the bot + dashboard
# docker compose logs -f # View logs # docker compose logs -f # View logs
# #
# Web config: http://localhost:7682 (TUI in browser) # Dashboard: http://localhost:8080
# #
# Config is stored in the meshai_data volume at /data/config.yaml # Config is stored in the meshai_data volume at /data/config.yaml
# #
# For serial connection (USB), uncomment the devices section below # For serial connection (USB), uncomment the devices section below
# For TCP connection, configure via web interface # For TCP connection, edit config.yaml or use the dashboard
services: services:
meshai: meshai:
@ -41,8 +41,6 @@ services:
# - /dev/ttyACM0:/dev/ttyACM0 # - /dev/ttyACM0:/dev/ttyACM0
ports: ports:
# Web-based config interface (ttyd)
- "7682:7682"
# Dashboard API # Dashboard API
- "8080:8080" - "8080:8080"
@ -50,7 +48,7 @@ services:
# Persistent data (database, config) # Persistent data (database, config)
- meshai_data:/data - meshai_data:/data
# Run interactively for first-time setup wizard # Allocate a TTY for cleaner log output
stdin_open: true stdin_open: true
tty: true tty: true

View file

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
# MeshAI Docker Entrypoint # MeshAI Docker Entrypoint
# Runs ttyd for web config access and the bot # Writes a default config on first run, then runs the bot
export MESHAI_CONFIG="/data/config.yaml" export MESHAI_CONFIG="/data/config.yaml"
export TERM="${TERM:-xterm-256color}" export TERM="${TERM:-xterm-256color}"
@ -10,7 +10,7 @@ if [ ! -f "$MESHAI_CONFIG" ]; then
mkdir -p /data mkdir -p /data
cat > "$MESHAI_CONFIG" << 'EOF' cat > "$MESHAI_CONFIG" << 'EOF'
# MeshAI Configuration # MeshAI Configuration
# Configure via http://localhost:7682 # Edit this file directly, or configure via the dashboard
bot: bot:
name: ai name: ai
@ -66,22 +66,10 @@ meshmonitor:
enabled: false enabled: false
inject_into_prompt: true inject_into_prompt: true
EOF EOF
echo "Default config created. Configure via http://localhost:7682" echo "Default config created at $MESHAI_CONFIG. Edit it or configure via the dashboard."
fi fi
# Start ttyd for web-based config access
echo "Starting web config interface on port 7682..."
ttyd -W -p 7682 \
-t enableClipboard=true \
-t titleFixed="MeshAI Config" \
-t 'theme={"background":"#0d1117","foreground":"#c9d1d9","cursor":"#58a6ff","selectionBackground":"#388bfd"}' \
-t fontSize=14 \
/bin/bash -c 'while true; do python3 -m meshai --config-file "$MESHAI_CONFIG" --config; sleep 1; done' &
# Keep ttyd running even if bot fails
trap "kill %1 2>/dev/null" EXIT
# Kill bot gracefully with SIGKILL fallback # Kill bot gracefully with SIGKILL fallback
kill_bot() { kill_bot() {
local pid=$1 local pid=$1

View file

@ -1,5 +1 @@
"""CLI tools for MeshAI.""" """CLI tools for MeshAI."""
from .configurator import run_configurator
__all__ = ["run_configurator"]

File diff suppressed because it is too large Load diff

View file

@ -1090,7 +1090,7 @@ def save_config(config: Config, config_path: Optional[Path] = None) -> None:
data = _dataclass_to_dict(config) data = _dataclass_to_dict(config)
# Add header comment # Add header comment
header = "# MeshAI Configuration\n# Generated by meshai --config\n\n" header = "# MeshAI Configuration\n# Generated by meshai\n\n"
with open(config_path, "w") as f: with open(config_path, "w") as f:
f.write(header) f.write(header)

View file

@ -12,7 +12,6 @@ from typing import Optional
from . import __version__ from . import __version__
from .backends import AnthropicBackend, GoogleBackend, LLMBackend, OpenAIBackend from .backends import AnthropicBackend, GoogleBackend, LLMBackend, OpenAIBackend
from .cli import run_configurator
from .commands import CommandDispatcher from .commands import CommandDispatcher
from .commands.dispatcher import create_dispatcher from .commands.dispatcher import create_dispatcher
from .commands.status import set_start_time from .commands.status import set_start_time
@ -876,9 +875,6 @@ def main() -> None:
parser.add_argument( parser.add_argument(
"--version", "-V", action="version", version=f"%(prog)s {__version__}" "--version", "-V", action="version", version=f"%(prog)s {__version__}"
) )
parser.add_argument(
"--config", "-c", action="store_true", help="Launch configuration tool"
)
parser.add_argument( parser.add_argument(
"--config-file", "--config-file",
"-f", "-f",
@ -892,11 +888,6 @@ def main() -> None:
setup_logging(args.verbose) setup_logging(args.verbose)
# Launch configurator if requested
if args.config:
run_configurator(args.config_file)
return
# Load config - support both old (/data/config.yaml) and new (/data/config/) layouts # Load config - support both old (/data/config.yaml) and new (/data/config/) layouts
config_path = args.config_file config_path = args.config_file
config_dir = get_config_dir_from_path(config_path) config_dir = get_config_dir_from_path(config_path)
@ -912,7 +903,7 @@ def main() -> None:
config = legacy_load(config_path) config = legacy_load(config_path)
else: else:
logger.warning(f"Config not found at {config_path} or {config_dir}") logger.warning(f"Config not found at {config_path} or {config_dir}")
logger.info("Run 'meshai --config' to create one, or copy config.example.yaml") logger.info("Copy config.example.yaml to get started, or configure via the dashboard")
sys.exit(1) sys.exit(1)
# Create and run bot # Create and run bot

View file

@ -35,7 +35,6 @@ dependencies = [
"openai>=1.0.0", "openai>=1.0.0",
"anthropic>=0.18.0", "anthropic>=0.18.0",
"google-genai>=1.0.0", "google-genai>=1.0.0",
"rich>=13.0.0",
"httpx>=0.25.0", "httpx>=0.25.0",
"fastapi>=0.110.0", "fastapi>=0.110.0",
"uvicorn[standard]>=0.27.0", "uvicorn[standard]>=0.27.0",

View file

@ -5,7 +5,6 @@ aiosqlite>=0.19.0
openai>=1.0.0 openai>=1.0.0
anthropic>=0.18.0 anthropic>=0.18.0
google-genai>=1.0.0 google-genai>=1.0.0
rich>=13.0.0
httpx>=0.25.0 httpx>=0.25.0
fastembed>=0.3.0 fastembed>=0.3.0
sqlite-vec>=0.1.0 sqlite-vec>=0.1.0