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.
Files changed (290) hide show
  1. package/CLAUDE.md +53 -48
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +84 -0
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +4 -2
  4. package/_shared/pr-loop/scripts/grant_project_claude_permissions.py +306 -306
  5. package/_shared/pr-loop/scripts/pr_loop_shared_constants/claude_permissions_constants.py +44 -0
  6. package/_shared/pr-loop/scripts/pr_loop_shared_constants/copilot_quota_constants.py +24 -24
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/stale_worktree_rule_sweep_constants.py +107 -107
  8. package/_shared/pr-loop/scripts/revoke_project_claude_permissions.py +290 -48
  9. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +42 -2
  10. package/_shared/pr-loop/scripts/tests/test_claude_permissions_constants.py +36 -0
  11. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +100 -1
  12. package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -497
  13. package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +311 -2
  14. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep.py +301 -301
  15. package/_shared/pr-loop/scripts/tests/test_stale_worktree_rule_sweep_constants.py +85 -85
  16. package/_shared/pr-loop/worker-spawn.md +1 -1
  17. package/agents/CLAUDE.md +3 -1
  18. package/agents/caveman.md +0 -1
  19. package/agents/clasp-deployment-orchestrator.md +0 -1
  20. package/agents/clean-coder.md +0 -1
  21. package/agents/code-advisor.md +0 -1
  22. package/agents/code-quality-agent.md +1 -2
  23. package/agents/code-verifier.md +3 -4
  24. package/agents/deep-research.md +0 -1
  25. package/agents/docs-agent.md +0 -1
  26. package/agents/git-commit-crafter.md +0 -1
  27. package/agents/issue-tracker.md +42 -0
  28. package/agents/plan-packet-validator.md +0 -1
  29. package/agents/pr-description-writer.md +0 -1
  30. package/agents/skill-writer-agent.md +84 -0
  31. package/agents/test_agent_frontmatter.py +67 -18
  32. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +105 -3
  33. package/audit-rubrics/prompts/category-o-docstring-vs-impl-drift.md +29 -13
  34. package/bin/CLAUDE.md +68 -5
  35. package/bin/ever-shipped-skills.mjs +1 -0
  36. package/bin/install-constants.mjs +88 -0
  37. package/bin/install.mjs +1138 -114
  38. package/bin/install.prune.test.mjs +869 -19
  39. package/bin/install.test.mjs +906 -2
  40. package/commands/implement.md +1 -1
  41. package/commands/right-size.md +1 -1
  42. package/docs/CLAUDE.md +2 -0
  43. package/docs/host-pool-health-monitor.md +102 -0
  44. package/docs/references/CLAUDE.md +5 -2
  45. package/docs/references/advisor-tool.md +13 -0
  46. package/docs/references/code-review-enforcement.md +107 -0
  47. package/docs/references/team-advisor-skill.md +14 -0
  48. package/docs/wsl-docker-cowork-starter-matrix.md +89 -0
  49. package/hooks/blocking/CLAUDE.md +9 -1
  50. package/hooks/blocking/code_review_enforcement_config_bootstrap.py +53 -0
  51. package/hooks/blocking/code_review_gate_deny.py +74 -0
  52. package/hooks/blocking/code_review_pr_create_gate.py +198 -0
  53. package/hooks/blocking/code_review_push_gate.py +145 -0
  54. package/hooks/blocking/code_review_stamp_directory_write_blocker.py +348 -0
  55. package/hooks/blocking/code_review_stamp_store.py +233 -0
  56. package/hooks/blocking/code_review_stamp_write_blocker_parts/__init__.py +7 -0
  57. package/hooks/blocking/code_review_stamp_write_blocker_parts/conftest.py +15 -0
  58. package/hooks/blocking/code_review_stamp_write_blocker_parts/obfuscated_stamp_path_reference.py +212 -0
  59. package/hooks/blocking/code_review_stamp_write_blocker_parts/split_directory_change_into_stamp.py +138 -0
  60. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_obfuscated_stamp_path_reference.py +49 -0
  61. package/hooks/blocking/code_review_stamp_write_blocker_parts/test_split_directory_change_into_stamp.py +38 -0
  62. package/hooks/blocking/code_verifier_spawn_preflight_gate.py +39 -27
  63. package/hooks/blocking/config/__init__.py +5 -5
  64. package/hooks/blocking/config/code_review_enforcement_constants.py +113 -0
  65. package/hooks/blocking/config/test_code_review_enforcement_constants.py +113 -0
  66. package/hooks/blocking/config/verified_commit_constants.py +160 -155
  67. package/hooks/blocking/conftest.py +2 -0
  68. package/hooks/blocking/convergence_gate_blocker.py +112 -23
  69. package/hooks/blocking/destructive_command_blocker.py +19 -6
  70. package/hooks/blocking/orchestrator_refresh_reschedule_gate.py +256 -0
  71. package/hooks/blocking/pr_description_proof_of_work.py +52 -34
  72. package/hooks/blocking/pre_tool_use_dispatcher.py +24 -24
  73. package/hooks/blocking/test_bash_pre_tool_use_dispatcher.py +4 -1
  74. package/hooks/blocking/test_code_review_enforcement_config_bootstrap.py +62 -0
  75. package/hooks/blocking/test_code_review_gate_deny.py +54 -0
  76. package/hooks/blocking/test_code_review_pr_create_gate.py +199 -0
  77. package/hooks/blocking/test_code_review_push_gate.py +205 -0
  78. package/hooks/blocking/test_code_review_stamp_directory_write_blocker.py +199 -0
  79. package/hooks/blocking/test_code_review_stamp_store.py +205 -0
  80. package/hooks/blocking/test_code_verifier_spawn_preflight_gate.py +124 -2
  81. package/hooks/blocking/test_convergence_gate_blocker.py +153 -5
  82. package/hooks/blocking/test_destructive_command_blocker.py +1 -1
  83. package/hooks/blocking/test_destructive_command_blocker_deny_mode.py +45 -0
  84. package/hooks/blocking/test_orchestrator_refresh_reschedule_gate.py +231 -0
  85. package/hooks/blocking/test_pr_description_proof_of_work.py +151 -0
  86. package/hooks/blocking/test_pre_tool_use_dispatcher.py +17 -8
  87. package/hooks/blocking/test_verdict_directory_write_blocker.py +808 -808
  88. package/hooks/blocking/test_verification_verdict_store.py +974 -903
  89. package/hooks/blocking/test_verified_commit_gate.py +581 -581
  90. package/hooks/blocking/test_verified_commit_message_accuracy_blocker.py +131 -131
  91. package/hooks/blocking/test_volatile_path_in_post_blocker.py +114 -2
  92. package/hooks/blocking/verdict_directory_write_blocker.py +687 -687
  93. package/hooks/blocking/verification_verdict_store.py +1039 -1014
  94. package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +29 -17
  95. package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +35 -0
  96. package/hooks/blocking/verified_commit_message_accuracy_blocker.py +167 -167
  97. package/hooks/blocking/verifier_verdict_minter.py +280 -280
  98. package/hooks/blocking/volatile_path_in_post_blocker.py +69 -8
  99. package/hooks/git-hooks/git_hooks_constants/__init__.py +6 -0
  100. package/hooks/git-hooks/pre_push.py +89 -2
  101. package/hooks/git-hooks/test_pre_push.py +128 -0
  102. package/hooks/hooks.json +26 -1
  103. package/hooks/hooks_constants/CLAUDE.md +3 -1
  104. package/hooks/hooks_constants/bash_pre_tool_use_dispatcher_constants.py +8 -0
  105. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
  106. package/hooks/hooks_constants/code_verifier_spawn_preflight_gate_constants.py +26 -11
  107. package/hooks/hooks_constants/convergence_gate_blocker_constants.py +20 -3
  108. package/hooks/hooks_constants/destructive_command_segment_constants.py +3 -1
  109. package/hooks/hooks_constants/enter_worktree_prefetch_constants.py +18 -18
  110. package/hooks/hooks_constants/orchestrator_refresh_reschedule_gate_constants.py +48 -0
  111. package/hooks/hooks_constants/pr_description_proof_of_work_constants.py +0 -4
  112. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
  113. package/hooks/hooks_constants/pyproject_config_discovery_constants.py +16 -0
  114. package/hooks/hooks_constants/ruff_integration_constants.py +16 -0
  115. package/hooks/hooks_constants/test_bash_pre_tool_use_dispatcher_constants.py +24 -0
  116. package/hooks/hooks_constants/test_pre_tool_use_dispatcher_constants.py +6 -0
  117. package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +8 -1
  118. package/hooks/lifecycle/enter_worktree_origin_prefetch.py +163 -146
  119. package/hooks/lifecycle/test_enter_worktree_origin_prefetch.py +185 -178
  120. package/hooks/pyproject.toml +1 -0
  121. package/hooks/validators/CLAUDE.md +2 -0
  122. package/hooks/validators/config/__init__.py +0 -0
  123. package/hooks/validators/config/directory_exemption_constants.py +183 -0
  124. package/hooks/validators/config/test_directory_exemption_constants.py +21 -0
  125. package/hooks/validators/conftest.py +4 -0
  126. package/hooks/validators/mypy_integration.py +63 -50
  127. package/hooks/validators/pyproject_config_discovery.py +101 -0
  128. package/hooks/validators/ruff_integration.py +257 -25
  129. package/hooks/validators/run_all_validators.py +223 -19
  130. package/hooks/validators/test_directory_exemption_constants.py +185 -0
  131. package/hooks/validators/test_mypy_integration.py +32 -0
  132. package/hooks/validators/test_pyproject_config_discovery.py +94 -0
  133. package/hooks/validators/test_python_antipattern_checks.py +110 -5
  134. package/hooks/validators/test_ruff_integration.py +160 -2
  135. package/hooks/validators/test_run_all_validators.py +140 -68
  136. package/hooks/validators/test_run_all_validators_config_discovery.py +123 -0
  137. package/hooks/validators/test_run_all_validators_pretooluse.py +159 -1
  138. package/package.json +10 -2
  139. package/rules/CLAUDE.md +1 -0
  140. package/rules/docstring-prose-matches-implementation.md +45 -67
  141. package/rules/durable-post-artifacts.md +7 -0
  142. package/rules/state-what-is.md +25 -0
  143. package/rules/verified-commit-gate-skip.md +1 -1
  144. package/scripts/CLAUDE.md +1 -0
  145. package/scripts/Capture-PoolHealth.ps1 +410 -0
  146. package/scripts/_code_review_test_support.py +404 -0
  147. package/scripts/claude_chain_runner.py +141 -1
  148. package/scripts/codec_forwarding_test_support.py +83 -0
  149. package/scripts/conftest.py +23 -0
  150. package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -2
  151. package/scripts/dev_env_scripts_constants/claude_chain_constants.py +53 -1
  152. package/scripts/dev_env_scripts_constants/code_review_constants.py +129 -12
  153. package/scripts/dev_env_scripts_constants/test_code_review_constants.py +55 -0
  154. package/scripts/invoke_code_review.py +550 -38
  155. package/scripts/resolve_worker_spawn.py +626 -619
  156. package/scripts/spawn_grok_batch.py +672 -672
  157. package/scripts/test_claude_chain_runner.py +131 -0
  158. package/scripts/test_invoke_code_review_chain.py +70 -0
  159. package/scripts/test_invoke_code_review_cli.py +192 -0
  160. package/scripts/test_invoke_code_review_codec.py +77 -0
  161. package/scripts/test_invoke_code_review_contract.py +256 -0
  162. package/scripts/test_invoke_code_review_git.py +123 -0
  163. package/scripts/test_invoke_code_review_mode.py +99 -0
  164. package/scripts/test_resolve_worker_spawn.py +1014 -1014
  165. package/scripts/test_resolve_worker_spawn_codec.py +101 -0
  166. package/skills/CLAUDE.md +2 -0
  167. package/skills/auditing-claude-config/SKILL.md +114 -114
  168. package/skills/autoconverge/SKILL.md +427 -421
  169. package/skills/autoconverge/reference/convergence.md +26 -4
  170. package/skills/autoconverge/reference/multi-pr.md +6 -1
  171. package/skills/autoconverge/reference/stop-conditions.md +16 -10
  172. package/skills/autoconverge/workflow/CLAUDE.md +1 -0
  173. package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +4 -4
  174. package/skills/autoconverge/workflow/converge.codex-gate.test.mjs +175 -3
  175. package/skills/autoconverge/workflow/converge.contract.test.mjs +1263 -1244
  176. package/skills/autoconverge/workflow/converge.mjs +191 -8
  177. package/skills/autoconverge/workflow/converge.p2-advance.test.mjs +202 -0
  178. package/skills/autoconverge/workflow/converge_multi.mjs +7 -3
  179. package/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +5 -0
  180. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a11d903476b803493.jsonl +2 -2
  181. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a26213978adeef6fb.jsonl +2 -2
  182. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a3def0d15ed9d9110.jsonl +2 -2
  183. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a41f41b1b708ee3b7.jsonl +2 -2
  184. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a758b880abecc3ff7.jsonl +2 -2
  185. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-a8897b89656b1bd16.jsonl +2 -2
  186. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-abd463d744a1437bc.jsonl +2 -2
  187. package/skills/autoconverge/workflow/fixtures/wf_run/subagents/workflows/wf_881252e6-700/agent-ad19d027ae8ee1816.jsonl +2 -2
  188. package/skills/autoconverge/workflow/fixtures/wf_run/workflows/wf_881252e6-700.json +265 -265
  189. package/skills/closeout/SKILL.md +33 -50
  190. package/skills/codex-review/scripts/codex_review_scripts_constants/run_constants.py +8 -0
  191. package/skills/codex-review/scripts/run_codex_review.py +233 -1
  192. package/skills/codex-review/scripts/test_run_codex_review.py +189 -0
  193. package/skills/condensing-instructions/SKILL.md +81 -0
  194. package/skills/copilot-review/SKILL.md +119 -119
  195. package/skills/e-code-review/SKILL.md +52 -0
  196. package/skills/e-code-review/reference/fix.md +54 -0
  197. package/skills/e-code-review/reference/loop.md +43 -0
  198. package/skills/e-code-review/reference/low.md +57 -0
  199. package/skills/e-code-review/reference/medium.md +153 -0
  200. package/skills/e-code-review/reference/xhigh.md +182 -0
  201. package/skills/e-simplify/SKILL.md +97 -0
  202. package/skills/fresh-branch/CLAUDE.md +2 -0
  203. package/skills/fresh-branch/SKILL.md +2 -0
  204. package/skills/fresh-branch/scripts/create_fresh_branch.py +78 -180
  205. package/skills/fresh-branch/scripts/fresh_branch_git_commands.py +285 -0
  206. package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +1 -0
  207. package/skills/fresh-branch/scripts/pytest.ini +4 -0
  208. package/skills/fresh-branch/scripts/test_create_fresh_branch.py +98 -0
  209. package/skills/fresh-branch/scripts/test_fresh_branch_git_commands.py +310 -0
  210. package/skills/issue-tracker/SKILL.md +92 -0
  211. package/skills/issue-tracker/reference/epic-and-sub-issue-model.md +55 -0
  212. package/skills/issue-tracker/reference/handoff-schema.md +64 -0
  213. package/skills/issue-tracker/reference/operation-matrix.md +41 -0
  214. package/skills/orchestrator/SKILL.md +162 -21
  215. package/skills/orchestrator/scripts/status_gate.py +625 -0
  216. package/skills/orchestrator/scripts/status_gate_constants/__init__.py +1 -0
  217. package/skills/orchestrator/scripts/status_gate_constants/config/__init__.py +1 -0
  218. package/skills/orchestrator/scripts/status_gate_constants/config/constants.py +47 -0
  219. package/skills/orchestrator/scripts/test_status_gate.py +439 -0
  220. package/skills/orchestrator-refresh/SKILL.md +110 -35
  221. package/skills/plan-to-pr/SKILL.md +155 -0
  222. package/skills/plan-to-pr/reference/final-validation-tasks.md +15 -0
  223. package/skills/plan-to-pr/reference/model-routing.md +36 -0
  224. package/skills/plan-to-pr/reference/packet-contract.md +43 -0
  225. package/skills/plan-to-pr/reference/packet-schema.json +57 -0
  226. package/skills/plan-to-pr/reference/process-inventory.md +22 -0
  227. package/skills/plan-to-pr/reference/review-loop.md +33 -0
  228. package/skills/plan-to-pr/reference/run-record.schema.json +27 -0
  229. package/skills/plan-to-pr/reference/self-audit-tasks.md +15 -0
  230. package/skills/plan-to-pr/reference/task-seeds.md +14 -0
  231. package/skills/plan-to-pr/reference/task-ticket.md +38 -0
  232. package/skills/plan-to-pr/scripts/config/__init__.py +1 -0
  233. package/skills/plan-to-pr/scripts/config/constants.py +193 -0
  234. package/skills/plan-to-pr/scripts/create_packet.py +173 -0
  235. package/skills/plan-to-pr/scripts/test_create_packet.py +102 -0
  236. package/skills/plan-to-pr/scripts/test_validate_packet.py +256 -0
  237. package/skills/plan-to-pr/scripts/test_validate_protocol.py +135 -0
  238. package/skills/plan-to-pr/scripts/test_validate_run.py +158 -0
  239. package/skills/plan-to-pr/scripts/validate_packet.py +655 -0
  240. package/skills/plan-to-pr/scripts/validate_protocol.py +622 -0
  241. package/skills/plan-to-pr/scripts/validate_run.py +173 -0
  242. package/skills/plan-to-pr/test_skill_contract.py +207 -0
  243. package/skills/plan-to-pr/test_task_ticket_contract.py +151 -0
  244. package/skills/pr-converge/SKILL.md +472 -469
  245. package/skills/pr-converge/reference/examples.md +3 -3
  246. package/skills/pr-converge/reference/fix-protocol.md +1 -1
  247. package/skills/pr-converge/reference/ground-rules.md +7 -4
  248. package/skills/pr-converge/reference/multi-pr-orchestration.md +4 -1
  249. package/skills/pr-converge/reference/per-tick.md +5 -5
  250. package/skills/pr-converge/reference/progress-checklist.md +1 -1
  251. package/skills/pr-converge/scripts/check_convergence_gates.py +279 -279
  252. package/skills/pr-converge/scripts/test_check_convergence_codex.py +507 -507
  253. package/skills/pr-converge/scripts/test_check_convergence_gates.py +84 -84
  254. package/skills/pr-converge/test_step5_host_branch.py +1 -1
  255. package/skills/pr-fix-protocol/SKILL.md +1 -1
  256. package/skills/privacy-hygiene/SKILL.md +68 -68
  257. package/skills/prototype/SKILL.md +86 -0
  258. package/skills/prototype/reference/honest-limitations.md +23 -0
  259. package/skills/prototype/reference/promotion-tasks.md +23 -0
  260. package/skills/prototype/scripts/build_sandbox_settings.py +249 -0
  261. package/skills/prototype/scripts/conftest.py +15 -0
  262. package/skills/prototype/scripts/launch_sandbox.py +205 -0
  263. package/skills/prototype/scripts/probe_sandbox_safety.py +311 -0
  264. package/skills/prototype/scripts/prototype_scripts_constants/__init__.py +1 -0
  265. package/skills/prototype/scripts/prototype_scripts_constants/config/__init__.py +0 -0
  266. package/skills/prototype/scripts/prototype_scripts_constants/config/build_sandbox_settings_constants.py +41 -0
  267. package/skills/prototype/scripts/prototype_scripts_constants/config/launch_sandbox_constants.py +23 -0
  268. package/skills/prototype/scripts/prototype_scripts_constants/config/probe_sandbox_safety_constants.py +45 -0
  269. package/skills/prototype/scripts/prototype_scripts_constants/config/prototype_common_constants.py +10 -0
  270. package/skills/prototype/scripts/test_build_sandbox_settings.py +275 -0
  271. package/skills/prototype/scripts/test_launch_sandbox.py +303 -0
  272. package/skills/prototype/scripts/test_probe_sandbox_safety.py +284 -0
  273. package/skills/prototype/workflows/promotion.md +27 -0
  274. package/skills/prototype/workflows/sandbox.md +35 -0
  275. package/skills/release-notes-html/SKILL.md +164 -0
  276. package/skills/skill-builder/CLAUDE.md +3 -3
  277. package/skills/skill-builder/SKILL.md +5 -5
  278. package/skills/skill-builder/references/CLAUDE.md +1 -1
  279. package/skills/skill-builder/references/delegation-map.md +3 -3
  280. package/skills/skill-builder/references/description-field.md +1 -1
  281. package/skills/skill-builder/references/skill-modularity.md +2 -3
  282. package/skills/skill-builder/workflows/CLAUDE.md +1 -1
  283. package/skills/skill-builder/workflows/improve-skill.md +1 -1
  284. package/skills/skill-builder/workflows/new-skill.md +2 -2
  285. package/skills/task-build/CLAUDE.md +8 -7
  286. package/skills/task-build/SKILL.md +16 -8
  287. package/skills/task-build/reference/tool-routing.md +19 -0
  288. package/skills/team-advisor/SKILL.md +2 -2
  289. package/scripts/test_invoke_code_review.py +0 -672
  290. package/skills/closeout/reference/issue-body-templates.md +0 -108
@@ -7,15 +7,22 @@ from pr_loop_shared_constants.preflight_constants import GIT_DIRECTORY_NAME
7
7
  __all__ = (
8
8
  "ALL_AGENT_CONFIG_DENY_TOOLS",
9
9
  "ALL_AGENT_CONFIG_PATH_PATTERNS",
10
+ "ALL_INERT_FILE_PERMISSION_TOOLS",
11
+ "ALL_LEGACY_PERMISSION_REAP_TOOLS",
10
12
  "ALL_PERMISSION_ALLOW_TOOLS",
11
13
  "ALL_TRUST_ENTRY_PROJECT_PATH_BOUNDARY_QUOTE_CHARACTERS",
12
14
  "AUTO_MODE_ENVIRONMENT_ENTRY_PREFIX",
13
15
  "AUTO_MODE_ENVIRONMENT_ENTRY_TEMPLATE",
14
16
  "CLAUDE_SETTINGS_DIRECTORY_NAME",
15
17
  "CLAUDE_SETTINGS_FILENAME",
18
+ "CLAUDE_SETTINGS_LOCAL_FILENAME",
16
19
  "GIT_DIRECTORY_NAME",
20
+ "HOME_PROJECT_PATH_ALIAS",
21
+ "INERT_RULES_REMOVED_LOG_PREFIX",
22
+ "PROJECT_LOCAL_INERT_RULES_REMOVED_LOG_PREFIX",
17
23
  "TEXT_FILE_ENCODING",
18
24
  "UNIQUE_TEMPORARY_SUFFIX_BYTE_LENGTH",
25
+ "get_claude_project_local_settings_path",
19
26
  "get_claude_user_settings_path",
20
27
  )
21
28
 
@@ -24,6 +31,20 @@ ALL_PERMISSION_ALLOW_TOOLS: tuple[str, ...] = ("Edit", "Read")
24
31
 
25
32
  ALL_AGENT_CONFIG_DENY_TOOLS: tuple[str, ...] = ("Edit", "Read")
26
33
 
34
+ ALL_LEGACY_PERMISSION_REAP_TOOLS: tuple[str, ...] = ("Write", "Glob")
35
+
36
+ ALL_INERT_FILE_PERMISSION_TOOLS: tuple[str, ...] = ("Write", "Glob", "NotebookEdit")
37
+
38
+ HOME_PROJECT_PATH_ALIAS: str = "$HOME"
39
+
40
+ INERT_RULES_REMOVED_LOG_PREFIX: str = (
41
+ "Inert Write/Glob/NotebookEdit rules removed: "
42
+ )
43
+
44
+ PROJECT_LOCAL_INERT_RULES_REMOVED_LOG_PREFIX: str = (
45
+ "Project-local inert Write/Glob/NotebookEdit rules removed: "
46
+ )
47
+
27
48
  ALL_AGENT_CONFIG_PATH_PATTERNS: tuple[str, ...] = (
28
49
  "settings*.json",
29
50
  "hooks/**",
@@ -81,6 +102,8 @@ CLAUDE_SETTINGS_DIRECTORY_NAME: str = ".claude"
81
102
 
82
103
  CLAUDE_SETTINGS_FILENAME: str = "settings.json"
83
104
 
105
+ CLAUDE_SETTINGS_LOCAL_FILENAME: str = "settings.local.json"
106
+
84
107
  TEXT_FILE_ENCODING: str = "utf-8"
85
108
 
86
109
  UNIQUE_TEMPORARY_SUFFIX_BYTE_LENGTH: int = 8
@@ -88,3 +111,24 @@ UNIQUE_TEMPORARY_SUFFIX_BYTE_LENGTH: int = 8
88
111
 
89
112
  def get_claude_user_settings_path() -> Path:
90
113
  return Path.home() / CLAUDE_SETTINGS_DIRECTORY_NAME / CLAUDE_SETTINGS_FILENAME
114
+
115
+
116
+ def get_claude_project_local_settings_path(
117
+ project_root_path: Path | None = None,
118
+ ) -> Path:
119
+ """Return ``<project>/.claude/settings.local.json`` for the project root.
120
+
121
+ Args:
122
+ project_root_path: Project root; defaults to the process cwd.
123
+
124
+ Returns:
125
+ Path to the project-local Claude settings file (may not exist yet).
126
+ """
127
+ resolved_project_root_path = (
128
+ project_root_path if project_root_path is not None else Path.cwd()
129
+ )
130
+ return (
131
+ resolved_project_root_path
132
+ / CLAUDE_SETTINGS_DIRECTORY_NAME
133
+ / CLAUDE_SETTINGS_LOCAL_FILENAME
134
+ )
@@ -1,24 +1,24 @@
1
- """Configuration constants for the Copilot premium-interaction quota pre-check."""
2
-
3
- from __future__ import annotations
4
-
5
- from pathlib import Path
6
-
7
- COPILOT_QUOTA_ACCOUNT_ENV_VAR_NAME: str = "COPILOT_QUOTA_ACCOUNT"
8
- GH_TOKEN_ENV_VAR_NAME: str = "GH_TOKEN"
9
- COPILOT_INTERNAL_USER_API_PATH: str = "copilot_internal/user"
10
-
11
- QUOTA_SNAPSHOTS_FIELD_NAME: str = "quota_snapshots"
12
- PREMIUM_INTERACTIONS_FIELD_NAME: str = "premium_interactions"
13
- PREMIUM_UNLIMITED_FIELD_NAME: str = "unlimited"
14
- PREMIUM_REMAINING_FIELD_NAME: str = "remaining"
15
- PREMIUM_OVERAGE_PERMITTED_FIELD_NAME: str = "overage_permitted"
16
- PREMIUM_ENTITLEMENT_FIELD_NAME: str = "entitlement"
17
- PREMIUM_PERCENT_REMAINING_FIELD_NAME: str = "percent_remaining"
18
-
19
- EXIT_CODE_QUOTA_AVAILABLE: int = 0
20
- EXIT_CODE_OUT_OF_QUOTA: int = 1
21
- EXIT_CODE_QUOTA_API_DOWN: int = 2
22
- EXIT_CODE_NO_ACCOUNT_CONFIGURED: int = 3
23
-
24
- COPILOT_QUOTA_DEFAULT_ENV_FILE_PATH: Path = Path(__file__).resolve().parents[4] / ".env"
1
+ """Configuration constants for the Copilot premium-interaction quota pre-check."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+
7
+ COPILOT_QUOTA_ACCOUNT_ENV_VAR_NAME: str = "COPILOT_QUOTA_ACCOUNT"
8
+ GH_TOKEN_ENV_VAR_NAME: str = "GH_TOKEN"
9
+ COPILOT_INTERNAL_USER_API_PATH: str = "copilot_internal/user"
10
+
11
+ QUOTA_SNAPSHOTS_FIELD_NAME: str = "quota_snapshots"
12
+ PREMIUM_INTERACTIONS_FIELD_NAME: str = "premium_interactions"
13
+ PREMIUM_UNLIMITED_FIELD_NAME: str = "unlimited"
14
+ PREMIUM_REMAINING_FIELD_NAME: str = "remaining"
15
+ PREMIUM_OVERAGE_PERMITTED_FIELD_NAME: str = "overage_permitted"
16
+ PREMIUM_ENTITLEMENT_FIELD_NAME: str = "entitlement"
17
+ PREMIUM_PERCENT_REMAINING_FIELD_NAME: str = "percent_remaining"
18
+
19
+ EXIT_CODE_QUOTA_AVAILABLE: int = 0
20
+ EXIT_CODE_OUT_OF_QUOTA: int = 1
21
+ EXIT_CODE_QUOTA_API_DOWN: int = 2
22
+ EXIT_CODE_NO_ACCOUNT_CONFIGURED: int = 3
23
+
24
+ COPILOT_QUOTA_DEFAULT_ENV_FILE_PATH: Path = Path(__file__).resolve().parents[4] / ".env"
@@ -1,107 +1,107 @@
1
- """Constants and rule-format readers for stale_worktree_rule_sweep.
2
-
3
- The worktrees root is derived from the same ~/.claude home the permission
4
- grant script mints its rules under, so the location is named in exactly one
5
- place. A worktree rule points at a directory one or more segments below that
6
- root (flat or nested layouts)::
7
-
8
- Edit(<claude home>/worktrees/<worktree name>/.claude/**)
9
- ^^^^^^^^^^^^^^^
10
- segment 1 (flat)
11
-
12
- Edit(<claude home>/worktrees/<repository>/<worktree name>/.claude/**)
13
- ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
14
- nested layout
15
-
16
- worktree_directory_for_rule(rule, root) -> project directory under root
17
-
18
- A rule whose target path lies outside the worktrees root reads back as None,
19
- so the sweep leaves it untouched.
20
- """
21
-
22
- from pathlib import Path
23
-
24
- from pr_loop_shared_constants.claude_permissions_constants import (
25
- get_claude_user_settings_path,
26
- )
27
-
28
- WORKTREES_SUBDIRECTORY_NAME: str = "worktrees"
29
-
30
- MINIMUM_WORKTREE_PATH_SEGMENT_COUNT: int = 1
31
-
32
- RULE_PATH_OPEN_DELIMITER: str = "("
33
-
34
- RULE_PATH_CLOSE_DELIMITER: str = ")"
35
-
36
- CLAUDE_HOME_PATH_MARKER: str = "/.claude"
37
-
38
-
39
- def get_claude_worktrees_root() -> Path:
40
- """Return the ~/.claude/worktrees directory the grant rules point under.
41
-
42
- Reuses get_claude_user_settings_path so the ~/.claude home is resolved
43
- in one place: the settings file's parent directory is the home, and the
44
- worktrees live directly beneath it.
45
-
46
- Returns:
47
- The absolute path to the user's worktrees root directory.
48
- """
49
- claude_home_directory = get_claude_user_settings_path().parent
50
- return claude_home_directory / WORKTREES_SUBDIRECTORY_NAME
51
-
52
-
53
- def extract_rule_target_path(rule: str) -> str | None:
54
- """Return the path a permission rule targets, or None when unparsable.
55
-
56
- A rule reads `Tool(<path>)`; the target is the text between the first
57
- open delimiter and the last close delimiter::
58
-
59
- Edit(/repo/wt/.claude/**) -> /repo/wt/.claude/**
60
- not a rule -> None
61
-
62
- Args:
63
- rule: The permission rule string to read.
64
-
65
- Returns:
66
- The target path string, or None when the delimiters are absent.
67
- """
68
- open_index = rule.find(RULE_PATH_OPEN_DELIMITER)
69
- close_index = rule.rfind(RULE_PATH_CLOSE_DELIMITER)
70
- if open_index == -1 or close_index <= open_index:
71
- return None
72
- return rule[open_index + 1 : close_index]
73
-
74
-
75
- def worktree_directory_for_rule(rule: str, worktrees_root: Path) -> Path | None:
76
- """Return the worktree directory a rule targets, or None when it is not one.
77
-
78
- Keeps every path segment below the worktrees root so flat
79
- (`worktrees/<name>`) and nested (`worktrees/<repo>/<name>`) layouts
80
- both resolve to the on-disk project directory::
81
-
82
- Edit(<root>/flat-wt/.claude/**) -> <root>/flat-wt
83
- Edit(<root>/repo/wt/.claude/**) -> <root>/repo/wt
84
- Edit(/elsewhere/project/.claude/**) -> None
85
-
86
- Args:
87
- rule: The permission rule string to read.
88
- worktrees_root: The ~/.claude/worktrees directory rules live under.
89
-
90
- Returns:
91
- The worktree directory, or None when the target lies outside the
92
- worktrees root or has no path segments under it.
93
- """
94
- target_path = extract_rule_target_path(rule)
95
- if target_path is None:
96
- return None
97
- project_portion = target_path.rsplit(CLAUDE_HOME_PATH_MARKER, 1)[0]
98
- if not project_portion:
99
- return None
100
- try:
101
- relative_path = Path(project_portion).relative_to(worktrees_root)
102
- except ValueError:
103
- return None
104
- all_segments = relative_path.parts
105
- if len(all_segments) < MINIMUM_WORKTREE_PATH_SEGMENT_COUNT:
106
- return None
107
- return worktrees_root.joinpath(*all_segments)
1
+ """Constants and rule-format readers for stale_worktree_rule_sweep.
2
+
3
+ The worktrees root is derived from the same ~/.claude home the permission
4
+ grant script mints its rules under, so the location is named in exactly one
5
+ place. A worktree rule points at a directory one or more segments below that
6
+ root (flat or nested layouts)::
7
+
8
+ Edit(<claude home>/worktrees/<worktree name>/.claude/**)
9
+ ^^^^^^^^^^^^^^^
10
+ segment 1 (flat)
11
+
12
+ Edit(<claude home>/worktrees/<repository>/<worktree name>/.claude/**)
13
+ ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
14
+ nested layout
15
+
16
+ worktree_directory_for_rule(rule, root) -> project directory under root
17
+
18
+ A rule whose target path lies outside the worktrees root reads back as None,
19
+ so the sweep leaves it untouched.
20
+ """
21
+
22
+ from pathlib import Path
23
+
24
+ from pr_loop_shared_constants.claude_permissions_constants import (
25
+ get_claude_user_settings_path,
26
+ )
27
+
28
+ WORKTREES_SUBDIRECTORY_NAME: str = "worktrees"
29
+
30
+ MINIMUM_WORKTREE_PATH_SEGMENT_COUNT: int = 1
31
+
32
+ RULE_PATH_OPEN_DELIMITER: str = "("
33
+
34
+ RULE_PATH_CLOSE_DELIMITER: str = ")"
35
+
36
+ CLAUDE_HOME_PATH_MARKER: str = "/.claude"
37
+
38
+
39
+ def get_claude_worktrees_root() -> Path:
40
+ """Return the ~/.claude/worktrees directory the grant rules point under.
41
+
42
+ Reuses get_claude_user_settings_path so the ~/.claude home is resolved
43
+ in one place: the settings file's parent directory is the home, and the
44
+ worktrees live directly beneath it.
45
+
46
+ Returns:
47
+ The absolute path to the user's worktrees root directory.
48
+ """
49
+ claude_home_directory = get_claude_user_settings_path().parent
50
+ return claude_home_directory / WORKTREES_SUBDIRECTORY_NAME
51
+
52
+
53
+ def extract_rule_target_path(rule: str) -> str | None:
54
+ """Return the path a permission rule targets, or None when unparsable.
55
+
56
+ A rule reads `Tool(<path>)`; the target is the text between the first
57
+ open delimiter and the last close delimiter::
58
+
59
+ Edit(/repo/wt/.claude/**) -> /repo/wt/.claude/**
60
+ not a rule -> None
61
+
62
+ Args:
63
+ rule: The permission rule string to read.
64
+
65
+ Returns:
66
+ The target path string, or None when the delimiters are absent.
67
+ """
68
+ open_index = rule.find(RULE_PATH_OPEN_DELIMITER)
69
+ close_index = rule.rfind(RULE_PATH_CLOSE_DELIMITER)
70
+ if open_index == -1 or close_index <= open_index:
71
+ return None
72
+ return rule[open_index + 1 : close_index]
73
+
74
+
75
+ def worktree_directory_for_rule(rule: str, worktrees_root: Path) -> Path | None:
76
+ """Return the worktree directory a rule targets, or None when it is not one.
77
+
78
+ Keeps every path segment below the worktrees root so flat
79
+ (`worktrees/<name>`) and nested (`worktrees/<repo>/<name>`) layouts
80
+ both resolve to the on-disk project directory::
81
+
82
+ Edit(<root>/flat-wt/.claude/**) -> <root>/flat-wt
83
+ Edit(<root>/repo/wt/.claude/**) -> <root>/repo/wt
84
+ Edit(/elsewhere/project/.claude/**) -> None
85
+
86
+ Args:
87
+ rule: The permission rule string to read.
88
+ worktrees_root: The ~/.claude/worktrees directory rules live under.
89
+
90
+ Returns:
91
+ The worktree directory, or None when the target lies outside the
92
+ worktrees root or has no path segments under it.
93
+ """
94
+ target_path = extract_rule_target_path(rule)
95
+ if target_path is None:
96
+ return None
97
+ project_portion = target_path.rsplit(CLAUDE_HOME_PATH_MARKER, 1)[0]
98
+ if not project_portion:
99
+ return None
100
+ try:
101
+ relative_path = Path(project_portion).relative_to(worktrees_root)
102
+ except ValueError:
103
+ return None
104
+ all_segments = relative_path.parts
105
+ if len(all_segments) < MINIMUM_WORKTREE_PATH_SEGMENT_COUNT:
106
+ return None
107
+ return worktrees_root.joinpath(*all_segments)