evolver-tools 13.0.0__tar.gz → 14.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 (225) hide show
  1. {evolver_tools-13.0.0/src/evolver_tools.egg-info → evolver_tools-14.0.0}/PKG-INFO +2 -2
  2. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/pyproject.toml +2 -2
  3. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/cli.py +1 -1
  4. evolver_tools-14.0.0/src/evolver_tools/vendor/ansi_strip.py +34 -0
  5. evolver_tools-14.0.0/src/evolver_tools/vendor/env_diff.py +69 -0
  6. evolver_tools-14.0.0/src/evolver_tools/vendor/file_joiner.py +86 -0
  7. evolver_tools-14.0.0/src/evolver_tools/vendor/file_splitter.py +129 -0
  8. evolver_tools-14.0.0/src/evolver_tools/vendor/git_log_pretty.py +51 -0
  9. evolver_tools-14.0.0/src/evolver_tools/vendor/git_stats.py +93 -0
  10. evolver_tools-14.0.0/src/evolver_tools/vendor/hash_file.py +63 -0
  11. evolver_tools-14.0.0/src/evolver_tools/vendor/ini2json.py +41 -0
  12. evolver_tools-14.0.0/src/evolver_tools/vendor/json2ini.py +51 -0
  13. evolver_tools-14.0.0/src/evolver_tools/vendor/key_value_store.py +123 -0
  14. evolver_tools-14.0.0/src/evolver_tools/vendor/screen_recorder.py +147 -0
  15. evolver_tools-14.0.0/src/evolver_tools/vendor/toml2json.py +58 -0
  16. evolver_tools-14.0.0/src/evolver_tools/vendor/uri_encode.py +39 -0
  17. evolver_tools-14.0.0/src/evolver_tools/vendor/web_download.py +77 -0
  18. evolver_tools-14.0.0/src/evolver_tools/vendor/yaml2toml.py +63 -0
  19. {evolver_tools-13.0.0 → evolver_tools-14.0.0/src/evolver_tools.egg-info}/PKG-INFO +2 -2
  20. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools.egg-info/SOURCES.txt +15 -0
  21. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/LICENSE +0 -0
  22. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/README.md +0 -0
  23. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/setup.cfg +0 -0
  24. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/__init__.py +0 -0
  25. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/__main__.py +0 -0
  26. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/autoreg.py +0 -0
  27. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/__init__.py +0 -0
  28. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/agent_b_tool.py +0 -0
  29. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/api_tester.py +0 -0
  30. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ascii_gen.py +0 -0
  31. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/audit_log.py +0 -0
  32. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/b64/__init__.py +0 -0
  33. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  34. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/backup.py +0 -0
  35. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/banner/__init__.py +0 -0
  36. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/banner/banner.py +0 -0
  37. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/banner.py +0 -0
  38. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/bookmark.py +0 -0
  39. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cal_tool/__init__.py +0 -0
  40. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +0 -0
  41. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/calendar_cli.py +0 -0
  42. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cert_check.py +0 -0
  43. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cert_info.py +0 -0
  44. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/changelog_gen/__init__.py +0 -0
  45. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +0 -0
  46. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/changelog_gen.py +0 -0
  47. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +0 -0
  48. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  49. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/checksum_dir.py +0 -0
  50. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/clipboard/__init__.py +0 -0
  51. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/clipboard/clipboard.py +0 -0
  52. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/code_auditor.py +0 -0
  53. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/code_stats.py +0 -0
  54. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/colorize.py +0 -0
  55. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/colors/__init__.py +0 -0
  56. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  57. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/config_validator.py +0 -0
  58. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/config_vault.py +0 -0
  59. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cron/__init__.py +0 -0
  60. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  61. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/cron_pretty.py +0 -0
  62. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/crontab_helper.py +0 -0
  63. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/crypto_box.py +0 -0
  64. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/crypto_price.py +0 -0
  65. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv2json.py +0 -0
  66. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv_stats/__init__.py +0 -0
  67. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  68. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  69. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +0 -0
  70. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/csv_validate.py +0 -0
  71. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/db_mate.py +0 -0
  72. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/db_schema.py +0 -0
  73. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dep_graph.py +0 -0
  74. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dev_dashboard.py +0 -0
  75. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dice_roll.py +0 -0
  76. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/diff_csv.py +0 -0
  77. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +0 -0
  78. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  79. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +0 -0
  80. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/disk_cleanup.py +0 -0
  81. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/disk_usage/__init__.py +0 -0
  82. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/disk_usage/disk_usage.py +0 -0
  83. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dns_lookup.py +0 -0
  84. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/docker_helper.py +0 -0
  85. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/dt_convert.py +0 -0
  86. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/env_manager.py +0 -0
  87. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +0 -0
  88. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/excel2csv.py +0 -0
  89. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ff/__init__.py +0 -0
  90. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  91. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/figlet_cli.py +0 -0
  92. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/figlet_tool.py +0 -0
  93. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/file_encrypt.py +0 -0
  94. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/file_watch.py +0 -0
  95. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/find_dups/__init__.py +0 -0
  96. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/find_dups/cli.py +0 -0
  97. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/firewall_rule.py +0 -0
  98. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/fmt/__init__.py +0 -0
  99. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/fmt/fmt.py +0 -0
  100. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/geo_ip.py +0 -0
  101. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/git_branch_cleaner.py +0 -0
  102. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +0 -0
  103. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  104. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/hex_tool.py +0 -0
  105. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/html2markdown.py +0 -0
  106. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/html2md.py +0 -0
  107. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/http_headers.py +0 -0
  108. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/http_live/__init__.py +0 -0
  109. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  110. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/image_meta.py +0 -0
  111. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ini_parser/__init__.py +0 -0
  112. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ini_parser/ini_parser.py +0 -0
  113. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ip_location.py +0 -0
  114. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +0 -0
  115. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  116. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ipinfo/__init__.py +0 -0
  117. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  118. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/join.py +0 -0
  119. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/joke.py +0 -0
  120. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +0 -0
  121. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  122. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/json2csv/__init__.py +0 -0
  123. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  124. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/json_pretty/__init__.py +0 -0
  125. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/json_pretty/json_pretty.py +0 -0
  126. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/json_schema_validate.py +0 -0
  127. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +0 -0
  128. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  129. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/license_cli/__init__.py +0 -0
  130. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  131. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/license_cli/cli.py +0 -0
  132. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/log_analyzer.py +0 -0
  133. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/log_hawk.py +0 -0
  134. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/log_tail.py +0 -0
  135. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/macrogen.py +0 -0
  136. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +0 -0
  137. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/markdown_preview.py +0 -0
  138. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/markdown_toc.py +0 -0
  139. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/media_studio.py +0 -0
  140. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/morse.py +0 -0
  141. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/nb/__init__.py +0 -0
  142. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  143. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/net_analyzer.py +0 -0
  144. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/net_speed.py +0 -0
  145. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/network_scan.py +0 -0
  146. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/note_taker.py +0 -0
  147. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/otp_gen.py +0 -0
  148. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/passgen/__init__.py +0 -0
  149. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/password_strength.py +0 -0
  150. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/pdf_text.py +0 -0
  151. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/pipe_viewer.py +0 -0
  152. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/portcheck/__init__.py +0 -0
  153. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +0 -0
  154. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/pr_tool/__init__.py +0 -0
  155. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/pr_tool/pr_tool.py +0 -0
  156. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/process_kill.py +0 -0
  157. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/progress_bar.py +0 -0
  158. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +0 -0
  159. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  160. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/qrcode.py +0 -0
  161. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/quote_tool/__init__.py +0 -0
  162. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/quote_tool/quote.py +0 -0
  163. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/rainbow.py +0 -0
  164. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/reminder.py +0 -0
  165. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ren/__init__.py +0 -0
  166. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  167. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/replace_text.py +0 -0
  168. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/restore.py +0 -0
  169. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/route_trace.py +0 -0
  170. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/scan_ports.py +0 -0
  171. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/screenshot_cli.py +0 -0
  172. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/search_files.py +0 -0
  173. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/search_history.py +0 -0
  174. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/secret_scanner.py +0 -0
  175. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/service_check.py +0 -0
  176. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/shuffle.py +0 -0
  177. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +0 -0
  178. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  179. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +0 -0
  180. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  181. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sort/__init__.py +0 -0
  182. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sort/sort.py +0 -0
  183. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/spinner.py +0 -0
  184. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/split.py +0 -0
  185. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/split_tool/__init__.py +0 -0
  186. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/split_tool/split.py +0 -0
  187. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sql2csv.py +0 -0
  188. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +0 -0
  189. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  190. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ssh_key_gen.py +0 -0
  191. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/ssl_check.py +0 -0
  192. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/stopwatch.py +0 -0
  193. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +0 -0
  194. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  195. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/sysmon_pro.py +0 -0
  196. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/system_info.py +0 -0
  197. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/temp_cleaner.py +0 -0
  198. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/text_stats.py +0 -0
  199. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/timer/__init__.py +0 -0
  200. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/timer_pro/__init__.py +0 -0
  201. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/timer_pro/timer_pro.py +0 -0
  202. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/timer_pro.py +0 -0
  203. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/todo_cli.py +0 -0
  204. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/treedir/__init__.py +0 -0
  205. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/treedir/__main__.py +0 -0
  206. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/uniq_tool/__init__.py +0 -0
  207. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/uniq_tool/uniq.py +0 -0
  208. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/unit_convert.py +0 -0
  209. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -0
  210. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +0 -0
  211. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +0 -0
  212. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  213. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/weather_cli.py +0 -0
  214. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +0 -0
  215. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  216. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/whois_lookup.py +0 -0
  217. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/wordcount/__init__.py +0 -0
  218. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +0 -0
  219. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/xml2json.py +0 -0
  220. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/yaml2json/__init__.py +0 -0
  221. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/yaml2json/yaml2json.py +0 -0
  222. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools/vendor/yaml_validate.py +0 -0
  223. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  224. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools.egg-info/entry_points.txt +0 -0
  225. {evolver_tools-13.0.0 → evolver_tools-14.0.0}/src/evolver_tools.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: evolver-tools
3
- Version: 13.0.0
4
- Summary: 144 CLI tools + 9 flagship projects — one pip install
3
+ Version: 14.0.0
4
+ Summary: 159 CLI tools + 9 flagship projects — one pip install
5
5
  Author: EVOLVER
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://evolver-dev.github.io/evolver-tools
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "evolver-tools"
7
- version = "13.0.0"
8
- description = "144 CLI tools + 9 flagship projects — one pip install"
7
+ version = "14.0.0"
8
+ description = "159 CLI tools + 9 flagship projects — one pip install"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  requires-python = ">=3.8"
@@ -14,7 +14,7 @@ from evolver_tools.autoreg import auto_discover
14
14
  def list_tools():
15
15
  """Display all available tools."""
16
16
  tools = auto_discover()
17
- print(f'\x1b[1;36m===== EVOLVER Tools v13.0.0 =====\x1b[0m')
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v14.0.0 =====\x1b[0m')
18
18
  print()
19
19
  for name, info in sorted(tools.items()):
20
20
  print(f' \033[1;33m{name:<18}\033[0m {info["desc"]}')
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env python3
2
+ """ansi-strip — Strip ANSI escape codes from text."""
3
+ import re
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "ansi-strip",
8
+ "func": "main",
9
+ "desc": "Strip ANSI escape codes. Usage: ansi-strip [file]",
10
+ }
11
+
12
+ ANSI_PATTERN = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
13
+
14
+ def main():
15
+ args = sys.argv[1:]
16
+ if args and args[0] in ("-h", "--help"):
17
+ print("Usage: ansi-strip [file]")
18
+ print(" command_with_colors | ansi-strip")
19
+ return
20
+ if args:
21
+ filepath = args[0]
22
+ try:
23
+ with open(filepath, "r") as f:
24
+ text = f.read()
25
+ except Exception as e:
26
+ print(f"Error: {e}", file=sys.stderr)
27
+ sys.exit(1)
28
+ else:
29
+ text = sys.stdin.read()
30
+ result = ANSI_PATTERN.sub("", text)
31
+ sys.stdout.write(result)
32
+
33
+ if __name__ == "__main__":
34
+ main()
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """env-diff — Compare two .env files."""
3
+ import os
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "env-diff",
8
+ "func": "main",
9
+ "desc": "Compare .env files. Usage: env-diff <file1.env> <file2.env>",
10
+ }
11
+
12
+ def parse_env(filepath):
13
+ vars = {}
14
+ with open(filepath) as f:
15
+ for line in f:
16
+ line = line.strip()
17
+ if not line or line.startswith("#"):
18
+ continue
19
+ if "=" in line:
20
+ key, val = line.split("=", 1)
21
+ vars[key.strip()] = val.strip().strip("\"'")
22
+ return vars
23
+
24
+ def main():
25
+ args = sys.argv[1:]
26
+ if len(args) < 2 or args[0] in ("-h", "--help"):
27
+ print("Usage: env-diff <file1.env> <file2.env>")
28
+ return
29
+ f1, f2 = args[0], args[1]
30
+ for f in [f1, f2]:
31
+ if not os.path.exists(f):
32
+ print(f"File not found: {f}", file=sys.stderr)
33
+ sys.exit(1)
34
+ env1 = parse_env(f1)
35
+ env2 = parse_env(f2)
36
+ keys1 = set(env1.keys())
37
+ keys2 = set(env2.keys())
38
+ only_in_1 = keys1 - keys2
39
+ only_in_2 = keys2 - keys1
40
+ common = keys1 & keys2
41
+ different = {k for k in common if env1[k] != env2[k]}
42
+ print(f"Comparison: {os.path.basename(f1)} vs {os.path.basename(f2)}")
43
+ print(f"Total vars: {len(keys1)} → {len(keys2)}")
44
+ print()
45
+ if only_in_1:
46
+ print(f"Only in {os.path.basename(f1)} ({len(only_in_1)}):")
47
+ for k in sorted(only_in_1):
48
+ print(f" + {k}={env1[k]}")
49
+ print()
50
+ if only_in_2:
51
+ print(f"Only in {os.path.basename(f2)} ({len(only_in_2)}):")
52
+ for k in sorted(only_in_2):
53
+ print(f" + {k}={env2[k]}")
54
+ print()
55
+ if different:
56
+ print(f"Different values ({len(different)}):")
57
+ for k in sorted(different):
58
+ print(f" * {k}")
59
+ print(f" - {env1[k]}")
60
+ print(f" + {env2[k]}")
61
+ print()
62
+ if not only_in_1 and not only_in_2 and not different:
63
+ print("✓ Files are identical")
64
+ else:
65
+ changed = len(only_in_1) + len(only_in_2) + len(different)
66
+ print(f"Summary: {changed} difference(s)")
67
+
68
+ if __name__ == "__main__":
69
+ main()
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python3
2
+ """file-joiner — Join split file chunks back together."""
3
+ import os
4
+ import re
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "file-joiner",
9
+ "func": "main",
10
+ "desc": "Join split file chunks. Usage: file-joiner <base_name> [--output file]",
11
+ }
12
+
13
+ def main():
14
+ args = sys.argv[1:]
15
+ if not args or args[0] in ("-h", "--help"):
16
+ print("Usage: file-joiner <base_name> [--output file]")
17
+ print(" Joins files matching base_name.part*")
18
+ return
19
+ base = args[0]
20
+ output = None
21
+ if "--output" in args:
22
+ idx = args.index("--output")
23
+ if idx + 1 < len(args):
24
+ output = args[idx + 1]
25
+ # Find parts
26
+ base_no_ext = os.path.splitext(base)[0]
27
+ ext = os.path.splitext(base)[1]
28
+ parts = []
29
+ pattern = re.compile(re.escape(base_no_ext) + r"\.part(\d+)" + re.escape(ext) + "$")
30
+ for f in os.listdir(os.path.dirname(base) or "."):
31
+ m = pattern.match(f)
32
+ if m:
33
+ parts.append((int(m.group(1)), f))
34
+ if not parts:
35
+ # Try *.part* pattern
36
+ pattern2 = re.compile(re.escape(base) + r"\.part(\d+)$")
37
+ for f in os.listdir("."):
38
+ m = pattern2.match(f)
39
+ if m:
40
+ parts.append((int(m.group(1)), f))
41
+ if not parts:
42
+ print(f"No parts found for: {base}", file=sys.stderr)
43
+ sys.exit(1)
44
+ parts.sort(key=lambda x: x[0])
45
+ if not output:
46
+ # Auto-detect output name
47
+ name_only = os.path.basename(base)
48
+ if ext:
49
+ output = base
50
+ else:
51
+ # Remove .part suffix
52
+ first_part = parts[0][1]
53
+ output = re.sub(r"\.part\d+", "", first_part)
54
+ if not os.path.splitext(output)[1]:
55
+ output = base # fallback
56
+ total_size = 0
57
+ is_binary = False
58
+ for _, part_path in parts:
59
+ try:
60
+ with open(part_path, "rb") as f:
61
+ header = f.read(1024)
62
+ if b"\x00" in header:
63
+ is_binary = True
64
+ break
65
+ except Exception:
66
+ pass
67
+ if is_binary:
68
+ with open(output, "wb") as out:
69
+ for _, part_path in parts:
70
+ with open(part_path, "rb") as pf:
71
+ data = pf.read()
72
+ out.write(data)
73
+ total_size += len(data)
74
+ print(f" + {part_path}")
75
+ else:
76
+ with open(output, "w") as out:
77
+ for _, part_path in parts:
78
+ with open(part_path, "r") as pf:
79
+ data = pf.read()
80
+ out.write(data)
81
+ total_size += len(data.encode())
82
+ print(f" + {part_path}")
83
+ print(f"\nJoined {len(parts)} parts → {output} ({total_size} bytes)")
84
+
85
+ if __name__ == "__main__":
86
+ main()
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env python3
2
+ """file-splitter — Split large files into smaller chunks."""
3
+ import os
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "file-splitter",
8
+ "func": "main",
9
+ "desc": "Split files into chunks. Usage: file-splitter <file> --lines N | --size N[K|M|G]",
10
+ }
11
+
12
+ def format_size(size):
13
+ for unit in ["B", "KB", "MB", "GB"]:
14
+ if size < 1024:
15
+ return f"{size:.1f}{unit}"
16
+ size /= 1024
17
+ return f"{size:.1f}TB"
18
+
19
+ def main():
20
+ args = sys.argv[1:]
21
+ if not args or args[0] in ("-h", "--help"):
22
+ print("Usage: file-splitter <file> --lines N")
23
+ print(" file-splitter <file> --size N[K|M|G]")
24
+ print(" file-splitter <file> --chunks N")
25
+ return
26
+ filepath = args[0]
27
+ if not os.path.exists(filepath):
28
+ print(f"File not found: {filepath}", file=sys.stderr)
29
+ sys.exit(1)
30
+ split_lines = None
31
+ split_size = None
32
+ num_chunks = None
33
+ i = 1
34
+ while i < len(args):
35
+ if args[i] == "--lines" and i + 1 < len(args):
36
+ split_lines = int(args[i + 1])
37
+ i += 2
38
+ elif args[i] == "--size" and i + 1 < len(args):
39
+ val = args[i + 1].upper()
40
+ if val.endswith("K"):
41
+ split_size = int(val[:-1]) * 1024
42
+ elif val.endswith("M"):
43
+ split_size = int(val[:-1]) * 1024 * 1024
44
+ elif val.endswith("G"):
45
+ split_size = int(val[:-1]) * 1024 * 1024 * 1024
46
+ else:
47
+ split_size = int(val)
48
+ i += 2
49
+ elif args[i] == "--chunks" and i + 1 < len(args):
50
+ num_chunks = int(args[i + 1])
51
+ i += 2
52
+ else:
53
+ i += 1
54
+ total_size = os.path.getsize(filepath)
55
+ total_lines = 0
56
+ with open(filepath) as f:
57
+ for _ in f:
58
+ total_lines += 1
59
+ if num_chunks:
60
+ split_lines = max(1, total_lines // num_chunks)
61
+ if split_lines:
62
+ base, ext = os.path.splitext(filepath)
63
+ chunk_num = 1
64
+ with open(filepath) as f:
65
+ out_lines = []
66
+ out_size = 0
67
+ for line in f:
68
+ out_lines.append(line)
69
+ out_size += len(line)
70
+ if len(out_lines) >= split_lines:
71
+ chunk_file = f"{base}.part{chunk_num:03d}{ext}"
72
+ with open(chunk_file, "w") as cf:
73
+ cf.writelines(out_lines)
74
+ print(f" Created: {chunk_file} ({format_size(out_size)})")
75
+ out_lines = []
76
+ out_size = 0
77
+ chunk_num += 1
78
+ if out_lines:
79
+ chunk_file = f"{base}.part{chunk_num:03d}{ext}"
80
+ with open(chunk_file, "w") as cf:
81
+ cf.writelines(out_lines)
82
+ print(f" Created: {chunk_file} ({format_size(out_size)})")
83
+ print(f"Split {filepath} into {chunk_num} parts ({format_size(total_size)} total)")
84
+ elif split_size:
85
+ base, ext = os.path.splitext(filepath)
86
+ chunk_num = 1
87
+ with open(filepath) as f:
88
+ out_data = b""
89
+ if ext.lower() in (".txt", ".py", ".md", ".json", ".csv", ".yaml", ".yml", ".xml", ".html", ".css", ".js"):
90
+ # Text mode
91
+ f_text = open(filepath, "r")
92
+ out_lines = []
93
+ out_bytes = 0
94
+ for line in f_text:
95
+ out_lines.append(line)
96
+ out_bytes += len(line.encode())
97
+ if out_bytes >= split_size:
98
+ chunk_file = f"{base}.part{chunk_num:03d}{ext}"
99
+ with open(chunk_file, "w") as cf:
100
+ cf.writelines(out_lines)
101
+ print(f" Created: {chunk_file} ({format_size(out_bytes)})")
102
+ out_lines = []
103
+ out_bytes = 0
104
+ chunk_num += 1
105
+ if out_lines:
106
+ chunk_file = f"{base}.part{chunk_num:03d}{ext}"
107
+ with open(chunk_file, "w") as cf:
108
+ cf.writelines(out_lines)
109
+ print(f" Created: {chunk_file} ({format_size(out_bytes)})")
110
+ f_text.close()
111
+ else:
112
+ # Binary mode
113
+ with open(filepath, "rb") as f:
114
+ while True:
115
+ chunk = f.read(split_size)
116
+ if not chunk:
117
+ break
118
+ chunk_file = f"{base}.part{chunk_num:03d}{ext}"
119
+ with open(chunk_file, "wb") as cf:
120
+ cf.write(chunk)
121
+ print(f" Created: {chunk_file} ({format_size(len(chunk))})")
122
+ chunk_num += 1
123
+ print(f"Split {filepath} into {chunk_num - 1} parts ({format_size(total_size)} total)")
124
+ else:
125
+ print("Specify --lines N, --size N, or --chunks N", file=sys.stderr)
126
+ sys.exit(1)
127
+
128
+ if __name__ == "__main__":
129
+ main()
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """git-log-pretty — Pretty git log with graph and formatting."""
3
+ import subprocess
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "git-log-pretty",
8
+ "func": "main",
9
+ "desc": "Pretty git log. Usage: git-log-pretty [--count N] [--author name]",
10
+ }
11
+
12
+ def main():
13
+ args = sys.argv[1:]
14
+ count = 20
15
+ author = None
16
+ i = 0
17
+ while i < len(args):
18
+ if args[i] == "--count" and i + 1 < len(args):
19
+ count = int(args[i + 1])
20
+ i += 2
21
+ elif args[i] == "--author" and i + 1 < len(args):
22
+ author = args[i + 1]
23
+ i += 2
24
+ else:
25
+ i += 1
26
+ # Use pretty git log format
27
+ fmt = "%C(auto)%h%d %C(cyan)%an%Creset %C(green)%ar%Creset%n%s"
28
+ git_cmd = ["git", "log", f"--pretty=format:{fmt}", f"-{count}", "--graph", "--date=relative"]
29
+ if author:
30
+ git_cmd.extend(["--author", author])
31
+ try:
32
+ result = subprocess.run(git_cmd, capture_output=True, text=True, timeout=15)
33
+ if result.returncode != 0:
34
+ print("Not a git repository", file=sys.stderr)
35
+ sys.exit(1)
36
+ output = result.stdout
37
+ if output.strip():
38
+ print(output)
39
+ # Show tag info
40
+ tag_cmd = ["git", "describe", "--tags", "--abbrev=0", "HEAD"]
41
+ tag_result = subprocess.run(tag_cmd, capture_output=True, text=True, timeout=5)
42
+ if tag_result.returncode == 0:
43
+ print(f"\nLatest tag: {tag_result.stdout.strip()}")
44
+ else:
45
+ print("No commits found")
46
+ except subprocess.TimeoutExpired:
47
+ print("Command timed out", file=sys.stderr)
48
+ sys.exit(1)
49
+
50
+ if __name__ == "__main__":
51
+ main()
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python3
2
+ """git-stats — Show git contribution statistics."""
3
+ import subprocess
4
+ import sys
5
+ from collections import defaultdict
6
+
7
+ TOOL_META = {
8
+ "name": "git-stats",
9
+ "func": "main",
10
+ "desc": "Show git contribution stats. Usage: git-stats [--author name] [--since 30.days]",
11
+ }
12
+
13
+ def main():
14
+ args = sys.argv[1:]
15
+ author = None
16
+ since = None
17
+ i = 0
18
+ while i < len(args):
19
+ if args[i] == "--author" and i + 1 < len(args):
20
+ author = args[i + 1]
21
+ i += 2
22
+ elif args[i] == "--since" and i + 1 < len(args):
23
+ since = args[i + 1]
24
+ i += 2
25
+ else:
26
+ i += 1
27
+ git_cmd = ["git", "log", "--format=%an|%ae|%s", "--no-merges"]
28
+ if author:
29
+ git_cmd.extend(["--author", author])
30
+ if since:
31
+ git_cmd.extend(["--since", since])
32
+ try:
33
+ result = subprocess.run(git_cmd, capture_output=True, text=True, timeout=15)
34
+ if result.returncode != 0:
35
+ print("Not a git repository", file=sys.stderr)
36
+ sys.exit(1)
37
+ commits = result.stdout.strip().split("\n")
38
+ if not commits or commits == [""]:
39
+ print("No commits found")
40
+ return
41
+ author_commits = defaultdict(int)
42
+ author_lines = defaultdict(lambda: {"added": 0, "deleted": 0})
43
+ for commit in commits:
44
+ if "|" not in commit:
45
+ continue
46
+ parts = commit.split("|", 2)
47
+ if len(parts) < 2:
48
+ continue
49
+ name = parts[0].strip()
50
+ author_commits[name] += 1
51
+ # Get detailed stats
52
+ stat_cmd = ["git", "log", "--format=%an|%ae", "--no-merges", "--numstat"]
53
+ if author:
54
+ stat_cmd.extend(["--author", author])
55
+ if since:
56
+ stat_cmd.extend(["--since", since])
57
+ stat_result = subprocess.run(stat_cmd, capture_output=True, text=True, timeout=30)
58
+ if stat_result.returncode == 0:
59
+ current_author = None
60
+ for line in stat_result.stdout.split("\n"):
61
+ if "|" in line:
62
+ parts = line.split("|", 1)
63
+ current_author = parts[0].strip()
64
+ elif line.strip() and current_author:
65
+ parts = line.split("\t")
66
+ if len(parts) >= 3:
67
+ try:
68
+ added = int(parts[0]) if parts[0] != "-" else 0
69
+ deleted = int(parts[1]) if parts[1] != "-" else 0
70
+ author_lines[current_author]["added"] += added
71
+ author_lines[current_author]["deleted"] += deleted
72
+ except ValueError:
73
+ pass
74
+ print(f"Git Stats (since: {since or 'beginning'})")
75
+ print("=" * 60)
76
+ print(f"{'Author':<25} {'Commits':>8} {'Added':>8} {'Deleted':>8}")
77
+ print("-" * 60)
78
+ sorted_authors = sorted(author_commits.items(), key=lambda x: -x[1])
79
+ for name, count in sorted_authors:
80
+ added = author_lines[name]["added"] if name in author_lines else 0
81
+ deleted = author_lines[name]["deleted"] if name in author_lines else 0
82
+ print(f"{name:<25} {count:>8} {added:>8} {deleted:>8}")
83
+ total_commits = sum(author_commits.values())
84
+ total_added = sum(a["added"] for a in author_lines.values())
85
+ total_deleted = sum(a["deleted"] for a in author_lines.values())
86
+ print("-" * 60)
87
+ print(f"{'TOTAL':<25} {total_commits:>8} {total_added:>8} {total_deleted:>8}")
88
+ except subprocess.TimeoutExpired:
89
+ print("Command timed out", file=sys.stderr)
90
+ sys.exit(1)
91
+
92
+ if __name__ == "__main__":
93
+ main()
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """hash-file — Compute file hashes (MD5, SHA1, SHA256, SHA512)."""
3
+ import hashlib
4
+ import os
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "hash-file",
9
+ "func": "main",
10
+ "desc": "Compute file hashes. Usage: hash-file <file> [--md5|--sha1|--sha256|--sha512|--all]",
11
+ }
12
+
13
+ HASH_ALGOS = {
14
+ "md5": hashlib.md5,
15
+ "sha1": hashlib.sha1,
16
+ "sha256": hashlib.sha256,
17
+ "sha512": hashlib.sha512,
18
+ }
19
+
20
+ def main():
21
+ args = sys.argv[1:]
22
+ if not args or args[0] in ("-h", "--help"):
23
+ print("Usage: hash-file <file> [--md5|--sha1|--sha256|--sha512|--all]")
24
+ print(" Default: --sha256")
25
+ return
26
+ filepath = args[0]
27
+ if not os.path.exists(filepath):
28
+ print(f"File not found: {filepath}", file=sys.stderr)
29
+ sys.exit(1)
30
+ # Determine which algorithms
31
+ algos = []
32
+ if "--all" in args:
33
+ algos = ["md5", "sha1", "sha256", "sha512"]
34
+ else:
35
+ for a in ["--md5", "--sha1", "--sha256", "--sha512"]:
36
+ if a in args:
37
+ algos.append(a[2:]) # remove --
38
+ if not algos:
39
+ algos = ["sha256"] # default
40
+ # Compute
41
+ hashers = {name: HASH_ALGOS[name]() for name in algos if name in HASH_ALGOS}
42
+ file_size = os.path.getsize(filepath)
43
+ try:
44
+ with open(filepath, "rb") as f:
45
+ while True:
46
+ chunk = f.read(65536)
47
+ if not chunk:
48
+ break
49
+ for h in hashers.values():
50
+ h.update(chunk)
51
+ except Exception as e:
52
+ print(f"Error reading file: {e}", file=sys.stderr)
53
+ sys.exit(1)
54
+ # Output
55
+ print(f"File: {filepath}")
56
+ print(f"Size: {file_size:,} bytes")
57
+ print()
58
+ for name in algos:
59
+ if name in hashers:
60
+ print(f"{name.upper():>6}: {hashers[name].hexdigest()}")
61
+
62
+ if __name__ == "__main__":
63
+ main()
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+ """ini2json — Convert INI/CFG files to JSON."""
3
+ import json
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "ini2json",
8
+ "func": "main",
9
+ "desc": "Convert INI to JSON. Usage: ini2json <file.ini> [--pretty]",
10
+ }
11
+
12
+ def main():
13
+ args = sys.argv[1:]
14
+ if not args or args[0] in ("-h", "--help"):
15
+ print("Usage: ini2json <file.ini> [--pretty]")
16
+ print(" cat file.ini | ini2json")
17
+ return
18
+ pretty = "--pretty" in args
19
+ filepath = None
20
+ for a in args:
21
+ if not a.startswith("-"):
22
+ filepath = a
23
+ break
24
+ import configparser
25
+ config = configparser.ConfigParser()
26
+ try:
27
+ if filepath:
28
+ config.read(filepath)
29
+ else:
30
+ config.read_string(sys.stdin.read())
31
+ except Exception as e:
32
+ print(f"Error: {e}", file=sys.stderr)
33
+ sys.exit(1)
34
+ result = {}
35
+ for section in config.sections():
36
+ result[section] = dict(config[section])
37
+ indent = 2 if pretty else None
38
+ print(json.dumps(result, indent=indent, default=str))
39
+
40
+ if __name__ == "__main__":
41
+ main()
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env python3
2
+ """json2ini — Convert JSON to INI format."""
3
+ import json
4
+ import os
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "json2ini",
9
+ "func": "main",
10
+ "desc": "Convert JSON to INI format. Usage: json2ini <file.json>",
11
+ }
12
+
13
+ def to_ini(data):
14
+ lines = []
15
+ if not isinstance(data, dict):
16
+ print("Error: JSON must be an object", file=sys.stderr)
17
+ sys.exit(1)
18
+ for section, values in data.items():
19
+ lines.append(f"[{section}]")
20
+ if isinstance(values, dict):
21
+ for key, val in values.items():
22
+ lines.append(f"{key} = {val}")
23
+ else:
24
+ lines.append(f"value = {values}")
25
+ lines.append("")
26
+ return "\n".join(lines)
27
+
28
+ def main():
29
+ args = sys.argv[1:]
30
+ if not args or args[0] in ("-h", "--help"):
31
+ print("Usage: json2ini <file.json>")
32
+ print(" cat file.json | json2ini")
33
+ return
34
+ filepath = None
35
+ for a in args:
36
+ if not a.startswith("-"):
37
+ filepath = a
38
+ break
39
+ try:
40
+ if filepath:
41
+ with open(filepath) as f:
42
+ data = json.load(f)
43
+ else:
44
+ data = json.loads(sys.stdin.read())
45
+ except Exception as e:
46
+ print(f"Error: {e}", file=sys.stderr)
47
+ sys.exit(1)
48
+ print(to_ini(data))
49
+
50
+ if __name__ == "__main__":
51
+ main()