claude-dev-env 8.49.1 → 8.49.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-dev-env",
3
- "version": "8.49.1",
3
+ "version": "8.49.3",
4
4
  "description": "Claude Code development standards — rules, hooks, agents, commands, and skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -211,6 +211,7 @@ class _RunContext:
211
211
  all_attempts: list[tuple[str, str]]
212
212
  all_spent_accounts: set[Account]
213
213
  all_spent_resets: dict[Account, datetime]
214
+ start_failure_text: str = ""
214
215
 
215
216
 
216
217
  def _prepare_run(
@@ -234,7 +235,7 @@ def _wait_outcome(context: _RunContext, decision: Decision) -> JobOutcome:
234
235
  context.report.final_decision = decision
235
236
  all_attempt_statuses = {each_status for _, each_status in context.all_attempts}
236
237
  if all_attempt_statuses == {"start_failed"}:
237
- return JobOutcome(COMMAND_MISSING_EXIT_CODE, "", "", None, tuple(context.all_attempts), "start_failed", None, None)
238
+ return JobOutcome(COMMAND_MISSING_EXIT_CODE, "", context.start_failure_text, None, tuple(context.all_attempts), "start_failed", None, None)
238
239
  status = "exhausted" if context.all_attempts else "wait"
239
240
  return JobOutcome(WAIT_EXIT_CODE, "", "", None, tuple(context.all_attempts), status, None, decision.resets_at, decision.reason)
240
241
 
@@ -287,6 +288,7 @@ def _attempt_once(context: _RunContext, decision: Decision) -> JobOutcome | None
287
288
  except (OSError, subprocess.TimeoutExpired) as error:
288
289
  status = "timeout" if isinstance(error, subprocess.TimeoutExpired) else "start_failed"
289
290
  _record_spent_attempt(context, account, status, COMMAND_MISSING_EXIT_CODE)
291
+ context.start_failure_text = str(error)
290
292
  if isinstance(error, subprocess.TimeoutExpired) or not context.all_readings:
291
293
  context.report.final_decision = decision
292
294
  final_status = "advisor_blocked" if context.product is Product.CLAUDE else status
@@ -908,6 +908,20 @@ def test_should_record_start_failure_without_launching_a_command_missing_from_pa
908
908
  assert outcome.returncode == 127
909
909
 
910
910
 
911
+ def test_should_keep_the_start_failure_text_when_no_account_can_start(monkeypatch: pytest.MonkeyPatch) -> None:
912
+ monkeypatch.setitem(account_broker.all_product_adapters, Product.CLAUDE, _adapter(
913
+ (_account("first", Product.CLAUDE), _account("second", Product.CLAUDE)),
914
+ {"first": _meters(80, 80), "second": _meters(70, 70)},
915
+ ))
916
+ monkeypatch.setattr(shutil, "which", lambda name: None)
917
+ monkeypatch.setattr(account_broker.support.subprocess, "run", lambda *arguments, **options: pytest.fail("a missing command ran"))
918
+
919
+ outcome, _ = account_broker._execute(Product.CLAUDE, ("claude", "-p"), now=NOW)
920
+
921
+ assert outcome.status == "start_failed"
922
+ assert "claude" in outcome.stderr
923
+
924
+
911
925
  @pytest.mark.parametrize("marked_name", ["retired", "first"])
912
926
  def test_should_run_past_a_stored_spent_mark_beyond_the_platform_range(
913
927
  monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], marked_name: str
@@ -2,16 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import sys
6
5
  import urllib.parse
7
- from pathlib import Path
8
6
 
9
7
  import pytest
10
8
 
11
- _SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
12
- if str(_SCRIPTS_DIRECTORY) not in sys.path:
13
- sys.path.insert(0, str(_SCRIPTS_DIRECTORY))
14
-
15
9
  import agent_merge_check
16
10
  from dev_env_scripts_constants.agent_merge_check_constants import (
17
11
  BEHIND_HOLD_REASON,