termapy 0.78.0__tar.gz → 0.80.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. {termapy-0.78.0 → termapy-0.80.0}/PKG-INFO +124 -60
  2. {termapy-0.78.0 → termapy-0.80.0}/README.md +120 -57
  3. {termapy-0.78.0 → termapy-0.80.0}/pyproject.toml +20 -6
  4. {termapy-0.78.0 → termapy-0.80.0}/pyproject.toml.orig +40 -10
  5. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/app.py +890 -471
  6. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/app_dirs.py +4 -3
  7. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/app_hooks.py +76 -74
  8. termapy-0.80.0/src/termapy/boards/__init__.py +363 -0
  9. termapy-0.80.0/src/termapy/boards/esp32s3/config.json +11 -0
  10. termapy-0.80.0/src/termapy/boards/esp32s3/firmware/main.py +98 -0
  11. termapy-0.80.0/src/termapy/boards/esp32s3/profile.json +121 -0
  12. termapy-0.80.0/src/termapy/boards/micropython/firmware/termapy_json.py +443 -0
  13. termapy-0.80.0/src/termapy/boards/micropython/firmware/termapy_mem.py +250 -0
  14. termapy-0.80.0/src/termapy/boards/pico/config.json +11 -0
  15. termapy-0.80.0/src/termapy/boards/pico/firmware/main.py +71 -0
  16. termapy-0.80.0/src/termapy/boards/pico/profile.json +108 -0
  17. termapy-0.80.0/src/termapy/breadcrumbs.py +419 -0
  18. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/_cfg_icon.py +13 -13
  19. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/_crc_verbs.py +27 -10
  20. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/_run_record.py +23 -14
  21. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/_xmodem_handlers.py +15 -8
  22. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/_ymodem_handlers.py +7 -2
  23. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/app.py +238 -41
  24. termapy-0.80.0/src/termapy/builtins/commands/board.py +219 -0
  25. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/cap.py +59 -39
  26. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/cfg.py +215 -95
  27. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/cls.py +7 -3
  28. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/confirm.py +10 -3
  29. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/credits.py +20 -7
  30. termapy-0.80.0/src/termapy/builtins/commands/delay.py +83 -0
  31. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/demo.py +13 -0
  32. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/dev.py +127 -94
  33. termapy-0.80.0/src/termapy/builtins/commands/edit.py +135 -0
  34. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/env.py +66 -41
  35. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/exit.py +8 -3
  36. termapy-0.80.0/src/termapy/builtins/commands/expect.py +209 -0
  37. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/find.py +71 -52
  38. termapy-0.80.0/src/termapy/builtins/commands/firmware.py +231 -0
  39. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/grep.py +16 -53
  40. termapy-0.80.0/src/termapy/builtins/commands/help.py +1548 -0
  41. termapy-0.80.0/src/termapy/builtins/commands/log.py +615 -0
  42. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/mcp.py +28 -94
  43. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/mem.py +357 -151
  44. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/os_cmd.py +30 -8
  45. termapy-0.80.0/src/termapy/builtins/commands/ping.py +125 -0
  46. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/plugin.py +9 -5
  47. termapy-0.80.0/src/termapy/builtins/commands/port.py +822 -0
  48. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/print.py +10 -0
  49. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/profile.py +40 -19
  50. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/proto.py +229 -146
  51. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/raw.py +14 -5
  52. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/repeat.py +10 -4
  53. termapy-0.80.0/src/termapy/builtins/commands/run.py +446 -0
  54. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/search.py +58 -42
  55. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/seq.py +22 -8
  56. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/show.py +25 -15
  57. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/ss.py +13 -0
  58. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/stop.py +6 -0
  59. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/sym.py +91 -61
  60. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/term.py +335 -173
  61. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/var.py +168 -76
  62. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/commands/xfer.py +26 -9
  63. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/demo.cfg +35 -26
  64. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/demo.symbols.json +9 -2
  65. termapy-0.80.0/src/termapy/builtins/demo/dev/console.device.json +18 -0
  66. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/plugin/cmd.py +4 -0
  67. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/plugin/probe.py +14 -7
  68. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/plugin/temp_plot.py +9 -3
  69. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/plugin/traffic.py +64 -19
  70. termapy-0.80.0/src/termapy/builtins/demo/run/doc_screenshots.run +25 -0
  71. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/welcome.run +2 -2
  72. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/capture_view.py +9 -8
  73. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/cli.py +109 -60
  74. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/cli_flags.py +279 -72
  75. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/cli_prompt.py +12 -10
  76. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/config.py +606 -193
  77. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/config_resolve.py +65 -5
  78. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/converters.py +72 -8
  79. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/credits_data.py +11 -3
  80. termapy-0.80.0/src/termapy/defaults.py +1020 -0
  81. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/demo.py +35 -5
  82. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/demo_ndjson.py +46 -30
  83. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/devices/__init__.py +117 -8
  84. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/devices/converters/__init__.py +2 -1
  85. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/devices/converters/svd.py +13 -3
  86. termapy-0.80.0/src/termapy/diag_log.py +370 -0
  87. termapy-0.80.0/src/termapy/dialogs/_common.py +679 -0
  88. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/cfg_confirm.py +3 -2
  89. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/config_editor.py +165 -159
  90. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/config_picker.py +51 -6
  91. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/filename_dialog.py +25 -9
  92. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/port_picker.py +14 -31
  93. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/proto_editor.py +18 -10
  94. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/proto_picker.py +37 -8
  95. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/quick_setup.py +36 -8
  96. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/script_editor.py +25 -13
  97. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/script_picker.py +36 -11
  98. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/set_var_dialog.py +34 -10
  99. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/entry.py +113 -11
  100. termapy-0.80.0/src/termapy/firmware/__init__.py +223 -0
  101. termapy-0.80.0/src/termapy/firmware/c/termapy_json.c +919 -0
  102. termapy-0.80.0/src/termapy/firmware/c/termapy_json.h +473 -0
  103. termapy-0.80.0/src/termapy/firmware/c/termapy_mem.c +528 -0
  104. termapy-0.80.0/src/termapy/firmware/c/termapy_mem.h +224 -0
  105. termapy-0.80.0/src/termapy/folder_ops.py +880 -0
  106. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/folders.py +132 -12
  107. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/acknowledgments.md +13 -7
  108. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/authoring-profiles.md +1 -1
  109. termapy-0.80.0/src/termapy/help/boards.md +169 -0
  110. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/cli.md +78 -36
  111. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/commands.md +110 -28
  112. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/config.md +122 -46
  113. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/custom-buttons.md +22 -3
  114. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/data-capture.md +4 -2
  115. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/demo.md +18 -14
  116. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/devices.md +20 -2
  117. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/environment.md +31 -11
  118. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/file-transfer.md +3 -1
  119. termapy-0.80.0/src/termapy/help/firmware-json.md +294 -0
  120. termapy-0.80.0/src/termapy/help/firmware.md +39 -0
  121. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/getting-started.md +72 -10
  122. termapy-0.80.0/src/termapy/help/img/doc_01_main_tui.svg +204 -0
  123. termapy-0.80.0/src/termapy/help/img/doc_02_help.svg +206 -0
  124. termapy-0.80.0/src/termapy/help/img/doc_02b_help_group.svg +204 -0
  125. termapy-0.80.0/src/termapy/help/img/doc_03_help_proto.svg +208 -0
  126. termapy-0.80.0/src/termapy/help/img/doc_04_proto_send.svg +205 -0
  127. termapy-0.80.0/src/termapy/help/img/doc_05_proto_crc.svg +205 -0
  128. termapy-0.80.0/src/termapy/help/img/doc_06_proto_delay.svg +203 -0
  129. termapy-0.80.0/src/termapy/help/img/doc_07_crc_python.svg +205 -0
  130. termapy-0.80.0/src/termapy/help/img/doc_08_variables.svg +206 -0
  131. termapy-0.80.0/src/termapy/help/img/doc_09_target_help.svg +204 -0
  132. termapy-0.80.0/src/termapy/help/img/doc_10_config_info.svg +206 -0
  133. termapy-0.80.0/src/termapy/help/img/doc_11_proto_run.svg +207 -0
  134. termapy-0.80.0/src/termapy/help/img/doc_12_cap_struct.svg +205 -0
  135. {termapy-0.78.0/src/termapy/html → termapy-0.80.0/src/termapy/help}/img/doc_13_cap_progress.svg +85 -84
  136. termapy-0.80.0/src/termapy/help/img/doc_14_port_list.svg +203 -0
  137. termapy-0.80.0/src/termapy/help/img/doc_15_xfer.svg +205 -0
  138. {termapy-0.78.0/src/termapy/html → termapy-0.80.0/src/termapy/help}/img/doc_17_proto_debug.svg +104 -103
  139. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/index.md +2 -0
  140. termapy-0.80.0/src/termapy/help/mcp-server.md +321 -0
  141. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/memory.md +112 -27
  142. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/ports.md +231 -5
  143. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/protocol-testing.md +51 -7
  144. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/scripting.md +101 -15
  145. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/serial-tools.md +2 -1
  146. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/symbols.md +127 -31
  147. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/toolbar.md +58 -4
  148. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/variables.md +31 -8
  149. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/vt100.md +13 -4
  150. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/writing-plugins.md +267 -48
  151. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help_dynamic.py +6 -3
  152. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help_tooltip.py +6 -2
  153. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/404.html +91 -11
  154. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/acknowledgments.html +104 -18
  155. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/assets/javascripts/LICENSE +29 -29
  156. termapy-0.80.0/src/termapy/html/assets/javascripts/bundle.3cb411a8.min.js +10 -0
  157. termapy-0.78.0/src/termapy/html/assets/javascripts/workers/search.c47bb847.min.js → termapy-0.80.0/src/termapy/html/assets/javascripts/workers/search.719e0d91.min.js +1 -1
  158. termapy-0.80.0/src/termapy/html/assets/stylesheets/classic/main.0006804e.min.css +6 -0
  159. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/assets/stylesheets/classic/palette.813d4b3f.min.css +3 -3
  160. termapy-0.80.0/src/termapy/html/assets/stylesheets/modern/main.ebb7f775.min.css +6 -0
  161. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/assets/stylesheets/modern/palette.b60ce83d.min.css +3 -3
  162. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/authoring-profiles.html +92 -12
  163. termapy-0.80.0/src/termapy/html/boards.html +1502 -0
  164. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/cli.html +215 -75
  165. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/commands.html +324 -52
  166. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/config.html +376 -166
  167. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/custom-buttons.html +148 -14
  168. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/data-capture.html +94 -13
  169. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/demo.html +109 -27
  170. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/device-help.html +91 -11
  171. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/devices.html +147 -30
  172. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/environment.html +128 -24
  173. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/file-transfer.html +97 -15
  174. termapy-0.80.0/src/termapy/html/firmware-json.html +1770 -0
  175. termapy-0.80.0/src/termapy/html/firmware.html +1204 -0
  176. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/getting-started.html +204 -48
  177. termapy-0.80.0/src/termapy/html/img/doc_01_main_tui.svg +204 -0
  178. termapy-0.80.0/src/termapy/html/img/doc_02_help.svg +206 -0
  179. termapy-0.80.0/src/termapy/html/img/doc_02b_help_group.svg +204 -0
  180. termapy-0.80.0/src/termapy/html/img/doc_03_help_proto.svg +208 -0
  181. termapy-0.80.0/src/termapy/html/img/doc_04_proto_send.svg +205 -0
  182. termapy-0.80.0/src/termapy/html/img/doc_05_proto_crc.svg +205 -0
  183. termapy-0.80.0/src/termapy/html/img/doc_06_proto_delay.svg +203 -0
  184. termapy-0.80.0/src/termapy/html/img/doc_07_crc_python.svg +205 -0
  185. termapy-0.80.0/src/termapy/html/img/doc_08_variables.svg +206 -0
  186. termapy-0.80.0/src/termapy/html/img/doc_09_target_help.svg +204 -0
  187. termapy-0.80.0/src/termapy/html/img/doc_10_config_info.svg +206 -0
  188. termapy-0.80.0/src/termapy/html/img/doc_11_proto_run.svg +207 -0
  189. termapy-0.80.0/src/termapy/html/img/doc_12_cap_struct.svg +205 -0
  190. {termapy-0.78.0/src/termapy/help → termapy-0.80.0/src/termapy/html}/img/doc_13_cap_progress.svg +85 -84
  191. termapy-0.80.0/src/termapy/html/img/doc_14_port_list.svg +203 -0
  192. termapy-0.80.0/src/termapy/html/img/doc_15_xfer.svg +205 -0
  193. {termapy-0.78.0/src/termapy/help → termapy-0.80.0/src/termapy/html}/img/doc_17_proto_debug.svg +104 -103
  194. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/index.html +93 -11
  195. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/installation.html +91 -11
  196. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/mcp-server.html +370 -102
  197. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/memory.html +302 -45
  198. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/on-ai-assistance.html +91 -11
  199. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/ports.html +505 -24
  200. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/protocol-testing.html +174 -17
  201. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/scripting.html +238 -46
  202. termapy-0.80.0/src/termapy/html/search.json +1 -0
  203. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/serial-tools.html +93 -12
  204. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/sitemap.xml +2 -2
  205. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/symbols.html +347 -78
  206. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/toolbar.html +185 -15
  207. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/using-git.html +91 -11
  208. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/variables.html +153 -34
  209. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/vt100.html +124 -15
  210. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/writing-plugins.html +633 -262
  211. termapy-0.80.0/src/termapy/idioms.py +167 -0
  212. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/info_views.py +9 -10
  213. termapy-0.80.0/src/termapy/load_report.py +252 -0
  214. termapy-0.80.0/src/termapy/markup.py +192 -0
  215. termapy-0.80.0/src/termapy/matching.py +133 -0
  216. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/mcp/catalog.py +20 -10
  217. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/mcp/server.py +299 -173
  218. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/memory.py +2 -2
  219. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/memory_views.py +82 -4
  220. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/migration.py +140 -9
  221. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/palette_provider.py +6 -1
  222. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/pickers.py +70 -45
  223. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/__init__.py +30 -2
  224. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/capabilities.py +38 -4
  225. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/command.py +456 -52
  226. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/context.py +23 -10
  227. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/fs.py +78 -11
  228. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/internal.py +53 -22
  229. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/io.py +64 -3
  230. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/serial.py +64 -3
  231. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/ui.py +6 -2
  232. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/loader.py +91 -39
  233. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/output_levels.py +12 -5
  234. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/params.py +29 -0
  235. termapy-0.80.0/src/termapy/plugins/views.py +435 -0
  236. termapy-0.80.0/src/termapy/plugins/waiting.py +80 -0
  237. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/port_control.py +523 -155
  238. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/port_format.py +130 -23
  239. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/profile/loader.py +10 -8
  240. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/profile/matcher.py +2 -2
  241. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/profile/types.py +2 -2
  242. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/proto_debug.py +291 -95
  243. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/__init__.py +2 -0
  244. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/core.py +31 -1
  245. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/crc.py +7 -8
  246. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/runner.py +72 -31
  247. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/viz.py +10 -9
  248. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/repl.py +662 -294
  249. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/request_response.py +29 -33
  250. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/run_docstring.py +1 -1
  251. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/scripting.py +99 -4
  252. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/serial_engine.py +75 -14
  253. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/serial_port.py +75 -14
  254. termapy-0.80.0/src/termapy/session_log.py +130 -0
  255. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/__init__.py +4 -0
  256. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/address.py +3 -1
  257. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/converters/__init__.py +27 -6
  258. termapy-0.80.0/src/termapy/symbols/converters/elf.py +666 -0
  259. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/converters/xc32.py +92 -1
  260. termapy-0.80.0/src/termapy/symbols/format.py +468 -0
  261. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/session.py +82 -36
  262. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/table.py +194 -37
  263. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/terminal_host.py +374 -65
  264. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/title_bar.py +76 -27
  265. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/tree_render.py +6 -3
  266. termapy-0.80.0/src/termapy/typed_lines.py +59 -0
  267. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/update_check.py +6 -2
  268. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb/__init__.py +2 -0
  269. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb/chips.py +72 -49
  270. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb/vendors.py +39 -0
  271. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb_tree.py +23 -7
  272. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/variables.py +179 -37
  273. termapy-0.80.0/src/termapy/vt100.py +410 -0
  274. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/widgets/__init__.py +15 -1
  275. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/widgets/checkbox.py +3 -1
  276. termapy-0.80.0/src/termapy/widgets/link_log.py +108 -0
  277. termapy-0.80.0/src/termapy/widgets/prompt_input.py +63 -0
  278. termapy-0.80.0/src/termapy/widgets/selectable_log.py +317 -0
  279. termapy-0.80.0/src/termapy/widgets/selection_list.py +105 -0
  280. termapy-0.80.0/src/termapy/widgets/status_bar.py +124 -0
  281. termapy-0.78.0/src/termapy/builtins/commands/delay.py +0 -105
  282. termapy-0.78.0/src/termapy/builtins/commands/edit.py +0 -287
  283. termapy-0.78.0/src/termapy/builtins/commands/expect.py +0 -133
  284. termapy-0.78.0/src/termapy/builtins/commands/help.py +0 -937
  285. termapy-0.78.0/src/termapy/builtins/commands/log.py +0 -408
  286. termapy-0.78.0/src/termapy/builtins/commands/ping.py +0 -91
  287. termapy-0.78.0/src/termapy/builtins/commands/port.py +0 -741
  288. termapy-0.78.0/src/termapy/builtins/commands/run.py +0 -263
  289. termapy-0.78.0/src/termapy/builtins/demo/run/doc_screenshots.run +0 -124
  290. termapy-0.78.0/src/termapy/defaults.py +0 -596
  291. termapy-0.78.0/src/termapy/dialogs/_common.py +0 -366
  292. termapy-0.78.0/src/termapy/folder_ops.py +0 -493
  293. termapy-0.78.0/src/termapy/help/img/doc_01_main_tui.svg +0 -202
  294. termapy-0.78.0/src/termapy/help/img/doc_02_help.svg +0 -205
  295. termapy-0.78.0/src/termapy/help/img/doc_03_help_proto.svg +0 -206
  296. termapy-0.78.0/src/termapy/help/img/doc_04_proto_send.svg +0 -203
  297. termapy-0.78.0/src/termapy/help/img/doc_05_proto_crc.svg +0 -203
  298. termapy-0.78.0/src/termapy/help/img/doc_06_proto_delay.svg +0 -204
  299. termapy-0.78.0/src/termapy/help/img/doc_07_crc_python.svg +0 -201
  300. termapy-0.78.0/src/termapy/help/img/doc_08_variables.svg +0 -203
  301. termapy-0.78.0/src/termapy/help/img/doc_09_target_help.svg +0 -205
  302. termapy-0.78.0/src/termapy/help/img/doc_10_config_info.svg +0 -204
  303. termapy-0.78.0/src/termapy/help/img/doc_11_proto_run.svg +0 -205
  304. termapy-0.78.0/src/termapy/help/img/doc_12_cap_struct.svg +0 -203
  305. termapy-0.78.0/src/termapy/help/img/doc_14_port_list.svg +0 -201
  306. termapy-0.78.0/src/termapy/help/img/doc_15_xfer.svg +0 -203
  307. termapy-0.78.0/src/termapy/help/mcp-server.md +0 -234
  308. termapy-0.78.0/src/termapy/html/assets/javascripts/bundle.a2388154.min.js +0 -10
  309. termapy-0.78.0/src/termapy/html/assets/stylesheets/classic/main.68ef4dbf.min.css +0 -6
  310. termapy-0.78.0/src/termapy/html/assets/stylesheets/modern/main.e442bf79.min.css +0 -6
  311. termapy-0.78.0/src/termapy/html/img/doc_01_main_tui.svg +0 -202
  312. termapy-0.78.0/src/termapy/html/img/doc_02_help.svg +0 -205
  313. termapy-0.78.0/src/termapy/html/img/doc_03_help_proto.svg +0 -206
  314. termapy-0.78.0/src/termapy/html/img/doc_04_proto_send.svg +0 -203
  315. termapy-0.78.0/src/termapy/html/img/doc_05_proto_crc.svg +0 -203
  316. termapy-0.78.0/src/termapy/html/img/doc_06_proto_delay.svg +0 -204
  317. termapy-0.78.0/src/termapy/html/img/doc_07_crc_python.svg +0 -201
  318. termapy-0.78.0/src/termapy/html/img/doc_08_variables.svg +0 -203
  319. termapy-0.78.0/src/termapy/html/img/doc_09_target_help.svg +0 -205
  320. termapy-0.78.0/src/termapy/html/img/doc_10_config_info.svg +0 -204
  321. termapy-0.78.0/src/termapy/html/img/doc_11_proto_run.svg +0 -205
  322. termapy-0.78.0/src/termapy/html/img/doc_12_cap_struct.svg +0 -203
  323. termapy-0.78.0/src/termapy/html/img/doc_14_port_list.svg +0 -201
  324. termapy-0.78.0/src/termapy/html/img/doc_15_xfer.svg +0 -203
  325. termapy-0.78.0/src/termapy/html/search.json +0 -1
  326. termapy-0.78.0/src/termapy/legacy.py +0 -238
  327. termapy-0.78.0/src/termapy/markup.py +0 -101
  328. termapy-0.78.0/src/termapy/plugins/views.py +0 -185
  329. termapy-0.78.0/src/termapy/run_legacy.py +0 -230
  330. termapy-0.78.0/src/termapy/symbols/format.py +0 -273
  331. termapy-0.78.0/src/termapy/vt100.py +0 -246
  332. termapy-0.78.0/src/termapy/widgets/status_bar.py +0 -75
  333. {termapy-0.78.0 → termapy-0.80.0}/LICENSE +0 -0
  334. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/__init__.py +0 -0
  335. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/__main__.py +0 -0
  336. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/__init__.py +0 -0
  337. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/crc/__init__.py +0 -0
  338. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/crc/sum16.py +0 -0
  339. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/crc/sum8.py +0 -0
  340. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/.gitignore +0 -0
  341. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/__init__.py +0 -0
  342. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/demo.profile.json +0 -0
  343. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/demo_legacy.profile.json +0 -0
  344. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/demo_ndjson.profile.json +0 -0
  345. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/plugin/__init__.py +0 -0
  346. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/proto/at_test.pro +0 -0
  347. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/proto/bitfield_inline.pro +0 -0
  348. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/proto/modbus_inline.pro +0 -0
  349. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/at_demo.run +0 -0
  350. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/crc_tour.run +0 -0
  351. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/expect_test.run +0 -0
  352. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/gps_demo.run +0 -0
  353. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/smoke_test.run +0 -0
  354. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/status_check.run +0 -0
  355. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/demo/run/var_demo.run +0 -0
  356. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/viz/__init__.py +0 -0
  357. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/viz/hex_view.py +0 -0
  358. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/builtins/viz/text_view.py +0 -0
  359. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/capture.py +0 -0
  360. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/demo_vt100.py +0 -0
  361. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/__init__.py +0 -0
  362. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/confirm_dialog.py +0 -0
  363. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/dialogs/update_available.py +0 -0
  364. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/env_flags.py +0 -0
  365. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/.coverage +0 -0
  366. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/device-help.md +0 -0
  367. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_16_toolbar.svg +0 -0
  368. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_20_palette.svg +0 -0
  369. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_21_script_picker.svg +0 -0
  370. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_22_script_editor.svg +0 -0
  371. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_23_config_editor.svg +0 -0
  372. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_24_cmd_picker.svg +0 -0
  373. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_30_new_cfg.png +0 -0
  374. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_31_cli_completion.png +0 -0
  375. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_32_port_picker.png +0 -0
  376. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_33_port_tooltip.png +0 -0
  377. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_34_latency_timer.png +0 -0
  378. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_35_vt100_menu.png +0 -0
  379. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_36_vt100_status.png +0 -0
  380. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/img/doc_37_config_picker.svg +0 -0
  381. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/installation.md +0 -0
  382. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/on-ai-assistance.md +0 -0
  383. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/help/using-git.md +0 -0
  384. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/history_nav.py +0 -0
  385. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/.coverage +0 -0
  386. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/assets/images/favicon.png +0 -0
  387. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_16_toolbar.svg +0 -0
  388. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_20_palette.svg +0 -0
  389. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_21_script_picker.svg +0 -0
  390. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_22_script_editor.svg +0 -0
  391. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_23_config_editor.svg +0 -0
  392. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_24_cmd_picker.svg +0 -0
  393. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_30_new_cfg.png +0 -0
  394. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_31_cli_completion.png +0 -0
  395. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_32_port_picker.png +0 -0
  396. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_33_port_tooltip.png +0 -0
  397. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_34_latency_timer.png +0 -0
  398. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_35_vt100_menu.png +0 -0
  399. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_36_vt100_status.png +0 -0
  400. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/html/img/doc_37_config_picker.svg +0 -0
  401. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/install_info.py +0 -0
  402. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/mcp/__init__.py +0 -0
  403. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/mcp/prompts.py +0 -0
  404. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/plugins/handles/__init__.py +0 -0
  405. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/profile/__init__.py +0 -0
  406. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/profile/schema.json +0 -0
  407. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/protocol/type_codes.py +0 -0
  408. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/response_parsers.py +0 -0
  409. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/symbols/provenance.py +0 -0
  410. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/icons/termapy.icns +0 -0
  411. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/icons/termapy.ico +0 -0
  412. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/icons/termapy.png +0 -0
  413. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/icons/termapy.svg +0 -0
  414. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/linux/termapy.desktop.template +0 -0
  415. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/macos/Termapy.app/Contents/Info.plist +0 -0
  416. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/templates/macos/Termapy.app/Contents/MacOS/launcher.template +0 -0
  417. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb/_vendors_full.py +0 -0
  418. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/usb/aliases.py +0 -0
  419. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/LICENSES.md +0 -0
  420. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/__init__.py +0 -0
  421. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/__init__.py +0 -0
  422. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/__main__.py +0 -0
  423. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/rfc2217.py +0 -0
  424. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/rs485.py +0 -0
  425. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/serialcli.py +0 -0
  426. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/serialjava.py +0 -0
  427. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/serialposix.py +0 -0
  428. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/serialutil.py +0 -0
  429. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/serialwin32.py +0 -0
  430. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/threaded/__init__.py +0 -0
  431. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/__init__.py +0 -0
  432. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/hexlify_codec.py +0 -0
  433. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports.py +0 -0
  434. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports_common.py +0 -0
  435. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports_linux.py +0 -0
  436. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports_osx.py +0 -0
  437. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports_posix.py +0 -0
  438. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/list_ports_windows.py +0 -0
  439. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/tools/miniterm.py +0 -0
  440. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/__init__.py +0 -0
  441. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_alt.py +0 -0
  442. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_cp2110.py +0 -0
  443. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_hwgrep.py +0 -0
  444. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_loop.py +0 -0
  445. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_rfc2217.py +0 -0
  446. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_socket.py +0 -0
  447. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/urlhandler/protocol_spy.py +0 -0
  448. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/serial/win32.py +0 -0
  449. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/xmodem.py +0 -0
  450. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/CRC.py +0 -0
  451. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/Platform.py +0 -0
  452. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/Protocol.py +0 -0
  453. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/Socket.py +0 -0
  454. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/Version.py +0 -0
  455. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/vendor/ymodem/__init__.py +0 -0
  456. {termapy-0.78.0 → termapy-0.80.0}/src/termapy/widgets/suggester.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: termapy
3
- Version: 0.78.0
3
+ Version: 0.80.0
4
4
  Summary: A TUI serial terminal with ANSI color support, built on Textual and pyserial
5
5
  Keywords: serial,terminal,tui,textual,pyserial,embedded,xmodem,ymodem
6
6
  Author: Chuck Bass
@@ -20,10 +20,10 @@ Classifier: Programming Language :: Python :: 3.15
20
20
  Classifier: Topic :: Communications
21
21
  Classifier: Topic :: System :: Hardware
22
22
  Classifier: Topic :: Terminals :: Serial
23
- Requires-Dist: textual>=0.80
23
+ Requires-Dist: textual>=2.0
24
24
  Requires-Dist: prompt-toolkit>=3.0
25
25
  Requires-Dist: pygments>=2.20.0
26
- Requires-Dist: tree-sitter>=0.25.0,<0.27
26
+ Requires-Dist: tree-sitter>=0.25.0,<0.26.1
27
27
  Requires-Dist: tree-sitter-json>=0.24.0,<0.25
28
28
  Requires-Dist: tree-sitter-toml>=0.6.0,<0.8
29
29
  Requires-Dist: tree-sitter-bash>=0.23.0,<0.26
@@ -31,6 +31,7 @@ Requires-Dist: packaging>=24.0
31
31
  Requires-Dist: frist>=0.21
32
32
  Requires-Dist: platformdirs>=4.0
33
33
  Requires-Dist: crcglot>=0.32.1
34
+ Requires-Dist: pyelftools>=0.33
34
35
  Requires-Dist: termapy[mcp,web] ; extra == 'all'
35
36
  Requires-Dist: mcp>=2,<3 ; extra == 'mcp'
36
37
  Requires-Dist: textual-serve>=1.1 ; extra == 'web'
@@ -95,12 +96,24 @@ Low time commitment: about 1 minute from scratch, or under 10 seconds if you alr
95
96
  uv tool uninstall termapy
96
97
  ```
97
98
 
98
- For your own device, one line creates a config and connects:
99
+ For your own device, name its port, as with `screen`. termapy keeps the settings for next time, in your user folder rather than the project:
100
+
101
+ ```sh
102
+ termapy COM4 115200 8N1
103
+ ```
104
+
105
+ When the device deserves a project of its own (scripts, plugins, a profile, MCP), one line creates its config here and connects:
99
106
 
100
107
  ```sh
101
108
  termapy --new my_device COM4 115200 8N1
102
109
  ```
103
110
 
111
+ For a new dev board, a starter project gives it a command monitor that answers you and an MCP agent on day one. The Raspberry Pi Pico and the ESP32-S3 DevKitC-1 have one; see the Dev boards help page:
112
+
113
+ ```sh
114
+ termapy --board pico
115
+ ```
116
+
104
117
  For a plain-text terminal (no TUI), use CLI mode:
105
118
 
106
119
  ```sh
@@ -130,11 +143,13 @@ PuTTY works. So does minicom, screen, and CoolTerm. Use them if they do what you
130
143
 
131
144
  - **Runs anywhere Python does.** Same tool on Windows, macOS, Linux. No GUI installer, no system dependencies.
132
145
  - **Session logging and screenshots.** Every session is logged. Ctrl+S saves an SVG screenshot you can paste into a report or email.
133
- - **Scripting.** Record a sequence of commands in a text file and replay it with one click. Add delays, prompts, and REPL commands.
146
+ - **Scripting.** Record a sequence of commands in a text file and replay it with one click, or rerun the last few commands you typed with `/run.last`. Add delays, prompts, and REPL commands.
147
+ - **Paste to run, no script file needed.** Paste a block of commands into the prompt and every line runs as if you typed it: device lines go to the device, `/` lines run as termapy commands, Escape stops the rest. Paste a copied session, prompts, replies and all, and only its commands run again; the replies are skipped, never sent to the device. Copy what you did, paste it, and it happens again. See [Pasting several lines](src/termapy/help/toolbar.md#pasting-several-lines).
134
148
  - **Data capture.** Capture serial text (timed) or binary data (by byte/record count) to files. Binary captures use the same format spec language as protocol testing to decode mixed-type records into CSV/TSV.
135
149
  - **Binary protocol testing.** Send raw hex, run scripted send/expect tests with pass/fail, decode Modbus and custom protocols with pluggable visualizers.
136
150
  - **Plugin system.** Add custom commands with a simple Python API. Drop a file in a folder, define a handler, done. Includes examples to get started.
137
151
  - **Everything in one folder.** Each device config gets its own subfolder with logs, screenshots, scripts, and plugins. Check it into git so the whole team has the same config.
152
+ - **Line-based, so device code stays small.** Editing, history and type-ahead happen in termapy, and a line goes out only when you press Enter, so the device needs a line buffer and nothing more: no backspace, cursor or completion code. Name a C variable or a register and termapy sends the address. The same lines replay from a log or a paste and are what an MCP agent sends. See [Why termapy is line-based](docs/why-line-based.md).
138
153
 
139
154
  See the [detailed feature comparison](docs/comparison.md) against RealTerm, CoolTerm, Tera Term, Docklight, and HTerm.
140
155
 
@@ -150,11 +165,26 @@ See the [detailed feature comparison](docs/comparison.md) against RealTerm, Cool
150
165
 
151
166
  </details>
152
167
 
168
+ ## Feature status
169
+
170
+ Termapy is in beta: everything not listed here is stable and ready for public testing. These parts work and are used daily, but they are still being developed and may change in any release.
171
+
172
+ | Feature | Commands | Status |
173
+ | --- | --- | --- |
174
+ | MCP server | `/mcp` | preview |
175
+ | Device files | `/dev` | preview |
176
+ | Symbols | `/sym` | preview |
177
+ | Memory access | `/mem` | preview |
178
+ | Dev board starters | `/board` | prototype |
179
+ | Device-side firmware | `/firmware` | prototype |
180
+
181
+ **Preview** works but may change in any release; **prototype** is new and incomplete, and may change or be removed. `/help` states the level on the command's page and, in a listing, puts the name in italics with the level in its tooltip; the MCP catalog carries it, and a prototype says so once a session when it first runs.
182
+
153
183
  ## Security
154
184
 
155
- Termapy runs with your privileges and does whatever you — or a connected MCP client — tell it, so point it at devices, profiles, and MCP clients you trust. The MCP server is **sandboxed by default**: an automated agent is confined to the serial device and config directory (at worst, a hostile device or profile hangs the session), and each class of host access below stays off until you opt in.
185
+ Termapy runs with your privileges and does whatever you — or a connected MCP client — tell it, so point it at devices, profiles, and MCP clients you trust. The MCP server is a preview, and its limits on host access are not complete yet: by default it refuses the access below on the main routes, but known gaps remain (listed in the [MCP server](src/termapy/help/mcp-server.md) help), so the MCP client's own permissions are the real boundary.
156
186
 
157
- | Host access (off by default) | Opt in with |
187
+ | Host access (refused by default on the main routes) | Opt in with |
158
188
  | --- | --- |
159
189
  | Files outside the config directory | `TERMAPY_MCP_FS_UNCONFINED=1` |
160
190
  | Network sockets (`socket://`, `rfc2217://`) | `TERMAPY_MCP_NET_EGRESS=1` |
@@ -162,6 +192,8 @@ Termapy runs with your privileges and does whatever you — or a connected MCP c
162
192
 
163
193
  Each flag takes any boolean token (`1`, `on`, `true`, `yes`, ...); a value outside that vocabulary refuses to start, naming the variable, rather than silently meaning off.
164
194
 
195
+ No flag opens the rest to an MCP client: a shell (`/os`), renaming or deleting files, writing into `plugin/` or `viz/`, and replacing a file outside the config's folder. These limit termapy's own commands; a client that can write files some other way is outside them.
196
+
165
197
  <details>
166
198
  <summary><strong>The basics</strong> - keyboard shortcuts, title bar, REPL commands</summary>
167
199
 
@@ -173,9 +205,15 @@ Each flag takes any boolean token (`1`, `on`, `true`, `yes`, ...); a value outsi
173
205
  | Ctrl+S | Save SVG screenshot |
174
206
  | Ctrl+T | Save text screenshot |
175
207
  | Ctrl+P | Command palette |
208
+ | Ctrl+C | Copy the selected text; with nothing selected, send Ctrl-C to the device |
209
+ | Ctrl+D | On an empty prompt, send Ctrl-D to the device |
210
+ | Ctrl+Z | On an empty prompt, send Ctrl-Z to the device (an AT modem's send-SMS key) |
211
+ | Ctrl+A | Select all output (click it first) |
212
+ | Ctrl+F | Find in the config editor (Alt+F in VS Code) |
213
+ | Shift+Up | Select output lines from the prompt; then Shift+arrows grow it |
176
214
  | F1–F4 | Help / Cfg / Run / Proto buttons (Ctrl+Shift+1–4 in VS Code); F10 edits the config |
177
215
  | Up/Down | Cycle through command history |
178
- | Escape | Clear input / exit history browsing |
216
+ | Escape | Stop what is running; otherwise clear the prompt, or, when it is empty, send Esc to the device |
179
217
  | Right | Accept type-ahead suggestion |
180
218
 
181
219
  See [Environment and compatibility](src/termapy/help/environment.md)
@@ -225,11 +263,11 @@ The most common ones:
225
263
  | `/port {name}` | Open Port picker (bare TUI), list ports (bare CLI), or open by name |
226
264
  | `/port.help` | Same as `/help port` |
227
265
  | `/port.list` | List available serial ports |
228
- | `/port.connect {name} {baud} {mode}` | Connect with optional baud and mode (e.g. /port.connect COM3 9600 N81) |
229
- | `/port.mode {baud} {mode}` | Show or set serial mode (e.g. /port.mode 9600 N81) |
266
+ | `/port.connect {name} {baud} {mode} {custom=<bool>}` | Connect with optional baud and mode (e.g. /port.connect COM3 9600 N81); a non-standard rate needs `custom=true` |
267
+ | `/port.mode {baud} {mode} {custom=<bool>}` | Show or set serial mode (e.g. /port.mode 9600 N81); a non-standard rate needs `custom=true` |
230
268
  | `/port.disconnect` | Disconnect from the serial port |
231
269
  | `/port.info` | Show port status, serial parameters, and hardware lines |
232
- | `/port.baud_rate {value}` | Show or set baud rate (hardware only) |
270
+ | `/port.baud_rate {value} {custom=<bool>}` | Show or set baud rate (hardware only): a standard one, or any from 300 with `custom=true` |
233
271
  | `/port.byte_size {value}` | Show or set data bits (hardware only) |
234
272
  | `/port.parity {value}` | Show or set parity (hardware only) |
235
273
  | `/port.stop_bits {value}` | Show or set stop bits (hardware only) |
@@ -245,6 +283,7 @@ The most common ones:
245
283
  | `/cfg.auto <key> <value>` | Set an in-memory config key immediately (no confirmation) |
246
284
  | `/cfg.list` | List all config files |
247
285
  | `/cfg.load <name>` | Switch to a different config by name |
286
+ | `/cfg.loaded` | Show what the config load loaded: plugin files, symbols, device files |
248
287
  | `/cfg.show` | Open the current config file in the system viewer |
249
288
  | `/cfg.help` | Same as `/help cfg` |
250
289
  | `/ss.svg {name}` | Save SVG screenshot |
@@ -252,7 +291,7 @@ The most common ones:
252
291
  | `/ss.list` | List screenshots, newest first, with size and age |
253
292
  | `/ss.explore` | Open the screenshot folder in the system file explorer |
254
293
  | `/cls` | Clear the terminal screen |
255
- | `/run {filename}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep |
294
+ | `/run {filename}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep; `--echo` shows each command line as it runs |
256
295
  | `/run.list` | List .run files in run/, newest first, with size, age, and summary |
257
296
  | `/run.rename <old> <new>` | Rename a script (`.run` kept; never overwrites) |
258
297
  | `/run.help` | Same as `/help run` |
@@ -266,22 +305,23 @@ The most common ones:
266
305
  | `/show <name>` | Show a file |
267
306
  | `/show.cfg` | Show the current config file |
268
307
  | `/term` | Terminal display / session toggles (echo, line_no, timestamps, ...) |
269
- | `/term.info` | Snapshot the state of every `/term.*` toggle |
270
- | `/term.echo {on\|off\|toggle}` | Local echo of device commands sent to the wire (persisted via cfg `echo`) |
308
+ | `/term.info` | Snapshot every `/term.*` toggle, and the bytes sent and received |
309
+ | `/term.echo {on\|off\|toggle}` | Local echo of device commands to the wire; session only, seeded by cfg `echo` |
271
310
  | `/term.echo_repl {on\|off\|toggle}` | Local echo of REPL (slash) commands, session only; off inside scripts |
272
311
  | `/term.line_no {on\|off\|toggle}` | Toggle line numbers in serial output (TUI only) |
273
312
  | `/term.eol.markers {on\|off\|toggle}` | Toggle visible `\r` `\n` markers for line-ending troubleshooting |
274
313
  | `/term.output {level\|cycle}` | Show or set output level (silent/quiet/normal/verbose) |
275
314
  | `/term.timestamps {on\|off\|toggle}` | Toggle `[HH:MM:SS.mmm]` timestamp prefix |
315
+ | `/term.traffic {on\|off\|toggle}` | Show live TX/RX byte counts in the bottom bar (TUI only) |
276
316
  | `/term.hex {on\|off\|toggle}` | Toggle hex display of incoming bytes |
277
317
  | `/term.encoding {name}` | Show or set byte-decoding encoding (utf-8, latin-1, ...) |
278
- | `/term.json {compact\|indent\|color\|cycle}` | How JSON answers print: one line, indented, or indented and colored |
318
+ | `/term.json_fmt {compact\|indent\|color\|cycle}` | How JSON answers print: one line, indented, or indented and colored |
279
319
  | `/term.send_bare_enter {on\|off\|toggle}` | Send line ending on empty Enter |
280
320
  | `/edit <file>` | Edit a project file (`run/`, `proto/` or `plugin/`) |
281
321
  | `/edit.cfg` | Edit the current config file |
282
322
  | `/edit.log` | Open the session log in the system viewer |
283
323
  | `/edit.info` | Open the info report in the system viewer |
284
- | `/os <cmd>` | Run a shell command (10s timeout, requires `TERMAPY_OS_CMD_ENABLED=1` in env) |
324
+ | `/os <cmd>` | Run a shell command (10s timeout, requires `TERMAPY_OS_CMD_ENABLED=1` in env); a nonzero exit stops a script |
285
325
  | `/grep <pattern>` | Search scrollback for regex matches (case-insensitive, skips own output) |
286
326
  | `/cfg.info {--display}` | Write and show the project report (folder tree, config, buttons, log and history tails); also written at exit; `--display` opens it |
287
327
  | `/proto` | Open Proto picker (bare TUI) or list proto/ (bare CLI) |
@@ -291,31 +331,32 @@ The most common ones:
291
331
  | `/proto.list` | List .pro files in proto/, newest first, with size, age and each one's `name` |
292
332
  | `/proto.rename <old> <new>` | Rename a protocol script (`.pro` kept; never overwrites) |
293
333
  | `/proto.hex {on\|off\|toggle}` | Same flag as `/term.hex` |
294
- | `/proto.crc.list {pat}` | List available CRC algorithms (optional glob filter) |
334
+ | `/proto.crc.list {pat}` | List available CRC algorithms (optional name pattern: `modbus`, `crc16*`) |
295
335
  | `/proto.crc.info <name>` | Show CRC algorithm parameters and description |
296
336
  | `/proto.crc.calc <n> {d}` | Compute CRC over hex bytes, quoted text, or a file; omit data to verify check string |
297
337
  | `/proto.crc.find bin=<hex>\|asc=<text>\|cmd=<trigger>` | Identify CRC algorithm from a captured packet, text, or a command's reply |
298
338
  | `/proto.info` | Print current protocol state |
299
- | `/mem.dump <target> {len} {type}` | Hexdump or typed word columns at an address or symbol |
339
+ | `/mem.dump <target> {len} {type}` | Hexdump or typed word columns; columns follow the output level (bytes at quiet, +ASCII at normal, +address at verbose) |
300
340
  | `/mem.read <target> {type}` | One typed value: scalar, char, register field, bit or slice |
301
- | `/mem.write <target> <hex>` | Write hex bytes, or set a register field/bit (audited; destructive over MCP) |
341
+ | `/mem.write <target> <value>` | Write a value to a named symbol, register or field, or hex bytes at an address (audited; destructive over MCP) |
302
342
  | `/mem.or <target> <mask>` | Boolean ops on one word (also `.and`, `.clear`, `.xor`, `.not`); atomic via `MEM.M` where expressible |
303
343
  | `/mem.str <target> {max}` | Read a NUL-terminated string as a first-class value |
304
344
  | `/mem.info` | Memory access config: dialect, block limit, width, endian, atomic modify |
305
345
  | `/sym <addr\|name>` | Symbol table: name to address, or address to `name+offset` |
306
- | `/sym.import {file} {format=<value>}` | Convert a linker map to `sym/<cfg>.symbols.json` and load it (bare: re-import the same map) |
346
+ | `/sym.import {file} {format=<value>}` | Convert an ELF or a linker map to `sym/<cfg>.symbols.json` and load it (bare: re-import the same file) |
307
347
  | `/sym.info` | Show the loaded symbol table: file, source, counts by section, range |
308
348
  | `/sym.load {path}` | Load a symbol table (default: the cfg sidecar `/sym.import` writes) |
309
- | `/sym.search <pattern>` | Search symbols by name: exact, glob, regex, or substring |
349
+ | `/sym.search <pattern>` | Search symbols by name: the exact name, else a name pattern (`gpio`, `Mon*`) |
310
350
  | `/sym.unload` | Clear the loaded symbol table |
311
351
  | `/dev.import <file> {format=<value>} {category=<value>} {to=<value>} {use=on\|off}` | Convert a vendor register description (CMSIS-SVD) into this config's `lib/` and reference it from `dev/` (`to=global` shares it) |
312
352
  | `/dev.lib {pattern}` | List the parts the libraries hold (available, not loaded), with their layer |
313
353
  | `/dev.list` | List the devices this config has loaded, with layer and placement |
354
+ | `/dev.regs <device> {pattern}` | List a loaded device's registers from its file (never the chip), hazards flagged |
314
355
  | `/dev.use <part> {at=<value>}` | Add a library part to this config; `at=NAME@ADDR ...` places a relocatable one |
315
356
  | `/var {name}` | List user variables, or show one by name |
316
357
  | `/var.set <NAME> <value>` | Set a user variable |
317
358
  | `/var.clear` | Clear all user variables |
318
- | `/env.list {pattern}` | List environment variables (all, by name, or glob) |
359
+ | `/env.list {pattern}` | List environment variables (all, or a name pattern: `path`, `COM*`) |
319
360
  | `/env.set <name> <value>` | Set a session-scoped environment variable |
320
361
  | `/env.reload` | Re-snapshot variables from the OS environment |
321
362
  | `/cap.text <f> ...` | Capture serial text to file for a timed duration |
@@ -342,6 +383,7 @@ Everything termapy creates (configs, scripts, test files, plugins, logs) lives i
342
383
  ```text
343
384
  termapy_cfg/
344
385
  ├── plugin/ # global plugins (all configs), once you add one
386
+ ├── log/ # diagnostic log, one file per run: what went wrong, with tracebacks
345
387
  └── demo/
346
388
  ├── demo.cfg # config file
347
389
  ├── demo_legacy.profile.json # /mem.* through the device's own `mem` grammar
@@ -359,6 +401,7 @@ termapy_cfg/
359
401
  │ ├── temp_plot.py
360
402
  │ └── traffic.py
361
403
  ├── sym/ # symbol tables (demo.symbols.json, auto-loaded)
404
+ ├── dev/ # device files (console.device.json: the UART block CONSOLE names)
362
405
  └── proto/ # protocol test scripts
363
406
  ├── at_test.pro
364
407
  ├── bitfield_inline.pro
@@ -402,7 +445,7 @@ You can also manage environment variables at runtime with REPL commands:
402
445
 
403
446
  | Command | Description |
404
447
  | ----------------------- | -------------------------------------------------- |
405
- | `/env.list {pattern}` | List variables (all, by name, or glob like `COM*`) |
448
+ | `/env.list {pattern}` | List variables (all, or a name pattern: `COM*`) |
406
449
  | `/env.set <name> <val>` | Set a session-scoped variable (in-memory only) |
407
450
  | `/env.reload` | Re-snapshot variables from the OS environment |
408
451
 
@@ -455,7 +498,7 @@ Run `/run setup_modbus.run` then `/run test_registers.run`. The variables persis
455
498
  | `/var.set NAME val` | Set a variable (explicit command form) |
456
499
  | `/var.clear` | Clear all variables |
457
500
 
458
- **Scope:** Variables persist for the interactive session. They are automatically cleared when a script is launched from the Run picker, but *not* when `/run` is typed interactively or called within a script. This lets you run a setup script to define variables, then run a test script that uses them. Use `/var.clear` to reset manually.
501
+ **Scope:** Variables persist until a config loads, which starts clean. A script is not a load: it sees them however it was launched, and what it sets stays after it ends. This lets you run a setup script to define variables, then run a test script that uses them. Use `/var.clear` to reset manually.
459
502
 
460
503
  **Naming:** Variable names are case-sensitive (`$(PORT)` and `$(port)` are different variables). Names must start with a letter or underscore and contain only letters, digits, and underscores.
461
504
 
@@ -498,7 +541,7 @@ termapy --cfg-dir /path/to/configs
498
541
 
499
542
  ### Config validation
500
543
 
501
- Termapy validates config files on load and when saving from the editor. Invalid serial settings (baud rate, parity, data bits, stop bits, flow control, encoding) and unknown keys (typos) produce yellow warnings in the log window. Non-standard baud rates are flagged but allowed, since some hardware uses custom rates.
544
+ Termapy checks every key the same way on load, in the config editor and at `/cfg`. A bad value (a parity that does not exist, `max_lines` of 0, a regex that does not compile) produces a yellow warning on load, turns red in the editor and blocks its Save, and is refused by `/cfg` and `/cfg.auto`. Unknown keys (typos) warn too. Non-standard baud rates are flagged but allowed, since some hardware uses custom rates.
502
545
 
503
546
  To validate a config from the command line without launching the UI:
504
547
 
@@ -572,18 +615,9 @@ Set `serial.flow_control` to `"manual"` to get DTR, RTS, and Break buttons in th
572
615
  <!-- validate-config-keys -->
573
616
  ```json
574
617
  {
575
- "config_version": 30,
618
+ "config_version": 39,
576
619
  "title": "",
577
620
  "border_color": "",
578
- "max_lines": 10000,
579
- "default_ui": "tui",
580
- "vt100_hint": true,
581
- "cmd_prefix": "/",
582
- "cli_prompt": "$(CFG)> ",
583
- "cli_completion": true,
584
- "config_read_only": false,
585
- "profile_path": "",
586
- "validate_typed_args": false,
587
621
  "serial": {
588
622
  "port": "COM4",
589
623
  "baud_rate": 115200,
@@ -593,44 +627,65 @@ Set `serial.flow_control` to `"manual"` to get DTR, RTS, and Break buttons in th
593
627
  "stop_bits": 1,
594
628
  "flow_control": "none"
595
629
  },
596
- "encoding": "utf-8",
597
- "cmd_delay_ms": 0,
598
- "protocol": "text",
599
- "ndjson_field_routing": {
600
- "response_id": "id",
601
- "error_field": "error",
602
- "event_field": "event"
603
- },
604
- "default_response_timeout_ms": 1000,
605
630
  "auto_connect": false,
606
631
  "auto_reconnect": false,
607
632
  "on_connect_cmd": "",
608
633
  "tui_on_connect_cmd": "",
609
634
  "cli_on_connect_cmd": "",
610
635
  "mcp_on_connect_cmd": "",
636
+ "encoding": "utf-8",
611
637
  "eol": "\r",
638
+ "tx_char_delay_ms": 0,
639
+ "tx_line_delay_ms": 0,
640
+ "tx_chunking": true,
612
641
  "eol_rx": "auto",
642
+ "eol_markers": false,
613
643
  "send_bare_enter": false,
644
+ "cmd_delay_ms": 0,
645
+ "multiline_paste": true,
646
+ "multiline_paste_delay_ms": 10,
647
+ "control_keys": true,
614
648
  "echo": false,
615
649
  "echo_fmt": "[purple]$(CFG)> {cmd}[/]",
616
- "log_file": "",
617
- "show_traceback": false,
618
- "proto_frame_gap_ms": 50,
619
- "proto_results_template": "{name}_results.json",
620
650
  "timestamps": false,
621
- "eol_markers": false,
622
651
  "line_no": false,
623
652
  "hex": false,
653
+ "color": true,
654
+ "output_level": "normal",
655
+ "max_lines": 10000,
656
+ "max_grep_lines": 100,
657
+ "protocol": "text",
658
+ "ndjson_field_routing": {
659
+ "response_id": "id",
660
+ "error_field": "error",
661
+ "event_field": "event"
662
+ },
624
663
  "request_mode": false,
625
664
  "request_err_pattern": "(?i)^(ERROR|ERR|FAULT)\\b",
626
- "json_style": "compact",
627
665
  "strip_device_echo": false,
628
- "max_grep_lines": 100,
666
+ "json_fmt": {
667
+ "highlight": true,
668
+ "indent": 2
669
+ },
670
+ "profile_path": "",
671
+ "validate_typed_args": false,
672
+ "default_response_timeout_ms": 1000,
673
+ "log_file": "",
629
674
  "file_xfer_root": "",
675
+ "proto_frame_gap_ms": 50,
676
+ "proto_results_template": "{name}_results.json",
677
+ "default_ui": "tui",
678
+ "quiet_start": true,
679
+ "vt100_hint": true,
680
+ "cmd_prefix": "/",
681
+ "cli_prompt": "$(CFG)> ",
682
+ "cli_completion": true,
630
683
  "cfg_enabled": true,
631
684
  "run_enabled": true,
632
685
  "proto_enabled": true,
633
686
  "record_enabled": true,
687
+ "config_read_only": false,
688
+ "custom_buttons_side": "bottom",
634
689
  "custom_buttons": []
635
690
  }
636
691
  ```
@@ -639,7 +694,7 @@ See the **[config field reference](src/termapy/help/config.md#config-field-refer
639
694
 
640
695
  **Note on `eol_markers`:** This is a debug mode for troubleshooting line-ending mismatches (`\r` vs `\n` vs `\r\n`). When enabled, dim `\r` and `\n` markers appear inline in serial output before the characters are consumed by line splitting. Sent commands also show the configured line ending. Since the markers use ANSI escape sequences, they may interfere with device ANSI color output, so turn `eol_markers` off when not actively debugging.
641
696
 
642
- **Note on device color (ANSI):** The TUI and CLI render ANSI color (SGR) from device output inline, so colored log lines appear colored. termapy is line-oriented by design and does **not** emulate cursor addressing or full-screen redraws in the TUI - for devices that drive the terminal that way (menus, `top`/`vi` on an embedded console, bootloader UIs), use `--vt100` (see the VT100 mode section below), which hands raw bytes to your own terminal to emulate. In the CLI, `--no-color` (or `/term.color off`) strips color for clean piping. Over MCP, color defaults **off** so device ANSI is stripped from the JSON an agent receives (`/term.color on` re-enables passthrough); silence it at the source with the device's own `color off` in `mcp_on_connect_cmd`.
697
+ **Note on device color (ANSI):** The TUI and CLI render ANSI color (SGR) from device output inline, so colored log lines appear colored. termapy is line-oriented by design and does **not** emulate cursor addressing or full-screen redraws in the TUI - for devices that drive the terminal that way (menus, `top`/`vi` on an embedded console, bootloader UIs), use `--vt100` (see the VT100 mode section below), which hands raw bytes to your own terminal to emulate. `/term.color off` drops every color in either frontend, termapy's own included, and the CLI's `--no-color` starts it that way for clean piping. Over MCP, color defaults **off** so device ANSI is stripped from the JSON an agent receives (`/term.color on` re-enables passthrough); silence it at the source with the device's own `color off` in `mcp_on_connect_cmd`.
643
698
 
644
699
  </details>
645
700
 
@@ -682,6 +737,15 @@ Capture serial data to files without interrupting normal terminal display.
682
737
  /cap.bin raw.bin bytes=256 cmd=read_all
683
738
  ```
684
739
 
740
+ **Raw traffic log** (every byte in both directions, through pyserial's `spy://`):
741
+
742
+ ```sh
743
+ /port spy://COM3?file=traffic.txt # reopens the port and logs to cap/traffic.txt
744
+ /port COM3 # reopens it again, and logging stops
745
+ ```
746
+
747
+ Or put the URL in the config's `port` key. [Logging the raw traffic](src/termapy/help/ports.md#logging-the-raw-traffic) shows the format and what to expect.
748
+
685
749
  **Structured capture** (binary data decoded via format spec to CSV):
686
750
 
687
751
  ```sh
@@ -907,7 +971,7 @@ The device supports a full AT command set. Type commands and get responses just
907
971
  | `AT+STATUS` | Device status (LED, uptime, connections) |
908
972
  | `AT+RESET` | Reset device (simulates boot sequence) |
909
973
  | `mem <addr> [len]` | Hex memory dump (deterministic, max 256 bytes) |
910
- | `help` | List all commands |
974
+ | `help` | The command landscape, grouped |
911
975
 
912
976
  #### GPS / NMEA commands
913
977
 
@@ -996,7 +1060,7 @@ termapy --vt100 --demo # no hardware: an interactive ANSI menu/dashboard
996
1060
 
997
1061
  `--vt100 --demo` connects to a simulated VT100 device that draws a colored, cursor-addressed menu (arrow keys to move, Enter to open) and a live status dashboard - the quickest way to see what passthrough buys you over plain line output. Quit with Ctrl-].
998
1062
 
999
- It's a peer of CLI and TUI mode: set `"default_ui": "vt100"` in a config to make it the default, and `--vt100` overrides the config the same way `--cli` does. The byte pump is the vendored pyserial `miniterm`, which enables VT processing on Windows 10+ automatically.
1063
+ It's a peer of CLI and TUI mode: set `"default_ui": "vt100"` in a config to make it the default, and `--vt100` overrides the config the same way `--cli` does. The port is termapy's own serial engine, as in every mode; the console is the vendored pyserial `miniterm`, which enables VT processing on Windows 10+ automatically. It writes the TUI's session log, `<cfg>.log`: received lines only, since in passthrough each key goes to the device as typed and the device's echo is the record.
1000
1064
 
1001
1065
  It's also a reversible toggle from inside the TUI, like `/cli` <-> `/tui`: `/vt100` hands the current device to a passthrough terminal, and `/demo.vt100` jumps to the widget tour. In both cases Ctrl-] returns you to the TUI (when launched from the shell with `--vt100`, Ctrl-] quits instead).
1002
1066
 
@@ -1011,7 +1075,7 @@ It's also a reversible toggle from inside the TUI, like `/cli` <-> `/tui`: `/vt1
1011
1075
 
1012
1076
  ### Symbols, memory and parts
1013
1077
 
1014
- `/sym.import build/mem.map` turns your linker map into names, so `/mem.read gTemp` reads a variable by name instead of by address. `/dev.import part.svd` does the same for the silicon: a vendor CMSIS-SVD becomes a **device file** -- every register of the part with its bit fields -- stored once in the config's `lib/` and referenced from its `dev/`, so `/mem.read PORT_GROUP0_DIR` works and a checked-in config folder carries its parts. A part on the external bus (two ADCs, an FPGA block) is written once with register offsets and placed per board: `/dev.use acme-adc16 at=ADC1@0x60000000 ADC2@0x60001000`. Registers are live silicon, not variables, so `/mem.*` refuses bulk reads over them, refuses reads of write-only registers, and logs the rest. The device side is the MEM wire spec (`examples/firmware/termapy_mem.c`, a drop-in) or a profile block describing your monitor's own peek/poke grammar. See the Symbols, Devices and Memory help pages.
1078
+ `/sym.import out/default.elf` turns your build into names, sizes and C types (from its debug info), so `/mem.read gTemp` reads a variable by name instead of by address, signed or float as declared; a linker map works too, with names and sizes only. A `const` in the build keeps its value, and a pointer constant to a peripheral names its registers under your own name (`SPI_PORT_DIR` for `PORTC_DIR`). `/dev.import part.svd` does the same for the silicon: a vendor CMSIS-SVD becomes a **device file** -- every register of the part with its bit fields -- stored once in the config's `lib/` and referenced from its `dev/`, so `/mem.read PORT_GROUP0_DIR` works and a checked-in config folder carries its parts. A part on the external bus (two ADCs, an FPGA block) is written once with register offsets and placed per board: `/dev.use acme-adc16 at=ADC1@0x60000000 ADC2@0x60001000`. Registers are live silicon, not variables, so `/mem.*` refuses bulk reads over them, refuses reads of write-only registers, and logs the rest. The device side is the MEM wire spec (`/firmware.copy mem` writes the drop-in `termapy_mem.c` into your tree) or a profile block describing your monitor's own peek/poke grammar. See the Symbols, Devices and Memory help pages.
1015
1079
 
1016
1080
  ### Plugins
1017
1081
 
@@ -1021,12 +1085,13 @@ Add custom REPL commands by dropping a `.py` file in a plugin folder. No classes
1021
1085
 
1022
1086
  ```python
1023
1087
  # hello.py - drop into termapy_cfg/plugin/ or termapy_cfg/<config>/plugin/
1024
- from termapy.plugins import Command, PluginContext
1088
+ from termapy.plugins import CmdResult, Command, PluginContext
1025
1089
 
1026
1090
 
1027
- def _handler(ctx: PluginContext, args: str):
1091
+ def _handler(ctx: PluginContext, args: str) -> CmdResult:
1028
1092
  name = args.strip() or "world"
1029
1093
  ctx.io.result(f"Hello, {name}!")
1094
+ return CmdResult.ok(value=name)
1030
1095
 
1031
1096
 
1032
1097
  # ── COMMAND (must be at end of file) ──────────────────────────────────────────
@@ -1047,7 +1112,7 @@ COMMAND = Command(
1047
1112
 
1048
1113
  Resolution is the same in every frontend (TUI, CLI, MCP server) and reruns on every config switch; a folder plugin can never take an app hook's name.
1049
1114
 
1050
- Subcommands (`/tool.run`, `/tool.status`), typed parameters, scriptable return values, the full `PluginContext` API with its five handles and capability gating, and the `ctx.internal` escape hatch that built-ins use are all in the [Writing plugins](src/termapy/help/writing-plugins.md) guide, which also ships in the in-app help.
1115
+ Subcommands (`/tool.run`, `/tool.status`), typed parameters, scriptable return values, the full `PluginContext` API with its five handles and capability gating, and `ctx.internal`, the engine and host services every plugin may use, are all in the [Writing plugins](src/termapy/help/writing-plugins.md) guide, which also ships in the in-app help.
1051
1116
 
1052
1117
  <details>
1053
1118
  <summary>Example plugins</summary>
@@ -1058,7 +1123,6 @@ See `examples/plugins/` for working examples:
1058
1123
  - **at_test.py:** send AT commands over serial
1059
1124
  - **timestamp.py:** print the current date/time
1060
1125
  - **ping.py:** send a command and measure response time
1061
- - **traffic.py:** passive RX/TX byte tap (count, hexdump, rate, snoop) -- also shipped with `--demo`
1062
1126
 
1063
1127
  More complete examples ship with `--demo`: `probe.py` demonstrates the drain → write → read → parse cycle for device interaction; `traffic.py` (with `/traffic.count`, `/traffic.hexdump`, `/traffic.rate`, `/traffic.snoop`) demonstrates the passive RX/TX observer pattern via the `ctx.serial.rx_observer()` / `ctx.serial.tx_observer()` context managers. Run `/help probe` or `/help traffic` to see the documentation, or `/help.dev <name>` for the source docstrings.
1064
1128
 
@@ -1212,7 +1276,7 @@ Every command runs on a worker thread, the serial reader is the only long-lived
1212
1276
  </details>
1213
1277
 
1214
1278
  <details>
1215
- <summary><strong>Test coverage</strong> - 5077 tests</summary>
1279
+ <summary><strong>Test coverage</strong> - 6993 tests</summary>
1216
1280
 
1217
1281
  Run the full suite with `uv run pytest`. (The count above is the one place it
1218
1282
  is tracked; `release_prep` refreshes it each release.) The coverage figure is