claude-dev-env 8.47.2 → 8.47.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.
|
@@ -207,17 +207,21 @@ def aggregate_bash_hook_results(
|
|
|
207
207
|
|
|
208
208
|
|
|
209
209
|
def _emit_decision(decision: BashDispatcherDecision) -> None:
|
|
210
|
-
"""Write one PreToolUse permission payload to stdout when an outcome exists.
|
|
210
|
+
"""Write one PreToolUse permission payload to stdout when an outcome exists.
|
|
211
|
+
|
|
212
|
+
A rewrite carries updatedInput with no permissionDecision, so the harness
|
|
213
|
+
applies the rewritten command and then runs its normal permission prompt.
|
|
214
|
+
"""
|
|
211
215
|
if not decision.decision:
|
|
212
216
|
return
|
|
213
|
-
hook_specific: dict[str, object] = {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
+
hook_specific: dict[str, object] = {"hookEventName": HOOK_EVENT_NAME}
|
|
218
|
+
is_rewrite = decision.decision == ALLOW_DECISION and decision.updated_input is not None
|
|
219
|
+
if is_rewrite:
|
|
220
|
+
hook_specific[_UPDATED_INPUT_KEY] = decision.updated_input
|
|
221
|
+
else:
|
|
222
|
+
hook_specific[_PERMISSION_DECISION_KEY] = decision.decision
|
|
217
223
|
if decision.reasons:
|
|
218
224
|
hook_specific[_PERMISSION_REASON_KEY] = REASON_JOIN_SEPARATOR.join(decision.reasons)
|
|
219
|
-
if decision.decision == ALLOW_DECISION and decision.updated_input is not None:
|
|
220
|
-
hook_specific[_UPDATED_INPUT_KEY] = decision.updated_input
|
|
221
225
|
if decision.all_additional_context:
|
|
222
226
|
hook_specific[_ADDITIONAL_CONTEXT_KEY] = CONTEXT_JOIN_SEPARATOR.join(
|
|
223
227
|
decision.all_additional_context
|
|
@@ -235,3 +235,19 @@ def test_emit_decision_re_emits_silent_deny_fields(
|
|
|
235
235
|
assert hook_specific["additionalContext"] == "see docs/runbook.md"
|
|
236
236
|
assert emitted_payload["systemMessage"] == "[gh-gate] blocked redirected gh pr create"
|
|
237
237
|
assert emitted_payload["suppressOutput"] is True
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_emit_decision_sends_a_rewrite_through_the_permission_prompt(
|
|
241
|
+
capsys: pytest.CaptureFixture[str],
|
|
242
|
+
) -> None:
|
|
243
|
+
"""A rewritten command reaches the harness with updatedInput and no permissionDecision."""
|
|
244
|
+
rewrite = BashDispatcherDecision(
|
|
245
|
+
decision="allow",
|
|
246
|
+
updated_input={"command": "MSYS2_ARG_CONV_EXCL='*' git show HEAD:a.py"},
|
|
247
|
+
)
|
|
248
|
+
_emit_decision(rewrite)
|
|
249
|
+
hook_specific = json.loads(capsys.readouterr().out.strip())["hookSpecificOutput"]
|
|
250
|
+
assert "permissionDecision" not in hook_specific
|
|
251
|
+
assert hook_specific["updatedInput"] == {
|
|
252
|
+
"command": "MSYS2_ARG_CONV_EXCL='*' git show HEAD:a.py"
|
|
253
|
+
}
|
package/package.json
CHANGED
|
@@ -54,7 +54,6 @@ export const PRE_TOOL_USE_EVENT_NAME = 'PreToolUse';
|
|
|
54
54
|
export const SESSION_START_HOOK_SCRIPT_NAME = 'working_style_prompt.py';
|
|
55
55
|
export const BASH_HOOK_SCRIPT_NAME = 'bash_pre_tool_use_dispatcher.py';
|
|
56
56
|
export const BASH_MATCHER = 'Bash';
|
|
57
|
-
export const ALLOW_DECISION = 'allow';
|
|
58
57
|
|
|
59
58
|
export const SESSION_START_PAYLOAD = {
|
|
60
59
|
hook_event_name: SESSION_START_EVENT_NAME,
|
|
@@ -238,8 +237,8 @@ function runBlockingStage(settingsPath, scratchHome, evidenceDirectory) {
|
|
|
238
237
|
);
|
|
239
238
|
const hookResult = runInstalledHook(command, scratchHome, BASH_HOOK_PAYLOAD);
|
|
240
239
|
const envelope = readEnvelope(hookResult.stdout, PRE_TOOL_USE_EVENT_NAME);
|
|
241
|
-
if (envelope.permissionDecision !==
|
|
242
|
-
throw new Error(`The PreToolUse envelope
|
|
240
|
+
if (envelope.permissionDecision !== undefined) {
|
|
241
|
+
throw new Error(`The PreToolUse envelope skipped the permission prompt with ${envelope.permissionDecision}`);
|
|
243
242
|
}
|
|
244
243
|
const rewrittenCommand = envelope.updatedInput?.command ?? '';
|
|
245
244
|
if (!rewrittenCommand.includes(REWRITE_MARKER)) {
|