drydock-cli 3.1.38__tar.gz → 3.1.39__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.
- {drydock_cli-3.1.38/drydock_cli.egg-info → drydock_cli-3.1.39}/PKG-INFO +1 -1
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/ratchet.py +29 -9
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/swarm.py +5 -5
- {drydock_cli-3.1.38 → drydock_cli-3.1.39/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/pyproject.toml +1 -1
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_swarm.py +14 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/LICENSE +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/NOTICE +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/README.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/__init__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/__main__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/advisor.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/agent.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/asr.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/bottleneck.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/budget.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/document-canvas.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-data.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-debug.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-finetune.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-metrics.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-rl.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/ml-train.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/nist-csf.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/capacity.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/cci.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/cli.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/comms/__init__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/comms/attention.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/comms/channels.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/comms/events.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/compaction.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/config.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/detect.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/doccanvas.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/eratchet.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/events.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/extract.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/gittools.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/graphrag.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/groundtruth.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/guards.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/jobs.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/mcp.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/mission.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/mission_cli.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/mission_run.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/pdfredbox.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/phases.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/poam.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/predictions.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/progress.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/providers.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/recipes.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/recovery.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/resume.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/rmf.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/skills.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/stig.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/subagents.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/suggest.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/task_state.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tool_policy.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tool_result.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tool_select.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tool_validate.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tools/__init__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/trajectory.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tui/app.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/tuning.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/verification.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock/web.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/setup.cfg +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_advisor.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_approval.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_asr.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_back_command.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_bottleneck.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_budget.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_capacity.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_cci.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_comms.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_compaction.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_config.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_context_limit_issue25.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_criteria_coverage.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_cycling_detection.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_declared_deps.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_degenerate_argument.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_detect.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_doccanvas.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_edit_thrash_and_compaction.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_effort_governor.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_eratchet.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_events.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_extract.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_gittools.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_graphrag_sqlite.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_groundtruth_predictions.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_jobs.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_knowledge_tool_available.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_main_api_key.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_mcp.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_mission.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_mission_cli.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_mission_run.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_model_registry.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_pdfredbox.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_phases.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_poam.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_progress.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_ratchet.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_ratchet_offer.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_read_index.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_recipes.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_recovery.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_recovery_config.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_recovery_integration.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_repeated_outcome.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_resume_events.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_resume_restore.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_resume_snapshot.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_rmf.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_rolling_plan.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_screenshot.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_skills.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_sqlite_events.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_stig.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_stop.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_subagent.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_subagents.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_suggest.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_task_state.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_text_only_model.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_timeline.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_todo.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_canonical.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_policy.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_result.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_select.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tool_validate.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_trajectory.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_truncated_turn.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tui.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_tuning.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_verification_gate.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_worker_subagent.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.1.38 → drydock_cli-3.1.39}/tests/test_xccdf.py +0 -0
|
@@ -87,6 +87,30 @@ class VerifyResult:
|
|
|
87
87
|
return self.total > 0 and self.passed >= self.total
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def run_shell_bounded(command: str, cwd: str | None, timeout: float) -> tuple[str, int, bool]:
|
|
91
|
+
"""Run a shell command with a timeout that actually holds: the command runs in its
|
|
92
|
+
own process group and the whole group is killed on timeout. (subprocess.run with
|
|
93
|
+
shell=True only kills /bin/sh; a hung child — e.g. pytest stuck in an infinite loop —
|
|
94
|
+
keeps the output pipes open and the call blocks far past the timeout.)
|
|
95
|
+
Returns (combined output, returncode, timed_out)."""
|
|
96
|
+
import signal
|
|
97
|
+
|
|
98
|
+
proc = subprocess.Popen(command, shell=True, cwd=cwd, stdout=subprocess.PIPE,
|
|
99
|
+
stderr=subprocess.PIPE, text=True, start_new_session=True)
|
|
100
|
+
try:
|
|
101
|
+
out, err = proc.communicate(timeout=timeout)
|
|
102
|
+
timed_out = False
|
|
103
|
+
except subprocess.TimeoutExpired:
|
|
104
|
+
try:
|
|
105
|
+
os.killpg(proc.pid, signal.SIGKILL)
|
|
106
|
+
except (ProcessLookupError, PermissionError):
|
|
107
|
+
proc.kill()
|
|
108
|
+
out, err = proc.communicate()
|
|
109
|
+
timed_out = True
|
|
110
|
+
text = (out or "") + ("\n" + err if err else "")
|
|
111
|
+
return text, (124 if timed_out else proc.returncode), timed_out
|
|
112
|
+
|
|
113
|
+
|
|
90
114
|
@dataclass
|
|
91
115
|
class Verifier:
|
|
92
116
|
"""Runs a shell command and scores it. The command is the ground truth the
|
|
@@ -99,15 +123,11 @@ class Verifier:
|
|
|
99
123
|
|
|
100
124
|
def run(self) -> VerifyResult:
|
|
101
125
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
out
|
|
107
|
-
rc = proc.returncode
|
|
108
|
-
except subprocess.TimeoutExpired as e:
|
|
109
|
-
out = (e.output or "") + "\n[verifier timed out]"
|
|
110
|
-
rc = 124
|
|
126
|
+
out, rc, timed_out = run_shell_bounded(self.command, self.cwd, self.timeout)
|
|
127
|
+
except OSError as e:
|
|
128
|
+
out, rc, timed_out = f"[verifier failed to start: {e}]", 127, False
|
|
129
|
+
if timed_out:
|
|
130
|
+
out += "\n[verifier timed out]"
|
|
111
131
|
p, t = score_output(out, self.mode, rc)
|
|
112
132
|
return VerifyResult(p, t, rc, out)
|
|
113
133
|
|
|
@@ -589,21 +589,21 @@ VerifyFn = Callable[["Candidate"], "tuple[int, int]"]
|
|
|
589
589
|
|
|
590
590
|
|
|
591
591
|
def make_shell_verifier(verify_cmd: str, fitness: str = "auto",
|
|
592
|
-
timeout: int =
|
|
592
|
+
timeout: int = 600) -> VerifyFn:
|
|
593
593
|
"""A verifier that runs `verify_cmd` in the candidate's worktree and scores the output
|
|
594
594
|
with drydock.ratchet.score_output — the same scorer the ratchet/eratchet use, so a
|
|
595
595
|
candidate is judged by a real test run, never by the builder's self-report (§18/§20)."""
|
|
596
|
-
from drydock.ratchet import score_output
|
|
596
|
+
from drydock.ratchet import run_shell_bounded, score_output
|
|
597
597
|
|
|
598
598
|
def verify(cand: Candidate) -> tuple[int, int]:
|
|
599
599
|
if not cand.worktree or not Path(cand.worktree).exists():
|
|
600
600
|
return 0, 0
|
|
601
601
|
try:
|
|
602
|
-
|
|
603
|
-
capture_output=True, text=True, timeout=timeout)
|
|
602
|
+
out, rc, _ = run_shell_bounded(verify_cmd, cand.worktree, timeout)
|
|
604
603
|
except (OSError, subprocess.SubprocessError):
|
|
605
604
|
return 0, 1
|
|
606
|
-
|
|
605
|
+
# a hung candidate (killed at the timeout) scores whatever finished before the kill
|
|
606
|
+
return score_output(out, fitness, rc)
|
|
607
607
|
|
|
608
608
|
return verify
|
|
609
609
|
|
|
@@ -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.
|
|
10
|
+
version = "3.1.39"
|
|
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"
|
|
@@ -496,3 +496,17 @@ def test_run_swarm_cancel_stops_queued_waves_and_verification(tmp_path):
|
|
|
496
496
|
assert verified == [] # verification skipped on cancel
|
|
497
497
|
assert "cancelled" in events and "judge" in events
|
|
498
498
|
assert len([c for c in res.candidates if c.commit]) == 1
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
def test_shell_verifier_timeout_kills_hung_child(tmp_path):
|
|
502
|
+
import time
|
|
503
|
+
|
|
504
|
+
wt = tmp_path / "wt"
|
|
505
|
+
wt.mkdir()
|
|
506
|
+
cand = swarm.Candidate(id="c-1", agent="a", commit="x", worktree=str(wt))
|
|
507
|
+
# the shell spawns a child that outlives the shell's own kill and holds the pipes open
|
|
508
|
+
verify = swarm.make_shell_verifier("sleep 30 & sleep 30; echo done", timeout=1)
|
|
509
|
+
t0 = time.monotonic()
|
|
510
|
+
passed, _total = verify(cand)
|
|
511
|
+
assert time.monotonic() - t0 < 10
|
|
512
|
+
assert passed == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|