drydock-cli 3.1.28__tar.gz → 3.1.29__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. {drydock_cli-3.1.28/drydock_cli.egg-info → drydock_cli-3.1.29}/PKG-INFO +1 -1
  2. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/capacity.py +61 -31
  3. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/config.py +5 -4
  4. {drydock_cli-3.1.28 → drydock_cli-3.1.29/drydock_cli.egg-info}/PKG-INFO +1 -1
  5. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/pyproject.toml +1 -1
  6. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_capacity.py +29 -9
  7. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/LICENSE +0 -0
  8. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/NOTICE +0 -0
  9. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/README.md +0 -0
  10. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/__init__.py +0 -0
  11. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/__main__.py +0 -0
  12. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/advisor.py +0 -0
  13. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/agent.py +0 -0
  14. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/bash_safety.py +0 -0
  15. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/bottleneck.py +0 -0
  16. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/budget.py +0 -0
  17. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/__init__.py +0 -0
  18. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/document-canvas.md +0 -0
  19. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/fiar-assess.md +0 -0
  20. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/fiar-cap.md +0 -0
  21. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/fiar-evidence.md +0 -0
  22. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/fiar-readiness.md +0 -0
  23. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-data.md +0 -0
  24. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-debug.md +0 -0
  25. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-finetune.md +0 -0
  26. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-metrics.md +0 -0
  27. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-rl.md +0 -0
  28. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/ml-train.md +0 -0
  29. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
  30. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/nist-csf.md +0 -0
  31. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/rmf-categorize.md +0 -0
  32. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/rmf-control.md +0 -0
  33. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/rmf-poam.md +0 -0
  34. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/rmf-review.md +0 -0
  35. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/stig-assess.md +0 -0
  36. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/builtin_skills/stig-remediate.md +0 -0
  37. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/cci.py +0 -0
  38. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/cli.py +0 -0
  39. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/comms/__init__.py +0 -0
  40. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/comms/attention.py +0 -0
  41. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/comms/channels.py +0 -0
  42. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/comms/events.py +0 -0
  43. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/compaction.py +0 -0
  44. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/detect.py +0 -0
  45. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/doccanvas.py +0 -0
  46. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/eratchet.py +0 -0
  47. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/events.py +0 -0
  48. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/extract.py +0 -0
  49. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/fiar.py +0 -0
  50. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/gittools.py +0 -0
  51. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/graphrag.py +0 -0
  52. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/groundtruth.py +0 -0
  53. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/guards.py +0 -0
  54. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/jobs.py +0 -0
  55. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/loop_detect.py +0 -0
  56. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/mcp.py +0 -0
  57. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/pdfredbox.py +0 -0
  58. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/phases.py +0 -0
  59. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/poam.py +0 -0
  60. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/predictions.py +0 -0
  61. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/progress.py +0 -0
  62. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/providers.py +0 -0
  63. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/ratchet.py +0 -0
  64. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/recipes.py +0 -0
  65. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/recovery.py +0 -0
  66. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/resume.py +0 -0
  67. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/rmf.py +0 -0
  68. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/rmf_graph.py +0 -0
  69. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/skills.py +0 -0
  70. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/stig.py +0 -0
  71. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/subagents.py +0 -0
  72. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/suggest.py +0 -0
  73. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/swarm.py +0 -0
  74. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/task_state.py +0 -0
  75. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tool_policy.py +0 -0
  76. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tool_registry.py +0 -0
  77. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tool_result.py +0 -0
  78. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tool_select.py +0 -0
  79. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tool_validate.py +0 -0
  80. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tools/__init__.py +0 -0
  81. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/trajectory.py +0 -0
  82. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tui/__init__.py +0 -0
  83. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tui/app.py +0 -0
  84. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tui/approval.py +0 -0
  85. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tui/messages.py +0 -0
  86. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tui/widgets.py +0 -0
  87. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/tuning.py +0 -0
  88. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/verification.py +0 -0
  89. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock/web.py +0 -0
  90. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock_cli.egg-info/SOURCES.txt +0 -0
  91. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock_cli.egg-info/dependency_links.txt +0 -0
  92. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock_cli.egg-info/entry_points.txt +0 -0
  93. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock_cli.egg-info/requires.txt +0 -0
  94. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/drydock_cli.egg-info/top_level.txt +0 -0
  95. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/setup.cfg +0 -0
  96. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_advisor.py +0 -0
  97. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_approval.py +0 -0
  98. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_back_command.py +0 -0
  99. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_background.py +0 -0
  100. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_binary_output.py +0 -0
  101. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_crossplatform.py +0 -0
  102. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_output_bounding.py +0 -0
  103. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_process_group.py +0 -0
  104. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_safety.py +0 -0
  105. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_sanitize.py +0 -0
  106. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_shell.py +0 -0
  107. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_stdin.py +0 -0
  108. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_stop_partial.py +0 -0
  109. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_timeout_network.py +0 -0
  110. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bash_timeout_param.py +0 -0
  111. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_bottleneck.py +0 -0
  112. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_budget.py +0 -0
  113. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_cci.py +0 -0
  114. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_cli_agents.py +0 -0
  115. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_comms.py +0 -0
  116. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_compact_command.py +0 -0
  117. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_compaction.py +0 -0
  118. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_config.py +0 -0
  119. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_config_migration.py +0 -0
  120. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_context_limit_config.py +0 -0
  121. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_context_limit_issue25.py +0 -0
  122. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_criteria_coverage.py +0 -0
  123. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_cycling_detection.py +0 -0
  124. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_declared_deps.py +0 -0
  125. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_degenerate_argument.py +0 -0
  126. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_detect.py +0 -0
  127. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_dispatch.py +0 -0
  128. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_doccanvas.py +0 -0
  129. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_e2e_connected.py +0 -0
  130. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_edit_replace_all.py +0 -0
  131. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_edit_thrash_and_compaction.py +0 -0
  132. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_effort_governor.py +0 -0
  133. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_empty_response.py +0 -0
  134. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_eratchet.py +0 -0
  135. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_events.py +0 -0
  136. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_extract.py +0 -0
  137. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_failure_loop.py +0 -0
  138. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_fiar.py +0 -0
  139. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_first_run_setup.py +0 -0
  140. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_gittools.py +0 -0
  141. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_glob_edit_edges.py +0 -0
  142. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_graphify_example.py +0 -0
  143. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_graphrag.py +0 -0
  144. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_graphrag_quoted_path.py +0 -0
  145. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_graphrag_sqlite.py +0 -0
  146. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_grep_and_read_robust.py +0 -0
  147. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_groundtruth_predictions.py +0 -0
  148. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_guards_and_tools.py +0 -0
  149. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_hallucinated_tools.py +0 -0
  150. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_jobs.py +0 -0
  151. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_knowledge_tool_available.py +0 -0
  152. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_leaked_tool_call.py +0 -0
  153. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_loop_detect.py +0 -0
  154. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_mcp.py +0 -0
  155. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_model_registry.py +0 -0
  156. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_oneshot_unreachable.py +0 -0
  157. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_overthink_interrupt.py +0 -0
  158. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_pdfredbox.py +0 -0
  159. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_phases.py +0 -0
  160. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_plan_autocontinue.py +0 -0
  161. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_poam.py +0 -0
  162. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_progress.py +0 -0
  163. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_providers_unreachable.py +0 -0
  164. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_ratchet.py +0 -0
  165. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_ratchet_offer.py +0 -0
  166. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_read_index.py +0 -0
  167. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_recipes.py +0 -0
  168. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_recovery.py +0 -0
  169. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_recovery_config.py +0 -0
  170. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_recovery_integration.py +0 -0
  171. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_repeated_outcome.py +0 -0
  172. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_repetition_interrupt.py +0 -0
  173. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_resume_events.py +0 -0
  174. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_resume_restore.py +0 -0
  175. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_resume_snapshot.py +0 -0
  176. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_rmf.py +0 -0
  177. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_rmf_graph.py +0 -0
  178. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_rmf_stig_graph.py +0 -0
  179. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_rolling_plan.py +0 -0
  180. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_runaway_repetition.py +0 -0
  181. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_screenshot.py +0 -0
  182. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_server_probe.py +0 -0
  183. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_skills.py +0 -0
  184. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_sqlite_events.py +0 -0
  185. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_stall_retry.py +0 -0
  186. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_stig.py +0 -0
  187. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_stop.py +0 -0
  188. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_streaming_newlines.py +0 -0
  189. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_subagent.py +0 -0
  190. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_subagents.py +0 -0
  191. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_suggest.py +0 -0
  192. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_swarm.py +0 -0
  193. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_system_prompt_help.py +0 -0
  194. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_task_state.py +0 -0
  195. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_timeline.py +0 -0
  196. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_todo.py +0 -0
  197. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_arg_coercion.py +0 -0
  198. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_arg_coercion_more.py +0 -0
  199. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_arg_parsing.py +0 -0
  200. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_canonical.py +0 -0
  201. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_policy.py +0 -0
  202. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_result.py +0 -0
  203. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_select.py +0 -0
  204. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tool_validate.py +0 -0
  205. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tools_undo.py +0 -0
  206. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_trajectory.py +0 -0
  207. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tui.py +0 -0
  208. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_tuning.py +0 -0
  209. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_verification_gate.py +0 -0
  210. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_viewimage.py +0 -0
  211. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_vision_input.py +0 -0
  212. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_web_tools.py +0 -0
  213. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_windows_shell.py +0 -0
  214. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_worker_subagent.py +0 -0
  215. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_write_content_coerce.py +0 -0
  216. {drydock_cli-3.1.28 → drydock_cli-3.1.29}/tests/test_xccdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.1.28
3
+ Version: 3.1.29
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -6,14 +6,15 @@ agents just queue — more tokens, no more wall-clock. So "hammer the 8-GPU vLLM
6
6
  down the -np 2 laptop" reduces to: estimate the server's concurrency C, then size the swarm
7
7
  to min(C, task-demand, budget). This module estimates C.
8
8
 
9
- Detection order (first hit wins), all swallow-error / never-raise:
10
- 1. explicit — `config['swarm_concurrency']` or $DRYDOCK_SWARM_CONCURRENCY (the operator
11
- knows their hardware; always the most reliable);
12
- 2. llama.cpp — GET /slots (its `-np` parallel slots);
13
- 3. empirical probe — fire a burst of tiny concurrent requests and infer parallelism from
14
- wall-time vs single-request latency (server-agnostic; the honest signal for vLLM, whose
15
- max_num_seqs isn't exposed over the OpenAI API);
16
- 4. fallback — a conservative default.
9
+ Detection is FULLY AUTOMATIC — the user configures nothing. Order (first hit wins), all
10
+ swallow-error / never-raise:
11
+ 1. llama.cpp — GET /slots (its `-np` parallel slots), a free exact read;
12
+ 2. empirical ramp probe — double a burst of tiny concurrent requests until the server
13
+ saturates (server-agnostic; the honest signal for vLLM, whose max_num_seqs isn't exposed
14
+ over the OpenAI API — an 8-GPU box reads big, a -np 2 laptop reads small, with no config);
15
+ 3. fallback — a conservative default.
16
+ An OPTIONAL escape hatch, checked first and needed by no one: `config['swarm_concurrency']`
17
+ or $DRYDOCK_SWARM_CONCURRENCY, for an operator who wants to pin it or skip probing entirely.
17
18
 
18
19
  Stdlib-only; the probe funcs are injectable so this is testable without a live server.
19
20
  """
@@ -71,37 +72,66 @@ def _default_requester(base_url: str, model: str) -> Callable[[], None]:
71
72
  return req
72
73
 
73
74
 
74
- def probe_concurrency(base_url: str, model: str, *, burst: int = 16,
75
- requester: Callable[[], None] | None = None) -> int:
76
- """Empirically estimate useful parallelism: one warm request costs t1; `burst` concurrent
77
- requests finish in wall time W. Total work ≈ burst·t1 done in W ⇒ parallelism ≈ burst·t1/W
78
- (≈burst if fully batched, ≈1 if serialized). Server-agnostic. Returns 1..burst."""
79
- req = requester or _default_requester(base_url, model)
75
+ _PROBE_CACHE: dict[str, int] = {}
76
+
77
+
78
+ def clear_probe_cache() -> None:
79
+ """Forget cached probe results (mainly for tests / a changed server)."""
80
+ _PROBE_CACHE.clear()
81
+
82
+
83
+ def _safe_call(req: Callable[[], None]) -> None:
80
84
  try:
81
- t0 = time.monotonic()
82
85
  req()
83
- t1 = time.monotonic() - t0
84
86
  except Exception: # noqa: BLE001
85
- return 1
86
- if t1 <= 0:
87
- return burst
87
+ pass
88
+
89
+
90
+ def _burst_wall(req: Callable[[], None], b: int) -> float:
88
91
  start = time.monotonic()
89
92
  try:
90
- with concurrent.futures.ThreadPoolExecutor(max_workers=burst) as ex:
91
- list(ex.map(lambda _: _safe_call(req), range(burst)))
93
+ with concurrent.futures.ThreadPoolExecutor(max_workers=b) as ex:
94
+ list(ex.map(lambda _: _safe_call(req), range(b)))
92
95
  except Exception: # noqa: BLE001
93
- return 1
94
- wall = time.monotonic() - start
95
- if wall <= 0:
96
- return burst
97
- return max(1, min(burst, round(burst * t1 / wall)))
98
-
99
-
100
- def _safe_call(req: Callable[[], None]) -> None:
96
+ return -1.0
97
+ return time.monotonic() - start
98
+
99
+
100
+ def probe_concurrency(base_url: str, model: str, *, max_probe: int = 64,
101
+ requester: Callable[[], None] | None = None, cache: bool = True) -> int:
102
+ """Empirically estimate useful parallelism with ZERO configuration, by RAMPING the burst
103
+ until the server saturates — so an 8-GPU vLLM box is detected as big and a -np 2 laptop
104
+ as small, without anyone declaring anything.
105
+
106
+ One warm request costs t1; a burst of B concurrent requests finishes in wall W, so
107
+ parallelism P ≈ B·t1/W (≈B if fully batched, ≈1 if serialized). Ramp B = 4, 8, 16, …:
108
+ while the server keeps the whole burst parallel (P ≈ B) it can take more, so double B;
109
+ the first time it can't (P < B) is its ceiling. Cached per server (the probe costs a
110
+ handful of max_tokens=1 requests, run once)."""
111
+ if cache and base_url in _PROBE_CACHE:
112
+ return _PROBE_CACHE[base_url]
113
+ req = requester or _default_requester(base_url, model)
101
114
  try:
115
+ t0 = time.monotonic()
102
116
  req()
103
- except Exception: # noqa: BLE001
104
- pass
117
+ t1 = time.monotonic() - t0
118
+ except Exception: # noqa: BLE001 — server unreachable
119
+ return 1
120
+ if t1 <= 0:
121
+ result = max_probe
122
+ else:
123
+ best, burst = 1, 4
124
+ while burst <= max_probe:
125
+ wall = _burst_wall(req, burst)
126
+ p = burst if wall <= 0 else max(1, min(burst, round(burst * t1 / wall)))
127
+ best = max(best, p)
128
+ if p < burst * 0.75: # couldn't keep the whole burst parallel → ceiling
129
+ break
130
+ burst *= 2
131
+ result = best
132
+ if cache:
133
+ _PROBE_CACHE[base_url] = result
134
+ return result
105
135
 
106
136
 
107
137
  def detect_concurrency(base_url: str, *, provider: str = "vllm", model: str = "",
@@ -102,10 +102,11 @@ DEFAULTS: dict[str, object] = {
102
102
  # (docs/multi_agent_swarm_prd.md). On by default; set false to keep every request single-
103
103
  # agent unless the user runs /swarm explicitly.
104
104
  "swarm_auto_escalate": True,
105
- # Swarm sizing: the harness caps agents at the inference server's real concurrency
106
- # (drydock/capacity.py) — hammer an 8-GPU vLLM box, tone down a -np 2 laptop. Set
107
- # swarm_concurrency to your server's parallel capacity to skip auto-detection (most
108
- # reliable); 0 = auto-detect (llama.cpp /slots, else an empirical burst probe).
105
+ # Swarm sizing is FULLY AUTOMATIC: the harness detects the inference server's real
106
+ # concurrency (drydock/capacity.py — llama.cpp /slots, else an empirical ramp probe) and
107
+ # caps agents at it, so an 8-GPU vLLM box gets hammered and a -np 2 laptop toned down with
108
+ # NO configuration. swarm_concurrency is an optional pin (0 = auto-detect, the default);
109
+ # nobody needs to set it.
109
110
  "swarm_concurrency": 0,
110
111
  "swarm_concurrency_default": 4,
111
112
  # URL substrings the web tools refuse: WebSearch drops matching results,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.1.28
3
+ Version: 3.1.29
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.1.28"
10
+ version = "3.1.29"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -59,20 +59,40 @@ def test_detect_order_slots_then_probe_then_default(monkeypatch):
59
59
  assert capacity.detect_concurrency("http://x/v1", model="", config={"swarm_concurrency_default": 9}) == 9
60
60
 
61
61
 
62
- def test_probe_detects_parallel_vs_serial():
63
- # parallel server: burst finishes in ~one request's time → P near burst
62
+ def test_probe_ramps_to_detect_a_big_parallel_server():
63
+ # a fully-batched server keeps every burst parallel → the ramp climbs past the old cap,
64
+ # so an 8-GPU vLLM box reads BIG with zero config
64
65
  def parallel_req():
65
- time.sleep(0.03)
66
+ time.sleep(0.02)
66
67
 
67
- p = capacity.probe_concurrency("http://x/v1", "m", burst=8, requester=parallel_req)
68
- assert p >= 4 # detected substantial parallelism
68
+ p = capacity.probe_concurrency("http://big/v1", "m", max_probe=32,
69
+ requester=parallel_req, cache=False)
70
+ assert p >= 16
69
71
 
70
- # serialized server: a lock forces one-at-a-time → P collapses toward 1
72
+
73
+ def test_probe_detects_a_small_serial_server():
74
+ # a lock forces one-at-a-time → the ramp stops immediately at ~1 (auto tone-down)
71
75
  lock = threading.Lock()
72
76
 
73
77
  def serial_req():
74
78
  with lock:
75
- time.sleep(0.03)
79
+ time.sleep(0.02)
80
+
81
+ s = capacity.probe_concurrency("http://small/v1", "m", max_probe=32,
82
+ requester=serial_req, cache=False)
83
+ assert s <= 3
84
+
85
+
86
+ def test_probe_result_is_cached_per_server():
87
+ calls = {"n": 0}
88
+
89
+ def req():
90
+ calls["n"] += 1
91
+ time.sleep(0.005)
76
92
 
77
- s = capacity.probe_concurrency("http://x/v1", "m", burst=8, requester=serial_req)
78
- assert s <= 3 # detected near-serial
93
+ capacity.clear_probe_cache()
94
+ a = capacity.probe_concurrency("http://cache/v1", "m", max_probe=8, requester=req)
95
+ n_after_first = calls["n"]
96
+ assert n_after_first > 1 # it actually probed (warm + bursts)
97
+ b = capacity.probe_concurrency("http://cache/v1", "m", max_probe=8, requester=req)
98
+ assert a == b and calls["n"] == n_after_first # cached: no new requests
File without changes
File without changes
File without changes
File without changes