Commit Graph
26 Commits
Author SHA1 Message Date
Jean-Pierre MartineauandClaude Opus 5.5 b7a1ad47c2 The Oxford comma, always, the one-line description included
Every list of three or more takes the serial comma: the one-liner in
pyproject.toml, meshterm/__init__.py, and --help ("USB, Bluetooth, or TCP",
"Windows, macOS, and Linux"), the README, the changelog, the manuals, the
issue and PR templates, and six strings the app shows (the region-name
rule, a repeater setting's help, the diagnostics tool's description, and
the archive confirms). The Windows-console notice is rewrapped so its
comma keeps it inside 72 columns.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 21:28:00 -04:00
Jean-Pierre MartineauandClaude Opus 5 6a060a0451 One line says what MeshTerm is, everywhere
Four different one-liners were in circulation: the repository's "interactive, scriptable
CLI toolkit", the README's "full-screen terminal companion", the About page's "client that
lives in your terminal", and the package summary's "TUI-based client ... companion
connection". JP picked one:

  A full-featured TUI MeshCore client for your terminal

It now opens the README, the About page, the package summary, meshterm.__doc__ and the
`meshterm --help` header, which cli.py already says must stay the same as the summary.
The summary's second sentence loses its grammar slip on the way: "Connects to a companion
over USB, Bluetooth or TCP." CLAUDE.md opens with the same line.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 11:37:19 -04:00
Jean-Pierre MartineauandClaude Opus 5 37955639c6 MeshTerm 0.9.0
The first public release. The version goes to 0.9.0 and the changelog carries one
entry, which the release job lifts verbatim as the release notes.

[Unreleased] had refilled since the last fold with one change -- --mock keeping its
invented mesh out of your real history. On a first release there is no previous
behaviour for it to have changed from, so it is folded into the entry's existing --mock
sentence, in that entry's voice, and [Unreleased] is empty again.

Reading the notes as a newcomer would, three claims were not true, and each was checked
against the running app rather than argued:

- `meshterm map` is not a command. It was the first example a stranger would type, and
  it answers "No such command". The map is a picture, so it lives in the menu; the
  example is `meshterm info` now.
- The Time Machine does not wind the map back. It is braille charts of recorded history
  over a day, a week, a month or all of it -- no map in it at all.
- Only the PicoCalc gets the handheld layout. It is chosen solely by the device tree
  reading "Luckfox Lyra"; the uConsole has no detection and runs the desktop layout on
  its 1280x720 screen, which has the room for it.

The manual's three sample outputs move from 0.3.7 to 0.9.0 with it, so the version a
reader sees in docs/cli.md matches the one they downloaded.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-21 04:01:28 -04:00
Jean-Pierre Martineau aed1d91484 MeshTerm 0.3.7
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
GitHub release / put the version on meshterm.net (push) Canceled after 0s
2026-09-19 02:37:13 -04:00
Jean-Pierre Martineau bde2a08b7b MeshTerm 0.3.6
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
GitHub release / put the version on meshterm.net (push) Canceled after 0s
2026-09-17 01:34:19 -04:00
Jean-Pierre Martineau ce4ff0f57e MeshTerm 0.3.5
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
GitHub release / put the version on meshterm.net (push) Canceled after 0s
2026-09-14 01:50:09 -04:00
Jean-Pierre MartineauandClaude Fable 5.1 bca1c83dcd MeshTerm 0.3.4
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
The macOS installers of 0.3.3 never built: the notices step refused pyobjc-core and
pyobjc-framework-libdispatch, whose wheels ship no licence text. Their MIT text is vendored
now, and a test checks every vendored path on every platform.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 15:50:53 -04:00
Jean-Pierre Martineau 48f975b33b MeshTerm 0.3.3
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
2026-09-13 15:44:44 -04:00
Jean-Pierre MartineauandClaude Fable 5.1 c9f5a71ce7 Every Python file names its licence with an SPDX identifier
Apache-2.0 does not require per-file headers, but a file lifted out of the tree carried no marking at all. One comment line, first (or right after a shebang), on every .py under meshterm/, tests/, packaging/ and scripts/, plus the extensionless SPI bridge; tests/test_spdx.py keeps a new file from landing without one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-13 13:09:18 -04:00
Jean-Pierre MartineauandClaude Opus 5 09956c764c MeshTerm 0.3.2
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 04:29:19 -04:00
Jean-Pierre Martineau 8875a45070 MeshTerm 0.3.1
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
2026-09-09 02:32:47 -04:00
Jean-Pierre MartineauandClaude Opus 5 4d8c67358c Release 0.3.0
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
The command line was rebuilt around the fact that it has two readers.
`--json` is the machine contract and now covers all 49 subcommands
instead of two; the plain face is free to be read by a person, which is
what it was always for.

The changelog entry had been written for the intermediate design — it
promised quoted names and absolute timestamps, both of which the finished
work deliberately reverses — so it describes what shipped instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-08 05:07:51 -04:00
Jean-Pierre MartineauandClaude Opus 5 2790159d04 Ask for a window MeshTerm fits in, rather than taking whatever is open
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
JP saw the PicoCalc's wordmark on a desktop session. The splash picks the
widest mark that fits, the desktop one is 71 columns, and below that it swaps
to the 53 drawn for the handheld -- so the app was announcing itself as the
handheld and truncating every menu description onto the pager underneath.

The window was 64 columns. reopen() passed no window argument, so wt.exe put
the session in a *tab* of whatever window happened to be open and it inherited
that size; with no window open it would instead have taken the reader's global
launch size, which is a setting about their shell and nothing to do with this
app. Either way the app could land somewhere too small for it, and the failure
was quiet and cosmetic rather than anything that announced itself.

It now asks for a window of its own at the platform's stated minimum plus a
margin -- 80x30 on the desktop, derived from readable_cols/readable_rows so it
follows them. Windows Terminal clamps to what the display can show, so a small
screen degrades exactly as it did before.

The tab is titled MeshTerm too. It was showing the executable's full path,
which on a downloaded build is a line of Downloads folder. The icon is not ours
to set -- Windows Terminal takes that from a profile and a bare command line is
not one.

Release 0.2.8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:28:54 -04:00
Jean-Pierre MartineauandClaude Opus 5 690807370b Take them to the better terminal instead of asking permission to
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
The classic Windows console cannot draw a single MeshTerm icon whatever font
it is given, so "reopen in Windows Terminal?" had exactly one sensible answer
-- and was being put to someone who had not seen the app yet and so had nothing
to weigh it against, at the one moment nothing had been drawn.

So it moves. It still says what it is doing and still names the way to stop it,
because a program that opens a window you did not ask for should say so.

Installing a font keeps its consent, and the split is deliberate: moving window
costs nothing and undoes itself by closing, while a font is a file written to
someone's machine that Windows will not let go of until their next logon.

The console_setup preference reads auto/off now rather than ask/off, and its
help says what it does. An older stored "ask" is not "off", so it keeps working
and simply means auto.

JP's call, and it is the right one -- the reference experience should be what
an end user gets, not what they think to ask for.

Release 0.2.7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 19:42:46 -04:00
Jean-Pierre MartineauandClaude Opus 5 564e051d1a The reopened session must not inherit the bundle's own bookkeeping
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
Found by testing the release artifact rather than the repo. A PyInstaller
one-file build unpacks itself and re-runs itself, the halves coordinating
through _PYI* environment variables. reopen() handed the whole environment to
the new copy, so its bootloader concluded it was stage two of a launch nobody
had made, checked that its parent was the same executable, found wt.exe, and
aborted:

    [PYI-33368:ERROR] Security validation failure: parent process has
    different executable!
    [process exited with code 4294967295]

A new window holding a message nobody can act on, with the window that offered
the move already gone. Strictly worse than not offering.

child_environment() strips them, and restores the loader paths the bootloader
parks aside. Verified against a locally frozen build: before, the bootloader
error; after, the session comes up in Windows Terminal with its emoji and its
charts.

The source build could never have shown this. Same shape as 0.2.2's empty tool
registry -- the packaged build is a platform of its own, and the only way to
test it is to run it.

Release 0.2.6.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:57:10 -04:00
Jean-Pierre MartineauandClaude Opus 5 a11c43c347 Release 0.2.5
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 17:43:20 -04:00
Jean-Pierre MartineauandClaude Opus 5 d062b5b706 The Windows console call that broke the app is ours alone
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
MeshTerm died building its screen on Windows with a ctypes type error, and on a
double-clicked build the traceback and the window it printed to were destroyed
together — which is why this needed a log file before it could be looked at.

`ctypes.windll.kernel32` is a cache. Every caller in the process receives the same
object and each function on it is a shared attribute, so declaring `.argtypes` is
not configuration, it is a process-wide mutation where the last writer wins. The
emoji-width probe declared `GetConsoleScreenBufferInfo` as taking a pointer to its
own copy of the screen-buffer struct; prompt_toolkit then called that same function
object with a pointer to its own copy — same layout, different class — and ctypes
refused it.

Nothing here reaches for `ctypes.windll` any more. Five call sites take private
handles from `core/win32dll.py`, built by constructing `WinDLL` directly so each
one gets its own function cache and a declaration made for one purpose cannot be
seen by anything else. Each call returns a fresh handle, because two parts of
MeshTerm disagreeing about a signature is the same bug in miniature.

The regression test was checked against the defect rather than assumed to cover
it: with the old line restored it fails, and with the fix it passes. A test that
passes either way would only have recorded that somebody thought about the
problem.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 15:16:26 -04:00
Jean-Pierre MartineauandClaude Opus 5 056ac3f770 MeshTerm 0.2.3
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
The build to diagnose a double-click with: a window that waits after a failure, a
log that keeps what happened, and a level you can turn up before reproducing it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 14:57:24 -04:00
Jean-Pierre MartineauandClaude Opus 5 9b2c5527f8 MeshTerm 0.2.2
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
The first build that contains the whole app. 0.2.1's binaries start and then
offer you nothing, so this replaces them rather than adding to them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 13:54:54 -04:00
Jean-Pierre MartineauandClaude Opus 5 2ea8f9fb83 MeshTerm 0.2.1
Installers / windows-x64 (push) Canceled after 0s
Installers / macos-x64 (push) Canceled after 0s
Installers / macos-arm64 (push) Canceled after 0s
Installers / linux-x64 (push) Canceled after 0s
Installers / linux-arm64 (push) Canceled after 0s
GitHub release / build (push) Canceled after 0s
GitHub release / create the release (push) Canceled after 0s
Closes out the changelog's Unreleased section under a date, which is the whole
ceremony: everything since 0.2.0 was written down as it landed, so cutting a
release is renaming a heading rather than reading a week of commits back.

0.2.0's link points at its tag rather than a release page, because 0.2.0 was
never released anywhere — it was tagged locally before there was anything to
build or anywhere to put it. 0.2.1 is the first version that exists outside this
machine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 13:30:11 -04:00
Jean-Pierre MartineauandClaude Opus 5 660540a84e The version is written once, and there is somewhere to record a change
Two pieces of release machinery that have to exist before a first bump, plus
the bump: 0.1.0 to 0.2.0.

The version was written twice — `pyproject.toml` and `meshterm/__init__.py` —
and kept in step by hand. That is a drift waiting to happen, and an unusually
visible one here: `__version__` is read by the splash wordmark, the menu mark,
the About page, a trace export and the tile-server user agent, so the number a
user reads on screen is the package attribute, while the number in a built
wheel would have been the `pyproject` literal. `[project] version` is now
`dynamic` and hatchling reads the attribute, so there is one place to edit and
the two cannot disagree. Verified against hatchling rather than assumed: it
resolves `0.2.0`.

`CHANGELOG.md` starts in Keep a Changelog form, with the `[Unreleased]` heading
that makes release notes a rename rather than an excavation of the log. Its
first entry is 0.2.0 and it says plainly that the history before it is not
reconstructed — 596 commits of pre-history would be a worse document, not a
more complete one.

0.2.0 rather than something nearer the announced 0.9.0: the numbers between here
and the release are for real feature sets, and there is no reason to spend them
early. 0.9.0 is a number chosen for the launch, not one to be arrived at by
counting — landing on 0.7.0 on the day and bumping straight to 0.9.0 is fine.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 03:34:42 -04:00
Jean-Pierre MartineauandClaude Opus 5 b7c629b50f The whole project spells macOS and Bluetooth one way
Two words the project was saying two ways, now settled to one each.

`macOS` is how Apple has styled it since 2016, and the repo was already split:
`connection.py`, `flash.py` and `test_disconnect.py` had it right, while the
About page and the new Summary said `MacOS`. Three files change, all of them
prose. Same five characters either way, so nothing about a rendered width moves.

`BLE` becomes `Bluetooth` in the Summary and the package docstring. Those two
lines are read by people deciding whether this runs on their machine, and
`Bluetooth` is the word they know and the word the About page already uses. The
identifier stays `BLE` everywhere it is one — the transport name, the connection
code, the config keys, the CLI. That is the boundary: the acronym is what the
thing is called in the code, the plain word is what it is called when introducing
the project to someone who has not met it yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 02:15:03 -04:00
Jean-Pierre MartineauandClaude Opus 5 37e46bfda5 The project says what it is in one line
The Summary is the only description most people will ever read: it is the line
under the name in PyPI search results, the one a package manager echoes, and the
sentence that decides whether anyone opens the README. It said "A modern
command-line toolkit for tuning and exploring a MeshCore mesh", which named a
category rather than the thing, and left out every fact a reader is actually
deciding on.

The new one is JP's own wording and answers those instead: what it is (a
full-featured TUI-based MeshCore client for your terminal), how it reaches a
radio (USB, BLE, TCP), and whether it runs on the reader's machine (Windows,
MacOS, Linux). "USB" and "MacOS" are the spellings the About page already uses,
so the front door and the metadata now say it the same way.

The package docstring carries the same sentence, split at the summary line as
`D205` wants, so `help(meshterm)` and the PyPI page agree.

The README's opening is untouched. It is doing a different job — a paragraph that
gets to breathe, with the links and the longitudinal-record pitch in it — and a
one-line summary is not a replacement for it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 02:09:25 -04:00
Jean-Pierre MartineauandClaude Opus 5 b5006cc415 Every line fits the hundred columns it was configured for
`E501` across 69 lines, wrapped rather than exempted.

The prose ones — module docstrings in `menu`, `node_detail_screen`,
`pathline`, `pathgraph`, `walk_screen`, `trace_runner` and `test_about` — are
reflowed as paragraphs, so the block keeps its shape instead of gaining one
short orphan line. Nothing they say changed.

The code ones mostly gained a line break inside a call. Where a break would
have read worse than a name, the sub-expression got one instead: `reach` in
`topology`'s quality clamp, `plain_cells` in `pathline`, `numbering` in the
trace list, `listed` in `flash.py`'s refusal, and a small `shape`/`is_strip`
helper in two tests that were comparing or matching the same shape twice on one
line. Four docstring summaries lost a word they were not using.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-06 20:22:52 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 a27b5951b7 Copyright: one canonical notice, hung under the logo
Consolidate the copyright into a single meshterm.copyright_notice() beside
__version__ (was defined twice, disagreeing on wording, holder, and year
span). Every startup splash draws from it, so it can never drift.

Place it immediately under the wordmark, right-justified to the logo edge, so
the two read as one signed block. Simplify the display logic: it now rides
every splash that shows the logo (picker, spinner, PIN, notices) rather than
being dropped after the first selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 02:07:53 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 2ec18138a7 Rename project from MeshTools to MeshTerm
Rename the package directory, imports, brand strings, env-var prefixes,
console-script entry point, and the config/data dir (~/.config/meshterm).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 19:40:49 -04:00