Commit Graph

459 Commits

Author SHA1 Message Date
Stacy Olivas 14d3c0ca2d refactor: move command aliases to per-command config section
Each command's aliases are now configured as an `aliases` key in its own
config section (e.g. [Wx_Command] aliases = !weather, !w) rather than a
separate [Aliases] section. BaseCommand._load_aliases_from_config() reads
and injects them into keywords at startup. CommandManager.load_aliases()
and _apply_aliases() are removed. No behaviour change for commands without
aliases configured.
2026-03-17 19:56:57 -07:00
Stacy Olivas 7309fda745 docs: update BUGS.md commit references after rebase
Update commit SHAs in BUGS.md fixed-bugs table to reflect the rebased
history.
2026-03-17 18:07:19 -07:00
Stacy Olivas 111f3116fd docs: update tracking files for BUG-025/026/027/028/029 and coverage expansion
- BUGS.md: mark BUG-025/026 fixed; add BUG-027/028/029 entries with
  fix details and commit references
- TESTING.md: document MQTT test framework, coverage targets, and
  newly added test modules
- TODO.md: mark completed sub-tasks; update coverage percentage and
  fail_under threshold; add remaining coverage targets
2026-03-17 18:07:19 -07:00
Stacy Olivas a667e3cba4 test: MQTT live test framework and packet fixtures
Add live and offline packet-parsing tests using paho-mqtt:
- tests/test_mqtt_live.py: schema validation + live integration tests;
  subscribes to meshcore/SEA/+/packets; validates JSON against schema
- tests/mqtt_test_config.ini: broker/topic/timeout config; primary LAN
  broker (10.0.2.123:1883); letsmesh as documented alternative
- tests/fixtures/mqtt_packets.json: 8 real packets from SEA region for
  offline fallback

Run live: pytest -m mqtt
Run offline: pytest -m "not mqtt"
Collect fixtures: python tests/test_mqtt_live.py --collect-fixtures
2026-03-17 18:07:19 -07:00
Stacy Olivas 9be5166485 test: coverage expansion — commands, web viewer, and infrastructure
New test modules:
- test_announcements_command: parse, record_trigger, execute paths
- test_aurora_command: KP index parsing, alert levels, execute paths
- test_channel_manager: generate_hashtag_key, cache lookups, validation
- test_channels_command: remaining channel info display paths
- test_dadjoke_command: format, split, length, execute
- test_graph_trace_helper: geo-location helper and graph algorithm paths
- test_hacker_command: text transform logic
- test_help_command: format list, channel filter, general/specific help
- test_i18n: fallback loops, format failure, PermissionError, get_value
- test_joke_command: seasonal, format, split, dark, execute
- test_moon_command: phase calc, execute success/error
- test_multitest_command: multi-channel test sequences
- test_stats_command: adverts leaderboard, get_stats_summary, cleanup
- test_trace_command: path extract, parse, format inline/vertical
- test_web_viewer_integration: circuit breaker, JSON serializer,
  packet capture, channel message
- test_webviewer_command: 100% coverage

Extended existing: test_command_manager, test_feed_manager,
test_message_handler, test_rate_limiter, test_repeater_manager,
test_scheduler_logic, test_security_utils, test_transmission_tracker,
test_utils, test_web_viewer
2026-03-17 18:07:19 -07:00
Stacy Olivas ad77d7b00d fix: BUG-025/026/027/028/029 implementations and ruff/mypy refinements
BUG-025: send_channel_message retry logic on no_event_received
BUG-026: split_text_into_chunks and chunked dispatch in message_handler
BUG-027: test_weekly_on_wrong_day_does_not_run patch uses fake_now
BUG-028: byte_data = b"" initialised before try in decode_meshcore_packet
BUG-029: app.py db_path via self._config_base; realtime.html socket race
  fixed; base.html forceNew removed; ping_timeout 5 to 20s

Additional: ruff and mypy refinements across all modules; discord bridge,
telegram bridge, rate limiter, and service plugin updates
2026-03-17 18:07:19 -07:00
Stacy Olivas c95ddf667a infra: raise coverage threshold and update pytest config
- fail_under raised to 27 after confirming baseline coverage
- asyncio_mode and timeout settings refined
- requirements.txt synced with updated dependencies
2026-03-17 18:07:18 -07:00
Stacy Olivas ae57e651ea test: expanded test suite for v0.9.0 modules
Command tests:
- tests/commands/: test_base_command, test_cmd_command, test_dice_command,
  test_hello_command, test_help_command, test_magic8_command,
  test_ping_command, test_roll_command
- tests/test_bridge_bot_responses, test_channel_manager_logic,
  test_checkin_service, test_command_manager, test_command_prefix,
  test_config_merge, test_config_validation, test_db_manager,
  test_plugin_loader, test_profanity_filter, test_security_utils,
  test_service_plugin_loader, test_utils

Integration and unit:
- tests/integration/: test_path_graph_integration, test_path_resolution
- tests/regression/: test_keyword_escapes
- tests/unit/: test_mesh_graph, test_mesh_graph_edges,
  test_mesh_graph_multihop, test_mesh_graph_optimizations,
  test_mesh_graph_scoring, test_mesh_graph_validation,
  test_path_command_graph, test_path_command_graph_selection,
  test_path_command_multibyte

Helpers: tests/conftest.py, tests/helpers.py
2026-03-17 18:07:18 -07:00
Stacy Olivas 7f9e14d99a docs: update README, config example, and tracking files for v0.9.0
- README: reflect all new features, installation steps, Python 3.9
  minimum requirement, and updated configuration reference
- config.ini.example: add [Aliases], [Webhook], [Rate_Limits],
  [Logging] json_logging, [Path_Command] geographic_scoring_enabled,
  [Web_Viewer] web_viewer_password, and all new scheduler/backup options
- BUGS.md, TESTING.md, TODO.md: updated to reflect current state
- scripts/update_todos.py: updated scan output
2026-03-17 18:07:18 -07:00
Stacy Olivas ce884cee87 fix: auth, db migrations, retry, chunking, socket race, trace, timezone, repeater, and ruff/mypy cleanup
BUG-001: web viewer login/session auth (in web viewer commit)
BUG-002: db_manager ALTER TABLE for missing channel_operations and
  feed_message_queue columns on startup
BUG-015: scheduler thread blocked on future.result(); replaced all
  blocking waits with add_done_callback (fire-and-forget)
BUG-016: reboot_radio sends meshcore.commands.reboot() before disconnect
BUG-017: radio disconnect uses asyncio.wait_for(timeout=10)
BUG-022: custom asyncio loop exception handler suppresses IndexError
  from meshcore parser at DEBUG level
BUG-024: last_db_backup_run updated after each run; 2-min startup
  window; last-run seeded from DB on restart
BUG-025: send_channel_message retries up to 2 times (2s delay) on
  no_event_received via _is_no_event_received() helper
BUG-026: split_text_into_chunks() and get_max_message_length() added
  to CommandManager; keyword dispatch uses send_response_chunked()
BUG-028: byte_data = b"" initialised before try block in
  decode_meshcore_packet to prevent UnboundLocalError in except handler
TraceCommand: path nodes reversed and return path truncated; fixed
format_elapsed_display: UTC normalisation before elapsed computation (#75)
RepeaterManager: auto_manage_contacts guard before any purge logic (#50)
Command aliases: [Aliases] config section injects shorthands at startup
JSON logging: _JsonFormatter; json_logging = true in [Logging]
Structured JSON logging compatible with Loki, Elasticsearch, Splunk
Discord bridge, Telegram bridge, and all service plugins updated
MeshGraph edge promotion logic corrected
Shutdown: scheduler and meshcore disconnect joined cleanly; log spam fixed
All modules: ruff and mypy cleanup applied (type annotations, imports)
2026-03-17 18:07:18 -07:00
Stacy Olivas 93f73a15a2 feat: web viewer — auth, contact management, live streaming, config, maintenance, and backup
Auth (BUG-001):
- Optional password via web_viewer_password in [Web_Viewer]; /login and
  /logout; Flask session guard on all routes and SocketIO handlers

Contact management and export:
- Star contacts of any type; purge-preview + purge inactive contacts
- GET /api/export/contacts and /api/export/paths: CSV/JSON with time-range

Config tab and maintenance:
- /config page: SMTP, log rotation, DB backup settings in bot_metadata
- Nightly email digest (uptime, contacts, DB size, log errors); SMTP
  timeout=30s; pre-rotation log attachment hook
- GET /api/maintenance/status: Maintenance Status card

DB backup, restore, and purge:
- POST /api/maintenance/backup_now; GET /api/maintenance/list_backups;
  POST /api/maintenance/restore (SQLite magic-byte validation)
- POST /api/maintenance/purge: remove rows older than threshold
- Scheduled backups: daily/weekly/manual with retention pruning
- Config save validates db_backup_dir exists; 400 on missing path

Live streaming and realtime monitoring:
- Live Activity panel: colour-coded SocketIO feed with pause/clear
- capture_channel_message() feeds packet_stream; message_data event
- /realtime page: three independent stream panels; [#channel] prefix
- /logs page: subscribe_logs/log_line; log-tail thread; level colouring
- History replay: last 50/50/200 items on connect
- Werkzeug 3.1 WebSocket fix: _apply_werkzeug_websocket_fix()
- BUG-029: db_path resolved via config_base = Path(config_path).parent;
  stored as self._config_base; dead _get_db_path() removed

Scroll/filter controls and connected agents:
- Scroll-to-top/bottom on Live Activity and all realtime panels
- Type-filter checkboxes (Packets/Commands/Messages) with applyFilters()
- GET /api/connected_clients: agent count clickable; Bootstrap modal
2026-03-17 18:07:18 -07:00
Stacy Olivas 2a3a78711c feat: !path geographic scoring toggle
Add geographic_scoring_enabled = true/false to [Path_Command] config.
When disabled, path scoring uses hop count only and ignores GPS
coordinates. Evaluated per-command invocation; no restart required.
2026-03-17 18:07:18 -07:00
Stacy Olivas 97e5c59ca6 feat: !schedule command listing scheduled messages and advert interval
Add ScheduleCommand (DM-only by default). Displays configured scheduled
message times, target channels, message previews, and the current
advertisement interval. Read-only; does not modify schedule state.
2026-03-17 18:07:18 -07:00
Stacy Olivas 25eb7ccf5c feat: per-channel rate limiting
Add ChannelRateLimiter to rate_limiter.py. Configure per-channel
cooldowns via [Rate_Limits] channel.<name>_seconds. Integrated into
_check_rate_limits() and send_channel_message() in command_manager.py.
GET /api/stats/rate_limiters exposes live stats for all four limiter
types.
2026-03-17 18:07:18 -07:00
Stacy Olivas d07cca6d7a feat: inbound webhook relay with bearer token authentication
Add POST /webhook endpoint to the web viewer. Authenticated via
Authorization: Bearer <token> set in [Webhook] config section. Relays
JSON or text payload to a configured MeshCore channel or user DM.
2026-03-17 18:07:18 -07:00
Stacy Olivas 904303ff00 infra: DB migration versioning, aiosqlite AsyncDBManager, and APScheduler
Migration versioning:
- db_migrations.py: MigrationRunner with five numbered migrations;
  schema_version table tracks applied state; migrations are append-only;
  runner called on startup from db_manager.py

AsyncDBManager:
- AsyncDBManager in db_manager.py provides non-blocking DB access in
  async coroutines via aiosqlite; exposed as bot.async_db_manager
- aiosqlite>=0.19.0 added to dependencies

APScheduler:
- scheduler.py migrated from schedule lib to APScheduler
  BackgroundScheduler + CronTrigger; schedule dependency removed

Message write queue:
- Background drain thread eliminates per-packet sqlite3.connect();
  executemany batch insert every 0.5s; shutdown path flushes remaining rows
2026-03-17 18:07:18 -07:00
Stacy Olivas da1e68f500 infra: ncurses config TUI via scripts/config_tui.py
Add scripts/config_tui.py: browse, edit, save, validate, and migrate
config.ini interactively. Key bindings: r rename key, a add key+value,
d/Delete remove key with confirmation. Dynamic sections such as
[Scheduled_Messages] suppress the unknown-key ? marker. Access via
make config or CONFIG=path make config.
2026-03-17 18:07:18 -07:00
Stacy Olivas c7f2bdbf72 infra: .deb packaging via scripts/build-deb.sh
Add scripts/build-deb.sh using fakeroot and dpkg-deb to produce a
Debian package. Includes DEBIAN/control, postinst (venv setup, systemd
enable), prerm (systemd stop), and postrm (cleanup). Add make deb
target. Update install-service.sh and uninstall-service.sh for current
paths and Python version.
2026-03-17 18:07:18 -07:00
Stacy Olivas 5b6f2829b8 infra: Docker multi-arch build with SBOM and provenance
Add .github/workflows/docker-build.yml triggered on push to main and
version tags. Builds linux/amd64, linux/arm64, and linux/arm/v7 via
QEMU. Attaches SBOM and provenance attestations to the image manifest.
Update Dockerfile with non-root user and current Python base image.
2026-03-17 18:07:18 -07:00
Stacy Olivas e1cf2ebdd9 infra: CI lint gates for ruff, mypy, eslint, and shellcheck
Add four jobs to .github/workflows/test.yml:
- lint: ruff check modules/ tests/ — zero violations enforced
- typecheck: mypy modules/ with incremental strict mode; per-module
  disallow_untyped_defs where applicable
- lint-frontend: ESLint (eslint-plugin-html) + HTMLHint on templates/
- lint-shell: ShellCheck --severity=warning on all .sh files

Add [tool.ruff] and [tool.mypy] sections to pyproject.toml.
Add .eslintrc.json, .htmlhintrc, package.json for frontend tooling.
2026-03-17 18:07:18 -07:00
Stacy Olivas c2149bcb01 infra: makefile and virtual environment setup
Add Makefile with targets: install, dev, test, test-no-cov, lint, fix,
deb, config, clean. Uses .venv for isolation. Add pyproject.toml
[project] metadata and [project.optional-dependencies] dev and test
extras. Sync requirements.txt from pyproject.toml dependencies.
2026-03-17 18:07:18 -07:00
Stacy Olivas 9de9230c2b infra: initial test suite and project tracking files
Test modules:
- test_enums: enum values and flag combinations
- test_models: MeshMessage dataclass field and type validation
- test_transmission_tracker: full TransmissionTracker coverage
- test_message_handler: path parsing, RF correlation, message routing
- test_repeater_manager: role detection, ACL, device type classification
- test_core: config loading, radio settings, reload paths

Tracking files:
- BUGS.md: known bugs and fix history log
- TESTING.md: test strategy, coverage targets, and how-to guide
- TODO.md: feature and task backlog with completion status
- scripts/update_todos.py: scans source for # TODO/FIXME/HACK markers
  and regenerates the Inline TODOs section in TODO.md
2026-03-17 18:07:18 -07:00
Stacy Olivas ba32accc44 infra: pytest configuration, timeout enforcement, and coverage threshold
- pytest-timeout>=2.1.0 added; timeout=30s per test prevents runaway
  tests from hanging CI
- asyncio_mode=auto in pyproject.toml [tool.pytest.ini_options]; async
  tests run without per-test markers
- fail_under=27 in [tool.coverage.report] as the enforced coverage
  floor; target 40% tracked in TASK-14
- CI test matrix updated for Python 3.9, 3.11, 3.12
2026-03-17 18:07:18 -07:00
agessaman fb6963249e Enhance Discord bridge configuration to support multiple webhooks per channel
- Updated config.ini.example and discord-bridge.md to reflect the ability to fan out a single MeshCore channel to multiple Discord servers using a comma- or whitespace-separated list of webhook URLs.
- Modified DiscordBridgeService to handle multiple webhooks per channel, including validation and logging improvements for better monitoring of configured webhooks.
2026-03-17 18:06:38 -07:00
agessaman 4be5fd6181 Update .gitignore and enhance install-service.sh for virtual environment management
- Added patterns to .gitignore to exclude log files and local configuration files.
- Improved the install-service.sh script to verify the integrity of the virtual environment and ensure pip is available and up to date before installing dependencies.
2026-03-17 18:06:38 -07:00
agessaman 581b2c771d Merge main into dev: resolve DOCKER.md -> docker.md 2026-03-11 20:50:22 -07:00
Adam Gessaman 8d72c9a034 Update funding information in FUNDING.yml
Updated GitHub Sponsors username and commented out other funding options.
2026-03-11 20:48:18 -07:00
Jeroen Vermeulen 1264f49410 Fixed repeater and webviewer usage like #50.
Fixed webviewer responses.
2026-03-11 20:48:18 -07:00
agessaman 53c8b40364 Update Docker documentation to include instructions for connecting COM ports on Windows 11. Added detailed steps for installing USB bridge, binding devices, and configuring Docker to use Linux device names. 2026-03-11 20:48:18 -07:00
agessaman d28a8b0d1d Fix documentation links 2026-03-11 20:44:47 -07:00
agessaman 2178a80dca Refactor cleanup methods in core.py and mesh_graph.py to suppress logging during shutdown
- Updated the _cleanup_web_viewer and _cleanup_mesh_graph methods to avoid logging errors during shutdown, as the logger's stream may be closed at that time.
- Modified the shutdown method in MeshGraph to prevent logging of flushing errors, enhancing stability during the atexit process.
- Adjusted test configurations to use Path objects for bot_root and local_root, improving path handling in tests.
2026-03-11 20:41:44 -07:00
agessaman 6ee4639ab7 Update test_checkin_service.py to skip tests when checkin_service plugin is not present
- Modified the test file to include a conditional import for the CheckInService, allowing tests to be skipped if the plugin is not installed. This change improves test reliability and clarity regarding plugin dependencies.
2026-03-11 20:29:03 -07:00
agessaman 43a36dd6d7 Update meshcore dependency version in requirements.txt
- Changed the meshcore dependency from a fixed version (2.2.14) to a minimum version (2.2.31) to ensure compatibility with newer features and improvements.
2026-03-10 10:45:33 -07:00
agessaman 58deb123b9 Update RepeaterManager to respect auto-manage contacts configuration
- Modified the RepeaterManager class to enable or disable auto-purge based on the 'auto_manage_contacts' setting from the bot's configuration.
- This change allows for more flexible management of contacts, aligning with the bot's operational mode.
2026-03-10 10:31:39 -07:00
agessaman 8b363afed7 Update IATA code in configuration files and packet capture service
- Changed the default IATA code from 'LOC' to 'XYZ' in `config.ini.example` and `packet-capture.md` to reflect updated routing requirements.
- Updated the `PacketCaptureService` to use 'XYZ' as the fallback IATA code, ensuring consistency across the application.
2026-03-09 22:09:39 -07:00
agessaman 0b58d9fed6 Update ServicePluginLoader to include modules directory in service path
- Enhanced the ServicePluginLoader to add the modules directory to the path for local services, ensuring that utility modules can be resolved correctly.
- This change improves the loading mechanism for service plugins by allowing better integration of local utilities.
2026-03-09 18:07:53 -07:00
agessaman f908395834 Enhance ServicePluginLoader to support dynamic service paths
- Updated the ServicePluginLoader to include a built-in services directory in the module path, improving the loading mechanism for service plugins.
- Modified the class to accept BaseServicePlugin from both built-in and local services, allowing for greater flexibility in service integration.
- Enhanced the logic for identifying service classes, ensuring compatibility with multiple base service implementations.
2026-03-09 16:26:06 -07:00
agessaman 5a96dec558 Refactor TraceCommand to improve hop labeling logic
- Updated the TraceCommand class to enhance the labeling of hops in the trace output.
- Replaced direct hash retrieval with a conditional approach to determine the source label for each hop, improving clarity in the output format.
- Ensured consistent labeling for the first and last hops, enhancing the readability of the trace results.
2026-03-09 15:56:07 -07:00
agessaman d084c6bd29 Enhance PrefixCommand to support multi-byte hex prefix lookups
- Updated the command to handle 1-, 2-, or 3-byte hex prefixes, with longer input truncated to 3 bytes.
- Improved usage instructions and examples to clarify accepted prefix formats (2, 4, or 6 hex characters).
- Enhanced validation logic for prefix format, ensuring proper handling of hex strings and truncation.
- Updated documentation strings to reflect changes in prefix handling and expected input formats.
2026-03-09 14:54:23 -07:00
agessaman 6c8151389b Enhance MeshGraph edge promotion logic and update BotDataViewer API
- Updated the MeshGraph class to prevent promoting a 1-byte edge to a 3-byte edge when the existing 1-byte edge lacks public keys, ensuring accurate observation attribution.
- Added a new test case to verify the behavior of edge promotion under specific conditions.
- Modified the BotDataViewer API to return the prefix length dynamically based on the edges, improving data consistency and user experience in the web viewer.
- Enhanced the mesh.html template to support displaying prefix byte counts, providing clearer information on node connections.
2026-03-09 09:43:49 -07:00
agessaman 6df2da5083 Add support for dynamic local services module
- Introduced a check in `load_service_from_path` to ensure the `local_services` module is created in `sys.modules` if it doesn't exist, facilitating proper relative and absolute imports for service plugins.
- This enhancement improves the loading mechanism for local service plugins, ensuring smoother integration and functionality.
2026-03-08 12:51:32 -07:00
agessaman 6b4e6351c4 Enhance logging configuration and documentation
- Added support for rotating log files in `core.py` using `RotatingFileHandler`, with a maximum size of 5 MB and up to 3 backup files.
- Updated `config.ini.example`, `config.ini.minimal-example`, and `config.ini.quickstart` to include descriptions of the new log rotation feature.
- Enhanced `data-retention.md` to clarify log file management and retention policies.
2026-03-08 12:41:15 -07:00
Adam Gessaman d1f915c256 Update funding information in FUNDING.yml
Updated GitHub Sponsors username and commented out other funding options.
2026-03-08 10:23:32 -07:00
agessaman adf5bc191e Enhance stats collection for web viewer dashboard
- Updated documentation in `data-retention.md` and `web-viewer.md` to clarify how stats are collected and displayed, including the new `collect_stats` configuration option.
- Modified `StatsCommand` in `stats_command.py` to introduce `collect_stats`, allowing message and command statistics to be recorded even when the `stats` command is disabled.
- Adjusted logic in `record_message`, `record_command_stats`, and `record_path_stats` methods to utilize the new `collect_stats` setting for improved flexibility in stats tracking.
2026-03-07 13:23:37 -08:00
agessaman f86fe0b140 Add support for local plugins configuration and directory handling
- Updated `config.ini.example` and `config.ini.minimal-example` to include optional `local_dir_path` for specifying a custom local plugins directory.
- Enhanced `install-service.sh` to preserve the `local/` directory during installation and create its structure if it doesn't exist.
- Modified `CommandManager` and `MeshCoreBot` to resolve the local commands and services directory based on the new configuration.
- Added validation in `config_validation.py` to check the existence and readability of the specified local plugins path.
- Improved documentation in `local-plugins.md` to clarify the usage of local plugins and the new configuration options.
2026-03-07 12:31:54 -08:00
agessaman e9f17ec48e Enhance shutdown process with scheduler thread handling and improved meshcore disconnect logic
- Added a `join` method in `MessageScheduler` to wait for the scheduler thread to finish during shutdown.
- Updated the shutdown sequence in `core.py` to include a timeout for the `meshcore.disconnect()` method, with error handling for potential timeouts and exceptions.
- Improved logging to provide clearer information during the shutdown process.
2026-03-07 11:21:43 -08:00
agessaman 0c060a515b Implement chunked message sending for improved rate limit handling
- Added `send_channel_messages_chunked` method to `CommandManager` for sending multiple messages with appropriate rate-limit spacing.
- Introduced `send_response_chunked` method in `BaseCommand` to facilitate chunked responses in both channels and DMs.
- Updated `GreeterCommand` to utilize the new chunked response functionality, simplifying the greeting message sending process.
- Enhanced documentation in `local-plugins.md` with examples for using chunked message sending, improving clarity on handling long messages and rate limits.
2026-03-07 09:02:12 -08:00
agessaman 69ac3ccdfb Update requirements and enhance documentation for service installation and message handling
- Changed `meshcore` dependency version in `requirements.txt` from `>=2.2.14` to `==2.2.14` for consistency.
- Added detailed instructions in `SERVICE-INSTALLATION.md` regarding Python version compatibility and potential f-string issues with Python 3.11.
- Introduced a new section in `local-plugins.md` explaining how to handle message chunking and bot rate limits, providing code examples for better clarity.
2026-03-06 22:03:13 -08:00
agessaman f57f480c9f Enhance MeshGraph and BotDataViewer for multi-byte support and improved edge handling
- Updated MeshGraph to support multi-resolution storage and node identity, allowing for better handling of 1-byte, 2-byte, and 3-byte edges.
- Implemented logic for merging and promoting edges based on observation counts and specificity.
- Enhanced BotDataViewer API to dynamically adjust prefix length based on configuration, improving data representation.
- Updated mesh.html template to display prefix byte counts, enhancing user experience with clearer information on node connections.
2026-03-06 16:57:57 -08:00
agessaman a4d1f678cf Enhance path handling in BotDataViewer and ModernContactsManager
- Added support for bytes per hop in the BotDataViewer, allowing for better path data representation.
- Updated the contacts template to display bytes per hop and adjusted path formatting based on this value.
- Improved the decode path functionality to utilize the correct bytes per hop for decoding paths, enhancing overall path handling and user experience.
2026-03-06 10:02:45 -08:00