Skip to content

Releases: hucker/termapy

v0.64.0

01 May 21:28

Choose a tag to compare

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.verbose toggle. Each level
    adds a channel: silent shows nothing (script consumers read
    CmdResult.value), quiet shows the answer, normal adds bulk
    data output, verbose adds 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 / --verbose set the default before the REPL boots,
    which matters most for --run script invocations.

  • --ports --json with stable schema -- one JSON object per port
    with snake_case keys, null for unknown values (not omitted),
    numeric vid / pid plus the formatted lowercase-hex vid_pid
    string, and a boolean in_use. Schema is documented in
    help/cli.md and treated as API for scripts. --chips --json
    similarly emits the bundled chip lookup as structured records.

  • Multi-axis port filters -- --vid / --pid / --mfg /
    --sn AND-compose with each other and with the existing
    --ports <name> filter. Hex flags accept 0x0403 or 0403;
    --mfg is a case-insensitive substring; --sn is 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.

    • vendor is the silicon-vendor name resolved from the VID via a
      new curated usb_vendor table (~30 entries covering FTDI,
      Silicon Labs, WCH, Microchip, Microsoft, Espressif, ST, NXP, ...).
      Independent of the descriptor / driver-INF manufacturer string,
      so a Microchip USB-CDC chip running on Microsoft's usbser.sys
      correctly reports Microchip as the silicon vendor while
      manufacturer_raw still preserves the literal Microsoft.

    • location is the bus path (1-2.3 on Linux,
      Hub_#0009.Port_#0004 on 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.

    • driver is 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 --json and termapy --info DEMO now 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's loop:// URL handler is reachable
    but not enumerated.

  • --watch lighter on CPU -- the watch loop previously called a
    per-port _check_in_use probe that opens each port via
    serial.Serial() to detect contention. On Windows this is
    ~250 ms / port (driver init on each CreateFile), 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 -- --ports and
    --info keep 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
    udev events would benefit more; future work.

  • /port.connect and /port.disconnect -- /port.open and
    /port.close are 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 exposes manufacturer_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_flags is now mechanically enforced by a test that
    fails if Textual / Rich / prompt_toolkit ever sneak into the
    termapy --ports import path. Cold-start under 50 ms is
    preserved.

  • Migration forwarders and /run.legacy updates --
    /verbose on|off continues to work, translating to
    /term.output verbose|normal. /term.verbose similarly.
    The old "set silently" idiom (echo.quiet on, term.echo.quiet on) is now recognized by /run.legacy --fix, which rewrites it
    to the .silent form. Existing .run scripts 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_ORDER reprioritized so vendor
    outranks chip / vid_pid / driver when narrow -- Microchip in
    9 characters beats 04D8:9036 or a 32-character chip name when
    the row is squeezed.

  • FTDI Windows location recovery -- pyserial returns None for
    location on FTDI ports because the FTDIBUS driver hides bus-
    location info from SetupAPI. termapy now falls back to the registry:
    reads the FTDI device's ContainerID, walks HKLM\\SYSTEM\\ CurrentControlSet\\Enum\\USB for the matching USB partner node,
    and reads LocationInformation from there. Strings are
    normalized so hub appears before port (Hub_#0009.Port_#0004,
    not Port_#0004.Hub_#0009) to match natural reading order.

v0.63.1

29 Apr 19:06

Choose a tag to compare

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

29 Apr 17:20

Choose a tag to compare

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.legacy migration tool -- scans a .run script 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 .help subcommand that prints
    the same long help plus an AVAILABLE FILES tree of what's
    actually in the relevant folder. /cfg.show is 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 later
    

    Plus /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. Accepts bin=<hex> (tries trailing 1/2/4
    bytes as CRC, both endians) or asc=<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 red X,
    positioned by OS convention (top-left on mac/linux, top-right on
    Windows). The ? help button is renamed to Help and moves
    after the Cfg / Run / Proto trio. 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.find attribution & /credits -- a new
    ACKNOWLEDGMENTS.md page (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). /credits prints it in-terminal.
    The Help button tooltip is restructured into a colored Rich table
    with author attribution.

0.63.0 Improvements

  • Animated /delay progress bar in TUI -- the CLI has had
    [####....] 3s/10s for a while; the TUI now shows the same bar.
    Interactive /delay renders into the status bar; script
    /delay appends 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
    po typed in the input now shows only commands containing po
    (/port, /proto, /stop, ...) instead of the full list
    from the top. /po and po behave 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;
    the Ctrl+Shift+digit aliases survive VS Code's terminal capture
    via modifyOtherKeys / csi-u. The VS Code detected banner now
    labels each shortcut so users know what Alt+P / Alt+S /
    Alt+T actually 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 --ports CLI flag. The zero-config welcome screen
    picks up the richer output for free.

  • cli_intellisense -> cli_completion rename --
    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.list added as
    an explicit alias for bare /var listing.

  • New Environment & compatibility help 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.

  • FileTree extracted to tree_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_tree and help.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, /raw bypass, CRC append via
    /proto.send, latin-1 encoding on the wire, plain round-trip.
    /cap.bin with exact byte-count targets so captures close on
    target-hit (reliable) rather than timeout.

v0.62.0

20 Apr 02:10

Choose a tag to compare

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 --cli mode -- termapy --cli with 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
    .cfg file.

  • /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.open line-ending + echo tokens --
    /port.open COM4 9600 N81 crlf echo sets baud + frame mode +
    line ending + echo in one command. New tokens: cr / lf /
    crlf for line ending, echo / noecho for 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 .configs or .dir or .list.

0.62.0 Improvements

  • Long device responses no longer chop the next prompt -- a
    device streaming 40+ lines of help output in --cli mode
    used to race with prompt_toolkit's prompt redraw and leave the
    prompt overlaid mid-stream. The interactive loop now runs under
    prompt_toolkit's patch_stdout so 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 --cli had this bug.

  • /port <SN> status line names the actual device -- when
    you typed /port A1B2C3D4, the status said Port changed to A1B2C3D4 (session) even though you were actually on COM4.
    Now says Port changed to COM4 (session), matching the
    already-correct connect banner.

  • termapy> prompt in zero-config -- previously the CLI
    prompt read none> when no config was loaded (the $(CFG)
    variable fell back to the literal "none"). The zero-config
    fallback is now "termapy", so you see termapy> 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 place port=""
    appears; it synthesizes in memory and never persists.

  • CI publish workflow handles PyPI double-upload --
    release_publish.py publishes to PyPI from the dev machine,
    then GitHub's release:published event 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 uses uv publish --check-url which
    detects the already-published file and exits 0.

Breaking changes

  • /cfg.configs renamed to /cfg.list.
  • /ss.dir removed; 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.viz and their
    .dump/.show/.explore/.clear children. Use top-level
    /run.list, /ss.list, /proto.list, /cap.list,
    /plugin.list, etc. instead.

v0.61.0

18 Apr 22:39

Choose a tag to compare

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 an Update button 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 via update_check: false.
  • /app command + state.json -- app-wide state (last-seen
    version, recent configs, update-check timestamp, window geometry,
    custom buttons) now lives in a single state.json under the
    user-level app directory instead of scattered files. The new
    /app REPL 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 (via lsof). Instead of a bare
    PermissionError, you get Cannot 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_FLEET environment variable -- set this and
    --ports, --watch, --info, and /port.list enumerate 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
    existing port: DEMO (fake open) config value.

0.61.0 Improvements

  • cmd_prefix override 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.help now fail gracefully and point you at
    /proto.crc.list when you pass an unknown algorithm name
    (previously some paths crashed or leaked the {prefix}
    placeholder to the screen).
  • proto_frame_gap_ms now has a default -- previously a fresh
    config was missing this key and /proto.send would 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 dedicated SHUTDOWN_RACE tuple
    instead of a broad except Exception; and open /
    xdg-open child 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 *.html can't
    slip into a tag, and a new scripts/check_dep_updates.py surfaces
    outdated dependencies for pre-release review.

v0.60.0

18 Apr 00:36

Choose a tag to compare

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+C to 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=ftdi filters 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.list now 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 --info with 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, so termapy --ports
    no longer pays the ~300 ms / 40 MB cost of importing Textual.
    python -m termapy --help now answers in stdlib+pyserial time.
  • Cleaner config-path resolution -- find_config, resolve_config,
    and infer_config_from_run_file moved to their own Textual-free
    module, eliminating a previously-duplicated copy in the CLI.

v0.59.0

16 Apr 22:17

Choose a tag to compare

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 (and PluginInfo.long_help) now accepts a callable (PluginContext) -> str as 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. See writing-plugins.md for the pattern.
  • Dynamic help on built-in commands -- /help for /cfg, /port and each port subcommand, /include, /cap.*, /ss, /run.edit, /proto (+ subcommands), /edit.run|proto|plugin, /var, /env, and /seq now 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_dynamic module 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. See writing-plugins.md.
  • Target-command parity -- /include'd device commands now support optional long_help and flags fields in their JSON. /help <target> renders a full man page (NAME, SYNOPSIS, DESCRIPTION, FLAGS, source marker) when those fields are present. /search indexes target commands alongside REPL plugins, tagging device-command hits with (target) so they're visually distinct. The demo device's AT+HELP.JSON uses the new fields on AT+INFO, AT+TEMP, AT+LED, and AT+BINDUMP so the feature is live out of the box in --demo.
  • Device schema versioning -- /include JSON may carry an optional top-level version string (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.reload still 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

  • /help is 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 INCLUDE used to silently lowercase and hit /include; it now falls through to the forgiving candidate list (which is still case-insensitive internally), where /include surfaces as a candidate. This is the change that makes /help AT+INFO work for included device commands.

v0.58.0

16 Apr 01:08

Choose a tag to compare

0.58.0 New Features

  • Forgiving /help -- /help now does substring matching across command names, flags, args, and help text when there is no exact match. /help crc surfaces every CRC-related command; /help dev finds /help.dev and /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 /help search -- combine terms to narrow down in a sea of commands:

    • /help table crc -- commands matching both words
    • /help crc -table -- CRC commands, excluding the --table codegen 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 --dev to also search handler docstrings. Returns matching command names as CmdResult.value so 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 via ctx.flag("--name"). Benefits you will notice:

    • Flags appear under their own Flags: section in /help <cmd> output
    • /help table finds --table directly
    • Typos like --talbe get a did you mean --table? suggestion instead of being silently ignored
    • Short aliases work uniformly: /run foo.run -v and /run foo.run --verbose both set the same flag
  • /cap.poll -- new command for polling one or more device commands on a schedule, streaming the responses to a CSV or JSONL file. Supports count=, delay=, file=, labels=, regex= extraction, and --overwrite / --notime flags.

  • Network serial ports -- pyserial URL-style ports (loop://, socket://<host>:<port>, rfc2217://...) are now accepted wherever a port name would go.

  • CmdResult.value for 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 --table CRC 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 /help search forms.
  • /cfg.info --display, /cap.poll --overwrite / --notime, /help.search --dev, /run --verbose all converted to first-class flags. Behavior unchanged; discoverability improved.
  • long_help text added for /cap.text, /cap.bin, /ping, /ping.quiet, /repeat so /help <cmd> actually explains what they do.
  • Config help examples validated -- README and config.md examples are now checked at release time to make sure they match the real config schema.

0.58.0 Bug Fixes

  • /cap.poll JSONL output -- fixed two type-checker errors that could surface when writing JSON Lines capture output with the --notime flag. No behavior change.

v0.57.0

13 Apr 01:05

Choose a tag to compare

0.57.0 New Features

  • Custom baud rates -- new custom_baud config 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 unless custom_baud is 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

12 Apr 18:44

Choose a tag to compare

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|off or the cli_intellisense config 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.open accepts baud+mode args, /port.mode sets serial parameters inline.
  • Lifecycle hooks -- new on_app_start, on_app_stop hooks 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 check overrides resolved.
  • Port in-use detection -- correctly identifies when termapy itself has a port open vs another process.