dreadnode 2.0.5__tar.gz → 2.0.7__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 (424) hide show
  1. {dreadnode-2.0.5 → dreadnode-2.0.7}/PKG-INFO +1 -1
  2. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/agent.py +13 -0
  3. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/events.py +64 -3
  4. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/mcp/client.py +101 -3
  5. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/mcp/config.py +2 -2
  6. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/types.py +3 -3
  7. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/atlas.py +2 -2
  8. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/nist.py +2 -2
  9. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/owasp.py +2 -2
  10. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/owasp_agentic.py +2 -2
  11. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/saif.py +2 -2
  12. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/events.py +3 -3
  13. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/reporting/json_report.py +2 -2
  14. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/reporting/markdown.py +2 -2
  15. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/api/client.py +17 -0
  16. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/api/models.py +6 -0
  17. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/airt.py +2 -1
  18. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/capability.py +23 -15
  19. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/dataset.py +44 -8
  20. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/evaluation.py +5 -0
  21. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/main.py +6 -5
  22. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/model.py +6 -5
  23. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/shared.py +85 -20
  24. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/task.py +26 -20
  25. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/main.py +2 -2
  26. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/app.py +303 -41
  27. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/default-agent/tools/coding.py +2 -2
  28. dreadnode-2.0.7/dreadnode/app/server/prompt.py +182 -0
  29. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/app.py +333 -148
  30. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/client.py +46 -9
  31. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/commands.py +77 -7
  32. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/dreadnode.tcss +44 -13
  33. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/event_contract.py +7 -0
  34. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/model_variants.py +154 -7
  35. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/runtime_cache.py +4 -4
  36. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/__init__.py +4 -0
  37. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/auth.py +3 -3
  38. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/base.py +1 -1
  39. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/capabilities.py +78 -3
  40. dreadnode-2.0.7/dreadnode/app/tui/screens/connection_error.py +149 -0
  41. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/console.py +7 -4
  42. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/environments.py +1 -1
  43. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/evaluations.py +6 -6
  44. dreadnode-2.0.7/dreadnode/app/tui/screens/mcp.py +493 -0
  45. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/runtimes.py +8 -8
  46. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/sandboxes.py +5 -5
  47. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/sessions.py +4 -4
  48. dreadnode-2.0.7/dreadnode/app/tui/screens/theme_showcase.py +446 -0
  49. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/traces.py +1 -1
  50. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/workspaces.py +5 -4
  51. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/theme.py +9 -9
  52. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/turn_reducer.py +33 -4
  53. dreadnode-2.0.7/dreadnode/app/tui/update_check.py +197 -0
  54. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/__init__.py +2 -0
  55. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/composer.py +2 -2
  56. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/context_bar.py +67 -9
  57. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/conversation.py +49 -22
  58. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/prompt_info.py +10 -4
  59. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/status_bar.py +44 -13
  60. dreadnode-2.0.7/dreadnode/app/tui/widgets/tool.py +125 -0
  61. dreadnode-2.0.7/dreadnode/app/tui/widgets/whoami.py +74 -0
  62. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/loader.py +3 -0
  63. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/log.py +1 -1
  64. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/metric.py +3 -3
  65. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/scorer.py +2 -2
  66. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/util.py +1 -1
  67. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/events.py +2 -2
  68. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/sample.py +2 -2
  69. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/base.py +10 -2
  70. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/litellm_.py +62 -4
  71. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/events.py +4 -4
  72. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/jobs.py +2 -2
  73. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/trial.py +2 -2
  74. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/oci.py +1 -1
  75. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/storage/session_store.py +7 -7
  76. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/storage/storage.py +3 -3
  77. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/__init__.py +2 -6
  78. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/execute.py +5 -5
  79. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/fetch.py +1 -1
  80. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/exporters.py +4 -4
  81. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/span.py +3 -3
  82. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/trace_converter.py +2 -2
  83. {dreadnode-2.0.5 → dreadnode-2.0.7}/pyproject.toml +2 -2
  84. dreadnode-2.0.5/dreadnode/app/server/system-prompt.md +0 -8
  85. dreadnode-2.0.5/dreadnode/app/tui/update_check.py +0 -105
  86. dreadnode-2.0.5/dreadnode/app/tui/widgets/mcp_dialog.py +0 -68
  87. dreadnode-2.0.5/dreadnode/app/tui/widgets/tool.py +0 -60
  88. {dreadnode-2.0.5 → dreadnode-2.0.7}/.gitignore +0 -0
  89. {dreadnode-2.0.5 → dreadnode-2.0.7}/LICENSE +0 -0
  90. {dreadnode-2.0.5 → dreadnode-2.0.7}/README.md +0 -0
  91. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/__init__.py +0 -0
  92. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/__main__.py +0 -0
  93. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/__init__.py +0 -0
  94. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/exceptions.py +0 -0
  95. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/format.py +0 -0
  96. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/hooks.py +0 -0
  97. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/mcp/__init__.py +0 -0
  98. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/mcp/auth.py +0 -0
  99. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/mcp/server.py +0 -0
  100. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/reactions.py +0 -0
  101. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/skills.py +0 -0
  102. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/stopping.py +0 -0
  103. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/subagent.py +0 -0
  104. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/tools.py +0 -0
  105. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/agents/trajectory.py +0 -0
  106. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/__init__.py +0 -0
  107. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/__init__.py +0 -0
  108. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/aggregator.py +0 -0
  109. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/classifier.py +0 -0
  110. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/compliance.py +0 -0
  111. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/engine.py +0 -0
  112. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/analytics/recommendations.py +0 -0
  113. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/assessment.py +0 -0
  114. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/autodan_turbo.py +0 -0
  115. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/beast.py +0 -0
  116. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/compliance/__init__.py +0 -0
  117. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/constants.py +0 -0
  118. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/crescendo.py +0 -0
  119. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/__init__.py +0 -0
  120. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/assets/audio/adversarial_query.mp3 +0 -0
  121. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/assets/image/bomb.jpg +0 -0
  122. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/assets/image/meth.png +0 -0
  123. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/prompts/adversarial_benchmark_subset.csv +0 -0
  124. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/prompts/ai_safety.csv +0 -0
  125. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/data_exfiltration.yaml +0 -0
  126. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/goal_hijacking.yaml +0 -0
  127. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/memory_poisoning.yaml +0 -0
  128. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/privilege_escalation.yaml +0 -0
  129. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/rce.yaml +0 -0
  130. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/scope_creep.yaml +0 -0
  131. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/tool_chaining.yaml +0 -0
  132. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/tool_selection_safety.yaml +0 -0
  133. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/unbounded_agency.yaml +0 -0
  134. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/rubrics/web_chatbot_security.yaml +0 -0
  135. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/templates/crescendo/variant_1.yaml +0 -0
  136. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/templates/crescendo/variant_2.yaml +0 -0
  137. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/templates/crescendo/variant_3.yaml +0 -0
  138. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/templates/crescendo/variant_4.yaml +0 -0
  139. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/data/templates/crescendo/variant_5.yaml +0 -0
  140. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/deep_inception.py +0 -0
  141. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/drattack.py +0 -0
  142. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/goat.py +0 -0
  143. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/gptfuzzer.py +0 -0
  144. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/image.py +0 -0
  145. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/multimodal.py +0 -0
  146. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/pair.py +0 -0
  147. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/prompt.py +0 -0
  148. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/rainbow.py +0 -0
  149. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/renellm.py +0 -0
  150. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/reporting/__init__.py +0 -0
  151. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/reporting/llm_summary.py +0 -0
  152. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/airt/tap.py +0 -0
  153. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/__init__.py +0 -0
  154. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/api/__init__.py +0 -0
  155. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/__init__.py +0 -0
  156. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/optimize.py +0 -0
  157. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/runtime.py +0 -0
  158. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/train.py +0 -0
  159. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/cli/worlds.py +0 -0
  160. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/print_mode.py +0 -0
  161. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/__init__.py +0 -0
  162. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/auth.py +0 -0
  163. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/default-agent/tools/subagent.py +0 -0
  164. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/session.py +0 -0
  165. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/server/utils.py +0 -0
  166. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/__init__.py +0 -0
  167. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/connection.py +0 -0
  168. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/model_picker.py +0 -0
  169. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/screens/secrets.py +0 -0
  170. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/agent_dialog.py +0 -0
  171. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/agent_suggester.py +0 -0
  172. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/flash.py +0 -0
  173. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/header_bar.py +0 -0
  174. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/help_panel.py +0 -0
  175. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/mention_overlay.py +0 -0
  176. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/message_queue.py +0 -0
  177. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/overlay_mixin.py +0 -0
  178. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/permission_prompt.py +0 -0
  179. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/session_sidebar.py +0 -0
  180. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/skills_dialog.py +0 -0
  181. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/slash_overlay.py +0 -0
  182. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/throbber.py +0 -0
  183. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/tool_progress.py +0 -0
  184. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/tools_dialog.py +0 -0
  185. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/app/tui/widgets/welcome.py +0 -0
  186. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/__init__.py +0 -0
  187. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/capability.py +0 -0
  188. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/sync.py +0 -0
  189. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/tool_rules.py +0 -0
  190. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/capabilities/types.py +0 -0
  191. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/__init__.py +0 -0
  192. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/conditions.py +0 -0
  193. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/discovery.py +0 -0
  194. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/environment.py +0 -0
  195. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/exceptions.py +0 -0
  196. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/execution.py +0 -0
  197. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/hook.py +0 -0
  198. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/judge.py +0 -0
  199. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/load.py +0 -0
  200. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/meta/__init__.py +0 -0
  201. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/meta/config.py +0 -0
  202. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/meta/context.py +0 -0
  203. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/meta/hydrate.py +0 -0
  204. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/meta/introspect.py +0 -0
  205. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/object.py +0 -0
  206. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/serialization.py +0 -0
  207. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/stopping.py +0 -0
  208. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/task.py +0 -0
  209. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/transforms.py +0 -0
  210. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/__init__.py +0 -0
  211. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/audio.py +0 -0
  212. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/base.py +0 -0
  213. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/common.py +0 -0
  214. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/image.py +0 -0
  215. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/object_3d.py +0 -0
  216. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/table.py +0 -0
  217. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/text.py +0 -0
  218. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/core/types/video.py +0 -0
  219. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/datasets/__init__.py +0 -0
  220. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/datasets/dataset.py +0 -0
  221. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/datasets/hf.py +0 -0
  222. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/datasets/local.py +0 -0
  223. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/__init__.py +0 -0
  224. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/console.py +0 -0
  225. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/evaluation.py +0 -0
  226. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/format.py +0 -0
  227. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/evaluations/result.py +0 -0
  228. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/__init__.py +0 -0
  229. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/caching.py +0 -0
  230. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/chat.py +0 -0
  231. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/data.py +0 -0
  232. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/exceptions.py +0 -0
  233. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/__init__.py +0 -0
  234. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/http.py +0 -0
  235. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/transformers_.py +0 -0
  236. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/generator/vllm_.py +0 -0
  237. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/message.py +0 -0
  238. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/models.py +0 -0
  239. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/parsing.py +0 -0
  240. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/tokenizer/__init__.py +0 -0
  241. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/tokenizer/base.py +0 -0
  242. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/tokenizer/transformers_.py +0 -0
  243. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/generators/utils.py +0 -0
  244. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/models/__init__.py +0 -0
  245. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/models/hf.py +0 -0
  246. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/models/local.py +0 -0
  247. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/models/model.py +0 -0
  248. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/__init__.py +0 -0
  249. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/adapters/__init__.py +0 -0
  250. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/adapters/agent.py +0 -0
  251. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/api.py +0 -0
  252. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/backends/__init__.py +0 -0
  253. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/backends/base.py +0 -0
  254. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/backends/gepa.py +0 -0
  255. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/collectors.py +0 -0
  256. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/config.py +0 -0
  257. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/console.py +0 -0
  258. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/format.py +0 -0
  259. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/result.py +0 -0
  260. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/sampler.py +0 -0
  261. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/sampling.py +0 -0
  262. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/search.py +0 -0
  263. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/stopping.py +0 -0
  264. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/optimization/study.py +0 -0
  265. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/__init__.py +0 -0
  266. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/loader.py +0 -0
  267. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/manifest.py +0 -0
  268. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/package.py +1 -1
  269. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/packaging/task_validation.py +0 -0
  270. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/py.typed +0 -0
  271. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/__init__.py +0 -0
  272. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/boundary.py +0 -0
  273. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/fuzzing.py +0 -0
  274. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/graph.py +0 -0
  275. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/grid.py +0 -0
  276. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/image.py +0 -0
  277. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/mapelites.py +0 -0
  278. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/optuna.py +0 -0
  279. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/random.py +0 -0
  280. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/registry.py +0 -0
  281. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/samplers/strategy.py +0 -0
  282. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/__init__.py +0 -0
  283. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/advanced_jailbreak_detection.py +0 -0
  284. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/agent_security.py +0 -0
  285. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/agentic.py +0 -0
  286. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/agentic_workflow.py +0 -0
  287. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/classification.py +0 -0
  288. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/consistency.py +0 -0
  289. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/contains.py +0 -0
  290. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/cosine_sim.py +0 -0
  291. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/credentials.py +0 -0
  292. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/crucible.py +0 -0
  293. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/documentation_security.py +0 -0
  294. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/exfiltration_detection.py +0 -0
  295. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/format.py +0 -0
  296. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/harm.py +0 -0
  297. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/ide_security.py +0 -0
  298. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/image.py +0 -0
  299. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/json.py +0 -0
  300. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/judge.py +0 -0
  301. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/length.py +0 -0
  302. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/lexical.py +0 -0
  303. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/mcp_security.py +0 -0
  304. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/memorization.py +0 -0
  305. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/multi_agent_security.py +0 -0
  306. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/pii.py +0 -0
  307. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/prompt_leak.py +0 -0
  308. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/readability.py +0 -0
  309. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/reasoning_security.py +0 -0
  310. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/sentiment.py +0 -0
  311. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/scorers/similarity.py +0 -0
  312. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/storage/__init__.py +0 -0
  313. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/storage/providers.py +0 -0
  314. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/_ripgrep.py +0 -0
  315. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/apply_patch.py +0 -0
  316. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/editing.py +0 -0
  317. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/glob.py +0 -0
  318. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/grep.py +0 -0
  319. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/interaction.py +0 -0
  320. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/ls.py +0 -0
  321. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/memory.py +0 -0
  322. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/read.py +0 -0
  323. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/task.py +0 -0
  324. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/think.py +0 -0
  325. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/todo.py +0 -0
  326. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/web_search.py +0 -0
  327. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tools/write.py +0 -0
  328. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/__init__.py +0 -0
  329. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/constants.py +0 -0
  330. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/convert.py +0 -0
  331. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/exporter.py +0 -0
  332. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/tracing/spans.py +0 -0
  333. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/__init__.py +0 -0
  334. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/base.py +0 -0
  335. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/dpo.py +0 -0
  336. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/etl/__init__.py +0 -0
  337. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/etl/_common.py +0 -0
  338. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/etl/rl.py +0 -0
  339. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/etl/sft.py +0 -0
  340. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/etl/worlds.py +0 -0
  341. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/events.py +0 -0
  342. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/grpo.py +0 -0
  343. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/jobs.py +0 -0
  344. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ppo.py +0 -0
  345. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/prime.py +0 -0
  346. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/__init__.py +0 -0
  347. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/async_trainer.py +0 -0
  348. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/config.py +0 -0
  349. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/coordinator.py +0 -0
  350. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/distributed.py +0 -0
  351. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/dpo.py +0 -0
  352. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/experience.py +0 -0
  353. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/fsdp2_learner.py +0 -0
  354. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/inference.py +0 -0
  355. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/learner.py +0 -0
  356. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/multi_turn.py +0 -0
  357. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/ppo.py +0 -0
  358. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/reward_model.py +0 -0
  359. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/rollout_env.py +0 -0
  360. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/rollout_worker.py +0 -0
  361. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/sft.py +0 -0
  362. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/ray/trainer.py +0 -0
  363. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/recipes.py +0 -0
  364. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/__init__.py +0 -0
  365. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/aggregator.py +0 -0
  366. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/functions.py +0 -0
  367. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/scorer_bridge.py +0 -0
  368. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/shaping.py +0 -0
  369. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rewards/types.py +0 -0
  370. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rollouts/__init__.py +0 -0
  371. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rollouts/adapters.py +0 -0
  372. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rollouts/orchestrator.py +0 -0
  373. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rollouts/types.py +0 -0
  374. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/rollouts/worlds.py +0 -0
  375. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/serving/__init__.py +0 -0
  376. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/serving/vllm_client.py +0 -0
  377. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/sft.py +0 -0
  378. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/__init__.py +0 -0
  379. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/config.py +0 -0
  380. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/data.py +0 -0
  381. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/renderer.py +0 -0
  382. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/rl.py +0 -0
  383. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker/trainer.py +0 -0
  384. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/tinker_sft.py +0 -0
  385. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/training/utils.py +0 -0
  386. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/__init__.py +0 -0
  387. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/advanced_jailbreak.py +0 -0
  388. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/adversarial_suffix.py +0 -0
  389. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/agent_skill.py +0 -0
  390. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/agentic_workflow.py +0 -0
  391. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/audio.py +0 -0
  392. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/browser_agent_attacks.py +0 -0
  393. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/cipher.py +0 -0
  394. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/constitutional.py +0 -0
  395. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/document.py +0 -0
  396. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/documentation_poison.py +0 -0
  397. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/encoding.py +0 -0
  398. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/exfiltration.py +0 -0
  399. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/flip_attack.py +0 -0
  400. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/guardrail_bypass.py +0 -0
  401. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/ide_injection.py +0 -0
  402. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/image.py +0 -0
  403. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/injection.py +0 -0
  404. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/json_tools.py +0 -0
  405. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/language.py +0 -0
  406. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/logic_bomb.py +0 -0
  407. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/mcp_attacks.py +0 -0
  408. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/multi_agent_attacks.py +0 -0
  409. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/persuasion.py +0 -0
  410. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/perturbation.py +0 -0
  411. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/pii_extraction.py +0 -0
  412. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/pythonic_tools.py +0 -0
  413. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/rag_poisoning.py +0 -0
  414. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/reasoning_attacks.py +0 -0
  415. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/refine.py +0 -0
  416. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/response_steering.py +0 -0
  417. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/stylistic.py +0 -0
  418. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/substitution.py +0 -0
  419. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/swap.py +0 -0
  420. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/system_prompt_extraction.py +0 -0
  421. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/text.py +0 -0
  422. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/video.py +0 -0
  423. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/transforms/xml_tools.py +0 -0
  424. {dreadnode-2.0.5 → dreadnode-2.0.7}/dreadnode/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dreadnode
3
- Version: 2.0.5
3
+ Version: 2.0.7
4
4
  Summary: Dreadnode SDK
5
5
  Project-URL: Homepage, https://dreadnode.io
6
6
  Project-URL: Documentation, https://docs.dreadnode.io
@@ -27,6 +27,7 @@ from dreadnode.agents.events import (
27
27
  AgentStep,
28
28
  AgentStopReason,
29
29
  CompactionEvent,
30
+ GenerationContent,
30
31
  GenerationEnd,
31
32
  GenerationError,
32
33
  GenerationStart,
@@ -668,6 +669,18 @@ class Agent(Executor[AgentEvent, Trajectory]):
668
669
  msg.metadata.setdefault("model", self.model_name)
669
670
  messages.extend(step_chat.generated)
670
671
 
672
+ # Emit content for TUI rendering BEFORE tools/stop-checks
673
+ # so text is visible immediately (ENG-5879)
674
+ last_msg = step_chat.generated[-1] if step_chat.generated else None
675
+ if last_msg and last_msg.content:
676
+ yield GenerationContent(
677
+ agent_id=self.agent_id,
678
+ agent_name=self.name,
679
+ step=step_count,
680
+ content=str(last_msg.content),
681
+ extra=step_chat.extra,
682
+ )
683
+
671
684
  # Check stop conditions INSIDE span
672
685
  if any(cond(self.trajectory.steps) for cond in self.stop_conditions):
673
686
  logger.info("A stop condition was met. Ending run.")
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  import typing as t
3
- from datetime import datetime, timezone
3
+ from datetime import UTC, datetime
4
4
  from uuid import UUID, uuid4
5
5
 
6
6
  import typing_extensions as te
@@ -80,7 +80,7 @@ class AgentEvent(BaseModel):
80
80
 
81
81
  model_config = ConfigDict(arbitrary_types_allowed=True)
82
82
 
83
- timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), kw_only=True)
83
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC), kw_only=True)
84
84
  agent_id: UUID = Field(default_factory=uuid4)
85
85
  agent_name: str | None = None
86
86
  status: AgentStatus | None = Field(default=None)
@@ -775,9 +775,37 @@ class GenerationEnd(AgentStep):
775
775
  stop_reason: str | None = None
776
776
 
777
777
  def _get_data(self) -> dict[str, t.Any]:
778
+ content = None
779
+ tool_calls = []
780
+
781
+ if self.messages:
782
+ last_msg = self.messages[-1]
783
+ content = str(last_msg.content)[:4000] if last_msg.content else None
784
+
785
+ for tc in last_msg.tool_calls or []:
786
+ try:
787
+ args = json.loads(tc.function.arguments)
788
+ except (json.JSONDecodeError, TypeError):
789
+ args = tc.function.arguments
790
+ tool_calls.append(
791
+ {
792
+ "id": tc.id,
793
+ "name": tc.name,
794
+ "arguments": args,
795
+ }
796
+ )
797
+
778
798
  return {
779
- "model": self.generator.model if self.generator else None,
780
799
  "step": self.step,
800
+ "content": content,
801
+ "tool_calls": tool_calls,
802
+ "usage": {
803
+ "input_tokens": self.usage.input_tokens,
804
+ "output_tokens": self.usage.output_tokens,
805
+ "total_tokens": self.usage.total_tokens,
806
+ },
807
+ "stop_reason": self.stop_reason,
808
+ "model": self.generator.model if self.generator else None,
781
809
  }
782
810
 
783
811
  def emit(self, span: "TaskSpan") -> None:
@@ -814,6 +842,38 @@ class GenerationEnd(AgentStep):
814
842
  super().emit(span)
815
843
 
816
844
 
845
+ class GenerationContent(AgentEvent):
846
+ """Event: The LLM produced content, emitted before tool execution.
847
+
848
+ This is a TUI rendering signal — it carries the generation text so it can
849
+ be displayed immediately, before tools run. GenerationEnd/GenerationStep
850
+ still fire after tools for trajectory, hooks, and telemetry.
851
+
852
+ Attributes:
853
+ step: The step number.
854
+ content: The generated text content.
855
+ tool_calls: Tool calls requested by the generation.
856
+ extra: Additional metadata (reasoning_content, etc.).
857
+ """
858
+
859
+ step: int = 0
860
+ content: str | None = None
861
+ tool_calls: list[dict[str, t.Any]] = Field(default_factory=list)
862
+ extra: dict[str, t.Any] = Field(default_factory=dict)
863
+
864
+ def _get_data(self) -> dict[str, t.Any]:
865
+ return {
866
+ "step": self.step,
867
+ "content": self.content,
868
+ "tool_calls": self.tool_calls,
869
+ "extra": self.extra,
870
+ }
871
+
872
+ def emit(self, span: "TaskSpan") -> None:
873
+ # No telemetry — GenerationEnd handles that
874
+ pass
875
+
876
+
817
877
  class GenerationError(AgentEvent):
818
878
  """Event: An error occurred during a generation step
819
879
 
@@ -938,6 +998,7 @@ EVENT_TYPES: dict[str, type[AgentEvent]] = {
938
998
  "GenerationStart": GenerationStart,
939
999
  "GenerationEnd": GenerationEnd,
940
1000
  "GenerationStep": GenerationStep,
1001
+ "GenerationContent": GenerationContent,
941
1002
  "GenerationError": GenerationError,
942
1003
  "ReactStep": ReactStep,
943
1004
  "UserInputRequired": UserInputRequired,
@@ -6,6 +6,7 @@ fallback for streamable-http connections.
6
6
  """
7
7
 
8
8
  import asyncio
9
+ import contextlib
9
10
  import typing as t
10
11
  import warnings
11
12
  from contextlib import AsyncExitStack
@@ -36,6 +37,56 @@ if t.TYPE_CHECKING:
36
37
  from dreadnode.generators.message import Content
37
38
 
38
39
 
40
+ class _StderrCapture:
41
+ """Async reader that buffers the last N lines from a pipe fd.
42
+
43
+ Used to capture MCP subprocess stderr without blocking and without
44
+ letting it spill into the parent terminal. On connection failure the
45
+ buffered lines are included in the error message so users can see
46
+ why the server process crashed.
47
+ """
48
+
49
+ _MAX_LINES = 50
50
+
51
+ def __init__(self, read_fd: int, exit_stack: AsyncExitStack) -> None:
52
+ import os
53
+ import threading
54
+
55
+ self._lines: list[str] = []
56
+ self._read_file = os.fdopen(read_fd, "r")
57
+
58
+ def _reader() -> None:
59
+ try:
60
+ for raw in self._read_file:
61
+ line = raw.rstrip("\n")
62
+ if line:
63
+ logger.debug("MCP stderr: {}", line)
64
+ self._lines.append(line)
65
+ if len(self._lines) > self._MAX_LINES:
66
+ self._lines.pop(0)
67
+ except (OSError, ValueError):
68
+ pass # fd closed
69
+
70
+ self._thread = threading.Thread(target=_reader, daemon=True)
71
+ self._thread.start()
72
+ exit_stack.callback(self._close)
73
+
74
+ def _close(self) -> None:
75
+ with contextlib.suppress(OSError):
76
+ self._read_file.close()
77
+ self._thread.join(timeout=1)
78
+
79
+ @property
80
+ def output(self) -> str:
81
+ """Return captured stderr as a single string."""
82
+ return "\n".join(self._lines)
83
+
84
+ @property
85
+ def last_lines(self) -> list[str]:
86
+ """Return the buffered lines."""
87
+ return list(self._lines)
88
+
89
+
39
90
  def _convert_mcp_result_to_message_parts(result: "CallToolResult") -> list[t.Any]:
40
91
  from mcp.types import TextResourceContents
41
92
 
@@ -121,6 +172,7 @@ class MCPClient:
121
172
  self._session = None
122
173
  self._oauth_config = oauth
123
174
  self._init_timeout = init_timeout
175
+ self._stderr_capture: _StderrCapture | None = None
124
176
 
125
177
  @classmethod
126
178
  def from_config(cls, config: ServerConfig) -> "MCPClient":
@@ -185,11 +237,35 @@ class MCPClient:
185
237
  ]
186
238
 
187
239
  async def _connect_via_stdio(self, connection: StdioConnection) -> "ClientSession":
240
+ import os
241
+
188
242
  from mcp import ClientSession, StdioServerParameters
189
243
  from mcp.client.stdio import stdio_client
190
244
 
245
+ # Capture subprocess stderr via an OS pipe instead of letting it spill
246
+ # into the parent terminal. An async reader task buffers the last N
247
+ # lines so we can surface them in error messages on connection failure.
248
+ read_fd, write_fd = os.pipe()
249
+ write_file = os.fdopen(write_fd, "w")
250
+
251
+ stderr_capture = _StderrCapture(read_fd, self._exit_stack)
252
+ self._stderr_capture = stderr_capture
253
+
191
254
  server_params = StdioServerParameters(**connection)
192
- read, write = await self._exit_stack.enter_async_context(stdio_client(server_params))
255
+ try:
256
+ read, write = await self._exit_stack.enter_async_context(
257
+ stdio_client(server_params, errlog=write_file)
258
+ )
259
+ except BaseException:
260
+ # If the subprocess fails to start (e.g. command not found),
261
+ # close the write end so the reader thread sees EOF and exits.
262
+ write_file.close()
263
+ raise
264
+ # Close parent's write end now that the subprocess has inherited
265
+ # the fd. This ensures the pipe reader sees EOF when the subprocess
266
+ # exits, preventing hangs.
267
+ write_file.close()
268
+
193
269
  return await self._exit_stack.enter_async_context(ClientSession(read, write))
194
270
 
195
271
  async def _probe_supports_streamable_http(
@@ -323,9 +399,27 @@ class MCPClient:
323
399
  self._status = MCPStatus.CONNECTED
324
400
  self._error = None
325
401
 
326
- except Exception as e:
402
+ except BaseException as e:
327
403
  await self._shutdown()
328
- error_msg = str(e)
404
+
405
+ # anyio TaskGroups wrap failures in BaseExceptionGroup — unwrap
406
+ # to surface the actual root cause (e.g. ConnectionRefusedError)
407
+ # instead of the opaque "unhandled errors in a TaskGroup" message.
408
+ cause = e
409
+ if isinstance(e, BaseExceptionGroup):
410
+ leaf = e.exceptions[0] if e.exceptions else e
411
+ while isinstance(leaf, BaseExceptionGroup) and leaf.exceptions:
412
+ leaf = leaf.exceptions[0]
413
+ cause = leaf
414
+
415
+ error_msg = str(cause)
416
+
417
+ # Append captured subprocess stderr for stdio failures —
418
+ # this surfaces the actual crash output (tracebacks, missing
419
+ # modules, config errors) instead of just "Connection closed".
420
+ if self._stderr_capture and self._stderr_capture.last_lines:
421
+ stderr_tail = "\n".join(self._stderr_capture.last_lines[-10:])
422
+ error_msg = f"{error_msg}\n\nServer stderr:\n{stderr_tail}"
329
423
 
330
424
  # Check for auth-related failures
331
425
  error_lower = error_msg.lower()
@@ -335,6 +429,10 @@ class MCPClient:
335
429
  self._status = MCPStatus.FAILED
336
430
 
337
431
  self._error = error_msg
432
+
433
+ # Re-raise the unwrapped cause so callers can catch with `except Exception`
434
+ if cause is not e and isinstance(cause, Exception):
435
+ raise cause from e
338
436
  raise
339
437
 
340
438
  async def disconnect(self) -> None:
@@ -8,7 +8,7 @@ StdioServerConfig → stdio, HttpServerConfig → streamable-http.
8
8
 
9
9
  import typing as t
10
10
  from dataclasses import dataclass, field
11
- from enum import Enum
11
+ from enum import StrEnum
12
12
  from pathlib import Path
13
13
 
14
14
  import typing_extensions as te
@@ -25,7 +25,7 @@ DEFAULT_SSE_READ_TIMEOUT = 60 * 5
25
25
  Transport = t.Literal["stdio", "streamable-http"]
26
26
 
27
27
 
28
- class MCPStatus(str, Enum):
28
+ class MCPStatus(StrEnum):
29
29
  """Status of an MCP server connection."""
30
30
 
31
31
  CONNECTED = "connected"
@@ -8,14 +8,14 @@ from __future__ import annotations
8
8
 
9
9
  import typing as t
10
10
  from dataclasses import asdict, dataclass, field
11
- from enum import Enum
11
+ from enum import StrEnum
12
12
 
13
13
  # ---------------------------------------------------------------------------
14
14
  # Enums
15
15
  # ---------------------------------------------------------------------------
16
16
 
17
17
 
18
- class Severity(str, Enum):
18
+ class Severity(StrEnum):
19
19
  """Risk severity levels for attack findings."""
20
20
 
21
21
  CRITICAL = "critical"
@@ -42,7 +42,7 @@ _SEVERITY_RANK: dict[Severity, int] = {
42
42
  }
43
43
 
44
44
 
45
- class GoalCategory(str, Enum):
45
+ class GoalCategory(StrEnum):
46
46
  """Impact categories for severity classification.
47
47
 
48
48
  Each category represents a class of attack objective. The category
@@ -6,10 +6,10 @@ AI/ML-specific attack techniques organized by tactics similar to MITRE ATT&CK.
6
6
  Reference: https://atlas.mitre.org/
7
7
  """
8
8
 
9
- from enum import Enum
9
+ from enum import StrEnum
10
10
 
11
11
 
12
- class ATLASTechnique(str, Enum):
12
+ class ATLASTechnique(StrEnum):
13
13
  """
14
14
  MITRE ATLAS AI/ML Attack Technique IDs.
15
15
 
@@ -6,10 +6,10 @@ Risk management functions and categories for AI systems.
6
6
  Reference: https://www.nist.gov/itl/ai-risk-management-framework
7
7
  """
8
8
 
9
- from enum import Enum
9
+ from enum import StrEnum
10
10
 
11
11
 
12
- class NISTAIRMFFunction(str, Enum):
12
+ class NISTAIRMFFunction(StrEnum):
13
13
  """
14
14
  NIST AI Risk Management Framework Core Functions.
15
15
 
@@ -4,10 +4,10 @@ OWASP Top 10 for LLM Applications 2025.
4
4
  Reference: https://genai.owasp.org/llm-top-10/
5
5
  """
6
6
 
7
- from enum import Enum
7
+ from enum import StrEnum
8
8
 
9
9
 
10
- class OWASPCategory(str, Enum):
10
+ class OWASPCategory(StrEnum):
11
11
  """
12
12
  OWASP Top 10 for LLM Applications 2025.
13
13
 
@@ -19,10 +19,10 @@ Example:
19
19
  ```
20
20
  """
21
21
 
22
- from enum import Enum
22
+ from enum import StrEnum
23
23
 
24
24
 
25
- class OWASPAgenticCategory(str, Enum):
25
+ class OWASPAgenticCategory(StrEnum):
26
26
  """
27
27
  OWASP Top 10 for Agentic Applications (2026).
28
28
 
@@ -6,10 +6,10 @@ Security categories for AI/ML systems aligned with Google's security principles.
6
6
  Reference: https://blog.google/technology/safety-security/google-secure-ai-framework/
7
7
  """
8
8
 
9
- from enum import Enum
9
+ from enum import StrEnum
10
10
 
11
11
 
12
- class SAIFCategory(str, Enum):
12
+ class SAIFCategory(StrEnum):
13
13
  """
14
14
  Google SAIF (Secure AI Framework) Security Categories.
15
15
 
@@ -23,7 +23,7 @@ Hierarchy::
23
23
  from __future__ import annotations
24
24
 
25
25
  import typing as t
26
- from datetime import datetime, timezone
26
+ from datetime import UTC, datetime
27
27
 
28
28
  from pydantic import BaseModel, ConfigDict, Field
29
29
 
@@ -77,7 +77,7 @@ class AssessmentEvent(BaseModel):
77
77
 
78
78
  model_config = ConfigDict(arbitrary_types_allowed=True)
79
79
 
80
- timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), kw_only=True)
80
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC), kw_only=True)
81
81
  assessment_id: str = ""
82
82
  assessment_name: str = ""
83
83
 
@@ -498,7 +498,7 @@ class TransformApplied(BaseModel):
498
498
 
499
499
  model_config = ConfigDict(arbitrary_types_allowed=True)
500
500
 
501
- timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), kw_only=True)
501
+ timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC), kw_only=True)
502
502
  transform_name: str = ""
503
503
  transform_index: int = 0
504
504
  chain_length: int = 0
@@ -7,7 +7,7 @@ Suitable for CI/CD integration (e.g. ``jq '.summary.severity_breakdown.critical'
7
7
  from __future__ import annotations
8
8
 
9
9
  import typing as t
10
- from datetime import datetime, timezone
10
+ from datetime import UTC, datetime
11
11
 
12
12
  from dreadnode.airt.analytics.types import (
13
13
  ASRBreakdown,
@@ -87,7 +87,7 @@ def generate_json_report(analytics: CampaignAnalytics) -> dict[str, t.Any]:
87
87
 
88
88
  return {
89
89
  "meta": {
90
- "generated_at": datetime.now(tz=timezone.utc).isoformat(),
90
+ "generated_at": datetime.now(tz=UTC).isoformat(),
91
91
  "report_version": "1.0",
92
92
  },
93
93
  "summary": {
@@ -6,7 +6,7 @@ document suitable for human review or conversion to HTML/PDF.
6
6
 
7
7
  from __future__ import annotations
8
8
 
9
- from datetime import datetime, timezone
9
+ from datetime import UTC, datetime
10
10
 
11
11
  from dreadnode.airt.analytics.types import (
12
12
  ASRBreakdown,
@@ -41,7 +41,7 @@ def _truncate(text: str, max_len: int = 500) -> str:
41
41
 
42
42
 
43
43
  def _render_header(analytics: CampaignAnalytics) -> str:
44
- now = datetime.now(tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
44
+ now = datetime.now(tz=UTC).strftime("%Y-%m-%d %H:%M:%S UTC")
45
45
  stats = analytics.execution_stats
46
46
  return (
47
47
  "# AIRT Campaign Report\n\n"
@@ -355,6 +355,18 @@ class ApiClient:
355
355
  """DELETE /api/org/{org}/datasets/{name}/{version} - Delete dataset artifact."""
356
356
  self.request("DELETE", f"/org/{org}/datasets/{name}/{version}")
357
357
 
358
+ def download_dataset(
359
+ self, org: str, name: str, version: str, *, format: str = "raw", split: str | None = None
360
+ ) -> dict:
361
+ """POST /api/org/{org}/datasets/{name}/{version}/download - Get presigned download URL."""
362
+ body: dict[str, t.Any] = {"format": format}
363
+ if split:
364
+ body["split"] = split
365
+ response = self.request(
366
+ "POST", f"/org/{org}/datasets/{name}/{version}/download", json_data=body
367
+ )
368
+ return response.json()
369
+
358
370
  def list_models(self, org: str) -> list[Package]:
359
371
  """GET /api/org/{org}/models - List models."""
360
372
  response = self.request("GET", f"/org/{org}/models")
@@ -1217,6 +1229,11 @@ class ApiClient:
1217
1229
  response = self.request("GET", f"/org/{org}/capabilities/{name}/versions")
1218
1230
  return t.cast("dict[str, t.Any]", response.json())
1219
1231
 
1232
+ def list_public_capability_versions(self, owner: str, name: str) -> dict[str, t.Any]:
1233
+ """GET /capabilities/{owner}/{name}/versions - List public capability versions."""
1234
+ response = self.request("GET", f"/capabilities/{owner}/{name}/versions")
1235
+ return t.cast("dict[str, t.Any]", response.json())
1236
+
1220
1237
  def get_capability(self, org: str, name: str, version: str) -> dict[str, t.Any]:
1221
1238
  """GET /org/{org}/capabilities/{name}/{version} - Get artifact detail."""
1222
1239
  response = self.request("GET", f"/org/{org}/capabilities/{name}/{version}")
@@ -857,6 +857,11 @@ class ComponentStatusInfo(BaseModel):
857
857
  status: t.Literal["ok", "error", "degraded"]
858
858
  error: str | None = None
859
859
  detail: str | None = None
860
+ # MCP-specific optional fields
861
+ qualified_name: str | None = None
862
+ capability: str | None = None
863
+ transport: str | None = None
864
+ tool_count: int | None = None
860
865
 
861
866
 
862
867
  class CapabilityInfo(BaseModel):
@@ -874,6 +879,7 @@ class CapabilityInfo(BaseModel):
874
879
  origin: dict[str, t.Any] | None = None
875
880
  enabled: bool = True
876
881
  binding_id: str | None = None
882
+ update_available: str | None = None
877
883
  components: list[ComponentStatusInfo] = []
878
884
  # Existing fields retained for backward compat
879
885
  entry_agent: str | None = None
@@ -13,6 +13,7 @@ from dreadnode.app.cli.shared import (
13
13
  _render_airt_assessment_list,
14
14
  _render_airt_reports,
15
15
  configured_dreadnode,
16
+ console,
16
17
  require_workspace_context,
17
18
  )
18
19
 
@@ -161,7 +162,7 @@ def delete(
161
162
  dn = configured_dreadnode(platform)
162
163
  org, workspace, client = require_workspace_context(dn, label="AIRT")
163
164
  client.delete_airt_assessment(org, workspace, assessment_id)
164
- print(f"Deleted AIRT assessment {assessment_id}")
165
+ console.print(f"Deleted AIRT assessment [dim]{assessment_id}[/dim]")
165
166
 
166
167
 
167
168
  # ---------------------------------------------------------------------------
@@ -11,6 +11,7 @@ from dreadnode.app.cli.shared import (
11
11
  _render_capability_list,
12
12
  _sync_progress,
13
13
  configured_dreadnode,
14
+ console,
14
15
  require_registry_context,
15
16
  )
16
17
 
@@ -45,13 +46,15 @@ def push(
45
46
  except (ValueError, RuntimeError) as exc:
46
47
  raise SystemExit(str(exc)) from exc
47
48
 
49
+ name = result.name
50
+ version = result.version
48
51
  if result.status == "built":
49
- print(f"Built {result.name}@{result.version}")
52
+ console.print(f"Built [cyan]{name}[/cyan]@[dim]{version}[/dim]")
50
53
  elif result.status == "up_to_date":
51
- print(f"{result.name}@{result.version} already up to date")
54
+ console.print(f"[cyan]{name}[/cyan]@[dim]{version}[/dim] already up to date")
52
55
  else:
53
56
  digest = result.digest or "unknown"
54
- print(f"Pushed {result.name}@{result.version} ({digest})")
57
+ console.print(f"Pushed [cyan]{name}[/cyan]@[dim]{version}[/dim] [dim]({digest})[/dim]")
55
58
 
56
59
 
57
60
  # ---------------------------------------------------------------------------
@@ -110,7 +113,7 @@ def delete(
110
113
  org, client = require_registry_context(dn)
111
114
  name, version = _parse_versioned_ref(ref, field_name="ref")
112
115
  client.delete_capability(org, name, version)
113
- print(f"Deleted {org}/{name}@{version}")
116
+ console.print(f"Deleted [dim]{org}/[/dim][cyan]{name}[/cyan]@[dim]{version}[/dim]")
114
117
 
115
118
 
116
119
  # ---------------------------------------------------------------------------
@@ -168,10 +171,11 @@ def sync(
168
171
  )
169
172
 
170
173
  total = len(result.uploaded) + len(result.skipped) + len(result.failed)
171
- print(
174
+ console.print(
172
175
  f"\nSynced {total} capability(ies): "
173
- f"uploaded={len(result.uploaded)} skipped={len(result.skipped)} "
174
- f"failed={len(result.failed)}"
176
+ f"[green]uploaded={len(result.uploaded)}[/green] "
177
+ f"[dim]skipped={len(result.skipped)}[/dim] "
178
+ f"[red]failed={len(result.failed)}[/red]"
175
179
  )
176
180
  if not result.ok:
177
181
  raise SystemExit(1)
@@ -195,7 +199,7 @@ def validate(
195
199
 
196
200
  resolved = Path(path).resolve()
197
201
  if not resolved.exists():
198
- print(f"Path not found: {resolved}")
202
+ console.print(f"[red]Path not found:[/red] {resolved}")
199
203
  raise SystemExit(1)
200
204
 
201
205
  # If path contains capability.yaml directly, validate just that one
@@ -207,7 +211,9 @@ def validate(
207
211
  d for d in resolved.iterdir() if d.is_dir() and (d / "capability.yaml").exists()
208
212
  )
209
213
  if not dirs:
210
- print(f"No capability.yaml found in {resolved} or its subdirectories")
214
+ console.print(
215
+ f"[red]No capability.yaml found in {resolved} or its subdirectories[/red]"
216
+ )
211
217
  raise SystemExit(1)
212
218
 
213
219
  errors: list[tuple[str, str]] = []
@@ -233,20 +239,22 @@ def validate(
233
239
 
234
240
  if health_errors:
235
241
  warnings.append(cap.name)
236
- print(f" WARN {cap.name}@{cap.version} ({summary})")
242
+ console.print(f" [yellow]WARN[/yellow] {cap.name}@{cap.version} ({summary})")
237
243
  for h in health_errors:
238
- print(f" {h.get('component', '?')}: {h.get('error', 'unknown')}")
244
+ console.print(f" {h.get('component', '?')}: {h.get('error', 'unknown')}")
239
245
  else:
240
- print(f" OK {cap.name}@{cap.version} ({summary})")
246
+ console.print(f" [green]OK[/green] {cap.name}@{cap.version} ({summary})")
241
247
  except (ValueError, FileNotFoundError) as exc:
242
248
  errors.append((dir_name, str(exc)))
243
- print(f" FAIL {dir_name}: {exc}")
249
+ console.print(f" [red]FAIL[/red] {dir_name}: {exc}")
244
250
 
245
251
  total = len(dirs)
246
252
  failed = len(errors)
247
253
  warned = len(warnings)
248
- print(
249
- f"\nValidated {total} capability(ies): {total - failed - warned} ok, {warned} warn, {failed} failed"
254
+ ok_count = total - failed - warned
255
+ console.print(
256
+ f"\nValidated {total} capability(ies): "
257
+ f"[green]{ok_count} ok[/green], [yellow]{warned} warn[/yellow], [red]{failed} failed[/red]"
250
258
  )
251
259
  if errors or (strict and warnings):
252
260
  raise SystemExit(1)