attacklm 0.9.2__tar.gz → 0.9.8__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 (219) hide show
  1. attacklm-0.9.8/.github/workflows/ci.yml +33 -0
  2. attacklm-0.9.8/.github/workflows/release.yml +86 -0
  3. {attacklm-0.9.2 → attacklm-0.9.8}/CHANGELOG.md +54 -0
  4. {attacklm-0.9.2 → attacklm-0.9.8}/CONTRIBUTING.md +1 -1
  5. {attacklm-0.9.2 → attacklm-0.9.8}/EVALUATION.md +6 -6
  6. {attacklm-0.9.2 → attacklm-0.9.8}/PKG-INFO +2 -1
  7. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/command_forms.py +3 -4
  8. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_form.py +1 -1
  9. {attacklm-0.9.2 → attacklm-0.9.8}/pipeline.example.yaml +1 -1
  10. {attacklm-0.9.2 → attacklm-0.9.8}/pyproject.toml +6 -29
  11. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/_eval_loader.py +1 -1
  12. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/balance_buckets.py +4 -4
  13. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/build.py +8 -8
  14. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/convert_to_gguf.py +12 -10
  15. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_elastic_rules.py +1 -1
  16. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_mordor.py +1 -1
  17. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_sigma_defensive.py +1 -1
  18. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_splunk_content.py +1 -1
  19. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_threathunter_playbook.py +1 -1
  20. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/init_pipeline.py +23 -23
  21. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/merge_adapter.py +3 -3
  22. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/pipeline.py +4 -4
  23. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/train_template.py +29 -7
  24. attacklm-0.9.8/src/attacklm/__version__.py +1 -0
  25. {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/cli.py +12 -205
  26. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_balance_buckets.py +21 -16
  27. attacklm-0.9.8/tests/test_cli.py +656 -0
  28. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_eval_loader.py +22 -7
  29. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_eval_retention.py +1 -1
  30. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_init_pipeline.py +7 -2
  31. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_memory_optimization.py +115 -1
  32. attacklm-0.9.2/.github/workflows/release.yml +0 -99
  33. attacklm-0.9.2/src/attacklm/__version__.py +0 -1
  34. {attacklm-0.9.2 → attacklm-0.9.8}/.gitignore +0 -0
  35. {attacklm-0.9.2 → attacklm-0.9.8}/ATTRIBUTION.md +0 -0
  36. {attacklm-0.9.2 → attacklm-0.9.8}/LICENSE +0 -0
  37. {attacklm-0.9.2 → attacklm-0.9.8}/MANIFEST.in +0 -0
  38. {attacklm-0.9.2 → attacklm-0.9.8}/Makefile +0 -0
  39. {attacklm-0.9.2 → attacklm-0.9.8}/NOTICE +0 -0
  40. {attacklm-0.9.2 → attacklm-0.9.8}/README.md +0 -0
  41. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/README.md +0 -0
  42. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/pyproject.toml +0 -0
  43. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/__init__.py +0 -0
  44. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/app.py +0 -0
  45. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/cli.py +0 -0
  46. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/presets.py +0 -0
  47. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/runner.py +0 -0
  48. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/__init__.py +0 -0
  49. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/main_menu.py +0 -0
  50. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/screens/train_live.py +0 -0
  51. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/src/attacklm_gui/widgets/__init__.py +0 -0
  52. {attacklm-0.9.2 → attacklm-0.9.8}/attacklm-gui/tests/test_gui.py +0 -0
  53. {attacklm-0.9.2 → attacklm-0.9.8}/data/ATTRIBUTION.md +0 -0
  54. {attacklm-0.9.2 → attacklm-0.9.8}/data/LEGAL.md +0 -0
  55. {attacklm-0.9.2 → attacklm-0.9.8}/data/REMOVAL.md +0 -0
  56. {attacklm-0.9.2 → attacklm-0.9.8}/data/bench/questions.jsonl +0 -0
  57. {attacklm-0.9.2 → attacklm-0.9.8}/data/bench/speed_context.txt +0 -0
  58. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/acquisition_report.json +0 -0
  59. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/manifest.json +0 -0
  60. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/README.md +0 -0
  61. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/_index.json +0 -0
  62. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/LICENSE.md +0 -0
  63. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/SOURCE.md +0 -0
  64. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/collection/data.jsonl +0 -0
  65. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/discovery/data.jsonl +0 -0
  66. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/execution/data.jsonl +0 -0
  67. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/exfiltration/data.jsonl +0 -0
  68. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/atomic-red-team/base/persistence/data.jsonl +0 -0
  69. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/LICENSE.md +0 -0
  70. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/SOURCE.md +0 -0
  71. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/attacklm-synthetic/orchestrator/data.jsonl +0 -0
  72. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/LICENSE.md +0 -0
  73. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/azure-pyrit/SOURCE.md +0 -0
  74. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/LICENSE.md +0 -0
  75. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/cyberark-fuzzyai/SOURCE.md +0 -0
  76. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/LICENSE.md +0 -0
  77. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/SOURCE.md +0 -0
  78. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/elastic-rules/defensive/detection_engineering/data.jsonl +0 -0
  79. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/LICENSE.md +0 -0
  80. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/SOURCE.md +0 -0
  81. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/cloud/attacks/data_llm.jsonl +0 -0
  82. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/ics/attacks/data_llm.jsonl +0 -0
  83. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/social_engineering/phishing/data_llm.jsonl +0 -0
  84. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/llm-generated/wireless/attacks/data_llm.jsonl +0 -0
  85. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/LICENSE.md +0 -0
  86. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/SOURCE.md +0 -0
  87. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/collection/data.jsonl +0 -0
  88. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/credential_access/data.jsonl +0 -0
  89. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/defense_evasion/data.jsonl +0 -0
  90. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/discovery/data.jsonl +0 -0
  91. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/execution/data.jsonl +0 -0
  92. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/lateral_movement/data.jsonl +0 -0
  93. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/persistence/data.jsonl +0 -0
  94. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/base/privilege_escalation/data.jsonl +0 -0
  95. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/metasploit-framework/tools/metasploit/data.jsonl +0 -0
  96. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/LICENSE.md +0 -0
  97. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/SOURCE.md +0 -0
  98. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-atlas-arsenal/base/discovery/data.jsonl +0 -0
  99. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/LICENSE.md +0 -0
  100. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/SOURCE.md +0 -0
  101. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/collection/data.jsonl +0 -0
  102. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/discovery/data.jsonl +0 -0
  103. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/execution/data.jsonl +0 -0
  104. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/exfiltration/data.jsonl +0 -0
  105. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mitre-stockpile/base/persistence/data.jsonl +0 -0
  106. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/LICENSE.md +0 -0
  107. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/SOURCE.md +0 -0
  108. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/mordor/defensive/threat_hunting/data.jsonl +0 -0
  109. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/LICENSE.md +0 -0
  110. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/SOURCE.md +0 -0
  111. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nist-ir/defensive/incident_response/data.jsonl +0 -0
  112. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/LICENSE.md +0 -0
  113. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/SOURCE.md +0 -0
  114. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/nvidia-garak/ai/jailbreaking/data.jsonl +0 -0
  115. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/LICENSE.md +0 -0
  116. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/SOURCE.md +0 -0
  117. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptfoo/ai/prompt-injection/data.jsonl +0 -0
  118. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/LICENSE.md +0 -0
  119. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/SOURCE.md +0 -0
  120. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/promptmap/ai/prompt-injection/data.jsonl +0 -0
  121. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/LICENSE.md +0 -0
  122. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/SOURCE.md +0 -0
  123. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_code.jsonl +0 -0
  124. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_conversation.jsonl +0 -0
  125. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_factual.jsonl +0 -0
  126. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/replay-general/base/replay/data_reasoning.jsonl +0 -0
  127. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/LICENSE.md +0 -0
  128. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/SOURCE.md +0 -0
  129. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/sigma-hq/defensive/detection_engineering/data.jsonl +0 -0
  130. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/LICENSE.md +0 -0
  131. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/SOURCE.md +0 -0
  132. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/splunk-content/defensive/detection_engineering/data.jsonl +0 -0
  133. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/LICENSE.md +0 -0
  134. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/SOURCE.md +0 -0
  135. {attacklm-0.9.2 → attacklm-0.9.8}/data/datasets/buckets/sources/threathunter-playbook/defensive/threat_hunting/data.jsonl +0 -0
  136. {attacklm-0.9.2 → attacklm-0.9.8}/data/golden/prompts.jsonl +0 -0
  137. {attacklm-0.9.2 → attacklm-0.9.8}/data/reference/prompts.jsonl +0 -0
  138. {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/opsec_aware.txt +0 -0
  139. {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/opsec_unaware.txt +0 -0
  140. {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/succinct.txt +0 -0
  141. {attacklm-0.9.2 → attacklm-0.9.8}/data/steering/prompts/verbose.txt +0 -0
  142. {attacklm-0.9.2 → attacklm-0.9.8}/experiments/README.md +0 -0
  143. {attacklm-0.9.2 → attacklm-0.9.8}/experiments/synthetic_dataset_mutator_evol_instruct.py +0 -0
  144. {attacklm-0.9.2 → attacklm-0.9.8}/hf/.gitattributes +0 -0
  145. {attacklm-0.9.2 → attacklm-0.9.8}/hf/README.md +0 -0
  146. {attacklm-0.9.2 → attacklm-0.9.8}/hf/data/manifest.json +0 -0
  147. {attacklm-0.9.2 → attacklm-0.9.8}/hf/dataset_infos.json +0 -0
  148. {attacklm-0.9.2 → attacklm-0.9.8}/hf/scripts/build_hf_dataset.py +0 -0
  149. {attacklm-0.9.2 → attacklm-0.9.8}/hf/scripts/push_to_hf.py +0 -0
  150. {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/.gitkeep +0 -0
  151. {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/hpo_state.json +0 -0
  152. {attacklm-0.9.2 → attacklm-0.9.8}/hpo_runs/hpo_trial_dataset.jsonl +0 -0
  153. {attacklm-0.9.2 → attacklm-0.9.8}/logs/.gitkeep +0 -0
  154. {attacklm-0.9.2 → attacklm-0.9.8}/presets/blue-team.json +0 -0
  155. {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/README.md +0 -0
  156. {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero2_cpu_offload.json +0 -0
  157. {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero3_cpu_offload.json +0 -0
  158. {attacklm-0.9.2 → attacklm-0.9.8}/presets/deepspeed/zero3_gpu_only.json +0 -0
  159. {attacklm-0.9.2 → attacklm-0.9.8}/presets/purple-team.json +0 -0
  160. {attacklm-0.9.2 → attacklm-0.9.8}/presets/red-team.json +0 -0
  161. {attacklm-0.9.2 → attacklm-0.9.8}/requirements.txt +0 -0
  162. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_cloud_attack_dataset.py +0 -0
  163. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_ics_dataset.py +0 -0
  164. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_phishing_dataset.py +0 -0
  165. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_red_team_tactics.py +0 -0
  166. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_replay_general.py +0 -0
  167. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_supply_chain_dataset.py +0 -0
  168. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_web_attack_dataset.py +0 -0
  169. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/acquire_wireless_dataset.py +0 -0
  170. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/audit_dataset.py +0 -0
  171. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/bucket_loader.py +0 -0
  172. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/clone_repos.sh +0 -0
  173. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/collect_reference.py +0 -0
  174. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/compare_scores.py +0 -0
  175. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/demo.py +0 -0
  176. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/device_utils.py +0 -0
  177. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/domain_bench.py +0 -0
  178. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/eval_retention.py +0 -0
  179. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/evolve_pairs.py +0 -0
  180. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/evolved_mixer.py +0 -0
  181. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_ai_tools_to_jsonl.py +0 -0
  182. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_atomic_red_team_to_jsonl.py +0 -0
  183. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_by_tactic.py +0 -0
  184. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_caldera_plugins_to_jsonl.py +0 -0
  185. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_infection_monkey_to_jsonl.py +0 -0
  186. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_nist_ir.py +0 -0
  187. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/extract_rta_to_jsonl.py +0 -0
  188. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/filter_evolved.py +0 -0
  189. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/generate_synthetic_scarce.py +0 -0
  190. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/golden_vectors.py +0 -0
  191. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/hpo_runner.py +0 -0
  192. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/import_gguf.sh +0 -0
  193. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/import_to_lmstudio.sh +0 -0
  194. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/infer.py +0 -0
  195. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/mitre_tactic_lookup.py +0 -0
  196. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/package_dataset.py +0 -0
  197. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/parse_metasploit_to_jsonl.py +0 -0
  198. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/rebuild_manifest.py +0 -0
  199. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/register_ollama.py +0 -0
  200. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/reorganize_buckets.py +0 -0
  201. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/replay_mixer.py +0 -0
  202. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/score_candidates.py +0 -0
  203. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/setup_buckets.py +0 -0
  204. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/speed_bench.py +0 -0
  205. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/steering.py +0 -0
  206. {attacklm-0.9.2 → attacklm-0.9.8}/scripts/train_all.py +0 -0
  207. {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/__init__.py +0 -0
  208. {attacklm-0.9.2 → attacklm-0.9.8}/src/attacklm/_project_root.py +0 -0
  209. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_collect_reference.py +0 -0
  210. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_compare_scores.py +0 -0
  211. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_domain_bench.py +0 -0
  212. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_evolve_pairs.py +0 -0
  213. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_golden_vectors.py +0 -0
  214. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_replay_mixer.py +0 -0
  215. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_score_candidates.py +0 -0
  216. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_speed_bench.py +0 -0
  217. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_steering.py +0 -0
  218. {attacklm-0.9.2 → attacklm-0.9.8}/tests/test_thinking_models.py +0 -0
  219. {attacklm-0.9.2 → attacklm-0.9.8}/uv.lock +0 -0
@@ -0,0 +1,33 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+
22
+ - name: Install dependencies
23
+ run: |
24
+ python -m pip install --upgrade pip
25
+ pip install -e ".[dev,extract]"
26
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
27
+
28
+ - name: Run tests
29
+ run: pytest tests/ -v
30
+
31
+ - name: Lint
32
+ run: ruff check src/ tests/ scripts/
33
+ continue-on-error: true
@@ -0,0 +1,86 @@
1
+ # AttackLM — Publish to PyPI
2
+ #
3
+ # Trigger: push a tag matching v* (e.g., git tag v0.9.4 && git push origin v0.9.4)
4
+ #
5
+ # Uses PyPI Trusted Publishing (OIDC). The repository is configured as a
6
+ # trusted publisher on PyPI with environment name "pypi".
7
+ # No API tokens or passwords are stored in GitHub secrets.
8
+
9
+ name: Release
10
+
11
+ on:
12
+ push:
13
+ tags: ["v*"]
14
+
15
+ jobs:
16
+ validate:
17
+ name: Validate version
18
+ runs-on: ubuntu-latest
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+
22
+ - name: Validate version
23
+ run: |
24
+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
25
+ PKG_VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' src/attacklm/__version__.py)
26
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
27
+ echo "Tag v${TAG_VERSION} != package __version__ ${PKG_VERSION}"
28
+ exit 1
29
+ fi
30
+ echo "Version $PKG_VERSION validated"
31
+
32
+ test:
33
+ name: Run tests
34
+ needs: validate
35
+ runs-on: ubuntu-latest
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+
39
+ - uses: actions/setup-python@v5
40
+ with:
41
+ python-version: "3.13"
42
+
43
+ - name: Install
44
+ run: |
45
+ pip install -e ".[dev,extract]"
46
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
47
+
48
+ - name: Test
49
+ run: pytest tests/ -v
50
+
51
+ build:
52
+ name: Build distribution
53
+ needs: test
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - uses: actions/setup-python@v5
59
+ with:
60
+ python-version: "3.13"
61
+
62
+ - name: Install build
63
+ run: pip install build
64
+
65
+ - name: Build
66
+ run: python -m build
67
+
68
+ - uses: actions/upload-artifact@v4
69
+ with:
70
+ name: dist
71
+ path: dist/
72
+
73
+ publish:
74
+ name: Publish to PyPI
75
+ needs: build
76
+ runs-on: ubuntu-latest
77
+ environment: pypi
78
+ permissions:
79
+ id-token: write
80
+ steps:
81
+ - uses: actions/download-artifact@v4
82
+ with:
83
+ name: dist
84
+ path: dist/
85
+
86
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -1,5 +1,59 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.5] — 2026-07-05 — CI/CD, test fixes, CLI tests, GitHub Releases
4
+
5
+ ### Added
6
+ - **GitHub Actions CI**: `.github/workflows/ci.yml` — runs on push/PR to main, matrix across Python 3.11/3.12/3.13, full test suite + ruff lint
7
+ - **PyPI publish workflow**: `.github/workflows/release.yml` — OIDC Trusted Publishing, validate → test → build → publish pipeline on tag push
8
+ - **CLI subcommand tests**: `tests/test_cli.py` — 33 tests covering all 8 subcommands (train, init, balance, build, infer, eval, demo, gui) plus edge cases
9
+ - **GitHub Releases**: Created releases for v0.8.3 through v0.9.4 with full CHANGELOG notes
10
+
11
+ ### Fixed
12
+ - **11 test failures resolved** (414 tests passing, up from 333):
13
+ - `test_eval_loader.py`: Fixed mock structure (transformers.utils, peft), missing adapter_path arg, CWD pollution, empty string handling
14
+ - `test_eval_retention.py`: Fixed CWD capture in test_adapter_relative_path
15
+ - `test_memory_optimization.py`: Added transformers mock before train_template import
16
+ - `_eval_loader.py`: Empty model_id_or_path now raises ValueError
17
+
18
+ ---
19
+
20
+ ## [0.9.3] — 2026-07-04 — Remove deprecated hyphenated commands, --compile + QLoRA guard
21
+
22
+ ### Removed
23
+ - **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.
24
+ - `attacklm-train` → `attacklm train`
25
+ - `attacklm-train-all` → `attacklm train --all`
26
+ - `attacklm-train-lora` → `attacklm train`
27
+ - `attacklm-hpo` → `attacklm train --hpo`
28
+ - `attacklm-extract` → `attacklm init --extract-only`
29
+ - `attacklm-buckets` → `attacklm init --buckets-only`
30
+ - `attacklm-attribute` → `attacklm init --attribute-only`
31
+ - `attacklm-clone` → `attacklm init --clone-only`
32
+ - `attacklm-init` → `attacklm init`
33
+ - `attacklm-balance` → `attacklm balance`
34
+ - `attacklm-merge` → `attacklm build --merge-only`
35
+ - `attacklm-gguf` → `attacklm build --gguf-only`
36
+ - `attacklm-build` → `attacklm build`
37
+ - `attacklm-infer` → `attacklm infer`
38
+ - `attacklm-demo` → `attacklm demo`
39
+ - `attacklm-eval` → `attacklm eval`
40
+ - `attacklm-collect-ref` → `attacklm eval --collect-ref`
41
+ - `attacklm-score` → `attacklm eval --score`
42
+ - `attacklm-compare` → `attacklm eval --compare`
43
+ - `attacklm-golden` → `attacklm eval --golden`
44
+ - `attacklm-pipeline` → `attacklm pipeline`
45
+ - **Deprecated wrapper code**: Removed `_deprecated()` helper, `_DEPRECATED_MSG` constant, and all 19 `main_*` wrapper functions from `src/attacklm/cli.py`
46
+
47
+ ### Added
48
+ - **`--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.
49
+ - **5 new tests** in `test_memory_optimization.py` verifying the compile+QLoRA guard and compatibility with GaLore, DeepSpeed, and Unsloth
50
+
51
+ ### Changed
52
+ - **All script references updated**: 30+ references across 10 script files, 5 extractors, GUI, and pipeline config updated from hyphenated to subcommand form
53
+ - **Documentation**: `CONTRIBUTING.md` and `EVALUATION.md` updated with new command forms
54
+
55
+ ---
56
+
3
57
  ## [0.9.0] — 2026-07-01 — Memory optimization: DeepSpeed, torch.compile, LOMO
4
58
 
5
59
  ### 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.8
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
@@ -94,6 +94,7 @@ Provides-Extra: dev
94
94
  Requires-Dist: ipython; extra == 'dev'
95
95
  Requires-Dist: mypy; extra == 'dev'
96
96
  Requires-Dist: pytest; extra == 'dev'
97
+ Requires-Dist: rich; extra == 'dev'
97
98
  Requires-Dist: ruff; extra == 'dev'
98
99
  Requires-Dist: scipy>=1.11; extra == 'dev'
99
100
  Provides-Extra: eval
@@ -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.
@@ -209,6 +209,7 @@ dev = [
209
209
  "mypy",
210
210
  "ipython",
211
211
  "scipy>=1.11", # needed for eval tests (Spearman correlation)
212
+ "rich", # needed by train_template.py (imported in tests)
212
213
  ]
213
214
  eval = [
214
215
  "scipy>=1.11", # for Spearman correlation in golden_vectors.py
@@ -226,45 +227,21 @@ all-rocm = ["attacklm[train-rocm,extract,convert]"]
226
227
 
227
228
  # ── Console script entry points ───────────────────────────────────────────────
228
229
  #
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.
230
+ # v0.8.0+ introduced the unified ``attacklm`` command (subcommand-based).
231
+ # The old hyphenated commands (attacklm-train, attacklm-merge, etc.) were
232
+ # deprecated in v0.8.x and removed in v0.9.3.
233
233
 
234
234
  [project.scripts]
235
- # New unified CLI
235
+ # Unified CLI (the only entry point since v0.9.3)
236
236
  attacklm = "attacklm.cli:main"
237
237
 
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
238
  # ── Hatch build configuration ─────────────────────────────────────────────────
262
239
 
263
240
  [tool.hatch.build.targets.wheel]
264
241
  packages = ["src/attacklm"]
265
242
 
266
243
  # Include scripts/ in the wheel so CLI entry points can find them.
267
- # Without this, `attacklm-train-all` etc. fail with "script not found"
244
+ # Without this, the unified ``attacklm`` command fails with "script not found"
268
245
  # because _SCRIPTS_DIR resolves to site-packages/scripts/ which is empty.
269
246
  # scripts/ is ~200KB of Python — negligible for the wheel.
270
247
  [tool.hatch.build.targets.wheel.force-include]
@@ -50,7 +50,7 @@ def resolve_model_path(model_id_or_path: str) -> str:
50
50
  Otherwise, return it as-is (assumed to be an HF Hub model ID).
51
51
  """
52
52
  if not model_id_or_path:
53
- return model_id_or_path
53
+ raise ValueError("model_id_or_path must not be empty")
54
54
  p = model_id_or_path.rstrip("/")
55
55
  is_path = (
56
56
  p.startswith(("/", "./", "../", "~/"))
@@ -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"))