claude-dev-env 4.3.0 → 7.1.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 +5 -4
- package/.agents/skills/pull-request/SKILL.md +11 -13
- package/.agents/skills/pull-request/reference/publication-tasks.md +3 -3
- package/.agents/skills/pull-request/scripts/github_pr_command_constants/config/constants.py +9 -1
- package/.agents/skills/pull-request/scripts/pull_request.py +35 -44
- package/.agents/skills/pull-request/scripts/test_github_pr_command_constants.py +9 -0
- package/.agents/skills/pull-request/scripts/test_pull_request.py +35 -3
- package/.agents/skills/session-continuity/README.md +189 -0
- package/.agents/skills/session-continuity/SKILL.md +114 -0
- package/.agents/skills/session-continuity/continuity.mjs +375 -0
- package/.agents/skills/session-continuity/continuity.test.mjs +303 -0
- package/.agents/skills/skill-builder/SKILL.md +3 -196
- package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +0 -7
- package/.agents/skills/windows-scheduled-task/SKILL.md +153 -0
- 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/cde.mjs +36 -8
- package/bin/cde.test.mjs +48 -0
- package/bin/ever-shipped-skills.mjs +2 -20
- package/bin/ever-shipped-skills.test.mjs +8 -0
- package/bin/expand_home_directory_tokens.mjs +4 -5
- package/bin/expand_home_directory_tokens.test.mjs +128 -0
- package/bin/git_hooks_installer.mjs +22 -3
- package/bin/git_hooks_installer.test.mjs +159 -5
- package/bin/install-session-continuity.mjs +78 -0
- package/bin/install-session-continuity.test.mjs +42 -0
- package/bin/install.agents-home.test.mjs +15 -13
- package/bin/install.codex-rules.test.mjs +5 -2
- package/bin/install.cursor-rules.test.mjs +5 -2
- package/bin/install.mjs +506 -63
- package/bin/install.policy-lint.test.mjs +130 -0
- package/bin/install.profiles.test.mjs +10 -0
- package/bin/install.prune.test.mjs +286 -37
- package/bin/install.pstack-plugin.test.mjs +114 -0
- package/bin/install.test.mjs +537 -120
- package/bin/install.transaction.test.mjs +3 -3
- package/bin/refresh-pstack-plugin-skills.test.mjs +211 -0
- package/docs/CODE_RULES.md +1 -1
- 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_banned_identifiers.py +3 -0
- package/hooks/blocking/code_rules_paired_test.py +22 -15
- package/hooks/blocking/precommit_code_rules_gate.py +5 -8
- package/hooks/blocking/test_bash_dispatcher_interpreter_starts.py +7 -52
- package/hooks/blocking/test_bash_post_call_dispatcher.py +65 -4
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +0 -69
- package/hooks/blocking/test_code_rules_banned_identifiers.py +64 -0
- 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_pre_tool_use_dispatcher.py +43 -342
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +20 -51
- package/hooks/blocking/test_shared_stdin_adoption.py +1 -47
- package/hooks/git-hooks/git_hooks_constants/staged_policy_lint.py +12 -0
- package/hooks/git-hooks/git_hooks_constants/verification_notice_constants.py +116 -0
- package/hooks/git-hooks/post_commit.py +33 -0
- package/hooks/git-hooks/pre_commit.py +18 -49
- package/hooks/git-hooks/pre_push.py +45 -541
- package/hooks/git-hooks/test_installed_policy_lint.py +208 -0
- package/hooks/git-hooks/test_native_hook_support.py +129 -0
- package/hooks/git-hooks/test_native_policy_commit.py +120 -0
- package/hooks/git-hooks/test_post_commit.py +43 -0
- package/hooks/git-hooks/test_pre_commit.py +38 -148
- package/hooks/git-hooks/test_pre_push.py +48 -1631
- package/hooks/git-hooks/test_verification_notice.py +60 -0
- package/hooks/git-hooks/test_verification_start.py +173 -0
- package/hooks/git-hooks/verification_notice.py +192 -0
- package/hooks/git-hooks/verification_notice_context.py +253 -0
- package/hooks/git-hooks/verification_notice_state.py +237 -0
- package/hooks/git-hooks/verification_start.py +100 -0
- package/hooks/hooks.json +1 -120
- package/hooks/hooks_constants/banned_identifiers_constants.py +4 -0
- package/hooks/hooks_constants/bash_post_call_dispatcher_constants.py +14 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +1 -15
- package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -4
- package/hooks/hooks_constants/pr_done_reminder_constants.py +98 -0
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +10 -93
- package/hooks/hooks_constants/stop_dispatcher_constants.py +1 -4
- package/hooks/hooks_constants/test_bash_post_call_dispatcher_constants.py +19 -2
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +3 -66
- package/hooks/hooks_constants/test_pr_done_reminder_constants.py +40 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +46 -201
- package/hooks/hooks_constants/test_stop_dispatcher_constants.py +3 -25
- package/hooks/validation/test_post_tool_use_dispatcher.py +35 -298
- package/hooks/validators/run_all_validators.py +5 -1
- package/hooks/validators/security_checks.py +57 -2
- package/hooks/validators/test_hook_timing_harness.py +2 -5
- package/hooks/validators/test_run_all_validators_mutation_tool_parity.py +3 -11
- package/hooks/validators/test_run_all_validators_policy_lint.py +36 -0
- package/hooks/validators/test_security_checks.py +57 -0
- package/package.json +2 -2
- package/rules/confirm-implementation-forks.md +2 -0
- package/rules/durable-post-artifacts.md +2 -1
- package/rules/git-workflow.md +18 -6
- package/rules/pstack-host-mapping.md +48 -0
- package/rules/vault-context.md +3 -5
- package/rules/verify-runtime-state.md +7 -0
- package/scripts/audit-hooks-cli.mjs +5 -0
- package/scripts/audit-hooks.mjs +72 -16
- package/scripts/automatic_advisory/__init__.py +1 -0
- package/scripts/automatic_advisory/checkout.py +51 -0
- package/scripts/automatic_advisory/cli.py +334 -0
- package/scripts/automatic_advisory/config/__init__.py +1 -0
- package/scripts/automatic_advisory/config/constants.py +93 -0
- package/scripts/automatic_advisory/config/timing.py +4 -0
- package/scripts/automatic_advisory/configuration.py +197 -0
- package/scripts/automatic_advisory/execution.py +350 -0
- package/scripts/automatic_advisory/git.py +69 -0
- package/scripts/automatic_advisory/model.py +107 -0
- package/scripts/automatic_advisory/process_host.py +32 -0
- package/scripts/automatic_advisory/publisher.py +84 -0
- package/scripts/automatic_advisory/runner.py +399 -0
- package/scripts/automatic_advisory/state.py +116 -0
- package/scripts/automatic_advisory/window_flags.py +41 -0
- package/scripts/automatic_advisory/windows_job.py +122 -0
- 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/codex_compat_materializer.py +99 -13
- package/scripts/dev_env_scripts_constants/shared_tree_constants.py +4 -5
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/durable_post_lint.py +35 -43
- package/{.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/durable_post_lint_constants.py → scripts/durable_post_lint_config/config/constants.py} +10 -10
- package/{.agents/skills/_shared/pr-loop/scripts/test_durable_post_lint_constants.py → scripts/durable_post_lint_config/config/test_constants.py} +14 -1
- package/scripts/local_report_cli.py +184 -0
- package/scripts/local_report_core.py +247 -0
- package/scripts/local_report_publisher.py +12 -0
- package/scripts/local_report_validation.py +357 -0
- package/scripts/local_verification/__init__.py +23 -0
- package/scripts/local_verification/check_runner.py +364 -0
- package/scripts/local_verification/check_support.py +99 -0
- package/scripts/local_verification/cli.py +158 -0
- package/scripts/local_verification/command_runner.py +84 -0
- package/scripts/local_verification/config/__init__.py +1 -0
- package/scripts/local_verification/config/constants.py +89 -0
- package/scripts/local_verification/config/timing.py +1 -0
- package/scripts/local_verification/git_state.py +146 -0
- package/scripts/local_verification/manifest.py +224 -0
- package/scripts/local_verification/model.py +174 -0
- package/scripts/local_verification/runner.py +234 -0
- package/scripts/policy_lint/adapter_detectors.py +13 -6
- package/scripts/policy_lint/adapter_pairing.py +58 -3
- package/scripts/policy_lint/adapters.py +7 -4
- package/scripts/policy_lint/config/approved_test_pairs.py +323 -0
- 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/pr_verification/__init__.py +1 -0
- package/scripts/pr_verification/branch_refs.py +114 -0
- package/scripts/pr_verification/config/__init__.py +1 -0
- package/scripts/pr_verification/config/constants.py +84 -0
- package/scripts/pr_verification/config/timing.py +5 -0
- package/scripts/pr_verification/github.py +137 -0
- package/scripts/pr_verification/github_api.py +376 -0
- package/scripts/pr_verification/github_labels.py +88 -0
- package/scripts/pr_verification/github_parsing.py +182 -0
- package/scripts/pr_verification/github_transport.py +91 -0
- package/scripts/pr_verification/lock.py +122 -0
- package/scripts/pr_verification/model.py +43 -0
- package/scripts/pr_verification/requirements.txt +1 -0
- package/scripts/refresh_pstack_plugin_skills.mjs +200 -0
- package/scripts/shared_tree_paths.py +32 -3
- package/{.agents/skills/_shared/pr-loop/scripts → scripts}/test_durable_post_lint.py +97 -0
- package/scripts/test_shared_tree_paths.py +33 -0
- package/scripts/tests/test-audit-hooks-cli.mjs +150 -0
- package/scripts/tests/test-audit-hooks.mjs +94 -2
- package/scripts/tests/test_automatic_advisory.py +376 -0
- package/scripts/tests/test_automatic_advisory_job_cleanup.py +71 -0
- package/scripts/tests/test_automatic_advisory_polling.py +216 -0
- package/scripts/tests/test_automatic_advisory_recovery.py +320 -0
- package/scripts/tests/test_automatic_advisory_repairs.py +400 -0
- package/scripts/tests/test_automatic_advisory_settings.py +48 -0
- package/scripts/tests/test_automatic_advisory_window_flags.py +163 -0
- package/scripts/tests/test_closed_pr_label.py +157 -0
- package/scripts/tests/test_codex_compat_materializer.py +189 -6
- package/scripts/tests/test_github_labels.py +101 -0
- package/scripts/tests/test_github_transport.py +125 -0
- package/scripts/tests/test_local_report_publisher.py +396 -0
- package/scripts/tests/test_local_report_publisher_cli.py +85 -0
- package/scripts/tests/test_local_verification.py +348 -0
- package/scripts/tests/test_local_verification_cli.py +98 -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_pairing.py +163 -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_pr_verification_github.py +392 -0
- package/scripts/tests/test_pr_verification_lock.py +168 -0
- package/scripts/tests/test_rules.py +3 -7
- package/scripts/tests/test_verification_notice.py +347 -0
- package/.agents/skills/_shared/pr-loop/.claude/CLAUDE.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/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/blocking/ask_user_question_shape_blocker.py +0 -83
- package/hooks/blocking/bot_mention_comment_blocker.py +0 -76
- package/hooks/blocking/claude_md_orphan_file_blocker.py +0 -129
- package/hooks/blocking/cursor_cli_python_misfire_blocker.py +0 -108
- package/hooks/blocking/destructive_command_blocker.py +0 -2073
- package/hooks/blocking/fable_spawn_gate.py +0 -187
- package/hooks/blocking/luna_fast_mode_gate.py +0 -160
- package/hooks/blocking/nas_ssh_binary_enforcer.py +0 -163
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +0 -260
- package/hooks/blocking/package_inventory_stale_blocker.py +0 -107
- package/hooks/blocking/pii_prevention_blocker.py +0 -365
- package/hooks/blocking/piped_pytest_blocker.py +0 -1223
- package/hooks/blocking/question_to_user_enforcer.py +0 -130
- package/hooks/blocking/send_user_file_open_locally_blocker.py +0 -71
- package/hooks/blocking/sensitive_file_protector.py +0 -167
- package/hooks/blocking/session_edit_stage_gate.py +0 -684
- package/hooks/blocking/session_handoff_blocker.py +0 -182
- package/hooks/blocking/shell_substitution_blocker.py +0 -350
- package/hooks/blocking/test_ask_user_question_shape.py +0 -69
- package/hooks/blocking/test_bot_mention_comment_blocker.py +0 -131
- package/hooks/blocking/test_claude_md_orphan_file_blocker.py +0 -1277
- package/hooks/blocking/test_cursor_cli_python_misfire_blocker.py +0 -208
- package/hooks/blocking/test_destructive_command_blocker.py +0 -2024
- package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +0 -105
- package/hooks/blocking/test_destructive_command_blocker_no_verify.py +0 -122
- package/hooks/blocking/test_destructive_command_blocker_patterns.py +0 -133
- package/hooks/blocking/test_fable_spawn_gate.py +0 -381
- package/hooks/blocking/test_inventory_deadlock_resolution.py +0 -154
- package/hooks/blocking/test_luna_fast_mode_gate.py +0 -211
- package/hooks/blocking/test_nas_ssh_binary_enforcer.py +0 -225
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +0 -231
- package/hooks/blocking/test_package_inventory_stale_blocker.py +0 -382
- package/hooks/blocking/test_pii_prevention_blocker.py +0 -1222
- package/hooks/blocking/test_pii_prevention_windows_git_path.py +0 -41
- package/hooks/blocking/test_pii_write_surface_ephemeral.py +0 -221
- package/hooks/blocking/test_piped_pytest_blocker.py +0 -587
- package/hooks/blocking/test_precommit_code_rules_gate_native_owner.py +0 -233
- package/hooks/blocking/test_question_to_user_enforcer.py +0 -169
- package/hooks/blocking/test_send_user_file_open_locally_blocker.py +0 -118
- package/hooks/blocking/test_sensitive_file_protector.py +0 -365
- package/hooks/blocking/test_session_edit_stage_gate.py +0 -537
- package/hooks/blocking/test_session_edit_stage_gate_staging.py +0 -64
- package/hooks/blocking/test_session_edit_stage_gate_support.py +0 -204
- package/hooks/blocking/test_session_edit_stage_gate_tracker.py +0 -116
- package/hooks/blocking/test_session_handoff_blocker.py +0 -318
- package/hooks/blocking/test_shell_substitution_blocker.py +0 -298
- package/hooks/blocking/test_unscoped_search_blocker.py +0 -102
- package/hooks/blocking/test_write_existing_file_blocker.py +0 -122
- package/hooks/blocking/tests/test_pii_prevention_blocker.py +0 -259
- package/hooks/blocking/unscoped_search_blocker.py +0 -391
- package/hooks/blocking/write_existing_file_blocker.py +0 -124
- package/hooks/hooks_constants/bot_mention_comment_blocker_constants.py +0 -19
- package/hooks/hooks_constants/cursor_cli_python_misfire_blocker_constants.py +0 -79
- package/hooks/hooks_constants/fable_spawn_gate_constants.py +0 -61
- package/hooks/hooks_constants/luna_fast_mode_gate_constants.py +0 -45
- package/hooks/hooks_constants/nas_ssh_binary_enforcer_constants.py +0 -20
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +0 -57
- package/hooks/hooks_constants/send_user_file_open_locally_blocker_constants.py +0 -17
- package/hooks/hooks_constants/sensitive_file_protector_constants.py +0 -40
- package/hooks/hooks_constants/session_handoff_blocker_constants.py +0 -10
- package/hooks/hooks_constants/shell_substitution_blocker_constants.py +0 -80
- /package/.agents/skills/{_shared/pr-loop → session-continuity}/AGENTS.md +0 -0
- /package/{_shared/pr-loop → .agents/skills/session-continuity}/CLAUDE.md +0 -0
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
"""Tests for post_audit_thread_constants.py extracted constant set."""
|
|
2
|
-
|
|
3
|
-
import importlib.util
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
from types import ModuleType
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def _load_constants_module() -> ModuleType:
|
|
9
|
-
module_path = (
|
|
10
|
-
Path(__file__).parent.parent
|
|
11
|
-
/ "pr_loop_shared_constants"
|
|
12
|
-
/ "post_audit_thread_constants.py"
|
|
13
|
-
)
|
|
14
|
-
specification = importlib.util.spec_from_file_location(
|
|
15
|
-
"pr_loop_shared_constants.post_audit_thread_constants", module_path
|
|
16
|
-
)
|
|
17
|
-
assert specification is not None
|
|
18
|
-
assert specification.loader is not None
|
|
19
|
-
module = importlib.util.module_from_spec(specification)
|
|
20
|
-
specification.loader.exec_module(module)
|
|
21
|
-
return module
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
constants_module = _load_constants_module()
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def test_http_request_content_type_is_application_json() -> None:
|
|
28
|
-
assert constants_module.HTTP_REQUEST_CONTENT_TYPE == "application/json"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def test_http_method_post_constant_is_post() -> None:
|
|
32
|
-
assert constants_module.HTTP_METHOD_POST == "POST"
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def test_http_header_authorization_constant_is_authorization() -> None:
|
|
36
|
-
assert constants_module.HTTP_HEADER_AUTHORIZATION == "Authorization"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def test_http_header_accept_constant_is_accept() -> None:
|
|
40
|
-
assert constants_module.HTTP_HEADER_ACCEPT == "Accept"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def test_http_header_content_type_constant_is_content_type() -> None:
|
|
44
|
-
assert constants_module.HTTP_HEADER_CONTENT_TYPE == "Content-Type"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def test_http_header_github_api_version_constant_is_x_github_api_version() -> None:
|
|
48
|
-
assert constants_module.HTTP_HEADER_GITHUB_API_VERSION == "X-GitHub-Api-Version"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_http_header_user_agent_constant_is_user_agent() -> None:
|
|
52
|
-
assert constants_module.HTTP_HEADER_USER_AGENT == "User-Agent"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def test_http_authorization_bearer_prefix_is_bearer_with_trailing_space() -> None:
|
|
56
|
-
prefix = constants_module.HTTP_AUTHORIZATION_BEARER_PREFIX
|
|
57
|
-
assert prefix == "Bearer "
|
|
58
|
-
assert prefix.endswith(" ")
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def test_http_request_timeout_seconds_is_positive_int() -> None:
|
|
62
|
-
timeout_seconds = constants_module.HTTP_REQUEST_TIMEOUT_SECONDS
|
|
63
|
-
assert isinstance(timeout_seconds, int)
|
|
64
|
-
assert timeout_seconds > 0
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def test_error_response_preview_chars_is_positive_int() -> None:
|
|
68
|
-
preview_chars = constants_module.ERROR_RESPONSE_PREVIEW_CHARS
|
|
69
|
-
assert isinstance(preview_chars, int)
|
|
70
|
-
assert preview_chars > 0
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def test_single_review_api_path_template_uses_pr_number_placeholder() -> None:
|
|
74
|
-
template_text = constants_module.SINGLE_REVIEW_API_PATH_TEMPLATE
|
|
75
|
-
assert "{owner}" in template_text
|
|
76
|
-
assert "{repo}" in template_text
|
|
77
|
-
assert "{pr_number}" in template_text
|
|
78
|
-
assert "{review_id}" in template_text
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def test_single_review_comments_api_path_template_uses_pr_number_placeholder() -> None:
|
|
82
|
-
template_text = constants_module.SINGLE_REVIEW_COMMENTS_API_PATH_TEMPLATE
|
|
83
|
-
assert "{owner}" in template_text
|
|
84
|
-
assert "{repo}" in template_text
|
|
85
|
-
assert "{pr_number}" in template_text
|
|
86
|
-
assert "{review_id}" in template_text
|
|
87
|
-
assert template_text.endswith("/comments")
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def test_audit_body_skeleton_marker_tokens_present() -> None:
|
|
91
|
-
open_marker = constants_module.AUDIT_BODY_SKELETON_OPEN_MARKER
|
|
92
|
-
close_marker = constants_module.AUDIT_BODY_SKELETON_CLOSE_MARKER
|
|
93
|
-
assert open_marker.startswith("<!--") and open_marker.endswith("-->")
|
|
94
|
-
assert close_marker.startswith("<!--") and close_marker.endswith("-->")
|
|
95
|
-
assert open_marker != close_marker
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def test_template_path_resolves_to_existing_markdown_file() -> None:
|
|
99
|
-
resolved_path = constants_module.template_path()
|
|
100
|
-
assert resolved_path.is_file(), f"missing: {resolved_path}"
|
|
101
|
-
assert resolved_path.suffix == ".md"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def test_template_contains_skeleton_markers() -> None:
|
|
105
|
-
resolved_path = constants_module.template_path()
|
|
106
|
-
template_text = resolved_path.read_text(encoding="utf-8")
|
|
107
|
-
assert constants_module.AUDIT_BODY_SKELETON_OPEN_MARKER in template_text
|
|
108
|
-
assert constants_module.AUDIT_BODY_SKELETON_CLOSE_MARKER in template_text
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def test_live_test_fixture_names_are_not_exposed_from_production_config_module() -> None:
|
|
112
|
-
forbidden_attribute_names = [
|
|
113
|
-
"LIVE_TEST_OWNER",
|
|
114
|
-
"LIVE_TEST_REPO",
|
|
115
|
-
"LIVE_TEST_BRANCH_PREFIX",
|
|
116
|
-
"LIVE_TEST_PR_TITLE",
|
|
117
|
-
"LIVE_TEST_PR_BODY",
|
|
118
|
-
"LIVE_TEST_BASE_BRANCH",
|
|
119
|
-
"LIVE_TEST_FIXTURE_FILENAME",
|
|
120
|
-
"LIVE_TEST_FIXTURE_CONTENT",
|
|
121
|
-
"LIVE_TEST_FIXTURE_LINE_FOR_FINDING_ONE",
|
|
122
|
-
"LIVE_TEST_FIXTURE_LINE_FOR_FINDING_TWO",
|
|
123
|
-
"LIVE_TEST_FIXTURE_LINE_FOR_FINDING_THREE",
|
|
124
|
-
]
|
|
125
|
-
for each_attribute_name in forbidden_attribute_names:
|
|
126
|
-
assert not hasattr(constants_module, each_attribute_name), (
|
|
127
|
-
f"production config module exposes test-only fixture "
|
|
128
|
-
f"{each_attribute_name!r}; move it to test_post_audit_thread.py"
|
|
129
|
-
)
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# State schema
|
|
2
|
-
|
|
3
|
-
State each PR-loop workflow tracks across iterations. Workflows differ on persistence (in-memory vs files) and which fields they use; shapes overlap.
|
|
4
|
-
|
|
5
|
-
## Common fields
|
|
6
|
-
|
|
7
|
-
| Field | Type | Purpose |
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| `loop_count` | int | Iterations completed; bumps on each AUDIT or tick |
|
|
10
|
-
| `last_action` | enum | `fresh`, `audited`, `fixed` — drives next-step dispatch |
|
|
11
|
-
| `last_findings` | object | `{p0, p1, p2, total}` count of findings from most recent AUDIT |
|
|
12
|
-
| `audit_log` | list[str] | Per-iteration one-line summaries for the final report |
|
|
13
|
-
| `starting_sha` | str | `git rev-parse HEAD` at workflow start |
|
|
14
|
-
| `loop_comment_index` | dict | `{finding_id: {finding_comment_id, finding_comment_url, thread_node_id, fix_status, ...}}` (`thread_node_id` is the PR review thread node id — `PRRT_kwDOxxx` — captured at audit time when calling `get_review_comments`, used by `resolve_thread` at FIX time) |
|
|
15
|
-
|
|
16
|
-
## autoconverge (workflow and portable pacer)
|
|
17
|
-
|
|
18
|
-
Workflow runs hold round state in the workflow journal. On `pacer=portable`, the
|
|
19
|
-
continuous driver seeds `pr-converge-state.json` under the job directory and
|
|
20
|
-
advances phases through `portable_converge_driver.py`. Portable state carries
|
|
21
|
-
`current_head`, `phase`, `codex_clean_at`, `codex_down`, `codex_required`, and
|
|
22
|
-
pending `next` / `wait_seconds` stamps. Round shape and terminal gates are
|
|
23
|
-
documented in
|
|
24
|
-
[`../../.agents/skills/autoconverge/reference/convergence.md`](../../.agents/skills/autoconverge/reference/convergence.md).
|
|
25
|
-
The machine readiness checklist is
|
|
26
|
-
[`../../.agents/skills/autoconverge/reference/convergence-gates.md`](../../.agents/skills/autoconverge/reference/convergence-gates.md).
|
|
27
|
-
|
|
28
|
-
## Archived workflow extensions
|
|
29
|
-
|
|
30
|
-
Historical field lists for retired entry skills live under
|
|
31
|
-
`packages/claude-dev-env/.agents/skills-archived/`:
|
|
32
|
-
|
|
33
|
-
- **bugteam** — inline orchestrator state, `team_name`, `gate_round_count`, exit payload fields. See [`../../.agents/skills-archived/bugteam/SKILL.md`](../../.agents/skills-archived/bugteam/SKILL.md).
|
|
34
|
-
- **pr-converge** — file-backed multi-PR state, phase enum, dual persistence. See [`../../.agents/skills-archived/pr-converge/reference/state-schema.md`](../../.agents/skills-archived/pr-converge/reference/state-schema.md) and [`../../.agents/skills-archived/pr-converge/reference/multi-pr-orchestration.md`](../../.agents/skills-archived/pr-converge/reference/multi-pr-orchestration.md).
|
|
35
|
-
|
|
36
|
-
## Reset semantics
|
|
37
|
-
|
|
38
|
-
- **autoconverge** — portable state resets on a fresh `open-run`; workflow journal is per run id.
|
|
39
|
-
- **Archived bugteam** — cleared on each new invocation; see archived skill body.
|
|
40
|
-
- **Archived pr-converge** — see archived [`state-schema.md`](../../.agents/skills-archived/pr-converge/reference/state-schema.md); multi-PR file state persists across orchestrator runs and only `last_seen_comment_id` advances monotonically.
|
|
41
|
-
|
|
42
|
-
## Convergence checks
|
|
43
|
-
|
|
44
|
-
- **autoconverge** — `packages/claude-dev-env/_shared/pr-loop/scripts/check_convergence.py` is the single readiness source; gate labels are listed in [`../../.agents/skills/autoconverge/reference/convergence-gates.md`](../../.agents/skills/autoconverge/reference/convergence-gates.md). On pass, mark the PR ready (`gh pr ready`).
|
|
45
|
-
- **Archived pr-converge** — same script and archived [`convergence-gates.md`](../../.agents/skills-archived/pr-converge/reference/convergence-gates.md) reference.
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
# Worker-spawn protocol
|
|
2
|
-
|
|
3
|
-
Single home for the worker-spawn dispatcher contract and for Claude-only
|
|
4
|
-
slash-step host routing. Skills that need a role-bound headless worker call
|
|
5
|
-
[`scripts/resolve_worker_spawn.py`](../../scripts/resolve_worker_spawn.py)
|
|
6
|
-
(or import `resolve_worker_spawn`) and read this page for the tier walk, inputs,
|
|
7
|
-
JSON result shape, host rules, and setup. Skills that run a Claude-only slash
|
|
8
|
-
step (for example `/code-review`) read the code-review host-routing section.
|
|
9
|
-
|
|
10
|
-
Composed helpers (preflight, headless runners, and the code-review invoker)
|
|
11
|
-
stay documented at their own modules; this page states how callers use them.
|
|
12
|
-
|
|
13
|
-
## Three tiers
|
|
14
|
-
|
|
15
|
-
Walk order is fixed: soft-gate preflight for tier 1, then tier 1, then host
|
|
16
|
-
branching for tiers 2 and 3.
|
|
17
|
-
|
|
18
|
-
| Tier | Name | Who runs it |
|
|
19
|
-
|---|---|---|
|
|
20
|
-
| 1 | Grok headless | Python helper: `grok_worker_preflight` then `grok_headless_runner.run_headless_worker` |
|
|
21
|
-
| 2 | `claude_agent_required` | **Not** the Python helper. A stop signal so the **calling skill / harness** runs the Claude Code Agent tool itself |
|
|
22
|
-
| 3 | Claude headless | Python helper: `claude_chain_runner.run_claude` with `-p --output-format json --agent <stem>`, prompt body on stdin from the prompt file, and subprocess `cwd` set to the caller's working directory |
|
|
23
|
-
|
|
24
|
-
### `claude_agent_required` boundary
|
|
25
|
-
|
|
26
|
-
A Python helper cannot spawn Claude Code Agent-tool subagents. On a **Claude**
|
|
27
|
-
host, when the claude headless tier is **not** enabled (`--enable-claude-tier`
|
|
28
|
-
absent / `is_claude_tier_enabled=False`), a grok fallthrough records tier 2 with
|
|
29
|
-
reason `claude_agent_required`, leaves `tier_used` null, and returns. The
|
|
30
|
-
calling skill must then run the Agent tool in-process.
|
|
31
|
-
|
|
32
|
-
On a **ThirdParty** host, or when the claude tier is enabled on a Claude host,
|
|
33
|
-
the dispatcher continues to tier 3.
|
|
34
|
-
|
|
35
|
-
## Tier-1 fleets via grok-spawn
|
|
36
|
-
|
|
37
|
-
For a fleet of tier-1 grok workers (batch spec in, reports out), use the
|
|
38
|
-
**grok-spawn** skill when that skill is installed on the host (it ships on a
|
|
39
|
-
sibling stack and is not part of this dispatcher page). When present, that
|
|
40
|
-
skill owns the batch playbook and flag profiles under its reference docs.
|
|
41
|
-
This page stays the single-worker dispatcher contract (`resolve_worker_spawn`).
|
|
42
|
-
|
|
43
|
-
The calling session owns verification and every commit, push, or GitHub post.
|
|
44
|
-
Workers never commit or post.
|
|
45
|
-
|
|
46
|
-
## Required inputs
|
|
47
|
-
|
|
48
|
-
### CLI
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
python resolve_worker_spawn.py \
|
|
52
|
-
--role <role> \
|
|
53
|
-
--prompt-file <path> \
|
|
54
|
-
--cwd <dir> \
|
|
55
|
-
--run-temp-dir <dir> \
|
|
56
|
-
[--timeout-seconds N] \
|
|
57
|
-
[--enable-claude-tier]
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
| Flag | Required | Meaning |
|
|
61
|
-
|---|---|---|
|
|
62
|
-
| `--role` | no (default `bugteam`) | Role name for preflight agent-set checks; mapped to the primary agent stem for headless `--agent` (for example `bugteam` → `code-quality-agent`, `clean-coder` → `clean-coder`; unknown roles fall back to the raw role string) |
|
|
63
|
-
| `--prompt-file` | yes | Prompt file path for headless workers |
|
|
64
|
-
| `--cwd` | yes | Working directory for headless grok and claude workers |
|
|
65
|
-
| `--run-temp-dir` | yes | Run-scoped directory for leader sockets and preflight cache (created if missing) |
|
|
66
|
-
| `--timeout-seconds` | no (default `600`) | Per-tier timeout in seconds |
|
|
67
|
-
| `--enable-claude-tier` | no | Allow tier 3 on a Claude host |
|
|
68
|
-
|
|
69
|
-
There is no separate outcome-file flag. The result surface is **stdout JSON**
|
|
70
|
-
plus the process exit code.
|
|
71
|
-
|
|
72
|
-
### Import API
|
|
73
|
-
|
|
74
|
-
`resolve_worker_spawn(...)` takes keyword-only arguments:
|
|
75
|
-
`role`, `prompt_file`, `working_directory`, `timeout_seconds`,
|
|
76
|
-
`is_claude_tier_enabled`, `run_state_directory`.
|
|
77
|
-
`encode_spawn_outcome` turns a `SpawnOutcome` into the same JSON shape the CLI
|
|
78
|
-
prints.
|
|
79
|
-
|
|
80
|
-
The grok tier runs with no turn cap; `timeout_seconds` is its only bound.
|
|
81
|
-
|
|
82
|
-
## JSON result shape
|
|
83
|
-
|
|
84
|
-
Stdout is one JSON object:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"tier_used": 1,
|
|
89
|
-
"ok": true,
|
|
90
|
-
"attempts": [
|
|
91
|
-
{"tier": 1, "ok": true, "reason": null}
|
|
92
|
-
],
|
|
93
|
-
"output": "<serving tier stdout>",
|
|
94
|
-
"returncode": 0
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
| Key | Meaning |
|
|
99
|
-
|---|---|
|
|
100
|
-
| `tier_used` | Serving tier number (`1` or `3`), or `null` when no tier served |
|
|
101
|
-
| `ok` | Whether the serving call completed successfully |
|
|
102
|
-
| `attempts` | Ordered list of tries: each `{tier, ok, reason}` |
|
|
103
|
-
| `output` | Captured stdout from the serving tier (empty when none) |
|
|
104
|
-
| `returncode` | Process return code from the last tier run (or config-error code) |
|
|
105
|
-
|
|
106
|
-
`attempts` is in tried order. A Claude-host stop records tier `2` with
|
|
107
|
-
`reason: "claude_agent_required"`. Preflight or grok fallthrough reasons use the
|
|
108
|
-
preflight/runner classification strings (for example `grok_binary_missing`,
|
|
109
|
-
`usage_limit`).
|
|
110
|
-
|
|
111
|
-
### Exit codes
|
|
112
|
-
|
|
113
|
-
| Code | Meaning |
|
|
114
|
-
|---|---|
|
|
115
|
-
| `0` | A tier served (`tier_used` is not null) |
|
|
116
|
-
| `2` | Exhausted — no tier served |
|
|
117
|
-
| `3` | Config error: the `--prompt-file` path is not an existing file (`output` = `prompt_file_missing`) or claude chain configuration missing or invalid |
|
|
118
|
-
|
|
119
|
-
## Host detection
|
|
120
|
-
|
|
121
|
-
After a grok fallthrough the dispatcher calls `detect_host_profile()` from
|
|
122
|
-
`tier_model_ids` (advisor scripts). Detection order:
|
|
123
|
-
|
|
124
|
-
1. `ADVISOR_HOST_PROFILE` when set — must be `Claude`, `Codex`, or `ThirdParty` (any letter case).
|
|
125
|
-
2. `THIRD_PARTY` when truthy — `1`, `true`, `yes`, or `on`.
|
|
126
|
-
3. Default: `Claude`.
|
|
127
|
-
|
|
128
|
-
Profiles are the real names `Claude`, `Codex`, and `ThirdParty` (not a separate Grok host
|
|
129
|
-
profile). Grok is tier 1 on every host; host profile only chooses the post-grok
|
|
130
|
-
branch (Agent-tool handoff vs headless claude chain). A Codex profile takes the
|
|
131
|
-
non-Claude branch.
|
|
132
|
-
|
|
133
|
-
## Code-review host routing
|
|
134
|
-
|
|
135
|
-
Claude-only slash steps need a Claude Code harness. The built-in
|
|
136
|
-
`/code-review` command is the main case. The host-routing pair is:
|
|
137
|
-
|
|
138
|
-
- `detect_host_profile()` from `tier_model_ids` — same host detection as the
|
|
139
|
-
worker-spawn dispatcher above
|
|
140
|
-
- `invoke_code_review` — host-aware invoker for `/code-review` (lives next to
|
|
141
|
-
`resolve_worker_spawn` under the package scripts tree)
|
|
142
|
-
|
|
143
|
-
Mode decision:
|
|
144
|
-
|
|
145
|
-
| Host profile | Session model | Mode | Who runs `/code-review` |
|
|
146
|
-
|---|---|---|---|
|
|
147
|
-
| `Claude` | `opus` | `in_session` | The calling skill runs the slash command in-process |
|
|
148
|
-
| `Claude` | any other alias | `chain` | Headless spawn through `claude_chain_runner` |
|
|
149
|
-
| `ThirdParty` | any | `chain` | Headless spawn through `claude_chain_runner` |
|
|
150
|
-
|
|
151
|
-
The review always runs at effort **high** on model **opus**. Chain mode builds
|
|
152
|
-
a single-turn prompt `/code-review ultra --fix`, pins `--model opus`, sets
|
|
153
|
-
subprocess `cwd` to the PR working tree, and reads stdin from the empty stream
|
|
154
|
-
so the spawn does not wait for input.
|
|
155
|
-
|
|
156
|
-
After a chain run, a non-empty `git status --porcelain` means the review
|
|
157
|
-
applied fixes. The calling host commits and pushes those fixes per the fix
|
|
158
|
-
protocol. The chain process never commits or posts. A clean stamp requires
|
|
159
|
-
`returncode == 0` and a non-null `served_command` plus a clean tree —
|
|
160
|
-
`dirty_tree` false alone is not enough when the chain failed or never served.
|
|
161
|
-
|
|
162
|
-
GitHub transport (`pr-loop-cloud-transport`) is a separate axis from this
|
|
163
|
-
harness branch. That skill routes `gh` vs MCP; it does not change which host
|
|
164
|
-
can run Claude-only slash commands.
|
|
165
|
-
|
|
166
|
-
## Leader-socket rule
|
|
167
|
-
|
|
168
|
-
Every concurrent grok process gets its own `--leader-socket` path under the
|
|
169
|
-
caller-supplied run temp directory. The headless runner mints a unique
|
|
170
|
-
`grok-leader-<uuid>.sock` per invocation. Preflight auth and ping probes use
|
|
171
|
-
their own fixed socket filenames under the same directory so they never share a
|
|
172
|
-
socket with a live worker.
|
|
173
|
-
|
|
174
|
-
## Cloud setup
|
|
175
|
-
|
|
176
|
-
Unattended grok auth uses the `XAI_API_KEY` environment variable. Install the
|
|
177
|
-
CLI via the vendor curl installer or the `@xai-official/grok` package. Keep
|
|
178
|
-
agent definitions and hook config in parity with `npx claude-dev-env` so the
|
|
179
|
-
preflight role-agent check and local `~/.claude` layout match what the worker
|
|
180
|
-
expects.
|
|
181
|
-
|
|
182
|
-
Use placeholders for account-specific values; do not hardcode personal paths or
|
|
183
|
-
keys in skills or docs.
|
|
184
|
-
|
|
185
|
-
## GitHub transport
|
|
186
|
-
|
|
187
|
-
`pr-loop-cloud-transport` is a separate axis. This utility never posts reviews,
|
|
188
|
-
opens PRs, or substitutes `gh` for MCP. GitHub reachability and cloud session
|
|
189
|
-
routing stay outside the worker-spawn contract.
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""PreToolUse hook that enforces AskUserQuestion field shape."""
|
|
3
|
-
|
|
4
|
-
from __future__ import annotations
|
|
5
|
-
|
|
6
|
-
import json
|
|
7
|
-
import sys
|
|
8
|
-
from collections.abc import Mapping, Sequence
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
|
|
11
|
-
_hooks_dir = str(Path(__file__).resolve().parent.parent)
|
|
12
|
-
if _hooks_dir not in sys.path:
|
|
13
|
-
sys.path.insert(0, _hooks_dir)
|
|
14
|
-
|
|
15
|
-
from hooks_constants.ask_user_question_shape import ( # noqa: E402
|
|
16
|
-
analyze_ask_user_question_shape,
|
|
17
|
-
)
|
|
18
|
-
from hooks_constants.ask_user_question_shape_constants import ( # noqa: E402
|
|
19
|
-
ASK_USER_QUESTION_TOOL_NAME,
|
|
20
|
-
LEAN_QUESTION_BLOCK_GUIDANCE,
|
|
21
|
-
LEAN_QUESTION_BLOCK_PREFIX,
|
|
22
|
-
LEAN_QUESTION_VIOLATION_SEPARATOR,
|
|
23
|
-
USER_FACING_LEAN_QUESTION_NOTICE,
|
|
24
|
-
)
|
|
25
|
-
from hooks_constants.hook_block_logger import log_hook_block # noqa: E402
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def build_lean_block_reason(all_violations: Sequence[str]) -> str:
|
|
29
|
-
"""Build a deny reason that names each field-shape violation."""
|
|
30
|
-
violation_list = LEAN_QUESTION_VIOLATION_SEPARATOR.join(all_violations)
|
|
31
|
-
return f"{LEAN_QUESTION_BLOCK_PREFIX}{violation_list}. {LEAN_QUESTION_BLOCK_GUIDANCE}"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def evaluate(payload_by_key: Mapping[str, object]) -> str | None:
|
|
35
|
-
"""Return a deny reason when an AskUserQuestion payload breaks field shape."""
|
|
36
|
-
tool_name = payload_by_key.get("tool_name", "")
|
|
37
|
-
tool_input = payload_by_key.get("tool_input", {})
|
|
38
|
-
if tool_name != ASK_USER_QUESTION_TOOL_NAME:
|
|
39
|
-
return None
|
|
40
|
-
if not isinstance(tool_input, Mapping):
|
|
41
|
-
return None
|
|
42
|
-
shape_result = analyze_ask_user_question_shape(tool_input)
|
|
43
|
-
if shape_result.is_lean:
|
|
44
|
-
return None
|
|
45
|
-
return build_lean_block_reason(shape_result.all_violations)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def build_deny_payload(deny_reason: str) -> dict[str, object]:
|
|
49
|
-
"""Build the standard PreToolUse deny payload for a shape violation."""
|
|
50
|
-
log_hook_block(
|
|
51
|
-
calling_hook_name="ask_user_question_shape_blocker.py",
|
|
52
|
-
hook_event="PreToolUse",
|
|
53
|
-
block_reason=deny_reason,
|
|
54
|
-
)
|
|
55
|
-
return {
|
|
56
|
-
"hookSpecificOutput": {
|
|
57
|
-
"hookEventName": "PreToolUse",
|
|
58
|
-
"permissionDecision": "deny",
|
|
59
|
-
"permissionDecisionReason": deny_reason,
|
|
60
|
-
},
|
|
61
|
-
"systemMessage": USER_FACING_LEAN_QUESTION_NOTICE,
|
|
62
|
-
"suppressOutput": True,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def main() -> None:
|
|
67
|
-
"""Read one PreToolUse payload and deny malformed question shape."""
|
|
68
|
-
try:
|
|
69
|
-
payload_by_key = json.load(sys.stdin)
|
|
70
|
-
except json.JSONDecodeError:
|
|
71
|
-
sys.exit(0)
|
|
72
|
-
|
|
73
|
-
if not isinstance(payload_by_key, dict):
|
|
74
|
-
sys.exit(0)
|
|
75
|
-
deny_reason = evaluate(payload_by_key)
|
|
76
|
-
if deny_reason is None:
|
|
77
|
-
sys.exit(0)
|
|
78
|
-
sys.stdout.write(json.dumps(build_deny_payload(deny_reason)))
|
|
79
|
-
sys.stdout.flush()
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if __name__ == "__main__":
|
|
83
|
-
main()
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""PreToolUse hook: block @cursor or @copilot mentions in add_issue_comment body.
|
|
3
|
-
|
|
4
|
-
Bugbot trigger requires exactly ``bugbot run`` with no other text. Copilot review
|
|
5
|
-
requires the GitHub REST API endpoint, not an issue comment mention. This hook
|
|
6
|
-
catches both mistakes and returns the correct procedure for each.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import json
|
|
10
|
-
import sys
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
|
|
13
|
-
_hooks_dir = str(Path(__file__).resolve().parent.parent)
|
|
14
|
-
if _hooks_dir not in sys.path:
|
|
15
|
-
sys.path.insert(0, _hooks_dir)
|
|
16
|
-
|
|
17
|
-
from hooks_constants.bot_mention_comment_blocker_constants import ( # noqa: E402
|
|
18
|
-
COPILOT_MENTION_TOKEN,
|
|
19
|
-
CORRECTIVE_MESSAGE_COPILOT,
|
|
20
|
-
CORRECTIVE_MESSAGE_CURSOR,
|
|
21
|
-
CURSOR_MENTION_TOKEN,
|
|
22
|
-
TOOL_NAME,
|
|
23
|
-
)
|
|
24
|
-
from hooks_constants.hook_block_logger import log_hook_block # noqa: E402
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def _body_contains_token(body: str, token: str) -> bool:
|
|
28
|
-
return token.lower() in body.lower()
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def _detect_bot_mention(body: str) -> str | None:
|
|
32
|
-
"""Return corrective message if body contains a blocked mention, else None."""
|
|
33
|
-
if _body_contains_token(body, COPILOT_MENTION_TOKEN):
|
|
34
|
-
return CORRECTIVE_MESSAGE_COPILOT
|
|
35
|
-
if _body_contains_token(body, CURSOR_MENTION_TOKEN):
|
|
36
|
-
return CORRECTIVE_MESSAGE_CURSOR
|
|
37
|
-
return None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def main() -> None:
|
|
41
|
-
try:
|
|
42
|
-
hook_input = json.load(sys.stdin)
|
|
43
|
-
except json.JSONDecodeError:
|
|
44
|
-
sys.exit(0)
|
|
45
|
-
|
|
46
|
-
if hook_input.get("tool_name", "") != TOOL_NAME:
|
|
47
|
-
sys.exit(0)
|
|
48
|
-
|
|
49
|
-
body = hook_input.get("tool_input", {}).get("body", "")
|
|
50
|
-
if not body:
|
|
51
|
-
sys.exit(0)
|
|
52
|
-
|
|
53
|
-
corrective_message = _detect_bot_mention(body)
|
|
54
|
-
if corrective_message is None:
|
|
55
|
-
sys.exit(0)
|
|
56
|
-
|
|
57
|
-
deny_payload = {
|
|
58
|
-
"hookSpecificOutput": {
|
|
59
|
-
"hookEventName": "PreToolUse",
|
|
60
|
-
"permissionDecision": "deny",
|
|
61
|
-
"permissionDecisionReason": corrective_message,
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
log_hook_block(
|
|
65
|
-
calling_hook_name="bot_mention_comment_blocker.py",
|
|
66
|
-
hook_event="PreToolUse",
|
|
67
|
-
block_reason=corrective_message,
|
|
68
|
-
tool_name=TOOL_NAME,
|
|
69
|
-
)
|
|
70
|
-
print(json.dumps(deny_payload))
|
|
71
|
-
sys.stdout.flush()
|
|
72
|
-
sys.exit(0)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if __name__ == "__main__":
|
|
76
|
-
main()
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""PreToolUse hook: blocks a per-directory CLAUDE.md that names a file absent from its subtree.
|
|
3
|
-
|
|
4
|
-
A per-directory ``CLAUDE.md`` documents the files reachable from its own
|
|
5
|
-
directory in a markdown table whose first column names each file in backticks,
|
|
6
|
-
and shows run commands inside fenced code blocks that invoke those files. When a
|
|
7
|
-
first-column cell, or an interpreter invocation inside a fenced run command
|
|
8
|
-
(``python script.py``), names a bare filename that exists nowhere under the scan
|
|
9
|
-
root (the CLAUDE.md directory's parent, which covers the directory, its
|
|
10
|
-
subdirectories, and its siblings), the doc points a reader at a file that is not
|
|
11
|
-
there. This hook fires on Write, Edit, and MultiEdit targeting a file named
|
|
12
|
-
``CLAUDE.md`` and blocks the write when any such cell or run command names a file
|
|
13
|
-
absent from the scan root. A table block or a run-command fence whose own region
|
|
14
|
-
declares an explicit relative-path source (a ``../`` token, in the rows/fence or
|
|
15
|
-
the prose that introduces it) documents files outside the subtree, so that block's
|
|
16
|
-
rows or that fence's commands are left alone — the exemption is scoped to the
|
|
17
|
-
region, not the whole file.
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
import sys
|
|
21
|
-
from pathlib import Path
|
|
22
|
-
|
|
23
|
-
try:
|
|
24
|
-
_hooks_root_directory = str(Path(__file__).resolve().parent.parent)
|
|
25
|
-
_blocking_directory = str(Path(__file__).resolve().parent)
|
|
26
|
-
for each_bootstrap_directory in (_hooks_root_directory, _blocking_directory):
|
|
27
|
-
if each_bootstrap_directory not in sys.path:
|
|
28
|
-
sys.path.insert(0, each_bootstrap_directory)
|
|
29
|
-
from claude_md_orphan_file_blocker_parts import (
|
|
30
|
-
decision,
|
|
31
|
-
references,
|
|
32
|
-
scan_plan,
|
|
33
|
-
subtree_scan,
|
|
34
|
-
)
|
|
35
|
-
from claude_md_orphan_file_blocker_parts.subtree_scan import (
|
|
36
|
-
MAX_SUBTREE_FILES_SCANNED, # noqa: F401
|
|
37
|
-
)
|
|
38
|
-
from inventory_intent_records import records
|
|
39
|
-
|
|
40
|
-
from hooks_constants.pre_tool_use_stdin import (
|
|
41
|
-
read_hook_input_dictionary_from_stdin,
|
|
42
|
-
)
|
|
43
|
-
except ImportError as import_error:
|
|
44
|
-
raise ImportError(
|
|
45
|
-
"claude_md_orphan_file_blocker: cannot import its parts submodules; "
|
|
46
|
-
"ensure the hooks directory is importable."
|
|
47
|
-
) from import_error
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
is_claude_md_file = references.is_claude_md_file
|
|
51
|
-
find_referenced_filenames = references.find_referenced_filenames
|
|
52
|
-
find_run_command_filenames = references.find_run_command_filenames
|
|
53
|
-
find_missing_filenames = subtree_scan.find_missing_filenames
|
|
54
|
-
build_orphan_scan_plan = scan_plan.build_orphan_scan_plan
|
|
55
|
-
collect_missing_filenames = scan_plan.collect_missing_filenames
|
|
56
|
-
deny_orphan_files = decision.deny_orphan_files
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def _partition_by_file_intent(
|
|
60
|
-
session_id: str, directory: str, all_missing_filenames: list[str]
|
|
61
|
-
) -> tuple[list[str], list[str]]:
|
|
62
|
-
"""Split missing filenames into those with a pending file intent and those without."""
|
|
63
|
-
matched_filenames = [
|
|
64
|
-
each_filename
|
|
65
|
-
for each_filename in all_missing_filenames
|
|
66
|
-
if records.has_fresh_file_intent(session_id, directory, each_filename)
|
|
67
|
-
]
|
|
68
|
-
unmatched_filenames = [
|
|
69
|
-
each_filename
|
|
70
|
-
for each_filename in all_missing_filenames
|
|
71
|
-
if each_filename not in matched_filenames
|
|
72
|
-
]
|
|
73
|
-
return matched_filenames, unmatched_filenames
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def _emit_orphan_decision(
|
|
77
|
-
input_data: dict,
|
|
78
|
-
tool_name: str,
|
|
79
|
-
file_path: str,
|
|
80
|
-
directory: str,
|
|
81
|
-
all_missing_filenames: list[str],
|
|
82
|
-
) -> None:
|
|
83
|
-
"""Consume covered rows and deny any genuine orphan the change introduces."""
|
|
84
|
-
session_id = str(input_data.get("session_id") or "")
|
|
85
|
-
matched_filenames, unmatched_filenames = _partition_by_file_intent(
|
|
86
|
-
session_id, directory, all_missing_filenames
|
|
87
|
-
)
|
|
88
|
-
if unmatched_filenames:
|
|
89
|
-
for each_filename in unmatched_filenames:
|
|
90
|
-
records.record_row_intent(session_id, directory, each_filename)
|
|
91
|
-
deny_orphan_files(tool_name, file_path, directory, unmatched_filenames)
|
|
92
|
-
return
|
|
93
|
-
for each_filename in matched_filenames:
|
|
94
|
-
records.consume_file_intent(session_id, directory, each_filename)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def main() -> None:
|
|
98
|
-
"""Read the PreToolUse payload from stdin and block an orphan-file CLAUDE.md."""
|
|
99
|
-
input_data = read_hook_input_dictionary_from_stdin()
|
|
100
|
-
if input_data is None:
|
|
101
|
-
sys.exit(0)
|
|
102
|
-
tool_name = input_data.get("tool_name", "")
|
|
103
|
-
if not isinstance(tool_name, str):
|
|
104
|
-
sys.exit(0)
|
|
105
|
-
tool_input = input_data.get("tool_input", {})
|
|
106
|
-
if not isinstance(tool_input, dict):
|
|
107
|
-
sys.exit(0)
|
|
108
|
-
if tool_name not in ("Write", "Edit", "MultiEdit"):
|
|
109
|
-
sys.exit(0)
|
|
110
|
-
file_path = tool_input.get("file_path", "")
|
|
111
|
-
if not isinstance(file_path, str) or not is_claude_md_file(file_path):
|
|
112
|
-
sys.exit(0)
|
|
113
|
-
claude_md_directory = Path(file_path).resolve().parent
|
|
114
|
-
if not claude_md_directory.is_dir():
|
|
115
|
-
sys.exit(0)
|
|
116
|
-
scan_plan_result = build_orphan_scan_plan(tool_name, tool_input, file_path, claude_md_directory)
|
|
117
|
-
if not scan_plan_result.candidate_contents:
|
|
118
|
-
sys.exit(0)
|
|
119
|
-
missing_filenames = collect_missing_filenames(scan_plan_result, claude_md_directory)
|
|
120
|
-
if not missing_filenames:
|
|
121
|
-
sys.exit(0)
|
|
122
|
-
_emit_orphan_decision(
|
|
123
|
-
input_data, tool_name, file_path, str(claude_md_directory), missing_filenames
|
|
124
|
-
)
|
|
125
|
-
sys.exit(0)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if __name__ == "__main__":
|
|
129
|
-
main()
|