termapy 0.75.0__tar.gz → 0.76.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 (344) hide show
  1. {termapy-0.75.0 → termapy-0.76.0}/PKG-INFO +47 -41
  2. {termapy-0.75.0 → termapy-0.76.0}/README.md +46 -40
  3. {termapy-0.75.0 → termapy-0.76.0}/pyproject.toml +1 -1
  4. {termapy-0.75.0 → termapy-0.76.0}/pyproject.toml.orig +1 -1
  5. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/app.py +55 -0
  6. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/credits.py +29 -15
  7. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/plugin/traffic.py +1 -1
  8. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/doc_screenshots.run +3 -2
  9. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/config.py +79 -0
  10. termapy-0.76.0/src/termapy/credits_data.py +181 -0
  11. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/_common.py +43 -3
  12. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/config_picker.py +50 -24
  13. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/filename_dialog.py +5 -1
  14. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/proto_picker.py +20 -6
  15. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/script_picker.py +29 -8
  16. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/entry.py +1 -1
  17. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/folder_ops.py +68 -1
  18. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/acknowledgments.md +29 -15
  19. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/authoring-profiles.md +10 -10
  20. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/cli.md +13 -5
  21. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/commands.md +28 -21
  22. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/config.md +11 -4
  23. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/custom-buttons.md +3 -2
  24. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/data-capture.md +7 -2
  25. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/demo.md +15 -12
  26. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/device-help.md +2 -2
  27. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/environment.md +3 -3
  28. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/file-transfer.md +1 -0
  29. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/getting-started.md +14 -8
  30. termapy-0.76.0/src/termapy/help/img/doc_21_script_picker.svg +213 -0
  31. termapy-0.76.0/src/termapy/help/img/doc_37_config_picker.svg +213 -0
  32. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/index.md +4 -2
  33. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/installation.md +132 -132
  34. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/mcp-server.md +11 -1
  35. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/ports.md +4 -3
  36. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/protocol-testing.md +60 -31
  37. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/scripting.md +14 -8
  38. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/serial-tools.md +42 -34
  39. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/toolbar.md +17 -12
  40. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/using-git.md +109 -110
  41. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/variables.md +13 -7
  42. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/vt100.md +2 -1
  43. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/writing-plugins.md +47 -8
  44. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help_tooltip.py +13 -17
  45. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/404.html +5 -5
  46. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/acknowledgments.html +35 -20
  47. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/authoring-profiles.html +15 -15
  48. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/cli.html +33 -10
  49. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/commands.html +41 -40
  50. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/config.html +14 -9
  51. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/custom-buttons.html +8 -7
  52. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/data-capture.html +11 -7
  53. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/demo.html +30 -18
  54. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/device-help.html +7 -7
  55. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/environment.html +8 -8
  56. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/file-transfer.html +6 -5
  57. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/getting-started.html +21 -16
  58. termapy-0.76.0/src/termapy/html/img/doc_21_script_picker.svg +213 -0
  59. termapy-0.76.0/src/termapy/html/img/doc_37_config_picker.svg +213 -0
  60. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/index.html +9 -7
  61. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/installation.html +7 -7
  62. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/mcp-server.html +36 -6
  63. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/on-ai-assistance.html +5 -5
  64. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/ports.html +9 -8
  65. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/protocol-testing.html +100 -40
  66. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/scripting.html +24 -15
  67. termapy-0.76.0/src/termapy/html/search.json +1 -0
  68. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/serial-tools.html +45 -39
  69. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/toolbar.html +38 -28
  70. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/using-git.html +12 -13
  71. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/variables.html +35 -13
  72. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/vt100.html +7 -6
  73. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/writing-plugins.html +185 -126
  74. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/pickers.py +44 -5
  75. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/__init__.py +1 -1
  76. termapy-0.75.0/src/termapy/help/img/doc_21_script_picker.svg +0 -209
  77. termapy-0.75.0/src/termapy/html/img/doc_21_script_picker.svg +0 -209
  78. termapy-0.75.0/src/termapy/html/search.json +0 -1
  79. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/__init__.py +0 -0
  80. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/__main__.py +0 -0
  81. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/app_dirs.py +0 -0
  82. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/app_hooks.py +0 -0
  83. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/__init__.py +0 -0
  84. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/_cfg_icon.py +0 -0
  85. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/_crc_verbs.py +0 -0
  86. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/_run_record.py +0 -0
  87. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/_xmodem_handlers.py +0 -0
  88. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/_ymodem_handlers.py +0 -0
  89. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/app.py +0 -0
  90. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/cap.py +0 -0
  91. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/cfg.py +0 -0
  92. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/cls.py +0 -0
  93. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/confirm.py +0 -0
  94. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/edit.py +0 -0
  95. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/env.py +0 -0
  96. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/exit.py +0 -0
  97. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/find.py +0 -0
  98. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/grep.py +0 -0
  99. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/help.py +0 -0
  100. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/log.py +0 -0
  101. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/mcp.py +0 -0
  102. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/os_cmd.py +0 -0
  103. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/ping.py +0 -0
  104. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/plugin.py +0 -0
  105. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/port.py +0 -0
  106. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/print.py +0 -0
  107. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/profile.py +0 -0
  108. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/proto.py +0 -0
  109. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/repeat.py +0 -0
  110. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/run.py +0 -0
  111. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/run_edit.py +0 -0
  112. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/search.py +0 -0
  113. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/seq.py +0 -0
  114. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/show.py +0 -0
  115. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/ss.py +0 -0
  116. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/stop.py +0 -0
  117. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/term.py +0 -0
  118. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/var.py +0 -0
  119. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/commands/xfer.py +0 -0
  120. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/crc/__init__.py +0 -0
  121. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/crc/sum16.py +0 -0
  122. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/crc/sum8.py +0 -0
  123. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/.gitignore +0 -0
  124. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/__init__.py +0 -0
  125. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/demo.cfg +0 -0
  126. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/demo.profile.json +0 -0
  127. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/demo_ndjson.profile.json +0 -0
  128. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/plugin/__init__.py +0 -0
  129. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/plugin/cmd.py +0 -0
  130. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/plugin/probe.py +0 -0
  131. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/plugin/temp_plot.py +0 -0
  132. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/proto/at_test.pro +0 -0
  133. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/proto/bitfield_inline.pro +0 -0
  134. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/proto/modbus_inline.pro +0 -0
  135. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/at_demo.run +0 -0
  136. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/crc_tour.run +0 -0
  137. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/expect_test.run +0 -0
  138. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/gps_demo.run +0 -0
  139. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/smoke_test.run +0 -0
  140. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/status_check.run +0 -0
  141. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/var_demo.run +0 -0
  142. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/demo/run/welcome.run +0 -0
  143. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/viz/__init__.py +0 -0
  144. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/viz/hex_view.py +0 -0
  145. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/viz/modbus_view.py.old +0 -0
  146. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/builtins/viz/text_view.py +0 -0
  147. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/capture.py +0 -0
  148. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/capture_view.py +0 -0
  149. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/cli.py +0 -0
  150. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/cli_flags.py +0 -0
  151. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/config_resolve.py +0 -0
  152. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/defaults.py +0 -0
  153. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/demo.py +0 -0
  154. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/demo_ndjson.py +0 -0
  155. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/demo_vt100.py +0 -0
  156. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/__init__.py +0 -0
  157. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/cfg_confirm.py +0 -0
  158. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/config_editor.py +0 -0
  159. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/confirm_dialog.py +0 -0
  160. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/name_picker.py +0 -0
  161. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/port_picker.py +0 -0
  162. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/proto_editor.py +0 -0
  163. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/quick_setup.py +0 -0
  164. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/script_editor.py +0 -0
  165. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/set_var_dialog.py +0 -0
  166. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/update_available.py +0 -0
  167. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/dialogs/welcome_dialog.py +0 -0
  168. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/env_flags.py +0 -0
  169. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/folders.py +0 -0
  170. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/.coverage +0 -0
  171. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_01_main_tui.svg +0 -0
  172. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_02_help.svg +0 -0
  173. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_03_help_proto.svg +0 -0
  174. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_04_proto_send.svg +0 -0
  175. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_05_proto_crc.svg +0 -0
  176. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_06_proto_delay.svg +0 -0
  177. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_07_crc_python.svg +0 -0
  178. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_08_variables.svg +0 -0
  179. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_09_target_help.svg +0 -0
  180. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_10_config_info.svg +0 -0
  181. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_11_proto_run.svg +0 -0
  182. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_12_cap_struct.svg +0 -0
  183. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_13_cap_progress.svg +0 -0
  184. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_14_port_list.svg +0 -0
  185. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_15_xfer.svg +0 -0
  186. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_16_toolbar.svg +0 -0
  187. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_17_proto_debug.svg +0 -0
  188. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_20_palette.svg +0 -0
  189. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_22_script_editor.svg +0 -0
  190. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_23_config_editor.svg +0 -0
  191. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_24_cmd_picker.svg +0 -0
  192. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_30_new_cfg.png +0 -0
  193. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_31_cli_completion.png +0 -0
  194. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_32_port_picker.png +0 -0
  195. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_33_port_tooltip.png +0 -0
  196. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_34_latency_timer.png +0 -0
  197. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_35_vt100_menu.png +0 -0
  198. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/img/doc_36_vt100_status.png +0 -0
  199. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help/on-ai-assistance.md +0 -0
  200. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/help_dynamic.py +0 -0
  201. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/history_nav.py +0 -0
  202. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/.coverage +0 -0
  203. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/images/favicon.png +0 -0
  204. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/javascripts/LICENSE +0 -0
  205. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/javascripts/bundle.49251538.min.js +0 -0
  206. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/javascripts/workers/search.7d14d953.min.js +0 -0
  207. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/stylesheets/classic/main.38807bfb.min.css +0 -0
  208. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/stylesheets/classic/palette.c7ab7c71.min.css +0 -0
  209. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/stylesheets/modern/main.5da3a30f.min.css +0 -0
  210. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/assets/stylesheets/modern/palette.812a03bb.min.css +0 -0
  211. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_01_main_tui.svg +0 -0
  212. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_02_help.svg +0 -0
  213. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_03_help_proto.svg +0 -0
  214. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_04_proto_send.svg +0 -0
  215. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_05_proto_crc.svg +0 -0
  216. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_06_proto_delay.svg +0 -0
  217. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_07_crc_python.svg +0 -0
  218. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_08_variables.svg +0 -0
  219. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_09_target_help.svg +0 -0
  220. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_10_config_info.svg +0 -0
  221. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_11_proto_run.svg +0 -0
  222. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_12_cap_struct.svg +0 -0
  223. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_13_cap_progress.svg +0 -0
  224. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_14_port_list.svg +0 -0
  225. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_15_xfer.svg +0 -0
  226. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_16_toolbar.svg +0 -0
  227. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_17_proto_debug.svg +0 -0
  228. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_20_palette.svg +0 -0
  229. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_22_script_editor.svg +0 -0
  230. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_23_config_editor.svg +0 -0
  231. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_24_cmd_picker.svg +0 -0
  232. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_30_new_cfg.png +0 -0
  233. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_31_cli_completion.png +0 -0
  234. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_32_port_picker.png +0 -0
  235. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_33_port_tooltip.png +0 -0
  236. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_34_latency_timer.png +0 -0
  237. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_35_vt100_menu.png +0 -0
  238. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/img/doc_36_vt100_status.png +0 -0
  239. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/objects.inv +0 -0
  240. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/html/sitemap.xml +0 -0
  241. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/info_views.py +0 -0
  242. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/install_info.py +0 -0
  243. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/legacy.py +0 -0
  244. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/mcp/__init__.py +0 -0
  245. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/mcp/catalog.py +0 -0
  246. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/mcp/prompts.py +0 -0
  247. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/mcp/server.py +0 -0
  248. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/migration.py +0 -0
  249. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/palette_provider.py +0 -0
  250. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/capabilities.py +0 -0
  251. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/command.py +0 -0
  252. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/context.py +0 -0
  253. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/__init__.py +0 -0
  254. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/fs.py +0 -0
  255. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/internal.py +0 -0
  256. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/io.py +0 -0
  257. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/serial.py +0 -0
  258. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/handles/ui.py +0 -0
  259. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/loader.py +0 -0
  260. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/output_levels.py +0 -0
  261. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/plugins/params.py +0 -0
  262. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/port_control.py +0 -0
  263. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/port_format.py +0 -0
  264. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/profile/__init__.py +0 -0
  265. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/profile/loader.py +0 -0
  266. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/profile/matcher.py +0 -0
  267. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/profile/schema.json +0 -0
  268. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/profile/types.py +0 -0
  269. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/proto_debug.py +0 -0
  270. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/protocol/__init__.py +0 -0
  271. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/protocol/core.py +0 -0
  272. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/protocol/crc.py +0 -0
  273. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/protocol/runner.py +0 -0
  274. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/protocol/viz.py +0 -0
  275. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/repl.py +0 -0
  276. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/request_response.py +0 -0
  277. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/response_parsers.py +0 -0
  278. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/run_docstring.py +0 -0
  279. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/run_legacy.py +0 -0
  280. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/run_profile_hooks.py +0 -0
  281. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/scripting.py +0 -0
  282. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/serial_engine.py +0 -0
  283. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/serial_port.py +0 -0
  284. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/smoke.txt +0 -0
  285. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/icons/termapy.icns +0 -0
  286. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/icons/termapy.ico +0 -0
  287. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/icons/termapy.png +0 -0
  288. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/icons/termapy.svg +0 -0
  289. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/linux/termapy.desktop.template +0 -0
  290. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/macos/Termapy.app/Contents/Info.plist +0 -0
  291. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/templates/macos/Termapy.app/Contents/MacOS/launcher.template +0 -0
  292. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/terminal_host.py +0 -0
  293. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/title_bar.py +0 -0
  294. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/tree_render.py +0 -0
  295. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/update_check.py +0 -0
  296. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb/__init__.py +0 -0
  297. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb/_vendors_full.py +0 -0
  298. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb/aliases.py +0 -0
  299. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb/chips.py +0 -0
  300. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb/vendors.py +0 -0
  301. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/usb_tree.py +0 -0
  302. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/variables.py +0 -0
  303. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/LICENSES.md +0 -0
  304. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/__init__.py +0 -0
  305. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/__init__.py +0 -0
  306. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/__main__.py +0 -0
  307. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/rfc2217.py +0 -0
  308. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/rs485.py +0 -0
  309. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/serialcli.py +0 -0
  310. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/serialjava.py +0 -0
  311. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/serialposix.py +0 -0
  312. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/serialutil.py +0 -0
  313. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/serialwin32.py +0 -0
  314. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/threaded/__init__.py +0 -0
  315. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/__init__.py +0 -0
  316. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/hexlify_codec.py +0 -0
  317. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports.py +0 -0
  318. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports_common.py +0 -0
  319. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports_linux.py +0 -0
  320. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports_osx.py +0 -0
  321. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports_posix.py +0 -0
  322. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/list_ports_windows.py +0 -0
  323. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/tools/miniterm.py +0 -0
  324. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/__init__.py +0 -0
  325. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_alt.py +0 -0
  326. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_cp2110.py +0 -0
  327. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_hwgrep.py +0 -0
  328. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_loop.py +0 -0
  329. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_rfc2217.py +0 -0
  330. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_socket.py +0 -0
  331. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/urlhandler/protocol_spy.py +0 -0
  332. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/serial/win32.py +0 -0
  333. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/xmodem.py +0 -0
  334. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/CRC.py +0 -0
  335. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/Platform.py +0 -0
  336. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/Protocol.py +0 -0
  337. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/Socket.py +0 -0
  338. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/Version.py +0 -0
  339. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vendor/ymodem/__init__.py +0 -0
  340. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/vt100.py +0 -0
  341. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/widgets/__init__.py +0 -0
  342. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/widgets/checkbox.py +0 -0
  343. {termapy-0.75.0 → termapy-0.76.0}/src/termapy/widgets/status_bar.py +0 -0
  344. {termapy-0.75.0 → termapy-0.76.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.75.0
3
+ Version: 0.76.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
@@ -58,7 +58,7 @@ Runs on Windows, macOS, and Linux. A serial interface terminal like PuTTY or Ter
58
58
 
59
59
  Low time commitment: about 1 minute from scratch, or under 10 seconds if you already have [uv](https://docs.astral.sh/uv/) installed.
60
60
 
61
- ![termapy screenshot](img/main.png)
61
+ ![termapy screenshot](src/termapy/help/img/doc_01_main_tui.svg)
62
62
 
63
63
  ## Install and connect
64
64
 
@@ -109,7 +109,7 @@ There's a lot more: scripting, binary protocol testing, every CRC algorithm in t
109
109
 
110
110
  1. **Connect:** click the port button in the title bar, pick your COM port, click the status button to connect (it turns green)
111
111
  2. **Type:** enter commands in the input box at the bottom and press Enter
112
- 3. **Change settings:** click `Cfg` to edit port, baud rate, and other settings through the UI
112
+ 3. **Change settings:** click the config name in the title bar (or `Cfg` → `Edit`) to change port, baud rate, and other settings through the UI
113
113
 
114
114
  Everything works through the UI. No config files to edit unless you want to.
115
115
 
@@ -164,6 +164,7 @@ Termapy runs with your privileges and does whatever you — or a connected MCP c
164
164
  | Ctrl+S | Save SVG screenshot |
165
165
  | Ctrl+T | Save text screenshot |
166
166
  | Ctrl+P | Command palette |
167
+ | F1–F4 | Help / Cfg / Run / Proto buttons (Ctrl+Shift+1–4 in VS Code); F10 edits the config |
167
168
  | Up/Down | Cycle through command history |
168
169
  | Escape | Clear input / exit history browsing |
169
170
  | Right | Accept type-ahead suggestion |
@@ -176,10 +177,11 @@ macOS Option-as-Meta, KVM cross-platform keyboards, etc.).
176
177
 
177
178
  | Button | Action |
178
179
  | ------ | ------------------------------------------------------------------- |
179
- | `?` | Open the help guide |
180
- | `#` | Toggle line numbers (green when active) |
181
- | `Cfg` | Open the config picker |
182
- | `Run` | Open the script picker |
180
+ | `Help` | Open the help guide |
181
+ | `Cfg` | Open the config picker (Load / Edit / New / Rename / Delete) |
182
+ | `Run` | Open the script picker (Run / Edit / New / Rename / Delete) |
183
+ | `Proto`| Open the protocol-test picker |
184
+ | `Update` | Appears only when a newer termapy is on PyPI |
183
185
  | Center | Click to edit the current config |
184
186
  | Port | Click to select a serial port |
185
187
  | Status | Click to connect/disconnect (red = disconnected, green = connected) |
@@ -200,7 +202,7 @@ The most common ones:
200
202
  | `/ss.svg [name]` | Save SVG screenshot |
201
203
  | `/cls` | Clear the terminal |
202
204
  | `/run {filename}` | Open Run picker (bare TUI), or run a named script |
203
- | `/term.echo [on \| off]` | Toggle command echo |
205
+ | `/term.echo [on \| off]` | Local echo of device commands sent to the wire |
204
206
  | `/grep <pattern>` | Search scrollback |
205
207
  | `/exit` | Exit termapy |
206
208
 
@@ -232,17 +234,18 @@ The most common ones:
232
234
  | `/port.break {ms}` | Send break signal (default 250ms) |
233
235
  | `/cfg [key [value]]` | Open Cfg picker (bare TUI), dump JSON (bare CLI), or get/set with args |
234
236
  | `/cfg.auto <key> <value>` | Set an in-memory config key immediately (no confirmation) |
235
- | `/cfg.configs` | List all config files |
237
+ | `/cfg.list` | List all config files |
236
238
  | `/cfg.load <name>` | Switch to a different config by name |
237
239
  | `/cfg.show` | Open the current config file in the system viewer |
238
240
  | `/cfg.help` | Same as `/help cfg` |
239
241
  | `/ss.svg [name]` | Save SVG screenshot |
240
242
  | `/ss.txt [name]` | Save text screenshot |
241
- | `/ss.dir` | Show the screenshot folder |
243
+ | `/ss.list` | List screenshots, newest first, with size and age |
244
+ | `/ss.explore` | Open the screenshot folder in the system file explorer |
242
245
  | `/cls` | Clear the terminal screen |
243
- | `/run {filename} {-v}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep |
246
+ | `/run {filename}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep |
244
247
  | `/run.list` | List .run files in run/, newest first, with size, age, and summary |
245
- | `/run.load <filename>` | Run a script file (same as /run) |
248
+ | `/run.rename <old> <new>` | Rename a script (`.run` kept; never overwrites) |
246
249
  | `/run.help` | Same as `/help run` |
247
250
  | `/delay <duration>` | Wait for a duration (e.g. `500ms`, `1.5s`) |
248
251
  | `/confirm {message}` | Show Yes/Cancel dialog; Cancel stops a running script (see `at_demo.run`) |
@@ -255,8 +258,8 @@ The most common ones:
255
258
  | `/show.cfg` | Show the current config file |
256
259
  | `/term` | Terminal display / session toggles (echo, line_no, timestamps, ...) |
257
260
  | `/term.info` | Snapshot the state of every `/term.*` toggle |
258
- | `/term.echo [on \| off]` | Toggle REPL command echo |
259
- | `/term.echo.silent <on \| off>` | Set echo on/off without echoing the change (for scripts and on_connect_cmd) |
261
+ | `/term.echo [on \| off]` | Local echo of device commands sent to the wire (persisted via cfg `echo`) |
262
+ | `/term.echo_repl [on \| off]` | Local echo of REPL (slash) commands, session only; off inside scripts |
260
263
  | `/term.line_no [on \| off]` | Toggle line numbers in serial output (TUI only) |
261
264
  | `/term.eol.markers [on \| off]` | Toggle visible `\r` `\n` markers for line-ending troubleshooting |
262
265
  | `/term.output {level}` | Show or set output level (silent/quiet/normal/verbose) |
@@ -270,20 +273,19 @@ The most common ones:
270
273
  | `/edit.info` | Open the info report in the system viewer |
271
274
  | `/os <cmd>` | Run a shell command (10s timeout, requires `TERMAPY_OS_CMD_ENABLED=1` in env) |
272
275
  | `/grep <pattern>` | Search scrollback for regex matches (case-insensitive, skips own output) |
273
- | `/cfg.info {--display}` | Show project summary; `--display` opens full report in system viewer |
274
- | `/cfg.files` | Show project directory tree |
276
+ | `/cfg.info {--display}` | Show project summary (folder tree + config + buttons); `--display` opens the full report |
275
277
  | `/proto` | Open Proto picker (bare TUI) or show long-help (bare CLI) |
276
278
  | `/proto.help` | Same as `/help proto` |
277
279
  | `/proto.send <hex>` | Send raw hex bytes and/or quoted text, display response as hex (see below) |
278
280
  | `/proto.run <file>` | Run a binary protocol test script (.pro) with pass/fail |
279
281
  | `/proto.list` | List .pro files in proto/, newest first, with size and age |
280
- | `/proto.load <file>` | Run a protocol test script (same as /proto.run) |
282
+ | `/proto.rename <old> <new>` | Rename a protocol script (`.pro` kept; never overwrites) |
281
283
  | `/proto.hex [on \| off]` | Toggle hex display mode for serial I/O |
282
284
  | `/proto.crc.list {pat}` | List available CRC algorithms (optional glob filter) |
283
285
  | `/proto.crc.info <name>` | Show CRC algorithm parameters and description |
284
286
  | `/proto.crc.calc <n> {d}` | Compute CRC over hex bytes, text, or file; omit data to verify check string |
285
287
  | `/proto.crc.find <pkt>` | Identify CRC algorithm from a captured packet (bin= hex or asc= text) |
286
- | `/proto.status` | Show current protocol mode state |
288
+ | `/proto.info` | Print current protocol state |
287
289
  | `/var {name}` | List user variables, or show one by name |
288
290
  | `/var.set <NAME> <value>` | Set a user variable |
289
291
  | `/var.clear` | Clear all user variables |
@@ -317,18 +319,21 @@ termapy_cfg/
317
319
  └── demo/
318
320
  ├── demo.cfg # config file
319
321
  ├── demo.log # session log
320
- ├── .cmd_history.txt # command history
322
+ ├── demo.history # command history
321
323
  ├── ss/ # screenshots
322
324
  ├── run/ # script files for /run
323
325
  │ ├── at_demo.run
324
326
  │ ├── smoke_test.run
325
- │ └── status_check.run
327
+ │ ├── status_check.run
328
+ │ └── ... # gps_demo, var_demo, expect_test, crc_tour, ...
326
329
  ├── plugin/ # per-config plugins
327
330
  │ ├── cmd.py
328
331
  │ ├── probe.py
329
332
  │ ├── temp_plot.py
330
333
  │ └── traffic.py
331
334
  ├── cap/ # data capture output files
335
+ ├── prof/ # /run.profile timing CSVs
336
+ ├── viz/ # per-config packet visualizers
332
337
  └── proto/ # protocol test scripts
333
338
  ├── at_test.pro
334
339
  ├── bitfield_inline.pro
@@ -426,7 +431,7 @@ Run `/run setup_modbus.run` then `/run test_registers.run`. The variables persis
426
431
  | `/var.set NAME val` | Set a variable (explicit command form) |
427
432
  | `/var.clear` | Clear all variables |
428
433
 
429
- **Scope:** Variables persist for the interactive session. They are automatically cleared when a script is launched from the Scripts button or Run menu, 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.
434
+ **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.
430
435
 
431
436
  **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.
432
437
 
@@ -435,7 +440,7 @@ Run `/run setup_modbus.run` then `/run test_registers.run`. The variables persis
435
440
  | Variable | Set when | Updates? |
436
441
  | --------------------- | ------------------------------------------- | -------------------- |
437
442
  | `$(LAUNCH_DATETIME)` | App starts | Never - frozen |
438
- | `$(SESSION_DATETIME)` | Script launched (Scripts button / Run menu) | Per script launch |
443
+ | `$(SESSION_DATETIME)` | Script launched (Run picker) | Per script launch |
439
444
  | `$(DATETIME)` | Every expansion | Always current clock |
440
445
 
441
446
  Each group also has `_DATE` and `_TIME` variants (e.g. `$(LAUNCH_DATE)`, `$(SESSION_TIME)`).
@@ -451,7 +456,7 @@ Add a `.gitignore` for session files you don't need to track:
451
456
  ```gitignore
452
457
  # termapy_cfg - keep configs and scripts, ignore session files
453
458
  termapy_cfg/*/*.log
454
- termapy_cfg/*/.cmd_history.txt
459
+ termapy_cfg/*/*.history
455
460
  termapy_cfg/*/ss/
456
461
  ```
457
462
 
@@ -612,7 +617,7 @@ See the **[config field reference](src/termapy/help/config.md#config-field-refer
612
617
 
613
618
  **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.
614
619
 
615
- **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 `color off` in `mcp_on_connect_cmd`.
620
+ **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`.
616
621
 
617
622
  </details>
618
623
 
@@ -621,9 +626,9 @@ See the **[config field reference](src/termapy/help/config.md#config-field-refer
621
626
  <details>
622
627
  <summary><strong>Scripting</strong> - automate command sequences with text files</summary>
623
628
 
624
- ![Run menu / script picker dialog](img/run.png)
629
+ ![Run picker: newest first, with size, updated, and docstring summary](src/termapy/help/img/doc_21_script_picker.svg)
625
630
 
626
- Create text files with one command per line and run them from the Run button or with the `/run` or the Scripts button. IN the file ines starting with `/` are REPL commands, lines starting with `#` are comments and everything else is sent to the device.
631
+ Create text files with one command per line and run them from the **Run** button or with `/run`. In the file, lines starting with `/` are REPL commands, lines starting with `#` are comments and everything else is sent to the device.
627
632
 
628
633
  ```text
629
634
  # Quick status check
@@ -843,7 +848,7 @@ Summary: 4/4 PASS (4 tests)
843
848
 
844
849
  ### CRC algorithms
845
850
 
846
- Every CRC algorithm in the [reveng catalog](https://reveng.sourceforge.io/crc-catalogue/all.htm) (maintained by Greg Cook -- see [ACKNOWLEDGMENTS](src/termapy/help/acknowledgments.md)) is built in, with full parameterization (poly, init, refin, refout, xorout) and each one verified against its catalog check value in the test suite. If you need a CRC and it has a name, termapy already has it, correctly. Browse with `/proto.crc.list`, inspect with `/proto.crc.info <name>`, compute with `/proto.crc.calc`, identify an unknown one from a captured packet with `/proto.crc.find`. You can also generate standalone C, Python, or Rust source for any of them with `/proto.crc.python`, `/proto.crc.c`, `/proto.crc.rust` so you never have to port one by hand again.
851
+ Every CRC algorithm in the [reveng catalog](https://reveng.sourceforge.io/crc-catalogue/all.htm) (maintained by Greg Cook -- see [ACKNOWLEDGMENTS](src/termapy/help/acknowledgments.md)) is built in, with full parameterization (poly, init, refin, refout, xorout) and each one verified against its catalog check value in the test suite. If you need a CRC and it has a name, termapy already has it, correctly. Browse with `/proto.crc.list`, inspect with `/proto.crc.info <name>`, compute with `/proto.crc.calc`, identify an unknown one from a captured packet with `/proto.crc.find`. You can also generate standalone C, C#, Go, Java, Lua, Python, Rust, TypeScript, Verilog, VHDL, or Zig source for any of them with `/proto.crc.python`, `/proto.crc.c`, `/proto.crc.rust` so you never have to port one by hand again.
847
852
 
848
853
  </details>
849
854
 
@@ -907,9 +912,9 @@ Modbus RTU supports function 0x03 (read holding registers) and 0x06 (write singl
907
912
 
908
913
  The demo comes with everything wired up so you can try each feature:
909
914
 
910
- - **Scripts:** `at_demo.run`, `smoke_test.run`, `status_check.run`. Run via the Scripts button or `/run`.
915
+ - **Scripts:** `at_demo.run`, `smoke_test.run`, `status_check.run`, `gps_demo.run`, `var_demo.run`, `expect_test.run`, `crc_tour.run`, and more. Run via the Run button or `/run`.
911
916
  - **Proto test files:** `at_test.pro`, `bitfield_inline.pro`, `modbus_inline.pro`. Run via the Proto button for pass/fail results.
912
- - **Plugins:** `/probe` sends a command sequence and reports results; `/cmd` adds a custom shortcut.
917
+ - **Plugins:** `/probe` sends a command sequence and reports results; `/cmd` adds a custom shortcut; `/temp_plot` draws a sparkline; `/traffic.*` taps RX/TX bytes.
913
918
 
914
919
  </details>
915
920
 
@@ -935,16 +940,16 @@ Passing a `.run` file to `--cli` automatically infers the config from the file's
935
940
 
936
941
  **Features:**
937
942
 
938
- - Rich colored output (toggle with `/color on|off` or `--no-color`)
943
+ - Rich colored output (toggle with `/term.color on|off` or `--no-color`)
939
944
  - Command history shared with TUI (up/down arrows, persisted across sessions)
940
945
  - Tab completion for REPL commands
941
946
  - Script execution with `/run` (same scripts work in both TUI and CLI)
942
- - `/delay` with progress bar for waits over 3 seconds (Ctrl+C to cancel)
947
+ - `/delay` with progress bar for waits of a second or longer (Ctrl+C to cancel)
943
948
  - All `/port`, `/cfg`, `/var`, `/env`, `/proto.crc`, `/edit` commands work
944
949
 
945
950
  **TUI-only features** (not available in CLI mode):
946
951
 
947
- - `/ss.svg`, `/ss.txt` - screenshots (prints "not supported" message)
952
+ - `/ss.svg`, `/ss.txt` - screenshots (fail the `screen_capture` capability gate with a clear error)
948
953
  - `/grep` - scrollback search (no scrollback buffer in CLI)
949
954
  - `/edit.cfg` - opens in system editor instead of built-in config editor
950
955
  - Mouse interaction, modal dialogs, custom buttons
@@ -1055,7 +1060,6 @@ The `ctx` object passed to every handler is a thin shell over **five capability
1055
1060
  | `ctx.io.notify(text)` | Always-works fallback notification (toast in TUI, plain in CLI) |
1056
1061
  | `ctx.io.log(prefix, text)` | Write to session log: `">"` TX, `"<"` RX, `"#"` status |
1057
1062
  | `ctx.serial.is_connected` | Bool: serial port is open |
1058
- | `ctx.serial.port` | The raw pyserial object, or `None` when disconnected |
1059
1063
  | `ctx.serial.write(data)` | Send bytes to the serial port (auto-logged as TX) |
1060
1064
  | `ctx.serial.read_raw(timeout_ms)` | Read raw bytes with timeout framing (returns `bytes`) |
1061
1065
  | `ctx.serial.drain()` | Drain pending RX data |
@@ -1099,6 +1103,8 @@ See `examples/plugins/` for working examples:
1099
1103
  - **at_test.py:** send AT commands over serial
1100
1104
  - **timestamp.py:** print the current date/time
1101
1105
  - **ping.py:** send a command and measure response time
1106
+ - **traffic.py:** passive RX/TX byte tap (count, hexdump, rate, snoop) -- also shipped with `--demo`
1107
+ - **pic_map.py:** decode a PIC memory map
1102
1108
 
1103
1109
  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.
1104
1110
 
@@ -1143,7 +1149,7 @@ Actual: 01 00 C9 FF FE 0A -> ID:01 Temp:201 Signed:-2 Status:0A
1143
1149
  | `F` | IEEE 754 float | `F1-4` | `3.14` |
1144
1150
  | `B` | Bit field | `B1.3`, `B1-2.7-9` | `1`, `5` |
1145
1151
  | `_` | Padding (hidden) | `_:_3-4` | *(skipped)* |
1146
- | `crc*` | CRC verify | `CRC:crc16m_le` | pass/fail |
1152
+ | `crc*` | CRC verify | `CRC:crc16-modbus_le` | pass/fail |
1147
1153
 
1148
1154
  Integers support 1, 2, 3, 4, and 8 byte widths. Floats are 4-byte (F32) or 8-byte (F64).
1149
1155
 
@@ -1244,19 +1250,19 @@ Textual runs on a single async event loop. Termapy uses `@work(thread=True)` for
1244
1250
 
1245
1251
  | Worker | Lifetime | Purpose |
1246
1252
  | ------------------- | ----------- | ------------------------------------------------------- |
1247
- | `read_serial()` | Long-lived | Reads serial data in a loop, posts lines to the RichLog |
1248
- | `_auto_reconnect()` | Short-lived | Retries serial connection every 2.5s until success |
1253
+ | `SerialEngine.read_loop()` | Long-lived | The reader thread (`start_reader` / `stop_reader`); hands RX to the UI without blocking |
1254
+ | `_run_reconnect()` | Short-lived | Retries serial connection every 2.5s until success |
1249
1255
  | `_run_lines()` | Short-lived | Sends multiple commands with inter-command delay |
1250
1256
  | `_run_script()` | Short-lived | Executes a `.run` script file line by line |
1251
- | `_send_test()` | Short-lived | Runs a single protocol test case (send/receive/match) |
1252
- | `_run_cmds()` | Short-lived | Sends setup/teardown commands for protocol tests |
1257
+ | `_send_test()` | Short-lived | Runs a single protocol test case (`proto_debug.py`) |
1258
+ | `_run_cmds()` | Short-lived | Sends setup/teardown commands for protocol tests (`proto_debug.py`) |
1253
1259
 
1254
- Only `read_serial()` is long-lived. At most two workers run concurrently: the serial reader plus one command/script/test worker.
1260
+ Only the reader is long-lived. At most two workers run concurrently: the serial reader plus one command/script/test worker.
1255
1261
 
1256
1262
  </details>
1257
1263
 
1258
1264
  <details>
1259
- <summary><strong>Test coverage</strong> - 3363 tests, 72% core-module coverage</summary>
1265
+ <summary><strong>Test coverage</strong> - 3394 tests, 72% core-module coverage</summary>
1260
1266
 
1261
1267
  Run the full suite with `uv run pytest`. (The count above is the one place it
1262
1268
  is tracked; `release_prep` refreshes it each release.)
@@ -1273,7 +1279,7 @@ generator permutation.
1273
1279
 
1274
1280
  **Built-in plugins:** broad coverage via `test_builtins.py` plus per-plugin test files (`test_var.py`, `test_env_var.py`, `test_xmodem.py`, `test_ymodem.py`, `test_app_plugin.py`, `test_proto_send_crc.py`, etc.).
1275
1281
 
1276
- **UI code:** `app.py`, `proto_debug.py`, and `dialogs/` are the Textual UI and are tested manually (Textual Pilot + the CLI gold test), not unit-tested. The headline coverage figure is **core-module** coverage, measured with `app.py`, `dialogs/`, and `builtins/` **omitted** (see `[tool.coverage.run]` in `pyproject.toml`) — so it is *not* whole-repo coverage. Counting the whole repo (only vendored third-party code omitted) is lower, and that gap is exactly this untested UI layer. The omit is deliberate — the focus has been on extracting business logic into unit-testable modules and keeping the UI as thin delegation — but the headline number is core-module, not overall.
1282
+ **UI code:** `app.py` is driven headless by `tests/test_app_pilot.py` (Textual Pilot boots the real app), and the dialogs have Pilot tests of their own; `proto_debug.py` is still exercised manually. The headline coverage figure is **core-module** coverage, measured with `dialogs/`, the `builtins/` package top level, and vendored code **omitted** (see `[tool.coverage.run]` in `pyproject.toml`) — so it is *not* whole-repo coverage. Counting the whole repo (only vendored third-party code omitted) is lower, and that gap is exactly this untested UI layer. The omit is deliberate — the focus has been on extracting business logic into unit-testable modules and keeping the UI as thin delegation — but the headline number is core-module, not overall.
1277
1283
 
1278
1284
  </details>
1279
1285
 
@@ -12,7 +12,7 @@ Runs on Windows, macOS, and Linux. A serial interface terminal like PuTTY or Ter
12
12
 
13
13
  Low time commitment: about 1 minute from scratch, or under 10 seconds if you already have [uv](https://docs.astral.sh/uv/) installed.
14
14
 
15
- ![termapy screenshot](img/main.png)
15
+ ![termapy screenshot](src/termapy/help/img/doc_01_main_tui.svg)
16
16
 
17
17
  ## Install and connect
18
18
 
@@ -63,7 +63,7 @@ There's a lot more: scripting, binary protocol testing, every CRC algorithm in t
63
63
 
64
64
  1. **Connect:** click the port button in the title bar, pick your COM port, click the status button to connect (it turns green)
65
65
  2. **Type:** enter commands in the input box at the bottom and press Enter
66
- 3. **Change settings:** click `Cfg` to edit port, baud rate, and other settings through the UI
66
+ 3. **Change settings:** click the config name in the title bar (or `Cfg` → `Edit`) to change port, baud rate, and other settings through the UI
67
67
 
68
68
  Everything works through the UI. No config files to edit unless you want to.
69
69
 
@@ -118,6 +118,7 @@ Termapy runs with your privileges and does whatever you — or a connected MCP c
118
118
  | Ctrl+S | Save SVG screenshot |
119
119
  | Ctrl+T | Save text screenshot |
120
120
  | Ctrl+P | Command palette |
121
+ | F1–F4 | Help / Cfg / Run / Proto buttons (Ctrl+Shift+1–4 in VS Code); F10 edits the config |
121
122
  | Up/Down | Cycle through command history |
122
123
  | Escape | Clear input / exit history browsing |
123
124
  | Right | Accept type-ahead suggestion |
@@ -130,10 +131,11 @@ macOS Option-as-Meta, KVM cross-platform keyboards, etc.).
130
131
 
131
132
  | Button | Action |
132
133
  | ------ | ------------------------------------------------------------------- |
133
- | `?` | Open the help guide |
134
- | `#` | Toggle line numbers (green when active) |
135
- | `Cfg` | Open the config picker |
136
- | `Run` | Open the script picker |
134
+ | `Help` | Open the help guide |
135
+ | `Cfg` | Open the config picker (Load / Edit / New / Rename / Delete) |
136
+ | `Run` | Open the script picker (Run / Edit / New / Rename / Delete) |
137
+ | `Proto`| Open the protocol-test picker |
138
+ | `Update` | Appears only when a newer termapy is on PyPI |
137
139
  | Center | Click to edit the current config |
138
140
  | Port | Click to select a serial port |
139
141
  | Status | Click to connect/disconnect (red = disconnected, green = connected) |
@@ -154,7 +156,7 @@ The most common ones:
154
156
  | `/ss.svg [name]` | Save SVG screenshot |
155
157
  | `/cls` | Clear the terminal |
156
158
  | `/run {filename}` | Open Run picker (bare TUI), or run a named script |
157
- | `/term.echo [on \| off]` | Toggle command echo |
159
+ | `/term.echo [on \| off]` | Local echo of device commands sent to the wire |
158
160
  | `/grep <pattern>` | Search scrollback |
159
161
  | `/exit` | Exit termapy |
160
162
 
@@ -186,17 +188,18 @@ The most common ones:
186
188
  | `/port.break {ms}` | Send break signal (default 250ms) |
187
189
  | `/cfg [key [value]]` | Open Cfg picker (bare TUI), dump JSON (bare CLI), or get/set with args |
188
190
  | `/cfg.auto <key> <value>` | Set an in-memory config key immediately (no confirmation) |
189
- | `/cfg.configs` | List all config files |
191
+ | `/cfg.list` | List all config files |
190
192
  | `/cfg.load <name>` | Switch to a different config by name |
191
193
  | `/cfg.show` | Open the current config file in the system viewer |
192
194
  | `/cfg.help` | Same as `/help cfg` |
193
195
  | `/ss.svg [name]` | Save SVG screenshot |
194
196
  | `/ss.txt [name]` | Save text screenshot |
195
- | `/ss.dir` | Show the screenshot folder |
197
+ | `/ss.list` | List screenshots, newest first, with size and age |
198
+ | `/ss.explore` | Open the screenshot folder in the system file explorer |
196
199
  | `/cls` | Clear the terminal screen |
197
- | `/run {filename} {-v}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep |
200
+ | `/run {filename}` | Open Run picker (bare TUI), list scripts (bare CLI), or run; nests 5 deep |
198
201
  | `/run.list` | List .run files in run/, newest first, with size, age, and summary |
199
- | `/run.load <filename>` | Run a script file (same as /run) |
202
+ | `/run.rename <old> <new>` | Rename a script (`.run` kept; never overwrites) |
200
203
  | `/run.help` | Same as `/help run` |
201
204
  | `/delay <duration>` | Wait for a duration (e.g. `500ms`, `1.5s`) |
202
205
  | `/confirm {message}` | Show Yes/Cancel dialog; Cancel stops a running script (see `at_demo.run`) |
@@ -209,8 +212,8 @@ The most common ones:
209
212
  | `/show.cfg` | Show the current config file |
210
213
  | `/term` | Terminal display / session toggles (echo, line_no, timestamps, ...) |
211
214
  | `/term.info` | Snapshot the state of every `/term.*` toggle |
212
- | `/term.echo [on \| off]` | Toggle REPL command echo |
213
- | `/term.echo.silent <on \| off>` | Set echo on/off without echoing the change (for scripts and on_connect_cmd) |
215
+ | `/term.echo [on \| off]` | Local echo of device commands sent to the wire (persisted via cfg `echo`) |
216
+ | `/term.echo_repl [on \| off]` | Local echo of REPL (slash) commands, session only; off inside scripts |
214
217
  | `/term.line_no [on \| off]` | Toggle line numbers in serial output (TUI only) |
215
218
  | `/term.eol.markers [on \| off]` | Toggle visible `\r` `\n` markers for line-ending troubleshooting |
216
219
  | `/term.output {level}` | Show or set output level (silent/quiet/normal/verbose) |
@@ -224,20 +227,19 @@ The most common ones:
224
227
  | `/edit.info` | Open the info report in the system viewer |
225
228
  | `/os <cmd>` | Run a shell command (10s timeout, requires `TERMAPY_OS_CMD_ENABLED=1` in env) |
226
229
  | `/grep <pattern>` | Search scrollback for regex matches (case-insensitive, skips own output) |
227
- | `/cfg.info {--display}` | Show project summary; `--display` opens full report in system viewer |
228
- | `/cfg.files` | Show project directory tree |
230
+ | `/cfg.info {--display}` | Show project summary (folder tree + config + buttons); `--display` opens the full report |
229
231
  | `/proto` | Open Proto picker (bare TUI) or show long-help (bare CLI) |
230
232
  | `/proto.help` | Same as `/help proto` |
231
233
  | `/proto.send <hex>` | Send raw hex bytes and/or quoted text, display response as hex (see below) |
232
234
  | `/proto.run <file>` | Run a binary protocol test script (.pro) with pass/fail |
233
235
  | `/proto.list` | List .pro files in proto/, newest first, with size and age |
234
- | `/proto.load <file>` | Run a protocol test script (same as /proto.run) |
236
+ | `/proto.rename <old> <new>` | Rename a protocol script (`.pro` kept; never overwrites) |
235
237
  | `/proto.hex [on \| off]` | Toggle hex display mode for serial I/O |
236
238
  | `/proto.crc.list {pat}` | List available CRC algorithms (optional glob filter) |
237
239
  | `/proto.crc.info <name>` | Show CRC algorithm parameters and description |
238
240
  | `/proto.crc.calc <n> {d}` | Compute CRC over hex bytes, text, or file; omit data to verify check string |
239
241
  | `/proto.crc.find <pkt>` | Identify CRC algorithm from a captured packet (bin= hex or asc= text) |
240
- | `/proto.status` | Show current protocol mode state |
242
+ | `/proto.info` | Print current protocol state |
241
243
  | `/var {name}` | List user variables, or show one by name |
242
244
  | `/var.set <NAME> <value>` | Set a user variable |
243
245
  | `/var.clear` | Clear all user variables |
@@ -271,18 +273,21 @@ termapy_cfg/
271
273
  └── demo/
272
274
  ├── demo.cfg # config file
273
275
  ├── demo.log # session log
274
- ├── .cmd_history.txt # command history
276
+ ├── demo.history # command history
275
277
  ├── ss/ # screenshots
276
278
  ├── run/ # script files for /run
277
279
  │ ├── at_demo.run
278
280
  │ ├── smoke_test.run
279
- │ └── status_check.run
281
+ │ ├── status_check.run
282
+ │ └── ... # gps_demo, var_demo, expect_test, crc_tour, ...
280
283
  ├── plugin/ # per-config plugins
281
284
  │ ├── cmd.py
282
285
  │ ├── probe.py
283
286
  │ ├── temp_plot.py
284
287
  │ └── traffic.py
285
288
  ├── cap/ # data capture output files
289
+ ├── prof/ # /run.profile timing CSVs
290
+ ├── viz/ # per-config packet visualizers
286
291
  └── proto/ # protocol test scripts
287
292
  ├── at_test.pro
288
293
  ├── bitfield_inline.pro
@@ -380,7 +385,7 @@ Run `/run setup_modbus.run` then `/run test_registers.run`. The variables persis
380
385
  | `/var.set NAME val` | Set a variable (explicit command form) |
381
386
  | `/var.clear` | Clear all variables |
382
387
 
383
- **Scope:** Variables persist for the interactive session. They are automatically cleared when a script is launched from the Scripts button or Run menu, 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.
388
+ **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.
384
389
 
385
390
  **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.
386
391
 
@@ -389,7 +394,7 @@ Run `/run setup_modbus.run` then `/run test_registers.run`. The variables persis
389
394
  | Variable | Set when | Updates? |
390
395
  | --------------------- | ------------------------------------------- | -------------------- |
391
396
  | `$(LAUNCH_DATETIME)` | App starts | Never - frozen |
392
- | `$(SESSION_DATETIME)` | Script launched (Scripts button / Run menu) | Per script launch |
397
+ | `$(SESSION_DATETIME)` | Script launched (Run picker) | Per script launch |
393
398
  | `$(DATETIME)` | Every expansion | Always current clock |
394
399
 
395
400
  Each group also has `_DATE` and `_TIME` variants (e.g. `$(LAUNCH_DATE)`, `$(SESSION_TIME)`).
@@ -405,7 +410,7 @@ Add a `.gitignore` for session files you don't need to track:
405
410
  ```gitignore
406
411
  # termapy_cfg - keep configs and scripts, ignore session files
407
412
  termapy_cfg/*/*.log
408
- termapy_cfg/*/.cmd_history.txt
413
+ termapy_cfg/*/*.history
409
414
  termapy_cfg/*/ss/
410
415
  ```
411
416
 
@@ -566,7 +571,7 @@ See the **[config field reference](src/termapy/help/config.md#config-field-refer
566
571
 
567
572
  **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.
568
573
 
569
- **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 `color off` in `mcp_on_connect_cmd`.
574
+ **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`.
570
575
 
571
576
  </details>
572
577
 
@@ -575,9 +580,9 @@ See the **[config field reference](src/termapy/help/config.md#config-field-refer
575
580
  <details>
576
581
  <summary><strong>Scripting</strong> - automate command sequences with text files</summary>
577
582
 
578
- ![Run menu / script picker dialog](img/run.png)
583
+ ![Run picker: newest first, with size, updated, and docstring summary](src/termapy/help/img/doc_21_script_picker.svg)
579
584
 
580
- Create text files with one command per line and run them from the Run button or with the `/run` or the Scripts button. IN the file ines starting with `/` are REPL commands, lines starting with `#` are comments and everything else is sent to the device.
585
+ Create text files with one command per line and run them from the **Run** button or with `/run`. In the file, lines starting with `/` are REPL commands, lines starting with `#` are comments and everything else is sent to the device.
581
586
 
582
587
  ```text
583
588
  # Quick status check
@@ -797,7 +802,7 @@ Summary: 4/4 PASS (4 tests)
797
802
 
798
803
  ### CRC algorithms
799
804
 
800
- Every CRC algorithm in the [reveng catalog](https://reveng.sourceforge.io/crc-catalogue/all.htm) (maintained by Greg Cook -- see [ACKNOWLEDGMENTS](src/termapy/help/acknowledgments.md)) is built in, with full parameterization (poly, init, refin, refout, xorout) and each one verified against its catalog check value in the test suite. If you need a CRC and it has a name, termapy already has it, correctly. Browse with `/proto.crc.list`, inspect with `/proto.crc.info <name>`, compute with `/proto.crc.calc`, identify an unknown one from a captured packet with `/proto.crc.find`. You can also generate standalone C, Python, or Rust source for any of them with `/proto.crc.python`, `/proto.crc.c`, `/proto.crc.rust` so you never have to port one by hand again.
805
+ Every CRC algorithm in the [reveng catalog](https://reveng.sourceforge.io/crc-catalogue/all.htm) (maintained by Greg Cook -- see [ACKNOWLEDGMENTS](src/termapy/help/acknowledgments.md)) is built in, with full parameterization (poly, init, refin, refout, xorout) and each one verified against its catalog check value in the test suite. If you need a CRC and it has a name, termapy already has it, correctly. Browse with `/proto.crc.list`, inspect with `/proto.crc.info <name>`, compute with `/proto.crc.calc`, identify an unknown one from a captured packet with `/proto.crc.find`. You can also generate standalone C, C#, Go, Java, Lua, Python, Rust, TypeScript, Verilog, VHDL, or Zig source for any of them with `/proto.crc.python`, `/proto.crc.c`, `/proto.crc.rust` so you never have to port one by hand again.
801
806
 
802
807
  </details>
803
808
 
@@ -861,9 +866,9 @@ Modbus RTU supports function 0x03 (read holding registers) and 0x06 (write singl
861
866
 
862
867
  The demo comes with everything wired up so you can try each feature:
863
868
 
864
- - **Scripts:** `at_demo.run`, `smoke_test.run`, `status_check.run`. Run via the Scripts button or `/run`.
869
+ - **Scripts:** `at_demo.run`, `smoke_test.run`, `status_check.run`, `gps_demo.run`, `var_demo.run`, `expect_test.run`, `crc_tour.run`, and more. Run via the Run button or `/run`.
865
870
  - **Proto test files:** `at_test.pro`, `bitfield_inline.pro`, `modbus_inline.pro`. Run via the Proto button for pass/fail results.
866
- - **Plugins:** `/probe` sends a command sequence and reports results; `/cmd` adds a custom shortcut.
871
+ - **Plugins:** `/probe` sends a command sequence and reports results; `/cmd` adds a custom shortcut; `/temp_plot` draws a sparkline; `/traffic.*` taps RX/TX bytes.
867
872
 
868
873
  </details>
869
874
 
@@ -889,16 +894,16 @@ Passing a `.run` file to `--cli` automatically infers the config from the file's
889
894
 
890
895
  **Features:**
891
896
 
892
- - Rich colored output (toggle with `/color on|off` or `--no-color`)
897
+ - Rich colored output (toggle with `/term.color on|off` or `--no-color`)
893
898
  - Command history shared with TUI (up/down arrows, persisted across sessions)
894
899
  - Tab completion for REPL commands
895
900
  - Script execution with `/run` (same scripts work in both TUI and CLI)
896
- - `/delay` with progress bar for waits over 3 seconds (Ctrl+C to cancel)
901
+ - `/delay` with progress bar for waits of a second or longer (Ctrl+C to cancel)
897
902
  - All `/port`, `/cfg`, `/var`, `/env`, `/proto.crc`, `/edit` commands work
898
903
 
899
904
  **TUI-only features** (not available in CLI mode):
900
905
 
901
- - `/ss.svg`, `/ss.txt` - screenshots (prints "not supported" message)
906
+ - `/ss.svg`, `/ss.txt` - screenshots (fail the `screen_capture` capability gate with a clear error)
902
907
  - `/grep` - scrollback search (no scrollback buffer in CLI)
903
908
  - `/edit.cfg` - opens in system editor instead of built-in config editor
904
909
  - Mouse interaction, modal dialogs, custom buttons
@@ -1009,7 +1014,6 @@ The `ctx` object passed to every handler is a thin shell over **five capability
1009
1014
  | `ctx.io.notify(text)` | Always-works fallback notification (toast in TUI, plain in CLI) |
1010
1015
  | `ctx.io.log(prefix, text)` | Write to session log: `">"` TX, `"<"` RX, `"#"` status |
1011
1016
  | `ctx.serial.is_connected` | Bool: serial port is open |
1012
- | `ctx.serial.port` | The raw pyserial object, or `None` when disconnected |
1013
1017
  | `ctx.serial.write(data)` | Send bytes to the serial port (auto-logged as TX) |
1014
1018
  | `ctx.serial.read_raw(timeout_ms)` | Read raw bytes with timeout framing (returns `bytes`) |
1015
1019
  | `ctx.serial.drain()` | Drain pending RX data |
@@ -1053,6 +1057,8 @@ See `examples/plugins/` for working examples:
1053
1057
  - **at_test.py:** send AT commands over serial
1054
1058
  - **timestamp.py:** print the current date/time
1055
1059
  - **ping.py:** send a command and measure response time
1060
+ - **traffic.py:** passive RX/TX byte tap (count, hexdump, rate, snoop) -- also shipped with `--demo`
1061
+ - **pic_map.py:** decode a PIC memory map
1056
1062
 
1057
1063
  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.
1058
1064
 
@@ -1097,7 +1103,7 @@ Actual: 01 00 C9 FF FE 0A -> ID:01 Temp:201 Signed:-2 Status:0A
1097
1103
  | `F` | IEEE 754 float | `F1-4` | `3.14` |
1098
1104
  | `B` | Bit field | `B1.3`, `B1-2.7-9` | `1`, `5` |
1099
1105
  | `_` | Padding (hidden) | `_:_3-4` | *(skipped)* |
1100
- | `crc*` | CRC verify | `CRC:crc16m_le` | pass/fail |
1106
+ | `crc*` | CRC verify | `CRC:crc16-modbus_le` | pass/fail |
1101
1107
 
1102
1108
  Integers support 1, 2, 3, 4, and 8 byte widths. Floats are 4-byte (F32) or 8-byte (F64).
1103
1109
 
@@ -1198,19 +1204,19 @@ Textual runs on a single async event loop. Termapy uses `@work(thread=True)` for
1198
1204
 
1199
1205
  | Worker | Lifetime | Purpose |
1200
1206
  | ------------------- | ----------- | ------------------------------------------------------- |
1201
- | `read_serial()` | Long-lived | Reads serial data in a loop, posts lines to the RichLog |
1202
- | `_auto_reconnect()` | Short-lived | Retries serial connection every 2.5s until success |
1207
+ | `SerialEngine.read_loop()` | Long-lived | The reader thread (`start_reader` / `stop_reader`); hands RX to the UI without blocking |
1208
+ | `_run_reconnect()` | Short-lived | Retries serial connection every 2.5s until success |
1203
1209
  | `_run_lines()` | Short-lived | Sends multiple commands with inter-command delay |
1204
1210
  | `_run_script()` | Short-lived | Executes a `.run` script file line by line |
1205
- | `_send_test()` | Short-lived | Runs a single protocol test case (send/receive/match) |
1206
- | `_run_cmds()` | Short-lived | Sends setup/teardown commands for protocol tests |
1211
+ | `_send_test()` | Short-lived | Runs a single protocol test case (`proto_debug.py`) |
1212
+ | `_run_cmds()` | Short-lived | Sends setup/teardown commands for protocol tests (`proto_debug.py`) |
1207
1213
 
1208
- Only `read_serial()` is long-lived. At most two workers run concurrently: the serial reader plus one command/script/test worker.
1214
+ Only the reader is long-lived. At most two workers run concurrently: the serial reader plus one command/script/test worker.
1209
1215
 
1210
1216
  </details>
1211
1217
 
1212
1218
  <details>
1213
- <summary><strong>Test coverage</strong> - 3363 tests, 72% core-module coverage</summary>
1219
+ <summary><strong>Test coverage</strong> - 3394 tests, 72% core-module coverage</summary>
1214
1220
 
1215
1221
  Run the full suite with `uv run pytest`. (The count above is the one place it
1216
1222
  is tracked; `release_prep` refreshes it each release.)
@@ -1227,7 +1233,7 @@ generator permutation.
1227
1233
 
1228
1234
  **Built-in plugins:** broad coverage via `test_builtins.py` plus per-plugin test files (`test_var.py`, `test_env_var.py`, `test_xmodem.py`, `test_ymodem.py`, `test_app_plugin.py`, `test_proto_send_crc.py`, etc.).
1229
1235
 
1230
- **UI code:** `app.py`, `proto_debug.py`, and `dialogs/` are the Textual UI and are tested manually (Textual Pilot + the CLI gold test), not unit-tested. The headline coverage figure is **core-module** coverage, measured with `app.py`, `dialogs/`, and `builtins/` **omitted** (see `[tool.coverage.run]` in `pyproject.toml`) — so it is *not* whole-repo coverage. Counting the whole repo (only vendored third-party code omitted) is lower, and that gap is exactly this untested UI layer. The omit is deliberate — the focus has been on extracting business logic into unit-testable modules and keeping the UI as thin delegation — but the headline number is core-module, not overall.
1236
+ **UI code:** `app.py` is driven headless by `tests/test_app_pilot.py` (Textual Pilot boots the real app), and the dialogs have Pilot tests of their own; `proto_debug.py` is still exercised manually. The headline coverage figure is **core-module** coverage, measured with `dialogs/`, the `builtins/` package top level, and vendored code **omitted** (see `[tool.coverage.run]` in `pyproject.toml`) — so it is *not* whole-repo coverage. Counting the whole repo (only vendored third-party code omitted) is lower, and that gap is exactly this untested UI layer. The omit is deliberate — the focus has been on extracting business logic into unit-testable modules and keeping the UI as thin delegation — but the headline number is core-module, not overall.
1231
1237
 
1232
1238
  </details>
1233
1239
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "termapy"
3
- version = "0.75.0"
3
+ version = "0.76.0"
4
4
  description = "A TUI serial terminal with ANSI color support, built on Textual and pyserial"
5
5
  license = "MIT"
6
6
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "termapy"
3
- version = "0.75.0"
3
+ version = "0.76.0"
4
4
  description = "A TUI serial terminal with ANSI color support, built on Textual and pyserial"
5
5
  license = "MIT"
6
6
  requires-python = ">=3.11"