claude-dev-env 8.88.1 → 8.88.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/bin/codex-trimmed-sol.mjs +100 -3
- package/bin/codex-trimmed-sol.test.mjs +155 -2
- package/bin/folder-lockers.mjs +142 -0
- package/bin/folder-lockers.test.mjs +55 -0
- package/bin/global-install-shadow.mjs +75 -0
- package/bin/global-install-shadow.test.mjs +56 -0
- package/bin/install-deepstack-plugin.mjs +45 -16
- package/bin/install-deepstack-plugin.test.mjs +65 -1
- package/bin/install-pstack-plugin.mjs +20 -4
- package/bin/install-pstack-plugin.test.mjs +53 -0
- package/bin/install.mjs +79 -6
- package/bin/install.test.mjs +93 -0
- package/bin/profile-stop-gate.mjs +193 -0
- package/bin/profile-stop-gate.test.mjs +124 -0
- package/docs/agents-guidance/asks.md +2 -1
- package/docs/codex-accounts.md +14 -2
- package/docs/decisions/deepstack-gate.md +6 -2
- package/hooks/features/session-context.md +1 -1
- package/hooks/hooks_constants/deepen_default_rewrite_constants.py +39 -0
- package/hooks/session/deepen_default_rewrite.py +128 -0
- package/hooks/session/deepen_first_prompt.py +3 -15
- package/hooks/session/test_deepen_default_rewrite.py +90 -0
- package/hooks/session/test_deepen_first_prompt.py +12 -1
- package/package.json +1 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Tests for the role-shaped default rewrite."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
9
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
10
|
+
|
|
11
|
+
from deepen_default_rewrite import role_default_rewrite
|
|
12
|
+
from deepen_role_gate import refusal_reason
|
|
13
|
+
from hooks_constants.deepen_first_prompt_constants import ALL_FOUR_QUESTION_STEMS, DEEPEN_MARKER
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _role_line(rewrite: str, label: str) -> str:
|
|
17
|
+
return next(each for each in rewrite.splitlines() if each.startswith(label))[len(label) :].strip()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_should_pass_the_gate_for_a_plain_task() -> None:
|
|
21
|
+
task = "Add dark mode to the settings page"
|
|
22
|
+
rewrite = role_default_rewrite(task)
|
|
23
|
+
assert rewrite.startswith(DEEPEN_MARKER)
|
|
24
|
+
assert refusal_reason(task, rewrite) is None
|
|
25
|
+
assert _role_line(rewrite, "SCOPE (role):") == task
|
|
26
|
+
assert _role_line(rewrite, "EXAMPLES (illustration only):") == "none"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_should_not_paste_the_four_question_stems() -> None:
|
|
30
|
+
rewrite = role_default_rewrite("Add dark mode to the settings page")
|
|
31
|
+
assert not any(each_stem in rewrite for each_stem in ALL_FOUR_QUESTION_STEMS)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_should_move_a_marked_example_out_of_the_scope() -> None:
|
|
35
|
+
task = "fix the flaky tests, e.g. test_auth and test_cache, and keep CI fast"
|
|
36
|
+
rewrite = role_default_rewrite(task)
|
|
37
|
+
assert refusal_reason(task, rewrite) is None
|
|
38
|
+
assert _role_line(rewrite, "SCOPE (role):") == "fix the flaky tests and keep CI fast"
|
|
39
|
+
assert _role_line(rewrite, "EXAMPLES (illustration only):") == "test_auth and test_cache"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_should_ask_before_narrowing_when_the_scope_names_the_example() -> None:
|
|
43
|
+
task = "Fix the login failure. For example, the login failure on Safari."
|
|
44
|
+
rewrite = role_default_rewrite(task)
|
|
45
|
+
assert refusal_reason(task, rewrite) is None
|
|
46
|
+
assert _role_line(rewrite, "ZOOM-IN BLOCKER:").startswith("the scope names something")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_should_keep_every_hard_constraint_line() -> None:
|
|
50
|
+
task = "Keep the build green. For example, the login failure.\n\nHARD CONSTRAINTS\n- Never open a pull request.\n"
|
|
51
|
+
rewrite = role_default_rewrite(task)
|
|
52
|
+
assert refusal_reason(task, rewrite) is None
|
|
53
|
+
assert "- Never open a pull request." in rewrite.splitlines()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_should_keep_every_task_sentence_in_scope_when_the_task_opens_with_context() -> None:
|
|
57
|
+
task = "We have a Django app. Add CSV export to the reports page, e.g. the monthly sales report, and keep the existing URLs."
|
|
58
|
+
rewrite = role_default_rewrite(task)
|
|
59
|
+
assert refusal_reason(task, rewrite) is None
|
|
60
|
+
assert _role_line(rewrite, "SCOPE (role):") == (
|
|
61
|
+
"We have a Django app. Add CSV export to the reports page and keep the existing URLs."
|
|
62
|
+
)
|
|
63
|
+
assert _role_line(rewrite, "EXAMPLES (illustration only):") == "the monthly sales report"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_should_clip_a_long_scope_and_point_at_the_full_task() -> None:
|
|
67
|
+
task = "Refactor the module. " * 40
|
|
68
|
+
rewrite = role_default_rewrite(task.strip())
|
|
69
|
+
scope = _role_line(rewrite, "SCOPE (role):")
|
|
70
|
+
assert scope.endswith("(the rest is in the task below)")
|
|
71
|
+
assert len(scope) < len(task)
|
|
72
|
+
assert refusal_reason(task.strip(), rewrite) is None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_should_keep_a_marker_word_inside_a_longer_word_in_the_scope() -> None:
|
|
76
|
+
task = "Search the codebase for examples of deprecated API calls and replace each one with the new client."
|
|
77
|
+
rewrite = role_default_rewrite(task)
|
|
78
|
+
assert refusal_reason(task, rewrite) is None
|
|
79
|
+
assert _role_line(rewrite, "SCOPE (role):") == task
|
|
80
|
+
assert _role_line(rewrite, "EXAMPLES (illustration only):") == "none"
|
|
81
|
+
assumption_task = "Avoid such assumptions in the parser and add input validation."
|
|
82
|
+
assert _role_line(role_default_rewrite(assumption_task), "SCOPE (role):") == assumption_task
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_should_move_every_marked_example_in_a_sentence_out_of_the_scope() -> None:
|
|
86
|
+
task = "Speed up the slow pages such as the dashboard, and cache reads, e.g. the user lookup, and keep the API stable."
|
|
87
|
+
rewrite = role_default_rewrite(task)
|
|
88
|
+
assert refusal_reason(task, rewrite) is None
|
|
89
|
+
assert _role_line(rewrite, "SCOPE (role):") == "Speed up the slow pages and cache reads and keep the API stable."
|
|
90
|
+
assert _role_line(rewrite, "EXAMPLES (illustration only):") == "the dashboard; the user lookup"
|
|
@@ -31,6 +31,7 @@ from hooks_constants.deepen_first_prompt_constants import (
|
|
|
31
31
|
REFUSAL_EXAMPLE_NOUN_IN_SCOPE,
|
|
32
32
|
REFUSAL_MISSING_ROLE_LINES,
|
|
33
33
|
REFUSAL_RESTATES_FOUR_QUESTIONS,
|
|
34
|
+
ALL_FOUR_QUESTION_STEMS,
|
|
34
35
|
SKIP_DEEPEN_ENV_VAR,
|
|
35
36
|
USER_PROMPT_SUBMIT_EVENT_NAME,
|
|
36
37
|
CURSOR_BEFORE_SUBMIT_PROMPT_EVENT_NAME,
|
|
@@ -341,12 +342,20 @@ def test_should_strip_the_deepen_slash_before_rewriting() -> None:
|
|
|
341
342
|
assert deepen.task_text_for_deepen("/deepen fix the login page") == "fix the login page"
|
|
342
343
|
|
|
343
344
|
|
|
344
|
-
def test_should_refuse_the_paste_path_as_the_known_bad() -> None:
|
|
345
|
+
def test_should_refuse_the_paste_path_as_the_known_bad(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
346
|
+
pasted_questions = "\n".join(ALL_FOUR_QUESTION_STEMS)
|
|
347
|
+
monkeypatch.setenv(DEEPEN_REWRITE_ENV_VAR, _role_rewrite(pasted_questions))
|
|
345
348
|
decision = deepen.decide_first_prompt(_payload("Add dark mode to the settings page"))
|
|
346
349
|
assert isinstance(decision, deepen.Refuse)
|
|
347
350
|
assert decision.reason == REFUSAL_RESTATES_FOUR_QUESTIONS
|
|
348
351
|
|
|
349
352
|
|
|
353
|
+
def test_should_deepen_with_the_default_rewrite_when_nothing_is_configured() -> None:
|
|
354
|
+
decision = deepen.decide_first_prompt(_payload("Add dark mode to the settings page"))
|
|
355
|
+
assert isinstance(decision, deepen.Deepen)
|
|
356
|
+
assert "SCOPE (role): Add dark mode to the settings page" in decision.rewritten_prompt
|
|
357
|
+
|
|
358
|
+
|
|
350
359
|
def test_should_refuse_the_filled_four_answer_stub_without_role_lines(
|
|
351
360
|
monkeypatch: pytest.MonkeyPatch,
|
|
352
361
|
) -> None:
|
|
@@ -427,6 +436,7 @@ def test_should_print_a_json_refusal_for_the_paste_path(
|
|
|
427
436
|
monkeypatch: pytest.MonkeyPatch,
|
|
428
437
|
) -> None:
|
|
429
438
|
monkeypatch.setenv("CDE_DEEPEN_OUTPUT", DEEPEN_OUTPUT_JSON)
|
|
439
|
+
monkeypatch.setenv(DEEPEN_REWRITE_ENV_VAR, _role_rewrite("\n".join(ALL_FOUR_QUESTION_STEMS)))
|
|
430
440
|
printed = _run_main(_payload("Add dark mode to the settings page"))
|
|
431
441
|
assert json.loads(printed) == {
|
|
432
442
|
"decision": "refuse",
|
|
@@ -438,4 +448,5 @@ def test_should_stay_silent_in_rewrite_mode_when_the_gate_refuses(
|
|
|
438
448
|
monkeypatch: pytest.MonkeyPatch,
|
|
439
449
|
) -> None:
|
|
440
450
|
monkeypatch.setenv("CDE_DEEPEN_OUTPUT", DEEPEN_OUTPUT_REWRITE)
|
|
451
|
+
monkeypatch.setenv(DEEPEN_REWRITE_ENV_VAR, _FILLED_FOUR_ANSWERS)
|
|
441
452
|
assert _run_main(_payload("Add dark mode to the settings page")) == ""
|