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
|
@@ -32,6 +32,7 @@ from pr_loop_shared_constants.terminology_sweep_constants import (
|
|
|
32
32
|
ALL_COMMON_ENGLISH_COMPOUND_TAIL_WORDS,
|
|
33
33
|
ALL_DIFF_FILE_PATH_STRIP_PREFIXES,
|
|
34
34
|
ALL_GIT_DIFF_CACHED_UNIFIED_ZERO_COMMAND,
|
|
35
|
+
ALL_GIT_DIFF_UNIFIED_ZERO_COMMAND,
|
|
35
36
|
ALL_GIT_GREP_BASE_TREE_COMMAND_PREFIX,
|
|
36
37
|
ALL_PROSE_STOPWORD_TOKENS,
|
|
37
38
|
ALL_STRING_ESCAPE_SEQUENCES,
|
|
@@ -622,21 +623,23 @@ def _identifier_names_on_added_code_lines(diff_text: str) -> frozenset[str]:
|
|
|
622
623
|
|
|
623
624
|
|
|
624
625
|
def _base_tree_names(
|
|
625
|
-
repository_root: Path,
|
|
626
|
+
repository_root: Path,
|
|
627
|
+
all_names: frozenset[str],
|
|
628
|
+
tree_revision: str,
|
|
626
629
|
) -> frozenset[str]:
|
|
627
|
-
"""Return the names the
|
|
630
|
+
"""Return the names the comparison tree already contains.
|
|
628
631
|
|
|
629
|
-
Each name is looked up as a whole word in
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
That is the behaviour the sweep has with no base-tree check at all.
|
|
632
|
+
Each name is looked up as a whole word in ``tree_revision``. A repository
|
|
633
|
+
with no commits yet, or a lookup that git cannot run, reports the name as
|
|
634
|
+
absent, so the sweep treats it as newly introduced.
|
|
633
635
|
|
|
634
636
|
Args:
|
|
635
637
|
repository_root: The repository root the lookups run in.
|
|
636
638
|
all_names: The identifier names to look up.
|
|
639
|
+
tree_revision: The revision whose tree is searched.
|
|
637
640
|
|
|
638
641
|
Returns:
|
|
639
|
-
The subset of names present in
|
|
642
|
+
The subset of names present in that tree.
|
|
640
643
|
"""
|
|
641
644
|
all_present_names: set[str] = set()
|
|
642
645
|
for each_name in sorted(all_names):
|
|
@@ -645,7 +648,7 @@ def _base_tree_names(
|
|
|
645
648
|
[
|
|
646
649
|
*ALL_GIT_GREP_BASE_TREE_COMMAND_PREFIX,
|
|
647
650
|
each_name,
|
|
648
|
-
|
|
651
|
+
tree_revision,
|
|
649
652
|
],
|
|
650
653
|
cwd=str(repository_root),
|
|
651
654
|
capture_output=True,
|
|
@@ -695,14 +698,16 @@ def _raise_for_git_failure(
|
|
|
695
698
|
|
|
696
699
|
|
|
697
700
|
def _strict_base_tree_names(
|
|
698
|
-
repository_root: Path,
|
|
701
|
+
repository_root: Path,
|
|
702
|
+
all_names: frozenset[str],
|
|
703
|
+
tree_revision: str,
|
|
699
704
|
) -> frozenset[str]:
|
|
700
705
|
all_present_names: set[str] = set()
|
|
701
706
|
for each_name in sorted(all_names):
|
|
702
707
|
all_arguments = (
|
|
703
708
|
*ALL_GIT_GREP_BASE_TREE_COMMAND_PREFIX,
|
|
704
709
|
each_name,
|
|
705
|
-
|
|
710
|
+
tree_revision,
|
|
706
711
|
)
|
|
707
712
|
grep_process = _run_strict_git(repository_root, all_arguments)
|
|
708
713
|
if grep_process.returncode == 0:
|
|
@@ -728,14 +733,53 @@ def strict_staged_terminology_findings(repository_root: Path) -> list[str]:
|
|
|
728
733
|
RuntimeError: Git could not read the staged diff or look up an
|
|
729
734
|
identifier in HEAD.
|
|
730
735
|
"""
|
|
731
|
-
|
|
732
|
-
repository_root,
|
|
736
|
+
return _strict_terminology_findings(
|
|
737
|
+
repository_root,
|
|
738
|
+
ALL_GIT_DIFF_CACHED_UNIFIED_ZERO_COMMAND,
|
|
739
|
+
GIT_BASE_TREE_REVISION,
|
|
733
740
|
)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
def strict_base_terminology_findings(
|
|
744
|
+
repository_root: Path, base_revision: str
|
|
745
|
+
) -> list[str]:
|
|
746
|
+
"""Return near-miss findings for worktree changes against a base revision.
|
|
747
|
+
|
|
748
|
+
Args:
|
|
749
|
+
repository_root: The repository root the worktree diff is read from.
|
|
750
|
+
base_revision: The tree that worktree changes are compared against.
|
|
751
|
+
|
|
752
|
+
Returns:
|
|
753
|
+
One finding string per near-miss term on an added prose line.
|
|
754
|
+
|
|
755
|
+
Raises:
|
|
756
|
+
RuntimeError: Git could not read the committed diff or look up an
|
|
757
|
+
identifier in the comparison tree.
|
|
758
|
+
"""
|
|
759
|
+
all_arguments = (
|
|
760
|
+
*ALL_GIT_DIFF_UNIFIED_ZERO_COMMAND,
|
|
761
|
+
base_revision,
|
|
762
|
+
)
|
|
763
|
+
return _strict_terminology_findings(
|
|
764
|
+
repository_root,
|
|
765
|
+
all_arguments,
|
|
766
|
+
base_revision,
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
def _strict_terminology_findings(
|
|
771
|
+
repository_root: Path,
|
|
772
|
+
all_diff_arguments: Sequence[str],
|
|
773
|
+
tree_revision: str,
|
|
774
|
+
) -> list[str]:
|
|
775
|
+
diff_process = _run_strict_git(repository_root, all_diff_arguments)
|
|
734
776
|
_raise_for_git_failure(diff_process, GIT_DIFF_OPERATION)
|
|
735
777
|
all_added_names = _identifier_names_on_added_code_lines(diff_process.stdout)
|
|
736
778
|
preexisting_tuples = frozenset(
|
|
737
779
|
_identifier_token_tuple(each_name)
|
|
738
|
-
for each_name in _strict_base_tree_names(
|
|
780
|
+
for each_name in _strict_base_tree_names(
|
|
781
|
+
repository_root, all_added_names, tree_revision
|
|
782
|
+
)
|
|
739
783
|
)
|
|
740
784
|
return _find_terminology_near_misses(diff_process.stdout, preexisting_tuples)
|
|
741
785
|
|
|
@@ -743,16 +787,15 @@ def strict_staged_terminology_findings(repository_root: Path) -> list[str]:
|
|
|
743
787
|
def staged_terminology_findings(repository_root: Path) -> list[str]:
|
|
744
788
|
"""Return terminology near-miss findings for a repository's staged diff.
|
|
745
789
|
|
|
746
|
-
An identifier
|
|
747
|
-
|
|
748
|
-
identifiers are swept.
|
|
790
|
+
An identifier already present in HEAD is not treated as introduced, so
|
|
791
|
+
prose is not flagged against it.
|
|
749
792
|
|
|
750
793
|
Args:
|
|
751
794
|
repository_root: The repository root the staged diff is read from.
|
|
752
795
|
|
|
753
796
|
Returns:
|
|
754
|
-
One finding string per near-miss term on a staged
|
|
755
|
-
|
|
797
|
+
One finding string per near-miss term on a staged prose line, or an
|
|
798
|
+
empty list when the staged diff is empty or git cannot be run.
|
|
756
799
|
"""
|
|
757
800
|
diff_process = subprocess.run(
|
|
758
801
|
list(ALL_GIT_DIFF_CACHED_UNIFIED_ZERO_COMMAND),
|
|
@@ -770,7 +813,9 @@ def staged_terminology_findings(repository_root: Path) -> list[str]:
|
|
|
770
813
|
all_added_names = _identifier_names_on_added_code_lines(diff_process.stdout)
|
|
771
814
|
preexisting_tuples = frozenset(
|
|
772
815
|
_identifier_token_tuple(each_name)
|
|
773
|
-
for each_name in _base_tree_names(
|
|
816
|
+
for each_name in _base_tree_names(
|
|
817
|
+
repository_root, all_added_names, GIT_BASE_TREE_REVISION
|
|
818
|
+
)
|
|
774
819
|
)
|
|
775
820
|
return _find_terminology_near_misses(diff_process.stdout, preexisting_tuples)
|
|
776
821
|
|
|
@@ -31,6 +31,7 @@ sweep_module = _load_sweep_module()
|
|
|
31
31
|
sweep_diff = sweep_module.sweep_diff
|
|
32
32
|
staged_terminology_findings = sweep_module.staged_terminology_findings
|
|
33
33
|
strict_staged_terminology_findings = sweep_module.strict_staged_terminology_findings
|
|
34
|
+
strict_base_terminology_findings = sweep_module.strict_base_terminology_findings
|
|
34
35
|
main = sweep_module.main
|
|
35
36
|
parse_added_lines = sweep_module._parse_added_lines
|
|
36
37
|
|
|
@@ -53,6 +54,54 @@ def _init_git_repository(repository_path: Path) -> None:
|
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
|
|
57
|
+
def _run_repository_git(repository_path: Path, all_arguments: list[str]) -> str:
|
|
58
|
+
completed = subprocess.run(
|
|
59
|
+
all_arguments,
|
|
60
|
+
cwd=repository_path,
|
|
61
|
+
check=True,
|
|
62
|
+
capture_output=True,
|
|
63
|
+
text=True,
|
|
64
|
+
env=_hermetic_git_environment(),
|
|
65
|
+
)
|
|
66
|
+
return completed.stdout.strip()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _write_repository_text(
|
|
70
|
+
repository_path: Path, relative_path: str, text: str
|
|
71
|
+
) -> None:
|
|
72
|
+
(repository_path / relative_path).write_text(text, encoding="utf-8")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _commit_all(repository_path: Path, message: str) -> None:
|
|
76
|
+
_run_repository_git(repository_path, ["git", "add", "-A"])
|
|
77
|
+
_run_repository_git(repository_path, ["git", "commit", "-m", message])
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _head_revision(repository_path: Path) -> str:
|
|
81
|
+
return _run_repository_git(repository_path, ["git", "rev-parse", "HEAD"])
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _committed_near_miss_repository(repository_path: Path) -> str:
|
|
85
|
+
_init_git_repository(repository_path)
|
|
86
|
+
_write_repository_text(repository_path, "quota.py", "baseline = 1\n")
|
|
87
|
+
_write_repository_text(repository_path, "README.md", "Baseline quota text.\n")
|
|
88
|
+
_commit_all(repository_path, "base")
|
|
89
|
+
comparison_revision = _head_revision(repository_path)
|
|
90
|
+
_write_repository_text(
|
|
91
|
+
repository_path,
|
|
92
|
+
"quota.py",
|
|
93
|
+
"baseline = 1\npremium_request_interactions = 5\n",
|
|
94
|
+
)
|
|
95
|
+
_commit_all(repository_path, "identifier")
|
|
96
|
+
_write_repository_text(
|
|
97
|
+
repository_path,
|
|
98
|
+
"README.md",
|
|
99
|
+
"The premium-request-budget field gates the run.\n",
|
|
100
|
+
)
|
|
101
|
+
_commit_all(repository_path, "documentation")
|
|
102
|
+
return comparison_revision
|
|
103
|
+
|
|
104
|
+
|
|
56
105
|
CODE_AND_PROSE_DIFF = (
|
|
57
106
|
"diff --git a/api/quota.py b/api/quota.py\n"
|
|
58
107
|
"--- a/api/quota.py\n"
|
|
@@ -310,6 +359,16 @@ def test_staged_terminology_findings_empty_when_clean(tmp_path: Path) -> None:
|
|
|
310
359
|
assert staged_terminology_findings(tmp_path) == []
|
|
311
360
|
|
|
312
361
|
|
|
362
|
+
def test_strict_base_terminology_findings_reports_committed_near_miss(
|
|
363
|
+
tmp_path: Path,
|
|
364
|
+
) -> None:
|
|
365
|
+
comparison_revision = _committed_near_miss_repository(tmp_path)
|
|
366
|
+
all_findings = strict_base_terminology_findings(tmp_path, comparison_revision)
|
|
367
|
+
assert len(all_findings) == 1
|
|
368
|
+
assert "README.md:1" in all_findings[0]
|
|
369
|
+
assert "premium-request-budget" in all_findings[0]
|
|
370
|
+
|
|
371
|
+
|
|
313
372
|
def test_parse_added_lines_counts_pre_increment_content_as_added_line() -> None:
|
|
314
373
|
diff_with_pre_increment = (
|
|
315
374
|
"diff --git a/app.mjs b/app.mjs\n"
|
|
@@ -88,6 +88,7 @@ export const EVER_SHIPPED_SKILL_NAMES = new Set([
|
|
|
88
88
|
'pr-loop-lifecycle',
|
|
89
89
|
'pr-review-responder',
|
|
90
90
|
'pr-scope-resolve',
|
|
91
|
+
'pull-request',
|
|
91
92
|
'pre-compact',
|
|
92
93
|
'privacy-hygiene',
|
|
93
94
|
'prototype',
|
|
@@ -122,6 +123,7 @@ export const EVER_SHIPPED_SKILL_NAMES = new Set([
|
|
|
122
123
|
'syncing-submodules',
|
|
123
124
|
'task-build',
|
|
124
125
|
'team-advisor',
|
|
126
|
+
'test-runner',
|
|
125
127
|
'update',
|
|
126
128
|
'usage-pause',
|
|
127
129
|
'verified-build',
|
|
@@ -28,3 +28,11 @@ test('EVER_SHIPPED_SKILL_NAMES includes every current shipped skill', () => {
|
|
|
28
28
|
|
|
29
29
|
assert.deepEqual(allUncoveredSkillNames, [], 'every current skill must enter the fallback set');
|
|
30
30
|
});
|
|
31
|
+
|
|
32
|
+
test('EVER_SHIPPED_SKILL_NAMES retains the explicit test runner', () => {
|
|
33
|
+
assert.ok(EVER_SHIPPED_SKILL_NAMES.has('test-runner'));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('EVER_SHIPPED_SKILL_NAMES includes the pull request skill', () => {
|
|
37
|
+
assert.equal(EVER_SHIPPED_SKILL_NAMES.has('pull-request'), true);
|
|
38
|
+
});
|
|
@@ -32,6 +32,8 @@ const INSTALLER_PATH = join(THIS_DIRECTORY, 'install.mjs');
|
|
|
32
32
|
const PACKAGE_DIRECTORY = dirname(THIS_DIRECTORY);
|
|
33
33
|
const SHIPPED_SKILL_NAME = 'privacy-hygiene';
|
|
34
34
|
const ELI5_SKILL_NAME = 'eli5';
|
|
35
|
+
const E_CODE_REVIEW_SKILL_NAME = 'e-code-review';
|
|
36
|
+
const REFERENCE_DIRECTORY_NAME = 'reference';
|
|
35
37
|
const SHIPPED_AGENT_FILE_NAME = 'clean-coder.md';
|
|
36
38
|
const SHIPPED_AGENT_FILE_NAMES = [
|
|
37
39
|
SHIPPED_AGENT_FILE_NAME,
|
|
@@ -69,10 +71,7 @@ const CLEAN_CODER_POLICY_REFERENCES = [
|
|
|
69
71
|
],
|
|
70
72
|
];
|
|
71
73
|
const PERSONAL_SKILL_NAME = 'my-notes';
|
|
72
|
-
const SHARED_DIRECTORY_NAME = '_shared';
|
|
73
|
-
const PR_LOOP_DIRECTORY_NAME = 'pr-loop';
|
|
74
74
|
const PREFLIGHT_PROPOSAL_FILE_NAME = 'preflight-proposal.md';
|
|
75
|
-
const PREFLIGHT_PROPOSAL_POINTER = '@~/.claude/_shared/pr-loop/preflight-proposal.md';
|
|
76
75
|
|
|
77
76
|
/**
|
|
78
77
|
* @param {string} homeDirectory
|
|
@@ -100,20 +99,23 @@ function runInstaller(homeDirectory, extraArguments, environmentOverrides = {})
|
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
/**
|
|
103
|
-
* @param {{
|
|
102
|
+
* @param {{ skillsInstallDirectory: string }} installationPaths
|
|
104
103
|
*/
|
|
105
104
|
function assertProposalContractInstallation(installationPaths) {
|
|
106
|
-
const {
|
|
105
|
+
const { skillsInstallDirectory } = installationPaths;
|
|
107
106
|
const allContractPathSegments = [
|
|
108
|
-
|
|
107
|
+
E_CODE_REVIEW_SKILL_NAME,
|
|
108
|
+
REFERENCE_DIRECTORY_NAME,
|
|
109
|
+
PREFLIGHT_PROPOSAL_FILE_NAME,
|
|
109
110
|
];
|
|
110
|
-
const
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const installedContractPath = join(skillsInstallDirectory, ...allContractPathSegments);
|
|
112
|
+
const sourceSkillsDirectory = resolvePackageManagedDirectory(
|
|
113
|
+
PACKAGE_DIRECTORY,
|
|
114
|
+
MANAGED_SKILLS_DIRECTORY_NAME,
|
|
115
|
+
);
|
|
116
|
+
const sourceContractPath = join(sourceSkillsDirectory, ...allContractPathSegments);
|
|
115
117
|
|
|
116
|
-
assert.equal(
|
|
118
|
+
assert.equal(existsSync(installedContractPath), true);
|
|
117
119
|
assert.equal(readFileSync(installedContractPath, 'utf8'), readFileSync(sourceContractPath, 'utf8'));
|
|
118
120
|
}
|
|
119
121
|
|
|
@@ -197,7 +199,7 @@ test('a full install writes skills and agents under .agents and points .claude a
|
|
|
197
199
|
);
|
|
198
200
|
assert.equal(realpathSync(lookupSkillFile), realpathSync(canonicalSkillFile));
|
|
199
201
|
assert.equal(realpathSync(lookupEli5SkillFile), realpathSync(canonicalEli5SkillFile));
|
|
200
|
-
assertProposalContractInstallation({
|
|
202
|
+
assertProposalContractInstallation({ skillsInstallDirectory });
|
|
201
203
|
assert.equal(
|
|
202
204
|
readFileSync(lookupAgentFile, 'utf8'),
|
|
203
205
|
readFileSync(canonicalAgentFile, 'utf8'),
|
package/bin/install.mjs
CHANGED
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
WINDOWS_PYTHON_LAUNCHER_COMMAND,
|
|
36
36
|
PYTHON_PROBE_TIMEOUT_MILLISECONDS,
|
|
37
37
|
} from './install-constants.mjs';
|
|
38
|
+
import {
|
|
39
|
+
PSTACK_PLUGIN_DIRECTORY_NAME,
|
|
40
|
+
PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH,
|
|
41
|
+
refreshPstackPluginManifest,
|
|
42
|
+
} from '../scripts/refresh_pstack_plugin_skills.mjs';
|
|
38
43
|
import {
|
|
39
44
|
resolveInstallRoot,
|
|
40
45
|
parseExplicitTargetFromArgv,
|
|
@@ -172,6 +177,7 @@ export const CORE_SKILLS = [
|
|
|
172
177
|
'grok-spawn',
|
|
173
178
|
'pr-small-cl',
|
|
174
179
|
'everything-search',
|
|
180
|
+
'test-runner',
|
|
175
181
|
'privacy-hygiene',
|
|
176
182
|
'issue-tracker',
|
|
177
183
|
'task-build',
|
|
@@ -428,6 +434,26 @@ export function runCursorRuleSync(pythonCommand, scriptPath, claudeRoot, cursorR
|
|
|
428
434
|
);
|
|
429
435
|
}
|
|
430
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Refresh the pstack plugin manifest Claude Code reads, when this home has one.
|
|
439
|
+
*
|
|
440
|
+
* Claude Code loads a skills-directory folder as a plugin when it holds
|
|
441
|
+
* `.claude-plugin/plugin.json`, and namespaces its skills as `pstack:how`.
|
|
442
|
+
* Without the manifest, a folder of skill folders loads nothing.
|
|
443
|
+
*
|
|
444
|
+
* @param {string} [skillsRoot] The skills root to read. Defaults to the root
|
|
445
|
+
* this run installs into.
|
|
446
|
+
* @returns {string|null} The manifest path when this run wrote it, else null.
|
|
447
|
+
*/
|
|
448
|
+
export function refreshInstalledPstackPluginManifest(
|
|
449
|
+
skillsRoot = join(CLAUDE_HOME, MANAGED_SKILLS_DIRECTORY_NAME),
|
|
450
|
+
) {
|
|
451
|
+
const pluginRoot = join(skillsRoot, PSTACK_PLUGIN_DIRECTORY_NAME);
|
|
452
|
+
const outcome = refreshPstackPluginManifest(pluginRoot);
|
|
453
|
+
if (!outcome.didWrite) return null;
|
|
454
|
+
return join(pluginRoot, PSTACK_PLUGIN_MANIFEST_RELATIVE_PATH);
|
|
455
|
+
}
|
|
456
|
+
|
|
431
457
|
function seedCodexPstackPreferences() {
|
|
432
458
|
const preferenceDirectory = join(AGENTS_HOME, CURSOR_RULES_DIRECTORY_NAME);
|
|
433
459
|
const preferencePath = join(
|
|
@@ -1181,6 +1207,11 @@ export const FOLDED_HOOK_RELATIVE_PATHS = new Set([
|
|
|
1181
1207
|
'blocking/pytest_testpaths_orphan_blocker.py',
|
|
1182
1208
|
'blocking/open_questions_in_plans_blocker.py',
|
|
1183
1209
|
'blocking/md_to_html_blocker.py',
|
|
1210
|
+
'blocking/gh_body_arg_blocker.py',
|
|
1211
|
+
'blocking/volatile_path_in_post_blocker.py',
|
|
1212
|
+
'blocking/conventional_pr_title_gate.py',
|
|
1213
|
+
'blocking/gh_pr_author_enforcer.py',
|
|
1214
|
+
'blocking/pr_description_writer_gate.py',
|
|
1184
1215
|
'session/untracked_repo_detector.py',
|
|
1185
1216
|
]);
|
|
1186
1217
|
|
|
@@ -1198,11 +1229,13 @@ export const POST_FOLDED_HOOK_RELATIVE_PATHS = new Set([
|
|
|
1198
1229
|
'workflow/auto_formatter.py',
|
|
1199
1230
|
'workflow/doc_gist_auto_publish.py',
|
|
1200
1231
|
'workflow/md_to_html_companion.py',
|
|
1232
|
+
'blocking/gh_pr_author_restore.py',
|
|
1201
1233
|
]);
|
|
1202
1234
|
|
|
1203
|
-
/** Hook scripts that still ship but no longer run as registered hooks. */
|
|
1204
1235
|
export const RETIRED_HOOK_REGISTRATION_RELATIVE_PATHS = new Set([
|
|
1205
1236
|
'session/untracked_repo_detector.py',
|
|
1237
|
+
'session/gh_pr_author_session_cleanup.py',
|
|
1238
|
+
'observability/pr_description_writer_spawn_tracker.py',
|
|
1206
1239
|
]);
|
|
1207
1240
|
|
|
1208
1241
|
/**
|
|
@@ -2312,6 +2345,9 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
|
|
|
2312
2345
|
}
|
|
2313
2346
|
summary.skills = { created: skillsCreated, updated: skillsUpdated, pruned: 0, paths: skillPaths };
|
|
2314
2347
|
allInstalledFiles.push(...skillPaths);
|
|
2348
|
+
const pstackManifestPath = refreshInstalledPstackPluginManifest();
|
|
2349
|
+
if (pstackManifestPath) allInstalledFiles.push(pstackManifestPath);
|
|
2350
|
+
summary.pstackPlugin = { manifestPath: pstackManifestPath };
|
|
2315
2351
|
syncWrittenPaths([...allInstalledFiles, ...publishedPointerPaths]);
|
|
2316
2352
|
throwIfFault(FAULT_PHASES.AFTER_FILE_STAGING);
|
|
2317
2353
|
throwIfFault(FAULT_PHASES.BEFORE_DURABLE_PROMOTION);
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import {
|
|
5
|
+
FOLDED_HOOK_RELATIVE_PATHS,
|
|
6
|
+
mergeHooksIntoSettings,
|
|
7
|
+
} from './install.mjs';
|
|
8
|
+
|
|
9
|
+
const allRetiredWriteHooks = [
|
|
10
|
+
'blocking/code_rules_enforcer.py',
|
|
11
|
+
'blocking/tdd_enforcer.py',
|
|
12
|
+
'blocking/windows_rmtree_blocker.py',
|
|
13
|
+
'blocking/state_description_blocker.py',
|
|
14
|
+
'blocking/subprocess_budget_completeness.py',
|
|
15
|
+
'blocking/hook_prose_detector_consistency.py',
|
|
16
|
+
'blocking/workflow_substitution_slot_blocker.py',
|
|
17
|
+
];
|
|
18
|
+
const sourceHooks = JSON.parse(readFileSync(new URL('../hooks/hooks.json', import.meta.url), 'utf8'));
|
|
19
|
+
const installedRoot = '/fixture-home/.claude';
|
|
20
|
+
const foreignCommand = 'python /unmanaged/keep_this_hook.py';
|
|
21
|
+
const foreignSessionCommand = 'node /unmanaged/session.js';
|
|
22
|
+
|
|
23
|
+
function legacySettings() {
|
|
24
|
+
return {
|
|
25
|
+
permissions: { allow: ['Read'] },
|
|
26
|
+
hooks: {
|
|
27
|
+
PreToolUse: [{
|
|
28
|
+
matcher: 'Write|Edit|MultiEdit|apply_patch',
|
|
29
|
+
hooks: [
|
|
30
|
+
{ type: 'command', command: foreignCommand, timeout: 17 },
|
|
31
|
+
...allRetiredWriteHooks.map(relativePath => ({
|
|
32
|
+
type: 'command',
|
|
33
|
+
command: `python ${installedRoot}/hooks/${relativePath}`,
|
|
34
|
+
timeout: 10,
|
|
35
|
+
})),
|
|
36
|
+
],
|
|
37
|
+
}],
|
|
38
|
+
SessionStart: [{
|
|
39
|
+
matcher: '',
|
|
40
|
+
hooks: [{ type: 'command', command: foreignSessionCommand, timeout: 9 }],
|
|
41
|
+
}],
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function allCommands(settings) {
|
|
47
|
+
return Object.values(settings.hooks).flatMap(groups =>
|
|
48
|
+
groups.flatMap(group => group.hooks.map(hook => hook.command)));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
test('every retired write registration already has an installer-owned prune path', () => {
|
|
52
|
+
for (const relativePath of allRetiredWriteHooks) {
|
|
53
|
+
assert.ok(FOLDED_HOOK_RELATIVE_PATHS.has(relativePath), relativePath);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('upgrade prunes legacy direct file checks while retaining foreign hooks', () => {
|
|
58
|
+
const settings = legacySettings();
|
|
59
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
60
|
+
const commands = allCommands(settings);
|
|
61
|
+
for (const relativePath of allRetiredWriteHooks) {
|
|
62
|
+
assert.ok(!commands.some(command => command.includes(relativePath)), relativePath);
|
|
63
|
+
}
|
|
64
|
+
assert.ok(commands.includes(foreignCommand));
|
|
65
|
+
assert.ok(commands.includes(foreignSessionCommand));
|
|
66
|
+
assert.deepEqual(settings.permissions, { allow: ['Read'] });
|
|
67
|
+
assert.ok(commands.some(command => command.includes('/blocking/pre_tool_use_dispatcher.py')));
|
|
68
|
+
assert.ok(commands.some(command => command.includes('/blocking/bash_pre_tool_use_dispatcher.py')));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('reinstall does not restore retired direct checks or duplicate foreign hooks', () => {
|
|
72
|
+
const settings = legacySettings();
|
|
73
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
74
|
+
const firstInstall = structuredClone(settings);
|
|
75
|
+
mergeHooksIntoSettings(settings, sourceHooks, installedRoot, 'python3');
|
|
76
|
+
assert.deepEqual(settings, firstInstall);
|
|
77
|
+
assert.equal(allCommands(settings).filter(command => command === foreignCommand).length, 1);
|
|
78
|
+
});
|