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.
- package/.agents/skills/_shared/advisor/scripts/README.md +1 -1
- package/.agents/skills/autoconverge/SKILL.md +19 -15
- package/.agents/skills/autoconverge/reference/gotchas.md +3 -3
- package/.agents/skills/autoconverge/reference/multi-pr.md +6 -2
- package/.agents/skills/autoconverge/workflow/converge.contract.test.mjs +11 -0
- package/.agents/skills/autoconverge/workflow/converge.mjs +26 -33
- package/.agents/skills/autoconverge/workflow/converge.run-input.test.mjs +26 -2
- package/.agents/skills/autoconverge/workflow/converge_multi.mjs +12 -28
- package/.agents/skills/autoconverge/workflow/converge_multi.run-input.test.mjs +16 -0
- package/.agents/skills/team-advisor/SKILL.md +11 -11
- package/_shared/advisor/advisor-protocol.md +51 -51
- package/_shared/advisor/reference/advisor-block.md +9 -9
- package/_shared/advisor/reference/astra-rung.md +39 -0
- package/_shared/advisor/reference/identity.md +4 -4
- package/_shared/advisor/reference/lifecycle.md +6 -6
- package/_shared/advisor/reference/spawn-walk-log.md +9 -9
- package/_shared/advisor/reference/third-party-bind.md +11 -11
- package/_shared/advisor/reference/warm-up.md +13 -13
- package/_shared/advisor/scripts/codex_astra_advisor.py +308 -0
- package/_shared/advisor/scripts/codex_astra_preflight.py +115 -0
- package/_shared/advisor/scripts/codex_astra_reply.py +159 -0
- package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +3 -3
- package/_shared/advisor/scripts/config/advisor_scripts_constants/astra_advisor_constants.py +38 -0
- package/_shared/advisor/scripts/model_tier_run_validator.py +17 -18
- package/_shared/advisor/scripts/tests/test_codex_astra_advisor.py +271 -0
- package/_shared/advisor/scripts/tests/test_codex_astra_preflight.py +24 -0
- package/_shared/advisor/scripts/tests/test_codex_astra_reply.py +42 -0
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +55 -30
- package/_shared/advisor/scripts/tests/test_tier_model_ids.py +14 -4
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +14 -0
- package/_shared/pr-loop/scripts/terminology_sweep.py +138 -50
- package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +13 -1
- package/bin/cde.mjs +175 -0
- package/bin/cde.test.mjs +222 -0
- package/bin/install-constants.mjs +4 -0
- package/bin/install.cursor-rules.test.mjs +233 -2
- package/bin/install.mjs +49 -3
- package/bin/pstack-model-preferences.codex.json +23 -0
- package/bin/select-pstack-models.test.mjs +378 -0
- package/docs/references/team-advisor-skill.md +3 -3
- package/hooks/hooks_constants/tool_names.py +20 -0
- package/hooks/validators/README.md +35 -1
- package/hooks/validators/fast_save_validators.py +63 -89
- package/hooks/validators/run_all_validators.py +16 -8
- package/hooks/validators/test_fast_save_validators_policy_lint.py +25 -0
- package/hooks/validators/test_run_all_validators_policy_lint.py +52 -0
- package/package.json +3 -2
- package/rules/pstack-models.md +119 -0
- package/scripts/cde_lint.py +258 -0
- package/scripts/check.ps1 +18 -6
- package/scripts/policy_lint/__init__.py +41 -0
- package/scripts/policy_lint/adapter_configuration.py +91 -0
- package/scripts/policy_lint/adapter_detectors.py +368 -0
- package/scripts/policy_lint/adapter_pairing.py +145 -0
- package/scripts/policy_lint/adapter_support.py +97 -0
- package/scripts/policy_lint/adapters.py +376 -0
- package/scripts/policy_lint/config/__init__.py +1 -0
- package/scripts/policy_lint/config/constants.py +77 -0
- package/scripts/policy_lint/engine.py +224 -0
- package/scripts/policy_lint/model.py +388 -0
- package/scripts/policy_lint/registry.py +171 -0
- package/scripts/policy_lint/render.py +91 -0
- package/scripts/policy_lint/selection.py +372 -0
- package/scripts/policy_lint/selection_git.py +147 -0
- package/scripts/repository_checks/__init__.py +1 -0
- package/scripts/repository_checks/claude_md.py +108 -0
- package/scripts/repository_checks/config/__init__.py +1 -0
- package/scripts/repository_checks/config/constants.py +150 -0
- package/scripts/repository_checks/env_var_documentation.py +243 -0
- package/scripts/repository_checks/hook_modules.py +34 -0
- package/scripts/repository_checks/models.py +37 -0
- package/scripts/repository_checks/package_inventory.py +118 -0
- package/scripts/repository_checks/pytest_testpaths.py +84 -0
- package/scripts/repository_checks/reporting.py +39 -0
- package/scripts/repository_checks/runner.py +93 -0
- package/scripts/repository_checks/tracked_secrets.py +147 -0
- package/scripts/repository_checks/tracked_tree.py +28 -0
- package/scripts/repository_policy.py +120 -0
- package/scripts/select_pstack_models.mjs +304 -0
- package/scripts/tests/repository_policy_test_support.py +89 -0
- package/scripts/tests/test_cde_lint.py +398 -0
- package/scripts/tests/test_claude_md.py +68 -0
- package/scripts/tests/test_env_var_documentation.py +133 -0
- package/scripts/tests/test_hook_modules.py +17 -0
- package/scripts/tests/test_models.py +26 -0
- package/scripts/tests/test_package_inventory.py +96 -0
- package/scripts/tests/test_policy_lint_rules_engine.py +381 -0
- package/scripts/tests/test_policy_lint_rules_registry.py +369 -0
- package/scripts/tests/test_policy_lint_selection.py +373 -0
- package/scripts/tests/test_pytest_testpaths.py +66 -0
- package/scripts/tests/test_reporting.py +54 -0
- package/scripts/tests/test_repository_policy.py +71 -0
- package/scripts/tests/test_runner.py +59 -0
- package/scripts/tests/test_tracked_secrets.py +175 -0
- package/scripts/tests/test_tracked_tree.py +28 -0
- package/_shared/advisor/reference/sol-rung.md +0 -39
- package/_shared/advisor/scripts/codex_sol_advisor.py +0 -581
- package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +0 -38
- 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.
|