Skip to content

Releases: AS-FOSS/mandible

v0.2.2

Choose a tag to compare

@github-actions github-actions released this 09 Aug 23:26
v0.2.2
7384b6f

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release introduces two general parser fixes that significantly improve documentation extraction. Together, they increase described coverage across the PATH sweep from 89.23% to 94.18% on 2,266 tools, with zero regressions.

Fixed

  • Tab-Aligned Entry Tables: The parser now recognizes tabs as valid description gaps. Previously, find_description_gap only looked for runs of two or more spaces, causing tab-separated columns to appear undocumented (e.g., mokutil --help reported 38 flags with 0 described). Because a tab inherently advances to the next 8-column stop, it now correctly separates columns. This fix recovers 100% description coverage for mokutil and restores 11 real commands for mysqladmin/mariadb-admin.
  • Option Synonym Handling: As a necessary companion to the tab-alignment fix, a second column of option spellings is no longer mistakenly read as a description. For example, awk --help pairs POSIX short options with GNU long equivalents separated by a tab. Treating that tab as a description gap previously gave -f progfile the false description --file=progfile. Single tokens beginning with - in the description column are now recognized as synonyms and dropped, preserving the tool's accurate "no description" state.
  • Positional Headers in Option Tables: An options table is no longer discarded if it opens with a positional argument. The parser's flags-vs-bare-words decision previously only evaluated the section's first content line. Because kill --help opens its Options: block with <pid> [...], every subsequent flag was discarded, resulting in 0 parsed flags. The parser now evaluates up to three leading non-flag rows at the block's indent level, provided it still finds a real --leading row. This boundary deliberately prevents fabrication while successfully recovering all 6 flags for kill.

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 09 Aug 22:14
v0.2.1
1d0334b

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release addresses the root causes behind the execution safety lockouts introduced in previous versions. By fixing a severe underlying argument-parsing bug and refining fallback behaviors, Mandible is now globally safer and has restored documentation support for essential system-state tools.

Critical Safety & Execution Hardening

  • Fixed the Empty Positional Hazard (<tool> -- ""): The primary cause of the catastrophic system freezes reported in earlier versions has been identified and fixed. A clap completion probe was passing an empty string as a first positional argument (<tool> -- ""). For pattern-matching tools like pkill, an empty string means "match everything." Measured in a private PID namespace, pkill -- "" killed every reachable process. This specific argument shape is now globally refused at the execution chokepoint (Spec §6 rule 2a) for all tools.
  • Blocked Dangerous Fallbacks (-h): Mandible normally falls back to -h if --help fails. However, for machine-state tools (halt, poweroff, reboot, shutdown), -h is an action flag meaning "halt". Unprivileged execution was the only thing preventing Mandible from rebooting the host machine during a background sweep. The -h fallback is now strictly refused for these specific system tools.
  • Specification Correction: Corrected the safety rationale in spec.md. The previous assumption that killall foo --help was dangerous was factually incorrect (on glibc, GNU getopt permutes arguments and safely processes --help first). The true hazard was the empty positional bug mentioned above.

Restored Tool Support

  • Process Killers & System Tools Browsable: With the root execution bugs fixed, tools previously locked behind a blanket ban (pkill, killall, fuser, reboot, shutdown, etc.) are now safely probed using a strict <tool> --help shape.
  • Coverage Boost: Twelve of the thirteen previously locked tools now parse successfully. pkill now yields 27 fully described flags, and killall/fuser yield 16 each. This bumps overall described coverage from 89.20% to 89.23%.

Parser Accuracy Improvements

  • Removed Inaccurate clap CompleteEnv Probe: This probe was the source of the dangerous empty positional argument. Beyond being unsafe, it was highly inaccurate—lacking a strict protocol signature, it relied on shape heuristics that falsely matched unrelated tools (like echo, bzless, and update-alternatives). Removing it deleted eight bogus parses and actually improved described accuracy without losing valid data for any tool.

Project Metadata

  • Canonical Repository Move: The project's official repository is now [https://github.com/AS-FOSS/mandible](https://github.com/AS-FOSS/mandible). This update is reflected in the crates.io metadata and the mandible mandible easter egg.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 09 Aug 13:25
v0.2.0
35034b4

Install

cargo install mandible

Or download a binary below. Verify with the accompanying .sha256.


Six fixes, three of them found by rendering a deliberately awkward CLI through a
real pseudo-terminal rather than by any test.

Fixed

  • The USAGE line no longer repeats the command name. docker import
    rendered as import docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]].
    The check asked whether the usage's first word was the node's name, but
    cobra and argparse both print the full command path, so the name was stapled
    on the front of nearly every subcommand of every such tool. It now scans the
    whole leading run of command words. Tools that print no name at all
    (Usage: [OPTIONS] FILE) still get one added, which is what the prepending
    was for.

  • A token wider than the pane is broken across lines instead of discarded.
    It was ellipsis-truncated, so a 150-character URL rendered as
    https://registry.example.com/v2/org… with everything after it unrecoverable
    from the parsed view. Splits are placed by display width, so a double-width
    character cannot straddle the boundary and overflow the pane.

  • A relative tool path works. mandible ./scripts/tool.py failed with
    "No such file or directory" for a file plainly present: the path was checked
    against the caller's working directory, then the probe ran with its own
    directory redirected into a scratch dir (§6 rule 8). Resolution now yields an
    absolute path — via std::path::absolute, deliberately not
    fs::canonicalize; see below.

  • argparse subcommands survive a styled section heading.
    add_subparsers(title="commands") is the ordinary way to name that block,
    and the dedicated scan was gated on the heading reading positional arguments, so a styled heading collapsed the entire command tree to a single
    node. The scan's structural evidence — a {a,b,c} pseudo-entry with deeper
    lines beneath it — is stronger than the heading text ever was, and still
    refuses a plain positional carrying choices=[...].

  • A command list at the same indent as its heading is recognized. dnf 4
    prints its whole command list flush at column 0 under a flush-left heading;
    the engine required content indented more than its heading, so mandible dnf showed one node and no subcommands. Now 30.

  • A pending row's spinner no longer touches the name. dnf's longest
    command rendered check-update⋯ loading, one mangled word rather than a name
    and its status — the same defect fixed for summaries in an earlier release
    (apt-get's dselect-upgradeFollow) and missed in the sibling branch,
    because no tool in the suite had a pending row at the column until dnf
    gained subcommands.

Notes on two near-misses

Both were caught by the PATH-wide coverage sweep and by nothing else; the unit
suite was green through both.

  • Making resolved paths absolute with fs::canonicalize defeated §6 rule 0.
    is_never_probe matches on the file name, and reboot, poweroff,
    shutdown and telinit are symlinks to systemctl — resolving renamed them
    before the refusal ran. It also broke ten iptables* tools, which dispatch on
    argv[0]. Fixed by using std::path::absolute, which does not follow links.
  • The same-indent command rule initially fabricated 28 subcommands out of
    mysqlslap's config-variable table (port 3306, no-drop FALSE), because at
    a shared indent every row is a candidate heading for the rows beneath it and
    init-command contains the word "command". A heading must now not itself look
    like a row.

Final sweep is identical to baseline on every aggregate — 89.19% described
across 2266 tools, 1 suspicious, 320 verbatim — with zero status changes, zero
nodes lost, and dnf the only gain.

Internal

  • scripts/smoke_cli.py: a deliberately awkward argparse CLI for exercising
    layout by hand — a twelve-level command chain, four flag-table shapes, tokens
    with no whitespace to wrap at, and sixty flags. It found three of the bugs
    above within minutes of existing.

v0.1.7

Choose a tag to compare

@github-actions github-actions released this 08 Aug 19:37
v0.1.7
cfc1837

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release introduces responsive table layouts for narrow terminals and completely eliminates sandbox path leakage in tool documentation, ensuring extracted defaults reflect expected environment variables rather than ephemeral test directories.

Sandbox Path Sanitization & Environment Isolation

  • Dynamic Path Masking: Tools outputting environment-derived defaults (e.g., docker --help printing its config path) will no longer leak Mandible's ephemeral sandbox paths (like /tmp/mandible-exec-L3saJ8/.docker). At the execution boundary, these scratch paths are now dynamically masked back to their source variables (e.g., $HOME/.docker). This keeps documentation readable and captured fixtures independent of the machine that generated them.
  • Symlink & Resolution Awareness: Paths are masked using both logical and canonicalized spellings. This ensures correct masking even when a probed tool resolves its own working directory (e.g., macOS $TMPDIR resolving from /var to /private/var).
  • Strict Variable Isolation: Each redirected variable (HOME, TMPDIR, XDG_*) now receives its own dedicated scratch subdirectory. Previously, they shared a single directory, creating an impossible filesystem state where writing to a cache directory and reading from a home directory resolved to the same file. This isolation also serves as the foundation enabling the dynamic path masking above.

Responsive UI & Table Layouts

  • Invariant Table Alignment: The flag description column is now strictly aligned across the entire list. Previously, exceptionally wide flags pushed the column boundary for themselves, creating ragged prose and causing spelling and value placeholders (e.g., --log-level string) to visually collapse into single tokens. Now, outlier wide flags simply hang their descriptions on the next line.
  • Narrow Terminal Stacking: Below a usable table width, parameter lists now automatically stack—placing the flag spelling on the first line with the description indented underneath. This mirrors standard CLI help behavior and prevents severe line-wrapping artifacts (such as a six-word description breaking across six lines).

Internal Tooling

  • PTY Rendering Tests: Restored scripts/pty_screenshot.py to render the TUI through a genuine pseudo-terminal. This debugging tool caught both of the UI layout defects addressed in this release, proving its value over the standard TestBackend suite which reported green throughout.

v0.1.6

Choose a tag to compare

@github-actions github-actions released this 08 Aug 03:05
v0.1.6
6352172

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release fundamentally overhauls the re-extraction (r) workflow, addressing critical concurrency defects reported in [#6](#6) and ensuring the UI retains your exact context across refreshes.

Stateful Re-extraction

  • Context Retention: Pressing r to re-extract no longer rebuilds the application state from scratch. Your expanded nodes, selection, scroll position, search filter, and view mode are all preserved. The selection is intelligently restored by path rather than row index, accommodating changes in the underlying tree structure.
  • Root Fill Restoration: Fixed a bug where a refresh left the detail pane entirely empty. The root fill is now properly re-queued to start the tree walk immediately, removing the need to manually trigger an expansion to force an update.

Concurrency & Performance Fixes

A series of shared architectural defects were resolved surrounding how the event loop handles a refreshed state:

  • Input Buffer Clearing: Holding r on a slow tool no longer queues up multiple synchronous re-extractions. Because extraction runs on the UI thread, key auto-repeat previously filled the input buffer with blind events that continuously re-froze the screen. Input arriving during this blocking operation is now explicitly discarded.
  • Non-Blocking Cascade Abandonment: Refreshing the tree now safely orphans previous background warming cascades using generation counters via Warmer::reset. Previously, dropping the rayon::ThreadPool forced the UI to wait for running jobs to finish, freezing the screen for the exact duration of the abandoned work.
  • Warming Budget Reset: The MAX_WARMED_NODES bounding counter now correctly resets per generation. Previously, this counter was monotonic across refreshes, meaning each r consumed a non-replenishing budget until background warming silently stopped working for the rest of the session.

UI Discoverability

  • Footer Visibility: The r (re-extract) key binding is now explicitly displayed in the status footer.
  • Help Pinning: The ? help hint is now permanently pinned alongside ^C quit. On narrow terminals, this guarantees the most critical discoverability hint is never pushed off-screen by other status text.

v0.1.5

Choose a tag to compare

@github-actions github-actions released this 08 Aug 02:21
v0.1.5
2718b6a

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release introduces an on-demand audit toggle to expose parser inaccuracies, restructures the project documentation, and fixes a critical missing UI hint for pane navigation.

Added

  • Raw Output Audit Toggle (t): Pressing t on any node now displays the tool's raw --help output instead of the parsed tree.
  • The Rationale: While low-confidence parses already carry warnings, a grammar can misread a layout and produce a plausible but fabricated tree—which looks identical to a correct one. Every fabricated subcommand regression in Mandible's history was caught by comparing the parsed tree to the real output. This toggle puts that audit capability one keystroke away for all users.
  • Memory Efficiency: The raw text is re-probed on demand rather than cached. Caching raw text for every node across a warmed tree would consume megabytes of memory and risk displaying stale data.
  • Transparent Refusals: If a tool cannot be probed (e.g., due to safety rules), the refusal reason is rendered in the pane rather than swallowed, preventing confusion with tools that genuinely print nothing.

Changed

  • README Restructuring: The README now leads with evidence—coverage metrics and safety guarantees—rather than reference material. The exhaustive keybinding table has been replaced with prose covering only non-obvious interactions. The in-app ? overlay and status footer remain the authoritative, drift-proof sources for keybindings.

Fixed

  • Missing Navigation Hint: Added Tab to the status footer. Although bound since the first release, its absence from the footer left many users unable to focus the detail pane or scroll long flag lists unless they had explicitly opened the ? help overlay.

v0.1.4

Choose a tag to compare

@github-actions github-actions released this 08 Aug 00:31
v0.1.4
090cebf

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release introduces a critical execution safety update to prevent Mandible from accidentally triggering destructive system commands during background probing, alongside a UX fix for tools that output full man pages.

Critical Safety Fix

  • Blocked Destructive Commands: Mandible will no longer execute programs designed to kill processes or alter system states. (Previously, running mandible pkill could trigger a system freeze requiring a hard reset).
  • The Root Cause: Mandible's specification permits probing tools using argument shapes like <tool> <word> --help. For process killers, the first positional argument is treated as a target, not a subcommand. Therefore, an automated probe of killall foo --help attempts to kill everything named foo. Any parser change that emitted subcommands for these tools risked turning the background tree-warmer into a process massacre.
  • Chokepoint Defense: Execution of kill, pkill, killall, killall5, skill, xkill, fuser, halt, poweroff, reboot, shutdown, telinit, and init is now explicitly refused before any process is spawned. This check sits at the single execution chokepoint, protecting all tiers, including the background PATH sweeper.
  • Architectural Distinction: This blocklist is explicitly a safety rule based on what a program does, preserving Mandible's strict architectural ban on hardcoding per-tool parsing logic.

Fixed

  • Accurate Confidence Reporting: Fixed an issue where tools falling back to raw man pages (like mandible git) displayed a misleading "low confidence: 0% parsed" warning on every node. For tools like git clone --help (which renders 405 lines of roff prose), degrading to verbatim text with 0.0 confidence is the intentional, correct behavior. The low-confidence caveat now appropriately skips verbatim nodes while still flagging genuinely poor structural parses (e.g., find at 11%, ip at 9%).

v0.1.3

Choose a tag to compare

@github-actions github-actions released this 07 Aug 19:27
v0.1.3
b5c9d05

Install

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


This release restores critical functionality for developers using version managers and formalizes Mandible's architectural specifications based on real-world edge cases.

Toolchain Resolution & Shim Support

  • Version Manager Compatibility: Restored parsing for developer tools managed by rustup, pyenv, nvm, asdf, sdkman, and volta. Previously, Mandible's strict execution sandboxing—which redirects $HOME to a scratch directory—prevented these tool shims from resolving their underlying binaries.
  • Targeted Sandbox Exemptions: Safely bypassed this limitation by explicitly passing through specific toolchain variables (such as RUSTUP_HOME, PYENV_ROOT, and NVM_DIR) while keeping the core $HOME redirect intact.
  • Restored Coverage: Essential developer tools are fully readable again. For example, cargo now correctly parses 12 nodes and 13 flags instead of throwing a resolution error.

Architecture & Specification Updates

  • Framework Detection Constraints (Spec §7): Documented the rationale behind the ~17% implemented detection rate versus the theoretical 71% recall rate. Mandible strictly optimizes for high-precision markers over broad recall; guessing the wrong framework silently applies the wrong grammar and corrupts output, while unidentified tools safely fall back to the general engine.
  • Process Containment Limits (Spec §6): Detailed the root cause of hanging coverage-sweep shards. Background processes that call setsid (like chromedriver or vimtutor) escape their process group and avoid timeout termination. Full containment requires OS-level sandboxing, as cheaper mitigations like PR_SET_PDEATHSIG require pre_exec, violating the project's strict #![forbid(unsafe_code)] guarantee.

General Updates

  • Crate Metadata: The authors field in the manifest now explicitly names the maintainer rather than using a placeholder.

v0.1.2

Choose a tag to compare

@github-actions github-actions released this 07 Aug 18:17
v0.1.2
b20bf4b

Install

cargo install mandible

Or download a binary below. Verify with the accompanying .sha256.


This release focuses on transforming the detail pane from flat output into structured documentation, alongside major universality improvements ensuring Mandible remains fully functional in constrained environments—like minimal containers lacking Unicode or color support.

Detail Pane Redesign

  • Aligned Columns: Flag descriptions now share a single aligned column, converting ragged prose into a readable parameter table.
  • Value Placeholders: Arguments receive their own dedicated column (preventing --env and list from running together as a single token). This column collapses entirely if no flags in the group take a value.
  • Original Tool Ordering: Flag groups now preserve the tool's original editorial ordering rather than sorting alphabetically (e.g., tar now opens with "Archive format selection" instead of "Main operation mode").
  • Permitted Values Displayed: A flag's accepted values are now explicitly surfaced in the UI (e.g., showing that --format accepts exactly gnu, oldgnu, pax, posix, ustar, v7).
  • Cleaner Typography: Section headings now feature a visual rule (e.g., FLAGS ─────) for better anchoring. The usage signature block no longer redundantly repeats the tool's name, and padding has been added to prevent text from sitting flush against terminal borders.

Universality & Environment Support

  • Robust ASCII Fallback: Every UI glyph now has an ASCII fallback, automatically chosen from the locale or forced via MANDIBLE_ASCII=1. This prevents broken rendering (tofu blocks) in non-UTF-8 environments. This is enforced by a test that asserts no cell contains a non-ASCII symbol during fallback.
  • Environment-Aware Styling: Setting TERM=dumb or piping output to a non-terminal stdout now correctly strips color escapes.
  • Formalized Rendering Policy: Added spec §9.2, which dictates that rendering capabilities must be detectable (permanently ruling out requirements like Nerd Fonts) and must degrade gracefully.
  • Wordmark: Running mandible mandible now renders an animated wordmark, redrawn in place so it stays in scrollback (skipped if piped or if the terminal lacks block element support).

Controls & Provenance UI

  • Status Row Overhaul: UI controls are now anchored to the left of the status row, with provenance information on the right.
  • Dynamic Status Messages: Status messages now expire. Previously, copying a flag with y left copied: <command> in the footer indefinitely, masking keybinding hints for the rest of the session.
  • Help Overlay: Reorganized into logical categories (MOVE / SEARCH / ACTIONS), padded for readability, and purged of stale keybinding entries.
  • Streamlined Provenance: The repetitive per-command footer has been removed. Framework metadata has moved to the tree pane title, and low-confidence parse scores (e.g., find scoring 0.11) are now explicitly surfaced.

Fixed

  • Search Modes Clarified: Name-mode search now strictly matches command names. Flag spellings have been moved to the alternative mode, now explicitly labeled everything. This fixes confusing behaviors where a command surfaced in search only because a hidden flag contained the search string.
  • Scroll Boundaries: Fixed a bug where holding the down arrow on a short description would scroll the text completely off the top of the pane.
  • Formatting Artifacts: Value placeholders are no longer italicized, avoiding rendering artifacts on terminals that ignore or mishandle italic modifiers.

CI & Infrastructure

  • Sharded PATH Sweeps: The executable sweep now runs in 16 shards and logs tools immediately before and after probing. If a runner hangs, the exact blocking tool is clearly identified.
  • Stable Asset URLs: Release assets now include version-less copies (e.g., mandible-<target>.tar.gz) to ensure automated download links remain unbroken across releases.
  • Auditing: Added cargo-deny checks for advisories, licenses, bans, and sources.

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 07 Aug 14:36
v0.1.1
c577b13

This release addresses parser edge cases and UI issues discovered while running version 0.1.0 against real-world CLI tools. Three major tools that previously returned incomplete structures now correctly parse their subcommand trees.

Installation

cargo install mandible

Or download a pre-compiled binary from the assets below. Verify with the accompanying .sha256.


Key Improvements

  • apt-get: Recovered 17 subcommands with descriptions (1 node → 18 nodes).
  • busybox: Added support for wrapped, comma-separated applet lists (1 node → 271 nodes).
  • openssl: Cleared false-positive suspicious flags across 151 bare commands.

Fixed

  • Literal Name-Mode Search: names mode now strictly performs literal substring matching on names and flag spellings. Fuzzy search across descriptions is isolated to names+text mode.
  • Search Match Indicators: Rows surfaced because of a flag match now explicitly display via <flag> (e.g., via --no-trunc) in place of their summary during search.
  • Accurate Search Status Bar: Fixed footer guidance while searching. The status bar now displays type to filter ↑↓ move Enter/Esc leave search / names↔text ^C quit instead of indicating q to quit.
  • Layout Overflow: Fixed zero-padding layout collapses where long node names overflowed directly into summary text.
  • openssl False-Positive Verification: Added CommandNode::heading_attested to prevent legitimate bare subcommands (nodes with no flags, children, or summaries) under verified headings from being flagged as fabricated structure.
  • apt-get Subcommand Extraction: Added support for - (space-dash-space) entry separators under recognized command headings, allowing apt-get subcommand descriptions to be parsed correctly.
  • busybox Applet List Extraction: Implemented a dedicated FrameworkProfile::comma_separated_command_list scanner to handle tab-indented, comma-separated applet blocks under "Currently defined functions:".

Added

  • Supply-Chain & License Auditing: Integrated cargo-deny into CI (deny.toml) with policy configurations for direct vs. indirect unmaintained dependencies and explicit MPL-2.0 license handling.
  • Coverage Scoreboard Queue: The cargo xtask coverage scoreboard footer now lists the top ~25 unidentified tools ranked by flag count to prioritize future framework fingerprinting.