claude-dev-env 2.36.0 → 4.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.
Files changed (84) hide show
  1. package/.agents/skills/_shared/advisor/scripts/README.md +1 -1
  2. package/.agents/skills/syncing-submodules/SKILL.md +101 -0
  3. package/.agents/skills/syncing-submodules/reference/run-tasks.md +9 -0
  4. package/.agents/skills/syncing-submodules/scripts/submodule_sync.py +383 -0
  5. package/.agents/skills/syncing-submodules/scripts/submodule_sync_constants/__init__.py +1 -0
  6. package/.agents/skills/syncing-submodules/scripts/submodule_sync_constants/config/__init__.py +1 -0
  7. package/.agents/skills/syncing-submodules/scripts/submodule_sync_constants/config/constants.py +66 -0
  8. package/.agents/skills/syncing-submodules/scripts/sync_parent_pointer.py +88 -0
  9. package/.agents/skills/syncing-submodules/scripts/test_submodule_sync.py +303 -0
  10. package/.agents/skills/syncing-submodules/scripts/test_sync_parent_pointer.py +83 -0
  11. package/.agents/skills/team-advisor/SKILL.md +11 -11
  12. package/_shared/advisor/advisor-protocol.md +51 -51
  13. package/_shared/advisor/reference/advisor-block.md +9 -9
  14. package/_shared/advisor/reference/astra-rung.md +39 -0
  15. package/_shared/advisor/reference/identity.md +4 -4
  16. package/_shared/advisor/reference/lifecycle.md +6 -6
  17. package/_shared/advisor/reference/spawn-walk-log.md +9 -9
  18. package/_shared/advisor/reference/third-party-bind.md +11 -11
  19. package/_shared/advisor/reference/warm-up.md +13 -13
  20. package/_shared/advisor/scripts/codex_astra_advisor.py +308 -0
  21. package/_shared/advisor/scripts/codex_astra_preflight.py +115 -0
  22. package/_shared/advisor/scripts/codex_astra_reply.py +159 -0
  23. package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +3 -3
  24. package/_shared/advisor/scripts/config/advisor_scripts_constants/astra_advisor_constants.py +38 -0
  25. package/_shared/advisor/scripts/model_tier_run_validator.py +17 -18
  26. package/_shared/advisor/scripts/tests/test_codex_astra_advisor.py +271 -0
  27. package/_shared/advisor/scripts/tests/test_codex_astra_preflight.py +24 -0
  28. package/_shared/advisor/scripts/tests/test_codex_astra_reply.py +42 -0
  29. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +55 -30
  30. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +14 -4
  31. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +14 -0
  32. package/_shared/pr-loop/scripts/terminology_sweep.py +138 -50
  33. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +13 -1
  34. package/bin/ever-shipped-skills.mjs +1 -0
  35. package/bin/ever-shipped-skills.test.mjs +30 -0
  36. package/bin/git_hooks_installer.mjs +0 -1
  37. package/bin/git_hooks_installer.test.mjs +16 -1
  38. package/bin/install.mjs +5 -2
  39. package/bin/install.prune.test.mjs +36 -24
  40. package/bin/install.test.mjs +7 -0
  41. package/docs/references/team-advisor-skill.md +3 -3
  42. package/hooks/validators/README.md +35 -1
  43. package/package.json +1 -1
  44. package/scripts/check.ps1 +18 -6
  45. package/scripts/policy_lint/adapter_detectors.py +42 -2
  46. package/scripts/policy_lint/adapters.py +24 -0
  47. package/scripts/policy_lint/config/constants.py +11 -0
  48. package/scripts/policy_lint/engine.py +1 -1
  49. package/scripts/policy_lint/model.py +1 -0
  50. package/scripts/policy_lint/registry.py +10 -1
  51. package/scripts/repository_checks/__init__.py +1 -0
  52. package/scripts/repository_checks/claude_md.py +108 -0
  53. package/scripts/repository_checks/config/__init__.py +1 -0
  54. package/scripts/repository_checks/config/constants.py +150 -0
  55. package/scripts/repository_checks/env_var_documentation.py +243 -0
  56. package/scripts/repository_checks/hook_modules.py +34 -0
  57. package/scripts/repository_checks/models.py +37 -0
  58. package/scripts/repository_checks/package_inventory.py +118 -0
  59. package/scripts/repository_checks/pytest_testpaths.py +84 -0
  60. package/scripts/repository_checks/reporting.py +39 -0
  61. package/scripts/repository_checks/runner.py +93 -0
  62. package/scripts/repository_checks/tracked_secrets.py +147 -0
  63. package/scripts/repository_checks/tracked_tree.py +28 -0
  64. package/scripts/repository_policy.py +120 -0
  65. package/scripts/tests/repository_policy_test_support.py +89 -0
  66. package/scripts/tests/test_cde_lint.py +25 -1
  67. package/scripts/tests/test_claude_md.py +68 -0
  68. package/scripts/tests/test_env_var_documentation.py +133 -0
  69. package/scripts/tests/test_hook_modules.py +17 -0
  70. package/scripts/tests/test_models.py +26 -0
  71. package/scripts/tests/test_package_inventory.py +96 -0
  72. package/scripts/tests/test_policy_lint_rules_registry.py +117 -0
  73. package/scripts/tests/test_pytest_testpaths.py +66 -0
  74. package/scripts/tests/test_reporting.py +54 -0
  75. package/scripts/tests/test_repository_policy.py +71 -0
  76. package/scripts/tests/test_runner.py +59 -0
  77. package/scripts/tests/test_tracked_secrets.py +175 -0
  78. package/scripts/tests/test_tracked_tree.py +28 -0
  79. package/_shared/advisor/reference/sol-rung.md +0 -39
  80. package/_shared/advisor/scripts/codex_sol_advisor.py +0 -581
  81. package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +0 -38
  82. package/_shared/advisor/scripts/tests/test_codex_sol_advisor.py +0 -740
  83. package/hooks/git-hooks/post_commit.py +0 -241
  84. package/hooks/git-hooks/test_post_commit.py +0 -298
package/scripts/check.ps1 CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env pwsh
2
2
  <#
3
3
  .SYNOPSIS
4
- One-shot quality gate — runs ruff, hooks mypy, pr-loop mypy,
5
- process-tree mypy, and the blocking pytest suite from a single entry point.
4
+ One-shot quality gate. Runs ruff, hooks mypy, pr-loop mypy,
5
+ process-tree mypy, repository-policy, and the blocking pytest suite from a
6
+ single entry point.
6
7
 
7
8
  .DESCRIPTION
8
9
  Resolves paths relative to $PSScriptRoot so the script works from any CWD
@@ -11,9 +12,10 @@
11
12
  propagates this file). Tools: ruff over hooks/, mypy over hooks blocking
12
13
  and validators, mypy-pr-loop over _shared/pr-loop/scripts production
13
14
  modules, mypy-process-tree over the shared process-tree kill helper and
14
- its constants, and optional pytest over the blocking enforcer suite. Each tool
15
- runs sequentially; the first non-zero exit code is preserved as the
16
- script's exit code so CI/pre-commit can short-circuit on the first failure.
15
+ its constants, repository-policy over the committed tree, and optional
16
+ pytest over the blocking enforcer suite. Each tool runs in sequence. The
17
+ first non-zero exit code is preserved as the script's exit code so CI and
18
+ pre-commit can stop on the first failure.
17
19
 
18
20
  .PARAMETER SkipTests
19
21
  Skip the pytest run. Useful during local iteration when you want only the
@@ -25,19 +27,23 @@
25
27
  .PARAMETER SkipRuff
26
28
  Skip the ruff run.
27
29
 
30
+ .PARAMETER SkipRepositoryPolicy
31
+ Skip the committed-tree repository_policy.py run.
32
+
28
33
  .PARAMETER CommentPolicyBase
29
34
  Optional git reference used as the comment-policy baseline.
30
35
 
31
36
  .OUTPUTS
32
37
  Per-tool status lines on stdout. Final summary line:
33
38
  CHECK: OK
34
- CHECK: FAILED tools=ruff,mypy,mypy-pr-loop,mypy-process-tree,pytest
39
+ CHECK: FAILED tools=ruff,repository-policy,mypy,mypy-pr-loop,mypy-process-tree,pytest
35
40
  #>
36
41
  [CmdletBinding()]
37
42
  param(
38
43
  [switch]$SkipTests,
39
44
  [switch]$SkipMypy,
40
45
  [switch]$SkipRuff,
46
+ [switch]$SkipRepositoryPolicy,
41
47
  [string]$CommentPolicyBase
42
48
  )
43
49
 
@@ -121,6 +127,12 @@ Invoke-Tool -Label 'comment-policy' -Action {
121
127
  }
122
128
  }
123
129
 
130
+ if (-not $SkipRepositoryPolicy) {
131
+ Invoke-Tool -Label 'repository-policy' -Action {
132
+ python (Join-Path $PSScriptRoot 'repository_policy.py') --repository-root $repositoryRoot
133
+ }
134
+ }
135
+
124
136
  if (-not $SkipMypy) {
125
137
  Invoke-Tool -Label 'mypy' -Action {
126
138
  Push-Location $hooksRoot
@@ -3,11 +3,51 @@ from __future__ import annotations
3
3
  from collections.abc import Iterable
4
4
  from contextlib import redirect_stderr, redirect_stdout
5
5
  from io import StringIO
6
- from pathlib import Path
6
+ from pathlib import Path, PurePosixPath
7
7
 
8
8
  from . import adapter_support
9
9
  from .config import constants
10
- from .model import Diagnostic, Document
10
+ from .model import Diagnostic, Document, DocumentSet, Location, SelectionKind, Severity
11
+
12
+
13
+ def _terminology_diagnostic(finding: str) -> Diagnostic:
14
+ finding_match = constants.TERMINOLOGY_FINDING_PATTERN.fullmatch(finding)
15
+ if finding_match is None:
16
+ raise ValueError(finding)
17
+ return Diagnostic(
18
+ constants.TERMINOLOGY_SWEEP_RULE_ID,
19
+ Severity.ERROR,
20
+ finding_match.group(constants.TERMINOLOGY_MESSAGE_GROUP),
21
+ Location(
22
+ PurePosixPath(finding_match.group(constants.TERMINOLOGY_PATH_GROUP)),
23
+ int(finding_match.group(constants.TERMINOLOGY_LINE_NUMBER_GROUP)),
24
+ ),
25
+ )
26
+
27
+
28
+ def terminology_diagnostics(
29
+ document_set: DocumentSet,
30
+ load_module: adapter_support.HookModuleLoader,
31
+ ) -> tuple[Diagnostic, ...]:
32
+ """Report staged prose that near-misses a newly introduced identifier.
33
+
34
+ Args:
35
+ document_set: Candidate staged documents and repository root.
36
+ load_module: Shared script module loader.
37
+
38
+ Returns:
39
+ Diagnostics that name the prose file and line.
40
+ """
41
+ if document_set.selection is not SelectionKind.STAGED:
42
+ return ()
43
+ terminology_module = load_module(constants.TERMINOLOGY_SWEEP_MODULE_NAME)
44
+ helper_stdout = StringIO()
45
+ helper_stderr = StringIO()
46
+ with redirect_stdout(helper_stdout), redirect_stderr(helper_stderr):
47
+ all_findings = terminology_module.strict_staged_terminology_findings(
48
+ document_set.repository_root
49
+ )
50
+ return tuple(_terminology_diagnostic(each_finding) for each_finding in all_findings)
11
51
 
12
52
 
13
53
  def _stable_validator_message(document: Document, raw_message: str) -> str:
@@ -23,6 +23,16 @@ def _hooks_module(module_name: str) -> ModuleType:
23
23
  return importlib.import_module(module_name)
24
24
 
25
25
 
26
+ def _pr_loop_script_module(module_name: str) -> ModuleType:
27
+ package_directory = Path(__file__).resolve().parent.parent.parent
28
+ scripts_directory = str(
29
+ package_directory.joinpath(*constants.ALL_PR_LOOP_SCRIPTS_PATH_SEGMENTS)
30
+ )
31
+ if scripts_directory not in sys.path:
32
+ sys.path.insert(0, scripts_directory)
33
+ return importlib.import_module(module_name)
34
+
35
+
26
36
  def validator_diagnostics(
27
37
  document: Document, repository_root: Path
28
38
  ) -> tuple[Diagnostic, ...]:
@@ -222,6 +232,20 @@ def test_pairing_diagnostics(document_set: DocumentSet) -> tuple[Diagnostic, ...
222
232
  return adapter_pairing.test_pairing_diagnostics(document_set, _hooks_module)
223
233
 
224
234
 
235
+ def terminology_diagnostics(document_set: DocumentSet) -> tuple[Diagnostic, ...]:
236
+ """Report staged prose that near-misses a newly introduced identifier.
237
+
238
+ Args:
239
+ document_set: Candidate staged documents and repository root.
240
+
241
+ Returns:
242
+ Diagnostics that name the prose file and line.
243
+ """
244
+ return adapter_detectors.terminology_diagnostics(
245
+ document_set, _pr_loop_script_module
246
+ )
247
+
248
+
225
249
  def hook_format_diagnostics(
226
250
  document: Document, repository_root: Path
227
251
  ) -> tuple[Diagnostic, ...]:
@@ -1,3 +1,5 @@
1
+ import re
2
+
1
3
  INCOMPLETE_EXIT_CODE = 3
2
4
  INVALID_INPUT_EXIT_CODE = 2
3
5
  GIT_EXECUTABLE = "git"
@@ -64,3 +66,12 @@ FAST_SAVE_VALIDATORS_STEM = "fast_save_validators"
64
66
  ALL_OVERLAPPING_VALIDATOR_NAMES = frozenset(
65
67
  {"Python Style", "Magic Values", "Type Safety", "Test Safety", "React"}
66
68
  )
69
+ ALL_PR_LOOP_SCRIPTS_PATH_SEGMENTS = ("_shared", "pr-loop", "scripts")
70
+ TERMINOLOGY_SWEEP_MODULE_NAME = "terminology_sweep"
71
+ TERMINOLOGY_SWEEP_RULE_ID = "terminology-sweep"
72
+ TERMINOLOGY_FINDING_PATTERN = re.compile(
73
+ r"^(?P<path>.+):(?P<line_number>\d+): (?P<message>.+)$"
74
+ )
75
+ TERMINOLOGY_PATH_GROUP = "path"
76
+ TERMINOLOGY_LINE_NUMBER_GROUP = "line_number"
77
+ TERMINOLOGY_MESSAGE_GROUP = "message"
@@ -180,7 +180,7 @@ def _run_changeset_rule(
180
180
  all_diagnostics: list[Diagnostic],
181
181
  all_skipped_rules: list[str],
182
182
  ) -> None:
183
- if document_set.selection not in {SelectionKind.STAGED, SelectionKind.BASE}:
183
+ if document_set.selection not in rule.selections:
184
184
  all_skipped_rules.append(rule.rule_id)
185
185
  return
186
186
  all_diagnostics.extend(rule.check(document_set))
@@ -284,6 +284,7 @@ class DocumentRule:
284
284
  class ChangeSetRule:
285
285
  rule_id: str
286
286
  rule_sets: frozenset[str]
287
+ selections: frozenset[SelectionKind]
287
288
  check: DocumentSetChecker
288
289
 
289
290
 
@@ -133,7 +133,16 @@ def default_registry() -> tuple[model.Rule, ...]:
133
133
  *_text_document_rules(),
134
134
  *_configuration_document_rules(),
135
135
  model.ChangeSetRule(
136
- "test-pairing", frozenset({"changed"}), adapters.test_pairing_diagnostics
136
+ "test-pairing",
137
+ frozenset({"changed"}),
138
+ frozenset({model.SelectionKind.STAGED, model.SelectionKind.BASE}),
139
+ adapters.test_pairing_diagnostics,
140
+ ),
141
+ model.ChangeSetRule(
142
+ "terminology-sweep",
143
+ frozenset({"changed"}),
144
+ frozenset({model.SelectionKind.STAGED}),
145
+ adapters.terminology_diagnostics,
137
146
  ),
138
147
  model.RepositoryRule(
139
148
  "repository-path-collision",
@@ -0,0 +1 @@
1
+ """Committed-tree repository checks used by the repository_policy command."""
@@ -0,0 +1,108 @@
1
+ """CLAUDE.md reference checks for committed trees."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections import deque
6
+ from collections.abc import Sequence
7
+ from pathlib import Path
8
+ from types import ModuleType
9
+
10
+ from policy_lint.config.constants import PATH_SEPARATOR, UTF8_ENCODING
11
+
12
+ from repository_checks.config.constants import (
13
+ CHECK_ID_CLAUDE_MD_ORPHANS,
14
+ CLAUDE_MD_CONSTANTS_MODULE_NAME,
15
+ CLAUDE_MD_MISSING_FILE_MESSAGE_TEMPLATE,
16
+ CLAUDE_MD_SCAN_MODULE_NAME,
17
+ WINDOWS_PATH_SEPARATOR,
18
+ )
19
+ from repository_checks.hook_modules import load_hooks_module
20
+ from repository_checks.models import RepositoryFinding
21
+
22
+
23
+ def collect_claude_md_orphan_findings(
24
+ repository_root: Path, all_tracked_paths: Sequence[str]
25
+ ) -> list[RepositoryFinding]:
26
+ """Return missing CLAUDE.md references in the tracked tree.
27
+
28
+ Args:
29
+ repository_root: Git repository root.
30
+ all_tracked_paths: Repository-relative tracked paths.
31
+
32
+ Returns:
33
+ Findings for references whose files are absent.
34
+ """
35
+ subtree_scan = load_hooks_module(CLAUDE_MD_SCAN_MODULE_NAME)
36
+ claude_md_constants = load_hooks_module(CLAUDE_MD_CONSTANTS_MODULE_NAME)
37
+ all_findings: list[RepositoryFinding] = []
38
+ for each_relative_path in all_tracked_paths:
39
+ all_findings.extend(
40
+ find_orphan_findings_for_path(
41
+ repository_root,
42
+ each_relative_path,
43
+ subtree_scan,
44
+ claude_md_constants,
45
+ )
46
+ )
47
+ return all_findings
48
+
49
+
50
+ def find_orphan_findings_for_path(
51
+ repository_root: Path,
52
+ relative_path: str,
53
+ subtree_scan: ModuleType,
54
+ claude_md_constants: ModuleType,
55
+ ) -> list[RepositoryFinding]:
56
+ """Return missing files named by one CLAUDE.md file.
57
+
58
+ Args:
59
+ repository_root: Git repository root.
60
+ relative_path: Repository-relative path to inspect.
61
+ subtree_scan: Existing reference detector module.
62
+ claude_md_constants: Existing detector constants module.
63
+
64
+ Returns:
65
+ Findings for referenced files that are absent from the scan root.
66
+ """
67
+ if Path(relative_path).name != claude_md_constants.CLAUDE_MD_FILENAME:
68
+ return []
69
+ absolute_path = repository_root / relative_path
70
+ if not absolute_path.is_file():
71
+ return []
72
+ return _find_orphans_in_claude_md(absolute_path, relative_path, subtree_scan)
73
+
74
+
75
+ def _find_orphans_in_claude_md(
76
+ absolute_path: Path,
77
+ relative_path: str,
78
+ subtree_scan: ModuleType,
79
+ ) -> list[RepositoryFinding]:
80
+ content = absolute_path.read_text(encoding=UTF8_ENCODING)
81
+ claude_md_directory = absolute_path.parent
82
+ subtree_root = _subtree_root_for(claude_md_directory)
83
+ subtree_root.stat()
84
+ deque(subtree_root.rglob("*"), maxlen=0)
85
+ all_missing_filenames = subtree_scan.find_missing_filenames(
86
+ content, claude_md_directory
87
+ )
88
+ return _build_findings(relative_path, all_missing_filenames)
89
+
90
+
91
+ def _subtree_root_for(claude_md_directory: Path) -> Path:
92
+ parent_directory = claude_md_directory.parent
93
+ if parent_directory == claude_md_directory:
94
+ return claude_md_directory
95
+ return parent_directory
96
+
97
+
98
+ def _build_findings(
99
+ relative_path: str, all_missing_filenames: Sequence[str]
100
+ ) -> list[RepositoryFinding]:
101
+ return [
102
+ RepositoryFinding(
103
+ CHECK_ID_CLAUDE_MD_ORPHANS,
104
+ relative_path.replace(WINDOWS_PATH_SEPARATOR, PATH_SEPARATOR),
105
+ CLAUDE_MD_MISSING_FILE_MESSAGE_TEMPLATE.format(filename=each_filename),
106
+ )
107
+ for each_filename in all_missing_filenames
108
+ ]
@@ -0,0 +1 @@
1
+ """Configuration for the committed-tree repository checker."""
@@ -0,0 +1,150 @@
1
+ """Stable identifiers, report tokens, and committed-tree exemption tables."""
2
+
3
+ from policy_lint.config.constants import (
4
+ GIT_FILES_ARGUMENT,
5
+ GIT_ZERO_TERMINATED_FLAG,
6
+ INCOMPLETE_EXIT_CODE,
7
+ INVALID_INPUT_EXIT_CODE,
8
+ )
9
+
10
+ CHECK_ID_CLAUDE_MD_ORPHANS = "claude-md-orphans"
11
+ CHECK_ID_ENV_VAR_DOCUMENTATION = "env-var-documentation"
12
+ CHECK_ID_PACKAGE_INVENTORY = "package-inventory"
13
+ CHECK_ID_PYTEST_TESTPATHS = "pytest-testpaths"
14
+ CHECK_ID_TRACKED_PERSONAL_DATA = "tracked-secrets"
15
+
16
+ ALL_CHECK_IDS = (
17
+ CHECK_ID_CLAUDE_MD_ORPHANS,
18
+ CHECK_ID_ENV_VAR_DOCUMENTATION,
19
+ CHECK_ID_PACKAGE_INVENTORY,
20
+ CHECK_ID_PYTEST_TESTPATHS,
21
+ CHECK_ID_TRACKED_PERSONAL_DATA,
22
+ )
23
+
24
+ SUCCESS_EXIT_CODE = 0
25
+ FINDINGS_EXIT_CODE = 1
26
+ FAILED_CHECK_EXIT_CODE = INCOMPLETE_EXIT_CODE
27
+ USAGE_EXIT_CODE = INVALID_INPUT_EXIT_CODE
28
+
29
+ REPOSITORY_ROOT_FLAG = "--repository-root"
30
+ FINDING_LINE_TEMPLATE = "{check_id}: {relative_path}: {message}"
31
+ RULE_FAILED_LINE_TEMPLATE = "error: rule failed: {check_id}"
32
+ REPORT_LINE_SEPARATOR = "\n"
33
+ EMPTY_REPORT_TEXT = ""
34
+ TRACKED_MATCH_MESSAGE_TEMPLATE = "[{category}] {preview}"
35
+ CLAUDE_MD_MISSING_FILE_MESSAGE_TEMPLATE = "references missing file {filename}"
36
+ PACKAGE_INVENTORY_MESSAGE_TEMPLATE = "production file is absent from package inventory"
37
+ PYTEST_TESTPATH_MESSAGE_TEMPLATE = (
38
+ "test file is outside the package testpaths allowlist"
39
+ )
40
+ ALL_GIT_LS_FILES_ARGUMENTS = (GIT_FILES_ARGUMENT, GIT_ZERO_TERMINATED_FLAG)
41
+ PYPROJECT_FILENAME = "pyproject.toml"
42
+ WINDOWS_PATH_SEPARATOR = "\\"
43
+
44
+ CLAUDE_MD_SCAN_MODULE_NAME = "blocking.claude_md_orphan_file_blocker_parts.subtree_scan"
45
+ CLAUDE_MD_CONSTANTS_MODULE_NAME = (
46
+ "hooks_constants.claude_md_orphan_file_blocker_constants"
47
+ )
48
+ ENV_VAR_DRIFT_MODULE_NAME = "blocking.env_var_table_code_drift_blocker"
49
+ ENV_VAR_DRIFT_CONSTANTS_MODULE_NAME = (
50
+ "hooks_constants.env_var_table_code_drift_constants"
51
+ )
52
+ PACKAGE_INVENTORY_DETECTION_MODULE_NAME = (
53
+ "blocking.package_inventory_stale_blocker_parts.inventory_detection"
54
+ )
55
+ PACKAGE_INVENTORY_CONSTANTS_MODULE_NAME = (
56
+ "hooks_constants.package_inventory_stale_blocker_constants"
57
+ )
58
+ PYTEST_TESTPATHS_MODULE_NAME = "blocking.pytest_testpaths_orphan_blocker"
59
+ PII_SCANNER_MODULE_NAME = "blocking.pii_scanner"
60
+ REPOSITORY_EXEMPTION_MODULE_NAME = (
61
+ "blocking.pii_prevention_blocker_parts.repository_exemption"
62
+ )
63
+
64
+ ALL_FAIL_CLOSED_EXCEPTION_TYPES = (
65
+ AttributeError,
66
+ ImportError,
67
+ KeyError,
68
+ OSError,
69
+ RuntimeError,
70
+ SyntaxError,
71
+ TypeError,
72
+ UnicodeError,
73
+ ValueError,
74
+ )
75
+
76
+ ALL_ARCHIVED_SKILL_DIRECTORY_SEGMENTS = (".agents", "skills-archived")
77
+ ALL_TRACKED_SECRET_EXACT_EXEMPTIONS: frozenset[tuple[str, str, str]] = frozenset(
78
+ (
79
+ (
80
+ "packages/claude-dev-env/.agents/skills-archived/pr-converge/reference/per-tick.md",
81
+ "email",
82
+ "3de132cd98be7bf26b6f08e81c31c799a891bc32046b61f0b6fe3671ca2e44b5",
83
+ ),
84
+ (
85
+ "packages/claude-dev-env/.agents/skills/_shared/pr-loop/prompts/pr-consistency-audit.xml",
86
+ "home-path",
87
+ "805e3271caeec55a94438e221726e9349e46fa4970592bd03ffd3adac5e0ea8a",
88
+ ),
89
+ (
90
+ "packages/claude-dev-env/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py",
91
+ "home-path",
92
+ "a4f1f978f88b601288424144a5f5066cdc9154868cf2aaab6e0869a103be72a5",
93
+ ),
94
+ (
95
+ "packages/claude-dev-env/.agents/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py",
96
+ "home-path",
97
+ "665e48f1b198dd2a6526e25700fbcb86566d1f8b47d4475a6cc318b1634a4546",
98
+ ),
99
+ (
100
+ "packages/claude-dev-env/_shared/pr-loop/scripts/_claude_permissions_common.py",
101
+ "home-path",
102
+ "9c48917645524d03ea0a4f4d8755aa8f0d59f3108e1aa976202a02e613c1444d",
103
+ ),
104
+ (
105
+ "packages/claude-dev-env/_shared/pr-loop/scripts/_claude_permissions_common.py",
106
+ "home-path",
107
+ "07ba214cb23325675bc68e5513c030e968eccf2760cb5917d932ae5da29d5af1",
108
+ ),
109
+ (
110
+ "packages/claude-dev-env/_shared/pr-loop/scripts/_claude_permissions_common.py",
111
+ "home-path",
112
+ "d41ce8d0f21de2d5320bdd8cd4e8693a2f3d6ea59db6df5ea102a7d2be4b2c22",
113
+ ),
114
+ (
115
+ "packages/claude-dev-env/audit-rubrics/prompts/category-n-test-name-scenario-verifier.md",
116
+ "home-path",
117
+ "550c7b16a2a04e1d05a8a6b4f5b764b8d4fdef65e9d79d09e5dbb3a15a855812",
118
+ ),
119
+ (
120
+ "packages/claude-dev-env/audit-rubrics/prompts/category-n-test-name-scenario-verifier.md",
121
+ "home-path",
122
+ "b8bbdd1a7ebdad16f4e51377a3f21d05dd35992d89e35971b28b05f53245c69d",
123
+ ),
124
+ (
125
+ "packages/claude-dev-env/bin/expand_home_directory_tokens.mjs",
126
+ "home-path",
127
+ "10d5571e7126d2018ee7fb06aa29c72a9d503cac79a4e52d6848602ee10e8832",
128
+ ),
129
+ (
130
+ "packages/claude-dev-env/bin/expand_home_directory_tokens.mjs",
131
+ "home-path",
132
+ "09f83c224a02c370d3d63de5c330e1a830fc92866330fc7963b5b5fd20ffcb91",
133
+ ),
134
+ (
135
+ "packages/claude-dev-env/hooks/blocking/volatile_path_in_post_blocker.py",
136
+ "home-path",
137
+ "ed9203c8078e4c6b832600085f28f24656d679aa8dca82ecc2557afc3df25036",
138
+ ),
139
+ (
140
+ "packages/claude-dev-env/hooks/hooks_constants/hardcoded_user_path_constants.py",
141
+ "home-path",
142
+ "0967160658d782c558722232cad7d47dc19267943d4667b41d3eff1e605be2f4",
143
+ ),
144
+ (
145
+ "packages/claude-dev-env/hooks/hooks_constants/hardcoded_user_path_constants.py",
146
+ "home-path",
147
+ "a541acfac2e649581bca0cd03e4c3dcf306344915017d9cd6be4ad57a8fd7379",
148
+ ),
149
+ )
150
+ )