Skip to content

Commit 6b1317a

Browse files
authored
feat(overlay): two-field rule editor, per-tool input display, Skill auto-allow (#19)
* feat(overlay): two-field rule editor, per-tool input display, Skill auto-allow * fix(overlay): restore mode auto-allow, write tools fall through to native dialog * fix(mode): acceptEdits auto-allows read tools inside cwd (superset of default) * fix(overlay): pre-fill rule editor fields with current values via read -i * feat(overlay): session context header, 300s hook timeout * fix(overlay): remove speculative CLAUDE_SESSION_NAME, use tmux window only * feat(overlay): kitty/wezterm window title in session context header * fix(overlay): compact header with cwd + session, robust cwd fallback * fix(lock): detect and remove stale locks from killed hook processes
1 parent 33282df commit 6b1317a

11 files changed

Lines changed: 355 additions & 137 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "passthru",
3-
"version": "0.5.1",
3+
"version": "0.5.2",
44
"description": "Regex-based permission rules for Claude Code via hooks",
55
"owner": {
66
"name": "nnemirovsky"

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "passthru",
3-
"version": "0.5.1",
3+
"version": "0.5.2",
44
"description": "Regex-based permission rules for Claude Code via hooks",
55
"license": "MIT"
66
}

hooks/common.sh

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,9 @@ overlay_available() {
361361
#
362362
# Mode behavior:
363363
# bypassPermissions: always 0 (everything auto-allowed).
364-
# acceptEdits: 0 for Write/Edit/NotebookEdit/MultiEdit when the
365-
# target file_path resolves inside cwd. Non-edit tools
366-
# in acceptEdits return 1.
364+
# acceptEdits: superset of default. 0 for Write/Edit/NotebookEdit/
365+
# MultiEdit + Read/Grep/Glob/NotebookRead/LS when the
366+
# target path resolves inside cwd.
367367
# default (+ empty mode value): 0 for read-only tools
368368
# (Read/Grep/Glob/NotebookRead/LS) when the target path
369369
# is inside cwd. Everything else returns 1, including
@@ -408,6 +408,8 @@ permission_mode_auto_allows() {
408408

409409
case "$mode" in
410410
acceptEdits)
411+
# acceptEdits is a superset of default: everything default auto-allows
412+
# (Read/Grep/Glob/LS inside cwd) PLUS edit tools inside cwd.
411413
case "$tool_name" in
412414
Write|Edit|NotebookEdit|MultiEdit)
413415
local fp
@@ -417,6 +419,25 @@ permission_mode_auto_allows() {
417419
fi
418420
return 1
419421
;;
422+
Read|NotebookRead)
423+
local fp
424+
fp="$(jq -r '.file_path // .notebook_path // ""' <<<"$tool_input" 2>/dev/null || printf '')"
425+
if _pm_path_inside_cwd "$fp" "$cwd"; then
426+
return 0
427+
fi
428+
return 1
429+
;;
430+
Grep|Glob|LS)
431+
local gp
432+
gp="$(jq -r '.path // ""' <<<"$tool_input" 2>/dev/null || printf '')"
433+
if [ -z "$gp" ]; then
434+
return 0
435+
fi
436+
if _pm_path_inside_cwd "$gp" "$cwd"; then
437+
return 0
438+
fi
439+
return 1
440+
;;
420441
*)
421442
return 1
422443
;;

hooks/handlers/pre-tool-use.sh

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ fi
487487
# that should never trigger the overlay. Pass them through unconditionally.
488488
if [ "$MATCHED" != "ask" ]; then
489489
case "$TOOL_NAME" in
490-
ToolSearch|TaskCreate|TaskUpdate|TaskGet|TaskList|TaskOutput|TaskStop|\
490+
ToolSearch|Skill|TaskCreate|TaskUpdate|TaskGet|TaskList|TaskOutput|TaskStop|\
491491
AskUserQuestion|SendMessage|EnterPlanMode|ExitPlanMode|ScheduleWakeup|\
492492
CronCreate|CronDelete|CronList|Monitor|LSP|RemoteTrigger|\
493493
EnterWorktree|ExitWorktree|TeamCreate|TeamDelete)
@@ -497,12 +497,38 @@ if [ "$MATCHED" != "ask" ]; then
497497
esac
498498
fi
499499

500-
# --- 8. Overlay path -------------------------------------------------------
501-
# Passthru handles ALL non-internal tool calls. There is no mode-based
502-
# auto-allow shortcut. Every unmatched call goes to the overlay so the user
503-
# always sees a prompt. CC's native dialog only fires as a fallback when the
504-
# user explicitly cancels the overlay (Esc) or the overlay is unavailable.
505-
#
500+
# --- 8. Mode-based auto-allow -----------------------------------------------
501+
# Replicate CC's per-mode auto-allow logic within passthru. Calls that CC
502+
# would silently approve (e.g. Read inside cwd in default mode, Write inside
503+
# cwd in acceptEdits mode) get an explicit allow from passthru so the overlay
504+
# does not fire for routine operations. Passthru emits allow (not continue),
505+
# keeping the decision on our side rather than falling through to CC.
506+
if [ "$MATCHED" != "ask" ]; then
507+
if permission_mode_auto_allows "$PERMISSION_MODE" "$TOOL_NAME" "$TOOL_INPUT" "$CC_CWD" 2>/dev/null; then
508+
MSG="passthru mode-allow: ${PERMISSION_MODE:-default}"
509+
emit_decision "allow" "$MSG"
510+
audit_write_line "allow" "$TOOL_NAME" "mode:${PERMISSION_MODE:-default}" "" "" "$TOOL_USE_ID" "passthru-mode"
511+
exit 0
512+
fi
513+
fi
514+
515+
# --- 9. Write tools -> native dialog (for diff rendering) ------------------
516+
# Write/Edit/NotebookEdit that weren't mode-auto-allowed (step 8) should
517+
# fall through to CC's native dialog which renders diffs. The overlay can't
518+
# show diffs, so forcing Esc for every edit is bad UX. An explicit ask-rule
519+
# match still routes to the overlay (user opted in).
520+
if [ "$MATCHED" != "ask" ]; then
521+
case "$TOOL_NAME" in
522+
Write|Edit|NotebookEdit|MultiEdit)
523+
emit_decision "ask" "passthru: write tool, deferring to native dialog for diff"
524+
audit_write_line "ask" "$TOOL_NAME" "write-tool native fallback" "" "" "$TOOL_USE_ID"
525+
audit_write_breadcrumb "$TOOL_USE_ID" "$TOOL_NAME" "$TOOL_INPUT"
526+
exit 0
527+
;;
528+
esac
529+
fi
530+
531+
# --- 10. Overlay path ------------------------------------------------------
506532
# Reached when either:
507533
# * an ask[] rule matched, or
508534
# * no rule matched AND mode did NOT auto-allow.
@@ -582,6 +608,7 @@ fi
582608
export PASSTHRU_OVERLAY_RESULT_FILE="$OVERLAY_RESULT"
583609
export PASSTHRU_OVERLAY_TOOL_NAME="$TOOL_NAME"
584610
export PASSTHRU_OVERLAY_TOOL_INPUT_JSON="$TOOL_INPUT"
611+
export PASSTHRU_OVERLAY_CWD="$CC_CWD"
585612

586613
# Invoke the overlay and capture its exit code. We have an ERR trap in place
587614
# (converts unexpected errors to fail-open passthrough), so we cannot rely on

hooks/hooks.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
{
99
"type": "command",
1010
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/handlers/pre-tool-use.sh",
11-
"timeout": 75
11+
"timeout": 300
1212
}
1313
]
1414
}

0 commit comments

Comments
 (0)