drydock-cli 3.1.34__tar.gz → 3.1.35__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.34/drydock_cli.egg-info → drydock_cli-3.1.35}/PKG-INFO +1 -1
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/mission_cli.py +17 -2
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/mission_run.py +30 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/pyproject.toml +1 -1
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_mission_cli.py +19 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_mission_run.py +24 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/LICENSE +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/NOTICE +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/README.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/__init__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/__main__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/advisor.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/agent.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/asr.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/bottleneck.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/budget.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/document-canvas.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/fiar-assess.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/fiar-cap.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/fiar-evidence.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/fiar-readiness.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-data.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-debug.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-finetune.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-metrics.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-rl.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/ml-train.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/nist-ai-rmf.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/nist-csf.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/capacity.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/cci.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/cli.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/comms/__init__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/comms/attention.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/comms/channels.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/comms/events.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/compaction.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/config.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/detect.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/doccanvas.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/eratchet.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/events.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/extract.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/fiar.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/gittools.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/graphrag.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/groundtruth.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/guards.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/jobs.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/mcp.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/mission.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/pdfredbox.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/phases.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/poam.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/predictions.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/progress.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/providers.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/ratchet.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/recipes.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/recovery.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/resume.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/rmf.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/skills.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/stig.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/subagents.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/suggest.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/swarm.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/task_state.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tool_policy.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tool_result.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tool_select.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tool_validate.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tools/__init__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/trajectory.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tui/app.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/tuning.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/verification.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock/web.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/setup.cfg +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_advisor.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_approval.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_asr.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_back_command.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_crossplatform.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_stop_partial.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bash_timeout_param.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_bottleneck.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_budget.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_capacity.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_cci.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_comms.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_compaction.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_config.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_context_limit_issue25.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_criteria_coverage.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_cycling_detection.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_declared_deps.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_degenerate_argument.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_detect.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_doccanvas.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_edit_replace_all.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_edit_thrash_and_compaction.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_effort_governor.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_eratchet.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_events.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_extract.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_fiar.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_gittools.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_glob_edit_edges.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_graphrag_quoted_path.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_graphrag_sqlite.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_grep_and_read_robust.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_groundtruth_predictions.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_jobs.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_knowledge_tool_available.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_main_api_key.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_mcp.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_mission.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_model_registry.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_overthink_interrupt.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_pdfredbox.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_phases.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_poam.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_progress.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_ratchet.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_ratchet_offer.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_read_index.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_recipes.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_recovery.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_recovery_config.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_recovery_integration.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_repeated_outcome.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_repetition_interrupt.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_resume_events.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_resume_restore.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_resume_snapshot.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_rmf.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_rolling_plan.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_screenshot.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_skills.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_sqlite_events.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_stall_retry.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_stig.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_stop.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_subagent.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_subagents.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_suggest.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_swarm.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_task_state.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_timeline.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_todo.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_arg_coercion.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_arg_coercion_more.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_canonical.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_policy.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_result.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_select.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tool_validate.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_trajectory.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tui.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_tuning.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_verification_gate.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_windows_shell.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_worker_subagent.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_write_content_coerce.py +0 -0
- {drydock_cli-3.1.34 → drydock_cli-3.1.35}/tests/test_xccdf.py +0 -0
|
@@ -215,6 +215,13 @@ def _parse_budget(argv: list[str]) -> tuple[dict, dict, str, list[str], dict, li
|
|
|
215
215
|
elif a == "--max-escalations" and nxt: # ladder climbs before BLOCKED/AWAITING_HUMAN (§23)
|
|
216
216
|
eval_cfg["max_escalations"] = int(nxt) if nxt.isdigit() else 3
|
|
217
217
|
i += 2
|
|
218
|
+
elif a == "--swarm": # solve each task with a SWARM, not one agent
|
|
219
|
+
eval_cfg["swarm"] = True
|
|
220
|
+
i += 1
|
|
221
|
+
elif a == "--swarm-agents" and nxt: # agents per task's swarm (implies --swarm)
|
|
222
|
+
eval_cfg["swarm"] = True
|
|
223
|
+
eval_cfg["swarm_agents"] = int(nxt) if nxt.isdigit() else 4
|
|
224
|
+
i += 2
|
|
218
225
|
elif a == "--model" and nxt: # mission carries its own model/endpoint (§33)
|
|
219
226
|
eval_cfg["model"] = nxt
|
|
220
227
|
i += 2
|
|
@@ -248,7 +255,7 @@ def run_cli(argv: list, config: dict | None = None) -> int:
|
|
|
248
255
|
if not objective:
|
|
249
256
|
print('usage: drydock mission create "<objective>" [--target ">=70"] '
|
|
250
257
|
'[--verify CMD] [--protect GLOB]... [--samples N] [--noise-band F] '
|
|
251
|
-
'[--time-budget 48h] [--max-experiments N]')
|
|
258
|
+
'[--swarm | --swarm-agents N] [--time-budget 48h] [--max-experiments N]')
|
|
252
259
|
return 1
|
|
253
260
|
mconf = {"verify_cmd": verify, "model": config.get("model", ""),
|
|
254
261
|
"base_url": config.get("base_url", ""), "provider": config.get("provider", "vllm"),
|
|
@@ -337,6 +344,14 @@ def _run(store: M.MissionStore, mid: str, cwd: str, config: dict, *, resume: boo
|
|
|
337
344
|
if mconf.get(key):
|
|
338
345
|
base_config[key] = mconf[key]
|
|
339
346
|
print(f" model: {base_config.get('model')} @ {base_config.get('base_url')}")
|
|
347
|
+
# Worker: one bounded agent per task (default), OR a swarm per task (--swarm) — parallel
|
|
348
|
+
# diversified agents + blackboard cross-pollination, KEEP/REVERT on the swarm winner (§Phase-4).
|
|
349
|
+
if mconf.get("swarm"):
|
|
350
|
+
n = int(mconf.get("swarm_agents") or 4)
|
|
351
|
+
worker = R.make_swarm_worker(agents=n, share=True, waves=2)
|
|
352
|
+
print(f" worker: SWARM ({n} agents/task, shared blackboard)")
|
|
353
|
+
else:
|
|
354
|
+
worker = R.default_worker
|
|
340
355
|
if evaluator is not None:
|
|
341
356
|
b = R.establish_baseline(store, mid, cwd, evaluator)
|
|
342
357
|
if b is not None:
|
|
@@ -352,7 +367,7 @@ def _run(store: M.MissionStore, mid: str, cwd: str, config: dict, *, resume: boo
|
|
|
352
367
|
print(f" ⚑ {kind}: {d}")
|
|
353
368
|
write_views(store, mid, cwd)
|
|
354
369
|
|
|
355
|
-
R.run_mission(store, mid, cwd=cwd, repo=cwd, evaluator=evaluator,
|
|
370
|
+
R.run_mission(store, mid, cwd=cwd, repo=cwd, worker=worker, evaluator=evaluator,
|
|
356
371
|
planner=decomposing_planner(m["objective"], verify, cwd), base_config=base_config,
|
|
357
372
|
stagnation_limit=int(mconf.get("stagnation_limit") or 5),
|
|
358
373
|
max_escalations=int(mconf.get("max_escalations") or 3),
|
|
@@ -191,6 +191,36 @@ def default_worker(task: dict, mission: dict, cwd: str, base_config: dict) -> Wo
|
|
|
191
191
|
out_tokens=int(getattr(state, "total_output_tokens", 0) or 0))
|
|
192
192
|
|
|
193
193
|
|
|
194
|
+
def make_swarm_worker(agents: "int | str" = 4, share: bool = True, waves: int = 2,
|
|
195
|
+
max_turns: int = 30, runner=None) -> WorkerFn:
|
|
196
|
+
"""A WorkerFn that solves each mission task with a SWARM (parallel diversified agents +
|
|
197
|
+
blackboard cross-pollination) instead of a single agent — the long-horizon mission dispatches
|
|
198
|
+
a swarm per task (ASR Phase-4: durable depth × parallel breadth). The winning candidate's
|
|
199
|
+
commit is checked out into the mission's working tree (no commit of its own — the mission's
|
|
200
|
+
KEEP/REVERT handles that), so the mission evaluator scores the swarm's best result."""
|
|
201
|
+
def worker(task: dict, mission: dict, cwd: str, base_config: dict) -> WorkerResult:
|
|
202
|
+
from drydock import swarm as S
|
|
203
|
+
objective = task.get("objective", "")
|
|
204
|
+
verify_cmd = (mission.get("config") or {}).get("verify_cmd") or None
|
|
205
|
+
kw: dict = dict(agents=agents, base_config=base_config or {}, base_ref="HEAD",
|
|
206
|
+
verify_cmd=verify_cmd, share=share, waves=waves, max_turns=max_turns)
|
|
207
|
+
if runner is not None:
|
|
208
|
+
kw["runner"] = runner
|
|
209
|
+
try:
|
|
210
|
+
res = S.run_swarm(cwd, objective, **kw)
|
|
211
|
+
except Exception as e: # noqa: BLE001 — a swarm crash is contained like any worker (§32)
|
|
212
|
+
return WorkerResult(ok=False, error=f"swarm failed: {type(e).__name__}: {e}")
|
|
213
|
+
w = res.winner
|
|
214
|
+
if w is not None and w.commit:
|
|
215
|
+
# bring the winner's tree into the mission's working dir; the mission's checkpoint
|
|
216
|
+
# (KEEP) or restore (REVERT) commits/discards it, so no extra commit here.
|
|
217
|
+
_git(["checkout", w.commit, "--", "."], cwd)
|
|
218
|
+
return WorkerResult(ok=True, summary=(f"swarm winner {w.agent} "
|
|
219
|
+
f"{w.tests_passed}/{w.tests_total}: {(w.summary or '')[:200]}"))
|
|
220
|
+
return WorkerResult(ok=True, summary="swarm produced no winning candidate")
|
|
221
|
+
return worker
|
|
222
|
+
|
|
223
|
+
|
|
194
224
|
def _median(xs: list[float]) -> float:
|
|
195
225
|
s = sorted(xs)
|
|
196
226
|
n = len(s)
|
|
@@ -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.35"
|
|
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"
|
|
@@ -107,6 +107,25 @@ def test_cli_create_persists_integrity_and_noise_flags(tmp_path):
|
|
|
107
107
|
assert cfg["eval_samples"] == 3 and cfg["noise_band"] == 1.5
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
def test_cli_swarm_flag_persists_and_selects_swarm_worker(tmp_path, monkeypatch):
|
|
111
|
+
rc = C.run_cli(["create", "fix", "it", "--swarm-agents", "5", "--verify", "true"],
|
|
112
|
+
{"cwd": str(tmp_path)})
|
|
113
|
+
assert rc == 0
|
|
114
|
+
mid = M.list_missions(tmp_path)[0]
|
|
115
|
+
cfg = M.open_store(tmp_path, mid).get_mission(mid)["config"]
|
|
116
|
+
assert cfg["swarm"] is True and cfg["swarm_agents"] == 5 # persisted to mission config
|
|
117
|
+
|
|
118
|
+
# _run must pick make_swarm_worker (not default_worker) when swarm is set
|
|
119
|
+
captured = {}
|
|
120
|
+
monkeypatch.setattr(R, "make_swarm_worker",
|
|
121
|
+
lambda **kw: captured.update(kw) or (lambda *a: R.WorkerResult(ok=True)))
|
|
122
|
+
monkeypatch.setattr(R, "run_mission", lambda *a, **kw: captured.update(worker_set=True) or
|
|
123
|
+
R.RunSummary(mission_id=mid, status="COMPLETED", cycles=0, final_metric=100.0))
|
|
124
|
+
monkeypatch.setattr(R, "establish_baseline", lambda *a, **k: None)
|
|
125
|
+
C.run_cli(["run", mid], {"cwd": str(tmp_path)})
|
|
126
|
+
assert captured.get("agents") == 5 and captured.get("share") is True # swarm worker built with N=5
|
|
127
|
+
|
|
128
|
+
|
|
110
129
|
def test_cli_knowledge_view(tmp_path, capsys):
|
|
111
130
|
C.run_cli(["create", "obj here"], {"cwd": str(tmp_path)})
|
|
112
131
|
mid = M.list_missions(tmp_path)[0]
|
|
@@ -275,6 +275,30 @@ def test_negative_knowledge_is_discriminating_by_target(tmp_path):
|
|
|
275
275
|
assert hit and "test_roman" in hit[0]["statement"] and "roman.py" in hit[0]["statement"]
|
|
276
276
|
|
|
277
277
|
|
|
278
|
+
def test_swarm_worker_applies_winner_to_mission_tree(tmp_path):
|
|
279
|
+
"""ASR Phase-4: a mission task solved by a SWARM; the winning candidate lands in the
|
|
280
|
+
mission's working tree so KEEP/REVERT scores it. Injected runner — no model."""
|
|
281
|
+
from drydock import swarm as S
|
|
282
|
+
repo = tmp_path / "proj"
|
|
283
|
+
(repo / "tests").mkdir(parents=True)
|
|
284
|
+
(repo / "toolkit.py").write_text("def add(a, b):\n raise NotImplementedError\n")
|
|
285
|
+
(repo / "tests" / "test_it.py").write_text("from toolkit import add\ndef test_add(): assert add(2,3)==5\n")
|
|
286
|
+
(repo / "conftest.py").write_text("")
|
|
287
|
+
for c in (["git", "init", "-q"], ["git", "config", "user.email", "t@t"],
|
|
288
|
+
["git", "config", "user.name", "t"], ["git", "add", "-A"], ["git", "commit", "-qm", "base"]):
|
|
289
|
+
subprocess.run(c, cwd=repo, check=True)
|
|
290
|
+
|
|
291
|
+
def runner(objective, cwd, base_config, system_prompt, allow, mt, mtc):
|
|
292
|
+
(Path(cwd) / "toolkit.py").write_text("def add(a, b):\n return a + b\n") # the fix
|
|
293
|
+
return S.RunResult(summary="implemented add", in_tokens=1, out_tokens=1, turns=1)
|
|
294
|
+
|
|
295
|
+
worker = R.make_swarm_worker(agents=2, share=False, runner=runner)
|
|
296
|
+
wr = worker({"objective": "make add() work"},
|
|
297
|
+
{"config": {"verify_cmd": "python -m pytest -q"}}, str(repo), {})
|
|
298
|
+
assert wr.ok and "winner" in wr.summary # swarm found + reported a winner
|
|
299
|
+
assert "return a + b" in (repo / "toolkit.py").read_text() # winner applied to the mission tree
|
|
300
|
+
|
|
301
|
+
|
|
278
302
|
def test_run_mission_stops_on_success(tmp_path):
|
|
279
303
|
repo = _repo(tmp_path)
|
|
280
304
|
s = M.MissionStore(tmp_path / "s.db")
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|