evolver-tools 19.0.0__tar.gz → 21.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 (258) hide show
  1. {evolver_tools-19.0.0/src/evolver_tools.egg-info → evolver_tools-21.0.0}/PKG-INFO +2 -2
  2. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/pyproject.toml +2 -2
  3. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/cli.py +1 -1
  4. evolver_tools-21.0.0/src/evolver_tools/vendor/csv_merge.py +158 -0
  5. evolver_tools-21.0.0/src/evolver_tools/vendor/diff_files.py +86 -0
  6. evolver_tools-21.0.0/src/evolver_tools/vendor/fold.py +85 -0
  7. evolver_tools-21.0.0/src/evolver_tools/vendor/http_server.py +66 -0
  8. evolver_tools-21.0.0/src/evolver_tools/vendor/json_flatten.py +81 -0
  9. evolver_tools-21.0.0/src/evolver_tools/vendor/pdf_info.py +106 -0
  10. evolver_tools-21.0.0/src/evolver_tools/vendor/pomodoro.py +90 -0
  11. evolver_tools-21.0.0/src/evolver_tools/vendor/seq.py +84 -0
  12. evolver_tools-21.0.0/src/evolver_tools/vendor/tr.py +101 -0
  13. evolver_tools-21.0.0/src/evolver_tools/vendor/watch.py +86 -0
  14. {evolver_tools-19.0.0 → evolver_tools-21.0.0/src/evolver_tools.egg-info}/PKG-INFO +2 -2
  15. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools.egg-info/SOURCES.txt +10 -0
  16. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/LICENSE +0 -0
  17. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/README.md +0 -0
  18. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/setup.cfg +0 -0
  19. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/__init__.py +0 -0
  20. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/__main__.py +0 -0
  21. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/autoreg.py +0 -0
  22. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/__init__.py +0 -0
  23. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/agent_b_tool.py +0 -0
  24. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ansi_strip.py +0 -0
  25. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/api_tester.py +0 -0
  26. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ascii_gen.py +0 -0
  27. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/audit_log.py +0 -0
  28. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/b64/__init__.py +0 -0
  29. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  30. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/backup.py +0 -0
  31. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/banner/__init__.py +0 -0
  32. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/banner/banner.py +0 -0
  33. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/banner.py +0 -0
  34. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/base32.py +0 -0
  35. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/bookmark.py +0 -0
  36. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cal_tool/__init__.py +0 -0
  37. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +0 -0
  38. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/calendar_cli.py +0 -0
  39. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cert_check.py +0 -0
  40. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cert_info.py +0 -0
  41. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/changelog_gen/__init__.py +0 -0
  42. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +0 -0
  43. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/changelog_gen.py +0 -0
  44. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +0 -0
  45. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  46. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/checksum_dir.py +0 -0
  47. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/clipboard/__init__.py +0 -0
  48. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/clipboard/clipboard.py +0 -0
  49. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/code_auditor.py +0 -0
  50. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/code_stats.py +0 -0
  51. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/colorize.py +0 -0
  52. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/colors/__init__.py +0 -0
  53. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  54. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/config_validator.py +0 -0
  55. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/config_vault.py +0 -0
  56. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cowsay.py +0 -0
  57. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cron/__init__.py +0 -0
  58. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  59. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/cron_pretty.py +0 -0
  60. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/crontab_helper.py +0 -0
  61. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/crypto_box.py +0 -0
  62. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/crypto_price.py +0 -0
  63. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv2json.py +0 -0
  64. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_stats/__init__.py +0 -0
  65. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  66. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  67. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +0 -0
  68. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_validate.py +0 -0
  69. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/csv_view.py +0 -0
  70. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/db_mate.py +0 -0
  71. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/db_schema.py +0 -0
  72. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dep_graph.py +0 -0
  73. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dev_dashboard.py +0 -0
  74. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dice_roll.py +0 -0
  75. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/diff_csv.py +0 -0
  76. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +0 -0
  77. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  78. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +0 -0
  79. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/disk_cleanup.py +0 -0
  80. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/disk_usage/__init__.py +0 -0
  81. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/disk_usage/disk_usage.py +0 -0
  82. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dns_lookup.py +0 -0
  83. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/docker_helper.py +0 -0
  84. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/dt_convert.py +0 -0
  85. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/env_diff.py +0 -0
  86. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/env_manager.py +0 -0
  87. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +0 -0
  88. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/epoch.py +0 -0
  89. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/excel2csv.py +0 -0
  90. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/factor.py +0 -0
  91. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ff/__init__.py +0 -0
  92. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  93. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/figlet_cli.py +0 -0
  94. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/figlet_tool.py +0 -0
  95. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/file_encrypt.py +0 -0
  96. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/file_joiner.py +0 -0
  97. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/file_splitter.py +0 -0
  98. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/file_watch.py +0 -0
  99. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/find_dups/__init__.py +0 -0
  100. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/find_dups/cli.py +0 -0
  101. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/firewall_rule.py +0 -0
  102. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/fmt/__init__.py +0 -0
  103. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/fmt/fmt.py +0 -0
  104. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/geo_ip.py +0 -0
  105. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/git_branch_cleaner.py +0 -0
  106. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/git_log_pretty.py +0 -0
  107. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/git_stats.py +0 -0
  108. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hash_check.py +0 -0
  109. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hash_file.py +0 -0
  110. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +0 -0
  111. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  112. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hex_tool.py +0 -0
  113. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/hexdump.py +0 -0
  114. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/html2markdown.py +0 -0
  115. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/html2md.py +0 -0
  116. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/http_headers.py +0 -0
  117. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/http_live/__init__.py +0 -0
  118. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  119. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/image_meta.py +0 -0
  120. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ini2json.py +0 -0
  121. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ini_parser/__init__.py +0 -0
  122. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ini_parser/ini_parser.py +0 -0
  123. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ip_location.py +0 -0
  124. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +0 -0
  125. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  126. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ipinfo/__init__.py +0 -0
  127. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  128. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/join.py +0 -0
  129. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/joke.py +0 -0
  130. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +0 -0
  131. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  132. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json2csv/__init__.py +0 -0
  133. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  134. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json2ini.py +0 -0
  135. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json_pretty/__init__.py +0 -0
  136. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json_pretty/json_pretty.py +0 -0
  137. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/json_schema_validate.py +0 -0
  138. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +0 -0
  139. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  140. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/key_value_store.py +0 -0
  141. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/license.py +0 -0
  142. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/license_cli/__init__.py +0 -0
  143. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  144. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/license_cli/cli.py +0 -0
  145. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/log_analyzer.py +0 -0
  146. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/log_hawk.py +0 -0
  147. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/log_tail.py +0 -0
  148. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/macrogen.py +0 -0
  149. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +0 -0
  150. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/markdown_preview.py +0 -0
  151. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/markdown_toc.py +0 -0
  152. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/media_studio.py +0 -0
  153. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/morse.py +0 -0
  154. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/nb/__init__.py +0 -0
  155. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  156. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/net_analyzer.py +0 -0
  157. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/net_speed.py +0 -0
  158. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/network_scan.py +0 -0
  159. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/nl.py +0 -0
  160. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/note_taker.py +0 -0
  161. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/otp_gen.py +0 -0
  162. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/passgen/__init__.py +0 -0
  163. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/password_strength.py +0 -0
  164. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/pdf_text.py +0 -0
  165. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/pipe_viewer.py +0 -0
  166. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/port_scan.py +0 -0
  167. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/portcheck/__init__.py +0 -0
  168. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +0 -0
  169. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/pr_tool/__init__.py +0 -0
  170. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/pr_tool/pr_tool.py +0 -0
  171. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/process_kill.py +0 -0
  172. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/progress_bar.py +0 -0
  173. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +0 -0
  174. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  175. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/qc_calc.py +0 -0
  176. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/qc_report.py +0 -0
  177. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/qc_sample.py +0 -0
  178. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/qr_cli.py +0 -0
  179. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/qrcode.py +0 -0
  180. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/quote.py +0 -0
  181. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/quote_tool/__init__.py +0 -0
  182. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/quote_tool/quote.py +0 -0
  183. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/rainbow.py +0 -0
  184. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/random.py +0 -0
  185. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/reminder.py +0 -0
  186. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ren/__init__.py +0 -0
  187. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  188. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/replace_text.py +0 -0
  189. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/restore.py +0 -0
  190. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/rot13.py +0 -0
  191. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/route_trace.py +0 -0
  192. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/scan_ports.py +0 -0
  193. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/screen_recorder.py +0 -0
  194. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/screenshot_cli.py +0 -0
  195. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/search_files.py +0 -0
  196. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/search_history.py +0 -0
  197. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/secret_scanner.py +0 -0
  198. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/service_check.py +0 -0
  199. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/shuffle.py +0 -0
  200. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +0 -0
  201. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  202. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +0 -0
  203. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  204. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sort/__init__.py +0 -0
  205. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sort/sort.py +0 -0
  206. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/spinner.py +0 -0
  207. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/split.py +0 -0
  208. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/split_tool/__init__.py +0 -0
  209. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/split_tool/split.py +0 -0
  210. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sql2csv.py +0 -0
  211. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +0 -0
  212. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  213. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ssh_key_gen.py +0 -0
  214. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/ssl_check.py +0 -0
  215. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/stopwatch.py +0 -0
  216. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/subnet.py +0 -0
  217. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +0 -0
  218. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  219. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/sysmon_pro.py +0 -0
  220. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/system_info.py +0 -0
  221. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/temp_cleaner.py +0 -0
  222. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/template.py +0 -0
  223. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/text_stats.py +0 -0
  224. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/timeout.py +0 -0
  225. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/timer/__init__.py +0 -0
  226. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/timer_pro/__init__.py +0 -0
  227. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/timer_pro/timer_pro.py +0 -0
  228. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/timer_pro.py +0 -0
  229. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/todo_cli.py +0 -0
  230. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/toml2json.py +0 -0
  231. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/tree.py +0 -0
  232. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/treedir/__init__.py +0 -0
  233. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/treedir/__main__.py +0 -0
  234. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/uniq_tool/__init__.py +0 -0
  235. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/uniq_tool/uniq.py +0 -0
  236. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/unit_convert.py +0 -0
  237. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/uri_encode.py +0 -0
  238. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/url_parser.py +0 -0
  239. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -0
  240. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +0 -0
  241. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +0 -0
  242. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  243. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/weather_cli.py +0 -0
  244. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/web_download.py +0 -0
  245. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +0 -0
  246. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  247. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/whois_lookup.py +0 -0
  248. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/wordcount/__init__.py +0 -0
  249. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +0 -0
  250. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/xml2json.py +0 -0
  251. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/yaml2json/__init__.py +0 -0
  252. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/yaml2json/yaml2json.py +0 -0
  253. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/yaml2toml.py +0 -0
  254. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/yaml_validate.py +0 -0
  255. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools/vendor/yes.py +0 -0
  256. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  257. {evolver_tools-19.0.0 → evolver_tools-21.0.0}/src/evolver_tools.egg-info/entry_points.txt +0 -0
  258. {evolver_tools-19.0.0 → evolver_tools-21.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: 19.0.0
4
- Summary: 181 CLI tools + 9 flagship projects — one pip install
3
+ Version: 21.0.0
4
+ Summary: 191 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 = "19.0.0"
8
- description = "181 CLI tools + 9 flagship projects — one pip install"
7
+ version = "21.0.0"
8
+ description = "191 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 v19.0.0 =====\x1b[0m')
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v21.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,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,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,85 @@
1
+ #!/usr/bin/env python3
2
+ """fold — Wrap input lines to a specified width.
3
+
4
+ Usage: fold <file> # wrap at 80
5
+ fold -w 40 <file> # wrap at 40
6
+ echo "long text" | fold -w 20 -s # break at spaces
7
+
8
+ Like standard Unix 'fold' command.
9
+ Zero-dependency (stdlib only).
10
+ """
11
+
12
+ import sys
13
+
14
+
15
+ def fold_line(line, width, spaces=False):
16
+ """Fold a single line to given width."""
17
+ if len(line) <= width or (len(line) == width + 1 and line.endswith('\n')):
18
+ return line
19
+
20
+ result = []
21
+ while line:
22
+ if len(line) <= width:
23
+ result.append(line)
24
+ break
25
+
26
+ chunk = line[:width]
27
+ if spaces:
28
+ # Find last space in the chunk
29
+ last_space = chunk.rfind(' ')
30
+ if last_space > 0:
31
+ result.append(line[:last_space] + '\n')
32
+ line = line[last_space:].lstrip()
33
+ continue
34
+
35
+ result.append(chunk.rstrip('\n') + '\n')
36
+ line = line[width:]
37
+ return ''.join(result)
38
+
39
+
40
+ def main():
41
+ args = sys.argv[1:]
42
+ width = 80
43
+ spaces = False
44
+
45
+ filtered = []
46
+ i = 0
47
+ while i < len(args):
48
+ if args[i] == '-w' and i + 1 < len(args):
49
+ width = int(args[i + 1])
50
+ i += 2
51
+ elif args[i].startswith('-w'):
52
+ width = int(args[i][2:])
53
+ i += 1
54
+ elif args[i] == '-s':
55
+ spaces = True
56
+ i += 1
57
+ elif args[i] in ('-h', '--help'):
58
+ print(__doc__)
59
+ return
60
+ else:
61
+ filtered.append(args[i])
62
+ i += 1
63
+
64
+ if filtered:
65
+ for path in filtered:
66
+ with open(path) as f:
67
+ for line in f:
68
+ print(fold_line(line.rstrip('\n'), width, spaces))
69
+ elif not sys.stdin.isatty():
70
+ for line in sys.stdin:
71
+ print(fold_line(line.rstrip('\n'), width, spaces))
72
+ else:
73
+ print("Usage: fold [-w <width>] [-s] <file>")
74
+ print(" cat <file> | fold [-w 40]")
75
+
76
+
77
+ # === Auto-registration metadata ===
78
+ TOOL_META = {
79
+ "name": "fold",
80
+ "func": "main",
81
+ "desc": 'Wrap input lines to specified width',
82
+ }
83
+
84
+ if __name__ == '__main__':
85
+ main()
@@ -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}")
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ """pdf_info — Extract PDF metadata (pages, author, title, size, etc.)
3
+
4
+ Usage: pdf_info file.pdf
5
+ pdf_info --json file.pdf
6
+
7
+ Zero-dependency PDF parser (basic metadata from PDF header/objects).
8
+ Full metadata requires PyMuPDF or similar — shows what's available.
9
+ """
10
+
11
+ import os
12
+ import re
13
+ import sys
14
+
15
+ TOOL_META = {
16
+ "name": "pdf_info",
17
+ "func": "main",
18
+ "desc": "Extract PDF metadata — pages, title, author, size",
19
+ }
20
+
21
+ def _scan_objects(data):
22
+ """Scan PDF for key metadata objects."""
23
+ info = {}
24
+ # Find /Info dictionary
25
+ m = re.search(rb'/Info\s+(\d+)\s+(\d+)\s+R', data)
26
+ if m:
27
+ obj_num = int(m.group(1))
28
+ gen_num = int(m.group(2))
29
+ # Find the actual Info object
30
+ pattern = rf'{obj_num}\s+{gen_num}\s+obj.*?endobj'.encode()
31
+ om = re.search(pattern, data, re.DOTALL)
32
+ if om:
33
+ chunk = om.group().decode('latin-1', errors='replace')
34
+ for key in ['Title', 'Author', 'Subject', 'Keywords', 'Creator', 'Producer']:
35
+ m2 = re.search(rf'/{key}\s+\(([^)]*)\)', chunk)
36
+ if m2:
37
+ info[key.lower()] = m2.group(1)
38
+ # Creation/Mod date
39
+ m2 = re.search(r'/CreationDate\s+\(D:([^)]*)\)', chunk)
40
+ if m2:
41
+ info['creation_date'] = m2.group(1)
42
+ m2 = re.search(r'/ModDate\s+\(D:([^)]*)\)', chunk)
43
+ if m2:
44
+ info['mod_date'] = m2.group(1)
45
+ return info
46
+
47
+
48
+ def main():
49
+ args = sys.argv[1:]
50
+ if not args or args[0] in ('-h', '--help'):
51
+ print(__doc__)
52
+ return
53
+
54
+ path = args[0]
55
+ json_mode = '--json' in args or '-j' in args
56
+
57
+ if not os.path.exists(path):
58
+ print(f"Error: file not found: {path}", file=sys.stderr)
59
+ sys.exit(1)
60
+
61
+ size = os.path.getsize(path)
62
+ with open(path, 'rb') as f:
63
+ data = f.read()
64
+
65
+ # Basic info
66
+ result = {
67
+ 'file': os.path.basename(path),
68
+ 'size_bytes': size,
69
+ 'size_kb': round(size / 1024, 1),
70
+ }
71
+
72
+ # PDF version
73
+ m = re.search(rb'%PDF-(\d+\.\d+)', data)
74
+ if m:
75
+ result['pdf_version'] = m.group(1).decode()
76
+
77
+ # Page count (count Pages objects)
78
+ pages = re.findall(rb'/Type\s*/Pages[^}]*/Count\s+(\d+)', data)
79
+ if pages:
80
+ result['pages'] = int(pages[0])
81
+
82
+ # Encrypted?
83
+ result['encrypted'] = '/Encrypt' in data.decode('latin-1', errors='replace')
84
+
85
+ # Metadata from Info dict
86
+ info = _scan_objects(data)
87
+ result.update(info)
88
+
89
+ if json_mode:
90
+ import json
91
+ print(json.dumps(result, indent=2))
92
+ return
93
+
94
+ print(f" File: {result['file']}")
95
+ print(f" Size: {result['size_kb']} KB ({result['size_bytes']} bytes)")
96
+ if 'pdf_version' in result:
97
+ print(f" PDF: {result['pdf_version']}")
98
+ if 'pages' in result:
99
+ print(f" Pages: {result['pages']}")
100
+ print(f" Encrypted: {result['encrypted']}")
101
+ for key in ('title', 'author', 'subject', 'creator', 'producer'):
102
+ if key in result:
103
+ print(f" {key.title()}: {result[key]}")
104
+ for key in ('creation_date', 'mod_date'):
105
+ if key in result:
106
+ print(f" {key.replace('_', ' ').title()}: {result[key]}")