claude-dev-env 2.35.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/.agents/skills/_shared/advisor/scripts/README.md +1 -1
  2. package/.agents/skills/autoconverge/SKILL.md +19 -15
  3. package/.agents/skills/autoconverge/reference/gotchas.md +3 -3
  4. package/.agents/skills/autoconverge/reference/multi-pr.md +6 -2
  5. package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +11 -0
  6. package/.agents/skills/autoconverge/workflow/converge.mjs +26 -33
  7. package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +26 -2
  8. package/.agents/skills/autoconverge/workflow/converge_multi.mjs +12 -28
  9. package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +16 -0
  10. package/.agents/skills/team-advisor/SKILL.md +11 -11
  11. package/_shared/advisor/advisor-protocol.md +51 -51
  12. package/_shared/advisor/reference/advisor-block.md +9 -9
  13. package/_shared/advisor/reference/astra-rung.md +39 -0
  14. package/_shared/advisor/reference/identity.md +4 -4
  15. package/_shared/advisor/reference/lifecycle.md +6 -6
  16. package/_shared/advisor/reference/spawn-walk-log.md +9 -9
  17. package/_shared/advisor/reference/third-party-bind.md +11 -11
  18. package/_shared/advisor/reference/warm-up.md +13 -13
  19. package/_shared/advisor/scripts/codex_astra_advisor.py +308 -0
  20. package/_shared/advisor/scripts/codex_astra_preflight.py +115 -0
  21. package/_shared/advisor/scripts/codex_astra_reply.py +159 -0
  22. package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +3 -3
  23. package/_shared/advisor/scripts/config/advisor_scripts_constants/astra_advisor_constants.py +38 -0
  24. package/_shared/advisor/scripts/model_tier_run_validator.py +17 -18
  25. package/_shared/advisor/scripts/tests/test_codex_astra_advisor.py +271 -0
  26. package/_shared/advisor/scripts/tests/test_codex_astra_preflight.py +24 -0
  27. package/_shared/advisor/scripts/tests/test_codex_astra_reply.py +42 -0
  28. package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +55 -30
  29. package/_shared/advisor/scripts/tests/test_tier_model_ids.py +14 -4
  30. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +14 -0
  31. package/_shared/pr-loop/scripts/terminology_sweep.py +138 -50
  32. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +13 -1
  33. package/bin/cde.mjs +175 -0
  34. package/bin/cde.test.mjs +222 -0
  35. package/bin/install-constants.mjs +4 -0
  36. package/bin/install.cursor-rules.test.mjs +233 -2
  37. package/bin/install.mjs +49 -3
  38. package/bin/pstack-model-preferences.codex.json +23 -0
  39. package/bin/select-pstack-models.test.mjs +378 -0
  40. package/docs/references/team-advisor-skill.md +3 -3
  41. package/hooks/hooks_constants/tool_names.py +20 -0
  42. package/hooks/validators/README.md +35 -1
  43. package/hooks/validators/fast_save_validators.py +63 -89
  44. package/hooks/validators/run_all_validators.py +16 -8
  45. package/hooks/validators/test_fast_save_validators_policy_lint.py +25 -0
  46. package/hooks/validators/test_run_all_validators_policy_lint.py +52 -0
  47. package/package.json +3 -2
  48. package/rules/pstack-models.md +119 -0
  49. package/scripts/cde_lint.py +258 -0
  50. package/scripts/check.ps1 +18 -6
  51. package/scripts/policy_lint/__init__.py +41 -0
  52. package/scripts/policy_lint/adapter_configuration.py +91 -0
  53. package/scripts/policy_lint/adapter_detectors.py +368 -0
  54. package/scripts/policy_lint/adapter_pairing.py +145 -0
  55. package/scripts/policy_lint/adapter_support.py +97 -0
  56. package/scripts/policy_lint/adapters.py +376 -0
  57. package/scripts/policy_lint/config/__init__.py +1 -0
  58. package/scripts/policy_lint/config/constants.py +77 -0
  59. package/scripts/policy_lint/engine.py +224 -0
  60. package/scripts/policy_lint/model.py +388 -0
  61. package/scripts/policy_lint/registry.py +171 -0
  62. package/scripts/policy_lint/render.py +91 -0
  63. package/scripts/policy_lint/selection.py +372 -0
  64. package/scripts/policy_lint/selection_git.py +147 -0
  65. package/scripts/repository_checks/__init__.py +1 -0
  66. package/scripts/repository_checks/claude_md.py +108 -0
  67. package/scripts/repository_checks/config/__init__.py +1 -0
  68. package/scripts/repository_checks/config/constants.py +150 -0
  69. package/scripts/repository_checks/env_var_documentation.py +243 -0
  70. package/scripts/repository_checks/hook_modules.py +34 -0
  71. package/scripts/repository_checks/models.py +37 -0
  72. package/scripts/repository_checks/package_inventory.py +118 -0
  73. package/scripts/repository_checks/pytest_testpaths.py +84 -0
  74. package/scripts/repository_checks/reporting.py +39 -0
  75. package/scripts/repository_checks/runner.py +93 -0
  76. package/scripts/repository_checks/tracked_secrets.py +147 -0
  77. package/scripts/repository_checks/tracked_tree.py +28 -0
  78. package/scripts/repository_policy.py +120 -0
  79. package/scripts/select_pstack_models.mjs +304 -0
  80. package/scripts/tests/repository_policy_test_support.py +89 -0
  81. package/scripts/tests/test_cde_lint.py +398 -0
  82. package/scripts/tests/test_claude_md.py +68 -0
  83. package/scripts/tests/test_env_var_documentation.py +133 -0
  84. package/scripts/tests/test_hook_modules.py +17 -0
  85. package/scripts/tests/test_models.py +26 -0
  86. package/scripts/tests/test_package_inventory.py +96 -0
  87. package/scripts/tests/test_policy_lint_rules_engine.py +381 -0
  88. package/scripts/tests/test_policy_lint_rules_registry.py +369 -0
  89. package/scripts/tests/test_policy_lint_selection.py +373 -0
  90. package/scripts/tests/test_pytest_testpaths.py +66 -0
  91. package/scripts/tests/test_reporting.py +54 -0
  92. package/scripts/tests/test_repository_policy.py +71 -0
  93. package/scripts/tests/test_runner.py +59 -0
  94. package/scripts/tests/test_tracked_secrets.py +175 -0
  95. package/scripts/tests/test_tracked_tree.py +28 -0
  96. package/_shared/advisor/reference/sol-rung.md +0 -39
  97. package/_shared/advisor/scripts/codex_sol_advisor.py +0 -581
  98. package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +0 -38
  99. package/_shared/advisor/scripts/tests/test_codex_sol_advisor.py +0 -740
@@ -0,0 +1,175 @@
1
+ """Behavior tests for tracked-secret checks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import hashlib
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+ from repository_checks.config.constants import (
11
+ ALL_TRACKED_SECRET_EXACT_EXEMPTIONS,
12
+ CHECK_ID_TRACKED_PERSONAL_DATA,
13
+ FINDINGS_EXIT_CODE,
14
+ )
15
+ from repository_checks.hook_modules import load_hooks_module
16
+ from repository_checks.tracked_secrets import collect_tracked_secret_findings
17
+
18
+ _TESTS_DIRECTORY = Path(__file__).resolve().parent
19
+ if str(_TESTS_DIRECTORY) not in sys.path:
20
+ sys.path.insert(0, str(_TESTS_DIRECTORY))
21
+
22
+ from repository_policy_test_support import (
23
+ commit_tracked_files,
24
+ initialize_repository,
25
+ run_policy,
26
+ write_text,
27
+ )
28
+
29
+ _SYNTHETIC_GITHUB_TOKEN = "ghp_" + ("A" * 36)
30
+ _UTF8_ENCODING = "utf-8"
31
+ _REPOSITORY_ROOT = Path(__file__).resolve().parents[4]
32
+ _EXEMPT_FIXTURE_EMAIL = "fixture-owner@company.io"
33
+ _OTHER_FIXTURE_EMAIL = "other-owner@company.io"
34
+ _OTHER_FIXTURE_HOME_PATH = "C:/Users/realname/notes.txt"
35
+ _FIXTURE_NOTES_RELATIVE_PATH = "src/notes.py"
36
+ _OTHER_NOTES_RELATIVE_PATH = "src/other_notes.py"
37
+ _PII_PREVENTION_CONSTANTS = load_hooks_module(
38
+ "hooks_constants.pii_prevention_constants"
39
+ )
40
+ _PII_CATEGORY_EMAIL = _PII_PREVENTION_CONSTANTS.CATEGORY_EMAIL
41
+ _PII_CATEGORY_HOME_PATH = _PII_PREVENTION_CONSTANTS.CATEGORY_HOME_PATH
42
+
43
+
44
+ def test_should_flag_a_tracked_secret(tmp_path: Path) -> None:
45
+ repository_root = tmp_path / "repo"
46
+ initialize_repository(repository_root)
47
+ write_text(
48
+ repository_root / "src" / "app.py", f"token = '{_SYNTHETIC_GITHUB_TOKEN}'\n"
49
+ )
50
+ commit_tracked_files(repository_root)
51
+ exit_code, stdout_text, _stderr_text = run_policy(repository_root)
52
+ assert exit_code == FINDINGS_EXIT_CODE
53
+ assert CHECK_ID_TRACKED_PERSONAL_DATA in stdout_text
54
+ assert "src/app.py" in stdout_text
55
+ assert _SYNTHETIC_GITHUB_TOKEN not in stdout_text
56
+
57
+
58
+ def test_should_fail_closed_before_reading_a_tracked_symlink_outside_repository(
59
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
60
+ ) -> None:
61
+ repository_root = tmp_path / "repo"
62
+ repository_root.mkdir()
63
+ outside_path = tmp_path / "outside.py"
64
+ write_text(outside_path, f"token = '{_SYNTHETIC_GITHUB_TOKEN}'\n")
65
+ tracked_symlink = repository_root / "linked.py"
66
+ tracked_symlink.symlink_to(outside_path)
67
+ original_read_text = Path.read_text
68
+ all_read_paths: list[Path] = []
69
+
70
+ def record_read_path(
71
+ file_path: Path,
72
+ encoding: str | None = None,
73
+ errors: str | None = None,
74
+ ) -> str:
75
+ all_read_paths.append(file_path)
76
+ return original_read_text(file_path, encoding=encoding, errors=errors)
77
+
78
+ monkeypatch.setattr(Path, "read_text", record_read_path)
79
+ with pytest.raises(OSError):
80
+ collect_tracked_secret_findings(repository_root, ["linked.py"])
81
+ assert tracked_symlink not in all_read_paths
82
+
83
+
84
+ def test_should_flag_a_different_email_in_the_same_exact_exempted_file(
85
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
86
+ ) -> None:
87
+ repository_root = tmp_path / "repo"
88
+ initialize_repository(repository_root)
89
+ _write_exact_exemption_fixture(repository_root)
90
+ commit_tracked_files(repository_root)
91
+ _install_exact_email_exemption(monkeypatch)
92
+ exit_code, stdout_text, _stderr_text = run_policy(repository_root)
93
+ assert exit_code == FINDINGS_EXIT_CODE
94
+ assert _pii_categories_for_path(stdout_text, _FIXTURE_NOTES_RELATIVE_PATH) == [
95
+ _PII_CATEGORY_EMAIL,
96
+ _PII_CATEGORY_HOME_PATH,
97
+ _PII_PREVENTION_CONSTANTS.CATEGORY_SECRET,
98
+ ]
99
+ assert _EXEMPT_FIXTURE_EMAIL not in stdout_text
100
+ assert _SYNTHETIC_GITHUB_TOKEN not in stdout_text
101
+
102
+
103
+ def test_should_flag_an_exact_exempt_value_at_a_different_path(
104
+ tmp_path: Path, monkeypatch: pytest.MonkeyPatch
105
+ ) -> None:
106
+ repository_root = tmp_path / "repo"
107
+ initialize_repository(repository_root)
108
+ _write_exact_exemption_fixture(repository_root)
109
+ commit_tracked_files(repository_root)
110
+ _install_exact_email_exemption(monkeypatch)
111
+ _exit_code, stdout_text, _stderr_text = run_policy(repository_root)
112
+ assert _PII_CATEGORY_EMAIL in _pii_categories_for_path(
113
+ stdout_text, _OTHER_NOTES_RELATIVE_PATH
114
+ )
115
+
116
+
117
+ def test_should_store_tracked_secret_exemptions_as_digests() -> None:
118
+ sha256_hex_digest_length = hashlib.sha256(b"").digest_size * 2
119
+ assert ALL_TRACKED_SECRET_EXACT_EXEMPTIONS
120
+ for _relative_path, _category, each_digest in ALL_TRACKED_SECRET_EXACT_EXEMPTIONS:
121
+ assert len(each_digest) == sha256_hex_digest_length
122
+ bytes.fromhex(each_digest)
123
+
124
+
125
+ def test_should_keep_owned_checker_modules_free_of_tracked_secret_findings() -> None:
126
+ checker_directory = (
127
+ _REPOSITORY_ROOT
128
+ / "packages"
129
+ / "claude-dev-env"
130
+ / "scripts"
131
+ / "repository_checks"
132
+ )
133
+ all_relative_paths = [
134
+ each_path.relative_to(_REPOSITORY_ROOT).as_posix()
135
+ for each_path in checker_directory.rglob("*.py")
136
+ if each_path.is_file()
137
+ ]
138
+ assert collect_tracked_secret_findings(_REPOSITORY_ROOT, all_relative_paths) == []
139
+
140
+
141
+ def _write_exact_exemption_fixture(repository_root: Path) -> None:
142
+ write_text(
143
+ repository_root / _FIXTURE_NOTES_RELATIVE_PATH,
144
+ f"contact = '{_EXEMPT_FIXTURE_EMAIL}'\nalt = '{_OTHER_FIXTURE_EMAIL}'\nhome = '{_OTHER_FIXTURE_HOME_PATH}'\ntoken = '{_SYNTHETIC_GITHUB_TOKEN}'\n",
145
+ )
146
+ write_text(
147
+ repository_root / _OTHER_NOTES_RELATIVE_PATH,
148
+ f"contact = '{_EXEMPT_FIXTURE_EMAIL}'\n",
149
+ )
150
+
151
+
152
+ def _pii_categories_for_path(stdout_text: str, relative_path: str) -> list[str]:
153
+ finding_prefix = f"{CHECK_ID_TRACKED_PERSONAL_DATA}: {relative_path}:"
154
+ return sorted(
155
+ each_line.split("[", 1)[1].split("]", 1)[0]
156
+ for each_line in stdout_text.splitlines()
157
+ if each_line.startswith(finding_prefix)
158
+ )
159
+
160
+
161
+ def _install_exact_email_exemption(monkeypatch: pytest.MonkeyPatch) -> None:
162
+ monkeypatch.setattr(
163
+ "repository_checks.tracked_secrets.repository_constants.ALL_TRACKED_SECRET_EXACT_EXEMPTIONS",
164
+ frozenset(
165
+ {
166
+ (
167
+ _FIXTURE_NOTES_RELATIVE_PATH,
168
+ _PII_CATEGORY_EMAIL,
169
+ hashlib.sha256(
170
+ _EXEMPT_FIXTURE_EMAIL.encode(_UTF8_ENCODING)
171
+ ).hexdigest(),
172
+ )
173
+ }
174
+ ),
175
+ )
@@ -0,0 +1,28 @@
1
+ """Behavior tests for tracked repository path discovery."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ _TESTS_DIRECTORY = Path(__file__).resolve().parent
9
+ if str(_TESTS_DIRECTORY) not in sys.path:
10
+ sys.path.insert(0, str(_TESTS_DIRECTORY))
11
+
12
+ from repository_checks.tracked_tree import tracked_relative_paths
13
+ from repository_policy_test_support import run_policy, seed_clean_repository, write_text
14
+
15
+
16
+ def test_should_list_only_committed_relative_paths(tmp_path: Path) -> None:
17
+ repository_root = seed_clean_repository(tmp_path / "repo")
18
+ write_text(repository_root / "untracked.txt", "not committed\n")
19
+ assert tracked_relative_paths(repository_root) == ("README.md",)
20
+
21
+
22
+ def test_should_skip_a_tracked_path_absent_from_the_worktree(tmp_path: Path) -> None:
23
+ repository_root = seed_clean_repository(tmp_path / "repo")
24
+ (repository_root / "README.md").unlink()
25
+ exit_code, stdout_text, stderr_text = run_policy(repository_root)
26
+ assert exit_code == 0
27
+ assert stdout_text == ""
28
+ assert stderr_text == ""
@@ -1,39 +0,0 @@
1
- # Sol rung
2
-
3
- Detail behind the **Host profiles → Sol rung** section of [`advisor-protocol.md`](../advisor-protocol.md).
4
- Open this when Fable is out of usage on a Claude or ThirdParty host and a Sol fallback bind is starting.
5
- On a Codex host, Sol is the in-session default; see [`identity.md`](identity.md).
6
-
7
- ## Flag
8
-
9
- `ADVISOR_SOL=1` (or `true` / `yes` / `on`) opens the Sol fallback after Fable is out of usage. Two channels exist: set the variable in the helper's process environment, or pass `--enable-sol` on the helper invocation — the CLI flag opens the rung for that run without touching the environment.
10
- Flag off both ways: fail closed when Fable did not bind.
11
- A Windows `setx` write only updates the persisted user environment; only a process started after that write inherits the new value, so an already-running session either sets the flag in its own invoking process environment or passes `--enable-sol`.
12
-
13
- ## Effort
14
-
15
- `ADVISOR_EFFORT` selects Codex `model_reasoning_effort` for Sol and `--effort` for Fable: `low`, `medium`, `high`, `xhigh`, or `max`. The default is `low`, which sends `model_reasoning_effort="low"`. Pass `--effort <level>` on the helper to set effort for that Sol run without changing the environment. An unset or unrecognized value uses `low`.
16
-
17
- Every fallback reply carries a `fallback_kind` field: `declined` when policy closed the rung (flag off, usage meter at or below the gate) and `broken` when the Sol path itself failed (missing executable, spawn error, timeout, malformed reply). A `broken` fallback is a defect to report, not a routing outcome.
18
-
19
- ## Preflight
20
-
21
- Flag on: run the Codex preflight first —
22
-
23
- ```
24
- python ~/.claude/_shared/pr-loop/scripts/codex_usage_probe.py
25
- ```
26
-
27
- **GOTCHA — probe path:** that installed path is the only one. `codex_sol_advisor.resolve_usage_probe_path` builds `~/.claude/_shared/pr-loop/scripts/codex_usage_probe.py` and stops. Do not hunt `skills/codex-review/`, Codex worktrees under `C:\dev\.codex\worktrees\`, or other copies. Repo home: `packages/claude-dev-env/_shared/pr-loop/scripts/`.
28
-
29
- The shared entry point is `~/.claude/_shared/advisor/scripts/codex_sol_advisor.py`; it calls the installed probe and owns Sol bind or resume parsing. Bind with `python ~/.claude/_shared/advisor/scripts/codex_sol_advisor.py --bind --enable-sol --cwd <repo-root>` and pipe the charter on stdin. Resume with `--resume <session_id>` and pipe the delta consult on stdin.
30
-
31
- The gate passes only when the probe exits 0, `percent_left` is finite numeric data, and `percent_left` is strictly greater than `WEEKLY_USAGE_GATE_THRESHOLD_PERCENT` from the existing probe. The exact-threshold case fails closed when Fable did not bind.
32
-
33
- ## Branches
34
-
35
- **Preflight pass** — bind one Codex CLI session at `gpt-5.6-sol` with `model_reasoning_effort` set from `ADVISOR_EFFORT` (default `low`), `--sandbox read-only`, and JSON output. The helper receives the standing-reviewer charter on stdin and returns only parsed ENDORSE / CORRECTION / PLAN / STOP guidance with a session ID.
36
-
37
- **Preflight fail** — probe failure, non-zero exit, timeout, missing or malformed usage, `null`, non-finite usage, or usage at or below the threshold fails closed when Fable did not bind.
38
-
39
- The helper owns the Sol attempt and returns an explicit fallback result. The consuming advisor path owns the Fable bind. Apply the same gate to every Sol attempt, including resume.