feat: v0.8.1 answer sessions from the inbox: allow/deny, peek & reply
- PermissionRequest hook: the state file records tool, detail and description of a pending permission; Notification keeps it. - devdesk attach --answer (presses 1/Esc only if the same wait is on and the prompt is visible), --peek (last exchange from the transcript), --reply (bracketed paste + Enter, streamed like uploads). - Inbox: Allow/Deny/Open for permission waits; Peek & reply for other waits and finished sessions. Matrix messages include the command. Closes #22 Closes #23 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
# Claude Code hook (wired in via claude-settings.json) that tracks what Claude is
|
||||
# doing in each DevDesk session, for the sidebar's at-a-glance status:
|
||||
# UserPromptSubmit, PostToolUse -> working
|
||||
# PermissionRequest -> waiting, with what Claude wants to run
|
||||
# (tool + command/file/URL), for the inbox's
|
||||
# Allow/Deny (devdesk#22)
|
||||
# Notification -> waiting (Claude needs input or a permission)
|
||||
# Stop, SessionStart -> idle
|
||||
# SessionEnd -> exited
|
||||
@@ -35,7 +38,7 @@ PostToolUse:Edit | PostToolUse:Write | PostToolUse:MultiEdit | PostToolUse:Noteb
|
||||
esac
|
||||
case $event in
|
||||
UserPromptSubmit | PostToolUse) state=working ;;
|
||||
Notification) state=waiting ;;
|
||||
Notification | PermissionRequest) state=waiting ;;
|
||||
Stop | SessionStart) state=idle ;;
|
||||
SessionEnd) state=exited ;;
|
||||
*) exit 0 ;;
|
||||
@@ -47,19 +50,33 @@ file="$dir/$session.json"
|
||||
if [ "$state" != waiting ] && [ -f "$file" ] && grep -q "\"state\":\"$state\"" "$file"; then
|
||||
exit 0
|
||||
fi
|
||||
# What a permission prompt is about. tool_use_id is null in PermissionRequest,
|
||||
# so a wait is identified by its `since` instead.
|
||||
request=null
|
||||
if [ "$event" = PermissionRequest ]; then
|
||||
request=$(jq -cM '(.tool_input // {}) as $i | {tool: (.tool_name // "a tool"),
|
||||
detail: (($i.command // $i.file_path // $i.notebook_path // $i.url // $i.pattern // $i.query // $i.path // ($i | tostring)) | tostring | .[0:600]),
|
||||
description: ($i.description // null)}' <<<"$input" 2>/dev/null) || request=null
|
||||
message="Claude wants to use ${tool:-a tool}"
|
||||
fi
|
||||
# A second Notification during the same wait updates the message but keeps
|
||||
# `since`, so the wait stays one wait (one Matrix message at most).
|
||||
# `since` (and what the wait is about), so the wait stays one wait (one Matrix
|
||||
# message at most).
|
||||
since=$(date +%s)
|
||||
was_waiting=0
|
||||
if [ "$state" = waiting ] && grep -q '"state":"waiting"' "$file" 2>/dev/null; then
|
||||
was_waiting=1
|
||||
since=$(jq -rM '.since // empty' "$file" 2>/dev/null) || since=$(date +%s)
|
||||
[[ $since =~ ^[0-9]+$ ]] || since=$(date +%s)
|
||||
if [ "$request" = null ]; then
|
||||
request=$(jq -cM '.request // null' "$file" 2>/dev/null) || request=null
|
||||
[ "$request" = null ] || message=$(jq -rM '.message // empty' "$file" 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
mkdir -p "$dir" 2>/dev/null || exit 0
|
||||
tmp=$(mktemp "$dir/.$session.XXXXXX" 2>/dev/null) || exit 0
|
||||
if jq -cMn --arg s "$state" --arg m "$message" --arg e "$event" --argjson t "$since" \
|
||||
'{state: $s, since: $t, event: $e, message: (if $m == "" then null else $m end)}' >"$tmp"; then
|
||||
if jq -cMn --arg s "$state" --arg m "$message" --arg e "$event" --argjson t "$since" --argjson r "${request:-null}" \
|
||||
'{state: $s, since: $t, event: $e, message: (if $m == "" then null else $m end)} + (if $r then {request: $r} else {} end)' >"$tmp"; then
|
||||
mv -f "$tmp" "$file"
|
||||
else
|
||||
rm -f "$tmp"
|
||||
|
||||
Reference in New Issue
Block a user