- Crash on raw hex: reader raw() returns `data` as a hex STRING; the raw
path fed that to bytes() -> "string argument without an encoding".
_raw_exchange now returns the bytes (`raw` field, or converts `data`);
render_exchange accepts bytes or a hex string.
- Completion for numeric entry, transponder-dependent: typing hex ("60")
or binary ("01100000") now matches the identified tag's command opcodes
and surfaces the named command (GET_VERSION) with its help. Honours a
0x/0b prefix and the current entry mode.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The trace formatter's line now carries a trailing newline; rawcli was
stripping only a leading one (.lstrip), so the trailing \n survived and
the printer added another -> a blank line between every trace line (and a
\n\n join inside render_exchange). Use .strip("\n") so it's correct
whether the formatter emits a leading or trailing newline.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First slice of `pm3py rawcli` — the interactive, annotated raw-command
tool (separate from pyws and from the future `pm3py client` CLI).
- pm3py/cli: a top-level `pm3py` console-script dispatcher (argparse)
with a `rawcli` subcommand; prompt_toolkit gated behind a [rawcli] extra
- rawcli/session.py: RawSession — device/field/transponder/entry-mode
state + the segmented breadcrumb `[raw / hf|lf / $tag / 0x|0b]`
- rawcli/trace_view.py: render a reader<->tag exchange as annotated,
Proxmark-style trace lines, reusing TraceFormatter + the 14a/15693
decoders
- rawcli/app.py: minimal PromptSession loop (connect best-effort,
breadcrumb prompt, help/quit, raw-hex -> annotated exchange)
Entry-mode toggle, identify/connection, the command catalog, and TLV
editing follow in later phases. 9 hardware-free tests (session, trace
render, CLI dispatch); device I/O is the user's local hardware test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>