evolver-tools 5.0.0__tar.gz → 12.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 (195) hide show
  1. {evolver_tools-5.0.0/src/evolver_tools.egg-info → evolver_tools-12.0.0}/PKG-INFO +2 -2
  2. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/pyproject.toml +2 -2
  3. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/cli.py +1 -1
  4. evolver_tools-12.0.0/src/evolver_tools/vendor/code_stats.py +130 -0
  5. evolver_tools-12.0.0/src/evolver_tools/vendor/csv2json.py +52 -0
  6. evolver_tools-12.0.0/src/evolver_tools/vendor/csv_validate.py +63 -0
  7. evolver_tools-12.0.0/src/evolver_tools/vendor/dns_lookup.py +91 -0
  8. evolver_tools-12.0.0/src/evolver_tools/vendor/file_watch.py +66 -0
  9. evolver_tools-12.0.0/src/evolver_tools/vendor/http_headers.py +46 -0
  10. evolver_tools-12.0.0/src/evolver_tools/vendor/json_schema_validate.py +113 -0
  11. evolver_tools-12.0.0/src/evolver_tools/vendor/markdown_toc.py +40 -0
  12. evolver_tools-12.0.0/src/evolver_tools/vendor/pdf_text.py +97 -0
  13. evolver_tools-12.0.0/src/evolver_tools/vendor/route_trace.py +88 -0
  14. evolver_tools-12.0.0/src/evolver_tools/vendor/screenshot_cli.py +57 -0
  15. evolver_tools-12.0.0/src/evolver_tools/vendor/search_history.py +79 -0
  16. evolver_tools-12.0.0/src/evolver_tools/vendor/secret_scanner.py +82 -0
  17. evolver_tools-12.0.0/src/evolver_tools/vendor/whois_lookup.py +65 -0
  18. evolver_tools-12.0.0/src/evolver_tools/vendor/yaml_validate.py +59 -0
  19. {evolver_tools-5.0.0 → evolver_tools-12.0.0/src/evolver_tools.egg-info}/PKG-INFO +2 -2
  20. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools.egg-info/SOURCES.txt +15 -0
  21. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/LICENSE +0 -0
  22. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/README.md +0 -0
  23. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/setup.cfg +0 -0
  24. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/__init__.py +0 -0
  25. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/__main__.py +0 -0
  26. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/autoreg.py +0 -0
  27. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/__init__.py +0 -0
  28. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/agent_b_tool.py +0 -0
  29. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/api_tester.py +0 -0
  30. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ascii_gen.py +0 -0
  31. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/audit_log.py +0 -0
  32. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/b64/__init__.py +0 -0
  33. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/b64/b64.py +0 -0
  34. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/backup.py +0 -0
  35. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/banner/__init__.py +0 -0
  36. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/banner/banner.py +0 -0
  37. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/banner.py +0 -0
  38. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/bookmark.py +0 -0
  39. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/cal_tool/__init__.py +0 -0
  40. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/cal_tool/cli.py +0 -0
  41. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/cert_check.py +0 -0
  42. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/changelog_gen/__init__.py +0 -0
  43. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/changelog_gen/changelog_gen.py +0 -0
  44. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/changelog_gen.py +0 -0
  45. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/chart_cli/__init__.py +0 -0
  46. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/chart_cli/__main__.py +0 -0
  47. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/checksum_dir.py +0 -0
  48. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/clipboard/__init__.py +0 -0
  49. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/clipboard/clipboard.py +0 -0
  50. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/code_auditor.py +0 -0
  51. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/colorize.py +0 -0
  52. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/colors/__init__.py +0 -0
  53. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/colors/__main__.py +0 -0
  54. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/config_validator.py +0 -0
  55. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/config_vault.py +0 -0
  56. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/cron/__init__.py +0 -0
  57. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/cron/__main__.py +0 -0
  58. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/crontab_helper.py +0 -0
  59. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/crypto_box.py +0 -0
  60. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/crypto_price.py +0 -0
  61. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/csv_stats/__init__.py +0 -0
  62. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/csv_stats/__main__.py +0 -0
  63. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/csv_stats/analyzer.py +0 -0
  64. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/csv_stats/cli.py +0 -0
  65. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/db_mate.py +0 -0
  66. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/db_schema.py +0 -0
  67. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/dep_graph.py +0 -0
  68. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/dev_dashboard.py +0 -0
  69. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/dice_roll.py +0 -0
  70. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/diff_csv.py +0 -0
  71. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/diff_tool/__init__.py +0 -0
  72. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/diff_tool/__main__.py +0 -0
  73. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/dirsize/__init__.py +0 -0
  74. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/disk_usage/__init__.py +0 -0
  75. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/disk_usage/disk_usage.py +0 -0
  76. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/dt_convert.py +0 -0
  77. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/env_manager.py +0 -0
  78. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/envcheck/__init__.py +0 -0
  79. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/excel2csv.py +0 -0
  80. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ff/__init__.py +0 -0
  81. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ff/__main__.py +0 -0
  82. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/figlet_cli.py +0 -0
  83. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/figlet_tool.py +0 -0
  84. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/file_encrypt.py +0 -0
  85. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/find_dups/__init__.py +0 -0
  86. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/find_dups/cli.py +0 -0
  87. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/firewall_rule.py +0 -0
  88. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/fmt/__init__.py +0 -0
  89. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/fmt/fmt.py +0 -0
  90. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/git_branch_cleaner.py +0 -0
  91. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/hashsum/__init__.py +0 -0
  92. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/hashsum/__main__.py +0 -0
  93. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/html2markdown.py +0 -0
  94. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/html2md.py +0 -0
  95. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/http_live/__init__.py +0 -0
  96. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/http_live/__main__.py +0 -0
  97. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/image_meta.py +0 -0
  98. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ini_parser/__init__.py +0 -0
  99. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ini_parser/ini_parser.py +0 -0
  100. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ip_location.py +0 -0
  101. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ipcalc/__init__.py +0 -0
  102. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ipcalc/__main__.py +0 -0
  103. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ipinfo/__init__.py +0 -0
  104. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ipinfo/__main__.py +0 -0
  105. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/join.py +0 -0
  106. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/joke.py +0 -0
  107. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/jq_lite/__init__.py +0 -0
  108. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/jq_lite/__main__.py +0 -0
  109. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/json2csv/__init__.py +0 -0
  110. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/json2csv/__main__.py +0 -0
  111. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/json_pretty/__init__.py +0 -0
  112. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/json_pretty/json_pretty.py +0 -0
  113. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/jsonql/__init__.py +0 -0
  114. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/jsonql/__main__.py +0 -0
  115. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/license_cli/__init__.py +0 -0
  116. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/license_cli/__main__.py +0 -0
  117. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/license_cli/cli.py +0 -0
  118. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/log_analyzer.py +0 -0
  119. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/log_hawk.py +0 -0
  120. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/log_tail.py +0 -0
  121. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/markdown_check/__init__.py +0 -0
  122. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/media_studio.py +0 -0
  123. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/morse.py +0 -0
  124. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/nb/__init__.py +0 -0
  125. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/nb/__main__.py +0 -0
  126. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/net_analyzer.py +0 -0
  127. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/net_speed.py +0 -0
  128. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/note_taker.py +0 -0
  129. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/otp_gen.py +0 -0
  130. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/passgen/__init__.py +0 -0
  131. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/password_strength.py +0 -0
  132. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/portcheck/__init__.py +0 -0
  133. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/portcheck/__main__.py +0 -0
  134. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/pr_tool/__init__.py +0 -0
  135. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/pr_tool/pr_tool.py +0 -0
  136. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/process_kill.py +0 -0
  137. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/progress_bar.py +0 -0
  138. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/project_doctor/__init__.py +0 -0
  139. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/project_doctor/__main__.py +0 -0
  140. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/qrcode.py +0 -0
  141. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/quote_tool/__init__.py +0 -0
  142. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/quote_tool/quote.py +0 -0
  143. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/rainbow.py +0 -0
  144. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/reminder.py +0 -0
  145. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ren/__init__.py +0 -0
  146. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ren/__main__.py +0 -0
  147. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/restore.py +0 -0
  148. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/scan_ports.py +0 -0
  149. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/service_check.py +0 -0
  150. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/shuffle.py +0 -0
  151. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/siege_lite/__init__.py +0 -0
  152. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/siege_lite/__main__.py +0 -0
  153. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/smellfinder/__init__.py +0 -0
  154. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/smellfinder/__main__.py +0 -0
  155. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sort/__init__.py +0 -0
  156. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sort/sort.py +0 -0
  157. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/spinner.py +0 -0
  158. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/split.py +0 -0
  159. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/split_tool/__init__.py +0 -0
  160. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/split_tool/split.py +0 -0
  161. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sql2csv.py +0 -0
  162. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sqlite_cli/__init__.py +0 -0
  163. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sqlite_cli/__main__.py +0 -0
  164. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ssh_key_gen.py +0 -0
  165. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/ssl_check.py +0 -0
  166. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/stopwatch.py +0 -0
  167. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sysmon/__init__.py +0 -0
  168. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sysmon/__main__.py +0 -0
  169. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/sysmon_pro.py +0 -0
  170. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/text_stats.py +0 -0
  171. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/timer/__init__.py +0 -0
  172. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/timer_pro/__init__.py +0 -0
  173. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/timer_pro/timer_pro.py +0 -0
  174. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/timer_pro.py +0 -0
  175. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/todo_cli.py +0 -0
  176. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/treedir/__init__.py +0 -0
  177. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/treedir/__main__.py +0 -0
  178. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/uniq_tool/__init__.py +0 -0
  179. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/uniq_tool/uniq.py +0 -0
  180. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/unit_convert.py +0 -0
  181. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/urlparse_tool/__init__.py +0 -0
  182. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/urlparse_tool/cli.py +0 -0
  183. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/uuid_tool/__init__.py +0 -0
  184. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/uuid_tool/__main__.py +0 -0
  185. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/weather_cli.py +0 -0
  186. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/web_summary/__init__.py +0 -0
  187. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/web_summary/__main__.py +0 -0
  188. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/wordcount/__init__.py +0 -0
  189. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/wordcount/__main__.py +0 -0
  190. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/xml2json.py +0 -0
  191. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/yaml2json/__init__.py +0 -0
  192. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools/vendor/yaml2json/yaml2json.py +0 -0
  193. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools.egg-info/dependency_links.txt +0 -0
  194. {evolver_tools-5.0.0 → evolver_tools-12.0.0}/src/evolver_tools.egg-info/entry_points.txt +0 -0
  195. {evolver_tools-5.0.0 → evolver_tools-12.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: 5.0.0
4
- Summary: 105 essential CLI tools + 9 flagship projects — one pip install
3
+ Version: 12.0.0
4
+ Summary: 129 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 = "5.0.0"
8
- description = "105 essential CLI tools + 9 flagship projects — one pip install"
7
+ version = "12.0.0"
8
+ description = "129 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 v5.0.0 =====\x1b[0m')
17
+ print(f'\x1b[1;36m===== EVOLVER Tools v12.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,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,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,91 @@
1
+ #!/usr/bin/env python3
2
+ """dns-lookup — DNS lookup tool."""
3
+ import sys
4
+
5
+ TOOL_META = {
6
+ "name": "dns-lookup",
7
+ "func": "main",
8
+ "desc": "DNS lookup tool. Usage: dns-lookup <domain> [--type A|AAAA|MX|TXT|NS|CNAME|SOA]",
9
+ }
10
+
11
+ RECORD_TYPES = {
12
+ "A": "A",
13
+ "AAAA": "AAAA",
14
+ "MX": "MX",
15
+ "TXT": "TXT",
16
+ "NS": "NS",
17
+ "CNAME": "CNAME",
18
+ "SOA": "SOA",
19
+ "all": None,
20
+ }
21
+
22
+ def resolve_socket(hostname, qtype="A"):
23
+ """Use Python's socket module for basic DNS resolution."""
24
+ import socket
25
+ try:
26
+ if qtype == "A":
27
+ result = socket.getaddrinfo(hostname, None, socket.AF_INET)
28
+ addresses = set()
29
+ for r in result:
30
+ addresses.add(r[4][0])
31
+ return list(addresses), f"A records for {hostname}"
32
+ elif qtype == "AAAA":
33
+ result = socket.getaddrinfo(hostname, None, socket.AF_INET6)
34
+ addresses = set()
35
+ for r in result:
36
+ addresses.add(r[4][0])
37
+ return list(addresses), f"AAAA records for {hostname}"
38
+ except socket.gaierror as e:
39
+ return [], f"Error: {e}"
40
+ return [], "No results"
41
+
42
+ def resolve_dnspython(hostname, qtype=None):
43
+ """Use dnspython for full DNS resolution."""
44
+ try:
45
+ import dns.resolver
46
+ import dns.rdatatype
47
+ except ImportError:
48
+ return None
49
+ results = []
50
+ types = [qtype] if qtype and qtype != "all" else ["A", "AAAA", "MX", "TXT", "NS", "CNAME", "SOA"]
51
+ for t in types:
52
+ try:
53
+ answers = dns.resolver.resolve(hostname, t)
54
+ for rdata in answers:
55
+ results.append((t, str(rdata)))
56
+ except Exception:
57
+ pass
58
+ return results if results else None
59
+
60
+ def main():
61
+ args = sys.argv[1:]
62
+ if not args or args[0] in ("-h", "--help"):
63
+ print("Usage: dns-lookup <domain> [--type A|AAAA|MX|TXT|NS|CNAME|SOA|all]", file=sys.stderr)
64
+ print(" Default: A record", file=sys.stderr)
65
+ sys.exit(1)
66
+ hostname = args[0]
67
+ qtype = "A"
68
+ if "--type" in args:
69
+ idx = args.index("--type")
70
+ if idx + 1 < len(args):
71
+ qtype = args[idx + 1].upper()
72
+ if qtype not in RECORD_TYPES:
73
+ print(f"Unknown record type: {qtype}", file=sys.stderr)
74
+ print(f"Supported: {', '.join(RECORD_TYPES.keys())}", file=sys.stderr)
75
+ sys.exit(1)
76
+ # Try dnspython first
77
+ dns_results = resolve_dnspython(hostname, qtype)
78
+ if dns_results:
79
+ for t, val in dns_results:
80
+ print(f"{t:<6} {val}")
81
+ return
82
+ # Fallback to socket
83
+ addresses, label = resolve_socket(hostname, qtype)
84
+ if addresses:
85
+ for addr in addresses:
86
+ print(f"{qtype:<6} {addr}")
87
+ else:
88
+ print(label or f"No {qtype} records found for {hostname}")
89
+
90
+ if __name__ == "__main__":
91
+ main()
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """file-watch — Watch a file for changes in real-time."""
3
+ import os
4
+ import sys
5
+ import time
6
+ from datetime import datetime
7
+
8
+ TOOL_META = {
9
+ "name": "file-watch",
10
+ "func": "main",
11
+ "desc": "Watch file for changes. Usage: file-watch <file> [--tail]",
12
+ }
13
+
14
+ def main():
15
+ args = sys.argv[1:]
16
+ if not args or args[0] in ("-h", "--help"):
17
+ print("Usage: file-watch <file> [--tail]", file=sys.stderr)
18
+ print(" --tail Follow new content (like tail -f)", file=sys.stderr)
19
+ sys.exit(1)
20
+ filepath = args[0]
21
+ follow = "--tail" in args
22
+ if not os.path.exists(filepath):
23
+ print(f"File not found: {filepath}", file=sys.stderr)
24
+ sys.exit(1)
25
+ last_mtime = os.path.getmtime(filepath)
26
+ last_size = os.path.getsize(filepath)
27
+ if follow:
28
+ # Read existing content first
29
+ try:
30
+ with open(filepath, "r") as f:
31
+ content = f.read()
32
+ print(content, end="")
33
+ except Exception:
34
+ pass
35
+ print(f"\n[ Watching {filepath} for changes — Ctrl+C to stop ]")
36
+ try:
37
+ while True:
38
+ time.sleep(0.5)
39
+ if os.path.getmtime(filepath) != last_mtime:
40
+ new_size = os.path.getsize(filepath)
41
+ if new_size > last_size:
42
+ with open(filepath, "r") as f:
43
+ f.seek(last_size)
44
+ new_data = f.read()
45
+ print(new_data, end="", flush=True)
46
+ else:
47
+ # File was truncated or rewritten
48
+ with open(filepath, "r") as f:
49
+ print(f"\n--- File updated at {datetime.now().strftime('%H:%M:%S')} ---")
50
+ print(f.read(), end="", flush=True)
51
+ last_mtime = os.path.getmtime(filepath)
52
+ last_size = new_size
53
+ except KeyboardInterrupt:
54
+ print("\n[ Stopped ]")
55
+ else:
56
+ print(f"Last modified: {datetime.fromtimestamp(last_mtime).strftime('%Y-%m-%d %H:%M:%S')}")
57
+ print(f"Size: {last_size} bytes")
58
+ print("---")
59
+ try:
60
+ with open(filepath, "r") as f:
61
+ print(f.read())
62
+ except Exception as e:
63
+ print(f"Error reading: {e}", file=sys.stderr)
64
+
65
+ if __name__ == "__main__":
66
+ main()
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env python3
2
+ """http-headers — Inspect HTTP response headers."""
3
+ import sys
4
+
5
+ TOOL_META = {
6
+ "name": "http-headers",
7
+ "func": "main",
8
+ "desc": "Inspect HTTP response headers. Usage: http-headers <url>",
9
+ }
10
+
11
+ def main():
12
+ args = sys.argv[1:]
13
+ if not args or args[0] in ("-h", "--help"):
14
+ print("Usage: http-headers <url>", file=sys.stderr)
15
+ sys.exit(1)
16
+ url = args[0]
17
+ if not url.startswith("http"):
18
+ url = "https://" + url
19
+ try:
20
+ import urllib.request
21
+ req = urllib.request.Request(url, method="HEAD")
22
+ req.add_header("User-Agent", "evolver-tools/11.0")
23
+ with urllib.request.urlopen(req, timeout=15) as resp:
24
+ print(f"HTTP/1.1 {resp.status} {resp.reason}")
25
+ print(f"URL: {resp.url}")
26
+ print("--- Headers ---")
27
+ for key, val in resp.headers.items():
28
+ print(f" {key}: {val}")
29
+ except Exception as e:
30
+ # Fallback: try GET
31
+ try:
32
+ import urllib.request
33
+ req = urllib.request.Request(url)
34
+ req.add_header("User-Agent", "evolver-tools/11.0")
35
+ with urllib.request.urlopen(req, timeout=15) as resp:
36
+ print(f"HTTP/1.1 {resp.status} {resp.reason}")
37
+ print(f"URL: {resp.url}")
38
+ print("--- Headers ---")
39
+ for key, val in resp.headers.items():
40
+ print(f" {key}: {val}")
41
+ except Exception as e2:
42
+ print(f"Error: {e2}", file=sys.stderr)
43
+ sys.exit(1)
44
+
45
+ if __name__ == "__main__":
46
+ main()
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python3
2
+ """json-schema-validate — Validate JSON data against a JSON schema."""
3
+ import json
4
+ import os
5
+ import sys
6
+
7
+ TOOL_META = {
8
+ "name": "json-schema-validate",
9
+ "func": "main",
10
+ "desc": "Validate JSON against JSON Schema. Usage: json-schema-validate <data.json> <schema.json>",
11
+ }
12
+
13
+ def validate_fast(data, schema):
14
+ """Simple fast validation without jsonschema library."""
15
+ errors = []
16
+ # Check type
17
+ if "type" in schema:
18
+ type_map = {
19
+ "string": str, "number": (int, float), "integer": int,
20
+ "boolean": bool, "null": type(None),
21
+ "array": list, "object": dict,
22
+ }
23
+ expected_type = type_map.get(schema["type"])
24
+ if expected_type and not isinstance(data, expected_type):
25
+ errors.append(f"Expected type '{schema['type']}', got {type(data).__name__}")
26
+ return errors
27
+ # Check required properties
28
+ if isinstance(data, dict):
29
+ required = schema.get("required", [])
30
+ for prop in required:
31
+ if prop not in data:
32
+ errors.append(f"Missing required property: '{prop}'")
33
+ # Check properties
34
+ for key, prop_schema in schema.get("properties", {}).items():
35
+ if key in data:
36
+ sub_errors = validate_fast(data[key], prop_schema)
37
+ for e in sub_errors:
38
+ errors.append(f"{key}: {e}")
39
+ # Check array items
40
+ if isinstance(data, list) and "items" in schema:
41
+ for i, item in enumerate(data):
42
+ sub_errors = validate_fast(item, schema["items"])
43
+ for e in sub_errors:
44
+ errors.append(f"[{i}]: {e}")
45
+ # Check enum
46
+ if "enum" in schema and data not in schema["enum"]:
47
+ errors.append(f"Value {data!r} not in enum: {schema['enum']}")
48
+ # Check min/max
49
+ if isinstance(data, (int, float)):
50
+ if "minimum" in schema and data < schema["minimum"]:
51
+ errors.append(f"Value {data} < minimum {schema['minimum']}")
52
+ if "maximum" in schema and data > schema["maximum"]:
53
+ errors.append(f"Value {data} > maximum {schema['maximum']}")
54
+ if isinstance(data, str):
55
+ if "minLength" in schema and len(data) < schema["minLength"]:
56
+ errors.append(f"String length {len(data)} < minLength {schema['minLength']}")
57
+ if "maxLength" in schema and len(data) > schema["maxLength"]:
58
+ errors.append(f"String length {len(data)} > maxLength {schema['maxLength']}")
59
+ if "pattern" in schema:
60
+ import re
61
+ if not re.match(schema["pattern"], data):
62
+ errors.append(f"String '{data}' does not match pattern '{schema['pattern']}'")
63
+ if isinstance(data, list):
64
+ if "minItems" in schema and len(data) < schema["minItems"]:
65
+ errors.append(f"Array length {len(data)} < minItems {schema['minItems']}")
66
+ if "maxItems" in schema and len(data) > schema["maxItems"]:
67
+ errors.append(f"Array length {len(data)} > maxItems {schema['maxItems']}")
68
+ return errors
69
+
70
+ def main():
71
+ args = sys.argv[1:]
72
+ if len(args) < 2 or args[0] in ("-h", "--help"):
73
+ print("Usage: json-schema-validate <data.json> <schema.json>")
74
+ print(" json-schema-validate <data.json> <schema.json> --full (try jsonschema lib)")
75
+ return
76
+ data_path = args[0]
77
+ schema_path = args[1]
78
+ use_lib = "--full" in args
79
+ for p in [data_path, schema_path]:
80
+ if not os.path.exists(p):
81
+ print(f"File not found: {p}", file=sys.stderr)
82
+ sys.exit(1)
83
+ with open(data_path) as f:
84
+ data = json.load(f)
85
+ with open(schema_path) as f:
86
+ schema = json.load(f)
87
+ # Try jsonschema library if requested
88
+ if use_lib:
89
+ try:
90
+ from jsonschema import validate, ValidationError
91
+ try:
92
+ validate(data, schema)
93
+ print(f"✓ {data_path}: valid against {schema_path}")
94
+ return
95
+ except ValidationError as e:
96
+ print(f"✗ Validation error:")
97
+ print(f" {e.message}")
98
+ print(f" Path: {' → '.join(str(p) for p in e.absolute_path)}")
99
+ sys.exit(1)
100
+ except ImportError:
101
+ print("Note: Install jsonschema for full validation: pip install jsonschema", file=sys.stderr)
102
+ # Fallback to fast validation
103
+ errors = validate_fast(data, schema)
104
+ if not errors:
105
+ print(f"✓ {data_path}: valid against {schema_path} (basic validation)")
106
+ else:
107
+ print(f"✗ Validation errors ({len(errors)}):")
108
+ for e in errors:
109
+ print(f" • {e}")
110
+ sys.exit(1)
111
+
112
+ if __name__ == "__main__":
113
+ main()
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python3
2
+ """markdown-toc — Generate a table of contents from markdown."""
3
+ import re
4
+ import sys
5
+
6
+ TOOL_META = {
7
+ "name": "markdown-toc",
8
+ "func": "main",
9
+ "desc": "Generate table of contents from Markdown. Usage: markdown-toc [file.md]",
10
+ }
11
+
12
+ def main():
13
+ args = sys.argv[1:]
14
+ if args and args[0] in ("-h", "--help"):
15
+ print("Usage: markdown-toc [file.md]")
16
+ print(" cat file.md | markdown-toc")
17
+ return
18
+ if args:
19
+ with open(args[0], "r") as f:
20
+ content = f.read()
21
+ else:
22
+ content = sys.stdin.read()
23
+ toc_lines = []
24
+ for line in content.split("\n"):
25
+ m = re.match(r"^(#{1,6})\s+(.+)$", line)
26
+ if m:
27
+ level = len(m.group(1))
28
+ title = m.group(2).strip()
29
+ anchor = title.lower()
30
+ anchor = re.sub(r"[^a-z0-9\s\-]", "", anchor)
31
+ anchor = re.sub(r"\s+", "-", anchor.strip())
32
+ indent = " " * (level - 1)
33
+ toc_lines.append(f"{indent}- [{title}](#{anchor})")
34
+ if toc_lines:
35
+ print("\n".join(toc_lines))
36
+ else:
37
+ print("(no headings found)")
38
+
39
+ if __name__ == "__main__":
40
+ main()