claude-dev-env 8.51.1 → 8.51.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.
|
@@ -9,8 +9,9 @@ stop once and tells the model to set '<emoji> <name>'.
|
|
|
9
9
|
The hook stays silent when:
|
|
10
10
|
|
|
11
11
|
- the stop is already a retry after a block (stop_hook_active is true);
|
|
12
|
-
- the session shows no title tool: no
|
|
13
|
-
and no
|
|
12
|
+
- the session shows no title tool: no title tool named anywhere in the
|
|
13
|
+
transcript, and either no remote session id in the environment or a
|
|
14
|
+
deferred tool listing that leaves the title tool out;
|
|
14
15
|
- the transcript cannot be read.
|
|
15
16
|
"""
|
|
16
17
|
|
|
@@ -79,6 +80,11 @@ def _title_tool_names_in(all_entry_fields: dict[str, object]) -> list[str]:
|
|
|
79
80
|
return [each_name for each_name in all_names if TITLE_TOOL_NAME_PATTERN.match(each_name)]
|
|
80
81
|
|
|
81
82
|
|
|
83
|
+
def _lists_deferred_tools(all_entry_fields: dict[str, object]) -> bool:
|
|
84
|
+
attachment = all_entry_fields.get("attachment")
|
|
85
|
+
return isinstance(attachment, dict) and attachment.get("type") in DEFERRED_TOOL_ATTACHMENT_TYPES
|
|
86
|
+
|
|
87
|
+
|
|
82
88
|
def _is_title_call(entry_type: object, all_block_fields: dict[str, object]) -> bool:
|
|
83
89
|
return (
|
|
84
90
|
entry_type == "assistant"
|
|
@@ -125,10 +131,11 @@ def stop_block_reason(all_entries: list[dict[str, object]], is_remote_session: b
|
|
|
125
131
|
prompt -> set_session_title -> ok result => None
|
|
126
132
|
prompt -> work, no title call => block reason
|
|
127
133
|
no title tool anywhere, not remote => None
|
|
134
|
+
remote, tool list lacks the title tool => None
|
|
128
135
|
|
|
129
136
|
Args:
|
|
130
137
|
all_entries: The transcript entries, oldest first.
|
|
131
|
-
is_remote_session: True when the session runs in a cloud session
|
|
138
|
+
is_remote_session: True when the session runs in a cloud session.
|
|
132
139
|
|
|
133
140
|
Returns:
|
|
134
141
|
The reason to send back to the model, or None to let the turn end.
|
|
@@ -136,7 +143,9 @@ def stop_block_reason(all_entries: list[dict[str, object]], is_remote_session: b
|
|
|
136
143
|
all_seen_tool_names = [
|
|
137
144
|
each_name for each_entry in all_entries for each_name in _title_tool_names_in(each_entry)
|
|
138
145
|
]
|
|
139
|
-
if not all_seen_tool_names and
|
|
146
|
+
if not all_seen_tool_names and (
|
|
147
|
+
not is_remote_session or any(_lists_deferred_tools(each) for each in all_entries)
|
|
148
|
+
):
|
|
140
149
|
return None
|
|
141
150
|
if _title_set_since(all_entries[_turn_start_index(all_entries) :]):
|
|
142
151
|
return None
|
|
@@ -172,6 +172,33 @@ def test_should_stay_silent_in_a_session_with_no_title_tool(
|
|
|
172
172
|
assert run_gate(monkeypatch, capsys, tmp_path, all_entries) == (0, "")
|
|
173
173
|
|
|
174
174
|
|
|
175
|
+
def test_should_stay_silent_in_a_remote_session_whose_tool_list_lacks_the_title_tool(
|
|
176
|
+
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], tmp_path: Path
|
|
177
|
+
) -> None:
|
|
178
|
+
monkeypatch.setenv(REMOTE_SESSION_VARIABLE, "cse_1")
|
|
179
|
+
all_entries = [
|
|
180
|
+
deferred_tools("TaskCreate", "mcp__claude-code-remote__get_session"),
|
|
181
|
+
prompt("Fix the runner"),
|
|
182
|
+
tool_call("t1", "Bash"),
|
|
183
|
+
tool_result("t1"),
|
|
184
|
+
]
|
|
185
|
+
assert run_gate(monkeypatch, capsys, tmp_path, all_entries) == (0, "")
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def test_should_block_a_remote_session_whose_tool_list_names_the_title_tool(
|
|
189
|
+
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], tmp_path: Path
|
|
190
|
+
) -> None:
|
|
191
|
+
monkeypatch.setenv(REMOTE_SESSION_VARIABLE, "cse_1")
|
|
192
|
+
all_entries = [
|
|
193
|
+
deferred_tools("TaskCreate", REMOTE_TITLE_TOOL),
|
|
194
|
+
prompt("Fix the runner"),
|
|
195
|
+
tool_call("t1", "Bash"),
|
|
196
|
+
tool_result("t1"),
|
|
197
|
+
]
|
|
198
|
+
_, stdout_text = run_gate(monkeypatch, capsys, tmp_path, all_entries)
|
|
199
|
+
assert json.loads(stdout_text)["decision"] == "block"
|
|
200
|
+
|
|
201
|
+
|
|
175
202
|
def test_should_stay_silent_on_the_retry_after_a_block(
|
|
176
203
|
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str], tmp_path: Path
|
|
177
204
|
) -> None:
|
package/package.json
CHANGED