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,355 +0,0 @@
|
|
|
1
|
-
"""Load and validate the A-Q audit-category schema.
|
|
2
|
-
|
|
3
|
-
One machine-readable source under audit-rubrics/audit-categories.json holds
|
|
4
|
-
each category id, title, slug, and sub-bucket id/axis pairs. Worked examples
|
|
5
|
-
stay in the rubric markdown files only.
|
|
6
|
-
|
|
7
|
-
::
|
|
8
|
-
|
|
9
|
-
schema = load_audit_category_schema()
|
|
10
|
-
entries = category_id_title_entries()
|
|
11
|
-
# entries[0] == ("A", "API contract verification")
|
|
12
|
-
findings = validate_projections()
|
|
13
|
-
# findings == [] when rubrics and prompt skeletons match the schema
|
|
14
|
-
|
|
15
|
-
Use validate_projections before shipping a rubric or prompt change so the
|
|
16
|
-
three surfaces cannot drift.
|
|
17
|
-
"""
|
|
18
|
-
|
|
19
|
-
from __future__ import annotations
|
|
20
|
-
|
|
21
|
-
import argparse
|
|
22
|
-
import json
|
|
23
|
-
import re
|
|
24
|
-
import sys
|
|
25
|
-
from pathlib import Path
|
|
26
|
-
|
|
27
|
-
from skills_pr_loop_constants.audit_category_schema_constants import (
|
|
28
|
-
CATEGORY_ID_KEY,
|
|
29
|
-
CATEGORY_RUBRICS_DIRECTORY,
|
|
30
|
-
CATEGORY_SLUG_KEY,
|
|
31
|
-
CATEGORY_SLUG_PREFIX_TEMPLATE,
|
|
32
|
-
CATEGORY_SUB_BUCKETS_KEY,
|
|
33
|
-
CATEGORY_TITLE_KEY,
|
|
34
|
-
EXPECTED_CATEGORY_IDS,
|
|
35
|
-
HEADING_LETTER_GROUP,
|
|
36
|
-
HEADING_PATTERN,
|
|
37
|
-
HEADING_TITLE_GROUP,
|
|
38
|
-
JSON_INDENT,
|
|
39
|
-
NEWLINE,
|
|
40
|
-
PACKAGE_ROOT,
|
|
41
|
-
PROMPTS_DIRECTORY,
|
|
42
|
-
RUBRIC_SUB_BUCKET_ROW_TEMPLATE,
|
|
43
|
-
SCHEMA_CATEGORIES_KEY,
|
|
44
|
-
SCHEMA_RELATIVE_PATH,
|
|
45
|
-
SCHEMA_VERSION,
|
|
46
|
-
SCHEMA_VERSION_KEY,
|
|
47
|
-
SKELETON_COUNT_PATTERN,
|
|
48
|
-
SKELETON_PLACEHOLDER_FRAGMENT,
|
|
49
|
-
SKELETON_SEPARATOR_LINE,
|
|
50
|
-
SUB_BUCKET_AXIS_KEY,
|
|
51
|
-
UTF8_ENCODING,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
CategoryMapping = dict[str, object]
|
|
55
|
-
SchemaMapping = dict[str, object]
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def audit_category_schema_path() -> Path:
|
|
59
|
-
"""Return the path to the committed A-Q schema JSON file.
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
Absolute path to audit-categories.json under the package root.
|
|
63
|
-
"""
|
|
64
|
-
return PACKAGE_ROOT / SCHEMA_RELATIVE_PATH
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def load_audit_category_schema() -> SchemaMapping:
|
|
68
|
-
"""Load and structurally check the A-Q schema document.
|
|
69
|
-
|
|
70
|
-
Returns:
|
|
71
|
-
The schema object with schema_version and categories.
|
|
72
|
-
|
|
73
|
-
Raises:
|
|
74
|
-
FileNotFoundError: When the schema file is missing.
|
|
75
|
-
ValueError: When required fields or order are wrong.
|
|
76
|
-
json.JSONDecodeError: When the schema file is not valid JSON.
|
|
77
|
-
"""
|
|
78
|
-
schema_path = audit_category_schema_path()
|
|
79
|
-
loaded_document = json.loads(schema_path.read_text(encoding=UTF8_ENCODING))
|
|
80
|
-
if not isinstance(loaded_document, dict):
|
|
81
|
-
raise ValueError("schema root must be an object")
|
|
82
|
-
if loaded_document.get(SCHEMA_VERSION_KEY) != SCHEMA_VERSION:
|
|
83
|
-
raise ValueError(
|
|
84
|
-
f"schema_version must be {SCHEMA_VERSION}, "
|
|
85
|
-
f"got {loaded_document.get(SCHEMA_VERSION_KEY)!r}"
|
|
86
|
-
)
|
|
87
|
-
all_categories = loaded_document.get(SCHEMA_CATEGORIES_KEY)
|
|
88
|
-
if not isinstance(all_categories, list) or not all_categories:
|
|
89
|
-
raise ValueError("categories must be a non-empty list")
|
|
90
|
-
all_ids = [
|
|
91
|
-
each_category.get(CATEGORY_ID_KEY)
|
|
92
|
-
for each_category in all_categories
|
|
93
|
-
if isinstance(each_category, dict)
|
|
94
|
-
]
|
|
95
|
-
if all_ids != list(EXPECTED_CATEGORY_IDS):
|
|
96
|
-
raise ValueError(f"categories must list A-Q in order, got {all_ids!r}")
|
|
97
|
-
all_checked_categories: list[CategoryMapping] = []
|
|
98
|
-
for each_category in all_categories:
|
|
99
|
-
if not isinstance(each_category, dict):
|
|
100
|
-
raise ValueError("each category must be an object")
|
|
101
|
-
all_checked_categories.append(_require_category_shape(each_category))
|
|
102
|
-
return {
|
|
103
|
-
SCHEMA_VERSION_KEY: SCHEMA_VERSION,
|
|
104
|
-
SCHEMA_CATEGORIES_KEY: all_checked_categories,
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def _require_category_shape(all_category_fields: CategoryMapping) -> CategoryMapping:
|
|
109
|
-
category_id = all_category_fields.get(CATEGORY_ID_KEY)
|
|
110
|
-
if not isinstance(category_id, str) or len(category_id) != 1:
|
|
111
|
-
raise ValueError(f"category id must be a single letter, got {category_id!r}")
|
|
112
|
-
title = all_category_fields.get(CATEGORY_TITLE_KEY)
|
|
113
|
-
if not isinstance(title, str) or not title.strip():
|
|
114
|
-
raise ValueError(f"category {category_id} title must be a non-empty string")
|
|
115
|
-
slug = all_category_fields.get(CATEGORY_SLUG_KEY)
|
|
116
|
-
expected_slug_prefix = CATEGORY_SLUG_PREFIX_TEMPLATE.format(letter=category_id.lower())
|
|
117
|
-
if not isinstance(slug, str) or not slug.startswith(expected_slug_prefix):
|
|
118
|
-
raise ValueError(
|
|
119
|
-
f"category {category_id} slug must start with {expected_slug_prefix!r}, "
|
|
120
|
-
f"got {slug!r}"
|
|
121
|
-
)
|
|
122
|
-
all_sub_bucket_fields = all_category_fields.get(CATEGORY_SUB_BUCKETS_KEY)
|
|
123
|
-
if not isinstance(all_sub_bucket_fields, list) or not all_sub_bucket_fields:
|
|
124
|
-
raise ValueError(f"category {category_id} needs a non-empty sub_buckets list")
|
|
125
|
-
all_sub_buckets: list[CategoryMapping] = []
|
|
126
|
-
for each_index, each_sub_bucket in enumerate(all_sub_bucket_fields):
|
|
127
|
-
if not isinstance(each_sub_bucket, dict):
|
|
128
|
-
raise ValueError(f"category {category_id} sub_bucket {each_index} must be object")
|
|
129
|
-
expected_id = f"{category_id}{each_index + 1}"
|
|
130
|
-
sub_bucket_id = each_sub_bucket.get(CATEGORY_ID_KEY)
|
|
131
|
-
if sub_bucket_id != expected_id:
|
|
132
|
-
raise ValueError(
|
|
133
|
-
f"category {category_id} sub_bucket {each_index} id must be "
|
|
134
|
-
f"{expected_id}, got {sub_bucket_id!r}"
|
|
135
|
-
)
|
|
136
|
-
axis_name = each_sub_bucket.get(SUB_BUCKET_AXIS_KEY)
|
|
137
|
-
if not isinstance(axis_name, str) or not axis_name.strip():
|
|
138
|
-
raise ValueError(
|
|
139
|
-
f"category {category_id} sub_bucket {sub_bucket_id} needs axis_name"
|
|
140
|
-
)
|
|
141
|
-
all_sub_buckets.append(
|
|
142
|
-
{CATEGORY_ID_KEY: expected_id, SUB_BUCKET_AXIS_KEY: axis_name}
|
|
143
|
-
)
|
|
144
|
-
return {
|
|
145
|
-
CATEGORY_ID_KEY: category_id,
|
|
146
|
-
CATEGORY_TITLE_KEY: title,
|
|
147
|
-
CATEGORY_SLUG_KEY: slug,
|
|
148
|
-
CATEGORY_SUB_BUCKETS_KEY: all_sub_buckets,
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def category_id_title_entries() -> list[tuple[str, str]]:
|
|
153
|
-
"""Return (id, title) pairs in A-Q order from the schema.
|
|
154
|
-
|
|
155
|
-
Returns:
|
|
156
|
-
List of (category letter, title) tuples from the schema file.
|
|
157
|
-
"""
|
|
158
|
-
all_schema = load_audit_category_schema()
|
|
159
|
-
all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
|
|
160
|
-
assert isinstance(all_categories, list)
|
|
161
|
-
all_entries: list[tuple[str, str]] = []
|
|
162
|
-
for each_category in all_categories:
|
|
163
|
-
assert isinstance(each_category, dict)
|
|
164
|
-
category_id = each_category[CATEGORY_ID_KEY]
|
|
165
|
-
title = each_category[CATEGORY_TITLE_KEY]
|
|
166
|
-
assert isinstance(category_id, str)
|
|
167
|
-
assert isinstance(title, str)
|
|
168
|
-
all_entries.append((category_id, title))
|
|
169
|
-
return all_entries
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def render_skeleton_projections(all_schema: SchemaMapping) -> dict[str, str]:
|
|
173
|
-
"""Build deterministic skeleton text per category from the schema only.
|
|
174
|
-
|
|
175
|
-
Args:
|
|
176
|
-
all_schema: Loaded audit-category schema.
|
|
177
|
-
|
|
178
|
-
Returns:
|
|
179
|
-
Map of category letter to a stable multi-line skeleton projection.
|
|
180
|
-
"""
|
|
181
|
-
projection_by_letter: dict[str, str] = {}
|
|
182
|
-
all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
|
|
183
|
-
assert isinstance(all_categories, list)
|
|
184
|
-
for each_category in all_categories:
|
|
185
|
-
assert isinstance(each_category, dict)
|
|
186
|
-
category_id = each_category[CATEGORY_ID_KEY]
|
|
187
|
-
title = each_category[CATEGORY_TITLE_KEY]
|
|
188
|
-
slug = each_category[CATEGORY_SLUG_KEY]
|
|
189
|
-
all_sub_buckets = each_category[CATEGORY_SUB_BUCKETS_KEY]
|
|
190
|
-
assert isinstance(category_id, str)
|
|
191
|
-
assert isinstance(title, str)
|
|
192
|
-
assert isinstance(slug, str)
|
|
193
|
-
assert isinstance(all_sub_buckets, list)
|
|
194
|
-
sub_bucket_count = len(all_sub_buckets)
|
|
195
|
-
all_lines = [
|
|
196
|
-
f"Category {category_id} — {title}",
|
|
197
|
-
f"slug: {slug}",
|
|
198
|
-
f"decomposed into {sub_bucket_count} sub-buckets",
|
|
199
|
-
f"For each sub-bucket {category_id}1-{category_id}{sub_bucket_count}:",
|
|
200
|
-
]
|
|
201
|
-
for each_sub_bucket in all_sub_buckets:
|
|
202
|
-
assert isinstance(each_sub_bucket, dict)
|
|
203
|
-
sub_bucket_id = each_sub_bucket[CATEGORY_ID_KEY]
|
|
204
|
-
axis_name = each_sub_bucket[SUB_BUCKET_AXIS_KEY]
|
|
205
|
-
all_lines.append(f"{sub_bucket_id}. {axis_name}")
|
|
206
|
-
projection_by_letter[category_id] = NEWLINE.join(all_lines) + NEWLINE
|
|
207
|
-
return projection_by_letter
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
def _validate_one_category(each_category: CategoryMapping) -> list[str]:
|
|
211
|
-
category_id = each_category[CATEGORY_ID_KEY]
|
|
212
|
-
slug = each_category[CATEGORY_SLUG_KEY]
|
|
213
|
-
title = each_category[CATEGORY_TITLE_KEY]
|
|
214
|
-
all_sub_buckets = each_category[CATEGORY_SUB_BUCKETS_KEY]
|
|
215
|
-
assert isinstance(category_id, str)
|
|
216
|
-
assert isinstance(slug, str)
|
|
217
|
-
assert isinstance(title, str)
|
|
218
|
-
assert isinstance(all_sub_buckets, list)
|
|
219
|
-
all_findings: list[str] = []
|
|
220
|
-
rubric_path = CATEGORY_RUBRICS_DIRECTORY / f"{slug}.md"
|
|
221
|
-
prompt_path = PROMPTS_DIRECTORY / f"{slug}.md"
|
|
222
|
-
if not rubric_path.is_file():
|
|
223
|
-
return [f"{category_id}: missing rubric {rubric_path.name}"]
|
|
224
|
-
if not prompt_path.is_file():
|
|
225
|
-
return [f"{category_id}: missing prompt {prompt_path.name}"]
|
|
226
|
-
rubric_text = rubric_path.read_text(encoding=UTF8_ENCODING)
|
|
227
|
-
all_rubric_lines = rubric_text.splitlines()
|
|
228
|
-
if not all_rubric_lines:
|
|
229
|
-
return [f"{category_id}: empty rubric"]
|
|
230
|
-
heading_match = HEADING_PATTERN.match(all_rubric_lines[0])
|
|
231
|
-
if heading_match is None:
|
|
232
|
-
return [f"{category_id}: rubric heading does not match pattern"]
|
|
233
|
-
heading_letter = heading_match.group(HEADING_LETTER_GROUP)
|
|
234
|
-
heading_title = heading_match.group(HEADING_TITLE_GROUP)
|
|
235
|
-
if heading_letter != category_id:
|
|
236
|
-
all_findings.append(f"{category_id}: rubric heading letter {heading_letter!r}")
|
|
237
|
-
if heading_title != title:
|
|
238
|
-
all_findings.append(
|
|
239
|
-
f"{category_id}: rubric title {heading_title!r} != schema {title!r}"
|
|
240
|
-
)
|
|
241
|
-
row_pattern = re.compile(
|
|
242
|
-
RUBRIC_SUB_BUCKET_ROW_TEMPLATE.format(category_id=re.escape(category_id)),
|
|
243
|
-
re.MULTILINE,
|
|
244
|
-
)
|
|
245
|
-
all_rubric_rows = row_pattern.findall(rubric_text)
|
|
246
|
-
all_schema_rows: list[tuple[str, str]] = []
|
|
247
|
-
for each_sub_bucket in all_sub_buckets:
|
|
248
|
-
assert isinstance(each_sub_bucket, dict)
|
|
249
|
-
sub_bucket_id = each_sub_bucket[CATEGORY_ID_KEY]
|
|
250
|
-
axis_name = each_sub_bucket[SUB_BUCKET_AXIS_KEY]
|
|
251
|
-
assert isinstance(sub_bucket_id, str)
|
|
252
|
-
assert isinstance(axis_name, str)
|
|
253
|
-
all_schema_rows.append((sub_bucket_id, axis_name))
|
|
254
|
-
all_rubric_pairs = [(row_id, axis.strip()) for row_id, axis in all_rubric_rows]
|
|
255
|
-
if all_rubric_pairs != all_schema_rows:
|
|
256
|
-
all_findings.append(
|
|
257
|
-
f"{category_id}: rubric sub-buckets {all_rubric_pairs!r} "
|
|
258
|
-
f"!= schema {all_schema_rows!r}"
|
|
259
|
-
)
|
|
260
|
-
all_findings.extend(
|
|
261
|
-
_validate_prompt_skeleton_count(category_id, prompt_path, len(all_sub_buckets))
|
|
262
|
-
)
|
|
263
|
-
return all_findings
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
def _validate_prompt_skeleton_count(
|
|
267
|
-
category_id: str,
|
|
268
|
-
prompt_path: Path,
|
|
269
|
-
sub_bucket_count: int,
|
|
270
|
-
) -> list[str]:
|
|
271
|
-
prompt_text = prompt_path.read_text(encoding=UTF8_ENCODING)
|
|
272
|
-
all_skeleton_lines: list[str] = []
|
|
273
|
-
for each_line in prompt_text.splitlines():
|
|
274
|
-
if each_line == SKELETON_SEPARATOR_LINE:
|
|
275
|
-
break
|
|
276
|
-
all_skeleton_lines.append(each_line)
|
|
277
|
-
skeleton_text = NEWLINE.join(all_skeleton_lines)
|
|
278
|
-
if SKELETON_PLACEHOLDER_FRAGMENT in skeleton_text:
|
|
279
|
-
return [
|
|
280
|
-
f"{category_id}: prompt skeleton still uses [N] placeholder; "
|
|
281
|
-
f"use numeric count {sub_bucket_count}"
|
|
282
|
-
]
|
|
283
|
-
count_match = SKELETON_COUNT_PATTERN.search(skeleton_text)
|
|
284
|
-
if count_match is None:
|
|
285
|
-
return [f"{category_id}: prompt skeleton missing sub-bucket count form"]
|
|
286
|
-
skeleton_count = int(count_match.group(HEADING_LETTER_GROUP))
|
|
287
|
-
if skeleton_count != sub_bucket_count:
|
|
288
|
-
return [
|
|
289
|
-
f"{category_id}: prompt skeleton count {skeleton_count} "
|
|
290
|
-
f"!= schema {sub_bucket_count}"
|
|
291
|
-
]
|
|
292
|
-
return []
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
def validate_projections() -> list[str]:
|
|
296
|
-
"""Compare schema against on-disk rubric and prompt skeleton projections.
|
|
297
|
-
|
|
298
|
-
Returns:
|
|
299
|
-
Finding strings; empty when every category is in parity.
|
|
300
|
-
"""
|
|
301
|
-
all_schema = load_audit_category_schema()
|
|
302
|
-
all_categories = all_schema[SCHEMA_CATEGORIES_KEY]
|
|
303
|
-
assert isinstance(all_categories, list)
|
|
304
|
-
all_findings: list[str] = []
|
|
305
|
-
for each_category in all_categories:
|
|
306
|
-
assert isinstance(each_category, dict)
|
|
307
|
-
all_findings.extend(_validate_one_category(each_category))
|
|
308
|
-
return all_findings
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
def main(all_argv: list[str]) -> int:
|
|
312
|
-
"""CLI: validate projections or print deterministic skeleton projections.
|
|
313
|
-
|
|
314
|
-
Args:
|
|
315
|
-
all_argv: Argument list without the program name.
|
|
316
|
-
|
|
317
|
-
Returns:
|
|
318
|
-
Process exit code (0 success, 1 validation findings).
|
|
319
|
-
"""
|
|
320
|
-
parser = argparse.ArgumentParser(description=__doc__)
|
|
321
|
-
parser.add_argument(
|
|
322
|
-
"--validate",
|
|
323
|
-
action="store_true",
|
|
324
|
-
help="Validate rubric and prompt projections against the schema.",
|
|
325
|
-
)
|
|
326
|
-
parser.add_argument(
|
|
327
|
-
"--render-skeletons",
|
|
328
|
-
action="store_true",
|
|
329
|
-
help="Print deterministic skeleton projections as JSON.",
|
|
330
|
-
)
|
|
331
|
-
arguments = parser.parse_args(all_argv)
|
|
332
|
-
if arguments.validate:
|
|
333
|
-
all_findings = validate_projections()
|
|
334
|
-
if all_findings:
|
|
335
|
-
for each_finding in all_findings:
|
|
336
|
-
print(each_finding, file=sys.stderr)
|
|
337
|
-
return 1
|
|
338
|
-
print("OK")
|
|
339
|
-
return 0
|
|
340
|
-
if arguments.render_skeletons:
|
|
341
|
-
all_schema = load_audit_category_schema()
|
|
342
|
-
print(
|
|
343
|
-
json.dumps(
|
|
344
|
-
render_skeleton_projections(all_schema),
|
|
345
|
-
indent=JSON_INDENT,
|
|
346
|
-
ensure_ascii=False,
|
|
347
|
-
)
|
|
348
|
-
)
|
|
349
|
-
return 0
|
|
350
|
-
parser.print_help()
|
|
351
|
-
return 0
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if __name__ == "__main__":
|
|
355
|
-
raise SystemExit(main(sys.argv[1:]))
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
"""Emit the complete AUDIT spawn prompt XML to stdout.
|
|
2
|
-
|
|
3
|
-
Builds <context> and <scope> from CLI args; <bug_categories>,
|
|
4
|
-
<rubric_reference>, and <constraints> come from the shared constants in
|
|
5
|
-
skills_pr_loop_constants; <comment_posting> and <output_format> follow
|
|
6
|
-
``--flavor`` (agent or headless). <pr_description> carries the PR body
|
|
7
|
-
text read from --pr-body-file, and stays empty when that argument is
|
|
8
|
-
absent or the file cannot be read.
|
|
9
|
-
|
|
10
|
-
Usage:
|
|
11
|
-
python scripts/build_audit_prompt.py --owner jl-cmd --repo claude-dev-env --pr-number 422 --loop 1 --head-ref feat/branch --base-ref main --worktree-path <PATH> --run-temp-dir <PATH> [--flavor agent|headless]
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import argparse
|
|
17
|
-
import sys
|
|
18
|
-
from xml.etree.ElementTree import Element, SubElement
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
|
|
21
|
-
_self_dir = Path(__file__).resolve().parent
|
|
22
|
-
if str(_self_dir) not in sys.path:
|
|
23
|
-
sys.path.insert(0, str(_self_dir))
|
|
24
|
-
|
|
25
|
-
from _path_resolver import outcome_xml_path
|
|
26
|
-
from _xml_utils import emit_pretty_xml
|
|
27
|
-
from skills_pr_loop_constants.path_resolver_constants import (
|
|
28
|
-
ALL_AUDIT_CATEGORY_ENTRIES,
|
|
29
|
-
ALL_AUDIT_CONSTRAINT_TEXTS,
|
|
30
|
-
ALL_AUDIT_PROMPT_FLAVORS,
|
|
31
|
-
AUDIT_COMMENT_POSTING_AGENT_TEXT,
|
|
32
|
-
AUDIT_COMMENT_POSTING_HEADLESS_TEXT,
|
|
33
|
-
AUDIT_OUTPUT_FORMAT_AGENT_TEXT,
|
|
34
|
-
AUDIT_OUTPUT_FORMAT_HEADLESS_TEMPLATE,
|
|
35
|
-
AUDIT_PROMPT_FLAVOR_AGENT,
|
|
36
|
-
AUDIT_PROMPT_FLAVOR_HEADLESS,
|
|
37
|
-
AUDIT_RUBRIC_REFERENCE_TEXT,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def read_pr_body_text(pr_body_file: Path | None) -> str | None:
|
|
42
|
-
"""Read the PR description body from a file when given and readable.
|
|
43
|
-
|
|
44
|
-
Args:
|
|
45
|
-
pr_body_file: Path to a file holding the PR description body, or None.
|
|
46
|
-
|
|
47
|
-
Returns:
|
|
48
|
-
The file's text when the path is given and readable, otherwise None.
|
|
49
|
-
"""
|
|
50
|
-
if pr_body_file is None:
|
|
51
|
-
return None
|
|
52
|
-
try:
|
|
53
|
-
return pr_body_file.read_text(encoding="utf-8")
|
|
54
|
-
except OSError:
|
|
55
|
-
return None
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def _append_pr_description(root: Element, pr_body_text: str | None) -> None:
|
|
59
|
-
"""Append a <pr_description> element carrying the PR body text.
|
|
60
|
-
|
|
61
|
-
Args:
|
|
62
|
-
root: Root element the <pr_description> child is appended to.
|
|
63
|
-
pr_body_text: PR description body text, or None when unavailable.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
None.
|
|
67
|
-
"""
|
|
68
|
-
pr_description = SubElement(root, "pr_description")
|
|
69
|
-
if pr_body_text:
|
|
70
|
-
pr_description.text = pr_body_text
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _comment_posting_text(flavor: str) -> str:
|
|
74
|
-
"""Return the <comment_posting> body for the given prompt flavor.
|
|
75
|
-
|
|
76
|
-
Args:
|
|
77
|
-
flavor: ``agent`` or ``headless`` prompt flavor.
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
Comment-posting instruction text for that flavor.
|
|
81
|
-
"""
|
|
82
|
-
if flavor == AUDIT_PROMPT_FLAVOR_HEADLESS:
|
|
83
|
-
return AUDIT_COMMENT_POSTING_HEADLESS_TEXT
|
|
84
|
-
return AUDIT_COMMENT_POSTING_AGENT_TEXT
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def _format_instruction_text(
|
|
88
|
-
*,
|
|
89
|
-
flavor: str,
|
|
90
|
-
worktree_path: Path,
|
|
91
|
-
pr_number: int,
|
|
92
|
-
loop: int,
|
|
93
|
-
) -> str:
|
|
94
|
-
"""Return the <output_format> body for the given prompt flavor.
|
|
95
|
-
|
|
96
|
-
Args:
|
|
97
|
-
flavor: ``agent`` or ``headless`` prompt flavor.
|
|
98
|
-
worktree_path: Path to the git worktree.
|
|
99
|
-
pr_number: Pull request number.
|
|
100
|
-
loop: Loop iteration number.
|
|
101
|
-
|
|
102
|
-
Returns:
|
|
103
|
-
Format-instruction text for that flavor.
|
|
104
|
-
"""
|
|
105
|
-
if flavor == AUDIT_PROMPT_FLAVOR_HEADLESS:
|
|
106
|
-
outcome_path = outcome_xml_path(worktree_path, pr_number, loop)
|
|
107
|
-
return AUDIT_OUTPUT_FORMAT_HEADLESS_TEMPLATE.format(
|
|
108
|
-
outcome_path=outcome_path.as_posix(),
|
|
109
|
-
)
|
|
110
|
-
return AUDIT_OUTPUT_FORMAT_AGENT_TEXT
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def build_audit_prompt_xml(
|
|
114
|
-
*,
|
|
115
|
-
owner: str,
|
|
116
|
-
repo: str,
|
|
117
|
-
pr_number: int,
|
|
118
|
-
loop: int,
|
|
119
|
-
head_ref: str,
|
|
120
|
-
base_ref: str,
|
|
121
|
-
worktree_path: Path,
|
|
122
|
-
run_temp_dir: Path,
|
|
123
|
-
pr_body_text: str | None = None,
|
|
124
|
-
flavor: str = AUDIT_PROMPT_FLAVOR_AGENT,
|
|
125
|
-
) -> Element:
|
|
126
|
-
"""Build the complete AUDIT spawn prompt XML.
|
|
127
|
-
|
|
128
|
-
Args:
|
|
129
|
-
owner: GitHub repository owner.
|
|
130
|
-
repo: GitHub repository name.
|
|
131
|
-
pr_number: Pull request number.
|
|
132
|
-
loop: Loop iteration number.
|
|
133
|
-
head_ref: Head branch ref.
|
|
134
|
-
base_ref: Base branch ref.
|
|
135
|
-
worktree_path: Path to the git worktree.
|
|
136
|
-
run_temp_dir: Path to the run temp directory.
|
|
137
|
-
pr_body_text: PR description body text, or None when unavailable.
|
|
138
|
-
flavor: Prompt flavor — ``agent`` (MCP posting) or ``headless``
|
|
139
|
-
(outcome file, lead-owned posting).
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
Root <spawn_prompt> element.
|
|
143
|
-
"""
|
|
144
|
-
root = Element("spawn_prompt", {"role": "audit", "loop": str(loop)})
|
|
145
|
-
|
|
146
|
-
context = SubElement(root, "context")
|
|
147
|
-
SubElement(context, "owner").text = owner
|
|
148
|
-
SubElement(context, "repo").text = repo
|
|
149
|
-
SubElement(context, "pr_number").text = str(pr_number)
|
|
150
|
-
SubElement(context, "head_ref").text = head_ref
|
|
151
|
-
SubElement(context, "base_ref").text = base_ref
|
|
152
|
-
SubElement(context, "worktree_path").text = worktree_path.as_posix()
|
|
153
|
-
SubElement(context, "run_temp_dir").text = run_temp_dir.as_posix()
|
|
154
|
-
|
|
155
|
-
scope = SubElement(root, "scope")
|
|
156
|
-
scope.text = (
|
|
157
|
-
f"Audit the full diff of {owner}/{repo}#{pr_number} "
|
|
158
|
-
f"({head_ref} against {base_ref}) for CODE_RULES violations, "
|
|
159
|
-
f"bugs, and anti-patterns. Work in {worktree_path.as_posix()}."
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
_append_pr_description(root, pr_body_text)
|
|
163
|
-
|
|
164
|
-
bug_categories = SubElement(root, "bug_categories")
|
|
165
|
-
for each_category_id, each_category_label in ALL_AUDIT_CATEGORY_ENTRIES:
|
|
166
|
-
cat_elem = SubElement(bug_categories, "category", {"id": each_category_id})
|
|
167
|
-
cat_elem.text = each_category_label
|
|
168
|
-
|
|
169
|
-
rubric_reference = SubElement(root, "rubric_reference")
|
|
170
|
-
rubric_reference.text = AUDIT_RUBRIC_REFERENCE_TEXT
|
|
171
|
-
|
|
172
|
-
constraints = SubElement(root, "constraints")
|
|
173
|
-
for each_constraint in ALL_AUDIT_CONSTRAINT_TEXTS:
|
|
174
|
-
SubElement(constraints, "constraint").text = each_constraint
|
|
175
|
-
|
|
176
|
-
comment_posting = SubElement(root, "comment_posting")
|
|
177
|
-
comment_posting.text = _comment_posting_text(flavor)
|
|
178
|
-
|
|
179
|
-
format_section = SubElement(root, "output_format")
|
|
180
|
-
format_section.text = _format_instruction_text(
|
|
181
|
-
flavor=flavor,
|
|
182
|
-
worktree_path=worktree_path,
|
|
183
|
-
pr_number=pr_number,
|
|
184
|
-
loop=loop,
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
return root
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
def emit_audit_prompt(
|
|
191
|
-
*,
|
|
192
|
-
owner: str,
|
|
193
|
-
repo: str,
|
|
194
|
-
pr_number: int,
|
|
195
|
-
loop: int,
|
|
196
|
-
head_ref: str,
|
|
197
|
-
base_ref: str,
|
|
198
|
-
worktree_path: Path,
|
|
199
|
-
run_temp_dir: Path,
|
|
200
|
-
pr_body_text: str | None = None,
|
|
201
|
-
flavor: str = AUDIT_PROMPT_FLAVOR_AGENT,
|
|
202
|
-
) -> str:
|
|
203
|
-
"""Build and serialize the AUDIT spawn prompt to a pretty-printed XML string.
|
|
204
|
-
|
|
205
|
-
Args:
|
|
206
|
-
owner: GitHub repository owner.
|
|
207
|
-
repo: GitHub repository name.
|
|
208
|
-
pr_number: Pull request number.
|
|
209
|
-
loop: Loop iteration number.
|
|
210
|
-
head_ref: Head branch ref.
|
|
211
|
-
base_ref: Base branch ref.
|
|
212
|
-
worktree_path: Path to the git worktree.
|
|
213
|
-
run_temp_dir: Path to the run temp directory.
|
|
214
|
-
pr_body_text: PR description body text, or None when unavailable.
|
|
215
|
-
flavor: Prompt flavor — ``agent`` or ``headless``.
|
|
216
|
-
|
|
217
|
-
Returns:
|
|
218
|
-
Pretty-printed XML string.
|
|
219
|
-
"""
|
|
220
|
-
root = build_audit_prompt_xml(
|
|
221
|
-
owner=owner,
|
|
222
|
-
repo=repo,
|
|
223
|
-
pr_number=pr_number,
|
|
224
|
-
loop=loop,
|
|
225
|
-
head_ref=head_ref,
|
|
226
|
-
base_ref=base_ref,
|
|
227
|
-
worktree_path=worktree_path,
|
|
228
|
-
run_temp_dir=run_temp_dir,
|
|
229
|
-
pr_body_text=pr_body_text,
|
|
230
|
-
flavor=flavor,
|
|
231
|
-
)
|
|
232
|
-
return emit_pretty_xml(root)
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
def parse_arguments(all_argv: list[str]) -> argparse.Namespace:
|
|
236
|
-
"""Parse command-line arguments.
|
|
237
|
-
|
|
238
|
-
Args:
|
|
239
|
-
all_argv: Command-line argument list.
|
|
240
|
-
|
|
241
|
-
Returns:
|
|
242
|
-
Parsed namespace with all required audit prompt parameters.
|
|
243
|
-
"""
|
|
244
|
-
parser = argparse.ArgumentParser(description=__doc__)
|
|
245
|
-
parser.add_argument("--owner", required=True)
|
|
246
|
-
parser.add_argument("--repo", required=True)
|
|
247
|
-
parser.add_argument("--pr-number", type=int, required=True)
|
|
248
|
-
parser.add_argument("--loop", type=int, required=True)
|
|
249
|
-
parser.add_argument("--head-ref", required=True)
|
|
250
|
-
parser.add_argument("--base-ref", required=True)
|
|
251
|
-
parser.add_argument("--worktree-path", type=Path, required=True)
|
|
252
|
-
parser.add_argument("--run-temp-dir", type=Path, required=True)
|
|
253
|
-
parser.add_argument("--pr-body-file", type=Path, default=None)
|
|
254
|
-
parser.add_argument(
|
|
255
|
-
"--flavor",
|
|
256
|
-
choices=sorted(ALL_AUDIT_PROMPT_FLAVORS),
|
|
257
|
-
default=AUDIT_PROMPT_FLAVOR_AGENT,
|
|
258
|
-
)
|
|
259
|
-
return parser.parse_args(all_argv)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
def main(all_arguments: list[str]) -> int:
|
|
263
|
-
"""Entry point: emit AUDIT spawn prompt XML to stdout.
|
|
264
|
-
|
|
265
|
-
Args:
|
|
266
|
-
all_arguments: Command-line arguments.
|
|
267
|
-
|
|
268
|
-
Returns:
|
|
269
|
-
0 on success.
|
|
270
|
-
"""
|
|
271
|
-
arguments = parse_arguments(all_arguments)
|
|
272
|
-
xml_output = emit_audit_prompt(
|
|
273
|
-
owner=arguments.owner,
|
|
274
|
-
repo=arguments.repo,
|
|
275
|
-
pr_number=arguments.pr_number,
|
|
276
|
-
loop=arguments.loop,
|
|
277
|
-
head_ref=arguments.head_ref,
|
|
278
|
-
base_ref=arguments.base_ref,
|
|
279
|
-
worktree_path=arguments.worktree_path,
|
|
280
|
-
run_temp_dir=arguments.run_temp_dir,
|
|
281
|
-
pr_body_text=read_pr_body_text(arguments.pr_body_file),
|
|
282
|
-
flavor=arguments.flavor,
|
|
283
|
-
)
|
|
284
|
-
sys.stdout.write(xml_output)
|
|
285
|
-
return 0
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if __name__ == "__main__":
|
|
289
|
-
raise SystemExit(main(sys.argv[1:]))
|