Releases: hucker/termapy
v0.64.0
CLI and output-system overhaul. The pre-0.64 boolean verbose toggle
and the all-or-nothing .quiet suffix are replaced by a single
monotonic dial -- silent < quiet < normal < verbose --
that works the same way at three scopes (session default, per-call
suffix, per-call flag). termapy --ports gains a stable JSON shape
with multi-axis filters, and the new vendor / location /
driver fields make port identification practical when you have
identical adapters or unrecognized chips. --watch is much
lighter on CPU (3-4% during a session, was ~50% on multi-port hosts)
thanks to a fast-gather path that skips the per-port in-use probe;
user-observable reaction time is bounded by Windows USB-enumeration
latency, which polling can't move. Old command
names continue to work as hidden forwarders, with /run.legacy
extended to rewrite them.
0.64.0 New Features
-
Four-level output dial --
/term.output {silent|quiet|normal| verbose}replaces the boolean/term.verbosetoggle. Each level
adds a channel:silentshows nothing (script consumers read
CmdResult.value),quietshows the answer,normaladds bulk
data output,verboseadds progress chatter. The same vocabulary
works as a per-call flag (cmd --quiet) or suffix (cmd.quiet);
the universal level dispatch means every command accepts them
without per-handler setup. CLI startup flags--silent/
--quiet/--verboseset the default before the REPL boots,
which matters most for--runscript invocations. -
--ports --jsonwith stable schema -- one JSON object per port
with snake_case keys,nullfor unknown values (not omitted),
numericvid/pidplus the formatted lowercase-hexvid_pid
string, and a booleanin_use. Schema is documented in
help/cli.mdand treated as API for scripts.--chips --json
similarly emits the bundled chip lookup as structured records. -
Multi-axis port filters --
--vid/--pid/--mfg/
--snAND-compose with each other and with the existing
--ports <name>filter. Hex flags accept0x0403or0403;
--mfgis a case-insensitive substring;--snis exact.
Distinct exit codes for "bad input" (2) and "no match" (1) so CI
pipelines can distinguish typo from missing-device. -
Vendor / location / driver columns -- three new fields on every
port record, surfaced in--ports, the JSON output, both port
pickers (PortPicker and QuickSetup), and the title-bar port hover
tooltip.-
vendoris the silicon-vendor name resolved from the VID via a
new curatedusb_vendortable (~30 entries covering FTDI,
Silicon Labs, WCH, Microchip, Microsoft, Espressif, ST, NXP, ...).
Independent of the descriptor / driver-INFmanufacturerstring,
so a Microchip USB-CDC chip running on Microsoft'susbser.sys
correctly reportsMicrochipas the silicon vendor while
manufacturer_rawstill preserves the literalMicrosoft. -
locationis the bus path (1-2.3on Linux,
Hub_#0009.Port_#0004on Windows after registry fallback for
FTDI, hex location ID on macOS). Disambiguates two physically
distinct adapters that share VID/PID/SN, which cheap clones and
duplicate-of-the-same-product scenarios both produce. -
driveris the bound kernel module (Linux) or service name
(Windows):ftdi_sio,cdc_acm,cp210x,FTSER2K,
usbser, etc. Surfaces driver-binding problems at a glance.
-
-
DEMO synthesis for hardware-free CI --
termapy --ports DEMO --jsonandtermapy --info DEMOnow return synthetic records
for the reserved virtual port names so CI pipelines can exercise
the CLI without plugging in real hardware. Bare--ports(no
filter) does NOT include DEMO -- it appears only when explicitly
named, the same way pyserial'sloop://URL handler is reachable
but not enumerated. -
--watchlighter on CPU -- the watch loop previously called a
per-port_check_in_useprobe that opens each port via
serial.Serial()to detect contention. On Windows this is
~250 ms / port (driver init on eachCreateFile), so gather
scaled linearly with port count and consumed ~50% CPU during a
watch session on a multi-port host. A new fast-gather path skips
the in-use probe for the watch loop only ----portsand
--infokeep the full check -- so gather drops from 250+ ms to
~7 ms regardless of port count, and CPU during watch falls to
~3-4%.Note: this does not lower user-observable hot-plug reaction
time meaningfully on Windows.comports()itself returns stale
data for 1-3 seconds after a USB event (longer for FTDI, whose
driver does an EEPROM-read handshake on every connect), so the
floor is OS USB-enumeration latency, not termapy's polling loop.
Reaching that floor would require event-driven APIs (WMI Win32_DeviceChangeEvent,RegisterDeviceNotification), and
even those fire only after the driver finishes init -- so the
practical improvement on Windows would be small. Linux with
udevevents would benefit more; future work. -
/port.connectand/port.disconnect--/port.openand
/port.closeare renamed to match the user-facing language already
used in status messages (Connected:/Disconnected.). Old
names keep working as hidden forwarders. -
Three-field manufacturer breadcrumbs -- the
--ports --json
record now exposesmanufacturer_raw(literal descriptor / INF
string),manufacturer(column-friendly aliased short form), and
vendor(silicon vendor by VID). These often agree; when they
diverge -- typically because a device uses a generic class driver --
all three are visible so engineers can spot the layering instead of
having one source silently override the others.
0.64.0 Improvements
-
Faster CLI startup -- the import-discipline guard for
termapy.cli_flagsis now mechanically enforced by a test that
fails if Textual / Rich / prompt_toolkit ever sneak into the
termapy --portsimport path. Cold-start under 50 ms is
preserved. -
Migration forwarders and
/run.legacyupdates --
/verbose on|offcontinues to work, translating to
/term.output verbose|normal./term.verbosesimilarly.
The old "set silently" idiom (echo.quiet on,term.echo.quiet on) is now recognized by/run.legacy --fix, which rewrites it
to the.silentform. Existing.runscripts continue to
work; migrate at your own pace with/run.legacy *. -
Port pickers widened to 130 columns -- the QuickSetup ("New
Config") and PortPicker dialogs gain horizontal space for the new
vendor/location columns.DROP_ORDERreprioritized so vendor
outranks chip / vid_pid / driver when narrow --Microchipin
9 characters beats04D8:9036or a 32-character chip name when
the row is squeezed. -
FTDI Windows location recovery -- pyserial returns
Nonefor
locationon FTDI ports because the FTDIBUS driver hides bus-
location info from SetupAPI. termapy now falls back to the registry:
reads the FTDI device'sContainerID, walksHKLM\\SYSTEM\\ CurrentControlSet\\Enum\\USBfor the matching USB partner node,
and readsLocationInformationfrom there. Strings are
normalized so hub appears before port (Hub_#0009.Port_#0004,
notPort_#0004.Hub_#0009) to match natural reading order.
v0.63.1
Documentation-only patch release. Sync of the bundled in-app help
with the v0.63.0 UI changes -- title-bar button labels (Help, no
longer ?, plus the relocated Exit X), the new Ctrl+Shift+1..5
hotkey aliases, the /term.* namespace, and one-line entries for
the new commands (/run.legacy, /credits, /var.list, plus
the chip-aware /port.list table). No code changes.
v0.63.0
REPL UX overhaul. Termapy's title-bar buttons, pickers, and command
popup are now reachable from typed commands, with parity between TUI
and CLI. Display and session toggles consolidate under a new
/term.* namespace, session logs gain a /log.* family for
inspection, and /proto.crc.find identifies an unknown CRC algorithm
from a captured packet. Old command names keep working as hidden
forwarders, with a /run.legacy tool to find and rewrite them in
existing scripts.
0.63.0 New Features
-
/term.*namespace -- display and session toggles consolidate
under one namespace, matching/port.*and/cfg.*. Nine
subcommands cover the ground that used to be scattered across
top-level commands:echo,line_no,line_endings,
verbose,timestamps,hex,encoding,
send_bare_enter,info. The old names (/echo,
/line_no,/show_line_endings,/verbose) keep working as
hidden forwarders -- they redirect transparently to the/term.*
equivalents and emit a one-time dim note suggesting the new spelling. -
/run.legacymigration tool -- scans a.runscript for
old command names and either reports or (with--fix) rewrites
in place./run.legacy *scans every script in the config's
run/directory in one pass, so a project full of pre-0.63
scripts can be migrated with a single command. -
Bare command opens a picker --
/cfg/run/proto
/port(no args) open the matching picker dialog in TUI mode and
fall through to/help <name>in CLI mode, with parity across
all four. Each command gains a.helpsubcommand that prints
the same long help plus anAVAILABLE FILEStree of what's
actually in the relevant folder./cfg.showis new, opening the
loaded config in the system viewer for symmetry with
/run.show//proto.show//ss.show. -
/log.*namespace for session-log inspection -- alongside
the existing/log.clear:/log.show opens the session log in the system viewer /log.dump {N} prints the entire log (or last N lines) to terminal /log.fingerprint writes OS, terminal, Python, termapy, config, and serial port state to the log so old logs are unambiguous when read back laterPlus
/term.log <text>for annotating the log without echoing
to screen -- useful for markers, timestamps, and notes that are
only interesting on later review. -
/proto.crc.find-- identify an unknown CRC algorithm from
a captured packet. Acceptsbin=<hex>(tries trailing 1/2/4
bytes as CRC, both endians) orasc=<text>(trailing 2/4/8
chars as hex-ASCII CRC). Iterates all 64 catalogue algorithms,
collapses catalogue aliases to one canonical line, and prints the
source-code generation command when exactly one algorithm matches. -
Title-bar Exit, config-gated buttons -- the Exit button moves
out of the bottom bar and into the title bar as a redX,
positioned by OS convention (top-left on mac/linux, top-right on
Windows). The?help button is renamed toHelpand moves
after theCfg/Run/Prototrio. New config booleans
cfg_enabled/run_enabled/proto_enabled(default
true) hide the corresponding title-bar buttons for projects that
don't use them. -
/proto.crc.findattribution &/credits-- a new
ACKNOWLEDGMENTS.mdpage (bundled into help) names the projects
Termapy depends on: Greg Cook (reveng CRC catalogue), Will McGugan
/ Textualize (Textual + Rich), Jonathan Slenders (prompt_toolkit),
Chris Liechti (pyserial)./creditsprints it in-terminal.
The Help button tooltip is restructured into a colored Rich table
with author attribution.
0.63.0 Improvements
-
Animated
/delayprogress bar in TUI -- the CLI has had
[####....] 3s/10sfor a while; the TUI now shows the same bar.
Interactive/delayrenders into the status bar; script
/delayappends to the script overlay so
delay.run [1/4] [bar]stays in one line. -
Escape dismisses every modal --
ConfigEditor,
MarkdownViewer,QuickSetup,NamePicker, and the proto
debug screen now accept Escape as an alternate dismiss key
alongside Ctrl+Q. -
Filtered command popup -- clicking the
/button with
potyped in the input now shows only commands containingpo
(/port,/proto,/stop, ...) instead of the full list
from the top./poandpobehave identically; arguments
past the first token are ignored. -
Ctrl+Shift+1..5 hotkeys replace the unreliable
Alt+F*
aliases for Help/Cfg/Run/Proto/Edit-Config. F-keys remain primary;
theCtrl+Shift+digitaliases survive VS Code's terminal capture
viamodifyOtherKeys/ csi-u. The VS Code detected banner now
labels each shortcut so users know whatAlt+P/Alt+S/
Alt+Tactually do. -
Richer
/port.list-- now uses the picker-style table
(PORT / MFG / DESCRIPTION / CHIP / SPEED / VID:PID / SN, with
terminal-width-aware column drop) -- same format as bare/port
and the--portsCLI flag. The zero-config welcome screen
picks up the richer output for free. -
cli_intellisense->cli_completionrename --
IntelliSense is a Microsoft trademark, and "completion" is the
accurate name anyway (tab completion + auto-suggest + help
toolbar). Migration v13 -> v14 handles the rename for existing
configs. -
/proto.crc.help->/proto.crc.info-- the command
shows algorithm parameters, not command help, so the name was
misleading. -
Command and error-message consistency audit --
{on|off}
spellings are uniform (no inner spaces, all toggles optional).
Error messages adopt sentence case and a small set of standard
phrasings (Unknown X/Invalid X/X not found/
No X loaded./Usage: /cmd ...)./var.listadded as
an explicit alias for bare/varlisting. -
New
Environment & compatibilityhelp page -- one place
for OS support, terminal emulators, VS Code quirks, macOS
Option-as-Meta, KVM cross-platform keyboards, and SSH/WSL/container
notes. Replaces the inline VS Code block that used to live in
getting-started.md. -
FileTreeextracted totree_render.py-- single source
of truth for box-drawing connectors, dim/cyan/blue style triplet,
and child-indent pattern that used to be duplicated between
cfg._build_treeandhelp.append_files_section. Pure
module, no Textual or serial deps; 14 new unit tests. -
Loopback integration tests -- 7 new tests using pyserial's
loop://URL exercise the termapy <-> pyserial send path:
line-ending config,/rawbypass, CRC append via
/proto.send, latin-1 encoding on the wire, plain round-trip.
/cap.binwith exact byte-count targets so captures close on
target-hit (reliable) rather than timeout.
v0.62.0
CLI-mode release. Termapy's --cli frontend gained a lot of
polish: it now runs without a config file, knows how to switch
configs in a live session, keeps long device responses from
colliding with the next prompt, and got one bug fix that was
actively breaking help-style commands on firmware. The
cfg["port"] field learned to take USB serial numbers with
pipe-separated fallback chains, and every folder-owning command now
exposes the same list / explore / show / dump / clear subcommand
family.
0.62.0 New Features
-
USB serial numbers in the port field --
cfg["port"]now
accepts a USB serial number ("A1B2C3D4") in addition to a
device name, with a|-separated fallback chain:"port": "A1B2C3D4|COM3""Prefer serial number A1B2C3D4; if it's not connected, fall back
to COM3." Stable across replugs, stable across machines, stable
across reboots. Resolution happens at every connect, so
unplug/replug events automatically find the device's new COM
number when the SN survives. Composes cleanly with environment
expansion:"$(env.DEVICE_SN)|COM3"works. Ambiguous serial
numbers (two devices sharing"0001"from cheap CH340 clones)
are a hard error naming both colliding devices, not a silent
guess. -
Zero-config
--climode --termapy --cliwith no config
file used to print"no config found"and exit. Now it shows
a welcome banner listing available ports, names the built-in
defaults (115200 N81 cr noecho), and hints at/port.open <name>. You can talk to a serial device without ever writing a
.cfgfile. -
/cfg.load <name>-- switch configs inside a live CLI
session. Pairs with zero-config mode:termapy --cli->
/cfg.load myproj-> you're in the project. No more exiting
and re-running to change configs. -
/port.openline-ending + echo tokens --
/port.open COM4 9600 N81 crlf echosets baud + frame mode +
line ending + echo in one command. New tokens:cr/lf/
crlffor line ending,echo/noechofor echo. Port
name must come first; everything else is order-independent. -
Uniform folder subcommand family -- every folder-owning
command (/ss,/run,/proto,/cap,/cfg,
/plugin,/app) now exposes the same shape:/<folder>.list list files /<folder>.explore open folder in file manager /<folder>.show open newest file in system viewer /<folder>.dump print newest (or named) file to terminal /<folder>.clear delete all files (only on ss, cap, prof)Which of show/dump/clear is exposed follows the folder's nature:
user-authored folders (run/, proto/, plugin/) don't get a
.clear; machine-generated folders (ss/, cap/, prof/) do. No
more guessing whether it's.configsor.diror.list.
0.62.0 Improvements
-
Long device responses no longer chop the next prompt -- a
device streaming 40+ lines ofhelpoutput in--climode
used to race with prompt_toolkit's prompt redraw and leave the
prompt overlaid mid-stream. The interactive loop now runs under
prompt_toolkit'spatch_stdoutso reader-thread output gets
buffered and inserted above the active prompt instead of
colliding with it. The TUI was never affected (it has a
separate input widget); only--clihad this bug. -
/port <SN>status line names the actual device -- when
you typed/port A1B2C3D4, the status saidPort changed to A1B2C3D4 (session)even though you were actually on COM4.
Now saysPort changed to COM4 (session), matching the
already-correct connect banner. -
termapy>prompt in zero-config -- previously the CLI
prompt readnone>when no config was loaded (the$(CFG)
variable fell back to the literal"none"). The zero-config
fallback is now"termapy", so you seetermapy>instead. -
Bottom toolbar removed -- prompt_toolkit was reserving a
full-width row below the prompt for a help tooltip that never
populated. The completion dropdown (still there, via Tab) is
scaled to terminal height: 8 rows of dropdown on a 40+-line
terminal, 4 rows on smaller, 0 (no dropdown) below 10 rows. -
Empty
"port": ""in configs now warns -- a valid port is
any of: literal device name, USB serial number, reserved name
("DEMO","DEMO_FAIL"), or pyserial URL. Empty string is
invalid and now produces a validation warning on config load.
The zero-config CLI path is the only legitimate placeport=""
appears; it synthesizes in memory and never persists. -
CI publish workflow handles PyPI double-upload --
release_publish.pypublishes to PyPI from the dev machine,
then GitHub'srelease:publishedevent triggers the Actions
workflow which tries to upload again. Previously the second
upload failed with "file already exists" and the workflow showed
red on every release. Now usesuv publish --check-urlwhich
detects the already-published file and exits 0.
Breaking changes
/cfg.configsrenamed to/cfg.list./ss.dirremoved; use/ss.list(which actually lists files,
not just the folder path).- The
/cfg.<folder>listing subtree is gone --
/cfg.run,/cfg.ss,/cfg.proto,/cfg.cap,
/cfg.prof,/cfg.plugin,/cfg.vizand their
.dump/.show/.explore/.clearchildren. Use top-level
/run.list,/ss.list,/proto.list,/cap.list,
/plugin.list, etc. instead.
v0.61.0
Quality-of-life release. Termapy now tells you when a new version is
available on PyPI, consolidates its own app-level state (update checks,
recent configs, window geometry) into a single state.json that you
can inspect with the new /app command, names the process holding a
locked port on Unix, and makes the command palette a little smarter on
non-Linux platforms. Under the hood, the cmd_prefix override is now
fully plumbed so users with a non-/ prefix see it everywhere in help
output.
0.61.0 New Features
- PyPI update check + Update title-bar button -- termapy quietly
checks PyPI on startup (no network call blocks the UI) and, when a
newer release is available, lights up anUpdatebutton in the
title bar. Clicking it jumps straight to the installation docs so
you can see how to upgrade for your install method. The check runs
at most once a day and is fully opt-out viaupdate_check: false. /appcommand +state.json-- app-wide state (last-seen
version, recent configs, update-check timestamp, window geometry,
custom buttons) now lives in a singlestate.jsonunder the
user-level app directory instead of scattered files. The new
/appREPL command lets you query or edit any field interactively:
/app,/app recent,/app.set custom_button_4 "/port.info", etc.- Friendlier "port in use" errors -- when the OS refuses to open
a port because another process has it, termapy now reports which
process on Linux / macOS (vialsof). Instead of a bare
PermissionError, you getCannot open /dev/ttyUSB0: permission denied (held by arduino, PID 12847). - Smarter
/palette -- the command palette hides Linux-only
commands (/port.latency_timer,/port.permissions) on macOS and
Windows so they don't clutter the view with never-applicable rows.
Help text is column-aligned at position 50 for a tidier two-column
look at wider terminal widths. - Plugin-source labels in startup status -- the green startup
banner now annotates each plugin with its origin (builtin,
global,config) so you can see at a glance where a custom
command came from when a config pulls plugins from multiple
sources. TERMAPY_DEMO_FLEETenvironment variable -- set this and
--ports,--watch,--info, and/port.listenumerate a
fixed three-port synthetic fleet (FTDI FT232R on COM3, Silicon
Labs CP2102 on COM4, Microsoft USB Serial on COM7) instead of
real hardware. Handy for docs, screenshots, bug reports, or
trying the tool before you own an adapter. Sibling to the
existingport: DEMO(fake open) config value.
0.61.0 Improvements
cmd_prefixoverride is now complete -- users with a non-/
prefix in their config (cmd_prefix: "!") previously saw stray
/literals in help output, search hits, subcommand listings,
and CRC error messages. Every help-rendering site now runs the
live prefix through the same interpolation helper, and the plugin
source strings use a{prefix}sentinel that's substituted at
render time. A new end-to-end test proves dispatch + output
both honor the override.- Friendlier CRC error messages --
/proto.crc.c,
/proto.crc.python,/proto.crc.rust,/proto.crc.calc, and
/proto.crc.helpnow fail gracefully and point you at
/proto.crc.listwhen you pass an unknown algorithm name
(previously some paths crashed or leaked the{prefix}
placeholder to the screen). proto_frame_gap_msnow has a default -- previously a fresh
config was missing this key and/proto.sendwould complain;
it now defaults to 50 ms so the first thing you try works.- Better shutdown hygiene -- race conditions between the reader
thread firing a final callback and the Textual widget tree
tearing down are now caught by a dedicatedSHUTDOWN_RACEtuple
instead of a broadexcept Exception; andopen/
xdg-openchild processes are reaped by a daemon thread so they
don't leak zombies when you close help or a capture file from
the TUI. - Deprecated vs. mistyped config keys -- the config validator
now distinguishes keys that used to be real (deprecated --
silently dropped with a yellow hint) from keys that are likely
typos (flagged in red with a did-you-mean suggestion). - Release-tooling improvements -- the release script now
asserts HTML help freshness after rebuild so stale*.htmlcan't
slip into a tag, and a newscripts/check_dep_updates.pysurfaces
outdated dependencies for pre-release review.
v0.60.0
Command-line release. Termapy now has a set of one-shot shell flags --
--ports, --watch, --info, --chips, --check -- that skip the TUI
entirely and print plain text to stdout, so you can answer "what's plugged
in?" from a shell or script without waiting on Textual. The flags pay
only pyserial's import cost and start fast.
0.60.0 New Features
termapy --ports-- one-line-per-port table matching the in-app
port picker. Filter to a single port with--ports=COM4. Row width
adapts to the terminal so narrow windows drop low-priority columns
(speed / chip / vid_pid) before wrapping. Physical ports only --
pyserial URL handlers remain a config-side concern.termapy --watch-- live log of port events; start watching,
plug the cable in, see which COM number it got. One-character
event markers (+plug,-unplug,~chip re-EEPROM, blank for
baseline and open/close transitions) make plug events punch out
of the stream visually.Ctrl+Cto exit.termapy --info-- full per-port chip dump (same data as
/port.chip), identifies chip model, USB speed class, serial
number, and VID:PID. Unknown chips print the VID:PID so you can
identify them manually and nudge you to file an issue so the
lookup table can grow.termapy --chips-- dump the USB-serial chip lookup table;
--chips=ftdifilters to substring matches.termapy --check-- validate your config and print a JSON
status line without launching the TUI.- USB manufacturer / serial-number columns in the picker --
the port picker and/port.chip.listnow show USB serial numbers
and an aliased manufacturer column (FTDI / MSFT / SiLabs) for
faster disambiguation between identical cables.
0.60.0 Improvements
- Command-Line Flags help page -- a new page in the docs
walks through--ports,--watch, and--infowith real
captures and an annotated marker-column legend. - Faster CLI startup -- the entry point and all print-and-exit
flags have been split into Textual-free modules, sotermapy --ports
no longer pays the ~300 ms / 40 MB cost of importing Textual.
python -m termapy --helpnow answers in stdlib+pyserial time. - Cleaner config-path resolution --
find_config,resolve_config,
andinfer_config_from_run_filemoved to their own Textual-free
module, eliminating a previously-duplicated copy in the CLI.
v0.59.0
Help-system release. Every built-in command's /help page now opens with a one-line live status, device commands brought in by /include become first-class citizens in both /help and /search, and the device JSON schema picks up an optional version field so firmware updates automatically refresh the cache.
0.59.0 New Features
- Dynamic help --
Command.long_help(andPluginInfo.long_help) now accepts a callable(PluginContext) -> stras well as a static string. Callables are invoked at render time so a command's DESCRIPTION section can reflect live runtime state (loaded files, current connection, cached counts). Existing static-string declarations are unchanged. Seewriting-plugins.mdfor the pattern. - Dynamic help on built-in commands --
/helpfor/cfg,/portand each port subcommand,/include,/cap.*,/ss,/run.edit,/proto(+ subcommands),/edit.run|proto|plugin,/var,/env, and/seqnow opens with a green single-line status reflecting the current state (active cfg name, connected port, counter count, file counts in the relevant folder, etc.). Single-value commands show only the state line; multi-option commands keep their existing prose. - Dynamic-help helpers -- new
termapy.help_dynamicmodule supplies small reusable building blocks (state_line,folder_line,port_status,cfg_status,ns_count,compose,green) so plugin authors can wire dynamic DESCRIPTION content in one or two lines. Seewriting-plugins.md. - Target-command parity --
/include'd device commands now support optionallong_helpandflagsfields in their JSON./help <target>renders a full man page (NAME, SYNOPSIS, DESCRIPTION, FLAGS, source marker) when those fields are present./searchindexes target commands alongside REPL plugins, tagging device-command hits with(target)so they're visually distinct. The demo device'sAT+HELP.JSONuses the new fields onAT+INFO,AT+TEMP,AT+LED, andAT+BINDUMPso the feature is live out of the box in--demo. - Device schema versioning --
/includeJSON may carry an optional top-levelversionstring (device's own schema version, not termapy's). On fetch, if the device's version is strictly newer than the cached one (PEP 440 compare), the cache is overwritten; otherwise the cache is kept. First-time fetches with no cache always apply./include.reloadstill bypasses the gate for manual refresh. The demo device advertises"version": "1.0.0"so the round-trip is exercised end-to-end.
0.59.0 Changes
/helpis now case-sensitive on exact match -- the argument is no longer lowercased before lookup. Plugin names (conventionally lowercase) and device AT commands (conventionally upper) both match exactly. Typing/help INCLUDEused to silently lowercase and hit/include; it now falls through to the forgiving candidate list (which is still case-insensitive internally), where/includesurfaces as a candidate. This is the change that makes/help AT+INFOwork for included device commands.
v0.58.0
0.58.0 New Features
-
Forgiving
/help--/helpnow does substring matching across command names, flags, args, and help text when there is no exact match./help crcsurfaces every CRC-related command;/help devfinds/help.devand/help.search --dev. Results group under headings (Command Name, Flags, Help String, Arguments, Long Help) so you can see why each command matched, and the matched terms are underlined throughout. -
Multi-term
/helpsearch -- combine terms to narrow down in a sea of commands:/help table crc-- commands matching both words/help crc -table-- CRC commands, excluding the--tablecodegen ones/help --table-- literal flag lookup
Long-help hits render the full long_help inline so you don't need a second command.
-
/help.search <pattern>-- regex search across every command. Pass--devto also search handler docstrings. Returns matching command names asCmdResult.valueso scripts can capture the list with$(VAR) <- /help.search .... -
First-class flags -- plugin commands now declare their flags on a
Command(flags={...})dict. The dispatcher parses and strips declared flags before the handler runs; handlers read them viactx.flag("--name"). Benefits you will notice:- Flags appear under their own Flags: section in
/help <cmd>output /help tablefinds--tabledirectly- Typos like
--talbeget adid you mean --table?suggestion instead of being silently ignored - Short aliases work uniformly:
/run foo.run -vand/run foo.run --verboseboth set the same flag
- Flags appear under their own Flags: section in
-
/cap.poll-- new command for polling one or more device commands on a schedule, streaming the responses to a CSV or JSONL file. Supportscount=,delay=,file=,labels=,regex=extraction, and--overwrite/--notimeflags. -
Network serial ports -- pyserial URL-style ports (
loop://,socket://<host>:<port>,rfc2217://...) are now accepted wherever a port name would go. -
CmdResult.valuefor scripting -- plugin handlers can now return a captured value that scripts read back with$(VAR) <- /command. Enables composing command output into variables without parsing terminal text. -
/cap.poll --tableCRC codegen --/proto.crc.{c,python,rust}now ship a worked bit-by-bit vs table-driven example in the help pages, so you can see what the generated code looks like for either form.
0.58.0 Improvements
- Getting Started page gains a concise "finding commands" section listing the
/helpsearch forms. /cfg.info --display,/cap.poll --overwrite / --notime,/help.search --dev,/run --verboseall converted to first-class flags. Behavior unchanged; discoverability improved.long_helptext added for/cap.text,/cap.bin,/ping,/ping.quiet,/repeatso/help <cmd>actually explains what they do.- Config help examples validated -- README and
config.mdexamples are now checked at release time to make sure they match the real config schema.
0.58.0 Bug Fixes
/cap.pollJSONL output -- fixed two type-checker errors that could surface when writing JSON Lines capture output with the--notimeflag. No behavior change.
v0.57.0
0.57.0 New Features
- Custom baud rates -- new
custom_baudconfig option unlocks non-standard baud rates (>= 300) for hardware that needs them. By default only standard rates are accepted to catch typos that silently break connections. QuickSetup dialog adds a toggle button to switch between standard list and custom entry. Config editor blocks save on non-standard rates unlesscustom_baudis enabled. - TUI-only command warnings -- CLI now shows "Only available in /tui mode" for commands that require the TUI (screenshots, line numbers, proto debug) instead of silently doing nothing.
0.57.0 Improvements
- Serial engine decoupling -- DTR/RTS/break toggle, reconnect loop, and hardware signal queries moved from the TUI into SerialEngine. All serial operations now go through the engine rather than touching pyserial directly.
- TerminalHost base class -- connect/disconnect lifecycle, serial helpers, capture proto_active handling, port switching, and context callbacks consolidated in the shared base class, removing duplication between TUI and CLI.
- New Config dialog -- first serial port selected by default, Connect button disabled with "No Ports" label when no ports are available, title case labels.
- PyPI publish -- release_publish.py now builds and uploads to PyPI as part of the release flow.
v0.56.0
Architecture and CLI experience release. Extracts a shared TerminalHost base class from the TUI and CLI frontends, replaces pyreadline3 with prompt_toolkit for cross-platform CLI intellisense, and adds serial observer hooks, plugin config persistence, and status bar APIs for plugin authors.
0.56.0 New Features
- CLI intellisense -- tab completion, fish-style auto-suggest from history, and a help toolbar that shows command docs as you type. Toggle with
/cli.intellisense on|offor thecli_intellisenseconfig key. - Serial observers -- plugins can register RX/TX observer callbacks to monitor serial traffic without disrupting the display pipeline.
- Status bar API --
ctx.status_bar(text)shows transient text in the TUI bottom bar (no-op in CLI). - PluginConfig API -- persistent per-config key-value storage for plugins (
ctx.plugin_cfg("name")), backed by JSON files in the plugin/ folder. - PIC map plugin -- parse Microchip PIC memory map files and look up symbols by address.
- Port mode command --
/port.openaccepts baud+mode args,/port.modesets serial parameters inline. - Lifecycle hooks -- new
on_app_start,on_app_stophooks for plugin initialization and cleanup.
0.56.0 Improvements
- TerminalHost extraction -- shared base class for TUI and CLI consolidates serial I/O, dispatch, capture, context wiring, and hook handlers. ~240 lines of duplicated code removed, 27 callbacks written once.
- CLI scrolling fixed -- terminal output now scrolls correctly at the bottom of the window on all Windows console hosts.
- Shared history -- TUI and CLI modes use the same history file per config.
- Test coverage boost -- 68 new tests covering terminal_host.py (92%), repl.py (89%), overall 66% to 70%.
- Type checker clean -- all
ty checkoverrides resolved. - Port in-use detection -- correctly identifies when termapy itself has a port open vs another process.