bpsai-pair 2.28.1__tar.gz → 2.28.2__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.
- {bpsai_pair-2.28.1/bpsai_pair.egg-info → bpsai_pair-2.28.2}/PKG-INFO +7 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/README.md +5 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/cli_startup.py +37 -13
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/arch_lint_commands.py +13 -3
- bpsai_pair-2.28.2/bpsai_pair/commands/arch_wiring.py +161 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/budget.py +1 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage.py +14 -28
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_branch.py +6 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_branch_multi.py +13 -6
- bpsai_pair-2.28.2/bpsai_pair/commands/engage_executor.py +116 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_pause_resume.py +17 -37
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_pr.py +126 -20
- bpsai_pair-2.28.2/bpsai_pair/commands/engage_resume_integrity.py +140 -0
- bpsai_pair-2.28.2/bpsai_pair/commands/gitignore.py +138 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/init_commands.py +4 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/init_repo.py +1 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/preflight.py +4 -6
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/support.py +43 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/upgrade.py +12 -5
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/upgrade_helpers.py +2 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/upgrade_prompt.py +16 -5
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_defaults.py +9 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_handlers.py +0 -5
- bpsai_pair-2.28.2/bpsai_pair/core/hook_metrics.py +105 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hooks.py +14 -7
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/preset_definitions.py +4 -4
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/reachability_ast.py +8 -2
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/reachability_lint.py +16 -4
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/subprocess_lint.py +7 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/settings.json +3 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/scripts/bootstrap-remote.sh +1 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/engage/constants.py +27 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/calibration.py +17 -36
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/schema.py +4 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/stats.py +33 -20
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/harness/claude_code.py +18 -3
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/binding.py +62 -2
- bpsai_pair-2.28.2/bpsai_pair/licensing/cache_signing.py +127 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/core.py +13 -6
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/online.py +62 -15
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/startup.py +5 -0
- bpsai_pair-2.28.2/bpsai_pair/licensing/unchecked.py +39 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/validation_cache.py +16 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/backlog_parser.py +20 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/backlog_validation.py +62 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/backlog_yaml.py +4 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/branch_review.py +2 -2
- bpsai_pair-2.28.2/bpsai_pair/orchestration/checkin_diagnostic.py +143 -0
- bpsai_pair-2.28.2/bpsai_pair/orchestration/engage_push.py +159 -0
- bpsai_pair-2.28.2/bpsai_pair/orchestration/engage_push_scan.py +85 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/engage_review.py +2 -2
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/headless.py +43 -28
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/headless_runner.py +7 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/headless_runner_helpers.py +56 -2
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/heartbeat.py +47 -15
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/pr_review.py +7 -7
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/review_common.py +26 -8
- bpsai_pair-2.28.2/bpsai_pair/orchestration/review_severity.py +93 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_commit.py +3 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_executor_baseline.py +38 -4
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_executor_outcome.py +26 -9
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_models.py +9 -0
- bpsai_pair-2.28.2/bpsai_pair/orchestration/wiring_review.py +85 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_commands.py +3 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_update_enforcement.py +62 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/release/commands.py +88 -10
- bpsai_pair-2.28.2/bpsai_pair/release/phase89_gate.py +189 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/release/release_checks.py +6 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/statusline_install.py +32 -3
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/_serialization.py +2 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/collector.py +15 -12
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/schema.py +21 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/tokens.py +8 -3
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/budget_api.py +3 -3
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/chat_api.py +1 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/budget.html +18 -6
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2/bpsai_pair.egg-info}/PKG-INFO +7 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair.egg-info/SOURCES.txt +9 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair.egg-info/requires.txt +1 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/pyproject.toml +2 -1
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_statusline_install.py +73 -2
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_template_signal_hooks.py +18 -0
- bpsai_pair-2.28.1/bpsai_pair/commands/arch_wiring.py +0 -71
- bpsai_pair-2.28.1/bpsai_pair/commands/engage_executor.py +0 -61
- bpsai_pair-2.28.1/bpsai_pair/commands/gitignore.py +0 -57
- bpsai_pair-2.28.1/bpsai_pair/core/hook_metrics.py +0 -319
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/LICENSE +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/MANIFEST.in +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/__main__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/benchmarks/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/benchmarks/reports.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/benchmarks/runner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/benchmarks/validation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/cli.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/cli_registration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/arch.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/audit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/benchmark.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/budget_programmatic.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/cache.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/claude_md_merge.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/compaction_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/config_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/containment_checkpoint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/containment_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/containment_session.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/context_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/core.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/doctor.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/enforce.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/enforce_containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/enforce_state_edit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/enforce_task_edit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_base.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_cross_module.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_guards.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_navigator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_plan_id.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_pr_multi.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_preflight.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_qa_multi.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_result.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_resume.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_security.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_sweep.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_target_repo.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/engage_worktree.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/feedback.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/feedback_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/fleet_check.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/init_feature.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/license.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/license_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/mcp.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/metrics/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/metrics/analysis_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/metrics/burndown_command.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/metrics/helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/metrics/summary_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/orchestrate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/orchestrate_evaluate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_crud.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_diagnostics.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_hierarchy_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_migrate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/pm_sprint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/preset.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/prime_learn.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/provider_command.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/provider_presets.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/qc_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/query.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/review.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/security.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/session.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/session_check.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/session_status.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/setup_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/state_validation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/status_handoff.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/subscription.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/sweep_command.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/sweep_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/system.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_aggregate_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_display.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_export.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_log_failure.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/telemetry_log_lifecycle.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/timer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/upgrade_containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/upgrade_execute.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/validation_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/version_consistency.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/wizard.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_impact.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_index_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_init_project.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_setup_permissions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/commands/workspace_validate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/compaction.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/compaction_events.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/compaction_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/compaction_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/compaction_recovery.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/context/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/context/cache.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/context/freshness.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/context/loader.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/arch_headroom.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/budget_heuristic.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/bypass_log.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/cache_paths.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ci_gate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_architecture.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_loader.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_templates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_validation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/config_validator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/constants.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/deprecation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/encoding.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/encoding_lint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enforcement.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enforcement_analyzer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enforcement_checker.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enforcement_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enforcement_utils.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/engage_task_start.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enrichment_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/enrichment_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/file_role_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/gate_executor.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/gate_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_budget.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_budget_programmatic.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_pm.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_routing.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_trello.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/hook_types.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops_ci.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops_context.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops_feature.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops_git.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/ops_project.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/orchestration_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/preconditions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/preferences.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/preset_config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/presets.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/programmatic_credit_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/programmatic_credit_validator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/routing.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/task_acceptance.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/task_ready.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/task_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/core/utils.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/containment_section.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/README.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/cookiecutter.json +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.agentpackignore +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agent-memory/bellona/MEMORY.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agent-memory/driver/MEMORY.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agent-memory/laverna/MEMORY.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agent-memory/navigator/MEMORY.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agent-memory/nayru/MEMORY.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/bellona.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/divona.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/driver.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/laverna.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/navigator.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/nayru.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/agents/vaivora.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/draft-backlog.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/make-it-so.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/pc-audit-sibling.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/pc-plan.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/run-qc.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/start-task.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/commands/update-skills.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/rules/architecture.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/architecting-modules/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/auditing-sibling-projects/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/creating-skills/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/designing-and-implementing/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/finishing-branches/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/implementing-with-tdd/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/managing-task-lifecycle/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/managing-task-lifecycle/reference/all-cli-commands.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/managing-task-lifecycle/reference/bps-trello-conventions.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/managing-task-lifecycle/scripts/check_completion.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/managing-task-lifecycle/scripts/validate_task_status.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/planning-with-pm/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/planning-with-trello/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/reviewing-code/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.claude/skills/running-qc/SKILL.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.editorconfig +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.gitignore +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/.gitignore +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/capabilities.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/context/project.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/context/state.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/context/workflow.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/feedback/.gitkeep +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/history/.gitkeep +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/plans/.gitkeep +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/security/allowlist.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/security/sandbox.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/security/secret-allowlist.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/tasks/.gitkeep +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.paircoder/telemetry/.gitkeep +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/CLAUDE.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/scripts/on_permission_denied.sh +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/hooks/on_permission_denied.sh +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/workflows/bps-full.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/data/workflows/simple.yaml +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/engage/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/engage/a2a_push.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/engage/containment_audit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/anomaly.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/benchmark_seed.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/calibration_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/calibration_refresh.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/classifier.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/fleet.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/overhead.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/query_builder.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/scoring.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/service.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/stack_detect.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/state_query.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/feedback/workspace_query.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/client.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/merge_strategy.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/pr.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/pr_manager.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/pr_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/github/pr_workflow.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/harness/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/harness/dispatch_adapter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/harness/env_overrides.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/harness/provider_loader.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/init_bundled_cli.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/integrations/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/integrations/time_tracking.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/integrations/toggl.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/gap_mapper.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/gate_mapper.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/license_gate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/mapper_base.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/pipeline.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/recommender.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/recommender_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/recommender_weights.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/scorer_mapper.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/session_mapper.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/signal_model.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/task_hook.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intelligence/telemetry_mapper.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/approval.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/approval_gate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/capability_gate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/classifier.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/dispatch_guard.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/frustration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/response_injection.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/intent_gate/schema.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/json_envelope.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/activation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/keys.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/machine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/paths.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/public_key.pem +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/schema.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/security.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/snapshot_bridge.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/licensing/tier_change.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/server.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/channels.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/context.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/metrics.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/orchestration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/planning.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/support.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/tasks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/mcp/tools/trello.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/memory_retention.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/accuracy.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/budget.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/burndown.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/collector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/estimation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/hours_comparison.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/reports.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/token_estimator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/token_feedback.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/metrics/velocity.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/migrate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/agent_names.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/agent_selector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/autonomous.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/autonomous_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/autonomous_steps.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/backlog_header.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/backlog_materializer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/circuit_breaker_recovery.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/commit_verification.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/completion_guard.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/dependency_resolver.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/engage_run_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/findings_loop.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/handoff.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/handoff_consumer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/handoff_retention.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/impact_dedup.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/invoker.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/manager.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/model_routing.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/nayru_deterministic.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/nayru_pregates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/orchestrator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/orchestrator_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/orchestrator_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/output_verifier.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/output_verifier_git_args.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/output_verifier_signals.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/package_builder.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/plan_graph.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/plan_graph_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/planner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/pre_dispatch_check.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/pre_task_sha.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/reconciliation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/review_checks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/review_dispatch.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/review_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/review_output.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/reviewer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/security.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/security_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/security_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/serializer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_executor.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_executor_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_lifecycle_args.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_lifecycle_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_review_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_signals.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_skipped_handler.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/sprint_summary.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/subagent_context.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/target_repo_resolution.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/targeted_tests.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/task_md_runtime.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/task_review.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/task_review_command.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/task_timeout.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/orchestration/workflow_guide.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/auto_assign.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/cli_update_cache.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/completion_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/intelligence_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/intent_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/intent_detection.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_complete_command.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_crud_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_enums.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_estimation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_intelligence.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_legacy_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_legacy_sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_model.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_pm_enrich.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_pm_hierarchy.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_pm_sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_query_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_status_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_task_push.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_trello_sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/plan_workspace.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/review_intent.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/scope_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/standup.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/standup_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/status_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_archive_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_check_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_consistency.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_done.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_model.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/task_update_completion.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/planning/token_estimator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/actions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/backlog_mixin.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/backlog_rollup.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/backlog_types.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/compat.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/completion_cascade.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/completion_eval.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/engine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/errors.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/hierarchy.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/lifecycle.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/migration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/null_provider.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/orchestration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/presets.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/project_hooks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/provider.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/registry.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/sprint_lifecycle.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/types.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/workflow.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm/workflow_validation.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/adapter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/backlog_engage.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/backlog_tree.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/discovery.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/enrichment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/label_resolver.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/provider.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/relationship_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/relationships.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/pm_trello/sync_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/prime_learn/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/prime_learn/a2a_push.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/prime_learn/storage.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/prime_learn/synthesis.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/executor.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/fill_validator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/gate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/loader.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/reporter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/results.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/step_handlers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/telemetry_store.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/templates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/qc/timeout_handler.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/a2a_adapter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/driver_activity.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/qc_trends.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/quality_metrics.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/remote_query_client.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/review_findings.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/schema_validator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/session_outcomes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/sprint_status.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/query_skills/task_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/release/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/release/template.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/release/validate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/Dockerfile.containment +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/allowlist.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/allowlist_data.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/allowlist_matching.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint_base.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint_containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint_format.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/checkpoint_rollback.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/containment_check.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/containment_config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/data_classes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/dep_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/dep_scanner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/dependencies.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/image_manager.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/interactive_runner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/network.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/network_control.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/review.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/review_agent.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/review_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/review_patterns.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/review_scanner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/runner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/sandbox.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/secrets.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/secrets_format.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/secrets_patterns.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/secrets_scanner.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/security/secrets_types.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/session.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/session_finalize.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/session_handoff.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/classifier.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/classifier_engine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/classifier_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/classifier_report.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/cli_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/display_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/export_base.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/exporter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gap_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gap_engine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gap_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gap_persistence.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gaps_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gate_definitions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gate_evaluator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/gates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/generator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/generator_engine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/generator_io.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/generator_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/installer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/intent_matcher.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/pattern_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/scorer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/scorer_engine.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/scorer_format.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/scorer_models.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/scorer_telemetry.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_export_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_gap_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_install_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_recommend_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_score_cmds.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_suggester.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/skill_validate_cmd.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/subagent_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/subagent_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/subagent_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/subagent_patterns.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/suggestion.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/skills/validator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sprint/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sprint/commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/statusline.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/statusline_state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/support/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/support/auth.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/support/client.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/support/system_info.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/a2a_integration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/classifier.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/diff_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/providers/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/providers/_patterns.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/providers/generic.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/sweep/providers/python_provider.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/tasks/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/tasks/archiver.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/tasks/changelog.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/tasks/lifecycle.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/aggregate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/aggregates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/audit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/auto_compaction.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/batch_submit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/cache_health.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/collector_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/collectors.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/compaction.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/failure_pattern_detector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/hook_collector.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/hooks_schema.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/migrate.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/privacy.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/queries.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/query_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/recovery.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/recovery_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/session_outcomes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/session_store.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/signal_checks.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/signal_emitter.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/signal_thresholds.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/snapshot.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/sqlite_migration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/sqlite_schema.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/sqlite_telemetry_store.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/store.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/task_state_index.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/telemetry/task_state_log.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/activity.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/auth.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/board_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/board_setup.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/checklist_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/client.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/connection.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/custom_fields.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/field_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/fields.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/label_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/list_resolver.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/progress.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync_cards.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync_checklists.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync_fields.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/sync_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_card_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_completion.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_display.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_done_pipeline.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_handoff.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_helpers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_lifecycle.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_operations.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_pm_routing.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/task_sync.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/templates.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook_auth.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook_commands.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook_config.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook_handlers.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/trello/webhook_server.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/utils/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/utils/sysproc.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/api_routes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/app.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/config_builder.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/config_parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/containment_step.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/creator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/demo.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/editor_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/enforcement_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/github_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/guided_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/license_installer.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/loader.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/mcp_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/page_routes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/pro_page_routes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/project_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/prompts/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/prompts/guided_setup.md +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/review_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/routes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/session.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/state.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/static/chat.js +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/static/style.css +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/static/wizard.js +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/steps.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/base.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/chat.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/enforcement.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/github.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/index.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/mcp.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/partials/license_install.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/partials/locked_overlay.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/partials/upgrade_modal.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/project.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/review.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/success.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/trello.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/welcome.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/templates/workflow.html +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/trello_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/update_api.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/wizard/workflow_routes.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/__init__.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/agent_spawning.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/agent_teams.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/audit.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/contracts.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/discovery.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/execution_plan.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/git_ops.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/gitignore.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/impact.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/init_project.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/membership.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/orchestrator.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/parser.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/permissions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/project_md.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/schema.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/sibling_conventions.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/stack_detect.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/task_push.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair/workspace/workspace_index.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair.egg-info/dependency_links.txt +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair.egg-info/entry_points.txt +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/bpsai_pair.egg-info/top_level.txt +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/setup.cfg +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_cli_registration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_compaction_containment.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_compaction_coverage.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_compaction_decomp.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_compaction_events.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_feature_gating.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_init_bundled_cli.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_main_entrypoint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_memory_retention.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_session_finalize.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_stale_task_lint.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_statusline.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_statusline_heartbeat.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_statusline_integration.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_statusline_mtime.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_t42_1_qc_rename.py +0 -0
- {bpsai_pair-2.28.1 → bpsai_pair-2.28.2}/tests/test_website_signal_hooks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: bpsai-pair
|
|
3
|
-
Version: 2.28.
|
|
3
|
+
Version: 2.28.2
|
|
4
4
|
Summary: AI-augmented pair programming framework with 220+ CLI commands for planning, orchestration, Trello/GitHub integration, and autonomous workflows
|
|
5
5
|
Author-email: BPS AI Software <support@paircoder.ai>
|
|
6
6
|
License-Expression: LicenseRef-Proprietary
|
|
@@ -29,6 +29,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
29
29
|
Requires-Dist: tiktoken>=0.5.0
|
|
30
30
|
Requires-Dist: pydantic>=2.0
|
|
31
31
|
Requires-Dist: cryptography>=41.0
|
|
32
|
+
Requires-Dist: keyring>=25.0
|
|
32
33
|
Requires-Dist: fastapi>=0.109.0
|
|
33
34
|
Requires-Dist: jinja2>=3.1.0
|
|
34
35
|
Requires-Dist: uvicorn>=0.27.0
|
|
@@ -182,6 +183,11 @@ Check your license: `bpsai-pair license status`
|
|
|
182
183
|
|
|
183
184
|
> Full release history and detailed notes: [paircoder.ai](https://paircoder.ai).
|
|
184
185
|
|
|
186
|
+
**v2.28.2 — Latest-model support + engage durability (patch)**
|
|
187
|
+
- Claude Sonnet 5 and Fable 5 selectable in the wizard/config; current-gen context limits corrected to 1M for accurate budgets.
|
|
188
|
+
- Engage pushes its branch at kickoff and after every task — crash durability + mid-run visibility.
|
|
189
|
+
- Fixes: engage on Windows, `support create`/`list` scope, `upgrade` artifact hygiene, fail-closed `review pr`, engage auto-PR `--head`.
|
|
190
|
+
|
|
185
191
|
**v2.28.0 — Cross-repo engage, provider-agnostic PM, plan-time arch headroom (minor)**
|
|
186
192
|
|
|
187
193
|
- **Cross-repo engage.** A sprint can target sibling repos — engage commits, branches, opens PRs, and verifies in the right repo per task; backlogs declare a `Target repo:` (backlog-level or per-task), and QA/security/review fan out across every touched repo.
|
|
@@ -108,6 +108,11 @@ Check your license: `bpsai-pair license status`
|
|
|
108
108
|
|
|
109
109
|
> Full release history and detailed notes: [paircoder.ai](https://paircoder.ai).
|
|
110
110
|
|
|
111
|
+
**v2.28.2 — Latest-model support + engage durability (patch)**
|
|
112
|
+
- Claude Sonnet 5 and Fable 5 selectable in the wizard/config; current-gen context limits corrected to 1M for accurate budgets.
|
|
113
|
+
- Engage pushes its branch at kickoff and after every task — crash durability + mid-run visibility.
|
|
114
|
+
- Fixes: engage on Windows, `support create`/`list` scope, `upgrade` artifact hygiene, fail-closed `review pr`, engage auto-PR `--head`.
|
|
115
|
+
|
|
111
116
|
**v2.28.0 — Cross-repo engage, provider-agnostic PM, plan-time arch headroom (minor)**
|
|
112
117
|
|
|
113
118
|
- **Cross-repo engage.** A sprint can target sibling repos — engage commits, branches, opens PRs, and verifies in the right repo per task; backlogs declare a `Target repo:` (backlog-level or per-task), and QA/security/review fan out across every touched repo.
|
|
@@ -25,26 +25,54 @@ def version_callback(value: bool):
|
|
|
25
25
|
raise typer.Exit()
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
def _check_expired_license():
|
|
29
|
+
"""Hard-fail if an expired subscription/trial license is installed (LA3.3).
|
|
30
|
+
|
|
31
|
+
Perpetual licenses are unaffected (is_expired returns False for them).
|
|
32
|
+
"""
|
|
33
|
+
import sys
|
|
34
|
+
|
|
35
|
+
from .licensing.core import is_expired
|
|
36
|
+
from .licensing.unchecked import load_license_unchecked
|
|
37
|
+
|
|
38
|
+
unchecked = load_license_unchecked()
|
|
39
|
+
if unchecked is None or not is_expired(unchecked):
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
ltype = unchecked.payload.type
|
|
43
|
+
if ltype not in ("subscription", "trial"):
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
exp = unchecked.payload.expires_at
|
|
47
|
+
date_str = exp.strftime("%Y-%m-%d") if exp else "unknown"
|
|
48
|
+
err_console = Console(file=sys.stderr)
|
|
49
|
+
err_console.print(
|
|
50
|
+
f"[bold red]Your {ltype} license expired on {date_str}.[/bold red]\n"
|
|
51
|
+
f"Renew at [cyan]https://paircoder.ai/pricing[/cyan] "
|
|
52
|
+
f"or run: [cyan]bpsai-pair license renew[/cyan]"
|
|
53
|
+
)
|
|
54
|
+
sys.exit(2)
|
|
55
|
+
|
|
56
|
+
|
|
28
57
|
def _run_license_validation():
|
|
29
58
|
"""Run license validation on startup (silent for non-critical signals).
|
|
30
59
|
|
|
31
|
-
License validation runs in background. Errors are NOT printed here to avoid
|
|
32
|
-
polluting JSON output and quiet mode commands. Users can check license status
|
|
33
|
-
with `bpsai-pair license status`.
|
|
34
|
-
|
|
35
60
|
Hard-fail conditions (exit non-zero with stderr message):
|
|
61
|
+
- Expired subscription/trial license — LA3.3
|
|
36
62
|
- Revoked license — always
|
|
37
63
|
- machine_activated=False AND past grace period — T45.22 (#157)
|
|
38
64
|
|
|
39
|
-
|
|
40
|
-
`bpsai-pair license status` exposes the full state.
|
|
65
|
+
Network/import errors are caught gracefully (offline grace preserved).
|
|
41
66
|
"""
|
|
42
67
|
try:
|
|
43
68
|
import sys
|
|
44
69
|
|
|
70
|
+
from .licensing.online import NetworkError
|
|
45
71
|
from .licensing.startup import run_startup_validation
|
|
46
72
|
from .licensing.binding import is_in_grace_period
|
|
47
73
|
|
|
74
|
+
_check_expired_license()
|
|
75
|
+
|
|
48
76
|
result = run_startup_validation()
|
|
49
77
|
if result is None:
|
|
50
78
|
return
|
|
@@ -56,10 +84,6 @@ def _run_license_validation():
|
|
|
56
84
|
err_console.print(f"[bold red]License revoked:[/bold red] {reason}")
|
|
57
85
|
sys.exit(2)
|
|
58
86
|
|
|
59
|
-
# T45.22 #157: server says this machine isn't activated. The local
|
|
60
|
-
# binding.is_machine_activated check uses grace period as a fallback;
|
|
61
|
-
# mirror that here so a fresh install isn't immediately locked out.
|
|
62
|
-
# Once the grace window passes, fail closed with the activation prompt.
|
|
63
87
|
if not result.machine_activated and not is_in_grace_period():
|
|
64
88
|
err_console.print(
|
|
65
89
|
"[bold red]License not activated on this machine.[/bold red]\n"
|
|
@@ -68,9 +92,9 @@ def _run_license_validation():
|
|
|
68
92
|
)
|
|
69
93
|
sys.exit(2)
|
|
70
94
|
except SystemExit:
|
|
71
|
-
raise
|
|
72
|
-
except
|
|
73
|
-
pass # Don't block CLI on
|
|
95
|
+
raise
|
|
96
|
+
except (NetworkError, ConnectionError, TimeoutError, OSError, ImportError):
|
|
97
|
+
pass # Don't block CLI on network/import errors
|
|
74
98
|
|
|
75
99
|
|
|
76
100
|
def _find_project_root():
|
|
@@ -129,15 +129,25 @@ def _register_wiring(app: typer.Typer) -> None:
|
|
|
129
129
|
False, "--strict",
|
|
130
130
|
help="Exit non-zero on any finding (default: advisory, exit 0)",
|
|
131
131
|
),
|
|
132
|
+
gen_baseline: bool = typer.Option(
|
|
133
|
+
False, "--generate-baseline",
|
|
134
|
+
help="Write .wiring-baseline.json with current findings and exit",
|
|
135
|
+
),
|
|
132
136
|
):
|
|
133
137
|
"""Flag public symbols/modules written but never wired in (#384).
|
|
134
138
|
|
|
135
139
|
Catches the dead-on-arrival class: a public symbol/module unit-tested but
|
|
136
140
|
never invoked/imported in the package. Exempts ``__all__``, CLI callbacks,
|
|
137
141
|
tests, dunders/``main``, string refs, and ``[project.scripts]``. ADVISORY
|
|
138
|
-
by default (exit 0); use --strict to gate in CI.
|
|
139
|
-
|
|
142
|
+
by default (exit 0); use --strict to gate in CI.
|
|
143
|
+
|
|
144
|
+
Use --generate-baseline to snapshot current findings into
|
|
145
|
+
``.wiring-baseline.json`` (committed, reviewable debt allowlist).
|
|
140
146
|
"""
|
|
141
|
-
from .arch_wiring import run_check_wiring
|
|
147
|
+
from .arch_wiring import generate_baseline, run_check_wiring
|
|
142
148
|
|
|
149
|
+
if gen_baseline:
|
|
150
|
+
outpath = generate_baseline(path, Path.cwd())
|
|
151
|
+
console.print(f"[green]✓ Baseline written to {outpath}[/green]")
|
|
152
|
+
raise typer.Exit(code=0)
|
|
143
153
|
run_check_wiring(path, strict)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Render logic for ``bpsai-pair arch check-wiring`` (#384, #WG2.3).
|
|
2
|
+
|
|
3
|
+
Kept separate from ``arch.py`` so the Typer wrapper there stays thin and the
|
|
4
|
+
module stays under the architecture line limit. The command body reads
|
|
5
|
+
``[project.scripts]`` entry points from the nearest ``pyproject.toml`` so
|
|
6
|
+
console-script symbols are not flagged as unwired.
|
|
7
|
+
|
|
8
|
+
WG2.3 additions:
|
|
9
|
+
- ``generate_baseline()`` writes ``.wiring-baseline.json`` for a repo.
|
|
10
|
+
- ``run_check_wiring_core()`` returns filtered findings (baseline-aware).
|
|
11
|
+
- ``run_check_wiring()`` uses baseline filtering before reporting.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
import typer
|
|
19
|
+
from rich.console import Console
|
|
20
|
+
|
|
21
|
+
from ..core.reachability_lint import Finding, check_directory
|
|
22
|
+
from ..orchestration.wiring_review import filter_baseline, load_baseline
|
|
23
|
+
|
|
24
|
+
console = Console()
|
|
25
|
+
|
|
26
|
+
_BASELINE_FILE = ".wiring-baseline.json"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _entry_point_symbols(start: Path) -> set[str]:
|
|
30
|
+
"""Read symbol names from the nearest pyproject ``[project.scripts]``.
|
|
31
|
+
|
|
32
|
+
``foo = "pkg.mod:func"`` contributes the symbol ``func``. Best-effort:
|
|
33
|
+
returns an empty set if no pyproject or tomllib is available.
|
|
34
|
+
"""
|
|
35
|
+
try:
|
|
36
|
+
import tomllib
|
|
37
|
+
except ModuleNotFoundError: # pragma: no cover - py<3.11
|
|
38
|
+
return set()
|
|
39
|
+
for parent in [start, *start.resolve().parents]:
|
|
40
|
+
candidate = parent / "pyproject.toml"
|
|
41
|
+
if not candidate.is_file():
|
|
42
|
+
continue
|
|
43
|
+
try:
|
|
44
|
+
data = tomllib.loads(candidate.read_text(encoding="utf-8"))
|
|
45
|
+
except (OSError, ValueError):
|
|
46
|
+
return set()
|
|
47
|
+
scripts = data.get("project", {}).get("scripts", {})
|
|
48
|
+
return {str(v).rsplit(":", 1)[-1] for v in scripts.values() if ":" in str(v)}
|
|
49
|
+
return set()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _relativize(finding_path: Path, scan_root: Path) -> str:
|
|
53
|
+
"""Return the finding path relative to scan_root, as posix."""
|
|
54
|
+
try:
|
|
55
|
+
return finding_path.resolve().relative_to(scan_root.resolve()).as_posix()
|
|
56
|
+
except ValueError:
|
|
57
|
+
return finding_path.as_posix()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _findings_to_baseline_json(
|
|
61
|
+
findings: list[Finding], scan_root: Path,
|
|
62
|
+
) -> list[dict]:
|
|
63
|
+
"""Convert findings to the baseline JSON format with relative paths."""
|
|
64
|
+
return [
|
|
65
|
+
{
|
|
66
|
+
"file": _relativize(f.file, scan_root),
|
|
67
|
+
"symbol": f.symbol,
|
|
68
|
+
"kind": f.kind,
|
|
69
|
+
}
|
|
70
|
+
for f in findings
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def generate_baseline(path: str, project_root: Path) -> Path:
|
|
75
|
+
"""Produce ``.wiring-baseline.json`` from current findings.
|
|
76
|
+
|
|
77
|
+
Scans ``path`` for unwired symbols/modules and writes the full set
|
|
78
|
+
as the baseline allowlist at ``project_root / .wiring-baseline.json``.
|
|
79
|
+
Paths are stored relative to the scan root for portability.
|
|
80
|
+
Returns the path to the written file.
|
|
81
|
+
"""
|
|
82
|
+
target = Path(path)
|
|
83
|
+
findings = check_directory(target, entry_points=_entry_point_symbols(target))
|
|
84
|
+
data = _findings_to_baseline_json(findings, target)
|
|
85
|
+
outpath = project_root / _BASELINE_FILE
|
|
86
|
+
outpath.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
87
|
+
return outpath
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _normalize_findings_for_baseline(
|
|
91
|
+
findings: list[Finding], scan_root: Path,
|
|
92
|
+
) -> list[Finding]:
|
|
93
|
+
"""Rewrite finding paths to be relative to scan_root (for baseline matching)."""
|
|
94
|
+
out: list[Finding] = []
|
|
95
|
+
for f in findings:
|
|
96
|
+
rel = _relativize(f.file, scan_root)
|
|
97
|
+
out.append(Finding(kind=f.kind, symbol=f.symbol, file=Path(rel), line=f.line))
|
|
98
|
+
return out
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def run_check_wiring_core(
|
|
102
|
+
path: str, *, baseline_root: Path | None = None,
|
|
103
|
+
) -> list[Finding]:
|
|
104
|
+
"""Return non-baselined findings (no I/O side-effects).
|
|
105
|
+
|
|
106
|
+
Scans ``path`` for unwired symbols, loads the baseline from
|
|
107
|
+
``baseline_root`` (if provided), and returns only NEW findings
|
|
108
|
+
that are not in the baseline allowlist. Baseline entries use
|
|
109
|
+
paths relative to ``baseline_root``, so findings are normalized
|
|
110
|
+
relative to ``baseline_root`` (not the scan root) when filtering.
|
|
111
|
+
"""
|
|
112
|
+
target = Path(path)
|
|
113
|
+
findings = check_directory(target, entry_points=_entry_point_symbols(target))
|
|
114
|
+
if baseline_root is not None:
|
|
115
|
+
baseline = load_baseline(baseline_root)
|
|
116
|
+
if baseline:
|
|
117
|
+
findings = _normalize_findings_for_baseline(findings, baseline_root)
|
|
118
|
+
findings = filter_baseline(findings, baseline)
|
|
119
|
+
return findings
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def run_check_wiring(path: str, strict: bool) -> None:
|
|
123
|
+
"""Execute the wiring/reachability advisory lint and print findings.
|
|
124
|
+
|
|
125
|
+
Loads ``.wiring-baseline.json`` from the nearest project root and
|
|
126
|
+
excludes baselined findings. Advisory: exits 0 unless ``strict``
|
|
127
|
+
is set. Raises ``typer.Exit``.
|
|
128
|
+
"""
|
|
129
|
+
target = Path(path)
|
|
130
|
+
if not target.exists():
|
|
131
|
+
console.print(f"[red]Error: Path not found: {target}[/red]")
|
|
132
|
+
raise typer.Exit(code=2)
|
|
133
|
+
|
|
134
|
+
baseline_root = _find_baseline_root(target)
|
|
135
|
+
findings = run_check_wiring_core(path, baseline_root=baseline_root)
|
|
136
|
+
if not findings:
|
|
137
|
+
console.print(f"[green]✓ No unwired public symbols/modules in {target}[/green]")
|
|
138
|
+
raise typer.Exit(code=0)
|
|
139
|
+
|
|
140
|
+
symbols = [f for f in findings if f.kind == "symbol"]
|
|
141
|
+
modules = [f for f in findings if f.kind == "module"]
|
|
142
|
+
console.print(
|
|
143
|
+
f"[yellow]⚠ {len(findings)} possibly-unwired item(s) in {target} "
|
|
144
|
+
f"({len(symbols)} symbol(s), {len(modules)} module(s)) — "
|
|
145
|
+
f"advisory, confirm before acting:[/yellow]\n"
|
|
146
|
+
)
|
|
147
|
+
for f in findings:
|
|
148
|
+
console.print(f" {f.message()}")
|
|
149
|
+
console.print(
|
|
150
|
+
"\n[dim]Static analysis cannot see dynamic dispatch; treat these as "
|
|
151
|
+
"candidates, not proof.[/dim]"
|
|
152
|
+
)
|
|
153
|
+
raise typer.Exit(code=1 if strict else 0)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _find_baseline_root(start: Path) -> Path | None:
|
|
157
|
+
"""Walk up from ``start`` to find a directory with .wiring-baseline.json."""
|
|
158
|
+
for parent in [start, *start.resolve().parents]:
|
|
159
|
+
if (parent / _BASELINE_FILE).is_file():
|
|
160
|
+
return parent
|
|
161
|
+
return None
|
|
@@ -128,6 +128,7 @@ def _find_task_file(task_id: str, root: Path) -> Optional[Path]:
|
|
|
128
128
|
|
|
129
129
|
_MODEL_COST_PER_1K = {
|
|
130
130
|
"opus": 0.005, # Opus 4.5/4.6: $5/MTok input
|
|
131
|
+
"fable": 0.010, # Fable 5: $10/MTok input
|
|
131
132
|
"sonnet": 0.003, # Sonnet 4.0/4.5: $3/MTok input
|
|
132
133
|
"haiku": 0.001, # Haiku 4.5: $1/MTok input
|
|
133
134
|
}
|
|
@@ -13,6 +13,7 @@ from bpsai_pair.commands.engage_branch import ( # noqa: F401
|
|
|
13
13
|
_cleanup_orphan_branch,
|
|
14
14
|
_create_feature_branch,
|
|
15
15
|
_validate_branch_name,
|
|
16
|
+
push_branch_at_kickoff,
|
|
16
17
|
)
|
|
17
18
|
from bpsai_pair.commands.engage_guards import ( # noqa: F401
|
|
18
19
|
_check_protected_branch,
|
|
@@ -124,7 +125,7 @@ def engage(
|
|
|
124
125
|
if dry_run:
|
|
125
126
|
project_root = repo_root()
|
|
126
127
|
_run_containment_audit_display(parsed.tasks, project_root)
|
|
127
|
-
return _show_dry_run(parsed, json_out)
|
|
128
|
+
return _show_dry_run(parsed, json_out, project_root=project_root)
|
|
128
129
|
env_overrides = _resolve_provider(provider) if provider else {}
|
|
129
130
|
if not sprint:
|
|
130
131
|
sprint = _infer_sprint(parsed)
|
|
@@ -157,7 +158,11 @@ from bpsai_pair.commands.engage_plan_id import ( # noqa: E402, F401
|
|
|
157
158
|
_dispatch_navigator, # re-exported for tests importing it from engage
|
|
158
159
|
resolve_reuse_plan_id as _resolve_reuse_plan_id,
|
|
159
160
|
)
|
|
160
|
-
from bpsai_pair.commands.engage_executor import
|
|
161
|
+
from bpsai_pair.commands.engage_executor import ( # noqa: E402, F401
|
|
162
|
+
execute_sprint as _execute_sprint,
|
|
163
|
+
fan_out_sibling_branches as _fan_out_sibling_branches,
|
|
164
|
+
preflight_parallel_same_target as _preflight_parallel_same_target,
|
|
165
|
+
)
|
|
161
166
|
# CR.4.1 (#411): result rendering lives in ``engage_result`` (line cap);
|
|
162
167
|
# re-exported so ``engage._output_result`` / ``engage._show_result`` /
|
|
163
168
|
# ``engage._result_dict`` patch targets keep resolving.
|
|
@@ -296,24 +301,6 @@ def _run_preflight(
|
|
|
296
301
|
return outcome, preflight_block
|
|
297
302
|
|
|
298
303
|
|
|
299
|
-
def _fan_out_sibling_branches(
|
|
300
|
-
parsed: Any, project_root: Path, active_branch: str,
|
|
301
|
-
touched_siblings: list[tuple[Path, str | None]] | None,
|
|
302
|
-
) -> None:
|
|
303
|
-
"""Create the SIBLING engage branches (CR-R7) and record them (CR-R9).
|
|
304
|
-
|
|
305
|
-
Runs only AFTER the preflight gate passes and BEFORE dispatch. Records each
|
|
306
|
-
touched sibling (with its prior branch) into ``touched_siblings`` so a later
|
|
307
|
-
sprint failure can restore those working trees (see ``_run_engage``).
|
|
308
|
-
"""
|
|
309
|
-
if not active_branch:
|
|
310
|
-
return
|
|
311
|
-
touched = _branch_multi.create_cross_repo_branch(
|
|
312
|
-
parsed, project_root, active_branch)
|
|
313
|
-
if touched_siblings is not None:
|
|
314
|
-
touched_siblings.extend(touched)
|
|
315
|
-
|
|
316
|
-
|
|
317
304
|
def _run_sprint_pipeline(
|
|
318
305
|
run_root: Path, backlog_path: Path, parsed: Any,
|
|
319
306
|
sprint: str, max_parallel: int,
|
|
@@ -324,9 +311,7 @@ def _run_sprint_pipeline(
|
|
|
324
311
|
touched_siblings: list[tuple[Path, str | None]] | None = None,
|
|
325
312
|
) -> dict[str, Any]:
|
|
326
313
|
"""Execute planning, sprint, and finalization in *run_root*."""
|
|
327
|
-
|
|
328
|
-
project_root = run_root
|
|
329
|
-
|
|
314
|
+
project_root = project_root or run_root
|
|
330
315
|
reuse_plan_id = _resolve_reuse_plan_id(
|
|
331
316
|
run_root, backlog_path, parsed, skip_planning, resume,
|
|
332
317
|
) # paircoder#388: reconcile onto Navigator id, not divergent engage id
|
|
@@ -336,13 +321,14 @@ def _run_sprint_pipeline(
|
|
|
336
321
|
backlog_target, per_task_repos = _preflight.resolve_targets_or_refuse(
|
|
337
322
|
parsed, project_root,
|
|
338
323
|
)
|
|
339
|
-
_, preflight_block = _run_preflight(
|
|
340
|
-
|
|
341
|
-
)
|
|
324
|
+
_, preflight_block = _run_preflight(backlog_target, per_task_repos, project_root)
|
|
325
|
+
# EH2.3: parallel-same-target guard is a preflight -> run BEFORE fan-out (below) so a refused plan branches no siblings.
|
|
326
|
+
_preflight_parallel_same_target(run_root, plan_id, max_parallel, backlog_target, per_task_repos)
|
|
342
327
|
from bpsai_pair.pm_trello.backlog_engage import create_backlog_tree_for_engage as _create_bt # noqa: E402
|
|
343
328
|
_create_bt(run_root, plan_id, parsed) # #430: after preflight → refused runs leave no orphan PM cards
|
|
344
|
-
|
|
345
|
-
|
|
329
|
+
# EH1.1 (#427): push the branch to origin before dispatch (best-effort durability).
|
|
330
|
+
push_branch_at_kickoff(run_root, active_branch)
|
|
331
|
+
_fan_out_sibling_branches(parsed, project_root, active_branch, touched_siblings)
|
|
346
332
|
result = _execute_sprint(
|
|
347
333
|
run_root, plan_id, max_parallel, completed_tasks=completed,
|
|
348
334
|
target_repo=backlog_target,
|
|
@@ -15,6 +15,12 @@ from bpsai_pair.commands.engage_guards import (
|
|
|
15
15
|
_check_protected_branch,
|
|
16
16
|
_derive_branch_slug,
|
|
17
17
|
)
|
|
18
|
+
# EH1.1 (#427): kickoff push helper lives in ``orchestration.engage_push``
|
|
19
|
+
# (keeps engage.py under the arch cap); re-exported here so engage.py can call
|
|
20
|
+
# it via its existing ``engage_branch`` import block without a new import stmt.
|
|
21
|
+
from bpsai_pair.orchestration.engage_push import ( # noqa: F401
|
|
22
|
+
push_branch_at_kickoff,
|
|
23
|
+
)
|
|
18
24
|
|
|
19
25
|
logger = logging.getLogger(__name__)
|
|
20
26
|
|
|
@@ -121,7 +121,10 @@ def restore_siblings_on_failure(
|
|
|
121
121
|
for repo, prior in touched:
|
|
122
122
|
if prior:
|
|
123
123
|
restored = subprocess.run(
|
|
124
|
-
|
|
124
|
+
# EH2.1: ``switch --`` end-of-options guard so a flag-like prior
|
|
125
|
+
# branch name is never parsed as an option (defense-in-depth;
|
|
126
|
+
# refs are ``_validate_branch_name``-checked upstream).
|
|
127
|
+
["git", "switch", "--", prior],
|
|
125
128
|
cwd=repo, capture_output=True, check=False,
|
|
126
129
|
encoding="utf-8", errors="replace",
|
|
127
130
|
)
|
|
@@ -289,18 +292,22 @@ def _safe_checkout_engage_branch(repo: Path, branch: str) -> None:
|
|
|
289
292
|
branch from whatever the sibling had checked out (stale feature branch /
|
|
290
293
|
dirty ``main``), so the later PR diff could carry unrelated work. We now
|
|
291
294
|
resolve the repo's base/default branch and cut FROM it. Idempotent: if the
|
|
292
|
-
engage branch already exists (re-run), ``
|
|
293
|
-
back to a plain
|
|
295
|
+
engage branch already exists (re-run), ``switch -c`` fails and we fall
|
|
296
|
+
back to a plain ``switch``.
|
|
294
297
|
"""
|
|
295
298
|
base = _detect_pr_base(repo)
|
|
296
299
|
created = subprocess.run(
|
|
297
|
-
|
|
300
|
+
# EH2.1: ``switch -c … -- <base>`` end-of-options guard so a flag-like
|
|
301
|
+
# base ref is never parsed as an option (the new branch name is safe as
|
|
302
|
+
# the ``-c`` argument). Mirrors the push/rev-list/gh hardening.
|
|
303
|
+
["git", "switch", "-c", branch, "--", base],
|
|
298
304
|
cwd=repo, capture_output=True, check=False,
|
|
299
305
|
encoding="utf-8", errors="replace",
|
|
300
306
|
)
|
|
301
307
|
if created.returncode != 0:
|
|
302
308
|
fallback = subprocess.run(
|
|
303
|
-
|
|
309
|
+
# EH2.1: ``switch --`` end-of-options guard on the fallback ref too.
|
|
310
|
+
["git", "switch", "--", branch],
|
|
304
311
|
cwd=repo, capture_output=True, check=False,
|
|
305
312
|
encoding="utf-8", errors="replace",
|
|
306
313
|
)
|
|
@@ -321,7 +328,7 @@ def create_branch_in_repos(repos: list[Path], branch: str) -> None:
|
|
|
321
328
|
each repo is also checked for a clean tree and a non-protected branch name
|
|
322
329
|
(CR-R2, Finding B), mirroring the run repo's ``_setup_branch`` rigor. The
|
|
323
330
|
branch is created FROM the repo's resolved base; if it already exists
|
|
324
|
-
(re-run) the
|
|
331
|
+
(re-run) the create falls back to a plain ``switch`` instead of failing.
|
|
325
332
|
"""
|
|
326
333
|
# CR-R3 (P2-1): the sibling fan-out is a funnel for the run-repo slug, an
|
|
327
334
|
# explicit ``--branch`` flag, AND the derived engage name -- validate the
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Sprint execution helper extracted from engage.py to keep that file
|
|
2
|
+
under the 400-line architecture limit.
|
|
3
|
+
"""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from bpsai_pair.orchestration.headless import HEADLESS_ALLOWED_TOOLS
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def preflight_parallel_same_target(
|
|
13
|
+
project_root: Path, plan_id: str, max_parallel: int,
|
|
14
|
+
backlog_target: Path | None = None,
|
|
15
|
+
per_task_target_repos: dict[str, Path] | None = None,
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Refuse a parallel-same-target plan BEFORE any sibling mutation (EH2.3).
|
|
18
|
+
|
|
19
|
+
The parallel-same-target check is logically a PREFLIGHT: it refuses a
|
|
20
|
+
``ExecutionMode.PARALLEL`` phase whose tasks share one un-isolated sibling
|
|
21
|
+
target repo. ``_run_sprint_pipeline`` calls this BEFORE
|
|
22
|
+
``_fan_out_sibling_branches`` so a refused plan branches no siblings (nothing
|
|
23
|
+
to restore). ``execute_sprint`` still runs the same guard as an idempotent
|
|
24
|
+
backstop -- that call also covers the resume path, which re-enters through
|
|
25
|
+
``execute_sprint`` rather than the fresh pipeline.
|
|
26
|
+
|
|
27
|
+
A same-repo run (no per-task overrides and no sibling backlog target) has no
|
|
28
|
+
sibling target at all, so no parallel-same-sibling conflict is possible --
|
|
29
|
+
return early without building the plan graph. Only a sibling target (set via
|
|
30
|
+
``per_task_target_repos`` or a cross-repo ``backlog_target``) can conflict.
|
|
31
|
+
"""
|
|
32
|
+
if not per_task_target_repos and backlog_target is None:
|
|
33
|
+
return
|
|
34
|
+
from bpsai_pair.orchestration import plan_graph
|
|
35
|
+
from bpsai_pair.orchestration.target_repo_resolution import (
|
|
36
|
+
guard_parallel_same_target,
|
|
37
|
+
)
|
|
38
|
+
graph = plan_graph.PlanGraphBuilder(project_root).build(plan_id)
|
|
39
|
+
guard_parallel_same_target(
|
|
40
|
+
graph, per_task_target_repos, backlog_target, project_root,
|
|
41
|
+
max_parallel=max_parallel,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def fan_out_sibling_branches(
|
|
46
|
+
parsed: Any, project_root: Path, active_branch: str,
|
|
47
|
+
touched_siblings: list[tuple[Path, str | None]] | None,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""Create the SIBLING engage branches (CR-R7) and record them (CR-R9).
|
|
50
|
+
|
|
51
|
+
Runs after the preflight gate + parallel-same-target guard pass and before
|
|
52
|
+
dispatch; records each touched sibling (with its prior branch) into
|
|
53
|
+
``touched_siblings`` so a later sprint failure can restore those working
|
|
54
|
+
trees (see ``_run_engage``). EH2.3 relocated this here (from ``engage``) so
|
|
55
|
+
the guard can run before it while keeping ``engage`` under the arch line cap.
|
|
56
|
+
"""
|
|
57
|
+
from bpsai_pair.commands import engage_branch_multi as _branch_multi
|
|
58
|
+
|
|
59
|
+
if not active_branch:
|
|
60
|
+
return
|
|
61
|
+
touched = _branch_multi.create_cross_repo_branch(
|
|
62
|
+
parsed, project_root, active_branch)
|
|
63
|
+
if touched_siblings is not None:
|
|
64
|
+
touched_siblings.extend(touched)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def execute_sprint(
|
|
68
|
+
project_root: Path, plan_id: str, max_parallel: int,
|
|
69
|
+
completed_tasks: list[str] | None = None,
|
|
70
|
+
target_repo: Path | None = None,
|
|
71
|
+
per_task_target_repos: dict[str, Path] | None = None,
|
|
72
|
+
env_overrides: dict[str, str] | None = None,
|
|
73
|
+
) -> Any:
|
|
74
|
+
"""Build plan graph and execute tasks via headless runner.
|
|
75
|
+
|
|
76
|
+
EH1.6: ``target_repo`` (from backlog ``**Target repo:**``) sets
|
|
77
|
+
SprintConfig.target_repo so the no-output detector reads the
|
|
78
|
+
sibling repo instead of the orchestrator cwd.
|
|
79
|
+
|
|
80
|
+
PD4 (2026-05-27): ``per_task_target_repos`` carries per-task
|
|
81
|
+
overrides for multi-repo backlogs. Each task whose
|
|
82
|
+
``ParsedTask.target_repo`` resolved cleanly contributes a
|
|
83
|
+
``{task_id: Path}`` entry; the executor picks the per-task value
|
|
84
|
+
when present, then falls back to ``target_repo``.
|
|
85
|
+
"""
|
|
86
|
+
from bpsai_pair.orchestration import (
|
|
87
|
+
sprint_executor, plan_graph, headless_runner,
|
|
88
|
+
)
|
|
89
|
+
from bpsai_pair.orchestration.target_repo_resolution import (
|
|
90
|
+
guard_parallel_same_target,
|
|
91
|
+
)
|
|
92
|
+
graph = plan_graph.PlanGraphBuilder(project_root).build(plan_id)
|
|
93
|
+
for tid in completed_tasks or []:
|
|
94
|
+
graph.mark_done(tid)
|
|
95
|
+
# CR-R8 (P1) + R10 Fix 3 (Codex P1): refuse a PARALLEL phase sharing one
|
|
96
|
+
# sibling target before dispatch, but only when effective parallelism > 1
|
|
97
|
+
# (``--max-parallel 1`` serializes -> safe; the executor uses min(mp, n)).
|
|
98
|
+
guard_parallel_same_target(
|
|
99
|
+
graph, per_task_target_repos, target_repo, project_root,
|
|
100
|
+
max_parallel=max_parallel,
|
|
101
|
+
)
|
|
102
|
+
config = sprint_executor.SprintConfig(
|
|
103
|
+
max_parallel=max_parallel, target_repo=target_repo,
|
|
104
|
+
per_task_target_repos=per_task_target_repos or {},
|
|
105
|
+
env_overrides=env_overrides or {},
|
|
106
|
+
)
|
|
107
|
+
task_runner = headless_runner._make_headless_runner(
|
|
108
|
+
project_root, permission_mode="auto",
|
|
109
|
+
allowed_tools=HEADLESS_ALLOWED_TOOLS, approved_by="engage-cli",
|
|
110
|
+
sprint_config=config,
|
|
111
|
+
)
|
|
112
|
+
task_hook = sprint_executor.make_default_task_hook(project_root)
|
|
113
|
+
return sprint_executor.SprintExecutor(
|
|
114
|
+
project_root, graph, config,
|
|
115
|
+
task_runner=task_runner, task_complete_hook=task_hook,
|
|
116
|
+
).execute()
|
|
@@ -31,6 +31,10 @@ from bpsai_pair.commands.engage_guards import (
|
|
|
31
31
|
from bpsai_pair.commands.engage_executor import execute_sprint as _execute_sprint
|
|
32
32
|
from bpsai_pair.core.utils import repo_root
|
|
33
33
|
from bpsai_pair.orchestration.backlog_parser import BacklogParser
|
|
34
|
+
from bpsai_pair.commands.engage_resume_integrity import (
|
|
35
|
+
_confine_persisted_repos,
|
|
36
|
+
enforce_repo_set_agreement_or_exit,
|
|
37
|
+
)
|
|
34
38
|
from bpsai_pair.orchestration.engage_run_state import (
|
|
35
39
|
load_run_state, save_pause_state, verify_paused_task_done,
|
|
36
40
|
)
|
|
@@ -96,36 +100,6 @@ def handle_pause(
|
|
|
96
100
|
return _result_dict(result, paused_task=result.paused_task, run_id=run_id)
|
|
97
101
|
|
|
98
102
|
|
|
99
|
-
def _confine_persisted_repos(
|
|
100
|
-
raw: dict[str, str], project_root: Path,
|
|
101
|
-
) -> dict[str, Path]:
|
|
102
|
-
"""Re-apply the workspace-boundary check to every persisted
|
|
103
|
-
``per_task_target_repos`` entry on resume.
|
|
104
|
-
|
|
105
|
-
P2-Laverna on PR #348 re-review: persisted paths come from a state.json an
|
|
106
|
-
attacker with local write access could tamper with -- a planted ``"/etc"``
|
|
107
|
-
(outside ``project_root.parent``) would become the ``cwd`` of git
|
|
108
|
-
subprocess calls. Drop+WARN on escapes so the run continues with the fresh
|
|
109
|
-
backlog re-resolution rather than trusting the poisoned state.
|
|
110
|
-
"""
|
|
111
|
-
boundary = project_root.resolve().parent
|
|
112
|
-
cleaned: dict[str, Path] = {}
|
|
113
|
-
for tid, raw_path in raw.items():
|
|
114
|
-
candidate = Path(raw_path).resolve()
|
|
115
|
-
try:
|
|
116
|
-
candidate.relative_to(boundary)
|
|
117
|
-
except ValueError:
|
|
118
|
-
logger.warning(
|
|
119
|
-
"resume: persisted target_repo for %s (%s) escapes the "
|
|
120
|
-
"workspace boundary (%s); dropping. Will re-resolve from "
|
|
121
|
-
"backlog if the task is still listed.",
|
|
122
|
-
tid, raw_path, boundary,
|
|
123
|
-
)
|
|
124
|
-
continue
|
|
125
|
-
cleaned[tid] = candidate
|
|
126
|
-
return cleaned
|
|
127
|
-
|
|
128
|
-
|
|
129
103
|
def _rehydrate_per_task_repos(
|
|
130
104
|
state, project_root: Path,
|
|
131
105
|
) -> tuple[Path | None, dict[str, Path]]:
|
|
@@ -300,13 +274,14 @@ def resume_engage(run_id: str) -> dict[str, Any]:
|
|
|
300
274
|
so the security scan + PR + review cover EVERY touched repo on resume.
|
|
301
275
|
|
|
302
276
|
CR-followup (Codex P1, drift): the ``parsed`` driving the fan-out AND
|
|
303
|
-
finalize is
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
run inside a failure guard
|
|
309
|
-
stranded siblings on a
|
|
277
|
+
finalize is SYNTHESIZED from the rehydrated ``per_task_repos`` map (the SAME
|
|
278
|
+
set ``_execute_sprint`` commits to), NOT a freshly re-parsed backlog -- the
|
|
279
|
+
invariant is branched == scanned == PR'd == committed. EH2.4: that set must
|
|
280
|
+
also agree with a fresh re-resolution of the on-disk backlog -- divergence
|
|
281
|
+
(an edited backlog) refuses loudly BEFORE fan-out/dispatch. CR-R11 Fix 1:
|
|
282
|
+
dispatch + finalize run inside a failure guard
|
|
283
|
+
(``_execute_and_finalize_resume``) that restores stranded siblings on a
|
|
284
|
+
raised exception.
|
|
310
285
|
"""
|
|
311
286
|
project_root = repo_root()
|
|
312
287
|
state = load_run_state(project_root, run_id)
|
|
@@ -325,6 +300,11 @@ def resume_engage(run_id: str) -> dict[str, Any]:
|
|
|
325
300
|
parsed = _branch_multi.build_parsed_from_repo_map(
|
|
326
301
|
per_task_repos, project_root, target_repo_path,
|
|
327
302
|
)
|
|
303
|
+
# EH2.4: the set dispatch/fan-out act on must agree with the on-disk
|
|
304
|
+
# backlog -- an edited backlog fails loud here, before any fan-out.
|
|
305
|
+
enforce_repo_set_agreement_or_exit(
|
|
306
|
+
parsed, state.backlog_path or "", project_root,
|
|
307
|
+
)
|
|
328
308
|
touched_siblings = _fan_out_resume_siblings(
|
|
329
309
|
parsed, project_root, active_branch,
|
|
330
310
|
)
|