claude-dev-env 4.2.0 → 7.0.0
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.
- package/.agents/agents/pr-description-writer.md +2 -2
- package/.agents/agents/test_agent_frontmatter.py +2 -2
- package/.agents/agents/test_pr_description_writer_style.py +1 -3
- package/.agents/skills/e-code-review/SKILL.md +12 -12
- package/.agents/skills/e-code-review/preflight-proposal.contract.test.mjs +20 -0
- package/.agents/skills/e-code-review/reference/fix.md +15 -17
- package/.agents/skills/e-code-review/reference/loop.md +35 -39
- package/.agents/skills/e-code-review/reference/mode-contract.test.mjs +2 -1
- package/.agents/skills/e-code-review/reference/preflight-proposal.md +44 -9
- package/.agents/skills/e-code-review/reference/runner-selection.md +13 -14
- package/.agents/skills/issue-tracker/SKILL.md +7 -0
- package/.agents/skills/pull-request/SKILL.md +216 -0
- package/.agents/skills/pull-request/reference/publication-tasks.md +18 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/__init__.py +1 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/__init__.py +1 -0
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +69 -0
- package/.agents/skills/pull-request/scripts/pull_request.py +265 -0
- package/.agents/skills/pull-request/scripts/recover_legacy_author.py +251 -0
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +58 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +396 -0
- package/.agents/skills/pull-request/scripts/test_recover_legacy_author.py +221 -0
- package/.agents/skills/skill-builder/SKILL.md +3 -196
- package/.agents/skills/test-runner/SKILL.md +69 -0
- package/.agents/skills/test-runner/scripts/preflight_checks.py +365 -0
- package/.agents/skills/test-runner/scripts/run_tests.py +316 -0
- package/.agents/skills/test-runner/scripts/test_preflight_checks.py +185 -0
- package/.agents/skills/test-runner/scripts/test_run_tests.py +281 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/__init__.py +1 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/config/__init__.py +1 -0
- package/.agents/skills/test-runner/scripts/test_runner_constants/config/constants.py +96 -0
- package/.agents/skills-archived/pr-loop-cloud-transport/reference/identity-and-hooks.md +1 -1
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +6 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +64 -19
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +59 -0
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/ever-shipped-skills.test.mjs +8 -0
- package/bin/install.agents-home.test.mjs +15 -13
- package/bin/install.mjs +37 -1
- package/bin/install.policy-lint.test.mjs +78 -0
- package/bin/install.prune.test.mjs +149 -20
- package/bin/install.pstack-plugin.test.mjs +114 -0
- package/bin/install.test.mjs +61 -7
- package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
- package/hooks/advisory/pr_done_reminder.py +342 -0
- package/hooks/advisory/test_pr_done_reminder.py +249 -0
- package/hooks/blocking/bash_post_call_dispatcher.py +53 -6
- package/hooks/blocking/code_rules_paired_test.py +22 -15
- package/hooks/blocking/pii_prevention_blocker.py +32 -51
- package/hooks/blocking/test_bash_post_call_dispatcher.py +55 -17
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +1 -4
- package/hooks/blocking/test_code_rules_command_dispatch.py +2 -2
- package/hooks/blocking/test_code_rules_enforcer_paired_test.py +36 -29
- package/hooks/blocking/test_code_rules_js_resume_task_enumeration.py +4 -4
- package/hooks/blocking/test_code_rules_js_returns_object_schemaless.py +5 -5
- package/hooks/blocking/test_pii_prevention_blocker.py +37 -89
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +68 -133
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
- package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +18 -18
- package/hooks/gh_post_body_texts.py +195 -0
- package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
- package/hooks/git-hooks/pre_commit.py +52 -11
- package/hooks/git-hooks/test_installed_policy_lint.py +159 -0
- package/hooks/git-hooks/test_native_policy_commit.py +87 -0
- package/hooks/git-hooks/test_pre_commit.py +246 -0
- package/hooks/hooks.json +1 -16
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -2
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +0 -8
- package/hooks/hooks_constants/gh_post_body_texts_constants.py +12 -0
- package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -43
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +17 -7
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +0 -7
- package/hooks/hooks_constants/test_failure_recorder_constants.py +3 -3
- package/hooks/hooks_constants/test_gh_post_body_texts_constants.py +19 -0
- package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +20 -32
- package/hooks/observability/test_failure_recorder.py +1 -1
- package/hooks/pyproject.toml +1 -1
- package/hooks/test_gh_post_body_texts.py +79 -0
- package/package.json +2 -2
- package/rules/durable-post-artifacts.md +32 -20
- package/rules/gh-cli-conventions.md +23 -13
- package/rules/git-workflow.md +21 -8
- package/scripts/check.ps1 +0 -1
- package/{.agents/skills/run-claude-dev-env/driver.mjs → scripts/ci/installer-lifecycle.mjs} +3 -28
- package/scripts/ci/installer-lifecycle.test.mjs +26 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +1 -11
- package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
- package/scripts/durable_post_lint.py +206 -0
- package/scripts/durable_post_lint_config/config/constants.py +96 -0
- package/scripts/durable_post_lint_config/config/test_constants.py +25 -0
- package/scripts/policy_lint/adapter_configuration.py +53 -12
- package/scripts/policy_lint/adapter_detectors.py +13 -6
- package/scripts/policy_lint/adapters.py +7 -4
- package/scripts/policy_lint/config/constants.py +5 -0
- package/scripts/policy_lint/engine.py +48 -4
- package/scripts/policy_lint/model.py +1 -0
- package/scripts/policy_lint/registry.py +1 -1
- package/scripts/policy_lint/selection.py +2 -1
- package/scripts/policy_lint/selection_git.py +2 -0
- package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
- package/scripts/repository_checks/config/constants.py +0 -5
- package/scripts/shared_tree_paths.py +32 -3
- package/scripts/test_durable_post_lint.py +332 -0
- package/scripts/test_shared_tree_paths.py +33 -0
- package/scripts/tests/test_adapter_configuration.py +54 -0
- package/scripts/tests/test_policy_lint_rules_archive.py +120 -0
- package/scripts/tests/test_policy_lint_rules_engine.py +25 -4
- package/scripts/tests/test_policy_lint_rules_installed_loader.py +29 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +227 -13
- package/scripts/tests/test_policy_lint_selection.py +25 -2
- package/scripts/tests/test_policy_lint_selection_native_index.py +30 -0
- package/scripts/tests/test_rules.py +3 -7
- package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/audit-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/audit-reply-template.md +0 -5
- package/.agents/skills/_shared/pr-loop/code-rules-gate.md +0 -5
- package/.agents/skills/_shared/pr-loop/fix-protocol.md +0 -5
- package/.agents/skills/_shared/pr-loop/gh-payloads.md +0 -5
- package/.agents/skills/_shared/pr-loop/portable-driver.md +0 -149
- package/.agents/skills/_shared/pr-loop/post-audit-thread-contract.md +0 -5
- package/.agents/skills/_shared/pr-loop/precatch-rubric.md +0 -5
- package/.agents/skills/_shared/pr-loop/preflight-proposal.contract.test.mjs +0 -119
- package/.agents/skills/_shared/pr-loop/preflight-proposal.md +0 -5
- package/.agents/skills/_shared/pr-loop/prompts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml +0 -324
- package/.agents/skills/_shared/pr-loop/scripts/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/RUNTIME_SCRIPTS.md +0 -29
- package/.agents/skills/_shared/pr-loop/scripts/_cli_utils.py +0 -22
- package/.agents/skills/_shared/pr-loop/scripts/_path_resolver.py +0 -186
- package/.agents/skills/_shared/pr-loop/scripts/_xml_utils.py +0 -20
- package/.agents/skills/_shared/pr-loop/scripts/audit_category_schema.py +0 -355
- package/.agents/skills/_shared/pr-loop/scripts/build_audit_prompt.py +0 -289
- package/.agents/skills/_shared/pr-loop/scripts/build_converge_task_list.py +0 -310
- package/.agents/skills/_shared/pr-loop/scripts/build_fix_prompt.py +0 -292
- package/.agents/skills/_shared/pr-loop/scripts/init_loop_state.py +0 -134
- package/.agents/skills/_shared/pr-loop/scripts/portable_converge_driver.py +0 -1646
- package/.agents/skills/_shared/pr-loop/scripts/preflight_worktree.py +0 -392
- package/.agents/skills/_shared/pr-loop/scripts/select_converge_pacer.py +0 -215
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/AGENTS.md +0 -1
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/__init__.py +0 -0
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +0 -37
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +0 -56
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/handoff_constants.py +0 -45
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +0 -47
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +0 -157
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +0 -177
- package/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/preflight_constants.py +0 -70
- package/.agents/skills/_shared/pr-loop/scripts/teardown_worktrees.py +0 -172
- package/.agents/skills/_shared/pr-loop/scripts/test__path_resolver.py +0 -106
- package/.agents/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +0 -94
- package/.agents/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +0 -499
- package/.agents/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +0 -140
- package/.agents/skills/_shared/pr-loop/scripts/test_build_fix_prompt.py +0 -262
- package/.agents/skills/_shared/pr-loop/scripts/test_init_loop_state.py +0 -71
- package/.agents/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +0 -1119
- package/.agents/skills/_shared/pr-loop/scripts/test_preflight_worktree.py +0 -287
- package/.agents/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +0 -207
- package/.agents/skills/_shared/pr-loop/scripts/test_teardown_worktrees.py +0 -59
- package/.agents/skills/_shared/pr-loop/scripts/test_write_handoff.py +0 -201
- package/.agents/skills/_shared/pr-loop/scripts/write_audit_outcomes.py +0 -182
- package/.agents/skills/_shared/pr-loop/scripts/write_fix_outcomes.py +0 -206
- package/.agents/skills/_shared/pr-loop/scripts/write_handoff.py +0 -309
- package/.agents/skills/_shared/pr-loop/state-schema.md +0 -5
- package/.agents/skills/_shared/pr-loop/worker-spawn.md +0 -5
- package/.agents/skills/autoconverge/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/SKILL.md +0 -431
- package/.agents/skills/autoconverge/reference/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/reference/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/reference/closing-report.md +0 -93
- package/.agents/skills/autoconverge/reference/convergence-gates.md +0 -31
- package/.agents/skills/autoconverge/reference/convergence.md +0 -219
- package/.agents/skills/autoconverge/reference/copilot-findings.md +0 -51
- package/.agents/skills/autoconverge/reference/gotchas.md +0 -66
- package/.agents/skills/autoconverge/reference/headless-safety.md +0 -44
- package/.agents/skills/autoconverge/reference/multi-pr.md +0 -128
- package/.agents/skills/autoconverge/reference/self-closing-loop.md +0 -84
- package/.agents/skills/autoconverge/reference/stop-conditions.md +0 -127
- package/.agents/skills/autoconverge/test_portable_pacer_gate.py +0 -54
- package/.agents/skills/autoconverge/workflow/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/aggregate_runs.py +0 -371
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/.claude/CLAUDE.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/AGENTS.md +0 -1
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/__init__.py +0 -0
- package/.agents/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +0 -250
- package/.agents/skills/autoconverge/workflow/converge.clean-audit.test.mjs +0 -665
- package/.agents/skills/autoconverge/workflow/converge.codex-gate.test.mjs +0 -472
- package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +0 -64
- package/.agents/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +0 -1009
- package/.agents/skills/autoconverge/workflow/converge.fix-progress.test.mjs +0 -107
- package/.agents/skills/autoconverge/workflow/converge.fix-recovery.test.mjs +0 -33
- package/.agents/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +0 -15
- package/.agents/skills/autoconverge/workflow/converge.mjs +0 -3132
- package/.agents/skills/autoconverge/workflow/converge.p2-advance.test.mjs +0 -202
- package/.agents/skills/autoconverge/workflow/converge.path-aware.test.mjs +0 -47
- package/.agents/skills/autoconverge/workflow/converge.precatch.test.mjs +0 -152
- package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +0 -116
- package/.agents/skills/autoconverge/workflow/converge_multi.mjs +0 -169
- package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +0 -173
- package/.agents/skills/autoconverge/workflow/convergence_summary.py +0 -110
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ab1c2d3e4f5a6b7c8.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +0 -2
- package/.agents/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +0 -266
- package/.agents/skills/autoconverge/workflow/render_report.py +0 -1024
- package/.agents/skills/autoconverge/workflow/test_aggregate_runs.py +0 -134
- package/.agents/skills/autoconverge/workflow/test_convergence_summary.py +0 -149
- package/.agents/skills/autoconverge/workflow/test_render_report.py +0 -812
- package/.agents/skills/hitl/SKILL.md +0 -45
- package/.agents/skills/pr-cleanup/SKILL.md +0 -140
- package/.agents/skills/pr-cleanup/reference/process-inventory.md +0 -17
- package/.agents/skills/pr-cleanup/reference/task-seeds.md +0 -22
- package/.agents/skills/pr-name-by-capability/SKILL.md +0 -73
- package/.agents/skills/pr-name-by-capability/reference/fetch-commands.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/offense-examples.md +0 -32
- package/.agents/skills/pr-name-by-capability/reference/report-template.md +0 -29
- package/.agents/skills/pr-name-by-capability/reference/rule-checklist.md +0 -38
- package/.agents/skills/pr-name-by-capability/reference/task-seeds.md +0 -10
- package/.agents/skills/pr-plain-language-cleanup/SKILL.md +0 -93
- package/.agents/skills/pr-refinement/SKILL.md +0 -31
- package/.agents/skills/pr-shared-extraction/SKILL.md +0 -177
- package/.agents/skills/pr-shared-extraction/reference/examples.md +0 -46
- package/.agents/skills/pr-shared-extraction/reference/offense-taxonomy.md +0 -100
- package/.agents/skills/pr-small-cl/SKILL.md +0 -52
- package/.agents/skills/pr-title-description/SKILL.md +0 -96
- package/.agents/skills/prototype/SKILL.md +0 -85
- package/.agents/skills/prototype/reference/honest-limitations.md +0 -23
- package/.agents/skills/prototype/reference/promotion-tasks.md +0 -23
- package/.agents/skills/prototype/scripts/build_sandbox_settings.py +0 -249
- package/.agents/skills/prototype/scripts/conftest.py +0 -15
- package/.agents/skills/prototype/scripts/launch_sandbox.py +0 -205
- package/.agents/skills/prototype/scripts/probe_sandbox_safety.py +0 -311
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/__init__.py +0 -1
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +0 -41
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +0 -23
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +0 -45
- package/.agents/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +0 -10
- package/.agents/skills/prototype/scripts/test_build_sandbox_settings.py +0 -275
- package/.agents/skills/prototype/scripts/test_launch_sandbox.py +0 -303
- package/.agents/skills/prototype/scripts/test_probe_sandbox_safety.py +0 -312
- package/.agents/skills/prototype/workflows/promotion.md +0 -25
- package/.agents/skills/prototype/workflows/sandbox.md +0 -35
- package/.agents/skills/rebase/.claude/CLAUDE.md +0 -1
- package/.agents/skills/rebase/AGENTS.md +0 -1
- package/.agents/skills/rebase/SKILL.md +0 -178
- package/.agents/skills/review-router/SKILL.md +0 -51
- package/.agents/skills/review-router/reference/route-policy.json +0 -7
- package/.agents/skills/review-router/reference/task-seeds.md +0 -1
- package/.agents/skills/review-router/scripts/conftest.py +0 -4
- package/.agents/skills/review-router/scripts/review_router.py +0 -50
- package/.agents/skills/review-router/scripts/review_router_cli.py +0 -211
- package/.agents/skills/review-router/scripts/review_router_constants/__init__.py +0 -1
- package/.agents/skills/review-router/scripts/review_router_constants/config/__init__.py +0 -0
- package/.agents/skills/review-router/scripts/review_router_constants/config/constants.py +0 -13
- package/.agents/skills/review-router/scripts/test_review_router.py +0 -23
- package/.agents/skills/review-router/scripts/test_review_router_cli.py +0 -47
- package/.agents/skills/review-tier/SKILL.md +0 -56
- package/.agents/skills/review-tier/reference/task-seeds.md +0 -1
- package/.agents/skills/review-tier/reference/tier-policy.json +0 -9
- package/.agents/skills/review-tier/scripts/conftest.py +0 -4
- package/.agents/skills/review-tier/scripts/review_tier.py +0 -359
- package/.agents/skills/review-tier/scripts/review_tier_constants/__init__.py +0 -1
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/__init__.py +0 -0
- package/.agents/skills/review-tier/scripts/review_tier_constants/config/constants.py +0 -29
- package/.agents/skills/review-tier/scripts/test_generation.py +0 -159
- package/.agents/skills/review-tier/scripts/test_review_tier.py +0 -33
- package/.agents/skills/run-claude-dev-env/SKILL.md +0 -84
- package/.agents/skills/session-log/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-log/AGENTS.md +0 -1
- package/.agents/skills/session-log/SKILL.md +0 -170
- package/.agents/skills/session-log/templates/frontmatter.md +0 -40
- package/.agents/skills/session-tidy/.claude/CLAUDE.md +0 -1
- package/.agents/skills/session-tidy/AGENTS.md +0 -1
- package/.agents/skills/session-tidy/SKILL.md +0 -191
- package/.agents/skills/skill-builder/references/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/references/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/references/delegation-map.md +0 -130
- package/.agents/skills/skill-builder/references/description-field.md +0 -111
- package/.agents/skills/skill-builder/references/deterministic-elements.md +0 -218
- package/.agents/skills/skill-builder/references/progressive-disclosure.md +0 -122
- package/.agents/skills/skill-builder/references/self-audit-checklist.md +0 -126
- package/.agents/skills/skill-builder/references/skill-modularity.md +0 -111
- package/.agents/skills/skill-builder/references/skill-types.md +0 -232
- package/.agents/skills/skill-builder/references/thariq-x-post-skills.json +0 -33
- package/.agents/skills/skill-builder/templates/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/templates/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/templates/gap-analysis.md +0 -87
- package/.agents/skills/skill-builder/workflows/.claude/CLAUDE.md +0 -1
- package/.agents/skills/skill-builder/workflows/AGENTS.md +0 -1
- package/.agents/skills/skill-builder/workflows/improve-skill.md +0 -136
- package/.agents/skills/skill-builder/workflows/new-skill.md +0 -179
- package/.agents/skills/skill-builder/workflows/polish-skill.md +0 -139
- package/.agents/skills/source-command-sr-loop/SKILL.md +0 -82
- package/.agents/skills/update/.claude/CLAUDE.md +0 -1
- package/.agents/skills/update/AGENTS.md +0 -1
- package/.agents/skills/update/SKILL.md +0 -190
- package/_shared/pr-loop/AGENTS.md +0 -1
- package/_shared/pr-loop/CLAUDE.md +0 -1
- package/_shared/pr-loop/audit-contract.md +0 -183
- package/_shared/pr-loop/audit-reply-template.md +0 -151
- package/_shared/pr-loop/code-rules-gate.md +0 -65
- package/_shared/pr-loop/fix-protocol.md +0 -60
- package/_shared/pr-loop/gh-payloads.md +0 -75
- package/_shared/pr-loop/post-audit-thread-contract.md +0 -51
- package/_shared/pr-loop/precatch-rubric.md +0 -66
- package/_shared/pr-loop/preflight-proposal.md +0 -56
- package/_shared/pr-loop/scripts/post_audit_thread.py +0 -1242
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/post_audit_thread_constants.py +0 -199
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread.py +0 -1115
- package/_shared/pr-loop/scripts/tests/test_post_audit_thread_constants.py +0 -129
- package/_shared/pr-loop/state-schema.md +0 -45
- package/_shared/pr-loop/worker-spawn.md +0 -189
- package/hooks/_gh_pr_author_swap_utils.py +0 -1225
- package/hooks/blocking/conventional_pr_title_gate.py +0 -443
- package/hooks/blocking/gh_body_arg_blocker.py +0 -176
- package/hooks/blocking/gh_pr_author_enforcer.py +0 -487
- package/hooks/blocking/gh_pr_author_restore.py +0 -105
- package/hooks/blocking/pr_description_writer_gate.py +0 -256
- package/hooks/blocking/test_conventional_pr_title_gate.py +0 -640
- package/hooks/blocking/test_gh_body_arg_blocker.py +0 -441
- package/hooks/blocking/test_gh_pr_author_enforcer.py +0 -1166
- package/hooks/blocking/test_gh_pr_author_restore.py +0 -513
- package/hooks/blocking/test_gh_pr_author_swap_utils.py +0 -910
- package/hooks/blocking/test_pr_description_writer_gate.py +0 -234
- package/hooks/blocking/test_preflight_check.py +0 -343
- package/hooks/blocking/test_test_preflight_check.py +0 -80
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +0 -322
- package/hooks/blocking/volatile_path_in_post_blocker.py +0 -461
- package/hooks/hooks_constants/conventional_pr_title_gate_constants.py +0 -58
- package/hooks/hooks_constants/gh_pr_author_swap_constants.py +0 -76
- package/hooks/hooks_constants/pr_description_writer_gate_constants.py +0 -73
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +0 -55
- package/hooks/observability/pr_description_writer_spawn_tracker.py +0 -113
- package/hooks/observability/test_pr_description_writer_spawn_tracker.py +0 -150
- package/hooks/session/gh_pr_author_session_cleanup.py +0 -175
- package/hooks/session/test_gh_pr_author_session_cleanup.py +0 -576
- package/hooks/test__gh_pr_author_swap_utils.py +0 -333
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
"""Tests for preflight_worktree against real git working trees."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import importlib.util
|
|
6
|
-
import subprocess
|
|
7
|
-
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
from types import ModuleType
|
|
10
|
-
|
|
11
|
-
import pytest
|
|
12
|
-
|
|
13
|
-
_SCRIPTS_DIR = Path(__file__).resolve().parent
|
|
14
|
-
if str(_SCRIPTS_DIR) not in sys.path:
|
|
15
|
-
sys.path.insert(0, str(_SCRIPTS_DIR))
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def _load_preflight() -> ModuleType:
|
|
19
|
-
module_path = _SCRIPTS_DIR / "preflight_worktree.py"
|
|
20
|
-
spec = importlib.util.spec_from_file_location("preflight_worktree", module_path)
|
|
21
|
-
assert spec is not None
|
|
22
|
-
assert spec.loader is not None
|
|
23
|
-
module = importlib.util.module_from_spec(spec)
|
|
24
|
-
sys.modules["preflight_worktree"] = module
|
|
25
|
-
spec.loader.exec_module(module)
|
|
26
|
-
return module
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
preflight = _load_preflight()
|
|
30
|
-
|
|
31
|
-
GIT_TIMEOUT = 30
|
|
32
|
-
CLAUDE_REMOTE = "https://github.com/jl-cmd/claude-dev-env.git"
|
|
33
|
-
GIT_CEILING_DIRECTORIES = "GIT_CEILING_DIRECTORIES"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@pytest.fixture(autouse=True)
|
|
37
|
-
def _isolate_git_from_ancestor_repos(
|
|
38
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
39
|
-
) -> None:
|
|
40
|
-
monkeypatch.setenv(GIT_CEILING_DIRECTORIES, str(tmp_path))
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def _git(repo_dir: Path, *args: str) -> None:
|
|
44
|
-
subprocess.run(
|
|
45
|
-
["git", "-C", str(repo_dir), *args],
|
|
46
|
-
check=True,
|
|
47
|
-
capture_output=True,
|
|
48
|
-
text=True,
|
|
49
|
-
timeout=GIT_TIMEOUT,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def _init_repo(repo_dir: Path, origin_url: str | None) -> Path:
|
|
54
|
-
repo_dir.mkdir(parents=True, exist_ok=True)
|
|
55
|
-
subprocess.run(
|
|
56
|
-
["git", "init", "-q", str(repo_dir)],
|
|
57
|
-
check=True,
|
|
58
|
-
capture_output=True,
|
|
59
|
-
text=True,
|
|
60
|
-
timeout=GIT_TIMEOUT,
|
|
61
|
-
)
|
|
62
|
-
if origin_url is not None:
|
|
63
|
-
_git(repo_dir, "remote", "add", "origin", origin_url)
|
|
64
|
-
return repo_dir
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@pytest.mark.parametrize(
|
|
68
|
-
("remote_url", "expected_owner", "expected_repo"),
|
|
69
|
-
[
|
|
70
|
-
(
|
|
71
|
-
"https://github.com/jl-cmd/claude-dev-env.git",
|
|
72
|
-
"jl-cmd",
|
|
73
|
-
"claude-dev-env",
|
|
74
|
-
),
|
|
75
|
-
(
|
|
76
|
-
"https://github.com/jl-cmd/claude-dev-env",
|
|
77
|
-
"jl-cmd",
|
|
78
|
-
"claude-dev-env",
|
|
79
|
-
),
|
|
80
|
-
("git@github.com:Example/llm-settings.git", "example", "llm-settings"),
|
|
81
|
-
(
|
|
82
|
-
"ssh://git@github.com/jl-cmd/Claude-Dev-Env",
|
|
83
|
-
"jl-cmd",
|
|
84
|
-
"claude-dev-env",
|
|
85
|
-
),
|
|
86
|
-
("https://github.com/jl-cmd/repo/", "jl-cmd", "repo"),
|
|
87
|
-
],
|
|
88
|
-
)
|
|
89
|
-
def test_parse_repo_identity_accepts_every_github_remote_form(
|
|
90
|
-
remote_url: str, expected_owner: str, expected_repo: str
|
|
91
|
-
) -> None:
|
|
92
|
-
identity = preflight.parse_repo_identity(remote_url)
|
|
93
|
-
assert identity is not None
|
|
94
|
-
assert identity.owner == expected_owner
|
|
95
|
-
assert identity.repo == expected_repo
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@pytest.mark.parametrize(
|
|
99
|
-
"remote_url",
|
|
100
|
-
["https://gitlab.com/foo/bar.git", "", "not-a-url"],
|
|
101
|
-
)
|
|
102
|
-
def test_parse_repo_identity_rejects_non_github_remotes(remote_url: str) -> None:
|
|
103
|
-
assert preflight.parse_repo_identity(remote_url) is None
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def test_is_inside_work_tree_true_in_git_repo(tmp_path: Path) -> None:
|
|
107
|
-
repo_dir = _init_repo(tmp_path / "session", None)
|
|
108
|
-
assert preflight.is_inside_work_tree(repo_dir) is True
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def test_is_inside_work_tree_false_in_plain_directory(tmp_path: Path) -> None:
|
|
112
|
-
plain_dir = tmp_path / "home"
|
|
113
|
-
plain_dir.mkdir()
|
|
114
|
-
assert preflight.is_inside_work_tree(plain_dir) is False
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def test_worktree_machinery_is_healthy_true_in_git_repo(tmp_path: Path) -> None:
|
|
118
|
-
repo_dir = _init_repo(tmp_path / "session", None)
|
|
119
|
-
assert preflight.worktree_machinery_is_healthy(repo_dir) is True
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def test_worktree_machinery_is_healthy_false_in_plain_directory(
|
|
123
|
-
tmp_path: Path,
|
|
124
|
-
) -> None:
|
|
125
|
-
plain_dir = tmp_path / "home"
|
|
126
|
-
plain_dir.mkdir()
|
|
127
|
-
assert preflight.worktree_machinery_is_healthy(plain_dir) is False
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
def test_classify_same_repo_when_origin_matches_pr(tmp_path: Path) -> None:
|
|
131
|
-
repo_dir = _init_repo(tmp_path / "session", CLAUDE_REMOTE)
|
|
132
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
133
|
-
verdict = preflight.classify_environment(repo_dir, pr_identity)
|
|
134
|
-
assert verdict.outcome == preflight.OUTCOME_SAME_REPO
|
|
135
|
-
assert verdict.cwd_identity == pr_identity
|
|
136
|
-
assert verdict.has_healthy_worktree_machinery is True
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def test_classify_different_repo_when_origin_is_another_github_repo(
|
|
140
|
-
tmp_path: Path,
|
|
141
|
-
) -> None:
|
|
142
|
-
repo_dir = _init_repo(
|
|
143
|
-
tmp_path / "session", "https://github.com/example/llm-settings.git"
|
|
144
|
-
)
|
|
145
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
146
|
-
verdict = preflight.classify_environment(repo_dir, pr_identity)
|
|
147
|
-
assert verdict.outcome == preflight.OUTCOME_DIFFERENT_REPO
|
|
148
|
-
assert verdict.cwd_identity == preflight.RepoIdentity("example", "llm-settings")
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
def test_classify_different_repo_when_origin_is_non_github(tmp_path: Path) -> None:
|
|
152
|
-
repo_dir = _init_repo(tmp_path / "session", "https://gitlab.com/foo/bar.git")
|
|
153
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
154
|
-
verdict = preflight.classify_environment(repo_dir, pr_identity)
|
|
155
|
-
assert verdict.outcome == preflight.OUTCOME_DIFFERENT_REPO
|
|
156
|
-
assert verdict.cwd_identity is None
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def test_classify_re_rooted_when_origin_is_absent(tmp_path: Path) -> None:
|
|
160
|
-
repo_dir = _init_repo(tmp_path / "session", None)
|
|
161
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
162
|
-
verdict = preflight.classify_environment(repo_dir, pr_identity)
|
|
163
|
-
assert verdict.outcome == preflight.OUTCOME_RE_ROOTED
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
def test_classify_re_rooted_when_directory_is_not_a_work_tree(
|
|
167
|
-
tmp_path: Path,
|
|
168
|
-
) -> None:
|
|
169
|
-
plain_dir = tmp_path / "home"
|
|
170
|
-
plain_dir.mkdir()
|
|
171
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
172
|
-
verdict = preflight.classify_environment(plain_dir, pr_identity)
|
|
173
|
-
assert verdict.outcome == preflight.OUTCOME_RE_ROOTED
|
|
174
|
-
assert verdict.has_healthy_worktree_machinery is False
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
@pytest.mark.parametrize(
|
|
178
|
-
("outcome", "is_healthy", "mode", "expected_exit"),
|
|
179
|
-
[
|
|
180
|
-
("same_repo", True, "strict", 0),
|
|
181
|
-
("same_repo", True, "classify", 0),
|
|
182
|
-
("same_repo", False, "strict", 1),
|
|
183
|
-
("same_repo", False, "classify", 1),
|
|
184
|
-
("different_repo", True, "strict", 1),
|
|
185
|
-
("different_repo", True, "classify", 0),
|
|
186
|
-
("re_rooted", False, "strict", 1),
|
|
187
|
-
("re_rooted", False, "classify", 1),
|
|
188
|
-
],
|
|
189
|
-
)
|
|
190
|
-
def test_decide_exit_code_matrix(
|
|
191
|
-
outcome: str, is_healthy: bool, mode: str, expected_exit: int
|
|
192
|
-
) -> None:
|
|
193
|
-
verdict = preflight.PreflightVerdict(
|
|
194
|
-
outcome=outcome,
|
|
195
|
-
cwd_identity=None,
|
|
196
|
-
has_healthy_worktree_machinery=is_healthy,
|
|
197
|
-
)
|
|
198
|
-
assert preflight.decide_exit_code(verdict, mode) == expected_exit
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
def test_build_report_lines_marks_outcome_and_routes_cross_repo() -> None:
|
|
202
|
-
verdict = preflight.PreflightVerdict(
|
|
203
|
-
outcome=preflight.OUTCOME_DIFFERENT_REPO,
|
|
204
|
-
cwd_identity=preflight.RepoIdentity("example", "llm-settings"),
|
|
205
|
-
has_healthy_worktree_machinery=True,
|
|
206
|
-
)
|
|
207
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
208
|
-
classify_lines = preflight.build_report_lines(
|
|
209
|
-
verdict, "classify", Path("/tmp/x"), pr_identity
|
|
210
|
-
)
|
|
211
|
-
assert classify_lines[0] == "PREFLIGHT_OUTCOME=different_repo"
|
|
212
|
-
assert any("ROUTE" in line for line in classify_lines)
|
|
213
|
-
strict_lines = preflight.build_report_lines(
|
|
214
|
-
verdict, "strict", Path("/tmp/x"), pr_identity
|
|
215
|
-
)
|
|
216
|
-
assert any("ABORT" in line for line in strict_lines)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def test_build_report_lines_aborts_on_broken_worktree_machinery() -> None:
|
|
220
|
-
verdict = preflight.PreflightVerdict(
|
|
221
|
-
outcome=preflight.OUTCOME_SAME_REPO,
|
|
222
|
-
cwd_identity=preflight.RepoIdentity("jl-cmd", "claude-dev-env"),
|
|
223
|
-
has_healthy_worktree_machinery=False,
|
|
224
|
-
)
|
|
225
|
-
pr_identity = preflight.RepoIdentity("jl-cmd", "claude-dev-env")
|
|
226
|
-
lines = preflight.build_report_lines(verdict, "strict", Path("/tmp/x"), pr_identity)
|
|
227
|
-
assert lines[0] == "PREFLIGHT_OUTCOME=same_repo"
|
|
228
|
-
assert any("git worktree prune" in line for line in lines)
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def test_main_strict_passes_in_matching_repo(
|
|
232
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
233
|
-
) -> None:
|
|
234
|
-
repo_dir = _init_repo(tmp_path / "session", CLAUDE_REMOTE)
|
|
235
|
-
monkeypatch.chdir(repo_dir)
|
|
236
|
-
exit_code = preflight.main(
|
|
237
|
-
["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "strict"]
|
|
238
|
-
)
|
|
239
|
-
captured = capsys.readouterr()
|
|
240
|
-
assert exit_code == preflight.EXIT_PREFLIGHT_OK
|
|
241
|
-
assert "PREFLIGHT_OUTCOME=same_repo" in captured.out
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def test_main_strict_aborts_when_session_rooted_in_other_repo(
|
|
245
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
246
|
-
) -> None:
|
|
247
|
-
repo_dir = _init_repo(
|
|
248
|
-
tmp_path / "session", "https://github.com/example/llm-settings.git"
|
|
249
|
-
)
|
|
250
|
-
monkeypatch.chdir(repo_dir)
|
|
251
|
-
exit_code = preflight.main(
|
|
252
|
-
["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "strict"]
|
|
253
|
-
)
|
|
254
|
-
captured = capsys.readouterr()
|
|
255
|
-
assert exit_code == preflight.EXIT_PREFLIGHT_ABORT
|
|
256
|
-
assert "PREFLIGHT_OUTCOME=different_repo" in captured.out
|
|
257
|
-
assert "ABORT" in captured.out
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
def test_main_classify_routes_cross_repo_without_abort(
|
|
261
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
262
|
-
) -> None:
|
|
263
|
-
repo_dir = _init_repo(
|
|
264
|
-
tmp_path / "session", "https://github.com/example/llm-settings.git"
|
|
265
|
-
)
|
|
266
|
-
monkeypatch.chdir(repo_dir)
|
|
267
|
-
exit_code = preflight.main(
|
|
268
|
-
["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "classify"]
|
|
269
|
-
)
|
|
270
|
-
captured = capsys.readouterr()
|
|
271
|
-
assert exit_code == preflight.EXIT_PREFLIGHT_OK
|
|
272
|
-
assert "PREFLIGHT_OUTCOME=different_repo" in captured.out
|
|
273
|
-
assert "ROUTE" in captured.out
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def test_main_classify_aborts_when_re_rooted(
|
|
277
|
-
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
278
|
-
) -> None:
|
|
279
|
-
plain_dir = tmp_path / "home"
|
|
280
|
-
plain_dir.mkdir()
|
|
281
|
-
monkeypatch.chdir(plain_dir)
|
|
282
|
-
exit_code = preflight.main(
|
|
283
|
-
["--owner", "jl-cmd", "--repo", "claude-dev-env", "--mode", "classify"]
|
|
284
|
-
)
|
|
285
|
-
captured = capsys.readouterr()
|
|
286
|
-
assert exit_code == preflight.EXIT_PREFLIGHT_ABORT
|
|
287
|
-
assert "PREFLIGHT_OUTCOME=re_rooted" in captured.out
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
"""Tests for select_converge_pacer — host tool surface → pacer mapping."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import subprocess
|
|
7
|
-
import sys
|
|
8
|
-
from pathlib import Path
|
|
9
|
-
|
|
10
|
-
import pytest
|
|
11
|
-
|
|
12
|
-
_SCRIPTS_DIR = Path(__file__).resolve().parent
|
|
13
|
-
if str(_SCRIPTS_DIR) not in sys.path:
|
|
14
|
-
sys.path.insert(0, str(_SCRIPTS_DIR))
|
|
15
|
-
|
|
16
|
-
import select_converge_pacer as pacer_module # noqa: E402
|
|
17
|
-
from skills_pr_loop_constants.pacer_constants import ( # noqa: E402
|
|
18
|
-
CLI_HAS_SCHEDULE_WAKEUP_FLAG,
|
|
19
|
-
CLI_HAS_WORKFLOW_FLAG,
|
|
20
|
-
CLI_SKILL_FLAG,
|
|
21
|
-
ENTRY_SKILL_AUTOCONVERGE,
|
|
22
|
-
ENTRY_SKILL_PR_CONVERGE,
|
|
23
|
-
EXIT_SUCCESS,
|
|
24
|
-
EXIT_USAGE_ERROR,
|
|
25
|
-
PACER_PORTABLE,
|
|
26
|
-
PACER_SCHEDULE_WAKEUP,
|
|
27
|
-
PACER_WORKFLOW,
|
|
28
|
-
RESULT_KEY_ENTRY_SKILL,
|
|
29
|
-
RESULT_KEY_HAS_SCHEDULE_WAKEUP,
|
|
30
|
-
RESULT_KEY_HAS_WORKFLOW,
|
|
31
|
-
RESULT_KEY_PACER,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
SCRIPT_PATH = _SCRIPTS_DIR / "select_converge_pacer.py"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def test_autoconverge_with_workflow_selects_workflow() -> None:
|
|
38
|
-
selection = pacer_module.select_converge_pacer(
|
|
39
|
-
entry_skill=ENTRY_SKILL_AUTOCONVERGE,
|
|
40
|
-
has_workflow=True,
|
|
41
|
-
has_schedule_wakeup=False,
|
|
42
|
-
)
|
|
43
|
-
assert selection.pacer == PACER_WORKFLOW
|
|
44
|
-
assert selection.entry_skill == ENTRY_SKILL_AUTOCONVERGE
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def test_autoconverge_without_workflow_selects_portable() -> None:
|
|
48
|
-
selection = pacer_module.select_converge_pacer(
|
|
49
|
-
entry_skill=ENTRY_SKILL_AUTOCONVERGE,
|
|
50
|
-
has_workflow=False,
|
|
51
|
-
has_schedule_wakeup=True,
|
|
52
|
-
)
|
|
53
|
-
assert selection.pacer == PACER_PORTABLE
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def test_pr_converge_with_schedule_wakeup_selects_schedule_wakeup() -> None:
|
|
57
|
-
selection = pacer_module.select_converge_pacer(
|
|
58
|
-
entry_skill=ENTRY_SKILL_PR_CONVERGE,
|
|
59
|
-
has_workflow=False,
|
|
60
|
-
has_schedule_wakeup=True,
|
|
61
|
-
)
|
|
62
|
-
assert selection.pacer == PACER_SCHEDULE_WAKEUP
|
|
63
|
-
assert selection.entry_skill == ENTRY_SKILL_PR_CONVERGE
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def test_pr_converge_without_schedule_wakeup_selects_portable() -> None:
|
|
67
|
-
selection = pacer_module.select_converge_pacer(
|
|
68
|
-
entry_skill=ENTRY_SKILL_PR_CONVERGE,
|
|
69
|
-
has_workflow=True,
|
|
70
|
-
has_schedule_wakeup=False,
|
|
71
|
-
)
|
|
72
|
-
assert selection.pacer == PACER_PORTABLE
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def test_third_party_surface_selects_portable_for_both_entries() -> None:
|
|
76
|
-
for each_skill in (ENTRY_SKILL_AUTOCONVERGE, ENTRY_SKILL_PR_CONVERGE):
|
|
77
|
-
selection = pacer_module.select_converge_pacer(
|
|
78
|
-
entry_skill=each_skill,
|
|
79
|
-
has_workflow=False,
|
|
80
|
-
has_schedule_wakeup=False,
|
|
81
|
-
)
|
|
82
|
-
assert selection.pacer == PACER_PORTABLE, each_skill
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def test_unknown_entry_skill_raises() -> None:
|
|
86
|
-
with pytest.raises(ValueError, match="entry skill must be one of"):
|
|
87
|
-
pacer_module.select_converge_pacer(
|
|
88
|
-
entry_skill="bugteam",
|
|
89
|
-
has_workflow=False,
|
|
90
|
-
has_schedule_wakeup=False,
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def test_parse_bool_flag_accepts_common_tokens() -> None:
|
|
95
|
-
assert pacer_module.parse_bool_flag("1") is True
|
|
96
|
-
assert pacer_module.parse_bool_flag("true") is True
|
|
97
|
-
assert pacer_module.parse_bool_flag("YES") is True
|
|
98
|
-
assert pacer_module.parse_bool_flag("0") is False
|
|
99
|
-
assert pacer_module.parse_bool_flag("false") is False
|
|
100
|
-
assert pacer_module.parse_bool_flag("OFF") is False
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def test_parse_bool_flag_rejects_unknown_token() -> None:
|
|
104
|
-
with pytest.raises(ValueError, match="boolean token"):
|
|
105
|
-
pacer_module.parse_bool_flag("maybe")
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def test_selection_as_json_dict_uses_stable_keys() -> None:
|
|
109
|
-
selection = pacer_module.select_converge_pacer(
|
|
110
|
-
entry_skill=ENTRY_SKILL_PR_CONVERGE,
|
|
111
|
-
has_workflow=False,
|
|
112
|
-
has_schedule_wakeup=False,
|
|
113
|
-
)
|
|
114
|
-
payload = pacer_module.selection_as_json_dict(selection)
|
|
115
|
-
assert payload[RESULT_KEY_PACER] == PACER_PORTABLE
|
|
116
|
-
assert payload[RESULT_KEY_ENTRY_SKILL] == ENTRY_SKILL_PR_CONVERGE
|
|
117
|
-
assert payload[RESULT_KEY_HAS_WORKFLOW] is False
|
|
118
|
-
assert payload[RESULT_KEY_HAS_SCHEDULE_WAKEUP] is False
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def test_cli_prints_json_and_exits_zero() -> None:
|
|
122
|
-
completed = subprocess.run(
|
|
123
|
-
[
|
|
124
|
-
sys.executable,
|
|
125
|
-
str(SCRIPT_PATH),
|
|
126
|
-
"--skill",
|
|
127
|
-
ENTRY_SKILL_AUTOCONVERGE,
|
|
128
|
-
"--has-workflow",
|
|
129
|
-
"0",
|
|
130
|
-
"--has-schedule-wakeup",
|
|
131
|
-
"0",
|
|
132
|
-
],
|
|
133
|
-
check=False,
|
|
134
|
-
capture_output=True,
|
|
135
|
-
text=True,
|
|
136
|
-
)
|
|
137
|
-
assert completed.returncode == EXIT_SUCCESS, completed.stderr
|
|
138
|
-
payload = json.loads(completed.stdout)
|
|
139
|
-
assert payload[RESULT_KEY_PACER] == PACER_PORTABLE
|
|
140
|
-
assert payload[RESULT_KEY_ENTRY_SKILL] == ENTRY_SKILL_AUTOCONVERGE
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
def test_cli_rejects_bad_bool_with_usage_exit() -> None:
|
|
144
|
-
completed = subprocess.run(
|
|
145
|
-
[
|
|
146
|
-
sys.executable,
|
|
147
|
-
str(SCRIPT_PATH),
|
|
148
|
-
"--skill",
|
|
149
|
-
ENTRY_SKILL_PR_CONVERGE,
|
|
150
|
-
"--has-workflow",
|
|
151
|
-
"nope",
|
|
152
|
-
"--has-schedule-wakeup",
|
|
153
|
-
"0",
|
|
154
|
-
],
|
|
155
|
-
check=False,
|
|
156
|
-
capture_output=True,
|
|
157
|
-
text=True,
|
|
158
|
-
)
|
|
159
|
-
assert completed.returncode == EXIT_USAGE_ERROR
|
|
160
|
-
assert "boolean token" in completed.stderr
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def test_main_returns_usage_error_on_value_error(
|
|
164
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
165
|
-
) -> None:
|
|
166
|
-
def raise_value_error(**_kwargs: object) -> object:
|
|
167
|
-
raise ValueError("entry skill must be one of")
|
|
168
|
-
|
|
169
|
-
monkeypatch.setattr(
|
|
170
|
-
pacer_module, "select_converge_pacer", raise_value_error
|
|
171
|
-
)
|
|
172
|
-
exit_code = pacer_module.main(
|
|
173
|
-
[
|
|
174
|
-
"--skill",
|
|
175
|
-
ENTRY_SKILL_PR_CONVERGE,
|
|
176
|
-
"--has-workflow",
|
|
177
|
-
"0",
|
|
178
|
-
"--has-schedule-wakeup",
|
|
179
|
-
"0",
|
|
180
|
-
]
|
|
181
|
-
)
|
|
182
|
-
assert exit_code == EXIT_USAGE_ERROR
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def test_build_argument_parser_requires_skill_and_host_flags() -> None:
|
|
186
|
-
parser = pacer_module.build_argument_parser()
|
|
187
|
-
all_option_strings = {
|
|
188
|
-
each_option
|
|
189
|
-
for each_action in parser._actions
|
|
190
|
-
for each_option in each_action.option_strings
|
|
191
|
-
}
|
|
192
|
-
assert CLI_SKILL_FLAG in all_option_strings
|
|
193
|
-
assert CLI_HAS_WORKFLOW_FLAG in all_option_strings
|
|
194
|
-
assert CLI_HAS_SCHEDULE_WAKEUP_FLAG in all_option_strings
|
|
195
|
-
parsed_namespace = parser.parse_args(
|
|
196
|
-
[
|
|
197
|
-
CLI_SKILL_FLAG,
|
|
198
|
-
ENTRY_SKILL_AUTOCONVERGE,
|
|
199
|
-
CLI_HAS_WORKFLOW_FLAG,
|
|
200
|
-
"1",
|
|
201
|
-
CLI_HAS_SCHEDULE_WAKEUP_FLAG,
|
|
202
|
-
"0",
|
|
203
|
-
]
|
|
204
|
-
)
|
|
205
|
-
assert parsed_namespace.skill == ENTRY_SKILL_AUTOCONVERGE
|
|
206
|
-
assert parsed_namespace.has_workflow == "1"
|
|
207
|
-
assert parsed_namespace.has_schedule_wakeup == "0"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
"""Tests for teardown_worktrees.teardown_run consuming the typed workspace."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import importlib.util
|
|
6
|
-
import sys
|
|
7
|
-
from pathlib import Path
|
|
8
|
-
from types import ModuleType
|
|
9
|
-
|
|
10
|
-
_SCRIPTS_DIR = Path(__file__).resolve().parent
|
|
11
|
-
if str(_SCRIPTS_DIR) not in sys.path:
|
|
12
|
-
sys.path.insert(0, str(_SCRIPTS_DIR))
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def _load_teardown_module() -> ModuleType:
|
|
16
|
-
module_path = _SCRIPTS_DIR / "teardown_worktrees.py"
|
|
17
|
-
spec = importlib.util.spec_from_file_location("teardown_worktrees", module_path)
|
|
18
|
-
assert spec is not None
|
|
19
|
-
assert spec.loader is not None
|
|
20
|
-
module = importlib.util.module_from_spec(spec)
|
|
21
|
-
spec.loader.exec_module(module)
|
|
22
|
-
return module
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
teardown_worktrees = _load_teardown_module()
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def test_teardown_run_returns_zero_when_no_worktrees_exist(tmp_path: Path) -> None:
|
|
29
|
-
"""With absent worktrees, teardown_run removes nothing and reports zero,
|
|
30
|
-
reading each worktree path from the typed PerPrWorkspace.worktree attribute
|
|
31
|
-
rather than a dict lookup."""
|
|
32
|
-
run_temp_dir = tmp_path / "run"
|
|
33
|
-
run_temp_dir.mkdir()
|
|
34
|
-
all_pr_entries: list[dict[str, object]] = [
|
|
35
|
-
{"number": 7, "owner": "owner", "repo": "repo"},
|
|
36
|
-
]
|
|
37
|
-
removed_count = teardown_worktrees.teardown_run(
|
|
38
|
-
run_temp_dir=run_temp_dir,
|
|
39
|
-
all_pr_entries=all_pr_entries,
|
|
40
|
-
)
|
|
41
|
-
assert removed_count == 0
|
|
42
|
-
assert not run_temp_dir.exists()
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def test_teardown_run_skips_entries_without_integer_number(tmp_path: Path) -> None:
|
|
46
|
-
"""A PR entry whose number is not an integer is skipped before any workspace
|
|
47
|
-
resolution, so teardown_run reports zero removals and still clears the run
|
|
48
|
-
temp directory."""
|
|
49
|
-
run_temp_dir = tmp_path / "run"
|
|
50
|
-
run_temp_dir.mkdir()
|
|
51
|
-
all_pr_entries: list[dict[str, object]] = [
|
|
52
|
-
{"number": "not-an-int", "owner": "owner", "repo": "repo"},
|
|
53
|
-
]
|
|
54
|
-
removed_count = teardown_worktrees.teardown_run(
|
|
55
|
-
run_temp_dir=run_temp_dir,
|
|
56
|
-
all_pr_entries=all_pr_entries,
|
|
57
|
-
)
|
|
58
|
-
assert removed_count == 0
|
|
59
|
-
assert not run_temp_dir.exists()
|