18 Commits

Author SHA1 Message Date
aaa1e9b0c3 chore(release): bump version to 3.3.2 in package.json, pyproject.toml, and version.py
Some checks failed
Build and Release / Build and Release (push) Successful in 2m43s
CI / lint (push) Failing after 4m56s
CI / build-frontend (push) Successful in 9m34s
2026-01-02 11:12:00 -06:00
8e976f39bb chore(ci): streamline Electron app build process and enhance artifact collection in CI workflow 2026-01-02 11:11:34 -06:00
9734c18c4f chore(Taskfile): consolidate build commands for Electron apps and add task for building all platforms 2026-01-02 11:11:30 -06:00
71476c9196 feat(meshchat): fix file serving capabilities and improve path handling 2026-01-02 11:11:26 -06:00
d259bd4839 fix(README): update video link and remove outdated showcase video file 2026-01-02 11:11:04 -06:00
1f9632b396 chore(release): bump version to 3.3.1 and update README with additional screenshots
All checks were successful
Build and Release / Build and Release (push) Successful in 7m22s
CI / lint (push) Successful in 9m28s
CI / build-frontend (push) Successful in 9m34s
2026-01-02 10:28:15 -06:00
6ecd46dcec fix(MicronEditorPage): disable and enable eslint rule for v-html usage
All checks were successful
CI / build-frontend (push) Successful in 9m33s
CI / lint (push) Successful in 9m35s
2026-01-02 09:40:02 -06:00
0b5c8e4e68 refactor(CallPage): cleanup 2026-01-02 09:39:48 -06:00
42e7c2cf3b chore(ci): refactor CI workflow for improved readability and maintainability 2026-01-02 09:39:33 -06:00
e23c5abdd9 fix(version): standardize version string quotes in version.py 2026-01-02 09:39:26 -06:00
fea9389a14 chore(ci): update build workflow to include Windows support and improve release asset handling
Some checks failed
CI / lint (push) Failing after 4m54s
CI / build-frontend (push) Successful in 9m32s
2026-01-02 09:31:16 -06:00
20c0e10767 chore(Taskfile): add tasks for setting up Python environment and linting 2026-01-02 09:31:11 -06:00
7618300619 chore(ci): add CI workflow for linting and building frontend 2026-01-02 09:31:08 -06:00
98092d3c77 chore(cx_setup): update include_files logic to conditionally add directories 2026-01-02 09:23:16 -06:00
2d8e050d61 chore(build): remove sync versions step from workflow 2026-01-02 09:23:10 -06:00
dc6f0cae29 chore(Taskfile): simplify install task and remove sync-version task 2026-01-02 09:23:01 -06:00
2f00c39aba chore(sync_version): remove sync_version.py script as it is no longer needed 2026-01-02 09:20:18 -06:00
92204ba16a docs(README): update 2026-01-02 09:18:19 -06:00
13 changed files with 208 additions and 108 deletions

View File

@@ -71,16 +71,13 @@ jobs:
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng
sudo apt-get install -y patchelf libopusfile0 ffmpeg espeak-ng wine nsis
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: "3.46.3"
- name: Sync versions
run: python scripts/sync_version.py
- name: Install dependencies
run: task install
@@ -90,24 +87,39 @@ jobs:
- name: Build Python wheel
run: task wheel
- name: Build Electron App (Universal)
run: pnpm run dist-prebuilt
- name: Build Electron Apps (Linux and Windows)
run: task build-electron-all
- name: Prepare release assets
run: |
mkdir -p release-assets
# Collect artifacts
find dist -type f \( -name "*-linux*.AppImage" -o -name "*-linux*.deb" \) -exec cp {} release-assets/ \;
find python-dist -type f -name "*.whl" -exec cp {} release-assets/ \;
# Collect artifacts from dist/
# Linux artifacts
find dist -maxdepth 1 -type f \( -name "*-linux*.AppImage" -o -name "*-linux*.deb" \) -exec cp {} release-assets/ \;
# Windows artifacts
find dist -maxdepth 1 -type f \( -name "*-win*.exe" \) -exec cp {} release-assets/ \;
# Python artifacts
find python-dist -maxdepth 1 -type f -name "*.whl" -exec cp {} release-assets/ \;
# Generate checksums
cd release-assets
for file in *; do
if [ -f "$file" ] && [[ "$file" != *.sha256 ]]; then
sha256sum "$file" | tee "${file}.sha256"
fi
done
# Generate release notes (outside release-assets directory)
cd ..
echo "## SHA256 Checksums" > release-body.md
echo "" >> release-body.md
for file in *; do
if [ -f "$file" ] && [ "$file" != "release-body.md" ] && [[ "$file" != *.sha256 ]]; then
sha256sum "$file" | tee "${file}.sha256"
echo "\`$(cat "${file}.sha256")\`" >> release-body.md
for file in release-assets/*; do
if [ -f "$file" ] && [[ "$file" != *.sha256 ]] && [[ "$file" != *release-body.md* ]]; then
filename=$(basename "$file")
if [ -f "release-assets/${filename}.sha256" ]; then
# Extract just the filename and its sha256 (format: <sha256> <filename>)
echo "\`$(cat "release-assets/${filename}.sha256")\`" >> release-body.md
fi
fi
done
@@ -132,8 +144,13 @@ jobs:
gitea_token: ${{ secrets.GITEA_TOKEN }}
title: ${{ steps.version.outputs.version }}
tag: ${{ steps.version.outputs.version }}
files: "release-assets/*"
bodyFile: "release-assets/release-body.md"
files: |
release-assets/*.AppImage
release-assets/*.deb
release-assets/*.exe
release-assets/*.whl
release-assets/*.sha256
body_path: "release-body.md"
draft: false
prerelease: false

66
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,66 @@
name: CI
on:
push:
branches:
- "*"
workflow_dispatch:
env:
UV_LINK_MODE: copy
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: https://git.quad4.io/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Node.js
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22
cache: pnpm
- name: Setup Python
uses: https://git.quad4.io/actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.13"
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: "3.46.3"
- name: Setup uv
run: |
task setup-uv
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: Setup Python environment
run: task setup-python-env
- name: Install Node dependencies
run: task node_modules
- name: Lint
run: task lint
build-frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: https://git.quad4.io/actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Node.js
uses: https://git.quad4.io/actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22
cache: pnpm
- name: Setup Task
uses: https://git.quad4.io/actions/setup-task@0ab1b2a65bc55236a3bc64cde78f80e20e8885c2 # v1
with:
version: "3.46.3"
- name: Install dependencies
run: task node_modules
- name: Determine version
id: version
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
echo "version=${SHORT_SHA}" >> $GITHUB_OUTPUT
- name: Build frontend
run: task build-frontend
env:
VITE_APP_VERSION: ${{ steps.version.outputs.version }}

View File

@@ -2,7 +2,7 @@
A [Reticulum MeshChat](https://github.com/liamcottle/reticulum-meshchat) fork from the future.
<video src="showcase/showcase-video-call.mp4" controls="controls" style="max-width: 100%;"></video>
<video src="https://strg.0rbitzer0.net/view/62926a2a-0a9a-4f44-a5f6-000dd60deac1.mp4" controls="controls" style="max-width: 100%;"></video>
This project is seperate from the original Reticulum MeshChat project, and is not affiliated with the original project.
@@ -31,18 +31,23 @@ This project is seperate from the original Reticulum MeshChat project, and is no
<summary>Telephony & Calling</summary>
### Phone
![Phone](screenshots/phone.png)
### Active Call
![Calling](screenshots/calling.png)
### Call Ended
![Call Ended](screenshots/calling-end.png)
### Voicemail
![Voicemail](screenshots/voicemail.png)
### Ringtone Settings
![Ringtone](screenshots/ringtone.png)
</details>
@@ -51,6 +56,7 @@ This project is seperate from the original Reticulum MeshChat project, and is no
<summary>Networking & Visualization</summary>
### Network Visualiser
![Network Visualiser](screenshots/network-visualiser.png)
![Network Visualiser 2](screenshots/network-visualiser2.png)
@@ -60,9 +66,11 @@ This project is seperate from the original Reticulum MeshChat project, and is no
<summary>Page Archives</summary>
### Archives Browser
![Archives](screenshots/archives.png)
### Viewing Archived Page
![Archive View](screenshots/archive-view.png)
</details>
@@ -71,9 +79,11 @@ This project is seperate from the original Reticulum MeshChat project, and is no
<summary>Tools & Identities</summary>
### Tools
![Tools](screenshots/tools.png)
### Identity Management
![Identities](screenshots/identities.png)
</details>
@@ -88,7 +98,6 @@ This project is seperate from the original Reticulum MeshChat project, and is no
- [ ] RNS Tunnel - tunnel your regular services over RNS to another MeshchatX user.
- [ ] RNS Filesync - P2P file sync
- [ ] RNS Page Node
- [x] Micron Editor (w/ [micron-parser](https://github.com/RFnexus/micron-parser) by [RFnexus](https://github.com/RFnexus))
## Usage
@@ -135,7 +144,7 @@ All tasks support environment variable overrides. For example:
### Python Packaging
The backend uses Poetry with `pyproject.toml` for dependency management and packaging. Before building, run `python3 scripts/sync_version.py` (or `task sync-version`) to ensure the generated `src/version.py` reflects the version from `package.json` that the Electron artifacts use. This keeps the CLI release metadata, wheel packages, and other bundles aligned.
The backend uses Poetry with `pyproject.toml` for dependency management and packaging. `package.json` is the source of truth for the project version. When you run `task install` (or any task that builds/runs the app), the version is automatically synced to `pyproject.toml` and `src/version.py`. This keeps the CLI release metadata, wheel packages, and other bundles aligned with the Electron build.
#### Build Artifact Locations

View File

@@ -50,9 +50,35 @@ tasks:
cmds:
- task --list
setup-uv:
desc: Install uv
cmds:
- curl -LsSf https://astral.sh/uv/install.sh | sh
setup-python-env:
desc: Setup Python environment using uv
cmds:
- uv venv
- uv pip install ruff poetry
lint-python:
desc: Lint Python code using ruff
cmds:
- uv run ruff check .
- uv run ruff format --check .
lint-frontend:
desc: Lint frontend code
cmds:
- "{{.NPM}} run lint"
lint:
desc: Run all linters
deps: [lint-frontend, lint-python]
install:
desc: Install all dependencies (syncs version, installs node modules and python deps)
deps: [sync-version, node_modules, python]
desc: Install all dependencies (installs node modules and python deps)
deps: [node_modules, python]
node_modules:
desc: Install Node.js dependencies
@@ -109,6 +135,30 @@ tasks:
- "{{.NPM}} run electron-postinstall"
- "{{.NPM}} run dist -- --win portable"
build-electron-linux:
desc: Build Linux Electron app with prebuilt backend
deps: [build-frontend]
cmds:
- "{{.NPM}} run electron-postinstall"
- "{{.NPM}} run build-backend"
- "{{.NPM}} run dist -- --linux AppImage deb"
build-electron-windows:
desc: Build Windows Electron apps (portable and installer)
deps: [build-frontend]
cmds:
- "{{.NPM}} run electron-postinstall"
- "{{.NPM}} run build-backend"
- "{{.NPM}} run dist -- --win portable nsis"
build-electron-all:
desc: Build all Electron apps (Linux and Windows)
deps: [build-frontend]
cmds:
- "{{.NPM}} run electron-postinstall"
- "{{.NPM}} run build-backend"
- "{{.NPM}} run dist -- --linux AppImage deb --win portable nsis"
dist:
desc: Build distribution (defaults to AppImage)
cmds:
@@ -143,18 +193,14 @@ tasks:
- rm -rf dist
- rm -rf python-dist
- rm -rf meshchatx/public
- rm -rf build-dir
- task: android-clean
sync-version:
desc: Sync version numbers across project files
cmds:
- "{{.PYTHON}} scripts/sync_version.py"
fix:
desc: Format and fix linting issues (Python and frontend)
cmds:
- "{{.PYTHON}} -m poetry run ruff format ./"
- "{{.PYTHON}} -m poetry run ruff check --fix ./"
- uv run ruff format ./
- uv run ruff check --fix ./
- "{{.NPM}} run format"
- "{{.NPM}} run lint:fix"

View File

@@ -8,12 +8,17 @@ from meshchatx.src.version import __version__
ROOT = Path(__file__).resolve().parent
PUBLIC_DIR = ROOT / "meshchatx" / "public"
include_files = [
(str(PUBLIC_DIR), "public"),
("logo", "logo"),
]
include_files = []
if (ROOT / "bin").exists():
if PUBLIC_DIR.exists() and PUBLIC_DIR.is_dir():
include_files.append((str(PUBLIC_DIR), "public"))
logo_dir = ROOT / "logo"
if logo_dir.exists() and logo_dir.is_dir():
include_files.append(("logo", "logo"))
bin_dir = ROOT / "bin"
if bin_dir.exists() and bin_dir.is_dir():
include_files.append(("bin", "bin"))
packages = [

View File

@@ -91,6 +91,9 @@ from meshchatx.src.version import __version__ as app_version
# https://cx-freeze.readthedocs.io/en/latest/faq.html#using-data-files
# bearer:disable python_lang_path_traversal
def get_file_path(filename):
# Remove trailing slashes for path joining consistency
filename = filename.rstrip("/\\")
if getattr(sys, "frozen", False):
datadir = os.path.dirname(sys.executable)
return os.path.join(datadir, filename)
@@ -1706,6 +1709,15 @@ class ReticulumMeshChat:
},
)
# allow serving manifest.json and service-worker.js directly at root
@routes.get("/manifest.json")
async def manifest(request):
return web.FileResponse(get_file_path("public/manifest.json"))
@routes.get("/service-worker.js")
async def service_worker(request):
return web.FileResponse(get_file_path("public/service-worker.js"))
# serve ping
@routes.get("/api/v1/status")
async def status(request):
@@ -5969,6 +5981,8 @@ class ReticulumMeshChat:
response.headers["Content-Type"] = "text/css; charset=utf-8"
elif path.endswith(".json"):
response.headers["Content-Type"] = "application/json; charset=utf-8"
elif path.endswith(".wasm"):
response.headers["Content-Type"] = "application/wasm"
elif path.endswith(".html"):
response.headers["Content-Type"] = "text/html; charset=utf-8"
return response
@@ -6048,9 +6062,15 @@ class ReticulumMeshChat:
)
app.add_routes(routes)
app.add_routes(
[web.static("/", get_file_path("public/"))],
) # serve anything in public folder
# serve anything else from public folder
# we use add_static here as it's more robust for serving directories
public_dir = get_file_path("public")
if os.path.exists(public_dir):
app.router.add_static("/", public_dir, name="static", follow_symlinks=True)
else:
print(f"Warning: Static files directory not found at {public_dir}")
app.on_shutdown.append(
self.shutdown,
) # need to force close websockets and stop reticulum now

View File

@@ -1459,11 +1459,6 @@ export default {
isCallInputFocused: false,
};
},
watch: {
destinationHash() {
this.selectedSuggestionIndex = -1;
},
},
computed: {
isMicMuted() {
return this.activeCall?.is_mic_muted ?? false;
@@ -1533,6 +1528,11 @@ export default {
return suggestions.slice(0, 8);
},
},
watch: {
destinationHash() {
this.selectedSuggestionIndex = -1;
},
},
mounted() {
this.getConfig();
this.getAudioProfiles();

View File

@@ -51,11 +51,13 @@
isMobileView && showEditor ? 'hidden' : '',
]"
>
<!-- eslint-disable vue/no-v-html -->
<div
ref="previewRef"
class="flex-1 overflow-auto text-zinc-100 p-4 font-mono text-sm whitespace-pre-wrap break-words nodeContainer"
v-html="renderedContent"
></div>
<!-- eslint-enable vue/no-v-html -->
</div>
</div>
</div>

View File

@@ -3,4 +3,4 @@ Auto-generated helper so Python tooling and the Electron build
share the same version string.
"""
__version__ = '3.3.0'
__version__ = "3.3.2"

View File

@@ -1,6 +1,6 @@
{
"name": "reticulum-meshchatx",
"version": "3.3.0",
"version": "3.3.2",
"description": "A simple mesh network communications app powered by the Reticulum Network Stack",
"homepage": "https://git.quad4.io/RNS-Things/MeshChatX",
"author": "Sudo-Ivan",

View File

@@ -1,6 +1,6 @@
[project]
name = "reticulum-meshchatx"
version = "3.3.0"
version = "3.3.2"
description = "A simple mesh network communications app powered by the Reticulum Network Stack"
authors = [
{name = "Sudo-Ivan"}

View File

@@ -1,65 +0,0 @@
"""Update project version references to stay aligned with the Electron build.
Reads `package.json`, writes the same version into `src/version.py`, and
updates the `[tool.poetry] version` field inside `pyproject.toml`. Run this
before any Python packaging commands so the wheel version matches the
Electron artifacts.
"""
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
PACKAGE_JSON = ROOT / "package.json"
VERSION_PY = ROOT / "meshchatx" / "src" / "version.py"
PYPROJECT_TOML = ROOT / "pyproject.toml"
def read_package_version() -> str:
with PACKAGE_JSON.open() as handle:
return json.load(handle)["version"]
def write_version_module(version: str) -> None:
content = (
'"""\n'
"Auto-generated helper so Python tooling and the Electron build\n"
"share the same version string.\n"
'"""\n\n'
f"__version__ = {version!r}\n"
)
if VERSION_PY.exists() and VERSION_PY.read_text() == content:
return
VERSION_PY.write_text(content)
def update_poetry_version(version: str) -> None:
if not PYPROJECT_TOML.exists():
return
content = PYPROJECT_TOML.read_text()
def replacer(match):
return f"{match.group(1)}{version}{match.group(2)}"
new_content, replaced = re.subn(
r'(?m)^(version\s*=\s*")[^"]*(")',
replacer,
content,
count=1,
)
if replaced == 0:
msg = "failed to update version in pyproject.toml"
raise RuntimeError(msg)
if new_content != content:
PYPROJECT_TOML.write_text(new_content)
def main() -> None:
version = read_package_version()
write_version_module(version)
update_poetry_version(version)
if __name__ == "__main__":
main()

View File

Binary file not shown.