evolver-tools 11.0.0__tar.gz → 13.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 (210) hide show
  1. {evolver_tools-11.0.0/src/evolver_tools.egg-info → evolver_tools-13.0.0}/PKG-INFO +2 -2
  2. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/pyproject.toml +2 -2
  3. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/cli.py +1 -1
  4. evolver_tools-13.0.0/src/evolver_tools/vendor/calendar_cli.py +45 -0
  5. evolver_tools-13.0.0/src/evolver_tools/vendor/cert_info.py +95 -0
  6. evolver_tools-13.0.0/src/evolver_tools/vendor/code_stats.py +130 -0
  7. evolver_tools-13.0.0/src/evolver_tools/vendor/cron_pretty.py +128 -0
  8. evolver_tools-13.0.0/src/evolver_tools/vendor/csv2json.py +52 -0
  9. evolver_tools-13.0.0/src/evolver_tools/vendor/csv_validate.py +63 -0
  10. evolver_tools-13.0.0/src/evolver_tools/vendor/disk_cleanup.py +107 -0
  11. evolver_tools-13.0.0/src/evolver_tools/vendor/dns_lookup.py +91 -0
  12. evolver_tools-13.0.0/src/evolver_tools/vendor/docker_helper.py +74 -0
  13. evolver_tools-13.0.0/src/evolver_tools/vendor/file_watch.py +66 -0
  14. evolver_tools-13.0.0/src/evolver_tools/vendor/geo_ip.py +71 -0
  15. evolver_tools-13.0.0/src/evolver_tools/vendor/hex_tool.py +59 -0
  16. evolver_tools-13.0.0/src/evolver_tools/vendor/http_headers.py +46 -0
  17. evolver_tools-13.0.0/src/evolver_tools/vendor/json_schema_validate.py +113 -0
  18. evolver_tools-13.0.0/src/evolver_tools/vendor/macrogen.py +113 -0
  19. evolver_tools-13.0.0/src/evolver_tools/vendor/markdown_preview.py +100 -0
  20. evolver_tools-13.0.0/src/evolver_tools/vendor/markdown_toc.py +40 -0
  21. evolver_tools-13.0.0/src/evolver_tools/vendor/network_scan.py +81 -0
  22. evolver_tools-13.0.0/src/evolver_tools/vendor/pdf_text.py +97 -0
  23. evolver_tools-13.0.0/src/evolver_tools/vendor/pipe_viewer.py +77 -0
  24. evolver_tools-13.0.0/src/evolver_tools/vendor/replace_text.py +73 -0
  25. evolver_tools-13.0.0/src/evolver_tools/vendor/route_trace.py +88 -0
  26. evolver_tools-13.0.0/src/evolver_tools/vendor/screenshot_cli.py +57 -0
  27. evolver_tools-13.0.0/src/evolver_tools/vendor/search_files.py +101 -0
  28. evolver_tools-13.0.0/src/evolver_tools/vendor/search_history.py +79 -0
  29. evolver_tools-13.0.0/src/evolver_tools/vendor/secret_scanner.py +82 -0
  30. evolver_tools-13.0.0/src/evolver_tools/vendor/system_info.py +132 -0
  31. evolver_tools-13.0.0/src/evolver_tools/vendor/temp_cleaner.py +99 -0
  32. evolver_tools-13.0.0/src/evolver_tools/vendor/whois_lookup.py +65 -0
  33. evolver_tools-13.0.0/src/evolver_tools/vendor/yaml_validate.py +59 -0
  34. {evolver_tools-11.0.0 → evolver_tools-13.0.0/src/evolver_tools.egg-info}/PKG-INFO +2 -2
  35. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools.egg-info/SOURCES.txt +30 -0
  36. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/LICENSE +0 -0
  37. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/README.md +0 -0
  38. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/setup.cfg +0 -0
  39. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/__init__.py +0 -0
  40. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/__main__.py +0 -0
  41. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/autoreg.py +0 -0
  42. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/__init__.py +0 -0
  43. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/agent_b_tool.py +0 -0
  44. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/api_tester.py +0 -0
  45. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ascii_gen.py +0 -0
  46. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/audit_log.py +0 -0
  47. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/b64/__init__.py +0 -0
  48. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  49. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/backup.py +0 -0
  50. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/banner/__init__.py +0 -0
  51. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/banner/banner.py +0 -0
  52. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/banner.py +0 -0
  53. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/bookmark.py +0 -0
  54. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/cal_tool/__init__.py +0 -0
  55. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +0 -0
  56. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/cert_check.py +0 -0
  57. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/changelog_gen/__init__.py +0 -0
  58. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +0 -0
  59. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/changelog_gen.py +0 -0
  60. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +0 -0
  61. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  62. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/checksum_dir.py +0 -0
  63. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/clipboard/__init__.py +0 -0
  64. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/clipboard/clipboard.py +0 -0
  65. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/code_auditor.py +0 -0
  66. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/colorize.py +0 -0
  67. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/colors/__init__.py +0 -0
  68. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  69. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/config_validator.py +0 -0
  70. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/config_vault.py +0 -0
  71. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/cron/__init__.py +0 -0
  72. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  73. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/crontab_helper.py +0 -0
  74. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/crypto_box.py +0 -0
  75. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/crypto_price.py +0 -0
  76. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/csv_stats/__init__.py +0 -0
  77. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  78. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  79. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +0 -0
  80. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/db_mate.py +0 -0
  81. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/db_schema.py +0 -0
  82. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/dep_graph.py +0 -0
  83. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/dev_dashboard.py +0 -0
  84. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/dice_roll.py +0 -0
  85. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/diff_csv.py +0 -0
  86. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +0 -0
  87. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  88. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +0 -0
  89. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/disk_usage/__init__.py +0 -0
  90. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/disk_usage/disk_usage.py +0 -0
  91. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/dt_convert.py +0 -0
  92. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/env_manager.py +0 -0
  93. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +0 -0
  94. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/excel2csv.py +0 -0
  95. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ff/__init__.py +0 -0
  96. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  97. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/figlet_cli.py +0 -0
  98. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/figlet_tool.py +0 -0
  99. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/file_encrypt.py +0 -0
  100. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/find_dups/__init__.py +0 -0
  101. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/find_dups/cli.py +0 -0
  102. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/firewall_rule.py +0 -0
  103. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/fmt/__init__.py +0 -0
  104. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/fmt/fmt.py +0 -0
  105. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/git_branch_cleaner.py +0 -0
  106. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +0 -0
  107. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  108. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/html2markdown.py +0 -0
  109. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/html2md.py +0 -0
  110. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/http_live/__init__.py +0 -0
  111. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  112. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/image_meta.py +0 -0
  113. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ini_parser/__init__.py +0 -0
  114. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ini_parser/ini_parser.py +0 -0
  115. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ip_location.py +0 -0
  116. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +0 -0
  117. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  118. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ipinfo/__init__.py +0 -0
  119. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  120. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/join.py +0 -0
  121. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/joke.py +0 -0
  122. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +0 -0
  123. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  124. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/json2csv/__init__.py +0 -0
  125. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  126. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/json_pretty/__init__.py +0 -0
  127. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/json_pretty/json_pretty.py +0 -0
  128. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +0 -0
  129. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  130. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/license_cli/__init__.py +0 -0
  131. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  132. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/license_cli/cli.py +0 -0
  133. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/log_analyzer.py +0 -0
  134. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/log_hawk.py +0 -0
  135. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/log_tail.py +0 -0
  136. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +0 -0
  137. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/media_studio.py +0 -0
  138. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/morse.py +0 -0
  139. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/nb/__init__.py +0 -0
  140. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  141. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/net_analyzer.py +0 -0
  142. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/net_speed.py +0 -0
  143. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/note_taker.py +0 -0
  144. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/otp_gen.py +0 -0
  145. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/passgen/__init__.py +0 -0
  146. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/password_strength.py +0 -0
  147. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/portcheck/__init__.py +0 -0
  148. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +0 -0
  149. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/pr_tool/__init__.py +0 -0
  150. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/pr_tool/pr_tool.py +0 -0
  151. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/process_kill.py +0 -0
  152. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/progress_bar.py +0 -0
  153. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +0 -0
  154. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  155. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/qrcode.py +0 -0
  156. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/quote_tool/__init__.py +0 -0
  157. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/quote_tool/quote.py +0 -0
  158. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/rainbow.py +0 -0
  159. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/reminder.py +0 -0
  160. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ren/__init__.py +0 -0
  161. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  162. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/restore.py +0 -0
  163. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/scan_ports.py +0 -0
  164. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/service_check.py +0 -0
  165. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/shuffle.py +0 -0
  166. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +0 -0
  167. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  168. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +0 -0
  169. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  170. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sort/__init__.py +0 -0
  171. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sort/sort.py +0 -0
  172. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/spinner.py +0 -0
  173. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/split.py +0 -0
  174. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/split_tool/__init__.py +0 -0
  175. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/split_tool/split.py +0 -0
  176. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sql2csv.py +0 -0
  177. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +0 -0
  178. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  179. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ssh_key_gen.py +0 -0
  180. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/ssl_check.py +0 -0
  181. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/stopwatch.py +0 -0
  182. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +0 -0
  183. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  184. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/sysmon_pro.py +0 -0
  185. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/text_stats.py +0 -0
  186. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/timer/__init__.py +0 -0
  187. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/timer_pro/__init__.py +0 -0
  188. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/timer_pro/timer_pro.py +0 -0
  189. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/timer_pro.py +0 -0
  190. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/todo_cli.py +0 -0
  191. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/treedir/__init__.py +0 -0
  192. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/treedir/__main__.py +0 -0
  193. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/uniq_tool/__init__.py +0 -0
  194. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/uniq_tool/uniq.py +0 -0
  195. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/unit_convert.py +0 -0
  196. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -0
  197. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +0 -0
  198. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +0 -0
  199. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  200. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/weather_cli.py +0 -0
  201. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +0 -0
  202. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  203. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/wordcount/__init__.py +0 -0
  204. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +0 -0
  205. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/xml2json.py +0 -0
  206. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/yaml2json/__init__.py +0 -0
  207. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools/vendor/yaml2json/yaml2json.py +0 -0
  208. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  209. {evolver_tools-11.0.0 → evolver_tools-13.0.0}/src/evolver_tools.egg-info/entry_points.txt +0 -0
  210. {evolver_tools-11.0.0 → evolver_tools-13.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: 11.0.0
4
- Summary: 122 CLI tools + 9 flagship projects — one pip install
3
+ Version: 13.0.0
4
+ Summary: 144 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 = "11.0.0"
8
- description = "122 CLI tools + 9 flagship projects — one pip install"
7
+ version = "13.0.0"
8
+ description = "144 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 v11.0.0 =====\x1b[0m')
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v13.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,45 @@
1
+ #!/usr/bin/env python3
2
+ """calendar-cli — Display a terminal calendar."""
3
+ import calendar
4
+ import sys
5
+ from datetime import datetime
6
+
7
+ TOOL_META = {
8
+ "name": "calendar-cli",
9
+ "func": "main",
10
+ "desc": "Display terminal calendar. Usage: calendar-cli [year] [month]",
11
+ }
12
+
13
+ def main():
14
+ args = sys.argv[1:]
15
+ now = datetime.now()
16
+ year = now.year
17
+ month = now.month
18
+ if len(args) >= 2:
19
+ try:
20
+ year = int(args[0])
21
+ month = int(args[1])
22
+ except ValueError:
23
+ print("Usage: calendar-cli [year] [month]", file=sys.stderr)
24
+ sys.exit(1)
25
+ elif len(args) >= 1:
26
+ try:
27
+ year = int(args[0])
28
+ month = None
29
+ except ValueError:
30
+ print("Usage: calendar-cli [year] [month]", file=sys.stderr)
31
+ sys.exit(1)
32
+ cal = calendar.TextCalendar()
33
+ if month:
34
+ cal_str = cal.formatmonth(year, month)
35
+ # Highlight today
36
+ if year == now.year and month == now.month:
37
+ today = str(now.day)
38
+ cal_str = cal_str.replace(f" {today} ", f"[{today}]")
39
+ cal_str = cal_str.replace(f"{today} ", f"[{today}]")
40
+ print(cal_str)
41
+ else:
42
+ print(cal.formatyear(year))
43
+
44
+ if __name__ == "__main__":
45
+ main()
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python3
2
+ """cert-info — Display SSL certificate details for a domain."""
3
+ import ssl
4
+ import socket
5
+ import sys
6
+ from datetime import datetime
7
+
8
+ TOOL_META = {
9
+ "name": "cert-info",
10
+ "func": "main",
11
+ "desc": "Show SSL certificate info for a domain. Usage: cert-info <domain> [port]",
12
+ }
13
+
14
+ def main():
15
+ args = sys.argv[1:]
16
+ if not args or args[0] in ("-h", "--help"):
17
+ print("Usage: cert-info <domain> [port]", file=sys.stderr)
18
+ print(" Default port: 443", file=sys.stderr)
19
+ sys.exit(1)
20
+ host = args[0]
21
+ port = int(args[1]) if len(args) > 1 else 443
22
+ try:
23
+ ctx = ssl.create_default_context()
24
+ with socket.create_connection((host, port), timeout=10) as sock:
25
+ with ctx.wrap_socket(sock, server_hostname=host) as ssock:
26
+ cert = ssock.getpeercert()
27
+ if not cert:
28
+ print(f"No certificate returned by {host}:{port}", file=sys.stderr)
29
+ sys.exit(1)
30
+ print(f"SSL Certificate for {host}:{port}")
31
+ print("=" * 50)
32
+ # Subject
33
+ subject = dict(x[0] for x in cert.get("subject", []))
34
+ print(f"Subject:")
35
+ for key, val in subject.items():
36
+ print(f" {key}: {val}")
37
+ # Issuer
38
+ issuer = dict(x[0] for x in cert.get("issuer", []))
39
+ print(f"Issuer:")
40
+ for key, val in issuer.items():
41
+ print(f" {key}: {val}")
42
+ # Validity
43
+ print(f"Valid from: {cert.get('notBefore', 'N/A')}")
44
+ print(f"Valid until: {cert.get('notAfter', 'N/A')}")
45
+ # Check expiry
46
+ try:
47
+ not_after = cert.get("notAfter", "")
48
+ expiry = datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z")
49
+ now = datetime.utcnow()
50
+ remaining = (expiry - now).days
51
+ if remaining < 0:
52
+ print(f"⚠ EXPIRED {abs(remaining)} days ago!")
53
+ elif remaining < 30:
54
+ print(f"⚠ Expires in {remaining} days (soon!)")
55
+ else:
56
+ print(f"✓ Expires in {remaining} days")
57
+ except Exception:
58
+ pass
59
+ # SAN
60
+ san = cert.get("subjectAltName", [])
61
+ if san:
62
+ print(f"Subject Alt Names ({len(san)}):")
63
+ for _, name in san[:10]:
64
+ print(f" {name}")
65
+ if len(san) > 10:
66
+ print(f" ... and {len(san) - 10} more")
67
+ # Serial
68
+ serial = cert.get("serialNumber", "")
69
+ if serial:
70
+ print(f"Serial: {serial}")
71
+ # Version
72
+ print(f"Version: {cert.get('version', 'N/A')}")
73
+ # Fingerprints
74
+ try:
75
+ der = ssock.getpeercert(binary_form=True)
76
+ import hashlib
77
+ print(f"SHA256: {hashlib.sha256(der).hexdigest()}")
78
+ print(f"SHA1: {hashlib.sha1(der).hexdigest()}")
79
+ except Exception:
80
+ pass
81
+ except ssl.SSLError as e:
82
+ print(f"SSL Error: {e}", file=sys.stderr)
83
+ sys.exit(1)
84
+ except socket.gaierror:
85
+ print(f"Could not resolve: {host}", file=sys.stderr)
86
+ sys.exit(1)
87
+ except socket.timeout:
88
+ print(f"Connection timed out: {host}:{port}", file=sys.stderr)
89
+ sys.exit(1)
90
+ except Exception as e:
91
+ print(f"Error: {e}", file=sys.stderr)
92
+ sys.exit(1)
93
+
94
+ if __name__ == "__main__":
95
+ main()
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env python3
2
+ """code-stats — Code line statistics by language."""
3
+ import os
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "code-stats",
8
+ "func": "main",
9
+ "desc": "Count lines of code by language. Usage: code-stats [path]",
10
+ }
11
+
12
+ EXT_MAP = {
13
+ ".py": "Python",
14
+ ".js": "JavaScript",
15
+ ".ts": "TypeScript",
16
+ ".tsx": "TypeScript React",
17
+ ".jsx": "JavaScript React",
18
+ ".go": "Go",
19
+ ".rs": "Rust",
20
+ ".java": "Java",
21
+ ".rb": "Ruby",
22
+ ".php": "PHP",
23
+ ".c": "C",
24
+ ".h": "C Header",
25
+ ".cpp": "C++",
26
+ ".hpp": "C++ Header",
27
+ ".cs": "C#",
28
+ ".swift": "Swift",
29
+ ".kt": "Kotlin",
30
+ ".scala": "Scala",
31
+ ".sh": "Shell",
32
+ ".bash": "Shell",
33
+ ".zsh": "Shell",
34
+ ".fish": "Shell",
35
+ ".ps1": "PowerShell",
36
+ ".sql": "SQL",
37
+ ".r": "R",
38
+ ".m": "Objective-C",
39
+ ".lua": "Lua",
40
+ ".pl": "Perl",
41
+ ".pm": "Perl",
42
+ ".ex": "Elixir",
43
+ ".exs": "Elixir",
44
+ ".erl": "Erlang",
45
+ ".hs": "Haskell",
46
+ ".clj": "Clojure",
47
+ ".cljs": "ClojureScript",
48
+ ".dart": "Dart",
49
+ ".md": "Markdown",
50
+ ".rst": "reStructuredText",
51
+ ".html": "HTML",
52
+ ".css": "CSS",
53
+ ".scss": "SCSS",
54
+ ".sass": "Sass",
55
+ ".less": "Less",
56
+ ".json": "JSON",
57
+ ".yaml": "YAML",
58
+ ".yml": "YAML",
59
+ ".toml": "TOML",
60
+ ".xml": "XML",
61
+ ".tex": "LaTeX",
62
+ ".dockerfile": "Dockerfile",
63
+ ".makefile": "Makefile",
64
+ }
65
+
66
+ IGNORE_DIRS = {".git", "__pycache__", "node_modules", ".venv", "venv", ".tox", "dist", "build", ".egg-info", ".mypy_cache", ".pytest_cache", ".ruff_cache", "target", "vendor"}
67
+
68
+ def count_lines(filepath):
69
+ try:
70
+ with open(filepath, "rb") as f:
71
+ data = f.read()
72
+ lines = data.count(b"\n")
73
+ if data and not data.endswith(b"\n"):
74
+ lines += 1
75
+ return lines
76
+ except Exception:
77
+ return 0
78
+
79
+ def main():
80
+ args = sys.argv[1:]
81
+ path = args[0] if args else "."
82
+ path = os.path.abspath(path)
83
+ stats = {}
84
+ total_files = 0
85
+ total_lines = 0
86
+ if os.path.isfile(path):
87
+ ext = os.path.splitext(path)[1].lower()
88
+ lang = EXT_MAP.get(ext, "Unknown")
89
+ lines = count_lines(path)
90
+ stats[lang] = {"files": 1, "lines": lines}
91
+ total_files = 1
92
+ total_lines = lines
93
+ else:
94
+ for root, dirs, files in os.walk(path):
95
+ dirs[:] = [d for d in dirs if d not in IGNORE_DIRS and not d.startswith(".")]
96
+ for f in files:
97
+ ext = os.path.splitext(f)[1].lower()
98
+ lang = EXT_MAP.get(ext)
99
+ if not lang:
100
+ # Check for extensionless files
101
+ if f.lower() in ("dockerfile",):
102
+ lang = "Dockerfile"
103
+ elif f.lower() in ("makefile", "gnumakefile"):
104
+ lang = "Makefile"
105
+ else:
106
+ continue
107
+ filepath = os.path.join(root, f)
108
+ lines = count_lines(filepath)
109
+ if lang not in stats:
110
+ stats[lang] = {"files": 0, "lines": 0}
111
+ stats[lang]["files"] += 1
112
+ stats[lang]["lines"] += lines
113
+ total_files += 1
114
+ total_lines += lines
115
+ if not stats:
116
+ print(f"No code files found in {path}")
117
+ return
118
+ # Display
119
+ name_width = max(len(n) for n in stats.keys())
120
+ sorted_stats = sorted(stats.items(), key=lambda x: -x[1]["lines"])
121
+ print(f"{'Language':<{name_width}} {'Files':>6} {'Lines':>8} {'%':>5}")
122
+ print("-" * (name_width + 24))
123
+ for lang, info in sorted_stats:
124
+ pct = info["lines"] / total_lines * 100 if total_lines else 0
125
+ print(f"{lang:<{name_width}} {info['files']:>6} {info['lines']:>8} {pct:>4.1f}%")
126
+ print("-" * (name_width + 24))
127
+ print(f"{'TOTAL':<{name_width}} {total_files:>6} {total_lines:>8}")
128
+
129
+ if __name__ == "__main__":
130
+ main()
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env python3
2
+ """cron-pretty — Pretty-print cron expressions in human-readable format."""
3
+ import re
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "cron-pretty",
8
+ "func": "main",
9
+ "desc": "Describe cron schedule in plain English. Usage: cron-pretty '*/5 * * * *'",
10
+ }
11
+
12
+ WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
13
+ MONTHS = [None, "January", "February", "March", "April", "May", "June",
14
+ "July", "August", "September", "October", "November", "December"]
15
+
16
+ def describe(minute, hour, dom, month, dow):
17
+ parts = []
18
+ # Minute
19
+ if minute == "*":
20
+ min_desc = "every minute"
21
+ elif re.match(r"^\d+$", minute):
22
+ min_desc = f"at minute {minute}"
23
+ elif minute.startswith("*/"):
24
+ step = minute[2:]
25
+ min_desc = f"every {step} minutes"
26
+ else:
27
+ min_desc = f"minute {minute}"
28
+ parts.append(min_desc)
29
+ # Hour
30
+ if hour == "*":
31
+ hour_desc = "of every hour"
32
+ elif re.match(r"^\d+$", hour):
33
+ hour_desc = f"past hour {hour}"
34
+ elif hour.startswith("*/"):
35
+ step = hour[2:]
36
+ hour_desc = f"every {step} hours"
37
+ else:
38
+ hour_desc = f"hour {hour}"
39
+ parts.append(hour_desc)
40
+ # Day of month
41
+ if dom == "*":
42
+ dom_desc = "every day"
43
+ elif dom.startswith("*/"):
44
+ step = dom[2:]
45
+ dom_desc = f"every {step} days"
46
+ elif "," in dom:
47
+ days = dom.split(",")
48
+ dom_desc = f"on days {', '.join(days)}"
49
+ else:
50
+ dom_desc = f"on day {dom}"
51
+ parts.append(dom_desc)
52
+ # Month
53
+ if month == "*":
54
+ month_desc = "of every month"
55
+ elif re.match(r"^\d+$", month):
56
+ m = int(month)
57
+ month_desc = f"in {MONTHS[m] if m <= 12 else month}"
58
+ elif month.startswith("*/"):
59
+ step = month[2:]
60
+ month_desc = f"every {step} months"
61
+ else:
62
+ month_desc = f"in month {month}"
63
+ parts.append(month_desc)
64
+ # Day of week
65
+ if dow == "*":
66
+ dow_desc = ""
67
+ elif re.match(r"^\d+$", dow):
68
+ d = int(dow)
69
+ dow_desc = f"on {WEEKDAYS[d]}"
70
+ elif "," in dow:
71
+ days = [WEEKDAYS[int(d)] if d.isdigit() else d for d in dow.split(",")]
72
+ dow_desc = f"on {', '.join(days)}"
73
+ else:
74
+ dow_desc = f"on {dow}"
75
+ if dow_desc:
76
+ parts.append(dow_desc)
77
+ # Special cases
78
+ if minute == "0" and hour == "0" and dom == "*" and month == "*" and dow == "*":
79
+ return "At midnight, every day"
80
+ if minute == "0" and hour == "12" and dom == "*" and month == "*" and dow == "*":
81
+ return "At noon, every day"
82
+ if minute == "0" and hour in ("0", "12") and dom == "1" and month == "*" and dow == "*":
83
+ return f"At {hour}:00 AM, on the 1st of every month"
84
+ if minute == "0" and hour == "9" and dom == "*" and month == "*" and dow in ("1", "1-5"):
85
+ return "At 9:00 AM, Monday through Friday"
86
+ if minute == "30" and hour == "9" and dom == "*" and month == "*" and dow in ("1", "1-5"):
87
+ return "At 9:30 AM, Monday through Friday"
88
+ # Build description
89
+ result = f"{parts[0]} {parts[1]} {parts[2]} {parts[3]}"
90
+ if len(parts) > 4:
91
+ result += f" {parts[4]}"
92
+ return result
93
+
94
+ def main():
95
+ args = sys.argv[1:]
96
+ if not args or args[0] in ("-h", "--help"):
97
+ print("Usage: cron-pretty '*/5 * * * *'", file=sys.stderr)
98
+ print(" cron-pretty '30 9 * * 1-5'", file=sys.stderr)
99
+ sys.exit(1)
100
+ expr = args[0].strip()
101
+ fields = expr.split()
102
+ # Handle special strings
103
+ special = {
104
+ "@yearly": "0 0 1 1 *",
105
+ "@annually": "0 0 1 1 *",
106
+ "@monthly": "0 0 1 * *",
107
+ "@weekly": "0 0 * * 0",
108
+ "@daily": "0 0 * * *",
109
+ "@hourly": "0 * * * *",
110
+ "@reboot": None,
111
+ }
112
+ if expr in special:
113
+ resolved = special[expr]
114
+ if resolved is None:
115
+ print(f"'{expr}' — runs at system startup/reboot")
116
+ return
117
+ fields = resolved.split()
118
+ if len(fields) != 5:
119
+ print(f"Invalid cron expression: '{expr}'", file=sys.stderr)
120
+ print("Expected format: minute hour day-of-month month day-of-week", file=sys.stderr)
121
+ sys.exit(1)
122
+ minute, hour, dom, month, dow = fields
123
+ description = describe(minute, hour, dom, month, dow)
124
+ print(f" {expr}")
125
+ print(f" → {description}")
126
+
127
+ if __name__ == "__main__":
128
+ main()
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env python3
2
+ """csv2json — Convert CSV files to JSON."""
3
+ import csv
4
+ import json
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "csv2json",
9
+ "func": "main",
10
+ "desc": "Convert CSV to JSON. Usage: csv2json [file.csv] [--pretty] [--output file.json]",
11
+ }
12
+
13
+ def main():
14
+ args = sys.argv[1:]
15
+ pretty = False
16
+ input_file = None
17
+ output_file = None
18
+ i = 0
19
+ while i < len(args):
20
+ if args[i] == "--pretty":
21
+ pretty = True
22
+ elif args[i] == "--output" and i + 1 < len(args):
23
+ output_file = args[i + 1]
24
+ i += 1
25
+ elif not args[i].startswith("-"):
26
+ input_file = args[i]
27
+ i += 1
28
+ try:
29
+ if input_file:
30
+ with open(input_file, "r") as f:
31
+ reader = csv.DictReader(f)
32
+ data = list(reader)
33
+ else:
34
+ reader = csv.DictReader(sys.stdin)
35
+ data = list(reader)
36
+ except Exception as e:
37
+ print(f"Error reading CSV: {e}", file=sys.stderr)
38
+ sys.exit(1)
39
+ if not data:
40
+ print("[]")
41
+ return
42
+ indent = 2 if pretty else None
43
+ output = json.dumps(data, indent=indent, ensure_ascii=False, default=str)
44
+ if output_file:
45
+ with open(output_file, "w") as f:
46
+ f.write(output)
47
+ print(f"Written: {output_file} ({len(data)} rows)")
48
+ else:
49
+ print(output)
50
+
51
+ if __name__ == "__main__":
52
+ main()
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ """csv-validate — Validate CSV files for formatting issues."""
3
+ import csv
4
+ import os
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "csv-validate",
9
+ "func": "main",
10
+ "desc": "Validate CSV file format. Usage: csv-validate <file.csv>",
11
+ }
12
+
13
+ def main():
14
+ args = sys.argv[1:]
15
+ if not args or args[0] in ("-h", "--help"):
16
+ print("Usage: csv-validate <file.csv>")
17
+ return
18
+ filepath = args[0]
19
+ if not os.path.exists(filepath):
20
+ print(f"File not found: {filepath}", file=sys.stderr)
21
+ sys.exit(1)
22
+ errors = []
23
+ warnings = []
24
+ with open(filepath, "r") as f:
25
+ lines = f.readlines()
26
+ if not lines:
27
+ errors.append("File is empty")
28
+ else:
29
+ # Check header
30
+ header = lines[0].strip()
31
+ header_cols = next(csv.reader([header]))
32
+ expected_cols = len(header_cols)
33
+ if len(set(header_cols)) != len(header_cols):
34
+ warnings.append(f"Header has duplicate column names: {header_cols}")
35
+ # Check each row
36
+ for i, line in enumerate(lines[1:], 2):
37
+ line = line.strip()
38
+ if not line:
39
+ continue
40
+ try:
41
+ row = next(csv.reader([line]))
42
+ if len(row) != expected_cols:
43
+ errors.append(f"Row {i}: expected {expected_cols} columns, got {len(row)}")
44
+ except csv.Error as e:
45
+ errors.append(f"Row {i}: CSV parse error — {e}")
46
+ except StopIteration:
47
+ errors.append(f"Row {i}: empty row after strip")
48
+ if not errors and not warnings:
49
+ print(f"✓ {filepath}: valid CSV ({len(lines) - 1} rows, {expected_cols} columns)")
50
+ else:
51
+ if errors:
52
+ print(f"✗ ERRORS ({len(errors)}):")
53
+ for e in errors:
54
+ print(f" {e}")
55
+ if warnings:
56
+ print(f"⚠ WARNINGS ({len(warnings)}):")
57
+ for w in warnings:
58
+ print(f" {w}")
59
+ if errors:
60
+ sys.exit(1)
61
+
62
+ if __name__ == "__main__":
63
+ main()
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env python3
2
+ """disk-cleanup — Analyze disk usage and suggest cleanup actions."""
3
+ import os
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "disk-cleanup",
8
+ "func": "main",
9
+ "desc": "Analyze disk usage and suggest cleanup. Usage: disk-cleanup [path] [--deep]",
10
+ }
11
+
12
+ COMMON_CLEANUP = [
13
+ ("~/.cache", "Cache files"),
14
+ ("~/.local/share/Trash", "Trash"),
15
+ ("/tmp", "Temp files"),
16
+ ("~/.npm/_cacache", "npm cache"),
17
+ ("~/.rustup/tmp", "rustup temp"),
18
+ ("~/.cargo/registry/cache", "Cargo cache"),
19
+ ("~/.gradle/caches", "Gradle cache"),
20
+ ("~/.m2/repository", "Maven cache"),
21
+ ("~/.local/share/pip/cache", "pip cache"),
22
+ ]
23
+
24
+ def get_size(path):
25
+ try:
26
+ if os.path.isfile(path):
27
+ return os.path.getsize(path)
28
+ total = 0
29
+ for root, dirs, files in os.walk(path):
30
+ for f in files:
31
+ try:
32
+ total += os.path.getsize(os.path.join(root, f))
33
+ except Exception:
34
+ pass
35
+ return total
36
+ except Exception:
37
+ return 0
38
+
39
+ def format_size(size):
40
+ for unit in ["B", "KB", "MB", "GB"]:
41
+ if size < 1024:
42
+ return f"{size:.1f} {unit}"
43
+ size /= 1024
44
+ return f"{size:.1f} TB"
45
+
46
+ def find_large_files(path, limit=20, min_mb=50):
47
+ large = []
48
+ for root, dirs, files in os.walk(path):
49
+ dirs[:] = [d for d in dirs if not d.startswith(".") or d == "."]
50
+ for f in files:
51
+ try:
52
+ fp = os.path.join(root, f)
53
+ size = os.path.getsize(fp)
54
+ if size >= min_mb * 1024 * 1024:
55
+ large.append((fp, size))
56
+ except Exception:
57
+ pass
58
+ large.sort(key=lambda x: -x[1])
59
+ return large[:limit]
60
+
61
+ def main():
62
+ args = sys.argv[1:]
63
+ root_path = args[0] if args and not args[0].startswith("-") else os.path.expanduser("~")
64
+ deep = "--deep" in args
65
+ root_path = os.path.abspath(root_path)
66
+ print(f"Disk Cleanup Analysis: {root_path}")
67
+ print("=" * 50)
68
+ # Check common cleanup locations
69
+ print("\nCommon cleanup locations:")
70
+ any_found = False
71
+ for rel_path, label in COMMON_CLEANUP:
72
+ path = os.path.expanduser(rel_path)
73
+ if os.path.exists(path):
74
+ size = get_size(path)
75
+ if size > 0:
76
+ any_found = True
77
+ print(f" {format_size(size):>8} {label} ({path})")
78
+ if not any_found:
79
+ print(" (none found)")
80
+ # Check directory sizes if root path is a directory
81
+ if os.path.isdir(root_path):
82
+ print(f"\nLargest directories in {root_path}:")
83
+ dirs = []
84
+ for entry in os.listdir(root_path):
85
+ full = os.path.join(root_path, entry)
86
+ if os.path.isdir(full):
87
+ size = get_size(full)
88
+ dirs.append((entry, size))
89
+ dirs.sort(key=lambda x: -x[1])
90
+ for name, size in dirs[:10]:
91
+ if size > 1024 * 1024: # > 1MB
92
+ print(f" {format_size(size):>8} {name}")
93
+ if deep:
94
+ print(f"\nLargest files (>50MB):")
95
+ large = find_large_files(root_path)
96
+ if large:
97
+ for fp, size in large:
98
+ rel = os.path.relpath(fp, os.path.expanduser("~"))
99
+ print(f" {format_size(size):>8} ~/{rel}")
100
+ else:
101
+ print(" (none found)")
102
+ print("\nSuggestions:")
103
+ print(" temp-cleaner --dry-run Preview temp file cleanup")
104
+ print(" disk-usage Show disk usage summary")
105
+
106
+ if __name__ == "__main__":
107
+ main()