claude-dev-env 8.53.2 → 8.54.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/docs/rule-guides/request-scope.md +20 -0
- package/package.json +1 -1
- package/rules/request-scope.md +7 -0
- package/scripts/account_broker.py +4 -2
- package/scripts/dev_env_scripts_constants/codex_account_constants.py +3 -0
- package/scripts/test_account_broker.py +32 -0
- package/scripts/tests/test_rule_load_scopes.py +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Back to the [rule entry](../../rules/request-scope.md).
|
|
2
|
+
|
|
3
|
+
# Request scope
|
|
4
|
+
|
|
5
|
+
**When this applies:** The user asks whether part of a prompt, rule, card, or check is still needed, or asks you to change one.
|
|
6
|
+
|
|
7
|
+
## Rule
|
|
8
|
+
|
|
9
|
+
Answer for the whole block that part belongs to. When a shipped hook, gate, or check now enforces what a block tells an agent to do, every line of that block that restates the enforced behavior is dead text. Propose removing all of those lines, and name each line that stays with the reason it stays.
|
|
10
|
+
|
|
11
|
+
Before you report the change done, read the output the user will use and compare it with the user's own words.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
A starter's naming block holds title rules, rename steps, and steps to install a Stop hook. The user asks whether the Stop hook is still needed, and release notes show a shipped Stop gate and a title format gate.
|
|
16
|
+
|
|
17
|
+
- Narrow answer: remove the Stop hook steps and keep the rest. The title length rule and the rename steps stay, though the gates enforce both.
|
|
18
|
+
- Whole-block answer: remove the Stop hook steps, the rename steps, and every title rule the format gate checks. Keep the lines no gate checks, each with its reason.
|
|
19
|
+
|
|
20
|
+
**Enforcement:** none, the agent applies it.
|
package/package.json
CHANGED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Request scope
|
|
2
|
+
|
|
3
|
+
**When:** Asked whether part of a block is still needed, or asked to change one.
|
|
4
|
+
|
|
5
|
+
A shipped gate makes each block line restating what it enforces dead text. Propose removing all of them, past the part asked about, and give each kept line's reason. Read the output back before reporting done.
|
|
6
|
+
|
|
7
|
+
**Full text:** [`docs/rule-guides/request-scope.md`](../docs/rule-guides/request-scope.md)
|
|
@@ -54,6 +54,7 @@ from dev_env_scripts_constants.account_broker_constants import (
|
|
|
54
54
|
from dev_env_scripts_constants.codex_account_constants import (
|
|
55
55
|
CODEX_HOME_ENVIRONMENT_VARIABLE,
|
|
56
56
|
MAIN_CODEX_HOME_DIRECTORY_NAME,
|
|
57
|
+
NO_ROSTER_ACCOUNT_NAME,
|
|
57
58
|
TIER_NORMAL,
|
|
58
59
|
)
|
|
59
60
|
|
|
@@ -78,7 +79,7 @@ def choose_from_readings(
|
|
|
78
79
|
"""
|
|
79
80
|
if product is Product.CODEX and not all_readings:
|
|
80
81
|
home = Path(os.environ.get(CODEX_HOME_ENVIRONMENT_VARIABLE) or Path.home() / MAIN_CODEX_HOME_DIRECTORY_NAME).resolve()
|
|
81
|
-
return Decision("run", Account(product,
|
|
82
|
+
return Decision("run", Account(product, NO_ROSTER_ACCOUNT_NAME, home, True), None, "no roster is configured", TIER_NORMAL)
|
|
82
83
|
all_available = [each_reading for each_reading in all_readings if each_reading.account not in all_spent_accounts]
|
|
83
84
|
selected = (
|
|
84
85
|
_choose_claude(all_available, preferred_command)
|
|
@@ -366,7 +367,8 @@ def _parse_spent_mark(all_accounts_by_name: Mapping[str, Reading], mark: str, pr
|
|
|
366
367
|
raise BrokerConfigurationError(f"invalid reset for account {name}") from error
|
|
367
368
|
reading = all_accounts_by_name.get(name)
|
|
368
369
|
if reading is None:
|
|
369
|
-
|
|
370
|
+
if all_accounts_by_name or name != NO_ROSTER_ACCOUNT_NAME:
|
|
371
|
+
print(f"warning: spent mark names {name}, an account outside the roster; choose waits until its reset", file=sys.stderr)
|
|
370
372
|
return Reading(Account(product, name, Path(), False), None), reset
|
|
371
373
|
return reading, reset
|
|
372
374
|
|
|
@@ -66,6 +66,9 @@ CODEX_PROFILES_ROOT_ENVIRONMENT_VARIABLE: str = "CODEX_PROFILES_ROOT"
|
|
|
66
66
|
MAIN_CODEX_HOME_DIRECTORY_NAME: str = ".codex"
|
|
67
67
|
"""Directory under the user home that holds the shared Codex setup."""
|
|
68
68
|
|
|
69
|
+
NO_ROSTER_ACCOUNT_NAME: str = "default"
|
|
70
|
+
"""Account name the broker gives the shared Codex home when no roster is configured."""
|
|
71
|
+
|
|
69
72
|
CODEX_HOME_ENVIRONMENT_VARIABLE: str = "CODEX_HOME"
|
|
70
73
|
"""Environment variable that points Codex at one account's home."""
|
|
71
74
|
|
|
@@ -1026,6 +1026,38 @@ def test_should_warn_when_a_spent_mark_names_an_account_outside_the_roster(
|
|
|
1026
1026
|
assert "outside the roster" in all_warning_lines[0]
|
|
1027
1027
|
|
|
1028
1028
|
|
|
1029
|
+
def test_should_not_warn_when_the_default_account_is_marked_without_a_roster(
|
|
1030
|
+
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
1031
|
+
) -> None:
|
|
1032
|
+
monkeypatch.setitem(account_broker.all_product_adapters, Product.CODEX, _adapter((), {}))
|
|
1033
|
+
_freeze_clock(monkeypatch, NOW)
|
|
1034
|
+
reset = NOW + timedelta(hours=2)
|
|
1035
|
+
|
|
1036
|
+
account_broker.main(("choose", "--product", "codex", "--spent", f"default:{int(reset.timestamp())}"))
|
|
1037
|
+
|
|
1038
|
+
assert capsys.readouterr().err == ""
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
@pytest.mark.parametrize(
|
|
1042
|
+
("all_roster_names", "marked_name"),
|
|
1043
|
+
[(("first",), "default"), ((), "visitor")],
|
|
1044
|
+
)
|
|
1045
|
+
def test_should_warn_when_a_spent_mark_names_an_account_the_roster_lacks(
|
|
1046
|
+
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], all_roster_names: tuple[str, ...], marked_name: str
|
|
1047
|
+
) -> None:
|
|
1048
|
+
all_accounts = tuple(_account(each_name) for each_name in all_roster_names)
|
|
1049
|
+
monkeypatch.setitem(account_broker.all_product_adapters, Product.CODEX, _adapter(all_accounts, {each_name: _meters(80, 80) for each_name in all_roster_names}))
|
|
1050
|
+
_freeze_clock(monkeypatch, NOW)
|
|
1051
|
+
reset = NOW + timedelta(hours=2)
|
|
1052
|
+
|
|
1053
|
+
account_broker.main(("choose", "--product", "codex", "--spent", f"{marked_name}:{int(reset.timestamp())}"))
|
|
1054
|
+
|
|
1055
|
+
all_warning_lines = capsys.readouterr().err.splitlines()
|
|
1056
|
+
assert len(all_warning_lines) == 1
|
|
1057
|
+
assert marked_name in all_warning_lines[0]
|
|
1058
|
+
assert "outside the roster" in all_warning_lines[0]
|
|
1059
|
+
|
|
1060
|
+
|
|
1029
1061
|
@pytest.mark.parametrize("mark", ["", ":1800000000"])
|
|
1030
1062
|
def test_should_reject_a_spent_mark_without_an_account_name(
|
|
1031
1063
|
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], mark: str
|