diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 5bc79ba..5ba31cb 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,8 +1,8 @@ # Architecture -MeshChat is a PySide6 (Qt 6) desktop app that connects to **one** Meshtastic +OrcMesh is a PySide6 (Qt 6) desktop app that connects to **one** Meshtastic radio at a time over USB/Serial, Bluetooth, or TCP. The radio does the actual -LoRa transmit/receive; MeshChat's job is to talk to it, keep a local record of +LoRa transmit/receive; OrcMesh's job is to talk to it, keep a local record of everything it reports, and present that as a chat client plus a network monitor. @@ -213,7 +213,7 @@ test in isolation, and it should stay that way. PyInstaller (`scripts/build.ps1`) builds a windowed (non-console) exe. Two PySide6/QtWebEngine artifacts — `QtWebEngineProcess.exe` and `icudtl.dat` — -need a manual post-build copy into `dist/MeshChat/` since PyInstaller's +need a manual post-build copy into `dist/OrcMesh/` since PyInstaller's default hooks don't always pick them up. Because the release build is windowed, `app.py` installs a global excepthook so unhandled exceptions produce a visible crash dialog instead of silently exiting — this is how @@ -221,7 +221,7 @@ several real bugs in this project were first surfaced by user reports. ## Licensing constraint -MeshChat links the official `meshtastic` Python package, which is +OrcMesh links the official `meshtastic` Python package, which is GPL-3.0-only. That makes GPL-3.0-only the only license this project can legally ship under — this is a hard constraint on any future dependency choice too, not just the project's own license. diff --git a/README.md b/README.md index e78b7b3..e0b0df2 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@
-# MeshChat for Windows +# OrcMesh -**A native Windows client and deep network monitor for [Meshtastic](https://meshtastic.org) mesh radios.** +**A native Windows operations console for [Meshtastic](https://meshtastic.org) LoRa mesh radios.** -Chat with your mesh, then actually *see* it — every node, every packet, every hop. +Map. Monitor. Message. -[![Release](https://img.shields.io/github/v/release/hardcoreerik/MeshChat-Windows?include_prereleases&color=00D4FF)](https://github.com/hardcoreerik/MeshChat-Windows/releases) +[![Release](https://img.shields.io/github/v/release/hardcoreerik/OrcMesh?include_prereleases&color=00D4FF)](https://github.com/hardcoreerik/OrcMesh/releases) [![License](https://img.shields.io/badge/license-GPL--3.0-8B5CF6)](LICENSE) -[![Platform](https://img.shields.io/badge/platform-Windows%20x64-4F9EFF)](https://github.com/hardcoreerik/MeshChat-Windows/releases) +[![Platform](https://img.shields.io/badge/platform-Windows%20x64-4F9EFF)](https://github.com/hardcoreerik/OrcMesh/releases) [![Python](https://img.shields.io/badge/python-3.12%2B-00FF88)](https://www.python.org/)
@@ -19,8 +19,8 @@ Chat with your mesh, then actually *see* it — every node, every packet, every ## What this is -MeshChat connects to **one** Meshtastic radio over USB, Bluetooth, or Wi-Fi. -The radio — not the PC — sends and receives the actual LoRa packets. MeshChat +OrcMesh connects to **one** Meshtastic radio over USB, Bluetooth, or Wi-Fi. +The radio — not the PC — sends and receives the actual LoRa packets. OrcMesh gives you a chat client on top of it, plus a monitoring dashboard that surfaces what the mesh is really doing: who's reachable, how many hops away, what's relaying, and how the signal looks. @@ -92,28 +92,28 @@ environment sensors when a node reports them. Channel messaging across the radio's configured Meshtastic channels, direct messages to any reachable node, and local message history that survives restarts — Meshtastic radios don't store message history themselves, so -MeshChat keeps its own. +OrcMesh keeps its own. ### 📶 Spectrum *(optional — needs an RTL-SDR)* A waterfall view of raw RF energy in the LoRa ISM bands. This shows *that* activity is happening and where in the band — it does **not** decode LoRa packets. Requires an RTL-SDR dongle plus `pyrtlsdr` and the native librtlsdr -driver; MeshChat runs normally without any of that. +driver; OrcMesh runs normally without any of that. --- ## Install **Just want to run it?** Grab the latest build from -[Releases](https://github.com/hardcoreerik/MeshChat-Windows/releases), extract, -and run `MeshChat.exe`. No installer, no Python needed. Windows x64. +[Releases](https://github.com/hardcoreerik/OrcMesh/releases), extract, +and run `OrcMesh.exe`. No installer, no Python needed. Windows x64. **From source** (Python 3.12+ x64): ```powershell -git clone https://github.com/hardcoreerik/MeshChat-Windows.git -cd MeshChat-Windows +git clone https://github.com/hardcoreerik/OrcMesh.git +cd OrcMesh .\scripts\bootstrap.ps1 .\scripts\run-dev.ps1 ``` @@ -125,7 +125,7 @@ cd MeshChat-Windows | Transport | Notes | |---|---| | **USB / Serial** | Most reliable. Pick the COM port and hit Connect. | -| **Bluetooth** | Pair the radio in **Windows Settings first** — Meshtastic radios require OS-level pairing before any app can reach them. MeshChat detects this case and offers a shortcut to the Bluetooth settings page. | +| **Bluetooth** | Pair the radio in **Windows Settings first** — Meshtastic radios require OS-level pairing before any app can reach them. OrcMesh detects this case and offers a shortcut to the Bluetooth settings page. | | **Wi-Fi / TCP** | Enter the radio's hostname or IP (default port 4403). | --- @@ -134,11 +134,11 @@ cd MeshChat-Windows ```powershell .\scripts\test.ps1 # run the test suite -.\scripts\build.ps1 # build dist\MeshChat\MeshChat.exe +.\scripts\build.ps1 # build dist\OrcMesh\OrcMesh.exe .\scripts\run-dev.ps1 -Debug # verbose logging ``` -Logs are written to `%LOCALAPPDATA%\MeshChat\Logs\`. +For upgrade compatibility, logs remain under `%LOCALAPPDATA%\MeshChat\Logs\`. **Architecture** — PySide6 (Qt 6) desktop app. All blocking Meshtastic I/O runs on a dedicated `QThread`; the radio library's PubSub callbacks are marshalled @@ -168,7 +168,7 @@ issues are welcome. GPL-3.0-only — see [LICENSE](LICENSE). -MeshChat links the official Meshtastic Python package, which is GPL-3.0 +OrcMesh links the official Meshtastic Python package, which is GPL-3.0 copyleft, so this project is licensed to match. Full dependency licensing is in [THIRD_PARTY_LICENSES.md](THIRD_PARTY_LICENSES.md). diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index f5fa47d..d8dfe77 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -1,6 +1,6 @@ # Third Party Licenses -MeshChat for Windows is licensed **GPL-3.0-only** — see [LICENSE](LICENSE). +OrcMesh is licensed **GPL-3.0-only** — see [LICENSE](LICENSE). It is licensed this way because it links the official Meshtastic Python package, which is GPL-3.0-only copyleft. diff --git a/docs/mcoreimg-integration.md b/docs/mcoreimg-integration.md index 07c611e..db0fc51 100644 --- a/docs/mcoreimg-integration.md +++ b/docs/mcoreimg-integration.md @@ -3,7 +3,7 @@ Status: **exploratory — no implementation started.** This document captures the research and open decisions from an initial discussion about bringing [MCoreIMG](https://github.com/Aaron-KE9ETA/MCoreIMG) (a compact vector-image -transport protocol built for MeshCore) into MeshChat. +transport protocol built for MeshCore) into OrcMesh. --- @@ -56,12 +56,12 @@ MIT. No legal obstacle to forking or vendoring any part of it. MCoreIMG's framing constants are tuned to MeshCore's transport: -| | MeshCore (MCoreIMG's target) | Meshtastic (MeshChat's target) | +| | MeshCore (MCoreIMG's target) | Meshtastic (OrcMesh's target) | |---|---|---| -| Message size limit | 150 characters | 200 **bytes** (UTF-8; MeshChat already enforces this in the composer) | +| Message size limit | 150 characters | 200 **bytes** (UTF-8; OrcMesh already enforces this in the composer) | | Frame header | 15 chars, MeshCore-specific | would need a Meshtastic-specific design | | Per-frame integrity | CRC-16 | reusable as-is | -| Message addressing | MeshCore's own | Meshtastic channel index / direct-message node ID (MeshChat already models both — see `ChatMessage.destination_num`) | +| Message addressing | MeshCore's own | Meshtastic channel index / direct-message node ID (OrcMesh already models both — see `ChatMessage.destination_num`) | The **framing layer is the MeshCore-specific part** and can't be reused directly — the byte budget, header format, and message-count math would all @@ -76,7 +76,7 @@ the bytes. **Bottom line:** this is a vendor-and-adapt situation, not a drop-in dependency. The reusable core is real and substantial; the framing/transport layer and all -of the MeshChat-side UI would be new work. +of the OrcMesh-side UI would be new work. --- @@ -92,7 +92,7 @@ reason they feel like "more than the file size" is that the reader is a black/white cells is a much denser *visual* channel than, say, a 1D barcode, for that specific transport method (printed ink, camera sensor). -That trick doesn't apply here. MeshChat has no optical scan step — the +That trick doesn't apply here. OrcMesh has no optical scan step — the Meshtastic text messages *are* the data channel directly, with no image representation in between. Drawing our compressed bitstream as a QR-style raster pattern wouldn't add capacity; MCoreIMG's existing Base91 text encoding @@ -137,8 +137,8 @@ exists to make them explicit, not to answer them unilaterally. | Option | Tradeoff | |---|---| -| **Vendor a one-time copy** | Copy `model` + `compression` into MeshChat, adapt freely for our framing. No dependency on Aaron's repo staying maintained or stable. Loses future upstream compression improvements automatically. | -| **Real fork, track upstream** | Can pull in future protocol/compression improvements. More coordination overhead once MeshChat's framing diverges from MeshCore's — merges get harder the more the two projects' transport layers differ. | +| **Vendor a one-time copy** | Copy `model` + `compression` into OrcMesh, adapt freely for our framing. No dependency on Aaron's repo staying maintained or stable. Loses future upstream compression improvements automatically. | +| **Real fork, track upstream** | Can pull in future protocol/compression improvements. More coordination overhead once OrcMesh's framing diverges from MeshCore's — merges get harder the more the two projects' transport layers differ. | Given the framing layer *must* diverge regardless (Meshtastic's byte budget is different from MeshCore's), a real fork mostly buys future improvements to the @@ -158,21 +158,21 @@ Not a commitment, just what the work would concretely involve, to size it: bytes/message instead of 150 chars, reusing CRC-16 per-frame + CRC-32 stream-level integrity. Needs a message-count strategy (fixed N like MCoreIMG's "10", or variable based on content). -3. **New message kind in MeshChat's chat model.** `ChatMessage` currently +3. **New message kind in OrcMesh's chat model.** `ChatMessage` currently models plain text; an image transfer needs to be recognizable as "part of image transfer #X, frame N/M" so it doesn't render as garbled text in the chat bubble, and so out-of-order/partial arrivals can be buffered correctly (Meshtastic doesn't guarantee delivery order). 4. **Compose UI.** Import/select an SVG (or a simple drawing tool) in `ChatView`, live message-count budget as the user composes — mirroring - MCoreIMG's Constructor GUI feedback loop, adapted to MeshChat's theme + MCoreIMG's Constructor GUI feedback loop, adapted to OrcMesh's theme and widget set. 5. **Receive UI.** Detect an in-progress transfer, show a progress indicator across incoming frames, decode with the vendored Reconstructor logic once complete, render inline in the chat bubble (not a separate window). 6. **Decide fork vs. vendor** (see above) before step 1, since it affects - how the vendored files are organized in the MeshChat tree. + how the vendored files are organized in the OrcMesh tree. Sizing note: the codec port (step 1–2) is moderate, well-scoped work given the existing clean module boundaries. The UI (steps 3–5) is the larger piece — diff --git a/packaging/installer.iss b/packaging/installer.iss index 890245c..bc645f2 100644 --- a/packaging/installer.iss +++ b/packaging/installer.iss @@ -1,13 +1,13 @@ -; MeshChat for Windows — Inno Setup installer script. +; OrcMesh — Inno Setup installer script. ; -; Build with (after scripts\build.ps1 has produced dist\MeshChat\): +; Build with (after scripts\build.ps1 has produced dist\OrcMesh\): ; & "$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe" packaging\installer.iss ; (or wherever ISCC.exe landed for your Inno Setup install — winget installs ; per-user by default, not to Program Files.) ; -; Produces dist\MeshChat-Setup-.exe: a single installer with a +; Produces dist\OrcMesh-Setup-.exe: a single installer with a ; Start Menu shortcut, optional desktop icon, and a standard uninstaller -; registered in Windows' "Apps & features". No code signing — MeshChat +; registered in Windows' "Apps & features". No code signing — OrcMesh ; isn't signed yet (see ROADMAP.md), so Windows SmartScreen will show an ; "unrecognized publisher" warning on first run until it builds up ; enough download reputation. @@ -17,11 +17,11 @@ ; (pyproject.toml drives what gets baked into the exe via ; importlib.metadata; this drives the installer filename/registry entry). -#define MyAppName "MeshChat" -#define MyAppVersion "0.1.1" +#define MyAppName "OrcMesh" +#define MyAppVersion "0.2.0" #define MyAppPublisher "hardcoreerik" -#define MyAppURL "https://github.com/hardcoreerik/MeshChat-Windows" -#define MyAppExeName "MeshChat.exe" +#define MyAppURL "https://github.com/hardcoreerik/OrcMesh" +#define MyAppExeName "OrcMesh.exe" [Setup] AppId={{6E9C2C6D-6B7B-4F2E-9C2C-6D6B7B4F2E9C} @@ -40,7 +40,7 @@ LicenseFile=..\LICENSE PrivilegesRequired=lowest PrivilegesRequiredOverridesAllowed=dialog OutputDir=..\dist -OutputBaseFilename=MeshChat-Setup-{#MyAppVersion} +OutputBaseFilename=OrcMesh-Setup-{#MyAppVersion} Compression=lzma2 SolidCompression=yes WizardStyle=modern @@ -58,7 +58,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ ; Everything PyInstaller collected — the exe, its _internal/ dependency ; tree, and the QtWebEngineProcess.exe/icudtl.dat build.ps1 copies in ; alongside it. -Source: "..\dist\MeshChat\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +Source: "..\dist\OrcMesh\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs [Icons] Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" @@ -69,7 +69,7 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: de Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent [UninstallDelete] -; MeshChat writes logs/settings under %LOCALAPPDATA%\MeshChat (see +; OrcMesh retains its pre-rebrand data under %LOCALAPPDATA%\MeshChat (see ; platformdirs usage in app.py) — deliberately NOT removed here. An ; uninstall shouldn't silently delete a user's chat history/node ; database; that's what "Reset" inside the app (once it exists) or a diff --git a/packaging/meshchat.spec b/packaging/orcmesh.spec similarity index 97% rename from packaging/meshchat.spec rename to packaging/orcmesh.spec index d86564b..ad9ebac 100644 --- a/packaging/meshchat.spec +++ b/packaging/orcmesh.spec @@ -1,9 +1,9 @@ # -*- mode: python ; coding: utf-8 -*- """ -PyInstaller spec for MeshChat for Windows. +PyInstaller spec for OrcMesh. Build with: - .\.venv\Scripts\pyinstaller packaging\meshchat.spec + .\.venv\Scripts\pyinstaller packaging\orcmesh.spec Or use the build script: .\scripts\build.ps1 @@ -129,7 +129,7 @@ exe = EXE( a.scripts, [], exclude_binaries=True, - name="MeshChat", + name="OrcMesh", debug=False, bootloader_ignore_signals=False, strip=False, @@ -152,5 +152,5 @@ coll = COLLECT( strip=False, upx=True, upx_exclude=["vcruntime140.dll", "python3*.dll", "Qt6*.dll"], - name="MeshChat", + name="OrcMesh", ) diff --git a/pyproject.toml b/pyproject.toml index 73324c1..ff14b1c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,9 +3,9 @@ requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] -name = "meshchat-windows" +name = "orcmesh" version = "0.2.0" -description = "Native Windows desktop client and network monitor for Meshtastic mesh radio networks" +description = "Native Windows operations console for LoRa mesh networks" requires-python = ">=3.12" license = "GPL-3.0-only" dependencies = [ @@ -18,11 +18,11 @@ dependencies = [ ] [project.scripts] -meshchat = "meshchat.app:main" +orcmesh = "meshchat.app:main" [project.optional-dependencies] # RTL-SDR spectrum waterfall. Also needs the native librtlsdr driver — on -# Windows, install the WinUSB driver for the dongle with Zadig. MeshChat runs +# Windows, install the WinUSB driver for the dongle with Zadig. OrcMesh runs # normally without this; the Spectrum page just reports it as unavailable. sdr = [ "pyrtlsdr>=0.3", diff --git a/requirements-dev.txt b/requirements-dev.txt index eee456e..ea93295 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -# MeshChat for Windows — development dependencies +# OrcMesh — development dependencies # Mirrors [project.optional-dependencies].dev in pyproject.toml. # Preferred install is `pip install -e ".[dev]"` (or .\scripts\bootstrap.ps1). diff --git a/requirements.txt b/requirements.txt index 77f83e5..3fd136b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -# MeshChat for Windows — runtime dependencies +# OrcMesh — runtime dependencies # Mirrors [project.dependencies] in pyproject.toml. # Preferred install is `pip install -e .` (or .\scripts\bootstrap.ps1), # which reads pyproject.toml directly. @@ -12,5 +12,5 @@ numpy>=1.26 # Optional — RTL-SDR spectrum waterfall (Spectrum page). # Also needs the native librtlsdr driver; on Windows install the WinUSB -# driver for the dongle with Zadig. MeshChat runs fine without this. +# driver for the dongle with Zadig. OrcMesh runs fine without this. # pyrtlsdr>=0.3 diff --git a/scripts/bootstrap.ps1 b/scripts/bootstrap.ps1 index f44264a..cb6e4e7 100644 --- a/scripts/bootstrap.ps1 +++ b/scripts/bootstrap.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Bootstrap the MeshChat development environment. + Bootstrap the OrcMesh development environment. .DESCRIPTION Creates a virtual environment, installs the package in editable mode with all dev dependencies. Run once after cloning, or again to upgrade deps. @@ -9,7 +9,7 @@ $ErrorActionPreference = "Stop" $root = Split-Path $PSScriptRoot -Parent Set-Location $root -Write-Host "==> MeshChat bootstrap" -ForegroundColor Cyan +Write-Host "==> OrcMesh bootstrap" -ForegroundColor Cyan # ── Python version check ──────────────────────────────────────────────────── $py = Get-Command python -ErrorAction SilentlyContinue diff --git a/scripts/build.ps1 b/scripts/build.ps1 index fd6f254..f86aae5 100644 --- a/scripts/build.ps1 +++ b/scripts/build.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Build MeshChat for Windows as a standalone executable. + Build OrcMesh for Windows as a standalone executable. .PARAMETER SkipTests Skip the test suite (not recommended for release builds). .PARAMETER NoUpx @@ -43,7 +43,7 @@ if (Test-Path "dist") { Remove-Item -Recurse -Force dist } # ── PyInstaller ───────────────────────────────────────────────────────────── Write-Host "==> Running PyInstaller..." -ForegroundColor Cyan -$specArgs = @("packaging\meshchat.spec", "--clean", "--noconfirm") +$specArgs = @("packaging\orcmesh.spec", "--clean", "--noconfirm") if ($NoUpx) { $specArgs += "--noupx" } & ".\.venv\Scripts\pyinstaller.exe" @specArgs @@ -54,7 +54,7 @@ if ($LASTEXITCODE -ne 0) { # ── Post-build: copy QtWebEngineProcess.exe if PyInstaller missed it ──────── Write-Host "==> Post-build checks..." -ForegroundColor Cyan -$distDir = "dist\MeshChat" +$distDir = "dist\OrcMesh" $pyside6Src = & ".\.venv\Scripts\python.exe" -c "import PySide6, os; print(os.path.dirname(PySide6.__file__))" # QtWebEngineProcess.exe — must be in the root of the dist folder on Windows @@ -72,12 +72,12 @@ if ((Test-Path $icuDat) -and -not (Test-Path "$distDir\icudtl.dat")) { } # ── Verify ────────────────────────────────────────────────────────────────── -if (Test-Path "$distDir\MeshChat.exe") { - $size = (Get-Item "$distDir\MeshChat.exe").Length / 1MB +if (Test-Path "$distDir\OrcMesh.exe") { + $size = (Get-Item "$distDir\OrcMesh.exe").Length / 1MB Write-Host "" - Write-Host ("==> Build successful: $distDir\MeshChat.exe ({0:F1} MB)" -f $size) -ForegroundColor Green + Write-Host ("==> Build successful: $distDir\OrcMesh.exe ({0:F1} MB)" -f $size) -ForegroundColor Green Write-Host " Full dist directory: $((Get-Item $distDir).FullName)" } else { - Write-Error "Build failed — MeshChat.exe not found in dist\" + Write-Error "Build failed — OrcMesh.exe not found in dist\" exit 1 } diff --git a/scripts/capture_screenshots.py b/scripts/capture_screenshots.py index 0a30556..8ffa280 100644 --- a/scripts/capture_screenshots.py +++ b/scripts/capture_screenshots.py @@ -67,8 +67,8 @@ def main() -> int: from PySide6.QtWidgets import QApplication app = QApplication(sys.argv) - app.setOrganizationName("MeshChat") - app.setApplicationName("MeshChat") + app.setOrganizationName("OrcMesh") + app.setApplicationName("OrcMesh") from meshchat.ui.theme import global_stylesheet app.setStyleSheet(global_stylesheet()) diff --git a/scripts/fetch_vendors.py b/scripts/fetch_vendors.py index 3a1cd01..4dd1ed4 100644 --- a/scripts/fetch_vendors.py +++ b/scripts/fetch_vendors.py @@ -64,7 +64,7 @@ def fetch(url: str, dest: Path) -> None: dest.parent.mkdir(parents=True, exist_ok=True) print(f" downloading {dest.name} ...", end=" ", flush=True) try: - req = urllib.request.Request(url, headers={"User-Agent": "MeshChat-build/1.0"}) + req = urllib.request.Request(url, headers={"User-Agent": "OrcMesh-build/1.0"}) with urllib.request.urlopen(req, timeout=30) as resp: data = resp.read() dest.write_bytes(data) diff --git a/scripts/run-dev.ps1 b/scripts/run-dev.ps1 index 52e9dbc..cdff089 100644 --- a/scripts/run-dev.ps1 +++ b/scripts/run-dev.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Run MeshChat in development mode from the local venv. + Run OrcMesh in development mode from the local venv. .PARAMETER Debug Enable verbose debug logging. .PARAMETER Args @@ -23,5 +23,5 @@ $extraArgs = @() if ($Debug) { $extraArgs += "--debug" } if ($AppArgs) { $extraArgs += $AppArgs } -Write-Host "==> Launching MeshChat (dev)..." -ForegroundColor Cyan +Write-Host "==> Launching OrcMesh (dev)..." -ForegroundColor Cyan & ".\.venv\Scripts\python.exe" -m meshchat @extraArgs diff --git a/scripts/test.ps1 b/scripts/test.ps1 index 96dc403..eee268c 100644 --- a/scripts/test.ps1 +++ b/scripts/test.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Run the MeshChat test suite. + Run the OrcMesh test suite. .PARAMETER Fast Skip slow integration tests (marked with @pytest.mark.slow). .PARAMETER Args diff --git a/src/meshchat/__init__.py b/src/meshchat/__init__.py index ef0add5..9cdb67e 100644 --- a/src/meshchat/__init__.py +++ b/src/meshchat/__init__.py @@ -1 +1 @@ -"""MeshChat for Windows""" +"""OrcMesh — LoRa Mesh Operations Console.""" diff --git a/src/meshchat/app.py b/src/meshchat/app.py index f142eb6..51f5f63 100644 --- a/src/meshchat/app.py +++ b/src/meshchat/app.py @@ -1,4 +1,4 @@ -"""MeshChat for Windows — application entry point.""" +"""OrcMesh — application entry point.""" from __future__ import annotations import argparse @@ -29,9 +29,9 @@ def handler(exc_type, exc_value, exc_tb): if QApplication.instance() is not None: box = QMessageBox() box.setIcon(QMessageBox.Icon.Critical) - box.setWindowTitle("MeshChat — Unexpected Error") + box.setWindowTitle("OrcMesh — Unexpected Error") box.setText( - "MeshChat hit an unexpected error.\n\n" + "OrcMesh hit an unexpected error.\n\n" "It has been written to the log file " "(Help > Open Log Folder). The app may still be usable." ) @@ -46,11 +46,13 @@ def handler(exc_type, exc_value, exc_tb): def main() -> int: - parser = argparse.ArgumentParser(prog="meshchat", description="MeshChat for Windows") + parser = argparse.ArgumentParser( + prog="orcmesh", description="OrcMesh — LoRa Mesh Operations Console" + ) parser.add_argument("--debug", action="store_true", help="Enable verbose debug logging") parser.add_argument( "--version", action="store_true", - help="Print the MeshChat and dependency versions and exit", + help="Print the OrcMesh and dependency versions and exit", ) args, _rest = parser.parse_known_args() @@ -62,7 +64,7 @@ def main() -> int: from meshchat.version import __version__ - print(f"MeshChat {__version__}") + print(f"OrcMesh {__version__}") # Package metadata rather than a __version__ attribute: meshtastic # does not expose one, so getattr() reported "unknown" for it. for dist in ("meshtastic", "PySide6", "pyqtgraph"): @@ -89,9 +91,11 @@ def main() -> int: from PySide6.QtWidgets import QApplication app = QApplication(sys.argv) + # Keep the legacy Qt identity so upgrades retain existing settings. app.setOrganizationName("MeshChat") app.setOrganizationDomain("meshtastic.org") app.setApplicationName("MeshChat") + app.setApplicationDisplayName("OrcMesh") from meshchat.version import __version__ app.setApplicationVersion(__version__) diff --git a/src/meshchat/services/app_logging.py b/src/meshchat/services/app_logging.py index 9bff9c4..c2050c0 100644 --- a/src/meshchat/services/app_logging.py +++ b/src/meshchat/services/app_logging.py @@ -1,4 +1,4 @@ -"""MeshChat – services: application logging setup.""" +"""OrcMesh – services: application logging setup.""" from __future__ import annotations import logging @@ -8,6 +8,7 @@ import platformdirs +# Legacy storage name retained so upgrades keep existing logs. APP_NAME = "MeshChat" _configured = False @@ -49,7 +50,7 @@ def configure_logging(debug: bool = False) -> None: root.addHandler(sh) log = logging.getLogger(__name__) - log.info("MeshChat logging started. Log file: %s", log_file) + log.info("OrcMesh logging started. Log file: %s", log_file) def get_log_dir() -> Path: diff --git a/src/meshchat/services/monitor_store.py b/src/meshchat/services/monitor_store.py index f731f69..244cdd7 100644 --- a/src/meshchat/services/monitor_store.py +++ b/src/meshchat/services/monitor_store.py @@ -1,4 +1,4 @@ -"""MeshChat – services: SQLite-backed monitor data store with WAL mode.""" +"""OrcMesh – services: SQLite-backed monitor data store with WAL mode.""" from __future__ import annotations import logging @@ -22,6 +22,7 @@ from meshchat.models.telemetry_sample import TelemetrySample log = logging.getLogger(__name__) +# Legacy storage name retained so upgrades keep chat and monitoring history. APP_NAME = "MeshChat" #: Days of packet/position/telemetry history to keep. Node identities and diff --git a/src/meshchat/ui/main_window.py b/src/meshchat/ui/main_window.py index 5771fd8..b9aa061 100644 --- a/src/meshchat/ui/main_window.py +++ b/src/meshchat/ui/main_window.py @@ -1,4 +1,4 @@ -"""MeshChat – MainWindow: application shell with nav rail and page stack.""" +"""OrcMesh – MainWindow: application shell with nav rail and page stack.""" from __future__ import annotations import logging @@ -94,7 +94,7 @@ def __init__(self, icon: str, label: str, parent=None): class MainWindow(QMainWindow): def __init__(self): super().__init__() - self.setWindowTitle("MeshChat for Windows") + self.setWindowTitle("OrcMesh — LoRa Mesh Operations Console") self.setMinimumSize(1100, 700) self.resize(1400, 900) self.setStyleSheet(global_stylesheet()) @@ -312,7 +312,7 @@ def _build_menu(self) -> None: help_menu.addSeparator() - about_act = QAction("About MeshChat", self) + about_act = QAction("About OrcMesh", self) about_act.triggered.connect(self._show_about) help_menu.addAction(about_act) @@ -469,7 +469,7 @@ def _copy_diagnostic(self) -> None: from meshchat.version import VERSION import meshtastic lines = [ - f"MeshChat {VERSION}", + f"OrcMesh {VERSION}", f"Python {sys.version}", f"PySide6 {self._pyside6_ver()}", f"meshtastic {getattr(meshtastic, '__version__', '?')}", @@ -489,10 +489,10 @@ def _show_about(self) -> None: from meshchat.version import VERSION QMessageBox.about( self, - "About MeshChat", - f"MeshChat for Windows
Version {VERSION}

" - "Chat with your Meshtastic mesh network from Windows.

" - "MeshChat connects to one nearby Meshtastic radio.
" + "About OrcMesh", + f"OrcMesh
LoRa Mesh Operations Console
Version {VERSION}

" + "Map, monitor, and message your Meshtastic network from Windows.

" + "OrcMesh connects to one nearby Meshtastic radio.
" "The radio — not the PC — sends and receives LoRa packets.

" "© 2026 GPLv3 (via Meshtastic Python library)", ) diff --git a/src/meshchat/ui/map/web/index.html b/src/meshchat/ui/map/web/index.html index 23805fb..11fb1f8 100644 --- a/src/meshchat/ui/map/web/index.html +++ b/src/meshchat/ui/map/web/index.html @@ -2,7 +2,7 @@ -MeshChat Map + OrcMesh Map diff --git a/src/meshchat/ui/nodes/nodes_page.py b/src/meshchat/ui/nodes/nodes_page.py index cee7ec7..4973aad 100644 --- a/src/meshchat/ui/nodes/nodes_page.py +++ b/src/meshchat/ui/nodes/nodes_page.py @@ -253,18 +253,18 @@ def _on_context_menu(self, pos) -> None: def _confirm_remove(self, node_num: int, name: str) -> None: # Removing writes to the radio's own NodeDB — confirm before doing - # it. This does NOT touch MeshChat's own local node history at all: - # MeshChat's node table is intentionally exempt from history + # it. This does NOT touch OrcMesh's own local node history at all: + # OrcMesh's node table is intentionally exempt from history # pruning, so the entry keeps showing here (and in Rankings/the # Map) indefinitely regardless of whether the node ever transmits # again — say so explicitly rather than implying it only sticks # around until its next transmission, which overstates how much - # this action actually does on the MeshChat side. + # this action actually does on the OrcMesh side. reply = QMessageBox.question( self, "Remove Node", f"Remove “{name}” from the connected radio's own node database?\n\n" - "This only affects the physical radio. MeshChat's own node " + "This only affects the physical radio. OrcMesh's own node " "history here is untouched — the entry stays in the Nodes " "table, Rankings, and Map regardless.", QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel, diff --git a/src/meshchat/version.py b/src/meshchat/version.py index 63d93f9..f7dbb2f 100644 --- a/src/meshchat/version.py +++ b/src/meshchat/version.py @@ -1,4 +1,4 @@ -"""MeshChat version. +"""OrcMesh version. Single-sourced from the installed package metadata so this cannot drift from pyproject.toml. The literal is only a fallback for running straight from a @@ -14,10 +14,10 @@ from importlib.metadata import PackageNotFoundError from importlib.metadata import version as _pkg_version -_FALLBACK = "0.1.0" +_FALLBACK = "0.2.0" try: - __version__ = _pkg_version("meshchat-windows") + __version__ = _pkg_version("orcmesh") except PackageNotFoundError: # running from an uninstalled source checkout __version__ = _FALLBACK diff --git a/tests/test_connection_supervisor.py b/tests/test_connection_supervisor.py index 14ce388..9629ef1 100644 --- a/tests/test_connection_supervisor.py +++ b/tests/test_connection_supervisor.py @@ -6,8 +6,7 @@ """ from __future__ import annotations -import time -from unittest.mock import MagicMock, patch +from unittest.mock import MagicMock import pytest @@ -31,7 +30,6 @@ def qt_app(): @pytest.fixture def mock_controller(): - ctrl = MagicMock() # Provide real Signal-like objects so ConnectionSupervisor can connect to them. from PySide6.QtCore import QObject, Signal diff --git a/tests/test_monitor_store_settings.py b/tests/test_monitor_store_settings.py index 6704248..f271189 100644 --- a/tests/test_monitor_store_settings.py +++ b/tests/test_monitor_store_settings.py @@ -1,8 +1,6 @@ """Tests for MonitorStore get_setting / set_setting (app_settings table).""" from __future__ import annotations -from pathlib import Path - import pytest from meshchat.services.monitor_store import MonitorStore