Commit Graph

11 Commits

Author SHA1 Message Date
michael
cecfc03ba7 feat(rawcli): live relevance hint — per-transponder memory map
Surfaces what the input *means* on the identified tag, in a bottom-bar
hint that updates as you type (the point, over aggressive autocomplete):

- memory.py: page_role(transponder, page) maps a page/block to its role
  on the specific IC — UID, Capability Container, user memory, dynamic
  lock, CFG0/AUTH0, CFG1/ACCESS, PWD, PACK. Layouts mirror the models'
  page attributes (NTAG210/212/213/215/216, Ultralight EV1); a test
  guards against drift.
- input_hint(session, text): the command's purpose, and — once a page
  argument is typed (even partial, hex or decimal) — where that page
  lives. e.g. "READ(4)" -> user memory, "READ(0x2B" -> PWD,
  "WRITE(0x29" -> CFG0/AUTH0.
- app: wired as the prompt's bottom_toolbar.

11 new tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 13:02:59 -07:00
michael
1370526883 fix(rawcli): raw response crash + hex/binary opcode completion
- 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>
2026-07-14 13:00:31 -07:00
michael
41db552e05 fix(rawcli): render ANSI, stop mangling commands, fuller Type 2 catalog
Three fixes from live hardware use:

- Colors/ANSI now render. Output routes through prompt_toolkit's
  print_formatted_text(ANSI(...)) instead of print(), which showed the
  escape codes literally under patch_stdout. Formatters force is_tty so
  the printer decides color-vs-plain. dispatch()/handlers take an `out`.
- Auto-byte-spacing no longer mangles non-hex input. byte_space() only
  regroups a *pure* hex/binary run; command words ("help transponder",
  "identify", "close") and 0x/0b-prefixed tokens are left intact (a-f in
  words used to trigger regrouping -> failed hex parse).
- Type 2 catalog gains PWD_AUTH (0x1B), COMPAT_WRITE (0xA0), HALT — the
  NTAG213 set was missing password auth.
- identify trims the firmware buffer padding off the GET_VERSION response
  (was dumping ~40 trailing 00 bytes).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:50:01 -07:00
michael
6b4a4551d4 feat(rawcli): deep, traced identify — exact model via GET_VERSION
`identify` now probes and shows its work instead of a coarse SAK guess:

- Streams every probe exchange to the trace (proxmark-style annotated):
  the reconstructed 14a activation (WUPA/ATQA/anticollision CL1+CL2/
  SELECT/SAK) plus a REAL GET_VERSION (0x60 +CRC) sent over the persistent
  connection.
- Names the exact IC from GET_VERSION: an NTAG216 now reports "NTAG216",
  not "MIFARE UL/NTAG". Exact map mirrors the transponder models'
  _version_bytes (static, to dodge an import-order circular; a test guards
  against drift). Unknown chips fall back to product family + an honest
  memory-size *range* (AN10833 storage-byte encoding), not a bogus size.
- SAK fallback table + GET_VERSION product-nibble map aligned to NXP
  AN10833 (MIFARE type identification procedure).

11 tests (exact/structural decode, map-model sync, traced probe, SAK
names). GET_VERSION is a real device exchange — the user's hardware test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:40:41 -07:00
michael
3e7f47a740 fix(rawcli): Ctrl-/ key binding crashed launch ("Invalid key: c-/")
prompt_toolkit doesn't accept "c-/". Ctrl-/ is emitted as Ctrl-_ (0x1F)
by terminals, so bind "c-_" (plus "c-t" as an always-available fallback)
for the hex/binary toggle. install_key_bindings() now ignores any key
name a prompt_toolkit build rejects, so a bad key can never crash launch.
Regression test added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:25:36 -07:00
michael
f76663f798 feat(rawcli): ipython-style completion (Phase 6)
- completer.py: RawCompleter completes the leading command token —
  control verbs + the identified transponder's catalog commands — with
  each command's help as the completion meta (tooltip). `help <cmd>`
  completes catalog command names.
- app: wire the completer with complete_while_typing (live menu) +
  AutoSuggestFromHistory (inline hints) for the ipython feel.

Completes the 6-phase rawcli plan. 4 new tests (verb/catalog completion,
tooltips, help-arg completion).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:19:42 -07:00
michael
4e7181d289 feat(rawcli): TLV/NDEF formatting + multi-line editing (Phase 5)
- tlv.py: parse_tlv() walks a Type-2 TLV block (NULL/LOCK/MEM/NDEF/PROP/
  TERMINATOR, incl. 3-byte 0xFF length); format_tlv() renders an indented
  multi-line breakdown and annotates NDEF messages via the existing
  decode_ndef_annotation. prompt_tlv() opens a multi-line editor to
  compose a TLV as hex across lines.
- app/parser: `tlv <hex>` decodes + prints the breakdown; bare `tlv`
  opens the multi-line editor.

5 new tests (structure, extended length, multi-line format, command).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:15:54 -07:00
michael
9c84f9e7b0 feat(rawcli): command catalog + function-style commands (Phase 4)
- catalog.py: declarative per-transponder command sets (name, params,
  build(args)->bytes, help). Seeds: Type 2 (NTAG/UL: READ, FAST_READ,
  GET_VERSION, READ_SIG, READ_CNT, WRITE), MIFARE Classic (READ/WRITE/
  HALT), ISO 15693 (INVENTORY, READ_BLOCK, WRITE_BLOCK, GET_SYSTEM_INFO).
  catalog_for(session) resolves by protocol + identified transponder.
- app: function-style calls (READ(4) -> build -> raw exchange ->
  annotated trace); catalog-aware help (`help` lists the current tag's
  commands, `help READ` shows one). Bad args print usage.

9 new tests (catalog builds, resolver, call dispatch, help). Command
knowledge is declarative + hardware-free-testable; the exchange is the
user's device test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:13:14 -07:00
michael
e024294ec6 feat(rawcli): identify + persistent connection (Phase 3)
- identify.py: probe HF (14a -> 15693) then LF; set session field /
  protocol / transponder. The 14a scan uses NO_DISCONNECT so the tag
  stays selected (the persistent connection). SAK -> coarse family name
  for the breadcrumb.
- session: add `protocol` (drives raw-exchange routing)
- app: connect via Proxmark3.sync() (scan/raw become plain calls); wire
  identify / transponder / close control commands; protocol-aware
  _raw_exchange; breadcrumb fills in field + transponder after identify

8 new tests (identify 14a/15693/none, clear, control commands). Device
probes are mocked; live identify is the user's hardware test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:10:51 -07:00
michael
54e52f029f feat(rawcli): flexible entry + parser (Phase 2)
- parser.py: classify a line into control / function-call / raw payload;
  parse loose hex/binary with intermixed 0x/0b tokens (whitespace-
  insensitive, defaulting to the session entry mode)
- entry.py: byte_space() byte-group formatting + key bindings — Ctrl-/
  toggles hex/binary entry mode (breadcrumb updates), digits auto-space
  into byte groups as you type
- app.py: dispatch() drives the loop via parse_line (testable without a
  live prompt); identify/call are stubbed for Phases 3/4

14 new tests (parser tokens/intermix/errors, byte_space, dispatch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 12:07:21 -07:00
michael
028ce9c21e feat(rawcli): interactive raw-command TUI skeleton (Phase 1)
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>
2026-07-14 11:59:29 -07:00