evolver-tools 1.5.0__tar.gz → 3.0.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 (184) hide show
  1. evolver_tools-3.0.0/PKG-INFO +112 -0
  2. evolver_tools-3.0.0/README.md +90 -0
  3. evolver_tools-3.0.0/pyproject.toml +36 -0
  4. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/__init__.py +2 -0
  5. evolver_tools-3.0.0/src/evolver_tools/autoreg.py +88 -0
  6. evolver_tools-3.0.0/src/evolver_tools/cli.py +66 -0
  7. evolver_tools-3.0.0/src/evolver_tools/vendor/__init__.py +3 -0
  8. evolver_tools-3.0.0/src/evolver_tools/vendor/agent_b_tool.py +9 -0
  9. evolver_tools-3.0.0/src/evolver_tools/vendor/api_tester.py +237 -0
  10. evolver_tools-3.0.0/src/evolver_tools/vendor/ascii_gen.py +150 -0
  11. evolver_tools-3.0.0/src/evolver_tools/vendor/audit_log.py +269 -0
  12. evolver_tools-3.0.0/src/evolver_tools/vendor/b64/__init__.py +9 -0
  13. evolver_tools-3.0.0/src/evolver_tools/vendor/backup.py +87 -0
  14. evolver_tools-3.0.0/src/evolver_tools/vendor/banner/__init__.py +9 -0
  15. evolver_tools-3.0.0/src/evolver_tools/vendor/banner/banner.py +484 -0
  16. evolver_tools-3.0.0/src/evolver_tools/vendor/banner.py +77 -0
  17. evolver_tools-3.0.0/src/evolver_tools/vendor/bookmark.py +284 -0
  18. evolver_tools-3.0.0/src/evolver_tools/vendor/cal_tool/__init__.py +9 -0
  19. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +8 -0
  20. evolver_tools-3.0.0/src/evolver_tools/vendor/cert_check.py +265 -0
  21. evolver_tools-3.0.0/src/evolver_tools/vendor/changelog_gen/__init__.py +9 -0
  22. evolver_tools-3.0.0/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +199 -0
  23. evolver_tools-3.0.0/src/evolver_tools/vendor/changelog_gen.py +79 -0
  24. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +8 -0
  25. evolver_tools-3.0.0/src/evolver_tools/vendor/checksum_dir.py +309 -0
  26. evolver_tools-3.0.0/src/evolver_tools/vendor/clipboard/__init__.py +9 -0
  27. evolver_tools-3.0.0/src/evolver_tools/vendor/clipboard/clipboard.py +146 -0
  28. evolver_tools-3.0.0/src/evolver_tools/vendor/colorize.py +200 -0
  29. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/colors/__init__.py +7 -0
  30. evolver_tools-3.0.0/src/evolver_tools/vendor/config_validator.py +320 -0
  31. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/cron/__init__.py +8 -0
  32. evolver_tools-3.0.0/src/evolver_tools/vendor/crontab_helper.py +433 -0
  33. evolver_tools-3.0.0/src/evolver_tools/vendor/csv_stats/__init__.py +13 -0
  34. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +8 -0
  35. evolver_tools-3.0.0/src/evolver_tools/vendor/db_schema.py +217 -0
  36. evolver_tools-3.0.0/src/evolver_tools/vendor/dep_graph.py +258 -0
  37. evolver_tools-3.0.0/src/evolver_tools/vendor/diff_csv.py +203 -0
  38. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +7 -0
  39. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +8 -0
  40. evolver_tools-3.0.0/src/evolver_tools/vendor/disk_usage/__init__.py +9 -0
  41. evolver_tools-3.0.0/src/evolver_tools/vendor/disk_usage/disk_usage.py +176 -0
  42. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/dt_convert.py +8 -0
  43. evolver_tools-3.0.0/src/evolver_tools/vendor/env_manager.py +250 -0
  44. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +8 -0
  45. evolver_tools-3.0.0/src/evolver_tools/vendor/excel2csv.py +240 -0
  46. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ff/__init__.py +8 -0
  47. evolver_tools-3.0.0/src/evolver_tools/vendor/figlet_cli.py +150 -0
  48. evolver_tools-3.0.0/src/evolver_tools/vendor/figlet_tool.py +276 -0
  49. evolver_tools-3.0.0/src/evolver_tools/vendor/file_encrypt.py +184 -0
  50. evolver_tools-3.0.0/src/evolver_tools/vendor/find_dups/__init__.py +15 -0
  51. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/find_dups/cli.py +8 -0
  52. evolver_tools-3.0.0/src/evolver_tools/vendor/firewall_rule.py +280 -0
  53. evolver_tools-3.0.0/src/evolver_tools/vendor/fmt/__init__.py +9 -0
  54. evolver_tools-3.0.0/src/evolver_tools/vendor/fmt/fmt.py +143 -0
  55. evolver_tools-3.0.0/src/evolver_tools/vendor/git_branch_cleaner.py +242 -0
  56. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +8 -0
  57. evolver_tools-3.0.0/src/evolver_tools/vendor/html2markdown.py +158 -0
  58. evolver_tools-3.0.0/src/evolver_tools/vendor/html2md.py +383 -0
  59. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/http_live/__init__.py +8 -0
  60. evolver_tools-3.0.0/src/evolver_tools/vendor/image_meta.py +326 -0
  61. evolver_tools-3.0.0/src/evolver_tools/vendor/ini_parser/__init__.py +9 -0
  62. evolver_tools-3.0.0/src/evolver_tools/vendor/ini_parser/ini_parser.py +167 -0
  63. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +8 -0
  64. evolver_tools-3.0.0/src/evolver_tools/vendor/ipinfo/__init__.py +10 -0
  65. evolver_tools-3.0.0/src/evolver_tools/vendor/join.py +32 -0
  66. evolver_tools-3.0.0/src/evolver_tools/vendor/joke.py +99 -0
  67. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +8 -0
  68. evolver_tools-3.0.0/src/evolver_tools/vendor/json2csv/__init__.py +10 -0
  69. evolver_tools-3.0.0/src/evolver_tools/vendor/json_pretty/__init__.py +9 -0
  70. evolver_tools-3.0.0/src/evolver_tools/vendor/json_pretty/json_pretty.py +121 -0
  71. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +8 -0
  72. evolver_tools-3.0.0/src/evolver_tools/vendor/license_cli/__init__.py +9 -0
  73. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/license_cli/cli.py +8 -0
  74. evolver_tools-3.0.0/src/evolver_tools/vendor/log_analyzer.py +284 -0
  75. evolver_tools-3.0.0/src/evolver_tools/vendor/log_tail.py +125 -0
  76. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +8 -0
  77. evolver_tools-3.0.0/src/evolver_tools/vendor/morse.py +130 -0
  78. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/nb/__init__.py +8 -0
  79. evolver_tools-3.0.0/src/evolver_tools/vendor/net_speed.py +89 -0
  80. evolver_tools-3.0.0/src/evolver_tools/vendor/note_taker.py +124 -0
  81. evolver_tools-3.0.0/src/evolver_tools/vendor/otp_gen.py +237 -0
  82. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/passgen/__init__.py +8 -0
  83. evolver_tools-3.0.0/src/evolver_tools/vendor/password_strength.py +177 -0
  84. evolver_tools-3.0.0/src/evolver_tools/vendor/portcheck/__init__.py +10 -0
  85. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +8 -0
  86. evolver_tools-3.0.0/src/evolver_tools/vendor/pr_tool/__init__.py +9 -0
  87. evolver_tools-3.0.0/src/evolver_tools/vendor/pr_tool/pr_tool.py +118 -0
  88. evolver_tools-3.0.0/src/evolver_tools/vendor/process_kill.py +260 -0
  89. evolver_tools-3.0.0/src/evolver_tools/vendor/progress_bar.py +54 -0
  90. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +8 -0
  91. evolver_tools-3.0.0/src/evolver_tools/vendor/qrcode.py +129 -0
  92. evolver_tools-3.0.0/src/evolver_tools/vendor/quote_tool/__init__.py +9 -0
  93. evolver_tools-3.0.0/src/evolver_tools/vendor/quote_tool/quote.py +211 -0
  94. evolver_tools-3.0.0/src/evolver_tools/vendor/rainbow.py +80 -0
  95. evolver_tools-3.0.0/src/evolver_tools/vendor/reminder.py +102 -0
  96. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ren/__init__.py +8 -0
  97. evolver_tools-3.0.0/src/evolver_tools/vendor/restore.py +119 -0
  98. evolver_tools-3.0.0/src/evolver_tools/vendor/scan_ports.py +109 -0
  99. evolver_tools-3.0.0/src/evolver_tools/vendor/service_check.py +218 -0
  100. evolver_tools-3.0.0/src/evolver_tools/vendor/shuffle.py +37 -0
  101. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +8 -0
  102. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +8 -0
  103. evolver_tools-3.0.0/src/evolver_tools/vendor/sort/__init__.py +9 -0
  104. evolver_tools-3.0.0/src/evolver_tools/vendor/sort/sort.py +180 -0
  105. evolver_tools-3.0.0/src/evolver_tools/vendor/spinner.py +89 -0
  106. evolver_tools-3.0.0/src/evolver_tools/vendor/split.py +39 -0
  107. evolver_tools-3.0.0/src/evolver_tools/vendor/split_tool/__init__.py +9 -0
  108. evolver_tools-3.0.0/src/evolver_tools/vendor/split_tool/split.py +190 -0
  109. evolver_tools-3.0.0/src/evolver_tools/vendor/sql2csv.py +611 -0
  110. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +8 -0
  111. evolver_tools-3.0.0/src/evolver_tools/vendor/ssh_key_gen.py +130 -0
  112. evolver_tools-3.0.0/src/evolver_tools/vendor/ssl_check.py +127 -0
  113. evolver_tools-3.0.0/src/evolver_tools/vendor/stopwatch.py +102 -0
  114. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +8 -0
  115. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/timer/__init__.py +8 -0
  116. evolver_tools-3.0.0/src/evolver_tools/vendor/timer_pro/__init__.py +9 -0
  117. evolver_tools-3.0.0/src/evolver_tools/vendor/timer_pro/timer_pro.py +233 -0
  118. evolver_tools-3.0.0/src/evolver_tools/vendor/timer_pro.py +83 -0
  119. evolver_tools-3.0.0/src/evolver_tools/vendor/todo_cli.py +178 -0
  120. evolver_tools-3.0.0/src/evolver_tools/vendor/treedir/__init__.py +10 -0
  121. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/treedir/__main__.py +8 -0
  122. evolver_tools-3.0.0/src/evolver_tools/vendor/uniq_tool/__init__.py +9 -0
  123. evolver_tools-3.0.0/src/evolver_tools/vendor/uniq_tool/uniq.py +134 -0
  124. evolver_tools-3.0.0/src/evolver_tools/vendor/urlparse_tool/__init__.py +11 -0
  125. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +8 -0
  126. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +8 -0
  127. evolver_tools-3.0.0/src/evolver_tools/vendor/weather_cli.py +53 -0
  128. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +8 -0
  129. evolver_tools-3.0.0/src/evolver_tools/vendor/wordcount/__init__.py +10 -0
  130. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +8 -0
  131. evolver_tools-3.0.0/src/evolver_tools/vendor/xml2json.py +91 -0
  132. evolver_tools-3.0.0/src/evolver_tools/vendor/yaml2json/__init__.py +9 -0
  133. evolver_tools-3.0.0/src/evolver_tools/vendor/yaml2json/yaml2json.py +311 -0
  134. evolver_tools-3.0.0/src/evolver_tools.egg-info/PKG-INFO +112 -0
  135. evolver_tools-3.0.0/src/evolver_tools.egg-info/SOURCES.txt +164 -0
  136. evolver_tools-3.0.0/src/evolver_tools.egg-info/entry_points.txt +2 -0
  137. evolver_tools-1.5.0/PKG-INFO +0 -107
  138. evolver_tools-1.5.0/README.md +0 -85
  139. evolver_tools-1.5.0/pyproject.toml +0 -72
  140. evolver_tools-1.5.0/src/evolver_tools/cli.py +0 -93
  141. evolver_tools-1.5.0/src/evolver_tools/vendor/b64/__init__.py +0 -2
  142. evolver_tools-1.5.0/src/evolver_tools/vendor/cal_tool/__init__.py +0 -1
  143. evolver_tools-1.5.0/src/evolver_tools/vendor/csv_stats/__init__.py +0 -5
  144. evolver_tools-1.5.0/src/evolver_tools/vendor/find_dups/__init__.py +0 -7
  145. evolver_tools-1.5.0/src/evolver_tools/vendor/ipinfo/__init__.py +0 -3
  146. evolver_tools-1.5.0/src/evolver_tools/vendor/json2csv/__init__.py +0 -3
  147. evolver_tools-1.5.0/src/evolver_tools/vendor/license_cli/__init__.py +0 -1
  148. evolver_tools-1.5.0/src/evolver_tools/vendor/portcheck/__init__.py +0 -2
  149. evolver_tools-1.5.0/src/evolver_tools/vendor/treedir/__init__.py +0 -2
  150. evolver_tools-1.5.0/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -3
  151. evolver_tools-1.5.0/src/evolver_tools/vendor/wordcount/__init__.py +0 -2
  152. evolver_tools-1.5.0/src/evolver_tools.egg-info/PKG-INFO +0 -107
  153. evolver_tools-1.5.0/src/evolver_tools.egg-info/SOURCES.txt +0 -80
  154. evolver_tools-1.5.0/src/evolver_tools.egg-info/entry_points.txt +0 -38
  155. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/LICENSE +0 -0
  156. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/setup.cfg +0 -0
  157. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/__main__.py +0 -0
  158. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  159. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  160. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  161. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  162. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  163. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  164. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  165. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  166. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  167. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  168. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  169. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  170. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  171. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  172. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  173. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  174. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  175. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  176. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  177. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  178. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  179. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  180. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  181. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  182. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  183. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  184. {evolver_tools-1.5.0 → evolver_tools-3.0.0}/src/evolver_tools.egg-info/top_level.txt +0 -0
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: evolver-tools
3
+ Version: 3.0.0
4
+ Summary: 100 essential CLI tools - one pip install
5
+ Author: EVOLVER
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://evolver-dev.github.io/evolver-tools
8
+ Project-URL: Repository, https://github.com/evolver-dev/evolver-tools
9
+ Keywords: cli,devops,productivity,developer-tools,terminal
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: System Administrators
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.8
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Dynamic: license-file
22
+
23
+ # EVOLVER Tools
24
+
25
+ **50 essential CLI tools — one `pip install`.**
26
+
27
+ Zero-dependency (49/50), cross-platform, production-ready.
28
+ Systems ops, data processing, dev tools, security, and creativity.
29
+ ~170KB total — one install, not 50.
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ pip install evolver-tools
35
+ evtool list # Show all 50 tools
36
+ evtool ff < data.txt # Fuzzy search through data
37
+ evtool sysmon # Launch system monitor
38
+ evtool sort -n data.txt # Numeric sort
39
+ ```
40
+
41
+ ## Tools
42
+
43
+ ### Ops
44
+
45
+ | Tool | Description | Selling point |
46
+ |------|-------------|---------------|
47
+ | **sysmon** | Real-time system monitor (curses TUI — CPU/mem/disk/net/processes) | See your server breathe |
48
+ | **dirsize** | Recursive directory space analyzer | Find what's eating your disk |
49
+ | **envcheck** | Environment variable validator (missing keys, formats) | Stop .env typos from breaking prod |
50
+ | **portcheck** | TCP port scanner & service detection | Port open? Service running? |
51
+ | **siege-lite** | HTTP load tester (concurrency, latency percentile) | How many req/s can your app handle? |
52
+ | **http-live** | SSE hot-reload HTTP server for development | Edit code, see changes. No refresh. |
53
+ | **ipinfo** | Public IP & geolocation lookup | Where's this server? |
54
+ | **hashsum** | File hash verification (MD5/SHA-1/256/512/BLAKE2, auto-detect) | Verify downloads in one command |
55
+ | **find-dups** | Find duplicate files by SHA256 hash, size, or name | Reclaim gigabytes |
56
+
57
+ ### Developer
58
+
59
+ | Tool | Description | Selling point |
60
+ |------|-------------|---------------|
61
+ | **smellfinder** | Python code smell detector (AST-based, 10+ patterns) | Lint without pip install pylint |
62
+ | **project-doctor** | Project health checker (meta, structure, quality) | Project checkup in one command |
63
+ | **license-cli** | Open-source license generator/validator | License your repo instantly |
64
+ | **markdown-check** | Markdown format validator & style checker | Docs that don't embarrass you |
65
+ | **sqlite-cli** | SQLite query tool — CSV/JSON/table output | Query .db files without a GUI |
66
+ | **b64** | Base64 encode/decode with auto-detection | Paste, pipe, done |
67
+ | **jsonql** | Zero-dep JSON query tool (SQL-like syntax) | `jsonql "SELECT name FROM data WHERE age > 18"` |
68
+ | **jq-lite** | jq-style JSON query — filter, extract, transform | jq without installing jq |
69
+ | **urlparse** | URL parser & debugger | What's in that URL? |
70
+ | **colors** | 256-color table & HEX↔RGB conversion | Design that terminal theme |
71
+ | **fmt** | Code/text formatter — trailing whitespace, EOF newline, indent | Clean files, one command |
72
+
73
+ ### Data & Analysis
74
+
75
+ | Tool | Description | Selling point |
76
+ |------|-------------|---------------|
77
+ | **csv-stats** | CSV column analysis — histograms, frequencies, correlations | Understand your CSV in seconds |
78
+ | **json2csv** | JSON to CSV converter with nested key flattening | API response → spreadsheet |
79
+ | **chart-cli** | Terminal chart generator — bar, line, pie, histogram | Charts without leaving the terminal |
80
+ | **cal** | Calendar & date calculator | What day is 45 days from now? |
81
+ | **web-summary** | Web page content extractor (title, body, links) | Read the web from your terminal |
82
+ | **yaml2json** | Convert YAML to JSON (zero dependencies, basic YAML subset) | Config files \u2192 pipeable JSON |
83
+ | **sort** | Line sorting — alpha, numeric, reverse, unique, by column | Sort data without `sort(1)` |
84
+
85
+ ### Productivity
86
+
87
+ | Tool | Description | Selling point |
88
+ |------|-------------|---------------|
89
+ | **ff** | Interactive fuzzy finder (fzf, pure Python curses TUI) | Search files, history, anything |
90
+ | **nb** | Command-line notebook (JSON storage, full-text search) | Notes in your terminal |
91
+ | **ren** | Batch file renamer (prefix/suffix/regex/numbering) | Rename 100 files in one command |
92
+ | **timer** | Countdown timer & stopwatch with desktop notifications | Pomodoro in your terminal |
93
+ | **treedir** | Directory tree visualizer with depth control | `tree` on every OS |
94
+ | **wordcount** | Enhanced word/char/line counter with language detection | wc on steroids |
95
+ | **dt** | Date/time format converter (timestamps, timezones) | `dt 1735689600` → human date |
96
+
97
+ ### Security
98
+
99
+ | Tool | Description | Selling point |
100
+ |------|-------------|---------------|
101
+ | **passgen** | Password generator with entropy display & charset rules | Generate passwords that don't suck |
102
+ | **uuid** | UUID generator (v1/v3/v4/v5/v7) | v4, v7, any UUID in one command |
103
+ | **cron** | Cron expression parser & next-run calculator | "What does 0 2 * * 1 actually run?" |
104
+
105
+ ## Requirements
106
+
107
+ - Python 3.8+
108
+ - No external dependencies (38 of 39 tools use stdlib only; ipinfo hits ip-api.com)
109
+
110
+ ## License
111
+
112
+ MIT
@@ -0,0 +1,90 @@
1
+ # EVOLVER Tools
2
+
3
+ **50 essential CLI tools — one `pip install`.**
4
+
5
+ Zero-dependency (49/50), cross-platform, production-ready.
6
+ Systems ops, data processing, dev tools, security, and creativity.
7
+ ~170KB total — one install, not 50.
8
+
9
+ ## Quick Start
10
+
11
+ ```bash
12
+ pip install evolver-tools
13
+ evtool list # Show all 50 tools
14
+ evtool ff < data.txt # Fuzzy search through data
15
+ evtool sysmon # Launch system monitor
16
+ evtool sort -n data.txt # Numeric sort
17
+ ```
18
+
19
+ ## Tools
20
+
21
+ ### Ops
22
+
23
+ | Tool | Description | Selling point |
24
+ |------|-------------|---------------|
25
+ | **sysmon** | Real-time system monitor (curses TUI — CPU/mem/disk/net/processes) | See your server breathe |
26
+ | **dirsize** | Recursive directory space analyzer | Find what's eating your disk |
27
+ | **envcheck** | Environment variable validator (missing keys, formats) | Stop .env typos from breaking prod |
28
+ | **portcheck** | TCP port scanner & service detection | Port open? Service running? |
29
+ | **siege-lite** | HTTP load tester (concurrency, latency percentile) | How many req/s can your app handle? |
30
+ | **http-live** | SSE hot-reload HTTP server for development | Edit code, see changes. No refresh. |
31
+ | **ipinfo** | Public IP & geolocation lookup | Where's this server? |
32
+ | **hashsum** | File hash verification (MD5/SHA-1/256/512/BLAKE2, auto-detect) | Verify downloads in one command |
33
+ | **find-dups** | Find duplicate files by SHA256 hash, size, or name | Reclaim gigabytes |
34
+
35
+ ### Developer
36
+
37
+ | Tool | Description | Selling point |
38
+ |------|-------------|---------------|
39
+ | **smellfinder** | Python code smell detector (AST-based, 10+ patterns) | Lint without pip install pylint |
40
+ | **project-doctor** | Project health checker (meta, structure, quality) | Project checkup in one command |
41
+ | **license-cli** | Open-source license generator/validator | License your repo instantly |
42
+ | **markdown-check** | Markdown format validator & style checker | Docs that don't embarrass you |
43
+ | **sqlite-cli** | SQLite query tool — CSV/JSON/table output | Query .db files without a GUI |
44
+ | **b64** | Base64 encode/decode with auto-detection | Paste, pipe, done |
45
+ | **jsonql** | Zero-dep JSON query tool (SQL-like syntax) | `jsonql "SELECT name FROM data WHERE age > 18"` |
46
+ | **jq-lite** | jq-style JSON query — filter, extract, transform | jq without installing jq |
47
+ | **urlparse** | URL parser & debugger | What's in that URL? |
48
+ | **colors** | 256-color table & HEX↔RGB conversion | Design that terminal theme |
49
+ | **fmt** | Code/text formatter — trailing whitespace, EOF newline, indent | Clean files, one command |
50
+
51
+ ### Data & Analysis
52
+
53
+ | Tool | Description | Selling point |
54
+ |------|-------------|---------------|
55
+ | **csv-stats** | CSV column analysis — histograms, frequencies, correlations | Understand your CSV in seconds |
56
+ | **json2csv** | JSON to CSV converter with nested key flattening | API response → spreadsheet |
57
+ | **chart-cli** | Terminal chart generator — bar, line, pie, histogram | Charts without leaving the terminal |
58
+ | **cal** | Calendar & date calculator | What day is 45 days from now? |
59
+ | **web-summary** | Web page content extractor (title, body, links) | Read the web from your terminal |
60
+ | **yaml2json** | Convert YAML to JSON (zero dependencies, basic YAML subset) | Config files \u2192 pipeable JSON |
61
+ | **sort** | Line sorting — alpha, numeric, reverse, unique, by column | Sort data without `sort(1)` |
62
+
63
+ ### Productivity
64
+
65
+ | Tool | Description | Selling point |
66
+ |------|-------------|---------------|
67
+ | **ff** | Interactive fuzzy finder (fzf, pure Python curses TUI) | Search files, history, anything |
68
+ | **nb** | Command-line notebook (JSON storage, full-text search) | Notes in your terminal |
69
+ | **ren** | Batch file renamer (prefix/suffix/regex/numbering) | Rename 100 files in one command |
70
+ | **timer** | Countdown timer & stopwatch with desktop notifications | Pomodoro in your terminal |
71
+ | **treedir** | Directory tree visualizer with depth control | `tree` on every OS |
72
+ | **wordcount** | Enhanced word/char/line counter with language detection | wc on steroids |
73
+ | **dt** | Date/time format converter (timestamps, timezones) | `dt 1735689600` → human date |
74
+
75
+ ### Security
76
+
77
+ | Tool | Description | Selling point |
78
+ |------|-------------|---------------|
79
+ | **passgen** | Password generator with entropy display & charset rules | Generate passwords that don't suck |
80
+ | **uuid** | UUID generator (v1/v3/v4/v5/v7) | v4, v7, any UUID in one command |
81
+ | **cron** | Cron expression parser & next-run calculator | "What does 0 2 * * 1 actually run?" |
82
+
83
+ ## Requirements
84
+
85
+ - Python 3.8+
86
+ - No external dependencies (38 of 39 tools use stdlib only; ipinfo hits ip-api.com)
87
+
88
+ ## License
89
+
90
+ MIT
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "evolver-tools"
7
+ version = "3.0.0"
8
+ description = "100 essential CLI tools - one pip install"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.8"
12
+ keywords = ["cli", "devops", "productivity", "developer-tools", "terminal"]
13
+ authors = [
14
+ {name = "EVOLVER"},
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Intended Audience :: System Administrators",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Topic :: Utilities",
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://evolver-dev.github.io/evolver-tools"
29
+ Repository = "https://github.com/evolver-dev/evolver-tools"
30
+
31
+ [project.scripts]
32
+ evtool = "evolver_tools.cli:main"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
36
+ include = ["evolver_tools*"]
@@ -1,2 +1,4 @@
1
1
  """evolver-tools: 23 CLI tools in one package."""
2
2
  __version__ = "1.0.0"
3
+
4
+ from .autoreg import auto_discover
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env python3
2
+ """Auto-discovery module for EVOLVER tools.
3
+
4
+ Scans all vendor modules for TOOL_META exports and returns them
5
+ as a unified registry. Enables parallel agent workflows: each vendor
6
+ tool defines its own TOOL_META, eliminating merge conflicts on cli.py.
7
+
8
+ Usage:
9
+ from evolver_tools.autoreg import auto_discover
10
+ tools = auto_discover() # Returns dict[str, dict]
11
+ """
12
+
13
+ import importlib
14
+ import os
15
+ import pkgutil
16
+
17
+ # Cache after first discovery
18
+ _TOOLS_CACHE = None
19
+
20
+
21
+ def _vendor_dir():
22
+ """Return the absolute path to the vendor directory."""
23
+ # vendor is a namespace package (no __init__.py), so __file__ is None
24
+ # Walk up from autoreg.py location
25
+ here = os.path.dirname(os.path.abspath(__file__))
26
+ return os.path.join(here, "vendor")
27
+
28
+
29
+ def auto_discover():
30
+ """Scan all vendor modules and return a unified TOOLS dict.
31
+
32
+ Each vendor module (file or package) that exports TOOL_META dict
33
+ is discovered automatically. No manual registration needed.
34
+
35
+ Returns:
36
+ dict[str, dict]: Tool name -> {module, func, desc}
37
+ """
38
+ global _TOOLS_CACHE
39
+ if _TOOLS_CACHE is not None:
40
+ return _TOOLS_CACHE
41
+
42
+ tools = {}
43
+ vendor_dir = _vendor_dir()
44
+
45
+ for importer, modname, ispkg in pkgutil.iter_modules([vendor_dir]):
46
+ try:
47
+ mod = importlib.import_module(f"evolver_tools.vendor.{modname}")
48
+ except Exception:
49
+ continue
50
+
51
+ meta = getattr(mod, "TOOL_META", None)
52
+ if meta is None:
53
+ continue
54
+
55
+ tool_name = meta.get("name")
56
+ if not tool_name:
57
+ continue
58
+
59
+ func_name = meta.get("func", "main")
60
+ desc = meta.get("desc", "")
61
+
62
+ # If the package has a submodule (e.g. cal_tool/cli.py), use that
63
+ submodule = meta.get("submodule", "")
64
+ if submodule:
65
+ module_path = f"evolver_tools.vendor.{modname}.{submodule}"
66
+ else:
67
+ module_path = f"evolver_tools.vendor.{modname}"
68
+
69
+ tools[tool_name] = {
70
+ "module": module_path,
71
+ "func": func_name,
72
+ "desc": desc,
73
+ }
74
+
75
+ _TOOLS_CACHE = tools
76
+ return tools
77
+
78
+
79
+ def list_tools():
80
+ """Print all discovered tools to stdout."""
81
+ tools = auto_discover()
82
+ print(f"Discovered {len(tools)} tools:")
83
+ for name in sorted(tools.keys()):
84
+ print(f" - {name}")
85
+
86
+
87
+ if __name__ == "__main__":
88
+ list_tools()
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """evolver CLI - Unified interface for all EVOLVER tools.
3
+
4
+ Tools are auto-discovered via TOOL_META in each vendor module.
5
+ No manual registration needed — just add TOOL_META to your vendor file.
6
+ """
7
+
8
+ import sys
9
+ import importlib
10
+
11
+ from evolver_tools.autoreg import auto_discover
12
+
13
+
14
+ def list_tools():
15
+ """Display all available tools."""
16
+ tools = auto_discover()
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v3.0.0 =====\x1b[0m')
18
+ print()
19
+ for name, info in sorted(tools.items()):
20
+ print(f' \033[1;33m{name:<18}\033[0m {info["desc"]}')
21
+ print()
22
+ print(f' Total: {len(tools)} tools')
23
+ print()
24
+ print('Usage: evolver <toolname> [args...]')
25
+ print(' evolver list')
26
+
27
+
28
+ def run_tool(tool_name, args):
29
+ tools = auto_discover()
30
+ if tool_name not in tools:
31
+ print(f'Unknown tool: {tool_name}')
32
+ sys.exit(1)
33
+ info = tools[tool_name]
34
+ mod_path = info["module"]
35
+ func_name = info["func"]
36
+ old_argv = sys.argv
37
+ sys.argv = [tool_name] + args
38
+ try:
39
+ mod = importlib.import_module(mod_path)
40
+ func = getattr(mod, func_name)
41
+ result = func()
42
+ if result is not None:
43
+ print(result)
44
+ except KeyboardInterrupt:
45
+ pass
46
+ except Exception as e:
47
+ print(f'Error running {tool_name}: {e}', file=sys.stderr)
48
+ sys.exit(1)
49
+ finally:
50
+ sys.argv = old_argv
51
+
52
+
53
+ def main():
54
+ if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help"):
55
+ list_tools()
56
+ return
57
+ tool_name = sys.argv[1]
58
+ args = sys.argv[2:]
59
+ if tool_name == "list":
60
+ list_tools()
61
+ return
62
+ run_tool(tool_name, args)
63
+
64
+
65
+ if __name__ == "__main__":
66
+ main()
@@ -0,0 +1,3 @@
1
+ """EVOLVER Tools — vendor CLI tools."""
2
+
3
+ __all__ = []
@@ -0,0 +1,9 @@
1
+ def main():
2
+ print('agent b')
3
+
4
+ # === Auto-registration metadata ===
5
+ TOOL_META = {
6
+ "name": "agent-b-tool",
7
+ "func": "main",
8
+ "desc": 'Agent B tool',
9
+ }
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env python3
2
+ """api-tester — HTTP API testing tool with method, headers, body, JSON, and timing support."""
3
+
4
+ import sys
5
+ import os
6
+ import argparse
7
+ import json
8
+ import time
9
+ import urllib.request
10
+ import urllib.error
11
+ import urllib.parse
12
+ import ssl
13
+
14
+ METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
15
+
16
+
17
+ def build_request(method, url, headers=None, data=None, json_data=None, timeout=30):
18
+ """Build and execute an HTTP request."""
19
+ if json_data is not None:
20
+ data = json.dumps(json_data).encode('utf-8')
21
+ if headers is None:
22
+ headers = {}
23
+ if 'Content-Type' not in {k.lower() for k in headers}:
24
+ headers['Content-Type'] = 'application/json'
25
+ elif data is not None and isinstance(data, str):
26
+ data = data.encode('utf-8')
27
+
28
+ req = urllib.request.Request(url, data=data, method=method.upper())
29
+ if headers:
30
+ for k, v in headers.items():
31
+ req.add_header(k, v)
32
+
33
+ ctx = ssl.create_default_context()
34
+ ctx.check_hostname = False
35
+ ctx.verify_mode = ssl.CERT_NONE
36
+ return req, ctx
37
+
38
+
39
+ def do_request(method, url, headers=None, data=None, json_data=None, timeout=30):
40
+ """Execute a single request and return result dict."""
41
+ req, ctx = build_request(method, url, headers, data, json_data, timeout)
42
+ start = time.time()
43
+ try:
44
+ resp = urllib.request.urlopen(req, context=ctx, timeout=timeout)
45
+ elapsed = time.time() - start
46
+ body = resp.read()
47
+ content_type = resp.headers.get('Content-Type', '')
48
+ if 'application/json' in content_type:
49
+ try:
50
+ body_parsed = json.loads(body)
51
+ body_str = json.dumps(body_parsed, indent=2)
52
+ except (json.JSONDecodeError, ValueError):
53
+ body_str = body.decode('utf-8', errors='replace')
54
+ else:
55
+ body_str = body.decode('utf-8', errors='replace')
56
+ return {
57
+ 'status': resp.status,
58
+ 'reason': resp.reason,
59
+ 'headers': dict(resp.headers),
60
+ 'body': body_str,
61
+ 'elapsed': elapsed,
62
+ 'error': None,
63
+ }
64
+ except urllib.error.HTTPError as e:
65
+ elapsed = time.time() - start
66
+ body = e.read()
67
+ body_str = body.decode('utf-8', errors='replace')
68
+ return {
69
+ 'status': e.code,
70
+ 'reason': e.reason,
71
+ 'headers': dict(e.headers),
72
+ 'body': body_str,
73
+ 'elapsed': elapsed,
74
+ 'error': None,
75
+ }
76
+ except urllib.error.URLError as e:
77
+ return {
78
+ 'status': 0,
79
+ 'reason': str(e.reason),
80
+ 'headers': {},
81
+ 'body': '',
82
+ 'elapsed': 0,
83
+ 'error': str(e.reason),
84
+ }
85
+ except Exception as e:
86
+ return {
87
+ 'status': 0,
88
+ 'reason': str(e),
89
+ 'headers': {},
90
+ 'body': '',
91
+ 'elapsed': 0,
92
+ 'error': str(e),
93
+ }
94
+
95
+
96
+ def print_result(result, show_headers=True, show_body=True, verbose=False):
97
+ """Print a formatted request result."""
98
+ elapsed = result['elapsed']
99
+ status = result['status']
100
+
101
+ if result['error']:
102
+ print(f"\033[91mERROR: {result['error']}\033[0m", file=sys.stderr)
103
+ return
104
+
105
+ if status >= 200 and status < 300:
106
+ color = '\033[92m'
107
+ elif status >= 300 and status < 400:
108
+ color = '\033[93m'
109
+ else:
110
+ color = '\033[91m'
111
+ print(f"{color}{status} {result['reason']}\033[0m (\033[94m{elapsed:.3f}s\033[0m)")
112
+
113
+ if show_headers and result['headers']:
114
+ print(f"\n\033[1mHeaders:\033[0m")
115
+ for k, v in result['headers'].items():
116
+ if verbose or k.lower() not in ('set-cookie', 'x-powered-by'):
117
+ print(f" \033[33m{k}\033[0m: {v}")
118
+
119
+ if show_body and result['body']:
120
+ print(f"\n\033[1mBody:\033[0m")
121
+ print(result['body'])
122
+
123
+
124
+ def benchmark(method, url, count, headers=None, data=None, json_data=None, timeout=30):
125
+ """Run multiple requests and show stats."""
126
+ times = []
127
+ statuses = {}
128
+ errors = 0
129
+
130
+ print(f"\033[1mBenchmarking: {method} {url}\033[0m")
131
+ print(f" Requests: {count}")
132
+ print()
133
+
134
+ for i in range(count):
135
+ result = do_request(method, url, headers, data, json_data, timeout)
136
+ times.append(result['elapsed'])
137
+ if result['error']:
138
+ errors += 1
139
+ else:
140
+ s = result['status']
141
+ statuses[s] = statuses.get(s, 0) + 1
142
+
143
+ elapsed_str = f"\033[94m{result['elapsed']:.3f}s\033[0m"
144
+ if result['error']:
145
+ print(f" [{i+1}/{count}] \033[91mERROR\033[0m - {result['error']} ({elapsed_str})")
146
+ else:
147
+ print(f" [{i+1}/{count}] {result['status']} ({elapsed_str})")
148
+
149
+ if times:
150
+ print(f"\n\033[1mSummary:\033[0m")
151
+ print(f" Total time: \033[94m{sum(times):.3f}s\033[0m")
152
+ print(f" Avg time: \033[94m{sum(times)/len(times):.3f}s\033[0m")
153
+ print(f" Min time: \033[94m{min(times):.3f}s\033[0m")
154
+ print(f" Max time: \033[94m{max(times):.3f}s\033[0m")
155
+ if len(times) > 1:
156
+ variance = sum((t - sum(times)/len(times))**2 for t in times) / len(times)
157
+ print(f" Std dev: \033[94m{variance**0.5:.3f}s\033[0m")
158
+ print(f" Errors: \033[91m{errors}\033[0m" if errors else f" Errors: 0")
159
+ if statuses:
160
+ status_str = ', '.join(f"{k}={v}" for k, v in sorted(statuses.items()))
161
+ print(f" Statuses: {status_str}")
162
+
163
+
164
+ def main():
165
+ parser = argparse.ArgumentParser(
166
+ description='HTTP API testing tool. Send requests and inspect responses.',
167
+ formatter_class=argparse.RawDescriptionHelpFormatter,
168
+ epilog="""
169
+ Examples:
170
+ api-tester GET https://api.example.com/users
171
+ api-tester POST https://api.example.com/users -H "Content-Type: application/json" -d '{"name":"test"}'
172
+ api-tester --benchmark 5 GET https://example.com
173
+ api-tester PUT https://api.example.com/users/1 -j '{"name":"updated"}'
174
+ api-tester DELETE https://api.example.com/users/1
175
+ """,
176
+ )
177
+ parser.add_argument('method', nargs='?', choices=METHODS, help='HTTP method')
178
+ parser.add_argument('url', nargs='?', help='Target URL')
179
+ parser.add_argument('-H', '--header', action='append', dest='headers', default=[],
180
+ help='Request header (key:value, repeatable)')
181
+ parser.add_argument('-d', '--data', help='Request body data (string)')
182
+ parser.add_argument('-j', '--json', dest='json_data', help='JSON body (parsed)')
183
+ parser.add_argument('--benchmark', type=int, metavar='N', help='Run N requests for benchmarking')
184
+ parser.add_argument('--timeout', type=int, default=30, help='Request timeout in seconds')
185
+ parser.add_argument('--no-headers', action='store_true', help='Hide response headers')
186
+ parser.add_argument('--no-body', action='store_true', help='Hide response body')
187
+ parser.add_argument('--verbose', '-v', action='store_true', help='Show all headers including verbose ones')
188
+
189
+ args = parser.parse_args()
190
+
191
+ if not args.method or not args.url:
192
+ parser.print_help()
193
+ sys.exit(1)
194
+
195
+ headers = {}
196
+ for h in args.headers:
197
+ if ':' in h:
198
+ k, v = h.split(':', 1)
199
+ headers[k.strip()] = v.strip()
200
+ else:
201
+ print(f"Invalid header format: {h} (expected key:value)", file=sys.stderr)
202
+ sys.exit(1)
203
+
204
+ json_data = None
205
+ if args.json_data:
206
+ try:
207
+ json_data = json.loads(args.json_data)
208
+ except json.JSONDecodeError as e:
209
+ print(f"Invalid JSON data: {e}", file=sys.stderr)
210
+ sys.exit(1)
211
+
212
+ data = args.data
213
+
214
+ try:
215
+ if args.benchmark:
216
+ benchmark(args.method, args.url, args.benchmark, headers, data, json_data, args.timeout)
217
+ else:
218
+ result = do_request(args.method, args.url, headers, data, json_data, args.timeout)
219
+ print_result(result, show_headers=not args.no_headers, show_body=not args.no_body, verbose=args.verbose)
220
+ except KeyboardInterrupt:
221
+ print("\nAborted by user.", file=sys.stderr)
222
+ sys.exit(1)
223
+ except Exception as e:
224
+ print(f"Error: {e}", file=sys.stderr)
225
+ sys.exit(1)
226
+
227
+
228
+
229
+ # === Auto-registration metadata ===
230
+ TOOL_META = {
231
+ "name": "api-tester",
232
+ "func": "main",
233
+ "desc": 'HTTP API testing tool',
234
+ }
235
+
236
+ if __name__ == '__main__':
237
+ main()