evolver-tools 20.0.0__tar.gz → 22.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 (263) hide show
  1. {evolver_tools-20.0.0/src/evolver_tools.egg-info → evolver_tools-22.0.0}/PKG-INFO +2 -2
  2. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/pyproject.toml +2 -2
  3. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/cli.py +1 -1
  4. evolver_tools-22.0.0/src/evolver_tools/vendor/crc_check.py +77 -0
  5. evolver_tools-22.0.0/src/evolver_tools/vendor/csv_merge.py +158 -0
  6. evolver_tools-22.0.0/src/evolver_tools/vendor/date_diff.py +99 -0
  7. evolver_tools-22.0.0/src/evolver_tools/vendor/diff_files.py +86 -0
  8. evolver_tools-22.0.0/src/evolver_tools/vendor/env_template.py +81 -0
  9. evolver_tools-22.0.0/src/evolver_tools/vendor/http_server.py +66 -0
  10. evolver_tools-22.0.0/src/evolver_tools/vendor/json_flatten.py +81 -0
  11. evolver_tools-22.0.0/src/evolver_tools/vendor/math_eval.py +86 -0
  12. evolver_tools-22.0.0/src/evolver_tools/vendor/pdf_info.py +106 -0
  13. evolver_tools-22.0.0/src/evolver_tools/vendor/uuid_gen.py +77 -0
  14. {evolver_tools-20.0.0 → evolver_tools-22.0.0/src/evolver_tools.egg-info}/PKG-INFO +2 -2
  15. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools.egg-info/SOURCES.txt +10 -0
  16. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/LICENSE +0 -0
  17. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/README.md +0 -0
  18. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/setup.cfg +0 -0
  19. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/__init__.py +0 -0
  20. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/__main__.py +0 -0
  21. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/autoreg.py +0 -0
  22. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/__init__.py +0 -0
  23. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/agent_b_tool.py +0 -0
  24. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ansi_strip.py +0 -0
  25. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/api_tester.py +0 -0
  26. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ascii_gen.py +0 -0
  27. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/audit_log.py +0 -0
  28. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/b64/__init__.py +0 -0
  29. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  30. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/backup.py +0 -0
  31. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/banner/__init__.py +0 -0
  32. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/banner/banner.py +0 -0
  33. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/banner.py +0 -0
  34. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/base32.py +0 -0
  35. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/bookmark.py +0 -0
  36. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cal_tool/__init__.py +0 -0
  37. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +0 -0
  38. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/calendar_cli.py +0 -0
  39. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cert_check.py +0 -0
  40. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cert_info.py +0 -0
  41. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/changelog_gen/__init__.py +0 -0
  42. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +0 -0
  43. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/changelog_gen.py +0 -0
  44. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +0 -0
  45. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  46. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/checksum_dir.py +0 -0
  47. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/clipboard/__init__.py +0 -0
  48. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/clipboard/clipboard.py +0 -0
  49. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/code_auditor.py +0 -0
  50. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/code_stats.py +0 -0
  51. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/colorize.py +0 -0
  52. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/colors/__init__.py +0 -0
  53. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  54. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/config_validator.py +0 -0
  55. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/config_vault.py +0 -0
  56. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cowsay.py +0 -0
  57. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cron/__init__.py +0 -0
  58. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  59. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/cron_pretty.py +0 -0
  60. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/crontab_helper.py +0 -0
  61. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/crypto_box.py +0 -0
  62. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/crypto_price.py +0 -0
  63. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv2json.py +0 -0
  64. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_stats/__init__.py +0 -0
  65. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  66. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  67. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +0 -0
  68. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_validate.py +0 -0
  69. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/csv_view.py +0 -0
  70. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/db_mate.py +0 -0
  71. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/db_schema.py +0 -0
  72. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dep_graph.py +0 -0
  73. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dev_dashboard.py +0 -0
  74. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dice_roll.py +0 -0
  75. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/diff_csv.py +0 -0
  76. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +0 -0
  77. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  78. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +0 -0
  79. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/disk_cleanup.py +0 -0
  80. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/disk_usage/__init__.py +0 -0
  81. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/disk_usage/disk_usage.py +0 -0
  82. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dns_lookup.py +0 -0
  83. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/docker_helper.py +0 -0
  84. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/dt_convert.py +0 -0
  85. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/env_diff.py +0 -0
  86. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/env_manager.py +0 -0
  87. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +0 -0
  88. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/epoch.py +0 -0
  89. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/excel2csv.py +0 -0
  90. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/factor.py +0 -0
  91. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ff/__init__.py +0 -0
  92. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  93. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/figlet_cli.py +0 -0
  94. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/figlet_tool.py +0 -0
  95. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/file_encrypt.py +0 -0
  96. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/file_joiner.py +0 -0
  97. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/file_splitter.py +0 -0
  98. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/file_watch.py +0 -0
  99. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/find_dups/__init__.py +0 -0
  100. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/find_dups/cli.py +0 -0
  101. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/firewall_rule.py +0 -0
  102. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/fmt/__init__.py +0 -0
  103. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/fmt/fmt.py +0 -0
  104. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/fold.py +0 -0
  105. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/geo_ip.py +0 -0
  106. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/git_branch_cleaner.py +0 -0
  107. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/git_log_pretty.py +0 -0
  108. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/git_stats.py +0 -0
  109. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hash_check.py +0 -0
  110. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hash_file.py +0 -0
  111. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +0 -0
  112. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  113. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hex_tool.py +0 -0
  114. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/hexdump.py +0 -0
  115. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/html2markdown.py +0 -0
  116. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/html2md.py +0 -0
  117. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/http_headers.py +0 -0
  118. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/http_live/__init__.py +0 -0
  119. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  120. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/image_meta.py +0 -0
  121. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ini2json.py +0 -0
  122. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ini_parser/__init__.py +0 -0
  123. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ini_parser/ini_parser.py +0 -0
  124. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ip_location.py +0 -0
  125. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +0 -0
  126. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  127. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ipinfo/__init__.py +0 -0
  128. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  129. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/join.py +0 -0
  130. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/joke.py +0 -0
  131. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +0 -0
  132. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  133. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json2csv/__init__.py +0 -0
  134. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  135. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json2ini.py +0 -0
  136. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json_pretty/__init__.py +0 -0
  137. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json_pretty/json_pretty.py +0 -0
  138. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/json_schema_validate.py +0 -0
  139. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +0 -0
  140. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  141. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/key_value_store.py +0 -0
  142. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/license.py +0 -0
  143. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/license_cli/__init__.py +0 -0
  144. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  145. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/license_cli/cli.py +0 -0
  146. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/log_analyzer.py +0 -0
  147. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/log_hawk.py +0 -0
  148. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/log_tail.py +0 -0
  149. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/macrogen.py +0 -0
  150. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +0 -0
  151. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/markdown_preview.py +0 -0
  152. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/markdown_toc.py +0 -0
  153. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/media_studio.py +0 -0
  154. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/morse.py +0 -0
  155. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/nb/__init__.py +0 -0
  156. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  157. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/net_analyzer.py +0 -0
  158. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/net_speed.py +0 -0
  159. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/network_scan.py +0 -0
  160. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/nl.py +0 -0
  161. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/note_taker.py +0 -0
  162. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/otp_gen.py +0 -0
  163. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/passgen/__init__.py +0 -0
  164. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/password_strength.py +0 -0
  165. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/pdf_text.py +0 -0
  166. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/pipe_viewer.py +0 -0
  167. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/pomodoro.py +0 -0
  168. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/port_scan.py +0 -0
  169. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/portcheck/__init__.py +0 -0
  170. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +0 -0
  171. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/pr_tool/__init__.py +0 -0
  172. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/pr_tool/pr_tool.py +0 -0
  173. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/process_kill.py +0 -0
  174. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/progress_bar.py +0 -0
  175. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +0 -0
  176. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  177. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/qc_calc.py +0 -0
  178. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/qc_report.py +0 -0
  179. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/qc_sample.py +0 -0
  180. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/qr_cli.py +0 -0
  181. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/qrcode.py +0 -0
  182. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/quote.py +0 -0
  183. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/quote_tool/__init__.py +0 -0
  184. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/quote_tool/quote.py +0 -0
  185. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/rainbow.py +0 -0
  186. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/random.py +0 -0
  187. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/reminder.py +0 -0
  188. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ren/__init__.py +0 -0
  189. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  190. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/replace_text.py +0 -0
  191. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/restore.py +0 -0
  192. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/rot13.py +0 -0
  193. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/route_trace.py +0 -0
  194. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/scan_ports.py +0 -0
  195. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/screen_recorder.py +0 -0
  196. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/screenshot_cli.py +0 -0
  197. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/search_files.py +0 -0
  198. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/search_history.py +0 -0
  199. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/secret_scanner.py +0 -0
  200. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/seq.py +0 -0
  201. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/service_check.py +0 -0
  202. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/shuffle.py +0 -0
  203. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +0 -0
  204. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  205. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +0 -0
  206. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  207. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sort/__init__.py +0 -0
  208. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sort/sort.py +0 -0
  209. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/spinner.py +0 -0
  210. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/split.py +0 -0
  211. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/split_tool/__init__.py +0 -0
  212. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/split_tool/split.py +0 -0
  213. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sql2csv.py +0 -0
  214. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +0 -0
  215. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  216. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ssh_key_gen.py +0 -0
  217. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/ssl_check.py +0 -0
  218. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/stopwatch.py +0 -0
  219. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/subnet.py +0 -0
  220. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +0 -0
  221. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  222. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/sysmon_pro.py +0 -0
  223. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/system_info.py +0 -0
  224. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/temp_cleaner.py +0 -0
  225. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/template.py +0 -0
  226. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/text_stats.py +0 -0
  227. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/timeout.py +0 -0
  228. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/timer/__init__.py +0 -0
  229. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/timer_pro/__init__.py +0 -0
  230. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/timer_pro/timer_pro.py +0 -0
  231. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/timer_pro.py +0 -0
  232. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/todo_cli.py +0 -0
  233. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/toml2json.py +0 -0
  234. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/tr.py +0 -0
  235. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/tree.py +0 -0
  236. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/treedir/__init__.py +0 -0
  237. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/treedir/__main__.py +0 -0
  238. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/uniq_tool/__init__.py +0 -0
  239. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/uniq_tool/uniq.py +0 -0
  240. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/unit_convert.py +0 -0
  241. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/uri_encode.py +0 -0
  242. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/url_parser.py +0 -0
  243. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -0
  244. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +0 -0
  245. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +0 -0
  246. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  247. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/watch.py +0 -0
  248. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/weather_cli.py +0 -0
  249. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/web_download.py +0 -0
  250. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +0 -0
  251. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  252. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/whois_lookup.py +0 -0
  253. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/wordcount/__init__.py +0 -0
  254. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +0 -0
  255. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/xml2json.py +0 -0
  256. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/yaml2json/__init__.py +0 -0
  257. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/yaml2json/yaml2json.py +0 -0
  258. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/yaml2toml.py +0 -0
  259. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/yaml_validate.py +0 -0
  260. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools/vendor/yes.py +0 -0
  261. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  262. {evolver_tools-20.0.0 → evolver_tools-22.0.0}/src/evolver_tools.egg-info/entry_points.txt +0 -0
  263. {evolver_tools-20.0.0 → evolver_tools-22.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: 20.0.0
4
- Summary: 186 CLI tools + 9 flagship projects — one pip install
3
+ Version: 22.0.0
4
+ Summary: 196 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 = "20.0.0"
8
- description = "186 CLI tools + 9 flagship projects — one pip install"
7
+ version = "22.0.0"
8
+ description = "196 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 v20.0.0 =====\x1b[0m')
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v22.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,77 @@
1
+ #!/usr/bin/env python3
2
+ """crc_check — CRC32/CRC64 checksum calculator for files.
3
+
4
+ Usage: crc_check file.bin
5
+ crc_check --crc64 file.bin
6
+ crc_check --all file.bin
7
+ cat file.bin | crc_check
8
+
9
+ Verify file integrity with CRC checksums.
10
+ Zero external dependencies (zlib.crc32 + pure Python CRC64).
11
+ """
12
+
13
+ import sys
14
+ import os
15
+ import zlib
16
+
17
+ TOOL_META = {
18
+ "name": "crc_check",
19
+ "func": "main",
20
+ "desc": "CRC32/CRC64 checksum calculator for files",
21
+ }
22
+
23
+ def crc64(data):
24
+ """Compute CRC64-ECMA-182."""
25
+ poly = 0xC96C5795D7870F42
26
+ crc = 0xFFFFFFFFFFFFFFFF
27
+ for byte in data:
28
+ crc ^= byte
29
+ for _ in range(8):
30
+ if crc & 1:
31
+ crc = (crc >> 1) ^ poly
32
+ else:
33
+ crc >>= 1
34
+ return crc ^ 0xFFFFFFFFFFFFFFFF
35
+
36
+
37
+ def main():
38
+ args = sys.argv[1:]
39
+ mode = 'crc32'
40
+ files = []
41
+
42
+ i = 0
43
+ while i < len(args):
44
+ if args[i] in ('-h', '--help'):
45
+ print(__doc__)
46
+ return
47
+ elif args[i] == '--crc64':
48
+ mode = 'crc64'
49
+ i += 1
50
+ elif args[i] == '--all':
51
+ mode = 'all'
52
+ i += 1
53
+ elif args[i].startswith('--'):
54
+ print(f"Unknown flag: {args[i]}", file=sys.stderr)
55
+ sys.exit(1)
56
+ else:
57
+ files.append(args[i])
58
+ i += 1
59
+
60
+ if files:
61
+ for path in files:
62
+ if not os.path.exists(path):
63
+ print(f"Error: file not found: {path}", file=sys.stderr)
64
+ sys.exit(1)
65
+ with open(path, 'rb') as f:
66
+ data = f.read()
67
+ name = os.path.basename(path)
68
+ if mode in ('crc32', 'all'):
69
+ print(f"CRC32({name}) = {zlib.crc32(data) & 0xFFFFFFFF:08x}")
70
+ if mode in ('crc64', 'all'):
71
+ print(f"CRC64({name}) = {crc64(data):016x}")
72
+ else:
73
+ data = sys.stdin.buffer.read()
74
+ if mode in ('crc32', 'all'):
75
+ print(f"CRC32 = {zlib.crc32(data) & 0xFFFFFFFF:08x}")
76
+ if mode in ('crc64', 'all'):
77
+ print(f"CRC64 = {crc64(data):016x}")
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env python3
2
+ """csv_merge — Merge multiple CSV files by a common column.
3
+
4
+ Usage: csv_merge file1.csv file2.csv --on id
5
+ csv_merge file1.csv file2.csv --on id --how outer
6
+ csv_merge *.csv --on user_id --output merged.csv
7
+
8
+ Joins CSV files on a common key column, like SQL JOIN.
9
+ Supports inner, left, and outer joins.
10
+ Zero external dependencies.
11
+ """
12
+
13
+ import csv
14
+ import sys
15
+ import os
16
+ from collections import OrderedDict
17
+
18
+ TOOL_META = {
19
+ "name": "csv_merge",
20
+ "func": "main",
21
+ "desc": "Merge CSV files by common column (inner/left/outer join)",
22
+ }
23
+
24
+ def load_csv(path):
25
+ with open(path, newline='', encoding='utf-8-sig') as f:
26
+ reader = csv.DictReader(f)
27
+ rows = list(reader)
28
+ if not rows:
29
+ return [], []
30
+ return rows, list(rows[0].keys())
31
+
32
+
33
+ def main():
34
+ args = sys.argv[1:]
35
+ if not args or args[0] in ('-h', '--help'):
36
+ print(__doc__)
37
+ return
38
+
39
+ # Parse --on, --how, --output
40
+ on_col = None
41
+ how = 'inner'
42
+ output = None
43
+ files = []
44
+
45
+ i = 0
46
+ while i < len(args):
47
+ if args[i] == '--on' and i + 1 < len(args):
48
+ on_col = args[i + 1]
49
+ i += 2
50
+ elif args[i] == '--how' and i + 1 < len(args):
51
+ how = args[i + 1].lower()
52
+ i += 2
53
+ elif args[i] == '--output' and i + 1 < len(args):
54
+ output = args[i + 1]
55
+ i += 2
56
+ else:
57
+ files.append(args[i])
58
+ i += 1
59
+
60
+ if len(files) < 2:
61
+ print("Error: need at least 2 CSV files", file=sys.stderr)
62
+ sys.exit(1)
63
+
64
+ if not on_col:
65
+ print("Error: --on <column> required", file=sys.stderr)
66
+ sys.exit(1)
67
+
68
+ # Load all CSVs
69
+ tables = []
70
+ for f in files:
71
+ if not os.path.exists(f):
72
+ print(f"Error: file not found: {f}", file=sys.stderr)
73
+ sys.exit(1)
74
+ rows, cols = load_csv(f)
75
+ tables.append((os.path.basename(f), rows, cols))
76
+
77
+ # Build lookup from first file
78
+ lookup = {}
79
+ for row in tables[0][1]:
80
+ key = row.get(on_col, '')
81
+ lookup[key] = row
82
+
83
+ # Merge subsequent files
84
+ merged = []
85
+ all_cols_set = OrderedDict()
86
+ for t in tables:
87
+ for c in t[2]:
88
+ all_cols_set[c] = True
89
+
90
+ all_cols = list(all_cols_set.keys())
91
+
92
+ if how == 'inner':
93
+ for t in tables[1:]:
94
+ for row in t[1]:
95
+ key = row.get(on_col, '')
96
+ if key in lookup:
97
+ merged_row = OrderedDict()
98
+ for c in all_cols:
99
+ merged_row[c] = lookup[key].get(c, '') or row.get(c, '')
100
+ merged.append(merged_row)
101
+ # For inner, merge first two then subsequent
102
+ if len(tables) > 2:
103
+ # Re-merge with remaining tables
104
+ temp = merged
105
+ for t in tables[2:]:
106
+ merged2 = []
107
+ t_lookup = {r.get(on_col, ''): r for r in t[1]}
108
+ for row in temp:
109
+ key = row.get(on_col, '')
110
+ if key in t_lookup:
111
+ merged_row = OrderedDict(row)
112
+ for c in t_lookup[key]:
113
+ if c != on_col and c not in merged_row:
114
+ merged_row[c] = t_lookup[key][c]
115
+ merged2.append(merged_row)
116
+ temp = merged2
117
+ merged = temp
118
+ elif how == 'left':
119
+ merged = list(lookup.values())
120
+ for t in tables[1:]:
121
+ t_lookup = {r.get(on_col, ''): r for r in t[1]}
122
+ for row in merged:
123
+ key = row.get(on_col, '')
124
+ if key in t_lookup:
125
+ for c, v in t_lookup[key].items():
126
+ if c != on_col and c not in row:
127
+ row[c] = v
128
+ elif how == 'outer':
129
+ all_keys = set()
130
+ for t in tables:
131
+ for r in t[1]:
132
+ all_keys.add(r.get(on_col, ''))
133
+ key_rows = {}
134
+ for t in tables:
135
+ for r in t[1]:
136
+ k = r.get(on_col, '')
137
+ if k not in key_rows:
138
+ key_rows[k] = OrderedDict()
139
+ key_rows[k][on_col] = k
140
+ for c, v in r.items():
141
+ if c != on_col and v:
142
+ key_rows[k][c] = v
143
+ merged = list(key_rows.values())
144
+ else:
145
+ print(f"Error: unknown join type: {how} (use inner/left/outer)", file=sys.stderr)
146
+ sys.exit(1)
147
+
148
+ # Write output
149
+ if output:
150
+ with open(output, 'w', newline='', encoding='utf-8') as f:
151
+ writer = csv.DictWriter(f, fieldnames=list(all_cols_set.keys()))
152
+ writer.writeheader()
153
+ writer.writerows(merged)
154
+ print(f"Merged {len(merged)} rows -> {output}")
155
+ else:
156
+ writer = csv.DictWriter(sys.stdout, fieldnames=list(all_cols_set.keys()))
157
+ writer.writeheader()
158
+ writer.writerows(merged)
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env python3
2
+ """date_diff — Calculate date/time differences.
3
+
4
+ Usage: date_diff 2026-01-01 2026-06-01
5
+ date_diff 2026-01-01 2026-06-01 --unit hours
6
+ date_diff now "2026-12-25"
7
+ date_diff "2026-01-01 09:00" "2026-01-01 17:30" --unit minutes
8
+
9
+ Show difference in days, hours, minutes, or seconds between two dates.
10
+ Accepts ISO 8601 dates, 'now', and datetime strings.
11
+ """
12
+
13
+ import sys
14
+ from datetime import datetime
15
+
16
+ TOOL_META = {
17
+ "name": "date_diff",
18
+ "func": "main",
19
+ "desc": "Calculate date/time differences",
20
+ }
21
+
22
+ def parse_date(s):
23
+ if s.lower() == 'now':
24
+ return datetime.now()
25
+ for fmt in ('%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d',
26
+ '%Y/%m/%d %H:%M:%S', '%Y/%m/%d %H:%M', '%Y/%m/%d',
27
+ '%m/%d/%Y', '%d/%m/%Y'):
28
+ try:
29
+ return datetime.strptime(s, fmt)
30
+ except ValueError:
31
+ continue
32
+ raise ValueError(f"Cannot parse date: {s}")
33
+
34
+
35
+ def main():
36
+ args = sys.argv[1:]
37
+ if not args or args[0] in ('-h', '--help'):
38
+ print(__doc__)
39
+ return
40
+
41
+ unit = 'days'
42
+ date_strs = []
43
+
44
+ i = 0
45
+ while i < len(args):
46
+ if args[i] == '--unit' and i + 1 < len(args):
47
+ unit = args[i + 1].lower()
48
+ i += 2
49
+ elif args[i].startswith('--'):
50
+ print(f"Unknown flag: {args[i]}", file=sys.stderr)
51
+ sys.exit(1)
52
+ else:
53
+ date_strs.append(args[i])
54
+ i += 1
55
+
56
+ if len(date_strs) < 2:
57
+ print("Error: need two dates", file=sys.stderr)
58
+ sys.exit(1)
59
+
60
+ try:
61
+ d1 = parse_date(date_strs[0])
62
+ d2 = parse_date(date_strs[1])
63
+ except ValueError as e:
64
+ print(f"Error: {e}", file=sys.stderr)
65
+ sys.exit(1)
66
+
67
+ delta = abs(d2 - d1)
68
+ total_seconds = delta.total_seconds()
69
+
70
+ if unit in ('days', 'day', 'd'):
71
+ result = total_seconds / 86400
72
+ label = 'days'
73
+ elif unit in ('hours', 'hour', 'h'):
74
+ result = total_seconds / 3600
75
+ label = 'hours'
76
+ elif unit in ('minutes', 'minute', 'min', 'm'):
77
+ result = total_seconds / 60
78
+ label = 'minutes'
79
+ elif unit in ('seconds', 'second', 'sec', 's'):
80
+ result = total_seconds
81
+ label = 'seconds'
82
+ elif unit in ('weeks', 'week', 'w'):
83
+ result = total_seconds / 604800
84
+ label = 'weeks'
85
+ elif unit in ('months', 'month'):
86
+ # Approximate
87
+ result = total_seconds / (86400 * 30.44)
88
+ label = 'months'
89
+ elif unit in ('years', 'year', 'y'):
90
+ result = total_seconds / (86400 * 365.25)
91
+ label = 'years'
92
+ else:
93
+ print(f"Error: unknown unit: {unit}", file=sys.stderr)
94
+ sys.exit(1)
95
+
96
+ if result == int(result):
97
+ print(f"{int(result)} {label}")
98
+ else:
99
+ print(f"{result:.2f} {label}")
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env python3
2
+ """diff_files — Line-by-line file comparison.
3
+
4
+ Usage: diff_files file1.txt file2.txt
5
+ diff_files file1.txt file2.txt --context 3
6
+ diff_files file1.txt file2.txt --brief
7
+
8
+ Simple diff tool. Shows added/removed lines with +/- markers.
9
+ Zero external dependencies (pure Python difflib).
10
+ """
11
+
12
+ import difflib
13
+ import sys
14
+ import os
15
+
16
+ TOOL_META = {
17
+ "name": "diff_files",
18
+ "func": "main",
19
+ "desc": "Line-by-line file comparison",
20
+ }
21
+
22
+
23
+ def main():
24
+ args = sys.argv[1:]
25
+ context = 3
26
+ brief = False
27
+ files = []
28
+
29
+ i = 0
30
+ while i < len(args):
31
+ if args[i] == '--context' and i + 1 < len(args):
32
+ context = int(args[i + 1])
33
+ i += 2
34
+ elif args[i] == '--brief' or args[i] == '-q':
35
+ brief = True
36
+ i += 1
37
+ elif args[i] in ('-h', '--help'):
38
+ print(__doc__)
39
+ return
40
+ else:
41
+ files.append(args[i])
42
+ i += 1
43
+
44
+ if len(files) != 2:
45
+ print("Error: need exactly 2 files", file=sys.stderr)
46
+ print(__doc__)
47
+ sys.exit(1)
48
+
49
+ file1, file2 = files
50
+ for f in (file1, file2):
51
+ if not os.path.exists(f):
52
+ print(f"Error: file not found: {f}", file=sys.stderr)
53
+ sys.exit(1)
54
+
55
+ with open(file1) as f:
56
+ lines1 = f.readlines()
57
+ with open(file2) as f:
58
+ lines2 = f.readlines()
59
+
60
+ if brief:
61
+ if lines1 != lines2:
62
+ print(f"Files {file1} and {file2} differ")
63
+ else:
64
+ print(f"Files {file1} and {file2} are identical")
65
+ return
66
+
67
+ diff = difflib.unified_diff(
68
+ lines1, lines2,
69
+ fromfile=file1, tofile=file2,
70
+ n=context
71
+ )
72
+
73
+ output = list(diff)
74
+ if not output:
75
+ print("Files are identical.")
76
+ return
77
+
78
+ for line in output:
79
+ if line.startswith('+') and not line.startswith('+++'):
80
+ sys.stdout.write(f'\033[32m{line}\033[0m')
81
+ elif line.startswith('-') and not line.startswith('---'):
82
+ sys.stdout.write(f'\033[31m{line}\033[0m')
83
+ elif line.startswith('@@'):
84
+ sys.stdout.write(f'\033[36m{line}\033[0m')
85
+ else:
86
+ sys.stdout.write(line)
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ """env_template — Generate .env.example from .env (strip values, keep keys).
3
+
4
+ Usage: env_template # Reads .env, writes .env.example
5
+ env_template .env.prod # Reads specific file
6
+ env_template --stdout # Print to stdout instead
7
+
8
+ Strip all values from .env files, keeping only the keys and comments.
9
+ Useful for committing a safe .env.example to version control.
10
+ """
11
+
12
+ import sys
13
+ import os
14
+ import re
15
+
16
+ TOOL_META = {
17
+ "name": "env_template",
18
+ "func": "main",
19
+ "desc": "Generate .env.example from .env (strip values, keep keys)",
20
+ }
21
+
22
+
23
+ def main():
24
+ args = sys.argv[1:]
25
+ input_file = '.env'
26
+ stdout_mode = False
27
+ output_file = '.env.example'
28
+
29
+ for arg in args:
30
+ if arg == '--stdout':
31
+ stdout_mode = True
32
+ elif arg in ('-h', '--help'):
33
+ print(__doc__)
34
+ return
35
+ elif not arg.startswith('--'):
36
+ input_file = arg
37
+ else:
38
+ print(f"Unknown flag: {arg}", file=sys.stderr)
39
+ sys.exit(1)
40
+
41
+ if not os.path.exists(input_file):
42
+ print(f"Error: {input_file} not found", file=sys.stderr)
43
+ sys.exit(1)
44
+
45
+ with open(input_file) as f:
46
+ lines = f.readlines()
47
+
48
+ result = []
49
+ for line in lines:
50
+ stripped = line.rstrip('\n')
51
+ # Comment line — keep as-is
52
+ if stripped.strip().startswith('#'):
53
+ result.append(stripped)
54
+ # Empty line — keep
55
+ elif not stripped.strip():
56
+ result.append('')
57
+ # Key=value line — strip value
58
+ elif '=' in stripped:
59
+ key = stripped.split('=', 1)[0].strip()
60
+ # Detect inline comments after key
61
+ comment = ''
62
+ cm = re.search(r'\s+#.*$', stripped)
63
+ if cm:
64
+ comment = cm.group()
65
+ result.append(f"{key}={comment.strip() if comment else ''}")
66
+ else:
67
+ # Keep lines that don't match known patterns
68
+ result.append(stripped)
69
+
70
+ output = '\n'.join(result)
71
+
72
+ if stdout_mode:
73
+ print(output)
74
+ else:
75
+ if not output_file:
76
+ base, _ = os.path.splitext(input_file)
77
+ output_file = f"{base}.example"
78
+ with open(output_file, 'w') as f:
79
+ f.write(output)
80
+ f.write('\n')
81
+ print(f"Written {output_file} ({len([l for l in result if '=' in l])} keys)")
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """http_server — Simple static file HTTP server.
3
+
4
+ Usage: http_server # Port 8080, current dir
5
+ http_server 3000 # Port 3000
6
+ http_server 8080 ./docs # Port 8080, serve ./docs
7
+ http_server --bind 0.0.0.0 9090
8
+
9
+ Lightweight alternative to 'python -m http.server' with
10
+ better defaults and cleaner output.
11
+ """
12
+
13
+ import os
14
+ import sys
15
+ import http.server
16
+ import socketserver
17
+
18
+ TOOL_META = {
19
+ "name": "http_server",
20
+ "func": "main",
21
+ "desc": "Simple static file HTTP server",
22
+ }
23
+
24
+
25
+ def main():
26
+ args = sys.argv[1:]
27
+ port = 8080
28
+ directory = os.getcwd()
29
+ bind = '127.0.0.1'
30
+
31
+ i = 0
32
+ while i < len(args):
33
+ if args[i] == '--bind' and i + 1 < len(args):
34
+ bind = args[i + 1]
35
+ i += 2
36
+ elif args[i] in ('-h', '--help'):
37
+ print(__doc__)
38
+ return
39
+ else:
40
+ try:
41
+ port = int(args[i])
42
+ except ValueError:
43
+ directory = os.path.abspath(args[i])
44
+ i += 1
45
+
46
+ if not os.path.isdir(directory):
47
+ print(f"Error: directory not found: {directory}", file=sys.stderr)
48
+ sys.exit(1)
49
+
50
+ os.chdir(directory)
51
+ handler = http.server.SimpleHTTPRequestHandler
52
+
53
+ class SilentHandler(handler):
54
+ def log_message(self, fmt, *args):
55
+ sys.stderr.write(f"[HTTP] {args[0]} {args[1]} {args[2]}\n")
56
+
57
+ try:
58
+ with socketserver.TCPServer((bind, port), SilentHandler) as httpd:
59
+ print(f"Serving {directory} at http://{bind}:{port}")
60
+ print("Press Ctrl+C to stop")
61
+ httpd.serve_forever()
62
+ except OSError as e:
63
+ print(f"Error: {e}", file=sys.stderr)
64
+ sys.exit(1)
65
+ except KeyboardInterrupt:
66
+ print("\nStopped.")
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env python3
2
+ """json_flatten — Flatten nested JSON to dot-notation key=value pairs.
3
+
4
+ Usage: json_flatten data.json
5
+ json_flatten data.json --sep /
6
+ cat data.json | json_flatten
7
+
8
+ Useful for converting nested JSON to flat key-value format
9
+ for CSV export, env files, or debugging.
10
+ """
11
+
12
+ import json
13
+ import sys
14
+ import os
15
+
16
+ TOOL_META = {
17
+ "name": "json_flatten",
18
+ "func": "main",
19
+ "desc": "Flatten nested JSON to dot-notation key=value pairs",
20
+ }
21
+
22
+ def flatten(obj, parent_key='', sep='.'):
23
+ items = []
24
+ if isinstance(obj, dict):
25
+ for k, v in obj.items():
26
+ new_key = f"{parent_key}{sep}{k}" if parent_key else k
27
+ if isinstance(v, (dict, list)):
28
+ items.extend(flatten(v, new_key, sep=sep))
29
+ else:
30
+ items.append((new_key, v))
31
+ elif isinstance(obj, list):
32
+ for i, v in enumerate(obj):
33
+ new_key = f"{parent_key}{sep}{i}" if parent_key else str(i)
34
+ if isinstance(v, (dict, list)):
35
+ items.extend(flatten(v, new_key, sep=sep))
36
+ else:
37
+ items.append((new_key, v))
38
+ else:
39
+ items.append((parent_key, obj))
40
+ return items
41
+
42
+
43
+ def main():
44
+ args = sys.argv[1:]
45
+ sep = '.'
46
+ files = []
47
+
48
+ i = 0
49
+ while i < len(args):
50
+ if args[i] == '--sep' and i + 1 < len(args):
51
+ sep = args[i + 1]
52
+ i += 2
53
+ elif args[i] in ('-h', '--help'):
54
+ print(__doc__)
55
+ return
56
+ else:
57
+ files.append(args[i])
58
+ i += 1
59
+
60
+ if files:
61
+ data = []
62
+ for f in files:
63
+ if not os.path.exists(f):
64
+ print(f"Error: file not found: {f}", file=sys.stderr)
65
+ sys.exit(1)
66
+ with open(f) as fp:
67
+ data.append(json.load(fp))
68
+ if len(data) == 1:
69
+ data = data[0]
70
+ else:
71
+ data = json.load(sys.stdin)
72
+
73
+ items = flatten(data, sep=sep)
74
+ for key, val in items:
75
+ if val is None:
76
+ val = 'null'
77
+ elif isinstance(val, bool):
78
+ val = str(val).lower()
79
+ elif isinstance(val, (int, float)):
80
+ val = str(val)
81
+ print(f"{key}={val}")