claude-dev-env 2.3.0 → 2.5.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/CLAUDE.md +53 -48
- package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
- package/_shared/pr-loop/scripts/code_rules_gate.py +4 -2
- package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
- package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
- package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
- package/_shared/pr-loop/worker-spawn.md +1 -1
- package/agents/CLAUDE.md +3 -1
- package/agents/caveman.md +0 -1
- package/agents/clasp-deployment-orchestrator.md +0 -1
- package/agents/clean-coder.md +0 -1
- package/agents/code-advisor.md +0 -1
- package/agents/code-quality-agent.md +1 -2
- package/agents/code-verifier.md +3 -4
- package/agents/deep-research.md +0 -1
- package/agents/docs-agent.md +0 -1
- package/agents/git-commit-crafter.md +0 -1
- package/agents/issue-tracker.md +42 -0
- package/agents/plan-packet-validator.md +0 -1
- package/agents/pr-description-writer.md +0 -1
- package/agents/skill-writer-agent.md +84 -0
- package/agents/test_agent_frontmatter.py +67 -18
- package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +105 -3
- package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +29 -13
- package/bin/CLAUDE.md +68 -5
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install-constants.mjs +88 -0
- package/bin/install.mjs +1138 -114
- package/bin/install.prune.test.mjs +869 -19
- package/bin/install.test.mjs +906 -2
- package/commands/implement.md +1 -1
- package/commands/right-size.md +1 -1
- package/docs/CLAUDE.md +2 -0
- package/docs/host-pool-health-monitor.md +102 -0
- package/docs/references/CLAUDE.md +5 -2
- package/docs/references/advisor-tool.md +13 -0
- package/docs/references/code-review-enforcement.md +107 -0
- package/docs/references/team-advisor-skill.md +14 -0
- package/docs/wsl-docker-cowork-starter-matrix.md +89 -0
- package/hooks/blocking/CLAUDE.md +9 -1
- package/hooks/blocking/code_review_enforcement_config_bootstrap.py +53 -0
- package/hooks/blocking/code_review_gate_deny.py +74 -0
- package/hooks/blocking/code_review_pr_create_gate.py +198 -0
- package/hooks/blocking/code_review_push_gate.py +145 -0
- package/hooks/blocking/code_review_stamp_directory_write_blocker.py +348 -0
- package/hooks/blocking/code_review_stamp_store.py +233 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +7 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +15 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +212 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +138 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +49 -0
- package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +38 -0
- package/hooks/blocking/code_verifier_spawn_preflight_gate.py +39 -27
- package/hooks/blocking/config/__init__.py +5 -5
- package/hooks/blocking/config/code_review_enforcement_constants.py +113 -0
- package/hooks/blocking/config/test_code_review_enforcement_constants.py +113 -0
- package/hooks/blocking/config/verified_commit_constants.py +160 -155
- package/hooks/blocking/conftest.py +2 -0
- package/hooks/blocking/convergence_gate_blocker.py +112 -23
- package/hooks/blocking/destructive_command_blocker.py +19 -6
- package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
- package/hooks/blocking/pr_description_proof_of_work.py +52 -34
- package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
- package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +4 -1
- package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +62 -0
- package/hooks/blocking/test_code_review_gate_deny.py +54 -0
- package/hooks/blocking/test_code_review_pr_create_gate.py +199 -0
- package/hooks/blocking/test_code_review_push_gate.py +205 -0
- package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +199 -0
- package/hooks/blocking/test_code_review_stamp_store.py +205 -0
- package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +124 -2
- package/hooks/blocking/test_convergence_gate_blocker.py +153 -5
- package/hooks/blocking/test_destructive_command_blocker.py +1 -1
- package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +45 -0
- package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
- package/hooks/blocking/test_pr_description_proof_of_work.py +151 -0
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +17 -8
- package/hooks/blocking/test_verdict_directory_write_blocker.py +808 -808
- package/hooks/blocking/test_verification_verdict_store.py +974 -903
- package/hooks/blocking/test_verified_commit_gate.py +581 -581
- package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +114 -2
- package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
- package/hooks/blocking/verification_verdict_store.py +1039 -1014
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +29 -17
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +35 -0
- package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
- package/hooks/blocking/verifier_verdict_minter.py +280 -280
- package/hooks/blocking/volatile_path_in_post_blocker.py +69 -8
- package/hooks/git-hooks/git_hooks_constants/__init__.py +6 -0
- package/hooks/git-hooks/pre_push.py +89 -2
- package/hooks/git-hooks/test_pre_push.py +128 -0
- package/hooks/hooks.json +26 -1
- package/hooks/hooks_constants/CLAUDE.md +3 -1
- package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +8 -0
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +26 -11
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +20 -3
- package/hooks/hooks_constants/destructive_command_segment_constants.py +3 -1
- package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
- package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
- package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -4
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
- package/hooks/hooks_constants/pyproject_config_discovery_constants.py +16 -0
- package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
- package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +24 -0
- package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +8 -1
- package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
- package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
- package/hooks/pyproject.toml +1 -0
- package/hooks/validators/CLAUDE.md +2 -0
- package/hooks/validators/config/__init__.py +0 -0
- package/hooks/validators/config/directory_exemption_constants.py +183 -0
- package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
- package/hooks/validators/conftest.py +4 -0
- package/hooks/validators/mypy_integration.py +63 -50
- package/hooks/validators/pyproject_config_discovery.py +101 -0
- package/hooks/validators/ruff_integration.py +257 -25
- package/hooks/validators/run_all_validators.py +223 -19
- package/hooks/validators/test_directory_exemption_constants.py +185 -0
- package/hooks/validators/test_mypy_integration.py +32 -0
- package/hooks/validators/test_pyproject_config_discovery.py +94 -0
- package/hooks/validators/test_python_antipattern_checks.py +110 -5
- package/hooks/validators/test_ruff_integration.py +160 -2
- package/hooks/validators/test_run_all_validators.py +140 -68
- package/hooks/validators/test_run_all_validators_config_discovery.py +123 -0
- package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
- package/package.json +10 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/docstring-prose-matches-implementation.md +45 -67
- package/rules/durable-post-artifacts.md +7 -0
- package/rules/state-what-is.md +25 -0
- package/rules/verified-commit-gate-skip.md +1 -1
- package/scripts/CLAUDE.md +1 -0
- package/scripts/Capture-PoolHealth.ps1 +410 -0
- package/scripts/_code_review_test_support.py +404 -0
- package/scripts/claude_chain_runner.py +141 -1
- package/scripts/codec_forwarding_test_support.py +83 -0
- package/scripts/conftest.py +23 -0
- package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -2
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +53 -1
- package/scripts/dev_env_scripts_constants/code_review_constants.py +129 -12
- package/scripts/dev_env_scripts_constants/test_code_review_constants.py +55 -0
- package/scripts/invoke_code_review.py +550 -38
- package/scripts/resolve_worker_spawn.py +626 -619
- package/scripts/spawn_grok_batch.py +672 -672
- package/scripts/test_claude_chain_runner.py +131 -0
- package/scripts/test_invoke_code_review_chain.py +70 -0
- package/scripts/test_invoke_code_review_cli.py +192 -0
- package/scripts/test_invoke_code_review_codec.py +77 -0
- package/scripts/test_invoke_code_review_contract.py +256 -0
- package/scripts/test_invoke_code_review_git.py +123 -0
- package/scripts/test_invoke_code_review_mode.py +99 -0
- package/scripts/test_resolve_worker_spawn.py +1014 -1014
- package/scripts/test_resolve_worker_spawn_codec.py +101 -0
- package/skills/CLAUDE.md +2 -0
- package/skills/auditing-claude-config/SKILL.md +114 -114
- package/skills/autoconverge/SKILL.md +427 -421
- package/skills/autoconverge/reference/convergence.md +26 -4
- package/skills/autoconverge/reference/multi-pr.md +6 -1
- package/skills/autoconverge/reference/stop-conditions.md +16 -10
- package/skills/autoconverge/workflow/CLAUDE.md +1 -0
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +4 -4
- package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +175 -3
- package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1244
- package/skills/autoconverge/workflow/converge.mjs +191 -8
- package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
- package/skills/autoconverge/workflow/converge_multi.mjs +7 -3
- package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +5 -0
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
- package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
- package/skills/closeout/SKILL.md +33 -50
- package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
- package/skills/codex-review/scripts/run_codex_review.py +233 -1
- package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
- package/skills/condensing-instructions/SKILL.md +81 -0
- package/skills/copilot-review/SKILL.md +119 -119
- package/skills/e-code-review/SKILL.md +52 -0
- package/skills/e-code-review/reference/fix.md +54 -0
- package/skills/e-code-review/reference/loop.md +43 -0
- package/skills/e-code-review/reference/low.md +57 -0
- package/skills/e-code-review/reference/medium.md +153 -0
- package/skills/e-code-review/reference/xhigh.md +182 -0
- package/skills/e-simplify/SKILL.md +97 -0
- package/skills/fresh-branch/CLAUDE.md +2 -0
- package/skills/fresh-branch/SKILL.md +2 -0
- package/skills/fresh-branch/scripts/create_fresh_branch.py +78 -180
- package/skills/fresh-branch/scripts/fresh_branch_git_commands.py +285 -0
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -0
- package/skills/fresh-branch/scripts/pytest.ini +4 -0
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +98 -0
- package/skills/fresh-branch/scripts/test_fresh_branch_git_commands.py +310 -0
- package/skills/issue-tracker/SKILL.md +92 -0
- package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
- package/skills/issue-tracker/reference/handoff-schema.md +64 -0
- package/skills/issue-tracker/reference/operation-matrix.md +41 -0
- package/skills/orchestrator/SKILL.md +162 -21
- package/skills/orchestrator/scripts/status_gate.py +625 -0
- package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
- package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
- package/skills/orchestrator/scripts/test_status_gate.py +439 -0
- package/skills/orchestrator-refresh/SKILL.md +110 -35
- package/skills/plan-to-pr/SKILL.md +155 -0
- package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
- package/skills/plan-to-pr/reference/model-routing.md +36 -0
- package/skills/plan-to-pr/reference/packet-contract.md +43 -0
- package/skills/plan-to-pr/reference/packet-schema.json +57 -0
- package/skills/plan-to-pr/reference/process-inventory.md +22 -0
- package/skills/plan-to-pr/reference/review-loop.md +33 -0
- package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
- package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
- package/skills/plan-to-pr/reference/task-seeds.md +14 -0
- package/skills/plan-to-pr/reference/task-ticket.md +38 -0
- package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
- package/skills/plan-to-pr/scripts/config/constants.py +193 -0
- package/skills/plan-to-pr/scripts/create_packet.py +173 -0
- package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
- package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
- package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
- package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
- package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
- package/skills/plan-to-pr/scripts/validate_run.py +173 -0
- package/skills/plan-to-pr/test_skill_contract.py +207 -0
- package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
- package/skills/pr-converge/SKILL.md +472 -469
- package/skills/pr-converge/reference/examples.md +3 -3
- package/skills/pr-converge/reference/fix-protocol.md +1 -1
- package/skills/pr-converge/reference/ground-rules.md +7 -4
- package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
- package/skills/pr-converge/reference/per-tick.md +5 -5
- package/skills/pr-converge/reference/progress-checklist.md +1 -1
- package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
- package/skills/pr-converge/test_step5_host_branch.py +1 -1
- package/skills/pr-fix-protocol/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -68
- package/skills/prototype/SKILL.md +86 -0
- package/skills/prototype/reference/honest-limitations.md +23 -0
- package/skills/prototype/reference/promotion-tasks.md +23 -0
- package/skills/prototype/scripts/build_sandbox_settings.py +249 -0
- package/skills/prototype/scripts/conftest.py +15 -0
- package/skills/prototype/scripts/launch_sandbox.py +205 -0
- package/skills/prototype/scripts/probe_sandbox_safety.py +311 -0
- package/skills/prototype/scripts/prototype_scripts_constants/__init__.py +1 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +41 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +23 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +45 -0
- package/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +10 -0
- package/skills/prototype/scripts/test_build_sandbox_settings.py +275 -0
- package/skills/prototype/scripts/test_launch_sandbox.py +303 -0
- package/skills/prototype/scripts/test_probe_sandbox_safety.py +284 -0
- package/skills/prototype/workflows/promotion.md +27 -0
- package/skills/prototype/workflows/sandbox.md +35 -0
- package/skills/release-notes-html/SKILL.md +164 -0
- package/skills/skill-builder/CLAUDE.md +3 -3
- package/skills/skill-builder/SKILL.md +5 -5
- package/skills/skill-builder/references/CLAUDE.md +1 -1
- package/skills/skill-builder/references/delegation-map.md +3 -3
- package/skills/skill-builder/references/description-field.md +1 -1
- package/skills/skill-builder/references/skill-modularity.md +2 -3
- package/skills/skill-builder/workflows/CLAUDE.md +1 -1
- package/skills/skill-builder/workflows/improve-skill.md +1 -1
- package/skills/skill-builder/workflows/new-skill.md +2 -2
- package/skills/task-build/CLAUDE.md +8 -7
- package/skills/task-build/SKILL.md +16 -8
- package/skills/task-build/reference/tool-routing.md +19 -0
- package/skills/team-advisor/SKILL.md +2 -2
- package/scripts/test_invoke_code_review.py +0 -672
- package/skills/closeout/reference/issue-body-templates.md +0 -108
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Constants for the orchestrator-refresh ScheduleWakeup reschedule gate."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup"
|
|
6
|
+
CRON_CREATE_TOOL_NAME = "CronCreate"
|
|
7
|
+
ALL_SCHEDULE_TOOL_NAMES: frozenset[str] = frozenset(
|
|
8
|
+
{
|
|
9
|
+
SCHEDULE_WAKEUP_TOOL_NAME,
|
|
10
|
+
CRON_CREATE_TOOL_NAME,
|
|
11
|
+
}
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
ORCHESTRATOR_REFRESH_PROMPT_TOKEN = "/orchestrator-refresh"
|
|
15
|
+
RUN_SLUG_PROMPT_FLAG = "--run-slug"
|
|
16
|
+
RUN_SLUG_PROMPT_VALUE_PATTERN = r"(?:=\s*|\s+)([^\s]+)"
|
|
17
|
+
PROMPT_FIELD_NAME = "prompt"
|
|
18
|
+
TOOL_NAME_FIELD_NAME = "tool_name"
|
|
19
|
+
TOOL_INPUT_FIELD_NAME = "tool_input"
|
|
20
|
+
CWD_FIELD_NAME = "cwd"
|
|
21
|
+
|
|
22
|
+
REASON_CRON_CREATE_FORBIDDEN = "cron_create_forbidden"
|
|
23
|
+
|
|
24
|
+
DENY_REASON_TEMPLATE = (
|
|
25
|
+
"BLOCKED: orchestrator-refresh re-arm denied ({reason}). "
|
|
26
|
+
"Use one-shot delayed wake only (never CronCreate / never recurring). "
|
|
27
|
+
"At most one re-arm slot: begin-firing at refresh start; "
|
|
28
|
+
"should-reschedule then create then claim-rearm (never claim before "
|
|
29
|
+
"ScheduleWakeup). Status must be active: "
|
|
30
|
+
"python skills/orchestrator/scripts/status_gate.py set "
|
|
31
|
+
"--status active. When finished: --status done. Never re-arm an idle loop."
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
CALLING_HOOK_NAME = "orchestrator_refresh_reschedule_gate.py"
|
|
35
|
+
HOOK_EVENT_NAME = "PreToolUse"
|
|
36
|
+
|
|
37
|
+
ALL_SKILL_SCRIPTS_RELATIVE_PARTS: tuple[str, ...] = (
|
|
38
|
+
"skills",
|
|
39
|
+
"orchestrator",
|
|
40
|
+
"scripts",
|
|
41
|
+
)
|
|
42
|
+
PLUGIN_ROOT_ENV_VAR = "CLAUDE_PLUGIN_ROOT"
|
|
43
|
+
ALL_HOME_SKILLS_RELATIVE_PARTS: tuple[str, ...] = (
|
|
44
|
+
".claude",
|
|
45
|
+
"skills",
|
|
46
|
+
"orchestrator",
|
|
47
|
+
"scripts",
|
|
48
|
+
)
|
|
@@ -22,8 +22,6 @@ GH_SLURP_FLAG: str = "--slurp"
|
|
|
22
22
|
PR_COMMENTS_API_PATH_TEMPLATE: str = "repos/{{owner}}/{{repo}}/issues/{pr_number}/comments"
|
|
23
23
|
ALL_PR_DIFF_SUBCOMMANDS: tuple[str, ...] = ("pr", "diff")
|
|
24
24
|
PR_DIFF_NAME_ONLY_FLAG: str = "--name-only"
|
|
25
|
-
ALL_PR_VIEW_NUMBER_ARGUMENTS: tuple[str, ...] = ("pr", "view", "--json", "number")
|
|
26
|
-
PR_NUMBER_JSON_FIELD: str = "number"
|
|
27
25
|
COMMENT_BODY_JSON_FIELD: str = "body"
|
|
28
26
|
GH_COMMAND_TIMEOUT_SECONDS: int = 6
|
|
29
27
|
MAX_DIFF_SCAN_CHARS: int = 200000
|
|
@@ -83,7 +81,6 @@ __all__ = [
|
|
|
83
81
|
"ALL_HONEST_GAP_PHRASES",
|
|
84
82
|
"ALL_PROOF_HEADING_KEYWORDS",
|
|
85
83
|
"ALL_PR_DIFF_SUBCOMMANDS",
|
|
86
|
-
"ALL_PR_VIEW_NUMBER_ARGUMENTS",
|
|
87
84
|
"ALL_VISUAL_FILE_SUFFIXES",
|
|
88
85
|
"COMMENT_BODY_JSON_FIELD",
|
|
89
86
|
"DIGIT_PATTERN",
|
|
@@ -104,7 +101,6 @@ __all__ = [
|
|
|
104
101
|
"PROOF_PART_VISUAL_MESSAGE",
|
|
105
102
|
"PR_COMMENTS_API_PATH_TEMPLATE",
|
|
106
103
|
"PR_DIFF_NAME_ONLY_FLAG",
|
|
107
|
-
"PR_NUMBER_JSON_FIELD",
|
|
108
104
|
"PR_READY_GATE_MESSAGE_TEMPLATE",
|
|
109
105
|
"PR_READY_INVOCATION_PATTERN",
|
|
110
106
|
"PR_READY_UNDO_FLAG",
|
|
@@ -80,6 +80,10 @@ ALL_HOSTED_HOOK_ENTRIES: tuple[HostedHookEntry, ...] = (
|
|
|
80
80
|
script_relative_path="blocking/sensitive_file_protector.py",
|
|
81
81
|
applicable_tool_names=ALL_WRITE_AND_EDIT_TOOL_NAMES,
|
|
82
82
|
),
|
|
83
|
+
HostedHookEntry(
|
|
84
|
+
script_relative_path="blocking/code_review_stamp_directory_write_blocker.py",
|
|
85
|
+
applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
|
|
86
|
+
),
|
|
83
87
|
HostedHookEntry(
|
|
84
88
|
script_relative_path="blocking/pii_prevention_blocker.py",
|
|
85
89
|
applicable_tool_names=ALL_WRITE_EDIT_MULTI_EDIT_TOOL_NAMES,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Table names used when a validator resolves its config from a pyproject.toml.
|
|
2
|
+
|
|
3
|
+
A ``pyproject.toml`` nests each tool's settings under ``[tool.<name>]``, so the
|
|
4
|
+
top-level table key is ``tool`` and each tool matches its own name below it.
|
|
5
|
+
These names live here so the discovery module carries no inline table literals.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"TOOL_TABLE_KEY",
|
|
10
|
+
"MYPY_TOOL_TABLE_NAME",
|
|
11
|
+
"RUFF_TOOL_TABLE_NAME",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
TOOL_TABLE_KEY: str = "tool"
|
|
15
|
+
MYPY_TOOL_TABLE_NAME: str = "mypy"
|
|
16
|
+
RUFF_TOOL_TABLE_NAME: str = "ruff"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Environment variable names used when ruff emits plain diagnostics.
|
|
2
|
+
|
|
3
|
+
The PreToolUse gate parses ``path:line:col:`` prefixes. Forcing ``NO_COLOR`` and
|
|
4
|
+
clearing ``FORCE_COLOR`` keeps ANSI codes out of those fields so baseline
|
|
5
|
+
scoping can locate each finding.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"FORCE_COLOR_ENVIRONMENT_VARIABLE_NAME",
|
|
10
|
+
"NO_COLOR_ENABLED_VALUE",
|
|
11
|
+
"NO_COLOR_ENVIRONMENT_VARIABLE_NAME",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
NO_COLOR_ENVIRONMENT_VARIABLE_NAME: str = "NO_COLOR"
|
|
15
|
+
FORCE_COLOR_ENVIRONMENT_VARIABLE_NAME: str = "FORCE_COLOR"
|
|
16
|
+
NO_COLOR_ENABLED_VALUE: str = "1"
|
|
@@ -40,12 +40,18 @@ _EXPECTED_BASH_ORDER = (
|
|
|
40
40
|
"blocking/gh_pr_author_enforcer.py",
|
|
41
41
|
"blocking/verified_commit_gate.py",
|
|
42
42
|
"blocking/verdict_directory_write_blocker.py",
|
|
43
|
+
"blocking/code_review_push_gate.py",
|
|
44
|
+
"blocking/code_review_pr_create_gate.py",
|
|
45
|
+
"blocking/code_review_stamp_directory_write_blocker.py",
|
|
43
46
|
)
|
|
44
47
|
|
|
45
48
|
_POWERSHELL_APPLICABLE = (
|
|
46
49
|
"blocking/pii_prevention_blocker.py",
|
|
47
50
|
"blocking/verified_commit_gate.py",
|
|
48
51
|
"blocking/verdict_directory_write_blocker.py",
|
|
52
|
+
"blocking/code_review_push_gate.py",
|
|
53
|
+
"blocking/code_review_pr_create_gate.py",
|
|
54
|
+
"blocking/code_review_stamp_directory_write_blocker.py",
|
|
49
55
|
)
|
|
50
56
|
|
|
51
57
|
|
|
@@ -80,6 +86,24 @@ def test_powershell_hooks_carry_the_shared_tool_set() -> None:
|
|
|
80
86
|
assert each_entry.applicable_tool_names == ALL_BASH_AND_POWERSHELL_TOOL_NAMES
|
|
81
87
|
|
|
82
88
|
|
|
89
|
+
def test_code_review_gate_family_registered_for_bash_and_powershell() -> None:
|
|
90
|
+
"""The three code-review shell gates run on both Bash and PowerShell."""
|
|
91
|
+
code_review_gate_paths = (
|
|
92
|
+
"blocking/code_review_push_gate.py",
|
|
93
|
+
"blocking/code_review_pr_create_gate.py",
|
|
94
|
+
"blocking/code_review_stamp_directory_write_blocker.py",
|
|
95
|
+
)
|
|
96
|
+
entry_by_path = {
|
|
97
|
+
each_entry.script_relative_path: each_entry
|
|
98
|
+
for each_entry in ALL_BASH_HOSTED_HOOK_ENTRIES
|
|
99
|
+
}
|
|
100
|
+
for each_gate_path in code_review_gate_paths:
|
|
101
|
+
assert each_gate_path in entry_by_path
|
|
102
|
+
assert entry_by_path[each_gate_path].applicable_tool_names == (
|
|
103
|
+
ALL_BASH_AND_POWERSHELL_TOOL_NAMES
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
83
107
|
def test_every_roster_path_points_at_an_existing_hook() -> None:
|
|
84
108
|
"""Each roster path names a hook script present on disk, catching a typo."""
|
|
85
109
|
hooks_root = Path(__file__).resolve().parent.parent
|
|
@@ -63,6 +63,12 @@ def test_duplicate_rmtree_helper_blocker_runs_via_runpy() -> None:
|
|
|
63
63
|
assert entry.native_module_name is None
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
def test_code_review_stamp_write_blocker_registered_for_all_file_tools() -> None:
|
|
67
|
+
entry = _entry_for("blocking/code_review_stamp_directory_write_blocker.py")
|
|
68
|
+
assert entry is not None
|
|
69
|
+
assert {"Write", "Edit", "MultiEdit"} <= entry.applicable_tool_names
|
|
70
|
+
|
|
71
|
+
|
|
66
72
|
def test_windows_rmtree_blocker_still_registered() -> None:
|
|
67
73
|
entry = _entry_for("blocking/windows_rmtree_blocker.py")
|
|
68
74
|
assert entry is not None
|
|
@@ -19,9 +19,16 @@ ALL_GH_POST_SUBCOMMANDS: dict[str, frozenset[str]] = {
|
|
|
19
19
|
"issue": frozenset({"create", "comment", "edit"}),
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
PATH_ANCHOR_CHARACTER: str = "/"
|
|
23
|
+
|
|
24
|
+
PATH_SEGMENT_START_CHARACTERS: str = "_-"
|
|
25
|
+
|
|
26
|
+
ALL_PATH_ANCHORED_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
|
|
23
27
|
".claude-editor/jobs/",
|
|
24
28
|
".claude/worktrees/",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
ALL_BARE_VOLATILE_PATH_MARKERS: tuple[str, ...] = (
|
|
25
32
|
"appdata/local/temp",
|
|
26
33
|
"/tmp/",
|
|
27
34
|
"%temp%",
|
|
@@ -1,146 +1,163 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""PreToolUse hook: fetch origin's default branch before EnterWorktree creates one.
|
|
3
|
-
|
|
4
|
-
``EnterWorktree`` in its default ``fresh`` mode bases a new worktree on the
|
|
5
|
-
locally cached ``refs/remotes/origin/<default-branch>`` ref and only runs
|
|
6
|
-
``git fetch`` when that ref is missing entirely -- so a worktree created
|
|
7
|
-
without a recent fetch silently starts behind the remote. This hook fetches
|
|
8
|
-
that ref immediately before the tool resolves its base, so the ref it reads
|
|
9
|
-
is current.
|
|
10
|
-
|
|
11
|
-
::
|
|
12
|
-
|
|
13
|
-
EnterWorktree({}) # tool_input has no "path"
|
|
14
|
-
|
|
|
15
|
-
v
|
|
16
|
-
this hook: git fetch origin <default-branch> # best-effort, never blocks
|
|
17
|
-
|
|
|
18
|
-
v
|
|
19
|
-
EnterWorktree resolves refs/remotes/origin/<default-branch> # now fresh
|
|
20
|
-
|
|
21
|
-
The hook is a no-op when ``tool_input`` carries a ``path`` (switching into an
|
|
22
|
-
already-existing worktree needs no fresh base) and always exits 0 -- a failed
|
|
23
|
-
or slow fetch never blocks worktree creation.
|
|
24
|
-
"""
|
|
25
|
-
|
|
26
|
-
from __future__ import annotations
|
|
27
|
-
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
import
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
_hooks_dir
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def is_enter_worktree_creation(payload_by_field: dict[str, object]) -> bool:
|
|
49
|
-
"""Return True when this hook invocation is an EnterWorktree creation call.
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
payload_by_field: The full PreToolUse hook payload (already JSON-parsed),
|
|
53
|
-
keyed by top-level field name.
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
True when ``tool_name == "EnterWorktree"`` and ``tool_input`` carries
|
|
57
|
-
no ``path`` key. A ``path`` value means the call switches into an
|
|
58
|
-
already-existing worktree rather than creating one, so it is False
|
|
59
|
-
for that case and for every other tool.
|
|
60
|
-
"""
|
|
61
|
-
if payload_by_field.get("tool_name", "") != ENTER_WORKTREE_TOOL_NAME:
|
|
62
|
-
return False
|
|
63
|
-
tool_input = payload_by_field.get("tool_input", {})
|
|
64
|
-
if not isinstance(tool_input, dict):
|
|
65
|
-
return True
|
|
66
|
-
return not tool_input.get(ENTER_WORKTREE_PATH_INPUT_KEY)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def
|
|
100
|
-
"""
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
repo_directory: Working directory to run ``git`` in.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"""
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PreToolUse hook: fetch origin's default branch before EnterWorktree creates one.
|
|
3
|
+
|
|
4
|
+
``EnterWorktree`` in its default ``fresh`` mode bases a new worktree on the
|
|
5
|
+
locally cached ``refs/remotes/origin/<default-branch>`` ref and only runs
|
|
6
|
+
``git fetch`` when that ref is missing entirely -- so a worktree created
|
|
7
|
+
without a recent fetch silently starts behind the remote. This hook fetches
|
|
8
|
+
that ref immediately before the tool resolves its base, so the ref it reads
|
|
9
|
+
is current.
|
|
10
|
+
|
|
11
|
+
::
|
|
12
|
+
|
|
13
|
+
EnterWorktree({}) # tool_input has no "path"
|
|
14
|
+
|
|
|
15
|
+
v
|
|
16
|
+
this hook: git fetch origin <default-branch> # best-effort, never blocks
|
|
17
|
+
|
|
|
18
|
+
v
|
|
19
|
+
EnterWorktree resolves refs/remotes/origin/<default-branch> # now fresh
|
|
20
|
+
|
|
21
|
+
The hook is a no-op when ``tool_input`` carries a ``path`` (switching into an
|
|
22
|
+
already-existing worktree needs no fresh base) and always exits 0 -- a failed
|
|
23
|
+
or slow fetch never blocks worktree creation.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
_hooks_dir = str(Path(__file__).resolve().parent.parent)
|
|
33
|
+
if _hooks_dir not in sys.path:
|
|
34
|
+
sys.path.insert(0, _hooks_dir)
|
|
35
|
+
|
|
36
|
+
from hooks_constants.enter_worktree_prefetch_constants import ( # noqa: E402
|
|
37
|
+
ENTER_WORKTREE_PATH_INPUT_KEY,
|
|
38
|
+
ENTER_WORKTREE_TOOL_NAME,
|
|
39
|
+
GIT_FETCH_TIMEOUT_SECONDS,
|
|
40
|
+
GIT_SYMBOLIC_REF_TIMEOUT_SECONDS,
|
|
41
|
+
ORIGIN_HEAD_SYMBOLIC_REF,
|
|
42
|
+
ORIGIN_REMOTE_NAME,
|
|
43
|
+
ORIGIN_REMOTE_REF_PREFIX,
|
|
44
|
+
)
|
|
45
|
+
from hooks_constants.pre_tool_use_stdin import read_hook_input_dictionary_from_stdin # noqa: E402
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def is_enter_worktree_creation(payload_by_field: dict[str, object]) -> bool:
|
|
49
|
+
"""Return True when this hook invocation is an EnterWorktree creation call.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
payload_by_field: The full PreToolUse hook payload (already JSON-parsed),
|
|
53
|
+
keyed by top-level field name.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
True when ``tool_name == "EnterWorktree"`` and ``tool_input`` carries
|
|
57
|
+
no ``path`` key. A ``path`` value means the call switches into an
|
|
58
|
+
already-existing worktree rather than creating one, so it is False
|
|
59
|
+
for that case and for every other tool.
|
|
60
|
+
"""
|
|
61
|
+
if payload_by_field.get("tool_name", "") != ENTER_WORKTREE_TOOL_NAME:
|
|
62
|
+
return False
|
|
63
|
+
tool_input = payload_by_field.get("tool_input", {})
|
|
64
|
+
if not isinstance(tool_input, dict):
|
|
65
|
+
return True
|
|
66
|
+
return not tool_input.get(ENTER_WORKTREE_PATH_INPUT_KEY)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _run_git_quietly(
|
|
70
|
+
repo_directory: str,
|
|
71
|
+
all_git_arguments: list[str],
|
|
72
|
+
timeout_seconds: int,
|
|
73
|
+
) -> subprocess.CompletedProcess[str] | None:
|
|
74
|
+
"""Run ``git`` with the given arguments, or return None when it cannot run.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
repo_directory: Working directory to run ``git`` in.
|
|
78
|
+
all_git_arguments: The git subcommand and its arguments, without the
|
|
79
|
+
leading ``"git"`` (for example ``["fetch", "origin", "main"]``).
|
|
80
|
+
timeout_seconds: Seconds to wait before abandoning the command.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The completed process, or None when git is unavailable, the OS refuses
|
|
84
|
+
to start it, or the command exceeds ``timeout_seconds``.
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
return subprocess.run(
|
|
88
|
+
["git", *all_git_arguments],
|
|
89
|
+
capture_output=True,
|
|
90
|
+
text=True,
|
|
91
|
+
timeout=timeout_seconds,
|
|
92
|
+
cwd=repo_directory,
|
|
93
|
+
check=False,
|
|
94
|
+
)
|
|
95
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def resolve_origin_default_branch(repo_directory: str) -> str | None:
|
|
100
|
+
"""Return the branch name origin's HEAD points at, or None if unresolved.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
repo_directory: Working directory to run ``git`` in.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
The branch name (for example ``"main"``) parsed from
|
|
107
|
+
``refs/remotes/origin/HEAD``, or None when the symbolic ref is
|
|
108
|
+
unset, git is unavailable, or the command times out.
|
|
109
|
+
"""
|
|
110
|
+
completed_process = _run_git_quietly(
|
|
111
|
+
repo_directory,
|
|
112
|
+
["symbolic-ref", ORIGIN_HEAD_SYMBOLIC_REF],
|
|
113
|
+
GIT_SYMBOLIC_REF_TIMEOUT_SECONDS,
|
|
114
|
+
)
|
|
115
|
+
if completed_process is None:
|
|
116
|
+
return None
|
|
117
|
+
if completed_process.returncode != 0:
|
|
118
|
+
return None
|
|
119
|
+
resolved_ref = completed_process.stdout.strip()
|
|
120
|
+
if not resolved_ref.startswith(ORIGIN_REMOTE_REF_PREFIX):
|
|
121
|
+
return None
|
|
122
|
+
return resolved_ref[len(ORIGIN_REMOTE_REF_PREFIX):]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def fetch_origin_branch(repo_directory: str, branch_name: str) -> None:
|
|
126
|
+
"""Best-effort ``git fetch origin <branch_name>``; never raises.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
repo_directory: Working directory to run ``git`` in.
|
|
130
|
+
branch_name: Branch to fetch from the ``origin`` remote.
|
|
131
|
+
"""
|
|
132
|
+
_run_git_quietly(
|
|
133
|
+
repo_directory,
|
|
134
|
+
["fetch", ORIGIN_REMOTE_NAME, branch_name],
|
|
135
|
+
GIT_FETCH_TIMEOUT_SECONDS,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def main() -> None:
|
|
140
|
+
"""Entry point for the PreToolUse:EnterWorktree hook.
|
|
141
|
+
|
|
142
|
+
Reads the PreToolUse payload from stdin, and when it is an EnterWorktree
|
|
143
|
+
creation call, fetches origin's default branch in the session's ``cwd``
|
|
144
|
+
before returning. Always exits 0: a fetch failure self-heals on the next
|
|
145
|
+
fetch rather than blocking worktree creation.
|
|
146
|
+
"""
|
|
147
|
+
hook_payload = read_hook_input_dictionary_from_stdin()
|
|
148
|
+
if hook_payload is None:
|
|
149
|
+
sys.exit(0)
|
|
150
|
+
if not is_enter_worktree_creation(hook_payload):
|
|
151
|
+
sys.exit(0)
|
|
152
|
+
repo_directory = hook_payload.get("cwd")
|
|
153
|
+
if not isinstance(repo_directory, str) or not repo_directory:
|
|
154
|
+
sys.exit(0)
|
|
155
|
+
default_branch = resolve_origin_default_branch(repo_directory)
|
|
156
|
+
if default_branch is None:
|
|
157
|
+
sys.exit(0)
|
|
158
|
+
fetch_origin_branch(repo_directory, default_branch)
|
|
159
|
+
sys.exit(0)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
if __name__ == "__main__":
|
|
163
|
+
main()
|