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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "8.53.2",
3
+ "version": "8.54.0",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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, "default", home, True), None, "no roster is configured", TIER_NORMAL)
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
- print(f"warning: spent mark names {name}, an account outside the roster; choose waits until its reset", file=sys.stderr)
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
@@ -20,6 +20,7 @@ ALWAYS_ON_RULE_NAMES = frozenset(
20
20
  "no-contrast-framing.md",
21
21
  "question-presentation.md",
22
22
  "research-mode.md",
23
+ "request-scope.md",
23
24
  "session-title.md",
24
25
  "skill-pointers.md",
25
26
  "shell-invocation.md",