attacklm 0.9.2__tar.gz → 0.9.4__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 (216) hide show
  1. {attacklm-0.9.2 → attacklm-0.9.4}/CHANGELOG.md +37 -0
  2. {attacklm-0.9.2 → attacklm-0.9.4}/CONTRIBUTING.md +1 -1
  3. {attacklm-0.9.2 → attacklm-0.9.4}/EVALUATION.md +6 -6
  4. {attacklm-0.9.2 → attacklm-0.9.4}/PKG-INFO +1 -1
  5. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/screens/command_forms.py +3 -4
  6. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/screens/train_form.py +1 -1
  7. {attacklm-0.9.2 → attacklm-0.9.4}/pipeline.example.yaml +1 -1
  8. {attacklm-0.9.2 → attacklm-0.9.4}/pyproject.toml +5 -29
  9. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/balance_buckets.py +4 -4
  10. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/build.py +8 -8
  11. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/convert_to_gguf.py +12 -10
  12. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_elastic_rules.py +1 -1
  13. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_mordor.py +1 -1
  14. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_sigma_defensive.py +1 -1
  15. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_splunk_content.py +1 -1
  16. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_threathunter_playbook.py +1 -1
  17. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/init_pipeline.py +23 -23
  18. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/merge_adapter.py +3 -3
  19. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/pipeline.py +4 -4
  20. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/train_template.py +29 -7
  21. attacklm-0.9.4/src/attacklm/__version__.py +1 -0
  22. {attacklm-0.9.2 → attacklm-0.9.4}/src/attacklm/cli.py +12 -205
  23. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_init_pipeline.py +7 -2
  24. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_memory_optimization.py +107 -0
  25. attacklm-0.9.2/src/attacklm/__version__.py +0 -1
  26. {attacklm-0.9.2 → attacklm-0.9.4}/.github/workflows/release.yml +0 -0
  27. {attacklm-0.9.2 → attacklm-0.9.4}/.gitignore +0 -0
  28. {attacklm-0.9.2 → attacklm-0.9.4}/ATTRIBUTION.md +0 -0
  29. {attacklm-0.9.2 → attacklm-0.9.4}/LICENSE +0 -0
  30. {attacklm-0.9.2 → attacklm-0.9.4}/MANIFEST.in +0 -0
  31. {attacklm-0.9.2 → attacklm-0.9.4}/Makefile +0 -0
  32. {attacklm-0.9.2 → attacklm-0.9.4}/NOTICE +0 -0
  33. {attacklm-0.9.2 → attacklm-0.9.4}/README.md +0 -0
  34. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/README.md +0 -0
  35. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/pyproject.toml +0 -0
  36. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/__init__.py +0 -0
  37. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/app.py +0 -0
  38. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/cli.py +0 -0
  39. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/presets.py +0 -0
  40. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/runner.py +0 -0
  41. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/screens/__init__.py +0 -0
  42. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/screens/main_menu.py +0 -0
  43. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/screens/train_live.py +0 -0
  44. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/src/attacklm_gui/widgets/__init__.py +0 -0
  45. {attacklm-0.9.2 → attacklm-0.9.4}/attacklm-gui/tests/test_gui.py +0 -0
  46. {attacklm-0.9.2 → attacklm-0.9.4}/data/ATTRIBUTION.md +0 -0
  47. {attacklm-0.9.2 → attacklm-0.9.4}/data/LEGAL.md +0 -0
  48. {attacklm-0.9.2 → attacklm-0.9.4}/data/REMOVAL.md +0 -0
  49. {attacklm-0.9.2 → attacklm-0.9.4}/data/bench/questions.jsonl +0 -0
  50. {attacklm-0.9.2 → attacklm-0.9.4}/data/bench/speed_context.txt +0 -0
  51. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/acquisition_report.json +0 -0
  52. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/manifest.json +0 -0
  53. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/README.md +0 -0
  54. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/_index.json +0 -0
  55. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  56. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  57. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  58. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  59. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  60. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  61. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  62. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  63. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  64. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  65. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  66. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  67. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  68. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  69. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  70. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  71. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/elastic-rules/defensive/detection_engineering/data.jsonl +0 -0
  72. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  73. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  74. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  75. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  76. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  77. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  78. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  79. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  80. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  81. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  82. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  83. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  84. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  85. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  86. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  87. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  88. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  89. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  90. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  91. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  92. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  93. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  94. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  95. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  96. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  97. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  98. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  99. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  100. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  101. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/mordor/defensive/threat_hunting/data.jsonl +0 -0
  102. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  103. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  104. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nist-ir/defensive/incident_response/data.jsonl +0 -0
  105. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  106. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  107. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  108. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  109. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  110. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  111. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  112. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  113. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  114. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  115. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  116. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  117. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  118. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  119. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  120. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  121. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  122. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/sigma-hq/defensive/detection_engineering/data.jsonl +0 -0
  123. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  124. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  125. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/splunk-content/defensive/detection_engineering/data.jsonl +0 -0
  126. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  127. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  128. {attacklm-0.9.2 → attacklm-0.9.4}/data/datasets/buckets/sources/threathunter-playbook/defensive/threat_hunting/data.jsonl +0 -0
  129. {attacklm-0.9.2 → attacklm-0.9.4}/data/golden/prompts.jsonl +0 -0
  130. {attacklm-0.9.2 → attacklm-0.9.4}/data/reference/prompts.jsonl +0 -0
  131. {attacklm-0.9.2 → attacklm-0.9.4}/data/steering/prompts/opsec_aware.txt +0 -0
  132. {attacklm-0.9.2 → attacklm-0.9.4}/data/steering/prompts/opsec_unaware.txt +0 -0
  133. {attacklm-0.9.2 → attacklm-0.9.4}/data/steering/prompts/succinct.txt +0 -0
  134. {attacklm-0.9.2 → attacklm-0.9.4}/data/steering/prompts/verbose.txt +0 -0
  135. {attacklm-0.9.2 → attacklm-0.9.4}/experiments/README.md +0 -0
  136. {attacklm-0.9.2 → attacklm-0.9.4}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  137. {attacklm-0.9.2 → attacklm-0.9.4}/hf/.gitattributes +0 -0
  138. {attacklm-0.9.2 → attacklm-0.9.4}/hf/README.md +0 -0
  139. {attacklm-0.9.2 → attacklm-0.9.4}/hf/data/manifest.json +0 -0
  140. {attacklm-0.9.2 → attacklm-0.9.4}/hf/dataset_infos.json +0 -0
  141. {attacklm-0.9.2 → attacklm-0.9.4}/hf/scripts/build_hf_dataset.py +0 -0
  142. {attacklm-0.9.2 → attacklm-0.9.4}/hf/scripts/push_to_hf.py +0 -0
  143. {attacklm-0.9.2 → attacklm-0.9.4}/hpo_runs/.gitkeep +0 -0
  144. {attacklm-0.9.2 → attacklm-0.9.4}/hpo_runs/hpo_state.json +0 -0
  145. {attacklm-0.9.2 → attacklm-0.9.4}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  146. {attacklm-0.9.2 → attacklm-0.9.4}/logs/.gitkeep +0 -0
  147. {attacklm-0.9.2 → attacklm-0.9.4}/presets/blue-team.json +0 -0
  148. {attacklm-0.9.2 → attacklm-0.9.4}/presets/deepspeed/README.md +0 -0
  149. {attacklm-0.9.2 → attacklm-0.9.4}/presets/deepspeed/zero2_cpu_offload.json +0 -0
  150. {attacklm-0.9.2 → attacklm-0.9.4}/presets/deepspeed/zero3_cpu_offload.json +0 -0
  151. {attacklm-0.9.2 → attacklm-0.9.4}/presets/deepspeed/zero3_gpu_only.json +0 -0
  152. {attacklm-0.9.2 → attacklm-0.9.4}/presets/purple-team.json +0 -0
  153. {attacklm-0.9.2 → attacklm-0.9.4}/presets/red-team.json +0 -0
  154. {attacklm-0.9.2 → attacklm-0.9.4}/requirements.txt +0 -0
  155. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/_eval_loader.py +0 -0
  156. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_cloud_attack_dataset.py +0 -0
  157. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_ics_dataset.py +0 -0
  158. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_phishing_dataset.py +0 -0
  159. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_red_team_tactics.py +0 -0
  160. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_replay_general.py +0 -0
  161. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_supply_chain_dataset.py +0 -0
  162. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_web_attack_dataset.py +0 -0
  163. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/acquire_wireless_dataset.py +0 -0
  164. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/audit_dataset.py +0 -0
  165. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/bucket_loader.py +0 -0
  166. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/clone_repos.sh +0 -0
  167. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/collect_reference.py +0 -0
  168. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/compare_scores.py +0 -0
  169. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/demo.py +0 -0
  170. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/device_utils.py +0 -0
  171. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/domain_bench.py +0 -0
  172. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/eval_retention.py +0 -0
  173. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/evolve_pairs.py +0 -0
  174. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/evolved_mixer.py +0 -0
  175. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  176. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  177. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_by_tactic.py +0 -0
  178. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  179. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  180. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_nist_ir.py +0 -0
  181. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/extract_rta_to_jsonl.py +0 -0
  182. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/filter_evolved.py +0 -0
  183. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/generate_synthetic_scarce.py +0 -0
  184. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/golden_vectors.py +0 -0
  185. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/hpo_runner.py +0 -0
  186. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/import_gguf.sh +0 -0
  187. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/import_to_lmstudio.sh +0 -0
  188. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/infer.py +0 -0
  189. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/mitre_tactic_lookup.py +0 -0
  190. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/package_dataset.py +0 -0
  191. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/parse_metasploit_to_jsonl.py +0 -0
  192. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/rebuild_manifest.py +0 -0
  193. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/register_ollama.py +0 -0
  194. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/reorganize_buckets.py +0 -0
  195. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/replay_mixer.py +0 -0
  196. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/score_candidates.py +0 -0
  197. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/setup_buckets.py +0 -0
  198. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/speed_bench.py +0 -0
  199. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/steering.py +0 -0
  200. {attacklm-0.9.2 → attacklm-0.9.4}/scripts/train_all.py +0 -0
  201. {attacklm-0.9.2 → attacklm-0.9.4}/src/attacklm/__init__.py +0 -0
  202. {attacklm-0.9.2 → attacklm-0.9.4}/src/attacklm/_project_root.py +0 -0
  203. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_balance_buckets.py +0 -0
  204. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_collect_reference.py +0 -0
  205. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_compare_scores.py +0 -0
  206. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_domain_bench.py +0 -0
  207. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_eval_loader.py +0 -0
  208. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_eval_retention.py +0 -0
  209. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_evolve_pairs.py +0 -0
  210. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_golden_vectors.py +0 -0
  211. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_replay_mixer.py +0 -0
  212. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_score_candidates.py +0 -0
  213. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_speed_bench.py +0 -0
  214. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_steering.py +0 -0
  215. {attacklm-0.9.2 → attacklm-0.9.4}/tests/test_thinking_models.py +0 -0
  216. {attacklm-0.9.2 → attacklm-0.9.4}/uv.lock +0 -0
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.3] — 2026-07-04 — Remove deprecated hyphenated commands, --compile + QLoRA guard
4
+
5
+ ### Removed
6
+ - **Deprecated hyphenated commands**: All 22 `attacklm-*` console scripts removed from `pyproject.toml` and `cli.py` after the v0.8.x deprecation window. Use `attacklm <subcommand>` instead.
7
+ - `attacklm-train` → `attacklm train`
8
+ - `attacklm-train-all` → `attacklm train --all`
9
+ - `attacklm-train-lora` → `attacklm train`
10
+ - `attacklm-hpo` → `attacklm train --hpo`
11
+ - `attacklm-extract` → `attacklm init --extract-only`
12
+ - `attacklm-buckets` → `attacklm init --buckets-only`
13
+ - `attacklm-attribute` → `attacklm init --attribute-only`
14
+ - `attacklm-clone` → `attacklm init --clone-only`
15
+ - `attacklm-init` → `attacklm init`
16
+ - `attacklm-balance` → `attacklm balance`
17
+ - `attacklm-merge` → `attacklm build --merge-only`
18
+ - `attacklm-gguf` → `attacklm build --gguf-only`
19
+ - `attacklm-build` → `attacklm build`
20
+ - `attacklm-infer` → `attacklm infer`
21
+ - `attacklm-demo` → `attacklm demo`
22
+ - `attacklm-eval` → `attacklm eval`
23
+ - `attacklm-collect-ref` → `attacklm eval --collect-ref`
24
+ - `attacklm-score` → `attacklm eval --score`
25
+ - `attacklm-compare` → `attacklm eval --compare`
26
+ - `attacklm-golden` → `attacklm eval --golden`
27
+ - `attacklm-pipeline` → `attacklm pipeline`
28
+ - **Deprecated wrapper code**: Removed `_deprecated()` helper, `_DEPRECATED_MSG` constant, and all 19 `main_*` wrapper functions from `src/attacklm/cli.py`
29
+
30
+ ### Added
31
+ - **`--compile` + QLoRA incompatibility guard**: `train_template.py` now exits with a clear error if `--compile` is used with default 4-bit QLoRA (BitsAndBytes NF4). torch.compile is incompatible with quantized models. Users are directed to use `--use-galore` or `--use-deepspeed` for full-parameter training with compilation.
32
+ - **5 new tests** in `test_memory_optimization.py` verifying the compile+QLoRA guard and compatibility with GaLore, DeepSpeed, and Unsloth
33
+
34
+ ### Changed
35
+ - **All script references updated**: 30+ references across 10 script files, 5 extractors, GUI, and pipeline config updated from hyphenated to subcommand form
36
+ - **Documentation**: `CONTRIBUTING.md` and `EVALUATION.md` updated with new command forms
37
+
38
+ ---
39
+
3
40
  ## [0.9.0] — 2026-07-01 — Memory optimization: DeepSpeed, torch.compile, LOMO
4
41
 
5
42
  ### Added
@@ -94,7 +94,7 @@ Buckets live in `data/datasets/buckets/<bucket_name>/` and contain a
94
94
  uv pip install -e ".[all,dev]"
95
95
 
96
96
  # Run a sanity check on the training pipeline
97
- attacklm-train \
97
+ attacklm train \
98
98
  --dataset data/datasets/combined/combined_*.jsonl \
99
99
  --output /tmp/test-output --dry-run
100
100
  ```
@@ -64,7 +64,7 @@ For each candidate, run these 4 patterns in order:
64
64
 
65
65
  ### Step 1: Golden Vectors (Pattern 2) — Fast Regression Gate
66
66
 
67
- **Script**: `python scripts/golden_vectors.py validate ...`
67
+ **Command**: `attacklm eval --golden ...`
68
68
 
69
69
  **Duration**: < 2 minutes
70
70
 
@@ -77,7 +77,7 @@ For each candidate, run these 4 patterns in order:
77
77
 
78
78
  ### Step 2: Reference Scoring (Pattern 1) — Quality Comparison
79
79
 
80
- **Script**: `python scripts/score_candidates.py ...` then `python scripts/compare_scores.py ...`
80
+ **Command**: `attacklm eval --collect-ref ...` then `attacklm eval --compare ...`
81
81
 
82
82
  **Duration**: ~15 minutes
83
83
 
@@ -87,7 +87,7 @@ For each candidate, run these 4 patterns in order:
87
87
 
88
88
  ### Step 3: Domain Benchmark (Pattern 3) — Capability Evaluation
89
89
 
90
- **Script**: `python scripts/domain_bench.py ...`
90
+ **Command**: `attacklm eval --score ...`
91
91
 
92
92
  **Duration**: ~10 minutes
93
93
 
@@ -100,7 +100,7 @@ For each candidate, run these 4 patterns in order:
100
100
 
101
101
  ### Step 4: Speed Benchmark (Pattern 4) — Performance Comparison
102
102
 
103
- **Script**: `python scripts/speed_bench.py ...`
103
+ **Command**: `attacklm eval --speed ...` (or via `scripts/speed_bench.py`)
104
104
 
105
105
  **Duration**: ~5 minutes
106
106
 
@@ -144,13 +144,13 @@ When iterating quickly (e.g., testing hyperparameter changes), run only:
144
144
 
145
145
  ```bash
146
146
  # Fast gate: 2 minutes
147
- python scripts/golden_vectors.py validate \
147
+ attacklm eval --golden \
148
148
  --base-model <model> --adapter <adapter> \
149
149
  --golden data/golden/vectors.json \
150
150
  --output /tmp/golden_check.json
151
151
 
152
152
  # If PASS, run domain benchmark: 10 minutes
153
- python scripts/domain_bench.py \
153
+ attacklm eval --score \
154
154
  --base-model <model> --adapter <adapter> \
155
155
  --questions data/bench/questions.jsonl \
156
156
  --output /tmp/bench_check.json
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attacklm
3
- Version: 0.9.2
3
+ Version: 0.9.4
4
4
  Summary: A high-performance fine-tuning pipeline (QLoRA, GaLore, Q-GaLore, Spectrum, PiSSA, DeepSpeed) for creating MITRE ATT&CK-grounded security AI assistants
5
5
  Project-URL: Homepage, https://github.com/Veedubin/AttackLM
6
6
  Project-URL: Repository, https://github.com/Veedubin/AttackLM
@@ -1,7 +1,6 @@
1
1
  """Simpler command form screens for non-training AttackLM commands.
2
2
 
3
- Updated for v0.8.0 unified CLI: uses 'attacklm <subcommand>' format
4
- instead of the old hyphenated commands.
3
+ Uses the unified 'attacklm <subcommand>' CLI format (v0.8.0+).
5
4
  """
6
5
 
7
6
  from __future__ import annotations
@@ -329,7 +328,7 @@ class EvalFormScreen(_BaseCommandScreen):
329
328
 
330
329
 
331
330
  class PipelineFormScreen(_BaseCommandScreen):
332
- """Run the training pipeline using 'attacklm-pipeline' (unchanged)."""
331
+ """Run the training pipeline using 'attacklm pipeline'."""
333
332
 
334
333
  def compose(self) -> ComposeResult:
335
334
  with Container(id="cmd-container"):
@@ -345,7 +344,7 @@ class PipelineFormScreen(_BaseCommandScreen):
345
344
  self.app.pop_screen()
346
345
  elif event.button.id == "btn-run":
347
346
  values = self._get_values()
348
- cmd = ["attacklm-pipeline"]
347
+ cmd = ["attacklm", "pipeline"]
349
348
  if values.get("config"):
350
349
  cmd.extend(["--config", values["config"]])
351
350
  import asyncio
@@ -319,7 +319,7 @@ class TrainFormScreen(Screen):
319
319
  return values
320
320
 
321
321
  def _build_command(self, values: dict) -> list[str]:
322
- """Build the attacklm-train command from form values."""
322
+ """Build the attacklm train command from form values."""
323
323
  cmd = ["attacklm", "train"]
324
324
 
325
325
  # Required
@@ -1,7 +1,7 @@
1
1
  # AttackLM Training Pipeline — Example Configuration
2
2
  #
3
3
  # Usage:
4
- # attacklm-pipeline --config pipeline.example.yaml
4
+ # attacklm pipeline --config pipeline.example.yaml
5
5
  #
6
6
  # Each job runs sequentially: train → merge → gguf → install.
7
7
  # If a stage fails, the pipeline skips to the next job.
@@ -226,45 +226,21 @@ all-rocm = ["attacklm[train-rocm,extract,convert]"]
226
226
 
227
227
  # ── Console script entry points ───────────────────────────────────────────────
228
228
  #
229
- # v0.8.0+: The unified ``attacklm`` command (subcommand-based) is the primary
230
- # interface. The old hyphenated commands are DEPRECATED but kept for one
231
- # release cycle. They print a deprecation warning and delegate to the new
232
- # subcommand. They will be removed in v0.9.0.
229
+ # v0.8.0+ introduced the unified ``attacklm`` command (subcommand-based).
230
+ # The old hyphenated commands (attacklm-train, attacklm-merge, etc.) were
231
+ # deprecated in v0.8.x and removed in v0.9.3.
233
232
 
234
233
  [project.scripts]
235
- # New unified CLI
234
+ # Unified CLI (the only entry point since v0.9.3)
236
235
  attacklm = "attacklm.cli:main"
237
236
 
238
- # Deprecated (v0.8.x) — to be removed in v0.9.0
239
- attacklm-train = "attacklm.cli:main_train"
240
- attacklm-train-all = "attacklm.cli:main_train_all"
241
- attacklm-hpo = "attacklm.cli:main_hpo"
242
- attacklm-infer = "attacklm.cli:main_infer"
243
- attacklm-merge = "attacklm.cli:main_merge"
244
- attacklm-gguf = "attacklm.cli:main_gguf"
245
- attacklm-demo = "attacklm.cli:main_demo"
246
- attacklm-extract = "attacklm.cli:main_extract"
247
- attacklm-buckets = "attacklm.cli:main_buckets"
248
- attacklm-attribute = "attacklm.cli:main_attribute"
249
- attacklm-clone = "attacklm.cli:main_clone"
250
- attacklm-init = "attacklm.cli:main_init"
251
- attacklm-balance = "attacklm.cli:main_balance"
252
- attacklm-build = "attacklm.cli:main_build"
253
- attacklm-train-lora = "attacklm.cli:main_train_lora"
254
- attacklm-eval = "attacklm.cli:main_eval"
255
- attacklm-collect-ref = "attacklm.cli:main_collect_ref"
256
- attacklm-score = "attacklm.cli:main_score"
257
- attacklm-compare = "attacklm.cli:main_compare"
258
- attacklm-golden = "attacklm.cli:main_golden"
259
- attacklm-pipeline = "attacklm.scripts.pipeline:main"
260
-
261
237
  # ── Hatch build configuration ─────────────────────────────────────────────────
262
238
 
263
239
  [tool.hatch.build.targets.wheel]
264
240
  packages = ["src/attacklm"]
265
241
 
266
242
  # Include scripts/ in the wheel so CLI entry points can find them.
267
- # Without this, `attacklm-train-all` etc. fail with "script not found"
243
+ # Without this, the unified ``attacklm`` command fails with "script not found"
268
244
  # because _SCRIPTS_DIR resolves to site-packages/scripts/ which is empty.
269
245
  # scripts/ is ~200KB of Python — negligible for the wheel.
270
246
  [tool.hatch.build.targets.wheel.force-include]
@@ -67,9 +67,9 @@ Write a balanced JSONL to data/datasets/balanced/:
67
67
  python scripts/balance_buckets.py --profile 7b-128gb \\
68
68
  --output data/datasets/balanced/balanced_7b-128gb.jsonl
69
69
 
70
- Then pass that file to attacklm-train:
70
+ Then pass that file to attacklm train:
71
71
 
72
- attacklm-train --dataset data/datasets/balanced/balanced_7b-128gb.jsonl \\
72
+ attacklm train --dataset data/datasets/balanced/balanced_7b-128gb.jsonl \\
73
73
  --output models/attacklm-7b-128gb \\
74
74
  --base-model huihui-ai/Qwen2.5-Coder-7B-Instruct-abliterated
75
75
 
@@ -104,7 +104,7 @@ from pathlib import Path
104
104
  from typing import Iterable
105
105
 
106
106
  # Reuse the existing bucket plumbing.
107
- # When invoked as a console script (`attacklm-balance`), the working
107
+ # When invoked as a console script (`attacklm balance`), the working
108
108
  # directory may not be the project root, so we need to make sure
109
109
  # sibling scripts in this directory are importable. Same pattern
110
110
  # as scripts/train_template.py.
@@ -1025,7 +1025,7 @@ def main(argv: list[str] | None = None) -> int:
1025
1025
  print(f"Wrote {len(selected):,} pairs ({size_mb:.1f} MB) to {args.output}")
1026
1026
  print(
1027
1027
  f"\nNext step:\n"
1028
- f" attacklm-train --dataset {args.output} \\\n"
1028
+ f" attacklm train --dataset {args.output} \\\n"
1029
1029
  f" --output models/attacklm-{args.profile.replace('-', '_')}_<timestamp> \\\n"
1030
1030
  f" --base-model huihui-ai/Qwen2.5-Coder-3B-Instruct-abliterated"
1031
1031
  )
@@ -7,12 +7,12 @@ manifest at models/built/{name}_{timestamp}/.
7
7
 
8
8
  This replaces the 3-command shell pipeline:
9
9
 
10
- attacklm-merge --base X --adapter Y --output Z \\
11
- && attacklm-gguf --input Z --install-lmstudio
10
+ attacklm build --merge-only -- --base X --adapter Y --output Z \\
11
+ && attacklm build --gguf-only -- --input Z --install-lmstudio
12
12
 
13
13
  with a single command:
14
14
 
15
- attacklm-build --adapter models/attacklm-3b_16g \\
15
+ attacklm build --adapter models/attacklm-3b_16g \\
16
16
  --base ./uncensored/ \\
17
17
  --name attacklm-3b-16g \\
18
18
  --install-lmstudio
@@ -29,24 +29,24 @@ orchestrator is just glue.
29
29
  Usage:
30
30
 
31
31
  # Full pipeline: merge + GGUF + LM Studio
32
- attacklm-build --adapter models/attacklm-3b_16g \\
32
+ attacklm build --adapter models/attacklm-3b_16g \\
33
33
  --base ./uncensored/ \\
34
34
  --name attacklm-3b-16g
35
35
 
36
36
  # Skip LM Studio install, drop the GGUF in models/gguf/ only
37
- attacklm-build --adapter models/attacklm-3b_16g \\
37
+ attacklm build --adapter models/attacklm-3b_16g \\
38
38
  --base ./uncensored/ \\
39
39
  --name attacklm-3b-16g \\
40
40
  --no-install-lmstudio
41
41
 
42
42
  # Register with Ollama too
43
- attacklm-build --adapter models/attacklm-3b_16g \\
43
+ attacklm build --adapter models/attacklm-3b_16g \\
44
44
  --base ./uncensored/ \\
45
45
  --name attacklm-3b-16g \\
46
46
  --register-ollama
47
47
 
48
48
  # Use an already-merged model (skip the merge step)
49
- attacklm-build --merged models/merged/attacklm-3b-16g \\
49
+ attacklm build --merged models/merged/attacklm-3b-16g \\
50
50
  --name attacklm-3b-16g
51
51
  """
52
52
 
@@ -106,7 +106,7 @@ def main(argv: list[str] | None = None) -> int:
106
106
  "--adapter",
107
107
  type=Path,
108
108
  default=None,
109
- help="Path to the LoRA adapter directory (output of attacklm-train).",
109
+ help="Path to the LoRA adapter directory (output of ``attacklm train``).",
110
110
  )
111
111
  parser.add_argument(
112
112
  "--merged",
@@ -7,13 +7,13 @@ Step 2: llama-quantize → Q4_K_M
7
7
 
8
8
  Usage:
9
9
  # Convert all merged models:
10
- attacklm-gguf
10
+ attacklm build --gguf-only
11
11
 
12
12
  # Convert a single model:
13
- attacklm-gguf --input models/merged/attacklm
13
+ attacklm build --gguf-only -- --input models/merged/attacklm
14
14
 
15
15
  # Convert and install to LM Studio:
16
- attacklm-gguf --install-lmstudio
16
+ attacklm build --gguf-only -- --install-lmstudio
17
17
  """
18
18
 
19
19
  import argparse
@@ -95,7 +95,7 @@ def _is_lora_adapter(model_dir: Path) -> bool:
95
95
  over from a previous training run), so the old "needs config.json" guard
96
96
  let it through and llama.cpp's converter then crashed on the wrong
97
97
  architecture. This check is explicit: if adapter_config.json says
98
- PEFT_TYPE_LORA, refuse with a pointer to attacklm-merge.
98
+ PEFT_TYPE_LORA, refuse with a pointer to ``attacklm build --merge-only``.
99
99
  """
100
100
  ac = model_dir / "adapter_config.json"
101
101
  if not ac.exists():
@@ -204,7 +204,7 @@ def main() -> None:
204
204
  # from a previous run, so the old "needs config.json" guard passed
205
205
  # it through and llama.cpp's converter then crashed on the wrong
206
206
  # architecture with `Failed to detect model architecture`. Detect
207
- # PEFT adapters early and point users at attacklm-merge.
207
+ # PEFT adapters early and point users at ``attacklm build --merge-only``.
208
208
  if _is_lora_adapter(input_path):
209
209
  # Try to read the auto-detected base from state.json (v0.1.6+)
210
210
  # or adapter_config.json (v0.1.5 and earlier) so the hint
@@ -237,11 +237,11 @@ def main() -> None:
237
237
  f" Need: a directory with config.json + *.safetensors (full merged weights)"
238
238
  )
239
239
  print(f"\nFix: merge the adapter into the base first, then convert.")
240
- print(f" attacklm-merge --adapter {args.input} \\")
240
+ print(f" attacklm build --merge-only -- --adapter {args.input} \\")
241
241
  print(f" --base {suggested_base} \\")
242
242
  print(f" --output models/merged/{input_path.name}")
243
243
  print(
244
- f" attacklm-gguf --input models/merged/{input_path.name}"
244
+ f" attacklm build --gguf-only -- --input models/merged/{input_path.name}"
245
245
  + (" --install-lmstudio" if args.install_lmstudio else "")
246
246
  )
247
247
  sys.exit(1)
@@ -250,7 +250,9 @@ def main() -> None:
250
250
  ):
251
251
  print(f"\nERROR: {args.input} is not a valid merged model directory")
252
252
  print("Expected a directory containing config.json and *.safetensors")
253
- print("If this is a LoRA adapter, run `attacklm-merge` first (see above).")
253
+ print(
254
+ "If this is a LoRA adapter, run ``attacklm build --merge-only`` first (see above)."
255
+ )
254
256
  sys.exit(1)
255
257
  models = [input_path]
256
258
  else:
@@ -258,9 +260,9 @@ def main() -> None:
258
260
  if not models:
259
261
  print(f"\nERROR: No merged models found in {MERGED_DIR}")
260
262
  print(
261
- "Run: attacklm-merge --adapter models/attacklm-single --output models/merged/attacklm"
263
+ "Run: attacklm build --merge-only -- --adapter models/attacklm-single --output models/merged/attacklm"
262
264
  )
263
- print(" or: attacklm-merge --merge-all")
265
+ print(" or: attacklm build --merge-only -- --merge-all")
264
266
  sys.exit(1)
265
267
 
266
268
  GGUF_DIR.mkdir(parents=True, exist_ok=True)
@@ -278,7 +278,7 @@ def main() -> int:
278
278
 
279
279
  if not RULES_DIR.exists():
280
280
  print(f"Elastic rules directory not found: {RULES_DIR}", file=sys.stderr)
281
- print("Run attacklm-clone or attacklm-init first.", file=sys.stderr)
281
+ print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
282
282
  return 1
283
283
 
284
284
  toml_files = sorted(RULES_DIR.rglob("*.toml"))
@@ -331,7 +331,7 @@ def main() -> int:
331
331
  scenarios = find_scenarios()
332
332
  if not scenarios:
333
333
  print(f"No Mordor scenarios found in {MORDOR_DIR}", file=sys.stderr)
334
- print("Run attacklm-clone or attacklm-init first.", file=sys.stderr)
334
+ print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
335
335
  return 1
336
336
 
337
337
  if args.max_files > 0:
@@ -239,7 +239,7 @@ def main() -> int:
239
239
 
240
240
  if not RULES_DIR.exists():
241
241
  print(f"Sigma rules directory not found: {RULES_DIR}", file=sys.stderr)
242
- print("Run attacklm-clone or attacklm-init first.", file=sys.stderr)
242
+ print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
243
243
  return 1
244
244
 
245
245
  yml_files = sorted(RULES_DIR.rglob("*.yml"))
@@ -240,7 +240,7 @@ def main() -> int:
240
240
  print(
241
241
  f"Splunk detections directory not found: {DETECTIONS_DIR}", file=sys.stderr
242
242
  )
243
- print("Run attacklm-clone or attacklm-init first.", file=sys.stderr)
243
+ print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
244
244
  return 1
245
245
 
246
246
  yml_files = sorted(DETECTIONS_DIR.rglob("*.yml"))
@@ -230,7 +230,7 @@ def main() -> int:
230
230
 
231
231
  if not PLAYBOOKS_DIR.exists():
232
232
  print(f"Playbooks directory not found: {PLAYBOOKS_DIR}", file=sys.stderr)
233
- print("Run attacklm-clone or attacklm-init first.", file=sys.stderr)
233
+ print("Run attacklm init --clone-only or attacklm init first.", file=sys.stderr)
234
234
  return 1
235
235
 
236
236
  md_files = sorted(PLAYBOOKS_DIR.rglob("*.md"))
@@ -10,20 +10,20 @@ developers who want to modify the extraction pipeline or rebuild from scratch.
10
10
 
11
11
  Usage::
12
12
 
13
- attacklm-init # download pre-built dataset (default)
14
- attacklm-init --from-source # rebuild from upstream repos
15
- attacklm-init --dataset-url URL # download from a custom URL
16
- attacklm-init --yes # auto-confirm prompts
17
- attacklm-init --dry-run # show what would happen, do nothing
13
+ attacklm init # download pre-built dataset (default)
14
+ attacklm init --from-source # rebuild from upstream repos
15
+ attacklm init --dataset-url URL # download from a custom URL
16
+ attacklm init --yes # auto-confirm prompts
17
+ attacklm init --dry-run # show what would happen, do nothing
18
18
 
19
19
  From-source flags (only apply with ``--from-source``)::
20
20
 
21
- attacklm-init --from-source --skip-clone # assume data on disk
22
- attacklm-init --from-source --skip-attribute # skip attribution
23
- attacklm-init --from-source --skip-buckets # skip bucketing
24
- attacklm-init --from-source --force-clone # re-clone repos
25
- attacklm-init --from-source --force-extract # re-run extractors
26
- attacklm-init --from-source --clean-buckets # clean old flat files
21
+ attacklm init --from-source --skip-clone # assume data on disk
22
+ attacklm init --from-source --skip-attribute # skip attribution
23
+ attacklm init --from-source --skip-buckets # skip bucketing
24
+ attacklm init --from-source --force-clone # re-clone repos
25
+ attacklm init --from-source --force-extract # re-run extractors
26
+ attacklm init --from-source --clean-buckets # clean old flat files
27
27
 
28
28
  Exit codes:
29
29
  0 success
@@ -101,7 +101,7 @@ def _check_download_deps() -> None:
101
101
  print(
102
102
  "\n!!! Missing Python dependencies: " + ", ".join(missing) + "\n"
103
103
  " Run: pip install attacklm[extract]\n"
104
- " and then re-run attacklm-init.\n",
104
+ " and then re-run attacklm init.\n",
105
105
  file=sys.stderr,
106
106
  )
107
107
  raise DependencyError(missing)
@@ -327,13 +327,13 @@ def _download_with_progress(url: str, dest: Path) -> None:
327
327
  print(
328
328
  "\n!!! Dataset tarball not found (HTTP 404).\n"
329
329
  " This usually means no release has been published yet.\n"
330
- " Try: attacklm-init --from-source\n",
330
+ " Try: attacklm init --from-source\n",
331
331
  file=sys.stderr,
332
332
  )
333
333
  sys.exit(3)
334
334
  print(
335
335
  f"\n!!! HTTP error {exc.code}: {exc.reason}\n"
336
- " Try: attacklm-init --from-source\n",
336
+ " Try: attacklm init --from-source\n",
337
337
  file=sys.stderr,
338
338
  )
339
339
  sys.exit(3)
@@ -341,14 +341,14 @@ def _download_with_progress(url: str, dest: Path) -> None:
341
341
  print(
342
342
  f"\n!!! Network error: {exc.reason}\n"
343
343
  " Check your internet connection and try again.\n"
344
- " Fallback: attacklm-init --from-source\n",
344
+ " Fallback: attacklm init --from-source\n",
345
345
  file=sys.stderr,
346
346
  )
347
347
  sys.exit(3)
348
348
  except OSError as exc:
349
349
  print(
350
350
  f"\n!!! Download failed: {exc}\n"
351
- " Fallback: attacklm-init --from-source\n",
351
+ " Fallback: attacklm init --from-source\n",
352
352
  file=sys.stderr,
353
353
  )
354
354
  sys.exit(3)
@@ -402,7 +402,7 @@ def _verify_extraction() -> None:
402
402
  "\n!!! Extraction verification failed: "
403
403
  f"{SOURCES_DIR.relative_to(BASE_DIR)} does not exist.\n"
404
404
  " The tarball may be corrupted or have an unexpected layout.\n"
405
- " Try: attacklm-init --from-source\n",
405
+ " Try: attacklm init --from-source\n",
406
406
  file=sys.stderr,
407
407
  )
408
408
  sys.exit(1)
@@ -412,7 +412,7 @@ def _verify_extraction() -> None:
412
412
  f"\n!!! Extraction verification failed: {SOURCES_DIR.relative_to(BASE_DIR)} "
413
413
  "is empty.\n"
414
414
  " The tarball may be corrupted.\n"
415
- " Try: attacklm-init --from-source\n",
415
+ " Try: attacklm init --from-source\n",
416
416
  file=sys.stderr,
417
417
  )
418
418
  sys.exit(1)
@@ -695,9 +695,9 @@ def _confirm(msg: str, assume_yes: bool) -> bool:
695
695
  def _print_next_steps() -> None:
696
696
  print(
697
697
  "\nNext steps:\n"
698
- " - attacklm-balance # balance the per-tactic distributions\n"
699
- " - attacklm-train-all # train all buckets\n"
700
- " - attacklm-build # merge → GGUF → install\n",
698
+ " - attacklm balance # balance the per-tactic distributions\n"
699
+ " - attacklm train --all # train all buckets\n"
700
+ " - attacklm build # merge → GGUF → install\n",
701
701
  file=sys.stderr,
702
702
  )
703
703
 
@@ -776,7 +776,7 @@ def main(argv: Sequence[str] | None = None) -> int:
776
776
  args = parser.parse_args(argv)
777
777
 
778
778
  print("=" * 72, file=sys.stderr)
779
- print("attacklm-init: one-shot dataset initialization", file=sys.stderr)
779
+ print("attacklm init: one-shot dataset initialization", file=sys.stderr)
780
780
  print("=" * 72, file=sys.stderr)
781
781
 
782
782
  # ── Download mode (default) ─────────────────────────────────────────────
@@ -902,7 +902,7 @@ def main(argv: Sequence[str] | None = None) -> int:
902
902
  return rc
903
903
 
904
904
  print("\n" + "=" * 72, file=sys.stderr)
905
- print("attacklm-init: complete (from-source)", file=sys.stderr)
905
+ print("attacklm init: complete (from-source)", file=sys.stderr)
906
906
  print("=" * 72, file=sys.stderr)
907
907
  _print_next_steps()
908
908
  return 0
@@ -4,13 +4,13 @@ merge_adapter.py — Merge a LoRA adapter into its base model for standalone dep
4
4
 
5
5
  Usage:
6
6
  # Merge a single adapter (base model auto-detected from adapter_config.json):
7
- attacklm-merge --adapter models/attacklm-single --output models/merged/attacklm
7
+ attacklm build --merge-only -- --adapter models/attacklm-single --output models/merged/attacklm
8
8
 
9
9
  # Merge all trained adapters:
10
- attacklm-merge --merge-all
10
+ attacklm build --merge-only -- --merge-all
11
11
 
12
12
  # Override the base model explicitly:
13
- attacklm-merge --adapter models/attacklm-single --output models/merged/attacklm --base-model Qwen/Qwen2.5-Coder-3B-Instruct
13
+ attacklm build --merge-only -- --adapter models/attacklm-single --output models/merged/attacklm --base-model Qwen/Qwen2.5-Coder-3B-Instruct
14
14
  """
15
15
 
16
16
  import argparse
@@ -5,7 +5,7 @@ Reads a YAML config file defining one or more training jobs.
5
5
  Each job runs sequentially: train → merge → gguf → install.
6
6
 
7
7
  Usage:
8
- attacklm-pipeline --config pipeline.yaml
8
+ attacklm pipeline --config pipeline.yaml
9
9
  python scripts/pipeline.py --config pipeline.yaml
10
10
  """
11
11
 
@@ -36,7 +36,7 @@ def parse_args():
36
36
 
37
37
 
38
38
  def run_train(job_name: str, train_cfg: dict) -> bool:
39
- """Run attacklm-train with the given config. Returns True on success."""
39
+ """Run attacklm train with the given config. Returns True on success."""
40
40
  script = str(Path(__file__).parent / "train_template.py")
41
41
  cmd = [sys.executable, script, "--train"]
42
42
 
@@ -84,7 +84,7 @@ def run_train(job_name: str, train_cfg: dict) -> bool:
84
84
 
85
85
 
86
86
  def run_merge(job_name: str, merge_cfg: dict, train_cfg: dict) -> bool:
87
- """Run attacklm-merge to combine LoRA adapter with base model."""
87
+ """Run attacklm build --merge-only to combine LoRA adapter with base model."""
88
88
  script = str(Path(__file__).parent / "merge.py")
89
89
 
90
90
  # Determine input: merge.output or train.output
@@ -114,7 +114,7 @@ def run_merge(job_name: str, merge_cfg: dict, train_cfg: dict) -> bool:
114
114
 
115
115
 
116
116
  def run_gguf(job_name: str, gguf_cfg: dict, merge_cfg: dict, train_cfg: dict) -> bool:
117
- """Run attacklm-gguf to convert merged model to GGUF format."""
117
+ """Run attacklm build --gguf-only to convert merged model to GGUF format."""
118
118
  script = str(Path(__file__).parent / "convert_to_gguf.py")
119
119
 
120
120
  # Determine input: gguf.output or merge.output or train.output